Skip to content

Commit

Permalink
Faster Wishbone
Browse files Browse the repository at this point in the history
  • Loading branch information
tilk committed Nov 5, 2023
1 parent e484fde commit 57bec62
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 29 deletions.
21 changes: 17 additions & 4 deletions coreblocks/frontend/icache.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,30 +382,43 @@ def elaborate(self, platform):
refill_active = Signal()
word_counter = Signal(range(self.params.words_in_block))

with Transaction().body(m, request=refill_active):
m.submodules.address_fwd = address_fwd = Forwarder(
[("word_counter", word_counter.shape()), ("refill_address", refill_address.shape())]
)

with Transaction().body(m):
address = address_fwd.read(m)
self.wb_master.request(
m,
addr=Cat(word_counter, refill_address),
addr=Cat(address["word_counter"], address["refill_address"]),
data=0,
we=0,
sel=Repl(1, self.wb_master.wb_params.data_width // self.wb_master.wb_params.granularity),
)

@def_method(m, self.start_refill, ready=~refill_active)
def _(addr) -> None:
m.d.sync += refill_address.eq(addr[self.params.offset_bits :])
address = addr[self.params.offset_bits :]
m.d.sync += refill_address.eq(address)
m.d.sync += refill_active.eq(1)
m.d.sync += word_counter.eq(0)

address_fwd.write(m, word_counter=0, refill_address=address)

@def_method(m, self.accept_refill, ready=refill_active)
def _():
fetched = self.wb_master.result(m)

last = (word_counter == (self.params.words_in_block - 1)) | fetched.err

m.d.sync += word_counter.eq(word_counter + 1)
next_word_counter = Signal.like(word_counter)
m.d.top_comb += next_word_counter.eq(word_counter + 1)

m.d.sync += word_counter.eq(next_word_counter)
with m.If(last):
m.d.sync += refill_active.eq(0)
with m.Else():
address_fwd.write(m, word_counter=next_word_counter, refill_address=refill_address)

return {
"addr": Cat(Repl(0, log2_int(self.params.word_width_bytes)), word_counter, refill_address),
Expand Down
55 changes: 32 additions & 23 deletions coreblocks/peripherals/wishbone.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
import operator

from transactron import Method, def_method, TModule
from transactron.core import Transaction
from transactron.lib import AdapterTrans
from coreblocks.utils.utils import OneHotSwitchDynamic, assign
from coreblocks.utils.fifo import BasicFifo
from transactron.lib.connectors import Forwarder


class WishboneParameters:
Expand Down Expand Up @@ -109,8 +111,6 @@ def __init__(self, wb_params: WishboneParameters):
self.request = Method(i=self.requestLayout)
self.result = Method(o=self.resultLayout)

self.ready = Signal()
self.res_ready = Signal()
self.result_data = Record(self.resultLayout)

# latched input signals
Expand All @@ -132,6 +132,10 @@ def generate_layouts(self, wb_params: WishboneParameters):
def elaborate(self, platform):
m = TModule()

m.submodules.result = result = Forwarder(self.resultLayout)

request_ready = Signal()

def FSMWBCycStart(request): # noqa: N802
# internal FSM function that starts Wishbone cycle
m.d.sync += self.wbMaster.cyc.eq(1)
Expand All @@ -140,49 +144,54 @@ def FSMWBCycStart(request): # noqa: N802
m.d.sync += self.wbMaster.dat_w.eq(Mux(request.we, request.data, 0))
m.d.sync += self.wbMaster.we.eq(request.we)
m.d.sync += self.wbMaster.sel.eq(request.sel)
m.next = "WBWaitACK"

@def_method(m, self.result, ready=self.res_ready)
def _():
m.d.sync += self.res_ready.eq(0)
return self.result_data

with m.FSM("Reset"):
with m.State("Reset"):
m.d.sync += self.wbMaster.rst.eq(1)
m.next = "Idle"
with m.State("Idle"):
# default values for important signals
m.d.sync += self.ready.eq(1)
m.d.sync += self.wbMaster.rst.eq(0)
m.d.sync += self.wbMaster.stb.eq(0)
m.d.sync += self.wbMaster.cyc.eq(0)

@def_method(m, self.request, ready=(self.ready & ~self.res_ready))
def _(arg):
m.d.sync += self.ready.eq(0)
m.d.sync += assign(self.txn_req, arg)
# do WBCycStart state in the same clock cycle
FSMWBCycStart(arg)
m.d.comb += request_ready.eq(1)
with m.If(self.request.run):
m.next = "WBWaitACK"

with m.State("WBCycStart"):
FSMWBCycStart(self.txn_req)
m.next = "WBWaitACK"

with m.State("WBWaitACK"):
with m.If(self.wbMaster.ack | self.wbMaster.err):
m.d.sync += self.wbMaster.cyc.eq(0)
m.d.sync += self.wbMaster.stb.eq(0)
m.d.sync += self.ready.eq(1)
m.d.sync += self.res_ready.eq(1)
m.d.sync += self.result_data.data.eq(Mux(self.txn_req.we, 0, self.wbMaster.dat_r))
m.d.sync += self.result_data.err.eq(self.wbMaster.err)
m.next = "Idle"
m.d.comb += request_ready.eq(1)
tr = Transaction()
with tr.body(m):
# will be always ready, as we checked that in Idle
result.write(m, data=Mux(self.txn_req.we, 0, self.wbMaster.dat_r), err=self.wbMaster.err)
with m.If(self.request.run):
m.next = "WBWaitACK"
with m.Else():
m.d.sync += self.wbMaster.cyc.eq(0)
m.d.sync += self.wbMaster.stb.eq(0)
m.next = "Idle"
with m.If(self.wbMaster.rty):
m.d.sync += self.wbMaster.cyc.eq(1)
m.d.sync += self.wbMaster.stb.eq(0)
m.next = "WBCycStart"

@def_method(m, self.result)
def _():
return result.read(m)

@def_method(m, self.request, ready=request_ready & result.write.ready)
def _(arg):
m.d.sync += assign(self.txn_req, arg)
# do WBCycStart state in the same clock cycle
FSMWBCycStart(arg)

tr.schedule_before(self.request)

return m


Expand Down
2 changes: 2 additions & 0 deletions test/frontend/test_icache.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ def wishbone_slave(self):
# Wishbone is addressing words, so we need to shit it a bit to get the real address.
addr = (yield self.test_module.wb_ctrl.wb.adr) << log2_int(self.cp.word_width_bytes)

yield
while random.random() < 0.5:
yield

Expand All @@ -107,6 +108,7 @@ def wishbone_slave(self):
def refiller_process(self):
while self.requests:
req_addr = self.requests.pop()

yield from self.test_module.start_refill.call(addr=req_addr)

for i in range(self.cp.words_in_block):
Expand Down
5 changes: 3 additions & 2 deletions test/peripherals/test_wishbone.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ def process():
# read request
yield from twbm.requestAdapter.call(addr=2, data=0, we=0, sel=1)
yield
assert not (yield wbm.request.ready)
yield from wwb.slave_verify(2, 0, 0, 1)
yield from wwb.slave_respond(8)
resp = yield from twbm.resultAdapter.call()
Expand All @@ -97,7 +96,8 @@ def process():
yield from wwb.slave_respond(1, ack=0, err=0, rty=1)
yield
assert not (yield wwb.wb.stb)
assert not (yield wbm.result.ready) # verify cycle restart
resp = yield from twbm.requestAdapter.call_try()
assert resp is None # verify cycle restart
yield from wwb.slave_wait()
yield from wwb.slave_verify(2, 0, 0, 0)
yield from wwb.slave_respond(1, ack=1, err=1, rty=0)
Expand Down Expand Up @@ -325,6 +325,7 @@ def mem_op_process():
yield from self.m.request.call(addr=addr, data=data, we=write, sel=sel)
res = yield from self.m.result.call()
if write:
yield # workaround, memory state will change the next cycle!
self.assertEqual((yield self.m.mem_slave.mem[addr]), mem_state[addr])
else:
self.assertEqual(res["data"], mem_state[addr])
Expand Down

0 comments on commit 57bec62

Please sign in to comment.