rockbox/utils/hwstub/tools/lua/xburst.lua

306 lines
11 KiB
Lua
Raw Normal View History

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
2017-01-23 21:48:42 +00:00
XBURST = {}
function XBURST.read_cp0(reg, sel)
return DEV.read32_cop({0, reg, sel})
end
function XBURST.write_cp0(reg, sel, val)
DEV.write32_cop({0, reg, sel}, val)
end
XBURST.prid_table = {
[0x0ad0024f] = "JZ4740",
[0x1ed0024f] = "JZ4755",
[0x2ed0024f] = "JZ4760(B)",
[0x3ee1024f] = "JZ4780"
}
XBURST.at_table = {
[0] = "MIPS32",
[1] = "MIPS64 with 32-bit segments",
[2] = "MIPS64"
}
XBURST.ar_table = {
[0] = "Release 1",
[1] = "Release 2 (or more)"
}
XBURST.mt_table = {
[0] = "None",
[1] = "Standard TLB",
[2] = "BAT",
[3] = "Fixed Mapping",
[4] = "Dual VTLB and FTLB"
}
XBURST.is_table = {
[0] = 64,
[1] = 128,
[2] = 256,
[3] = 512,
[4] = 1024,
[5] = 2048,
[6] = 4096,
[7] = 32
}
XBURST.il_table = {
[0] = 0,
[1] = 4,
[2] = 8,
[3] = 16,
[4] = 32,
[5] = 64,
[6] = 128
}
function XBURST.get_table_or(tbl, index, dflt)
if tbl[index] ~= nil then
return tbl[index]
else
return dflt
end
end
function XBURST.do_ebase_test()
XBURST.write_cp0(15, 1, 0x80000000)
print(string.format(" Value after writing 0x80000000: 0x%x", XBURST.read_cp0(15, 1)))
if XBURST.read_cp0(15, 1) ~= 0x80000000 then
return "Value 0x8000000 does not stick, EBASE is probably not working"
end
XBURST.write_cp0(15, 1, 0x80040000)
print(string.format(" Value after writing 0x80040000: 0x%x", XBURST.read_cp0(15, 1)))
if XBURST.read_cp0(15, 1) ~= 0x80040000 then
return "Value 0x80040000 does not stick, EBASE is probably not working"
end
return "EBase seems to work"
end
function XBURST.do_ebase_cfg7gate_test()
-- test gate in config7
config7_old = XBURST.read_cp0(16, 7)
XBURST.write_cp0(16, 7, bit32.replace(config7_old, 0, 7)) -- disable EBASE[30] modification
print(string.format(" Disable config7 gate: write 0x%x to Config7", bit32.replace(config7_old, 0, 7)))
XBURST.write_cp0(15, 1, 0xfffff000)
print(string.format(" Value after writing 0xfffff000: 0x%x", XBURST.read_cp0(15, 1)))
if XBURST.read_cp0(15, 1) == 0xfffff000 then
return "Config7 gate has no effect but modifications are allowed anyway"
end
XBURST.write_cp0(16, 7, bit32.replace(config7_old, 1, 7)) -- enable EBASE[30] modification
print(string.format(" Enable config7 gate: write 0x%x to Config7", bit32.replace(config7_old, 1, 7)))
XBURST.write_cp0(15, 1, 0xc0000000)
print(string.format(" Value after writing 0xc0000000: 0x%x", XBURST.read_cp0(15, 1)))
if XBURST.read_cp0(15, 1) ~= 0xc0000000 then
return "Config7 gate does not work"
end
XBURST.write_cp0(16, 7, config7_old)
return "Config7 gate seems to work"
end
function XBURST.do_ebase_exc_test(mem_addr)
if (mem_addr % 0x1000) ~= 0 then
return " memory address for exception test must aligned on a 0x1000 boundary";
end
print(string.format("Exception test with EBASE at 0x%x...", mem_addr))
print(" Writing instructions to memory")
-- create instructions in memory
exc_addr = mem_addr + 0x180 -- general exception vector
data_addr = mem_addr + 0x300
-- lui k0,<low part of data_addr>
-- ori k0,k0,<high part>
DEV.write32(exc_addr + 0, 0x3c1a0000 + bit32.rshift(data_addr, 16))
DEV.write32(exc_addr + 4, 0x375a0000 + bit32.band(data_addr, 0xffff))
-- lui k1,0xdead
-- ori k1,k1,0xbeef
DEV.write32(exc_addr + 8, 0x3c1bdead)
DEV.write32(exc_addr + 12, 0x377bbeef)
-- sw k1,0(k0)
DEV.write32(exc_addr + 16, 0xaf5b0000)
-- mfc0 k0,c0_epc
-- addi k0,k0,4
-- mtc0 k0,c0_epc
DEV.write32(exc_addr + 20, 0x401a7000)
DEV.write32(exc_addr + 24, 0x235a0004)
DEV.write32(exc_addr + 28, 0x409a7000)
-- eret
-- nop
DEV.write32(exc_addr + 32, 0x42000018)
DEV.write32(exc_addr + 36, 0)
-- fill data with some initial value
DEV.write32(data_addr, 0xcafebabe)
-- write instructions to trigger an interrupt
bug_addr = mem_addr
-- syscall
DEV.write32(bug_addr + 0, 0x0000000c)
-- jr ra
-- nop
DEV.write32(bug_addr + 4, 0x03e00008)
DEV.write32(bug_addr + 8, 0)
-- make sure we are the right shape for the test: SR should have BEV cleared,
-- mask all interrupts, enable interrupts
old_sr = XBURST.read_cp0(12, 0)
print(string.format(" Old SR: 0x%x", old_sr))
XBURST.write_cp0(12, 0, 0xfc00) -- BEV set to 0, all interrupts masked and interrupt disabled
print(string.format(" New SR: 0x%x", XBURST.read_cp0(12, 0)))
-- change EBASE
old_ebase = XBURST.read_cp0(15, 1)
XBURST.write_cp0(15, 1, mem_addr)
print(string.format(" EBASE: %x", XBURST.read_cp0(15, 1)))
-- test
print(string.format(" Before: %x", DEV.read32(data_addr)))
DEV.call(bug_addr)
print(string.format(" After: %x", DEV.read32(data_addr)))
success = DEV.read32(data_addr) == 0xdeadbeef
-- restore SR and EBASE
XBURST.write_cp0(12, 0, old_sr)
XBURST.write_cp0(15, 1, ebase_old)
return success and "Exception and EBASE are working" or "Exception and EBASE are NOT working"
end
function XBURST.test_ebase(mem_addr)
-- EBase
ebase_old = XBURST.read_cp0(15, 1)
sr_old = XBURST.read_cp0(12, 0)
print("Testing EBASE...")
print(" Disable BEV")
XBURST.write_cp0(12, 0, bit32.replace(sr_old, 0, 22)) -- clear BEV
print(string.format(" SR value: 0x%x", XBURST.read_cp0(12, 0)))
print(string.format(" EBASE value: 0x%x", ebase_old))
print(" Test result: " .. XBURST.do_ebase_test())
print(" Config7 result: " .. XBURST.do_ebase_cfg7gate_test())
XBURST.write_cp0(12, 0, sr_old)
XBURST.write_cp0(15, 1, ebase_old)
-- now try with actual exceptions
if mem_addr == nil then
print(" Not doing exception test, please specify memory to use: sram, ram")
return
end
print(" Exception result: " .. XBURST.do_ebase_exc_test(mem_addr))
end
function XBURST.test_ext_inst(mem_addr)
data_addr = mem_addr + 0x80
-----------
-- test ext
-----------
for pos = 0, 31 do
for size = 1, 32 - pos do
-- lui v0,<low part of data_addr>
-- addiu v0,v0,<high part>
-- lw v1,0(v0)
DEV.write32(mem_addr + 0, 0x3c020000 + bit32.rshift(data_addr, 16))
DEV.write32(mem_addr + 4, 0x8c430000 + bit32.band(data_addr, 0xffff))
DEV.write32(mem_addr + 8, 0x8c430000)
-- ext v1, v1, pos, size
DEV.write32(mem_addr + 12, 0x7c630000 + bit32.rshift(size - 1, 11) + bit32.rshift(pos, 6))
-- sw v1,0(v0)
DEV.write32(mem_addr + 16, 0xac430000)
-- jr ra
-- nop
DEV.write32(mem_addr + 20, 0x03e00008)
DEV.write32(mem_addr + 24, 0)
-- write some random data
data = math.random(0xffffffff)
print(string.format(" data: %x", data))
DEV.write32(data_addr, data)
DEV.call(mem_addr)
ext_data = DEV.read32(data_addr)
print(string.format(" result: %x vs %x", ext_data, bit32.extract(data, pos, size)))
break
end
break
end
end
function XBURST.test_ei_di_inst(mem_addr)
-- save SR and disable interrupts
old_sr = XBURST.read_cp0(12, 0)
XBURST.write_cp0(12, 0, bit32.replace(old_sr, 0, 0)) -- clear EI
print("Testing ei")
print(" Test SR")
print(" Enable interrupts with CP0")
XBURST.write_cp0(12, 0, bit32.replace(old_sr, 1, 0)) -- set EI
print(string.format(" SR: 0x%x", XBURST.read_cp0(12, 0)))
print(" Disable interrupts with CP0")
XBURST.write_cp0(12, 0, bit32.replace(old_sr, 0, 0)) -- clear EI
print(string.format(" SR: 0x%x", XBURST.read_cp0(12, 0)))
print(" Test ei/di")
print(" Enable interrupts with ei")
-- ei
-- jr ra
-- nop
DEV.write32(mem_addr + 4, 0x41606020)
DEV.write32(mem_addr + 4, 0x03e00008)
DEV.write32(mem_addr + 8, 0)
DEV.call(mem_addr)
print(string.format(" SR: 0x%x", XBURST.read_cp0(12, 0)))
print(" Disable interrupts with di")
-- di
DEV.write32(mem_addr + 4, 0x41606000)
DEV.call(mem_addr)
print(string.format(" SR: 0x%x", XBURST.read_cp0(12, 0)))
-- restore SR
XBURST.write_cp0(old_sr)
end
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
2017-01-23 21:48:42 +00:00
function XBURST.init()
-- enable CP1 in SR
sr_old = XBURST.read_cp0(12, 0)
XBURST.write_cp0(12, 0, bit32.replace(sr_old, 1, 29)) -- set CU1
print("XBurst:")
-- PRId
XBURST.prid = XBURST.read_cp0(15, 0)
print(string.format(" PRId: 0x%x", XBURST.prid))
print(" CPU: " .. XBURST.get_table_or(XBURST.prid_table, XBURST.prid, "unknown"))
-- Config
XBURST.config = XBURST.read_cp0(16, 0)
print(string.format(" Config: 0x%x", XBURST.config))
print(" Architecture Type: " .. XBURST.get_table_or(XBURST.at_table,
bit32.extract(XBURST.config, 13, 2), "unknown"))
print(" Architecture Level: " .. XBURST.get_table_or(XBURST.ar_table,
bit32.extract(XBURST.config, 10, 3), "unknown"))
print(" MMU Type: " .. XBURST.get_table_or(XBURST.mt_table,
bit32.extract(XBURST.config, 7, 3), "unknown"))
-- Config1
XBURST.config1 = XBURST.read_cp0(16, 1)
print(string.format(" Config1: 0x%x", XBURST.config1))
-- don't print of no MMU
if bit32.extract(XBURST.config, 7, 3) ~= 0 then
print(string.format(" MMU Size: %d", bit32.extract(XBURST.config1, 25, 6) + 1))
end
print(" ICache")
print(" Sets per way: " .. XBURST.get_table_or(XBURST.is_table,
bit32.extract(XBURST.config1, 22, 3), "unknown"))
print(" Ways: " .. (1 + bit32.extract(XBURST.config1, 16, 3)))
print(" Line size: " .. XBURST.get_table_or(XBURST.il_table,
bit32.extract(XBURST.config1, 19, 3), "unknown"))
print(" DCache")
print(" Sets per way: " .. XBURST.get_table_or(XBURST.is_table,
bit32.extract(XBURST.config1, 13, 3), "unknown"))
print(" Ways: " .. (1 + bit32.extract(XBURST.config1, 7, 3)))
print(" Line size: " .. XBURST.get_table_or(XBURST.il_table,
bit32.extract(XBURST.config1, 10, 3), "unknown"))
print(" FPU: " .. (bit32.extract(XBURST.config1, 0) == 1 and "yes" or "no"))
-- Config 2
XBURST.config2 = XBURST.read_cp0(16, 2)
print(string.format(" Config2: 0x%x", XBURST.config2))
-- Config 3
XBURST.config3 = XBURST.read_cp0(16, 3)
print(string.format(" Config3: 0x%x", XBURST.config3))
print(" Vectored interrupt: " .. (bit32.extract(XBURST.config2, 5) and "yes" or "no"))
-- Config 7
XBURST.config7 = XBURST.read_cp0(16, 7)
print(string.format(" Config7: 0x%x", XBURST.config7))
-- restore SR
XBURST.write_cp0(12, 0, sr_old)
end