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
7 from soc
.config
.test
.test_loadstore
import TestMemPspec
8 from soc
.config
.loadstore
import ConfigMemoryPortInterface
9 from openpower
.exceptions
import LDSTExceptionTuple
12 def wait_busy(port
, no
=False, debug
=None):
15 busy
= yield port
.busy_o
16 print("busy", no
, busy
, cnt
, debug
)
23 def wait_addr(port
,debug
=None):
26 addr_ok
= yield port
.addr_ok_o
27 exc_happened
= yield port
.exc_o
.happened
28 print("addrok", addr_ok
,cnt
,debug
,exc_happened
)
29 if addr_ok
or exc_happened
:
38 ldok
= yield port
.ld
.ok
39 exc_happened
= yield port
.exc_o
.happened
40 print("ldok", ldok
, "exception", exc_happened
, "count", cnt
)
42 if ldok
or exc_happened
:
47 def pi_st(port1
, addr
, data
, datalen
, msr
, is_dcbz
=0):
49 # have to wait until not busy
50 yield from wait_busy(port1
,debug
="pi_st_A") # wait while busy
52 # set up a ST on the port. address first:
53 yield port1
.is_dcbz_i
.eq(is_dcbz
) # reset dcbz too
54 yield port1
.is_st_i
.eq(1) # indicate ST
55 yield port1
.data_len
.eq(datalen
) # ST length (1/2/4/8)
56 yield port1
.priv_mode
.eq(~msr
.pr
)
57 yield port1
.virt_mode
.eq(msr
.dr
)
58 yield port1
.mode_32bit
.eq(~msr
.sf
)
60 yield port1
.addr
.data
.eq(addr
) # set address
61 yield port1
.addr
.ok
.eq(1) # set ok
64 # must check exception even before waiting for address.
65 # XXX TODO: wait_addr should check for exception
66 exc_info
= yield from get_exception_info(port1
.exc_o
)
67 exc_happened
= exc_info
.happened
69 print("print fast ST exception happened")
70 yield # MUST wait for one clock cycle before de-asserting these
71 yield port1
.is_st_i
.eq(0) # end
72 yield port1
.addr
.ok
.eq(0) # set !ok
73 yield port1
.is_dcbz_i
.eq(0) # reset dcbz too
74 return "fast", exc_info
76 yield from wait_addr(port1
) # wait until addr ok
78 exc_info
= yield from get_exception_info(port1
.exc_o
)
79 exc_happened
= exc_info
.happened
81 print("print fast ST exception happened")
82 yield # MUST wait for one clock cycle before de-asserting these
83 yield port1
.is_st_i
.eq(0) # end
84 yield port1
.addr
.ok
.eq(0) # set !ok
85 yield port1
.is_dcbz_i
.eq(0) # reset dcbz too
86 return "fast", exc_info
89 # yield # not needed, just for checking
90 # yield # not needed, just for checking
91 # assert "ST" for one cycle (required by the API)
92 yield port1
.st
.data
.eq(data
)
93 yield port1
.st
.ok
.eq(1)
95 yield port1
.st
.ok
.eq(0)
96 exc_info
= yield from get_exception_info(port1
.exc_o
)
97 exc_happened
= exc_info
.happened
99 print("print fast ST exception happened")
100 yield # MUST wait for one clock cycle before de-asserting these
101 yield port1
.is_st_i
.eq(0) # end
102 yield port1
.addr
.ok
.eq(0) # set !ok
103 yield port1
.is_dcbz_i
.eq(0) # reset dcbz too
104 return "fast", exc_info
106 yield from wait_busy(port1
,debug
="pi_st_E") # wait while busy
107 exc_info
= yield from get_exception_info(port1
.exc_o
)
108 exc_happened
= exc_info
.happened
110 yield # needed if mmu/dache is used
111 yield port1
.is_st_i
.eq(0) # end
112 yield port1
.addr
.ok
.eq(0) # set !ok
113 yield port1
.is_dcbz_i
.eq(0) # reset dcbz too
114 yield # needed if mmu/dache is used
115 return "slow", exc_info
117 # can go straight to reset.
118 yield port1
.is_st_i
.eq(0) # end
119 yield port1
.addr
.ok
.eq(0) # set !ok
120 yield port1
.is_dcbz_i
.eq(0) # reset dcbz too
121 yield # needed if mmu/dache is used
125 def get_exception_info(exc_o
):
127 for fname
in LDSTExceptionTuple
._fields
:
128 attr
= getattr(exc_o
, fname
)
131 return LDSTExceptionTuple(*attrs
)
134 # copy of pi_st removed
136 def pi_ld(port1
, addr
, datalen
, msr
):
138 # have to wait until not busy
139 yield from wait_busy(port1
,debug
="pi_ld_A") # wait while busy
141 # set up a LD on the port. address first:
142 yield port1
.is_ld_i
.eq(1) # indicate LD
143 yield port1
.data_len
.eq(datalen
) # LD length (1/2/4/8)
144 yield port1
.priv_mode
.eq(~msr
.pr
)
145 yield port1
.virt_mode
.eq(msr
.dr
)
146 yield port1
.mode_32bit
.eq(~msr
.sf
)
148 yield port1
.addr
.data
.eq(addr
) # set address
149 yield port1
.addr
.ok
.eq(1) # set ok
151 yield from wait_addr(port1
) # wait until addr ok
152 exc_info
= yield from get_exception_info(port1
.exc_o
)
153 exc_happened
= exc_info
.happened
155 print("print fast LD exception happened")
156 yield # MUST wait for one clock cycle before de-asserting these
157 yield port1
.is_ld_i
.eq(0) # end
158 yield port1
.addr
.ok
.eq(0) # set !ok
159 return None, "fast", exc_info
162 yield from wait_ldok(port1
) # wait until ld ok
163 data
= yield port1
.ld
.data
164 exc_info
= yield from get_exception_info(port1
.exc_o
)
165 exc_happened
= yield port1
.exc_o
.happened
166 exc_happened
= exc_info
.happened
169 yield port1
.is_ld_i
.eq(0) # end
170 yield port1
.addr
.ok
.eq(0) # set !ok
172 return None, "slow", exc_info
174 yield from wait_busy(port1
, debug
="pi_ld_E") # wait while busy
176 exc_info
= yield from get_exception_info(port1
.exc_o
)
177 exc_happened
= exc_info
.happened
179 return None, "slow", exc_info
181 return data
, None, None
184 def pi_ldst(arg
, dut
, msr
):
186 # do two half-word stores at consecutive addresses, then two loads
192 assert(yield from pi_st(dut
, addr1
, data
, 2, msr
) is None)
193 assert(yield from pi_st(dut
, addr2
, data2
, 2, msr
) is None)
194 result
, exc
= yield from pi_ld(dut
, addr1
, 2, msr
)
195 result2
, exc2
= yield from pi_ld(dut
, addr2
, 2, msr
)
198 arg
.assertEqual(data
, result
, "data %x != %x" % (result
, data
))
199 arg
.assertEqual(data2
, result2
, "data2 %x != %x" % (result2
, data2
))
201 # now load both in a 32-bit load to make sure they're really consecutive
202 data3
= data |
(data2
<< 16)
203 result3
, exc3
= yield from pi_ld(dut
, addr1
, 4, msr
)
205 arg
.assertEqual(data3
, result3
, "data3 %x != %x" % (result3
, data3
))
208 def tst_config_pi(testcls
, ifacetype
):
209 """set up a configureable memory test of type ifacetype
212 pspec
= TestMemPspec(ldst_ifacetype
=ifacetype
,
217 cmpi
= ConfigMemoryPortInterface(pspec
)
218 dut
.submodules
.pi
= cmpi
.pi
219 if hasattr(cmpi
, 'lsmem'): # hmmm not happy about this
220 dut
.submodules
.lsmem
= cmpi
.lsmem
.lsi
221 vl
= rtlil
.convert(dut
, ports
=[]) # dut.ports())
222 with
open("test_pi_%s.il" % ifacetype
, "w") as f
:
225 run_simulation(dut
, {"sync": pi_ldst(testcls
, cmpi
.pi
.pi
)},
226 vcd_name
='test_pi_%s.vcd' % ifacetype
)
229 # FIXME: TypeError: pi_ldst() missing 1 required positional argument: 'msr'
230 @unittest.skip('broken')
231 class TestPIMem(unittest
.TestCase
):
232 def test_pi_mem(self
):
233 tst_config_pi(self
, 'testpi')
235 def test_pi2ls(self
):
236 tst_config_pi(self
, 'testmem')
238 def test_pi2ls_bare_wb(self
):
239 tst_config_pi(self
, 'test_bare_wb')
242 if __name__
== '__main__':