fix test_random in test_loadstore1
[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 def wait_addr(port,debug=None):
23 cnt = 0
24 while True:
25 addr_ok = yield port.addr_ok_o
26 print("addrok", addr_ok,cnt,debug)
27 if addr_ok:
28 break
29 yield
30 cnt += 1
31
32
33 def wait_ldok(port):
34 cnt = 0
35 while True:
36 ldok = yield port.ld.ok
37 exc_happened = yield port.exc_o.happened
38 print("ldok", ldok, "exception", exc_happened, "count", cnt)
39 cnt += 1
40 if ldok or exc_happened:
41 break
42 yield
43
44
45 def pi_st(port1, addr, data, datalen, msr_pr=0, is_dcbz=0):
46
47 # have to wait until not busy
48 yield from wait_busy(port1,debug="pi_st_A") # wait while busy
49
50 # set up a ST on the port. address first:
51 yield port1.is_dcbz_i.eq(is_dcbz) # reset dcbz too
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 from wait_addr(port1) # wait until addr ok
61
62 # yield # not needed, just for checking
63 # yield # not needed, just for checking
64 # assert "ST" for one cycle (required by the API)
65 yield port1.st.data.eq(data)
66 yield port1.st.ok.eq(1)
67 yield
68 yield port1.st.ok.eq(0)
69 exc_happened = yield port1.exc_o.happened
70 if exc_happened:
71 print("print fast exception happened")
72 yield port1.is_st_i.eq(0) # end
73 yield port1.addr.ok.eq(0) # set !ok
74 yield port1.is_dcbz_i.eq(0) # reset dcbz too
75 return "fast"
76 yield from wait_busy(port1,debug="pi_st_E") # wait while busy
77
78 # can go straight to reset.
79 yield port1.is_st_i.eq(0) # end
80 yield port1.addr.ok.eq(0) # set !ok
81 yield port1.is_dcbz_i.eq(0) # reset dcbz too
82 yield # needed if mmu/dache is used
83
84 return None
85
86
87 # copy of pi_st removed
88
89 def pi_ld(port1, addr, datalen, msr_pr=0):
90
91 # have to wait until not busy
92 yield from wait_busy(port1,debug="pi_ld_A") # wait while busy
93
94 # set up a LD on the port. address first:
95 yield port1.is_ld_i.eq(1) # indicate LD
96 yield port1.data_len.eq(datalen) # LD length (1/2/4/8)
97 yield port1.msr_pr.eq(msr_pr) # MSR PR bit (1==>virt, 0==>real)
98
99 yield port1.addr.data.eq(addr) # set address
100 yield port1.addr.ok.eq(1) # set ok
101 yield Settle()
102 yield from wait_addr(port1) # wait until addr ok
103 exc_happened = yield port1.exc_o.happened
104 if exc_happened:
105 print("print fast exception happened")
106 yield port1.is_ld_i.eq(0) # end
107 yield port1.addr.ok.eq(0) # set !ok
108 return None, "fast"
109
110 yield
111 yield from wait_ldok(port1) # wait until ld ok
112 data = yield port1.ld.data
113 exc_happened = yield port1.exc_o.happened
114
115 # cleanup
116 yield port1.is_ld_i.eq(0) # end
117 yield port1.addr.ok.eq(0) # set !ok
118 if exc_happened:
119 return None, "slow"
120
121 yield from wait_busy(port1,debug="pi_ld_E") # wait while busy
122
123 exc_happened = yield port1.exc_o.happened
124 if exc_happened:
125 return None, "slow"
126
127 return data, None
128
129
130 def pi_ldst(arg, dut, msr_pr=0):
131
132 # do two half-word stores at consecutive addresses, then two loads
133 addr1 = 0x04
134 addr2 = addr1 + 0x2
135 data = 0xbeef
136 data2 = 0xf00f
137 #data = 0x4
138 assert(yield from pi_st(dut, addr1, data, 2, msr_pr) is None)
139 assert(yield from pi_st(dut, addr2, data2, 2, msr_pr) is None)
140 result, exc = yield from pi_ld(dut, addr1, 2, msr_pr)
141 result2, exc2 = yield from pi_ld(dut, addr2, 2, msr_pr)
142 assert(exc is None)
143 assert(exc2 is None)
144 arg.assertEqual(data, result, "data %x != %x" % (result, data))
145 arg.assertEqual(data2, result2, "data2 %x != %x" % (result2, data2))
146
147 # now load both in a 32-bit load to make sure they're really consecutive
148 data3 = data | (data2 << 16)
149 result3, exc3 = yield from pi_ld(dut, addr1, 4, msr_pr)
150 assert(exc3 is None)
151 arg.assertEqual(data3, result3, "data3 %x != %x" % (result3, data3))
152
153
154 def tst_config_pi(testcls, ifacetype):
155 """set up a configureable memory test of type ifacetype
156 """
157 dut = Module()
158 pspec = TestMemPspec(ldst_ifacetype=ifacetype,
159 imem_ifacetype='',
160 addr_wid=48,
161 mask_wid=8,
162 reg_wid=64)
163 cmpi = ConfigMemoryPortInterface(pspec)
164 dut.submodules.pi = cmpi.pi
165 if hasattr(cmpi, 'lsmem'): # hmmm not happy about this
166 dut.submodules.lsmem = cmpi.lsmem.lsi
167 vl = rtlil.convert(dut, ports=[]) # dut.ports())
168 with open("test_pi_%s.il" % ifacetype, "w") as f:
169 f.write(vl)
170
171 run_simulation(dut, {"sync": pi_ldst(testcls, cmpi.pi.pi)},
172 vcd_name='test_pi_%s.vcd' % ifacetype)
173
174
175 class TestPIMem(unittest.TestCase):
176
177 def test_pi_mem(self):
178 tst_config_pi(self, 'testpi')
179
180 def test_pi2ls(self):
181 tst_config_pi(self, 'testmem')
182
183 def test_pi2ls_bare_wb(self):
184 tst_config_pi(self, 'test_bare_wb')
185
186
187 if __name__ == '__main__':
188 unittest.main()