X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fadd%2Fmultipipe.py;h=35da5c2ec741aafc66e97804e842be0395b8a863;hb=25a0ec563bd7837b43a1d04036b2a5945c97023b;hp=af52ad9c450439cc45f90319370672338b481f13;hpb=2f774d33eb51b8cf4eb3250c02b8b0a56b56876c;p=ieee754fpu.git diff --git a/src/add/multipipe.py b/src/add/multipipe.py index af52ad9c..35da5c2e 100644 --- a/src/add/multipipe.py +++ b/src/add/multipipe.py @@ -1,4 +1,13 @@ -""" Combinatorial Multi-input multiplexer block conforming to Pipeline API +""" Combinatorial Multi-input and Multi-output multiplexer blocks + conforming to Pipeline API + + Multi-input is complex because if any one input is ready, the output + can be ready, and the decision comes from a separate module. + + Multi-output is simple (pretty much identical to UnbufferedPipeline), + and the selection is just a mux. The only proviso (difference) being: + the outputs not being selected have to have their o_ready signals + DEASSERTED. """ from math import log @@ -62,14 +71,27 @@ class MultiInControlBase: def ports(self): res = [] for i in range(len(self.p)): - res += [self.p[i].i_valid, self.p[i].o_ready, - self.p[i].i_data]# XXX need flattening!] - res += [self.n.i_ready, self.n.o_valid, - self.n.o_data] # XXX need flattening!] + p = self.p[i] + res += [p.i_valid, p.o_ready] + if hasattr(p.i_data, "ports"): + res += p.i_data.ports() + else: + rres = p.i_data + if not isinstance(rres, Sequence): + rres = [rres] + res += rres + n = self.n + res += [n.i_ready, n.o_valid] + if hasattr(n.o_data, "ports"): + res += n.o_data.ports() + else: + rres = n.o_data + if not isinstance(rres, Sequence): + rres = [rres] + res += rres return res - class MultiOutControlBase: """ Common functions for Pipeline API """ @@ -118,29 +140,29 @@ class MultiOutControlBase: return eq(self.p.i_data, i) def ports(self): - res = [] - res += [self.p.i_valid, self.p.o_ready, - self.p.i_data] # XXX need flattening! + res = [self.p.i_valid, self.p.o_ready] + if hasattr(self.p.i_data, "ports"): + res += self.p.i_data.ports() + else: + res += self.p.i_data + for i in range(len(self.n)): - res += [self.n[i].i_ready, self.n[i].o_valid, - self.n[i].o_data] # XXX need flattening! + n = self.n[i] + res += [n.i_ready, n.o_valid] + if hasattr(n.o_data, "ports"): + res += n.o_data.ports() + else: + res += n.o_data return res - class CombMultiOutPipeline(MultiOutControlBase): """ A multi-input Combinatorial block conforming to the Pipeline API Attributes: ----------- - p.i_data : StageInput, shaped according to ispec - The pipeline input - p.o_data : StageOutput, shaped according to ospec - The pipeline output - r_data : input_shape according to ispec - A temporary (buffered) copy of a prior (valid) input. - This is HELD if the output is not ready. It is updated - SYNCHRONOUSLY. + p.i_data : stage input data (non-array). shaped according to ispec + n.o_data : stage output data array. shaped according to ospec """ def __init__(self, stage, n_len, n_mux): @@ -156,43 +178,32 @@ class CombMultiOutPipeline(MultiOutControlBase): def elaborate(self, platform): m = Module() - #m.submodules += self.n_mux + if hasattr(self.n_mux, "elaborate"): # TODO: identify submodule? + m.submodules += self.n_mux # need buffer register conforming to *input* spec r_data = self.stage.ispec() # input type if hasattr(self.stage, "setup"): self.stage.setup(m, r_data) - data_valid = [] - n_i_readyn = [] - n_len = len(self.n) - for i in range(n_len): - data_valid.append(Signal(name="data_valid", reset_less=True)) - n_i_readyn.append(Signal(name="n_i_readyn", reset_less=True)) - n_i_readyn = Array(n_i_readyn) - data_valid = Array(data_valid) + # multiplexer id taken from n_mux + mid = self.n_mux.m_id + # temporaries p_i_valid = Signal(reset_less=True) - m.d.comb += p_i_valid.eq(self.p.i_valid_logic()) - - mid = self.n_mux.m_id + pv = Signal(reset_less=True) + m.d.comb += p_i_valid.eq(self.p.i_valid_test) + m.d.comb += pv.eq(self.p.i_valid & self.p.o_ready) - for i in range(n_len): - m.d.comb += data_valid[i].eq(0) - m.d.comb += n_i_readyn[i].eq(1) + # all outputs to next stages first initialised to zero (invalid) + # the only output "active" is then selected by the muxid + for i in range(len(self.n)): m.d.comb += self.n[i].o_valid.eq(0) - m.d.comb += self.n[mid].o_valid.eq(data_valid[mid]) - m.d.comb += n_i_readyn[mid].eq(~self.n[mid].i_ready & data_valid[mid]) - anyvalid = Signal(i, reset_less=True) - av = [] - for i in range(n_len): - av.append(~data_valid[i] | self.n[i].i_ready) - anyvalid = Cat(*av) - m.d.comb += self.p.o_ready.eq(anyvalid.bool()) - m.d.comb += data_valid[mid].eq(p_i_valid | \ - (n_i_readyn[mid] & data_valid[mid])) - - with m.If(self.p.i_valid & self.p.o_ready): + data_valid = self.n[mid].o_valid + m.d.comb += self.p.o_ready.eq(~data_valid | self.n[mid].i_ready) + m.d.comb += data_valid.eq(p_i_valid | \ + (~self.n[mid].i_ready & data_valid)) + with m.If(pv): m.d.comb += eq(r_data, self.p.i_data) m.d.comb += eq(self.n[mid].o_data, self.stage.process(r_data)) @@ -249,6 +260,8 @@ class CombMultiInPipeline(MultiInControlBase): n_i_readyn = Array(n_i_readyn) data_valid = Array(data_valid) + nirn = Signal(reset_less=True) + m.d.comb += nirn.eq(~self.n.i_ready) mid = self.p_mux.m_id for i in range(p_len): m.d.comb += data_valid[i].eq(0) @@ -257,7 +270,7 @@ class CombMultiInPipeline(MultiInControlBase): m.d.comb += self.p[i].o_ready.eq(0) m.d.comb += p_i_valid[mid].eq(self.p_mux.active) m.d.comb += self.p[mid].o_ready.eq(~data_valid[mid] | self.n.i_ready) - m.d.comb += n_i_readyn[mid].eq(~self.n.i_ready & data_valid[mid]) + m.d.comb += n_i_readyn[mid].eq(nirn & data_valid[mid]) anyvalid = Signal(i, reset_less=True) av = [] for i in range(p_len): @@ -278,7 +291,19 @@ class CombMultiInPipeline(MultiInControlBase): return m +class CombMuxOutPipe(CombMultiOutPipeline): + def __init__(self, stage, n_len): + # HACK: stage is also the n-way multiplexer + CombMultiOutPipeline.__init__(self, stage, n_len=n_len, n_mux=stage) + + # HACK: n-mux is also the stage... so set the muxid equal to input mid + stage.m_id = self.p.i_data.mid + + + class InputPriorityArbiter: + """ arbitration module for Input-Mux pipe, baed on PriorityEncoder + """ def __init__(self, pipe, num_rows): self.pipe = pipe self.num_rows = num_rows @@ -298,7 +323,7 @@ class InputPriorityArbiter: in_ready = [] for i in range(self.num_rows): p_i_valid = Signal(reset_less=True) - m.d.comb += p_i_valid.eq(self.pipe.p[i].i_valid_logic()) + 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 += self.active.eq(~pe.n) # encoder active (one input valid) @@ -311,18 +336,18 @@ class InputPriorityArbiter: -class ExamplePipeline(CombMultiInPipeline): +class PriorityCombMuxInPipe(CombMultiInPipeline): """ an example of how to use the combinatorial pipeline. """ - def __init__(self, p_len=2): + def __init__(self, stage, p_len=2): p_mux = InputPriorityArbiter(self, p_len) - CombMultiInPipeline.__init__(self, ExampleStage, p_len, p_mux) + CombMultiInPipeline.__init__(self, stage, p_len, p_mux) if __name__ == '__main__': - dut = ExamplePipeline() + dut = PriorityCombMuxInPipe(ExampleStage) vl = rtlil.convert(dut, ports=dut.ports()) with open("test_combpipe.il", "w") as f: f.write(vl)