3 @ SekRunPS runs PicoCpu and PicoCpuS68k interleaved in steps of PS_STEP_M68K
4 @ cycles. This is done without calling CycloneRun and jumping directly to
5 @ Cyclone code to avoid pushing/popping all the registers every time.
7 @ (c) Copyright 2007, Grazvydas "notaz" Ignotas
11 .equiv PS_STEP_M68K, ((488<<16)/20) @ ~24
13 @ .extern is ignored by gas, we add these here just to see what we depend on.
14 .extern CycloneJumpTab
15 .extern CycloneDoInterrupt
20 .extern SekCycleAimS68k
21 .extern SekCycleCntS68k
28 .global SekRunPS @ cyc_m68k, cyc_s68k
31 stmfd sp!, {r4-r11,lr}
32 sub sp, sp, #2*4 @ sp[0] = main_cycle_cnt, sp[4] = run_cycle_cnt
34 @ override CycloneEnd for both contexts
37 ldr r2, =CycloneEnd_M68k
38 ldr r3, =CycloneEnd_S68k
44 ldr r9, =SekCycleAimS68k
53 ldr r0, =((488<<16)-PS_STEP_M68K)
54 ldr r6, =CycloneJumpTab
56 @ schedule m68k for the first time..
58 str r0, [sp] @ main target 'left cycle' counter
60 subs r5, r1, r0, asr #16
61 ble schedule_s68k @ m68k has not enough cycles
63 str r5, [sp,#4] @ run_cycle_cnt
70 ldr r0, [sp,#4] @ run_cycle_cnt
72 str r4, [r7,#0x40] ;@ Save Current PC + Memory Base
73 strb r9, [r7,#0x46] ;@ Save Flags (NZCV)
74 sub r0, r0, r5 @ subtract leftover cycles (which should be negative)
79 ldr r8, =SekCycleCntS68k
80 ldr r9, =SekCycleAimS68k
87 add r3, r3, r2, asr #1
88 add r3, r3, r2, asr #3 @ cycn_s68k = (cycn + cycn/2 + cycn/8)
90 subs r5, r0, r3, asr #16
91 ble schedule_m68k @ s68k has not enough cycles
94 str r5, [sp,#4] @ run_cycle_cnt
100 ldr r3, =SekCycleCntS68k
101 ldr r0, [sp,#4] @ run_cycle_cnt
103 str r4, [r7,#0x40] ;@ Save Current PC + Memory Base
104 strb r9, [r7,#0x46] ;@ Save Flags (NZCV)
105 sub r0, r0, r5 @ subtract leftover cycles (should be negative)
110 ldr r1, =PS_STEP_M68K
111 ldr r3, [sp] @ main_cycle_cnt
119 str r3, [sp] @ update main_cycle_cnt
122 subs r5, r0, r3, asr #16
123 ble schedule_s68k @ m68k has not enough cycles
126 str r5, [sp,#4] @ run_cycle_cnt
135 str r0, [r7,#0x54] @ remove CycloneEnd handler
139 ldmfd sp!, {r4-r11,pc}
145 ;@ r0-3 = Temporary registers
146 ldr r4,[r7,#0x40] ;@ r4 = Current PC + Memory Base
148 ;@ r6 = Opcode Jump table
149 ;@ r7 = Pointer to Cpu Context
150 ;@ r8 = Current Opcode
151 ldrb r9,[r7,#0x46] ;@ r9 = Flags (NZCV)
152 ldr r1,[r7,#0x44] ;@ get SR high and IRQ level
153 orr r9,r9,r9,lsl #28 ;@ r9 = Flags 0xf0000000, cpsr format
154 ;@ r10 = Source value / Memory Base
157 movs r0,r1,lsr #24 ;@ Get IRQ level
160 andle r1,r1,#7 ;@ Get interrupt mask
161 cmple r0,r1 ;@ irq<=6: Is irq<=mask ?
162 ldrgt lr,[r7,#0x54] @ Interrupt will definitely use more cycles than our step,
163 bgt CycloneDoInterrupt @ so make this function return directly to CycloneEnd_*
166 ;@ Check if our processor is in stopped state and jump to opcode handler if not
168 ldrh r8,[r4],#2 ;@ Fetch first opcode
169 tst r0,r0 ;@ stopped?
170 andeq r9,r9,#0xf0000000
171 ldreq pc,[r6,r8,asl #2] ;@ Jump to opcode handler