diff options
author | Amaury Pouly <amaury.pouly@gmail.com> | 2017-01-23 22:48:42 +0100 |
---|---|---|
committer | Amaury Pouly <amaury.pouly@gmail.com> | 2017-01-24 15:25:14 +0100 |
commit | 8e07d6845277efb96e067306f1ec9bc378c58bc0 (patch) | |
tree | 579e455a36e85f09cfe542fc45128b53a77dbc96 /utils | |
parent | 50eaa2d9ac3e23c5212ba2d0cd1dba4a995ab2c1 (diff) | |
download | rockbox-8e07d6845277efb96e067306f1ec9bc378c58bc0.tar.gz rockbox-8e07d6845277efb96e067306f1ec9bc378c58bc0.zip |
hwstub: add various jz stuff and xburst tests
The JZ misc allows to enable and test SRAM.
The XBurst code uses the coprocessor interface to analyse the cpu. It also
provides a test platform for various features like EBASE and exceptions.
I was able to test and confirm that on jz4760b (thus xburst), EBASE works
(but top 2 bits are not controllable and always 01). The processor claims
to support vector interrupts but this is untested. The values in ConfigX
are not to be trusted blindly, clearly some are wrong. I tried to use the
JZ4780 Config7 "ebase gate" to change bit 30 of EBASE but it does not work,
which suggests that JZ480 uses a newer version of XBurst. Detailled log below:
> ./hwstub_shell -q -f lua/xburst.lua -e "XBURST.init()"
[...]
XBurst:
PRId: 0x2ed0024f
CPU: JZ4760(B)
Config: 0x80000483
Architecture Type: MIPS32
Architecture Level: Release 2 (or more)
MMU Type: Standard TLB
Config1: 0x3e63318a
MMU Size: 32
ICache
Sets per way: 128
Ways: 4
Line size: 32
DCache
Sets per way: 128
Ways: 4
Line size: 32
FPU: no
Config2: 0x80000000
Config3: 0x20
Vectored interrupt: yes
Config7: 0x0
> ./hwstub_shell -q -e 'require("jz/misc"); JZ.misc.enable_sram()' \
-f lua/xburst.lua -e "XBURST.test_ebase(0x80000000);XBURST.test_ebase(0xb32d0000)
[...]
Testing EBASE...
Disable BEV
SR value: 0x2000fc00
EBASE value: 0x80000000
Value after writing 0x80000000: 0x80000000
Value after writing 0x80040000: 0x80040000
Test result: EBase seems to work
Disable config7 gate: write 0x0 to Config7
Value after writing 0xfffff000: 0xbffff000
Enable config7 gate: write 0x80 to Config7
Value after writing 0xc0000000: 0x80000000
Config7 result: Config7 gate does not work
Exception test with EBASE at 0x80000000...
Writing instructions to memory
Old SR: 0x2000fc00
New SR: 0xfc00
EBASE: 80000000
Before: cafebabe
After: deadbeef
Exception result: Exception and EBASE are working
Testing EBASE...
Disable BEV
SR value: 0x2000fc00
EBASE value: 0x80000000
Value after writing 0x80000000: 0x80000000
Value after writing 0x80040000: 0x80040000
Test result: EBase seems to work
Disable config7 gate: write 0x0 to Config7
Value after writing 0xfffff000: 0xbffff000
Enable config7 gate: write 0x80 to Config7
Value after writing 0xc0000000: 0x80000000
Config7 result: Config7 gate does not work
Exception test with EBASE at 0xb32d0000...
Writing instructions to memory
Old SR: 0x2000fc00
New SR: 0xfc00
EBASE: b32d0000
Before: cafebabe
After: deadbeef
Exception result: Exception and EBASE are working
Change-Id: I894227981a141a8c14419b36ed9f519baf145ad1
Diffstat (limited to 'utils')
-rw-r--r-- | utils/hwstub/tools/lua/jz/misc.lua | 43 | ||||
-rw-r--r-- | utils/hwstub/tools/lua/xburst.lua | 238 |
2 files changed, 281 insertions, 0 deletions
diff --git a/utils/hwstub/tools/lua/jz/misc.lua b/utils/hwstub/tools/lua/jz/misc.lua new file mode 100644 index 0000000000..fb4185de33 --- /dev/null +++ b/utils/hwstub/tools/lua/jz/misc.lua | |||
@@ -0,0 +1,43 @@ | |||
1 | ---------- | ||
2 | -- MISC -- | ||
3 | ---------- | ||
4 | |||
5 | JZ.misc = {} | ||
6 | |||
7 | function JZ.misc.enable_sram() | ||
8 | HW.CPM.CLKGATE1.SRAM.clr() | ||
9 | HW.CPM.CLKGATE1.AHB1.clr() | ||
10 | end | ||
11 | |||
12 | function JZ.misc.test_sram() | ||
13 | DEV.write32(0xb32d0000, 0xaaaa5555) | ||
14 | if DEV.read32(0xb32d0000) ~= 0xaaaa5555 then | ||
15 | error("SRAM is not working") | ||
16 | end | ||
17 | DEV.write32(0xb32d0000, 0xdeadbeef) | ||
18 | if DEV.read32(0xb32d0000) ~= 0xdeadbeef then | ||
19 | error("SRAM is not working") | ||
20 | end | ||
21 | print("SRAM seems to be working") | ||
22 | size = 0 | ||
23 | for i=4,64*1024,4 do | ||
24 | DEV.write32(0xb32d0000, 0xdeadbeef) | ||
25 | DEV.write32(0xb32d0000 + i, 0xcafebabe) | ||
26 | if DEV.read32(0xb32d0000 + i) ~= 0xcafebabe or DEV.read32(0xb32d0000) == 0xcafebabe then | ||
27 | size = i | ||
28 | break | ||
29 | end | ||
30 | end | ||
31 | print(string.format("SRAM size: 0x%x (%d KiB)", size, size / 1024)) | ||
32 | -- double check | ||
33 | for i=0,size-1,2 do | ||
34 | DEV.write16(0xb32d0000 + i, i) | ||
35 | end | ||
36 | for i=0,size-1,2 do | ||
37 | if DEV.read16(0xb32d0000 + i) ~= i then | ||
38 | error(string.format("SRAM size is not confirmed: read @%x gives %d instead of %d", | ||
39 | 0xb32d0000 + i, DEV.read16(0xb32d0000 + i), i)) | ||
40 | end | ||
41 | end | ||
42 | print("SRAM size confirmed and working") | ||
43 | end | ||
diff --git a/utils/hwstub/tools/lua/xburst.lua b/utils/hwstub/tools/lua/xburst.lua new file mode 100644 index 0000000000..ddaf7fbc66 --- /dev/null +++ b/utils/hwstub/tools/lua/xburst.lua | |||
@@ -0,0 +1,238 @@ | |||
1 | XBURST = {} | ||
2 | |||
3 | function XBURST.read_cp0(reg, sel) | ||
4 | return DEV.read32_cop({0, reg, sel}) | ||
5 | end | ||
6 | |||
7 | function XBURST.write_cp0(reg, sel, val) | ||
8 | DEV.write32_cop({0, reg, sel}, val) | ||
9 | end | ||
10 | |||
11 | XBURST.prid_table = { | ||
12 | [0x0ad0024f] = "JZ4740", | ||
13 | [0x1ed0024f] = "JZ4755", | ||
14 | [0x2ed0024f] = "JZ4760(B)", | ||
15 | [0x3ee1024f] = "JZ4780" | ||
16 | } | ||
17 | |||
18 | XBURST.at_table = { | ||
19 | [0] = "MIPS32", | ||
20 | [1] = "MIPS64 with 32-bit segments", | ||
21 | [2] = "MIPS64" | ||
22 | } | ||
23 | |||
24 | XBURST.ar_table = { | ||
25 | [0] = "Release 1", | ||
26 | [1] = "Release 2 (or more)" | ||
27 | } | ||
28 | |||
29 | XBURST.mt_table = { | ||
30 | [0] = "None", | ||
31 | [1] = "Standard TLB", | ||
32 | [2] = "BAT", | ||
33 | [3] = "Fixed Mapping", | ||
34 | [4] = "Dual VTLB and FTLB" | ||
35 | } | ||
36 | |||
37 | XBURST.is_table = { | ||
38 | [0] = 64, | ||
39 | [1] = 128, | ||
40 | [2] = 256, | ||
41 | [3] = 512, | ||
42 | [4] = 1024, | ||
43 | [5] = 2048, | ||
44 | [6] = 4096, | ||
45 | [7] = 32 | ||
46 | } | ||
47 | |||
48 | XBURST.il_table = { | ||
49 | [0] = 0, | ||
50 | [1] = 4, | ||
51 | [2] = 8, | ||
52 | [3] = 16, | ||
53 | [4] = 32, | ||
54 | [5] = 64, | ||
55 | [6] = 128 | ||
56 | } | ||
57 | |||
58 | function XBURST.get_table_or(tbl, index, dflt) | ||
59 | if tbl[index] ~= nil then | ||
60 | return tbl[index] | ||
61 | else | ||
62 | return dflt | ||
63 | end | ||
64 | end | ||
65 | |||
66 | function XBURST.do_ebase_test() | ||
67 | XBURST.write_cp0(15, 1, 0x80000000) | ||
68 | print(string.format(" Value after writing 0x80000000: 0x%x", XBURST.read_cp0(15, 1))) | ||
69 | if XBURST.read_cp0(15, 1) ~= 0x80000000 then | ||
70 | return "Value 0x8000000 does not stick, EBASE is probably not working" | ||
71 | end | ||
72 | XBURST.write_cp0(15, 1, 0x80040000) | ||
73 | print(string.format(" Value after writing 0x80040000: 0x%x", XBURST.read_cp0(15, 1))) | ||
74 | if XBURST.read_cp0(15, 1) ~= 0x80040000 then | ||
75 | return "Value 0x80040000 does not stick, EBASE is probably not working" | ||
76 | end | ||
77 | return "EBase seems to work" | ||
78 | end | ||
79 | |||
80 | function XBURST.do_ebase_cfg7gate_test() | ||
81 | -- test gate in config7 | ||
82 | config7_old = XBURST.read_cp0(16, 7) | ||
83 | XBURST.write_cp0(16, 7, bit32.replace(config7_old, 0, 7)) -- disable EBASE[30] modification | ||
84 | print(string.format(" Disable config7 gate: write 0x%x to Config7", bit32.replace(config7_old, 0, 7))) | ||
85 | XBURST.write_cp0(15, 1, 0xfffff000) | ||
86 | print(string.format(" Value after writing 0xfffff000: 0x%x", XBURST.read_cp0(15, 1))) | ||
87 | if XBURST.read_cp0(15, 1) == 0xfffff000 then | ||
88 | return "Config7 gate has no effect but modifications are allowed anyway" | ||
89 | end | ||
90 | XBURST.write_cp0(16, 7, bit32.replace(config7_old, 1, 7)) -- enable EBASE[30] modification | ||
91 | print(string.format(" Enable config7 gate: write 0x%x to Config7", bit32.replace(config7_old, 1, 7))) | ||
92 | XBURST.write_cp0(15, 1, 0xc0000000) | ||
93 | print(string.format(" Value after writing 0xc0000000: 0x%x", XBURST.read_cp0(15, 1))) | ||
94 | if XBURST.read_cp0(15, 1) ~= 0xc0000000 then | ||
95 | return "Config7 gate does not work" | ||
96 | end | ||
97 | XBURST.write_cp0(16, 7, config7_old) | ||
98 | return "Config7 gate seems to work" | ||
99 | end | ||
100 | |||
101 | function XBURST.do_ebase_exc_test(mem_addr) | ||
102 | if (mem_addr % 0x1000) ~= 0 then | ||
103 | return " memory address for exception test must aligned on a 0x1000 boundary"; | ||
104 | end | ||
105 | print(string.format("Exception test with EBASE at 0x%x...", mem_addr)) | ||
106 | print(" Writing instructions to memory") | ||
107 | -- create instructions in memory | ||
108 | exc_addr = mem_addr + 0x180 -- general exception vector | ||
109 | data_addr = mem_addr + 0x300 | ||
110 | -- lui k0,<low part of data_addr> | ||
111 | -- ori k0,k0,<high part> | ||
112 | DEV.write32(exc_addr + 0, 0x3c1a0000 + bit32.rshift(data_addr, 16)) | ||
113 | DEV.write32(exc_addr + 4, 0x375a0000 + bit32.band(data_addr, 0xffff)) | ||
114 | -- lui k1,0xdead | ||
115 | -- ori k1,k1,0xbeef | ||
116 | DEV.write32(exc_addr + 8, 0x3c1bdead) | ||
117 | DEV.write32(exc_addr + 12, 0x377bbeef) | ||
118 | -- sw k1,0(k0) | ||
119 | DEV.write32(exc_addr + 16, 0xaf5b0000) | ||
120 | -- mfc0 k0,c0_epc | ||
121 | -- addi k0,k0,4 | ||
122 | -- mtc0 k0,c0_epc | ||
123 | DEV.write32(exc_addr + 20, 0x401a7000) | ||
124 | DEV.write32(exc_addr + 24, 0x235a0004) | ||
125 | DEV.write32(exc_addr + 28, 0x409a7000) | ||
126 | -- eret | ||
127 | -- nop | ||
128 | DEV.write32(exc_addr + 32, 0x42000018) | ||
129 | DEV.write32(exc_addr + 36, 0) | ||
130 | -- fill data with some initial value | ||
131 | DEV.write32(data_addr, 0xcafebabe) | ||
132 | -- write instructions to trigger an interrupt | ||
133 | bug_addr = mem_addr | ||
134 | -- syscall | ||
135 | DEV.write32(bug_addr + 0, 0x0000000c) | ||
136 | -- jr ra | ||
137 | -- nop | ||
138 | DEV.write32(bug_addr + 4, 0x03e00008) | ||
139 | DEV.write32(bug_addr + 8, 0) | ||
140 | |||
141 | -- make sure we are the right shape for the test: SR should have BEV cleared, | ||
142 | -- mask all interrupts, enable interrupts | ||
143 | old_sr = XBURST.read_cp0(12, 0) | ||
144 | print(string.format(" Old SR: 0x%x", old_sr)) | ||
145 | XBURST.write_cp0(12, 0, 0xfc00) -- BEV set to 0, all interrupts masked and interrupt disabled | ||
146 | print(string.format(" New SR: 0x%x", XBURST.read_cp0(12, 0))) | ||
147 | -- change EBASE | ||
148 | old_ebase = XBURST.read_cp0(15, 1) | ||
149 | XBURST.write_cp0(15, 1, mem_addr) | ||
150 | print(string.format(" EBASE: %x", XBURST.read_cp0(15, 1))) | ||
151 | -- test | ||
152 | print(string.format(" Before: %x", DEV.read32(data_addr))) | ||
153 | DEV.call(bug_addr) | ||
154 | print(string.format(" After: %x", DEV.read32(data_addr))) | ||
155 | success = DEV.read32(data_addr) == 0xdeadbeef | ||
156 | -- restore SR and EBASE | ||
157 | XBURST.write_cp0(12, 0, old_sr) | ||
158 | XBURST.write_cp0(15, 1, ebase_old) | ||
159 | |||
160 | return success and "Exception and EBASE are working" or "Exception and EBASE are NOT working" | ||
161 | end | ||
162 | |||
163 | function XBURST.test_ebase(mem_addr) | ||
164 | -- EBase | ||
165 | ebase_old = XBURST.read_cp0(15, 1) | ||
166 | sr_old = XBURST.read_cp0(12, 0) | ||
167 | print("Testing EBASE...") | ||
168 | print(" Disable BEV") | ||
169 | XBURST.write_cp0(12, 0, bit32.replace(sr_old, 0, 22)) -- clear BEV | ||
170 | print(string.format(" SR value: 0x%x", XBURST.read_cp0(12, 0))) | ||
171 | print(string.format(" EBASE value: 0x%x", ebase_old)) | ||
172 | print(" Test result: " .. XBURST.do_ebase_test()) | ||
173 | print(" Config7 result: " .. XBURST.do_ebase_cfg7gate_test()) | ||
174 | XBURST.write_cp0(12, 0, sr_old) | ||
175 | XBURST.write_cp0(15, 1, ebase_old) | ||
176 | -- now try with actual exceptions | ||
177 | if mem_addr == nil then | ||
178 | print(" Not doing exception test, please specify memory to use: sram, ram") | ||
179 | return | ||
180 | end | ||
181 | print(" Exception result: " .. XBURST.do_ebase_exc_test(mem_addr)) | ||
182 | end | ||
183 | |||
184 | function XBURST.init() | ||
185 | -- enable CP1 in SR | ||
186 | sr_old = XBURST.read_cp0(12, 0) | ||
187 | XBURST.write_cp0(12, 0, bit32.replace(sr_old, 1, 29)) -- set CU1 | ||
188 | print("XBurst:") | ||
189 | -- PRId | ||
190 | XBURST.prid = XBURST.read_cp0(15, 0) | ||
191 | print(string.format(" PRId: 0x%x", XBURST.prid)) | ||
192 | print(" CPU: " .. XBURST.get_table_or(XBURST.prid_table, XBURST.prid, "unknown")) | ||
193 | -- Config | ||
194 | XBURST.config = XBURST.read_cp0(16, 0) | ||
195 | print(string.format(" Config: 0x%x", XBURST.config)) | ||
196 | print(" Architecture Type: " .. XBURST.get_table_or(XBURST.at_table, | ||
197 | bit32.extract(XBURST.config, 13, 2), "unknown")) | ||
198 | print(" Architecture Level: " .. XBURST.get_table_or(XBURST.ar_table, | ||
199 | bit32.extract(XBURST.config, 10, 3), "unknown")) | ||
200 | print(" MMU Type: " .. XBURST.get_table_or(XBURST.mt_table, | ||
201 | bit32.extract(XBURST.config, 7, 3), "unknown")) | ||
202 | -- Config1 | ||
203 | XBURST.config1 = XBURST.read_cp0(16, 1) | ||
204 | print(string.format(" Config1: 0x%x", XBURST.config1)) | ||
205 | -- don't print of no MMU | ||
206 | if bit32.extract(XBURST.config, 7, 3) ~= 0 then | ||
207 | print(string.format(" MMU Size: %d", bit32.extract(XBURST.config1, 25, 6) + 1)) | ||
208 | end | ||
209 | print(" ICache") | ||
210 | print(" Sets per way: " .. XBURST.get_table_or(XBURST.is_table, | ||
211 | bit32.extract(XBURST.config1, 22, 3), "unknown")) | ||
212 | print(" Ways: " .. (1 + bit32.extract(XBURST.config1, 16, 3))) | ||
213 | print(" Line size: " .. XBURST.get_table_or(XBURST.il_table, | ||
214 | bit32.extract(XBURST.config1, 19, 3), "unknown")) | ||
215 | print(" DCache") | ||
216 | print(" Sets per way: " .. XBURST.get_table_or(XBURST.is_table, | ||
217 | bit32.extract(XBURST.config1, 13, 3), "unknown")) | ||
218 | print(" Ways: " .. (1 + bit32.extract(XBURST.config1, 7, 3))) | ||
219 | print(" Line size: " .. XBURST.get_table_or(XBURST.il_table, | ||
220 | bit32.extract(XBURST.config1, 10, 3), "unknown")) | ||
221 | print(" FPU: " .. (bit32.extract(XBURST.config1, 0) == 1 and "yes" or "no")) | ||
222 | |||
223 | -- Config 2 | ||
224 | XBURST.config2 = XBURST.read_cp0(16, 2) | ||
225 | print(string.format(" Config2: 0x%x", XBURST.config2)) | ||
226 | |||
227 | -- Config 3 | ||
228 | XBURST.config3 = XBURST.read_cp0(16, 3) | ||
229 | print(string.format(" Config3: 0x%x", XBURST.config3)) | ||
230 | print(" Vectored interrupt: " .. (bit32.extract(XBURST.config2, 5) and "yes" or "no")) | ||
231 | |||
232 | -- Config 7 | ||
233 | XBURST.config7 = XBURST.read_cp0(16, 7) | ||
234 | print(string.format(" Config7: 0x%x", XBURST.config7)) | ||
235 | |||
236 | -- restore SR | ||
237 | XBURST.write_cp0(12, 0, sr_old) | ||
238 | end | ||