Crudely beat the standard Masushi simulator into working in the ACK framework.
This commit is contained in:
parent
d908f9cfb2
commit
5034ed1c39
56
plat/linux68k/emu/build.lua
Normal file
56
plat/linux68k/emu/build.lua
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
cprogram {
|
||||||
|
name = "m68kmake",
|
||||||
|
srcs = {
|
||||||
|
"./musashi/m68kmake.c"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
normalrule {
|
||||||
|
name = "m68k_engine",
|
||||||
|
ins = {
|
||||||
|
"+m68kmake",
|
||||||
|
"./musashi/m68k_in.c",
|
||||||
|
"./musashi/m68kcpu.h",
|
||||||
|
"./m68kconf.h",
|
||||||
|
"./musashi/m68kcpu.c",
|
||||||
|
"./musashi/m68kdasm.c",
|
||||||
|
},
|
||||||
|
outleaves = {
|
||||||
|
"m68kopac.c",
|
||||||
|
"m68kopdm.c",
|
||||||
|
"m68kopnz.c",
|
||||||
|
"m68kops.c",
|
||||||
|
"m68kops.h",
|
||||||
|
"m68kcpu.h",
|
||||||
|
"m68kconf.h",
|
||||||
|
"m68kcpu.c",
|
||||||
|
"m68kdasm.c",
|
||||||
|
},
|
||||||
|
commands = {
|
||||||
|
"cp %{ins[2]} %{ins[3]} %{ins[4]} %{ins[5]} %{ins[6]} %{dir}",
|
||||||
|
"cd %{dir} && %{ins[1]}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clibrary {
|
||||||
|
name = "headers",
|
||||||
|
srcs = {},
|
||||||
|
hdrs = {
|
||||||
|
matching(filenamesof("+m68k_engine"), "%.h$"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cprogram {
|
||||||
|
name = "emu68k",
|
||||||
|
vars = {
|
||||||
|
["+cflags"] = {"-DM68K_COMPILE_FOR_MAME=0"}
|
||||||
|
},
|
||||||
|
srcs = {
|
||||||
|
"./sim.c",
|
||||||
|
matching(filenamesof("+m68k_engine"), "%.c$"),
|
||||||
|
},
|
||||||
|
deps = {
|
||||||
|
"+headers",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
192
plat/linux68k/emu/m68kconf.h
Executable file
192
plat/linux68k/emu/m68kconf.h
Executable file
|
@ -0,0 +1,192 @@
|
||||||
|
/* ======================================================================== */
|
||||||
|
/* ========================= LICENSING & COPYRIGHT ======================== */
|
||||||
|
/* ======================================================================== */
|
||||||
|
/*
|
||||||
|
* MUSASHI
|
||||||
|
* Version 3.4
|
||||||
|
*
|
||||||
|
* A portable Motorola M680x0 processor emulation engine.
|
||||||
|
* Copyright 1998-2001 Karl Stenerud. All rights reserved.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* containing this code in compiled form.
|
||||||
|
*
|
||||||
|
* All other lisencing terms must be negotiated with the author
|
||||||
|
* (Karl Stenerud).
|
||||||
|
*
|
||||||
|
* The latest version of this code can be obtained at:
|
||||||
|
* http://kstenerud.cjb.net
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef M68KCONF__HEADER
|
||||||
|
#define M68KCONF__HEADER
|
||||||
|
|
||||||
|
|
||||||
|
/* Configuration switches.
|
||||||
|
* Use OPT_SPECIFY_HANDLER for configuration options that allow callbacks.
|
||||||
|
* OPT_SPECIFY_HANDLER causes the core to link directly to the function
|
||||||
|
* or macro you specify, rather than using callback functions whose pointer
|
||||||
|
* must be passed in using m68k_set_xxx_callback().
|
||||||
|
*/
|
||||||
|
#define OPT_OFF 0
|
||||||
|
#define OPT_ON 1
|
||||||
|
#define OPT_SPECIFY_HANDLER 2
|
||||||
|
|
||||||
|
|
||||||
|
/* ======================================================================== */
|
||||||
|
/* ============================== MAME STUFF ============================== */
|
||||||
|
/* ======================================================================== */
|
||||||
|
|
||||||
|
/* 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.
|
||||||
|
*/
|
||||||
|
#ifndef M68K_COMPILE_FOR_MAME
|
||||||
|
#define M68K_COMPILE_FOR_MAME OPT_OFF
|
||||||
|
#endif /* M68K_COMPILE_FOR_MAME */
|
||||||
|
|
||||||
|
|
||||||
|
#if M68K_COMPILE_FOR_MAME == OPT_OFF
|
||||||
|
|
||||||
|
|
||||||
|
/* ======================================================================== */
|
||||||
|
/* ============================= CONFIGURATION ============================ */
|
||||||
|
/* ======================================================================== */
|
||||||
|
|
||||||
|
/* Turn ON if you want to use the following M68K variants */
|
||||||
|
#define M68K_EMULATE_010 OPT_ON
|
||||||
|
#define M68K_EMULATE_EC020 OPT_ON
|
||||||
|
#define M68K_EMULATE_020 OPT_ON
|
||||||
|
|
||||||
|
|
||||||
|
/* If ON, the CPU will call m68k_read_immediate_xx() for immediate 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()
|
||||||
|
*/
|
||||||
|
#define M68K_SEPARATE_READS OPT_OFF
|
||||||
|
|
||||||
|
/* 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().
|
||||||
|
* 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].
|
||||||
|
*/
|
||||||
|
#define M68K_SIMULATE_PD_WRITES OPT_OFF
|
||||||
|
|
||||||
|
/* If ON, CPU will call the interrupt acknowledge callback when it services an
|
||||||
|
* interrupt.
|
||||||
|
* If off, all interrupts will be autovectored and all interrupt requests will
|
||||||
|
* auto-clear when the interrupt is serviced.
|
||||||
|
*/
|
||||||
|
#define M68K_EMULATE_INT_ACK OPT_SPECIFY_HANDLER
|
||||||
|
#define M68K_INT_ACK_CALLBACK(A) cpu_irq_ack(A)
|
||||||
|
|
||||||
|
|
||||||
|
/* If ON, CPU will call the breakpoint acknowledge callback when it encounters
|
||||||
|
* a breakpoint instruction and it is running a 68010+.
|
||||||
|
*/
|
||||||
|
#define M68K_EMULATE_BKPT_ACK OPT_OFF
|
||||||
|
#define M68K_BKPT_ACK_CALLBACK() your_bkpt_ack_handler_function()
|
||||||
|
|
||||||
|
|
||||||
|
/* If ON, the CPU will monitor the trace flags and take trace exceptions
|
||||||
|
*/
|
||||||
|
#define M68K_EMULATE_TRACE OPT_OFF
|
||||||
|
|
||||||
|
|
||||||
|
/* If ON, CPU will call the output reset callback when it encounters a reset
|
||||||
|
* instruction.
|
||||||
|
*/
|
||||||
|
#define M68K_EMULATE_RESET OPT_SPECIFY_HANDLER
|
||||||
|
#define M68K_RESET_CALLBACK() cpu_pulse_reset()
|
||||||
|
|
||||||
|
|
||||||
|
/* If ON, CPU will call the set fc callback on every memory access to
|
||||||
|
* differentiate between user/supervisor, program/data access like a real
|
||||||
|
* 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
|
||||||
|
* to read/write data from different address spaces)
|
||||||
|
*/
|
||||||
|
#define M68K_EMULATE_FC OPT_SPECIFY_HANDLER
|
||||||
|
#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
|
||||||
|
* large value. This allows host programs to be nicer when it comes to
|
||||||
|
* fetching immediate data and instructions on a banked memory system.
|
||||||
|
*/
|
||||||
|
#define M68K_MONITOR_PC OPT_OFF
|
||||||
|
#define M68K_SET_PC_CALLBACK(A) your_pc_changed_handler_function(A)
|
||||||
|
|
||||||
|
|
||||||
|
/* If ON, CPU will call the instruction hook callback before every
|
||||||
|
* instruction.
|
||||||
|
*/
|
||||||
|
#define M68K_INSTRUCTION_HOOK OPT_SPECIFY_HANDLER
|
||||||
|
#define M68K_INSTRUCTION_CALLBACK() cpu_instr_callback()
|
||||||
|
|
||||||
|
|
||||||
|
/* If ON, the CPU will emulate the 4-byte prefetch queue of a real 68000 */
|
||||||
|
#define M68K_EMULATE_PREFETCH OPT_ON
|
||||||
|
|
||||||
|
|
||||||
|
/* If ON, the CPU will generate address error exceptions if it tries to
|
||||||
|
* access a word or longword at an odd address.
|
||||||
|
* NOTE: This is only emulated properly for 68000 mode.
|
||||||
|
*/
|
||||||
|
#define M68K_EMULATE_ADDRESS_ERROR OPT_ON
|
||||||
|
|
||||||
|
|
||||||
|
/* Turn ON to enable logging of illegal instruction calls.
|
||||||
|
* M68K_LOG_FILEHANDLE must be #defined to a stdio file stream.
|
||||||
|
* Turn on M68K_LOG_1010_1111 to log all 1010 and 1111 calls.
|
||||||
|
*/
|
||||||
|
#define M68K_LOG_ENABLE OPT_OFF
|
||||||
|
#define M68K_LOG_1010_1111 OPT_OFF
|
||||||
|
#define M68K_LOG_FILEHANDLE some_file_handle
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------------------------- COMPATIBILITY ---------------------------- */
|
||||||
|
|
||||||
|
/* The following options set optimizations that violate the current ANSI
|
||||||
|
* standard, but will be compliant under the forthcoming C9X standard.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* If ON, the enulation core will use 64-bit integers to speed up some
|
||||||
|
* operations.
|
||||||
|
*/
|
||||||
|
#define M68K_USE_64_BIT OPT_OFF
|
||||||
|
|
||||||
|
|
||||||
|
/* Set to your compiler's static inline keyword to enable it, or
|
||||||
|
* set it to blank to disable it.
|
||||||
|
* If you define INLINE in the makefile, it will override this value.
|
||||||
|
* NOTE: not enabling inline functions will SEVERELY slow down emulation.
|
||||||
|
*/
|
||||||
|
#ifndef INLINE
|
||||||
|
#define INLINE static __inline__
|
||||||
|
#endif /* INLINE */
|
||||||
|
|
||||||
|
#endif /* M68K_COMPILE_FOR_MAME */
|
||||||
|
|
||||||
|
#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_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_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_32(A, V) cpu_write_long(A, V)
|
||||||
|
|
||||||
|
|
||||||
|
/* ======================================================================== */
|
||||||
|
/* ============================== END OF FILE ============================= */
|
||||||
|
/* ======================================================================== */
|
||||||
|
|
||||||
|
#endif /* M68KCONF__HEADER */
|
561
plat/linux68k/emu/sim.c
Executable file
561
plat/linux68k/emu/sim.c
Executable file
|
@ -0,0 +1,561 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "sim.h"
|
||||||
|
#include "m68k.h"
|
||||||
|
|
||||||
|
void disassemble_program();
|
||||||
|
|
||||||
|
/* Memory-mapped IO ports */
|
||||||
|
#define INPUT_ADDRESS 0x800000
|
||||||
|
#define OUTPUT_ADDRESS 0x400000
|
||||||
|
|
||||||
|
/* IRQ connections */
|
||||||
|
#define IRQ_NMI_DEVICE 7
|
||||||
|
#define IRQ_INPUT_DEVICE 2
|
||||||
|
#define IRQ_OUTPUT_DEVICE 1
|
||||||
|
|
||||||
|
/* Time between characters sent to output device (seconds) */
|
||||||
|
#define OUTPUT_DEVICE_PERIOD 1
|
||||||
|
|
||||||
|
/* ROM and RAM sizes */
|
||||||
|
#define MAX_ROM 0xfff
|
||||||
|
#define MAX_RAM 0xff
|
||||||
|
|
||||||
|
|
||||||
|
/* Read/write macros */
|
||||||
|
#define READ_BYTE(BASE, ADDR) (BASE)[ADDR]
|
||||||
|
#define READ_WORD(BASE, ADDR) (((BASE)[ADDR]<<8) | \
|
||||||
|
(BASE)[(ADDR)+1])
|
||||||
|
#define READ_LONG(BASE, ADDR) (((BASE)[ADDR]<<24) | \
|
||||||
|
((BASE)[(ADDR)+1]<<16) | \
|
||||||
|
((BASE)[(ADDR)+2]<<8) | \
|
||||||
|
(BASE)[(ADDR)+3])
|
||||||
|
|
||||||
|
#define WRITE_BYTE(BASE, ADDR, VAL) (BASE)[ADDR] = (VAL)&0xff
|
||||||
|
#define WRITE_WORD(BASE, ADDR, VAL) (BASE)[ADDR] = ((VAL)>>8) & 0xff; \
|
||||||
|
(BASE)[(ADDR)+1] = (VAL)&0xff
|
||||||
|
#define WRITE_LONG(BASE, ADDR, VAL) (BASE)[ADDR] = ((VAL)>>24) & 0xff; \
|
||||||
|
(BASE)[(ADDR)+1] = ((VAL)>>16)&0xff; \
|
||||||
|
(BASE)[(ADDR)+2] = ((VAL)>>8)&0xff; \
|
||||||
|
(BASE)[(ADDR)+3] = (VAL)&0xff
|
||||||
|
|
||||||
|
|
||||||
|
/* Prototypes */
|
||||||
|
void exit_error(char* fmt, ...);
|
||||||
|
|
||||||
|
unsigned int cpu_read_byte(unsigned int address);
|
||||||
|
unsigned int cpu_read_word(unsigned int address);
|
||||||
|
unsigned int cpu_read_long(unsigned int address);
|
||||||
|
void cpu_write_byte(unsigned int address, unsigned int value);
|
||||||
|
void cpu_write_word(unsigned int address, unsigned int value);
|
||||||
|
void cpu_write_long(unsigned int address, unsigned int value);
|
||||||
|
void cpu_pulse_reset(void);
|
||||||
|
void cpu_set_fc(unsigned int fc);
|
||||||
|
int cpu_irq_ack(int level);
|
||||||
|
|
||||||
|
void nmi_device_reset(void);
|
||||||
|
void nmi_device_update(void);
|
||||||
|
int nmi_device_ack(void);
|
||||||
|
|
||||||
|
void input_device_reset(void);
|
||||||
|
void input_device_update(void);
|
||||||
|
int input_device_ack(void);
|
||||||
|
unsigned int input_device_read(void);
|
||||||
|
void input_device_write(unsigned int value);
|
||||||
|
|
||||||
|
void output_device_reset(void);
|
||||||
|
void output_device_update(void);
|
||||||
|
int output_device_ack(void);
|
||||||
|
unsigned int output_device_read(void);
|
||||||
|
void output_device_write(unsigned int value);
|
||||||
|
|
||||||
|
void int_controller_set(unsigned int value);
|
||||||
|
void int_controller_clear(unsigned int value);
|
||||||
|
|
||||||
|
void get_user_input(void);
|
||||||
|
|
||||||
|
|
||||||
|
/* Data */
|
||||||
|
unsigned int g_quit = 0; /* 1 if we want to quit */
|
||||||
|
unsigned int g_nmi = 0; /* 1 if nmi pending */
|
||||||
|
|
||||||
|
int g_input_device_value = -1; /* Current value in input device */
|
||||||
|
|
||||||
|
unsigned int g_output_device_ready = 0; /* 1 if output device is ready */
|
||||||
|
time_t g_output_device_last_output; /* Time of last char output */
|
||||||
|
|
||||||
|
unsigned int g_int_controller_pending = 0; /* list of pending interrupts */
|
||||||
|
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 */
|
||||||
|
|
||||||
|
|
||||||
|
/* Exit with an error message. Use printf syntax. */
|
||||||
|
void exit_error(char* fmt, ...)
|
||||||
|
{
|
||||||
|
static int guard_val = 0;
|
||||||
|
char buff[100];
|
||||||
|
unsigned int pc;
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
if(guard_val)
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
guard_val = 1;
|
||||||
|
|
||||||
|
va_start(args, fmt);
|
||||||
|
vfprintf(stderr, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
pc = m68k_get_reg(NULL, M68K_REG_PPC);
|
||||||
|
m68k_disassemble(buff, pc, M68K_CPU_TYPE_68000);
|
||||||
|
fprintf(stderr, "At %04x: %s\n", pc, buff);
|
||||||
|
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Read data from RAM, ROM, or a device */
|
||||||
|
unsigned int cpu_read_byte(unsigned int address)
|
||||||
|
{
|
||||||
|
if(g_fc & 2) /* Program */
|
||||||
|
{
|
||||||
|
if(address > MAX_ROM)
|
||||||
|
exit_error("Attempted to read byte from ROM address %08x", address);
|
||||||
|
return READ_BYTE(g_rom, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise it's data space */
|
||||||
|
switch(address)
|
||||||
|
{
|
||||||
|
case INPUT_ADDRESS:
|
||||||
|
return input_device_read();
|
||||||
|
case OUTPUT_ADDRESS:
|
||||||
|
return output_device_read();
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(address > MAX_RAM)
|
||||||
|
exit_error("Attempted to read byte from RAM address %08x", address);
|
||||||
|
return READ_BYTE(g_ram, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int cpu_read_word(unsigned int address)
|
||||||
|
{
|
||||||
|
if(g_fc & 2) /* Program */
|
||||||
|
{
|
||||||
|
if(address > MAX_ROM)
|
||||||
|
exit_error("Attempted to read word from ROM address %08x", address);
|
||||||
|
return READ_WORD(g_rom, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise it's data space */
|
||||||
|
switch(address)
|
||||||
|
{
|
||||||
|
case INPUT_ADDRESS:
|
||||||
|
return input_device_read();
|
||||||
|
case OUTPUT_ADDRESS:
|
||||||
|
return output_device_read();
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(address > MAX_RAM)
|
||||||
|
exit_error("Attempted to read word from RAM address %08x", address);
|
||||||
|
return READ_WORD(g_ram, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int cpu_read_long(unsigned int address)
|
||||||
|
{
|
||||||
|
if(g_fc & 2) /* Program */
|
||||||
|
{
|
||||||
|
if(address > MAX_ROM)
|
||||||
|
exit_error("Attempted to read long from ROM address %08x", address);
|
||||||
|
return READ_LONG(g_rom, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise it's data space */
|
||||||
|
switch(address)
|
||||||
|
{
|
||||||
|
case INPUT_ADDRESS:
|
||||||
|
return input_device_read();
|
||||||
|
case OUTPUT_ADDRESS:
|
||||||
|
return output_device_read();
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(address > MAX_RAM)
|
||||||
|
exit_error("Attempted to read long from RAM address %08x", address);
|
||||||
|
return READ_LONG(g_ram, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int cpu_read_word_dasm(unsigned int address)
|
||||||
|
{
|
||||||
|
if(address > MAX_ROM)
|
||||||
|
exit_error("Disassembler attempted to read word from ROM address %08x", address);
|
||||||
|
return READ_WORD(g_rom, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int cpu_read_long_dasm(unsigned int address)
|
||||||
|
{
|
||||||
|
if(address > MAX_ROM)
|
||||||
|
exit_error("Dasm attempted to read long from ROM address %08x", address);
|
||||||
|
return READ_LONG(g_rom, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Write data to RAM or a device */
|
||||||
|
void cpu_write_byte(unsigned int address, unsigned int value)
|
||||||
|
{
|
||||||
|
if(g_fc & 2) /* Program */
|
||||||
|
exit_error("Attempted to write %02x to ROM address %08x", value&0xff, address);
|
||||||
|
|
||||||
|
/* Otherwise it's data space */
|
||||||
|
switch(address)
|
||||||
|
{
|
||||||
|
case INPUT_ADDRESS:
|
||||||
|
input_device_write(value&0xff);
|
||||||
|
return;
|
||||||
|
case OUTPUT_ADDRESS:
|
||||||
|
output_device_write(value&0xff);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(address > MAX_RAM)
|
||||||
|
exit_error("Attempted to write %02x to RAM address %08x", value&0xff, address);
|
||||||
|
WRITE_BYTE(g_ram, address, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* Otherwise it's data space */
|
||||||
|
switch(address)
|
||||||
|
{
|
||||||
|
case INPUT_ADDRESS:
|
||||||
|
input_device_write(value&0xffff);
|
||||||
|
return;
|
||||||
|
case OUTPUT_ADDRESS:
|
||||||
|
output_device_write(value&0xffff);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(address > MAX_RAM)
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
15
plat/linux68k/emu/sim.h
Executable file
15
plat/linux68k/emu/sim.h
Executable file
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef SIM__HEADER
|
||||||
|
#define SIM__HEADER
|
||||||
|
|
||||||
|
unsigned int cpu_read_byte(unsigned int address);
|
||||||
|
unsigned int cpu_read_word(unsigned int address);
|
||||||
|
unsigned int cpu_read_long(unsigned int address);
|
||||||
|
void cpu_write_byte(unsigned int address, unsigned int value);
|
||||||
|
void cpu_write_word(unsigned int address, unsigned int value);
|
||||||
|
void cpu_write_long(unsigned int address, unsigned int value);
|
||||||
|
void cpu_pulse_reset(void);
|
||||||
|
void cpu_set_fc(unsigned int fc);
|
||||||
|
int cpu_irq_ack(int level);
|
||||||
|
void cpu_instr_callback();
|
||||||
|
|
||||||
|
#endif /* SIM__HEADER */
|
Loading…
Reference in a new issue