The following code reproduces an interesting issue for me. It is run from the origin in supervisor mode.
adr r3,datatable
ldmfd R3!,{R0-R2,R4-R14}
mov r3,#0
ADD R6,R6,#1
CMP R6,R8
LDRLS R3,[R9,R6,LSL #2]
MOVLS R4,R11
MOVHI R3,#0
TEQLSP PC,R10
MOV R12,R6 ; *** Not R8-R14
MOV R14,PC
;TEQP R14,#&40000000
b main
datatable & &380b284 ; r0 & &380b294 ; r1 & &00000010 ; r2 & &00000010 & &00000000 & &00000000 & &00000000 & &00000000 & &00000000 & &0380b28d & &00000024 & &0380b270 & &01c01f98 & &00000000
Basically I expect r12 to be set to 0x00000001 and r12_firq to be unset. However the amber.dis output is ...
000000014 0: add r3, pc, #40 000000016 4: ldmia r3!, {r0, r1, r2, r4, r5, r6, r7, r8, r9, r10, r11, ip, sp, lr} 000000019 read addr 30, data 0380b284 000000021 read addr 34, data 0380b294 000000023 read addr 38, data 00000010 000000025 read addr 3c, data 00000010 000000027 read addr 40, data 00000000 000000029 read addr 44, data 00000000 000000031 read addr 48, data 00000000 000000033 read addr 4c, data 00000000 000000035 read addr 50, data 00000000 000000037 read addr 54, data 0380b28d 000000039 read addr 58, data 00000024 000000041 read addr 5c, data 0380b270 000000043 read addr 60, data 01c01f98 000000045 read addr 64, data 00000000 000000048 8: mov r3, #0 000000050 c: add r6, r6, #1 000000052 10: cmp r6, r8 000000054 14: -ldrls r3, r9, r6, lsl #2 000000056 18: -movls r4, r11 000000058 1c: movhi r3, #0 000000060 20: -teqpls pc, r10 000000062 24: mov ip, r6 000000064 28: mov lr, pc 000000066 2c: b 0 000000067 jump from 2c to 0, r0 0380b284, r1 0380b294, r2 00000010, r3 00000000, r4 00000010, r5 00000000, r6 00000001, r7 00000000, r8 00000000, r9 00000000, r10 0380b28d, r11 00000024, r12 0380b270, r13 01c01f98, r14 2c000033, cc 2
Notice R12 is unchanged. I found this code in the RISC OS 3 operating system.
How did I find this? I am trying to boot RISC OS 3 on Amber core. I have found issues with the cpu core and i've instrumented the core against ArcEM archimedes emulator. I've been at this debugging for about 3 months.
It does, however, work correctly if i put a NOP between the
TEQLSP PC,R10
and
MOV R12,R6 ; *** Not R8-R14
I believe the ARM manual says you are supposed to do this after a TEQ instruction. However it looks like Wilson et al were smoking the good stuff while writing RISC OS and that real ARMs dont seem to mind.
Simplied example.
mov r8,#0
mov r6,#10
mov r10,#13
ADD R6,R6,#1
CMP R6,R8
LDRLS R3,[R9,R6,LSL #2]
MOVLS R4,R11
MOVHI R3,#0
TEQLSP PC,R10
MOV R12,R6 ; *** Not R8-R14
The issue is that the TEQLSP command sets i_status_bits_mode to a23_execute even when the instruction does not execute. This causes .i_mode_idec on a23_registers to get set incorrectly for the cycle immediately following a TEQ instruction that doesnt execute.
The following change seems to fix it but it would need verification.
change line 207 of a23_execute.v from
assign status_bits_out = (i_status_bits_mode_wen && i_status_bits_sel == 3'd1) ? alu_out1:0 : status_bits_mode ;
to
assign status_bits_out = (execute && i_status_bits_mode_wen && i_status_bits_sel == 3'd1) ? alu_out1:0 : status_bits_mode ;