From 8da413dec3b785745d9c2c46d9d0d9cdd4289555 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Wed, 7 Jun 2017 04:19:35 +0200 Subject: [PATCH] Briey SoC is now working with openOCD TCP JTAG connection. (GDB OK) Add SDRAM Verilator model --- src/main/scala/SpinalRiscv/demo/Briey.scala | 2 +- src/main/scala/SpinalRiscv/ip/DataCache.scala | 22 +- src/test/cpp/briey/.cproject | 121 +++ src/test/cpp/briey/installs.txt | 19 + src/test/cpp/briey/jtag.gtkw | 98 +++ src/test/cpp/briey/main.cpp | 722 ++++++++++++++++++ src/test/cpp/briey/makefile | 34 + src/test/cpp/briey/makefile~ | 26 + src/test/cpp/briey/sdram.gtkw | 115 +++ src/test/cpp/regression/.cproject | 121 +++ src/test/cpp/regression/main.cpp | 2 +- src/test/cpp/regression/makefile | 1 + 12 files changed, 1273 insertions(+), 10 deletions(-) create mode 100644 src/test/cpp/briey/.cproject create mode 100644 src/test/cpp/briey/installs.txt create mode 100644 src/test/cpp/briey/jtag.gtkw create mode 100644 src/test/cpp/briey/main.cpp create mode 100644 src/test/cpp/briey/makefile create mode 100644 src/test/cpp/briey/makefile~ create mode 100644 src/test/cpp/briey/sdram.gtkw create mode 100644 src/test/cpp/regression/.cproject diff --git a/src/main/scala/SpinalRiscv/demo/Briey.scala b/src/main/scala/SpinalRiscv/demo/Briey.scala index 6698775..3d53a48 100644 --- a/src/main/scala/SpinalRiscv/demo/Briey.scala +++ b/src/main/scala/SpinalRiscv/demo/Briey.scala @@ -339,7 +339,7 @@ class Briey(config: BrieyConfig) extends Component{ object Briey{ def main(args: Array[String]) { - val config = SpinalConfig().dumpWave() + val config = SpinalConfig() config.generateVerilog({ val toplevel = new Briey(BrieyConfig.default) toplevel diff --git a/src/main/scala/SpinalRiscv/ip/DataCache.scala b/src/main/scala/SpinalRiscv/ip/DataCache.scala index 879cb0e..e94ba36 100644 --- a/src/main/scala/SpinalRiscv/ip/DataCache.scala +++ b/src/main/scala/SpinalRiscv/ip/DataCache.scala @@ -187,6 +187,7 @@ case class DataCacheMemCmd(p : DataCacheConfig) extends Bundle{ val data = Bits(p.memDataWidth bits) val mask = Bits(p.memDataWidth/8 bits) val length = UInt(log2Up(p.burstLength) bits) + val last = Bool } case class DataCacheMemRsp(p : DataCacheConfig) extends Bundle{ val data = Bits(p.memDataWidth bit) @@ -212,21 +213,23 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave ) val cmdPreFork = if (stageCmd) cmd.stage.stage().s2mPipe() else cmd - val (cmdFork, dataFork) = StreamFork2(cmdPreFork.haltWhen((pendingWrites =/= 0 && !cmdPreFork.wr) || pendingWrites === pendingWritesMax)) - axi.sharedCmd.arbitrationFrom(cmdFork) - axi.sharedCmd.write := cmdFork.wr + val hazard = (pendingWrites =/= 0 && !cmdPreFork.wr) || pendingWrites === pendingWritesMax + val (cmdFork, dataFork) = StreamFork2(cmdPreFork.haltWhen(hazard)) + val cmdStage = cmdFork.throwWhen(RegNextWhen(!cmdFork.last,cmdFork.fire).init(False)) + val dataStage = dataFork.throwWhen(!dataFork.wr) + + axi.sharedCmd.arbitrationFrom(cmdStage) + axi.sharedCmd.write := cmdStage.wr axi.sharedCmd.prot := "010" axi.sharedCmd.cache := "1111" axi.sharedCmd.size := log2Up(p.memDataWidth/8) - axi.sharedCmd.addr := cmdFork.address - axi.sharedCmd.len := cmdFork.length.resized + axi.sharedCmd.addr := cmdStage.address + axi.sharedCmd.len := cmdStage.length.resized - val dataStage = dataFork.throwWhen(!dataFork.wr) axi.writeData.arbitrationFrom(dataStage) - axi.writeData.last := True axi.writeData.data := dataStage.data axi.writeData.strb := dataStage.mask - + axi.writeData.last := dataStage.last rsp.valid := axi.r.valid rsp.error := !axi.r.isOKAY() @@ -441,6 +444,7 @@ class DataCache(p : DataCacheConfig) extends Component{ io.mem.cmd.length := p.burstLength-1 io.mem.cmd.data := bufferReaded.payload io.mem.cmd.mask := (1<<(wordWidth/8))-1 + io.mem.cmd.last := bufferReadedCounter === bufferReadedCounter.maxValue when(!memCmdAlreadyUsed && io.mem.cmd.ready){ bufferReaded.ready := True @@ -556,6 +560,7 @@ class DataCache(p : DataCacheConfig) extends Component{ io.mem.cmd.mask := writeMask io.mem.cmd.data := request.data io.mem.cmd.length := 0 + io.mem.cmd.last := True when(!memCmdSent) { io.mem.cmd.valid := True @@ -606,6 +611,7 @@ class DataCache(p : DataCacheConfig) extends Component{ io.mem.cmd.wr := False io.mem.cmd.address := baseAddress(tagRange.high downto lineRange.low) @@ U(0,lineRange.low bit) io.mem.cmd.length := p.burstLength-1 + io.mem.cmd.last := True } when(valid && io.mem.cmd.ready){ diff --git a/src/test/cpp/briey/.cproject b/src/test/cpp/briey/.cproject new file mode 100644 index 0000000..be7ad7a --- /dev/null +++ b/src/test/cpp/briey/.cproject @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/cpp/briey/installs.txt b/src/test/cpp/briey/installs.txt new file mode 100644 index 0000000..aaada0d --- /dev/null +++ b/src/test/cpp/briey/installs.txt @@ -0,0 +1,19 @@ +sudo apt-get update +sudo apt-get install build-essential software-properties-common -y +sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y +sudo apt-get update +sudo apt-get install gcc-6 g++-6 -y +sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-6 60 --slave /usr/bin/g++ g++ /usr/bin/g++-6 + + +wget -O boost_1_64_0.tar.gz http://sourceforge.net/projects/boost/files/boost/1.64.0/boost_1_64_0.tar.gz/download +tar xzvf boost_1_64_0.tar.gz +cd boost_1_64_0/ +./bootstrap.sh --prefix=/usr/local +./b2 +sudo ./b2 install + + + +echo "using gcc : 6.3 : /usr/bin/g++-6 ; " >> tools/build/src/user-config.jam +bjam --toolset=gcc-6 \ No newline at end of file diff --git a/src/test/cpp/briey/jtag.gtkw b/src/test/cpp/briey/jtag.gtkw new file mode 100644 index 0000000..2faf5d8 --- /dev/null +++ b/src/test/cpp/briey/jtag.gtkw @@ -0,0 +1,98 @@ +[*] +[*] GTKWave Analyzer v3.3.58 (w)1999-2014 BSI +[*] Tue Jun 6 08:32:08 2017 +[*] +[dumpfile] "/home/spinalvm/Spinal/VexRiscv/src/test/cpp/briey/Briey.vcd" +[dumpfile_mtime] "Tue Jun 6 08:32:08 2017" +[dumpfile_size] 23745041 +[savefile] "/home/spinalvm/Spinal/VexRiscv/src/test/cpp/briey/jtag.gtkw" +[timestart] 6592000000 +[size] 1776 953 +[pos] -775 -353 +*-21.000000 5877400000 -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.Briey. +[treeopen] TOP.Briey.axi_jtagCtrl. +[treeopen] TOP.Briey.axi_jtagCtrl.jtagBridge_1. +[sst_width] 399 +[signals_width] 363 +[sst_expanded] 1 +[sst_vpaned_height] 503 +@28 +TOP.io_jtag_tck +TOP.io_jtag_tdi +TOP.io_jtag_tdo +TOP.io_jtag_tms +TOP.Briey.axi_jtagCtrl.jtagBridge_1.io_axiClk +TOP.Briey.axi_jtagCtrl.jtagBridge_1.io_jtag_tck +TOP.Briey.axi_jtagCtrl.jtagBridge_1.io_jtag_tdi +TOP.Briey.axi_jtagCtrl.jtagBridge_1.io_jtag_tdo +TOP.Briey.axi_jtagCtrl.jtagBridge_1.io_jtag_tms +TOP.Briey.axi_jtagCtrl.jtagBridge_1.jtag_idcodeArea_instructionHit +@22 +TOP.Briey.axi_jtagCtrl.jtagBridge_1.jtag_idcodeArea_shifter[31:0] +TOP.Briey.axi_jtagCtrl.jtagBridge_1.jtag_tap_fsm_state[3:0] +@28 +TOP.Briey.axi_jtagCtrl.debugger_io_mem_cmd_valid +@22 +TOP.Briey.axi_jtagCtrl.debugger_io_mem_cmd_payload_address[31:0] +TOP.Briey.axi_jtagCtrl.debugger_io_mem_cmd_payload_data[31:0] +@28 +TOP.Briey.axi_jtagCtrl.debugger_io_mem_cmd_payload_size[1:0] +TOP.Briey.axi_jtagCtrl.debugger_io_mem_cmd_payload_wr +TOP.Briey.axi_jtagCtrl.debugger_io_mem_rsp_valid +@22 +TOP.Briey.axi_jtagCtrl.io_axi_arw_payload_addr[31:0] +@28 +TOP.Briey.axi_jtagCtrl.io_axi_arw_payload_size[2:0] +TOP.Briey.axi_jtagCtrl.io_axi_arw_payload_write +TOP.Briey.axi_jtagCtrl.io_axi_arw_ready +TOP.Briey.axi_jtagCtrl.io_axi_arw_valid +TOP.Briey.axi_jtagCtrl.io_axi_b_ready +@22 +TOP.Briey.axi_jtagCtrl.io_axi_r_payload_data[31:0] +@28 +TOP.Briey.axi_jtagCtrl.io_axi_r_ready +TOP.Briey.axi_jtagCtrl.io_axi_r_valid +@22 +TOP.Briey.axi_jtagCtrl.io_axi_w_payload_data[31:0] +@28 +TOP.Briey.axi_jtagCtrl.io_axi_w_payload_last +@22 +TOP.Briey.axi_jtagCtrl.io_axi_w_payload_strb[3:0] +@28 +TOP.Briey.axi_jtagCtrl.io_axi_w_ready +TOP.Briey.axi_jtagCtrl.io_axi_w_valid +TOP.Briey.axi_jtagCtrl.debugger.io_remote_cmd_payload_fragment[0] +TOP.Briey.axi_jtagCtrl.debugger.io_remote_cmd_payload_last +TOP.Briey.axi_jtagCtrl.debugger.io_remote_cmd_valid +@22 +TOP.Briey.axi_jtagCtrl.debugger.io_remote_rsp_payload_data[31:0] +@28 +TOP.Briey.axi_jtagCtrl.debugger.io_remote_rsp_payload_error +TOP.Briey.axi_jtagCtrl.debugger.io_remote_rsp_valid +TOP.Briey.axi_jtagCtrl.jtagBridge_1.io_remote_cmd_payload_fragment[0] +TOP.Briey.axi_jtagCtrl.jtagBridge_1.io_remote_cmd_payload_last +TOP.Briey.axi_jtagCtrl.jtagBridge_1.io_remote_cmd_valid +@22 +TOP.Briey.axi_jtagCtrl.jtagBridge_1.io_remote_rsp_payload_data[31:0] +@28 +TOP.Briey.axi_jtagCtrl.jtagBridge_1.io_remote_rsp_payload_error +TOP.Briey.axi_jtagCtrl.jtagBridge_1.io_remote_rsp_valid +TOP.Briey.axi_jtagCtrl.jtagBridge_1.flowCCByToggle_1.io_input_payload_fragment[0] +TOP.Briey.axi_jtagCtrl.jtagBridge_1.flowCCByToggle_1.io_input_payload_last +TOP.Briey.axi_jtagCtrl.jtagBridge_1.flowCCByToggle_1.io_input_valid +TOP.Briey.axi_jtagCtrl.jtagBridge_1.flowCCByToggle_1.io_jtag_tck +TOP.Briey.axi_jtagCtrl.jtagBridge_1.flowCCByToggle_1.io_output_payload_fragment[0] +TOP.Briey.axi_jtagCtrl.jtagBridge_1.flowCCByToggle_1.io_output_payload_last +TOP.Briey.axi_jtagCtrl.jtagBridge_1.flowCCByToggle_1.io_output_valid +@29 +TOP.Briey.axi_jtagCtrl.jtagBridge_1.io_jtag_tck +TOP.Briey.axi_jtagCtrl.jtagBridge_1.io_jtag_tdi +TOP.Briey.axi_jtagCtrl.jtagBridge_1.io_jtag_tdo +TOP.Briey.axi_jtagCtrl.jtagBridge_1.io_jtag_tms +@22 +TOP.Briey.axi_jtagCtrl.jtagBridge_1.jtag_tap_fsm_state[3:0] +TOP.Briey.axi_jtagCtrl.jtagBridge_1.jtag_tap_instruction[3:0] +[pattern_trace] 1 +[pattern_trace] 0 diff --git a/src/test/cpp/briey/main.cpp b/src/test/cpp/briey/main.cpp new file mode 100644 index 0000000..0628a75 --- /dev/null +++ b/src/test/cpp/briey/main.cpp @@ -0,0 +1,722 @@ +#include "VBriey.h" +#include "VBriey_Briey.h" +#ifdef REF +#include "VBriey_RiscvCore.h" +#endif +#include "verilated.h" +#include "verilated_vcd_c.h" +#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 Process{ +public: + uint64_t wakeDelay = 0; + bool wakeEnable = false; +// std::function lambda; + virtual ~Process(){} + 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 ClockDomain : public Process{ +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 Process{ +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 + +/** 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 Process{ +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 period; +// 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->period = period; + *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); + 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); + } + } + virtual void tick(){ + if(clientHandle == -1){ + clientHandle = accept(serverSocket, (struct sockaddr *) &serverStorage, &addr_size); + if(clientHandle != -1) + printf("CONNECTED\n"); + } + if(clientHandle != -1){ + uint8_t buffer; + int n; + + if(ioctl(clientHandle,FIONREAD,&n) != 0) + connectionReset(); + else if(n >= 1){ + switch(read(clientHandle,&buffer,1)){ + case 0: break; + case 1: + *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"); + } + break; + default: + connectionReset(); + break; + } + } + } + schedule(period); + } + +}; + + +class success : public std::exception { }; + +class Workspace{ +public: + static uint32_t cycles; + vector processes; + 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(Process* p : processes) 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(); + + 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(Process* p : processes) + if(p->wakeEnable && p->wakeDelay < delay) + delay = p->wakeDelay; + + if(delay == ~0l){ + fail(); + } + if(delay != 0){ + dump(time); + } + for(Process* p : processes) { + p->wakeDelay -= delay; + if(p->wakeDelay == 0){ + p->wakeEnable = false; + p->tick(); + } + } + + top->eval(); + + + 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; + printf("Simulation speed : %f ms/realTime\n",(time - tickLastSimTime)/dt*timeToSec*1e3); + 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; + uint32_t bankCount; + uint32_t rowSize; + uint32_t colSize; + + SdramConfig(uint32_t byteCount, + uint32_t bankCount, + uint32_t rowSize, + uint32_t colSize){ + this->byteCount = byteCount; + this->bankCount = bankCount; + this->rowSize = rowSize; + this->colSize = colSize; + } +}; + +class SdramIo{ +public: + CData *BA; + CData *DQM; + CData *CASn; + CData *CKE; + CData *CSn; + CData *RASn; + CData *WEn; + SData *ADDR; + CData *DQ_read; + CData *DQ_write; + CData *DQ_writeEnable; +}; + +class Sdram : public SimElement{ +public: + + SdramConfig *config; + SdramIo *io; + + uint32_t CAS; + uint32_t burstLength; + + class Bank{ + public: + uint8_t *data; + SdramConfig *config; + + bool opened; + uint32_t openedRow; + void init(SdramConfig *config){ + this->config = config; + data = new uint8_t[config->rowSize * config->colSize * config->byteCount]; + opened = false; + } + + virtual ~Bank(){ + delete data; + } + + void activate(uint32_t row){ + if(opened) + cout << "SDRAM error open unclosed bank" << endl; + openedRow = row; + opened = true; + } + + void precharge(){ + opened = false; + } + + void write(uint32_t column, CData byteId, CData data){ + if(!opened) + cout << "SDRAM : write in closed bank" << endl; + uint32_t addr = byteId + (column + openedRow * config->colSize) * config->byteCount; + this->data[addr] = data; + + //printf("SDRAM : Write A=%08x D=%02x\n",addr,data); + } + + CData read(uint32_t column, CData byteId){ + if(!opened) + cout << "SDRAM : write in closed bank" << endl; + uint32_t addr = byteId + (column + openedRow * config->colSize) * config->byteCount; + //printf("SDRAM : Read A=%08x D=%02x\n",addr,data[addr]); + return data[addr]; + } + }; + + Bank* banks; + + CData * readShifter; + + Sdram(SdramConfig *config,SdramIo* io){ + this->config = config; + this->io = io; + banks = new Bank[config->bankCount]; + for(uint32_t bankId = 0;bankId < config->bankCount;bankId++) banks[bankId].init(config); + readShifter = new CData[config->byteCount*3]; + } + + virtual ~Sdram(){ + delete banks; + delete readShifter; + } + + + uint8_t ckeLast = 0; + + + virtual void postCycle(){ + if(CAS >= 2 && CAS <=3){ + for(uint32_t byteId = 0;byteId != config->byteCount;byteId++){ + io->DQ_read[byteId] = readShifter[byteId + (CAS-1)*config->byteCount]; + } + for(uint32_t latency = CAS-1;latency != 0;latency--){ //missing CKE + for(uint32_t byteId = 0;byteId != config->byteCount;byteId++){ + readShifter[byteId+latency*config->byteCount] = readShifter[byteId+(latency-1)*config->byteCount]; + } + } + } + } + + virtual void preCycle(){ + if(!*io->CSn && ckeLast){ + uint32_t code = ((*io->RASn) << 2) | ((*io->CASn) << 1) | ((*io->WEn) << 0); + switch(code){ + case 0: //Mode register set + if(*io->BA == 0 && (*io->ADDR & 0x400) == 0){ + CAS = ((*io->ADDR) >> 4) & 0x7; + burstLength = ((*io->ADDR) >> 0) & 0x7; + if((*io->ADDR & 0x388) != 0) + cout << "SDRAM : ???" << endl; + printf("SDRAM : MODE REGISTER DEFINITION CAS=%d burstLength=%d\n",CAS,burstLength); + } + break; + case 2: //Bank precharge + if((*io->ADDR & 0x400) != 0){ //all + for(uint32_t bankId = 0;bankId < config->bankCount;bankId++) + banks[bankId].precharge(); + } else { //single + banks[*io->BA].precharge(); + } + break; + case 3: //Bank activate + banks[*io->BA].activate(*io->ADDR & 0x7FF); + break; + case 4: //Write + if((*io->ADDR & 0x400) != 0) + cout << "SDRAM : Write autoprecharge not supported" << endl; + + if(*io->DQ_writeEnable == 0) + cout << "SDRAM : Write Wrong DQ direction" << endl; + + for(uint32_t byteId = 0;byteId < config->byteCount;byteId++){ + if(((*io->DQM >> byteId) & 1) == 0) + banks[*io->BA].write(*io->ADDR, byteId ,io->DQ_write[byteId]); + } + break; + + case 5: //Read + if((*io->ADDR & 0x400) != 0) + cout << "SDRAM : READ autoprecharge not supported" << endl; + + if(*io->DQ_writeEnable != 0) + cout << "SDRAM : READ Wrong DQ direction" << endl; + + //if(*io->DQM != config->byteCount-1) + //cout << "SDRAM : READ wrong DQM" << endl; + + for(uint32_t byteId = 0;byteId < config->byteCount;byteId++){ + readShifter[byteId] = banks[*io->BA].read(*io->ADDR, byteId); + } + break; + case 1: // Self refresh + break; + case 7: // NOP + break; + default: + cout << "SDRAM : unknown code" << endl; + break; + } + } + ckeLast = *io->CKE; + } +}; + + +class BrieyWorkspace : public Workspace{ +public: + BrieyWorkspace() : Workspace("Briey"){ + ClockDomain *axiClk = new ClockDomain(&top->io_axiClk,NULL,20000,100000); + ClockDomain *vgaClk = new ClockDomain(&top->io_vgaClk,NULL,40000,100000); + AsyncReset *asyncReset = new AsyncReset(&top->io_asyncReset,50000); + Jtag *jtag = new Jtag(&top->io_jtag_tms,&top->io_jtag_tdi,&top->io_jtag_tdo,&top->io_jtag_tck,200000); + processes.push_back(axiClk); + processes.push_back(vgaClk); + processes.push_back(asyncReset); + processes.push_back(jtag); + + SdramConfig *sdramConfig = new SdramConfig( + 2, //byteCount + 4, //bankCount + 13, //rowSize + 10 //colSize + ); + SdramIo *sdramIo = new SdramIo(); + sdramIo->BA = &top->io_sdram_BA ; + sdramIo->DQM = &top->io_sdram_DQM ; + sdramIo->CASn = &top->io_sdram_CASn ; + sdramIo->CKE = &top->io_sdram_CKE ; + sdramIo->CSn = &top->io_sdram_CSn ; + sdramIo->RASn = &top->io_sdram_RASn ; + sdramIo->WEn = &top->io_sdram_WEn ; + sdramIo->ADDR = &top->io_sdram_ADDR ; + sdramIo->DQ_read = (CData*)&top->io_sdram_DQ_read ; + sdramIo->DQ_write = (CData*)&top->io_sdram_DQ_write ; + sdramIo->DQ_writeEnable = &top->io_sdram_DQ_writeEnable; + Sdram *sdram = new Sdram(sdramConfig, sdramIo); + + axiClk->add(sdram); + #ifdef TRACE + speedFactor = 100e-6; + cout << "Simulation caped to " << timeToSec << " 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; +} + +#define redo(count,that) for(uint32_t xxx = 0;xxx < count;xxx++) that + + + + +/* +#include +#include +#include + +using boost::coroutines2::coroutine; + +void cooperative(coroutine::push_type &sink, int i) +{ + int j = i; + sink(++j); + sink(++j); + std::cout << "end\n"; +} + +int main2() +{ + using std::placeholders::_1; + coroutine::pull_type source{std::bind(cooperative, _1, 0)}; + std::cout << source.get() << '\n'; + source(); + std::cout << source.get() << '\n'; + source(); +}*/ + +int main(int argc, char **argv, char **env) { + + Verilated::randReset(2); + Verilated::commandArgs(argc, argv); + + printf("BOOT\n"); + timespec startedAt = timer_start(); + + BrieyWorkspace().run(100e6); + + 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; + /*if(successCounter == testsCounter) + cout << "SUCCESS " << successCounter << "/" << testsCounter << endl; + else + cout<< "FAILURE " << testsCounter - successCounter << "/" << testsCounter << endl;*/ + cout << "****************************************************************" << endl << endl; + + + exit(0); +} diff --git a/src/test/cpp/briey/makefile b/src/test/cpp/briey/makefile new file mode 100644 index 0000000..39d43a5 --- /dev/null +++ b/src/test/cpp/briey/makefile @@ -0,0 +1,34 @@ +DEBUG?=no +TRACE?=no +TRACE_START=0 +ADDCFLAGS += -CFLAGS -pthread + +ifeq ($(TRACE),yes) + VERILATOR_ARGS += --trace + ADDCFLAGS += -CFLAGS -DTRACE +endif +ifeq ($(DEBUG),yes) + ADDCFLAGS += -CFLAGS "-g -O0" +endif +ifneq ($(DEBUG),yes) + ADDCFLAGS += -CFLAGS "-O3" +endif + +ADDCFLAGS += -CFLAGS -DTRACE_START=${TRACE_START} + + + +all: clean compile + +run: compile + ./obj_dir/VBriey + +verilate: + verilator -cc ../../../../Briey.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 VBriey.mk VBriey + +clean: + rm -rf obj_dir + diff --git a/src/test/cpp/briey/makefile~ b/src/test/cpp/briey/makefile~ new file mode 100644 index 0000000..773ecb3 --- /dev/null +++ b/src/test/cpp/briey/makefile~ @@ -0,0 +1,26 @@ +TRACE?=no +TRACE_START=0 + +ADDCFLAGS += -CFLAGS -pthread + + + +ifeq ($(TRACE),yes) + VERILATOR_ARGS += --trace + ADDCFLAGS += -CFLAGS -DTRACE +endif +ADDCFLAGS += -CFLAGS -DTRACE_START=${TRACE_START} + + +run: compile + ./obj_dir/VBriey + +verilate: + verilator -cc ../../../../Briey.v -O3 -CFLAGS -std=c++11 -LDFLAGS -pthread ${ADDCFLAGS} --gdbbt ${VERILATOR_ARGS} -Wno-WIDTH --x-assign unique --exe main.cpp + +compile: verilate + make -j -C obj_dir/ -f VBriey.mk VBriey + +clean: + rm -rf obj_dir + diff --git a/src/test/cpp/briey/sdram.gtkw b/src/test/cpp/briey/sdram.gtkw new file mode 100644 index 0000000..e3fcbc8 --- /dev/null +++ b/src/test/cpp/briey/sdram.gtkw @@ -0,0 +1,115 @@ +[*] +[*] GTKWave Analyzer v3.3.58 (w)1999-2014 BSI +[*] Wed Jun 7 01:18:28 2017 +[*] +[dumpfile] "/home/spinalvm/Spinal/VexRiscv/src/test/cpp/briey/Briey.vcd" +[dumpfile_mtime] "Wed Jun 7 01:17:07 2017" +[dumpfile_size] 1021433582 +[savefile] "/home/spinalvm/Spinal/VexRiscv/src/test/cpp/briey/sdram.gtkw" +[timestart] 20762992700 +[size] 1776 953 +[pos] -1 -353 +*-16.000000 20763117800 -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.Briey. +[treeopen] TOP.Briey.axi_jtagCtrl. +[treeopen] TOP.Briey.axi_sdramCtrl. +[sst_width] 325 +[signals_width] 456 +[sst_expanded] 1 +[sst_vpaned_height] 503 +@28 +TOP.Briey.axi_core_cpu.DebugPlugin_haltIt +TOP.Briey.axi_sdramCtrl.io_sdram_BA[1:0] +TOP.Briey.axi_sdramCtrl.io_sdram_CKE +TOP.Briey.axi_sdramCtrl.io_sdram_CSn +TOP.Briey.axi_sdramCtrl.io_sdram_DQM[1:0] +@22 +TOP.Briey.axi_sdramCtrl.io_sdram_DQ_read[15:0] +@28 +TOP.Briey.axi_sdramCtrl.io_sdram_DQ_writeEnable +@22 +TOP.Briey.axi_sdramCtrl.io_sdram_DQ_write[15:0] +@28 +TOP.Briey.axi_sdramCtrl.io_sdram_RASn +TOP.Briey.axi_sdramCtrl.io_sdram_CASn +TOP.Briey.axi_sdramCtrl.io_sdram_WEn +@24 +TOP.Briey.axi_sdramCtrl.io_sdram_ADDR[12:0] +@22 +TOP.Briey.axi_sdramCtrl.ctrl.io_bus_cmd_payload_context_id[3:0] +@28 +TOP.Briey.axi_sdramCtrl.ctrl.io_bus_cmd_payload_context_last +@22 +TOP.Briey.axi_sdramCtrl.ctrl.io_bus_cmd_payload_data[15:0] +@28 +TOP.Briey.axi_sdramCtrl.ctrl.io_bus_cmd_payload_mask[1:0] +TOP.Briey.axi_sdramCtrl.ctrl.io_bus_cmd_valid +TOP.Briey.axi_sdramCtrl.ctrl.io_bus_cmd_ready +@22 +TOP.Briey.axi_sdramCtrl.ctrl.io_bus_cmd_payload_address[24:0] +@28 +TOP.Briey.axi_sdramCtrl.ctrl.io_bus_cmd_payload_write +@22 +TOP.Briey.axi_sdramCtrl.ctrl.io_bus_rsp_payload_context_id[3:0] +@28 +TOP.Briey.axi_sdramCtrl.ctrl.io_bus_rsp_payload_context_last +@22 +TOP.Briey.axi_sdramCtrl.ctrl.io_bus_rsp_payload_data[15:0] +@28 +TOP.Briey.axi_sdramCtrl.ctrl.io_bus_rsp_ready +TOP.Briey.axi_sdramCtrl.ctrl.io_bus_rsp_valid +TOP.Briey.axi_core_cpu.DebugPlugin_haltIt +TOP.Briey.axi_core_cpu.DebugPlugin_haltedByBreak +TOP.Briey.axi_core_cpu.DebugPlugin_isPipBusy +TOP.Briey.axi_core_cpu.DebugPlugin_resetIt +TOP.Briey.axi_core_cpu.DebugPlugin_stepIt +TOP.Briey.axi_core_cpu.DebugPlugin_insertDecodeInstruction +@22 +TOP.Briey.axi_jtagCtrl.debugger.io_mem_cmd_payload_address[31:0] +TOP.Briey.axi_jtagCtrl.debugger.io_mem_cmd_payload_data[31:0] +@28 +TOP.Briey.axi_jtagCtrl.debugger.io_mem_cmd_payload_size[1:0] +TOP.Briey.axi_jtagCtrl.debugger.io_mem_cmd_payload_wr +@29 +TOP.Briey.axi_jtagCtrl.debugger.io_mem_cmd_ready +@28 +TOP.Briey.axi_jtagCtrl.debugger.io_mem_cmd_valid +@22 +TOP.Briey.axi_jtagCtrl.debugger.io_mem_rsp_payload[31:0] +@28 +TOP.Briey.axi_jtagCtrl.debugger.io_mem_rsp_valid +@22 +TOP.Briey.axi_core_cpu.prefetch_PC[31:0] +TOP.Briey.axi_core_cpu.execute_PC[31:0] +@28 +TOP.Briey.axi_core_cpu.execute_IS_EBREAK +TOP.Briey.axi_core_cpu.execute_arbitration_isValid +@22 +TOP.Briey.axi_core_cpu.DebugPlugin_busReadDataReg[31:0] +@28 +TOP.Briey.axi_core_cpu.writeBack_arbitration_isValid +@22 +TOP.Briey.axi_core_cpu.writeBack_REGFILE_WRITE_DATA[31:0] +TOP.Briey.axi_core_cpu.writeBack_PC[31:0] +TOP.Briey.axi_core_cpu.execute_REGFILE_WRITE_DATA[31:0] +TOP.Briey.axi_core_cpu.execute_SRC1[31:0] +TOP.Briey.axi_core_cpu.execute_SRC2[31:0] +TOP.Briey.axi_core_cpu.decode_SRC1[31:0] +@28 +TOP.Briey.axi_core_cpu.decode_SRC1_CTRL[1:0] +@22 +TOP.Briey.axi_core_cpu.decode_SRC2[31:0] +@28 +TOP.Briey.axi_core_cpu.decode_SRC2_CTRL[1:0] +@22 +TOP.Briey.axi_core_cpu.decode_REG1[31:0] +TOP.Briey.axi_core_cpu.RegFilePlugin_regFile(0)[31:0] +TOP.Briey.axi_core_cpu.decode_RegFilePlugin_regFileReadAddress1[4:0] +@28 +TOP.Briey.axi_core_cpu.decode_IS_EBREAK +TOP.Briey.axi_core_cpu.decode_arbitration_isValid +@22 +TOP.Briey.axi_core_cpu.decode_INSTRUCTION[31:0] +[pattern_trace] 1 +[pattern_trace] 0 diff --git a/src/test/cpp/regression/.cproject b/src/test/cpp/regression/.cproject new file mode 100644 index 0000000..50a0b30 --- /dev/null +++ b/src/test/cpp/regression/.cproject @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index d01514b..ac3e3a9 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -307,8 +307,8 @@ public: currentTime = 4; // init trace dump - Verilated::traceEverOn(true); #ifdef TRACE + Verilated::traceEverOn(true); tfp = new VerilatedVcdC; top->trace(tfp, 99); tfp->open((string(name)+ ".vcd").c_str()); diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index 6438b48..e749621 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -66,6 +66,7 @@ ifeq ($(FREE_RTOS),yes) ADDCFLAGS += -CFLAGS -DFREE_RTOS endif +all: clean run run: compile ./obj_dir/VVexRiscv