73b264207fb1989d2440c88b4e4199a7d9760ef3
[ieee754fpu.git] / src / add / example_buf_pipe.py
1 """ nmigen implementation of buffered pipeline stage, based on zipcpu:
2 https://zipcpu.com/blog/2017/08/14/strategies-for-pipelining.html
3 """
4 from nmigen import Signal, Cat, Const, Mux, Module
5 from nmigen.compat.sim import run_simulation
6 from nmigen.cli import verilog, rtlil
7
8 class BufPipe:
9 """ buffered pipeline stage
10
11 stage-1 i_p_stb >>in stage o_n_stb out>> stage+1
12 stage-1 o_p_busy <<out stage i_n_busy <<in stage+1
13 stage-1 i_data >>in stage o_data out>> stage+1
14 | |
15 +-------> process
16 | |
17 +-- r_data ---+
18 """
19 def __init__(self):
20 # input
21 #self.i_p_rst = Signal() # >>in - comes in from PREVIOUS stage
22 self.i_p_stb = Signal() # >>in - comes in from PREVIOUS stage
23 self.i_n_busy = Signal() # in<< - comes in from the NEXT stage
24 self.i_data = Signal(32) # >>in - comes in from the PREVIOUS stage
25 #self.i_rst = Signal()
26
27 # buffered
28 self.r_data = Signal(32)
29
30 # output
31 self.o_n_stb = Signal() # out>> - goes out to the NEXT stage
32 self.o_p_busy = Signal() # <<out - goes out to the PREVIOUS stage
33 self.o_data = Signal(32) # out>> - goes out to the NEXT stage
34
35 def pre_process(self, d_in):
36 return d_in | 0xf0000
37
38 def process(self, d_in):
39 return d_in + 1
40
41 def elaborate(self, platform):
42 m = Module()
43
44 o_p_busyn = Signal(reset_less=True)
45 i_p_stb_o_p_busyn = Signal(reset_less=True)
46 m.d.comb += o_p_busyn.eq(~self.o_p_busy)
47 m.d.comb += i_p_stb_o_p_busyn.eq(self.i_p_stb & o_p_busyn)
48
49 result = Signal(32)
50 m.d.comb += result.eq(self.process(self.i_data))
51 with m.If(o_p_busyn): # not stalled
52 m.d.sync += self.r_data.eq(result)
53
54 #with m.If(self.i_p_rst): # reset
55 # m.d.sync += self.o_n_stb.eq(0)
56 # m.d.sync += self.o_p_busy.eq(0)
57 with m.If(~self.i_n_busy): # previous stage is not busy
58 with m.If(o_p_busyn): # not stalled
59 # nothing in buffer: send input direct to output
60 m.d.sync += self.o_n_stb.eq(self.i_p_stb)
61 m.d.sync += self.o_data.eq(result)
62 with m.Else(): # o_p_busy is true, and something is in our buffer.
63 # Flush the buffer to the output port.
64 m.d.sync += self.o_n_stb.eq(1)
65 m.d.sync += self.o_data.eq(self.r_data)
66 # ignore input, since o_p_busy is also true.
67 # also clear stall condition, declare register to be empty.
68 m.d.sync += self.o_p_busy.eq(0)
69
70 # (i_n_busy) is true here: previous stage is busy
71 with m.Elif(~self.o_n_stb): # next stage being told "not busy"
72 m.d.sync += self.o_n_stb.eq(self.i_p_stb)
73 m.d.sync += self.o_p_busy.eq(0) # Keep the buffer empty
74 # Apply the logic to the input data, and set the output data
75 m.d.sync += self.o_data.eq(result)
76
77 # (i_n_busy) and (o_n_stb) both true:
78 with m.Elif(i_p_stb_o_p_busyn):
79 # If next stage *is* busy, and not stalled yet, accept requested
80 # input and store in temporary
81 m.d.sync += self.o_p_busy.eq(self.i_p_stb & self.o_n_stb)
82 #with m.If(~self.o_n_stb):
83 #m.d.sync += self.r_data.eq(self.i_data)
84
85 with m.If(o_p_busyn): # not stalled
86 m.d.sync += self.r_data.eq(self.process(self.i_data))
87
88 return m
89
90 def ports(self):
91 return [self.i_p_stb, self.i_n_busy, self.i_data,
92 self.r_data,
93 self.o_n_stb, self.o_p_busy, self.o_data
94 ]
95
96
97 def testbench(dut):
98 #yield dut.i_p_rst.eq(1)
99 yield dut.i_n_busy.eq(1)
100 yield dut.o_p_busy.eq(1)
101 yield
102 yield
103 #yield dut.i_p_rst.eq(0)
104 yield dut.i_n_busy.eq(0)
105 yield dut.i_data.eq(5)
106 yield dut.i_p_stb.eq(1)
107 yield
108 yield dut.i_data.eq(7)
109 yield
110 yield dut.i_data.eq(2)
111 yield
112 yield dut.i_n_busy.eq(1)
113 yield dut.i_data.eq(9)
114 yield
115 yield dut.i_p_stb.eq(0)
116 yield dut.i_data.eq(12)
117 yield
118 yield dut.i_data.eq(32)
119 yield dut.i_n_busy.eq(0)
120 yield
121 yield
122 yield
123 yield
124
125
126 if __name__ == '__main__':
127 dut = BufPipe()
128 vl = rtlil.convert(dut, ports=dut.ports())
129 with open("test_bufpipe.il", "w") as f:
130 f.write(vl)
131 run_simulation(dut, testbench(dut), vcd_name="test_bufpipe.vcd")
132