Enable VexRiscv murax jtag simulator by verilator.
This commit is contained in:
parent
e3968e6fa7
commit
25a557365b
|
@ -0,0 +1 @@
|
||||||
|
.vscode
|
10
Readme.md
10
Readme.md
|
@ -1,7 +1,11 @@
|
||||||
# Weekend group
|
# Weekend group
|
||||||
|
|
||||||
我们不卷,只是爱好。
|
### 不要小看自己
|
||||||
|
|
||||||
自由的参与方式
|
### 我们不卷,只是爱好
|
||||||
|
|
||||||
## 分歧决议
|
### 自由的参与方式
|
||||||
|
|
||||||
|
### 自由发挥,无限创作空间
|
||||||
|
|
||||||
|
### 理性的分歧决议方法
|
|
@ -13,7 +13,7 @@ make -j
|
||||||
sudo make install
|
sudo make install
|
||||||
```
|
```
|
||||||
|
|
||||||
## install sbt
|
## install sbt to gen the VexRiscv core
|
||||||
|
|
||||||
```
|
```
|
||||||
# JAVA JDK 8
|
# JAVA JDK 8
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
+incdir+./+
|
|
@ -0,0 +1,284 @@
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <string.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <vector>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "verilated_fst_c.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
class SimElement{
|
||||||
|
public:
|
||||||
|
virtual ~SimElement(){}
|
||||||
|
virtual void onReset(){}
|
||||||
|
virtual void postReset(){}
|
||||||
|
virtual void preCycle(){}
|
||||||
|
virtual void postCycle(){}
|
||||||
|
};
|
||||||
|
|
||||||
|
//#include <functional>
|
||||||
|
class TimeProcess{
|
||||||
|
public:
|
||||||
|
uint64_t wakeDelay = 0;
|
||||||
|
bool wakeEnable = false;
|
||||||
|
// std::function<int(double)> lambda;
|
||||||
|
virtual ~TimeProcess(){}
|
||||||
|
virtual void schedule(uint64_t delay){
|
||||||
|
wakeDelay = delay;
|
||||||
|
wakeEnable = true;
|
||||||
|
}
|
||||||
|
virtual void tick(){
|
||||||
|
// lambda = [this](double x) { return x+1 + this->wakeDelay; };
|
||||||
|
// lambda(1.0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class SensitiveProcess{
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual ~SensitiveProcess(){}
|
||||||
|
virtual void tick(uint64_t time){
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ClockDomain : public TimeProcess{
|
||||||
|
public:
|
||||||
|
CData* clk;
|
||||||
|
CData* reset;
|
||||||
|
uint64_t tooglePeriod;
|
||||||
|
vector<SimElement*> simElements;
|
||||||
|
ClockDomain(CData *clk, CData *reset, uint64_t period, uint64_t delay){
|
||||||
|
this->clk = clk;
|
||||||
|
this->reset = reset;
|
||||||
|
*clk = 0;
|
||||||
|
this->tooglePeriod = period/2;
|
||||||
|
schedule(delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool postCycle = false;
|
||||||
|
virtual void tick(){
|
||||||
|
if(*clk == 0){
|
||||||
|
for(SimElement* simElement : simElements){
|
||||||
|
simElement->preCycle();
|
||||||
|
}
|
||||||
|
postCycle = true;
|
||||||
|
*clk = 1;
|
||||||
|
schedule(0);
|
||||||
|
}else{
|
||||||
|
if(postCycle){
|
||||||
|
postCycle = false;
|
||||||
|
for(SimElement* simElement : simElements){
|
||||||
|
simElement->postCycle();
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
*clk = 0;
|
||||||
|
}
|
||||||
|
schedule(tooglePeriod);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(SimElement *that){
|
||||||
|
simElements.push_back(that);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class AsyncReset : public TimeProcess{
|
||||||
|
public:
|
||||||
|
CData* reset;
|
||||||
|
uint32_t state;
|
||||||
|
uint64_t duration;
|
||||||
|
AsyncReset(CData *reset, uint64_t duration){
|
||||||
|
this->reset = reset;
|
||||||
|
*reset = 0;
|
||||||
|
state = 0;
|
||||||
|
this->duration = duration;
|
||||||
|
schedule(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void tick(){
|
||||||
|
switch(state){
|
||||||
|
case 0:
|
||||||
|
*reset = 1;
|
||||||
|
state = 1;
|
||||||
|
schedule(duration);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
*reset = 0;
|
||||||
|
state = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class success : public std::exception { };
|
||||||
|
static uint32_t workspaceCycles = 0;
|
||||||
|
template <class T> class Workspace{
|
||||||
|
public:
|
||||||
|
|
||||||
|
vector<TimeProcess*> timeProcesses;
|
||||||
|
vector<SensitiveProcess*> checkProcesses;
|
||||||
|
T* top;
|
||||||
|
bool resetDone = false;
|
||||||
|
double timeToSec = 1e-12;
|
||||||
|
double speedFactor = 1.0;
|
||||||
|
uint64_t allowedTime = 0;
|
||||||
|
string name;
|
||||||
|
uint64_t time = 0;
|
||||||
|
#ifdef TRACE
|
||||||
|
VerilatedFstC* tfp;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ofstream logTraces;
|
||||||
|
|
||||||
|
Workspace(string name){
|
||||||
|
this->name = name;
|
||||||
|
top = new T;
|
||||||
|
logTraces.open (name + ".logTrace");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~Workspace(){
|
||||||
|
delete top;
|
||||||
|
#ifdef TRACE
|
||||||
|
delete tfp;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for(auto* p : timeProcesses) delete p;
|
||||||
|
for(auto* p : checkProcesses) delete p;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Workspace* setSpeedFactor(double value){
|
||||||
|
speedFactor = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
virtual void postReset() {}
|
||||||
|
virtual void checks(){}
|
||||||
|
virtual void pass(){ throw success();}
|
||||||
|
virtual void fail(){ throw std::exception();}
|
||||||
|
|
||||||
|
virtual void dump(uint64_t i){
|
||||||
|
#ifdef TRACE
|
||||||
|
if(i >= TRACE_START) tfp->dump(i);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
Workspace* run(uint32_t timeout = 5000){
|
||||||
|
|
||||||
|
// init trace dump
|
||||||
|
#ifdef TRACE
|
||||||
|
Verilated::traceEverOn(true);
|
||||||
|
tfp = new VerilatedFstC;
|
||||||
|
top->trace(tfp, 99);
|
||||||
|
tfp->open((string(name)+ ".fst").c_str());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct timespec start_time,tick_time;
|
||||||
|
uint64_t tickLastSimTime = 0;
|
||||||
|
top->eval();
|
||||||
|
|
||||||
|
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_time);
|
||||||
|
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tick_time);
|
||||||
|
|
||||||
|
uint32_t flushCounter = 0;
|
||||||
|
try {
|
||||||
|
while(1){
|
||||||
|
uint64_t delay = ~0l;
|
||||||
|
for(TimeProcess* p : timeProcesses)
|
||||||
|
if(p->wakeEnable && p->wakeDelay < delay)
|
||||||
|
delay = p->wakeDelay;
|
||||||
|
|
||||||
|
if(delay == ~0l){
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
if(delay != 0){
|
||||||
|
dump(time);
|
||||||
|
}
|
||||||
|
for(TimeProcess* p : timeProcesses) {
|
||||||
|
p->wakeDelay -= delay;
|
||||||
|
if(p->wakeDelay == 0){
|
||||||
|
p->wakeEnable = false;
|
||||||
|
p->tick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
top->eval();
|
||||||
|
for(auto* p : checkProcesses) p->tick(time);
|
||||||
|
|
||||||
|
if(delay != 0){
|
||||||
|
if(time - tickLastSimTime > 1000*400000 || time - tickLastSimTime > 1.0*speedFactor/timeToSec){
|
||||||
|
struct timespec end_time;
|
||||||
|
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_time);
|
||||||
|
uint64_t diffInNanos = end_time.tv_sec*1e9 + end_time.tv_nsec - tick_time.tv_sec*1e9 - tick_time.tv_nsec;
|
||||||
|
tick_time = end_time;
|
||||||
|
double dt = diffInNanos*1e-9;
|
||||||
|
#ifdef PRINT_PERF
|
||||||
|
printf("Simulation speed : %f ms/realTime\n",(time - tickLastSimTime)/dt*timeToSec*1e3);
|
||||||
|
#endif
|
||||||
|
tickLastSimTime = time;
|
||||||
|
}
|
||||||
|
time += delay;
|
||||||
|
while(allowedTime < delay){
|
||||||
|
struct timespec end_time;
|
||||||
|
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_time);
|
||||||
|
uint64_t diffInNanos = end_time.tv_sec*1e9 + end_time.tv_nsec - start_time.tv_sec*1e9 - start_time.tv_nsec;
|
||||||
|
start_time = end_time;
|
||||||
|
double dt = diffInNanos*1e-9;
|
||||||
|
allowedTime += dt*speedFactor/timeToSec;
|
||||||
|
if(allowedTime > 0.01*speedFactor/timeToSec)
|
||||||
|
allowedTime = 0.01*speedFactor/timeToSec;
|
||||||
|
|
||||||
|
}
|
||||||
|
allowedTime-=delay;
|
||||||
|
|
||||||
|
flushCounter++;
|
||||||
|
if(flushCounter > 100000){
|
||||||
|
#ifdef TRACE
|
||||||
|
tfp->flush();
|
||||||
|
//printf("flush\n");
|
||||||
|
#endif
|
||||||
|
flushCounter = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (Verilated::gotFinish())
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
cout << "timeout" << endl;
|
||||||
|
fail();
|
||||||
|
} catch (const success e) {
|
||||||
|
cout <<"SUCCESS " << name << endl;
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
cout << "FAIL " << name << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
dump(time);
|
||||||
|
dump(time+10);
|
||||||
|
#ifdef TRACE
|
||||||
|
tfp->close();
|
||||||
|
#endif
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,177 @@
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
|
||||||
|
/** Returns true on success, or false if there was an error */
|
||||||
|
bool SetSocketBlockingEnabled(int fd, bool blocking)
|
||||||
|
{
|
||||||
|
if (fd < 0) return false;
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
unsigned long mode = blocking ? 0 : 1;
|
||||||
|
return (ioctlsocket(fd, FIONBIO, &mode) == 0) ? true : false;
|
||||||
|
#else
|
||||||
|
int flags = fcntl(fd, F_GETFL, 0);
|
||||||
|
if (flags < 0) return false;
|
||||||
|
flags = blocking ? (flags&~O_NONBLOCK) : (flags|O_NONBLOCK);
|
||||||
|
return (fcntl(fd, F_SETFL, flags) == 0) ? true : false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
class Jtag : public TimeProcess{
|
||||||
|
public:
|
||||||
|
CData *tms, *tdi, *tdo, *tck;
|
||||||
|
enum State {reset};
|
||||||
|
uint32_t state;
|
||||||
|
|
||||||
|
int serverSocket, clientHandle;
|
||||||
|
struct sockaddr_in serverAddr;
|
||||||
|
struct sockaddr_storage serverStorage;
|
||||||
|
socklen_t addr_size;
|
||||||
|
uint64_t tooglePeriod;
|
||||||
|
// char buffer[1024];
|
||||||
|
|
||||||
|
Jtag(CData *tms, CData *tdi, CData *tdo, CData* tck,uint64_t period){
|
||||||
|
this->tms = tms;
|
||||||
|
this->tdi = tdi;
|
||||||
|
this->tdo = tdo;
|
||||||
|
this->tck = tck;
|
||||||
|
this->tooglePeriod = period/2;
|
||||||
|
*tms = 0;
|
||||||
|
*tdi = 0;
|
||||||
|
*tdo = 0;
|
||||||
|
*tck = 0;
|
||||||
|
state = 0;
|
||||||
|
schedule(0);
|
||||||
|
|
||||||
|
//---- Create the socket. The three arguments are: ----//
|
||||||
|
// 1) Internet domain 2) Stream socket 3) Default protocol (TCP in this case) //
|
||||||
|
serverSocket = socket(PF_INET, SOCK_STREAM, 0);
|
||||||
|
assert(serverSocket != -1);
|
||||||
|
int flag = 1;
|
||||||
|
setsockopt( serverSocket, /* socket affected */
|
||||||
|
IPPROTO_TCP, /* set option at TCP level */
|
||||||
|
TCP_NODELAY, /* name of option */
|
||||||
|
(char *) &flag, /* the cast is historical
|
||||||
|
cruft */
|
||||||
|
sizeof(int)); /* length of option value */
|
||||||
|
|
||||||
|
/*int a = 0xFFF;
|
||||||
|
if (setsockopt(serverSocket, SOL_SOCKET, SO_RCVBUF, &a, sizeof(int)) == -1) {
|
||||||
|
fprintf(stderr, "Error setting socket opts: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
a = 0xFFFFFF;
|
||||||
|
if (setsockopt(serverSocket, SOL_SOCKET, SO_SNDBUF, &a, sizeof(int)) == -1) {
|
||||||
|
fprintf(stderr, "Error setting socket opts: %s\n", strerror(errno));
|
||||||
|
}*/
|
||||||
|
|
||||||
|
SetSocketBlockingEnabled(serverSocket,0);
|
||||||
|
|
||||||
|
|
||||||
|
//---- Configure settings of the server address struct ----//
|
||||||
|
// Address family = Internet //
|
||||||
|
serverAddr.sin_family = AF_INET;
|
||||||
|
serverAddr.sin_port = htons(7894);
|
||||||
|
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||||
|
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
|
||||||
|
|
||||||
|
//---- Bind the address struct to the socket ----//
|
||||||
|
bind(serverSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr));
|
||||||
|
|
||||||
|
//---- Listen on the socket, with 5 max connection requests queued ----//
|
||||||
|
listen(serverSocket,1);
|
||||||
|
|
||||||
|
//---- Accept call creates a new socket for the incoming connection ----//
|
||||||
|
addr_size = sizeof serverStorage;
|
||||||
|
clientHandle = -1;
|
||||||
|
|
||||||
|
}
|
||||||
|
void connectionReset(){
|
||||||
|
printf("CONNECTION RESET\n");
|
||||||
|
shutdown(clientHandle,SHUT_RDWR);
|
||||||
|
clientHandle = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
virtual ~Jtag(){
|
||||||
|
if(clientHandle != -1) {
|
||||||
|
shutdown(clientHandle,SHUT_RDWR);
|
||||||
|
usleep(100);
|
||||||
|
}
|
||||||
|
if(serverSocket != -1) {
|
||||||
|
close(serverSocket);
|
||||||
|
usleep(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t selfSleep = 0;
|
||||||
|
uint32_t checkNewConnectionsTimer = 0;
|
||||||
|
uint8_t rxBuffer[100];
|
||||||
|
int32_t rxBufferSize = 0;
|
||||||
|
int32_t rxBufferRemaining = 0;
|
||||||
|
virtual void tick(){
|
||||||
|
checkNewConnectionsTimer++;
|
||||||
|
if(checkNewConnectionsTimer == 5000){
|
||||||
|
checkNewConnectionsTimer = 0;
|
||||||
|
int newclientHandle = accept(serverSocket, (struct sockaddr *) &serverStorage, &addr_size);
|
||||||
|
if(newclientHandle != -1){
|
||||||
|
if(clientHandle != -1){
|
||||||
|
connectionReset();
|
||||||
|
}
|
||||||
|
clientHandle = newclientHandle;
|
||||||
|
printf("CONNECTED\n");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(clientHandle == -1)
|
||||||
|
selfSleep = 1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(selfSleep)
|
||||||
|
selfSleep--;
|
||||||
|
else{
|
||||||
|
if(clientHandle != -1){
|
||||||
|
uint8_t buffer;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if(rxBufferRemaining == 0){
|
||||||
|
if(ioctl(clientHandle,FIONREAD,&n) != 0)
|
||||||
|
connectionReset();
|
||||||
|
else if(n >= 1){
|
||||||
|
rxBufferSize = read(clientHandle,&rxBuffer,100);
|
||||||
|
if(rxBufferSize < 0){
|
||||||
|
connectionReset();
|
||||||
|
}else {
|
||||||
|
rxBufferRemaining = rxBufferSize;
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
selfSleep = 30;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rxBufferRemaining != 0){
|
||||||
|
uint8_t buffer = rxBuffer[rxBufferSize - (rxBufferRemaining--)];
|
||||||
|
*tms = (buffer & 1) != 0;
|
||||||
|
*tdi = (buffer & 2) != 0;
|
||||||
|
*tck = (buffer & 8) != 0;
|
||||||
|
if(buffer & 4){
|
||||||
|
buffer = (*tdo != 0);
|
||||||
|
//printf("TDO=%d\n",buffer);
|
||||||
|
if(-1 == send(clientHandle,&buffer,1,0))
|
||||||
|
connectionReset();
|
||||||
|
}else {
|
||||||
|
|
||||||
|
// printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
schedule(tooglePeriod);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
|
@ -0,0 +1,126 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class UartRx : public TimeProcess{
|
||||||
|
public:
|
||||||
|
|
||||||
|
CData *rx;
|
||||||
|
uint32_t uartTimeRate;
|
||||||
|
UartRx(CData *rx, uint32_t uartTimeRate){
|
||||||
|
this->rx = rx;
|
||||||
|
this->uartTimeRate = uartTimeRate;
|
||||||
|
schedule(uartTimeRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum State {START, DATA, STOP};
|
||||||
|
State state = START;
|
||||||
|
char data;
|
||||||
|
uint32_t counter;
|
||||||
|
|
||||||
|
|
||||||
|
virtual void tick(){
|
||||||
|
switch(state){
|
||||||
|
case START:
|
||||||
|
if(*rx == 0){
|
||||||
|
state = DATA;
|
||||||
|
counter = 0;
|
||||||
|
data = 0;
|
||||||
|
schedule(uartTimeRate*5/4);
|
||||||
|
} else {
|
||||||
|
schedule(uartTimeRate/4);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DATA:
|
||||||
|
data |= (*rx) << counter++;
|
||||||
|
if(counter == 8){
|
||||||
|
state = STOP;
|
||||||
|
}
|
||||||
|
schedule(uartTimeRate);
|
||||||
|
break;
|
||||||
|
case STOP:
|
||||||
|
if(*rx){
|
||||||
|
cout << data << flush;
|
||||||
|
} else {
|
||||||
|
cout << "UART RX FRAME ERROR at " << time << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
schedule(uartTimeRate/4);
|
||||||
|
state = START;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#include<pthread.h>
|
||||||
|
#include <mutex>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
class UartTx : public TimeProcess{
|
||||||
|
public:
|
||||||
|
|
||||||
|
CData *tx;
|
||||||
|
uint32_t uartTimeRate;
|
||||||
|
|
||||||
|
enum State {START, DATA, STOP};
|
||||||
|
State state = START;
|
||||||
|
char data;
|
||||||
|
uint32_t counter;
|
||||||
|
pthread_t inputThreadId;
|
||||||
|
queue<uint8_t> inputsQueue;
|
||||||
|
mutex inputsMutex;
|
||||||
|
|
||||||
|
UartTx(CData *tx, uint32_t uartTimeRate){
|
||||||
|
this->tx = tx;
|
||||||
|
this->uartTimeRate = uartTimeRate;
|
||||||
|
schedule(uartTimeRate);
|
||||||
|
pthread_create(&inputThreadId, NULL, &inputThreadWrapper, this);
|
||||||
|
*tx = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* inputThreadWrapper(void *uartTx){
|
||||||
|
((UartTx*)uartTx)->inputThread();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void inputThread(){
|
||||||
|
while(1){
|
||||||
|
uint8_t c = getchar();
|
||||||
|
inputsMutex.lock();
|
||||||
|
inputsQueue.push(c);
|
||||||
|
inputsMutex.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void tick(){
|
||||||
|
switch(state){
|
||||||
|
case START:
|
||||||
|
inputsMutex.lock();
|
||||||
|
if(!inputsQueue.empty()){
|
||||||
|
data = inputsQueue.front();
|
||||||
|
inputsQueue.pop();
|
||||||
|
inputsMutex.unlock();
|
||||||
|
state = DATA;
|
||||||
|
counter = 0;
|
||||||
|
*tx = 0;
|
||||||
|
schedule(uartTimeRate);
|
||||||
|
} else {
|
||||||
|
inputsMutex.unlock();
|
||||||
|
schedule(uartTimeRate*50);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DATA:
|
||||||
|
*tx = (data >> counter) & 1;
|
||||||
|
counter++;
|
||||||
|
if(counter == 8){
|
||||||
|
state = STOP;
|
||||||
|
}
|
||||||
|
schedule(uartTimeRate);
|
||||||
|
break;
|
||||||
|
case STOP:
|
||||||
|
*tx = 1;
|
||||||
|
schedule(uartTimeRate);
|
||||||
|
state = START;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,11 +1,11 @@
|
||||||
export CODE_BASE_PATH = ${PWD}/../../E906_RTL_FACTORY
|
export CODE_BASE_PATH = ${PWD}/../../E906_RTL_FACTORY
|
||||||
GDB_PREFIX = /opt/riscv/bin/riscv32-unknown-elf-gdb
|
GDB_PREFIX = /opt/riscv/bin/riscv64-unknown-elf-gdb
|
||||||
|
|
||||||
FILELIST = -F ./dpi/jtag.fl ../Murax.v
|
FILELIST = -F ../common/common.fl ../Murax.v
|
||||||
|
|
||||||
DEMODIR = ${PWD}
|
DEMODIR = ${PWD}
|
||||||
|
|
||||||
TEST = sim
|
TEST = Murax
|
||||||
|
|
||||||
# CFLAGS for verilator generated Makefiles. Without -std=c++11 it complains for `auto` variables
|
# CFLAGS for verilator generated Makefiles. Without -std=c++11 it complains for `auto` variables
|
||||||
CFLAGS += "-std=c++11"
|
CFLAGS += "-std=c++11"
|
||||||
|
@ -32,23 +32,19 @@ verilator-build:
|
||||||
-Wno-WIDTH \
|
-Wno-WIDTH \
|
||||||
-Wno-IMPLICIT \
|
-Wno-IMPLICIT \
|
||||||
${FILELIST} \
|
${FILELIST} \
|
||||||
soc_sim.v \
|
|
||||||
--trace \
|
--trace \
|
||||||
--top-module soc_sim -exe test_soc_sim.cpp --autoflush
|
--top-module Murax -exe main.cpp --autoflush
|
||||||
cp ${DEMODIR}/test_soc_sim.cpp obj_dir
|
$(MAKE) -j -C obj_dir/ -f VMurax.mk $(VERILATOR_MAKE_FLAGS)
|
||||||
$(MAKE) -j -C obj_dir/ -f Vsoc_sim.mk $(VERILATOR_MAKE_FLAGS)
|
|
||||||
|
|
||||||
##################### Simulation Runs #####################################
|
##################### Simulation Runs #####################################
|
||||||
|
|
||||||
verilator: verilator-build
|
verilator: verilator-build
|
||||||
./obj_dir/Vsoc_sim
|
./obj_dir/VMurax
|
||||||
|
|
||||||
##################### openocd #####################################
|
##################### openocd #####################################
|
||||||
|
|
||||||
openocd:
|
openocd:
|
||||||
openocd -c "set MURAX_CPU0_YAML cpu0.yaml" -f murax.cfg
|
openocd -f jtag_tcp.cfg -c "set MURAX_CPU0_YAML cpu0.yaml" -f murax.cfg
|
||||||
# openocd -f riscv.cfg
|
|
||||||
# openocd -f riscv.cfg -d3
|
|
||||||
|
|
||||||
gdb:
|
gdb:
|
||||||
$(GDB_PREFIX) -x gdbinit ./hello_world.elf
|
$(GDB_PREFIX) -x gdbinit ./hello_world.elf
|
||||||
|
|
|
@ -1,18 +1,7 @@
|
||||||
# jtag simulation
|
# 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
|
## quick start
|
||||||
|
|
||||||
At demo/jtag/
|
|
||||||
|
|
||||||
1. `make all`
|
1. `make all`
|
||||||
2. `make openocd`
|
2. `make openocd`
|
||||||
3. `make gdb`
|
3. `make gdb`
|
Binary file not shown.
|
@ -1,437 +0,0 @@
|
||||||
// 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;
|
|
||||||
}
|
|
|
@ -1,69 +0,0 @@
|
||||||
// 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_
|
|
|
@ -1,9 +0,0 @@
|
||||||
+incdir+./common+
|
|
||||||
+incdir+./jtagdpi+
|
|
||||||
|
|
||||||
-CFLAGS -lpthread
|
|
||||||
-LDFLAGS -lpthread
|
|
||||||
|
|
||||||
./common/tcp_server.c
|
|
||||||
./jtagdpi/jtagdpi.sv
|
|
||||||
./jtagdpi/jtagdpi.c
|
|
|
@ -1,164 +0,0 @@
|
||||||
// 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;
|
|
||||||
|
|
||||||
// // Use for debug jtag signal
|
|
||||||
// if ((((cmd - '0') >> 2) & 0x1) == 0x1 && (ctx->tck) == 0x0) {
|
|
||||||
// char tdo_ascii = ctx->tdo + '0';
|
|
||||||
// std::cout << "AAAAAA tms " << (int)(((cmd - '0') >> 1) & 0x1) << " tdi "
|
|
||||||
// << (int)(((cmd - '0') >> 0) & 0x1) << " tdo " << tdo_ascii
|
|
||||||
// << std::endl;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
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';
|
|
||||||
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;
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
// 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_
|
|
|
@ -1,58 +0,0 @@
|
||||||
// Copyright lowRISC contributors.
|
|
||||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
`timescale 1ns / 1ps
|
|
||||||
|
|
||||||
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
|
|
||||||
);
|
|
||||||
|
|
||||||
reg [1:0] plit;
|
|
||||||
|
|
||||||
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) plit <= plit + 1'b1;
|
|
||||||
|
|
||||||
always_ff @(posedge plit[1], negedge rst_ni) begin
|
|
||||||
jtagdpi_tick(ctx, jtag_tck, jtag_tms, jtag_tdi, jtag_trst_n, jtag_srst_n,
|
|
||||||
jtag_tdo);
|
|
||||||
end
|
|
||||||
|
|
||||||
endmodule
|
|
|
@ -1,2 +1,4 @@
|
||||||
target remote :3333
|
target extended-remote :3333
|
||||||
set remotetimeout 20000
|
set remotetimeout 2000
|
||||||
|
monitor reset halt
|
||||||
|
load
|
Binary file not shown.
|
@ -0,0 +1,6 @@
|
||||||
|
#
|
||||||
|
# Dummy interface (for testing purposes)
|
||||||
|
#
|
||||||
|
|
||||||
|
interface jtag_tcp
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
#include "VMurax.h"
|
||||||
|
#include "VMurax_Murax.h"
|
||||||
|
#include "verilated.h"
|
||||||
|
#include "verilated_vcd_c.h"
|
||||||
|
|
||||||
|
#include "../common/framework.h"
|
||||||
|
#include "../common/jtag.h"
|
||||||
|
#include "../common/uart.h"
|
||||||
|
|
||||||
|
class MuraxWorkspace : public Workspace<VMurax>{
|
||||||
|
public:
|
||||||
|
MuraxWorkspace() : Workspace("Murax"){
|
||||||
|
ClockDomain *mainClk = new ClockDomain(&top->io_mainClk,NULL,83333,300000);
|
||||||
|
AsyncReset *asyncReset = new AsyncReset(&top->io_asyncReset,50000);
|
||||||
|
UartRx *uartRx = new UartRx(&top->io_uart_txd,1.0e12/115200);
|
||||||
|
UartTx *uartTx = new UartTx(&top->io_uart_rxd,1.0e12/115200);
|
||||||
|
|
||||||
|
timeProcesses.push_back(mainClk);
|
||||||
|
timeProcesses.push_back(asyncReset);
|
||||||
|
timeProcesses.push_back(uartRx);
|
||||||
|
timeProcesses.push_back(uartTx);
|
||||||
|
|
||||||
|
Jtag *jtag = new Jtag(&top->io_jtag_tms,&top->io_jtag_tdi,&top->io_jtag_tdo,&top->io_jtag_tck,83333*4);
|
||||||
|
timeProcesses.push_back(jtag);
|
||||||
|
|
||||||
|
#ifdef TRACE
|
||||||
|
//speedFactor = 10e-3;
|
||||||
|
//cout << "Simulation caped to " << speedFactor << " of real time"<< endl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct timespec timer_start(){
|
||||||
|
struct timespec start_time;
|
||||||
|
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_time);
|
||||||
|
return start_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
long timer_end(struct timespec start_time){
|
||||||
|
struct timespec end_time;
|
||||||
|
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_time);
|
||||||
|
uint64_t diffInNanos = end_time.tv_sec*1e9 + end_time.tv_nsec - start_time.tv_sec*1e9 - start_time.tv_nsec;
|
||||||
|
return diffInNanos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char **argv, char **env) {
|
||||||
|
|
||||||
|
Verilated::randReset(2);
|
||||||
|
Verilated::commandArgs(argc, argv);
|
||||||
|
|
||||||
|
printf("BOOT\n");
|
||||||
|
timespec startedAt = timer_start();
|
||||||
|
|
||||||
|
MuraxWorkspace().run(100e6);
|
||||||
|
|
||||||
|
uint64_t duration = timer_end(startedAt);
|
||||||
|
cout << endl << "****************************************************************" << endl;
|
||||||
|
cout << "Had simulate " << workspaceCycles << " clock cycles in " << duration*1e-9 << " s (" << workspaceCycles / (duration*1e-9) << " Khz)" << endl;
|
||||||
|
cout << "****************************************************************" << endl << endl;
|
||||||
|
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
|
@ -1,9 +1,3 @@
|
||||||
|
|
||||||
adapter driver remote_bitbang
|
|
||||||
remote_bitbang host localhost
|
|
||||||
remote_bitbang port 44853
|
|
||||||
|
|
||||||
|
|
||||||
set _ENDIAN little
|
set _ENDIAN little
|
||||||
set _TAP_TYPE 1234
|
set _TAP_TYPE 1234
|
||||||
|
|
||||||
|
@ -14,8 +8,8 @@ if { [info exists CPUTAPID] } {
|
||||||
set _CPUTAPID 0x10001fff
|
set _CPUTAPID 0x10001fff
|
||||||
}
|
}
|
||||||
|
|
||||||
adapter speed 800
|
adapter_khz 800
|
||||||
adapter srst delay 260
|
adapter_nsrst_delay 260
|
||||||
jtag_ntrst_delay 250
|
jtag_ntrst_delay 250
|
||||||
|
|
||||||
set _CHIPNAME fpga_spinal
|
set _CHIPNAME fpga_spinal
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
# "JTAG adapter" for simulation, exposed to OpenOCD through a TCP socket
|
|
||||||
# speaking the remote_bitbang protocol. The adapter is implemented as
|
|
||||||
# SystemVerilog DPI module.
|
|
||||||
|
|
||||||
|
|
||||||
# reset_config srst_only # donot support TRST, use five tms=1
|
|
||||||
# adapter_nsrst_assert_width 100
|
|
||||||
|
|
||||||
adapter driver remote_bitbang
|
|
||||||
remote_bitbang host localhost
|
|
||||||
remote_bitbang port 44853
|
|
||||||
|
|
||||||
# Target configuration for the riscv chip
|
|
||||||
|
|
||||||
set _CHIPNAME riscv
|
|
||||||
set _TARGETNAME $_CHIPNAME.tap
|
|
||||||
|
|
||||||
jtag newtap $_CHIPNAME tap -irlen 5 -expected-id 0x10001fff
|
|
||||||
|
|
||||||
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
|
|
|
@ -1,154 +0,0 @@
|
||||||
// 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.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
// `define E906
|
|
||||||
// // `define SOC_TOP tb.x_soc
|
|
||||||
// // `define RTL_MEM tb.x_soc.x_smem_ctrl
|
|
||||||
// // `define ISA_MEM tb.x_pa_isa
|
|
||||||
// `define JTAG_5
|
|
||||||
|
|
||||||
// `define IAHB_LITE
|
|
||||||
// `define RTL_IAHBL_MEM soc_sim.rvsoc.x_cpu_sub_system_ahb.x_iahb_mem_ctrl
|
|
||||||
|
|
||||||
// `define DAHB_LITE
|
|
||||||
// `define RTL_DAHBL_MEM soc_sim.rvsoc.x_cpu_sub_system_ahb.x_dahb_mem_ctrl
|
|
||||||
|
|
||||||
// `define CLK_PERIOD 10
|
|
||||||
// `define TCLK_PERIOD 33
|
|
||||||
// `define MAX_RUN_TIME 700000000
|
|
||||||
// `define clk tb.clk
|
|
||||||
// `define rst_b tb.rst_b
|
|
||||||
// `include "../cpu/environment.h"
|
|
||||||
|
|
||||||
`timescale 1ns / 1ps
|
|
||||||
|
|
||||||
module soc_sim (
|
|
||||||
input bit clk,
|
|
||||||
output jtag_tdo,
|
|
||||||
output jtag_tck,
|
|
||||||
output jtag_tms,
|
|
||||||
output jtag_tdi
|
|
||||||
);
|
|
||||||
|
|
||||||
wire rst;
|
|
||||||
|
|
||||||
bit [63:0] cycleCnt;
|
|
||||||
|
|
||||||
reg uart_tx;
|
|
||||||
wire uart_rx;
|
|
||||||
wire [ 7:0] gpioa;
|
|
||||||
|
|
||||||
wire jrst_b;
|
|
||||||
wire nrst_b;
|
|
||||||
|
|
||||||
wire [ 7:0] WriteData;
|
|
||||||
|
|
||||||
parameter MAX_CYCLES = 10_000_000_0;
|
|
||||||
|
|
||||||
assign rst = cycleCnt > 30 || cycleCnt < 10;
|
|
||||||
assign jrst_b = cycleCnt > 30 || cycleCnt < 10; // Very important
|
|
||||||
assign nrst_b = cycleCnt > 30 || cycleCnt < 10;
|
|
||||||
|
|
||||||
// ///////////////////////////////////////
|
|
||||||
// // Memory Initialization
|
|
||||||
// ///////////////////////////////////////
|
|
||||||
// integer i;
|
|
||||||
// // reg [31:0] mem_data_size;
|
|
||||||
// // reg [31:0] mem_inst_size;
|
|
||||||
|
|
||||||
// reg [31:0] mem_inst_temp[65536];
|
|
||||||
// // reg [31:0] mem_data_temp[65536];
|
|
||||||
|
|
||||||
// initial begin
|
|
||||||
// $display("\t******START TO LOAD PROGRAM******\n");
|
|
||||||
// $readmemh("../work/case.pat", mem_inst_temp);
|
|
||||||
// // $readmemh("./data.pat", mem_data_temp);
|
|
||||||
|
|
||||||
// for (i = 0; i < 65536; i = i + 1) begin
|
|
||||||
// `RTL_IAHBL_MEM.ram0.mem[i][7:0] = ((^mem_inst_temp[i][31:24]) === 1'bx ) ? 8'b0:mem_inst_temp[i][31:24];
|
|
||||||
// `RTL_IAHBL_MEM.ram1.mem[i][7:0] = ((^mem_inst_temp[i][23:16]) === 1'bx ) ? 8'b0:mem_inst_temp[i][23:16];
|
|
||||||
// `RTL_IAHBL_MEM.ram2.mem[i][7:0] = ((^mem_inst_temp[i][15: 8]) === 1'bx ) ? 8'b0:mem_inst_temp[i][15: 8];
|
|
||||||
// `RTL_IAHBL_MEM.ram3.mem[i][7:0] = ((^mem_inst_temp[i][ 7: 0]) === 1'bx ) ? 8'b0:mem_inst_temp[i][ 7: 0];
|
|
||||||
// end
|
|
||||||
|
|
||||||
// for (i = 0; i <= 65536; i = i + 1) begin
|
|
||||||
// `RTL_DAHBL_MEM.ram0.mem[i][7:0] = 8'b0;
|
|
||||||
// `RTL_DAHBL_MEM.ram1.mem[i][7:0] = 8'b0;
|
|
||||||
// `RTL_DAHBL_MEM.ram2.mem[i][7:0] = 8'b0;
|
|
||||||
// `RTL_DAHBL_MEM.ram3.mem[i][7:0] = 8'b0;
|
|
||||||
// end
|
|
||||||
// for (i = 0; i <= 65536; i = i + 1) begin
|
|
||||||
// `RTL_DAHBL_MEM.ram4.mem[i][7:0] = 8'b0;
|
|
||||||
// `RTL_DAHBL_MEM.ram5.mem[i][7:0] = 8'b0;
|
|
||||||
// `RTL_DAHBL_MEM.ram6.mem[i][7:0] = 8'b0;
|
|
||||||
// `RTL_DAHBL_MEM.ram7.mem[i][7:0] = 8'b0;
|
|
||||||
// end
|
|
||||||
// end
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
Murax rvsoc (
|
|
||||||
.io_asyncReset(rst),
|
|
||||||
.io_mainClk(clk),
|
|
||||||
.io_jtag_tms(jtag_tms),
|
|
||||||
.io_jtag_tdi(jtag_tdi),
|
|
||||||
.io_jtag_tdo(jtag_tdo),
|
|
||||||
.io_jtag_tck(jtag_tck),
|
|
||||||
.io_gpioA_read(),
|
|
||||||
.io_gpioA_write(),
|
|
||||||
.io_gpioA_writeEnable(),
|
|
||||||
.io_uart_txd(uart_rx),
|
|
||||||
.io_uart_rxd(uart_tx)
|
|
||||||
);
|
|
||||||
|
|
||||||
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
|
|
|
@ -1,61 +0,0 @@
|
||||||
// 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;
|
|
||||||
const int isOpenDump = 0;
|
|
||||||
|
|
||||||
double sc_time_stamp() { return main_time; }
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
|
||||||
std::cout << "\nVerilatorTB: Start of sim\n" << std::endl;
|
|
||||||
|
|
||||||
Verilated::commandArgs(argc, argv);
|
|
||||||
Vsoc_sim* soc = new Vsoc_sim;
|
|
||||||
VerilatedVcdC* tfp = new VerilatedVcdC;
|
|
||||||
|
|
||||||
if (isOpenDump) {
|
|
||||||
Verilated::traceEverOn(true);
|
|
||||||
soc->trace(tfp, 99);
|
|
||||||
tfp->open("vlt_dump.vcd");
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!Verilated::gotFinish()) {
|
|
||||||
main_time += 5;
|
|
||||||
soc->clk = !soc->clk;
|
|
||||||
soc->eval();
|
|
||||||
|
|
||||||
if (isOpenDump) {
|
|
||||||
tfp->dump(main_time);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isOpenDump) {
|
|
||||||
tfp->close();
|
|
||||||
}
|
|
||||||
soc->final();
|
|
||||||
|
|
||||||
std::cout << "\nVerilatorTB: End of sim" << std::endl;
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
Loading…
Reference in New Issue