Add instruction cache plugin (tested)
This commit is contained in:
parent
32d32845bd
commit
95585b4d9a
|
@ -0,0 +1,318 @@
|
|||
package SpinalRiscv.Plugin
|
||||
|
||||
import SpinalRiscv._
|
||||
import spinal.core._
|
||||
import spinal.lib._
|
||||
|
||||
|
||||
case class InstructionCacheConfig( cacheSize : Int,
|
||||
bytePerLine : Int,
|
||||
wayCount : Int,
|
||||
wrappedMemAccess : Boolean,
|
||||
addressWidth : Int,
|
||||
cpuDataWidth : Int,
|
||||
memDataWidth : Int){
|
||||
def burstSize = bytePerLine*8/memDataWidth
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
class IBusCachedPlugin(catchAccessFault : Boolean, cacheConfig : InstructionCacheConfig) extends Plugin[VexRiscv]{
|
||||
var iBus : InstructionCacheMemBus = null
|
||||
|
||||
object IBUS_ACCESS_ERROR extends Stageable(Bool)
|
||||
var decodeExceptionPort : Flow[ExceptionCause] = null
|
||||
override def setup(pipeline: VexRiscv): Unit = {
|
||||
pipeline.unremovableStages += pipeline.prefetch
|
||||
|
||||
if(catchAccessFault) {
|
||||
val exceptionService = pipeline.service(classOf[ExceptionService])
|
||||
decodeExceptionPort = exceptionService.newExceptionPort(pipeline.decode,1)
|
||||
}
|
||||
}
|
||||
|
||||
override def build(pipeline: VexRiscv): Unit = {
|
||||
import pipeline._
|
||||
import pipeline.config._
|
||||
|
||||
assert(catchAccessFault == false) //unimplemented
|
||||
|
||||
|
||||
val cache = new InstructionCache(cacheConfig)
|
||||
iBus = master(new InstructionCacheMemBus(cacheConfig)).setName("iBus")
|
||||
iBus <> cache.io.mem
|
||||
|
||||
|
||||
//Connect prefetch cache side
|
||||
cache.io.cpu.cmd.isValid := prefetch.arbitration.isValid
|
||||
cache.io.cpu.cmd.isFiring := prefetch.arbitration.isFiring
|
||||
cache.io.cpu.cmd.address := prefetch.output(PC)
|
||||
prefetch.arbitration.haltIt setWhen(cache.io.cpu.cmd.haltIt)
|
||||
|
||||
//Connect fetch cache side
|
||||
cache.io.cpu.rsp.isValid := fetch.arbitration.isValid
|
||||
cache.io.cpu.rsp.isStuck := fetch.arbitration.isStuck
|
||||
cache.io.cpu.rsp.address := fetch.output(PC)
|
||||
fetch.arbitration.haltIt setWhen(cache.io.cpu.rsp.haltIt)
|
||||
fetch.insert(INSTRUCTION) := cache.io.cpu.rsp.data
|
||||
|
||||
cache.io.flush.cmd.valid := False
|
||||
|
||||
// fetch.insert(IBUS_ACCESS_ERROR) := iRsp.error
|
||||
|
||||
// if(catchAccessFault){
|
||||
// decodeExceptionPort.valid := decode.arbitration.isValid && decode.input(IBUS_ACCESS_ERROR)
|
||||
// decodeExceptionPort.code := 1
|
||||
// decodeExceptionPort.badAddr := decode.input(PC)
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
case class InstructionCacheCpuCmd(p : InstructionCacheConfig) extends Bundle with IMasterSlave{
|
||||
val isValid = Bool
|
||||
val isFiring = Bool
|
||||
val haltIt = Bool
|
||||
val address = UInt(p.addressWidth bit)
|
||||
|
||||
override def asMaster(): Unit = {
|
||||
out(isValid, isFiring, address)
|
||||
in(haltIt)
|
||||
}
|
||||
}
|
||||
|
||||
case class InstructionCacheCpuRsp(p : InstructionCacheConfig) extends Bundle with IMasterSlave {
|
||||
val isValid = Bool
|
||||
val haltIt = Bool
|
||||
val isStuck = Bool
|
||||
val address = UInt(p.addressWidth bit)
|
||||
val data = Bits(32 bit)
|
||||
|
||||
override def asMaster(): Unit = {
|
||||
out(isValid, isStuck, address)
|
||||
in(haltIt, data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
case class InstructionCacheCpuBus(p : InstructionCacheConfig) extends Bundle with IMasterSlave{
|
||||
val cmd = InstructionCacheCpuCmd(p)
|
||||
val rsp = InstructionCacheCpuRsp(p)
|
||||
|
||||
override def asMaster(): Unit = {
|
||||
master(cmd)
|
||||
master(rsp)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
case class InstructionCacheMemCmd(p : InstructionCacheConfig) extends Bundle{
|
||||
val address = UInt(p.addressWidth bit)
|
||||
}
|
||||
case class InstructionCacheMemRsp(p : InstructionCacheConfig) extends Bundle{
|
||||
val data = Bits(32 bit)
|
||||
}
|
||||
|
||||
case class InstructionCacheMemBus(p : InstructionCacheConfig) extends Bundle with IMasterSlave{
|
||||
val cmd = Stream (InstructionCacheMemCmd(p))
|
||||
val rsp = Flow (InstructionCacheMemRsp(p))
|
||||
|
||||
override def asMaster(): Unit = {
|
||||
master(cmd)
|
||||
slave(rsp)
|
||||
}
|
||||
}
|
||||
|
||||
case class InstructionCacheFlushBus() extends Bundle with IMasterSlave{
|
||||
val cmd = Event
|
||||
val rsp = Bool
|
||||
|
||||
override def asMaster(): Unit = {
|
||||
master(cmd)
|
||||
in(rsp)
|
||||
}
|
||||
}
|
||||
|
||||
class InstructionCache(p : InstructionCacheConfig) extends Component{
|
||||
import p._
|
||||
assert(wayCount == 1)
|
||||
assert(cpuDataWidth == memDataWidth)
|
||||
val io = new Bundle{
|
||||
val flush = slave(InstructionCacheFlushBus())
|
||||
val cpu = slave(InstructionCacheCpuBus(p))
|
||||
val mem = master(InstructionCacheMemBus(p))
|
||||
}
|
||||
// val haltCpu = False
|
||||
val lineWidth = bytePerLine*8
|
||||
val lineCount = cacheSize/bytePerLine
|
||||
val wordWidth = Math.max(memDataWidth,32)
|
||||
val wordWidthLog2 = log2Up(wordWidth)
|
||||
val wordPerLine = lineWidth/wordWidth
|
||||
val bytePerWord = wordWidth/8
|
||||
val wayLineCount = lineCount/wayCount
|
||||
val wayLineLog2 = log2Up(wayLineCount)
|
||||
val wayWordCount = wayLineCount * wordPerLine
|
||||
|
||||
val tagRange = addressWidth-1 downto log2Up(wayLineCount*bytePerLine)
|
||||
val lineRange = tagRange.low-1 downto log2Up(bytePerLine)
|
||||
val wordRange = log2Up(bytePerLine)-1 downto log2Up(bytePerWord)
|
||||
|
||||
|
||||
class LineInfo() extends Bundle{
|
||||
val valid = Bool
|
||||
val address = UInt(tagRange.length bit)
|
||||
}
|
||||
|
||||
val ways = Array.fill(wayCount)(new Area{
|
||||
val tags = Mem(new LineInfo(),wayLineCount)
|
||||
val datas = Mem(Bits(wordWidth bit),wayWordCount)
|
||||
})
|
||||
|
||||
|
||||
io.cpu.cmd.haltIt := False
|
||||
|
||||
val lineLoader = new Area{
|
||||
val requestIn = Stream(wrap(new Bundle{
|
||||
val addr = UInt(addressWidth bit)
|
||||
}))
|
||||
|
||||
|
||||
if(wrappedMemAccess)
|
||||
io.mem.cmd.address := requestIn.addr(tagRange.high downto wordRange.low) @@ U(0,wordRange.low bit)
|
||||
else
|
||||
io.mem.cmd.address := requestIn.addr(tagRange.high downto lineRange.low) @@ U(0,lineRange.low bit)
|
||||
|
||||
|
||||
val flushCounter = Reg(UInt(log2Up(wayLineCount) + 1 bit)) init(0)
|
||||
when(!flushCounter.msb){
|
||||
io.cpu.cmd.haltIt := True
|
||||
flushCounter := flushCounter + 1
|
||||
}
|
||||
when(!RegNext(flushCounter.msb)){
|
||||
io.cpu.cmd.haltIt := True
|
||||
}
|
||||
val flushFromInterface = RegInit(False)
|
||||
when(io.flush.cmd.valid){
|
||||
io.cpu.cmd.haltIt := True
|
||||
when(io.flush.cmd.ready){
|
||||
flushCounter := 0
|
||||
flushFromInterface := True
|
||||
}
|
||||
}
|
||||
|
||||
io.flush.rsp := flushCounter.msb.rise && flushFromInterface
|
||||
|
||||
val lineInfoWrite = new LineInfo()
|
||||
lineInfoWrite.valid := flushCounter.msb
|
||||
lineInfoWrite.address := requestIn.addr(tagRange)
|
||||
when(requestIn.fire || !flushCounter.msb){
|
||||
val tagsAddress = Mux(flushCounter.msb,requestIn.addr(lineRange),flushCounter(flushCounter.high-1 downto 0))
|
||||
ways(0).tags(tagsAddress) := lineInfoWrite //TODO
|
||||
}
|
||||
|
||||
|
||||
val request = requestIn.haltWhen(!io.mem.cmd.ready).stage()
|
||||
io.mem.cmd.valid := requestIn.valid && !request.isStall
|
||||
val wordIndex = Reg(UInt(log2Up(wordPerLine) bit))
|
||||
val loadedWordsNext = Bits(wordPerLine bit)
|
||||
val loadedWords = RegNext(loadedWordsNext)
|
||||
val loadedWordsReadable = RegNext(loadedWords)
|
||||
loadedWordsNext := loadedWords
|
||||
when(io.mem.rsp.fire){
|
||||
wordIndex := wordIndex + 1
|
||||
loadedWordsNext(wordIndex) := True
|
||||
ways(0).datas(request.addr(lineRange) @@ wordIndex) := io.mem.rsp.data //TODO
|
||||
}
|
||||
|
||||
val readyDelay = Reg(UInt(1 bit))
|
||||
when(loadedWordsNext === B(loadedWordsNext.range -> true)){
|
||||
readyDelay := readyDelay + 1
|
||||
}
|
||||
request.ready := readyDelay === 1
|
||||
|
||||
when(requestIn.ready){
|
||||
wordIndex := io.mem.cmd.address(wordRange)
|
||||
loadedWords := 0
|
||||
loadedWordsReadable := 0
|
||||
readyDelay := 0
|
||||
}
|
||||
}
|
||||
|
||||
val task = new Area{
|
||||
val waysHitValid = False
|
||||
val waysHitWord = Bits(wordWidth bit)
|
||||
waysHitWord.assignDontCare()
|
||||
|
||||
val waysRead = for(way <- ways) yield new Area{
|
||||
val readAddress = Mux(io.cpu.rsp.isStuck,io.cpu.rsp.address,io.cpu.cmd.address)
|
||||
val tag = way.tags.readSync(readAddress(lineRange))
|
||||
val data = way.datas.readSync(readAddress(lineRange.high downto wordRange.low))
|
||||
// val readAddress = request.address
|
||||
// val tag = way.tags.readAsync(readAddress(lineRange))
|
||||
// val data = way.datas.readAsync(readAddress(lineRange.high downto wordRange.low))
|
||||
// way.tags.add(new AttributeString("ramstyle","no_rw_check"))
|
||||
// way.datas.add(new AttributeString("ramstyle","no_rw_check"))
|
||||
when(tag.valid && tag.address === io.cpu.rsp.address(tagRange)) {
|
||||
waysHitValid := True
|
||||
waysHitWord := data
|
||||
}
|
||||
}
|
||||
|
||||
val loaderHitValid = lineLoader.request.valid && lineLoader.request.addr(tagRange) === io.cpu.rsp.address(tagRange)
|
||||
val loaderHitReady = lineLoader.loadedWordsReadable(io.cpu.rsp.address(wordRange))
|
||||
|
||||
|
||||
io.cpu.rsp.haltIt := io.cpu.rsp.isValid && !( waysHitValid && !(loaderHitValid && !loaderHitReady))
|
||||
io.cpu.rsp.data := waysHitWord //TODO
|
||||
lineLoader.requestIn.valid := io.cpu.rsp.isValid && ! waysHitValid
|
||||
lineLoader.requestIn.addr := io.cpu.rsp.address
|
||||
}
|
||||
|
||||
io.flush.cmd.ready := !(lineLoader.request.valid || io.cpu.rsp.isValid)
|
||||
}
|
||||
|
||||
object InstructionCacheMain{
|
||||
class TopLevel extends Component{
|
||||
implicit val p = InstructionCacheConfig(
|
||||
cacheSize =4096,
|
||||
bytePerLine =32,
|
||||
wayCount = 1,
|
||||
wrappedMemAccess = true,
|
||||
addressWidth = 32,
|
||||
cpuDataWidth = 32,
|
||||
memDataWidth = 32)
|
||||
// val io = new Bundle{
|
||||
// val cpu = slave(InstructionCacheCpuBus())
|
||||
// val mem = master(InstructionCacheMemBus())
|
||||
// }
|
||||
val cache = new InstructionCache(p)
|
||||
|
||||
// cache.io.cpu.cmd <-< io.cpu.cmd
|
||||
// cache.io.mem.cmd >-> io.mem.cmd
|
||||
// cache.io.mem.rsp <-< io.mem.rsp
|
||||
// cache.io.cpu.rsp >-> io.cpu.rsp
|
||||
// when(cache.io.cpu.rsp.valid){
|
||||
// cache.io.cpu.cmd.valid := RegNext(cache.io.cpu.cmd.valid)
|
||||
// cache.io.cpu.cmd.address := RegNext(cache.io.cpu.cmd.address)
|
||||
// }
|
||||
}
|
||||
def main(args: Array[String]) {
|
||||
implicit val p = InstructionCacheConfig(
|
||||
cacheSize =4096,
|
||||
bytePerLine =32,
|
||||
wayCount = 1,
|
||||
wrappedMemAccess = true,
|
||||
addressWidth = 32,
|
||||
cpuDataWidth = 32,
|
||||
memDataWidth = 32)
|
||||
// val io = new Bundle{
|
||||
// val cpu = slave(InstructionCacheCpuBus())
|
||||
// val mem = master(InstructionCacheMemBus())
|
||||
// }
|
||||
|
||||
SpinalVhdl(new InstructionCache(p))
|
||||
}
|
||||
}
|
||||
|
|
@ -44,8 +44,8 @@ class IBusSimplePlugin(interfaceKeepData : Boolean, catchAccessFault : Boolean)
|
|||
//Insert iRsp into INSTRUCTION
|
||||
iRsp = in(IBusSimpleRsp()).setName("iRsp")
|
||||
fetch.insert(INSTRUCTION) := iRsp.inst
|
||||
fetch.arbitration.haltIt setWhen(fetch.arbitration.isValid && !iRsp.ready)
|
||||
fetch.insert(IBUS_ACCESS_ERROR) := iRsp.error
|
||||
fetch.arbitration.haltIt setWhen(fetch.arbitration.isValid && !iRsp.ready)
|
||||
|
||||
if(catchAccessFault){
|
||||
decodeExceptionPort.valid := decode.arbitration.isValid && decode.input(IBUS_ACCESS_ERROR)
|
||||
|
|
|
@ -30,6 +30,16 @@ object TopLevel {
|
|||
pcWidth = 32
|
||||
)
|
||||
|
||||
// val iCacheConfig = InstructionCacheConfig(
|
||||
// cacheSize =4096,
|
||||
// bytePerLine =32,
|
||||
// wayCount = 1,
|
||||
// wrappedMemAccess = true,
|
||||
// addressWidth = 32,
|
||||
// cpuDataWidth = 32,
|
||||
// memDataWidth = 32
|
||||
// )
|
||||
|
||||
|
||||
val csrConfig = MachineCsrConfig(
|
||||
mvendorid = 11,
|
||||
|
@ -69,9 +79,21 @@ object TopLevel {
|
|||
|
||||
config.plugins ++= List(
|
||||
new PcManagerSimplePlugin(0x00000000l, false),
|
||||
new IBusSimplePlugin(
|
||||
interfaceKeepData = true,
|
||||
catchAccessFault = true
|
||||
// new IBusSimplePlugin(
|
||||
// interfaceKeepData = true,
|
||||
// catchAccessFault = true
|
||||
// ),
|
||||
new IBusCachedPlugin(
|
||||
catchAccessFault = false,
|
||||
cacheConfig = InstructionCacheConfig(
|
||||
cacheSize =4096,
|
||||
bytePerLine =32,
|
||||
wayCount = 1,
|
||||
wrappedMemAccess = true,
|
||||
addressWidth = 32,
|
||||
cpuDataWidth = 32,
|
||||
memDataWidth = 32
|
||||
)
|
||||
),
|
||||
new DecoderSimplePlugin(
|
||||
catchIllegalInstruction = true
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
#include <string.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
|
||||
//#define REF
|
||||
//#define TRACE
|
||||
|
||||
class Memory{
|
||||
public:
|
||||
|
@ -133,9 +133,21 @@ double sc_time_stamp(){
|
|||
}
|
||||
|
||||
|
||||
class SimElement{
|
||||
public:
|
||||
virtual void onReset(){}
|
||||
virtual void preCycle(){}
|
||||
virtual void postCycle(){}
|
||||
};
|
||||
|
||||
|
||||
class Workspace;
|
||||
void fillSimELements(Workspace *ws);
|
||||
|
||||
class Workspace{
|
||||
public:
|
||||
static uint32_t cycles;
|
||||
vector<SimElement*> simElements;
|
||||
Memory mem;
|
||||
string name;
|
||||
VVexRiscv* top;
|
||||
|
@ -161,6 +173,7 @@ public:
|
|||
regTraces.open (name + ".regTrace");
|
||||
memTraces.open (name + ".memTrace");
|
||||
logTraces.open (name + ".logTrace");
|
||||
fillSimELements(this);
|
||||
}
|
||||
|
||||
virtual ~Workspace(){
|
||||
|
@ -176,8 +189,16 @@ public:
|
|||
}
|
||||
|
||||
Workspace* bootAt(uint32_t pc) { bootPc = pc;}
|
||||
virtual uint32_t iRspOverride(uint32_t value) { return value; }
|
||||
|
||||
virtual bool isAccessError(uint32_t addr) { return addr == 0xF00FFF60u; }
|
||||
virtual void iBusAccess(uint32_t addr, uint32_t *data, bool *error) {
|
||||
assert(addr % 4 == 0);
|
||||
*data = ( (mem[addr + 0] << 0)
|
||||
| (mem[addr + 1] << 8)
|
||||
| (mem[addr + 2] << 16)
|
||||
| (mem[addr + 3] << 24));
|
||||
*error = addr == 0xF00FFF60u;
|
||||
}
|
||||
virtual void postReset() {}
|
||||
virtual void checks(){}
|
||||
virtual void pass(){ throw success();}
|
||||
|
@ -203,12 +224,10 @@ public:
|
|||
// Reset
|
||||
top->clk = 0;
|
||||
top->reset = 0;
|
||||
top->iCmd_ready = 1;
|
||||
top->dCmd_ready = 1;
|
||||
top->iRsp_ready = 1;
|
||||
top->dRsp_ready = 1;
|
||||
top->iRsp_error = 0;
|
||||
top->dRsp_error = 0;
|
||||
|
||||
for(SimElement* simElement : simElements) simElement->onReset();
|
||||
|
||||
top->eval(); currentTime = 3;
|
||||
top->reset = 1;
|
||||
|
@ -232,10 +251,9 @@ public:
|
|||
|
||||
try {
|
||||
// run simulation for 100 clock periods
|
||||
uint32_t iRsp_inst_next = top->iRsp_inst;
|
||||
uint32_t dRsp_inst_next = VL_RANDOM_I(32);
|
||||
bool iRsp_error_next = false, dRsp_error_next = false;
|
||||
bool iRsp_ready_pending = false, dRsp_ready_pending = false;
|
||||
bool dRsp_error_next = false;
|
||||
bool dRsp_ready_pending = false;
|
||||
for (i = 16; i < timeout*2; i+=2) {
|
||||
mTime = i/2;
|
||||
#ifdef CSR
|
||||
|
@ -251,26 +269,15 @@ public:
|
|||
|
||||
dump(i);
|
||||
top->clk = 0;
|
||||
top->eval(); top->eval();top->eval();
|
||||
top->eval();
|
||||
|
||||
|
||||
dump(i + 1);
|
||||
if (top->iCmd_valid && top->iCmd_ready && !iRsp_ready_pending) {
|
||||
assertEq(top->iCmd_payload_pc & 3,0);
|
||||
iRsp_ready_pending = true;
|
||||
//printf("%d\n",top->iCmd_payload_pc);
|
||||
|
||||
iRsp_inst_next = iRspOverride((mem[top->iCmd_payload_pc + 0] << 0)
|
||||
| (mem[top->iCmd_payload_pc + 1] << 8)
|
||||
| (mem[top->iCmd_payload_pc + 2] << 16)
|
||||
| (mem[top->iCmd_payload_pc + 3] << 24));
|
||||
iRsp_error_next = isAccessError(top->iCmd_payload_pc);
|
||||
}
|
||||
|
||||
if (top->dCmd_valid && top->dCmd_ready && ! dRsp_ready_pending) {
|
||||
dRsp_ready_pending = true;
|
||||
dRsp_inst_next = VL_RANDOM_I(32);
|
||||
//printf("%d\n",top->iCmd_payload_pc);
|
||||
uint32_t addr = top->dCmd_payload_address;
|
||||
dRsp_error_next = isAccessError(addr);
|
||||
if(top->dCmd_payload_wr){
|
||||
|
@ -334,19 +341,16 @@ public:
|
|||
" : reg[" << (uint32_t)top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_address << "] = " << top->VexRiscv->writeBack_RegFilePlugin_regFileWrite_payload_data << endl;
|
||||
}
|
||||
|
||||
for(SimElement* simElement : simElements) simElement->preCycle();
|
||||
checks();
|
||||
top->clk = 1;
|
||||
top->eval(); top->eval();
|
||||
top->eval();
|
||||
|
||||
cycles += 1;
|
||||
top->iRsp_ready = !iRsp_ready_pending;
|
||||
|
||||
for(SimElement* simElement : simElements) simElement->postCycle();
|
||||
|
||||
top->dRsp_ready = 0;
|
||||
if(iRsp_ready_pending && (!iStall || VL_RANDOM_I(8) < 100)){
|
||||
top->iRsp_inst = iRsp_inst_next;
|
||||
iRsp_ready_pending = false;
|
||||
top->iRsp_ready = 1;
|
||||
top->iRsp_error = iRsp_error_next;
|
||||
}
|
||||
if(dRsp_ready_pending && (!dStall || VL_RANDOM_I(8) < 100)){
|
||||
top->dRsp_data = dRsp_inst_next;
|
||||
dRsp_ready_pending = false;
|
||||
|
@ -356,7 +360,6 @@ public:
|
|||
top->dRsp_data = VL_RANDOM_I(32);
|
||||
}
|
||||
|
||||
if(iStall) top->iCmd_ready = VL_RANDOM_I(8) < 100 && !iRsp_ready_pending;
|
||||
if(dStall) top->dCmd_ready = VL_RANDOM_I(8) < 100 && !dRsp_ready_pending;
|
||||
|
||||
|
||||
|
@ -382,6 +385,104 @@ public:
|
|||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
#ifdef IBUS_SIMPLE
|
||||
class IBusSimple : public SimElement{
|
||||
public:
|
||||
uint32_t inst_next = VL_RANDOM_I(32);
|
||||
bool error_next = false;
|
||||
bool pending = false;
|
||||
|
||||
Workspace *ws;
|
||||
VVexRiscv* top;
|
||||
IBusSimple(Workspace* ws){
|
||||
this->ws = ws;
|
||||
this->top = ws->top;
|
||||
}
|
||||
|
||||
virtual void onReset(){
|
||||
top->iCmd_ready = 1;
|
||||
top->iRsp_ready = 1;
|
||||
}
|
||||
|
||||
virtual void preCycle(){
|
||||
if (top->iCmd_valid && top->iCmd_ready && !pending) {
|
||||
assertEq(top->iCmd_payload_pc & 3,0);
|
||||
pending = true;
|
||||
ws->iBusAccess(top->iCmd_payload_pc,&inst_next,&error_next);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void postCycle(){
|
||||
top->iRsp_ready = !pending;
|
||||
if(pending && (!ws->iStall || VL_RANDOM_I(8) < 100)){
|
||||
top->iRsp_inst = inst_next;
|
||||
pending = false;
|
||||
top->iRsp_ready = 1;
|
||||
top->iRsp_error = error_next;
|
||||
}
|
||||
if(ws->iStall) top->iCmd_ready = VL_RANDOM_I(8) < 100 && !pending;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef IBUS_CACHED
|
||||
class IBusCached : public SimElement{
|
||||
public:
|
||||
uint32_t inst_next = VL_RANDOM_I(32);
|
||||
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 = 8;
|
||||
address = top->iBus_cmd_payload_address;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void postCycle(){
|
||||
bool dummy;
|
||||
top->iBus_rsp_valid = 0;
|
||||
if(pendingCount != 0 && (!ws->iStall || VL_RANDOM_I(8) < 100)){
|
||||
ws->iBusAccess(address,&top->iBus_rsp_payload_data,&dummy);
|
||||
pendingCount--;
|
||||
address = (address & ~0x1F) + ((address + 4) & 0x1F);
|
||||
top->iBus_rsp_valid = 1;
|
||||
}
|
||||
if(ws->iStall) top->iBus_cmd_ready = VL_RANDOM_I(8) < 100 && pendingCount == 0;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
void fillSimELements(Workspace *ws){
|
||||
|
||||
#ifdef IBUS_SIMPLE
|
||||
ws->simElements.push_back(new IBusSimple(ws));
|
||||
#endif
|
||||
#ifdef IBUS_CACHED
|
||||
ws->simElements.push_back(new IBusCached(ws));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
uint32_t Workspace::cycles = 0;
|
||||
|
||||
#ifndef REF
|
||||
|
@ -474,12 +575,9 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
virtual uint32_t iRspOverride(uint32_t value) {
|
||||
switch(value){
|
||||
case 0x0ff0000f: return 0x00000013;
|
||||
default: return value;
|
||||
}
|
||||
virtual void iBusAccess(uint32_t addr, uint32_t *data, bool *error){
|
||||
Workspace::iBusAccess(addr,data,error);
|
||||
if(*data == 0x0ff0000f) *data = 0x00000013;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
@ -600,6 +698,7 @@ long timer_end(struct timespec start_time){
|
|||
int main(int argc, char **argv, char **env) {
|
||||
Verilated::randReset(2);
|
||||
Verilated::commandArgs(argc, argv);
|
||||
|
||||
printf("BOOT\n");
|
||||
timespec startedAt = timer_start();
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
IBUS=IBUS_CACHED
|
||||
DBUS=DBUS_SIMPLE
|
||||
TRACE=no
|
||||
TRACE_START=0
|
||||
CSR=yes
|
||||
|
@ -7,6 +9,8 @@ REDO=10
|
|||
REF=no
|
||||
TRACE_WITH_TIME=no
|
||||
|
||||
ADDCFLAGS += -CFLAGS -D${IBUS}
|
||||
ADDCFLAGS += -CFLAGS -D${DBUS}
|
||||
ADDCFLAGS += -CFLAGS -DREDO=${REDO}
|
||||
ifeq ($(DHRYSTONE),yes)
|
||||
ADDCFLAGS += -CFLAGS -DDHRYSTONE
|
||||
|
|
Loading…
Reference in New Issue