31b92363c2ca3ce897f376f8bdc6c57383bf29fc
[soc.git] / src / soc / config / test / test_pi2ls.py
1 from nmigen import Signal, Module, Record
2 from nmigen.back.pysim import Simulator, Delay
3 from nmigen.compat.sim import run_simulation, Settle
4 from nmutil.formaltest import FHDLTestCase
5 from nmigen.cli import rtlil
6 import unittest
7 from soc.config.test.test_loadstore import TestMemPspec
8 from soc.config.loadstore import ConfigMemoryPortInterface
9 from openpower.exceptions import LDSTExceptionTuple
10
11
12 def wait_busy(port, no=False, debug=None):
13 cnt = 0
14 while True:
15 busy = yield port.busy_o
16 print("busy", no, busy, cnt, debug)
17 if bool(busy) == no:
18 break
19 yield
20 cnt += 1
21
22
23 def wait_addr(port,debug=None):
24 cnt = 0
25 while True:
26 addr_ok = yield port.addr_ok_o
27 print("addrok", addr_ok,cnt,debug)
28 if addr_ok:
29 break
30 yield
31 cnt += 1
32
33
34 def wait_ldok(port):
35 cnt = 0
36 while True:
37 ldok = yield port.ld.ok
38 exc_happened = yield port.exc_o.happened
39 print("ldok", ldok, "exception", exc_happened, "count", cnt)
40 cnt += 1
41 if ldok or exc_happened:
42 break
43 yield
44
45
46 def pi_st(port1, addr, data, datalen, msr_pr=0, is_dcbz=0):
47
48 # have to wait until not busy
49 yield from wait_busy(port1,debug="pi_st_A") # wait while busy
50
51 # set up a ST on the port. address first:
52 yield port1.is_dcbz_i.eq(is_dcbz) # reset dcbz too
53 yield port1.is_st_i.eq(1) # indicate ST
54 yield port1.data_len.eq(datalen) # ST length (1/2/4/8)
55 yield port1.msr_pr.eq(msr_pr) # MSR PR bit (1==>virt, 0==>real)
56
57 yield port1.addr.data.eq(addr) # set address
58 yield port1.addr.ok.eq(1) # set ok
59 yield Settle()
60
61 # must check exception even before waiting for address.
62 # XXX TODO: wait_addr should check for exception
63 exc_info = yield from get_exception_info(port1.exc_o)
64 exc_happened = exc_info.happened
65 if exc_happened:
66 print("print fast ST exception happened")
67 yield # MUST wait for one clock cycle before de-asserting these
68 yield port1.is_st_i.eq(0) # end
69 yield port1.addr.ok.eq(0) # set !ok
70 yield port1.is_dcbz_i.eq(0) # reset dcbz too
71 return "fast", exc_info
72
73 yield from wait_addr(port1) # wait until addr ok
74
75 exc_info = yield from get_exception_info(port1.exc_o)
76 exc_happened = exc_info.happened
77 if exc_happened:
78 print("print fast ST exception happened")
79 yield # MUST wait for one clock cycle before de-asserting these
80 yield port1.is_st_i.eq(0) # end
81 yield port1.addr.ok.eq(0) # set !ok
82 yield port1.is_dcbz_i.eq(0) # reset dcbz too
83 return "fast", exc_info
84
85
86 # yield # not needed, just for checking
87 # yield # not needed, just for checking
88 # assert "ST" for one cycle (required by the API)
89 yield port1.st.data.eq(data)
90 yield port1.st.ok.eq(1)
91 yield
92 yield port1.st.ok.eq(0)
93 exc_info = yield from get_exception_info(port1.exc_o)
94 exc_happened = exc_info.happened
95 if exc_happened:
96 print("print fast ST exception happened")
97 yield # MUST wait for one clock cycle before de-asserting these
98 yield port1.is_st_i.eq(0) # end
99 yield port1.addr.ok.eq(0) # set !ok
100 yield port1.is_dcbz_i.eq(0) # reset dcbz too
101 return "fast", exc_info
102
103 yield from wait_busy(port1,debug="pi_st_E") # wait while busy
104 exc_info = yield from get_exception_info(port1.exc_o)
105 exc_happened = exc_info.happened
106 if exc_happened:
107 yield # needed if mmu/dache is used
108 yield port1.is_st_i.eq(0) # end
109 yield port1.addr.ok.eq(0) # set !ok
110 yield port1.is_dcbz_i.eq(0) # reset dcbz too
111 yield # needed if mmu/dache is used
112 return "slow", exc_info
113
114 # can go straight to reset.
115 yield port1.is_st_i.eq(0) # end
116 yield port1.addr.ok.eq(0) # set !ok
117 yield port1.is_dcbz_i.eq(0) # reset dcbz too
118 yield # needed if mmu/dache is used
119
120 return None, None
121
122 def get_exception_info(exc_o):
123 attrs = []
124 for fname in LDSTExceptionTuple._fields:
125 attr = getattr(exc_o, fname)
126 val = yield attr
127 attrs.append(val)
128 return LDSTExceptionTuple(*attrs)
129
130
131 # copy of pi_st removed
132
133 def pi_ld(port1, addr, datalen, msr_pr=0):
134
135 # have to wait until not busy
136 yield from wait_busy(port1,debug="pi_ld_A") # wait while busy
137
138 # set up a LD on the port. address first:
139 yield port1.is_ld_i.eq(1) # indicate LD
140 yield port1.data_len.eq(datalen) # LD length (1/2/4/8)
141 yield port1.msr_pr.eq(msr_pr) # MSR PR bit (1==>virt, 0==>real)
142
143 yield port1.addr.data.eq(addr) # set address
144 yield port1.addr.ok.eq(1) # set ok
145 yield Settle()
146 yield from wait_addr(port1) # wait until addr ok
147 exc_info = yield from get_exception_info(port1.exc_o)
148 exc_happened = exc_info.happened
149 if exc_happened:
150 print("print fast LD exception happened")
151 yield # MUST wait for one clock cycle before de-asserting these
152 yield port1.is_ld_i.eq(0) # end
153 yield port1.addr.ok.eq(0) # set !ok
154 return None, "fast", exc_info
155
156 yield
157 yield from wait_ldok(port1) # wait until ld ok
158 data = yield port1.ld.data
159 exc_info = yield from get_exception_info(port1.exc_o)
160 exc_happened = yield port1.exc_o.happened
161 exc_happened = exc_info.happened
162
163 # cleanup
164 yield port1.is_ld_i.eq(0) # end
165 yield port1.addr.ok.eq(0) # set !ok
166 if exc_happened:
167 return None, "slow", exc_info
168
169 yield from wait_busy(port1, debug="pi_ld_E") # wait while busy
170
171 exc_info = yield from get_exception_info(port1.exc_o)
172 exc_happened = exc_info.happened
173 if exc_happened:
174 return None, "slow", exc_info
175
176 return data, None, None
177
178
179 def pi_ldst(arg, dut, msr_pr=0):
180
181 # do two half-word stores at consecutive addresses, then two loads
182 addr1 = 0x04
183 addr2 = addr1 + 0x2
184 data = 0xbeef
185 data2 = 0xf00f
186 #data = 0x4
187 assert(yield from pi_st(dut, addr1, data, 2, msr_pr) is None)
188 assert(yield from pi_st(dut, addr2, data2, 2, msr_pr) is None)
189 result, exc = yield from pi_ld(dut, addr1, 2, msr_pr)
190 result2, exc2 = yield from pi_ld(dut, addr2, 2, msr_pr)
191 assert(exc is None)
192 assert(exc2 is None)
193 arg.assertEqual(data, result, "data %x != %x" % (result, data))
194 arg.assertEqual(data2, result2, "data2 %x != %x" % (result2, data2))
195
196 # now load both in a 32-bit load to make sure they're really consecutive
197 data3 = data | (data2 << 16)
198 result3, exc3 = yield from pi_ld(dut, addr1, 4, msr_pr)
199 assert(exc3 is None)
200 arg.assertEqual(data3, result3, "data3 %x != %x" % (result3, data3))
201
202
203 def tst_config_pi(testcls, ifacetype):
204 """set up a configureable memory test of type ifacetype
205 """
206 dut = Module()
207 pspec = TestMemPspec(ldst_ifacetype=ifacetype,
208 imem_ifacetype='',
209 addr_wid=48,
210 mask_wid=8,
211 reg_wid=64)
212 cmpi = ConfigMemoryPortInterface(pspec)
213 dut.submodules.pi = cmpi.pi
214 if hasattr(cmpi, 'lsmem'): # hmmm not happy about this
215 dut.submodules.lsmem = cmpi.lsmem.lsi
216 vl = rtlil.convert(dut, ports=[]) # dut.ports())
217 with open("test_pi_%s.il" % ifacetype, "w") as f:
218 f.write(vl)
219
220 run_simulation(dut, {"sync": pi_ldst(testcls, cmpi.pi.pi)},
221 vcd_name='test_pi_%s.vcd' % ifacetype)
222
223
224 class TestPIMem(unittest.TestCase):
225
226 def test_pi_mem(self):
227 tst_config_pi(self, 'testpi')
228
229 def test_pi2ls(self):
230 tst_config_pi(self, 'testmem')
231
232 def test_pi2ls_bare_wb(self):
233 tst_config_pi(self, 'test_bare_wb')
234
235
236 if __name__ == '__main__':
237 unittest.main()