Compare commits

...

12 commits

Author SHA1 Message Date
8dcac80091 Don't silently skip an opcode just because of an unexpected mask 2025-04-03 18:49:01 +02:00
43de90a9df WIP support emulator traps similar to basilisk 2025-03-30 20:28:34 -05:00
Matt Evans
b3144f12c1 TIDY: m68kcpu: fix warnings 2025-01-01 16:19:41 +00:00
Matt Evans
c8c2089edd TIDY: m68kfpu: fix warnings 2025-01-01 16:19:41 +00:00
Matt Evans
0b85a7a648 Move most frequently-used items to start of m68ki_cpu_core
This enables faster access on ISAs having small immediate offsets (e.g. armv6m).
2024-05-28 23:48:48 +01:00
Matt Evans
d4c4aa290d HACK: Add fast opcode read
m68ki_read_opcode_16 is both a different access path for instructions
(meaning we can decode addresses with certain assumptions), and also can be
implemented faster (always an aligned 16b read).
2024-05-28 23:48:48 +01:00
Matt Evans
91ecb76b7b Add M68K_FAST_FUNC, allowing project-specific attributes
Currently used only on m68k_execute(), this macro allows a project
to flag functions that are performance-critica.  For example, on
microcontroller builds certain functions might be decorated to
ensure the build locates them in faster types of memory.
2024-05-28 23:46:49 +01:00
Matt Evans
765c5af223 Add M68K_BUS_ERR_ENABLE config
Some projects don't use the m68k_pulse_bus_error() interface, so
disabling it will save some cycles in the inner loop.
2024-05-28 23:46:46 +01:00
Matt Evans
c2695c09d7 Add M68K_FIXED_CPU_TYPE config, for static CPU type selection
For some projects, runtime selection of CPU type isn't required,
and burns both time and space.  This config option allows a build-
time selection of CPU model.
2024-05-28 23:46:41 +01:00
Matt Evans
2ff6fd0683 Add M68K_DYNAMIC_INSTR_TABLES for runtime-generated decode/cycle tables
The static decode jump table is built via m68kmake, and with a project
config can be used by the main runloop.

Add M68K_CYCLE_COUNTING to enable per-instruction cycle counts
versus accumulating a dummy (constant) cost per instruction.

Move the cycle-counting to a macro -- for now, CYCLE_COUNTING is only
supported when using DYNAMIC_INSTR_TABLES (as no static table gen
is provided yet).

Static jumptable saves 256K of RAM, and avoiding cycle counting
saves 320K!
2024-05-15 23:16:46 +01:00
Matt Evans
fc885ffb03 m68kmake: Generate static jump table
An alternative to the runtime-generated decode jump table, this generates
one at build time.  The dynamic one uses more RAM, and the static one
makes the binary bigger.

This is qualified on a new M68K_DYNAMIC_INSTR_TABLES option.
2024-05-15 23:15:55 +01:00
Matt Evans
7fcef8fe6a Add new config option to compile disassembler
The disassembler is fairly large, so this allows builds to
save some space if it's not required.
2024-05-15 23:15:47 +01:00
9 changed files with 339 additions and 62 deletions

View file

@ -183,6 +183,27 @@
#define M68K_LOG_1010_1111 OPT_OFF
#define M68K_LOG_FILEHANDLE some_file_handle
/* Build in the disassembler. If disabled, the API still exists
* but does nothing. Turn off to save text/bss space.
*/
#define M68K_DASM_ENABLE OPT_ON
/* Use dynamically-created tables for decode and cyclecounts (if
* enabled by CYCLE_COUNTING), as opposed to tables created at build
* time. Using the dynamic version of the decode jumptable adds 256KB
* to RAM usage but makes the binary smaller. Using the static
* version adds 256KB to the binary and no RAM, but doesn't currently
* support instruction cycle counts.
*/
#define M68K_DYNAMIC_INSTR_TABLES OPT_ON
/* Count instruction cycles. This costs a table (created at runtime
* in RAM if DYNAMIC_INSTR_TABLES is on).
*
* NOTE: This is not currently supported when DYNAMIC_INSTR_TABLES is
* off.
*/
#define M68K_CYCLE_COUNTING OPT_ON
/* ----------------------------- COMPATIBILITY ---------------------------- */

5
m68k.h
View file

@ -151,6 +151,11 @@ typedef enum
M68K_REG_CPU_TYPE /* Type of CPU being run */
} m68k_register_t;
#ifndef M68K_FAST_FUNC
#define M68K_FAST_FUNC(x) x
#endif
/* ======================================================================== */
/* ====================== FUNCTIONS CALLED BY THE CPU ===================== */
/* ======================================================================== */

View file

@ -109,12 +109,26 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
M68KMAKE_PROTOTYPE_FOOTER
#if M68K_DYNAMIC_INSTR_TABLES
/* Build the opcode handler table */
void m68ki_build_opcode_table(void);
extern void (*m68ki_instruction_jump_table[0x10000])(void); /* opcode handler jump table */
#if M68K_CYCLE_COUNTING
extern unsigned char m68ki_cycles[][0x10000];
#endif
#else
/* Opcode handler table is already built at compile time */
static inline void m68ki_build_opcode_table(void) {}
extern void (*const m68ki_static_instruction_jump_table[0x10000])(void);
#if M68K_CYCLE_COUNTING
/* To support cycle counting in a static-tables scenario, extend
* m68kmake to generate a static table.
*/
#error "CYCLE_COUNTING is only supported with DYNAMIC_INSTR_TABLES"
#endif
#endif
/* ======================================================================== */
/* ============================== END OF FILE ============================= */
@ -136,8 +150,12 @@ M68KMAKE_TABLE_HEADER
#define NUM_CPU_TYPES 5
#if M68K_DYNAMIC_INSTR_TABLES
void (*m68ki_instruction_jump_table[0x10000])(void); /* opcode handler jump table */
#if M68K_CYCLE_COUNTING
unsigned char m68ki_cycles[NUM_CPU_TYPES][0x10000]; /* Cycles used by CPU type */
#endif
/* This is used to generate the opcode handler jump table */
typedef struct
@ -162,12 +180,16 @@ M68KMAKE_TABLE_FOOTER
{0, 0, 0, {0, 0, 0, 0, 0}}
};
#if M68K_CYCLE_COUNTING
#define SET_CPU_CYCLECOUNT(a, b, val) do { m68ki_cycles[k][i] = (val); } while(0)
#else
#define SET_CPU_CYCLECOUNT(a, b, val) do { } while(0)
#endif
/* Build the opcode handler jump table */
void m68ki_build_opcode_table(void)
{
const opcode_handler_struct *ostruct;
int cycle_cost;
int instr;
int i;
int j;
@ -178,7 +200,7 @@ void m68ki_build_opcode_table(void)
/* default to illegal */
m68ki_instruction_jump_table[i] = m68k_op_illegal;
for(k=0;k<NUM_CPU_TYPES;k++)
m68ki_cycles[k][i] = 0;
SET_CPU_CYCLECOUNT(k, i, 0);
}
ostruct = m68k_opcode_handler_table;
@ -190,7 +212,7 @@ void m68ki_build_opcode_table(void)
{
m68ki_instruction_jump_table[i] = ostruct->opcode_handler;
for(k=0;k<NUM_CPU_TYPES;k++)
m68ki_cycles[k][i] = ostruct->cycles[k];
SET_CPU_CYCLECOUNT(k, i, ostruct->cycles[k]);
}
}
ostruct++;
@ -201,7 +223,7 @@ void m68ki_build_opcode_table(void)
{
m68ki_instruction_jump_table[ostruct->match | i] = ostruct->opcode_handler;
for(k=0;k<NUM_CPU_TYPES;k++)
m68ki_cycles[k][ostruct->match | i] = ostruct->cycles[k];
SET_CPU_CYCLECOUNT(k, ostruct->match | i, ostruct->cycles[k]);
}
ostruct++;
}
@ -214,7 +236,7 @@ void m68ki_build_opcode_table(void)
instr = ostruct->match | (i << 9) | j;
m68ki_instruction_jump_table[instr] = ostruct->opcode_handler;
for(k=0;k<NUM_CPU_TYPES;k++)
m68ki_cycles[k][instr] = ostruct->cycles[k];
SET_CPU_CYCLECOUNT(k, instr, ostruct->cycles[k]);
/* SBF: don't add it here or the costs are added twice!
// For all shift operations with known shift distance (encoded in instruction word)
if((instr & 0xf000) == 0xe000 && (!(instr & 0x20)))
@ -238,7 +260,7 @@ void m68ki_build_opcode_table(void)
{
m68ki_instruction_jump_table[ostruct->match | i] = ostruct->opcode_handler;
for(k=0;k<NUM_CPU_TYPES;k++)
m68ki_cycles[k][ostruct->match | i] = ostruct->cycles[k];
SET_CPU_CYCLECOUNT(k, ostruct->match | i, ostruct->cycles[k]);
}
ostruct++;
}
@ -248,7 +270,7 @@ void m68ki_build_opcode_table(void)
{
m68ki_instruction_jump_table[ostruct->match | (i << 9)] = ostruct->opcode_handler;
for(k=0;k<NUM_CPU_TYPES;k++)
m68ki_cycles[k][ostruct->match | (i << 9)] = ostruct->cycles[k];
SET_CPU_CYCLECOUNT(k, ostruct->match | (i << 9), ostruct->cycles[k]);
}
ostruct++;
}
@ -258,7 +280,7 @@ void m68ki_build_opcode_table(void)
{
m68ki_instruction_jump_table[ostruct->match | i] = ostruct->opcode_handler;
for(k=0;k<NUM_CPU_TYPES;k++)
m68ki_cycles[k][ostruct->match | i] = ostruct->cycles[k];
SET_CPU_CYCLECOUNT(k, ostruct->match | i, ostruct->cycles[k]);
}
ostruct++;
}
@ -266,11 +288,13 @@ void m68ki_build_opcode_table(void)
{
m68ki_instruction_jump_table[ostruct->match] = ostruct->opcode_handler;
for(k=0;k<NUM_CPU_TYPES;k++)
m68ki_cycles[k][ostruct->match] = ostruct->cycles[k];
SET_CPU_CYCLECOUNT(k, ostruct->match, ostruct->cycles[k]);
ostruct++;
}
}
#endif // M68K_DYNAMIC_INSTR_TABLES
/* ======================================================================== */
/* ============================== END OF FILE ============================= */
@ -379,6 +403,7 @@ cpu cycles: Base number of cycles required to execute this opcode on the
name size proc ea bit pattern A+-DXWLdxI 0 1 2 3 4 000 010 020 030 040 comments
====== ==== ==== ==== ================ ========== = = = = = === === === === === =============
M68KMAKE_TABLE_START
emul_op 0 . . 011100011....... .......... U U U U U 4 4 4 4 4 Extended opcodes (illegal moveq form)
1010 0 . . 1010............ .......... U U U U U 4 4 4 4 4
1111 0 . . 1111............ .......... U U U U U 4 4 4 4 4
040fpu0 32 . . 11110010........ .......... . . . . U . . . . 0
@ -903,6 +928,11 @@ unpk 16 mm . 1000...110001... .......... . . U U U . . 13 1
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
M68KMAKE_OPCODE_HANDLER_BODY
M68KMAKE_OP(emul_op, 0, ., .)
{
m68ki_emul_op();
}
M68KMAKE_OP(1010, 0, ., .)
{
m68ki_exception_1010();
@ -9577,8 +9607,8 @@ M68KMAKE_OP(stop, 0, ., .)
m68ki_trace_t0(); /* auto-disable (see m68kcpu.h) */
CPU_STOPPED |= STOP_LEVEL_STOP;
m68ki_set_sr(new_sr);
if(m68ki_remaining_cycles >= CYC_INSTRUCTION[REG_IR])
m68ki_remaining_cycles = CYC_INSTRUCTION[REG_IR];
if(m68ki_remaining_cycles >= CYC_INSTRUCTION(REG_IR))
m68ki_remaining_cycles = CYC_INSTRUCTION(REG_IR);
else
USE_ALL_CYCLES();
return;

View file

@ -43,7 +43,6 @@
#define OPT_ON 1
#define OPT_SPECIFY_HANDLER 2
/* ======================================================================== */
/* ============================== MAME STUFF ============================== */
/* ======================================================================== */
@ -188,6 +187,41 @@
* so enable this only if it's useful */
#define M68K_EMULATE_PMMU OPT_ON
/* Build in the disassembler. If disabled, the API still exists
* but does nothing. Turn off to save text/bss space.
*/
#define M68K_DASM_ENABLE OPT_ON
/* Use dynamically-created tables for decode and cyclecounts (if
* enabled by CYCLE_COUNTING), as opposed to tables created at build
* time. Using the dynamic version of the decode jumptable adds 256KB
* to RAM usage but makes the binary smaller. Using the static
* version adds 256KB to the binary and no RAM, but doesn't currently
* support instruction cycle counts.
*/
#define M68K_DYNAMIC_INSTR_TABLES OPT_ON
/* Count instruction cycles. This costs a table (created at runtime
* in RAM if DYNAMIC_INSTR_TABLES is on).
*
* NOTE: This is not currently supported when DYNAMIC_INSTR_TABLES is
* off.
*/
#define M68K_CYCLE_COUNTING OPT_ON
/* Support bus error API: if this isn't ever called by the application,
* save some cycles by disabling it.
*/
#define M68K_BUS_ERR_ENABLE OPT_ON
/* If ON, CPU will support "emul_op" instructions from 0x7100..0x713f by
* calling m68k_end_timeslice when they are encountered. The caller can (must)
* check the IR register and implement the operation.
* If off, these remain illegal instructions.
*/
#define M68K_EMUL_OP OPT_OFF
/* ----------------------------- COMPATIBILITY ---------------------------- */
/* The following options set optimizations that violate the current ANSI
@ -195,7 +229,7 @@
*/
/* If ON, the enulation core will use 64-bit integers to speed up some
/* If ON, the emulation core will use 64-bit integers to speed up some
* operations.
*/
#define M68K_USE_64_BIT OPT_ON

View file

@ -38,12 +38,11 @@
/* ================================ INCLUDES ============================== */
/* ======================================================================== */
#include <assert.h>
extern void m68040_fpu_op0(void);
extern void m68040_fpu_op1(void);
extern void m68881_mmu_ops(void);
extern unsigned char m68ki_cycles[][0x10000];
extern void (*m68ki_instruction_jump_table[0x10000])(void); /* opcode handler jump table */
extern void m68ki_build_opcode_table(void);
#include "m68kops.h"
#include "m68kcpu.h"
@ -51,6 +50,18 @@ extern void m68ki_build_opcode_table(void);
#include "m68kfpu.c"
#include "m68kmmu.h" // uses some functions from m68kfpu.c which are static !
#if M68K_DYNAMIC_INSTR_TABLES
extern void (*m68ki_instruction_jump_table[0x10000])(void); /* opcode handler jump table */
void (**instruction_jump_table)(void) = m68ki_instruction_jump_table;
#if M68K_CYCLE_COUNTING
extern unsigned char m68ki_cycles[][0x10000];
#endif
#else
extern void (*const m68ki_static_instruction_jump_table[0x10000])(void);
void (**instruction_jump_table)(void) = (void (**)(void))m68ki_static_instruction_jump_table;
#endif
/* ======================================================================== */
/* ================================= DATA ================================= */
/* ======================================================================== */
@ -92,7 +103,9 @@ uint m68ki_aerr_address;
uint m68ki_aerr_write_mode;
uint m68ki_aerr_fc;
#if M68K_BUS_ERR_ENABLE
jmp_buf m68ki_bus_error_jmp_buf;
#endif
/* Used by shift & rotate instructions */
const uint8 m68ki_shift_8_table[65] =
@ -661,6 +674,9 @@ unsigned int m68k_get_reg(void* context, m68k_register_t regnum)
case M68K_REG_PPC: return MASK_OUT_ABOVE_32(cpu->ppc);
case M68K_REG_IR: return cpu->ir;
case M68K_REG_CPU_TYPE:
#ifdef M68K_FIXED_CPU_TYPE
return M68K_FIXED_CPU_TYPE;
#else
switch(cpu->cpu_type)
{
case CPU_TYPE_000: return (unsigned int)M68K_CPU_TYPE_68000;
@ -670,6 +686,7 @@ unsigned int m68k_get_reg(void* context, m68k_register_t regnum)
case CPU_TYPE_040: return (unsigned int)M68K_CPU_TYPE_68040;
}
return M68K_CPU_TYPE_INVALID;
#endif
default: return 0;
}
return 0;
@ -776,16 +793,32 @@ void m68k_set_instr_hook_callback(void (*callback)(unsigned int pc))
CALLBACK_INSTR_HOOK = callback ? callback : default_instr_hook_callback;
}
#if M68K_DYNAMIC_INSTR_TABLES && M68K_CYCLE_COUNTING
#define CYC_INSTR_INIT(x) m68ki_cpu.cyc_instruction = (x)
#else
/* FIXME: how to select a CPU flavour at compile time is TBD. */
#define CYC_INSTR_INIT(x) m68ki_cpu.cyc_instruction = NULL
#endif
#ifdef M68K_FIXED_CPU_TYPE
#define CPU_TYPE_INIT(x) do {} while(0)
#else
#define CPU_TYPE_INIT(x) do { CPU_TYPE = (x); } while(0)
#endif
/* Set the CPU type. */
void m68k_set_cpu_type(unsigned int cpu_type)
{
#ifdef M68K_FIXED_CPU_TYPE
assert(cpu_type == M68K_FIXED_CPU_TYPE);
#endif
switch(cpu_type)
{
case M68K_CPU_TYPE_68000:
CPU_TYPE = CPU_TYPE_000;
CPU_TYPE_INIT(CPU_TYPE_000);
CPU_ADDRESS_MASK = 0x00ffffff;
CPU_SR_MASK = 0xa71f; /* T1 -- S -- -- I2 I1 I0 -- -- -- X N Z V C */
CYC_INSTRUCTION = m68ki_cycles[0];
CYC_INSTR_INIT(m68ki_cycles[0]);
CYC_EXCEPTION = m68ki_exception_cycle_table[0];
CYC_BCC_NOTAKE_B = -2;
CYC_BCC_NOTAKE_W = 2;
@ -801,13 +834,13 @@ void m68k_set_cpu_type(unsigned int cpu_type)
case M68K_CPU_TYPE_SCC68070:
m68k_set_cpu_type(M68K_CPU_TYPE_68010);
CPU_ADDRESS_MASK = 0xffffffff;
CPU_TYPE = CPU_TYPE_SCC070;
CPU_TYPE_INIT(CPU_TYPE_SCC070);
return;
case M68K_CPU_TYPE_68010:
CPU_TYPE = CPU_TYPE_010;
CPU_TYPE_INIT(CPU_TYPE_010);
CPU_ADDRESS_MASK = 0x00ffffff;
CPU_SR_MASK = 0xa71f; /* T1 -- S -- -- I2 I1 I0 -- -- -- X N Z V C */
CYC_INSTRUCTION = m68ki_cycles[1];
CYC_INSTR_INIT(m68ki_cycles[1]);
CYC_EXCEPTION = m68ki_exception_cycle_table[1];
CYC_BCC_NOTAKE_B = -4;
CYC_BCC_NOTAKE_W = 0;
@ -821,10 +854,10 @@ void m68k_set_cpu_type(unsigned int cpu_type)
HAS_PMMU = 0;
return;
case M68K_CPU_TYPE_68EC020:
CPU_TYPE = CPU_TYPE_EC020;
CPU_TYPE_INIT(CPU_TYPE_EC020);
CPU_ADDRESS_MASK = 0x00ffffff;
CPU_SR_MASK = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */
CYC_INSTRUCTION = m68ki_cycles[2];
CYC_INSTR_INIT(m68ki_cycles[2]);
CYC_EXCEPTION = m68ki_exception_cycle_table[2];
CYC_BCC_NOTAKE_B = -2;
CYC_BCC_NOTAKE_W = 0;
@ -838,10 +871,10 @@ void m68k_set_cpu_type(unsigned int cpu_type)
HAS_PMMU = 0;
return;
case M68K_CPU_TYPE_68020:
CPU_TYPE = CPU_TYPE_020;
CPU_TYPE_INIT(CPU_TYPE_020);
CPU_ADDRESS_MASK = 0xffffffff;
CPU_SR_MASK = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */
CYC_INSTRUCTION = m68ki_cycles[2];
CYC_INSTR_INIT(m68ki_cycles[2]);
CYC_EXCEPTION = m68ki_exception_cycle_table[2];
CYC_BCC_NOTAKE_B = -2;
CYC_BCC_NOTAKE_W = 0;
@ -855,10 +888,10 @@ void m68k_set_cpu_type(unsigned int cpu_type)
HAS_PMMU = 0;
return;
case M68K_CPU_TYPE_68030:
CPU_TYPE = CPU_TYPE_030;
CPU_TYPE_INIT(CPU_TYPE_030);
CPU_ADDRESS_MASK = 0xffffffff;
CPU_SR_MASK = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */
CYC_INSTRUCTION = m68ki_cycles[3];
CYC_INSTR_INIT(m68ki_cycles[3]);
CYC_EXCEPTION = m68ki_exception_cycle_table[3];
CYC_BCC_NOTAKE_B = -2;
CYC_BCC_NOTAKE_W = 0;
@ -872,10 +905,10 @@ void m68k_set_cpu_type(unsigned int cpu_type)
HAS_PMMU = 1;
return;
case M68K_CPU_TYPE_68EC030:
CPU_TYPE = CPU_TYPE_EC030;
CPU_TYPE_INIT(CPU_TYPE_EC030);
CPU_ADDRESS_MASK = 0xffffffff;
CPU_SR_MASK = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */
CYC_INSTRUCTION = m68ki_cycles[3];
CYC_INSTR_INIT(m68ki_cycles[3]);
CYC_EXCEPTION = m68ki_exception_cycle_table[3];
CYC_BCC_NOTAKE_B = -2;
CYC_BCC_NOTAKE_W = 0;
@ -889,10 +922,10 @@ void m68k_set_cpu_type(unsigned int cpu_type)
HAS_PMMU = 0; /* EC030 lacks the PMMU and is effectively a die-shrink 68020 */
return;
case M68K_CPU_TYPE_68040: // TODO: these values are not correct
CPU_TYPE = CPU_TYPE_040;
CPU_TYPE_INIT(CPU_TYPE_040);
CPU_ADDRESS_MASK = 0xffffffff;
CPU_SR_MASK = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */
CYC_INSTRUCTION = m68ki_cycles[4];
CYC_INSTR_INIT(m68ki_cycles[4]);
CYC_EXCEPTION = m68ki_exception_cycle_table[4];
CYC_BCC_NOTAKE_B = -2;
CYC_BCC_NOTAKE_W = 0;
@ -906,10 +939,10 @@ void m68k_set_cpu_type(unsigned int cpu_type)
HAS_PMMU = 1;
return;
case M68K_CPU_TYPE_68EC040: // Just a 68040 without pmmu apparently...
CPU_TYPE = CPU_TYPE_EC040;
CPU_TYPE_INIT(CPU_TYPE_EC040);
CPU_ADDRESS_MASK = 0xffffffff;
CPU_SR_MASK = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */
CYC_INSTRUCTION = m68ki_cycles[4];
CYC_INSTR_INIT(m68ki_cycles[4]);
CYC_EXCEPTION = m68ki_exception_cycle_table[4];
CYC_BCC_NOTAKE_B = -2;
CYC_BCC_NOTAKE_W = 0;
@ -923,9 +956,9 @@ void m68k_set_cpu_type(unsigned int cpu_type)
HAS_PMMU = 0;
return;
case M68K_CPU_TYPE_68LC040:
CPU_TYPE = CPU_TYPE_LC040;
CPU_TYPE_INIT(CPU_TYPE_LC040);
m68ki_cpu.sr_mask = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */
m68ki_cpu.cyc_instruction = m68ki_cycles[4];
CYC_INSTR_INIT(m68ki_cycles[4]);
m68ki_cpu.cyc_exception = m68ki_exception_cycle_table[4];
m68ki_cpu.cyc_bcc_notake_b = -2;
m68ki_cpu.cyc_bcc_notake_w = 0;
@ -943,7 +976,7 @@ void m68k_set_cpu_type(unsigned int cpu_type)
/* Execute some instructions until we use up num_cycles clock cycles */
/* ASG: removed per-instruction interrupt checks */
int m68k_execute(int num_cycles)
int M68K_FAST_FUNC(m68k_execute)(int num_cycles)
{
/* eat up any reset cycles */
if (RESET_CYCLES) {
@ -972,7 +1005,6 @@ int m68k_execute(int num_cycles)
/* Main loop. Keep going until we run out of clock cycles */
do
{
int i;
/* Set tracing accodring to T1. (T0 is done inside instruction) */
m68ki_trace_t1(); /* auto-disable (see m68kcpu.h) */
@ -985,15 +1017,16 @@ int m68k_execute(int num_cycles)
/* Record previous program counter */
REG_PPC = REG_PC;
#if M68K_BUS_ERR_ENABLE
/* Record previous D/A register state (in case of bus error) */
for (i = 15; i >= 0; i--){
for (int i = 15; i >= 0; i--){
REG_DA_SAVE[i] = REG_DA[i];
}
#endif
/* Read an instruction and call its handler */
REG_IR = m68ki_read_imm_16();
m68ki_instruction_jump_table[REG_IR]();
USE_CYCLES(CYC_INSTRUCTION[REG_IR]);
REG_IR = m68ki_read_opcode_16();
instruction_jump_table[REG_IR]();
USE_CYCLES(CYC_INSTRUCTION(REG_IR));
/* Trace m68k_exception, if necessary */
m68ki_exception_if_trace(); /* auto-disable (see m68kcpu.h) */
@ -1102,7 +1135,9 @@ void m68k_init(void)
/* Trigger a Bus Error exception */
void m68k_pulse_bus_error(void)
{
#if M68K_BUS_ERR_ENABLE
m68ki_exception_bus_error();
#endif
}
/* Pulse the RESET line on the CPU */
@ -1155,7 +1190,7 @@ void m68k_pulse_halt(void)
/* Get and set the current CPU context */
/* This is to allow for multiple CPUs */
unsigned int m68k_context_size()
unsigned int m68k_context_size(void)
{
return sizeof(m68ki_cpu_core);
}

View file

@ -325,7 +325,11 @@ typedef uint32 uint64;
/* ------------------------------ CPU Access ------------------------------ */
/* Access the CPU registers */
#ifdef M68K_FIXED_CPU_TYPE
#define CPU_TYPE M68K_FIXED_CPU_TYPE
#else
#define CPU_TYPE m68ki_cpu.cpu_type
#endif
#define REG_DA m68ki_cpu.dar /* easy access to data and address regs */
#define REG_DA_SAVE m68ki_cpu.dar_save
@ -370,7 +374,12 @@ typedef uint32 uint64;
#define CPU_INSTR_MODE m68ki_cpu.instr_mode
#define CPU_RUN_MODE m68ki_cpu.run_mode
#define CYC_INSTRUCTION m68ki_cpu.cyc_instruction
#if M68K_DYNAMIC_INSTR_TABLES && M68K_CYCLE_COUNTING
#define CYC_INSTRUCTION(x) m68ki_cpu.cyc_instruction[x]
#else
#define CYC_INSTRUCTION(x) (8)
#endif
#define CYC_EXCEPTION m68ki_cpu.cyc_exception
#define CYC_BCC_NOTAKE_B m68ki_cpu.cyc_bcc_notake_b
#define CYC_BCC_NOTAKE_W m68ki_cpu.cyc_bcc_notake_w
@ -874,7 +883,7 @@ extern jmp_buf m68ki_aerr_trap;
#define USE_CYCLES(A) m68ki_remaining_cycles -= (A)
#define SET_CYCLES(A) m68ki_remaining_cycles = A
#define GET_CYCLES() m68ki_remaining_cycles
#define USE_ALL_CYCLES() m68ki_remaining_cycles %= CYC_INSTRUCTION[REG_IR]
#define USE_ALL_CYCLES() m68ki_remaining_cycles %= CYC_INSTRUCTION(REG_IR)
@ -925,19 +934,24 @@ typedef union
typedef struct
{
/* Most-used items at the front */
uint ir; /* Instruction Register */
uint ppc; /* Previous program counter */
uint pc; /* Program Counter */
#ifndef M68K_FIXED_CPU_TYPE
uint cpu_type; /* CPU Type: 68000, 68008, 68010, 68EC020, 68020, 68EC030, 68030, 68EC040, or 68040 */
#endif
uint dar[16]; /* Data and Address Registers */
#ifdef M68K_BUS_ERR_ENABLE
uint dar_save[16]; /* Saved Data and Address Registers (pushed onto the
stack when a bus error occurs)*/
uint ppc; /* Previous program counter */
uint pc; /* Program Counter */
#endif
uint sp[7]; /* User, Interrupt, and Master Stack Pointers */
uint vbr; /* Vector Base Register (m68010+) */
uint sfc; /* Source Function Code Register (m68010+) */
uint dfc; /* Destination Function Code Register (m68010+) */
uint cacr; /* Cache Control Register (m68020, unemulated) */
uint caar; /* Cache Address Register (m68020, unemulated) */
uint ir; /* Instruction Register */
floatx80 fpr[8]; /* FPU Data Register (m68030/040) */
uint fpiar; /* FPU Instruction Address Register (m68040) */
uint fpsr; /* FPU Status Register (m68040) */
@ -1072,6 +1086,14 @@ static inline uint m68ki_read_imm_16(void)
#endif /* M68K_EMULATE_PREFETCH */
}
/* Read an opcode. Properties: always aligned! */
static inline uint m68ki_read_opcode_16(void)
{
/* FIXME: fc, check addr err, check PMMU, etc. */
REG_PC += 2;
return m68k_read_instr_16(ADDRESS_68K(REG_PC-2));
}
static inline uint m68ki_read_imm_8(void)
{
/* map read immediate 8 to read immediate 16 */
@ -1847,7 +1869,7 @@ static inline void m68ki_exception_trap(uint vector)
m68ki_jump_vector(vector);
/* Use up some clock cycles and undo the instruction's cycles */
USE_CYCLES(CYC_EXCEPTION[vector] - CYC_INSTRUCTION[REG_IR]);
USE_CYCLES(CYC_EXCEPTION[vector] - CYC_INSTRUCTION(REG_IR));
}
/* Trap#n stacks a 0 frame but behaves like group2 otherwise */
@ -1858,7 +1880,7 @@ static inline void m68ki_exception_trapN(uint vector)
m68ki_jump_vector(vector);
/* Use up some clock cycles and undo the instruction's cycles */
USE_CYCLES(CYC_EXCEPTION[vector] - CYC_INSTRUCTION[REG_IR]);
USE_CYCLES(CYC_EXCEPTION[vector] - CYC_INSTRUCTION(REG_IR));
}
/* Exception for trace mode */
@ -1904,9 +1926,10 @@ static inline void m68ki_exception_privilege_violation(void)
m68ki_jump_vector(EXCEPTION_PRIVILEGE_VIOLATION);
/* Use up some clock cycles and undo the instruction's cycles */
USE_CYCLES(CYC_EXCEPTION[EXCEPTION_PRIVILEGE_VIOLATION] - CYC_INSTRUCTION[REG_IR]);
USE_CYCLES(CYC_EXCEPTION[EXCEPTION_PRIVILEGE_VIOLATION] - CYC_INSTRUCTION(REG_IR));
}
#if M68K_BUS_ERR_ENABLE
extern jmp_buf m68ki_bus_error_jmp_buf;
#define m68ki_check_bus_error_trap() setjmp(m68ki_bus_error_jmp_buf)
@ -1929,7 +1952,7 @@ static inline void m68ki_exception_bus_error(void)
CPU_RUN_MODE = RUN_MODE_BERR_AERR_RESET_WSF;
/* Use up some clock cycles and undo the instruction's cycles */
USE_CYCLES(CYC_EXCEPTION[EXCEPTION_BUS_ERROR] - CYC_INSTRUCTION[REG_IR]);
USE_CYCLES(CYC_EXCEPTION[EXCEPTION_BUS_ERROR] - CYC_INSTRUCTION(REG_IR));
for (i = 15; i >= 0; i--){
REG_DA[i] = REG_DA_SAVE[i];
@ -1946,6 +1969,9 @@ static inline void m68ki_exception_bus_error(void)
longjmp(m68ki_bus_error_jmp_buf, 1);
}
#else /* M68K_BUS_ERR_ENABLE */
#define m68ki_check_bus_error_trap() do {} while(0)
#endif
extern int cpu_log_enabled;
@ -1964,7 +1990,7 @@ static inline void m68ki_exception_1010(void)
m68ki_jump_vector(EXCEPTION_1010);
/* Use up some clock cycles and undo the instruction's cycles */
USE_CYCLES(CYC_EXCEPTION[EXCEPTION_1010] - CYC_INSTRUCTION[REG_IR]);
USE_CYCLES(CYC_EXCEPTION[EXCEPTION_1010] - CYC_INSTRUCTION(REG_IR));
}
/* Exception for F-Line instructions */
@ -1983,7 +2009,7 @@ static inline void m68ki_exception_1111(void)
m68ki_jump_vector(EXCEPTION_1111);
/* Use up some clock cycles and undo the instruction's cycles */
USE_CYCLES(CYC_EXCEPTION[EXCEPTION_1111] - CYC_INSTRUCTION[REG_IR]);
USE_CYCLES(CYC_EXCEPTION[EXCEPTION_1111] - CYC_INSTRUCTION(REG_IR));
}
#if M68K_ILLG_HAS_CALLBACK == OPT_SPECIFY_HANDLER
@ -2014,7 +2040,7 @@ static inline void m68ki_exception_illegal(void)
m68ki_jump_vector(EXCEPTION_ILLEGAL_INSTRUCTION);
/* Use up some clock cycles and undo the instruction's cycles */
USE_CYCLES(CYC_EXCEPTION[EXCEPTION_ILLEGAL_INSTRUCTION] - CYC_INSTRUCTION[REG_IR]);
USE_CYCLES(CYC_EXCEPTION[EXCEPTION_ILLEGAL_INSTRUCTION] - CYC_INSTRUCTION(REG_IR));
}
/* Exception for format errror in RTE */
@ -2025,7 +2051,7 @@ static inline void m68ki_exception_format_error(void)
m68ki_jump_vector(EXCEPTION_FORMAT_ERROR);
/* Use up some clock cycles and undo the instruction's cycles */
USE_CYCLES(CYC_EXCEPTION[EXCEPTION_FORMAT_ERROR] - CYC_INSTRUCTION[REG_IR]);
USE_CYCLES(CYC_EXCEPTION[EXCEPTION_FORMAT_ERROR] - CYC_INSTRUCTION(REG_IR));
}
/* Exception for address error */
@ -2132,6 +2158,13 @@ static inline void m68ki_exception_interrupt(uint int_level)
#endif /* M68K_EMULATE_INT_ACK */
}
static inline void m68ki_emul_op(void) {
#if M68K_EMUL_OP
m68k_end_timeslice();
#else
m68ki_exception_illegal();
#endif
}
/* ASG: Check for interrupts */
static inline void m68ki_check_interrupts(void)

View file

@ -146,6 +146,7 @@
#define COMBINE_OPCODE_FLAGS(X) (X)
#endif
#if M68K_DASM_ENABLE
/* ======================================================================== */
/* =============================== PROTOTYPES ============================= */
@ -3715,6 +3716,7 @@ static void build_opcode_table(void)
}
}
}
#endif // M68K_DASM_ENABLE
@ -3725,6 +3727,7 @@ static void build_opcode_table(void)
/* Disasemble one instruction at pc and store in str_buff */
unsigned int m68k_disassemble(char* str_buff, unsigned int pc, unsigned int cpu_type)
{
#if M68K_DASM_ENABLE
if(!g_initialized)
{
build_opcode_table();
@ -3770,18 +3773,31 @@ unsigned int m68k_disassemble(char* str_buff, unsigned int pc, unsigned int cpu_
g_instruction_table[g_cpu_ir]();
sprintf(str_buff, "%s%s", g_dasm_str, g_helper_str);
return COMBINE_OPCODE_FLAGS(g_cpu_pc - pc);
#else
(void)str_buff;
(void)pc;
(void)cpu_type;
return 0;
#endif
}
char* m68ki_disassemble_quick(unsigned int pc, unsigned int cpu_type)
{
#if M68K_DASM_ENABLE
static char buff[100];
buff[0] = 0;
m68k_disassemble(buff, pc, cpu_type);
return buff;
#else
(void)pc;
(void)cpu_type;
return 0;
#endif
}
unsigned int m68k_disassemble_raw(char* str_buff, unsigned int pc, const unsigned char* opdata, const unsigned char* argdata, unsigned int cpu_type)
{
#if M68K_DASM_ENABLE
unsigned int result;
(void)argdata;
@ -3790,11 +3806,20 @@ unsigned int m68k_disassemble_raw(char* str_buff, unsigned int pc, const unsigne
result = m68k_disassemble(str_buff, pc, cpu_type);
g_rawop = NULL;
return result;
#else
(void)str_buff;
(void)pc;
(void)opdata;
(void)argdata;
(void)cpu_type;
return 0;
#endif
}
/* Check if the instruction is a valid one */
unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cpu_type)
{
#if M68K_DASM_ENABLE
if(!g_initialized)
{
build_opcode_table();
@ -3996,6 +4021,11 @@ unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cp
return 0;
return 1;
#else
(void)instruction;
(void)cpu_type;
return 0;
#endif
}
// f028 2215 0008

View file

@ -646,7 +646,7 @@ static uint64 READ_EA_64(int ea)
static floatx80 READ_EA_FPE(int mode, int reg, uint32 di_mode_ea)
{
floatx80 fpr;
floatx80 fpr = {0};
switch (mode)
{
@ -727,7 +727,7 @@ static floatx80 READ_EA_FPE(int mode, int reg, uint32 di_mode_ea)
static floatx80 READ_EA_PACK(int ea)
{
floatx80 fpr;
floatx80 fpr = {0};
int mode = (ea >> 3) & 0x7;
int reg = (ea & 0x7);
@ -1749,7 +1749,7 @@ static void fmovem(uint16 w2)
}
}
static void fscc()
static void fscc(void)
{
// added by JFF, this seems to work properly now
int condition = OPER_I_16() & 0x3f;
@ -1819,7 +1819,7 @@ static void fbcc32(void)
}
void m68040_fpu_op0()
void m68040_fpu_op0(void)
{
m68ki_cpu.fpu_just_reset = 0;
@ -1908,7 +1908,7 @@ static void perform_fsave(uint32 addr, int inc)
}
// FRESTORE on a NULL frame reboots the FPU - all registers to NaN, the 3 status regs to 0
static void do_frestore_null()
static void do_frestore_null(void)
{
int i;
@ -1926,7 +1926,7 @@ static void do_frestore_null()
m68ki_cpu.fpu_just_reset = 1;
}
void m68040_fpu_op1()
void m68040_fpu_op1(void)
{
int ea = REG_IR & 0x3f;
int mode = (ea >> 3) & 0x7;

View file

@ -1207,6 +1207,93 @@ void read_insert(char* insert)
*ptr++ = 0;
}
void build_opcode_jump_table(FILE *outfile, const opcode_struct *opcode_table, int opcode_table_len)
{
/* Do what m68ki_build_opcode_table does, but generate a static version
* at build time. This allows a project to trade off RAM usage vs binary
* size (or even ROM size)
*/
int instr;
int i;
int j;
int k;
/* One entry per opcode/instruction. After allocating valid entries,
* anything remaining zero is implicitly the illegal instr handler.
*/
const char **handler_names = calloc(0x10000, sizeof(char *));
/* FIXME: Support cycle table -- for one CPU type? */
for (int opc = 0; opc < opcode_table_len; opc++) {
const opcode_struct *ostruct = &opcode_table[opc];
switch (ostruct->op_mask) {
default:
printf("Unsupported op_mask %04x for %s\n", ostruct->op_mask, ostruct->name);
[[fallthrough]]
case 0xf000:
case 0xf100:
case 0xf180:
case 0xf1c0:
case 0xfe00:
for(i = 0;i < 0x10000;i++)
{
if((i & ostruct->op_mask) == ostruct->op_match)
{
handler_names[i] = ostruct->name;
}
}
break;
case 0xff00:
for(i = 0;i <= 0xff;i++)
{
handler_names[ostruct->op_match | i] = ostruct->name;
}
break;
case 0xf1f8:
for(i = 0;i < 8;i++)
{
for(j = 0;j < 8;j++)
{
instr = ostruct->op_match | (i << 9) | j;
handler_names[instr] = ostruct->name;
}
}
break;
case 0xfff0:
for(i = 0;i <= 0x0f;i++)
{
handler_names[ostruct->op_match | i] = ostruct->name;
}
break;
case 0xf1ff:
for(i = 0;i <= 0x07;i++)
{
handler_names[ostruct->op_match | (i << 9)] = ostruct->name;
}
break;
case 0xfff8:
for(i = 0;i <= 0x07;i++)
{
handler_names[ostruct->op_match | i] = ostruct->name;
}
break;
case 0xffff:
handler_names[ostruct->op_match] = ostruct->name;
}
}
/* Output handler names to create the final table: */
fprintf(outfile, "#if !M68K_DYNAMIC_INSTR_TABLES\n");
fprintf(outfile, "void (*const m68ki_static_instruction_jump_table[0x10000])(void) = {\n");
for (i = 0; i < 0x10000; i++) {
fprintf(outfile, "\t%s,\n", handler_names[i] ?
handler_names[i] : " m68k_op_illegal");
}
fprintf(outfile, "};\n#endif\n");
free(handler_names);
}
/* ======================================================================== */
@ -1380,6 +1467,8 @@ int main(int argc, char **argv)
fprintf(g_table_file, "%s\n\n", table_header_insert);
print_opcode_output_table(g_table_file);
fprintf(g_table_file, "%s\n\n", table_footer_insert);
build_opcode_jump_table(g_table_file,
g_opcode_output_table, g_opcode_output_table_length);
fprintf(g_prototype_file, "%s\n\n", prototype_footer_insert);