blob: dc357631a2b09e4ea5397e10fa39768e2d890a90 [file] [log] [blame]
#include "Vcore.h"
#include "Vcore___024root.h"
#include <iostream>
#include <verilated_vcd_c.h>
#include <verilated.h>
#define MAX_TEST_TIME 200
uint64_t sim_time = 0;
uint64_t test_time = 0;
int req_time = 0;
int i_seq = 1;
void tick(Vcore *dut, VerilatedVcdC* vcd) {
do {
dut->i_clk ^= 1;
dut->eval();
vcd->dump(sim_time++);
} while(dut->i_clk);
std::cout<<".";
}
void cpu_reset(Vcore* dut, VerilatedVcdC* v_vcd) {
dut->i_rst = 1;
for(int i=0; i<4; i++)
tick(dut, v_vcd);
dut->i_rst = 0;
req_time = 0;
}
void sim_mem(Vcore* d, std::vector<int>& instr, bool randt=false) {
d->i_req_data_valid = 0;
if(d->o_req_active && !d->i_req_data_valid) {
static int req_addr = -1;
if(!req_time)
req_addr = d->o_req_addr;
if(++req_time >= (randt ? (rand()%3)+1 : 2)) {
req_time = 0;
d->i_req_data_valid = 1;
if (req_addr >= instr.size()) {
d->i_req_data = 0; // NOP
} else {
d->i_req_data = instr[req_addr];
}
std::cout<<"REQF "<<std::hex<<req_addr<<" r:"<<d->i_req_data<<"\n";
}
}
}
int data_mem_req_time = 0;
int data_mem_req_addr = 0, data_mem_req_data = 0;
bool data_mem_req_we = false;
short data_mem[100];
void sim_data_mem(Vcore* d) {
d->i_mem_ack = 0;
if(d->o_mem_req && !d->i_mem_ack) {
if (!req_time) {
data_mem_req_addr = d->o_mem_addr;
data_mem_req_data = d->o_mem_data;
data_mem_req_we = d->o_mem_we;
}
if(++data_mem_req_time >= 2) {
data_mem_req_time = 0;
d->i_mem_ack = 1;
assert(data_mem_req_addr < 100);
if(data_mem_req_we)
data_mem[data_mem_req_addr] = d->o_mem_data;
else
d->i_mem_data = data_mem[data_mem_req_addr];
std::cout<<"memreq a"<<data_mem_req_addr<<'d'<<(data_mem_req_we ? data_mem_req_data : d->i_mem_data)<<
'w'<<data_mem_req_we<<'\n';
}
}
}
bool test_simple (Vcore* dut, VerilatedVcdC* v_vcd) {
cpu_reset(dut, v_vcd);
/* listing
* ldi r0, 1
* ldi r1, 2
* add r0, r0, r1
* add r0, r0, r0
* adi r0, r0, 1
* sub r0, r0, r1
*/
std::vector <int> instr = {0, 0x00010004, 0x00020084, 0x00002007, 0x00000007, 0x00010008, 0x0000200A, 0x0, 0x0};
test_time = sim_time;
while (sim_time-test_time < MAX_TEST_TIME) {
// simulate external devices
sim_mem(dut, instr, true);
// clock tick
tick(dut, v_vcd);
std::cout<<"r0:"<<dut->dbg_r0<<" pc:"<<dut->dbg_pc<<'\n';
if(dut->dbg_pc >= instr.size())
break;
}
if(dut->dbg_r0 != 5) {
std::cout<<"test_simple failed\n";
return false;
}
std::cout<<"test_simple passed\n";
return true;
}
bool test_mispredict (Vcore* dut, VerilatedVcdC* v_vcd) {
cpu_reset(dut, v_vcd);
/* listing
ldi r0, 1
jmp b
mp:
ldi r0, 4
jmp mp
b:
cmi r0, 1
jne mp ; MISPREDICTION (pred taken)
c:
ldi r0, 8
jmp c
ldi r0, 5
nop
*/
std::vector <int> instr = {
0x0000010004,
0x000004000E,
0x0000040004,
0x000002000E,
0x000001000D,
0x000002038E,
0x0000080004,
0x000006000E,
0x0000050004,
0x0000000000};
test_time = sim_time;
int end_it = 0;
while (sim_time-test_time < MAX_TEST_TIME) {
// simulate external devices
sim_mem(dut, instr);
// clock tick
tick(dut, v_vcd);
std::cout<<"r0:"<<dut->dbg_r0<<" pc:"<<dut->dbg_pc<<'\n';
if(dut->dbg_pc == 0x7)
end_it++;
if(dut->dbg_pc >= instr.size() || end_it >= 3)
break;
}
if(dut->dbg_r0 != 8) {
std::cout<<"test_mispredict failed\n";
return false;
}
std::cout<<"test_mispredict passed\n";
return true;
}
bool test_mem_access(Vcore* dut, VerilatedVcdC* vcd) {
cpu_reset(dut, vcd);
/* listing
ldi r0, 3
std r0, 2
ldd r1, 2
ldi r3, 10
sto r3, r1, 1
ldi r2, 1
ldo r0, r2, 1
ldo r1, r2, 3
add r0, r0, r1
*/
std::vector <int> instr = {
0x00030004,
0x00020005,
0x00020082,
0x000A0184,
0x00012C06,
0x00010104,
0x00010803,
0x00030883,
0x00002007,
0x0, 0x0, 0x0};
test_time = sim_time;
while (sim_time-test_time < MAX_TEST_TIME) {
sim_mem(dut, instr);
sim_data_mem(dut);
tick(dut, vcd);
std::cout<<"r0:"<<dut->dbg_r0<<" pc:"<<dut->dbg_pc<<'\n';
if(dut->dbg_pc >= instr.size())
break;
}
if(dut->dbg_r0 != 13) {
std::cout<<"test_mem_access failed\n";
return false;
}
std::cout<<"test_mem_access passed\n";
return true;
}
bool test_interupts(Vcore* dut, VerilatedVcdC* vcd) {
cpu_reset(dut, vcd);
srand(3);
/* listing
jmp start
jmp irq
start:
ldi r1, 0
ldi r0, 0b101
srs r0, 1
ldi r0, 0
ldi r2, 0x10
; overcompicated counter to test functions under interrupts
loop:
adi r0, r0, 1
std r0, 2
ldi r0, 900
ldd r0, 2
cmi r0, 0
jge fwd_jmp
ldi r0, 800
fwd_jmp:
cmp r0, r2
jlt loop
jmp pass_ver
irq:
srl r3, 4
adi r1, r1, 1
srs r3, 4 ; recover arithemtic flags
nop ; nop instruction will clear interrrupt in custom tb
irt
pass_ver: ; with r0 and r1 verification in tb
jmp pass_ver
*/
std::vector <int> instr = {
0x0002000E,
0x0011000E,
0x00000084,
0x00050004,
0x00010011,
0x00000004,
0x00100104,
0x00010008,
0x00020005,
0x03840004,
0x00020002,
0x0000000D,
0x000E030E,
0x03200004,
0x0000400C,
0x0007018E,
0x0016000E,
0x00040190,
0x00010488,
0x00040C11,
0x00000000,
0x0000001E,
0x0016000E};
test_time = sim_time;
int irqc = 0;
while (sim_time-test_time < MAX_TEST_TIME*100) {
sim_mem(dut, instr);
sim_data_mem(dut);
if(rand() % 100 < 5 && !dut->i_irq && dut->dbg_pc != 0x14) {
std::cout<<"irq\n";
irqc++;
dut->i_irq = 1;
}
tick(dut, vcd);
if(dut->dbg_pc == 0x14) {
std::cout<<"cli\n";
dut->i_irq = 0; // cli
}
if(dut->dbg_pc >= instr.size()-1) {
std::cout<<"end";
break;
}
}
int r0 = dut->dbg_r0;
int r1 = dut->rootp->core__DOT__execute__DOT__rf__DOT____Vcellout__rf_regs__BRA__1__KET____DOT__rf_reg__o_d;
std::cout<<"r0: "<<r0<<" r1: "<<r1<<" ex:"<<irqc<<'\n';
if(r0 != 0x10 || r1 != irqc) {
std::cout<<"test_interrupt failed\n";
return false;
}
std::cout<<"test_interrupt passed\n";
return true;
}
int main() {
Vcore *dut = new Vcore;
Verilated::traceEverOn(true);
VerilatedVcdC *v_vcd = new VerilatedVcdC;
dut->trace(v_vcd, 99);
v_vcd->open("waveform.vcd");
bool fail = false;
srand(2);
fail |= !test_simple(dut, v_vcd);
fail |= !test_mispredict(dut, v_vcd);
fail |= !test_mem_access(dut, v_vcd);
fail |= !test_interupts(dut, v_vcd);
// Tests in assembly format are located in test/arch/, and are runned in basic core testbench
dut->final();
v_vcd->close();
delete dut;
std::cout<<'\n';
if(fail)
std::cout<<"SOME TESTS FAILED\n";
else
std::cout<<"ALL TESTS PASSED\n";
std::cout<<'\n';
return fail;
}