diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..ab5c2da --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/test/resources/VexRiscvRegressionData"] + path = src/test/resources/VexRiscvRegressionData + url = ../VexRiscvRegressionData.git diff --git a/.travis.yml b/.travis.yml index ee00974..832ba00 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,8 +11,8 @@ scala: sbt_args: -no-colors -J-Xss2m script: - - export VEXRISCV_REGRESSION_CONFIG_COUNT=100 - export VEXRISCV_REGRESSION_FREERTOS_COUNT=no + - export VEXRISCV_REGRESSION_THREAD_COUNT=1 - sbt -jvm-opts travis/jvmopts.compile compile - sbt -jvm-opts travis/jvmopts.test test @@ -22,7 +22,11 @@ jdk: # - openjdk7 env: - - secure: "v7FHP8yK/zixpv1ML05qcRhZfDVDFdTmTPjfMZHL7gmrJveVDgze22x4tY4tB1+JEXhKuVTYvimOrX/Ok+rOOT5gVKLowv4PUQwCR+HgWVIbqjcfZNLsa369v03/p4K/zbjJSiXFahZYOXa0ApED2KWHcVfCrNsPv0UF7YZGiIa1Q/lPBwfmpN1rLih2Mpgn4KVaJky22t7JXJyVrNdGVmIA51slVbyFwFAE8Ww/0tkC+i2PUcWWRMIxtXP4iyq/9Npcq5VdqOatKfWHqAElLfKSPNMYLMlcyxyNpNx4paq8cL6fQxFcBLi9M2msz2i/qpKv30a0tzNo5bQQgucAXOQJB2Buks728upLuqsr+k25hwcqrtjyMOr9UQkt7qXAJH/0kimW7aW1yoMxbm/6mNG98X9D1EzNRewHAKatwJeFy1bw5qIuSQxPBwQMGloManrHOHGotmHKk7Y+dgM/z1UlaAdxSQuKWGXBc8QlQvif8puPYEdJMoInJNRxiWfYu06XnmzTXgMketK7RdULM9DVYzw8hzS2EIWKu8Oa0zn0PTevD2YeJNd4G8mDqO0vz5hloIc7pFsq/exQUB/kFozfCsnvhW8P+MPN0LpuSpptBQTsLWbM5BH0hd46HoWcneDdlMvVrUcgsTPmmSroIkLIEUo+Y2iN5eQHPPp85Cw=" + - VEXRISCV_REGRESSION_CONFIG_COUNT=0 + - VEXRISCV_REGRESSION_CONFIG_COUNT=5 + - VEXRISCV_REGRESSION_CONFIG_COUNT=5 + - VEXRISCV_REGRESSION_CONFIG_COUNT=5 + - VEXRISCV_REGRESSION_CONFIG_COUNT=5 before_install: # JDK fix @@ -34,11 +38,9 @@ before_install: # Verilator - sudo apt-get install git make autoconf g++ flex bison -y # First time prerequisites - - git clone http://git.veripool.org/git/verilator # Only first time - - unset VERILATOR_ROOT # For bash + - wget https://www.veripool.org/ftp/verilator-4.012.tgz + - tar xvzf verilator*.t*gz - cd verilator - - git pull # Make sure we're up-to-date - - git checkout verilator_3_916 - autoconf # Create ./configure script - ./configure - make -j$(nproc) @@ -48,6 +50,7 @@ before_install: - git clone https://github.com/SpinalHDL/SpinalHDL.git -b dev - cd VexRiscv + - git submodule update --init --recursive #- curl -T README.md -udolu1990:$BINTRAY_KEY https://api.bintray.com/content/spinalhdl/VexRiscv/test/0.0.4/README.md #- curl -X POST -udolu1990:$BINTRAY_KEY https://api.bintray.com/content/spinalhdl/VexRiscv/test/0.0.4/publish #- sbt compile diff --git a/src/main/scala/vexriscv/Services.scala b/src/main/scala/vexriscv/Services.scala index 26ecf84..09cd098 100644 --- a/src/main/scala/vexriscv/Services.scala +++ b/src/main/scala/vexriscv/Services.scala @@ -33,7 +33,7 @@ case class ExceptionCause() extends Bundle{ trait ExceptionService{ def newExceptionPort(stage : Stage, priority : Int = 0) : Flow[ExceptionCause] - def isExceptionPending() : Bool + def isExceptionPending(stage : Stage) : Bool } trait PrivilegeService{ diff --git a/src/main/scala/vexriscv/demo/Linux.scala b/src/main/scala/vexriscv/demo/Linux.scala index fe60056..9b32dc9 100644 --- a/src/main/scala/vexriscv/demo/Linux.scala +++ b/src/main/scala/vexriscv/demo/Linux.scala @@ -40,13 +40,13 @@ cd VexRiscv Run regressions => sbt "runMain vexriscv.demo.LinuxGen -r" cd src/test/cpp/regression -make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes CSR=yes COMPRESSED=no LRSC=yes AMO=yes REDO=10 TRACE=no +make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yes SUPERVISOR=yes MMU=yes CSR=yes COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes REDO=10 TRACE=no COREMARK=yes LINUX_REGRESSION=yes Run linux in simulation (Require the machime mode emulator compiled in SIM mode) => sbt "runMain vexriscv.demo.LinuxGen" cd src/test/cpp/regression export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal -make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=no LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=$BUILDROOT/output/images/Image DTB=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb RAMDISK=$BUILDROOT/output/images/rootfs.cpio TRACE=no FLOW_INFO=no +make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=no LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=../../../main/c/emulator/build/emulator.bin VMLINUX=$BUILDROOT/output/images/Image DTB=$BUILDROOT/board/spinal/vexriscv_sim/rv32.dtb RAMDISK=$BUILDROOT/output/images/rootfs.cpio WITH_USER_IO=yes TRACE=no FLOW_INFO=no Run linux with QEMU (Require the machime mode emulator compiled in QEMU mode) export BUILDROOT=/home/miaou/pro/riscv/buildrootSpinal @@ -94,10 +94,12 @@ rm VexRiscv.v cp $DATA/VexRiscv.v ../../../.. make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD SUPERVISOR=yes CSR=yes COMPRESSED=no LRSC=yes AMO=yes REDO=0 DHRYSTONE=no LINUX_SOC=yes EMULATOR=$DATA/emulator.bin VMLINUX=$DATA/vmlinux.bin DTB=$DATA/rv32.dtb RAMDISK=$DATA/rootfs.cpio TRACE=no FLOW_INFO=no +make clean run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=no SUPERVISOR=yes CSR=yes COMPRESSED=no MUL=yes DIV=yes LRSC=yes AMO=yes MMU=yes REDO=1 TRACE=no LINUX_REGRESSION=yes qemu-system-riscv32 -nographic -machine virt -m 1536M -device loader,file=$DATA/emulator.bin,addr=0x80000000,cpu-num=0 -device loader,file=$DATA/rv32.dtb,addr=0xC3000000 -device loader,file=$DATA/vmlinux.bin,addr=0xC0000000 -device loader,file=$DATA/rootfs.cpio,addr=0xc2000000 +make run IBUS=CACHED DBUS=CACHED DEBUG_PLUGIN=STD DHRYSTONE=yess SUPERVISOR=yes CSR=yes COMPRESSED=yes MUL=yes DIV=yes LRSC=yes AMO=yes REDO=1 TRACE=no LINUX_REGRESSION=yes program ../../../main/c/emulator/build/emulator.bin 0x80000000 verify soc.loadBin(EMULATOR, 0x80000000); @@ -149,12 +151,12 @@ object LinuxGen { new IBusCachedPlugin( resetVector = 0x80000000l, compressedGen = false, - prediction = DYNAMIC_TARGET, + prediction = NONE, injectorStage = false, config = InstructionCacheConfig( - cacheSize = 4096*4, + cacheSize = 4096*1, bytePerLine = 32, - wayCount = 4, + wayCount = 1, addressWidth = 32, cpuDataWidth = 32, memDataWidth = 32, @@ -184,9 +186,9 @@ object LinuxGen { dBusCmdSlavePipe = true, dBusRspSlavePipe = true, config = new DataCacheConfig( - cacheSize = 4096*4, + cacheSize = 4096*1, bytePerLine = 32, - wayCount = 4, + wayCount = 1, addressWidth = 32, cpuDataWidth = 32, memDataWidth = 32, diff --git a/src/main/scala/vexriscv/demo/MuraxUtiles.scala b/src/main/scala/vexriscv/demo/MuraxUtiles.scala index 2422450..4e650d3 100644 --- a/src/main/scala/vexriscv/demo/MuraxUtiles.scala +++ b/src/main/scala/vexriscv/demo/MuraxUtiles.scala @@ -163,3 +163,8 @@ class MuraxApb3Timer extends Component{ interruptCtrl.io.inputs(1) := timerB.io.full io.interrupt := interruptCtrl.io.pendings.orR } + + +object MuraxApb3TimerGen extends App{ + SpinalVhdl(new MuraxApb3Timer()) +} \ No newline at end of file diff --git a/src/main/scala/vexriscv/plugin/CsrPlugin.scala b/src/main/scala/vexriscv/plugin/CsrPlugin.scala index 8057071..3c7b036 100644 --- a/src/main/scala/vexriscv/plugin/CsrPlugin.scala +++ b/src/main/scala/vexriscv/plugin/CsrPlugin.scala @@ -327,8 +327,8 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception interface } - var exceptionPending : Bool = null - override def isExceptionPending(): Bool = exceptionPending + var exceptionPendings : Vec[Bool] = null + override def isExceptionPending(stage : Stage): Bool = exceptionPendings(pipeline.stages.indexOf(stage)) var jumpInterface : Flow[UInt] = null var timerInterrupt, externalInterrupt, softwareInterrupt : Bool = null @@ -420,7 +420,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception jumpInterface.valid := False jumpInterface.payload.assignDontCare() - exceptionPending = False + exceptionPendings = Vec(Bool, pipeline.stages.length) timerInterrupt = in Bool() setName("timerInterrupt") externalInterrupt = in Bool() setName("externalInterrupt") softwareInterrupt = in Bool() setName("softwareInterrupt") default(False) @@ -721,7 +721,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception //Avoid the PC register of the last stage to change durring an exception handleing (Used to fill Xepc) stages.last.dontSample.getOrElseUpdate(PC, ArrayBuffer[Bool]()) += exceptionValids.last - exceptionPending setWhen(exceptionValidsRegs.orR) + exceptionPendings := exceptionValidsRegs } else null diff --git a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala index b48386c..78af84f 100644 --- a/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala +++ b/src/main/scala/vexriscv/plugin/DBusCachedPlugin.scala @@ -292,7 +292,8 @@ class DBusCachedPlugin(config : DataCacheConfig, val forceDatapath = False when(dBusAccess.cmd.valid){ decode.arbitration.haltByOther := True - when(!stagesFromExecute.map(_.arbitration.isValid).orR && !pipeline.service(classOf[ExceptionService]).isExceptionPending()){ + val exceptionService = pipeline.service(classOf[ExceptionService]) + when(!stagesFromExecute.map(s => s.arbitration.isValid || exceptionService.isExceptionPending(s)).orR){ when(!cache.io.cpu.redo) { cache.io.cpu.execute.isValid := True dBusAccess.cmd.ready := !execute.arbitration.isStuck diff --git a/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala b/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala index c713557..22afa26 100644 --- a/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/DecoderSimplePlugin.scala @@ -66,8 +66,8 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, forceLegalI } } - val defaults = mutable.HashMap[Stageable[_ <: BaseType], BaseType]() - val encodings = mutable.HashMap[MaskedLiteral,ArrayBuffer[(Stageable[_ <: BaseType], BaseType)]]() + val defaults = mutable.LinkedHashMap[Stageable[_ <: BaseType], BaseType]() + val encodings = mutable.LinkedHashMap[MaskedLiteral,ArrayBuffer[(Stageable[_ <: BaseType], BaseType)]]() var decodeExceptionPort : Flow[ExceptionCause] = null @@ -105,7 +105,7 @@ class DecoderSimplePlugin(catchIllegalInstruction : Boolean = false, forceLegalI } else { var offset = 0 var defaultValue, defaultCare = BigInt(0) - val offsetOf = mutable.HashMap[Stageable[_ <: BaseType], Int]() + val offsetOf = mutable.LinkedHashMap[Stageable[_ <: BaseType], Int]() //Build defaults value and field offset map stageables.foreach(e => { @@ -191,8 +191,8 @@ object DecodingBench extends App{ object Symplify{ - val cache = mutable.HashMap[Bits,mutable.HashMap[Masked,Bool]]() - def getCache(addr : Bits) = cache.getOrElseUpdate(addr,mutable.HashMap[Masked,Bool]()) + val cache = mutable.LinkedHashMap[Bits,mutable.LinkedHashMap[Masked,Bool]]() + def getCache(addr : Bits) = cache.getOrElseUpdate(addr,mutable.LinkedHashMap[Masked,Bool]()) //Generate terms logic for the given input def logicOf(input : Bits,terms : Seq[Masked]) = terms.map(t => getCache(input).getOrElseUpdate(t,t === input)).asBits.orR diff --git a/src/main/scala/vexriscv/plugin/HaltOnExceptionPlugin.scala b/src/main/scala/vexriscv/plugin/HaltOnExceptionPlugin.scala index fb51f10..6e39948 100644 --- a/src/main/scala/vexriscv/plugin/HaltOnExceptionPlugin.scala +++ b/src/main/scala/vexriscv/plugin/HaltOnExceptionPlugin.scala @@ -21,7 +21,7 @@ class HaltOnExceptionPlugin() extends Plugin[VexRiscv] with ExceptionService { exceptionPortsInfos += ExceptionPortInfo(interface,stage,priority) interface } - override def isExceptionPending(): Bool = False + override def isExceptionPending(stage : Stage): Bool = False override def build(pipeline: VexRiscv): Unit = { diff --git a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala index 0532d26..5b1d7ef 100644 --- a/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala +++ b/src/main/scala/vexriscv/plugin/IBusSimplePlugin.scala @@ -220,17 +220,18 @@ class IBusSimplePlugin(resetVector : BigInt, pipeline plug new FetchArea(pipeline) { var cmd = Stream(IBusSimpleCmd()) - iBus.cmd << (if(cmdForkPersistence && !cmdForkOnSecondStage) cmd.s2mPipe() else cmd) + val cmdWithS2mPipe = cmdForkPersistence && (!cmdForkOnSecondStage || mmuBus != null) + iBus.cmd << (if(cmdWithS2mPipe) cmd.s2mPipe() else cmd) //Avoid sending to many iBus cmd val pendingCmd = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0) val pendingCmdNext = pendingCmd + cmd.fire.asUInt - iBus.rsp.fire.asUInt pendingCmd := pendingCmdNext - def cmdForkStage = if(!cmdForkPersistence || !cmdForkOnSecondStage) iBusRsp.stages(if(cmdForkOnSecondStage) 1 else 0) else iBusRsp.stages(1) + val secondStagePersistence = cmdForkPersistence && cmdForkOnSecondStage && !cmdWithS2mPipe + def cmdForkStage = if(!secondStagePersistence) iBusRsp.stages(if(cmdForkOnSecondStage) 1 else 0) else iBusRsp.stages(1) - - val cmdFork = if(!cmdForkPersistence || !cmdForkOnSecondStage) new Area { + val cmdFork = if(!secondStagePersistence) new Area { //This implementation keep the cmd on the bus until it's executed or the the pipeline is flushed def stage = cmdForkStage stage.halt setWhen(stage.input.valid && (!cmd.valid || !cmd.ready)) @@ -255,7 +256,7 @@ class IBusSimplePlugin(resetVector : BigInt, mmuBus.cmd.isValid := cmdForkStage.input.valid mmuBus.cmd.virtualAddress := cmdForkStage.input.payload mmuBus.cmd.bypassTranslation := False - mmuBus.end := !cmdForkStage.output.fire || flush + mmuBus.end := cmdForkStage.output.fire || flush cmd.pc := mmuBus.rsp.physicalAddress(31 downto 2) @@ "00" @@ -265,7 +266,10 @@ class IBusSimplePlugin(resetVector : BigInt, cmd.valid := False } - cmdForkStage.halt.setWhen(mmuBus.busy) + when(mmuBus.busy){ + cmdForkStage.input.valid := False + cmdForkStage.input.ready := False + } val joinCtx = stageXToIBusRsp(cmdForkStage, mmuBus.rsp) } @@ -280,7 +284,7 @@ class IBusSimplePlugin(resetVector : BigInt, val discardCounter = Reg(UInt(log2Up(pendingMax + 1) bits)) init (0) discardCounter := discardCounter - (iBus.rsp.fire && discardCounter =/= 0).asUInt when(flush) { - if(cmdForkOnSecondStage && cmdForkPersistence) + if(secondStagePersistence) discardCounter := pendingCmd + cmd.valid.asUInt - iBus.rsp.fire.asUInt else discardCounter := (if(cmdForkOnSecondStage) pendingCmdNext else pendingCmd - iBus.rsp.fire.asUInt) @@ -318,7 +322,7 @@ class IBusSimplePlugin(resetVector : BigInt, if(memoryTranslatorPortConfig != null){ redoRequired setWhen( stages.last.input.valid && mmu.joinCtx.refilling) redoBranch.valid := redoRequired && iBusRsp.readyForError - redoBranch.payload := stages.last.input.payload + redoBranch.payload := decode.input(PC) decode.arbitration.flushAll setWhen(redoBranch.valid) } diff --git a/src/main/scala/vexriscv/plugin/MmuPlugin.scala b/src/main/scala/vexriscv/plugin/MmuPlugin.scala index f8a3418..ebf46c4 100644 --- a/src/main/scala/vexriscv/plugin/MmuPlugin.scala +++ b/src/main/scala/vexriscv/plugin/MmuPlugin.scala @@ -149,8 +149,6 @@ class MmuPlugin(ioRange : UInt => Bool, } val shared = new Area { - val busy = Reg(Bool) init(False) - val State = new SpinalEnum{ val IDLE, L1_CMD, L1_RSP, L0_CMD, L0_RSP = newElement() } @@ -182,7 +180,6 @@ class MmuPlugin(ioRange : UInt => Bool, is(State.IDLE){ for(port <- portsInfo.sortBy(_.priority)){ when(port.bus.cmd.isValid && port.bus.rsp.refilling){ - busy := True vpn(1) := port.bus.cmd.virtualAddress(31 downto 22) vpn(0) := port.bus.cmd.virtualAddress(21 downto 12) portId := port.id diff --git a/src/test/cpp/regression/main.cpp b/src/test/cpp/regression/main.cpp index 518f30c..5097a26 100644 --- a/src/test/cpp/regression/main.cpp +++ b/src/test/cpp/regression/main.cpp @@ -1634,6 +1634,7 @@ public: cout << "FAIL " << name << " at PC=" << hex << setw(8) << top->VexRiscv->writeBack_PC << dec; //<< " seed : " << seed << if(riscvRefEnable) cout << hex << " REF PC=" << riscvRef.lastPc << " REF I=" << riscvRef.lastInstruction << dec; + cout << " time=" << i; cout << endl; cycles += instanceCycles; @@ -3059,29 +3060,22 @@ public: //#endif + #include #include #include - termios stdinRestoreSettings; void stdinNonBuffered(){ static struct termios old, new1; - tcgetattr(STDIN_FILENO, &old); /* grab old terminal i/o settings */ - new1 = old; /* make new settings same as old settings */ - new1.c_lflag &= ~ICANON; /* disable buffered i/o */ + tcgetattr(STDIN_FILENO, &old); // grab old terminal i/o settings + new1 = old; // make new settings same as old settings + new1.c_lflag &= ~ICANON; // disable buffered i/o new1.c_lflag &= ~ECHO; - tcsetattr(STDIN_FILENO, TCSANOW, &new1); /* use these new terminal i/o settings now */ + tcsetattr(STDIN_FILENO, TCSANOW, &new1); // use these new terminal i/o settings now setvbuf(stdin, NULL, _IONBF, 0); stdinRestoreSettings = old; } -void stdoutNonBuffered(){ - setvbuf(stdout, NULL, _IONBF, 0); -} - -void stdinRestore(){ - tcsetattr(STDIN_FILENO, TCSANOW, &stdinRestoreSettings); /* use these new terminal i/o settings now */ -} bool stdinNonEmpty(){ struct timeval tv; @@ -3094,6 +3088,17 @@ bool stdinNonEmpty(){ return (FD_ISSET(0, &fds)); } + +void stdoutNonBuffered(){ + setvbuf(stdout, NULL, _IONBF, 0); +} + +void stdinRestore(){ + tcsetattr(STDIN_FILENO, TCSANOW, &stdinRestoreSettings); +} + + + void my_handler(int s){ printf("Caught signal %d\n",s); stdinRestore(); @@ -3111,23 +3116,39 @@ void captureCtrlC(){ sigaction(SIGINT, &sigIntHandler, NULL); } -#ifdef LINUX_SOC + + + +#if defined(LINUX_SOC) || defined(LINUX_REGRESSION) +#include class LinuxSoc : public Workspace{ public: + queue customCin; + void pushCin(string m){ + for(char& c : m) { + customCin.push(c); + } + } LinuxSoc(string name) : Workspace(name) { + #ifdef WITH_USER_IO stdinNonBuffered(); - stdoutNonBuffered(); captureCtrlC(); + #endif + stdoutNonBuffered(); } virtual ~LinuxSoc(){ + #ifdef WITH_USER_IO stdinRestore(); + #endif } virtual bool isDBusCheckedRegion(uint32_t address){ return true;} virtual bool isPerifRegion(uint32_t addr) { return (addr & 0xF0000000) == 0xF0000000 || (addr & 0xE0000000) == 0xE0000000;} virtual bool isMmuRegion(uint32_t addr) { return true; } + + virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size,uint32_t mask, uint32_t *data, bool *error) { if(isPerifRegion(addr)) switch(addr){ //TODO Emulate peripherals here @@ -3137,18 +3158,24 @@ public: case 0xFFFFFFEC: if(wr) mTimeCmp = (mTimeCmp & 0x00000000FFFFFFFF) | (((uint64_t)*data) << 32); else *data = mTimeCmp >> 32; break; case 0xFFFFFFF8: if(wr){ - cout << (char)*data; - logTraces << (char)*data; + char c = (char)*data; + cout << c; + logTraces << c; logTraces.flush(); + onStdout(c); } else { + #ifdef WITH_USER_IO if(stdinNonEmpty()){ char c; read(0, &c, 1); *data = c; - //cout << "getchar " << c << endl; + } else + #endif + if(!customCin.empty()){ + *data = customCin.front(); + customCin.pop(); } else { *data = -1; - //cout << "getchar NONE" << endl; } } break; @@ -3158,7 +3185,43 @@ public: Workspace::dBusAccess(addr,wr,size,mask,data,error); } + + virtual void onStdout(char c){ + + } }; + + +class LinuxRegression: public LinuxSoc{ +public: + string pendingLine = ""; + bool pendingLineContain(string m) { + return strstr(pendingLine.c_str(), m.c_str()) != NULL; + } + + enum State{LOGIN, ECHO_FILE, HEXDUMP, HEXDUMP_CHECK, PASS}; + State state = LOGIN; + LinuxRegression(string name) : LinuxSoc(name) { + + } + + ~LinuxRegression() { + } + + + virtual void onStdout(char c){ + pendingLine += c; + switch(state){ + case LOGIN: if (pendingLineContain("buildroot login:")) { pushCin("root\n"); state = ECHO_FILE; } break; + case ECHO_FILE: if (pendingLineContain("# ")) { pushCin("echo \"miaou\" > test.txt\n"); state = HEXDUMP; pendingLine = "";} break; + case HEXDUMP: if (pendingLineContain("# ")) { pushCin("hexdump -C test.txt\n"); state = HEXDUMP_CHECK; pendingLine = "";} break; + case HEXDUMP_CHECK: if (pendingLineContain("00000000 6d 69 61 6f 75 0a ")) { pushCin(""); state = PASS; pendingLine = "";} break; + case PASS: if (pendingLineContain("# ")) { pass(); } break; + } + if(c == '\n' || pendingLine.length() > 200) pendingLine = ""; + } +}; + #endif string riscvTestMain[] = { @@ -3490,7 +3553,7 @@ int main(int argc, char **argv, char **env) { soc.loadBin(DTB, 0xC3000000); soc.loadBin(RAMDISK, 0xC2000000); #endif - //soc.setIStall(true); //TODO It currently improve speed but should be removed later + //soc.setIStall(true); //soc.setDStall(true); soc.bootAt(0x80000000); soc.run(0); @@ -3500,6 +3563,10 @@ int main(int argc, char **argv, char **env) { } #endif + + + + // #ifdef MMU // redo(REDO,WorkspaceRegression("mmu").withRiscvRef()->loadHex("../raw/mmu/build/mmu.hex")->bootAt(0x80000000u)->run(50e3);); // #endif @@ -3722,15 +3789,36 @@ int main(int argc, char **argv, char **env) { queue > tasksSelected(std::deque>(tasks.begin(), tasks.end())); multiThreadedExecute(tasksSelected); #endif + + #if defined(LINUX_REGRESSION) + { + + LinuxRegression soc("linux"); + #ifndef DEBUG_PLUGIN_EXTERNAL + soc.withRiscvRef(); + soc.loadBin(EMULATOR, 0x80000000); + soc.loadBin(VMLINUX, 0xC0000000); + soc.loadBin(DTB, 0xC3000000); + soc.loadBin(RAMDISK, 0xC2000000); + #endif + //soc.setIStall(true); + //soc.setDStall(true); + soc.bootAt(0x80000000); + soc.run(153995602l*6); +// soc.run((470000000l + 2000000) / 2); +// soc.run(438700000l/2); + } + #endif + } 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-6) << " Khz)" << endl; if(Workspace::successCounter == Workspace::testsCounter) - cout << "SUCCESS " << Workspace::successCounter << "/" << Workspace::testsCounter << endl; + cout << "REGRESSION SUCCESS " << Workspace::successCounter << "/" << Workspace::testsCounter << endl; else - cout<< "FAILURE " << Workspace::testsCounter - Workspace::successCounter << "/" << Workspace::testsCounter << endl; + cout<< "REGRESSION FAILURE " << Workspace::testsCounter - Workspace::successCounter << "/" << Workspace::testsCounter << endl; cout << "****************************************************************" << endl << endl; diff --git a/src/test/cpp/regression/makefile b/src/test/cpp/regression/makefile index d82a3e4..9c4294f 100644 --- a/src/test/cpp/regression/makefile +++ b/src/test/cpp/regression/makefile @@ -34,6 +34,7 @@ COMPRESSED?=no SUPERVISOR?=no STOP_ON_ERROR?=no COREMARK=no +WITH_USER_IO?=no ADDCFLAGS += -CFLAGS -DIBUS_${IBUS} ADDCFLAGS += -CFLAGS -DDBUS_${DBUS} @@ -66,6 +67,31 @@ ifeq ($(LINUX_SOC),yes) ADDCFLAGS += -CFLAGS -DEMULATOR='\"$(EMULATOR)\"' endif +ARCH_LINUX=rv32i +ifeq ($(MUL),yes) +ifeq ($(DIV),yes) +ARCH_LINUX:=$(ARCH_LINUX)m +endif +endif +ARCH_LINUX:=$(ARCH_LINUX)a +ifeq ($(COMPRESSED),yes) +ARCH_LINUX:=$(ARCH_LINUX)c +endif + +ifeq ($(LINUX_REGRESSION),yes) +ifneq ($(ARCH_LINUX),rv32iac) +ifneq ($(ARCH_LINUX),rv32ia) + ADDCFLAGS += -CFLAGS -DLINUX_REGRESSION + ADDCFLAGS += -CFLAGS -DARCH_LINUX='\"$(ARCH_LINUX)\"' + ADDCFLAGS += -CFLAGS -DVMLINUX='\"../../resources/VexRiscvRegressionData/sim/linux/$(ARCH_LINUX)/Image\"' + ADDCFLAGS += -CFLAGS -DDTB='\"../../resources/VexRiscvRegressionData/sim/linux/$(ARCH_LINUX)/rv32.dtb\"' + ADDCFLAGS += -CFLAGS -DRAMDISK='\"../../resources/VexRiscvRegressionData/sim/linux/$(ARCH_LINUX)/rootfs.cpio\"' + ADDCFLAGS += -CFLAGS -DEMULATOR='\"../../resources/VexRiscvRegressionData/sim/linux/emulator/emulator.bin\"' +endif +endif +endif + + ifeq ($(FLOW_INFO),yes) ADDCFLAGS += -CFLAGS -DFLOW_INFO endif @@ -93,6 +119,10 @@ endif ifeq ($(IBUS_TC),yes) ADDCFLAGS += -CFLAGS -DIBUS_TC=yes endif +ifeq ($(WITH_USER_IO),yes) + ADDCFLAGS += -CFLAGS -DWITH_USER_IO=yes +endif + ifeq ($(COMPRESSED),yes) ADDCFLAGS += -CFLAGS -DCOMPRESSED diff --git a/src/test/resources/VexRiscvRegressionData b/src/test/resources/VexRiscvRegressionData new file mode 160000 index 0000000..77b66d3 --- /dev/null +++ b/src/test/resources/VexRiscvRegressionData @@ -0,0 +1 @@ +Subproject commit 77b66d304f888369176fb9ac2f9d6302dd4d276d diff --git a/src/test/scala/vexriscv/TestIndividualFeatures.scala b/src/test/scala/vexriscv/TestIndividualFeatures.scala index 5275cfa..034527c 100644 --- a/src/test/scala/vexriscv/TestIndividualFeatures.scala +++ b/src/test/scala/vexriscv/TestIndividualFeatures.scala @@ -49,6 +49,11 @@ object VexRiscvUniverse{ val universes = List(CATCH_ALL, MMU) } + +object Hack{ + var dCounter = 0 +} + class ShiftDimension extends VexRiscvDimension("Shift") { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = random(r, List( new VexRiscvPosition("FullLate") { @@ -287,13 +292,14 @@ class IBusDimension extends VexRiscvDimension("IBus") { override def instructionAnticipatedOk() = injectorStage } } else { + val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) val compressed = r.nextBoolean() - val tighlyCoupled = r.nextBoolean() + val tighlyCoupled = r.nextBoolean() && !catchAll // val tighlyCoupled = false val prediction = random(r, List(NONE, STATIC, DYNAMIC, DYNAMIC_TARGET)) - val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) val relaxedPcCalculation, twoCycleCache, injectorStage = r.nextBoolean() val twoCycleRam = r.nextBoolean() && twoCycleCache + val bytePerLine = List(8,16,32,64)(r.nextInt(4)) var cacheSize = 0 var wayCount = 0 do{ @@ -301,7 +307,7 @@ class IBusDimension extends VexRiscvDimension("IBus") { wayCount = 1 << r.nextInt(3) }while(cacheSize/wayCount < 512 || (catchAll && cacheSize/wayCount > 4096)) - new VexRiscvPosition("Cached" + (if(twoCycleCache) "2cc" else "") + (if(injectorStage) "Injstage" else "") + (if(twoCycleRam) "2cr" else "") + "S" + cacheSize + "W" + wayCount + (if(relaxedPcCalculation) "Relax" else "") + (if(compressed) "Rvc" else "") + prediction.getClass.getTypeName().replace("$","")+ (if(tighlyCoupled)"Tc" else "")) with InstructionAnticipatedPosition{ + new VexRiscvPosition("Cached" + (if(twoCycleCache) "2cc" else "") + (if(injectorStage) "Injstage" else "") + (if(twoCycleRam) "2cr" else "") + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine + (if(relaxedPcCalculation) "Relax" else "") + (if(compressed) "Rvc" else "") + prediction.getClass.getTypeName().replace("$","")+ (if(tighlyCoupled)"Tc" else "")) with InstructionAnticipatedPosition{ override def testParam = "IBUS=CACHED" + (if(compressed) " COMPRESSED=yes" else "") + (if(tighlyCoupled)" IBUS_TC=yes" else "") override def applyOn(config: VexRiscvConfig): Unit = { val p = new IBusCachedPlugin( @@ -313,7 +319,7 @@ class IBusDimension extends VexRiscvDimension("IBus") { memoryTranslatorPortConfig = mmuConfig, config = InstructionCacheConfig( cacheSize = cacheSize, - bytePerLine = 32, + bytePerLine = bytePerLine, wayCount = wayCount, addressWidth = 32, cpuDataWidth = 32, @@ -344,32 +350,37 @@ class DBusDimension extends VexRiscvDimension("DBus") { val mmuConfig = if(catchAll) MmuPortConfig( portTlbSize = 4) else null if(r.nextDouble() < 0.4){ + val withLrSc = catchAll val earlyInjection = r.nextBoolean() new VexRiscvPosition("Simple" + (if(earlyInjection) "Early" else "Late")) { - override def testParam = "DBUS=SIMPLE" + override def testParam = "DBUS=SIMPLE " + (if(withLrSc) "LRSC=yes " else "") override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new DBusSimplePlugin( catchAddressMisaligned = catchAll, catchAccessFault = catchAll, earlyInjection = earlyInjection, - memoryTranslatorPortConfig = mmuConfig + memoryTranslatorPortConfig = mmuConfig, + withLrSc = withLrSc ) // override def isCompatibleWith(positions: Seq[ConfigPosition[VexRiscvConfig]]) = catchAll == positions.exists(_.isInstanceOf[CatchAllPosition]) } } else { + val bytePerLine = List(8,16,32,64)(r.nextInt(4)) var cacheSize = 0 var wayCount = 0 + val withLrSc = catchAll + val withAmo = catchAll && r.nextBoolean() do{ cacheSize = 512 << r.nextInt(5) wayCount = 1 << r.nextInt(3) }while(cacheSize/wayCount < 512 || (catchAll && cacheSize/wayCount > 4096)) - new VexRiscvPosition("Cached" + "S" + cacheSize + "W" + wayCount) { - override def testParam = "DBUS=CACHED" + new VexRiscvPosition("Cached" + "S" + cacheSize + "W" + wayCount + "BPL" + bytePerLine) { + override def testParam = "DBUS=CACHED " + (if(withLrSc) "LRSC=yes " else "") + (if(withAmo) "AMO=yes " else "") override def applyOn(config: VexRiscvConfig): Unit = { config.plugins += new DBusCachedPlugin( config = new DataCacheConfig( cacheSize = cacheSize, - bytePerLine = 32, + bytePerLine = bytePerLine, wayCount = wayCount, addressWidth = 32, cpuDataWidth = 32, @@ -377,7 +388,8 @@ class DBusDimension extends VexRiscvDimension("DBus") { catchAccessError = catchAll, catchIllegal = catchAll, catchUnaligned = catchAll, - withLrSc = false + withLrSc = withLrSc, + withAmo = withAmo ), memoryTranslatorPortConfig = mmuConfig ) @@ -421,14 +433,14 @@ class MmuDimension extends VexRiscvDimension("DBus") { trait CatchAllPosition -//TODO CSR without exception + class CsrDimension(freertos : String) extends VexRiscvDimension("Csr") { override def randomPositionImpl(universes: Seq[ConfigUniverse], r: Random) = { val catchAll = universes.contains(VexRiscvUniverse.CATCH_ALL) if(catchAll){ new VexRiscvPosition("All") with CatchAllPosition{ override def applyOn(config: VexRiscvConfig): Unit = config.plugins += new CsrPlugin(CsrPluginConfig.linuxFull(0x80000020l)) - override def testParam = s"FREERTOS=$freertos" + override def testParam = s"FREERTOS=$freertos LINUX_REGRESSION=yes SUPERVISOR=yes" } } else if(r.nextDouble() < 0.2){ new VexRiscvPosition("AllNoException") with CatchAllPosition{ @@ -504,7 +516,7 @@ class TestIndividualFeatures extends FunSuite { new HazardDimension, new RegFileDimension, new SrcDimension, - new CsrDimension(sys.env.getOrElse("VEXRISCV_REGRESSION_FREERTOS_COUNT", "yes")), + new CsrDimension("no"),//sys.env.getOrElse("VEXRISCV_REGRESSION_FREERTOS_COUNT", "4")), TODO new DecoderDimension, new DebugDimension, new MmuDimension @@ -541,14 +553,14 @@ class TestIndividualFeatures extends FunSuite { test(prefix + name + "_test") { - val debug = false - val stdCmd = (if(debug) "make clean run REDO=1 TRACE=yes TRACE_ACCESS=yes STOP_ON_ERROR=yes DHRYSTONE=no THREAD_COUNT=1 TRACE_START=0 " else s"make clean run REDO=10 TRACE=no THREAD_COUNT=${sys.env.getOrElse("VEXRISCV_REGRESSION_THREAD_COUNT", Runtime.getRuntime().availableProcessors().toString)} ") + s" SEED=${testSeed} " + val debug = true + val stdCmd = (s"make clean run WITH_USER_IO=no REDO=10 TRACE=${if(debug) "yes" else "no"} TRACE_START=9999924910246l FLOW_INFO=no STOP_ON_ERROR=no DHRYSTONE=yes COREMARK=yes THREAD_COUNT=${sys.env.getOrElse("VEXRISCV_REGRESSION_THREAD_COUNT", Runtime.getRuntime().availableProcessors().toString)} ") + s" SEED=${testSeed} " // val stdCmd = "make clean run REDO=40 DHRYSTONE=no STOP_ON_ERROR=yes TRACE=yess " val testCmd = stdCmd + (positionsToApply).map(_.testParam).mkString(" ") println(testCmd) val str = doCmd(testCmd) - assert(!str.contains("FAIL") && !str.contains("Broken pipe")) + assert(str.contains("REGRESSION SUCCESS") && !str.contains("Broken pipe")) // val intFind = "(\\d+\\.?)+".r // val dmips = intFind.findFirstIn("DMIPS per Mhz\\: (\\d+.?)+".r.findAllIn(str).toList.last).get.toDouble } @@ -556,8 +568,8 @@ class TestIndividualFeatures extends FunSuite { // dimensions.foreach(d => d.positions.foreach(p => p.dimension = d)) -// val testId : Option[mutable.HashSet[Int]] = None -// val seed = Random.nextLong() + val testId : Option[mutable.HashSet[Int]] = None + val seed = Random.nextLong() // val testId = Some(mutable.HashSet(18,34,77,85,118,129,132,134,152,167,175,188,191,198,199)) //37/29 sp_flop_rv32i_O3 //val testId = Some(mutable.HashSet(18)) @@ -565,13 +577,6 @@ class TestIndividualFeatures extends FunSuite { // val seed = -2412372746600605141l -//// val testId = Some(mutable.HashSet[Int](0,28,45,93)) - val testId = Some(mutable.HashSet[Int](69, 43)) -//val testId = Some(mutable.HashSet[Int]( 43)) - val seed = -8485282932516819277l - - - val rand = new Random(seed) test("Info"){ @@ -589,6 +594,7 @@ class TestIndividualFeatures extends FunSuite { val testSeed = rand.nextInt() if(testId.isEmpty || testId.get.contains(i)) doTest(positions," random_" + i + "_", testSeed) + Hack.dCounter += 1 } // println(s"${usedPositions.size}/$positionsCount positions")