From 823ac353ff79a28aa14c1ed47d004a11989dc39f Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 28 Jul 2017 21:25:49 +0200 Subject: [PATCH] Add Murax SoC (very light, work on ice40) --- build.sbt | 4 +- src/main/scala/vexriscv/demo/Murax.scala | 90 ++++- src/test/cpp/briey/main.cpp | 475 +---------------------- src/test/cpp/common/framework.h | 281 ++++++++++++++ src/test/cpp/common/jtag.h | 177 +++++++++ src/test/cpp/murax/main.cpp | 61 +++ src/test/cpp/murax/makefile | 39 ++ src/test/cpp/murax/murax.gtkw | 88 +++++ src/test/cpp/regression/main.cpp | 27 +- 9 files changed, 747 insertions(+), 495 deletions(-) create mode 100644 src/test/cpp/common/framework.h create mode 100644 src/test/cpp/common/jtag.h create mode 100644 src/test/cpp/murax/main.cpp create mode 100644 src/test/cpp/murax/makefile create mode 100644 src/test/cpp/murax/murax.gtkw diff --git a/build.sbt b/build.sbt index afa76ee..6394e63 100644 --- a/build.sbt +++ b/build.sbt @@ -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" ) \ No newline at end of file diff --git a/src/main/scala/vexriscv/demo/Murax.scala b/src/main/scala/vexriscv/demo/Murax.scala index 2670c76..330a65d 100644 --- a/src/main/scala/vexriscv/demo/Murax.scala +++ b/src/main/scala/vexriscv/demo/Murax.scala @@ -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) + ) + ) } diff --git a/src/test/cpp/briey/main.cpp b/src/test/cpp/briey/main.cpp index 601e2ee..47936cb 100644 --- a/src/test/cpp/briey/main.cpp +++ b/src/test/cpp/briey/main.cpp @@ -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 -class TimeProcess{ -public: - uint64_t wakeDelay = 0; - bool wakeEnable = false; -// std::function 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 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 -#include -#include -#include -#include -#include -#include -#include - -/** 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 timeProcesses; - vector 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{ 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; diff --git a/src/test/cpp/common/framework.h b/src/test/cpp/common/framework.h new file mode 100644 index 0000000..1dd72d5 --- /dev/null +++ b/src/test/cpp/common/framework.h @@ -0,0 +1,281 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class SimElement{ +public: + virtual ~SimElement(){} + virtual void onReset(){} + virtual void postReset(){} + virtual void preCycle(){} + virtual void postCycle(){} +}; + +//#include +class TimeProcess{ +public: + uint64_t wakeDelay = 0; + bool wakeEnable = false; +// std::function 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 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 Workspace{ +public: + + vector timeProcesses; + vector 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; + } +}; + + diff --git a/src/test/cpp/common/jtag.h b/src/test/cpp/common/jtag.h new file mode 100644 index 0000000..868c745 --- /dev/null +++ b/src/test/cpp/common/jtag.h @@ -0,0 +1,177 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** 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); + } + +}; \ No newline at end of file diff --git a/src/test/cpp/murax/main.cpp b/src/test/cpp/murax/main.cpp new file mode 100644 index 0000000..064d497 --- /dev/null +++ b/src/test/cpp/murax/main.cpp @@ -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{ +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); +} diff --git a/src/test/cpp/murax/makefile b/src/test/cpp/murax/makefile new file mode 100644 index 0000000..ce18f87 --- /dev/null +++ b/src/test/cpp/murax/makefile @@ -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 + diff --git a/src/test/cpp/murax/murax.gtkw b/src/test/cpp/murax/murax.gtkw new file mode 100644 index 0000000..d2ebdc1 --- /dev/null +++ b/src/test/cpp/murax/murax.gtkw @@ -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 diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 36fc48a..a7d38ad 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -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(); + } } } }