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