Add Murax SoC (very light, work on ice40)

This commit is contained in:
Charles Papon 2017-07-28 21:25:49 +02:00
parent 1450077b70
commit 823ac353ff
9 changed files with 747 additions and 495 deletions

View File

@ -7,7 +7,7 @@ scalaVersion := "2.11.8"
EclipseKeys.withSource := true
libraryDependencies ++= Seq(
"com.github.spinalhdl" % "spinalhdl-core_2.11" % "0.10.14",
"com.github.spinalhdl" % "spinalhdl-lib_2.11" % "0.10.14",
"com.github.spinalhdl" % "spinalhdl-core_2.11" % "0.10.15",
"com.github.spinalhdl" % "spinalhdl-lib_2.11" % "0.10.15",
"org.yaml" % "snakeyaml" % "1.8"
)

View File

@ -2,6 +2,8 @@ package vexriscv.demo
import spinal.core._
import spinal.lib._
import spinal.lib.bus.amba3.apb.{Apb3Decoder, Apb3Gpio, Apb3}
import spinal.lib.bus.misc.SizeMapping
import spinal.lib.com.jtag.Jtag
import spinal.lib.com.uart.Uart
import spinal.lib.io.TriStateArray
@ -60,7 +62,7 @@ case class Murax(config : MuraxConfig) extends Component{
val jtag = slave(Jtag())
//Peripherals IO
// val gpioA = master(TriStateArray(32 bits))
val gpioA = master(TriStateArray(32 bits))
// val uart = master(Uart())
}
@ -164,7 +166,7 @@ case class Murax(config : MuraxConfig) extends Component{
plugin.externalInterrupt := BufferCC(io.coreInterrupt)
plugin.timerInterrupt := timerCtrl.io.interrupt
}*/
case plugin : DebugPlugin => {
case plugin : DebugPlugin => plugin.debugClockDomain{
resetCtrl.systemReset setWhen(RegNext(plugin.io.resetOut))
io.jtag <> plugin.io.bus.fromJtag()
}
@ -192,11 +194,11 @@ case class Murax(config : MuraxConfig) extends Component{
when(mainBus.cmd.fire){
rspTarget := dBus.cmd.valid
}
iBus.rsp.ready := mainBus.rsp.valid && rspTarget
iBus.rsp.ready := mainBus.rsp.valid && !rspTarget
iBus.rsp.inst := mainBus.rsp.data
iBus.rsp.error := False
dBus.rsp.ready := mainBus.rsp.valid && !rspTarget
dBus.rsp.ready := mainBus.rsp.valid && rspTarget
dBus.rsp.data := mainBus.rsp.data
dBus.rsp.error := False
@ -207,11 +209,11 @@ case class Murax(config : MuraxConfig) extends Component{
}
val ram = new Area{
def bus = mainBus//SimpleBus()
val ram = Mem(Bits(32 bits), (onChipRamSize / 4).toInt)
val bus = SimpleBus()
val ram = Mem(Bits(32 bits), onChipRamSize / 4)
bus.rsp.valid := RegNext(bus.cmd.fire && !bus.cmd.wr) init(False)
bus.rsp.data := ram.readWriteSync(
address = bus.cmd.address.resized,
address = (bus.cmd.address >> 2).resized,
data = bus.cmd.data,
enable = bus.cmd.valid,
write = bus.cmd.wr,
@ -221,12 +223,76 @@ case class Murax(config : MuraxConfig) extends Component{
}
/* val interconnect = new Area {
ramPort.enable := iBus.cmd.valid || dBus.cmd.valid
ramPort.
}
*/
val apbBridge = new Area{
val bus = SimpleBus()
val apb = Apb3(
addressWidth = 20,
dataWidth = 32
)
val cmdStage = bus.cmd.halfPipe()
val state = RegInit(False)
cmdStage.ready := False
apb.PSEL(0) := cmdStage.valid
apb.PENABLE := state
apb.PWRITE := cmdStage.wr
apb.PADDR := cmdStage.address.resized
apb.PWDATA := cmdStage.data
bus.rsp.valid := False
bus.rsp.data := apb.PRDATA
when(!state){
state := cmdStage.valid
} otherwise{
when(apb.PREADY){
state := False
bus.rsp.valid := !cmdStage.wr
cmdStage.ready := True
}
}
}
val interconnect = new Area {
def masterBus = mainBus
val specification = List[(SimpleBus,SizeMapping)](
ram.bus -> (0x00000000l, onChipRamSize kB),
apbBridge.bus -> (0xF0000000l, 1 MB)
)
val slaveBuses = specification.map(_._1)
val memorySpaces = specification.map(_._2)
val hits = for((slaveBus, memorySpace) <- specification) yield {
val hit = memorySpace.hit(masterBus.cmd.address)
slaveBus.cmd.valid := masterBus.cmd.valid && hit
slaveBus.cmd.payload := masterBus.cmd.payload
hit
}
masterBus.cmd.ready := (hits,slaveBuses).zipped.map(_ && _.cmd.ready).orR
val rspPending = RegInit(False) clearWhen(masterBus.rsp.valid) setWhen(masterBus.cmd.fire && !masterBus.cmd.wr)
val rspSourceId = RegNextWhen(OHToUInt(hits), masterBus.cmd.fire)
masterBus.rsp.valid := slaveBuses.map(_.rsp.valid).orR
masterBus.rsp.payload := slaveBuses.map(_.rsp.payload).read(rspSourceId)
when(rspPending && !masterBus.rsp.valid) { //Only one pending read request is allowed
masterBus.cmd.ready := False
slaveBuses.foreach(_.cmd.valid := False)
}
}
val gpioACtrl = Apb3Gpio(
gpioWidth = 32
)
io.gpioA <> gpioACtrl.io.gpio
val apbDecoder = Apb3Decoder(
master = apbBridge.apb,
slaves = List(
gpioACtrl.io.apb -> (0x00000, 4 kB)
)
)
}

View File

@ -23,468 +23,11 @@
#include "VBriey_VexRiscv.h"
class SimElement{
public:
virtual ~SimElement(){}
virtual void onReset(){}
virtual void postReset(){}
virtual void preCycle(){}
virtual void postCycle(){}
};
#include "../common/framework.h"
#include "../common/jtag.h"
//#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;
}
}
};
#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);
}
};
class success : public std::exception { };
class Workspace{
public:
static uint32_t cycles;
vector<TimeProcess*> timeProcesses;
vector<SensitiveProcess*> checkProcesses;
VBriey* top;
bool resetDone = false;
double timeToSec = 1e-12;
double speedFactor = 1.0;
uint64_t allowedTime = 0;
string name;
uint64_t time = 0;
#ifdef TRACE
VerilatedVcdC* tfp;
#endif
ofstream logTraces;
Workspace(string name){
this->name = name;
top = new VBriey;
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 fillSimELements();
virtual void dump(uint64_t i){
#ifdef TRACE
if(i >= TRACE_START) tfp->dump(i);
#endif
}
Workspace* run(uint32_t timeout = 5000){
fillSimELements();
// init trace dump
#ifdef TRACE
Verilated::traceEverOn(true);
tfp = new VerilatedVcdC;
top->trace(tfp, 99);
tfp->open((string(name)+ ".vcd").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;
}
};
void Workspace::fillSimELements(){
}
uint32_t Workspace::cycles = 0;
/*class SimElement{
public:
virtual ~SimElement(){}
virtual void onReset(){}
virtual void postReset(){}
virtual void preCycle(){}
virtual void postCycle(){}
};*/
class SdramConfig{
public:
uint32_t byteCount;
@ -882,7 +425,7 @@ public:
}
};
class BrieyWorkspace : public Workspace{
class BrieyWorkspace : public Workspace<VBriey>{
public:
BrieyWorkspace() : Workspace("Briey"){
ClockDomain *axiClk = new ClockDomain(&top->io_axiClk,NULL,20000,100000);
@ -961,14 +504,6 @@ long timer_end(struct timespec start_time){
return diffInNanos;
}
#define redo(count,that) for(uint32_t xxx = 0;xxx < count;xxx++) that
int main(int argc, char **argv, char **env) {
@ -979,11 +514,11 @@ int main(int argc, char **argv, char **env) {
printf("BOOT\n");
timespec startedAt = timer_start();
BrieyWorkspace().run(100e6);
BrieyWorkspace().run(1e9);
uint64_t duration = timer_end(startedAt);
cout << endl << "****************************************************************" << endl;
cout << "Had simulate " << Workspace::cycles << " clock cycles in " << duration*1e-9 << " s (" << Workspace::cycles / (duration*1e-9) << " Khz)" << endl;
cout << "Had simulate " << workspaceCycles << " clock cycles in " << duration*1e-9 << " s (" << workspaceCycles / (duration*1e-9) << " Khz)" << endl;
cout << "****************************************************************" << endl << endl;

View File

@ -0,0 +1,281 @@
#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>
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
VerilatedVcdC* 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 VerilatedVcdC;
top->trace(tfp, 99);
tfp->open((string(name)+ ".vcd").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;
}
};

177
src/test/cpp/common/jtag.h Normal file
View File

@ -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);
}
};

View File

@ -0,0 +1,61 @@
#include "VMurax.h"
#include "VMurax_Murax.h"
#include "verilated.h"
#include "verilated_vcd_c.h"
#include "../common/framework.h"
#include "../common/jtag.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);
timeProcesses.push_back(mainClk);
timeProcesses.push_back(asyncReset);
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);
}

View File

@ -0,0 +1,39 @@
DEBUG?=no
TRACE?=no
PRINT_PERF?=no
TRACE_START=0
ADDCFLAGS += -CFLAGS -pthread
ifeq ($(TRACE),yes)
VERILATOR_ARGS += --trace
ADDCFLAGS += -CFLAGS -DTRACE
endif
ifeq ($(DEBUG),yes)
ADDCFLAGS += -CFLAGS "-g3 -O0"
endif
ifneq ($(DEBUG),yes)
ADDCFLAGS += -CFLAGS "-O3"
endif
ifeq ($(PRINT_PERF),yes)
ADDCFLAGS += -CFLAGS -DPRINT_PERF
endif
ADDCFLAGS += -CFLAGS -DTRACE_START=${TRACE_START}
all: clean compile
run: compile
./obj_dir/VMurax
verilate:
verilator -cc ../../../../Murax.v -CFLAGS -std=c++11 ${ADDCFLAGS} --gdbbt ${VERILATOR_ARGS} -Wno-WIDTH --x-assign unique --exe main.cpp
compile: verilate
make -j -C obj_dir/ -f VMurax.mk VMurax
clean:
rm -rf obj_dir

View File

@ -0,0 +1,88 @@
[*]
[*] GTKWave Analyzer v3.3.58 (w)1999-2014 BSI
[*] Fri Jul 28 18:56:29 2017
[*]
[dumpfile] "/home/spinalvm/Spinal/VexRiscv/src/test/cpp/murax/Murax.vcd"
[dumpfile_mtime] "Fri Jul 28 18:50:07 2017"
[dumpfile_size] 141674930
[savefile] "/home/spinalvm/Spinal/VexRiscv/src/test/cpp/murax/murax.gtkw"
[timestart] 52797277000
[size] 1776 953
[pos] -775 -1
*-19.000000 52799592000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
[treeopen] TOP.
[treeopen] TOP.Murax.
[sst_width] 269
[signals_width] 398
[sst_expanded] 1
[sst_vpaned_height] 279
@22
TOP.io_gpioA_read[31:0]
TOP.io_gpioA_writeEnable[31:0]
TOP.io_gpioA_write[31:0]
[color] 3
TOP.Murax.system_mainBus_cmd_payload_address[31:0]
[color] 3
TOP.Murax.system_mainBus_cmd_payload_data[31:0]
[color] 3
TOP.Murax.system_mainBus_cmd_payload_mask[3:0]
@28
[color] 3
TOP.Murax.system_mainBus_cmd_payload_wr
[color] 3
TOP.Murax.system_mainBus_cmd_valid
[color] 3
TOP.Murax.system_mainBus_cmd_ready
@22
[color] 3
TOP.Murax.system_mainBus_rsp_payload_data[31:0]
@28
[color] 3
TOP.Murax.system_mainBus_rsp_valid
@29
TOP.Murax.system_ram_bus_cmd_valid
@28
TOP.Murax.system_ram_bus_cmd_ready
@22
TOP.Murax.system_ram_bus_cmd_payload_address[31:0]
TOP.Murax.system_ram_bus_cmd_payload_data[31:0]
TOP.Murax.system_ram_bus_cmd_payload_mask[3:0]
@28
TOP.Murax.system_ram_bus_cmd_payload_wr
@22
TOP.Murax.system_ram_bus_rsp_payload_data[31:0]
@28
TOP.Murax.system_ram_bus_rsp_valid
@22
[color] 1
TOP.Murax.system_apbBridge_bus_cmd_payload_address[31:0]
[color] 1
TOP.Murax.system_apbBridge_bus_cmd_payload_data[31:0]
@28
[color] 1
TOP.Murax.system_apbBridge_bus_cmd_payload_wr
[color] 1
TOP.Murax.system_apbBridge_bus_cmd_ready
[color] 1
TOP.Murax.system_apbBridge_bus_cmd_valid
@22
[color] 1
TOP.Murax.system_apbBridge_bus_rsp_payload_data[31:0]
@28
[color] 1
TOP.Murax.system_apbBridge_bus_rsp_valid
@22
TOP.Murax.system_apbBridge_apb_PADDR[19:0]
@28
TOP.Murax.system_apbBridge_apb_PSEL[0]
TOP.Murax.system_apbBridge_apb_PENABLE
@22
TOP.Murax.system_apbBridge_apb_PRDATA[31:0]
@28
TOP.Murax.system_apbBridge_apb_PREADY
@22
TOP.Murax.system_apbBridge_apb_PWDATA[31:0]
@28
TOP.Murax.system_apbBridge_apb_PWRITE
[pattern_trace] 1
[pattern_trace] 0

View File

@ -1291,17 +1291,22 @@ public:
}
virtual void checks(){
if(/*top->VexRiscv->writeBack_arbitration_isValid == 1 && */top->VexRiscv->writeBack_INSTRUCTION == 0x00000073){
uint32_t code = top->VexRiscv->RegFilePlugin_regFile[28];
if((code & 1) == 0){
cout << "Wrong error code"<< endl;
fail();
}
if(code == 1){
pass();
}else{
cout << "Error code " << code/2 << endl;
fail();
if(top->VexRiscv->writeBack_INSTRUCTION == 0x00000073){
uint32_t instruction;
bool error;
iBusAccess(top->VexRiscv->writeBack_PC, &instruction, &error);
if(instruction == 0x00000073){
uint32_t code = top->VexRiscv->RegFilePlugin_regFile[28];
if((code & 1) == 0){
cout << "Wrong error code"<< endl;
fail();
}
if(code == 1){
pass();
}else{
cout << "Error code " << code/2 << endl;
fail();
}
}
}
}