2012-01-10 11:10:18 -05:00
|
|
|
from migen.fhdl.structure import *
|
|
|
|
from migen.corelogic.record import *
|
|
|
|
from migen.corelogic.fsm import *
|
|
|
|
from migen.bus import wishbone
|
|
|
|
from migen.flow.actor import *
|
|
|
|
|
|
|
|
class Reader(Actor):
|
|
|
|
def __init__(self, layout):
|
|
|
|
self.bus = wishbone.Master()
|
|
|
|
Actor.__init__(self,
|
|
|
|
SchedulingModel(SchedulingModel.DYNAMIC),
|
2012-01-15 10:41:15 -05:00
|
|
|
("address", Sink, [("a", BV(30))]),
|
|
|
|
("data", Source, layout))
|
2012-01-10 11:10:18 -05:00
|
|
|
|
|
|
|
def get_fragment(self):
|
2012-01-15 10:41:15 -05:00
|
|
|
components, length = self.token("data").flatten(align=True, return_offset=True)
|
2012-01-10 11:10:18 -05:00
|
|
|
nwords = (length + 31)//32
|
|
|
|
|
|
|
|
# Address generator
|
|
|
|
ag_stb = Signal()
|
2012-01-15 10:41:15 -05:00
|
|
|
ag_sync = [If(ag_stb, self.bus.adr_o.eq(self.token("address").a))]
|
2012-01-10 11:10:18 -05:00
|
|
|
if nwords > 1:
|
|
|
|
ag_inc = Signal()
|
2012-01-15 10:41:15 -05:00
|
|
|
ag_sync.append(If(ag_inc, self.bus.adr_o.eq(self.bus.adr_o + 1)))
|
2012-01-10 11:10:18 -05:00
|
|
|
address_generator = Fragment(sync=ag_sync)
|
|
|
|
|
|
|
|
# Output buffer
|
|
|
|
ob_reg = Signal(BV(length))
|
|
|
|
ob_stbs = Signal(BV(nwords))
|
2012-01-15 10:41:15 -05:00
|
|
|
ob_sync = []
|
|
|
|
top = length
|
|
|
|
for w in range(nwords):
|
|
|
|
if top >= 32:
|
|
|
|
width = 32
|
|
|
|
sl = self.bus.dat_i
|
|
|
|
else:
|
|
|
|
width = top
|
|
|
|
sl = self.bus.dat_i[32-top:]
|
|
|
|
ob_sync.append(If(ob_stbs[w],
|
|
|
|
ob_reg[top-width:top].eq(sl)))
|
|
|
|
top -= width
|
2012-01-10 11:10:18 -05:00
|
|
|
ob_comb = []
|
|
|
|
offset = 0
|
|
|
|
for s in components:
|
|
|
|
w = s.bv.width
|
|
|
|
if isinstance(s, Signal):
|
2012-01-15 10:41:15 -05:00
|
|
|
ob_comb.append(s.eq(ob_reg[length-offset-w:length-offset]))
|
2012-01-10 11:10:18 -05:00
|
|
|
offset += w
|
|
|
|
output_buffer = Fragment(ob_comb, ob_sync)
|
|
|
|
|
|
|
|
# Controller
|
|
|
|
fetch_states = ["FETCH{0}".format(w) for w in range(nwords)]
|
|
|
|
states = ["IDLE"] + fetch_states + ["STROBE"]
|
|
|
|
fsm = FSM(*states)
|
|
|
|
self.busy.reset = Constant(1)
|
|
|
|
fsm.act(fsm.IDLE,
|
|
|
|
self.busy.eq(0),
|
|
|
|
ag_stb.eq(1),
|
|
|
|
self.endpoints["address"].ack.eq(1),
|
|
|
|
If(self.endpoints["address"].stb, fsm.next_state(fsm.FETCH0))
|
|
|
|
)
|
|
|
|
for w in range(nwords):
|
|
|
|
state = getattr(fsm, fetch_states[w])
|
|
|
|
if w == nwords - 1:
|
|
|
|
next_state = fsm.STROBE
|
|
|
|
else:
|
2012-01-15 10:41:15 -05:00
|
|
|
next_state = getattr(fsm, fetch_states[w+1])
|
2012-01-10 11:10:18 -05:00
|
|
|
fsm.act(state,
|
|
|
|
self.bus.cyc_o.eq(1),
|
|
|
|
self.bus.stb_o.eq(1),
|
2012-01-15 10:41:15 -05:00
|
|
|
ob_stbs[w].eq(1),
|
2012-01-10 11:10:18 -05:00
|
|
|
If(self.bus.ack_i,
|
2012-01-15 11:46:15 -05:00
|
|
|
fsm.next_state(next_state),
|
|
|
|
ag_inc.eq(1) if nwords > 1 else None
|
2012-01-10 11:10:18 -05:00
|
|
|
)
|
|
|
|
)
|
|
|
|
fsm.act(fsm.STROBE,
|
|
|
|
self.endpoints["data"].stb.eq(1),
|
|
|
|
If(self.endpoints["data"].ack, fsm.next_state(fsm.IDLE))
|
|
|
|
)
|
|
|
|
controller = fsm.get_fragment()
|
|
|
|
|
|
|
|
return address_generator + output_buffer + controller
|