Add dome on opene906
This commit is contained in:
parent
0d940ba004
commit
1d7ba86749
|
@ -0,0 +1,3 @@
|
||||||
|
obj_dir/
|
||||||
|
build/
|
||||||
|
logs/
|
|
@ -0,0 +1,79 @@
|
||||||
|
export CODE_BASE_PATH = ${PWD}/../../E906_RTL_FACTORY
|
||||||
|
GCC_PREFIX = /opt/riscv/bin/riscv32-unknown-elf
|
||||||
|
GDB_PREFIX = /opt/riscv/bin/riscv32-unknown-elf-gdb
|
||||||
|
|
||||||
|
FILELIST = -F ../../smart_run/logical/filelists/soc.fl -F ./dpi/jtag.fl
|
||||||
|
|
||||||
|
|
||||||
|
ABI = -mabi=ilp32 -march=rv32imc
|
||||||
|
|
||||||
|
DEMODIR = ${PWD}
|
||||||
|
BUILD_DIR = ${DEMODIR}/build
|
||||||
|
|
||||||
|
TEST = sim
|
||||||
|
|
||||||
|
|
||||||
|
LINK = $(DEMODIR)/link.ld
|
||||||
|
|
||||||
|
# CFLAGS for verilator generated Makefiles. Without -std=c++11 it complains for `auto` variables
|
||||||
|
CFLAGS += "-std=c++11"
|
||||||
|
# Optimization for better performance; alternative is nothing for slower runtime (faster compiles)
|
||||||
|
# -O2 for faster runtime (slower compiles), or -O for balance.
|
||||||
|
VERILATOR_MAKE_FLAGS = OPT_FAST="-Os"
|
||||||
|
|
||||||
|
# Targets
|
||||||
|
all: clean verilator
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf build obj_dir
|
||||||
|
|
||||||
|
##################### Verilog Builds #####################################
|
||||||
|
|
||||||
|
verilator-build:
|
||||||
|
verilator --cc -CFLAGS ${CFLAGS} \
|
||||||
|
-Wno-UNOPTFLAT \
|
||||||
|
-Wno-STMTDLY \
|
||||||
|
-Wno-MULTIDRIVEN \
|
||||||
|
-Wno-CASEINCOMPLETE \
|
||||||
|
-Wno-COMBDLY \
|
||||||
|
-Wno-LATCH \
|
||||||
|
-Wno-WIDTH \
|
||||||
|
-Wno-IMPLICIT \
|
||||||
|
${FILELIST} \
|
||||||
|
soc_sim.v \
|
||||||
|
--trace \
|
||||||
|
--top-module soc_sim -exe test_soc_sim.cpp --autoflush
|
||||||
|
cp ${DEMODIR}/test_soc_sim.cpp obj_dir
|
||||||
|
$(MAKE) -j -C obj_dir/ -f Vsoc_sim.mk $(VERILATOR_MAKE_FLAGS)
|
||||||
|
|
||||||
|
##################### Simulation Runs #####################################
|
||||||
|
|
||||||
|
verilator: program.hex verilator-build
|
||||||
|
cd build && ../obj_dir/Vsoc_sim
|
||||||
|
|
||||||
|
##################### Test hex Build #####################################
|
||||||
|
|
||||||
|
program.hex: $(TEST).o $(LINK)
|
||||||
|
@echo Building $(TEST)
|
||||||
|
$(GCC_PREFIX)-gcc $(ABI) -Wl,-Map=$(BUILD_DIR)/$(TEST).map -lgcc -T$(LINK) -o $(BUILD_DIR)/$(TEST).bin $(BUILD_DIR)/$(TEST).o -nostartfiles $(TEST_LIBS)
|
||||||
|
$(GCC_PREFIX)-objcopy -O verilog $(BUILD_DIR)/$(TEST).bin $(BUILD_DIR)/program.hex
|
||||||
|
$(GCC_PREFIX)-objdump -S $(BUILD_DIR)/$(TEST).bin > $(BUILD_DIR)/$(TEST).dis
|
||||||
|
@echo Completed building $(TEST)
|
||||||
|
|
||||||
|
%.o : %.s
|
||||||
|
@mkdir -p build
|
||||||
|
$(GCC_PREFIX)-cpp -g -I${BUILD_DIR} $< > $(BUILD_DIR)/$*.cpp.s
|
||||||
|
$(GCC_PREFIX)-as -g $(ABI) $(BUILD_DIR)/$*.cpp.s -o $(BUILD_DIR)/$@
|
||||||
|
|
||||||
|
##################### openocd #####################################
|
||||||
|
|
||||||
|
openocd:
|
||||||
|
openocd -f riscv.cfg
|
||||||
|
|
||||||
|
gdb:
|
||||||
|
$(GDB_PREFIX) -x gdbinit ./build/$(TEST).bin
|
||||||
|
|
||||||
|
help:
|
||||||
|
@echo Possible targets: verilator help clean all verilator-build program.hex
|
||||||
|
|
||||||
|
.PHONY: help clean verilator
|
|
@ -0,0 +1,18 @@
|
||||||
|
# jtag simulation
|
||||||
|
|
||||||
|
|
||||||
|
## start openocd
|
||||||
|
|
||||||
|
`openocd -d -f swerv.cfg`
|
||||||
|
|
||||||
|
## start gdb
|
||||||
|
|
||||||
|
`/opt/riscv/bin/riscv32-unknown-elf-gdb -ex "target extended-remote :3333"`
|
||||||
|
|
||||||
|
## quick start
|
||||||
|
|
||||||
|
At demo/jtag/
|
||||||
|
|
||||||
|
1. `make all`
|
||||||
|
2. `make openocd`
|
||||||
|
3. `make gdb`
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,437 @@
|
||||||
|
// Copyright lowRISC contributors.
|
||||||
|
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
#include "tcp_server.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple buffer for passing data between TCP sockets and DPI modules
|
||||||
|
*/
|
||||||
|
const int BUFSIZE_BYTE = 25600;
|
||||||
|
|
||||||
|
struct tcp_buf {
|
||||||
|
unsigned int rptr;
|
||||||
|
unsigned int wptr;
|
||||||
|
char buf[BUFSIZE_BYTE];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TCP Server thread context structure
|
||||||
|
*/
|
||||||
|
struct tcp_server_ctx {
|
||||||
|
// Writeable by the host thread
|
||||||
|
char *display_name;
|
||||||
|
uint16_t listen_port;
|
||||||
|
volatile bool socket_run;
|
||||||
|
// Writeable by the server thread
|
||||||
|
tcp_buf *buf_in;
|
||||||
|
tcp_buf *buf_out;
|
||||||
|
int sfd; // socket fd
|
||||||
|
int cfd; // client fd
|
||||||
|
pthread_t sock_thread;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool tcp_buffer_is_full(struct tcp_buf *buf) {
|
||||||
|
if (buf->wptr >= buf->rptr) {
|
||||||
|
return (buf->wptr - buf->rptr) == (BUFSIZE_BYTE - 1);
|
||||||
|
} else {
|
||||||
|
return (buf->rptr - buf->wptr) == 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool tcp_buffer_is_empty(struct tcp_buf *buf) {
|
||||||
|
return (buf->wptr == buf->rptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tcp_buffer_put_byte(struct tcp_buf *buf, char dat) {
|
||||||
|
bool done = false;
|
||||||
|
while (!done) {
|
||||||
|
if (!tcp_buffer_is_full(buf)) {
|
||||||
|
buf->buf[buf->wptr++] = dat;
|
||||||
|
buf->wptr %= BUFSIZE_BYTE;
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool tcp_buffer_get_byte(struct tcp_buf *buf, char *dat) {
|
||||||
|
if (tcp_buffer_is_empty(buf)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*dat = buf->buf[buf->rptr++];
|
||||||
|
buf->rptr %= BUFSIZE_BYTE;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct tcp_buf *tcp_buffer_new(void) {
|
||||||
|
struct tcp_buf *buf_new;
|
||||||
|
buf_new = (struct tcp_buf *)malloc(sizeof(struct tcp_buf));
|
||||||
|
buf_new->rptr = 0;
|
||||||
|
buf_new->wptr = 0;
|
||||||
|
return buf_new;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tcp_buffer_free(struct tcp_buf **buf) {
|
||||||
|
free(*buf);
|
||||||
|
*buf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start a TCP server
|
||||||
|
*
|
||||||
|
* This function creates attempts to create a new TCP socket instance. The
|
||||||
|
* socket is a non-blocking stream socket, with buffering disabled.
|
||||||
|
*
|
||||||
|
* @param ctx context object
|
||||||
|
* @return 0 on success, -1 in case of an error
|
||||||
|
*/
|
||||||
|
static int start(struct tcp_server_ctx *ctx) {
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
assert(ctx->sfd == 0 && "Server already started.");
|
||||||
|
|
||||||
|
// create socket
|
||||||
|
int sfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (sfd == -1) {
|
||||||
|
fprintf(stderr, "%s: Unable to create socket: %s (%d)\n", ctx->display_name,
|
||||||
|
strerror(errno), errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = fcntl(sfd, F_SETFL, O_NONBLOCK);
|
||||||
|
if (rv != 0) {
|
||||||
|
fprintf(stderr, "%s: Unable to make socket non-blocking: %s (%d)\n",
|
||||||
|
ctx->display_name, strerror(errno), errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reuse existing socket (if existing)
|
||||||
|
int reuse_socket = 1;
|
||||||
|
rv = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse_socket, sizeof(int));
|
||||||
|
if (rv != 0) {
|
||||||
|
fprintf(stderr, "%s: Unable to set socket options: %s (%d)\n",
|
||||||
|
ctx->display_name, strerror(errno), errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop tcp socket from buffering (buffering prevents timely responses to
|
||||||
|
// OpenOCD which severly limits debugging performance)
|
||||||
|
int tcp_nodelay = 1;
|
||||||
|
rv = setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, &tcp_nodelay, sizeof(int));
|
||||||
|
if (rv != 0) {
|
||||||
|
fprintf(stderr, "%s: Unable to set socket nodelay: %s (%d)\n",
|
||||||
|
ctx->display_name, strerror(errno), errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bind server
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
addr.sin_port = htons(ctx->listen_port);
|
||||||
|
|
||||||
|
rv = bind(sfd, (struct sockaddr *)&addr, sizeof(addr));
|
||||||
|
if (rv != 0) {
|
||||||
|
fprintf(stderr, "%s: Failed to bind socket: %s (%d)\n", ctx->display_name,
|
||||||
|
strerror(errno), errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// listen for incoming connections
|
||||||
|
rv = listen(sfd, 1);
|
||||||
|
if (rv != 0) {
|
||||||
|
fprintf(stderr, "%s: Failed to listen on socket: %s (%d)\n",
|
||||||
|
ctx->display_name, strerror(errno), errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->sfd = sfd;
|
||||||
|
assert(ctx->sfd > 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accept an incoming connection from a client (nonblocking)
|
||||||
|
*
|
||||||
|
* The resulting client fd is made non-blocking.
|
||||||
|
*
|
||||||
|
* @param ctx context object
|
||||||
|
* @return 0 on success, any other value indicates an error
|
||||||
|
*/
|
||||||
|
static int client_tryaccept(struct tcp_server_ctx *ctx) {
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
assert(ctx->sfd > 0);
|
||||||
|
assert(ctx->cfd == 0);
|
||||||
|
|
||||||
|
int cfd = accept(ctx->sfd, NULL, NULL);
|
||||||
|
|
||||||
|
if (cfd == -1 && errno == EAGAIN) {
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cfd == -1) {
|
||||||
|
fprintf(stderr, "%s: Unable to accept incoming connection: %s (%d)\n",
|
||||||
|
ctx->display_name, strerror(errno), errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = fcntl(cfd, F_SETFL, O_NONBLOCK);
|
||||||
|
if (rv != 0) {
|
||||||
|
fprintf(stderr, "%s: Unable to make client socket non-blocking: %s (%d)\n",
|
||||||
|
ctx->display_name, strerror(errno), errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->cfd = cfd;
|
||||||
|
assert(ctx->cfd > 0);
|
||||||
|
|
||||||
|
printf("%s: Accepted client connection\n", ctx->display_name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop the TCP server
|
||||||
|
*
|
||||||
|
* @param ctx context object
|
||||||
|
*/
|
||||||
|
static void stop(struct tcp_server_ctx *ctx) {
|
||||||
|
assert(ctx);
|
||||||
|
if (!ctx->sfd) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
close(ctx->sfd);
|
||||||
|
ctx->sfd = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive a byte from a connected client
|
||||||
|
*
|
||||||
|
* @param ctx context object
|
||||||
|
* @param cmd byte received
|
||||||
|
* @return true if a byte was read
|
||||||
|
*/
|
||||||
|
static bool get_byte(struct tcp_server_ctx *ctx, char *cmd) {
|
||||||
|
assert(ctx);
|
||||||
|
|
||||||
|
ssize_t num_read = read(ctx->cfd, cmd, 1);
|
||||||
|
|
||||||
|
if (num_read == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (num_read == -1) {
|
||||||
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
|
return false;
|
||||||
|
} else if (errno == EBADF) {
|
||||||
|
// Possibly client went away? Accept a new connection.
|
||||||
|
fprintf(stderr, "%s: Client disappeared.\n", ctx->display_name);
|
||||||
|
tcp_server_client_close(ctx);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "%s: Error while reading from client: %s (%d)\n",
|
||||||
|
ctx->display_name, strerror(errno), errno);
|
||||||
|
assert(0 && "Error reading from client");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(num_read == 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a byte to a connected client
|
||||||
|
*
|
||||||
|
* @param ctx context object
|
||||||
|
* @param cmd byte to send
|
||||||
|
*/
|
||||||
|
static void put_byte(struct tcp_server_ctx *ctx, char cmd) {
|
||||||
|
while (1) {
|
||||||
|
ssize_t num_written = send(ctx->cfd, &cmd, sizeof(cmd), MSG_NOSIGNAL);
|
||||||
|
if (num_written == -1) {
|
||||||
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
|
continue;
|
||||||
|
} else if (errno == EPIPE) {
|
||||||
|
printf("%s: Remote disconnected.\n", ctx->display_name);
|
||||||
|
tcp_server_client_close(ctx);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "%s: Error while writing to client: %s (%d)\n",
|
||||||
|
ctx->display_name, strerror(errno), errno);
|
||||||
|
assert(0 && "Error writing to client.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (num_written >= 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleanup server context
|
||||||
|
*
|
||||||
|
* @param ctx context object
|
||||||
|
*/
|
||||||
|
static void ctx_free(struct tcp_server_ctx *ctx) {
|
||||||
|
// Free the buffers
|
||||||
|
tcp_buffer_free(&ctx->buf_in);
|
||||||
|
tcp_buffer_free(&ctx->buf_out);
|
||||||
|
// Free the display name
|
||||||
|
free(ctx->display_name);
|
||||||
|
// Free the ctx
|
||||||
|
free(ctx);
|
||||||
|
ctx = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thread function to create a new server instance
|
||||||
|
*
|
||||||
|
* @param ctx_void context object
|
||||||
|
* @return Always returns NULL
|
||||||
|
*/
|
||||||
|
static void *server_create(void *ctx_void) {
|
||||||
|
// Cast to a server struct
|
||||||
|
struct tcp_server_ctx *ctx = (struct tcp_server_ctx *)ctx_void;
|
||||||
|
struct timeval timeout;
|
||||||
|
|
||||||
|
// Start the server
|
||||||
|
int rv = start(ctx);
|
||||||
|
if (rv != 0) {
|
||||||
|
fprintf(stderr, "%s: Unable to create TCP server on port %d\n",
|
||||||
|
ctx->display_name, ctx->listen_port);
|
||||||
|
goto err_cleanup_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialise timeout
|
||||||
|
timeout.tv_sec = 0;
|
||||||
|
|
||||||
|
// Initialise fd_set
|
||||||
|
|
||||||
|
// Start waiting for connection / data
|
||||||
|
char xfer_data;
|
||||||
|
while (ctx->socket_run) {
|
||||||
|
// Initialise structure of fds
|
||||||
|
fd_set read_fds;
|
||||||
|
FD_ZERO(&read_fds);
|
||||||
|
if (ctx->sfd) {
|
||||||
|
FD_SET(ctx->sfd, &read_fds);
|
||||||
|
}
|
||||||
|
if (ctx->cfd) {
|
||||||
|
FD_SET(ctx->cfd, &read_fds);
|
||||||
|
}
|
||||||
|
// max fd num
|
||||||
|
int mfd = (ctx->cfd > ctx->sfd) ? ctx->cfd : ctx->sfd;
|
||||||
|
|
||||||
|
// Set timeout - 50us gives good performance
|
||||||
|
timeout.tv_usec = 50;
|
||||||
|
|
||||||
|
// Wait for socket activity or timeout
|
||||||
|
rv = select(mfd + 1, &read_fds, NULL, NULL, &timeout);
|
||||||
|
|
||||||
|
if (rv < 0) {
|
||||||
|
printf("%s: Socket read failed, port: %d\n", ctx->display_name,
|
||||||
|
ctx->listen_port);
|
||||||
|
tcp_server_client_close(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// New connection
|
||||||
|
if (FD_ISSET(ctx->sfd, &read_fds)) {
|
||||||
|
client_tryaccept(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// New client data
|
||||||
|
if (FD_ISSET(ctx->cfd, &read_fds)) {
|
||||||
|
while (get_byte(ctx, &xfer_data)) {
|
||||||
|
tcp_buffer_put_byte(ctx->buf_in, xfer_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->cfd != 0) {
|
||||||
|
while (tcp_buffer_get_byte(ctx->buf_out, &xfer_data)) {
|
||||||
|
put_byte(ctx, xfer_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err_cleanup_return:
|
||||||
|
|
||||||
|
// Simulation done - clean up
|
||||||
|
tcp_server_client_close(ctx);
|
||||||
|
stop(ctx);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Abstract interface functions
|
||||||
|
tcp_server_ctx *tcp_server_create(const char *display_name, int listen_port) {
|
||||||
|
struct tcp_server_ctx *ctx =
|
||||||
|
(struct tcp_server_ctx *)calloc(1, sizeof(struct tcp_server_ctx));
|
||||||
|
assert(ctx);
|
||||||
|
|
||||||
|
// Create the buffers
|
||||||
|
struct tcp_buf *buf_in = tcp_buffer_new();
|
||||||
|
struct tcp_buf *buf_out = tcp_buffer_new();
|
||||||
|
assert(buf_in);
|
||||||
|
assert(buf_out);
|
||||||
|
|
||||||
|
// Populate the struct with buffer pointers
|
||||||
|
ctx->buf_in = buf_in;
|
||||||
|
ctx->buf_out = buf_out;
|
||||||
|
|
||||||
|
// Set up socket details
|
||||||
|
ctx->socket_run = true;
|
||||||
|
ctx->listen_port = listen_port;
|
||||||
|
ctx->display_name = strdup(display_name);
|
||||||
|
assert(ctx->display_name);
|
||||||
|
|
||||||
|
if (pthread_create(&ctx->sock_thread, NULL, server_create, (void *)ctx) !=
|
||||||
|
0) {
|
||||||
|
fprintf(stderr, "%s: Unable to create TCP socket thread\n",
|
||||||
|
ctx->display_name);
|
||||||
|
ctx_free(ctx);
|
||||||
|
free(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tcp_server_read(struct tcp_server_ctx *ctx, char *dat) {
|
||||||
|
return tcp_buffer_get_byte(ctx->buf_in, dat);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tcp_server_write(struct tcp_server_ctx *ctx, char dat) {
|
||||||
|
tcp_buffer_put_byte(ctx->buf_out, dat);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tcp_server_close(struct tcp_server_ctx *ctx) {
|
||||||
|
// Shut down the socket thread
|
||||||
|
ctx->socket_run = false;
|
||||||
|
pthread_join(ctx->sock_thread, NULL);
|
||||||
|
ctx_free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tcp_server_client_close(struct tcp_server_ctx *ctx) {
|
||||||
|
assert(ctx);
|
||||||
|
|
||||||
|
if (!ctx->cfd) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(ctx->cfd);
|
||||||
|
ctx->cfd = 0;
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
// Copyright lowRISC contributors.
|
||||||
|
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Functions to create and interact with a threaded TCP server
|
||||||
|
*
|
||||||
|
* This is intended to be used by simulation add-on DPI modules to provide
|
||||||
|
* basic TCP socket communication between a host and simulated peripherals.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TCP_SERVER_H_
|
||||||
|
#define TCP_SERVER_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct tcp_server_ctx;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Non-blocking read of a byte from a connected client
|
||||||
|
*
|
||||||
|
* @param ctx tcp server context object
|
||||||
|
* @param dat byte received
|
||||||
|
* @return true if a byte was read
|
||||||
|
*/
|
||||||
|
bool tcp_server_read(struct tcp_server_ctx *ctx, char *dat);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a byte to a connected client
|
||||||
|
*
|
||||||
|
* The write is internally buffered and so does not block if the client is not
|
||||||
|
* ready to accept data, but does block if the buffer is full.
|
||||||
|
*
|
||||||
|
* @param ctx tcp server context object
|
||||||
|
* @param dat byte to send
|
||||||
|
*/
|
||||||
|
void tcp_server_write(struct tcp_server_ctx *ctx, char dat);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new TCP server instance
|
||||||
|
*
|
||||||
|
* @param display_name C string description of server
|
||||||
|
* @param listen_port On which port the server should listen
|
||||||
|
* @return A pointer to the created context struct
|
||||||
|
*/
|
||||||
|
tcp_server_ctx *tcp_server_create(const char *display_name, int listen_port);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shut down the server and free all reserved memory
|
||||||
|
*
|
||||||
|
* @param ctx tcp server context object
|
||||||
|
*/
|
||||||
|
void tcp_server_close(struct tcp_server_ctx *ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instruct the server to disconnect a client
|
||||||
|
*
|
||||||
|
* @param ctx tcp server context object
|
||||||
|
*/
|
||||||
|
void tcp_server_client_close(struct tcp_server_ctx *ctx);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
#endif // TCP_SERVER_H_
|
|
@ -0,0 +1,9 @@
|
||||||
|
+incdir+./common+
|
||||||
|
+incdir+./jtagdpi+
|
||||||
|
|
||||||
|
-CFLAGS -lpthread
|
||||||
|
-LDFLAGS -lpthread
|
||||||
|
|
||||||
|
./common/tcp_server.c
|
||||||
|
./jtagdpi/jtagdpi.sv
|
||||||
|
./jtagdpi/jtagdpi.c
|
|
@ -0,0 +1,161 @@
|
||||||
|
// Copyright lowRISC contributors.
|
||||||
|
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
#include "jtagdpi.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "../common/tcp_server.h"
|
||||||
|
|
||||||
|
struct jtagdpi_ctx {
|
||||||
|
// Server context
|
||||||
|
struct tcp_server_ctx *sock;
|
||||||
|
// Signals
|
||||||
|
uint8_t tck;
|
||||||
|
uint8_t tms;
|
||||||
|
uint8_t tdi;
|
||||||
|
uint8_t tdo;
|
||||||
|
uint8_t trst_n;
|
||||||
|
uint8_t srst_n;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the JTAG signals to a "dongle unplugged" state
|
||||||
|
*/
|
||||||
|
static void reset_jtag_signals(struct jtagdpi_ctx *ctx) {
|
||||||
|
assert(ctx);
|
||||||
|
|
||||||
|
ctx->tck = 0;
|
||||||
|
ctx->tms = 0;
|
||||||
|
ctx->tdi = 0;
|
||||||
|
|
||||||
|
// trst_n is pulled down (reset active) by default
|
||||||
|
ctx->trst_n = 0;
|
||||||
|
|
||||||
|
// srst_n is pulled up (reset not active) by default
|
||||||
|
ctx->srst_n = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the JTAG signals in the context structure
|
||||||
|
*/
|
||||||
|
static void update_jtag_signals(struct jtagdpi_ctx *ctx) {
|
||||||
|
assert(ctx);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Documentation pointer:
|
||||||
|
* The remote_bitbang protocol implemented below is documented in the OpenOCD
|
||||||
|
* source tree at doc/manual/jtag/drivers/remote_bitbang.txt, or online at
|
||||||
|
* https://repo.or.cz/openocd.git/blob/HEAD:/doc/manual/jtag/drivers/remote_bitbang.txt
|
||||||
|
*/
|
||||||
|
|
||||||
|
// read a command byte
|
||||||
|
char cmd;
|
||||||
|
if (!tcp_server_read(ctx->sock, &cmd)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool act_send_resp = false;
|
||||||
|
bool act_quit = false;
|
||||||
|
|
||||||
|
// parse received command byte
|
||||||
|
if (cmd >= '0' && cmd <= '7') {
|
||||||
|
// JTAG write
|
||||||
|
char cmd_bit = cmd - '0';
|
||||||
|
ctx->tdi = (cmd_bit >> 0) & 0x1;
|
||||||
|
ctx->tms = (cmd_bit >> 1) & 0x1;
|
||||||
|
|
||||||
|
std::cout << "AAAAAA tdi " << (int)(ctx->tdi) << std::endl;
|
||||||
|
std::cout << "AAAAAA tms " << (int)(ctx->tms) << std::endl;
|
||||||
|
|
||||||
|
ctx->tck = (cmd_bit >> 2) & 0x1;
|
||||||
|
} else if (cmd >= 'r' && cmd <= 'u') {
|
||||||
|
// JTAG reset (active high from OpenOCD)
|
||||||
|
char cmd_bit = cmd - 'r';
|
||||||
|
ctx->srst_n = !((cmd_bit >> 0) & 0x1);
|
||||||
|
ctx->trst_n = !((cmd_bit >> 1) & 0x1);
|
||||||
|
} else if (cmd == 'R') {
|
||||||
|
// JTAG read
|
||||||
|
act_send_resp = true;
|
||||||
|
} else if (cmd == 'B') {
|
||||||
|
// printf("%s: BLINK ON!\n", ctx->display_name);
|
||||||
|
} else if (cmd == 'b') {
|
||||||
|
// printf("%s: BLINK OFF!\n", ctx->display_name);
|
||||||
|
} else if (cmd == 'Q') {
|
||||||
|
// quit (client disconnect)
|
||||||
|
act_quit = true;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr,
|
||||||
|
"JTAG DPI Protocol violation detected: unsupported command %c\n",
|
||||||
|
cmd);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// send tdo as response
|
||||||
|
if (act_send_resp) {
|
||||||
|
char tdo_ascii = ctx->tdo + '0';
|
||||||
|
std::cout << "AAAAAA tdo " << tdo_ascii << std::endl;
|
||||||
|
tcp_server_write(ctx->sock, tdo_ascii);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (act_quit) {
|
||||||
|
printf("JTAG DPI: Remote disconnected.\n");
|
||||||
|
tcp_server_client_close(ctx->sock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *jtagdpi_create(const char *display_name, int listen_port) {
|
||||||
|
struct jtagdpi_ctx *ctx =
|
||||||
|
(struct jtagdpi_ctx *)calloc(1, sizeof(struct jtagdpi_ctx));
|
||||||
|
assert(ctx);
|
||||||
|
|
||||||
|
// Create socket
|
||||||
|
ctx->sock = tcp_server_create(display_name, listen_port);
|
||||||
|
|
||||||
|
reset_jtag_signals(ctx);
|
||||||
|
|
||||||
|
printf(
|
||||||
|
"\n"
|
||||||
|
"JTAG: Virtual JTAG interface %s is listening on port %d. Use\n"
|
||||||
|
"OpenOCD and the following configuration to connect:\n"
|
||||||
|
" interface remote_bitbang\n"
|
||||||
|
" remote_bitbang_host localhost\n"
|
||||||
|
" remote_bitbang_port %d\n",
|
||||||
|
display_name, listen_port, listen_port);
|
||||||
|
|
||||||
|
return (void *)ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void jtagdpi_close(void *ctx_void) {
|
||||||
|
struct jtagdpi_ctx *ctx = (struct jtagdpi_ctx *)ctx_void;
|
||||||
|
if (!ctx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tcp_server_close(ctx->sock);
|
||||||
|
free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void jtagdpi_tick(void *ctx_void, svBit *tck, svBit *tms, svBit *tdi,
|
||||||
|
svBit *trst_n, svBit *srst_n, const svBit tdo) {
|
||||||
|
struct jtagdpi_ctx *ctx = (struct jtagdpi_ctx *)ctx_void;
|
||||||
|
|
||||||
|
ctx->tdo = tdo;
|
||||||
|
|
||||||
|
// TODO: Evaluate moving this functionality into a separate thread
|
||||||
|
if (ctx) {
|
||||||
|
update_jtag_signals(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
*tdi = ctx->tdi;
|
||||||
|
*tms = ctx->tms;
|
||||||
|
*tck = ctx->tck;
|
||||||
|
*srst_n = ctx->srst_n;
|
||||||
|
*trst_n = ctx->trst_n;
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
// Copyright lowRISC contributors.
|
||||||
|
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
#ifndef JTAGDPI_H_
|
||||||
|
#define JTAGDPI_H_
|
||||||
|
|
||||||
|
#include <svdpi.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct jtagdpi_ctx;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor: Create and initialize jtagdpi context object
|
||||||
|
*
|
||||||
|
* Call from a initial block.
|
||||||
|
*
|
||||||
|
* @param display_name Name of the JTAG interface (for display purposes only)
|
||||||
|
* @param listen_port Port to listen on
|
||||||
|
* @return an initialized struct jtagdpi_ctx context object
|
||||||
|
*/
|
||||||
|
void *jtagdpi_create(const char *display_name, int listen_port);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destructor: Close all connections and free all resources
|
||||||
|
*
|
||||||
|
* Call from a finish block.
|
||||||
|
*
|
||||||
|
* @param ctx_void a struct jtagdpi_ctx context object
|
||||||
|
*/
|
||||||
|
void jtagdpi_close(void *ctx_void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drive JTAG signals
|
||||||
|
*
|
||||||
|
* Call this function from the simulation at every clock tick to read/write
|
||||||
|
* from/to the JTAG signals.
|
||||||
|
*
|
||||||
|
* @param ctx_void a struct jtagdpi_ctx context object
|
||||||
|
* @param tck JTAG test clock signal
|
||||||
|
* @param tms JTAG test mode select signal
|
||||||
|
* @param tdi JTAG test data input signal
|
||||||
|
* @param trst_n JTAG test reset signal (active low)
|
||||||
|
* @param srst_n JTAG system reset signal (active low)
|
||||||
|
* @param tdo JTAG test data out
|
||||||
|
*/
|
||||||
|
void jtagdpi_tick(void *ctx_void, svBit *tck, svBit *tms, svBit *tdi,
|
||||||
|
svBit *trst_n, svBit *srst_n, const svBit tdo);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
#endif // JTAGDPI_H_
|
|
@ -0,0 +1,53 @@
|
||||||
|
// Copyright lowRISC contributors.
|
||||||
|
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
module jtagdpi #(
|
||||||
|
parameter string Name = "jtag0", // name of the JTAG interface (display only)
|
||||||
|
parameter int ListenPort = 44853 // TCP port to listen on
|
||||||
|
) (
|
||||||
|
input logic clk_i,
|
||||||
|
input logic rst_ni,
|
||||||
|
|
||||||
|
output logic jtag_tck,
|
||||||
|
output logic jtag_tms,
|
||||||
|
output logic jtag_tdi,
|
||||||
|
input logic jtag_tdo,
|
||||||
|
output logic jtag_trst_n,
|
||||||
|
output logic jtag_srst_n
|
||||||
|
);
|
||||||
|
|
||||||
|
import "DPI-C" function chandle jtagdpi_create(
|
||||||
|
input string name,
|
||||||
|
input int listen_port
|
||||||
|
);
|
||||||
|
|
||||||
|
import "DPI-C" function void jtagdpi_tick(
|
||||||
|
input chandle ctx,
|
||||||
|
output bit tck,
|
||||||
|
output bit tms,
|
||||||
|
output bit tdi,
|
||||||
|
output bit trst_n,
|
||||||
|
output bit srst_n,
|
||||||
|
input bit tdo
|
||||||
|
);
|
||||||
|
|
||||||
|
import "DPI-C" function void jtagdpi_close(input chandle ctx);
|
||||||
|
|
||||||
|
chandle ctx;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
ctx = jtagdpi_create(Name, ListenPort);
|
||||||
|
end
|
||||||
|
|
||||||
|
final begin
|
||||||
|
jtagdpi_close(ctx);
|
||||||
|
ctx = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
always_ff @(posedge clk_i, negedge rst_ni) begin
|
||||||
|
jtagdpi_tick(ctx, jtag_tck, jtag_tms, jtag_tdi, jtag_trst_n, jtag_srst_n,
|
||||||
|
jtag_tdo);
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,2 @@
|
||||||
|
target remote :3333
|
||||||
|
set remotetimeout 2000
|
|
@ -0,0 +1,16 @@
|
||||||
|
|
||||||
|
OUTPUT_ARCH( "riscv" )
|
||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0;
|
||||||
|
.text_init : { *(.text_init*) }
|
||||||
|
.text : { *(.text*) }
|
||||||
|
_end = .;
|
||||||
|
. = 0x4000;
|
||||||
|
.data : ALIGN(0x800) { *(.*data) *(.rodata*) STACK = ALIGN(16) + 0x2000; }
|
||||||
|
.bss : { *(.bss) }
|
||||||
|
. = 0xd0580000;
|
||||||
|
.data.io : { *(.data.io) }
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
# "JTAG adapter" for simulation, exposed to OpenOCD through a TCP socket
|
||||||
|
# speaking the remote_bitbang protocol. The adapter is implemented as
|
||||||
|
# SystemVerilog DPI module.
|
||||||
|
|
||||||
|
adapter driver remote_bitbang
|
||||||
|
remote_bitbang host localhost
|
||||||
|
remote_bitbang port 44853
|
||||||
|
|
||||||
|
# Target configuration for the riscv chip
|
||||||
|
|
||||||
|
set _CHIPNAME riscv
|
||||||
|
set _TARGETNAME $_CHIPNAME.cpu
|
||||||
|
|
||||||
|
jtag newtap $_CHIPNAME tap -irlen 5 -expected-id 01
|
||||||
|
set _TARGETNAME $_CHIPNAME.tap
|
||||||
|
target create $_TARGETNAME riscv -chain-position $_TARGETNAME
|
||||||
|
|
||||||
|
# Configure work area in on-chip SRAM
|
||||||
|
# $_TARGETNAME configure -work-area-phys 0x1000e000 -work-area-size 1000 -work-area-backup 0
|
||||||
|
|
||||||
|
riscv expose_csrs 1988
|
||||||
|
|
||||||
|
# Be verbose about GDB errors
|
||||||
|
gdb_report_data_abort enable
|
||||||
|
gdb_report_register_access_error enable
|
||||||
|
|
||||||
|
# Increase timeouts in simulation
|
||||||
|
riscv set_command_timeout_sec 1200
|
||||||
|
|
||||||
|
# Conclude OpenOCD configuration
|
||||||
|
init
|
||||||
|
|
||||||
|
# Halt the target
|
||||||
|
halt
|
|
@ -0,0 +1,11 @@
|
||||||
|
.global main
|
||||||
|
|
||||||
|
main:
|
||||||
|
|
||||||
|
# csrsi mstatus, 0x8
|
||||||
|
# csrci mhcr, 0x1
|
||||||
|
# csrci mhcr, 0x2
|
||||||
|
|
||||||
|
loop:
|
||||||
|
j loop
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// Copyright 2020 Western Digital Corporation or its affiliates.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
module soc_sim (
|
||||||
|
input bit clk,
|
||||||
|
output jtag_tdo,
|
||||||
|
output jtag_tck,
|
||||||
|
output jtag_tms,
|
||||||
|
output jtag_tdi
|
||||||
|
);
|
||||||
|
|
||||||
|
wire rst;
|
||||||
|
|
||||||
|
bit [31:0] cycleCnt;
|
||||||
|
|
||||||
|
reg uart_tx;
|
||||||
|
wire uart_rx;
|
||||||
|
wire [ 7:0] gpioa;
|
||||||
|
|
||||||
|
reg jrst_b;
|
||||||
|
reg nrst_b;
|
||||||
|
|
||||||
|
wire [ 7:0] WriteData;
|
||||||
|
|
||||||
|
parameter MAX_CYCLES = 10_000_000_0;
|
||||||
|
|
||||||
|
integer fd;
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
cycleCnt <= cycleCnt + 1;
|
||||||
|
if (cycleCnt == MAX_CYCLES) begin
|
||||||
|
$display("Hit max cycle count (%0d) .. stopping", cycleCnt);
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
if (WriteData[7:0] == 8'hff) begin
|
||||||
|
$display("\nFinished by program");
|
||||||
|
$display("TEST_PASSED");
|
||||||
|
$finish;
|
||||||
|
end else if (WriteData[7:0] == 8'h1) begin
|
||||||
|
$display("TEST_FAILED");
|
||||||
|
$finish;
|
||||||
|
end else begin
|
||||||
|
$fwrite(fd, "%c", WriteData[7:0]);
|
||||||
|
$write("%c", WriteData[7:0]);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
fd = $fopen("console.log", "w");
|
||||||
|
end
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
jrst_b = 1;
|
||||||
|
#100;
|
||||||
|
jrst_b = 0;
|
||||||
|
#100;
|
||||||
|
jrst_b = 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
nrst_b = 1;
|
||||||
|
#100;
|
||||||
|
nrst_b = 0;
|
||||||
|
#100;
|
||||||
|
nrst_b = 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
assign rst = cycleCnt > 5;
|
||||||
|
|
||||||
|
soc rvsoc (
|
||||||
|
.i_pad_clk (clk),
|
||||||
|
.i_pad_rst_b(rst),
|
||||||
|
|
||||||
|
.o_pad_jtg_tdo(jtag_tdo),
|
||||||
|
.i_pad_jtg_tclk(jtag_tck),
|
||||||
|
.i_pad_jtg_tms(jtag_tms),
|
||||||
|
.i_pad_jtg_tdi(jtag_tdi),
|
||||||
|
.i_pad_jtg_trst_b(jrst_b),
|
||||||
|
.i_pad_jtg_nrst_b(nrst_b),
|
||||||
|
.i_pad_uart0_sin(uart_tx),
|
||||||
|
.o_pad_uart0_sout(uart_rx),
|
||||||
|
.b_pad_gpio_porta(gpioa)
|
||||||
|
);
|
||||||
|
|
||||||
|
jtagdpi jtagdpi (
|
||||||
|
.clk_i (clk),
|
||||||
|
.rst_ni(rst),
|
||||||
|
|
||||||
|
.jtag_tck(jtag_tck),
|
||||||
|
.jtag_tms(jtag_tms),
|
||||||
|
.jtag_tdi(jtag_tdi),
|
||||||
|
.jtag_tdo(jtag_tdo),
|
||||||
|
.jtag_trst_n(),
|
||||||
|
.jtag_srst_n()
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
|
@ -0,0 +1,59 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// Copyright 2019 Western Digital Corporation or its affiliates.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "Vsoc_sim.h"
|
||||||
|
#include "verilated.h"
|
||||||
|
#include "verilated_vcd_c.h"
|
||||||
|
|
||||||
|
vluint64_t main_time = 0;
|
||||||
|
|
||||||
|
double sc_time_stamp() { return main_time; }
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
std::cout << "\nVerilatorTB: Start of sim\n" << std::endl;
|
||||||
|
|
||||||
|
Vsoc_sim* soc = new Vsoc_sim;
|
||||||
|
|
||||||
|
Verilated::commandArgs(argc, argv);
|
||||||
|
// Verilated::mkdir("logs");
|
||||||
|
Verilated::traceEverOn(true);
|
||||||
|
VerilatedVcdC* tfp = new VerilatedVcdC;
|
||||||
|
soc->trace(tfp, 99);
|
||||||
|
tfp->open("vlt_dump.vcd");
|
||||||
|
|
||||||
|
while (!Verilated::gotFinish()) {
|
||||||
|
main_time += 5;
|
||||||
|
soc->clk = !soc->clk;
|
||||||
|
soc->eval();
|
||||||
|
|
||||||
|
tfp->dump(main_time);
|
||||||
|
// tfp->dump(soc->jtag_tdo,"tdo");
|
||||||
|
// tfp->dump(soc->jtag_tdi,"tdi");
|
||||||
|
// tfp->dump(soc->jtag_tms,"tms");
|
||||||
|
// tfp->dump(soc->jtag_tck,"tck");
|
||||||
|
}
|
||||||
|
|
||||||
|
tfp->close();
|
||||||
|
// soc->final();
|
||||||
|
|
||||||
|
std::cout << "\nVerilatorTB: End of sim" << std::endl;
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
|
||||||
|
-f ${CODE_BASE_PATH}/gen_rtl/filelists/E906_asic_rtl.fl
|
||||||
|
-f ${CODE_BASE_PATH}/gen_rtl/filelists/tdt_dmi_top_rtl.fl
|
||||||
|
|
||||||
|
+incdir+../../logical/system+
|
||||||
|
+incdir+../../logical/mem+
|
||||||
|
|
||||||
|
-y ../../logical/system
|
||||||
|
-y ../../logical/mem
|
||||||
|
-y ../../logical/ahb
|
||||||
|
-y ../../logical/apb
|
||||||
|
-y ../../logical/uart
|
||||||
|
-y ../../logical/gpio
|
||||||
|
-y ../../logical/timer
|
||||||
|
-y ../../logical/pmu
|
||||||
|
-y ../../logical/smpu
|
||||||
|
-y ../../logical/wic
|
||||||
|
|
||||||
|
../../logical/system/soc.v
|
Loading…
Reference in New Issue