Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
baf7dc82fThis file is pinned to the selected release. Download the original to open it in your design tool.
#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 g : 1;
uint32_t a : 1;
uint32_t d : 1;
uint32_t _dummy : 2;
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 || !tlb.a) 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 || !tlb.d) 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: {
if(csr >= 0x3A0 && csr <= 0x3A3 || csr >= 0x3B0 && csr <= 0x3BF) break; //PMP
return true;
}break;
}
// if(csr == MSTATUS || csr == SSTATUS){
// printf("READ %x %x\n", pc, *value);
// }
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;
// if(csr == MSTATUS || csr == SSTATUS){
// printf("MIAOU %x %x\n", pc, value);
// }
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 & 0xFFFFFFFC; 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 & 0xFFFFFFFC; 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; status.fs = 3; break;
case FRM: fcsr.frm = value; status.fs = 3; break;
case FFLAGS: fcsr.flags = value; status.fs = 3; break;
#endif
default: {
if(csr >= 0x3A0 && csr <= 0x3A3 || csr >= 0x3B0 && csr <= 0x3BF) break; //PMP
ilegalInstruction();
return true;
}break;
}
// if(csr == MSTATUS || csr == SSTATUS){
// printf(" %x %x\n", pc, status.raw);
// }
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 {
cout << "CPU model doesn't has pending interrupt" << endl;
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*)®s[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
cout << "0xF00FFF20 test asked for failure " << *data << endl;
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, (1<<dBusAhbLite3_HSIZE),((uint8_t*)&data) + (dBusAhbLite3_HADDR&0x3),&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, (1<<dBusAhbLite3_HSIZE),((uint8_t*)&top->dBusAhbLite3_HRDATA) + (dBusAhbLite3_HADDR&0x3),&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
#include "jtag.h"
#ifdef VEXRISCV_JTAG
class VexRiscvJtag : public SimElement{
public:
Workspace *ws;
VVexRiscv* top;
VexRiscvJtag(Workspace* ws){
this->ws = ws;
this->top = ws->top;
}
virtual void onReset(){
top->debugReset = 1;
}
virtual void preCycle(){
}
virtual void postCycle(){
top->debugReset = 0;
}
};
#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
#ifdef RISCV_JTAG
simElements.push_back(new Jtag(&top->jtag_tms, &top->jtag_tdi, &top->jtag_tdo, &top->jtag_tck, 4));
simElements.push_back(new VexRiscvJtag(this));
#endif
#ifdef VEXRISCV_JTAG
simElements.push_back(new Jtag(&top->jtag_tms, &top->jtag_tdi, &top->jtag_tdo, &top->jtag_tck, 4));
simElements.push_back(new VexRiscvJtag(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;
if(name == "C.ADDI16SP" || name == "C.ADDI4SPN"){
top->VexRiscv->RegFilePlugin_regFile[2] = 0;
}
}
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)){
cout << "Bad compliance check" << endl;
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
//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 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
#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);
}