Skip to content

Commit

Permalink
added cycles_run during execute
Browse files Browse the repository at this point in the history
  • Loading branch information
cnvogelg committed Sep 26, 2024
1 parent 5e50217 commit 3a913ea
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 43 deletions.
132 changes: 95 additions & 37 deletions src/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,72 +18,112 @@
#define D(x)
#endif

static int end_flags;
static int execute_lock;
#define MAX_NESTING 16

#define RUN_MODE_IDLE 0
#define RUN_MODE_EXECUTE 1
#define RUN_MODE_DEFER_TRAP 2

typedef struct state {
int end_flags;
int cycles;
int run_mode;
int nesting;
} state_t;

static state_t states[MAX_NESTING];
static state_t *cur_state;
static int nesting;

static void init_state(state_t *state)
{
state->end_flags = 0;
state->cycles = 0;
state->run_mode = RUN_MODE_IDLE;
}

void cpu_init(void)
{
nesting = 0;
for(int i=0;i<MAX_NESTING;i++) {
states[i].nesting = i;
}

cur_state = &states[0];
init_state(cur_state);
}

void cpu_end(int flag)
{
if(end_flags == 0) {
if(cur_state->end_flags == 0) {
m68k_end_timeslice();
}

end_flags |= flag;
D((" cpu_end %08x\n", end_flags));
cur_state->end_flags |= flag;
D(("#%d cpu_end %08x\n", cur_state->nesting, cur_state->end_flags));
}

int cpu_execute(int max_cycles, int *got_cycles)
{
/* make sure we do not recurse while runnning m68k_execute()!
use deferred traps for that. */
if(execute_lock) {
if(cur_state->run_mode == RUN_MODE_EXECUTE) {
return CPU_END_RECURSE_EXECUTE;
}

int total_cycles = 0;
int local_end_flags = 0;
D(("exec loop begin\n"));
/* nesting */
int nested = 0;
if(cur_state->run_mode == RUN_MODE_DEFER_TRAP) {
if(nesting == (MAX_NESTING - 1)) {
return CPU_END_NESTING_TOO_DEEP;
}

nesting++;
cur_state = &states[nesting];
nested = 1;
}

init_state(cur_state);

D(("#%d exec loop begin\n", cur_state->nesting));
while(1) {
/* clear end flag for this run */
end_flags = 0;

/* set a lock */
execute_lock = 1;
cur_state->end_flags = 0;
cur_state->run_mode = RUN_MODE_EXECUTE;

/* call musashi CPU emulator.
callbacks triggered here might set end_flags and
end the time slice.
otherwise it will only return if the cycles are
used up.
*/
D((" begin execute. max=%d pc=%x\n", max_cycles, m68k_get_reg(NULL, M68K_REG_PC)));
int cycles = m68k_execute(max_cycles);
D((" end execute. cyc=%d pc=%x\n", cycles, m68k_get_reg(NULL, M68K_REG_PC)));

/* release lock */
execute_lock = 0;
D(("#%d begin execute. max=%d cycles=%d pc=%x\n",
cur_state->nesting, max_cycles, cur_state->cycles,
m68k_get_reg(NULL, M68K_REG_PC)));

total_cycles += cycles;
int cycles = m68k_execute(max_cycles);
cur_state->cycles += cycles;

/* copy end_flags into own local copy right now
since a deferred trap might call cpu_execute() recursively
and overwrite end_flags.
*/
local_end_flags = end_flags;
D(("#%d end execute. cyc=%d cycles=%d pc=%x\n",
cur_state->nesting, cycles, cur_state->cycles,
m68k_get_reg(NULL, M68K_REG_PC)));

/* if an error occurred then abort right now.
do not call any deferred traps.
the deferred trap is still there.
it may be called manually later on with trap_defer_call()
but usually you don't need it anyway.
*/
if(local_end_flags & CPU_END_ERROR_MASK) {
if(cur_state->end_flags & CPU_END_ERROR_MASK) {
break;
}

/* check for deferred trap */
if(local_end_flags & CPU_END_TRAP_DEFER) {
if(cur_state->end_flags & CPU_END_TRAP_DEFER) {
/* remove flag */
local_end_flags &= ~CPU_END_TRAP_DEFER;
cur_state->end_flags &= ~CPU_END_TRAP_DEFER;

cur_state->run_mode = RUN_MODE_DEFER_TRAP;

/* execute trap now deferred after execute().
here a recursive cpu_execute() might happen...
Expand All @@ -92,29 +132,47 @@ int cpu_execute(int max_cycles, int *got_cycles)

/* if trap failed then set error flag */
if(result != TRAP_RESULT_OK) {
local_end_flags |= CPU_END_TRAP_ERROR;
cur_state->end_flags |= CPU_END_TRAP_ERROR;
}
}

max_cycles -= cycles;

/* no more cycles left? */
if(max_cycles < cycles) {
local_end_flags |= CPU_END_MAX_CYCLES;
if(max_cycles <= 0) {
cur_state->end_flags |= CPU_END_MAX_CYCLES;
break;
}

/* end run? */
if(local_end_flags != 0) {
if(cur_state->end_flags != 0) {
break;
}

max_cycles -= cycles;
}
D(("exec loop end: %x\n", local_end_flags));
D(("#%d exec loop end: %x\n", cur_state->nesting, cur_state->end_flags));

/* return total cycles */
if(got_cycles != NULL) {
*got_cycles = total_cycles;
*got_cycles = cur_state->cycles;
}
int end_flags = cur_state->end_flags;

cur_state->cycles = 0;
cur_state->run_mode = RUN_MODE_IDLE;

if(nested) {
nesting--;
cur_state = &states[nesting];
}

return local_end_flags;
return end_flags;
}

int cpu_cycles_run(void)
{
int cycles = cur_state->cycles;
if(cur_state->run_mode == RUN_MODE_EXECUTE) {
cycles += m68k_cycles_run();
}
return cycles;
}
11 changes: 9 additions & 2 deletions src/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,18 @@ typedef unsigned int uint;
#define CPU_END_MEM_WRITE_FUNC_ERROR 0x0800

#define CPU_END_RECURSE_EXECUTE 0x1000
#define CPU_END_NESTING_TOO_DEEP 0x2000
#define CPU_END_ERROR_MASK 0xfff0

/* used by mem or trap internally only! */
extern void cpu_end(int flag);
extern void cpu_init(void);

/* return cycles (up to max_cycles) */
extern int cpu_execute(int max_cycles, int *got_cycles);

/* during an execute() call end the execution */
extern void cpu_end(int flag);

/* return cycles consumed so far during an execute() call */
extern int cpu_cycles_run(void);

#endif
3 changes: 3 additions & 0 deletions src/cpu.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ cdef extern from "cpu.h":
int CPU_END_MEM_WRITE_FUNC_ERROR

int CPU_END_RECURSE_EXECUTE
int CPU_END_NESTING_TOO_DEEP
int CPU_END_ERROR_MASK

void cpu_init()
void cpu_end(int flag)
int cpu_execute(int max_cycles, int *got_cycles);
int cpu_cycles_run()
1 change: 1 addition & 0 deletions src/m68k.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ cdef extern from "m68k.h":
void m68k_pulse_reset()
int m68k_execute(int num_cycles)
void m68k_end_timeslice()
int m68k_cycles_run()

unsigned int m68k_get_reg(void* context, m68k_register_t reg)
void m68k_set_reg(m68k_register_t reg, unsigned int value)
Expand Down
6 changes: 6 additions & 0 deletions src/pycpu.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ cdef class CPU:
def __cinit__(self, CPUType cpu_type):
m68k_set_cpu_type(<unsigned int>cpu_type)
m68k_init()
cpu_init()
self.cpu_type = cpu_type

def cleanup(self):
Expand Down Expand Up @@ -232,6 +233,8 @@ cdef class CPU:
# recursion?
if flags == CPU_END_RECURSE_EXECUTE:
raise RuntimeError("execute() called recursively")
elif flags == CPU_END_NESTING_TOO_DEEP:
raise RuntimeError("execute() nesting too deep")
# if execution was ended by an error then we assume run_exc was set
# and we will raise now the error in this function
elif (flags & CPU_END_ERROR_MASK) != 0:
Expand All @@ -242,6 +245,9 @@ cdef class CPU:
def end(self):
cpu_end(CPU_END_USER)

def cycles_run(self):
return cpu_cycles_run()

def set_pc_changed_callback(self, py_func):
global pc_changed_func
pc_changed_func = py_func
Expand Down
Loading

0 comments on commit 3a913ea

Please sign in to comment.