Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/migen
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: fd16b66bdfcd
Choose a base ref
...
head repository: m-labs/migen
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 33b536e505f0
Choose a head ref
  • 2 commits
  • 2 files changed
  • 1 contributor

Commits on Jun 2, 2015

  1. migen/genlib/fsm: fix delayed_enter when delay is negative (can happe…

    …n when delay is generated from others parameters)
    enjoy-digital committed Jun 2, 2015
    Copy the full SHA
    79624ce View commit details
  2. Copy the full SHA
    33b536e View commit details
Showing with 265 additions and 63 deletions.
  1. +264 −62 migen/bus/wishbone.py
  2. +1 −1 migen/genlib/fsm.py
326 changes: 264 additions & 62 deletions migen/bus/wishbone.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from migen.fhdl.std import *
from migen.genlib import roundrobin
from migen.genlib.record import *
from migen.genlib.misc import optree, chooser
from migen.genlib.misc import optree, chooser, FlipFlop, Counter
from migen.genlib.fsm import FSM, NextState
from migen.bus.transactions import *

@@ -120,89 +120,291 @@ def __init__(self, masters, slaves, register=False):


class DownConverter(Module):
# DownConverter splits Wishbone accesses of N bits in M accesses of L bits where:
# N is the original data-width
# L is the target data-width
# M = N/L
def __init__(self, dw_i, dw_o):
self.wishbone_i = Interface(dw_i)
self.wishbone_o = Interface(dw_o)
self.ratio = dw_i//dw_o
"""DownConverter
###
This module splits Wishbone accesses from a master interface to a smaller
slave interface.
Writes:
Writes from master are splitted N writes to the slave. Access is acked when the last
access is acked by the slave.
Reads:
Read from master are splitted in N reads to the the slave. Read datas from
the slave are cached before being presented concatenated on the last access.
TODO:
Manage err signal? (Not implemented since we generally don't use it on Migen/MiSoC modules)
"""
def __init__(self, master, slave):
dw_from = flen(master.dat_r)
dw_to = flen(slave.dat_w)
ratio = dw_from//dw_to

# # #

rst = Signal()
read = Signal()
write = Signal()

# generate internal write and read ack
write_ack = Signal()
read_ack = Signal()
ack = Signal()
counter = Counter(max=ratio)
self.submodules += counter
counter_done = Signal()
self.comb += counter_done.eq(counter.value == ratio-1)

# Main FSM
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE",
counter.reset.eq(1),
If(master.stb & master.cyc,
If(master.we,
NextState("WRITE")
).Else(
NextState("READ")
)
)
)
fsm.act("WRITE",
write.eq(1),
slave.we.eq(1),
slave.cyc.eq(1),
If(master.stb & master.cyc,
slave.stb.eq(1),
If(slave.ack,
counter.ce.eq(1),
If(counter_done,
master.ack.eq(1),
NextState("IDLE")
)
)
).Elif(~master.cyc,
NextState("IDLE")
)
)
fsm.act("READ",
read.eq(1),
slave.cyc.eq(1),
If(master.stb & master.cyc,
slave.stb.eq(1),
If(slave.ack,
counter.ce.eq(1),
If(counter_done,
master.ack.eq(1),
NextState("IDLE")
)
)
).Elif(~master.cyc,
NextState("IDLE")
)
)

# Address
self.comb += [
ack.eq(self.wishbone_o.cyc & self.wishbone_o.stb & self.wishbone_o.ack),
write_ack.eq(ack & self.wishbone_o.we),
read_ack.eq(ack & ~self.wishbone_o.we)
If(counter_done,
slave.cti.eq(7) # indicate end of burst
).Else(
slave.cti.eq(2)
),
slave.adr.eq(Cat(counter.value, master.adr))
]

# accesses counter logic
cnt = Signal(max=self.ratio)
self.sync += If(rst, cnt.eq(0)).Elif(ack, cnt.eq(cnt + 1))
# Datapath
cases = {}
for i in range(ratio):
cases[i] = [
slave.sel.eq(master.sel[i*dw_to//8:(i+1)*dw_to]),
slave.dat_w.eq(master.dat_w[i*dw_to:(i+1)*dw_to])
]
self.comb += Case(counter.value, cases)


cached_data = Signal(dw_from)
self.comb += master.dat_r.eq(Cat(cached_data[dw_to:], slave.dat_r))
self.sync += \
If(read & counter.ce,
cached_data.eq(master.dat_r)
)


# read data path
dat_r = Signal(dw_i)
self.sync += If(ack, dat_r.eq(Cat(self.wishbone_o.dat_r, dat_r[:dw_i-dw_o])))
class UpConverter(Module):
"""UpConverter
# write data path
dat_w = Signal(dw_i)
self.comb += dat_w.eq(self.wishbone_i.dat_w)
This module up-converts wishbone accesses and bursts from a master interface
to a wider slave interface. This allows efficient use wishbone bursts.
# errors generation
err = Signal()
self.sync += If(ack, err.eq(self.wishbone_o.err))
Writes:
Wishbone writes are cached before being written to the slave. Access to
the slave is done at the end of a burst or when address reach end of burst
addressing.
# direct connection of wishbone_i --> wishbone_o signals
for name, size, direction in self.wishbone_i.layout:
if direction == DIR_M_TO_S and name not in ["adr", "dat_w", "sel"]:
self.comb += getattr(self.wishbone_o, name).eq(getattr(self.wishbone_i, name))
Reads:
Cache is refilled only at the beginning of each burst, the subsequent
reads of a burst use the cached data.
# adaptation of adr & dat signals
TODO:
Manage err signal? (Not implemented since we generally don't use it on Migen/MiSoC modules)
"""
def __init__(self, master, slave):
dw_from = flen(master.dat_r)
dw_to = flen(slave.dat_w)
ratio = dw_to//dw_from
ratiobits = log2_int(ratio)

# # #

write = Signal()
evict = Signal()
refill = Signal()
read = Signal()

address = FlipFlop(30)
self.submodules += address
self.comb += address.d.eq(master.adr)

counter = Counter(max=ratio)
self.submodules += counter
counter_offset = Signal(max=ratio)
counter_done = Signal()
self.comb += [
self.wishbone_o.adr[0:flen(cnt)].eq(cnt),
self.wishbone_o.adr[flen(cnt):].eq(self.wishbone_i.adr)
counter_offset.eq(address.q),
counter_done.eq((counter.value + counter_offset) == ratio-1)
]

self.comb += chooser(dat_w, cnt, self.wishbone_o.dat_w, reverse=True)
self.comb += chooser(self.wishbone_i.sel, cnt, self.wishbone_o.sel, reverse=True)
cached_data = Signal(dw_to)
cached_sel = Signal(dw_to//8)

end_of_burst = Signal()
self.comb += end_of_burst.eq(~master.cyc |
(master.stb & master.cyc & master.ack & ((master.cti == 7) | counter_done)))

# fsm
fsm = FSM(reset_state="IDLE")
self.submodules += fsm

need_refill = FlipFlop(reset=1)
self.submodules += need_refill
self.comb += [
need_refill.reset.eq(end_of_burst),
need_refill.d.eq(0)
]

# Main FSM
self.submodules.fsm = fsm = FSM()
fsm.act("IDLE",
If(write_ack, NextState("WRITE_ADAPT")),
If(read_ack, NextState("READ_ADAPT"))
counter.reset.eq(1),
If(master.stb & master.cyc,
address.ce.eq(1),
If(master.we,
NextState("WRITE")
).Else(
If(need_refill.q,
NextState("REFILL")
).Else(
NextState("READ")
)
)
)
)

fsm.act("WRITE_ADAPT",
If(write_ack & (cnt == self.ratio-1),
NextState("IDLE"),
rst.eq(1),
self.wishbone_i.err.eq(err | self.wishbone_o.err),
self.wishbone_i.ack.eq(1),
fsm.act("WRITE",
If(master.stb & master.cyc,
write.eq(1),
counter.ce.eq(1),
master.ack.eq(1),
If(counter_done,
NextState("EVICT")
)
).Elif(~master.cyc,
NextState("EVICT")
)
)

master_i_dat_r = Signal(dw_i)
self.comb += master_i_dat_r.eq(Cat(self.wishbone_o.dat_r, dat_r[:dw_i-dw_o]))

fsm.act("READ_ADAPT",
If(read_ack & (cnt == self.ratio-1),
NextState("IDLE"),
rst.eq(1),
self.wishbone_i.err.eq(err | self.wishbone_o.err),
self.wishbone_i.ack.eq(1),
self.wishbone_i.dat_r.eq(master_i_dat_r)
fsm.act("EVICT",
evict.eq(1),
slave.stb.eq(1),
slave.we.eq(1),
slave.cyc.eq(1),
slave.dat_w.eq(cached_data),
slave.sel.eq(cached_sel),
If(slave.ack,
NextState("IDLE")
)
)
fsm.act("REFILL",
refill.eq(1),
slave.stb.eq(1),
slave.cyc.eq(1),
If(slave.ack,
need_refill.ce.eq(1),
NextState("READ")
)
)
fsm.act("READ",
read.eq(1),
If(master.stb & master.cyc,
master.ack.eq(1)
),
NextState("IDLE")
)

# Address
self.comb += [
slave.cti.eq(7), # we are not able to generate bursts since up-converting
slave.adr.eq(address.q[ratiobits:])
]

# Datapath
cached_datas = [FlipFlop(dw_from) for i in range(ratio)]
cached_sels = [FlipFlop(dw_from//8) for i in range(ratio)]
self.submodules += cached_datas, cached_sels

cases = {}
for i in range(ratio):
write_sel = Signal()
cases[i] = write_sel.eq(1)
self.comb += [
cached_sels[i].reset.eq(counter.reset),
If(write,
cached_datas[i].d.eq(master.dat_w),
).Else(
cached_datas[i].d.eq(slave.dat_r[dw_from*i:dw_from*(i+1)])
),
cached_sels[i].d.eq(master.sel),
If((write & write_sel) | refill,
cached_datas[i].ce.eq(1),
cached_sels[i].ce.eq(1)
)
]
self.comb += Case(counter.value + counter_offset, cases)

cases = {}
for i in range(ratio):
cases[i] = master.dat_r.eq(cached_datas[i].q)
self.comb += Case(address.q[:ratiobits], cases)

self.comb += [
cached_data.eq(Cat([cached_data.q for cached_data in cached_datas])),
cached_sel.eq(Cat([cached_sel.q for cached_sel in cached_sels]))
]


class Converter(Module):
"""Converter
This module is a wrapper for DownConverter and UpConverter.
It should preferably be used rather than direct instantiations
of specific converters.
"""
def __init__(self, master, slave):
self.master = master
self.slave = slave

# # #

dw_from = flen(master.dat_r)
dw_to = flen(slave.dat_r)
if dw_from > dw_to:
downconverter = DownConverter(master, slave)
self.submodules += downconverter
elif dw_from < dw_to:
upconverter = UpConverter(master, slave)
self.submodules += upconverter
else:
Record.connect(master, slave)


class Tap(Module):
2 changes: 1 addition & 1 deletion migen/genlib/fsm.py
Original file line number Diff line number Diff line change
@@ -74,7 +74,7 @@ def act(self, state, *statements):
def delayed_enter(self, name, target, delay):
if self.finalized:
raise FinalizeError
if delay:
if delay > 0:
state = name
for i in range(delay):
if i == delay - 1: