start new version of Pi2LSUI based on PortInterfaceBase
[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
33
34 class Pi2LSUI(PortInterfaceBase):
35
36 def __init__(self, name, lsui=None,
37 data_wid=64, mask_wid=8, addr_wid=48):
38 print ("pi2lsui reg mask addr", data_wid, mask_wid, addr_wid)
39 super().__init__(data_wid, addr_wid)
40 if lsui is None:
41 lsui = LoadStoreUnitInterface(addr_wid, self.addrbits, data_wid)
42 self.lsui = lsui
43
44 def set_wr_addr(self, m, addr, mask):
45 m.d.comb += self.lsui.x_mask_i.eq(mask)
46 m.d.comb += self.lsui.x_addr_i.eq(addr)
47
48 def set_rd_addr(self, m, addr, mask):
49 m.d.comb += self.lsui.x_mask_i.eq(mask)
50 m.d.comb += self.lsui.x_addr_i.eq(addr)
51
52 def set_wr_data(self, m, data, wen): # mask already done in addr setup
53 m.d.comb += self.lsui.x_st_data_i.eq(data)
54 return ~self.lsui.x_busy_o
55
56 def get_rd_data(self, m):
57 return self.lsui.m_ld_data_o, ~self.lsui.x_busy_o
58
59 def elaborate(self, platform):
60 m = super().elaborate(platform)
61
62 return m
63
64
65 class Pi2LSUI1(Elaboratable):
66
67 def __init__(self, name, pi=None, lsui=None,
68 data_wid=64, mask_wid=8, addr_wid=48):
69 print ("pi2lsui reg mask addr", data_wid, mask_wid, addr_wid)
70 self.addrbits = mask_wid
71 if pi is None:
72 piname = "%s_pi" % name
73 pi = PortInterface(piname, regwid=data_wid, addrwid=addr_wid)
74 self.pi = pi
75 if lsui is None:
76 lsui = LoadStoreUnitInterface(addr_wid, self.addrbits, data_wid)
77 self.lsui = lsui
78
79 def splitaddr(self, addr):
80 """split the address into top and bottom bits of the memory granularity
81 """
82 return addr[:self.addrbits], addr[self.addrbits:]
83
84 def connect_port(self, inport):
85 return self.pi.connect_port(inport)
86
87 def elaborate(self, platform):
88 m = Module()
89 pi, lsui, addrbits = self.pi, self.lsui, self.addrbits
90 m.submodules.lenexp = lenexp = LenExpand(log2_int(self.addrbits), 8)
91
92 ld_in_progress = Signal(reset=0)
93 st_in_progress = Signal(reset=0)
94
95 m.d.comb += lsui.x_ld_i.eq(pi.is_ld_i)
96 m.d.comb += lsui.x_st_i.eq(pi.is_st_i)
97 m.d.comb += pi.busy_o.eq(pi.is_ld_i | pi.is_st_i)#lsui.x_busy_o)
98
99 lsbaddr, msbaddr = self.splitaddr(pi.addr.data)
100 m.d.comb += lenexp.len_i.eq(pi.data_len)
101 m.d.comb += lenexp.addr_i.eq(lsbaddr) # LSBs of addr
102 m.d.comb += lsui.x_addr_i.eq(pi.addr.data) # XXX hmmm...
103
104 with m.If(pi.addr.ok):
105 # expand the LSBs of address plus LD/ST len into 16-bit mask
106 m.d.comb += lsui.x_mask_i.eq(lenexp.lexp_o)
107 # pass through the address, indicate "valid"
108 m.d.comb += lsui.x_valid_i.eq(1)
109 # indicate "OK" - XXX should be checking address valid
110 m.d.comb += pi.addr_ok_o.eq(1)
111
112 with m.If(~lsui.x_busy_o & pi.is_st_i & pi.addr.ok):
113 m.d.sync += st_in_progress.eq(1)
114
115 with m.If(pi.is_ld_i):
116 # shift/mask out the loaded data
117 m.d.comb += pi.ld.data.eq((lsui.m_ld_data_o & lenexp.rexp_o) >>
118 (lenexp.addr_i*8))
119 # remember we're in the process of loading
120 with m.If(pi.addr.ok):
121 m.d.sync += ld_in_progress.eq(1)
122
123 # If a load happened on the previous cycle and the memory is
124 # not busy, that means it returned the data from the load. In
125 # that case ld.ok should be set andwe can clear the
126 # ld_in_progress flag
127 with m.If(ld_in_progress & ~lsui.x_busy_o):
128 m.d.comb += pi.ld.ok.eq(1)
129 m.d.sync += ld_in_progress.eq(0)
130 with m.Else():
131 m.d.comb += pi.ld.ok.eq(0)
132
133 with m.If(pi.is_st_i & pi.st.ok):
134 m.d.comb += lsui.x_st_data_i.eq(pi.st.data << (lenexp.addr_i*8))
135 with m.If(st_in_progress):
136 m.d.sync += st_in_progress.eq(0)
137 with m.Else():
138 m.d.comb += pi.busy_o.eq(0)
139
140 return m