aboutsummaryrefslogtreecommitdiff
path: root/VexRiscv/src/test/cpp/regression/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'VexRiscv/src/test/cpp/regression/main.cpp')
-rw-r--r--VexRiscv/src/test/cpp/regression/main.cpp4514
1 files changed, 4514 insertions, 0 deletions
diff --git a/VexRiscv/src/test/cpp/regression/main.cpp b/VexRiscv/src/test/cpp/regression/main.cpp
new file mode 100644
index 0000000..3d61c9a
--- /dev/null
+++ b/VexRiscv/src/test/cpp/regression/main.cpp
@@ -0,0 +1,4514 @@
+#include "VVexRiscv.h"
+#include "VVexRiscv_VexRiscv.h"
+#ifdef REF
+#include "VVexRiscv_RiscvCore.h"
+#endif
+#include "verilated.h"
+#include "verilated_fst_c.h"
+#include <stdio.h>
+#include <iostream>
+#include <stdlib.h>
+#include <stdint.h>
+#include <cstring>
+#include <string.h>
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <mutex>
+#include <iomanip>
+#include <queue>
+#include <time.h>
+#include "encoding.h"
+
+#define VL_RANDOM_I_WIDTH(w) (VL_RANDOM_I() & (1l << w)-1l)
+
+using namespace std;
+
+struct timespec timer_get(){
+ struct timespec start_time;
+ clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_time);
+ return start_time;
+}
+
+class Memory{
+public:
+ uint8_t* mem[1 << 12];
+
+ Memory(){
+ for(uint32_t i = 0;i < (1 << 12);i++) mem[i] = NULL;
+ }
+ ~Memory(){
+ for(uint32_t i = 0;i < (1 << 12);i++) if(mem[i]) delete [] mem[i];
+ }
+
+ uint8_t* get(uint32_t address){
+ if(mem[address >> 20] == NULL) {
+ uint8_t* ptr = new uint8_t[1024*1024];
+ for(uint32_t i = 0;i < 1024*1024;i+=4) {
+ ptr[i + 0] = 0xFF;
+ ptr[i + 1] = 0xFF;
+ ptr[i + 2] = 0xFF;
+ ptr[i + 3] = 0xFF;
+ }
+ mem[address >> 20] = ptr;
+ }
+ return &mem[address >> 20][address & 0xFFFFF];
+ }
+
+ void read(uint32_t address,uint32_t length, uint8_t *data){
+ for(int i = 0;i < length;i++){
+ data[i] = (*this)[address + i];
+ }
+ }
+
+ void write(uint32_t address,uint32_t length, uint8_t *data){
+ for(int i = 0;i < length;i++){
+ (*this)[address + i] = data[i];
+ }
+ }
+
+ uint8_t& operator [](uint32_t address) {
+ return *get(address);
+ }
+
+ /*T operator [](uint32_t address) const {
+ return get(address);
+ }*/
+};
+
+//uint8_t memory[1024 * 1024];
+
+uint32_t hti(char c) {
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ return c - '0';
+}
+
+uint32_t hToI(char *c, uint32_t size) {
+ uint32_t value = 0;
+ for (uint32_t i = 0; i < size; i++) {
+ value += hti(c[i]) << ((size - i - 1) * 4);
+ }
+ return value;
+}
+
+void loadHexImpl(string path,Memory* mem) {
+ FILE *fp = fopen(&path[0], "r");
+ if(fp == 0){
+ cout << path << " not found" << endl;
+ }
+ //Preload 0x0 <-> 0x80000000 jumps
+ ((uint32_t*)mem->get(0))[0] = 0x800000b7;
+ ((uint32_t*)mem->get(0))[1] = 0x000080e7;
+ ((uint32_t*)mem->get(0x80000000))[0] = 0x00000097;
+
+ fseek(fp, 0, SEEK_END);
+ uint32_t size = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+ char* content = new char[size];
+ fread(content, 1, size, fp);
+ fclose(fp);
+
+ int offset = 0;
+ char* line = content;
+ while (1) {
+ if (line[0] == ':') {
+ uint32_t byteCount = hToI(line + 1, 2);
+ uint32_t nextAddr = hToI(line + 3, 4) + offset;
+ uint32_t key = hToI(line + 7, 2);
+// printf("%d %d %d\n", byteCount, nextAddr,key);
+ switch (key) {
+ case 0:
+ for (uint32_t i = 0; i < byteCount; i++) {
+ *(mem->get(nextAddr + i)) = hToI(line + 9 + i * 2, 2);
+ //printf("%x %x %c%c\n",nextAddr + i,hToI(line + 9 + i*2,2),line[9 + i * 2],line[9 + i * 2+1]);
+ }
+ break;
+ case 2:
+// cout << offset << endl;
+ offset = hToI(line + 9, 4) << 4;
+ break;
+ case 4:
+// cout << offset << endl;
+ offset = hToI(line + 9, 4) << 16;
+ break;
+ default:
+// cout << "??? " << key << endl;
+ break;
+ }
+ }
+
+ while (*line != '\n' && size != 0) {
+ line++;
+ size--;
+ }
+ if (size <= 1)
+ break;
+ line++;
+ size--;
+ }
+
+ delete [] content;
+}
+
+void loadBinImpl(string path,Memory* mem, uint32_t offset) {
+ FILE *fp = fopen(&path[0], "r");
+ if(fp == 0){
+ cout << path << " not found" << endl;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ uint32_t size = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+ char* content = new char[size];
+ fread(content, 1, size, fp);
+ fclose(fp);
+
+ for(int byteId = 0; byteId < size;byteId++){
+ *(mem->get(offset + byteId)) = content[byteId];
+ }
+
+ delete [] content;
+}
+
+
+
+#define TEXTIFY(A) #A
+
+void breakMe(){
+ int a = 0;
+}
+#define assertEq(x,ref) if(x != ref) {\
+ printf("\n*** %s is %d but should be %d ***\n\n",TEXTIFY(x),x,ref);\
+ breakMe();\
+ throw std::exception();\
+}
+
+class success : public std::exception { };
+
+
+
+
+#define MVENDORID 0xF11 // MRO Vendor ID.
+#define MARCHID 0xF12 // MRO Architecture ID.
+#define MIMPID 0xF13 // MRO Implementation ID.
+#define MHARTID 0xF14 // MRO Hardware thread ID.Machine Trap Setup
+#define MSTATUS 0x300 // MRW Machine status register.
+#define MISA 0x301 // MRW ISA and extensions
+#define MEDELEG 0x302 // MRW Machine exception delegation register.
+#define MIDELEG 0x303 // MRW Machine interrupt delegation register.
+#define MIE 0x304 // MRW Machine interrupt-enable register.
+#define MTVEC 0x305 // MRW Machine trap-handler base address. Machine Trap Handling
+#define MSCRATCH 0x340 // MRW Scratch register for machine trap handlers.
+#define MEPC 0x341 // MRW Machine exception program counter.
+#define MCAUSE 0x342 // MRW Machine trap cause.
+#define MBADADDR 0x343 // MRW Machine bad address.
+#define MIP 0x344 // MRW Machine interrupt pending.
+#define MBASE 0x380 // MRW Base register.
+#define MBOUND 0x381 // MRW Bound register.
+#define MIBASE 0x382 // MRW Instruction base register.
+#define MIBOUND 0x383 // MRW Instruction bound register.
+#define MDBASE 0x384 // MRW Data base register.
+#define MDBOUND 0x385 // MRW Data bound register.
+#define MCYCLE 0xB00 // MRW Machine cycle counter.
+#define MINSTRET 0xB02 // MRW Machine instructions-retired counter.
+#define MCYCLEH 0xB80 // MRW Upper 32 bits of mcycle, RV32I only.
+#define MINSTRETH 0xB82 // MRW Upper 32 bits of minstret, RV32I only.
+
+
+#define SSTATUS 0x100
+#define SIE 0x104
+#define STVEC 0x105
+#define SCOUNTEREN 0x106
+#define SSCRATCH 0x140
+#define SEPC 0x141
+#define SCAUSE 0x142
+#define STVAL 0x143
+#define SIP 0x144
+#define SATP 0x180
+
+#define UTIME 0xC01 // rdtime
+#define UTIMEH 0xC81
+
+#define SSTATUS_SIE 0x00000002
+#define SSTATUS_SPIE 0x00000020
+#define SSTATUS_SPP 0x00000100
+
+#ifdef SUPERVISOR
+#define MSTATUS_READ_MASK 0xFFFFFFFF
+#else
+#define MSTATUS_READ_MASK 0x7888
+#endif
+
+#ifdef RVF
+#define STATUS_FS_MASK 0x6000
+#else
+#define STATUS_FS_MASK 0x0000
+#endif
+
+#define FFLAGS 0x1
+#define FRM 0x2
+#define FCSR 0x3
+
+#define u32 uint32_t
+#define u64 uint64_t
+
+class FpuRsp{
+public:
+ u32 flags;
+ u64 value;
+};
+
+class FpuCommit{
+public:
+ u64 value;
+};
+
+class FpuCompletion{
+public:
+ u32 flags;
+};
+
+
+bool fpuCommitLut[32] = {true,true,true,true,true,true,false,false,true,false,false,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,false,false,false,true,false};
+bool fpuRspLut[32] = {false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,false,false,false,true,false,false,false,true,false,false,false};
+bool fpuRs1Lut[32] = {false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,false,false,false,true,false};
+class RiscvGolden {
+public:
+ int32_t pc, lastPc;
+ uint32_t lastInstruction;
+ int32_t regs[32];
+ uint64_t stepCounter;
+
+ uint32_t mscratch, sscratch;
+ uint32_t misa;
+ uint32_t privilege;
+
+ uint32_t medeleg;
+ uint32_t mideleg;
+
+ queue<FpuRsp> fpuRsp;
+ queue<FpuCommit> fpuCommit;
+ queue<FpuCompletion> fpuCompletion;
+
+ union status {
+ uint32_t raw;
+ struct {
+ uint32_t _1a : 1;
+ uint32_t sie : 1;
+ uint32_t _1b : 1;
+ uint32_t mie : 1;
+ uint32_t _2a : 1;
+ uint32_t spie : 1;
+ uint32_t _2b : 1;
+ uint32_t mpie : 1;
+ uint32_t spp : 1;
+ uint32_t _3 : 2;
+ uint32_t mpp : 2;
+ uint32_t fs : 2;
+ uint32_t _4 : 2;
+ uint32_t mprv : 1;
+ uint32_t sum : 1;
+ uint32_t mxr : 1;
+ };
+ }__attribute__((packed)) status;
+
+
+
+ uint32_t ipInput;
+ uint32_t ipSoft;
+ union IpOr {
+ uint32_t raw;
+ struct {
+ uint32_t _1a : 1;
+ uint32_t ssip : 1;
+ uint32_t _1b : 1;
+ uint32_t msip : 1;
+ uint32_t _2a : 1;
+ uint32_t stip : 1;
+ uint32_t _2b : 1;
+ uint32_t mtip : 1;
+ uint32_t _3a : 1;
+ uint32_t seip : 1;
+ uint32_t _3b : 1;
+ uint32_t meip : 1;
+ };
+ }__attribute__((packed));
+
+ IpOr getIp(){
+ IpOr ret;
+ ret.raw = ipSoft | ipInput;
+ return ret;
+ }
+
+ union mie {
+ uint32_t raw;
+ struct {
+ uint32_t _1a : 1;
+ uint32_t ssie : 1;
+ uint32_t _1b : 1;
+ uint32_t msie : 1;
+ uint32_t _2a : 1;
+ uint32_t stie : 1;
+ uint32_t _2b : 1;
+ uint32_t mtie : 1;
+ uint32_t _3a : 1;
+ uint32_t seie : 1;
+ uint32_t _3b : 1;
+ uint32_t meie : 1;
+ };
+ }__attribute__((packed)) ie;
+
+ union Xtvec {
+ uint32_t raw;
+ struct __attribute__((packed)) {
+ uint32_t _1 : 2;
+ uint32_t base : 30;
+ };
+ };
+
+ Xtvec mtvec, stvec;
+
+
+
+ union mcause {
+ uint32_t raw;
+ struct __attribute__((packed)) {
+ uint32_t exceptionCode : 31;
+ uint32_t interrupt : 1;
+ };
+ } mcause;
+
+
+ union scause {
+ uint32_t raw;
+ struct __attribute__((packed)){
+ uint32_t exceptionCode : 31;
+ uint32_t interrupt : 1;
+ };
+ } scause;
+
+ union satp {
+ uint32_t raw;
+ struct __attribute__((packed)){
+ uint32_t ppn : 22;
+ uint32_t _x : 9;
+ uint32_t mode : 1;
+ };
+ }satp;
+
+ union Tlb {
+ uint32_t raw;
+ struct __attribute__((packed)){
+ uint32_t v : 1;
+ uint32_t r : 1;
+ uint32_t w : 1;
+ uint32_t x : 1;
+ uint32_t u : 1;
+ uint32_t _dummy : 5;
+ uint32_t ppn : 22;
+ };
+ struct __attribute__((packed)){
+ uint32_t _dummyX : 10;
+ uint32_t ppn0 : 10;
+ uint32_t ppn1 : 12;
+ };
+ };
+
+ union fcsr {
+ uint32_t raw;
+ struct __attribute__((packed)){
+ uint32_t flags : 5;
+ uint32_t frm : 3;
+ };
+ }fcsr;
+
+
+ bool lrscReserved;
+ uint32_t lrscReservedAddress;
+ u32 fpuCompletionTockens;
+ u32 dutRfWriteValue;
+
+ RiscvGolden() {
+ pc = 0x80000000;
+ regs[0] = 0;
+ for (int i = 0; i < 32; i++)
+ regs[i] = 0;
+
+ ie.raw = 0;
+ mtvec.raw = 0x80000020;
+ mcause.raw = 0;
+ mbadaddr = 0;
+ mepc = 0;
+ misa = 0x40041101; //TODO
+ status.raw = 0;
+ status.mpp = 3;
+ status.spp = 1;
+ #ifdef RVF
+ status.fs = 1;
+ misa |= 1 << 5;
+ #endif
+ #ifdef RVD
+ misa |= 1 << 3;
+ #endif
+ fcsr.flags = 0;
+ fcsr.frm = 0;
+ privilege = 3;
+ medeleg = 0;
+ mideleg = 0;
+ satp.mode = 0;
+ ipSoft = 0;
+ ipInput = 0;
+ stepCounter = 0;
+ sbadaddr = 42;
+ lrscReserved = false;
+ fpuCompletionTockens = 0;
+ }
+
+ virtual void rfWrite(int32_t address, int32_t data) {
+ if (address != 0)
+ regs[address] = data;
+ }
+
+ virtual void pcWrite(int32_t target) {
+ if(isPcAligned(target)){
+ lastPc = pc;
+ pc = target;
+ } else {
+ trap(0, 0, target);
+ }
+ }
+ uint32_t mbadaddr, sbadaddr;
+ uint32_t mepc, sepc;
+
+ virtual bool iRead(int32_t address, uint32_t *data) = 0;
+ virtual bool dRead(int32_t address, int32_t size, uint8_t *data) = 0;
+ virtual void dWrite(int32_t address, int32_t size, uint8_t *data) = 0;
+
+ enum AccessKind {READ,WRITE,EXECUTE,READ_WRITE};
+ virtual bool isMmuRegion(uint32_t v) = 0;
+ bool v2p(uint32_t v, uint32_t *p, AccessKind kind){
+ uint32_t effectivePrivilege = status.mprv && kind != EXECUTE ? status.mpp : privilege;
+ if(effectivePrivilege == 3 || satp.mode == 0 || !isMmuRegion(v)){
+ *p = v;
+ } else {
+ Tlb tlb;
+ dRead((satp.ppn << 12) | ((v >> 22) << 2), 4, (uint8_t*)&tlb.raw);
+ if(!tlb.v) return true;
+ bool superPage = true;
+ if(!tlb.x && !tlb.r && !tlb.w){
+ dRead((tlb.ppn << 12) | (((v >> 12) & 0x3FF) << 2), 4, (uint8_t*)&tlb.raw);
+ if(!tlb.v) return true;
+ superPage = false;
+ }
+ if(!tlb.u && effectivePrivilege == 0) return true;
+ if( tlb.u && effectivePrivilege == 1 && !status.sum) return true;
+ if(superPage && tlb.ppn0 != 0) return true;
+ if(kind == READ || kind == READ_WRITE) if(!tlb.r && !(status.mxr && tlb.x)) return true;
+ if(kind == WRITE || kind == READ_WRITE) if(!tlb.w) return true;
+ if(kind == EXECUTE) if(!tlb.x) return true;
+
+ *p = (tlb.ppn1 << 22) | (superPage ? v & 0x3FF000 : tlb.ppn0 << 12) | (v & 0xFFF);
+ }
+ return false;
+ }
+
+ void trap(bool interrupt,int32_t cause) {
+ trap(interrupt, cause, false, 0);
+ }
+ void trap(bool interrupt,int32_t cause, uint32_t value) {
+ trap(interrupt, cause, true, value);
+ }
+ void trap(bool interrupt,int32_t cause, bool valueWrite, uint32_t value) {
+#ifdef FLOW_INFO
+// cout << "TRAP " << (interrupt ? "interrupt" : "exception") << " cause=" << cause << " PC=0x" << hex << pc << " val=0x" << hex << value << dec << endl;
+// if(cause == 9){
+// cout << hex << " a7=0x" << regs[17] << " a0=0x" << regs[10] << " a1=0x" << regs[11] << " a2=0x" << regs[12] << dec << endl;
+// }
+#endif
+ //Check leguality of the interrupt
+ if(interrupt) {
+ bool hit = false;
+ for(int i = 0;i < 5;i++){
+ if(pendingInterrupts[i] == 1 << cause){
+ hit = true;
+ break;
+ }
+ }
+ if(!hit){
+ cout << "DUT had trigger an interrupts which wasn't by the REF" << endl;
+ fail();
+ }
+ }
+
+ uint32_t deleg = interrupt ? mideleg : medeleg;
+ uint32_t targetPrivilege = 3;
+ if(deleg & (1 << cause)) targetPrivilege = 1;
+ targetPrivilege = max(targetPrivilege, privilege);
+ Xtvec xtvec = targetPrivilege == 3 ? mtvec : stvec;
+
+
+
+ switch(targetPrivilege){
+ case 3:
+ if(valueWrite) mbadaddr = value;
+ mcause.interrupt = interrupt;
+ mcause.exceptionCode = cause;
+ status.mpie = status.mie;
+ status.mie = false;
+ status.mpp = privilege;
+ mepc = pc;
+ break;
+ case 1:
+ if(valueWrite) sbadaddr = value;
+ scause.interrupt = interrupt;
+ scause.exceptionCode = cause;
+ status.spie = status.sie;
+ status.sie = false;
+ status.spp = privilege;
+ sepc = pc;
+ break;
+ }
+
+ privilege = targetPrivilege;
+ pcWrite(xtvec.base << 2);
+ if(interrupt) livenessInterrupt = 0;
+
+// if(!interrupt) step(); //As VexRiscv instruction which trap do not reach writeback stage fire
+ }
+
+ uint32_t currentInstruction;
+ void ilegalInstruction(){
+ trap(0, 2, currentInstruction);
+ }
+
+ virtual void fail() {
+ }
+
+
+
+ virtual bool csrRead(int32_t csr, uint32_t *value){
+ if(((csr >> 8) & 0x3) > privilege) return true;
+ switch(csr){
+ case MSTATUS: *value = (status.raw | (((status.raw & 0x6000) == 0x6000) ? 0x80000000 : 0)) & MSTATUS_READ_MASK; break;
+ case MIP: *value = getIp().raw; break;
+ case MIE: *value = ie.raw; break;
+ case MTVEC: *value = mtvec.raw; break;
+ case MCAUSE: *value = mcause.raw; break;
+ case MBADADDR: *value = mbadaddr; break;
+ case MEPC: *value = mepc; break;
+ case MSCRATCH: *value = mscratch; break;
+ case MISA: *value = misa; break;
+ case MEDELEG: *value = medeleg; break;
+ case MIDELEG: *value = mideleg; break;
+ case MHARTID: *value = 0; break;
+
+ case SSTATUS: *value = (status.raw | (((status.raw & 0x6000) == 0x6000) ? 0x80000000 : 0)) & (0x800C0133 | STATUS_FS_MASK); break;
+ case SIP: *value = getIp().raw & 0x333; break;
+ case SIE: *value = ie.raw & 0x333; break;
+ case STVEC: *value = stvec.raw; break;
+ case SCAUSE: *value = scause.raw; break;
+ case STVAL: *value = sbadaddr; break;
+ case SEPC: *value = sepc; break;
+ case SSCRATCH: *value = sscratch; break;
+ case SATP: *value = satp.raw; break;
+
+ #ifdef RVF
+ case FCSR: *value = fcsr.raw; break;
+ case FRM: *value = fcsr.frm; break;
+ case FFLAGS: *value = fcsr.flags; break;
+ #endif
+
+ #ifdef UTIME_INPUT
+ case UTIME: *value = dutRfWriteValue; break;
+ case UTIMEH: *value = dutRfWriteValue; break;
+ #endif
+
+ default: return true; break;
+ }
+ return false;
+ }
+
+ virtual uint32_t csrReadToWriteOverride(int32_t csr, uint32_t value){
+ if(((csr >> 8) & 0x3) > privilege) return true;
+ switch(csr){
+ case MIP: return ipSoft; break;
+ case SIP: return ipSoft & 0x333; break;
+ };
+ return value;
+ }
+
+ #define maskedWrite(dst, src, mask) dst=((dst) & ~(mask))|((src) & (mask));
+
+ virtual bool csrWrite(int32_t csr, uint32_t value){
+ if(((csr >> 8) & 0x3) > privilege) return true;
+ switch(csr){
+ case MSTATUS: status.raw = value & 0x7FFFFFFF; break;
+ case MIP: ipSoft = value; break;
+ case MIE: ie.raw = value; break;
+ case MTVEC: mtvec.raw = value; break;
+ case MCAUSE: mcause.raw = value; break;
+ case MBADADDR: mbadaddr = value; break;
+ case MEPC: mepc = value; break;
+ case MSCRATCH: mscratch = value; break;
+ case MISA: misa = value; break;
+ case MEDELEG: medeleg = value & (~0x8); break;
+ case MIDELEG: mideleg = value; break;
+
+ case SSTATUS: maskedWrite(status.raw, value, 0xC0133 | STATUS_FS_MASK); break;
+ case SIP: maskedWrite(ipSoft, value,0x333); break;
+ case SIE: maskedWrite(ie.raw, value,0x333); break;
+ case STVEC: stvec.raw = value; break;
+ case SCAUSE: scause.raw = value; break;
+ case STVAL: sbadaddr = value; break;
+ case SEPC: sepc = value; break;
+ case SSCRATCH: sscratch = value; break;
+ case SATP: satp.raw = value; break;
+
+ #ifdef RVF
+ case FCSR: fcsr.raw = value & 0x7F; break;
+ case FRM: fcsr.frm = value; break;
+ case FFLAGS: fcsr.flags = value; break;
+ #endif
+
+ default: ilegalInstruction(); return true; break;
+ }
+ return false;
+ }
+
+
+ int livenessStep = 0;
+ int livenessInterrupt = 0;
+ uint32_t pendingInterruptsPtr = 0;
+ uint32_t pendingInterrupts[5] = {0,0,0,0,0};
+ virtual void liveness(bool inWfi){
+ uint32_t pendingInterrupt = getPendingInterrupt();
+ pendingInterrupts[pendingInterruptsPtr++] = getPendingInterrupt();
+ if(pendingInterruptsPtr >= 5) pendingInterruptsPtr = 0;
+ if(pendingInterrupt) livenessInterrupt++; else livenessInterrupt = 0;
+ if(!inWfi) livenessStep++; else livenessStep = 0;
+
+ if(livenessStep > 10000){
+ cout << "Liveness step failure" << endl;
+ fail();
+ }
+
+ if(livenessInterrupt > 1000){
+ cout << "Liveness interrupt failure" << endl;
+ fail();
+ }
+ }
+
+
+ uint32_t getPendingInterrupt(){
+ uint32_t mEnabled = status.mie && privilege == 3 || privilege < 3;
+ uint32_t sEnabled = status.sie && privilege == 1 || privilege < 1;
+
+ uint32_t masked = getIp().raw & ~mideleg & -mEnabled & ie.raw;
+ if (masked == 0)
+ masked = getIp().raw & mideleg & -sEnabled & ie.raw & 0x333;
+
+ if (masked) {
+ if (masked & MIP_MEIP)
+ masked &= MIP_MEIP;
+ else if (masked & MIP_MSIP)
+ masked &= MIP_MSIP;
+ else if (masked & MIP_MTIP)
+ masked &= MIP_MTIP;
+ else if (masked & MIP_SEIP)
+ masked &= MIP_SEIP;
+ else if (masked & MIP_SSIP)
+ masked &= MIP_SSIP;
+ else if (masked & MIP_STIP)
+ masked &= MIP_STIP;
+ else
+ fail();
+ }
+
+ return masked;
+ }
+
+
+ bool isPcAligned(uint32_t pc){
+#ifdef COMPRESSED
+ return (pc & 1) == 0;
+#else
+ return (pc & 3) == 0;
+#endif
+ }
+
+
+
+ virtual void step() {
+ stepCounter++;
+ livenessStep = 0;
+
+ while(fpuCompletionTockens != 0 && !fpuCompletion.empty()){
+ FpuCompletion completion = fpuCompletion.front(); fpuCompletion.pop();
+ fcsr.flags |= completion.flags;
+ fpuCompletionTockens -= 1;
+ }
+
+
+ #define rd32 ((i >> 7) & 0x1F)
+ #define iBits(lo, len) ((i >> lo) & ((1 << len)-1))
+ #define iBitsSigned(lo, len) int32_t(i) << (32-lo-len) >> (32-len)
+ #define iSign() iBitsSigned(31, 1)
+ #define i32_rs1 regs[(i >> 15) & 0x1F]
+ #define i32_rs2 regs[(i >> 20) & 0x1F]
+ #define i32_i_imm (int32_t(i) >> 20)
+ #define i32_s_imm (iBits(7, 5) + (iBitsSigned(25, 7) << 5))
+ #define i32_shamt ((i >> 20) & 0x1F)
+ #define i32_sb_imm ((iBits(8, 4) << 1) + (iBits(25,6) << 5) + (iBits(7,1) << 11) + (iSign() << 12))
+ #define i32_csr iBits(20, 12)
+ #define i32_func3 iBits(12, 3)
+ #define i32_func7 iBits(25, 7)
+ #define i16_addi4spn_imm ((iBits(6, 1) << 2) + (iBits(5, 1) << 3) + (iBits(11, 2) << 4) + (iBits(7, 4) << 6))
+ #define i16_lw_imm ((iBits(6, 1) << 2) + (iBits(10, 3) << 3) + (iBits(5, 1) << 6))
+ #define i16_addr2 (iBits(2,3) + 8)
+ #define i16_addr1 (iBits(7,3) + 8)
+ #define i16_rf1 regs[i16_addr1]
+ #define i16_rf2 regs[i16_addr2]
+ #define rf_sp regs[2]
+ #define i16_imm (iBits(2, 5) + (iBitsSigned(12, 1) << 5))
+ #define i16_j_imm ((iBits(3, 3) << 1) + (iBits(11, 1) << 4) + (iBits(2, 1) << 5) + (iBits(7, 1) << 6) + (iBits(6, 1) << 7) + (iBits(9, 2) << 8) + (iBits(8, 1) << 10) + (iBitsSigned(12, 1) << 11))
+ #define i16_addi16sp_imm ((iBits(6, 1) << 4) + (iBits(2, 1) << 5) + (iBits(5, 1) << 6) + (iBits(3, 2) << 7) + (iBitsSigned(12, 1) << 9))
+ #define i16_zimm (iBits(2, 5))
+ #define i16_b_imm ((iBits(3, 2) << 1) + (iBits(10, 2) << 3) + (iBits(2, 1) << 5) + (iBits(5, 2) << 6) + (iBitsSigned(12, 1) << 8))
+ #define i16_lwsp_imm ((iBits(4, 3) << 2) + (iBits(12, 1) << 5) + (iBits(2, 2) << 6))
+ #define i16_swsp_imm ((iBits(9, 4) << 2) + (iBits(7, 2) << 6))
+ uint32_t i;
+ uint32_t u32Buf;
+ uint32_t pAddr;
+ if (pc & 2) {
+ if(v2p(pc - 2, &pAddr, EXECUTE)){ trap(0, 12, pc - 2); return; }
+ if(iRead(pAddr, &i)){
+ trap(0, 1, 0);
+ return;
+ }
+ i >>= 16;
+ if ((i & 3) == 3) {
+ uint32_t u32Buf;
+ if(v2p(pc + 2, &pAddr, EXECUTE)){ trap(0, 12, pc + 2); return; }
+ if(iRead(pAddr, &u32Buf)){
+ trap(0, 1, 0);
+ return;
+ }
+ i |= u32Buf << 16;
+ }
+ } else {
+ if(v2p(pc, &pAddr, EXECUTE)){ trap(0, 12, pc); return; }
+ if(iRead(pAddr, &i)){
+ trap(0, 1, 0);
+ return;
+ }
+ }
+ lastInstruction = i;
+ currentInstruction = i;
+ if ((i & 0x3) == 0x3) {
+ //32 bit
+ switch (i & 0x7F) {
+ #ifdef RVF
+ case 0x43:// RVFD
+ case 0x47:
+ case 0x4B:
+ case 0x4F:
+ case 0x53: {
+ u32 format = iBits(25,2);
+ u32 opcode = iBits(27,5);
+ bool withCommit = fpuCommitLut[opcode];
+ bool withRsp = fpuRspLut[opcode];
+ bool withRs1 = fpuRs1Lut[opcode];
+ if((i & 0x7F) != 0x53) { // FMADD
+ withCommit = true;
+ withRsp = false;
+ }
+ #ifdef RVD
+ if(format > 1) ilegalInstruction();
+ #else
+ if(format > 0) ilegalInstruction();
+ #endif
+
+ if(withCommit){
+ FpuCommit commit = fpuCommit.front(); fpuCommit.pop();
+ fpuCompletionTockens += 1;
+// cout << "withRs1 " << withRs1 << " " << opcode << endl;
+ if(withRs1 && memcmp(&i32_rs1, &commit.value, 4)){
+ cout << "FPU commit missmatch DUT=" << hex << commit.value << " REF=" << i32_rs1 << dec << endl;
+ fail();
+ return;
+ }
+ }
+ if(withRsp){
+ auto rsp = fpuRsp.front(); fpuRsp.pop();
+ fcsr.flags |= rsp.flags;
+ rfWrite(rd32, (u32)rsp.value);
+ }
+ status.fs = 3;
+ pcWrite(pc + 4);
+ } break;
+ case 0x07: { //Fpu load
+ uint32_t size = 1 << ((i >> 12) & 0x3);
+ if(size < 4) ilegalInstruction();
+ #ifdef RVD
+ if(size > 8) ilegalInstruction();
+ #else
+ if(format > 4) ilegalInstruction();
+ #endif
+ auto commit = fpuCommit.front(); fpuCommit.pop();
+ fpuCompletionTockens += 1;
+
+
+ uint64_t data = 0;
+ uint32_t address = i32_rs1 + i32_i_imm;
+ if(address & (size-1)){
+ trap(0, 4, address);
+ } else {
+ if(v2p(address, &pAddr, READ)){ trap(0, 13, address); return; }
+ if(dRead(pAddr, size, (uint8_t*)&data)){
+ trap(0, 5, address);
+ } else {
+ if(memcmp(&data, &commit.value, size)){
+ cout << "FPU load missmatch DUT=" << hex << commit.value << " REF=" << data << dec << endl;
+ fail();
+ } else {
+ status.fs = 3;
+ pcWrite(pc + 4);
+ }
+ }
+ }
+ } break;
+ case 0x27: { //Fpu store
+ uint32_t size = 1 << ((i >> 12) & 0x3);
+ if(size < 4) ilegalInstruction();
+ #ifdef RVD
+ if(size > 8) ilegalInstruction();
+ #else
+ if(format > 4) ilegalInstruction();
+ #endif
+
+ auto rsp = fpuRsp.front(); fpuRsp.pop();
+ fcsr.flags |= rsp.flags;
+ uint32_t address = i32_rs1 + i32_s_imm;
+ if(address & (size-1)){
+ trap(0, 6, address);
+ } else {
+ if(v2p(address, &pAddr, WRITE)){ trap(0, 15, address); return; }
+ dWrite(pAddr, size, (uint8_t*) &rsp.value);
+ status.fs = 3;
+ pcWrite(pc + 4);
+ lrscReserved = false;
+ }
+ } break;
+ #endif
+ case 0x37:rfWrite(rd32, i & 0xFFFFF000);pcWrite(pc + 4);break; // LUI
+ case 0x17:rfWrite(rd32, (i & 0xFFFFF000) + pc);pcWrite(pc + 4);break; //AUIPC
+ case 0x6F:rfWrite(rd32, pc + 4);pcWrite(pc + (iBits(21, 10) << 1) + (iBits(20, 1) << 11) + (iBits(12, 8) << 12) + (iSign() << 20));break; //JAL
+ case 0x67:{
+ uint32_t target = (i32_rs1 + i32_i_imm) & ~1;
+ if(isPcAligned(target)) rfWrite(rd32, pc + 4);
+ pcWrite(target);
+ } break; //JALR
+ case 0x63:
+ switch ((i >> 12) & 0x7) {
+ case 0x0:if (i32_rs1 == i32_rs2)pcWrite(pc + i32_sb_imm);else pcWrite(pc + 4);break;
+ case 0x1:if (i32_rs1 != i32_rs2)pcWrite(pc + i32_sb_imm);else pcWrite(pc + 4);break;
+ case 0x4:if (i32_rs1 < i32_rs2)pcWrite(pc + i32_sb_imm); else pcWrite(pc + 4);break;
+ case 0x5:if (i32_rs1 >= i32_rs2)pcWrite(pc + i32_sb_imm);else pcWrite(pc + 4);break;
+ case 0x6:if (uint32_t(i32_rs1) < uint32_t(i32_rs2)) pcWrite(pc + i32_sb_imm); else pcWrite(pc + 4);break;
+ case 0x7:if (uint32_t(i32_rs1) >= uint32_t(i32_rs2))pcWrite(pc + i32_sb_imm); else pcWrite(pc + 4);break;
+ }
+ break;
+ case 0x03:{ //LOADS
+ uint32_t data;
+ uint32_t address = i32_rs1 + i32_i_imm;
+ uint32_t size = 1 << ((i >> 12) & 0x3);
+ if(address & (size-1)){
+ trap(0, 4, address);
+ } else {
+ if(v2p(address, &pAddr, READ)){ trap(0, 13, address); return; }
+ if(dRead(pAddr, size, (uint8_t*)&data)){
+ trap(0, 5, address);
+ } else {
+ switch ((i >> 12) & 0x7) {
+ case 0x0:rfWrite(rd32, int8_t(data));pcWrite(pc + 4);break;
+ case 0x1:rfWrite(rd32, int16_t(data));pcWrite(pc + 4);break;
+ case 0x2:rfWrite(rd32, int32_t(data));pcWrite(pc + 4);break;
+ case 0x4:rfWrite(rd32, uint8_t(data));pcWrite(pc + 4);break;
+ case 0x5:rfWrite(rd32, uint16_t(data));pcWrite(pc + 4);break;
+ }
+ }
+ }
+ }break;
+ case 0x23: { //STORE
+ uint32_t address = i32_rs1 + i32_s_imm;
+ uint32_t size = 1 << ((i >> 12) & 0x3);
+ if(address & (size-1)){
+ trap(0, 6, address);
+ } else {
+ if(v2p(address, &pAddr, WRITE)){ trap(0, 15, address); return; }
+ dWrite(pAddr, size, (uint8_t*)&i32_rs2);
+ pcWrite(pc + 4);
+ lrscReserved = false;
+ }
+ }break;
+ case 0x13: //ALUi
+ switch ((i >> 12) & 0x7) {
+ case 0x0:rfWrite(rd32, i32_rs1 + i32_i_imm);pcWrite(pc + 4);break;
+ case 0x1:
+ switch ((i >> 25) & 0x7F) {
+ case 0x00:rfWrite(rd32, i32_rs1 << i32_shamt);pcWrite(pc + 4);break;
+ }
+ break;
+ case 0x2:rfWrite(rd32, i32_rs1 < i32_i_imm);pcWrite(pc + 4);break;
+ case 0x3:rfWrite(rd32, uint32_t(i32_rs1) < uint32_t(i32_i_imm));pcWrite(pc + 4);break;
+ case 0x4:rfWrite(rd32, i32_rs1 ^ i32_i_imm);pcWrite(pc + 4);break;
+ case 0x5:
+ switch ((i >> 25) & 0x7F) {
+ case 0x00:rfWrite(rd32, uint32_t(i32_rs1) >> i32_shamt);pcWrite(pc + 4);break;
+ case 0x20:rfWrite(rd32, i32_rs1 >> i32_shamt);pcWrite(pc + 4);break;
+ }
+ break;
+ case 0x6:rfWrite(rd32, i32_rs1 | i32_i_imm);pcWrite(pc + 4);break;
+ case 0x7: rfWrite(rd32, i32_rs1 & i32_i_imm);pcWrite(pc + 4);break;
+ }
+ break;
+ case 0x33: //ALU
+ if (((i >> 25) & 0x7F) == 0x01) {
+ switch ((i >> 12) & 0x7) {
+ case 0x0:rfWrite(rd32, int32_t(i32_rs1) * int32_t(i32_rs2));pcWrite(pc + 4);break;
+ case 0x1:rfWrite(rd32,(int64_t(i32_rs1) * int64_t(i32_rs2)) >> 32);pcWrite(pc + 4);break;
+ case 0x2:rfWrite(rd32,(int64_t(i32_rs1) * uint64_t(uint32_t(i32_rs2)))>> 32);pcWrite(pc + 4);break;
+ case 0x3:rfWrite(rd32,(uint64_t(uint32_t(i32_rs1)) * uint64_t(uint32_t(i32_rs2))) >> 32);pcWrite(pc + 4);break;
+ case 0x4:rfWrite(rd32,i32_rs2 == 0 ? -1 : int64_t(i32_rs1) / int64_t(i32_rs2));pcWrite(pc + 4);break;
+ case 0x5:rfWrite(rd32,i32_rs2 == 0 ? -1 : uint32_t(i32_rs1) / uint32_t(i32_rs2));pcWrite(pc + 4);break;
+ case 0x6:rfWrite(rd32,i32_rs2 == 0 ? i32_rs1 : int64_t(i32_rs1)% int64_t(i32_rs2));pcWrite(pc + 4);break;
+ case 0x7:rfWrite(rd32,i32_rs2 == 0 ? i32_rs1 : uint32_t(i32_rs1) % uint32_t(i32_rs2));pcWrite(pc + 4);break;
+ }
+ } else {
+ switch ((i >> 12) & 0x7) {
+ case 0x0:
+ switch ((i >> 25) & 0x7F) {
+ case 0x00:rfWrite(rd32, i32_rs1 + i32_rs2);pcWrite(pc + 4);break;
+ case 0x20:rfWrite(rd32, i32_rs1 - i32_rs2);pcWrite(pc + 4);break;
+ }
+ break;
+ case 0x1:rfWrite(rd32, i32_rs1 << (i32_rs2 & 0x1F));pcWrite(pc + 4);break;
+ case 0x2:rfWrite(rd32, i32_rs1 < i32_rs2);pcWrite(pc + 4);break;
+ case 0x3:rfWrite(rd32, uint32_t(i32_rs1) < uint32_t(i32_rs2));pcWrite(pc + 4);break;
+ case 0x4:rfWrite(rd32, i32_rs1 ^ i32_rs2);pcWrite(pc + 4);break;
+ case 0x5:
+ switch ((i >> 25) & 0x7F) {
+ case 0x00:rfWrite(rd32, uint32_t(i32_rs1) >> (i32_rs2 & 0x1F));pcWrite(pc + 4);break;
+ case 0x20:rfWrite(rd32, i32_rs1 >> (i32_rs2 & 0x1F));pcWrite(pc + 4);break;
+ }
+ break;
+ case 0x6:rfWrite(rd32, i32_rs1 | i32_rs2);pcWrite(pc + 4);break;
+ case 0x7:rfWrite(rd32, i32_rs1 & i32_rs2); pcWrite(pc + 4);break;
+ }
+ }
+ break;
+ case 0x73:{
+ if(i32_func3 == 0){
+ switch(i){
+ case 0x30200073:{ //MRET
+ if(privilege < 3){ ilegalInstruction(); return;}
+ privilege = status.mpp;
+ status.mie = status.mpie;
+ status.mpie = 1;
+ status.mpp = 0;
+ pcWrite(mepc);
+ }break;
+ case 0x10200073:{ //SRET
+ if(privilege < 1){ ilegalInstruction(); return;}
+ privilege = status.spp;
+ status.sie = status.spie;
+ status.spie = 1;
+ status.spp = 0;
+ pcWrite(sepc);
+ }break;
+ case 0x00000073:{ //ECALL
+ trap(0, 8+privilege, 0x00000073); //To follow the VexRiscv area saving implementation
+ }break;
+ case 0x10500073:{ //WFI
+ pcWrite(pc + 4);
+ }break;
+ default:
+ if((i & 0xFE007FFF) == 0x12000073){ //SFENCE.VMA
+ pcWrite(pc + 4);
+ }else {
+ ilegalInstruction();
+ }
+ break;
+ }
+ } else {
+ //CSR
+ uint32_t input = (i & 0x4000) ? ((i >> 15) & 0x1F) : i32_rs1;
+ uint32_t clear, set;
+ bool write;
+ switch ((i >> 12) & 0x3) {
+ case 1: clear = ~0; set = input; write = true; break;
+ case 2: clear = 0; set = input; write = ((i >> 15) & 0x1F) != 0; break;
+ case 3: clear = input; set = 0; write = ((i >> 15) & 0x1F) != 0; break;
+ }
+ uint32_t csrAddress = i32_csr;
+ uint32_t old;
+ if(csrRead(i32_csr, &old)) { ilegalInstruction();return; }
+ if(write) if(csrWrite(i32_csr, (csrReadToWriteOverride(i32_csr, old) & ~clear) | set)) { ilegalInstruction();return; }
+ rfWrite(rd32, old);
+ pcWrite(pc + 4);
+ }
+ break;
+ }
+ case 0x2F: // Atomic stuff
+ switch(i32_func3){
+ case 0x2:
+ switch(iBits(27,5)){
+ case 0x2:{ //LR
+ uint32_t data;
+ uint32_t address = i32_rs1;
+ if(address & 3){
+ trap(0, 4, address);
+ } else {
+ if(v2p(address, &pAddr, READ)){ trap(0, 13, address); return; }
+ if(dRead(pAddr, 4, (uint8_t*)&data)){
+ trap(0, 5, address);
+ } else {
+ lrscReserved = true;
+ lrscReservedAddress = pAddr;
+ rfWrite(rd32, data);
+ pcWrite(pc + 4);
+ }
+ }
+ } break;
+ case 0x3:{ //SC
+ uint32_t address = i32_rs1;
+ if(address & 3){
+ trap(0, 6, address);
+ } else {
+ if(v2p(address, &pAddr, WRITE)){ trap(0, 15, address); return; }
+ #ifdef DBUS_EXCLUSIVE
+ bool hit = lrscReserved && lrscReservedAddress == pAddr;
+ #else
+ bool hit = lrscReserved;
+ #endif
+ if(hit){
+ dWrite(pAddr, 4, (uint8_t*)&i32_rs2);
+ }
+ lrscReserved = false;
+ rfWrite(rd32, !hit);
+ pcWrite(pc + 4);
+ }
+ } break;
+ default: {
+ #ifndef AMO
+ ilegalInstruction();
+ #else
+ uint32_t sel = (i >> 27) & 0x1F;
+ uint32_t addr = i32_rs1;
+ int32_t src = i32_rs2;
+ int32_t readValue;
+
+ lrscReserved = false;
+
+
+ uint32_t pAddr;
+ if(v2p(addr, &pAddr, READ_WRITE)){ trap(0, 15, addr); return; }
+ if(dRead(pAddr, 4, (uint8_t*)&readValue)){
+ trap(0, 15, addr); return;
+ return;
+ }
+ int writeValue;
+ switch(sel){
+ case 0x0: writeValue = src + readValue; break;
+ case 0x1: writeValue = src; break;
+ case 0x4: writeValue = src ^ readValue; break;
+ case 0xC: writeValue = src & readValue; break;
+ case 0x8: writeValue = src | readValue; break;
+ case 0x10: writeValue = min(src, readValue); break;
+ case 0x14: writeValue = max(src, readValue); break;
+ case 0x18: writeValue = min((unsigned int)src, (unsigned int)readValue); break;
+ case 0x1C: writeValue = max((unsigned int)src, (unsigned int)readValue); break;
+ default: ilegalInstruction(); return; break;
+ }
+ dWrite(pAddr, 4, (uint8_t*)&writeValue);
+ rfWrite(rd32, readValue);
+ pcWrite(pc + 4);
+ #endif
+ } break;
+ }
+ break;
+ default: ilegalInstruction(); break;
+ }
+ break;
+ case 0x0f:
+ if(i == 0x100F || (i & 0xF00FFFFF) == 0x000F){ // FENCE FENCE.I
+ pcWrite(pc + 4);
+ } else{
+ ilegalInstruction();
+ }
+ break;
+ default: ilegalInstruction(); break;
+ }
+ } else {
+ #ifndef COMPRESSED
+ cout << "ERROR : RiscvGolden got a RVC instruction while the CPU isn't RVC ready" << endl;
+ ilegalInstruction(); return;
+ #endif
+ switch((iBits(0, 2) << 3) + iBits(13, 3)){
+ case 0: rfWrite(i16_addr2, rf_sp + i16_addi4spn_imm); pcWrite(pc + 2); break;
+ case 2: {
+ uint32_t data;
+ uint32_t address = i16_rf1 + i16_lw_imm;
+ if(address & 0x3){
+ trap(0, 4, address);
+ } else {
+ if(v2p(address, &pAddr, READ)){ trap(0, 13, address); return; }
+ if(dRead(pAddr, 4, (uint8_t*)&data)) {
+ trap(0, 5, address);
+ } else {
+ rfWrite(i16_addr2, data); pcWrite(pc + 2);
+ }
+ }
+ } break;
+ case 6: {
+ uint32_t address = i16_rf1 + i16_lw_imm;
+ if(address & 0x3){
+ trap(0, 6, address);
+ } else {
+ if(v2p(address, &pAddr, WRITE)){ trap(0, 15, address); return; }
+ dWrite(pAddr, 4, (uint8_t*)&i16_rf2);
+ pcWrite(pc + 2);
+ lrscReserved = false;
+ }
+ }break;
+ case 8: rfWrite(rd32, regs[rd32] + i16_imm); pcWrite(pc + 2); break;
+ case 9: rfWrite(1, pc + 2);pcWrite(pc + i16_j_imm); break;
+ case 10: rfWrite(rd32, i16_imm);pcWrite(pc + 2); break;
+ case 11:
+ if(rd32 == 2) { rfWrite(2, rf_sp + i16_addi16sp_imm);pcWrite(pc + 2); }
+ else { rfWrite(rd32, i16_imm << 12);pcWrite(pc + 2); } break;
+ case 12:
+ switch(iBits(10,2)){
+ case 0: rfWrite(i16_addr1, uint32_t(i16_rf1) >> i16_zimm); pcWrite(pc + 2);break;
+ case 1: rfWrite(i16_addr1, i16_rf1 >> i16_zimm); pcWrite(pc + 2);break;
+ case 2: rfWrite(i16_addr1, i16_rf1 & i16_imm); pcWrite(pc + 2);break;
+ case 3:
+ switch(iBits(5,2)){
+ case 0: rfWrite(i16_addr1, i16_rf1 - i16_rf2); pcWrite(pc + 2);break;
+ case 1: rfWrite(i16_addr1, i16_rf1 ^ i16_rf2); pcWrite(pc + 2);break;
+ case 2: rfWrite(i16_addr1, i16_rf1 | i16_rf2); pcWrite(pc + 2);break;
+ case 3: rfWrite(i16_addr1, i16_rf1 & i16_rf2); pcWrite(pc + 2);break;
+ }
+ break;
+ }
+ break;
+ case 13: pcWrite(pc + i16_j_imm); break;
+ case 14: pcWrite(i16_rf1 == 0 ? pc + i16_b_imm : pc + 2); break;
+ case 15: pcWrite(i16_rf1 != 0 ? pc + i16_b_imm : pc + 2); break;
+ case 16: rfWrite(rd32, regs[rd32] << i16_zimm); pcWrite(pc + 2); break;
+ case 18:{
+ uint32_t data;
+ uint32_t address = rf_sp + i16_lwsp_imm;
+ if(address & 0x3){
+ trap(0, 4, address);
+ } else {
+ if(v2p(address, &pAddr, READ)){ trap(0, 13, address); return; }
+ if(dRead(pAddr, 4,(uint8_t*) &data)){
+ trap(0, 5, address);
+ } else {
+ rfWrite(rd32, data); pcWrite(pc + 2);
+ }
+ }
+ }break;
+ case 20:
+ if(i & 0x1000){
+ if(iBits(2,10) == 0){
+
+ } else if(iBits(2,5) == 0){
+ rfWrite(1, pc + 2); pcWrite(regs[rd32] & ~1);
+ } else {
+ rfWrite(rd32, regs[rd32] + regs[iBits(2,5)]); pcWrite(pc + 2);
+ }
+ } else {
+ if(iBits(2,5) == 0){
+ pcWrite(regs[rd32] & ~1);
+ } else {
+ rfWrite(rd32, regs[iBits(2,5)]); pcWrite(pc + 2);
+ }
+ }
+ break;
+ case 22: {
+ uint32_t address = rf_sp + i16_swsp_imm;
+ if(address & 3){
+ trap(0,6, address);
+ } else {
+ if(v2p(address, &pAddr, WRITE)){ trap(0, 15, address); return; }
+ dWrite(pAddr, 4, (uint8_t*)&regs[iBits(2,5)]); pcWrite(pc + 2);
+ lrscReserved = false;
+ }
+ }break;
+ }
+ }
+ }
+};
+
+
+class SimElement{
+public:
+ virtual ~SimElement(){}
+ virtual void onReset(){}
+ virtual void postReset(){}
+ virtual void preCycle(){}
+ virtual void postCycle(){}
+};
+
+
+
+class Workspace;
+
+class Workspace{
+public:
+ static mutex staticMutex;
+ static uint32_t testsCounter, successCounter;
+ static uint64_t cycles;
+ uint64_t instanceCycles = 0;
+ vector<SimElement*> simElements;
+ Memory mem;
+ string name;
+ uint64_t currentTime = 22;
+ uint64_t mTimeCmp = 0;
+ uint64_t mTime = 0;
+ VVexRiscv* top;
+ bool resetDone = false;
+ bool riscvRefEnable = false;
+ uint64_t i;
+ double cyclesPerSecond = 10e6;
+ double allowedCycles = 0.0;
+ uint32_t bootPc = -1;
+ uint32_t iStall = STALL,dStall = STALL;
+ #ifdef TRACE
+ VerilatedFstC* tfp;
+ #endif
+ bool allowInvalidate = true;
+
+ uint32_t seed;
+
+ Workspace* setIStall(bool enable) { iStall = enable; return this; }
+ Workspace* setDStall(bool enable) { dStall = enable; return this; }
+
+ ofstream regTraces;
+ ofstream memTraces;
+ ofstream logTraces;
+ ofstream debugLog;
+
+ struct timespec start_time;
+
+ class CpuRef : public RiscvGolden{
+ public:
+ Memory mem;
+
+ class MemWrite {
+ public:
+ int32_t address, size;
+ uint8_t data42[64];
+ };
+
+ class MemRead {
+ public:
+ int32_t address, size;
+ uint8_t data42[64];
+ bool error;
+ };
+
+ uint32_t periphWriteTimer = 0;
+ queue<MemWrite> periphWritesGolden;
+ queue<MemWrite> periphWrites;
+ queue<MemRead> periphRead;
+ Workspace *ws;
+ CpuRef(Workspace *ws){
+ this->ws = ws;
+ }
+
+ virtual void fail() { ws->fail(); }
+
+
+ virtual bool isMmuRegion(uint32_t v) {return ws->isMmuRegion(v);}
+
+ bool rfWriteValid;
+ int32_t rfWriteAddress;
+ int32_t rfWriteData;
+ virtual void rfWrite(int32_t address, int32_t data){
+ rfWriteValid = address != 0;
+ rfWriteAddress = address;
+ rfWriteData = data;
+ RiscvGolden::rfWrite(address,data);
+ }
+
+
+ virtual bool iRead(int32_t address, uint32_t *data){
+ bool error;
+ ws->iBusAccess(address, data, &error);
+// ws->iBusAccessPatch(address,data,&error);
+ return error;
+ }
+
+ virtual bool dRead(int32_t address, int32_t size, uint8_t *data){
+ if(size < 1 || size > 8){
+ cout << "dRead size=" << size << endl;
+ fail();
+ }
+ if((address & (size-1)) != 0)
+ cout << "Ref did a unaligned read" << endl;
+ if(ws->isPerifRegion(address)){
+ MemRead t = periphRead.front();
+ if(t.address != address || t.size != size){
+ cout << "DRead missmatch" << hex << endl;
+ cout << " REF : address=" << address << " size=" << size << endl;
+ cout << " DUT : address=" << t.address << " size=" << t.size << endl;
+ fail();
+ }
+
+ for(int i = 0; i < size; i++){
+ data[i] = t.data42[i];
+ }
+ periphRead.pop();
+ return t.error;
+ }else {
+ mem.read(address, size, data);
+ }
+ return false;
+ }
+ virtual void dWrite(int32_t address, int32_t size, uint8_t *data){
+ if(address & (size-1) != 0)
+ cout << "Ref did a unaligned write" << endl;
+
+ if(!ws->isPerifRegion(address)){
+ mem.write(address, size, data);
+ }
+ if(ws->isDBusCheckedRegion(address)){
+ MemWrite w;
+ w.address = address;
+ w.size = size;
+ for(int i = 0; i < size; i++){
+ w.data42[i] = data[i];
+ }
+ periphWritesGolden.push(w);
+ if(periphWritesGolden.size() > 10){
+ cout << "??? periphWritesGolden" << endl;
+ fail();
+ }
+ }
+ }
+
+
+ void step() {
+ rfWriteValid = false;
+ RiscvGolden::step();
+
+ switch(periphWrites.empty() + uint32_t(periphWritesGolden.empty())*2){
+ case 3: periphWriteTimer = 0; break;
+ case 1: case 2: if(periphWriteTimer++ == 20){
+ cout << "periphWrite timout" << endl; fail();
+ } break;
+ case 0:
+ MemWrite t = periphWrites.front();
+ MemWrite t2 = periphWritesGolden.front();
+ bool dataMatch = true;
+ for(int i = 0;i < min(t.size, t2.size);i++) dataMatch &= t.data42[i] == t2.data42[i];
+ if(t.address != t2.address || t.size != t2.size || !dataMatch){
+ cout << hex << "periphWrite missmatch" << endl;
+ cout << " DUT address=" << t.address << " size=" << t.size << " data=" << *((uint32_t*)t.data42) << endl;
+ cout << " REF address=" << t2.address << " size=" << t2.size << " data=" << *((uint32_t*)t2.data42) << endl;
+ fail();
+ }
+ periphWrites.pop();
+ periphWritesGolden.pop();
+ periphWriteTimer = 0;
+ break;
+ }
+
+
+ }
+ };
+
+ CpuRef riscvRef = CpuRef(this);
+ string vcdName;
+ Workspace* setVcdName(string name){
+ vcdName = name;
+ return this;
+ }
+ Workspace(string name){
+ vcdName = name;
+ //seed = VL_RANDOM_I_WIDTH(32)^VL_RANDOM_I_WIDTH(32)^0x1093472;
+ //srand48(seed);
+ // setIStall(false);
+ // setDStall(false);
+ staticMutex.lock();
+ testsCounter++;
+ staticMutex.unlock();
+ this->name = name;
+ top = new VVexRiscv;
+ #ifdef TRACE_ACCESS
+ regTraces.open (name + ".regTrace");
+ memTraces.open (name + ".memTrace");
+ #endif
+ logTraces.open (name + ".logTrace");
+ debugLog.open (name + ".debugTrace");
+ fillSimELements();
+ clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_time);
+ }
+
+ virtual ~Workspace(){
+ delete top;
+ #ifdef TRACE
+ delete tfp;
+ #endif
+
+ for(SimElement* simElement : simElements) {
+ delete simElement;
+ }
+ }
+
+ Workspace* loadHex(string path){
+ loadHexImpl(path,&mem);
+ loadHexImpl(path,&riscvRef.mem);
+ return this;
+ }
+
+ Workspace* loadBin(string path, uint32_t offset){
+ loadBinImpl(path,&mem, offset);
+ loadBinImpl(path,&riscvRef.mem, offset);
+ return this;
+ }
+
+ Workspace* setCyclesPerSecond(double value){
+ cyclesPerSecond = value;
+ return this;
+ }
+
+ Workspace* bootAt(uint32_t pc) {
+ bootPc = pc;
+ riscvRef.pc = pc;
+ return this;
+ }
+
+ Workspace* withRiscvRef(){
+ #ifdef WITH_RISCV_REF
+ riscvRefEnable = true;
+ #endif
+ return this;
+ }
+
+ Workspace* withInvalidation(){
+ allowInvalidate = true;
+ return this;
+ }
+ Workspace* withoutInvalidation(){
+ allowInvalidate = false;
+ return this;
+ }
+ Workspace* writeWord(uint32_t address, uint32_t data){
+ mem.write(address, 4, (uint8_t*)&data);
+ riscvRef.mem.write(address, 4, (uint8_t*)&data);
+ return this;
+ }
+
+ virtual bool isPerifRegion(uint32_t addr) { return false; }
+ virtual bool isMmuRegion(uint32_t addr) { return true;}
+ virtual void iBusAccess(uint32_t addr, uint32_t *data, bool *error) {
+ if(addr % 4 != 0) {
+ cout << "Warning, unaligned IBusAccess : " << addr << endl;
+ fail();
+ }
+ *data = ( (mem[addr + 0] << 0)
+ | (mem[addr + 1] << 8)
+ | (mem[addr + 2] << 16)
+ | (mem[addr + 3] << 24));
+ *error = false;
+ }
+
+
+ virtual bool isDBusCheckedRegion(uint32_t address){ return isPerifRegion(address);}
+ virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size, uint8_t *data, bool *error) {
+ assertEq(addr % size, 0);
+ if(!isPerifRegion(addr)) {
+ if(wr){
+ for(uint32_t b = 0;b < size;b++){
+ *mem.get(addr + b) = ((uint8_t*)data)[b];
+ }
+
+ }else{
+ uint32_t innerOffset = addr & (DBUS_LOAD_DATA_WIDTH/8-1);
+ for(uint32_t b = 0;b < size;b++){
+ ((uint8_t*)data)[b] = mem[addr + b];
+ }
+ }
+ }
+
+
+ if(wr){
+ if(isDBusCheckedRegion(addr)){
+ CpuRef::MemWrite w;
+ w.address = addr;
+ w.size = size;
+ for(uint32_t b = 0;b < size;b++){
+ w.data42[b] = data[b];
+ }
+ riscvRef.periphWrites.push(w);
+ }
+ } else {
+ if(isPerifRegion(addr)){
+ CpuRef::MemRead r;
+ r.address = addr;
+ r.size = size;
+ for(uint32_t b = 0;b < size;b++){
+ r.data42[b] = data[b];
+ }
+ r.error = *error;
+ riscvRef.periphRead.push(r);
+ }
+ }
+ }
+
+// void periphAccess(uint32_t addr,bool wr, uint32_t size,uint32_t mask, uint32_t *data, bool *error){
+// if(wr){
+// CpuRef::MemWrite w;
+// w.address = addr;
+// w.size = 1 << size;
+// w.data = *data;
+// riscvRef.periphWrites.push(w);
+// } else {
+// CpuRef::MemRead r;
+// r.address = addr;
+// r.size = 1 << size;
+// r.data = *data;
+// r.error = *error;
+// riscvRef.periphRead.push(r);
+// }
+// }
+
+ 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 && i != 0) cout << "**" << endl << "**" << endl << "**" << endl << "**" << endl << "**" << endl << "START TRACE" << endl;
+ if(i >= TRACE_START) tfp->dump(i);
+ #ifdef TRACE_SPORADIC
+ else if(i % 1000000 < 100) tfp->dump(i);
+ #endif
+ #endif
+ }
+
+ uint64_t privilegeCounters[4] = {0,0,0,0};
+ Workspace* run(uint64_t timeout = 5000){
+// cout << "Start " << name << endl;
+ if(timeout == 0) timeout = 0x7FFFFFFFFFFFFFFF;
+
+ currentTime = 4;
+ // init trace dump
+ #ifdef TRACE
+ Verilated::traceEverOn(true);
+ tfp = new VerilatedFstC;
+ top->trace(tfp, 99);
+ tfp->open((vcdName + ".fst").c_str());
+ #endif
+
+ // Reset
+ top->clk = 0;
+ top->reset = 0;
+
+
+ top->eval(); currentTime = 3;
+ for(SimElement* simElement : simElements) simElement->onReset();
+
+ top->reset = 1;
+ top->eval();
+ top->clk = 1;
+ top->eval();
+ top->clk = 0;
+ top->eval();
+ #ifdef CSR
+ top->timerInterrupt = 0;
+ top->externalInterrupt = 1;
+ top->softwareInterrupt = 0;
+ #endif
+ #ifdef SUPERVISOR
+ top->externalInterruptS = 0;
+ #endif
+ #ifdef DEBUG_PLUGIN_EXTERNAL
+ top->timerInterrupt = 0;
+ top->externalInterrupt = 0;
+ #endif
+ dump(0);
+ top->reset = 0;
+ for(SimElement* simElement : simElements) simElement->postReset();
+
+ top->eval(); currentTime = 2;
+
+
+ postReset();
+
+ //Sync register file initial content
+ for(int i = 1;i < 32;i++){
+ riscvRef.regs[i] = top->VexRiscv->RegFilePlugin_regFile[i];
+ }
+ resetDone = true;
+
+ #ifdef REF
+ if(bootPc != -1) top->VexRiscv->core->prefetch_pc = bootPc;
+ #else
+ if(bootPc != -1) {
+ #if defined(IBUS_SIMPLE) || defined(IBUS_SIMPLE_WISHBONE) || defined(IBUS_SIMPLE_AHBLITE3)
+ top->VexRiscv->IBusSimplePlugin_fetchPc_pcReg = bootPc;
+ #ifdef COMPRESSED
+ top->VexRiscv->IBusSimplePlugin_decodePc_pcReg = bootPc;
+ #endif
+ #else
+ top->VexRiscv->IBusCachedPlugin_fetchPc_pcReg = bootPc;
+ #ifdef COMPRESSED
+ top->VexRiscv->IBusCachedPlugin_decodePc_pcReg = bootPc;
+ #endif
+ #endif
+ }
+ #endif
+
+
+ bool failed = false;
+ try {
+ // run simulation for 100 clock periods
+ for (i = 16; i < timeout*2; i+=2) {
+ /*while(allowedCycles <= 0.0){
+ 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;
+ allowedCycles += dt*cyclesPerSecond;
+ if(allowedCycles > cyclesPerSecond/100) allowedCycles = cyclesPerSecond/100;
+ }
+ allowedCycles-=1.0;*/
+
+
+ #ifndef REF_TIME
+ #ifndef MTIME_INSTR_FACTOR
+ mTime = i/2;
+ #else
+ mTime += top->VexRiscv->lastStageIsFiring*MTIME_INSTR_FACTOR;
+ #endif
+ #endif
+ #ifdef TIMER_INTERRUPT
+ top->timerInterrupt = mTime >= mTimeCmp ? 1 : 0;
+ //if(mTime == mTimeCmp) printf("SIM timer tick\n");
+ #endif
+
+
+ #ifdef UTIME_INPUT
+ top->utime = mTime;
+ #endif
+
+ currentTime = i;
+
+ #ifdef FLOW_INFO
+ if(i % 5000000 == 0) cout << endl << "**" << endl << "**" << endl << "PROGRESS TRACE_START=" << i << endl;
+ #endif
+
+
+ // dump variables into VCD file and toggle clock
+
+ dump(i);
+ //top->eval();
+ top->clk = 0;
+ top->eval();
+
+ #ifdef CSR
+ if(riscvRefEnable) {
+ riscvRef.ipInput = 0;
+ #ifdef TIMER_INTERRUPT
+ riscvRef.ipInput |= top->timerInterrupt << 7;
+ #endif
+ #ifdef EXTERNAL_INTERRUPT
+ riscvRef.ipInput |= top->externalInterrupt << 11;
+ #endif
+ #ifdef CSR
+ riscvRef.ipInput |= top->softwareInterrupt << 3;
+ #endif
+ #ifdef SUPERVISOR
+ // riscvRef.ipInput |= top->timerInterruptS << 5;
+ riscvRef.ipInput |= top->externalInterruptS << 9;
+ #endif
+
+ riscvRef.liveness(top->VexRiscv->CsrPlugin_inWfi);
+ if(top->VexRiscv->CsrPlugin_interruptJump){
+ if(riscvRefEnable) riscvRef.trap(true, top->VexRiscv->CsrPlugin_interrupt_code);
+ }
+ }
+ #endif
+
+ #ifdef RVF
+ if(riscvRefEnable) {
+ if(top->VexRiscv->writeBack_FpuPlugin_commit_valid && top->VexRiscv->writeBack_FpuPlugin_commit_ready && top->VexRiscv->writeBack_FpuPlugin_commit_payload_write){
+ FpuCommit c;
+ c.value = top->VexRiscv->writeBack_FpuPlugin_commit_payload_value;
+ riscvRef.fpuCommit.push(c);
+ }
+
+ if(top->VexRiscv->FpuPlugin_port_rsp_valid && top->VexRiscv->FpuPlugin_port_rsp_ready && top->VexRiscv->lastStageIsFiring){
+ FpuRsp c;
+ c.value = top->VexRiscv->FpuPlugin_port_rsp_payload_value;
+ c.flags = (top->VexRiscv->FpuPlugin_port_rsp_payload_NX << 0) |
+ (top->VexRiscv->FpuPlugin_port_rsp_payload_NV << 4);
+ riscvRef.fpuRsp.push(c);
+ }
+
+ if(top->VexRiscv->FpuPlugin_port_completion_valid && top->VexRiscv->FpuPlugin_port_completion_payload_written){
+ FpuCompletion c;
+ c.flags = (top->VexRiscv->FpuPlugin_port_completion_payload_flags_NX << 0) |
+ (top->VexRiscv->FpuPlugin_port_completion_payload_flags_UF << 1) |
+ (top->VexRiscv->FpuPlugin_port_completion_payload_flags_OF << 2) |
+ (top->VexRiscv->FpuPlugin_port_completion_payload_flags_DZ << 3) |
+ (top->VexRiscv->FpuPlugin_port_completion_payload_flags_NV << 4);
+ riscvRef.fpuCompletion.push(c);
+ }
+ }
+ #endif
+
+
+
+ if(top->VexRiscv->lastStageIsFiring){
+ if(riscvRefEnable) {
+// privilegeCounters[riscvRef.privilege]++;
+// if((riscvRef.stepCounter & 0xFFFFF) == 0){
+// cout << "privilege report" << endl;
+// cout << "- U " << privilegeCounters[0] << endl;
+// cout << "- S " << privilegeCounters[1] << endl;
+// cout << "- M " << privilegeCounters[3] << endl;
+// }
+ riscvRef.dutRfWriteValue = top->VexRiscv->lastStageRegFileWrite_payload_data;
+ riscvRef.step();
+ bool mIntTimer = false;
+ bool mIntExt = false;
+ }
+
+ if(riscvRefEnable && top->VexRiscv->lastStagePc != riscvRef.lastPc){
+ cout << hex << " pc missmatch " << top->VexRiscv->lastStagePc << " should be " << riscvRef.lastPc << dec << endl;
+ fail();
+ }
+
+
+ bool rfWriteValid = false;
+ int32_t rfWriteAddress;
+ int32_t rfWriteData;
+
+ if(top->VexRiscv->lastStageRegFileWrite_valid == 1 && top->VexRiscv->lastStageRegFileWrite_payload_address != 0){
+ rfWriteValid = true;
+ rfWriteAddress = top->VexRiscv->lastStageRegFileWrite_payload_address;
+ rfWriteData = top->VexRiscv->lastStageRegFileWrite_payload_data;
+ #ifdef TRACE_ACCESS
+ regTraces <<
+ #ifdef TRACE_WITH_TIME
+ currentTime <<
+ #endif
+ " PC " << hex << setw(8) << top->VexRiscv->lastStagePc << " : reg[" << dec << setw(2) << (uint32_t)top->VexRiscv->lastStageRegFileWrite_payload_address << "] = " << hex << setw(8) << top->VexRiscv->lastStageRegFileWrite_payload_data << dec << endl;
+ #endif
+ } else {
+ #ifdef TRACE_ACCESS
+ regTraces <<
+ #ifdef TRACE_WITH_TIME
+ currentTime <<
+ #endif
+ " PC " << hex << setw(8) << top->VexRiscv->lastStagePc << dec << endl;
+ #endif
+ }
+ if(riscvRefEnable) if(rfWriteValid != riscvRef.rfWriteValid ||
+ (rfWriteValid && (rfWriteAddress!= riscvRef.rfWriteAddress || rfWriteData!= riscvRef.rfWriteData))){
+ cout << "regFile write missmatch :" << endl;
+ if(rfWriteValid) cout << " REF: RF[" << riscvRef.rfWriteAddress << "] = 0x" << hex << riscvRef.rfWriteData << dec << endl;
+ if(rfWriteValid) cout << " DUT: RF[" << rfWriteAddress << "] = 0x" << hex << rfWriteData << dec << endl;
+ fail();
+ }
+ }
+
+ #ifdef CSR
+ if(top->VexRiscv->CsrPlugin_hadException){
+ if(riscvRefEnable) {
+ riscvRef.step();
+ }
+ }
+ #endif
+
+ for(SimElement* simElement : simElements) simElement->preCycle();
+
+ dump(i + 1);
+
+ checks();
+ //top->eval();
+ top->clk = 1;
+ top->eval();
+
+ instanceCycles += 1;
+
+ for(SimElement* simElement : simElements) simElement->postCycle();
+ #ifdef RVF
+ top->fpuCmdHalt = VL_RANDOM_I_WIDTH(1);
+ top->fpuCommitHalt = VL_RANDOM_I_WIDTH(1);
+ top->fpuRspHalt = VL_RANDOM_I_WIDTH(1);
+ #endif
+
+
+
+ if (Verilated::gotFinish())
+ exit(0);
+ }
+ cout << "timeout" << endl;
+ fail();
+ } catch (const success e) {
+ staticMutex.lock();
+ cout <<"SUCCESS " << name << endl;
+ successCounter++;
+ cycles += instanceCycles;
+ staticMutex.unlock();
+ } catch (const std::exception& e) {
+ staticMutex.lock();
+
+ cout << "FAIL " << name << " at PC=" << hex << setw(8) << top->VexRiscv->lastStagePc << dec; //<< " seed : " << seed <<
+ if(riscvRefEnable) cout << hex << " REF PC=" << riscvRef.lastPc << " REF I=" << riscvRef.lastInstruction << dec;
+ cout << " time=" << i;
+ cout << endl;
+
+ cycles += instanceCycles;
+ staticMutex.unlock();
+ failed = true;
+ }
+
+
+
+ dump(i+2);
+ dump(i+10);
+ #ifdef TRACE
+ tfp->close();
+ #endif
+ #ifdef STOP_ON_ERROR
+ if(failed){
+ sleep(1);
+ exit(-1);
+ }
+ #endif
+ return this;
+ }
+};
+
+
+class WorkspaceRegression : public Workspace {
+public:
+
+ WorkspaceRegression(string name) : Workspace(name){
+
+ }
+
+ virtual bool isPerifRegion(uint32_t addr) { return (addr & 0xF0000000) == 0xF0000000;}
+
+
+ virtual void iBusAccess(uint32_t addr, uint32_t *data, bool *error){
+ Workspace::iBusAccess(addr,data,error);
+ *error = addr == 0xF00FFF60u;
+ }
+
+ virtual void dutPutChar(char c){}
+
+ virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size, uint8_t *dataBytes, bool *error) {
+ uint32_t *data = ((uint32_t*)dataBytes);
+ if(wr){
+ switch(addr){
+ case 0xF0010000u: {
+ cout << (char)*data;
+ logTraces << (char)*data;
+ dutPutChar((char)*data);
+ break;
+ }
+#ifdef EXTERNAL_INTERRUPT
+ case 0xF0011000u: top->externalInterrupt = *data & 1; break;
+#endif
+#ifdef SUPERVISOR
+ case 0xF0012000u: top->externalInterruptS = *data & 1; break;
+#endif
+#ifdef CSR
+ case 0xF0013000u: top->softwareInterrupt = *data & 1; break;
+#endif
+ case 0xF00FFF00u: {
+ cout << (char)*data;
+ logTraces << (char)*data;
+ dutPutChar((char)*data);
+ break;
+ }
+ #ifndef DEBUG_PLUGIN_EXTERNAL
+ case 0xF00FFF20u:
+ if(*data == 0)
+ pass();
+ else
+ fail();
+ break;
+ case 0xF00FFF24u:
+ cout << "TEST ERROR CODE " << *data << endl;
+ fail();
+ break;
+ #endif
+ case 0xF00FFF48u: mTimeCmp = (mTimeCmp & 0xFFFFFFFF00000000) | *data;break;
+ case 0xF00FFF4Cu: mTimeCmp = (mTimeCmp & 0x00000000FFFFFFFF) | (((uint64_t)*data) << 32); break;
+ case 0xF00FFF50u: cout << "mTime " << *data << " : " << mTime << endl;
+ }
+ if((addr & 0xFFFFF000) == 0xF5670000){
+ uint32_t t = 0x900FF000 | (addr & 0xFFF);
+ uint32_t old = (*mem.get(t + 3) << 24) | (*mem.get(t + 2) << 16) | (*mem.get(t + 1) << 8) | (*mem.get(t + 0) << 0);
+ old++;
+ *mem.get(t + 0) = old & 0xFF; old >>= 8;
+ *mem.get(t + 1) = old & 0xFF; old >>= 8;
+ *mem.get(t + 2) = old & 0xFF; old >>= 8;
+ *mem.get(t + 3) = old & 0xFF; old >>= 8;
+ }
+ }else{
+ switch(addr){
+ case 0xF00FFF10u:
+ *data = mTime;
+ #ifdef REF_TIME
+ mTime += 100000;
+ #endif
+ break;
+ case 0xF00FFF40u: *data = mTime; break;
+ case 0xF00FFF44u: *data = mTime >> 32; break;
+ case 0xF00FFF48u: *data = mTimeCmp; break;
+ case 0xF00FFF4Cu: *data = mTimeCmp >> 32; break;
+ case 0xF0010004u: *data = ~0; break;
+ }
+ }
+
+ *error = addr == 0xF00FFF60u;
+ Workspace::dBusAccess(addr,wr,size,dataBytes,error);
+ }
+
+
+
+};
+
+
+
+class ZephyrRegression : public WorkspaceRegression{
+public:
+
+
+ uint32_t regFileWriteRefIndex = 0;
+ const char *target = "PROJECT EXECUTION SUCCESSFUL";
+ const char *hit = target;
+
+ ZephyrRegression(string name) : WorkspaceRegression(name) {
+ cout << endl << endl;
+
+ }
+
+ virtual void dutPutChar(char c){
+ if(*hit == c) hit++; else hit = target;
+ if(*hit == 0) {
+ cout << endl << "T=" << i <<endl;
+ cout << endl;
+ pass();
+ }
+ }
+};
+
+
+
+
+
+
+#ifdef IBUS_SIMPLE
+class IBusSimple : public SimElement{
+public:
+ uint32_t pendings[256];
+ uint32_t rPtr = 0, wPtr = 0;
+
+ Workspace *ws;
+ VVexRiscv* top;
+ IBusSimple(Workspace* ws){
+ this->ws = ws;
+ this->top = ws->top;
+ }
+
+ virtual void onReset(){
+ top->iBus_cmd_ready = 1;
+ top->iBus_rsp_valid = 0;
+ }
+
+ virtual void preCycle(){
+ if (top->iBus_cmd_valid && top->iBus_cmd_ready) {
+ //assertEq(top->iBus_cmd_payload_pc & 3,0);
+ pendings[wPtr] = (top->iBus_cmd_payload_pc);
+ wPtr = (wPtr + 1) & 0xFF;
+ //ws->iBusAccess(top->iBus_cmd_payload_pc,&inst_next,&error_next);
+ }
+ }
+ //TODO doesn't catch when instruction removed ?
+ virtual void postCycle(){
+ top->iBus_rsp_valid = 0;
+ if(rPtr != wPtr && (!ws->iStall || VL_RANDOM_I_WIDTH(7) < 100)){
+ uint32_t inst_next;
+ bool error_next;
+ ws->iBusAccess(pendings[rPtr], &inst_next,&error_next);
+ rPtr = (rPtr + 1) & 0xFF;
+ top->iBus_rsp_payload_inst = inst_next;
+ top->iBus_rsp_valid = 1;
+ top->iBus_rsp_payload_error = error_next;
+ } else {
+ top->iBus_rsp_payload_inst = VL_RANDOM_I_WIDTH(32);
+ top->iBus_rsp_payload_error = VL_RANDOM_I_WIDTH(1);
+ }
+ if(ws->iStall) top->iBus_cmd_ready = VL_RANDOM_I_WIDTH(7) < 100;
+ }
+};
+#endif
+
+
+#ifdef IBUS_TC
+
+class IBusTc : public SimElement{
+public:
+
+ uint32_t nextData;
+
+ Workspace *ws;
+ VVexRiscv* top;
+ IBusTc(Workspace* ws){
+ this->ws = ws;
+ this->top = ws->top;
+ }
+
+ virtual void onReset(){
+ }
+
+ virtual void preCycle(){
+ if (top->iBusTc_enable) {
+ if((top->iBusTc_address & 0x70000000) != 0){
+ printf("IBusTc access out of range\n");
+ ws->fail();
+ }
+ bool error_next;
+ ws->iBusAccess(top->iBusTc_address, &nextData,&error_next);
+ }
+ }
+
+ virtual void postCycle(){
+ top->iBusTc_data = nextData;
+ }
+};
+
+#endif
+
+
+#ifdef IBUS_SIMPLE_AVALON
+
+struct IBusSimpleAvalonRsp{
+ uint32_t data;
+ bool error;
+};
+
+
+class IBusSimpleAvalon : public SimElement{
+public:
+ queue<IBusSimpleAvalonRsp> rsps;
+
+ Workspace *ws;
+ VVexRiscv* top;
+ IBusSimpleAvalon(Workspace* ws){
+ this->ws = ws;
+ this->top = ws->top;
+ }
+
+ virtual void onReset(){
+ top->iBusAvalon_waitRequestn = 1;
+ top->iBusAvalon_readDataValid = 0;
+ }
+
+ virtual void preCycle(){
+ if (top->iBusAvalon_read && top->iBusAvalon_waitRequestn) {
+ IBusSimpleAvalonRsp rsp;
+ ws->iBusAccess(top->iBusAvalon_address,&rsp.data,&rsp.error);
+ rsps.push(rsp);
+ }
+ }
+ //TODO doesn't catch when instruction removed ?
+ virtual void postCycle(){
+ if(!rsps.empty() && (!ws->iStall || VL_RANDOM_I_WIDTH(7) < 100)){
+ IBusSimpleAvalonRsp rsp = rsps.front(); rsps.pop();
+ top->iBusAvalon_readDataValid = 1;
+ top->iBusAvalon_readData = rsp.data;
+ top->iBusAvalon_response = rsp.error ? 3 : 0;
+ } else {
+ top->iBusAvalon_readDataValid = 0;
+ top->iBusAvalon_readData = VL_RANDOM_I_WIDTH(32);
+ top->iBusAvalon_response = VL_RANDOM_I_WIDTH(2);
+ }
+ if(ws->iStall)
+ top->iBusAvalon_waitRequestn = VL_RANDOM_I_WIDTH(7) < 100;
+ }
+};
+#endif
+
+
+
+#ifdef IBUS_SIMPLE_AHBLITE3
+class IBusSimpleAhbLite3 : public SimElement{
+public:
+ Workspace *ws;
+ VVexRiscv* top;
+
+ uint32_t iBusAhbLite3_HRDATA;
+ bool iBusAhbLite3_HRESP;
+ bool pending;
+
+ IBusSimpleAhbLite3(Workspace* ws){
+ this->ws = ws;
+ this->top = ws->top;
+ }
+
+ virtual void onReset(){
+ pending = false;
+ top->iBusAhbLite3_HREADY = 1;
+ top->iBusAhbLite3_HRESP = 0;
+ }
+
+ virtual void preCycle(){
+ if (top->iBusAhbLite3_HTRANS == 2 && top->iBusAhbLite3_HREADY && !top->iBusAhbLite3_HWRITE) {
+ ws->iBusAccess(top->iBusAhbLite3_HADDR,&iBusAhbLite3_HRDATA,&iBusAhbLite3_HRESP);
+ pending = true;
+ }
+ }
+
+ virtual void postCycle(){
+ if(ws->iStall)
+ top->iBusAhbLite3_HREADY = (!ws->iStall || VL_RANDOM_I_WIDTH(7) < 100);
+
+ if(pending && top->iBusAhbLite3_HREADY){
+ top->iBusAhbLite3_HRDATA = iBusAhbLite3_HRDATA;
+ top->iBusAhbLite3_HRESP = iBusAhbLite3_HRESP;
+ pending = false;
+ } else {
+ top->iBusAhbLite3_HRDATA = VL_RANDOM_I_WIDTH(32);
+ top->iBusAhbLite3_HRESP = VL_RANDOM_I_WIDTH(1);
+ }
+ }
+};
+#endif
+
+
+#ifdef IBUS_CACHED
+class IBusCached : public SimElement{
+public:
+ bool error_next = false;
+ uint32_t pendingCount = 0;
+ uint32_t address;
+
+ Workspace *ws;
+ VVexRiscv* top;
+ IBusCached(Workspace* ws){
+ this->ws = ws;
+ this->top = ws->top;
+ }
+
+
+ virtual void onReset(){
+ top->iBus_cmd_ready = 1;
+ top->iBus_rsp_valid = 0;
+ }
+
+ virtual void preCycle(){
+ if (top->iBus_cmd_valid && top->iBus_cmd_ready && pendingCount == 0) {
+ assertEq((top->iBus_cmd_payload_address & 3),0);
+ pendingCount = (1 << top->iBus_cmd_payload_size)/4;
+ address = top->iBus_cmd_payload_address;
+ }
+ }
+
+ virtual void postCycle(){
+ bool error;
+ top->iBus_rsp_valid = 0;
+ if(pendingCount != 0 && (!ws->iStall || VL_RANDOM_I_WIDTH(7) < 100)){
+ #ifdef IBUS_TC
+ if((address & 0x70000000) == 0){
+ printf("IBUS_CACHED access out of range\n");
+ ws->fail();
+ }
+ #endif
+ error = false;
+ for(int idx = 0;idx < IBUS_DATA_WIDTH/32;idx++){
+ bool localError = false;
+ ws->iBusAccess(address+idx*4,((uint32_t*)&top->iBus_rsp_payload_data)+idx,&localError);
+ error |= localError;
+ }
+ top->iBus_rsp_payload_error = error;
+ pendingCount-=IBUS_DATA_WIDTH/32;
+ address = address + IBUS_DATA_WIDTH/8;
+ top->iBus_rsp_valid = 1;
+ }
+ if(ws->iStall) top->iBus_cmd_ready = VL_RANDOM_I_WIDTH(7) < 100 && pendingCount == 0;
+ }
+};
+#endif
+
+#ifdef IBUS_CACHED_AVALON
+#include <queue>
+
+struct IBusCachedAvalonTask{
+ uint32_t address;
+ uint32_t pendingCount;
+};
+
+class IBusCachedAvalon : public SimElement{
+public:
+ uint32_t inst_next = VL_RANDOM_I_WIDTH(32);
+ bool error_next = false;
+
+ queue<IBusCachedAvalonTask> tasks;
+ Workspace *ws;
+ VVexRiscv* top;
+
+ IBusCachedAvalon(Workspace* ws){
+ this->ws = ws;
+ this->top = ws->top;
+ }
+
+ virtual void onReset(){
+ top->iBusAvalon_waitRequestn = 1;
+ top->iBusAvalon_readDataValid = 0;
+ }
+
+ virtual void preCycle(){
+ if (top->iBusAvalon_read && top->iBusAvalon_waitRequestn) {
+ assertEq(top->iBusAvalon_address & 3,0);
+ IBusCachedAvalonTask task;
+ task.address = top->iBusAvalon_address;
+ task.pendingCount = top->iBusAvalon_burstCount;
+ tasks.push(task);
+ }
+ }
+
+ virtual void postCycle(){
+ bool error;
+ top->iBusAvalon_readDataValid = 0;
+ if(!tasks.empty() && (!ws->iStall || VL_RANDOM_I_WIDTH(7) < 100)){
+ uint32_t &address = tasks.front().address;
+ uint32_t &pendingCount = tasks.front().pendingCount;
+ bool error;
+ ws->iBusAccess(address,&top->iBusAvalon_readData,&error);
+ top->iBusAvalon_response = error ? 3 : 0;
+ pendingCount--;
+ address = (address & ~0x1F) + ((address + 4) & 0x1F);
+ top->iBusAvalon_readDataValid = 1;
+ if(pendingCount == 0)
+ tasks.pop();
+ }
+ if(ws->iStall)
+ top->iBusAvalon_waitRequestn = VL_RANDOM_I_WIDTH(7) < 100;
+ }
+};
+#endif
+
+
+#if defined(IBUS_CACHED_WISHBONE) || defined(IBUS_SIMPLE_WISHBONE)
+#include <queue>
+
+class IBusCachedWishbone : public SimElement{
+public:
+
+ Workspace *ws;
+ VVexRiscv* top;
+
+ IBusCachedWishbone(Workspace* ws){
+ this->ws = ws;
+ this->top = ws->top;
+ }
+
+ virtual void onReset(){
+ top->iBusWishbone_ACK = !ws->iStall;
+ top->iBusWishbone_ERR = 0;
+ }
+
+ virtual void preCycle(){
+
+ }
+
+ virtual void postCycle(){
+
+ if(ws->iStall)
+ top->iBusWishbone_ACK = VL_RANDOM_I_WIDTH(7) < 100;
+
+ top->iBusWishbone_DAT_MISO = VL_RANDOM_I_WIDTH(32);
+ if (top->iBusWishbone_CYC && top->iBusWishbone_STB && top->iBusWishbone_ACK) {
+ if(top->iBusWishbone_WE){
+
+ } else {
+ bool error;
+ ws->iBusAccess(top->iBusWishbone_ADR << 2,&top->iBusWishbone_DAT_MISO,&error);
+ top->iBusWishbone_ERR = error;
+ }
+ }
+ }
+};
+#endif
+
+
+#ifdef DBUS_SIMPLE
+class DBusSimple : public SimElement{
+public:
+ uint32_t data_next = VL_RANDOM_I_WIDTH(32);
+ bool error_next = false;
+ bool pending = false;
+
+ Workspace *ws;
+ VVexRiscv* top;
+ DBusSimple(Workspace* ws){
+ this->ws = ws;
+ this->top = ws->top;
+ }
+
+ virtual void onReset(){
+ top->dBus_cmd_ready = 1;
+ top->dBus_rsp_ready = 1;
+ }
+
+ virtual void preCycle(){
+ if (top->dBus_cmd_valid && top->dBus_cmd_ready) {
+ pending = true;
+ data_next = top->dBus_cmd_payload_data;
+ ws->dBusAccess(top->dBus_cmd_payload_address,top->dBus_cmd_payload_wr,1 << top->dBus_cmd_payload_size,((uint8_t*)&data_next) + (top->dBus_cmd_payload_address & 3),&error_next);
+ }
+ }
+
+ virtual void postCycle(){
+ top->dBus_rsp_ready = 0;
+ if(pending && (!ws->dStall || VL_RANDOM_I_WIDTH(7) < 100)){
+ pending = false;
+ top->dBus_rsp_ready = 1;
+ top->dBus_rsp_data = data_next;
+ top->dBus_rsp_error = error_next;
+ } else{
+ top->dBus_rsp_data = VL_RANDOM_I_WIDTH(32);
+ }
+
+ if(ws->dStall) top->dBus_cmd_ready = VL_RANDOM_I_WIDTH(7) < 100 && !pending;
+ }
+};
+#endif
+
+#ifdef DBUS_SIMPLE_AVALON
+#include <queue>
+struct DBusSimpleAvalonRsp{
+ uint32_t data;
+ bool error;
+};
+
+
+class DBusSimpleAvalon : public SimElement{
+public:
+ queue<DBusSimpleAvalonRsp> rsps;
+
+ Workspace *ws;
+ VVexRiscv* top;
+ DBusSimpleAvalon(Workspace* ws){
+ this->ws = ws;
+ this->top = ws->top;
+ }
+
+ virtual void onReset(){
+ top->dBusAvalon_waitRequestn = 1;
+ top->dBusAvalon_readDataValid = 0;
+ }
+
+ virtual void preCycle(){
+ if (top->dBusAvalon_write && top->dBusAvalon_waitRequestn) {
+ bool dummy;
+ ws->dBusAccess(top->dBusAvalon_address,1,2,top->dBusAvalon_byteEnable,&top->dBusAvalon_writeData,&dummy);
+ }
+ if (top->dBusAvalon_read && top->dBusAvalon_waitRequestn) {
+ DBusSimpleAvalonRsp rsp;
+ ws->dBusAccess(top->dBusAvalon_address,0,2,0xF,&rsp.data,&rsp.error);
+ rsps.push(rsp);
+ }
+ }
+ //TODO doesn't catch when instruction removed ?
+ virtual void postCycle(){
+ if(!rsps.empty() && (!ws->iStall || VL_RANDOM_I_WIDTH(7) < 100)){
+ DBusSimpleAvalonRsp rsp = rsps.front(); rsps.pop();
+ top->dBusAvalon_readDataValid = 1;
+ top->dBusAvalon_readData = rsp.data;
+ top->dBusAvalon_response = rsp.error ? 3 : 0;
+ } else {
+ top->dBusAvalon_readDataValid = 0;
+ top->dBusAvalon_readData = VL_RANDOM_I_WIDTH(32);
+ top->dBusAvalon_response = VL_RANDOM_I_WIDTH(2);
+ }
+ if(ws->iStall)
+ top->dBusAvalon_waitRequestn = VL_RANDOM_I_WIDTH(7) < 100;
+ }
+};
+#endif
+
+
+
+#ifdef DBUS_SIMPLE_AHBLITE3
+class DBusSimpleAhbLite3 : public SimElement{
+public:
+ Workspace *ws;
+ VVexRiscv* top;
+
+ uint32_t dBusAhbLite3_HADDR, dBusAhbLite3_HSIZE, dBusAhbLite3_HTRANS, dBusAhbLite3_HWRITE;
+
+ DBusSimpleAhbLite3(Workspace* ws){
+ this->ws = ws;
+ this->top = ws->top;
+ }
+
+ virtual void onReset(){
+ top->dBusAhbLite3_HREADY = 1;
+ top->dBusAhbLite3_HRESP = 0;
+ dBusAhbLite3_HTRANS = 0;
+ }
+
+ virtual void preCycle(){
+ if(top->dBusAhbLite3_HREADY && dBusAhbLite3_HTRANS == 2 && dBusAhbLite3_HWRITE){
+ uint32_t data = top->dBusAhbLite3_HWDATA;
+ bool error;
+ ws->dBusAccess(dBusAhbLite3_HADDR, 1, dBusAhbLite3_HSIZE, ((1 << (1 << dBusAhbLite3_HSIZE))-1) << (dBusAhbLite3_HADDR & 0x3),&data,&error);
+ }
+
+ if(top->dBusAhbLite3_HREADY){
+ dBusAhbLite3_HADDR = top->dBusAhbLite3_HADDR ;
+ dBusAhbLite3_HSIZE = top->dBusAhbLite3_HSIZE ;
+ dBusAhbLite3_HTRANS = top->dBusAhbLite3_HTRANS ;
+ dBusAhbLite3_HWRITE = top->dBusAhbLite3_HWRITE ;
+ }
+ }
+
+ virtual void postCycle(){
+ if(ws->iStall)
+ top->dBusAhbLite3_HREADY = (!ws->iStall || VL_RANDOM_I_WIDTH(7) < 100);
+
+ top->dBusAhbLite3_HRDATA = VL_RANDOM_I_WIDTH(32);
+ top->dBusAhbLite3_HRESP = VL_RANDOM_I_WIDTH(1);
+
+ if(top->dBusAhbLite3_HREADY && dBusAhbLite3_HTRANS == 2 && !dBusAhbLite3_HWRITE){
+
+ bool error;
+ ws->dBusAccess(dBusAhbLite3_HADDR, 0, dBusAhbLite3_HSIZE, ((1 << (1 << dBusAhbLite3_HSIZE))-1) << (dBusAhbLite3_HADDR & 0x3),&top->dBusAhbLite3_HRDATA,&error);
+ top->dBusAhbLite3_HRESP = error;
+ }
+ }
+};
+#endif
+
+
+#if defined(DBUS_CACHED_WISHBONE) || defined(DBUS_SIMPLE_WISHBONE)
+#include <queue>
+
+
+class DBusCachedWishbone : public SimElement{
+public:
+
+ Workspace *ws;
+ VVexRiscv* top;
+
+ DBusCachedWishbone(Workspace* ws){
+ this->ws = ws;
+ this->top = ws->top;
+ }
+
+ virtual void onReset(){
+ top->dBusWishbone_ACK = !ws->iStall;
+ top->dBusWishbone_ERR = 0;
+ }
+
+ virtual void preCycle(){
+
+ }
+
+ virtual void postCycle(){
+ if(ws->iStall)
+ top->dBusWishbone_ACK = VL_RANDOM_I_WIDTH(7) < 100;
+ top->dBusWishbone_DAT_MISO = VL_RANDOM_I_WIDTH(32);
+ if (top->dBusWishbone_CYC && top->dBusWishbone_STB && top->dBusWishbone_ACK) {
+ if(top->dBusWishbone_WE){
+ bool dummy;
+ ws->dBusAccess(top->dBusWishbone_ADR << 2 ,1,2,top->dBusWishbone_SEL,&top->dBusWishbone_DAT_MOSI,&dummy);
+ } else {
+ bool error;
+ ws->dBusAccess(top->dBusWishbone_ADR << 2,0,2,0xF,&top->dBusWishbone_DAT_MISO,&error);
+ top->dBusWishbone_ERR = error;
+ }
+ }
+ }
+};
+#endif
+
+#ifdef DBUS_CACHED
+
+//#include "VVexRiscv_DataCache.h"
+#include <queue>
+
+struct DBusCachedTask{
+ char data[DBUS_LOAD_DATA_WIDTH/8];
+ bool error;
+ bool last;
+ bool exclusive;
+};
+
+class DBusCached : public SimElement{
+public:
+ queue<DBusCachedTask> rsps;
+ queue<uint32_t> invalidationHint;
+
+ bool reservationValid = false;
+ uint32_t reservationAddress;
+ uint32_t pendingSync = 0;
+
+ Workspace *ws;
+ VVexRiscv* top;
+ DBusCachedTask rsp;
+
+ DBusCached(Workspace* ws){
+ this->ws = ws;
+ this->top = ws->top;
+ }
+
+ virtual void onReset(){
+ top->dBus_cmd_ready = 1;
+ top->dBus_rsp_valid = 0;
+ #ifdef DBUS_AGGREGATION
+ top->dBus_rsp_payload_aggregated = 0;
+ #endif
+ #ifdef DBUS_INVALIDATE
+ top->dBus_inv_valid = 0;
+ top->dBus_ack_ready = 0;
+ top->dBus_sync_valid = 0;
+ #ifdef DBUS_AGGREGATION
+ top->dBus_sync_payload_aggregated = 0;
+ #endif
+ #endif
+ }
+
+ virtual void preCycle(){
+ if (top->dBus_cmd_valid && top->dBus_cmd_ready) {
+ if(top->dBus_cmd_payload_wr){
+ int size = 1 << top->dBus_cmd_payload_size;
+ #ifdef DBUS_INVALIDATE
+ pendingSync += 1;
+ #endif
+ #ifndef DBUS_EXCLUSIVE
+ bool error;
+ int shift = top->dBus_cmd_payload_address & (DBUS_STORE_DATA_WIDTH/8-1);
+ ws->dBusAccess(top->dBus_cmd_payload_address,1,size,((uint8_t*)&top->dBus_cmd_payload_data) + shift,&error);
+ #else
+ bool cancel = false, error = false;
+ if(top->dBus_cmd_payload_exclusive){
+ bool hit = reservationValid && reservationAddress == top->dBus_cmd_payload_address;
+ rsp.exclusive = hit;
+ cancel = !hit;
+ }
+ if(!cancel) {
+ for(int idx = 0;idx < 1;idx++){
+ bool localError = false;
+ int shift = top->dBus_cmd_payload_address & (DBUS_STORE_DATA_WIDTH/8-1);
+ ws->dBusAccess(top->dBus_cmd_payload_address,1,size,((uint8_t*)&top->dBus_cmd_payload_data) + shift,&localError);
+ error |= localError;
+ }
+ }
+
+ reservationValid = false;
+ rsp.last = true;
+ rsp.error = error;
+ rsps.push(rsp);
+ #endif
+ } else {
+ bool error = false;
+ uint32_t beatCount = (((1 << top->dBus_cmd_payload_size)*8+DBUS_LOAD_DATA_WIDTH-1) / DBUS_LOAD_DATA_WIDTH)-1;
+ uint32_t startAt = top->dBus_cmd_payload_address;
+ uint32_t endAt = top->dBus_cmd_payload_address + (1 << top->dBus_cmd_payload_size);
+ uint32_t address = top->dBus_cmd_payload_address & ~(DBUS_LOAD_DATA_WIDTH/8-1);
+ uint8_t buffer[64];
+ ws->dBusAccess(top->dBus_cmd_payload_address,0,1 << top->dBus_cmd_payload_size,buffer, &error);
+ for(int beat = 0;beat <= beatCount;beat++){
+ for(int i = 0;i < DBUS_LOAD_DATA_WIDTH/8;i++){
+ rsp.data[i] = (address >= startAt && address < endAt) ? buffer[address-top->dBus_cmd_payload_address] : VL_RANDOM_I_WIDTH(8);
+ address += 1;
+ }
+ rsp.last = beat == beatCount;
+ #ifdef DBUS_EXCLUSIVE
+ if(top->dBus_cmd_payload_exclusive){
+ rsp.exclusive = true;
+ reservationValid = true;
+ reservationAddress = top->dBus_cmd_payload_address;
+ }
+ #endif
+ rsp.error = error;
+ rsps.push(rsp);
+ }
+
+ #ifdef DBUS_INVALIDATE
+ if(ws->allowInvalidate){
+ if(VL_RANDOM_I_WIDTH(7) < 10){
+ invalidationHint.push(top->dBus_cmd_payload_address + VL_RANDOM_I_WIDTH(5));
+ }
+ }
+ #endif
+ }
+ }
+ #ifdef DBUS_INVALIDATE
+ if(top->dBus_sync_valid && top->dBus_sync_ready){
+ pendingSync -= 1;
+ }
+ #endif
+ }
+
+ virtual void postCycle(){
+
+ if(!rsps.empty() && (!ws->dStall || VL_RANDOM_I_WIDTH(7) < 100)){
+ DBusCachedTask rsp = rsps.front();
+ rsps.pop();
+ top->dBus_rsp_valid = 1;
+ top->dBus_rsp_payload_error = rsp.error;
+ for(int idx = 0;idx < DBUS_LOAD_DATA_WIDTH/32;idx++){
+ ((uint32_t*)&top->dBus_rsp_payload_data)[idx] = ((uint32_t*)rsp.data)[idx];
+ }
+ top->dBus_rsp_payload_last = rsp.last;
+ #ifdef DBUS_EXCLUSIVE
+ top->dBus_rsp_payload_exclusive = rsp.exclusive;
+ #endif
+ } else{
+ top->dBus_rsp_valid = 0;
+ for(int idx = 0;idx < DBUS_LOAD_DATA_WIDTH/32;idx++){
+ ((uint32_t*)&top->dBus_rsp_payload_data)[idx] = VL_RANDOM_I_WIDTH(32);
+ }
+ top->dBus_rsp_payload_error = VL_RANDOM_I_WIDTH(1);
+ top->dBus_rsp_payload_last = VL_RANDOM_I_WIDTH(1);
+ #ifdef DBUS_EXCLUSIVE
+ top->dBus_rsp_payload_exclusive = VL_RANDOM_I_WIDTH(1);
+ #endif
+ }
+ top->dBus_cmd_ready = (ws->dStall ? VL_RANDOM_I_WIDTH(7) < 100 : 1);
+
+ #ifdef DBUS_INVALIDATE
+ if(ws->allowInvalidate){
+ if(top->dBus_inv_ready) top->dBus_inv_valid = 0;
+ if(top->dBus_inv_valid == 0 && VL_RANDOM_I_WIDTH(7) < 5){
+ top->dBus_inv_valid = 1;
+ top->dBus_inv_payload_fragment_enable = VL_RANDOM_I_WIDTH(7) < 100;
+ if(!invalidationHint.empty()){
+ top->dBus_inv_payload_fragment_address = invalidationHint.front();
+ invalidationHint.pop();
+ } else {
+ top->dBus_inv_payload_fragment_address = VL_RANDOM_I_WIDTH(32);
+ }
+ }
+ }
+ top->dBus_ack_ready = (ws->dStall ? VL_RANDOM_I_WIDTH(7) < 100 : 1);
+ if(top->dBus_sync_ready) top->dBus_sync_valid = 0;
+ if(top->dBus_sync_valid == 0 && pendingSync != 0 && (ws->dStall ? VL_RANDOM_I_WIDTH(7) < 80 : 1) ){
+ top->dBus_sync_valid = 1;
+ }
+ #endif
+
+ }
+};
+#endif
+
+#ifdef DBUS_CACHED_AVALON
+#include <queue>
+
+struct DBusCachedAvalonTask{
+ uint32_t data;
+ bool error;
+};
+
+class DBusCachedAvalon : public SimElement{
+public:
+ uint32_t beatCounter = 0;
+ queue<DBusCachedAvalonTask> rsps;
+
+ Workspace *ws;
+ VVexRiscv* top;
+ DBusCachedAvalon(Workspace* ws){
+ this->ws = ws;
+ this->top = ws->top;
+ }
+
+ virtual void onReset(){
+ top->dBusAvalon_waitRequestn = 1;
+ top->dBusAvalon_readDataValid = 0;
+ }
+
+
+ virtual void preCycle(){
+ if ((top->dBusAvalon_read || top->dBusAvalon_write) && top->dBusAvalon_waitRequestn) {
+ if(top->dBusAvalon_write){
+ uint32_t size = __builtin_popcount(top->dBusAvalon_byteEnable);
+ uint32_t offset = ffs(top->dBusAvalon_byteEnable)-1;
+ bool error_next = false;
+ ws->dBusAccess(top->dBusAvalon_address + beatCounter * 4 + offset,1,size,((uint8_t*)&top->dBusAvalon_writeData)+offset,&error_next);
+ beatCounter++;
+ if(beatCounter == top->dBusAvalon_burstCount){
+ beatCounter = 0;
+ }
+ } else {
+ for(int beat = 0;beat < top->dBusAvalon_burstCount;beat++){
+ DBusCachedAvalonTask rsp;
+ ws->dBusAccess(top->dBusAvalon_address + beat * 4 ,0,4,((uint8_t*)&rsp.data),&rsp.error);
+ rsps.push(rsp);
+ }
+ }
+ }
+ }
+
+ virtual void postCycle(){
+ if(!rsps.empty() && (!ws->dStall || VL_RANDOM_I_WIDTH(7) < 100)){
+ DBusCachedAvalonTask rsp = rsps.front();
+ rsps.pop();
+ top->dBusAvalon_response = rsp.error ? 3 : 0;
+ top->dBusAvalon_readData = rsp.data;
+ top->dBusAvalon_readDataValid = 1;
+ } else{
+ top->dBusAvalon_readDataValid = 0;
+ top->dBusAvalon_readData = VL_RANDOM_I_WIDTH(32);
+ top->dBusAvalon_response = VL_RANDOM_I_WIDTH(2); //TODO
+ }
+
+ top->dBusAvalon_waitRequestn = (ws->dStall ? VL_RANDOM_I_WIDTH(7) < 100 : 1);
+ }
+};
+#endif
+
+
+#ifdef DEBUG_PLUGIN
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <netinet/tcp.h>
+
+/** Returns true on success, or false if there was an error */
+bool SetSocketBlockingEnabled(int fd, bool blocking)
+{
+ if (fd < 0) return false;
+
+#ifdef WIN32
+ unsigned long mode = blocking ? 0 : 1;
+ return (ioctlsocket(fd, FIONBIO, &mode) == 0) ? true : false;
+#else
+ int flags = fcntl(fd, F_GETFL, 0);
+ if (flags < 0) return false;
+ flags = blocking ? (flags&~O_NONBLOCK) : (flags|O_NONBLOCK);
+ return (fcntl(fd, F_SETFL, flags) == 0) ? true : false;
+#endif
+}
+
+struct DebugPluginTask{
+ bool wr;
+ uint32_t address;
+ uint32_t data;
+};
+
+class DebugPlugin : public SimElement{
+public:
+ Workspace *ws;
+ VVexRiscv* top;
+
+ int serverSocket, clientHandle;
+ struct sockaddr_in serverAddr;
+ struct sockaddr_storage serverStorage;
+ socklen_t addr_size;
+ char buffer[1024];
+ uint32_t timeSpacer = 0;
+ bool taskValid = false;
+ DebugPluginTask task;
+
+
+ DebugPlugin(Workspace* ws){
+ this->ws = ws;
+ this->top = ws->top;
+
+ #ifdef DEBUG_PLUGIN_EXTERNAL
+ ws->mTimeCmp = ~0;
+ #endif
+ top->debugReset = 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);
+ int flag = 1;
+ int result = 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 */
+
+ //---- Configure settings of the server address struct ----//
+ // Address family = Internet //
+ serverAddr.sin_family = AF_INET;
+ // Set port number, using htons function to use proper byte order //
+ serverAddr.sin_port = htons(7893);
+ // Set IP address to localhost //
+ serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
+ // Set all bits of the padding field to 0 //
+ 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;
+ }
+
+ virtual ~DebugPlugin(){
+ if(clientHandle != -1) {
+ shutdown(clientHandle,SHUT_RDWR);
+ usleep(100);
+ }
+ if(serverSocket != -1) {
+ close(serverSocket);
+ usleep(100);
+ }
+ }
+
+ virtual void onReset(){
+ top->debugReset = 1;
+ }
+
+
+
+ virtual void postReset(){
+ top->debugReset = 0;
+ }
+
+ void connectionReset(){
+ printf("CONNECTION RESET\n");
+ shutdown(clientHandle,SHUT_RDWR);
+ clientHandle = -1;
+ }
+
+
+ virtual void preCycle(){
+
+ }
+
+ virtual void postCycle(){
+ top->reset = top->debug_resetOut;
+ if(timeSpacer == 0){
+ if(clientHandle == -1){
+ clientHandle = accept(serverSocket, (struct sockaddr *) &serverStorage, &addr_size);
+ if(clientHandle != -1)
+ printf("CONNECTED\n");
+ timeSpacer = 1000;
+ }
+
+
+ if(clientHandle != -1 && taskValid == false){
+ int requiredSize = 1 + 1 + 4 + 4;
+ int n;
+ timeSpacer = 20;
+ if(ioctl(clientHandle,FIONREAD,&n) != 0){
+ connectionReset();
+ } else if(n >= requiredSize){
+ if(requiredSize != read(clientHandle,buffer,requiredSize)){
+ connectionReset();
+ } else {
+ bool wr = buffer[0];
+ uint32_t size = buffer[1];
+ uint32_t address = *((uint32_t*)(buffer + 2));
+ uint32_t data = *((uint32_t*)(buffer + 6));
+
+ if((address & ~ 0x4) == 0xF00F0000){
+ assert(size == 2);
+ timeSpacer = 100;
+
+ taskValid = true;
+ task.wr = wr;
+ task.address = address;
+ task.data = data;
+ }
+ }
+ } else {
+ int error = 0;
+ socklen_t len = sizeof (error);
+ int retval = getsockopt (clientHandle, SOL_SOCKET, SO_ERROR, &error, &len);
+ if (retval != 0 || error != 0) {
+ connectionReset();
+ }
+ }
+ }
+ } else {
+ timeSpacer--;
+ }
+ }
+
+ void sendRsp(uint32_t data){
+ if(clientHandle != -1){
+ if(send(clientHandle,&data,4,0) == -1) connectionReset();
+ }
+ }
+};
+#endif
+
+#ifdef DEBUG_PLUGIN_STD
+class DebugPluginStd : public DebugPlugin{
+public:
+ DebugPluginStd(Workspace* ws) : DebugPlugin(ws){
+
+ }
+
+ virtual void onReset(){
+ DebugPlugin::onReset();
+ top->debug_bus_cmd_valid = 0;
+ }
+
+ bool rspFire = false;
+
+ virtual void preCycle(){
+ DebugPlugin::preCycle();
+
+ if(rspFire){
+ sendRsp(top->debug_bus_rsp_data);
+ rspFire = false;
+ }
+
+ if(top->debug_bus_cmd_valid && top->debug_bus_cmd_ready){
+ taskValid = false;
+ if(!top->debug_bus_cmd_payload_wr){
+ rspFire = true;
+ }
+ }
+ }
+
+ virtual void postCycle(){
+ DebugPlugin::postCycle();
+
+ if(taskValid){
+ top->debug_bus_cmd_valid = 1;
+ top->debug_bus_cmd_payload_wr = task.wr;
+ top->debug_bus_cmd_payload_address = task.address;
+ top->debug_bus_cmd_payload_data = task.data;
+ }else {
+ top->debug_bus_cmd_valid = 0;
+ top->debug_bus_cmd_payload_wr = VL_RANDOM_I_WIDTH(1);
+ top->debug_bus_cmd_payload_address = VL_RANDOM_I_WIDTH(8);
+ top->debug_bus_cmd_payload_data = VL_RANDOM_I_WIDTH(32);
+ }
+ }
+};
+
+#endif
+
+#ifdef DEBUG_PLUGIN_AVALON
+class DebugPluginAvalon : public DebugPlugin{
+public:
+ DebugPluginAvalon(Workspace* ws) : DebugPlugin(ws){
+
+ }
+
+ virtual void onReset(){
+ DebugPlugin::onReset();
+ top->debugBusAvalon_read = 0;
+ top->debugBusAvalon_write = 0;
+ }
+
+ bool rspFire = false;
+
+ virtual void preCycle(){
+ DebugPlugin::preCycle();
+
+ if(rspFire){
+ sendRsp(top->debugBusAvalon_readData);
+ rspFire = false;
+ }
+
+ if((top->debugBusAvalon_read || top->debugBusAvalon_write) && top->debugBusAvalon_waitRequestn){
+ taskValid = false;
+ if(top->debugBusAvalon_read){
+ rspFire = true;
+ }
+ }
+ }
+
+ virtual void postCycle(){
+ DebugPlugin::postCycle();
+
+ if(taskValid){
+ top->debugBusAvalon_write = task.wr;
+ top->debugBusAvalon_read = !task.wr;
+ top->debugBusAvalon_address = task.address;
+ top->debugBusAvalon_writeData = task.data;
+ }else {
+ top->debugBusAvalon_write = 0;
+ top->debugBusAvalon_read = 0;
+ top->debugBusAvalon_address = VL_RANDOM_I_WIDTH(8);
+ top->debugBusAvalon_writeData = VL_RANDOM_I_WIDTH(32);
+ }
+ }
+};
+
+#endif
+
+void Workspace::fillSimELements(){
+ #ifdef IBUS_SIMPLE
+ simElements.push_back(new IBusSimple(this));
+ #endif
+ #ifdef IBUS_SIMPLE_AVALON
+ simElements.push_back(new IBusSimpleAvalon(this));
+ #endif
+ #ifdef IBUS_SIMPLE_AHBLITE3
+ simElements.push_back(new IBusSimpleAhbLite3(this));
+ #endif
+
+
+ #ifdef IBUS_CACHED
+ simElements.push_back(new IBusCached(this));
+ #endif
+ #ifdef IBUS_CACHED_AVALON
+ simElements.push_back(new IBusCachedAvalon(this));
+ #endif
+ #if defined(IBUS_CACHED_WISHBONE) || defined(IBUS_SIMPLE_WISHBONE)
+ simElements.push_back(new IBusCachedWishbone(this));
+ #endif
+
+ #ifdef IBUS_TC
+ simElements.push_back(new IBusTc(this));
+ #endif
+
+ #ifdef DBUS_SIMPLE
+ simElements.push_back(new DBusSimple(this));
+ #endif
+ #ifdef DBUS_SIMPLE_AVALON
+ simElements.push_back(new DBusSimpleAvalon(this));
+ #endif
+ #ifdef DBUS_SIMPLE_AHBLITE3
+ simElements.push_back(new DBusSimpleAhbLite3(this));
+ #endif
+ #ifdef DBUS_CACHED
+ simElements.push_back(new DBusCached(this));
+ #endif
+ #ifdef DBUS_CACHED_AVALON
+ simElements.push_back(new DBusCachedAvalon(this));
+ #endif
+ #if defined(DBUS_CACHED_WISHBONE) || defined(DBUS_SIMPLE_WISHBONE)
+ simElements.push_back(new DBusCachedWishbone(this));
+ #endif
+ #ifdef DEBUG_PLUGIN_STD
+ simElements.push_back(new DebugPluginStd(this));
+ #endif
+ #ifdef DEBUG_PLUGIN_AVALON
+ simElements.push_back(new DebugPluginAvalon(this));
+ #endif
+}
+
+mutex Workspace::staticMutex;
+uint64_t Workspace::cycles = 0;
+uint32_t Workspace::testsCounter = 0, Workspace::successCounter = 0;
+
+#ifndef REF
+#define testA1ReagFileWriteRef {1,10},{2,20},{3,40},{4,60}
+#define testA2ReagFileWriteRef {5,1},{7,3}
+uint32_t regFileWriteRefArray[][2] = {
+ testA1ReagFileWriteRef,
+ testA1ReagFileWriteRef,
+ testA2ReagFileWriteRef,
+ testA2ReagFileWriteRef
+};
+
+class TestA : public WorkspaceRegression{
+public:
+
+
+ uint32_t regFileWriteRefIndex = 0;
+
+ TestA() : WorkspaceRegression("testA") {
+ loadHex(string(REGRESSION_PATH) + "../../resources/hex/testA.hex");
+ }
+
+ virtual void checks(){
+ if(top->VexRiscv->lastStageRegFileWrite_valid == 1 && top->VexRiscv->lastStageRegFileWrite_payload_address != 0){
+ assertEq(top->VexRiscv->lastStageRegFileWrite_payload_address, regFileWriteRefArray[regFileWriteRefIndex][0]);
+ assertEq(top->VexRiscv->lastStageRegFileWrite_payload_data, regFileWriteRefArray[regFileWriteRefIndex][1]);
+ //printf("%d\n",i);
+
+ regFileWriteRefIndex++;
+ if(regFileWriteRefIndex == sizeof(regFileWriteRefArray)/sizeof(regFileWriteRefArray[0])){
+ pass();
+ }
+ }
+ }
+};
+
+class TestX28 : public WorkspaceRegression{
+public:
+ uint32_t refIndex = 0;
+ uint32_t *ref;
+ uint32_t refSize;
+
+ TestX28(string name, uint32_t *ref, uint32_t refSize) : WorkspaceRegression(name) {
+ this->ref = ref;
+ this->refSize = refSize;
+ loadHex(string(REGRESSION_PATH) + "../../resources/hex/" + name + ".hex");
+ }
+
+ virtual void checks(){
+ if(top->VexRiscv->lastStageRegFileWrite_valid == 1 && top->VexRiscv->lastStageRegFileWrite_payload_address == 28){
+ assertEq(top->VexRiscv->lastStageRegFileWrite_payload_data, ref[refIndex]);
+ //printf("%d\n",i);
+
+ refIndex++;
+ if(refIndex == refSize){
+ pass();
+ }
+ }
+ }
+};
+
+
+class RiscvTest : public WorkspaceRegression{
+public:
+ RiscvTest(string name) : WorkspaceRegression(name) {
+ loadHex(string(REGRESSION_PATH) + "../../resources/hex/" + name + ".hex");
+ bootAt(0x800000bcu);
+ }
+
+ virtual void postReset() {
+// #ifdef CSR
+// top->VexRiscv->prefetch_PcManagerSimplePlugin_pcReg = 0x80000000u;
+// #else
+// #endif
+ }
+
+ virtual void checks(){
+ if(top->VexRiscv->lastStageIsFiring && top->VexRiscv->lastStageInstruction == 0x00000013){
+ uint32_t instruction;
+ bool error;
+ Workspace::mem.read(top->VexRiscv->lastStagePc, 4, (uint8_t*)&instruction);
+ //printf("%x => %x\n", top->VexRiscv->lastStagePc, instruction );
+ if(instruction == 0x00000073){
+ uint32_t code = top->VexRiscv->RegFilePlugin_regFile[28];
+ uint32_t code2 = top->VexRiscv->RegFilePlugin_regFile[3];
+ if((code & 1) == 0 && (code2 & 1) == 0){
+ cout << "Wrong error code"<< endl;
+ fail();
+ }
+ if(code == 1 || code2 == 1){
+ pass();
+ }else{
+ cout << "Error code " << code2/2 << endl;
+ fail();
+ }
+ }
+ }
+ }
+
+ virtual void iBusAccess(uint32_t addr, uint32_t *data, bool *error){
+ WorkspaceRegression::iBusAccess(addr,data,error);
+ if(*data == 0x0ff0000f) *data = 0x00000013;
+ if(*data == 0x00000073) *data = 0x00000013;
+ }
+};
+#endif
+class Dhrystone : public WorkspaceRegression{
+public:
+ string hexName;
+ Dhrystone(string name,string hexName,bool iStall, bool dStall) : WorkspaceRegression(name) {
+ setIStall(iStall);
+ setDStall(dStall);
+ withRiscvRef();
+ loadHex(string(REGRESSION_PATH) + "../../resources/hex/" + hexName + ".hex");
+ this->hexName = hexName;
+ }
+
+ virtual void checks(){
+
+ }
+
+ virtual void pass(){
+ FILE *refFile = fopen((hexName + ".logRef").c_str(), "r");
+ fseek(refFile, 0, SEEK_END);
+ uint32_t refSize = ftell(refFile);
+ fseek(refFile, 0, SEEK_SET);
+ char* ref = new char[refSize];
+ fread(ref, 1, refSize, refFile);
+ fclose(refFile);
+
+
+ logTraces.flush();
+ logTraces.close();
+
+ FILE *logFile = fopen((name + ".logTrace").c_str(), "r");
+ fseek(logFile, 0, SEEK_END);
+ uint32_t logSize = ftell(logFile);
+ fseek(logFile, 0, SEEK_SET);
+ char* log = new char[logSize];
+ fread(log, 1, logSize, logFile);
+ fclose(logFile);
+
+ if(refSize > logSize || memcmp(log,ref,refSize))
+ fail();
+ else
+ Workspace::pass();
+ }
+};
+
+class Compliance : public WorkspaceRegression{
+public:
+ string name;
+ ofstream out32;
+ int out32Counter = 0;
+ Compliance(string name) : WorkspaceRegression(name) {
+ withRiscvRef();
+ loadHex(string(REGRESSION_PATH) + "../../resources/hex/" + name + ".elf.hex");
+ out32.open (name + ".out32");
+ this->name = name;
+ }
+
+
+ virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size, uint8_t *dataBytes, bool *error) {
+ if(wr && addr == 0xF00FFF2C){
+ uint32_t *data = (uint32_t*)dataBytes;
+ out32 << hex << setw(8) << std::setfill('0') << *data << dec;
+ if(++out32Counter % 4 == 0) out32 << "\n";
+ }
+ WorkspaceRegression::dBusAccess(addr,wr,size,dataBytes,error);
+ }
+
+ virtual void checks(){
+
+ }
+
+
+
+ virtual void pass(){
+ FILE *refFile = fopen((string(REGRESSION_PATH) + string("../../resources/ref/") + name + ".reference_output").c_str(), "r");
+ fseek(refFile, 0, SEEK_END);
+ uint32_t refSize = ftell(refFile);
+ fseek(refFile, 0, SEEK_SET);
+ char* ref = new char[refSize];
+ fread(ref, 1, refSize, refFile);
+ fclose(refFile);
+
+
+ out32.flush();
+ out32.close();
+
+ FILE *logFile = fopen((name + ".out32").c_str(), "r");
+ fseek(logFile, 0, SEEK_END);
+ uint32_t logSize = ftell(logFile);
+ fseek(logFile, 0, SEEK_SET);
+ char* log = new char[logSize];
+ fread(log, 1, logSize, logFile);
+ fclose(logFile);
+
+ if(refSize > logSize || memcmp(log,ref,refSize))
+ fail();
+ else
+ Workspace::pass();
+ }
+};
+
+
+#ifdef DEBUG_PLUGIN
+
+#include<pthread.h>
+#include<stdlib.h>
+#include<unistd.h>
+#include <netinet/tcp.h>
+
+#define RISCV_SPINAL_FLAGS_RESET 1<<0
+#define RISCV_SPINAL_FLAGS_HALT 1<<1
+#define RISCV_SPINAL_FLAGS_PIP_BUSY 1<<2
+#define RISCV_SPINAL_FLAGS_IS_IN_BREAKPOINT 1<<3
+#define RISCV_SPINAL_FLAGS_STEP 1<<4
+#define RISCV_SPINAL_FLAGS_PC_INC 1<<5
+
+#define RISCV_SPINAL_FLAGS_RESET_SET 1<<16
+#define RISCV_SPINAL_FLAGS_HALT_SET 1<<17
+
+#define RISCV_SPINAL_FLAGS_RESET_CLEAR 1<<24
+#define RISCV_SPINAL_FLAGS_HALT_CLEAR 1<<25
+
+class DebugPluginTest : public WorkspaceRegression{
+public:
+ pthread_t clientThreadId;
+ char buffer[1024];
+ bool clientSuccess = false, clientFail = false;
+
+ static void* clientThreadWrapper(void *debugModule){
+ ((DebugPluginTest*)debugModule)->clientThread();
+ return NULL;
+ }
+
+ int clientSocket;
+ void accessCmd(bool wr, uint32_t size, uint32_t address, uint32_t data){
+ buffer[0] = wr;
+ buffer[1] = size;
+ *((uint32_t*) (buffer + 2)) = address;
+ *((uint32_t*) (buffer + 6)) = data;
+ send(clientSocket,buffer,10,0);
+ }
+
+ void writeCmd(uint32_t size, uint32_t address, uint32_t data){
+ accessCmd(true, 2, address, data);
+ }
+
+
+ uint32_t readCmd(uint32_t size, uint32_t address){
+ accessCmd(false, 2, address, VL_RANDOM_I_WIDTH(32));
+ int error;
+ if((error = recv(clientSocket, buffer, 4, 0)) != 4){
+ printf("Should read 4 bytes, had %d", error);
+ while(1);
+ }
+
+ return *((uint32_t*) buffer);
+ }
+
+
+
+ void clientThread(){
+ struct sockaddr_in serverAddr;
+
+ //---- Create the socket. The three arguments are: ----//
+ // 1) Internet domain 2) Stream socket 3) Default protocol (TCP in this case) //
+ clientSocket = socket(PF_INET, SOCK_STREAM, 0);
+ int flag = 1;
+ int result = setsockopt(clientSocket, /* 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 */
+
+ //---- Configure settings of the server address struct ----//
+ // Address family = Internet //
+ serverAddr.sin_family = AF_INET;
+ // Set port number, using htons function to use proper byte order //
+ serverAddr.sin_port = htons(7893);
+ // Set IP address to localhost //
+ serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
+ // Set all bits of the padding field to 0 //
+ memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
+
+ //---- Connect the socket to the server using the address struct ----//
+ socklen_t addr_size = sizeof serverAddr;
+ int error = connect(clientSocket, (struct sockaddr *) &serverAddr, addr_size);
+// printf("!! %x\n",readCmd(2,0x8));
+ uint32_t debugAddress = 0xF00F0000;
+ uint32_t readValue;
+
+ while(resetDone != true){usleep(100);}
+
+ while((readCmd(2,debugAddress) & RISCV_SPINAL_FLAGS_HALT) == 0){usleep(100);}
+ if((readValue = readCmd(2,debugAddress + 4)) != 0x8000000C){
+ printf("wrong breakA PC %x\n",readValue);
+ clientFail = true; return;
+ }
+
+ writeCmd(2, debugAddress + 4, 0x13 + (1 << 15)); //Read regfile
+ if((readValue = readCmd(2,debugAddress + 4)) != 10){
+ printf("wrong breakB PC %x\n",readValue);
+ clientFail = true; return;
+ }
+
+ writeCmd(2, debugAddress + 4, 0x13 + (2 << 15)); //Read regfile
+ if((readValue = readCmd(2,debugAddress + 4)) != 20){
+ printf("wrong breakC PC %x\n",readValue);
+ clientFail = true; return;
+ }
+
+ writeCmd(2, debugAddress + 4, 0x13 + (3 << 15)); //Read regfile
+ if((readValue = readCmd(2,debugAddress + 4)) != 30){
+ printf("wrong breakD PC %x\n",readValue);
+ clientFail = true; return;
+ }
+
+ writeCmd(2, debugAddress + 4, 0x13 + (1 << 7) + (40 << 20)); //Write x1 with 40
+ writeCmd(2, debugAddress + 4, 0x80000eb7); //Write x29 with 0x10
+ writeCmd(2, debugAddress + 4, 0x010e8e93); //Write x29 with 0x10
+ writeCmd(2, debugAddress + 4, 0x67 + (29 << 15)); //Branch x29
+ writeCmd(2, debugAddress + 0, RISCV_SPINAL_FLAGS_HALT_CLEAR); //Run CPU
+
+ while((readCmd(2,debugAddress) & RISCV_SPINAL_FLAGS_HALT) == 0){usleep(100);}
+ if((readValue = readCmd(2,debugAddress + 4)) != 0x80000014){
+ printf("wrong breakE PC 3 %x\n",readValue);
+ clientFail = true; return;
+ }
+
+
+ writeCmd(2, debugAddress + 4, 0x13 + (3 << 15)); //Read regfile
+ if((readValue = readCmd(2,debugAddress + 4)) != 60){
+ printf("wrong x1 %x\n",readValue);
+ clientFail = true; return;
+ }
+
+
+ writeCmd(2, debugAddress + 4, 0x80000eb7); //Write x29 with 0x10
+ writeCmd(2, debugAddress + 4, 0x018e8e93); //Write x29 with 0x10
+ writeCmd(2, debugAddress + 4, 0x67 + (29 << 15)); //Branch x29
+ writeCmd(2, debugAddress + 0, RISCV_SPINAL_FLAGS_HALT_CLEAR); //Run CPU
+
+
+
+ while((readCmd(2,debugAddress) & RISCV_SPINAL_FLAGS_HALT) == 0){usleep(100);}
+ if((readValue = readCmd(2,debugAddress + 4)) != 0x80000024){
+ printf("wrong breakF PC 3 %x\n",readValue);
+ clientFail = true; return;
+ }
+
+
+ writeCmd(2, debugAddress + 4, 0x13 + (3 << 15)); //Read x3
+ if((readValue = readCmd(2,debugAddress + 4)) != 171){
+ printf("wrong x3 %x\n",readValue);
+ clientFail = true; return;
+ }
+
+
+ clientSuccess = true;
+ }
+
+
+ DebugPluginTest() : WorkspaceRegression("DebugPluginTest") {
+ loadHex(string(REGRESSION_PATH) + "../../resources/hex/debugPlugin.hex");
+ pthread_create(&clientThreadId, NULL, &clientThreadWrapper, this);
+ }
+
+ virtual ~DebugPluginTest(){
+ if(clientSocket != -1) close(clientSocket);
+ }
+
+ virtual void checks(){
+ if(clientSuccess) pass();
+ if(clientFail) fail();
+ }
+
+ virtual void postReset(){
+ Workspace::postReset();
+ top->VexRiscv->DebugPlugin_debugUsed = 1;
+ }
+};
+
+#endif
+
+
+//#ifdef LITEX
+//class LitexSoC : public Workspace{
+//public:
+//
+// LitexSoC(string name) : Workspace(name) {
+//
+// }
+// virtual bool isDBusCheckedRegion(uint32_t address){ return true;}
+// virtual bool isPerifRegion(uint32_t addr) { return (addr & 0xF0000000) == 0xB0000000 || (addr & 0xE0000000) == 0xE0000000;}
+// virtual bool isMmuRegion(uint32_t addr) { return (addr & 0xFF000000) != 0x81000000;}
+//
+// 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
+// case 0xFFFFFFE0: if(wr) fail(); else *data = mTime; break;
+// case 0xFFFFFFE4: if(wr) fail(); else *data = mTime >> 32; break;
+// case 0xFFFFFFE8: if(wr) mTimeCmp = (mTimeCmp & 0xFFFFFFFF00000000) | *data; else *data = mTimeCmp; break;
+// 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;
+// logTraces.flush();
+// } else fail();
+// break;
+// case 0xFFFFFFFC: fail(); break; //Simulation end
+// default: cout << "Unmapped peripheral access : addr=0x" << hex << addr << " wr=" << wr << " mask=0x" << mask << " data=0x" << data << dec << endl; fail(); break;
+// }
+//
+// Workspace::dBusAccess(addr,wr,size,mask,data,error);
+// }
+//};
+//#endif
+
+
+
+#include <unistd.h>
+#include <termios.h>
+#include <fcntl.h>
+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
+ new1.c_lflag &= ~ECHO;
+ tcsetattr(STDIN_FILENO, TCSANOW, &new1); // use these new terminal i/o settings now
+ setvbuf(stdin, NULL, _IONBF, 0);
+ stdinRestoreSettings = old;
+}
+
+
+bool stdinNonEmpty(){
+ struct timeval tv;
+ fd_set fds;
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ FD_ZERO(&fds);
+ FD_SET(STDIN_FILENO, &fds);
+ select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
+ 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();
+ exit(1);
+}
+#include <signal.h>
+
+void captureCtrlC(){
+ struct sigaction sigIntHandler;
+
+ sigIntHandler.sa_handler = my_handler;
+ sigemptyset(&sigIntHandler.sa_mask);
+ sigIntHandler.sa_flags = 0;
+
+ sigaction(SIGINT, &sigIntHandler, NULL);
+}
+
+
+
+
+#if defined(LINUX_SOC) || defined(LINUX_REGRESSION)
+#include <queue>
+class LinuxSoc : public Workspace{
+public:
+ queue <char> customCin;
+ void pushCin(string m){
+ for(char& c : m) {
+ customCin.push(c);
+ }
+ }
+
+ LinuxSoc(string name) : Workspace(name) {
+ #ifdef WITH_USER_IO
+ stdinNonBuffered();
+ 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,uint8_t *dataBytes, bool *error) {
+ uint32_t *data = (uint32_t*)dataBytes;
+
+ if(isPerifRegion(addr)) {
+ switch(addr){
+ case 0xFFFFFFE0: if(wr) fail(); else *data = mTime; break;
+ case 0xFFFFFFE4: if(wr) fail(); else *data = mTime >> 32; break;
+ case 0xFFFFFFE8: if(wr) mTimeCmp = (mTimeCmp & 0xFFFFFFFF00000000) | *data; else *data = mTimeCmp; break;
+ case 0xFFFFFFEC: if(wr) mTimeCmp = (mTimeCmp & 0x00000000FFFFFFFF) | (((uint64_t)*data) << 32); else *data = mTimeCmp >> 32; break;
+ case 0xFFFFFFF8:
+ if(wr){
+ 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;
+ } else
+ #endif
+ if(!customCin.empty()){
+ *data = customCin.front();
+ customCin.pop();
+ } else {
+ *data = -1;
+ }
+ }
+ break;
+ case 0xFFFFFFFC: fail(); break; //Simulation end
+ default: cout << "Unmapped peripheral access : addr=0x" << hex << addr << " wr=" << wr << " mask=0x" << " data=0x" << data << dec << endl; fail(); break;
+ }
+ }
+ Workspace::dBusAccess(addr,wr,size,dataBytes,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
+
+#ifdef LINUX_SOC_SMP
+
+class LinuxSocSmp : public Workspace{
+public:
+ queue <char> customCin;
+ void pushCin(string m){
+ for(char& c : m) {
+ customCin.push(c);
+ }
+ }
+
+ LinuxSocSmp(string name) : Workspace(name) {
+ #ifdef WITH_USER_IO
+ stdinNonBuffered();
+ captureCtrlC();
+ #endif
+ stdoutNonBuffered();
+ }
+
+ virtual ~LinuxSocSmp(){
+ #ifdef WITH_USER_IO
+ stdinRestore();
+ #endif
+ }
+ virtual bool isDBusCheckedRegion(uint32_t address){ return true;}
+ virtual bool isPerifRegion(uint32_t addr) { return (addr & 0xF0000000) == 0xF0000000;}
+ virtual bool isMmuRegion(uint32_t addr) { return true; }
+
+
+
+ virtual void dBusAccess(uint32_t addr,bool wr, uint32_t size, uint8_t *dataBytes, bool *error) {
+ uint32_t *data = (uint32_t*)dataBytes;
+ if(isPerifRegion(addr)) switch(addr){
+ case 0xF0010000: if(wr && *data != 0) fail(); else *data = 0; break;
+ case 0xF001BFF8: if(wr) fail(); else *data = mTime; break;
+ case 0xF001BFFC: if(wr) fail(); else *data = mTime >> 32; break;
+ case 0xF0014000: if(wr) mTimeCmp = (mTimeCmp & 0xFFFFFFFF00000000) | *data; else fail(); break;
+ case 0xF0014004: if(wr) mTimeCmp = (mTimeCmp & 0x00000000FFFFFFFF) | (((uint64_t)*data) << 32); else fail(); break;
+ case 0xF0000000:
+ if(wr){
+ char c = (char)*data;
+ cout << c;
+ logTraces << c;
+ logTraces.flush();
+ onStdout(c);
+ }
+ case 0xF0000004:
+ if(!wr){
+ #ifdef WITH_USER_IO
+ if(stdinNonEmpty()){
+ char c;
+ read(0, &c, 1);
+ *data = c;
+ } else
+ #endif
+ if(!customCin.empty()){
+ *data = customCin.front();
+ customCin.pop();
+ } else {
+ *data = -1;
+ }
+ }
+ break;
+ default: cout << "Unmapped peripheral access : addr=0x" << hex << addr << " wr=" << wr << " data=0x" << data << dec << endl; fail(); break;
+ }
+ Workspace::dBusAccess(addr,wr,size,dataBytes,error);
+ }
+
+ virtual void onStdout(char c){
+
+ }
+};
+
+#endif
+
+string riscvTestMain[] = {
+ //"rv32ui-p-simple",
+ "rv32ui-p-lui",
+ "rv32ui-p-auipc",
+ "rv32ui-p-jal",
+ "rv32ui-p-jalr",
+ "rv32ui-p-beq",
+ "rv32ui-p-bge",
+ "rv32ui-p-bgeu",
+ "rv32ui-p-blt",
+ "rv32ui-p-bltu",
+ "rv32ui-p-bne",
+ "rv32ui-p-add",
+ "rv32ui-p-addi",
+ "rv32ui-p-and",
+ "rv32ui-p-andi",
+ "rv32ui-p-or",
+ "rv32ui-p-ori",
+ "rv32ui-p-sll",
+ "rv32ui-p-slli",
+ "rv32ui-p-slt",
+ "rv32ui-p-slti",
+ "rv32ui-p-sra",
+ "rv32ui-p-srai",
+ "rv32ui-p-srl",
+ "rv32ui-p-srli",
+ "rv32ui-p-sub",
+ "rv32ui-p-xor",
+ "rv32ui-p-xori"
+};
+
+string riscvTestMemory[] = {
+ "rv32ui-p-lb",
+ "rv32ui-p-lbu",
+ "rv32ui-p-lh",
+ "rv32ui-p-lhu",
+ "rv32ui-p-lw",
+ "rv32ui-p-sb",
+ "rv32ui-p-sh",
+ "rv32ui-p-sw"
+};
+
+
+string riscvTestFloat[] = {
+ "rv32uf-p-fmadd",
+ "rv32uf-p-fadd",
+ "rv32uf-p-fcmp",
+ "rv32uf-p-fcvt_w",
+ "rv32uf-p-ldst",
+ "rv32uf-p-recoding",
+ "rv32uf-p-fclass",
+ "rv32uf-p-fcvt",
+ "rv32uf-p-fdiv",
+ "rv32uf-p-fmin",
+ "rv32uf-p-move"
+};
+
+
+string riscvTestDouble[] = {
+ "rv32ud-p-fmadd",
+ "rv32ud-p-fadd",
+ "rv32ud-p-fcvt",
+ "rv32ud-p-recoding",
+ "rv32ud-p-fclass",
+ "rv32ud-p-fcvt_w",
+ "rv32ud-p-fmin",
+ "rv32ud-p-fcmp",
+ "rv32ud-p-fdiv",
+ "rv32ud-p-ldst"
+};
+
+
+
+
+string riscvTestMul[] = {
+ "rv32um-p-mul",
+ "rv32um-p-mulh",
+ "rv32um-p-mulhsu",
+ "rv32um-p-mulhu"
+};
+
+string riscvTestDiv[] = {
+ "rv32um-p-div",
+ "rv32um-p-divu",
+ "rv32um-p-rem",
+ "rv32um-p-remu"
+};
+
+string freeRtosTests[] = {
+// "test1","test1","test1","test1","test1","test1","test1","test1",
+// "test1","test1","test1","test1","test1","test1","test1","test1",
+// "test1","test1","test1","test1","test1","test1","test1","test1",
+// "test1","test1","test1","test1","test1","test1","test1","test1",
+// "test1","test1","test1","test1","test1","test1","test1","test1",
+// "test1","test1","test1","test1","test1","test1","test1","test1",
+// "test1","test1","test1","test1","test1","test1","test1","test1",
+// "test1","test1","test1","test1","test1","test1","test1","test1",
+// "test1","test1","test1","test1","test1","test1","test1","test1",
+// "test1","test1","test1","test1","test1","test1","test1","test1",
+// "test1","test1","test1","test1","test1","test1","test1","test1",
+// "test1","test1","test1","test1","test1","test1","test1","test1",
+// "test1","test1","test1","test1","test1","test1","test1","test1"
+
+ "AltQTest", "AltBlock", "AltPollQ", "blocktim", "countsem", "dead", "EventGroupsDemo", "flop", "integer", "QPeek",
+ "QueueSet", "recmutex", "semtest", "TaskNotify", "crhook", "dynamic",
+ "GenQTest", "PollQ", "QueueOverwrite", "QueueSetPolling", "sp_flop", "test1"
+ //"BlockQ","BlockQ","BlockQ","BlockQ","BlockQ","BlockQ","BlockQ","BlockQ"
+// "flop"
+// "flop", "sp_flop" // <- Simple test
+ // "AltBlckQ" ???
+
+};
+
+
+string zephyrTests[] = {
+ "tests_kernel_stack_stack_api",
+ "tests_kernel_context",
+// "tests_kernel_critical", //Too long
+ "tests_kernel_fifo_fifo_api",
+ "tests_kernel_mbox_mbox_usage",
+// "tests_kernel_mem_pool_mem_pool_threadsafe", //Too long
+ "tests_kernel_sleep"
+// "tests_kernel_timer_timer_api" //Lock like if the CPU is too slow, it will make it fail
+};
+
+
+
+string riscvComplianceMain[] = {
+ "I-IO",
+ "I-NOP-01",
+ "I-LUI-01",
+ "I-ADD-01",
+ "I-ADDI-01",
+ "I-AND-01",
+ "I-ANDI-01",
+ "I-SUB-01",
+ "I-OR-01",
+ "I-ORI-01",
+ "I-XOR-01",
+ "I-XORI-01",
+ "I-SRA-01",
+ "I-SRAI-01",
+ "I-SRL-01",
+ "I-SRLI-01",
+ "I-SLL-01",
+ "I-SLLI-01",
+ "I-SLT-01",
+ "I-SLTI-01",
+ "I-SLTIU-01",
+ "I-SLTU-01",
+ "I-AUIPC-01",
+ "I-BEQ-01",
+ "I-BGE-01",
+ "I-BGEU-01",
+ "I-BLT-01",
+ "I-BLTU-01",
+ "I-BNE-01",
+ "I-JAL-01",
+ "I-JALR-01",
+ "I-DELAY_SLOTS-01",
+ "I-ENDIANESS-01",
+ "I-RF_size-01",
+ "I-RF_width-01",
+ "I-RF_x0-01",
+};
+
+
+
+string complianceTestMemory[] = {
+ "I-LB-01",
+ "I-LBU-01",
+ "I-LH-01",
+ "I-LHU-01",
+ "I-LW-01",
+ "I-SB-01",
+ "I-SH-01",
+ "I-SW-01"
+};
+
+
+string complianceTestCsr[] = {
+ "I-CSRRC-01",
+ "I-CSRRCI-01",
+ "I-CSRRS-01",
+ "I-CSRRSI-01",
+ "I-CSRRW-01",
+ "I-CSRRWI-01",
+ #ifndef COMPRESSED
+ "I-MISALIGN_JMP-01", //Only apply for non RVC cores
+ #endif
+ "I-MISALIGN_LDST-01",
+ "I-ECALL-01",
+};
+
+
+string complianceTestMul[] = {
+ "MUL",
+ "MULH",
+ "MULHSU",
+ "MULHU",
+};
+
+string complianceTestDiv[] = {
+ "DIV",
+ "DIVU",
+ "REM",
+ "REMU",
+};
+
+
+string complianceTestC[] = {
+ "C.ADD",
+ "C.ADDI16SP",
+ "C.ADDI4SPN",
+ "C.ADDI",
+ "C.AND",
+ "C.ANDI",
+ "C.BEQZ",
+ "C.BNEZ",
+ "C.JAL",
+ "C.JALR",
+ "C.J",
+ "C.JR",
+ "C.LI",
+ "C.LUI",
+ "C.LW",
+ "C.LWSP",
+ "C.MV",
+ "C.OR",
+ "C.SLLI",
+ "C.SRAI",
+ "C.SRLI",
+ "C.SUB",
+ "C.SW",
+ "C.SWSP",
+ "C.XOR",
+};
+
+
+
+
+
+
+struct timespec timer_start(){
+ struct timespec start_time;
+ clock_gettime(CLOCK_REALTIME, &start_time); //CLOCK_PROCESS_CPUTIME_ID
+ return start_time;
+}
+
+long timer_end(struct timespec start_time){
+ struct timespec end_time;
+ clock_gettime(CLOCK_REALTIME, &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 <pthread.h>
+#include <queue>
+#include <functional>
+#include <thread>
+
+
+static void multiThreading(queue<std::function<void()>> *lambdas, std::mutex *mutex){
+ uint32_t counter = 0;
+ while(true){
+ mutex->lock();
+ if(lambdas->empty()){
+ mutex->unlock();
+ break;
+ }
+
+ #ifdef SEED
+ uint32_t seed = SEED + counter;
+ counter++;
+ srand48(seed);
+ printf("MT_SEED=%d \n", seed);
+ #endif
+ std::function<void()> lambda = lambdas->front();
+ lambdas->pop();
+ mutex->unlock();
+
+ lambda();
+ }
+}
+
+
+static void multiThreadedExecute(queue<std::function<void()>> &lambdas){
+ std::mutex mutex;
+ if(THREAD_COUNT == 1){
+ multiThreading(&lambdas, &mutex);
+ } else {
+ std::thread * t[THREAD_COUNT];
+ for(int id = 0;id < THREAD_COUNT;id++){
+ t[id] = new thread(multiThreading,&lambdas,&mutex);
+ }
+ for(int id = 0;id < THREAD_COUNT;id++){
+ t[id]->join();
+ delete t[id];
+ }
+ }
+}
+
+int main(int argc, char **argv, char **env) {
+ #ifdef SEED
+ srand48(SEED);
+ #endif
+ Verilated::randReset(2);
+ Verilated::commandArgs(argc, argv);
+
+ printf("BOOT\n");
+ timespec startedAt = timer_start();
+
+
+#ifdef LINUX_SOC_SMP
+ {
+
+ LinuxSocSmp soc("linuxSmp");
+ #ifndef DEBUG_PLUGIN_EXTERNAL
+ soc.withRiscvRef();
+ soc.loadBin(EMULATOR, 0x80000000);
+ soc.loadBin(VMLINUX, 0x80400000);
+ soc.loadBin(DTB, 0x80FF0000);
+ soc.loadBin(RAMDISK, 0x81000000);
+ #endif
+ //soc.setIStall(true);
+ //soc.setDStall(true);
+ soc.bootAt(0x80000000);
+ soc.run(0);
+// soc.run((496300000l + 2000000) / 2);
+// soc.run(438700000l/2);
+ return -1;
+ }
+#endif
+
+
+
+ #ifdef RVF
+ for(const string &name : riscvTestFloat){
+ redo(REDO,RiscvTest(name).withRiscvRef()->bootAt(0x80000188u)->writeWord(0x80000184u, 0x00305073)->run();)
+ }
+ #endif
+ #ifdef RVD
+ for(const string &name : riscvTestDouble){
+ redo(REDO,RiscvTest(name).withRiscvRef()->bootAt(0x80000188u)->writeWord(0x80000184u, 0x00305073)->run();)
+ }
+ #endif
+ //return 0;
+
+//#ifdef LITEX
+// LitexSoC("linux")
+// .withRiscvRef()
+// ->loadBin(EMULATOR, 0x80000000)
+// ->loadBin(DTB, 0x81000000)
+// ->loadBin(VMLINUX, 0xc0000000)
+// ->loadBin(RAMDISK, 0xc2000000)
+// ->setIStall(false) //TODO It currently improve speed but should be removed later
+// ->setDStall(false)
+// ->bootAt(0x80000000)
+// ->run(0);
+//#endif
+
+// {
+// static struct termios old, new1;
+// tcgetattr(0, &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(0, TCSANOW, &new1); /* use these new terminal i/o settings now */
+// }
+//
+// std::string initialCommand;
+//
+// while(true){
+// if(!inputAvailable()) {
+// std::cout << "Waiting for input (Ctrl-C to cancel)..." << std::endl;
+// sleep(1);
+// } else {
+// char c;
+// read(0, &c, 1); printf("%d\n", c);
+//// std::getline(std::cin, initialCommand);
+// }
+// }
+//
+
+// char c;
+// while (1) { read(0, &c, 1); printf("%d\n", c); }
+// while(true){
+// char c = getchar();
+// if(c > 0)
+// {
+// putchar(c);
+// } else {
+// putchar('*');
+// sleep(500);
+// }
+// }
+
+#ifdef LINUX_SOC
+ {
+
+ LinuxSoc 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(0);
+// soc.run((496300000l + 2000000) / 2);
+// soc.run(438700000l/2);
+ return -1;
+ }
+#endif
+
+
+
+
+
+// #ifdef MMU
+// redo(REDO,WorkspaceRegression("mmu").withRiscvRef()->loadHex("../raw/mmu/build/mmu.hex")->bootAt(0x80000000u)->run(50e3););
+// #endif
+// redo(REDO,WorkspaceRegression("deleg").withRiscvRef()->loadHex("../raw/deleg/build/deleg.hex")->bootAt(0x80000000u)->run(50e3););
+// return 0;
+
+
+ for(int idx = 0;idx < 1;idx++){
+
+ #if defined(DEBUG_PLUGIN_EXTERNAL) || defined(RUN_HEX)
+ {
+ WorkspaceRegression w("run");
+ #ifdef RUN_HEX
+ //w.loadHex("/home/spinalvm/hdl/zephyr/zephyrSpinalHdl/samples/synchronization/build/zephyr/zephyr.hex");
+ w.loadHex(RUN_HEX);
+ w.withRiscvRef();
+ #endif
+ w.setIStall(false);
+ w.setDStall(false);
+
+ #if defined(TRACE) || defined(TRACE_ACCESS)
+ //w.setCyclesPerSecond(5e3);
+ //printf("Speed reduced 5Khz\n");
+ #endif
+ w.run(0xFFFFFFFFFFFF);
+ exit(0);
+ }
+ #endif
+
+
+ #ifdef ISA_TEST
+
+ // redo(REDO,TestA().run();)
+ for(const string &name : riscvComplianceMain){
+ redo(REDO, Compliance(name).run();)
+ }
+ for(const string &name : complianceTestMemory){
+ redo(REDO, Compliance(name).run();)
+ }
+
+ #ifdef COMPRESSED
+ for(const string &name : complianceTestC){
+ redo(REDO, Compliance(name).run();)
+ }
+ #endif
+
+ #ifdef MUL
+ for(const string &name : complianceTestMul){
+ redo(REDO, Compliance(name).run();)
+ }
+ #endif
+ #ifdef DIV
+ for(const string &name : complianceTestDiv){
+ redo(REDO, Compliance(name).run();)
+ }
+ #endif
+ #if defined(CSR) && !defined(CSR_SKIP_TEST)
+ for(const string &name : complianceTestCsr){
+ redo(REDO, Compliance(name).run();)
+ }
+ #endif
+
+ #ifdef FENCEI
+ redo(REDO, Compliance("I-FENCE.I-01").run();)
+ #endif
+ #ifdef EBREAK
+ redo(REDO, Compliance("I-EBREAK-01").run();)
+ #endif
+
+ for(const string &name : riscvTestMain){
+ redo(REDO,RiscvTest(name).withRiscvRef()->run();)
+ }
+ for(const string &name : riscvTestMemory){
+ redo(REDO,RiscvTest(name).withRiscvRef()->run();)
+ }
+
+
+ #ifdef MUL
+ for(const string &name : riscvTestMul){
+ redo(REDO,RiscvTest(name).withRiscvRef()->run();)
+ }
+ #endif
+ #ifdef DIV
+ for(const string &name : riscvTestDiv){
+ redo(REDO,RiscvTest(name).withRiscvRef()->run();)
+ }
+ #endif
+
+ #ifdef COMPRESSED
+ redo(REDO,RiscvTest("rv32uc-p-rvc").withRiscvRef()->bootAt(0x800000FCu)->run());
+ #endif
+
+ #if defined(CSR) && !defined(CSR_SKIP_TEST)
+ #ifndef COMPRESSED
+ uint32_t machineCsrRef[] = {1,11, 2,0x80000003u, 3,0x80000007u, 4,0x8000000bu, 5,6,7,0x80000007u ,
+ 8,6,9,6,10,4,11,4, 12,13,0, 14,2, 15,5,16,17,1 };
+ redo(REDO,TestX28("../../cpp/raw/machineCsr/build/machineCsr",machineCsrRef, sizeof(machineCsrRef)/4).withRiscvRef()->setVcdName("machineCsr")->run(10e4);)
+ #else
+ uint32_t machineCsrRef[] = {1,11, 2,0x80000003u, 3,0x80000007u, 4,0x8000000bu, 5,6,7,0x80000007u ,
+ 8,6,9,6,10,4,11,4, 12,13, 14,2, 15,5,16,17,1 };
+ redo(REDO,TestX28("../../cpp/raw/machineCsr/build/machineCsrCompressed",machineCsrRef, sizeof(machineCsrRef)/4).withRiscvRef()->setVcdName("machineCsrCompressed")->run(10e4);)
+ #endif
+ #endif
+// #ifdef MMU
+// uint32_t mmuRef[] = {1,2,3, 0x11111111, 0x11111111, 0x11111111, 0x22222222, 0x22222222, 0x22222222, 4, 0x11111111, 0x33333333, 0x33333333, 5,
+// 13, 0xC4000000,0x33333333, 6,7,
+// 1,2,3, 0x11111111, 0x11111111, 0x11111111, 0x22222222, 0x22222222, 0x22222222, 4, 0x11111111, 0x33333333, 0x33333333, 5,
+// 13, 0xC4000000,0x33333333, 6,7};
+// redo(REDO,TestX28("mmu",mmuRef, sizeof(mmuRef)/4).noInstructionReadCheck()->run(4e4);)
+// #endif
+
+ #ifdef IBUS_CACHED
+ redo(REDO,WorkspaceRegression("icache").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/icache/build/icache.hex")->bootAt(0x80000000u)->run(50e3););
+ #endif
+ #ifdef DBUS_CACHED
+ redo(REDO,WorkspaceRegression("dcache").loadHex(string(REGRESSION_PATH) + "../raw/dcache/build/dcache.hex")->bootAt(0x80000000u)->run(2500e3););
+ #endif
+
+ #ifdef MMU
+ redo(REDO,WorkspaceRegression("mmu").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/mmu/build/mmu.hex")->bootAt(0x80000000u)->run(50e3););
+ #endif
+ #ifdef SUPERVISOR
+ redo(REDO,WorkspaceRegression("deleg").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/deleg/build/deleg.hex")->bootAt(0x80000000u)->run(50e3););
+ #endif
+
+ #ifdef DEBUG_PLUGIN
+ #ifndef CONCURRENT_OS_EXECUTIONS
+ redo(REDO,DebugPluginTest().run(1e6););
+ #endif
+ #endif
+ #endif
+
+ #ifdef CUSTOM_SIMD_ADD
+ redo(REDO,WorkspaceRegression("custom_simd_add").loadHex(string(REGRESSION_PATH) + "../custom/simd_add/build/custom_simd_add.hex")->bootAt(0x00000000u)->run(50e3););
+ #endif
+
+ #ifdef CUSTOM_CSR
+ redo(REDO,WorkspaceRegression("custom_csr").loadHex(string(REGRESSION_PATH) + "../custom/custom_csr/build/custom_csr.hex")->bootAt(0x00000000u)->run(50e3););
+ #endif
+
+
+ #ifdef LRSC
+ redo(REDO,WorkspaceRegression("lrsc").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/lrsc/build/lrsc.hex")->bootAt(0x00000000u)->run(10e3););
+ #endif
+
+ #ifdef PMP
+ redo(REDO,WorkspaceRegression("pmp").loadHex(string(REGRESSION_PATH) + "../raw/pmp/build/pmp.hex")->bootAt(0x80000000u)->run(10e3););
+ #endif
+
+ #ifdef AMO
+ redo(REDO,WorkspaceRegression("amo").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../raw/amo/build/amo.hex")->bootAt(0x00000000u)->run(10e3););
+ #endif
+
+ #ifdef DHRYSTONE
+ Dhrystone("dhrystoneO3_Stall","dhrystoneO3",true,true).run(1.5e6);
+ #if defined(COMPRESSED)
+ Dhrystone("dhrystoneO3C_Stall","dhrystoneO3C",true,true).run(1.5e6);
+ #endif
+ #if defined(MUL) && defined(DIV)
+ Dhrystone("dhrystoneO3M_Stall","dhrystoneO3M",true,true).run(1.9e6);
+ #if defined(COMPRESSED)
+ Dhrystone("dhrystoneO3MC_Stall","dhrystoneO3MC",true,true).run(1.9e6);
+ #endif
+ #endif
+ #if defined(COMPRESSED)
+ Dhrystone("dhrystoneO3C","dhrystoneO3C",false,false).run(1.9e6);
+ #endif
+ Dhrystone("dhrystoneO3","dhrystoneO3",false,false).run(1.9e6);
+ #if defined(MUL) && defined(DIV)
+ #if defined(COMPRESSED)
+ Dhrystone("dhrystoneO3MC","dhrystoneO3MC",false,false).run(1.9e6);
+ #endif
+ Dhrystone("dhrystoneO3M","dhrystoneO3M",false,false).run(1.9e6);
+ #endif
+ #endif
+
+ #ifdef COREMARK
+ for(int withStall = 1; true ;withStall--){
+ string rv = "rv32i";
+ #if defined(MUL) && defined(DIV)
+ rv += "m";
+ #endif
+ #if defined(COMPRESSED)
+ if(withStall == -2) break;
+ if(withStall != -1) rv += "c";
+ #else
+ if(withStall == -1) break;
+ #endif
+ WorkspaceRegression("coremark_" + rv + (withStall > 0 ? "_stall" : "_nostall")).withRiscvRef()
+ ->loadBin(string(REGRESSION_PATH) + "../../resources/bin/coremark_" + rv + ".bin", 0x80000000)
+ ->bootAt(0x80000000)
+ ->setIStall(withStall > 0)
+ ->setDStall(withStall > 0)
+ ->run(50e6);
+ }
+ #endif
+
+
+
+ #ifdef FREERTOS
+ {
+ #ifdef SEED
+ srand48(SEED);
+ #endif
+ //redo(1,WorkspaceRegression("freeRTOS_demo").loadHex("../../resources/hex/freeRTOS_demo.hex")->bootAt(0x80000000u)->run(100e6);)
+ vector <std::function<void()>> tasks;
+
+ /*for(int redo = 0;redo < 4;redo++)*/{
+ for(const string &name : freeRtosTests){
+ tasks.push_back([=]() { WorkspaceRegression(name + "_rv32i_O0").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/freertos/" + name + "_rv32i_O0.hex")->bootAt(0x80000000u)->run(4e6*15);});
+ tasks.push_back([=]() { WorkspaceRegression(name + "_rv32i_O3").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/freertos/" + name + "_rv32i_O3.hex")->bootAt(0x80000000u)->run(4e6*15);});
+ #ifdef COMPRESSED
+// tasks.push_back([=]() { WorkspaceRegression(name + "_rv32ic_O0").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/freertos/" + name + "_rv32ic_O0.hex")->bootAt(0x80000000u)->run(5e6*15);});
+ tasks.push_back([=]() { WorkspaceRegression(name + "_rv32ic_O3").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/freertos/" + name + "_rv32ic_O3.hex")->bootAt(0x80000000u)->run(4e6*15);});
+ #endif
+ #if defined(MUL) && defined(DIV)
+// #ifdef COMPRESSED
+// tasks.push_back([=]() { WorkspaceRegression(name + "_rv32imac_O3").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/freertos/" + name + "_rv32imac_O3.hex")->bootAt(0x80000000u)->run(4e6*15);});
+// #else
+ tasks.push_back([=]() { WorkspaceRegression(name + "_rv32im_O3").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/freertos/" + name + "_rv32im_O3.hex")->bootAt(0x80000000u)->run(4e6*15);});
+// #endif
+ #endif
+ }
+ }
+
+ while(tasks.size() > FREERTOS_COUNT){
+ tasks.erase(tasks.begin() + (VL_RANDOM_I_WIDTH(32)%tasks.size()));
+ }
+
+
+ queue <std::function<void()>> tasksSelected(std::deque<std::function<void()>>(tasks.begin(), tasks.end()));
+ multiThreadedExecute(tasksSelected);
+ }
+ #endif
+
+ #ifdef ZEPHYR
+ {
+ #ifdef SEED
+ srand48(SEED);
+ #endif
+ //redo(1,WorkspaceRegression("freeRTOS_demo").loadHex("../../resources/hex/freeRTOS_demo.hex")->bootAt(0x80000000u)->run(100e6);)
+ vector <std::function<void()>> tasks;
+
+ /*for(int redo = 0;redo < 4;redo++)*/{
+ for(const string &name : zephyrTests){
+ #ifdef COMPRESSED
+ tasks.push_back([=]() { ZephyrRegression(name + "_rv32ic").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/VexRiscvRegressionData/sim/zephyr/" + name + "_rv32ic.hex")->bootAt(0x80000000u)->run(180e6);});
+ #else
+ tasks.push_back([=]() { ZephyrRegression(name + "_rv32i").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/VexRiscvRegressionData/sim/zephyr/" + name + "_rv32i.hex")->bootAt(0x80000000u)->run(180e6);});
+ #endif
+ #if defined(MUL) && defined(DIV)
+ tasks.push_back([=]() { ZephyrRegression(name + "_rv32im").withRiscvRef()->loadHex(string(REGRESSION_PATH) + "../../resources/VexRiscvRegressionData/sim/zephyr/" + name + "_rv32im.hex")->bootAt(0x80000000u)->run(180e6);});
+ #endif
+ }
+ }
+
+ while(tasks.size() > ZEPHYR_COUNT){
+ tasks.erase(tasks.begin() + (VL_RANDOM_I_WIDTH(32)%tasks.size()));
+ }
+
+
+ queue <std::function<void()>> tasksSelected(std::deque<std::function<void()>>(tasks.begin(), tasks.end()));
+ multiThreadedExecute(tasksSelected);
+ }
+ #endif
+
+ #if defined(LINUX_REGRESSION)
+ {
+
+ LinuxRegression soc("linux");
+ #ifndef DEBUG_PLUGIN_EXTERNAL
+ soc.withRiscvRef();
+ soc.loadBin(string(REGRESSION_PATH) + EMULATOR, 0x80000000);
+ soc.loadBin(string(REGRESSION_PATH) + VMLINUX, 0xC0000000);
+ soc.loadBin(string(REGRESSION_PATH) + DTB, 0xC3000000);
+ soc.loadBin(string(REGRESSION_PATH) + RAMDISK, 0xC2000000);
+ #endif
+ //soc.setIStall(true);
+ //soc.setDStall(true);
+ soc.bootAt(0x80000000);
+ soc.run(153995602l*9);
+// 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 << "REGRESSION SUCCESS " << Workspace::successCounter << "/" << Workspace::testsCounter << endl;
+ else
+ cout<< "REGRESSION FAILURE " << Workspace::testsCounter - Workspace::successCounter << "/" << Workspace::testsCounter << endl;
+ cout << "****************************************************************" << endl << endl;
+
+
+ exit(0);
+}