Get the emulator to the point where it'll start to run code; it then fails,

because the version of Musashi I imported doesn't support floating point...
This commit is contained in:
David Given 2018-06-05 23:17:22 +09:00
parent a8802c934b
commit 2cf39be752
3 changed files with 453 additions and 753 deletions

View file

@ -1,192 +1,193 @@
/* ======================================================================== */ /* ======================================================================== */
/* ========================= LICENSING & COPYRIGHT ======================== */ /* ========================= LICENSING & COPYRIGHT ======================== */
/* ======================================================================== */ /* ======================================================================== */
/* /*
* MUSASHI * MUSASHI
* Version 3.4 * Version 3.4
* *
* A portable Motorola M680x0 processor emulation engine. * A portable Motorola M680x0 processor emulation engine.
* Copyright 1998-2001 Karl Stenerud. All rights reserved. * Copyright 1998-2001 Karl Stenerud. All rights reserved.
* *
* This code may be freely used for non-commercial purposes as long as this * This code may be freely used for non-commercial purposes as long as this
* copyright notice remains unaltered in the source code and any binary files * copyright notice remains unaltered in the source code and any binary files
* containing this code in compiled form. * containing this code in compiled form.
* *
* All other lisencing terms must be negotiated with the author * All other lisencing terms must be negotiated with the author
* (Karl Stenerud). * (Karl Stenerud).
* *
* The latest version of this code can be obtained at: * The latest version of this code can be obtained at:
* http://kstenerud.cjb.net * http://kstenerud.cjb.net
*/ */
#ifndef M68KCONF__HEADER #ifndef M68KCONF__HEADER
#define M68KCONF__HEADER #define M68KCONF__HEADER
/* Configuration switches. /* Configuration switches.
* Use OPT_SPECIFY_HANDLER for configuration options that allow callbacks. * Use OPT_SPECIFY_HANDLER for configuration options that allow callbacks.
* OPT_SPECIFY_HANDLER causes the core to link directly to the function * OPT_SPECIFY_HANDLER causes the core to link directly to the function
* or macro you specify, rather than using callback functions whose pointer * or macro you specify, rather than using callback functions whose pointer
* must be passed in using m68k_set_xxx_callback(). * must be passed in using m68k_set_xxx_callback().
*/ */
#define OPT_OFF 0 #define OPT_OFF 0
#define OPT_ON 1 #define OPT_ON 1
#define OPT_SPECIFY_HANDLER 2 #define OPT_SPECIFY_HANDLER 2
/* ======================================================================== */ /* ======================================================================== */
/* ============================== MAME STUFF ============================== */ /* ============================== MAME STUFF ============================== */
/* ======================================================================== */ /* ======================================================================== */
/* If you're compiling this for MAME, only change M68K_COMPILE_FOR_MAME /* If you're compiling this for MAME, only change M68K_COMPILE_FOR_MAME
* to OPT_ON and use m68kmame.h to configure the 68k core. * to OPT_ON and use m68kmame.h to configure the 68k core.
*/ */
#ifndef M68K_COMPILE_FOR_MAME #ifndef M68K_COMPILE_FOR_MAME
#define M68K_COMPILE_FOR_MAME OPT_OFF #define M68K_COMPILE_FOR_MAME OPT_OFF
#endif /* M68K_COMPILE_FOR_MAME */ #endif /* M68K_COMPILE_FOR_MAME */
#if M68K_COMPILE_FOR_MAME == OPT_OFF #if M68K_COMPILE_FOR_MAME == OPT_OFF
/* ======================================================================== */ /* ======================================================================== */
/* ============================= CONFIGURATION ============================ */ /* ============================= CONFIGURATION ============================ */
/* ======================================================================== */ /* ======================================================================== */
/* Turn ON if you want to use the following M68K variants */ /* Turn ON if you want to use the following M68K variants */
#define M68K_EMULATE_010 OPT_ON #define M68K_EMULATE_010 OPT_ON
#define M68K_EMULATE_EC020 OPT_ON #define M68K_EMULATE_EC020 OPT_ON
#define M68K_EMULATE_020 OPT_ON #define M68K_EMULATE_020 OPT_ON
/* If ON, the CPU will call m68k_read_immediate_xx() for immediate addressing /* If ON, the CPU will call m68k_read_immediate_xx() for immediate addressing
* and m68k_read_pcrelative_xx() for PC-relative addressing. * and m68k_read_pcrelative_xx() for PC-relative addressing.
* If off, all read requests from the CPU will be redirected to m68k_read_xx() * If off, all read requests from the CPU will be redirected to m68k_read_xx()
*/ */
#define M68K_SEPARATE_READS OPT_OFF #define M68K_SEPARATE_READS OPT_OFF
/* If ON, the CPU will call m68k_write_32_pd() when it executes move.l with a /* If ON, the CPU will call m68k_write_32_pd() when it executes move.l with a
* predecrement destination EA mode instead of m68k_write_32(). * predecrement destination EA mode instead of m68k_write_32().
* To simulate real 68k behavior, m68k_write_32_pd() must first write the high * To simulate real 68k behavior, m68k_write_32_pd() must first write the high
* word to [address+2], and then write the low word to [address]. * word to [address+2], and then write the low word to [address].
*/ */
#define M68K_SIMULATE_PD_WRITES OPT_OFF #define M68K_SIMULATE_PD_WRITES OPT_OFF
/* If ON, CPU will call the interrupt acknowledge callback when it services an /* If ON, CPU will call the interrupt acknowledge callback when it services an
* interrupt. * interrupt.
* If off, all interrupts will be autovectored and all interrupt requests will * If off, all interrupts will be autovectored and all interrupt requests will
* auto-clear when the interrupt is serviced. * auto-clear when the interrupt is serviced.
*/ */
#define M68K_EMULATE_INT_ACK OPT_SPECIFY_HANDLER #define M68K_EMULATE_INT_ACK OPT_OFF
#define M68K_INT_ACK_CALLBACK(A) cpu_irq_ack(A) #define M68K_INT_ACK_CALLBACK(A) cpu_irq_ack(A)
/* If ON, CPU will call the breakpoint acknowledge callback when it encounters /* If ON, CPU will call the breakpoint acknowledge callback when it encounters
* a breakpoint instruction and it is running a 68010+. * a breakpoint instruction and it is running a 68010+.
*/ */
#define M68K_EMULATE_BKPT_ACK OPT_OFF #define M68K_EMULATE_BKPT_ACK OPT_OFF
#define M68K_BKPT_ACK_CALLBACK() your_bkpt_ack_handler_function() #define M68K_BKPT_ACK_CALLBACK() your_bkpt_ack_handler_function()
/* If ON, the CPU will monitor the trace flags and take trace exceptions /* If ON, the CPU will monitor the trace flags and take trace exceptions
*/ */
#define M68K_EMULATE_TRACE OPT_OFF #define M68K_EMULATE_TRACE OPT_OFF
/* If ON, CPU will call the output reset callback when it encounters a reset /* If ON, CPU will call the output reset callback when it encounters a reset
* instruction. * instruction.
*/ */
#define M68K_EMULATE_RESET OPT_SPECIFY_HANDLER #define M68K_EMULATE_RESET OPT_OFF
#define M68K_RESET_CALLBACK() cpu_pulse_reset() #define M68K_RESET_CALLBACK() cpu_pulse_reset()
/* If ON, CPU will call the set fc callback on every memory access to /* If ON, CPU will call the set fc callback on every memory access to
* differentiate between user/supervisor, program/data access like a real * differentiate between user/supervisor, program/data access like a real
* 68000 would. This should be enabled and the callback should be set if you * 68000 would. This should be enabled and the callback should be set if you
* want to properly emulate the m68010 or higher. (moves uses function codes * want to properly emulate the m68010 or higher. (moves uses function codes
* to read/write data from different address spaces) * to read/write data from different address spaces)
*/ */
#define M68K_EMULATE_FC OPT_SPECIFY_HANDLER #define M68K_EMULATE_FC OPT_OFF
#define M68K_SET_FC_CALLBACK(A) cpu_set_fc(A) #define M68K_SET_FC_CALLBACK(A) cpu_set_fc(A)
/* If ON, CPU will call the pc changed callback when it changes the PC by a /* If ON, CPU will call the pc changed callback when it changes the PC by a
* large value. This allows host programs to be nicer when it comes to * large value. This allows host programs to be nicer when it comes to
* fetching immediate data and instructions on a banked memory system. * fetching immediate data and instructions on a banked memory system.
*/ */
#define M68K_MONITOR_PC OPT_OFF #define M68K_MONITOR_PC OPT_OFF
#define M68K_SET_PC_CALLBACK(A) your_pc_changed_handler_function(A) #define M68K_SET_PC_CALLBACK(A) your_pc_changed_handler_function(A)
/* If ON, CPU will call the instruction hook callback before every /* If ON, CPU will call the instruction hook callback before every
* instruction. * instruction.
*/ */
#define M68K_INSTRUCTION_HOOK OPT_SPECIFY_HANDLER #define M68K_INSTRUCTION_HOOK OPT_SPECIFY_HANDLER
#define M68K_INSTRUCTION_CALLBACK() cpu_instr_callback() #define M68K_INSTRUCTION_CALLBACK() cpu_instr_callback()
/* If ON, the CPU will emulate the 4-byte prefetch queue of a real 68000 */ /* If ON, the CPU will emulate the 4-byte prefetch queue of a real 68000 */
#define M68K_EMULATE_PREFETCH OPT_ON #define M68K_EMULATE_PREFETCH OPT_ON
/* If ON, the CPU will generate address error exceptions if it tries to /* If ON, the CPU will generate address error exceptions if it tries to
* access a word or longword at an odd address. * access a word or longword at an odd address.
* NOTE: This is only emulated properly for 68000 mode. * NOTE: This is only emulated properly for 68000 mode.
*/ */
#define M68K_EMULATE_ADDRESS_ERROR OPT_ON #define M68K_EMULATE_ADDRESS_ERROR OPT_ON
/* Turn ON to enable logging of illegal instruction calls. /* Turn ON to enable logging of illegal instruction calls.
* M68K_LOG_FILEHANDLE must be #defined to a stdio file stream. * M68K_LOG_FILEHANDLE must be #defined to a stdio file stream.
* Turn on M68K_LOG_1010_1111 to log all 1010 and 1111 calls. * Turn on M68K_LOG_1010_1111 to log all 1010 and 1111 calls.
*/ */
#define M68K_LOG_ENABLE OPT_OFF #define M68K_LOG_ENABLE OPT_OFF
#define M68K_LOG_1010_1111 OPT_OFF #define M68K_LOG_1010_1111 OPT_OFF
#define M68K_LOG_FILEHANDLE some_file_handle #define M68K_LOG_FILEHANDLE stderr
/* ----------------------------- COMPATIBILITY ---------------------------- */ /* ----------------------------- COMPATIBILITY ---------------------------- */
/* The following options set optimizations that violate the current ANSI /* The following options set optimizations that violate the current ANSI
* standard, but will be compliant under the forthcoming C9X standard. * standard, but will be compliant under the forthcoming C9X standard.
*/ */
/* If ON, the enulation core will use 64-bit integers to speed up some /* If ON, the enulation core will use 64-bit integers to speed up some
* operations. * operations.
*/ */
#define M68K_USE_64_BIT OPT_OFF #define M68K_USE_64_BIT OPT_OFF
/* Set to your compiler's static inline keyword to enable it, or /* Set to your compiler's static inline keyword to enable it, or
* set it to blank to disable it. * set it to blank to disable it.
* If you define INLINE in the makefile, it will override this value. * If you define INLINE in the makefile, it will override this value.
* NOTE: not enabling inline functions will SEVERELY slow down emulation. * NOTE: not enabling inline functions will SEVERELY slow down emulation.
*/ */
#ifndef INLINE #ifndef INLINE
#define INLINE static __inline__ //#define INLINE static __inline__
#endif /* INLINE */ #define INLINE static
#endif /* INLINE */
#endif /* M68K_COMPILE_FOR_MAME */
#endif /* M68K_COMPILE_FOR_MAME */
#include "sim.h"
#include "sim.h"
#define m68k_read_memory_8(A) cpu_read_byte(A)
#define m68k_read_memory_16(A) cpu_read_word(A) #define m68k_read_memory_8(A) cpu_read_byte(A)
#define m68k_read_memory_32(A) cpu_read_long(A) #define m68k_read_memory_16(A) cpu_read_word(A)
#define m68k_read_memory_32(A) cpu_read_long(A)
#define m68k_read_disassembler_16(A) cpu_read_word_dasm(A)
#define m68k_read_disassembler_32(A) cpu_read_long_dasm(A) #define m68k_read_disassembler_16(A) cpu_read_word_dasm(A)
#define m68k_read_disassembler_32(A) cpu_read_long_dasm(A)
#define m68k_write_memory_8(A, V) cpu_write_byte(A, V)
#define m68k_write_memory_16(A, V) cpu_write_word(A, V) #define m68k_write_memory_8(A, V) cpu_write_byte(A, V)
#define m68k_write_memory_32(A, V) cpu_write_long(A, V) #define m68k_write_memory_16(A, V) cpu_write_word(A, V)
#define m68k_write_memory_32(A, V) cpu_write_long(A, V)
/* ======================================================================== */
/* ============================== END OF FILE ============================= */ /* ======================================================================== */
/* ======================================================================== */ /* ============================== END OF FILE ============================= */
/* ======================================================================== */
#endif /* M68KCONF__HEADER */
#endif /* M68KCONF__HEADER */

View file

@ -1,561 +1,253 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include <time.h> #include <time.h>
#include "sim.h" #include "sim.h"
#include "m68k.h" #include "m68k.h"
void disassemble_program(); void disassemble_program();
/* Memory-mapped IO ports */ #define ADDRESS_MASK 0xffffffff
#define INPUT_ADDRESS 0x800000 #define RAM_BASE 0x08000000
#define OUTPUT_ADDRESS 0x400000 #define RAM_TOP 0x08100000
/* IRQ connections */ #define INIT_SP RAM_TOP
#define IRQ_NMI_DEVICE 7 #define INIT_PC 0x08000054
#define IRQ_INPUT_DEVICE 2
#define IRQ_OUTPUT_DEVICE 1 /* Read/write macros */
#define READ_BYTE(BASE, ADDR) (BASE)[ADDR]
/* Time between characters sent to output device (seconds) */ #define READ_WORD(BASE, ADDR) (((BASE)[ADDR]<<8) | \
#define OUTPUT_DEVICE_PERIOD 1 (BASE)[(ADDR)+1])
#define READ_LONG(BASE, ADDR) (((BASE)[ADDR]<<24) | \
/* ROM and RAM sizes */ ((BASE)[(ADDR)+1]<<16) | \
#define MAX_ROM 0xfff ((BASE)[(ADDR)+2]<<8) | \
#define MAX_RAM 0xff (BASE)[(ADDR)+3])
#define WRITE_BYTE(BASE, ADDR, VAL) (BASE)[ADDR] = (VAL)&0xff
/* Read/write macros */ #define WRITE_WORD(BASE, ADDR, VAL) (BASE)[ADDR] = ((VAL)>>8) & 0xff; \
#define READ_BYTE(BASE, ADDR) (BASE)[ADDR] (BASE)[(ADDR)+1] = (VAL)&0xff
#define READ_WORD(BASE, ADDR) (((BASE)[ADDR]<<8) | \ #define WRITE_LONG(BASE, ADDR, VAL) (BASE)[ADDR] = ((VAL)>>24) & 0xff; \
(BASE)[(ADDR)+1]) (BASE)[(ADDR)+1] = ((VAL)>>16)&0xff; \
#define READ_LONG(BASE, ADDR) (((BASE)[ADDR]<<24) | \ (BASE)[(ADDR)+2] = ((VAL)>>8)&0xff; \
((BASE)[(ADDR)+1]<<16) | \ (BASE)[(ADDR)+3] = (VAL)&0xff
((BASE)[(ADDR)+2]<<8) | \
(BASE)[(ADDR)+3])
static void exit_error(char* fmt, ...);
#define WRITE_BYTE(BASE, ADDR, VAL) (BASE)[ADDR] = (VAL)&0xff static void syscall(void);
#define WRITE_WORD(BASE, ADDR, VAL) (BASE)[ADDR] = ((VAL)>>8) & 0xff; \
(BASE)[(ADDR)+1] = (VAL)&0xff unsigned int cpu_read_byte(unsigned int address);
#define WRITE_LONG(BASE, ADDR, VAL) (BASE)[ADDR] = ((VAL)>>24) & 0xff; \ unsigned int cpu_read_word(unsigned int address);
(BASE)[(ADDR)+1] = ((VAL)>>16)&0xff; \ unsigned int cpu_read_long(unsigned int address);
(BASE)[(ADDR)+2] = ((VAL)>>8)&0xff; \ void cpu_write_byte(unsigned int address, unsigned int value);
(BASE)[(ADDR)+3] = (VAL)&0xff void cpu_write_word(unsigned int address, unsigned int value);
void cpu_write_long(unsigned int address, unsigned int value);
/* Prototypes */ unsigned char g_ram[RAM_TOP - RAM_BASE];
void exit_error(char* fmt, ...);
unsigned int cpu_read_byte(unsigned int address); /* Exit with an error message. Use printf syntax. */
unsigned int cpu_read_word(unsigned int address); void exit_error(char* fmt, ...)
unsigned int cpu_read_long(unsigned int address); {
void cpu_write_byte(unsigned int address, unsigned int value); static int guard_val = 0;
void cpu_write_word(unsigned int address, unsigned int value); char buff[100];
void cpu_write_long(unsigned int address, unsigned int value); unsigned int pc;
void cpu_pulse_reset(void); va_list args;
void cpu_set_fc(unsigned int fc);
int cpu_irq_ack(int level); if(guard_val)
return;
void nmi_device_reset(void); else
void nmi_device_update(void); guard_val = 1;
int nmi_device_ack(void);
va_start(args, fmt);
void input_device_reset(void); vfprintf(stderr, fmt, args);
void input_device_update(void); va_end(args);
int input_device_ack(void); fprintf(stderr, "\n");
unsigned int input_device_read(void); pc = m68k_get_reg(NULL, M68K_REG_PPC);
void input_device_write(unsigned int value); m68k_disassemble(buff, pc, M68K_CPU_TYPE_68000);
fprintf(stderr, "At %04x: %s\n", pc, buff);
void output_device_reset(void);
void output_device_update(void); exit(EXIT_FAILURE);
int output_device_ack(void); }
unsigned int output_device_read(void);
void output_device_write(unsigned int value); static inline unsigned int transform_address(unsigned int address)
{
void int_controller_set(unsigned int value); unsigned int i = (address & ADDRESS_MASK) - RAM_BASE;
void int_controller_clear(unsigned int value); if (i >= (unsigned int)(RAM_TOP - RAM_BASE))
exit_error("Attempted to read from RAM address %08x %08x", address, i);
void get_user_input(void); return i;
}
/* Data */ unsigned int cpu_read_long(unsigned int address)
unsigned int g_quit = 0; /* 1 if we want to quit */ {
unsigned int g_nmi = 0; /* 1 if nmi pending */ switch (address)
{
int g_input_device_value = -1; /* Current value in input device */ case 0x00: return INIT_SP;
case 0x04: return INIT_PC;
unsigned int g_output_device_ready = 0; /* 1 if output device is ready */ case 0x80: syscall(); return 0x10000;
time_t g_output_device_last_output; /* Time of last char output */ case 0x10000: return 0x4e73; /* rte */
case 0x10004: return 0;
unsigned int g_int_controller_pending = 0; /* list of pending interrupts */ default: return READ_LONG(g_ram, transform_address(address));
unsigned int g_int_controller_highest_int = 0; /* Highest pending interrupt */ }
}
unsigned char g_rom[MAX_ROM+1]; /* ROM */
unsigned char g_ram[MAX_RAM+1]; /* RAM */
unsigned int g_fc; /* Current function code from CPU */ unsigned int cpu_read_word(unsigned int address)
{
unsigned int l = cpu_read_long(address & ~3);
/* Exit with an error message. Use printf syntax. */ l >>= (address & 2) * 8;
void exit_error(char* fmt, ...) return l & 0xffff;
{ }
static int guard_val = 0;
char buff[100]; unsigned int cpu_read_byte(unsigned int address)
unsigned int pc; {
va_list args; unsigned int l = cpu_read_long(address & ~3);
l >>= (address & 3) * 8;
if(guard_val) return l & 0xff;
return; }
else
guard_val = 1; unsigned int cpu_read_word_dasm(unsigned int address)
{
va_start(args, fmt); return cpu_read_word(address);
vfprintf(stderr, fmt, args); }
va_end(args);
fprintf(stderr, "\n"); unsigned int cpu_read_long_dasm(unsigned int address)
pc = m68k_get_reg(NULL, M68K_REG_PPC); {
m68k_disassemble(buff, pc, M68K_CPU_TYPE_68000); return cpu_read_long(address);
fprintf(stderr, "At %04x: %s\n", pc, buff); }
exit(EXIT_FAILURE);
} /* Write data to RAM or a device */
void cpu_write_byte(unsigned int address, unsigned int value)
{
/* Read data from RAM, ROM, or a device */ WRITE_BYTE(g_ram, transform_address(address), value);
unsigned int cpu_read_byte(unsigned int address) }
{
if(g_fc & 2) /* Program */ void cpu_write_word(unsigned int address, unsigned int value)
{ {
if(address > MAX_ROM) WRITE_WORD(g_ram, transform_address(address), value);
exit_error("Attempted to read byte from ROM address %08x", address); }
return READ_BYTE(g_rom, address);
} void cpu_write_long(unsigned int address, unsigned int value)
{
/* Otherwise it's data space */ WRITE_LONG(g_ram, transform_address(address), value);
switch(address) }
{
case INPUT_ADDRESS: /* Disassembler */
return input_device_read(); void make_hex(char* buff, unsigned int pc, unsigned int length)
case OUTPUT_ADDRESS: {
return output_device_read(); char* ptr = buff;
default:
break; for(;length>0;length -= 2)
} {
if(address > MAX_RAM) sprintf(ptr, "%04x", cpu_read_word_dasm(pc));
exit_error("Attempted to read byte from RAM address %08x", address); pc += 2;
return READ_BYTE(g_ram, address); ptr += 4;
} if(length > 2)
*ptr++ = ' ';
unsigned int cpu_read_word(unsigned int address) }
{ }
if(g_fc & 2) /* Program */
{ void disassemble_program()
if(address > MAX_ROM) {
exit_error("Attempted to read word from ROM address %08x", address); unsigned int pc;
return READ_WORD(g_rom, address); unsigned int instr_size;
} char buff[100];
char buff2[100];
/* Otherwise it's data space */
switch(address) pc = cpu_read_long_dasm(4);
{
case INPUT_ADDRESS: while(pc <= 0x16e)
return input_device_read(); {
case OUTPUT_ADDRESS: instr_size = m68k_disassemble(buff, pc, M68K_CPU_TYPE_68000);
return output_device_read(); make_hex(buff2, pc, instr_size);
default: printf("%03x: %-20s: %s\n", pc, buff2, buff);
break; pc += instr_size;
} }
if(address > MAX_RAM) fflush(stdout);
exit_error("Attempted to read word from RAM address %08x", address); }
return READ_WORD(g_ram, address);
} void cpu_instr_callback()
{
unsigned int cpu_read_long(unsigned int address) /* The following code would print out instructions as they are executed */
{
if(g_fc & 2) /* Program */ #if 1
{ static char buff[100];
if(address > MAX_ROM) static char buff2[100];
exit_error("Attempted to read long from ROM address %08x", address); static unsigned int pc;
return READ_LONG(g_rom, address); static unsigned int instr_size;
}
pc = m68k_get_reg(NULL, M68K_REG_PC);
/* Otherwise it's data space */ instr_size = m68k_disassemble(buff, pc, M68K_CPU_TYPE_68020);
switch(address) make_hex(buff2, pc, instr_size);
{ printf("E %03x: %-20s: %s\n", pc, buff2, buff);
case INPUT_ADDRESS: fflush(stdout);
return input_device_read(); #endif
case OUTPUT_ADDRESS: }
return output_device_read();
default: static void syscall(void)
break; {
} int s = m68k_get_reg(NULL, M68K_REG_D0);
if(address > MAX_RAM) switch (s)
exit_error("Attempted to read long from RAM address %08x", address); {
return READ_LONG(g_ram, address); case 45: /* brk */
} m68k_set_reg(M68K_REG_D0, RAM_TOP-0x1000);
break;
unsigned int cpu_read_word_dasm(unsigned int address) default:
{ exit_error("unknown system call %d", s);
if(address > MAX_ROM) }
exit_error("Disassembler attempted to read word from ROM address %08x", address); }
return READ_WORD(g_rom, address);
} /* The main loop */
int main(int argc, char* argv[])
unsigned int cpu_read_long_dasm(unsigned int address) {
{ FILE* fhandle;
if(address > MAX_ROM)
exit_error("Dasm attempted to read long from ROM address %08x", address); if(argc != 2)
return READ_LONG(g_rom, address); {
} printf("Usage: sim <program file>\n");
exit(-1);
}
/* Write data to RAM or a device */
void cpu_write_byte(unsigned int address, unsigned int value) if((fhandle = fopen(argv[1], "rb")) == NULL)
{ exit_error("Unable to open %s", argv[1]);
if(g_fc & 2) /* Program */
exit_error("Attempted to write %02x to ROM address %08x", value&0xff, address); if(fread(g_ram, 1, RAM_TOP - RAM_BASE, fhandle) <= 0)
exit_error("Error reading %s", argv[1]);
/* Otherwise it's data space */
switch(address) // disassemble_program();
{
case INPUT_ADDRESS: m68k_init();
input_device_write(value&0xff); m68k_set_cpu_type(M68K_CPU_TYPE_68020);
return; m68k_pulse_reset();
case OUTPUT_ADDRESS:
output_device_write(value&0xff); /* On entry, the Linux stack looks like this.
return; *
default: * sp+.. NULL
break; * sp+8+(4*argc) env (X quads)
} * sp+4+(4*argc) NULL
if(address > MAX_RAM) * sp+4 argv (argc quads)
exit_error("Attempted to write %02x to RAM address %08x", value&0xff, address); * sp argc
WRITE_BYTE(g_ram, address, value); *
} * We'll set it up with a bodgy stack frame with argc=0 just to keep the
* startup code happy.
void cpu_write_word(unsigned int address, unsigned int value) */
{
if(g_fc & 2) /* Program */ {
exit_error("Attempted to write %04x to ROM address %08x", value&0xffff, address); unsigned int sp = INIT_SP;
cpu_write_long(sp -= 4, 0);
/* Otherwise it's data space */ unsigned int envp = sp;
switch(address) cpu_write_long(sp -= 4, envp);
{ cpu_write_long(sp -= 4, 0);
case INPUT_ADDRESS: unsigned long argv = sp;
input_device_write(value&0xffff); cpu_write_long(sp -= 4, argv);
return; cpu_write_long(sp -= 4, 0);
case OUTPUT_ADDRESS: m68k_set_reg(M68K_REG_SP, sp);
output_device_write(value&0xffff); }
return;
default: for (;;)
break; m68k_execute(100000);
}
if(address > MAX_RAM) return 0;
exit_error("Attempted to write %04x to RAM address %08x", value&0xffff, address); }
WRITE_WORD(g_ram, address, value);
}
void cpu_write_long(unsigned int address, unsigned int value)
{
if(g_fc & 2) /* Program */
exit_error("Attempted to write %08x to ROM address %08x", value, address);
/* Otherwise it's data space */
switch(address)
{
case INPUT_ADDRESS:
input_device_write(value);
return;
case OUTPUT_ADDRESS:
output_device_write(value);
return;
default:
break;
}
if(address > MAX_RAM)
exit_error("Attempted to write %08x to RAM address %08x", value, address);
WRITE_LONG(g_ram, address, value);
}
/* Called when the CPU pulses the RESET line */
void cpu_pulse_reset(void)
{
nmi_device_reset();
output_device_reset();
input_device_reset();
}
/* Called when the CPU changes the function code pins */
void cpu_set_fc(unsigned int fc)
{
g_fc = fc;
}
/* Called when the CPU acknowledges an interrupt */
int cpu_irq_ack(int level)
{
switch(level)
{
case IRQ_NMI_DEVICE:
return nmi_device_ack();
case IRQ_INPUT_DEVICE:
return input_device_ack();
case IRQ_OUTPUT_DEVICE:
return output_device_ack();
}
return M68K_INT_ACK_SPURIOUS;
}
/* Implementation for the NMI device */
void nmi_device_reset(void)
{
g_nmi = 0;
}
void nmi_device_update(void)
{
if(g_nmi)
{
g_nmi = 0;
int_controller_set(IRQ_NMI_DEVICE);
}
}
int nmi_device_ack(void)
{
printf("\nNMI\n");fflush(stdout);
int_controller_clear(IRQ_NMI_DEVICE);
return M68K_INT_ACK_AUTOVECTOR;
}
/* Implementation for the input device */
void input_device_reset(void)
{
g_input_device_value = -1;
int_controller_clear(IRQ_INPUT_DEVICE);
}
void input_device_update(void)
{
if(g_input_device_value >= 0)
int_controller_set(IRQ_INPUT_DEVICE);
}
int input_device_ack(void)
{
return M68K_INT_ACK_AUTOVECTOR;
}
unsigned int input_device_read(void)
{
int value = g_input_device_value > 0 ? g_input_device_value : 0;
int_controller_clear(IRQ_INPUT_DEVICE);
g_input_device_value = -1;
return value;
}
void input_device_write(unsigned int value)
{
}
/* Implementation for the output device */
void output_device_reset(void)
{
g_output_device_last_output = time(NULL);
g_output_device_ready = 0;
int_controller_clear(IRQ_OUTPUT_DEVICE);
}
void output_device_update(void)
{
if(!g_output_device_ready)
{
if((time(NULL) - g_output_device_last_output) >= OUTPUT_DEVICE_PERIOD)
{
g_output_device_ready = 1;
int_controller_set(IRQ_OUTPUT_DEVICE);
}
}
}
int output_device_ack(void)
{
return M68K_INT_ACK_AUTOVECTOR;
}
unsigned int output_device_read(void)
{
int_controller_clear(IRQ_OUTPUT_DEVICE);
return 0;
}
void output_device_write(unsigned int value)
{
char ch;
if(g_output_device_ready)
{
ch = value & 0xff;
printf("%c", ch);
g_output_device_last_output = time(NULL);
g_output_device_ready = 0;
int_controller_clear(IRQ_OUTPUT_DEVICE);
}
}
/* Implementation for the interrupt controller */
void int_controller_set(unsigned int value)
{
unsigned int old_pending = g_int_controller_pending;
g_int_controller_pending |= (1<<value);
if(old_pending != g_int_controller_pending && value > g_int_controller_highest_int)
{
g_int_controller_highest_int = value;
m68k_set_irq(g_int_controller_highest_int);
}
}
void int_controller_clear(unsigned int value)
{
g_int_controller_pending &= ~(1<<value);
for(g_int_controller_highest_int = 7;g_int_controller_highest_int > 0;g_int_controller_highest_int--)
if(g_int_controller_pending & (1<<g_int_controller_highest_int))
break;
m68k_set_irq(g_int_controller_highest_int);
}
/* Parse user input and update any devices that need user input */
void get_user_input(void)
{
static int last_ch = -1;
int ch = -1; /* not supported */
//int ch = osd_get_char();
if(ch >= 0)
{
switch(ch)
{
case 0x1b:
g_quit = 1;
break;
case '~':
if(last_ch != ch)
g_nmi = 1;
break;
default:
g_input_device_value = ch;
}
}
last_ch = ch;
}
/* Disassembler */
void make_hex(char* buff, unsigned int pc, unsigned int length)
{
char* ptr = buff;
for(;length>0;length -= 2)
{
sprintf(ptr, "%04x", cpu_read_word_dasm(pc));
pc += 2;
ptr += 4;
if(length > 2)
*ptr++ = ' ';
}
}
void disassemble_program()
{
unsigned int pc;
unsigned int instr_size;
char buff[100];
char buff2[100];
pc = cpu_read_long_dasm(4);
while(pc <= 0x16e)
{
instr_size = m68k_disassemble(buff, pc, M68K_CPU_TYPE_68000);
make_hex(buff2, pc, instr_size);
printf("%03x: %-20s: %s\n", pc, buff2, buff);
pc += instr_size;
}
fflush(stdout);
}
void cpu_instr_callback()
{
/* The following code would print out instructions as they are executed */
/*
static char buff[100];
static char buff2[100];
static unsigned int pc;
static unsigned int instr_size;
pc = m68k_get_reg(NULL, M68K_REG_PC);
instr_size = m68k_disassemble(buff, pc, M68K_CPU_TYPE_68000);
make_hex(buff2, pc, instr_size);
printf("E %03x: %-20s: %s\n", pc, buff2, buff);
fflush(stdout);
*/
}
/* The main loop */
int main(int argc, char* argv[])
{
FILE* fhandle;
if(argc != 2)
{
printf("Usage: sim <program file>\n");
exit(-1);
}
if((fhandle = fopen(argv[1], "rb")) == NULL)
exit_error("Unable to open %s", argv[1]);
if(fread(g_rom, 1, MAX_ROM+1, fhandle) <= 0)
exit_error("Error reading %s", argv[1]);
// disassemble_program();
m68k_init();
m68k_set_cpu_type(M68K_CPU_TYPE_68000);
m68k_pulse_reset();
input_device_reset();
output_device_reset();
nmi_device_reset();
g_quit = 0;
while(!g_quit)
{
// Our loop requires some interleaving to allow us to update the
// input, output, and nmi devices.
get_user_input();
// Values to execute determine the interleave rate.
// Smaller values allow for more accurate interleaving with multiple
// devices/CPUs but is more processor intensive.
// 100000 is usually a good value to start at, then work from there.
// Note that I am not emulating the correct clock speed!
m68k_execute(100000);
output_device_update();
input_device_update();
nmi_device_update();
}
return 0;
}

View file

@ -0,0 +1,7 @@
include("tests/plat/build.lua")
plat_testsuite {
name = "tests",
plat = "linux68k",
method = "plat/linux68k/emu+emu68k"
}