syn68k/runtime/init.c

137 lines
3.5 KiB
C

#include "config.h"
#include "syn68k_private.h"
#include "hash.h"
#include "rangetree.h"
#include "callback.h"
#include "trap.h"
#include "alloc.h"
#include "mapping.h"
#include "translate.h"
#include "native.h"
#include "checksum.h"
#include "deathqueue.h"
#include "interrupt.h"
#ifdef USE_BIOS_TIMER
#include "go32.h"
#include "dpmi.h"
#endif /* USE_BIOS_TIMER */
#include <assert.h>
#include <string.h>
/* Global CPU state struct. */
CPUState cpu_state;
#if SIZEOF_CHAR_P == 4
uint32 ROMlib_offset;
#else
uint64 ROMlib_offset;
#endif
/* This function initializes syn68k. Call it exactly once, before any
* other syn68k calls. DOS_INT_FLAG_ADDR is the conventional memory
* offset of the 32 bit synchronous interrupt flag. Just pass in zero
* for the non-MSDOS and non-SYNCHRONOUS_INTERRUPTS cases.
*/
void
initialize_68k_emulator (void (*while_busy)(int), int native_p,
uint32 trap_vector_storage[64],
uint32 dos_int_flag_addr)
{
static uint16 rte =
#ifdef LITTLEENDIAN
0x734E;
#else
0x4E73;
#endif
Block *b;
uint16 *code;
#ifdef __CHECKER__
/* Checker can't work with native code. */
native_p = FALSE;
#endif
/* Zero out CPU state (not necessary since statics are 0'd) */
memset (&cpu_state, 0, sizeof cpu_state);
memset (&cpu_state.jsr_stack, -1, sizeof cpu_state.jsr_stack);
/* Record the function to periodically call while we are busy doing stuff. */
call_while_busy_func = while_busy;
#ifdef GENERATE_NATIVE_CODE
native_code_p = native_p;
#endif
trap_vector_array = trap_vector_storage;
/* Set up the status register & interrupt stack pointer. */
cpu_state.sr = 0x2000; /* supervisor/interrupt mode (this appears
* to be what programs really expect, e.g.
* PGA Tour Golf does movew #8192,sr).
*/
cpu_state.usp = 0xDEADF00D; /* Never use this stack pointer! */
cpu_state.msp = 0xDEAD0666; /* Never use this stack pointer! */
#ifdef USE_BIOS_TIMER
dos_memory_selector = _go32_conventional_mem_selector ();
assert (dos_int_flag_addr != 0);
dos_interrupt_flag_addr = dos_int_flag_addr;
#endif /* USE_BIOS_TIMER */
#ifdef SYNCHRONOUS_INTERRUPTS
SET_INTERRUPT_STATUS (INTERRUPT_STATUS_UNCHANGED);
#endif
/* Call various initialization routines. */
hash_init ();
range_tree_init ();
callback_init ();
trap_init ();
#ifdef GENERATE_NATIVE_CODE
native_code_init ();
#endif /* GENERATE_NATIVE_CODE */
/* Create the magical block that exits the emulator if you ever
* jump to it. Don't add it to the death queue, since we never want
* this block to go away.
*/
b = make_artificial_block (NULL, MAGIC_EXIT_EMULATOR_ADDRESS,
OPCODE_WORDS, &code);
#ifdef USE_DIRECT_DISPATCH
*(const void **)code = direct_dispatch_table[0];
#else
*(const void **)code = (const void *)0; /* Exit emulator opc. */
#endif
hash_insert (b);
range_tree_insert (b);
/* Create the magical block that contains an RTE. */
b = NULL;
#if SIZEOF_CHAR_P != 8
generate_block (NULL, US_TO_SYN68K (&rte), &b, TRUE);
#else
{
typeof (ROMlib_offset) save_offset;
save_offset = ROMlib_offset;
ROMlib_offset = &rte; /* so the RTE will be reachable with 32 bit addr */
generate_block (NULL, US_TO_SYN68K (&rte), &b, TRUE);
ROMlib_offset = save_offset;
}
#endif
assert (b != NULL);
hash_remove (b);
range_tree_remove (b);
death_queue_dequeue (b);
b->m68k_start_address = MAGIC_RTE_ADDRESS;
b->m68k_code_length = 1;
b->checksum = compute_block_checksum (b);
b->immortal = TRUE;
hash_insert (b);
range_tree_insert (b);
}