use get_l0_mem in HDLState to get memory data
[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
10
11 def wait_busy(port, no=False,debug=None):
12 cnt = 0
13 while True:
14 busy = yield port.busy_o
15 print("busy", no, busy, cnt, debug)
16 if bool(busy) == no:
17 break
18 yield
19 cnt += 1
20
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):
47
48 # have to wait until not busy
49 yield from wait_busy(port1, no=False) # wait until not busy
50
51 # set up a ST on the port. address first:
52 yield port1.is_st_i.eq(1) # indicate ST
53 yield port1.data_len.eq(datalen) # ST length (1/2/4/8)
54 yield port1.msr_pr.eq(msr_pr) # MSR PR bit (1==>virt, 0==>real)
55
56 yield port1.addr.data.eq(addr) # set address
57 yield port1.addr.ok.eq(1) # set ok
58 yield Settle()
59 yield from wait_addr(port1) # wait until addr ok
60 # yield # not needed, just for checking
61 # yield # not needed, just for checking
62 # assert "ST" for one cycle (required by the API)
63 yield port1.st.data.eq(data)
64 yield port1.st.ok.eq(1)
65 yield
66 yield port1.st.ok.eq(0)
67 yield from wait_busy(port1, True) # wait while busy
68
69 # can go straight to reset.
70 yield port1.is_st_i.eq(0) # end
71 yield port1.addr.ok.eq(0) # set !ok
72 yield port1.is_dcbz.eq(0) # reset dcbz too
73
74
75 # copy of pi_st
76 def pi_dcbz(port1, addr, msr_pr=0):
77
78 # have to wait until not busy
79 yield from wait_busy(port1, no=False,debug="busy") # wait until not busy
80
81 # set up a ST on the port. address first:
82 yield port1.is_st_i.eq(1) # indicate ST
83 yield port1.msr_pr.eq(msr_pr) # MSR PR bit (1==>virt, 0==>real)
84
85 yield port1.is_dcbz.eq(1) # set dcbz
86
87 yield port1.addr.data.eq(addr) # set address
88 yield port1.addr.ok.eq(1) # set ok
89 yield Settle()
90
91 # guess: this is not needed
92 # yield from wait_addr(port1,debug="addr") # wait until addr ok
93
94 # just write some dummy data -- remove
95 print("dummy write begin")
96 yield port1.st.data.eq(0)
97 yield port1.st.ok.eq(1)
98 yield
99 yield port1.st.ok.eq(0)
100 print("dummy write end")
101
102 yield from wait_busy(port1, no=True, debug="not_busy") # wait while busy
103
104 # can go straight to reset.
105 yield port1.is_st_i.eq(0) # end
106 yield port1.addr.ok.eq(0) # set !ok
107 yield port1.is_dcbz.eq(0) # reset dcbz too
108
109
110 def pi_ld(port1, addr, datalen, msr_pr=0):
111
112 # have to wait until not busy
113 yield from wait_busy(port1, no=False) # wait until not busy
114
115 # set up a LD on the port. address first:
116 yield port1.is_ld_i.eq(1) # indicate LD
117 yield port1.data_len.eq(datalen) # LD length (1/2/4/8)
118 yield port1.msr_pr.eq(msr_pr) # MSR PR bit (1==>virt, 0==>real)
119
120 yield port1.addr.data.eq(addr) # set address
121 yield port1.addr.ok.eq(1) # set ok
122 yield Settle()
123 yield from wait_addr(port1) # wait until addr ok
124 yield
125 yield from wait_ldok(port1) # wait until ld ok
126 data = yield port1.ld.data
127 exc_happened = yield port1.exc_o.happened
128
129 # cleanup
130 yield port1.is_ld_i.eq(0) # end
131 yield port1.addr.ok.eq(0) # set !ok
132 if exc_happened:
133 return 0
134
135 yield from wait_busy(port1, no=False) # wait while not busy
136
137 return data
138
139
140 def pi_ldst(arg, dut, msr_pr=0):
141
142 # do two half-word stores at consecutive addresses, then two loads
143 addr1 = 0x04
144 addr2 = addr1 + 0x2
145 data = 0xbeef
146 data2 = 0xf00f
147 #data = 0x4
148 yield from pi_st(dut, addr1, data, 2, msr_pr)
149 yield from pi_st(dut, addr2, data2, 2, msr_pr)
150 result = yield from pi_ld(dut, addr1, 2, msr_pr)
151 result2 = yield from pi_ld(dut, addr2, 2, msr_pr)
152 arg.assertEqual(data, result, "data %x != %x" % (result, data))
153 arg.assertEqual(data2, result2, "data2 %x != %x" % (result2, data2))
154
155 # now load both in a 32-bit load to make sure they're really consecutive
156 data3 = data | (data2 << 16)
157 result3 = yield from pi_ld(dut, addr1, 4, msr_pr)
158 arg.assertEqual(data3, result3, "data3 %x != %x" % (result3, data3))
159
160
161 def tst_config_pi(testcls, ifacetype):
162 """set up a configureable memory test of type ifacetype
163 """
164 dut = Module()
165 pspec = TestMemPspec(ldst_ifacetype=ifacetype,
166 imem_ifacetype='',
167 addr_wid=48,
168 mask_wid=8,
169 reg_wid=64)
170 cmpi = ConfigMemoryPortInterface(pspec)
171 dut.submodules.pi = cmpi.pi
172 if hasattr(cmpi, 'lsmem'): # hmmm not happy about this
173 dut.submodules.lsmem = cmpi.lsmem.lsi
174 vl = rtlil.convert(dut, ports=[]) # dut.ports())
175 with open("test_pi_%s.il" % ifacetype, "w") as f:
176 f.write(vl)
177
178 run_simulation(dut, {"sync": pi_ldst(testcls, cmpi.pi.pi)},
179 vcd_name='test_pi_%s.vcd' % ifacetype)
180
181
182 class TestPIMem(unittest.TestCase):
183
184 def test_pi_mem(self):
185 tst_config_pi(self, 'testpi')
186
187 def test_pi2ls(self):
188 tst_config_pi(self, 'testmem')
189
190 def test_pi2ls_bare_wb(self):
191 tst_config_pi(self, 'test_bare_wb')
192
193
194 if __name__ == '__main__':
195 unittest.main()