From 5959a382a72632ae0cda7123ca075fc3c1b151e2 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Fri, 8 Apr 2022 16:23:51 -0700 Subject: [PATCH] format code --- src/nmutil/byterev.py | 5 +- src/nmutil/clz.py | 2 +- src/nmutil/concurrentunit.py | 75 +++++----- src/nmutil/dynamicpipe.py | 14 +- src/nmutil/formal/proof_clz.py | 6 +- src/nmutil/iocontrol.py | 49 ++++--- src/nmutil/latch.py | 8 +- src/nmutil/multipipe.py | 100 ++++++------- src/nmutil/nmoperator.py | 20 +-- src/nmutil/noconflict.py | 40 +++--- src/nmutil/picker.py | 21 +-- src/nmutil/pipemodbase.py | 10 +- src/nmutil/plru.py | 13 +- src/nmutil/queue.py | 25 ++-- src/nmutil/ripple.py | 17 ++- src/nmutil/sim_tmp_alternative.py | 2 +- src/nmutil/singlepipe.py | 133 ++++++++++-------- src/nmutil/stageapi.py | 31 ++-- src/nmutil/test/example_buf_pipe.py | 4 +- src/nmutil/test/example_gtkwave.py | 1 + src/nmutil/test/test_clz.py | 1 - src/nmutil/test/test_inout_mux_pipe.py | 44 +++--- .../test/test_inout_unary_mux_cancel_pipe.py | 48 +++---- src/nmutil/test/test_outmux_pipe.py | 23 +-- src/nmutil/test/test_reservation_stations.py | 36 ++--- src/nmutil/util.py | 10 +- 26 files changed, 391 insertions(+), 347 deletions(-) diff --git a/src/nmutil/byterev.py b/src/nmutil/byterev.py index 7dad450..84ba740 100644 --- a/src/nmutil/byterev.py +++ b/src/nmutil/byterev.py @@ -7,6 +7,8 @@ from nmigen import Signal, Cat # TODO: turn this into a module? + + def byte_reverse(m, name, data, length): """byte_reverse: unlike nmigen word_select this takes a dynamic length @@ -28,11 +30,10 @@ def byte_reverse(m, name, data, length): # Switch statement needed: dynamic length had better be = 1,2,4 or 8 with m.Switch(length): - for j in [1,2,4,8]: + for j in [1, 2, 4, 8]: with m.Case(j): rev = [] for i in range(j): rev.append(data.word_select(j-1-i, 8)) comb += data_r.eq(Cat(*rev)) return data_r - diff --git a/src/nmutil/clz.py b/src/nmutil/clz.py index 2fda8c2..39e8329 100644 --- a/src/nmutil/clz.py +++ b/src/nmutil/clz.py @@ -10,6 +10,7 @@ import math """ + class CLZ(Elaboratable): def __init__(self, width): self.width = width @@ -86,4 +87,3 @@ class CLZ(Elaboratable): comb += self.lz.eq(pairs[0][0]) return m - diff --git a/src/nmutil/concurrentunit.py b/src/nmutil/concurrentunit.py index e802ed6..bbb6059 100644 --- a/src/nmutil/concurrentunit.py +++ b/src/nmutil/concurrentunit.py @@ -101,6 +101,7 @@ class ALUProxy: sandwiched in between the fan-in and fan-out. One ALU looks like it is multiple concurrent ALUs """ + def __init__(self, alu, p, n): self.alu = alu self.p = p @@ -121,14 +122,15 @@ class ReservationStations(Elaboratable): Fan-in and Fan-out are combinatorial. """ + def __init__(self, num_rows, maskwid=0, feedback_width=None): self.num_rows = nr = num_rows self.feedback_width = feedback_width self.inpipe = InMuxPipe(nr, self.i_specfn, maskwid) # fan-in - self.outpipe = MuxOutPipe(nr, self.o_specfn, maskwid) # fan-out + self.outpipe = MuxOutPipe(nr, self.o_specfn, maskwid) # fan-out self.p = self.inpipe.p # kinda annoying, - self.n = self.outpipe.n # use pipe in/out as this class in/out + self.n = self.outpipe.n # use pipe in/out as this class in/out self._ports = self.inpipe.ports() + self.outpipe.ports() def setup_pseudoalus(self): @@ -190,6 +192,7 @@ class ReservationStations2(Elaboratable): FAILING TO SET THE MUXID IS GUARANTEED TO RESULT IN CORRUPTED DATA. """ + def __init__(self, alu, num_rows, alu_name=None): if alu_name is None: alu_name = "alu" @@ -208,7 +211,7 @@ class ReservationStations2(Elaboratable): self.p.append(p) self.n.append(n) - self.pipe = self # for Arbiter to select the incoming prevcontrols + self.pipe = self # for Arbiter to select the incoming prevcontrols # set up pseudo-alus that look like a standard pipeline self.pseudoalus = [] @@ -226,7 +229,7 @@ class ReservationStations2(Elaboratable): def elaborate(self, platform): m = Module() - pe = PriorityEncoder(self.num_rows) # input priority picker + pe = PriorityEncoder(self.num_rows) # input priority picker m.submodules[self.alu_name] = self.alu m.submodules.selector = pe for i, (p, n) in enumerate(zip(self.p, self.n)): @@ -238,9 +241,9 @@ class ReservationStations2(Elaboratable): self.m_id = Signal.like(pe.o) # ReservationStation status information, progressively updated in FSM - rsvd = Signal(self.num_rows) # indicates RS data in flight - sent = Signal(self.num_rows) # sent indicates data in pipeline - wait = Signal(self.num_rows) # the outputs are waiting for accept + rsvd = Signal(self.num_rows) # indicates RS data in flight + sent = Signal(self.num_rows) # sent indicates data in pipeline + wait = Signal(self.num_rows) # the outputs are waiting for accept # pick first non-reserved ReservationStation with data not already # sent into the ALU @@ -250,7 +253,7 @@ class ReservationStations2(Elaboratable): # mux in and mux out ids. note that all data *must* have a muxid mid = self.m_id # input mux selector - o_muxid = self.alu.n.o_data.muxid # output mux selector + o_muxid = self.alu.n.o_data.muxid # output mux selector # technically speaking this could be set permanently "HI". # when all the ReservationStations outputs are waiting, @@ -267,68 +270,68 @@ class ReservationStations2(Elaboratable): # first, establish input: select one input to pass data to (p_mux) for i in range(self.num_rows): - i_buf, o_buf = self.alu.new_specs("buf%d" % i) # buffers + i_buf, o_buf = self.alu.new_specs("buf%d" % i) # buffers with m.FSM(): # indicate ready to accept data, and accept it if incoming # BUT, if there is an opportunity to send on immediately # to the ALU, take it early (combinatorial) with m.State("ACCEPTING%d" % i): - m.d.comb += self.p[i].o_ready.eq(1) # ready indicator + m.d.comb += self.p[i].o_ready.eq(1) # ready indicator with m.If(self.p[i].i_valid): # valid data incoming m.d.sync += rsvd[i].eq(1) # now reserved # a unique opportunity: the ALU happens to be free - with m.If(mid == i): # picker selected us + with m.If(mid == i): # picker selected us with m.If(self.alu.p.o_ready): # ALU can accept - m.d.comb += self.alu.p.i_valid.eq(1) # transfer + # transfer + m.d.comb += self.alu.p.i_valid.eq(1) m.d.comb += nmoperator.eq(self.alu.p.i_data, - self.p[i].i_data) - m.d.sync += sent[i].eq(1) # now reserved - m.next = "WAITOUT%d" % i # move to "wait output" + self.p[i].i_data) + m.d.sync += sent[i].eq(1) # now reserved + m.next = "WAITOUT%d" % i # move to "wait output" with m.Else(): # nope. ALU wasn't free. try next cycle(s) m.d.sync += nmoperator.eq(i_buf, self.p[i].i_data) - m.next = "ACCEPTED%d" % i # move to "accepted" + m.next = "ACCEPTED%d" % i # move to "accepted" # now try to deliver to the ALU, but only if we are "picked" with m.State("ACCEPTED%d" % i): - with m.If(mid == i): # picker selected us + with m.If(mid == i): # picker selected us with m.If(self.alu.p.o_ready): # ALU can accept - m.d.comb += self.alu.p.i_valid.eq(1) # transfer + m.d.comb += self.alu.p.i_valid.eq(1) # transfer m.d.comb += nmoperator.eq(self.alu.p.i_data, i_buf) - m.d.sync += sent[i].eq(1) # now reserved - m.next = "WAITOUT%d" % i # move to "wait output" + m.d.sync += sent[i].eq(1) # now reserved + m.next = "WAITOUT%d" % i # move to "wait output" # waiting for output to appear on the ALU, take a copy # BUT, again, if there is an opportunity to send on # immediately, take it (combinatorial) with m.State("WAITOUT%d" % i): - with m.If(o_muxid == i): # when ALU output matches our RS + with m.If(o_muxid == i): # when ALU output matches our RS with m.If(self.alu.n.o_valid): # ALU can accept # second unique opportunity: the RS is ready - with m.If(self.n[i].i_ready): # ready to receive - m.d.comb += self.n[i].o_valid.eq(1) # valid + with m.If(self.n[i].i_ready): # ready to receive + m.d.comb += self.n[i].o_valid.eq(1) # valid m.d.comb += nmoperator.eq(self.n[i].o_data, self.alu.n.o_data) - m.d.sync += wait[i].eq(0) # clear waiting - m.d.sync += sent[i].eq(0) # and sending - m.d.sync += rsvd[i].eq(0) # and reserved - m.next = "ACCEPTING%d" % i # back to "accepting" + m.d.sync += wait[i].eq(0) # clear waiting + m.d.sync += sent[i].eq(0) # and sending + m.d.sync += rsvd[i].eq(0) # and reserved + m.next = "ACCEPTING%d" % i # back to "accepting" with m.Else(): # nope. RS wasn't ready. try next cycles - m.d.sync += wait[i].eq(1) # now waiting + m.d.sync += wait[i].eq(1) # now waiting m.d.sync += nmoperator.eq(o_buf, self.alu.n.o_data) - m.next = "SENDON%d" % i # move to "send data on" + m.next = "SENDON%d" % i # move to "send data on" # waiting for "valid" indicator on RS output: deliver it with m.State("SENDON%d" % i): - with m.If(self.n[i].i_ready): # user is ready to receive - m.d.comb += self.n[i].o_valid.eq(1) # indicate valid + with m.If(self.n[i].i_ready): # user is ready to receive + m.d.comb += self.n[i].o_valid.eq(1) # indicate valid m.d.comb += nmoperator.eq(self.n[i].o_data, o_buf) - m.d.sync += wait[i].eq(0) # clear waiting - m.d.sync += sent[i].eq(0) # and sending - m.d.sync += rsvd[i].eq(0) # and reserved - m.next = "ACCEPTING%d" % i # and back to "accepting" + m.d.sync += wait[i].eq(0) # clear waiting + m.d.sync += sent[i].eq(0) # and sending + m.d.sync += rsvd[i].eq(0) # and reserved + m.next = "ACCEPTING%d" % i # and back to "accepting" return m - diff --git a/src/nmutil/dynamicpipe.py b/src/nmutil/dynamicpipe.py index 0187cf2..95f58e5 100644 --- a/src/nmutil/dynamicpipe.py +++ b/src/nmutil/dynamicpipe.py @@ -27,6 +27,7 @@ import threading # list post: # http://lists.libre-riscv.org/pipermail/libre-riscv-dev/2019-July/002259.html + class Meta(ABCMeta): registry = {} recursing = threading.local() @@ -38,11 +39,11 @@ class Meta(ABCMeta): if mcls.recursing.check: return super().__call__(*args, **kw) spec = args[0] - base = spec.pipekls # pick up the dynamic class from PipelineSpec, HERE + base = spec.pipekls # pick up the dynamic class from PipelineSpec, HERE if (cls, base) not in mcls.registry: - print ("__call__", args, kw, cls, base, - base.__bases__, cls.__bases__) + print("__call__", args, kw, cls, base, + base.__bases__, cls.__bases__) mcls.registry[cls, base] = type( cls.__name__, (cls, base) + cls.__bases__[1:], @@ -74,7 +75,7 @@ class Meta(ABCMeta): class DynamicPipe(metaclass=Meta): def __init__(self, *args): - print ("DynamicPipe init", super(), args) + print("DynamicPipe init", super(), args) super().__init__(self, *args) @@ -84,7 +85,7 @@ class DynamicPipe(metaclass=Meta): # could hypothetically be passed through the pspec. class SimpleHandshakeRedir(SimpleHandshake): def __init__(self, mod, *args): - print ("redir", mod, args) + print("redir", mod, args) stage = self if args and args[0].stage: stage = args[0].stage @@ -97,6 +98,5 @@ class MaskCancellableRedir(MaskCancellable): maskwid = args[0].maskwid if args[0].stage: stage = args[0].stage - print ("redir mask", mod, args, maskwid) + print("redir mask", mod, args, maskwid) MaskCancellable.__init__(self, stage, maskwid) - diff --git a/src/nmutil/formal/proof_clz.py b/src/nmutil/formal/proof_clz.py index aac25d3..2bfcfe6 100644 --- a/src/nmutil/formal/proof_clz.py +++ b/src/nmutil/formal/proof_clz.py @@ -23,7 +23,6 @@ class Driver(Elaboratable): sig_in = Signal.like(dut.sig_in) count = Signal.like(dut.lz) - m.d.comb += [ sig_in.eq(AnyConst(width)), dut.sig_in.eq(sig_in), @@ -43,20 +42,23 @@ class Driver(Elaboratable): comb += result_sig.eq(result) comb += Assert(result_sig == count) - + # setup the inputs and outputs of the DUT as anyconst return m + class CLZTestCase(FHDLTestCase): def test_proof(self): module = Driver() self.assertFormal(module, mode="bmc", depth=4) + def test_ilang(self): dut = Driver() vl = rtlil.convert(dut, ports=[]) with open("clz.il", "w") as f: f.write(vl) + if __name__ == '__main__': unittest.main() diff --git a/src/nmutil/iocontrol.py b/src/nmutil/iocontrol.py index c4da57b..4705b00 100644 --- a/src/nmutil/iocontrol.py +++ b/src/nmutil/iocontrol.py @@ -42,9 +42,9 @@ class Object: self.fields = OrderedDict() def __setattr__(self, k, v): - print ("kv", k, v) + print("kv", k, v) if (k.startswith('_') or k in ["fields", "name", "src_loc"] or - k in dir(Object) or "fields" not in self.__dict__): + k in dir(Object) or "fields" not in self.__dict__): return object.__setattr__(self, k, v) self.fields[k] = v @@ -67,16 +67,16 @@ class Object: res = [] for (k, o) in self.fields.items(): i = getattr(inp, k) - print ("eq", o, i) + print("eq", o, i) rres = o.eq(i) if isinstance(rres, Sequence): res += rres else: res.append(rres) - print (res) + print(res) return res - def ports(self): # being called "keys" would be much better + def ports(self): # being called "keys" would be much better return list(self) @@ -92,16 +92,15 @@ def add_prefix_to_record_signals(prefix, record): class RecordObject(Record): def __init__(self, layout=None, name=None): - #if name is None: + # if name is None: # name = tracer.get_var_name(depth=2, default="$ro") Record.__init__(self, layout=layout or [], name=name) - def __setattr__(self, k, v): #print(f"RecordObject setattr({k}, {v})") #print (dir(Record)) if (k.startswith('_') or k in ["fields", "name", "src_loc"] or - k in dir(Record) or "fields" not in self.__dict__): + k in dir(Record) or "fields" not in self.__dict__): return object.__setattr__(self, k, v) if self.name is None: @@ -126,7 +125,7 @@ class RecordObject(Record): self.layout.fields.update(newlayout) def __iter__(self): - for x in self.fields.values(): # remember: fields is an OrderedDict + for x in self.fields.values(): # remember: fields is an OrderedDict if hasattr(x, 'ports'): yield from x.ports() elif isinstance(x, Record): @@ -137,7 +136,7 @@ class RecordObject(Record): else: yield x - def ports(self): # would be better being called "keys" + def ports(self): # would be better being called "keys" return list(self) @@ -151,7 +150,7 @@ class PrevControl(Elaboratable): """ def __init__(self, i_width=1, stage_ctl=False, maskwid=0, offs=0, - name=None): + name=None): if name is None: name = "" n_piv = "p_i_valid"+name @@ -164,7 +163,7 @@ class PrevControl(Elaboratable): self.stop_i = Signal(maskwid) # prev >>in self self.i_valid = Signal(i_width, name=n_piv) # prev >>in self self._o_ready = Signal(name=n_por) # prev <> next - self.stop_o = Signal(maskwid) # self out>> next - self.o_valid = Signal(name=n_nov) # self out>> next - self.i_ready = Signal(name=n_nir) # self <> next + self.stop_o = Signal(maskwid) # self out>> next + self.o_valid = Signal(name=n_nov) # self out>> next + self.i_ready = Signal(name=n_nir) # self < 1: # hmm always create an Array even of len 1 + if True: # len(r_data) > 1: # hmm always create an Array even of len 1 p_i_valid = Array(p_i_valid) n_i_readyn = Array(n_i_readyn) data_valid = Array(data_valid) @@ -323,7 +324,7 @@ class CombMultiInPipeline(MultiInControlBase): nirn = Signal(reset_less=True) m.d.comb += nirn.eq(~self.n.i_ready) mid = self.p_mux.m_id - print ("CombMuxIn mid", self, self.stage, self.routemask, mid, p_len) + print("CombMuxIn mid", self, self.stage, self.routemask, mid, p_len) for i in range(p_len): m.d.comb += data_valid[i].eq(0) m.d.comb += n_i_readyn[i].eq(1) @@ -346,8 +347,8 @@ class CombMultiInPipeline(MultiInControlBase): av.append(data_valid[i]) anyvalid = Cat(*av) m.d.comb += self.n.o_valid.eq(anyvalid.bool()) - m.d.comb += data_valid[mid].eq(p_i_valid[mid] | \ - (n_i_readyn[mid] )) + m.d.comb += data_valid[mid].eq(p_i_valid[mid] | + (n_i_readyn[mid])) if self.routemask: # XXX hack - fixes loop @@ -368,8 +369,8 @@ class CombMultiInPipeline(MultiInControlBase): with m.If(mid == i): m.d.comb += eq(self.n.o_data, r_data[i]) else: - ml = [] # accumulate output masks - ms = [] # accumulate output stops + ml = [] # accumulate output masks + ms = [] # accumulate output stops for i in range(p_len): vr = Signal(reset_less=True) p = self.p[i] @@ -417,7 +418,7 @@ class NonCombMultiInPipeline(MultiInControlBase): def __init__(self, stage, p_len, p_mux, maskwid=0, routemask=False): MultiInControlBase.__init__(self, p_len=p_len, maskwid=maskwid, - routemask=routemask) + routemask=routemask) self.stage = stage self.maskwid = maskwid self.p_mux = p_mux @@ -425,7 +426,7 @@ class NonCombMultiInPipeline(MultiInControlBase): # set up the input and output data for i in range(p_len): name = 'i_data_%d' % i - self.p[i].i_data = _spec(stage.ispec, name) # input type + self.p[i].i_data = _spec(stage.ispec, name) # input type self.n.o_data = _spec(stage.ospec, 'o_data') def process(self, i): @@ -445,12 +446,12 @@ class NonCombMultiInPipeline(MultiInControlBase): p_len = len(self.p) for i in range(p_len): name = 'r_%d' % i - r = _spec(self.stage.ispec, name) # input type + r = _spec(self.stage.ispec, name) # input type r_data.append(r) r_busy.append(Signal(name="r_busy%d" % i, reset_less=True)) p_i_valid.append(Signal(name="p_i_valid%d" % i, reset_less=True)) if hasattr(self.stage, "setup"): - print ("setup", self, self.stage, r) + print("setup", self, self.stage, r) self.stage.setup(m, r) if len(r_data) > 1: r_data = Array(r_data) @@ -460,7 +461,7 @@ class NonCombMultiInPipeline(MultiInControlBase): nirn = Signal(reset_less=True) m.d.comb += nirn.eq(~self.n.i_ready) mid = self.p_mux.m_id - print ("CombMuxIn mid", self, self.stage, self.routemask, mid, p_len) + print("CombMuxIn mid", self, self.stage, self.routemask, mid, p_len) for i in range(p_len): m.d.comb += r_busy[i].eq(0) m.d.comb += n_i_readyn[i].eq(1) @@ -481,8 +482,8 @@ class NonCombMultiInPipeline(MultiInControlBase): av.append(data_valid[i]) anyvalid = Cat(*av) m.d.comb += self.n.o_valid.eq(anyvalid.bool()) - m.d.comb += data_valid[mid].eq(p_i_valid[mid] | \ - (n_i_readyn[mid] )) + m.d.comb += data_valid[mid].eq(p_i_valid[mid] | + (n_i_readyn[mid])) if self.routemask: # XXX hack - fixes loop @@ -501,8 +502,8 @@ class NonCombMultiInPipeline(MultiInControlBase): m.d.comb += eq(self.n.mask_o, self.p[i].mask_i) m.d.comb += eq(r_data[i], self.p[i].i_data) else: - ml = [] # accumulate output masks - ms = [] # accumulate output stops + ml = [] # accumulate output masks + ms = [] # accumulate output stops for i in range(p_len): vr = Signal(reset_less=True) p = self.p[i] @@ -532,35 +533,35 @@ class NonCombMultiInPipeline(MultiInControlBase): class CombMuxOutPipe(CombMultiOutPipeline): def __init__(self, stage, n_len, maskwid=0, muxidname=None, - routemask=False): + routemask=False): muxidname = muxidname or "muxid" # HACK: stage is also the n-way multiplexer CombMultiOutPipeline.__init__(self, stage, n_len=n_len, - n_mux=stage, maskwid=maskwid, - routemask=routemask) + n_mux=stage, maskwid=maskwid, + routemask=routemask) # HACK: n-mux is also the stage... so set the muxid equal to input muxid muxid = getattr(self.p.i_data, muxidname) - print ("combmuxout", muxidname, muxid) + print("combmuxout", muxidname, muxid) stage.m_id = muxid - class InputPriorityArbiter(Elaboratable): """ arbitration module for Input-Mux pipe, baed on PriorityEncoder """ + def __init__(self, pipe, num_rows): self.pipe = pipe self.num_rows = num_rows self.mmax = int(log(self.num_rows) / log(2)) - self.m_id = Signal(self.mmax, reset_less=True) # multiplex id + self.m_id = Signal(self.mmax, reset_less=True) # multiplex id self.active = Signal(reset_less=True) def elaborate(self, platform): m = Module() assert len(self.pipe.p) == self.num_rows, \ - "must declare input to be same size" + "must declare input to be same size" pe = PriorityEncoder(self.num_rows) m.submodules.selector = pe @@ -576,7 +577,7 @@ class InputPriorityArbiter(Elaboratable): else: m.d.comb += p_i_valid.eq(self.pipe.p[i].i_valid_test) in_ready.append(p_i_valid) - m.d.comb += pe.i.eq(Cat(*in_ready)) # array of input "valids" + m.d.comb += pe.i.eq(Cat(*in_ready)) # array of input "valids" m.d.comb += self.active.eq(~pe.n) # encoder active (one input valid) m.d.comb += self.m_id.eq(pe.o) # output one active input @@ -586,7 +587,6 @@ class InputPriorityArbiter(Elaboratable): return [self.m_id, self.active] - class PriorityCombMuxInPipe(CombMultiInPipeline): """ an example of how to use the combinatorial pipeline. """ diff --git a/src/nmutil/nmoperator.py b/src/nmutil/nmoperator.py index a5fa03b..e48bb7f 100644 --- a/src/nmutil/nmoperator.py +++ b/src/nmutil/nmoperator.py @@ -41,6 +41,7 @@ class Visitor2: python object, enumerate them, find out the list of Signals that way, and assign them. """ + def iterator2(self, o, i): if isinstance(o, dict): yield from self.dict_iter2(o, i) @@ -83,10 +84,10 @@ class Visitor2: val = ai.fields else: val = ai - if hasattr(val, field_name): # check for attribute + if hasattr(val, field_name): # check for attribute val = getattr(val, field_name) else: - val = val[field_name] # dictionary-style specification + val = val[field_name] # dictionary-style specification yield from self.iterator2(ao.fields[field_name], val) def record_iter2(self, ao, ai): @@ -95,10 +96,10 @@ class Visitor2: val = ai.fields else: val = ai - if hasattr(val, field_name): # check for attribute + if hasattr(val, field_name): # check for attribute val = getattr(val, field_name) else: - val = val[field_name] # dictionary-style specification + val = val[field_name] # dictionary-style specification yield from self.iterator2(ao.fields[field_name], val) def arrayproxy_iter2(self, ao, ai): @@ -120,6 +121,7 @@ class Visitor: """ a helper class for iterating single-argument compound data structures. similar to Visitor2. """ + def iterate(self, i): """ iterate a compound structure recursively using yield """ @@ -141,10 +143,10 @@ class Visitor: val = ai.fields else: val = ai - if hasattr(val, field_name): # check for attribute + if hasattr(val, field_name): # check for attribute val = getattr(val, field_name) else: - val = val[field_name] # dictionary-style specification + val = val[field_name] # dictionary-style specification #print ("recidx", idx, field_name, field_shape, val) yield from self.iterate(val) @@ -181,8 +183,6 @@ def cat(i): """ flattens a compound structure recursively using Cat """ from nmigen._utils import flatten - #res = list(flatten(i)) # works (as of nmigen commit f22106e5) HOWEVER... - res = list(Visitor().iterate(i)) # needed because input may be a sequence + # res = list(flatten(i)) # works (as of nmigen commit f22106e5) HOWEVER... + res = list(Visitor().iterate(i)) # needed because input may be a sequence return Cat(*res) - - diff --git a/src/nmutil/noconflict.py b/src/nmutil/noconflict.py index ad7eb09..01bc52a 100644 --- a/src/nmutil/noconflict.py +++ b/src/nmutil/noconflict.py @@ -1,28 +1,33 @@ -import inspect, types +import inspect +import types ############## preliminary: two utility functions ##################### + def skip_redundant(iterable, skipset=None): - "Redundant items are repeated items or items in the original skipset." - if skipset is None: skipset = set() - for item in iterable: - if item not in skipset: - skipset.add(item) - yield item + "Redundant items are repeated items or items in the original skipset." + if skipset is None: + skipset = set() + for item in iterable: + if item not in skipset: + skipset.add(item) + yield item def remove_redundant(metaclasses): - skipset = set([type]) - for meta in metaclasses: # determines the metaclasses to be skipped - skipset.update(inspect.getmro(meta)[1:]) - return tuple(skip_redundant(metaclasses, skipset)) + skipset = set([type]) + for meta in metaclasses: # determines the metaclasses to be skipped + skipset.update(inspect.getmro(meta)[1:]) + return tuple(skip_redundant(metaclasses, skipset)) ################################################################## ## now the core of the module: two mutually recursive functions ## ################################################################## + memoized_metaclasses_map = {} + def get_noconflict_metaclass(bases, left_metas, right_metas): """Not intended to be used outside of this module, unless you know what you are doing.""" @@ -32,24 +37,25 @@ def get_noconflict_metaclass(bases, left_metas, right_metas): # return existing confict-solving meta, if any if needed_metas in memoized_metaclasses_map: - return memoized_metaclasses_map[needed_metas] + return memoized_metaclasses_map[needed_metas] # nope: compute, memoize and return needed conflict-solving meta elif not needed_metas: # wee, a trivial case, happy us meta = type - elif len(needed_metas) == 1: # another trivial case - meta = needed_metas[0] + elif len(needed_metas) == 1: # another trivial case + meta = needed_metas[0] # check for recursion, can happen i.e. for Zope ExtensionClasses - elif needed_metas == bases: + elif needed_metas == bases: raise TypeError("Incompatible root metatypes", needed_metas) - else: # gotta work ... + else: # gotta work ... metaname = '_' + ''.join([m.__name__ for m in needed_metas]) meta = classmaker()(metaname, needed_metas, {}) memoized_metaclasses_map[needed_metas] = meta return meta + def classmaker(left_metas=(), right_metas=()): def make_class(name, bases, adict): - print ("make_class", name) + print("make_class", name) metaclass = get_noconflict_metaclass(bases, left_metas, right_metas) return metaclass(name, bases, adict) return make_class diff --git a/src/nmutil/picker.py b/src/nmutil/picker.py index 0babc07..380ffb8 100644 --- a/src/nmutil/picker.py +++ b/src/nmutil/picker.py @@ -36,6 +36,7 @@ class PriorityPicker(Elaboratable): * reverse_i=True is for convenient reverseal of the input bits * reverse_o=True is for convenient reversal of the output bits """ + def __init__(self, wid, lsb_mode=False, reverse_i=False, reverse_o=False): self.wid = wid # inputs @@ -44,14 +45,14 @@ class PriorityPicker(Elaboratable): self.reverse_o = reverse_o self.i = Signal(wid, reset_less=True) self.o = Signal(wid, reset_less=True) - self.en_o = Signal(reset_less=True) # true if any output is true + self.en_o = Signal(reset_less=True) # true if any output is true def elaborate(self, platform): m = Module() # works by saying, "if all previous bits were zero, we get a chance" res = [] - ni = Signal(self.wid, reset_less = True) + ni = Signal(self.wid, reset_less=True) i = list(self.i) if self.reverse_i: i.reverse() @@ -60,7 +61,7 @@ class PriorityPicker(Elaboratable): if self.lsb_mode: prange.reverse() for n in prange: - t = Signal(name="t%d" % n, reset_less = True) + t = Signal(name="t%d" % n, reset_less=True) res.append(t) if n == 0: m.d.comb += t.eq(i[n]) @@ -71,7 +72,7 @@ class PriorityPicker(Elaboratable): # we like Cat(*xxx). turn lists into concatenated bits m.d.comb += self.o.eq(Cat(*res)) # useful "is any output enabled" signal - m.d.comb += self.en_o.eq(self.o.bool()) # true if 1 input is true + m.d.comb += self.en_o.eq(self.o.bool()) # true if 1 input is true return m @@ -95,16 +96,16 @@ class MultiPriorityPicker(Elaboratable): Also outputted (optional): an index for each picked "thing". """ + def __init__(self, wid, levels, indices=False, multiin=False): self.levels = levels self.wid = wid self.indices = indices self.multiin = multiin - if multiin: # multiple inputs, multiple outputs. - i_l = [] # array of picker outputs + i_l = [] # array of picker outputs for j in range(self.levels): i = Signal(self.wid, name="i_%d" % j, reset_less=True) i_l.append(i) @@ -114,7 +115,7 @@ class MultiPriorityPicker(Elaboratable): self.i = Signal(self.wid, reset_less=True) # create array of (single-bit) outputs (unary) - o_l = [] # array of picker outputs + o_l = [] # array of picker outputs for j in range(self.levels): o = Signal(self.wid, name="o_%d" % j, reset_less=True) o_l.append(o) @@ -128,7 +129,7 @@ class MultiPriorityPicker(Elaboratable): # add an array of indices lidx = math.ceil(math.log2(self.levels)) - idx_o = [] # store the array of indices + idx_o = [] # store the array of indices for j in range(self.levels): i = Signal(lidx, name="idxo_%d" % j, reset_less=True) idx_o.append(i) @@ -160,10 +161,10 @@ class MultiPriorityPicker(Elaboratable): p_mask = Const(0, self.wid) else: mask = Signal(self.wid, name="m_%d" % j, reset_less=True) - comb += mask.eq(prev_pp.o | p_mask) # accumulate output bits + comb += mask.eq(prev_pp.o | p_mask) # accumulate output bits comb += pp.i.eq(i & ~mask) # mask out input p_mask = mask - i = pp.i # for input to next round + i = pp.i # for input to next round prev_pp = pp # accumulate the enables diff --git a/src/nmutil/pipemodbase.py b/src/nmutil/pipemodbase.py index 1706e97..455a204 100644 --- a/src/nmutil/pipemodbase.py +++ b/src/nmutil/pipemodbase.py @@ -16,8 +16,9 @@ from nmutil.singlepipe import StageChain class PipeModBase(Elaboratable): """PipeModBase: common code between nearly every pipeline module """ + def __init__(self, pspec, modname): - self.modname = modname # use this to give a name to this module + self.modname = modname # use this to give a name to this module self.pspec = pspec self.i = self.ispec() self.o = self.ospec() @@ -39,6 +40,7 @@ class PipeModBaseChain(DynamicPipe): and uses pspec.pipekls to dynamically select the pipeline type Also conforms to the Pipeline Stage API """ + def __init__(self, pspec): self.pspec = pspec self.chain = self.get_chain() @@ -55,10 +57,10 @@ class PipeModBaseChain(DynamicPipe): return self.chain[-1].ospec() def process(self, i): - return self.o # ... returned here (see setup comment below) + return self.o # ... returned here (see setup comment below) def setup(self, m, i): """ links module to inputs and outputs """ - StageChain(self.chain).setup(m, i) # input linked here, through chain - self.o = self.chain[-1].o # output is the last thing in the chain... + StageChain(self.chain).setup(m, i) # input linked here, through chain + self.o = self.chain[-1].o # output is the last thing in the chain... diff --git a/src/nmutil/plru.py b/src/nmutil/plru.py index 4f07a88..5dabd14 100644 --- a/src/nmutil/plru.py +++ b/src/nmutil/plru.py @@ -63,7 +63,7 @@ class PLRU(Elaboratable): shift = LOG_TLB - lvl new_idx = Const(~((i >> (shift-1)) & 1), 1) plru_idx = idx_base + (i >> shift) - #print("plru", i, lvl, hex(idx_base), + # print("plru", i, lvl, hex(idx_base), # plru_idx, shift, new_idx) m.d.sync += plru_tree[plru_idx].eq(new_idx) @@ -91,8 +91,8 @@ class PLRU(Elaboratable): new_idx = (i >> (shift-1)) & 1 plru_idx = idx_base + (i >> shift) plru = Signal(reset_less=True, - name="plru-%d-%d-%d-%d" % \ - (i, lvl, plru_idx, new_idx)) + name="plru-%d-%d-%d-%d" % + (i, lvl, plru_idx, new_idx)) m.d.comb += plru.eq(plru_tree[plru_idx]) if new_idx: en.append(~plru) # yes inverted (using bool() below) @@ -134,8 +134,8 @@ class PLRUs(Elaboratable): comb += te.n.eq(~self.valid) comb += te.i.eq(self.index) - out = Array(Signal(self.n_bits, name="plru_out%d" % x) \ - for x in range(self.n_plrus)) + out = Array(Signal(self.n_bits, name="plru_out%d" % x) + for x in range(self.n_plrus)) for i in range(self.n_plrus): # PLRU interface @@ -160,10 +160,7 @@ if __name__ == '__main__': with open("test_plru.il", "w") as f: f.write(vl) - dut = PLRUs(4, 2) vl = rtlil.convert(dut, ports=dut.ports()) with open("test_plrus.il", "w") as f: f.write(vl) - - diff --git a/src/nmutil/queue.py b/src/nmutil/queue.py index 7bd75a6..f205e47 100644 --- a/src/nmutil/queue.py +++ b/src/nmutil/queue.py @@ -74,17 +74,19 @@ class Queue(FIFOInterface, Elaboratable): # deq is "dequeue" (data out, aka "next stage") p_o_ready = self.w_rdy p_i_valid = self.w_en - enq_data = self.w_data # aka p_i_data + enq_data = self.w_data # aka p_i_data n_o_valid = self.r_rdy n_i_ready = self.r_en - deq_data = self.r_data # aka n_o_data + deq_data = self.r_data # aka n_o_data # intermediaries ptr_width = bits_for(self.depth - 1) if self.depth > 1 else 0 - enq_ptr = Signal(ptr_width) # cyclic pointer to "insert" point (wrport) - deq_ptr = Signal(ptr_width) # cyclic pointer to "remove" point (rdport) - maybe_full = Signal() # not reset_less (set by sync) + # cyclic pointer to "insert" point (wrport) + enq_ptr = Signal(ptr_width) + # cyclic pointer to "remove" point (rdport) + deq_ptr = Signal(ptr_width) + maybe_full = Signal() # not reset_less (set by sync) # temporaries do_enq = Signal(reset_less=True) @@ -96,17 +98,17 @@ class Queue(FIFOInterface, Elaboratable): enq_max = Signal(reset_less=True) deq_max = Signal(reset_less=True) - m.d.comb += [ptr_match.eq(enq_ptr == deq_ptr), # read-ptr = write-ptr + m.d.comb += [ptr_match.eq(enq_ptr == deq_ptr), # read-ptr = write-ptr ptr_diff.eq(enq_ptr - deq_ptr), enq_max.eq(enq_ptr == self.depth - 1), deq_max.eq(deq_ptr == self.depth - 1), empty.eq(ptr_match & ~maybe_full), full.eq(ptr_match & maybe_full), - do_enq.eq(p_o_ready & p_i_valid), # write conditions ok - do_deq.eq(n_i_ready & n_o_valid), # read conditions ok + do_enq.eq(p_o_ready & p_i_valid), # write conditions ok + do_deq.eq(n_i_ready & n_o_valid), # read conditions ok # set r_rdy and w_rdy (NOTE: see pipe mode below) - n_o_valid.eq(~empty), # cannot read if empty! + n_o_valid.eq(~empty), # cannot read if empty! p_o_ready.eq(~full), # cannot write if full! # set up memory and connect to input and output @@ -114,8 +116,9 @@ class Queue(FIFOInterface, Elaboratable): ram_write.data.eq(enq_data), ram_write.en.eq(do_enq), ram_read.addr.eq(deq_ptr), - deq_data.eq(ram_read.data) # NOTE: overridden in fwft mode - ] + # NOTE: overridden in fwft mode + deq_data.eq(ram_read.data) + ] # under write conditions, SRAM write-pointer moves on next clock with m.If(do_enq): diff --git a/src/nmutil/ripple.py b/src/nmutil/ripple.py index 3630995..6b40d43 100644 --- a/src/nmutil/ripple.py +++ b/src/nmutil/ripple.py @@ -30,6 +30,7 @@ class Ripple(Elaboratable): results_in => 0 0 1 0 1 0 0 1 output => 1 1 1 0 0 1 1 1 """ + def __init__(self, width, start_lsb=True): self.width = width self.start_lsb = start_lsb @@ -43,13 +44,15 @@ class Ripple(Elaboratable): width = self.width results_in = list(self.results_in) - if not self.start_lsb: results_in = reversed(results_in) + if not self.start_lsb: + results_in = reversed(results_in) l = [results_in[0]] for i in range(width-1): l.append(Mux(self.gates[i], results_in[i+1], self.output[i])) - if not self.start_lsb: l = reversed(l) + if not self.start_lsb: + l = reversed(l) comb += self.output.eq(Cat(*l)) return m @@ -61,6 +64,7 @@ class RippleLSB(Ripple): based on a partition mask, the LSB is "rippled" (duplicated) up to the beginning of the next partition. """ + def __init__(self, width): Ripple.__init__(self, width, start_lsb=True) @@ -71,6 +75,7 @@ class RippleMSB(Ripple): based on a partition mask, the MSB is "rippled" (duplicated) down to the beginning of the next partition. """ + def __init__(self, width): Ripple.__init__(self, width, start_lsb=True) @@ -84,6 +89,7 @@ class MoveMSBDown(Elaboratable): into its own useful module), then ANDs the (new) LSB with the partition mask to isolate it. """ + def __init__(self, width): self.width = width self.results_in = Signal(width, reset_less=True) @@ -97,14 +103,14 @@ class MoveMSBDown(Elaboratable): intermed = Signal(width, reset_less=True) # first propagate MSB down until the nearest partition gate - comb += intermed[-1].eq(self.results_in[-1]) # start at MSB + comb += intermed[-1].eq(self.results_in[-1]) # start at MSB for i in range(width-2, -1, -1): cur = Mux(self.gates[i], self.results_in[i], intermed[i+1]) comb += intermed[i].eq(cur) # now only select those bits where the mask starts - out = [intermed[0]] # LSB of first part always set - for i in range(width-1): # length of partition gates + out = [intermed[0]] # LSB of first part always set + for i in range(width-1): # length of partition gates out.append(self.gates[i] & intermed[i+1]) comb += self.output.eq(Cat(*out)) @@ -116,4 +122,3 @@ if __name__ == "__main__": # then check with yosys "read_ilang ripple.il; show top" alu = MoveMSBDown(width=4) main(alu, ports=[alu.results_in, alu.gates, alu.output]) - diff --git a/src/nmutil/sim_tmp_alternative.py b/src/nmutil/sim_tmp_alternative.py index a90b6e7..21ecb74 100644 --- a/src/nmutil/sim_tmp_alternative.py +++ b/src/nmutil/sim_tmp_alternative.py @@ -41,7 +41,7 @@ except ImportError: Delay, Settle, Tick, Passive) nmigen_sim_environ_variable = os.environ.get("NMIGEN_SIM_MODE") \ - or "pysim" + or "pysim" """Detected run-time engine from environment""" diff --git a/src/nmutil/singlepipe.py b/src/nmutil/singlepipe.py index 9d7e154..3fae364 100644 --- a/src/nmutil/singlepipe.py +++ b/src/nmutil/singlepipe.py @@ -160,11 +160,13 @@ class RecordBasedStage(Stage): honestly it's a lot easier just to create a direct Records-based class (see ExampleAddRecordStage) """ + def __init__(self, in_shape, out_shape, processfn, setupfn=None): self.in_shape = in_shape self.out_shape = out_shape self.__process = processfn self.__setup = setupfn + def ispec(self): return Record(self.in_shape) def ospec(self): return Record(self.out_shape) def process(seif, i): return self.__process(i) @@ -179,6 +181,7 @@ class PassThroughStage(StageCls): (many APIs would potentially use a static "wrap" method in e.g. StageCls to achieve a similar effect) """ + def __init__(self, iospecfn): self.iospecfn = iospecfn def ispec(self): return self.iospecfn() def ospec(self): return self.iospecfn() @@ -194,6 +197,7 @@ class ControlBase(StageHelper, Elaboratable): *BYPASSES* a ControlBase instance ready/valid signalling, which clearly should not be done without a really, really good reason. """ + def __init__(self, stage=None, in_multi=None, stage_ctl=False, maskwid=0): """ Base class containing ready/valid/data to previous and next stages @@ -205,7 +209,7 @@ class ControlBase(StageHelper, Elaboratable): * add o_data member to NextControl (n) Calling ControlBase._new_data is a good way to do that. """ - print ("ControlBase", self, stage, in_multi, stage_ctl) + print("ControlBase", self, stage, in_multi, stage_ctl) StageHelper.__init__(self, stage) # set up input and output IO ACK (prev/next ready/valid) @@ -284,19 +288,19 @@ class ControlBase(StageHelper, Elaboratable): """ assert len(pipechain) > 0, "pipechain must be non-zero length" assert self.stage is None, "do not use connect with a stage" - eqs = [] # collated list of assignment statements + eqs = [] # collated list of assignment statements # connect inter-chain for i in range(len(pipechain)-1): pipe1 = pipechain[i] # earlier pipe2 = pipechain[i+1] # later (by 1) - eqs += pipe1.connect_to_next(pipe2) # earlier n to later p + eqs += pipe1.connect_to_next(pipe2) # earlier n to later p # connect front and back of chain to ourselves front = pipechain[0] # first in chain end = pipechain[-1] # last in chain - self.set_specs(front, end) # sets up ispec/ospec functions - self._new_data("chain") # NOTE: REPLACES existing data + self.set_specs(front, end) # sets up ispec/ospec functions + self._new_data("chain") # NOTE: REPLACES existing data eqs += front._connect_in(self) # front p to our p eqs += end._connect_out(self) # end n to our n @@ -308,8 +312,8 @@ class ControlBase(StageHelper, Elaboratable): return nmoperator.eq(self.p.i_data, i) def __iter__(self): - yield from self.p # yields ready/valid/data (data also gets yielded) - yield from self.n # ditto + yield from self.p # yields ready/valid/data (data also gets yielded) + yield from self.n # ditto def ports(self): return list(self) @@ -383,36 +387,39 @@ class BufferedHandshake(ControlBase): por_pivn = Signal(reset_less=True) npnn = Signal(reset_less=True) self.m.d.comb += [p_i_valid.eq(self.p.i_valid_test), - o_n_validn.eq(~self.n.o_valid), - n_i_ready.eq(self.n.i_ready_test), - nir_por.eq(n_i_ready & self.p._o_ready), - nir_por_n.eq(n_i_ready & ~self.p._o_ready), - nir_novn.eq(n_i_ready | o_n_validn), - nirn_novn.eq(~n_i_ready & o_n_validn), - npnn.eq(nir_por | nirn_novn), - por_pivn.eq(self.p._o_ready & ~p_i_valid) - ] + o_n_validn.eq(~self.n.o_valid), + n_i_ready.eq(self.n.i_ready_test), + nir_por.eq(n_i_ready & self.p._o_ready), + nir_por_n.eq(n_i_ready & ~self.p._o_ready), + nir_novn.eq(n_i_ready | o_n_validn), + nirn_novn.eq(~n_i_ready & o_n_validn), + npnn.eq(nir_por | nirn_novn), + por_pivn.eq(self.p._o_ready & ~p_i_valid) + ] # store result of processing in combinatorial temporary self.m.d.comb += nmoperator.eq(result, self.data_r) # if not in stall condition, update the temporary register - with self.m.If(self.p.o_ready): # not stalled - self.m.d.sync += nmoperator.eq(r_data, result) # update buffer + with self.m.If(self.p.o_ready): # not stalled + self.m.d.sync += nmoperator.eq(r_data, result) # update buffer # data pass-through conditions with self.m.If(npnn): - o_data = self._postprocess(result) # XXX TBD, does nothing right now - self.m.d.sync += [self.n.o_valid.eq(p_i_valid), # valid if p_valid - nmoperator.eq(self.n.o_data, o_data), # update out - ] + # XXX TBD, does nothing right now + o_data = self._postprocess(result) + self.m.d.sync += [self.n.o_valid.eq(p_i_valid), # valid if p_valid + # update out + nmoperator.eq(self.n.o_data, o_data), + ] # buffer flush conditions (NOTE: can override data passthru conditions) - with self.m.If(nir_por_n): # not stalled + with self.m.If(nir_por_n): # not stalled # Flush the [already processed] buffer to the output port. - o_data = self._postprocess(r_data) # XXX TBD, does nothing right now + # XXX TBD, does nothing right now + o_data = self._postprocess(r_data) self.m.d.sync += [self.n.o_valid.eq(1), # reg empty - nmoperator.eq(self.n.o_data, o_data), # flush - ] + nmoperator.eq(self.n.o_data, o_data), # flush + ] # output ready conditions self.m.d.sync += self.p._o_ready.eq(nir_novn | por_pivn) @@ -433,6 +440,7 @@ class MaskNoDelayCancellable(ControlBase): | | +--process->--^ """ + def __init__(self, stage, maskwid, in_multi=None, stage_ctl=False): ControlBase.__init__(self, stage, in_multi, stage_ctl, maskwid) @@ -459,8 +467,9 @@ class MaskNoDelayCancellable(ControlBase): m.d.sync += self.n.o_valid.eq(p_i_valid) m.d.sync += self.n.mask_o.eq(Mux(p_i_valid, maskedout, 0)) with m.If(p_i_valid): - o_data = self._postprocess(result) # XXX TBD, does nothing right now - m.d.sync += nmoperator.eq(self.n.o_data, o_data) # update output + # XXX TBD, does nothing right now + o_data = self._postprocess(result) + m.d.sync += nmoperator.eq(self.n.o_data, o_data) # update output # output valid if # input always "ready" @@ -492,8 +501,9 @@ class MaskCancellable(ControlBase): | | +--process->--^ """ + def __init__(self, stage, maskwid, in_multi=None, stage_ctl=False, - dynamic=False): + dynamic=False): ControlBase.__init__(self, stage, in_multi, stage_ctl, maskwid) self.dynamic = dynamic if dynamic: @@ -525,7 +535,7 @@ class MaskCancellable(ControlBase): m.d.comb += [p_i_valid.eq(self.p.i_valid_test & maskedout.bool()), n_i_ready.eq(self.n.i_ready_test), p_i_valid_p_o_ready.eq(p_i_valid & self.p.o_ready), - ] + ] # if idmask nonzero, mask gets passed on (and register set). # register is left as-is if idmask is zero, but out-mask is set to @@ -548,7 +558,7 @@ class MaskCancellable(ControlBase): m.d.sync += r_busy.eq(1) # output valid # previous invalid or not ready, however next is accepting with m.Elif(n_i_ready): - m.d.sync += r_busy.eq(0) # ...so set output invalid + m.d.sync += r_busy.eq(0) # ...so set output invalid # output set combinatorially from latch m.d.comb += nmoperator.eq(self.n.o_data, r_latch) @@ -627,24 +637,26 @@ class SimpleHandshake(ControlBase): m.d.comb += [p_i_valid.eq(self.p.i_valid_test), n_i_ready.eq(self.n.i_ready_test), p_i_valid_p_o_ready.eq(p_i_valid & self.p.o_ready), - ] + ] # store result of processing in combinatorial temporary m.d.comb += nmoperator.eq(result, self.data_r) # previous valid and ready with m.If(p_i_valid_p_o_ready): - o_data = self._postprocess(result) # XXX TBD, does nothing right now + # XXX TBD, does nothing right now + o_data = self._postprocess(result) m.d.sync += [r_busy.eq(1), # output valid - nmoperator.eq(self.n.o_data, o_data), # update output - ] + nmoperator.eq(self.n.o_data, o_data), # update output + ] # previous invalid or not ready, however next is accepting with m.Elif(n_i_ready): - o_data = self._postprocess(result) # XXX TBD, does nothing right now + # XXX TBD, does nothing right now + o_data = self._postprocess(result) m.d.sync += [nmoperator.eq(self.n.o_data, o_data)] # TODO: could still send data here (if there was any) - #m.d.sync += self.n.o_valid.eq(0) # ...so set output invalid - m.d.sync += r_busy.eq(0) # ...so set output invalid + # m.d.sync += self.n.o_valid.eq(0) # ...so set output invalid + m.d.sync += r_busy.eq(0) # ...so set output invalid m.d.comb += self.n.o_valid.eq(r_busy) # if next is ready, so is previous @@ -725,8 +737,8 @@ class UnbufferedPipeline(ControlBase): def elaborate(self, platform): self.m = m = ControlBase.elaborate(self, platform) - data_valid = Signal() # is data valid or not - r_data = _spec(self.stage.ospec, "r_tmp") # output type + data_valid = Signal() # is data valid or not + r_data = _spec(self.stage.ospec, "r_tmp") # output type # some temporaries p_i_valid = Signal(reset_less=True) @@ -742,7 +754,7 @@ class UnbufferedPipeline(ControlBase): with m.If(pv): m.d.sync += nmoperator.eq(r_data, self.data_r) - o_data = self._postprocess(r_data) # XXX TBD, does nothing right now + o_data = self._postprocess(r_data) # XXX TBD, does nothing right now m.d.comb += nmoperator.eq(self.n.o_data, o_data) return self.m @@ -812,8 +824,8 @@ class UnbufferedPipeline2(ControlBase): def elaborate(self, platform): self.m = m = ControlBase.elaborate(self, platform) - buf_full = Signal() # is data valid or not - buf = _spec(self.stage.ospec, "r_tmp") # output type + buf_full = Signal() # is data valid or not + buf = _spec(self.stage.ospec, "r_tmp") # output type # some temporaries p_i_valid = Signal(reset_less=True) @@ -824,7 +836,7 @@ class UnbufferedPipeline2(ControlBase): m.d.sync += buf_full.eq(~self.n.i_ready_test & self.n.o_valid) o_data = Mux(buf_full, buf, self.data_r) - o_data = self._postprocess(o_data) # XXX TBD, does nothing right now + o_data = self._postprocess(o_data) # XXX TBD, does nothing right now m.d.comb += nmoperator.eq(self.n.o_data, o_data) m.d.sync += nmoperator.eq(buf, self.n.o_data) @@ -867,7 +879,7 @@ class PassThroughHandshake(ControlBase): def elaborate(self, platform): self.m = m = ControlBase.elaborate(self, platform) - r_data = _spec(self.stage.ospec, "r_tmp") # output type + r_data = _spec(self.stage.ospec, "r_tmp") # output type # temporaries p_i_valid = Signal(reset_less=True) @@ -875,12 +887,12 @@ class PassThroughHandshake(ControlBase): m.d.comb += p_i_valid.eq(self.p.i_valid_test) m.d.comb += pvr.eq(p_i_valid & self.p.o_ready) - m.d.comb += self.p.o_ready.eq(~self.n.o_valid | self.n.i_ready_test) - m.d.sync += self.n.o_valid.eq(p_i_valid | ~self.p.o_ready) + m.d.comb += self.p.o_ready.eq(~self.n.o_valid | self.n.i_ready_test) + m.d.sync += self.n.o_valid.eq(p_i_valid | ~self.p.o_ready) odata = Mux(pvr, self.data_r, r_data) m.d.sync += nmoperator.eq(r_data, odata) - r_data = self._postprocess(r_data) # XXX TBD, does nothing right now + r_data = self._postprocess(r_data) # XXX TBD, does nothing right now m.d.comb += nmoperator.eq(self.n.o_data, r_data) return m @@ -891,6 +903,7 @@ class RegisterPipeline(UnbufferedPipeline): sync'd latch out of o_data and o_valid as an indirect byproduct of using PassThroughStage """ + def __init__(self, iospecfn): UnbufferedPipeline.__init__(self, PassThroughStage(iospecfn)) @@ -901,8 +914,9 @@ class FIFOControl(ControlBase): i_data -> fifo.din -> FIFO -> fifo.dout -> o_data """ + def __init__(self, depth, stage, in_multi=None, stage_ctl=False, - fwft=True, pipe=False): + fwft=True, pipe=False): """ FIFO Control * :depth: number of entries in the FIFO @@ -948,24 +962,25 @@ class FIFOControl(ControlBase): m.d.comb += nmoperator.eq(result, self.process(i_data)) return nmoperator.cat(result) - ## prev: make the FIFO (Queue object) "look" like a PrevControl... + # prev: make the FIFO (Queue object) "look" like a PrevControl... m.submodules.fp = fp = PrevControl() fp.i_valid, fp._o_ready, fp.i_data = fifo.w_en, fifo.w_rdy, fifo.w_data m.d.comb += fp._connect_in(self.p, fn=processfn) # next: make the FIFO (Queue object) "look" like a NextControl... m.submodules.fn = fn = NextControl() - fn.o_valid, fn.i_ready, fn.o_data = fifo.r_rdy, fifo.r_en, fifo.r_data + fn.o_valid, fn.i_ready, fn.o_data = fifo.r_rdy, fifo.r_en, fifo.r_data connections = fn._connect_out(self.n, fn=nmoperator.cat) valid_eq, ready_eq, o_data = connections # ok ok so we can't just do the ready/valid eqs straight: # first 2 from connections are the ready/valid, 3rd is data. if self.fwft: - m.d.comb += [valid_eq, ready_eq] # combinatorial on next ready/valid + # combinatorial on next ready/valid + m.d.comb += [valid_eq, ready_eq] else: - m.d.sync += [valid_eq, ready_eq] # non-fwft mode needs sync - o_data = self._postprocess(o_data) # XXX TBD, does nothing right now + m.d.sync += [valid_eq, ready_eq] # non-fwft mode needs sync + o_data = self._postprocess(o_data) # XXX TBD, does nothing right now m.d.comb += o_data return m @@ -975,19 +990,23 @@ class FIFOControl(ControlBase): class UnbufferedPipeline(FIFOControl): def __init__(self, stage, in_multi=None, stage_ctl=False): FIFOControl.__init__(self, 1, stage, in_multi, stage_ctl, - fwft=True, pipe=False) + fwft=True, pipe=False) # aka "BreakReadyStage" XXX had to set fwft=True to get it to work + + class PassThroughHandshake(FIFOControl): def __init__(self, stage, in_multi=None, stage_ctl=False): FIFOControl.__init__(self, 1, stage, in_multi, stage_ctl, - fwft=True, pipe=True) + fwft=True, pipe=True) # this is *probably* BufferedHandshake, although test #997 now succeeds. + + class BufferedHandshake(FIFOControl): def __init__(self, stage, in_multi=None, stage_ctl=False): FIFOControl.__init__(self, 2, stage, in_multi, stage_ctl, - fwft=True, pipe=False) + fwft=True, pipe=False) """ diff --git a/src/nmutil/stageapi.py b/src/nmutil/stageapi.py index fc5d709..bc79071 100644 --- a/src/nmutil/stageapi.py +++ b/src/nmutil/stageapi.py @@ -118,10 +118,10 @@ class StageCls(metaclass=ABCMeta): def ispec(self): pass # REQUIRED @abstractmethod def ospec(self): pass # REQUIRED - #@abstractmethod - #def setup(self, m, i): pass # OPTIONAL - #@abstractmethod - #def process(self, i): pass # OPTIONAL + # @abstractmethod + # def setup(self, m, i): pass # OPTIONAL + # @abstractmethod + # def process(self, i): pass # OPTIONAL class Stage(metaclass=ABCMeta): @@ -140,12 +140,12 @@ class Stage(metaclass=ABCMeta): @abstractmethod def ospec(): pass - #@staticmethod - #@abstractmethod + # @staticmethod + # @abstractmethod #def setup(m, i): pass - #@staticmethod - #@abstractmethod + # @staticmethod + # @abstractmethod #def process(i): pass @@ -157,6 +157,7 @@ class StageHelper(Stage): it differs from the stage that it wraps in that all the "optional" functions are provided (hence the designation "convenience wrapper") """ + def __init__(self, stage): self.stage = stage self._ispecfn = None @@ -197,8 +198,8 @@ class StageHelper(Stage): if self.stage is not None and hasattr(self.stage, "setup"): self.stage.setup(m, i) - def _postprocess(self, i): # XXX DISABLED - return i # RETURNS INPUT + def _postprocess(self, i): # XXX DISABLED + return i # RETURNS INPUT if hasattr(self.stage, "postprocess"): return self.stage.postprocess(i) return i @@ -243,6 +244,7 @@ class StageChain(StageHelper): side-effects (state-based / clock-based input) or conditional (inter-chain) dependencies, unless you really know what you are doing. """ + def __init__(self, chain, specallocate=False): assert len(chain) > 0, "stage chain must be non-zero length" self.chain = chain @@ -262,12 +264,13 @@ class StageChain(StageHelper): o = _spec(ofn, cname) if isinstance(o, Elaboratable): setattr(m.submodules, cname, o) - m.d.comb += nmoperator.eq(o, c.process(i)) # process input into "o" + # process input into "o" + m.d.comb += nmoperator.eq(o, c.process(i)) if idx == len(self.chain)-1: break ifn = self.chain[idx+1].ispec # new input on next loop i = _spec(ifn, 'chainin%d' % (idx+1)) - m.d.comb += nmoperator.eq(i, o) # assign to next input + m.d.comb += nmoperator.eq(i, o) # assign to next input self.o = o return self.o # last loop is the output @@ -280,6 +283,4 @@ class StageChain(StageHelper): return self.o # last loop is the output def process(self, i): - return self.o # conform to Stage API: return last-loop output - - + return self.o # conform to Stage API: return last-loop output diff --git a/src/nmutil/test/example_buf_pipe.py b/src/nmutil/test/example_buf_pipe.py index 61e9b13..823a999 100644 --- a/src/nmutil/test/example_buf_pipe.py +++ b/src/nmutil/test/example_buf_pipe.py @@ -4,8 +4,8 @@ from nmutil.nmoperator import eq from nmutil.iocontrol import (PrevControl, NextControl) from nmutil.singlepipe import (PrevControl, NextControl, ControlBase, - StageCls, Stage, StageChain, - BufferedHandshake, UnbufferedPipeline) + StageCls, Stage, StageChain, + BufferedHandshake, UnbufferedPipeline) from nmigen import Signal, Module from nmigen.cli import verilog, rtlil diff --git a/src/nmutil/test/example_gtkwave.py b/src/nmutil/test/example_gtkwave.py index 21fc491..c01bfac 100644 --- a/src/nmutil/test/example_gtkwave.py +++ b/src/nmutil/test/example_gtkwave.py @@ -28,6 +28,7 @@ class Shifter(Elaboratable): * ``n_o_valid`` and ``n_i_ready``: handshake """ + def __init__(self, width): self.width = width """data width""" diff --git a/src/nmutil/test/test_clz.py b/src/nmutil/test/test_clz.py index 14e3472..e9b893b 100644 --- a/src/nmutil/test/test_clz.py +++ b/src/nmutil/test/test_clz.py @@ -16,7 +16,6 @@ class CLZTestCase(unittest.TestCase): sig_in = Signal.like(dut.sig_in) count = Signal.like(dut.lz) - m.d.comb += [ dut.sig_in.eq(sig_in), count.eq(dut.lz)] diff --git a/src/nmutil/test/test_inout_mux_pipe.py b/src/nmutil/test/test_inout_mux_pipe.py index a9fd416..149c6a5 100644 --- a/src/nmutil/test/test_inout_mux_pipe.py +++ b/src/nmutil/test/test_inout_mux_pipe.py @@ -32,16 +32,15 @@ class PassData(Object): self.data = Signal(16, reset_less=True) - class PassThroughStage: def ispec(self): return PassData() + def ospec(self): - return self.ispec() # same as ospec + return self.ispec() # same as ospec def process(self, i): - return i # pass-through - + return i # pass-through class PassThroughPipe(SimpleHandshake): @@ -59,7 +58,7 @@ class InputTest: self.di[muxid] = {} self.do[muxid] = {} for i in range(self.tlen): - self.di[muxid][i] = randint(0, 255) + (muxid<<8) + self.di[muxid][i] = randint(0, 255) + (muxid << 8) self.do[muxid][i] = self.di[muxid][i] def send(self, muxid): @@ -76,7 +75,7 @@ class InputTest: yield o_p_ready = yield rs.o_ready - print ("send", muxid, i, hex(op2)) + print("send", muxid, i, hex(op2)) yield rs.i_valid.eq(0) # wait random period of time before queueing another value @@ -86,22 +85,22 @@ class InputTest: yield rs.i_valid.eq(0) yield - print ("send ended", muxid) + print("send ended", muxid) - ## wait random period of time before queueing another value - #for i in range(randint(0, 3)): + # wait random period of time before queueing another value + # for i in range(randint(0, 3)): # yield #send_range = randint(0, 3) - #if send_range == 0: + # if send_range == 0: # send = True - #else: + # else: # send = randint(0, send_range) != 0 def rcv(self, muxid): while True: #stall_range = randint(0, 3) - #for j in range(randint(1,10)): + # for j in range(randint(1,10)): # stall = randint(0, stall_range) != 0 # yield self.dut.n[0].i_ready.eq(stall) # yield @@ -117,20 +116,20 @@ class InputTest: out_i = yield n.o_data.idx out_v = yield n.o_data.data - print ("recv", out_muxid, out_i, hex(out_v)) + print("recv", out_muxid, out_i, hex(out_v)) # see if this output has occurred already, delete it if it has assert muxid == out_muxid, \ - "out_muxid %d not correct %d" % (out_muxid, muxid) + "out_muxid %d not correct %d" % (out_muxid, muxid) assert out_i in self.do[muxid], "out_i %d not in array %s" % \ - (out_i, repr(self.do[muxid])) - assert self.do[muxid][out_i] == out_v # pass-through data + (out_i, repr(self.do[muxid])) + assert self.do[muxid][out_i] == out_v # pass-through data del self.do[muxid][out_i] # check if there's any more outputs if len(self.do[muxid]) == 0: break - print ("recv ended", muxid) + print("recv ended", muxid) class TestPriorityMuxPipe(PriorityCombMuxInPipe): @@ -151,7 +150,7 @@ class OutputTest: muxid = i else: muxid = randint(0, dut.num_rows-1) - data = randint(0, 255) + (muxid<<8) + data = randint(0, 255) + (muxid << 8) def send(self): for i in range(self.tlen * dut.num_rows): @@ -167,7 +166,7 @@ class OutputTest: yield o_p_ready = yield rs.o_ready - print ("send", muxid, i, hex(op2)) + print("send", muxid, i, hex(op2)) yield rs.i_valid.eq(0) # wait random period of time before queueing another value @@ -187,13 +186,13 @@ class TestMuxOutPipe(CombMuxOutPipe): class TestInOutPipe(Elaboratable): def __init__(self, num_rows=4): self.num_rows = num_rows - self.inpipe = TestPriorityMuxPipe(num_rows) # fan-in (combinatorial) + self.inpipe = TestPriorityMuxPipe(num_rows) # fan-in (combinatorial) self.pipe1 = PassThroughPipe() # stage 1 (clock-sync) self.pipe2 = PassThroughPipe() # stage 2 (clock-sync) self.outpipe = TestMuxOutPipe(num_rows) # fan-out (combinatorial) self.p = self.inpipe.p # kinda annoying, - self.n = self.outpipe.n # use pipe in/out as this class in/out + self.n = self.outpipe.n # use pipe in/out as this class in/out self._ports = self.inpipe.ports() + self.outpipe.ports() def elaborate(self, platform): @@ -225,8 +224,9 @@ def test1(): test.rcv(3), test.rcv(2), test.send(0), test.send(1), test.send(3), test.send(2), - ], + ], vcd_name="test_inoutmux_pipe.vcd") + if __name__ == '__main__': test1() diff --git a/src/nmutil/test/test_inout_unary_mux_cancel_pipe.py b/src/nmutil/test/test_inout_unary_mux_cancel_pipe.py index e843d59..fd0570c 100644 --- a/src/nmutil/test/test_inout_unary_mux_cancel_pipe.py +++ b/src/nmutil/test/test_inout_unary_mux_cancel_pipe.py @@ -33,16 +33,15 @@ class PassData(Object): self.data = Signal(16, reset_less=True) - class PassThroughStage: def ispec(self): return PassData() + def ospec(self): - return self.ispec() # same as ospec + return self.ispec() # same as ospec def process(self, i): - return i # pass-through - + return i # pass-through class PassThroughPipe(MaskCancellable): @@ -62,7 +61,7 @@ class InputTest: self.do[muxid] = {} self.sent[muxid] = [] for i in range(self.tlen): - self.di[muxid][i] = randint(0, 255) + (muxid<<8) + self.di[muxid][i] = randint(0, 255) + (muxid << 8) self.do[muxid][i] = self.di[muxid][i] def send(self, muxid): @@ -80,7 +79,7 @@ class InputTest: yield o_p_ready = yield rs.o_ready - print ("send", muxid, i, hex(op2), op2) + print("send", muxid, i, hex(op2), op2) self.sent[muxid].append(i) yield rs.i_valid.eq(0) @@ -96,16 +95,16 @@ class InputTest: yield rs.i_valid.eq(0) yield - print ("send ended", muxid) + print("send ended", muxid) - ## wait random period of time before queueing another value - #for i in range(randint(0, 3)): + # wait random period of time before queueing another value + # for i in range(randint(0, 3)): # yield #send_range = randint(0, 3) - #if send_range == 0: + # if send_range == 0: # send = True - #else: + # else: # send = randint(0, send_range) != 0 def rcv(self, muxid): @@ -115,16 +114,16 @@ class InputTest: # check cancellation if self.sent[muxid] and randint(0, 2) == 0: todel = self.sent[muxid].pop() - print ("to delete", muxid, self.sent[muxid], todel) + print("to delete", muxid, self.sent[muxid], todel) if todel in self.do[muxid]: del self.do[muxid][todel] yield rs.stop_i.eq(1) - print ("left", muxid, self.do[muxid]) + print("left", muxid, self.do[muxid]) if len(self.do[muxid]) == 0: break stall_range = randint(0, 3) - for j in range(randint(1,10)): + for j in range(randint(1, 10)): stall = randint(0, stall_range) != 0 yield self.dut.n[0].i_ready.eq(stall) yield @@ -132,7 +131,7 @@ class InputTest: n = self.dut.n[muxid] yield n.i_ready.eq(1) yield - yield rs.stop_i.eq(0) # resets cancel mask + yield rs.stop_i.eq(0) # resets cancel mask o_n_valid = yield n.o_valid i_n_ready = yield n.i_ready if not o_n_valid or not i_n_ready: @@ -142,17 +141,17 @@ class InputTest: out_i = yield n.o_data.idx out_v = yield n.o_data.data - print ("recv", out_muxid, out_i, hex(out_v), out_v) + print("recv", out_muxid, out_i, hex(out_v), out_v) # see if this output has occurred already, delete it if it has assert muxid == out_muxid, \ - "out_muxid %d not correct %d" % (out_muxid, muxid) + "out_muxid %d not correct %d" % (out_muxid, muxid) if out_i not in self.sent[muxid]: - print ("cancelled/recv", muxid, out_i) + print("cancelled/recv", muxid, out_i) continue assert out_i in self.do[muxid], "out_i %d not in array %s" % \ - (out_i, repr(self.do[muxid])) - assert self.do[muxid][out_i] == out_v # pass-through data + (out_i, repr(self.do[muxid])) + assert self.do[muxid][out_i] == out_v # pass-through data del self.do[muxid][out_i] todel = self.sent[muxid].index(out_i) del self.sent[muxid][todel] @@ -161,7 +160,7 @@ class InputTest: if len(self.do[muxid]) == 0: break - print ("recv ended", muxid) + print("recv ended", muxid) class TestPriorityMuxPipe(PriorityCombMuxInPipe): @@ -183,7 +182,7 @@ class TestMuxOutPipe(CombMuxOutPipe): class TestInOutPipe(Elaboratable): def __init__(self, num_rows=4): self.num_rows = nr = num_rows - self.inpipe = TestPriorityMuxPipe(nr) # fan-in (combinatorial) + self.inpipe = TestPriorityMuxPipe(nr) # fan-in (combinatorial) self.pipe1 = PassThroughPipe(nr) # stage 1 (clock-sync) self.pipe2 = PassThroughPipe(nr) # stage 2 (clock-sync) self.pipe3 = PassThroughPipe(nr) # stage 3 (clock-sync) @@ -191,7 +190,7 @@ class TestInOutPipe(Elaboratable): self.outpipe = TestMuxOutPipe(nr) # fan-out (combinatorial) self.p = self.inpipe.p # kinda annoying, - self.n = self.outpipe.n # use pipe in/out as this class in/out + self.n = self.outpipe.n # use pipe in/out as this class in/out self._ports = self.inpipe.ports() + self.outpipe.ports() def elaborate(self, platform): @@ -228,8 +227,9 @@ def test1(): test.rcv(3), test.rcv(2), test.send(0), test.send(1), test.send(3), test.send(2), - ], + ], vcd_name="test_inoutmux_unarycancel_pipe.vcd") + if __name__ == '__main__': test1() diff --git a/src/nmutil/test/test_outmux_pipe.py b/src/nmutil/test/test_outmux_pipe.py index d94b639..4624a51 100644 --- a/src/nmutil/test/test_outmux_pipe.py +++ b/src/nmutil/test/test_outmux_pipe.py @@ -22,7 +22,7 @@ class PassThroughStage: def ospec(self, name): return Signal(16, name="%s_dout" % name, reset_less=True) - + def process(self, i): return i.data @@ -30,12 +30,12 @@ class PassThroughStage: class PassThroughDataStage: def ispec(self): return PassInData() + def ospec(self): - return self.ispec() # same as ospec + return self.ispec() # same as ospec def process(self, i): - return i # pass-through - + return i # pass-through class PassThroughPipe(PassThroughHandshake): @@ -54,7 +54,7 @@ class OutputTest: muxid = i else: muxid = randint(0, dut.num_rows-1) - data = randint(0, 255) + (muxid<<8) + data = randint(0, 255) + (muxid << 8) if muxid not in self.do: self.do[muxid] = [] self.di.append((data, muxid)) @@ -74,7 +74,7 @@ class OutputTest: yield o_p_ready = yield rs.o_ready - print ("send", muxid, i, hex(op2)) + print("send", muxid, i, hex(op2)) yield rs.i_valid.eq(0) # wait random period of time before queueing another value @@ -100,9 +100,9 @@ class OutputTest: out_v = yield n.o_data - print ("recv", muxid, out_i, hex(out_v)) + print("recv", muxid, out_i, hex(out_v)) - assert self.do[muxid][out_i] == out_v # pass-through data + assert self.do[muxid][out_i] == out_v # pass-through data out_i += 1 @@ -140,11 +140,11 @@ class TestSyncToPriorityPipe(Elaboratable): def ports(self): res = [self.p.i_valid, self.p.o_ready] + \ - self.p.i_data.ports() + self.p.i_data.ports() for i in range(len(self.n)): res += [self.n[i].i_ready, self.n[i].o_valid] + \ - [self.n[i].o_data] - #self.n[i].o_data.ports() + [self.n[i].o_data] + # self.n[i].o_data.ports() return res @@ -160,5 +160,6 @@ def test1(): test.send()], vcd_name="test_outmux_pipe.vcd") + if __name__ == '__main__': test1() diff --git a/src/nmutil/test/test_reservation_stations.py b/src/nmutil/test/test_reservation_stations.py index 62d2698..70c8495 100644 --- a/src/nmutil/test/test_reservation_stations.py +++ b/src/nmutil/test/test_reservation_stations.py @@ -33,16 +33,15 @@ class PassData(Object): self.data = Signal(16, name="data"+name, reset_less=True) - class PassThroughStage: def ispec(self, name=None): return PassData(name=name) + def ospec(self, name=None): - return self.ispec(name) # same as ospec + return self.ispec(name) # same as ospec def process(self, i): - return i # pass-through - + return i # pass-through class PassThroughPipe(SimpleHandshake): @@ -60,7 +59,7 @@ class InputTest: self.di[muxid] = {} self.do[muxid] = {} for i in range(self.tlen): - self.di[muxid][i] = randint(0, 255) + (muxid<<8) + self.di[muxid][i] = randint(0, 255) + (muxid << 8) self.do[muxid][i] = self.di[muxid][i] def send(self, muxid): @@ -77,7 +76,7 @@ class InputTest: yield o_p_ready = yield rs.o_ready - print ("send", muxid, i, hex(op2)) + print("send", muxid, i, hex(op2)) yield rs.i_valid.eq(0) # wait random period of time before queueing another value @@ -87,22 +86,22 @@ class InputTest: yield rs.i_valid.eq(0) yield - print ("send ended", muxid) + print("send ended", muxid) - ## wait random period of time before queueing another value - #for i in range(randint(0, 3)): + # wait random period of time before queueing another value + # for i in range(randint(0, 3)): # yield #send_range = randint(0, 3) - #if send_range == 0: + # if send_range == 0: # send = True - #else: + # else: # send = randint(0, send_range) != 0 def rcv(self, muxid): while True: #stall_range = randint(0, 3) - #for j in range(randint(1,10)): + # for j in range(randint(1,10)): # stall = randint(0, stall_range) != 0 # yield self.dut.n[0].i_ready.eq(stall) # yield @@ -118,20 +117,20 @@ class InputTest: out_i = yield n.o_data.idx out_v = yield n.o_data.data - print ("recv", out_muxid, out_i, hex(out_v)) + print("recv", out_muxid, out_i, hex(out_v)) # see if this output has occurred already, delete it if it has assert muxid == out_muxid, \ - "out_muxid %d not correct %d" % (out_muxid, muxid) + "out_muxid %d not correct %d" % (out_muxid, muxid) assert out_i in self.do[muxid], "out_i %d not in array %s" % \ - (out_i, repr(self.do[muxid])) - assert self.do[muxid][out_i] == out_v # pass-through data + (out_i, repr(self.do[muxid])) + assert self.do[muxid][out_i] == out_v # pass-through data del self.do[muxid][out_i] # check if there's any more outputs if len(self.do[muxid]) == 0: break - print ("recv ended", muxid) + print("recv ended", muxid) class TestALU(Elaboratable): @@ -172,8 +171,9 @@ def test1(): test.rcv(3), test.rcv(2), test.send(0), test.send(1), test.send(3), test.send(2), - ], + ], vcd_name="test_reservation_stations.vcd") + if __name__ == '__main__': test1() diff --git a/src/nmutil/util.py b/src/nmutil/util.py index 43fe1af..68180d4 100644 --- a/src/nmutil/util.py +++ b/src/nmutil/util.py @@ -34,18 +34,20 @@ def treereduce(tree, op, fn=None): treereduce(tree, operator.or_, lambda x: getattr(x, "o_data")) """ if fn is None: - fn = lambda x: x + def fn(x): return x if not isinstance(tree, list): return tree if len(tree) == 1: return fn(tree[0]) if len(tree) == 2: return op(fn(tree[0]), fn(tree[1])) - s = len(tree) // 2 # splitpoint + s = len(tree) // 2 # splitpoint return op(treereduce(tree[:s], op, fn), treereduce(tree[s:], op, fn)) # chooses assignment of 32 bit or full 64 bit depending on is_32bit + + def eq32(is_32bit, dest, src): return [dest[0:32].eq(src[0:32]), dest[32:64].eq(Mux(is_32bit, 0, src[32:64]))] @@ -71,8 +73,8 @@ def rising_edge(m, sig): rising = Signal.like(sig) delay.name = "%s_dly" % sig.name rising.name = "%s_rise" % sig.name - m.d.sync += delay.eq(sig) # 1 clock delay - m.d.comb += rising.eq(sig & ~delay) # sig is hi but delay-sig is lo + m.d.sync += delay.eq(sig) # 1 clock delay + m.d.comb += rising.eq(sig & ~delay) # sig is hi but delay-sig is lo return rising -- 2.30.2