EXPERIMENTAL repository for ARM7TDMI single-step tests
These tests are generated from fleroviux's excellent NanoBoyAdvance. Any errors in the test are likely errors in my code, not in NBA. Thanks to fleroviux for letting me use NBA for this! I will link both the original repository and my fork for creating these tests, in the near future.
You must run transcode_json.py after pulling the tests. This will translate the .json.bin format into .json format to easily work with. If you wish to use the binary representation, the .py file should document it fairly clearly, it's a very simple format.
These LIKELY have bugs. Until tested, don't be surprised if you get a wrong result. This is normal for releasing these tests.
These tests currently consist of 20,000 tests per .json file, each one testing a category of encoding. There may be holes or inaccuracies. Only ARM is covered, THUMB will come soon.
Each tests has a list with 500 entries that look like this (this is from hw_data_transfer_register.json):
{
"initial": {
"R": [
4172568239,
3218885584,
3611667212,
1565924574,
126631669,
898680852,
2152366193,
3510576945,
2585370008,
2084998222,
1710718908,
921484554,
857686631,
4076630577,
496381836,
3076961312
],
"R_fiq": [
1729278480,
3279118443,
1296478502,
1311475728,
2093184835,
617130518,
3124009755
],
"R_svc": [
1848569204,
3393792212
],
"R_abt": [
2644803584,
3237205884
],
"R_irq": [
4028872293,
1667487871
],
"R_und": [
1540154790,
1437581195
],
"CPSR": 805306395,
"SPSR": [
268435671,
3758096403,
1879048400,
268435483,
268435667,
805306512
],
"pipeline": [
1887645885,
10559586
]
},
"final": {
"R": [
4172568239,
3218885584,
3611667212,
1565924574,
126631669,
898680852,
2152366193,
3510576945,
2585370008,
2084998222,
1710718908,
921484554,
857686631,
0,
0,
3076961320
],
"R_fiq": [
1729278480,
3279118443,
1296478502,
1311475728,
2093184835,
617130518,
3124009755
],
"R_svc": [
1848569204,
3393792212
],
"R_abt": [
2644803584,
3237205884
],
"R_irq": [
4028872293,
1667487871
],
"R_und": [
4076630577,
496381836
],
"CPSR": 805306395,
"SPSR": [
0,
3758096403,
1879048400,
268435483,
268435667,
805306512
],
"pipeline": [
10629219,
10698852
]
},
"transactions": [
{
"kind": 0,
"size": 4,
"addr": 3076961312,
"data": 10629219,
"cycle": 1
},
{
"kind": 0,
"size": 4,
"addr": 3076961316,
"data": 10698852,
"cycle": 2
}
],
"opcodes": [
1887645885,
10559586,
10629219,
10698852,
11047017
],
"base_addr": 3076961306
},
Is the location in RAM where opcode[0] is located. Just the base address of the test.
They contain the initial and final state of all relevant registers in the CPU. Initial is what the CPU is set to before executing 2 instructions, and final is what all the same registers contain afterward.
- R: R0-R15
- R_fiq: R0-R6 banked for FIQ
- R_svc, R_abt, R_irq, R_und: R0-R1 banked for svc, abt, IRQ, and und.
- CPSR register
- SPSR registers in this order: regular, fiq, svc, abt, irq, und
- pipeline: The contents of the instruction instruction pipeline, in order
Honestly I don't have an ARM7TDMI core yet and I'm not sure if this is the best way to represent this data. Let me know if I can make it better. Moving on...
Are memory transactions.
"kind": 0,
"size": 4,
"addr": 3076961316,
"data": 10698852,
"cycle": 2
- kind is 0 for an instruction read, 1 for a general read, and 2 for a write
- size is in bytes. so 1 = 1 byte, 2 = 16 bits, 4 = 32 bits.
- addr is the address
- data is the data
- cycle is the cycle number this transaction happened on (experimental, I'm not sure if I instrumented NBA correctly for this number)
This section is a doozy. Testing a 32-bit RISC processor isn't like testing an 8-bit processor. We can't just allocate a flat 4 gigs of RAM and go. (Well, maybe many of us can, but it's not a good idea). Instead, we have a list of transactions to search through and match our transactions against, and a list of opcodes that are given in different circumstances.
Here is what the opcodes in the list ARE:
- 0: is the opcode being tested
- 1: is ADC R1, R2, store in R2
- 2: is ADC R2, R3, store in R3
- 3: is ADC R3, R4, store in R4
- 4: is ADC R8, R9, store in R9
All of the opcodes other than the specific one being tested were chosen specifically so that (a) they would be very simple (no shifts etc.) and easy to rely on, and (b) they would have different side-effects. This should help you determine where something goes wrong.
Opcode 0 is loaded into pipeline slot 0, opcode 1 is in pipeline slot 1, and R15 is set to the address of opcode 2 (+8 from the about-to-execute instruction).
The CPU is set up in this way, and runs 2 instructions.
Opcode 0 and then optionally either 1 or 3 should be executed. Opcode 1 is normally executed for most instructions. 3 is only executed if a branch is taken.
When your CPU issues a read or write, you should look it up in the list of transactions and compare it. If it isn't found in the transactions, you should return opcode 4 as the value, as that will have a side effect one way or another.
IF you do not emulate the pipeline, you may wish to add in the ability to return opcodes 0-4 based on read address. In pseudocode that looks something like this...
def read(addr, is_code):
if not is_code:
return lookup_transaction(addr)
if (addr >= test.base_addr) and (addr <= (test.base_addr + 12)):
diff = (addr - test.base_addr) / 4
return test.opcodes[diff]
else:
return test.opcodes[4]
- The tests do not properly restrict read and write alignment, other than instructions. Let me know if it's important to change this
- The tests treat RAM as a 32-bit flat space with no memory-mapped registers.
- The tests may have bugs, this is an in-development release v0.1
- There may be issues with the tests we don't know yet.
I hope you find it useful!