got Pi2LSUI FSM working
[soc.git] / src / soc / experiment / pi2ls.py
1 """PortInterface to LoadStoreUnitInterface adapter
2
3 PortInterface LoadStoreUnitInterface
4 ------------- ----------------------
5
6 is_ld_i/1 x_ld_i
7 is_st_i/1 x_st_i
8
9 data_len/4 x_mask/16 (translate using LenExpand)
10
11 busy_o/1 most likely to be x_busy_o
12 go_die_i/1 rst?
13 addr.data/48 x_addr_i (x_addr_i[:4] goes into LenExpand)
14 addr.ok/1 probably x_valid_i & ~x_stall_i
15
16 addr_ok_o/1 no equivalent. *might* work using x_stall_i
17 addr_exc_o/2(?) m_load_err_o and m_store_err_o
18
19 ld.data/64 m_ld_data_o
20 ld.ok/1 probably implicit, when x_busy drops low
21 st.data/64 x_st_data_i
22 st.ok/1 probably kinda redundant, set to x_st_i
23 """
24
25 from soc.minerva.units.loadstore import LoadStoreUnitInterface
26 from soc.experiment.pimem import PortInterface
27 from soc.scoreboard.addr_match import LenExpand
28 from soc.experiment.pimem import PortInterfaceBase
29 from nmigen.utils import log2_int
30
31 from nmigen import Elaboratable, Module, Signal
32 from nmutil.latch import SRLatch
33
34
35 class Pi2LSUI(PortInterfaceBase):
36
37 def __init__(self, name, lsui=None,
38 data_wid=64, mask_wid=8, addr_wid=48):
39 print ("pi2lsui reg mask addr", data_wid, mask_wid, addr_wid)
40 super().__init__(data_wid, addr_wid)
41 if lsui is None:
42 lsui = LoadStoreUnitInterface(addr_wid, self.addrbits, data_wid)
43 self.lsui = lsui
44 self.valid_l = SRLatch(False, name="valid")
45
46 def set_wr_addr(self, m, addr, mask):
47 m.d.comb += self.valid_l.s.eq(1)
48 m.d.comb += self.lsui.x_mask_i.eq(mask)
49 m.d.comb += self.lsui.x_addr_i.eq(addr)
50
51 def set_rd_addr(self, m, addr, mask):
52 m.d.comb += self.valid_l.s.eq(1)
53 m.d.comb += self.lsui.x_mask_i.eq(mask)
54 m.d.comb += self.lsui.x_addr_i.eq(addr)
55
56 def set_wr_data(self, m, data, wen): # mask already done in addr setup
57 m.d.comb += self.lsui.x_st_data_i.eq(data)
58 return ~self.lsui.x_busy_o
59
60 def get_rd_data(self, m):
61 return self.lsui.m_ld_data_o, ~self.lsui.x_busy_o
62
63 def elaborate(self, platform):
64 m = super().elaborate(platform)
65 pi, lsui, addrbits = self.pi, self.lsui, self.addrbits
66
67 m.submodules.valid_l = self.valid_l
68 ld_in_progress = Signal()
69
70 # pass ld/st through to LSUI
71 m.d.comb += lsui.x_ld_i.eq(pi.is_ld_i)
72 m.d.comb += lsui.x_st_i.eq(pi.is_st_i)
73
74 # indicate valid at both ends
75 m.d.comb += self.lsui.m_valid_i.eq(self.valid_l.q)
76 m.d.comb += self.lsui.x_valid_i.eq(self.valid_l.q)
77
78 # reset the valid latch when not busy
79 m.d.comb += self.valid_l.r.eq(~pi.busy_o)#self.lsui.x_busy_o)
80
81 return m
82
83
84 class Pi2LSUI1(Elaboratable):
85
86 def __init__(self, name, pi=None, lsui=None,
87 data_wid=64, mask_wid=8, addr_wid=48):
88 print ("pi2lsui reg mask addr", data_wid, mask_wid, addr_wid)
89 self.addrbits = mask_wid
90 if pi is None:
91 piname = "%s_pi" % name
92 pi = PortInterface(piname, regwid=data_wid, addrwid=addr_wid)
93 self.pi = pi
94 if lsui is None:
95 lsui = LoadStoreUnitInterface(addr_wid, self.addrbits, data_wid)
96 self.lsui = lsui
97
98 def splitaddr(self, addr):
99 """split the address into top and bottom bits of the memory granularity
100 """
101 return addr[:self.addrbits], addr[self.addrbits:]
102
103 def connect_port(self, inport):
104 return self.pi.connect_port(inport)
105
106 def elaborate(self, platform):
107 m = Module()
108 pi, lsui, addrbits = self.pi, self.lsui, self.addrbits
109 m.submodules.lenexp = lenexp = LenExpand(log2_int(self.addrbits), 8)
110
111 ld_in_progress = Signal(reset=0)
112 st_in_progress = Signal(reset=0)
113
114 m.d.comb += lsui.x_ld_i.eq(pi.is_ld_i)
115 m.d.comb += lsui.x_st_i.eq(pi.is_st_i)
116 m.d.comb += pi.busy_o.eq(pi.is_ld_i | pi.is_st_i)#lsui.x_busy_o)
117
118 lsbaddr, msbaddr = self.splitaddr(pi.addr.data)
119 m.d.comb += lenexp.len_i.eq(pi.data_len)
120 m.d.comb += lenexp.addr_i.eq(lsbaddr) # LSBs of addr
121 m.d.comb += lsui.x_addr_i.eq(pi.addr.data) # XXX hmmm...
122
123 with m.If(pi.addr.ok):
124 # expand the LSBs of address plus LD/ST len into 16-bit mask
125 m.d.comb += lsui.x_mask_i.eq(lenexp.lexp_o)
126 # pass through the address, indicate "valid"
127 m.d.comb += lsui.x_valid_i.eq(1)
128 # indicate "OK" - XXX should be checking address valid
129 m.d.comb += pi.addr_ok_o.eq(1)
130
131 with m.If(~lsui.x_busy_o & pi.is_st_i & pi.addr.ok):
132 m.d.sync += st_in_progress.eq(1)
133
134 with m.If(pi.is_ld_i):
135 # shift/mask out the loaded data
136 m.d.comb += pi.ld.data.eq((lsui.m_ld_data_o & lenexp.rexp_o) >>
137 (lenexp.addr_i*8))
138 # remember we're in the process of loading
139 with m.If(pi.addr.ok):
140 m.d.sync += ld_in_progress.eq(1)
141
142 # If a load happened on the previous cycle and the memory is
143 # not busy, that means it returned the data from the load. In
144 # that case ld.ok should be set andwe can clear the
145 # ld_in_progress flag
146 with m.If(ld_in_progress & ~lsui.x_busy_o):
147 m.d.comb += pi.ld.ok.eq(1)
148 m.d.sync += ld_in_progress.eq(0)
149 with m.Else():
150 m.d.comb += pi.ld.ok.eq(0)
151
152 with m.If(pi.is_st_i & pi.st.ok):
153 m.d.comb += lsui.x_st_data_i.eq(pi.st.data << (lenexp.addr_i*8))
154 with m.If(st_in_progress):
155 m.d.sync += st_in_progress.eq(0)
156 with m.Else():
157 m.d.comb += pi.busy_o.eq(0)
158
159 return m