Browse Source

verilator litex soc

master
openpowerwtf 4 months ago
parent
commit
cb04a607db
  1. 0
      dev/sim/verilator/cmod7_kintex_main_ram.init
  2. 0
      dev/sim/verilator/cmod7_kintex_mem.init
  3. 3795
      dev/sim/verilator/cmod7_kintex_rom.init
  4. 0
      dev/sim/verilator/cmod7_kintex_sram.init
  5. 88
      dev/sim/verilator/readme.md
  6. 1890
      dev/sim/verilator/soc.v
  7. 7
      dev/sim/verilator/tb_litex.cpp
  8. 428
      dev/sim/verilator/tb_litex_soc.cpp

0
dev/sim/verilator/cmod7_kintex_main_ram.init

0
dev/sim/verilator/cmod7_kintex_mem.init

3795
dev/sim/verilator/cmod7_kintex_rom.init

File diff suppressed because it is too large Load Diff

0
dev/sim/verilator/cmod7_kintex_sram.init

88
dev/sim/verilator/readme.md

@ -1,15 +1,99 @@ @@ -1,15 +1,99 @@
# Verilator

##
* verilator now successfully runs, once the nclk[] changes were completed to separate clk and rst, and
remove lcb's driving lclk's

## a2o w/WB wrapper

```
verilator -cc --exe --trace --Mdir obj_dir --language 1364-2001 -Wno-fatal -Wno-LITENDIAN --error-limit 1 -Iverilog/a2o_litex -Iverilog/work -Iverilog/trilib -Iverilog/unisims a2owb.v tb_litex.cpp |& tee verilator.txt
verilator -cc --exe --trace --Mdir obj_dir --language 1364-2001 -Wno-fatal -Wno-LITENDIAN --error-limit 1 -Iverilog/a2o_litex -Iverilog/work -Iverilog/trilib -Iverilog/unisims a2owb.v tb_litex.cpp |& tee verilator.txt
make -C obj_dir -f Va2owb.mk Va2owb
obj_dir/Va2owb

```

* about 5 non-scan UNOPTFLATs

## Litex SOC

* full SOC also runs; now need to add uart to tb and more code to get to litex terminal

```
top=cmod7_kintex
build=../../build/litex/build/$top/gateware
# keep consistent naming
mod=soc
cp $build/$top.v $mod.v
sed -i "s/module $top/module $mod/" $mod.v

# don't absolutely need this? soc will reset itself; also, csr can reset
# make public - would be nice to do these with a --publics <file>
sed -i 's#reg soc_rst =.*;#reg soc_rst /*verilator public*/ = 0;#' $mod.v

# verilog loads a rom init file; gen'd during soc build or externally
# test3 copies tst to @10000; ALSO! the tst wrapper has to be loaded into ram space since it has save/restore areas.
#cp $build/${top}_rom.init . #LE
cp ../mem/test3/rom_soc.init ${top}_rom.init #BE
touch ${top}_mem.init # csr
touch ${top}_sram.init # on-board
touch ${top}_main_ram.init # ext

verilator -cc --exe --trace --Mdir obj_dir_$mod --language 1364-2001 -Wno-fatal -Wno-LITENDIAN --error-limit 1 -I$. -Iverilog/a2o_litex -Iverilog/work -Iverilog/trilib -Iverilog/unisims -Iverilog/unisims_soc $mod tb_litex_$mod.cpp |& tee verilator_$mod.txt

make -C obj_dir_$mod -f V$mod.mk V$mod
obj_dir_$mod/V$mod | tee sim_soc.txt
vcd2fst a2olitex.vcd soc.fst
rm a2olitex.vcd
gtkwave soc.fst soc.gtkw
```

##### first try

* runs until last completion of 134C???

```
00001338 <tst_cleanup>:
1338: 3c 60 00 00 lis r3,0
133c: 60 63 10 60 ori r3,r3,4192
1340: 80 23 00 9c lwz r1,156(r3)
1344: 3c 60 08 67 lis r3,2151
1348: 60 63 53 09 ori r3,r3,21257
134c: 48 00 0e 0f bla e0c <tst_done>

00000e0c <tst_done>:
e0c: 94 21 ff e0 stwu r1,-32(r1)

```

* bumped stopOnHang to 500 cycles and it does complete 1C0 after 134C. dsi on stwu. dear=FFFFFFE0. that is suspiciously identical to 0-32. what is trying to be read from @1060 to set r1??? that is in rom space. the tst wrapper is being linked into rom and not relocated! it should probably use a linker-gen'd pointer to use for its r/w data space. but wouldn't generally be building a tst into rom.

##### second try

* changed linker.ld to put tst in .data so it's copied by bios to ram...

```
00024966 C0: CP 0:000FD8 0000000000000FD8
00024983 C0: CP 0:000FDC 1:000FE0 0000000000000FDC
00024985 C0: CP 0:000FE4 1:000FF4 0000000000000FE4
00024986 C0: CP 0:000FF8 1:000FFC 0000000000000FF8
00025000 ...tick...
00025005 C0: CP 0:001000 0000000000001000
00025006 C0: CP 0:001004 0000000000001004
00025008 C0: CP 0:001008 0000000000001008
00025022 C0: CP 0:00100C 000000000000100C
00025071 C0: CP 0:0007F0 00000000000007F0
*** Passing IAR detected ***


tb_litex_soc

Cycles run=25074

You has opulence.
```



## Experiments

### core-only initial experiment

1890
dev/sim/verilator/soc.v

File diff suppressed because it is too large Load Diff

7
dev/sim/verilator/tb_litex.cpp

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
// simple verilator top
// uses a2owb with sim mem interface
// uses a2owb with WB interface

#define TRACING

@ -61,6 +61,7 @@ const int quiesceCycles = 50; @@ -61,6 +61,7 @@ const int quiesceCycles = 50;
const int threads = 1;
const std::string testFile = "../mem/test3/rom.init";
const unsigned int bootAdr = 0x00000000;
const bool failMaxCycles = true;
const unsigned int stopOnHang = 200;
const unsigned int stopOnLoop = 10;
const unsigned long iarPass = 0x7F0;
@ -392,6 +393,10 @@ int main(int argc, char **argv) { @@ -392,6 +393,10 @@ int main(int argc, char **argv) {
if ((cycle % hbCycles) == 0) {
cout << dec << setw(8) << setfill('0') << cycle << " ...tick..." << endl;
}
if (failMaxCycles && (cycle == runCycles)) {
cout << "*** Max cycles reached ***" << endl;
ok = false;
}
}

tick++;

428
dev/sim/verilator/tb_litex_soc.cpp

@ -0,0 +1,428 @@ @@ -0,0 +1,428 @@
// simple verilator top
// litex soc w/a2o

#define TRACING

// old public access method
//#define OLD_PUBLIC

#include <cstddef>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <unordered_map>

#include "verilated.h"
#include "Vsoc.h"

#ifndef OLD_PUBLIC
// internal nets
#include "Vsoc___024root.h"
#endif

#include "Vsoc_soc.h"
#include "Vsoc_a2owb.h"
#include "Vsoc_a2l2wb.h"
#include "Vsoc_c.h"
#include "Vsoc_iuq.h"
#include "Vsoc_iuq_cpl_top.h"
#include "Vsoc_iuq_cpl.h"

#ifdef TRACING
#include "verilated_vcd_c.h"
VerilatedVcdC *t;
#else
unsigned int t = 0;
#endif

/*
#include "uart/uartsim.h"
*/

Vsoc* m;
#ifdef OLD_PUBLIC
Vsoc* root;
#else
Vsoc___024root* root;
#endif

vluint64_t main_time = 0; // in units of timeprecision used in verilog or --timescale-override

double sc_time_stamp() { // $time in verilog
return main_time;
}

const char* tbName = "tb_litex_soc";
const int resetCycle = 10;
const int threadRunCycle = resetCycle + 5;
const int runCycles = 100000;
const int hbCycles = 500;
const int quiesceCycles = 50;
const int threads = 1;
const std::string testFile = "";
const unsigned int bootAdr = 0x00000000;
const bool failMaxCycles = true;
const unsigned int stopOnHang = 500;
const unsigned int stopOnLoop = 10;
const unsigned long iarPass = 0x7F0;
const unsigned long iarFail = 0x7F4;
const bool debugWB = false;

// Cythonize this and use it for cocotb too...

class Memory {
std::unordered_map<unsigned int, unsigned int> mem;
public:
bool le;
bool logStores;
int defaultVal;
Memory();
void loadFile(std::string filename, unsigned int adr=0, bool le=false, std::string format="ascii");
int read(unsigned int adr);
void write(unsigned int adr, unsigned int dat);
void write(unsigned int adr, unsigned int be, unsigned int dat);
};

Memory::Memory() {

this->defaultVal = 0;
this->le = false;
this->logStores = true;

}

void Memory::loadFile(std::string filename, unsigned int adr, bool le, std::string format) {

unsigned int dat;
std::ifstream f;
f.open(filename, std::fstream::in);
// "ascii"
//while (f.peek()!=EOF) {
//f >> std::hex >> dat;
// f >> dat;
while (f >> std::hex >> dat) {
this->write(adr, dat);
adr += 4;
}

}

// adr is word-aligned byte address
int Memory::read(unsigned int adr) {
if (this->mem.find(adr) != this->mem.end()) {
return this->mem[adr];
} else {
return this->defaultVal;
}
}

// adr is word-aligned byte address
void Memory::write(unsigned int adr, unsigned int dat) {
unsigned int startDat = this->read(adr);
this->write(adr, 0xF, dat);
}

void Memory::write(unsigned int adr, unsigned int be, unsigned int dat) {
if (be == 0) return;

int mask = 0, startDat;
if (be >= 8) {
be = be - 8;
mask = 0xFF000000;
} else {
mask = 0;
}
if (be >= 4) {
be = be - 4;
mask |= 0x00FF0000;
}
if (be >= 2) {
be = be - 2;
mask |= 0x0000FF00;
}
if (be = 1) {
mask |= 0x000000FF;
}

startDat = this->read(adr);
this->mem[adr] = (startDat & ~mask) | (dat & mask);
if (this->logStores) {
std::cout << " * Mem Update @" << std::setw(8) << std::setfill('0') << std::uppercase << std::hex << adr <<
" " <<std::setw(8) << std::setfill('0') << std::uppercase << std::hex << startDat <<
"->" <<std::setw(8) << std::setfill('0') << std::uppercase << std::hex << this->read(adr) << std::endl;
}

}

Memory mem;

int main(int argc, char **argv) {
using namespace std;

cout << setfill('0');

Verilated::commandArgs(argc, argv);
m = new Vsoc;
#ifdef OLD_PUBLIC
root = m;
#else
root = m->rootp;
#endif

#ifdef TRACING
Verilated::traceEverOn(true);
t = new VerilatedVcdC;
m->trace(t, 99);
t->open("a2olitex.vcd");
cout << "Tracing enabled." << endl;
#endif

bool ok = true;
bool done = false;
bool resetDone = false;
bool booted = false;
unsigned int quiesceCount = 0;
unsigned int threadStop = 0x3;

unsigned int tick = 0;
unsigned int cycle = 1;
unsigned int readPending = 0;
unsigned int readAddr = 0;
unsigned int readTag = 0;
unsigned int readTID = 0;
unsigned int countReads = 0;
unsigned int lastCompCycle = 0;
unsigned int lastCompSame = 0;
bool wbRdPending = false, wbWrPending = false;

//unsigned int wbSel, wbDatW;
unsigned int iu0Comp, iu1Comp, iu0CompLast, iu1CompLast;
unsigned long iu0CompIFAR, iu1CompIFAR, iu0CompIFARLast, iu1CompIFARLast, iuCompFlushIFAR;


/*
# GPR pool and arch map
gprCompMap = []
lastGprCompMap = []
#wtf check what 33:36 are!
for i in range(36):
gprCompMap.append(sim.a2o.root.iuq0.iuq_slice_top0.slice0.rn_top0.fx_rn0.gpr_rn_map.xhdl3.comp_map0[i].comp_map_latch.dout)
lastGprCompMap.append(i)

gpr = []
for i in range(144):
gpr.append(sim.a2o.root.xu0.gpr.gpr0.loc[i].dat)

# CR fields pool and arch map
crCompMap = []
lastCrCompMap = []
for i in range(8):
crCompMap.append(sim.a2o.root.iuq0.iuq_slice_top0.slice0.rn_top0.fx_rn0.cr_rn_map.xhdl3.comp_map0[i].comp_map_latch.dout)
lastCrCompMap.append(i)

cr = []
for i in range(24):
cr.append(sim.a2o.root.xu0.cr.entry[i].reg_latch.dout)

# XER pool and arch map
xerCompMap = []
lastXerCompMap = []
for i in range(1):
xerCompMap.append(sim.a2o.root.iuq0.iuq_slice_top0.slice0.rn_top0.fx_rn0.xer_rn_map.xhdl3.comp_map0[i].comp_map_latch.dout)
lastXerCompMap.append(i)

xer = []
for i in range(12):
xer.append(sim.a2o.root.xu0.xer.entry[i].reg_latch.dout)

# CTR pool and arch map
ctrCompMap = []
lastCtrCompMap = []
for i in range(1):
ctrCompMap.append(sim.a2o.root.iuq0.iuq_slice_top0.slice0.rn_top0.fx_rn0.ctr_rn_map.xhdl3.comp_map0[i].comp_map_latch.dout)
lastCtrCompMap.append(i)

ctr = []
for i in range(8):
ctr.append(sim.a2o.root.xu0.ctr.entry[i].reg_latch.dout)

# LR pool and arch map
lrCompMap = []
lastLrCompMap = []
for i in range(1):
lrCompMap.append(sim.a2o.root.iuq0.iuq_slice_top0.slice0.rn_top0.fx_rn0.lr_rn_map.xhdl3.comp_map0[i].comp_map_latch.dout)
lastLrCompMap.append(i)

lr = []
for i in range(8):
lr.append(sim.a2o.root.xu0.lr.entry[i].reg_latch.dout)

*/

//mem.write(0xFFFFFFFC, 0x48000002);
//mem.loadFile(testFile);

root->soc->soc_rst = 1;

cout << dec << setw(8) << cycle << " Resetting..." << endl;

//m->an_ac_pm_thread_stop = threadStop; === a2l2.cfg_q[0] (do write to cfg_dat)
//cout << dec << setw(8) << cycle << " Thread stop=" << threadStop << endl;

//const int clocks[4] = {0x3, 0x2, 0x1, 0x0}; // 1x, 2x
//const int ticks1x = 4;
// all clk2x and clk4x fpga arrays overridden
const int clocks[2] = {0x1, 0x0}; // 1x
const int ticks1x = 2;

while (!Verilated::gotFinish() && (ok | quiesceCount > 0) && cycle <= runCycles && !done) {

if (!resetDone && (cycle > resetCycle)) {
root->soc->soc_rst = 0;
cout << dec << setw(8) << cycle << " Releasing reset." << endl;
resetDone = true;
}

if (threadStop && (cycle > threadRunCycle)) {
//threadStop = 0x0;
//m->an_ac_pm_thread_stop = threadStop;
//cout << dec << setw(8) << cycle << " Thread stop=" << threadStop << endl;
}

m->clk12 = clocks[tick % ticks1x];
m->eval();

// 1x clock
if ((tick % ticks1x) == 0) {

// core
iu0Comp = root->soc->a2owb->c0->iuq0->iuq_cpl_top0->iuq_cpl0->cp2_i0_completed;
iu1Comp = root->soc->a2owb->c0->iuq0->iuq_cpl_top0->iuq_cpl0->cp2_i1_completed;
iu0CompIFAR = root->soc->a2owb->c0->iuq0->iuq_cpl_top0->iuq_cpl0->cp2_i0_ifar << 2;
iu1CompIFAR = root->soc->a2owb->c0->iuq0->iuq_cpl_top0->iuq_cpl0->cp2_i1_ifar << 2;
iuCompFlushIFAR = root->soc->a2owb->c0->cp_t0_flush_ifar << 2;

if (iu0Comp || iu1Comp) {
cout << dec << setw(8) << setfill('0') << uppercase << cycle << " C0: CP";
if (iu0Comp)
cout << " 0:" << setw(6) << setfill('0') << hex << (iu0CompIFAR);
if (iu1Comp)
cout << " 1:" << setw(6) << setfill('0') << hex << (iu1CompIFAR);
cout << " " << setw(16) << setfill('0') << hex << (iuCompFlushIFAR);
cout << endl;
lastCompCycle = cycle;
if (quiesceCount > 0) {
// skip remaining checks
} else if ((iu0Comp && (iu0CompIFAR == iarPass)) || (iu1Comp && (iu1CompIFAR == iarPass))) {
cout << "*** Passing IAR detected ***" << endl;
quiesceCount = 5;
} else if ((iu0Comp && (iu0CompIFAR == iarFail)) || (iu1Comp && (iu1CompIFAR == iarFail))) {
cout << "*** Failing IAR detected ***" << endl;
ok = false;
quiesceCount = 5;
} else if ((iu0Comp == iu0CompLast) && (!iu0Comp || (iu0CompIFAR == iu0CompIFARLast)) &&
(iu1Comp == iu1CompLast) && (!iu1Comp || (iu1CompIFAR == iu1CompIFARLast))) {
lastCompSame++;
if (stopOnLoop && (lastCompSame == stopOnLoop)) {
ok = false;
cout << "*** Loop detected for " << dec << stopOnLoop << " iterations ***" << endl;
}
} else {
iu0CompLast = iu0Comp;
iu0CompIFARLast = iu0CompIFAR;
iu1CompLast = iu1Comp;
iu1CompIFARLast = iu1CompIFAR;
lastCompSame = 0;
}
} else if (!quiesceCount && (stopOnHang != 0) && (cycle - lastCompCycle > stopOnHang)) {
ok = false;
cout << "*** No completion detected in " << dec << stopOnHang << " cycles ***" << endl;
}

// wb - soc can monitor-only
if (wbRdPending) {
if (root->soc->a2owb->wb_ack)
if (debugWB)
cout << dec << setw(8) << setfill('0') << uppercase << cycle << " WB RD ACK RA=" << setw(8) << hex << setfill('0') << (root->soc->a2owb->wb_adr & 0xFFFFFFFC) <<
" DATA=" << setw(8) << hex << setfill('0') << root->soc->a2owb->wb_datr << endl;

wbRdPending = false;

} else if (wbWrPending) {
if (root->soc->a2owb->wb_ack)
if (debugWB)
cout << dec << setw(8) << setfill('0') << uppercase << cycle << " WB WR ACK RA=" << setw(8) << hex << setfill('0') << (root->soc->a2owb->wb_adr & 0xFFFFFFFC) <<
" SEL=" << setw(1) << setfill('0') << uppercase << hex << (unsigned int)root->soc->a2owb->wb_sel <<
" DATA=" << setw(8) << hex << setfill('0') << root->soc->a2owb->wb_datw << endl;
wbWrPending = false;

} else if (root->soc->a2owb->wb_cyc && root->soc->a2owb->wb_stb) {
if (!root->soc->a2owb->wb_we) {
if (debugWB)
cout << dec << setw(8) << setfill('0') << uppercase << cycle << " WB RD RA=" << setw(8) << hex << setfill('0') << root->soc->a2owb->wb_adr << endl;
wbRdPending = true;
} else {
if (debugWB)
cout << dec << setw(8) << setfill('0') << uppercase << cycle << " WB WR RA=" << setw(8) << hex << setfill('0') << root->soc->a2owb->wb_adr <<
" SEL=" << root->soc->a2owb->wb_sel << " DATA=" << setw(8) << hex << setfill('0') << root->soc->a2owb->wb_datw << endl;
wbWrPending = true;
}
}

// leds, btns, mem, etc.

// uart

}

m->eval(); // NEED THIS!!!!

// finish clock stuff
if ((tick % ticks1x) == 0) {
cycle++;
if ((cycle % hbCycles) == 0) {
cout << dec << setw(8) << setfill('0') << cycle << " ...tick..." << endl;
}
if (failMaxCycles && (cycle == runCycles)) {
cout << "*** Max cycles reached ***" << endl;
ok = false;
}
}

tick++;

#ifdef TRACING
t->dump(tick);
t->flush();
#endif

// check for fails

if (!ok && quiesceCount == 0) {
quiesceCount = quiesceCycles;
cout << "Quiescing..." << endl;
} else if (quiesceCount > 0) {
quiesceCount--;
if (ok && quiesceCount == 0) {
done = true;
}
}

}

#ifdef TRACING
t->close();
#endif
m->final();

cout << endl << endl << tbName << endl;
cout << endl << "Cycles run=" << dec << cycle << endl << endl;
if (!ok) {
cout << "You are worthless and weak." << endl;
exit(EXIT_FAILURE);
} else {
cout << "You has opulence." << endl;
exit(EXIT_SUCCESS);
}

}
Loading…
Cancel
Save