update platform linux68k

latest version of musashi engine
includes floating point emulation
(plus a few patches to add in missing opcodes needed by ack - see tags JFF & TBB)

added a few missing linux syscalls in sim.c

pascal now runs pretty well
quick test with modula2 passes

c gets the floating point numbers wrong, so more work needed here

other languages untested

plat/linux68k/emu/build.lua is probably not quite right - the softfloat directory is compiled in the wrong place
This commit is contained in:
tevorbl 2020-05-28 13:06:08 +01:00
parent 53a3630d2c
commit 799900f45a
38 changed files with 12899 additions and 2398 deletions

View file

@ -9,7 +9,8 @@ DEFAULT_PLATFORM = pc86
# Where should the ACK put its temporary files?
ACK_TEMP_DIR = /tmp
#ACK_TEMP_DIR = /tmp
ACK_TEMP_DIR = tmp
# Where is the ACK going to be installed, eventually? If you don't want to
# install it and just want to run the ACK from the build directory
@ -31,6 +32,7 @@ LDFLAGS =
AR = ar
CC = gcc
#CC = clang
# Which build system to use; use 'ninja' or 'make' (in lower case). Leave
# blank to autodetect.

View file

@ -11,15 +11,15 @@ normalrule {
"+m68kmake",
"./musashi/m68k_in.c",
"./musashi/m68kcpu.h",
"./musashi/m68kmmu.h",
"./m68kconf.h",
"./musashi/m68kcpu.c",
"./musashi/m68kfpu.c",
"./musashi/m68kdasm.c",
"./musashi/m68k.h",
"./musashi/softfloat",
},
outleaves = {
"m68kopac.c",
"m68kopdm.c",
"m68kopnz.c",
"m68kops.c",
"m68kops.h",
"m68kcpu.h",
@ -29,7 +29,7 @@ normalrule {
"m68k.h",
},
commands = {
"cp %{ins[2]} %{ins[3]} %{ins[4]} %{ins[5]} %{ins[6]} %{ins[7]} %{dir}",
"cp -R %{ins[2]} %{ins[3]} %{ins[4]} %{ins[5]} %{ins[6]} %{ins[7]} %{ins[8]} %{ins[9]} %{ins[10]} %{dir}",
"cd %{dir} && %{ins[1]}"
}
}
@ -50,9 +50,9 @@ cprogram {
srcs = {
"./sim.c",
matching(filenamesof("+m68k_engine"), "%.c$"),
"./musashi/softfloat/softfloat.c",
},
deps = {
"+headers",
}
}

View file

@ -3,20 +3,28 @@
/* ======================================================================== */
/*
* MUSASHI
* Version 3.4
* Version 3.32
*
* A portable Motorola M680x0 processor emulation engine.
* Copyright 1998-2001 Karl Stenerud. All rights reserved.
* Copyright 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.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* 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
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
@ -59,6 +67,8 @@
#define M68K_EMULATE_010 OPT_ON
#define M68K_EMULATE_EC020 OPT_ON
#define M68K_EMULATE_020 OPT_ON
#define M68K_EMULATE_030 OPT_ON
#define M68K_EMULATE_040 OPT_ON
/* If ON, the CPU will call m68k_read_immediate_xx() for immediate addressing
@ -101,6 +111,35 @@
#define M68K_EMULATE_RESET OPT_OFF
#define M68K_RESET_CALLBACK() cpu_pulse_reset()
/* If ON, CPU will call the callback when it encounters a cmpi.l #v, dn
* instruction.
*/
#define M68K_CMPILD_HAS_CALLBACK OPT_OFF
#define M68K_CMPILD_CALLBACK(v,r) your_cmpild_handler_function(v,r)
/* If ON, CPU will call the callback when it encounters a rte
* instruction.
*/
#define M68K_RTE_HAS_CALLBACK OPT_OFF
#define M68K_RTE_CALLBACK() your_rte_handler_function()
/* If ON, CPU will call the callback when it encounters a tas
* instruction.
*/
#define M68K_TAS_HAS_CALLBACK OPT_OFF
#define M68K_TAS_CALLBACK() your_tas_handler_function()
/* If ON, CPU will call the callback when it encounters an illegal instruction
* passing the opcode as argument. If the callback returns 1, then it's considered
* as a normal instruction, and the illegal exception in canceled. If it returns 0,
* the exception occurs normally.
* The callback looks like int callback(int opcode)
* You should put OPT_SPECIFY_HANDLER here if you cant to use it, otherwise it will
* use a dummy default handler and you'll have to call m68k_set_illg_instr_callback explicitely
*/
#define M68K_ILLG_HAS_CALLBACK OPT_OFF
#define M68K_ILLG_CALLBACK(opcode) op_illg(opcode)
/* If ON, CPU will call the set fc callback on every memory access to
* differentiate between user/supervisor, program/data access like a real
@ -111,7 +150,6 @@
#define M68K_EMULATE_FC OPT_OFF
#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.
@ -124,11 +162,11 @@
* instruction.
*/
#define M68K_INSTRUCTION_HOOK OPT_SPECIFY_HANDLER
#define M68K_INSTRUCTION_CALLBACK() cpu_instr_callback()
#define M68K_INSTRUCTION_CALLBACK(pc) cpu_instr_callback(pc)
/* 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_OFF /*xxx*/
/* If ON, the CPU will generate address error exceptions if it tries to
@ -146,6 +184,9 @@
#define M68K_LOG_1010_1111 OPT_OFF
#define M68K_LOG_FILEHANDLE stderr
/* Emulate PMMU : if you enable this, there will be a test to see if the current chip has some enabled pmmu added to every memory access,
* so enable this only if it's useful */
#define M68K_EMULATE_PMMU OPT_OFF
/* ----------------------------- COMPATIBILITY ---------------------------- */
@ -157,19 +198,9 @@
/* If ON, the enulation core will use 64-bit integers to speed up some
* operations.
*/
#define M68K_USE_64_BIT OPT_OFF
#define M68K_USE_64_BIT OPT_ON
/* 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__
#define INLINE static
#endif /* INLINE */
#endif /* M68K_COMPILE_FOR_MAME */
#include "sim.h"
@ -185,7 +216,6 @@
#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 ============================= */
/* ======================================================================== */

View file

@ -2,23 +2,23 @@ EXENAME = sim
OSD_DOS = osd_dos.c
OSDFILES = $(OSD_DOS)
OSDFILES = osd_linux.c # $(OSD_DOS)
MAINFILES = sim.c
MUSASHIFILES = m68kcpu.c m68kdasm.c
MUSASHIGENCFILES = m68kops.c m68kopac.c m68kopdm.c m68kopnz.c
MUSASHIFILES = m68kcpu.c m68kdasm.c softfloat/softfloat.c
MUSASHIGENCFILES = m68kops.c
MUSASHIGENHFILES = m68kops.h
MUSASHIGENERATOR = m68kmake
EXE = .exe
EXEPATH = .\\
# EXE =
# EXEPATH = ./
# EXE = .exe
# EXEPATH = .\\
EXE =
EXEPATH = ./
.CFILES = $(MAINFILES) $(OSDFILES) $(MUSASHIFILES) $(MUSASHIGENCFILES)
.OFILES = $(.CFILES:%.c=%.o)
CC = gcc
WARNINGS = -Wall -pedantic
WARNINGS = -Wall -Wextra -pedantic
CFLAGS = $(WARNINGS)
LFLAGS = $(WARNINGS)
@ -32,8 +32,8 @@ all: $(TARGET)
clean:
rm -f $(DELETEFILES)
$(TARGET): $(MUSASHIGENHFILES) $(.OFILES) makefile
$(CC) -o $@ $(.OFILES) $(LFLAGS)
$(TARGET): $(MUSASHIGENHFILES) $(.OFILES) Makefile
$(CC) -o $@ $(.OFILES) $(LFLAGS) -lm
$(MUSASHIGENCFILES) $(MUSASHIGENHFILES): $(MUSASHIGENERATOR)$(EXE)
$(EXEPATH)$(MUSASHIGENERATOR)$(EXE)

View file

@ -0,0 +1 @@
../m68k.h

View file

@ -0,0 +1 @@
../m68k_in.c

View file

@ -3,20 +3,28 @@
/* ======================================================================== */
/*
* MUSASHI
* Version 3.4
* Version 3.32
*
* A portable Motorola M680x0 processor emulation engine.
* Copyright 1998-2001 Karl Stenerud. All rights reserved.
* Copyright 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.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* 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
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
@ -59,6 +67,7 @@
#define M68K_EMULATE_010 OPT_ON
#define M68K_EMULATE_EC020 OPT_ON
#define M68K_EMULATE_020 OPT_ON
#define M68K_EMULATE_040 OPT_ON
/* If ON, the CPU will call m68k_read_immediate_xx() for immediate addressing
@ -101,6 +110,35 @@
#define M68K_EMULATE_RESET OPT_SPECIFY_HANDLER
#define M68K_RESET_CALLBACK() cpu_pulse_reset()
/* If ON, CPU will call the callback when it encounters a cmpi.l #v, dn
* instruction.
*/
#define M68K_CMPILD_HAS_CALLBACK OPT_OFF
#define M68K_CMPILD_CALLBACK(v,r) your_cmpild_handler_function(v,r)
/* If ON, CPU will call the callback when it encounters a rte
* instruction.
*/
#define M68K_RTE_HAS_CALLBACK OPT_OFF
#define M68K_RTE_CALLBACK() your_rte_handler_function()
/* If ON, CPU will call the callback when it encounters a tas
* instruction.
*/
#define M68K_TAS_HAS_CALLBACK OPT_OFF
#define M68K_TAS_CALLBACK() your_tas_handler_function()
/* If ON, CPU will call the callback when it encounters an illegal instruction
* passing the opcode as argument. If the callback returns 1, then it's considered
* as a normal instruction, and the illegal exception in canceled. If it returns 0,
* the exception occurs normally.
* The callback looks like int callback(int opcode)
* You should put OPT_SPECIFY_HANDLER here if you cant to use it, otherwise it will
* use a dummy default handler and you'll have to call m68k_set_illg_instr_callback explicitely
*/
#define M68K_ILLG_HAS_CALLBACK OPT_OFF
#define M68K_ILLG_CALLBACK(opcode) op_illg(opcode)
/* If ON, CPU will call the set fc callback on every memory access to
* differentiate between user/supervisor, program/data access like a real
@ -111,7 +149,6 @@
#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.
@ -124,7 +161,7 @@
* instruction.
*/
#define M68K_INSTRUCTION_HOOK OPT_SPECIFY_HANDLER
#define M68K_INSTRUCTION_CALLBACK() cpu_instr_callback()
#define M68K_INSTRUCTION_CALLBACK(pc) cpu_instr_callback(pc)
/* If ON, the CPU will emulate the 4-byte prefetch queue of a real 68000 */
@ -157,20 +194,9 @@
/* If ON, the enulation core will use 64-bit integers to speed up some
* operations.
*/
#define M68K_USE_64_BIT OPT_OFF
#define M68K_USE_64_BIT OPT_ON
/* 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)
@ -185,6 +211,8 @@
#define m68k_write_memory_32(A, V) cpu_write_long(A, V)
#endif /* M68K_COMPILE_FOR_MAME */
/* ======================================================================== */
/* ============================== END OF FILE ============================= */
/* ======================================================================== */

View file

@ -0,0 +1 @@
../m68kcpu.c

View file

@ -0,0 +1 @@
../m68kcpu.h

View file

@ -0,0 +1 @@
../m68kdasm.c

View file

@ -0,0 +1 @@
../m68kfpu.c

View file

@ -0,0 +1 @@
../m68kmake.c

View file

@ -0,0 +1 @@
../m68kmmu.h

View file

@ -0,0 +1,46 @@
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
void changemode(int dir)
{
static struct termios oldt, newt;
if ( dir == 1 )
{
tcgetattr( STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newt);
}
else
tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
}
int kbhit (void)
{
struct timeval tv;
fd_set rdfs;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&rdfs);
FD_SET (STDIN_FILENO, &rdfs);
select(STDIN_FILENO+1, &rdfs, NULL, NULL, &tv);
return FD_ISSET(STDIN_FILENO, &rdfs);
}
int osd_get_char() {
changemode(1);
int ch = -1;
while(kbhit())
ch = getchar();
changemode(0);
return ch;
}

View file

@ -359,6 +359,7 @@ unsigned int input_device_read(void)
void input_device_write(unsigned int value)
{
(void)value;
}
@ -491,8 +492,9 @@ void disassemble_program()
fflush(stdout);
}
void cpu_instr_callback()
void cpu_instr_callback(int pc)
{
(void)pc;
/* The following code would print out instructions as they are executed */
/*
static char buff[100];

View file

@ -10,6 +10,6 @@ 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();
void cpu_instr_callback(int pc);
#endif /* SIM__HEADER */

View file

@ -3,10 +3,10 @@
/* ======================================================================== */
/*
* MUSASHI
* Version 3.4
* Version 3.32
*
* A portable Motorola M680x0 processor emulation engine.
* Copyright 1998-2001 Karl Stenerud. All rights reserved.
* Copyright Karl Stenerud. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -30,14 +30,29 @@
#ifndef M68K__HEADER
#define M68K__HEADER
#ifdef __cplusplus
extern "C" {
#endif
#ifndef ARRAY_LENGTH
#define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0]))
#endif
#ifndef FALSE
#define FALSE 0
#define TRUE 1
#endif
/* ======================================================================== */
/* ============================= CONFIGURATION ============================ */
/* ======================================================================== */
/* Import the configuration for this build */
#ifdef MUSASHI_CNF
#include MUSASHI_CNF
#else
#include "m68kconf.h"
#endif
/* ======================================================================== */
/* ============================ GENERAL DEFINES =========================== */
@ -83,8 +98,12 @@ enum
M68K_CPU_TYPE_68010,
M68K_CPU_TYPE_68EC020,
M68K_CPU_TYPE_68020,
M68K_CPU_TYPE_68030, /* Supported by disassembler ONLY */
M68K_CPU_TYPE_68040 /* Supported by disassembler ONLY */
M68K_CPU_TYPE_68EC030,
M68K_CPU_TYPE_68030,
M68K_CPU_TYPE_68EC040,
M68K_CPU_TYPE_68LC040,
M68K_CPU_TYPE_68040,
M68K_CPU_TYPE_SCC68070
};
/* Registers used by m68k_get_reg() and m68k_set_reg() */
@ -241,6 +260,20 @@ void m68k_set_reset_instr_callback(void (*callback)(void));
*/
void m68k_set_pc_changed_callback(void (*callback)(unsigned int new_pc));
/* Set the callback for the TAS instruction.
* You must enable M68K_TAS_HAS_CALLBACK in m68kconf.h.
* The CPU calls this callback every time it encounters a TAS instruction.
* Default behavior: return 1, allow writeback.
*/
void m68k_set_tas_instr_callback(int (*callback)(void));
/* Set the callback for illegal instructions.
* You must enable M68K_ILLG_HAS_CALLBACK in m68kconf.h.
* The CPU calls this callback every time it encounters an illegal instruction
* which must return 1 if it handles the instruction normally or 0 if it's really an illegal instruction.
* Default behavior: return 0, exception will occur.
*/
void m68k_set_illg_instr_callback(int (*callback)(int));
/* Set the callback for CPU function code changes.
* You must enable M68K_EMULATE_FC in m68kconf.h.
@ -258,7 +291,7 @@ void m68k_set_fc_callback(void (*callback)(unsigned int new_fc));
* instruction cycle.
* Default behavior: do nothing.
*/
void m68k_set_instr_hook_callback(void (*callback)(void));
void m68k_set_instr_hook_callback(void (*callback)(unsigned int pc));
@ -304,11 +337,21 @@ void m68k_end_timeslice(void); /* End timeslice now */
*/
void m68k_set_irq(unsigned int int_level);
/* Set the virtual irq lines, where the highest level
* active line is automatically selected. If you use this function,
* do not use m68k_set_irq.
*/
void m68k_set_virq(unsigned int level, unsigned int active);
unsigned int m68k_get_virq(unsigned int level);
/* Halt the CPU as if you pulsed the HALT pin. */
void m68k_pulse_halt(void);
/* Trigger a bus error exception */
void m68k_pulse_bus_error(void);
/* Context switching to allow multiple CPUs */
/* Get the size of the cpu context in bytes */
@ -321,7 +364,7 @@ unsigned int m68k_get_context(void* dst);
void m68k_set_context(void* dst);
/* Register the CPU state information */
void m68k_state_register(const char *type);
void m68k_state_register(const char *type, int index);
/* Peek at the internals of a CPU context. This can either be a context
@ -341,6 +384,11 @@ unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cp
*/
unsigned int m68k_disassemble(char* str_buff, unsigned int pc, unsigned int cpu_type);
/* Same as above but accepts raw opcode data directly rather than fetching
* via the read/write interfaces.
*/
unsigned int m68k_disassemble_raw(char* str_buff, unsigned int pc, const unsigned char* opdata, const unsigned char* argdata, unsigned int cpu_type);
/* ======================================================================== */
/* ============================== MAME STUFF ============================== */
@ -355,4 +403,9 @@ unsigned int m68k_disassemble(char* str_buff, unsigned int pc, unsigned int cpu_
/* ============================== END OF FILE ============================= */
/* ======================================================================== */
#ifdef __cplusplus
}
#endif
#endif /* M68K__HEADER */

File diff suppressed because it is too large Load diff

View file

@ -3,10 +3,10 @@
/* ======================================================================== */
/*
* MUSASHI
* Version 3.4
* Version 3.32
*
* A portable Motorola M680x0 processor emulation engine.
* Copyright 1998-2001 Karl Stenerud. All rights reserved.
* Copyright Karl Stenerud. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -52,7 +52,7 @@
* to OPT_ON and use m68kmame.h to configure the 68k core.
*/
#ifndef M68K_COMPILE_FOR_MAME
#define M68K_COMPILE_FOR_MAME OPT_ON
#define M68K_COMPILE_FOR_MAME OPT_OFF
#endif /* M68K_COMPILE_FOR_MAME */
@ -67,6 +67,8 @@
#define M68K_EMULATE_010 OPT_ON
#define M68K_EMULATE_EC020 OPT_ON
#define M68K_EMULATE_020 OPT_ON
#define M68K_EMULATE_030 OPT_ON
#define M68K_EMULATE_040 OPT_ON
/* If ON, the CPU will call m68k_read_immediate_xx() for immediate addressing
@ -109,6 +111,35 @@
#define M68K_EMULATE_RESET OPT_OFF
#define M68K_RESET_CALLBACK() your_reset_handler_function()
/* If ON, CPU will call the callback when it encounters a cmpi.l #v, dn
* instruction.
*/
#define M68K_CMPILD_HAS_CALLBACK OPT_OFF
#define M68K_CMPILD_CALLBACK(v,r) your_cmpild_handler_function(v,r)
/* If ON, CPU will call the callback when it encounters a rte
* instruction.
*/
#define M68K_RTE_HAS_CALLBACK OPT_OFF
#define M68K_RTE_CALLBACK() your_rte_handler_function()
/* If ON, CPU will call the callback when it encounters a tas
* instruction.
*/
#define M68K_TAS_HAS_CALLBACK OPT_OFF
#define M68K_TAS_CALLBACK() your_tas_handler_function()
/* If ON, CPU will call the callback when it encounters an illegal instruction
* passing the opcode as argument. If the callback returns 1, then it's considered
* as a normal instruction, and the illegal exception in canceled. If it returns 0,
* the exception occurs normally.
* The callback looks like int callback(int opcode)
* You should put OPT_SPECIFY_HANDLER here if you cant to use it, otherwise it will
* use a dummy default handler and you'll have to call m68k_set_illg_instr_callback explicitely
*/
#define M68K_ILLG_HAS_CALLBACK OPT_OFF
#define M68K_ILLG_CALLBACK(opcode) op_illg(opcode)
/* If ON, CPU will call the set fc callback on every memory access to
* differentiate between user/supervisor, program/data access like a real
@ -119,7 +150,6 @@
#define M68K_EMULATE_FC OPT_OFF
#define M68K_SET_FC_CALLBACK(A) your_set_fc_handler_function(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.
@ -132,7 +162,7 @@
* instruction.
*/
#define M68K_INSTRUCTION_HOOK OPT_OFF
#define M68K_INSTRUCTION_CALLBACK() your_instruction_hook_function()
#define M68K_INSTRUCTION_CALLBACK(pc) your_instruction_hook_function(pc)
/* If ON, the CPU will emulate the 4-byte prefetch queue of a real 68000 */
@ -154,6 +184,9 @@
#define M68K_LOG_1010_1111 OPT_OFF
#define M68K_LOG_FILEHANDLE some_file_handle
/* Emulate PMMU : if you enable this, there will be a test to see if the current chip has some enabled pmmu added to every memory access,
* so enable this only if it's useful */
#define M68K_EMULATE_PMMU OPT_ON
/* ----------------------------- COMPATIBILITY ---------------------------- */
@ -165,21 +198,11 @@
/* If ON, the enulation core will use 64-bit integers to speed up some
* operations.
*/
#define M68K_USE_64_BIT OPT_OFF
#define M68K_USE_64_BIT OPT_ON
/* 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 */
/* ======================================================================== */
/* ============================== END OF FILE ============================= */
/* ======================================================================== */

View file

@ -3,10 +3,10 @@
/* ======================================================================== */
/*
* MUSASHI
* Version 3.4
* Version 4.60
*
* A portable Motorola M680x0 processor emulation engine.
* Copyright 1998-2001 Karl Stenerud. All rights reserved.
* Copyright Karl Stenerud. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -38,9 +38,19 @@
/* ================================ INCLUDES ============================== */
/* ======================================================================== */
extern void m68040_fpu_op0(void);
extern void m68040_fpu_op1(void);
extern void m68881_mmu_ops();
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"
#include "m68kfpu.c"
#include "m68kmmu.h" // uses some functions from m68kfpu.c which are static !
/* ======================================================================== */
/* ================================= DATA ================================= */
/* ======================================================================== */
@ -51,7 +61,7 @@ uint m68ki_tracing = 0;
uint m68ki_address_space;
#ifdef M68K_LOG_ENABLE
char* m68ki_cpu_names[9] =
const char *const m68ki_cpu_names[] =
{
"Invalid CPU",
"M68000",
@ -69,15 +79,21 @@ char* m68ki_cpu_names[9] =
m68ki_cpu_core m68ki_cpu = {0};
#if M68K_EMULATE_ADDRESS_ERROR
#ifdef _BSD_SETJMP_H
sigjmp_buf m68ki_aerr_trap;
#else
jmp_buf m68ki_aerr_trap;
#endif
#endif /* M68K_EMULATE_ADDRESS_ERROR */
uint m68ki_aerr_address;
uint m68ki_aerr_write_mode;
uint m68ki_aerr_fc;
jmp_buf m68ki_bus_error_jmp_buf;
/* Used by shift & rotate instructions */
uint8 m68ki_shift_8_table[65] =
const uint8 m68ki_shift_8_table[65] =
{
0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
@ -86,7 +102,7 @@ uint8 m68ki_shift_8_table[65] =
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff
};
uint16 m68ki_shift_16_table[65] =
const uint16 m68ki_shift_16_table[65] =
{
0x0000, 0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff, 0xffff,
@ -97,7 +113,7 @@ uint16 m68ki_shift_16_table[65] =
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff
};
uint m68ki_shift_32_table[65] =
const uint m68ki_shift_32_table[65] =
{
0x00000000, 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 0xf8000000,
0xfc000000, 0xfe000000, 0xff000000, 0xff800000, 0xffc00000, 0xffe00000,
@ -116,16 +132,16 @@ uint m68ki_shift_32_table[65] =
/* Number of clock cycles to use for exception processing.
* I used 4 for any vectors that are undocumented for processing times.
*/
uint8 m68ki_exception_cycle_table[3][256] =
const uint8 m68ki_exception_cycle_table[5][256] =
{
{ /* 000 */
4, /* 0: Reset - Initial Stack Pointer */
40, /* 0: Reset - Initial Stack Pointer */
4, /* 1: Reset - Initial Program Counter */
50, /* 2: Bus Error (unemulated) */
50, /* 3: Address Error (unemulated) */
34, /* 4: Illegal Instruction */
38, /* 5: Divide by Zero -- ASG: changed from 42 */
40, /* 6: CHK -- ASG: chanaged from 44 */
38, /* 5: Divide by Zero */
40, /* 6: CHK */
34, /* 7: TRAPV */
34, /* 8: Privilege Violation */
34, /* 9: Trace */
@ -151,7 +167,7 @@ uint8 m68ki_exception_cycle_table[3][256] =
44, /* 29: Level 5 Interrupt Autovector */
44, /* 30: Level 6 Interrupt Autovector */
44, /* 31: Level 7 Interrupt Autovector */
34, /* 32: TRAP #0 -- ASG: chanaged from 38 */
34, /* 32: TRAP #0 */
34, /* 33: TRAP #1 */
34, /* 34: TRAP #2 */
34, /* 35: TRAP #3 */
@ -192,7 +208,7 @@ uint8 m68ki_exception_cycle_table[3][256] =
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
},
{ /* 010 */
4, /* 0: Reset - Initial Stack Pointer */
40, /* 0: Reset - Initial Stack Pointer */
4, /* 1: Reset - Initial Program Counter */
126, /* 2: Bus Error (unemulated) */
126, /* 3: Address Error (unemulated) */
@ -336,10 +352,156 @@ uint8 m68ki_exception_cycle_table[3][256] =
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
},
{ /* 030 - not correct */
4, /* 0: Reset - Initial Stack Pointer */
4, /* 1: Reset - Initial Program Counter */
50, /* 2: Bus Error (unemulated) */
50, /* 3: Address Error (unemulated) */
20, /* 4: Illegal Instruction */
38, /* 5: Divide by Zero */
40, /* 6: CHK */
20, /* 7: TRAPV */
34, /* 8: Privilege Violation */
25, /* 9: Trace */
20, /* 10: 1010 */
20, /* 11: 1111 */
4, /* 12: RESERVED */
4, /* 13: Coprocessor Protocol Violation (unemulated) */
4, /* 14: Format Error */
30, /* 15: Uninitialized Interrupt */
4, /* 16: RESERVED */
4, /* 17: RESERVED */
4, /* 18: RESERVED */
4, /* 19: RESERVED */
4, /* 20: RESERVED */
4, /* 21: RESERVED */
4, /* 22: RESERVED */
4, /* 23: RESERVED */
30, /* 24: Spurious Interrupt */
30, /* 25: Level 1 Interrupt Autovector */
30, /* 26: Level 2 Interrupt Autovector */
30, /* 27: Level 3 Interrupt Autovector */
30, /* 28: Level 4 Interrupt Autovector */
30, /* 29: Level 5 Interrupt Autovector */
30, /* 30: Level 6 Interrupt Autovector */
30, /* 31: Level 7 Interrupt Autovector */
20, /* 32: TRAP #0 */
20, /* 33: TRAP #1 */
20, /* 34: TRAP #2 */
20, /* 35: TRAP #3 */
20, /* 36: TRAP #4 */
20, /* 37: TRAP #5 */
20, /* 38: TRAP #6 */
20, /* 39: TRAP #7 */
20, /* 40: TRAP #8 */
20, /* 41: TRAP #9 */
20, /* 42: TRAP #10 */
20, /* 43: TRAP #11 */
20, /* 44: TRAP #12 */
20, /* 45: TRAP #13 */
20, /* 46: TRAP #14 */
20, /* 47: TRAP #15 */
4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */
4, /* 49: FP Inexact Result (unemulated) */
4, /* 50: FP Divide by Zero (unemulated) */
4, /* 51: FP Underflow (unemulated) */
4, /* 52: FP Operand Error (unemulated) */
4, /* 53: FP Overflow (unemulated) */
4, /* 54: FP Signaling NAN (unemulated) */
4, /* 55: FP Unimplemented Data Type (unemulated) */
4, /* 56: MMU Configuration Error (unemulated) */
4, /* 57: MMU Illegal Operation Error (unemulated) */
4, /* 58: MMU Access Level Violation Error (unemulated) */
4, /* 59: RESERVED */
4, /* 60: RESERVED */
4, /* 61: RESERVED */
4, /* 62: RESERVED */
4, /* 63: RESERVED */
/* 64-255: User Defined */
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
},
{ /* 040 */ // TODO: these values are not correct
4, /* 0: Reset - Initial Stack Pointer */
4, /* 1: Reset - Initial Program Counter */
50, /* 2: Bus Error (unemulated) */
50, /* 3: Address Error (unemulated) */
20, /* 4: Illegal Instruction */
38, /* 5: Divide by Zero */
40, /* 6: CHK */
20, /* 7: TRAPV */
34, /* 8: Privilege Violation */
25, /* 9: Trace */
20, /* 10: 1010 */
20, /* 11: 1111 */
4, /* 12: RESERVED */
4, /* 13: Coprocessor Protocol Violation (unemulated) */
4, /* 14: Format Error */
30, /* 15: Uninitialized Interrupt */
4, /* 16: RESERVED */
4, /* 17: RESERVED */
4, /* 18: RESERVED */
4, /* 19: RESERVED */
4, /* 20: RESERVED */
4, /* 21: RESERVED */
4, /* 22: RESERVED */
4, /* 23: RESERVED */
30, /* 24: Spurious Interrupt */
30, /* 25: Level 1 Interrupt Autovector */
30, /* 26: Level 2 Interrupt Autovector */
30, /* 27: Level 3 Interrupt Autovector */
30, /* 28: Level 4 Interrupt Autovector */
30, /* 29: Level 5 Interrupt Autovector */
30, /* 30: Level 6 Interrupt Autovector */
30, /* 31: Level 7 Interrupt Autovector */
20, /* 32: TRAP #0 */
20, /* 33: TRAP #1 */
20, /* 34: TRAP #2 */
20, /* 35: TRAP #3 */
20, /* 36: TRAP #4 */
20, /* 37: TRAP #5 */
20, /* 38: TRAP #6 */
20, /* 39: TRAP #7 */
20, /* 40: TRAP #8 */
20, /* 41: TRAP #9 */
20, /* 42: TRAP #10 */
20, /* 43: TRAP #11 */
20, /* 44: TRAP #12 */
20, /* 45: TRAP #13 */
20, /* 46: TRAP #14 */
20, /* 47: TRAP #15 */
4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */
4, /* 49: FP Inexact Result (unemulated) */
4, /* 50: FP Divide by Zero (unemulated) */
4, /* 51: FP Underflow (unemulated) */
4, /* 52: FP Operand Error (unemulated) */
4, /* 53: FP Overflow (unemulated) */
4, /* 54: FP Signaling NAN (unemulated) */
4, /* 55: FP Unimplemented Data Type (unemulated) */
4, /* 56: MMU Configuration Error (unemulated) */
4, /* 57: MMU Illegal Operation Error (unemulated) */
4, /* 58: MMU Access Level Violation Error (unemulated) */
4, /* 59: RESERVED */
4, /* 60: RESERVED */
4, /* 61: RESERVED */
4, /* 62: RESERVED */
4, /* 63: RESERVED */
/* 64-255: User Defined */
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
}
};
uint8 m68ki_ea_idx_cycle_table[64] =
const uint8 m68ki_ea_idx_cycle_table[64] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, /* ..01.000 no memory indirect, base NULL */
@ -390,6 +552,31 @@ static void default_reset_instr_callback(void)
{
}
/* Called when a cmpi.l #v, dn instruction is executed */
static void default_cmpild_instr_callback(unsigned int val, int reg)
{
(void)val;
(void)reg;
}
/* Called when a rte instruction is executed */
static void default_rte_instr_callback(void)
{
}
/* Called when a tas instruction is executed */
static int default_tas_instr_callback(void)
{
return 1; // allow writeback
}
/* Called when an illegal instruction is encountered */
static int default_illg_instr_callback(int opcode)
{
(void)opcode;
return 0; // not handled : exception will occur
}
/* Called when the program counter changed by a large value */
static unsigned int default_pc_changed_callback_data;
static void default_pc_changed_callback(unsigned int new_pc)
@ -405,8 +592,9 @@ static void default_set_fc_callback(unsigned int new_fc)
}
/* Called every instruction cycle prior to execution */
static void default_instr_hook_callback(void)
static void default_instr_hook_callback(unsigned int pc)
{
(void)pc;
}
@ -415,7 +603,6 @@ static void default_instr_hook_callback(void)
jmp_buf m68ki_aerr_trap;
#endif /* M68K_EMULATE_ADDRESS_ERROR */
/* ======================================================================== */
/* ================================= API ================================== */
/* ======================================================================== */
@ -474,6 +661,7 @@ unsigned int m68k_get_reg(void* context, m68k_register_t regnum)
case CPU_TYPE_010: return (unsigned int)M68K_CPU_TYPE_68010;
case CPU_TYPE_EC020: return (unsigned int)M68K_CPU_TYPE_68EC020;
case CPU_TYPE_020: return (unsigned int)M68K_CPU_TYPE_68020;
case CPU_TYPE_040: return (unsigned int)M68K_CPU_TYPE_68040;
}
return M68K_CPU_TYPE_INVALID;
default: return 0;
@ -502,7 +690,7 @@ void m68k_set_reg(m68k_register_t regnum, unsigned int value)
case M68K_REG_A6: REG_A[6] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_A7: REG_A[7] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_PC: m68ki_jump(MASK_OUT_ABOVE_32(value)); return;
case M68K_REG_SR: m68ki_set_sr(value); return;
case M68K_REG_SR: m68ki_set_sr_noint_nosp(value); return;
case M68K_REG_SP: REG_SP = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_USP: if(FLAG_S)
REG_USP = MASK_OUT_ABOVE_32(value);
@ -547,6 +735,26 @@ void m68k_set_reset_instr_callback(void (*callback)(void))
CALLBACK_RESET_INSTR = callback ? callback : default_reset_instr_callback;
}
void m68k_set_cmpild_instr_callback(void (*callback)(unsigned int, int))
{
CALLBACK_CMPILD_INSTR = callback ? callback : default_cmpild_instr_callback;
}
void m68k_set_rte_instr_callback(void (*callback)(void))
{
CALLBACK_RTE_INSTR = callback ? callback : default_rte_instr_callback;
}
void m68k_set_tas_instr_callback(int (*callback)(void))
{
CALLBACK_TAS_INSTR = callback ? callback : default_tas_instr_callback;
}
void m68k_set_illg_instr_callback(int (*callback)(int))
{
CALLBACK_ILLG_INSTR = callback ? callback : default_illg_instr_callback;
}
void m68k_set_pc_changed_callback(void (*callback)(unsigned int new_pc))
{
CALLBACK_PC_CHANGED = callback ? callback : default_pc_changed_callback;
@ -557,7 +765,7 @@ void m68k_set_fc_callback(void (*callback)(unsigned int new_fc))
CALLBACK_SET_FC = callback ? callback : default_set_fc_callback;
}
void m68k_set_instr_hook_callback(void (*callback)(void))
void m68k_set_instr_hook_callback(void (*callback)(unsigned int pc))
{
CALLBACK_INSTR_HOOK = callback ? callback : default_instr_hook_callback;
}
@ -582,6 +790,12 @@ void m68k_set_cpu_type(unsigned int cpu_type)
CYC_MOVEM_L = 3;
CYC_SHIFT = 1;
CYC_RESET = 132;
HAS_PMMU = 0;
return;
case M68K_CPU_TYPE_SCC68070:
m68k_set_cpu_type(M68K_CPU_TYPE_68010);
CPU_ADDRESS_MASK = 0xffffffff;
CPU_TYPE = CPU_TYPE_SCC070;
return;
case M68K_CPU_TYPE_68010:
CPU_TYPE = CPU_TYPE_010;
@ -598,6 +812,7 @@ void m68k_set_cpu_type(unsigned int cpu_type)
CYC_MOVEM_L = 3;
CYC_SHIFT = 1;
CYC_RESET = 130;
HAS_PMMU = 0;
return;
case M68K_CPU_TYPE_68EC020:
CPU_TYPE = CPU_TYPE_EC020;
@ -614,6 +829,7 @@ void m68k_set_cpu_type(unsigned int cpu_type)
CYC_MOVEM_L = 2;
CYC_SHIFT = 0;
CYC_RESET = 518;
HAS_PMMU = 0;
return;
case M68K_CPU_TYPE_68020:
CPU_TYPE = CPU_TYPE_020;
@ -630,6 +846,91 @@ void m68k_set_cpu_type(unsigned int cpu_type)
CYC_MOVEM_L = 2;
CYC_SHIFT = 0;
CYC_RESET = 518;
HAS_PMMU = 0;
return;
case M68K_CPU_TYPE_68030:
CPU_TYPE = 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_EXCEPTION = m68ki_exception_cycle_table[3];
CYC_BCC_NOTAKE_B = -2;
CYC_BCC_NOTAKE_W = 0;
CYC_DBCC_F_NOEXP = 0;
CYC_DBCC_F_EXP = 4;
CYC_SCC_R_TRUE = 0;
CYC_MOVEM_W = 2;
CYC_MOVEM_L = 2;
CYC_SHIFT = 0;
CYC_RESET = 518;
HAS_PMMU = 1;
return;
case M68K_CPU_TYPE_68EC030:
CPU_TYPE = 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_EXCEPTION = m68ki_exception_cycle_table[3];
CYC_BCC_NOTAKE_B = -2;
CYC_BCC_NOTAKE_W = 0;
CYC_DBCC_F_NOEXP = 0;
CYC_DBCC_F_EXP = 4;
CYC_SCC_R_TRUE = 0;
CYC_MOVEM_W = 2;
CYC_MOVEM_L = 2;
CYC_SHIFT = 0;
CYC_RESET = 518;
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_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_EXCEPTION = m68ki_exception_cycle_table[4];
CYC_BCC_NOTAKE_B = -2;
CYC_BCC_NOTAKE_W = 0;
CYC_DBCC_F_NOEXP = 0;
CYC_DBCC_F_EXP = 4;
CYC_SCC_R_TRUE = 0;
CYC_MOVEM_W = 2;
CYC_MOVEM_L = 2;
CYC_SHIFT = 0;
CYC_RESET = 518;
HAS_PMMU = 1;
return;
case M68K_CPU_TYPE_68EC040: // Just a 68040 without pmmu apparently...
CPU_TYPE = 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_EXCEPTION = m68ki_exception_cycle_table[4];
CYC_BCC_NOTAKE_B = -2;
CYC_BCC_NOTAKE_W = 0;
CYC_DBCC_F_NOEXP = 0;
CYC_DBCC_F_EXP = 4;
CYC_SCC_R_TRUE = 0;
CYC_MOVEM_W = 2;
CYC_MOVEM_L = 2;
CYC_SHIFT = 0;
CYC_RESET = 518;
HAS_PMMU = 0;
return;
case M68K_CPU_TYPE_68LC040:
CPU_TYPE = 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];
m68ki_cpu.cyc_exception = m68ki_exception_cycle_table[4];
m68ki_cpu.cyc_bcc_notake_b = -2;
m68ki_cpu.cyc_bcc_notake_w = 0;
m68ki_cpu.cyc_dbcc_f_noexp = 0;
m68ki_cpu.cyc_dbcc_f_exp = 4;
m68ki_cpu.cyc_scc_r_true = 0;
m68ki_cpu.cyc_movem_w = 2;
m68ki_cpu.cyc_movem_l = 2;
m68ki_cpu.cyc_shift = 0;
m68ki_cpu.cyc_reset = 518;
HAS_PMMU = 1;
return;
}
}
@ -638,23 +939,34 @@ void m68k_set_cpu_type(unsigned int cpu_type)
/* ASG: removed per-instruction interrupt checks */
int m68k_execute(int num_cycles)
{
/* Make sure we're not stopped */
if(!CPU_STOPPED)
{
/* eat up any reset cycles */
if (RESET_CYCLES) {
int rc = RESET_CYCLES;
RESET_CYCLES = 0;
num_cycles -= rc;
if (num_cycles <= 0)
return rc;
}
/* Set our pool of clock cycles available */
SET_CYCLES(num_cycles);
m68ki_initial_cycles = num_cycles;
/* ASG: update cycles */
USE_CYCLES(CPU_INT_CYCLES);
CPU_INT_CYCLES = 0;
/* See if interrupts came in */
m68ki_check_interrupts();
/* Make sure we're not stopped */
if(!CPU_STOPPED)
{
/* Return point if we had an address error */
m68ki_set_address_error_trap(); /* auto-disable (see m68kcpu.h) */
m68ki_check_bus_error_trap();
/* 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) */
@ -662,11 +974,16 @@ int m68k_execute(int num_cycles)
m68ki_use_data_space(); /* auto-disable (see m68kcpu.h) */
/* Call external hook to peek at CPU */
m68ki_instr_hook(); /* auto-disable (see m68kcpu.h) */
m68ki_instr_hook(REG_PC); /* auto-disable (see m68kcpu.h) */
/* Record previous program counter */
REG_PPC = REG_PC;
/* Record previous D/A register state (in case of bus error) */
for (i = 15; i >= 0; i--){
REG_DA_SAVE[i] = REG_DA[i];
}
/* Read an instruction and call its handler */
REG_IR = m68ki_read_imm_16();
m68ki_instruction_jump_table[REG_IR]();
@ -678,22 +995,14 @@ int m68k_execute(int num_cycles)
/* set previous PC to current PC for the next entry into the loop */
REG_PPC = REG_PC;
/* ASG: update cycles */
USE_CYCLES(CPU_INT_CYCLES);
CPU_INT_CYCLES = 0;
}
else
SET_CYCLES(0);
/* return how many clocks we used */
return m68ki_initial_cycles - GET_CYCLES();
}
/* We get here if the CPU is stopped or halted */
SET_CYCLES(0);
CPU_INT_CYCLES = 0;
return num_cycles;
}
int m68k_cycles_run(void)
{
@ -732,9 +1041,29 @@ void m68k_set_irq(unsigned int int_level)
/* A transition from < 7 to 7 always interrupts (NMI) */
/* Note: Level 7 can also level trigger like a normal IRQ */
if(old_level != 0x0700 && CPU_INT_LEVEL == 0x0700)
m68ki_exception_interrupt(7); /* Edge triggered level 7 (NMI) */
m68ki_cpu.nmi_pending = TRUE;
}
void m68k_set_virq(unsigned int level, unsigned int active)
{
uint state = m68ki_cpu.virq_state;
uint blevel;
if(active)
state |= 1 << level;
else
m68ki_check_interrupts(); /* Level triggered (IRQ) */
state &= ~(1 << level);
m68ki_cpu.virq_state = state;
for(blevel = 7; blevel > 0; blevel--)
if(state & (1 << blevel))
break;
m68k_set_irq(blevel);
}
unsigned int m68k_get_virq(unsigned int level)
{
return (m68ki_cpu.virq_state & (1 << level)) ? 1 : 0;
}
void m68k_init(void)
@ -751,14 +1080,27 @@ void m68k_init(void)
m68k_set_int_ack_callback(NULL);
m68k_set_bkpt_ack_callback(NULL);
m68k_set_reset_instr_callback(NULL);
m68k_set_cmpild_instr_callback(NULL);
m68k_set_rte_instr_callback(NULL);
m68k_set_tas_instr_callback(NULL);
m68k_set_illg_instr_callback(NULL);
m68k_set_pc_changed_callback(NULL);
m68k_set_fc_callback(NULL);
m68k_set_instr_hook_callback(NULL);
}
/* Trigger a Bus Error exception */
void m68k_pulse_bus_error(void)
{
m68ki_exception_bus_error();
}
/* Pulse the RESET line on the CPU */
void m68k_pulse_reset(void)
{
/* Disable the PMMU on reset */
m68ki_cpu.pmmu_enabled = 0;
/* Clear all stop levels and eat up all remaining cycles */
CPU_STOPPED = 0;
SET_CYCLES(0);
@ -771,6 +1113,8 @@ void m68k_pulse_reset(void)
m68ki_clear_trace();
/* Interrupt mask to level 7 */
FLAG_INT_MASK = 0x0700;
CPU_INT_LEVEL = 0;
m68ki_cpu.virq_state = 0;
/* Reset VBR */
REG_VBR = 0;
/* Go to supervisor mode */
@ -789,6 +1133,8 @@ void m68k_pulse_reset(void)
m68ki_jump(REG_PC);
CPU_RUN_MODE = RUN_MODE_NORMAL;
RESET_CYCLES = CYC_EXCEPTION[EXCEPTION_RESET];
}
/* Pulse the HALT line on the CPU */
@ -797,7 +1143,6 @@ void m68k_pulse_halt(void)
CPU_STOPPED |= STOP_LEVEL_HALT;
}
/* Get and set the current CPU context */
/* This is to allow for multiple CPUs */
unsigned int m68k_context_size()
@ -816,20 +1161,16 @@ void m68k_set_context(void* src)
if(src) m68ki_cpu = *(m68ki_cpu_core*)src;
}
/* ======================================================================== */
/* ============================== MAME STUFF ============================== */
/* ======================================================================== */
#if M68K_COMPILE_FOR_MAME == OPT_ON
#include "state.h"
static struct {
UINT16 sr;
int stopped;
int halted;
UINT8 stopped;
UINT8 halted;
} m68k_substate;
static void m68k_prepare_substate(void)
@ -847,29 +1188,26 @@ static void m68k_post_load(void)
m68ki_jump(REG_PC);
}
void m68k_state_register(const char *type)
void m68k_state_register(const char *type, int index)
{
int cpu = cpu_getactivecpu();
state_save_register_UINT32(type, cpu, "D" , REG_D, 8);
state_save_register_UINT32(type, cpu, "A" , REG_A, 8);
state_save_register_UINT32(type, cpu, "PPC" , &REG_PPC, 1);
state_save_register_UINT32(type, cpu, "PC" , &REG_PC, 1);
state_save_register_UINT32(type, cpu, "USP" , &REG_USP, 1);
state_save_register_UINT32(type, cpu, "ISP" , &REG_ISP, 1);
state_save_register_UINT32(type, cpu, "MSP" , &REG_MSP, 1);
state_save_register_UINT32(type, cpu, "VBR" , &REG_VBR, 1);
state_save_register_UINT32(type, cpu, "SFC" , &REG_SFC, 1);
state_save_register_UINT32(type, cpu, "DFC" , &REG_DFC, 1);
state_save_register_UINT32(type, cpu, "CACR" , &REG_CACR, 1);
state_save_register_UINT32(type, cpu, "CAAR" , &REG_CAAR, 1);
state_save_register_UINT16(type, cpu, "SR" , &m68k_substate.sr, 1);
state_save_register_UINT32(type, cpu, "INT_LEVEL" , &CPU_INT_LEVEL, 1);
state_save_register_UINT32(type, cpu, "INT_CYCLES", &CPU_INT_CYCLES, 1);
state_save_register_int (type, cpu, "STOPPED" , &m68k_substate.stopped);
state_save_register_int (type, cpu, "HALTED" , &m68k_substate.halted);
state_save_register_UINT32(type, cpu, "PREF_ADDR" , &CPU_PREF_ADDR, 1);
state_save_register_UINT32(type, cpu, "PREF_DATA" , &CPU_PREF_DATA, 1);
/* Note, D covers A because the dar array is common, REG_A=REG_D+8 */
state_save_register_item_array(type, index, REG_D);
state_save_register_item(type, index, REG_PPC);
state_save_register_item(type, index, REG_PC);
state_save_register_item(type, index, REG_USP);
state_save_register_item(type, index, REG_ISP);
state_save_register_item(type, index, REG_MSP);
state_save_register_item(type, index, REG_VBR);
state_save_register_item(type, index, REG_SFC);
state_save_register_item(type, index, REG_DFC);
state_save_register_item(type, index, REG_CACR);
state_save_register_item(type, index, REG_CAAR);
state_save_register_item(type, index, m68k_substate.sr);
state_save_register_item(type, index, CPU_INT_LEVEL);
state_save_register_item(type, index, m68k_substate.stopped);
state_save_register_item(type, index, m68k_substate.halted);
state_save_register_item(type, index, CPU_PREF_ADDR);
state_save_register_item(type, index, CPU_PREF_DATA);
state_save_register_func_presave(m68k_prepare_substate);
state_save_register_func_postload(m68k_post_load);
}

File diff suppressed because it is too large Load diff

View file

@ -3,10 +3,10 @@
/* ======================================================================== */
/*
* MUSASHI
* Version 3.4
* Version 3.32
*
* A portable Motorola M680x0 processor emulation engine.
* Copyright 1998-2001 Karl Stenerud. All rights reserved.
* Copyright Karl Stenerud. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -38,6 +38,14 @@
#include <string.h>
#include "m68k.h"
#ifndef uint32
#define uint32 uint
#endif
#ifndef uint16
#define uint16 unsigned short
#endif
#ifndef DECL_SPEC
#define DECL_SPEC
#endif
@ -129,6 +137,15 @@
#define EXT_OUTER_DISPLACEMENT_LONG(A) (((A)&3) == 3 && ((A)&0x47) < 0x44)
/* Opcode flags */
#if M68K_COMPILE_FOR_MAME == OPT_ON
#define SET_OPCODE_FLAGS(x) g_opcode_type = x;
#define COMBINE_OPCODE_FLAGS(x) ((x) | g_opcode_type | DASMFLAG_SUPPORTED)
#else
#define SET_OPCODE_FLAGS(x)
#define COMBINE_OPCODE_FLAGS(X) (X)
#endif
/* ======================================================================== */
/* =============================== PROTOTYPES ============================= */
@ -147,6 +164,7 @@ uint peek_imm_32(void);
/* make signed integers 100% portably */
static int make_int_8(int value);
static int make_int_16(int value);
static int make_int_32(int value);
/* make a string of a hex value */
static char* make_signed_hex_str_8(uint val);
@ -201,20 +219,23 @@ static char g_helper_str[100]; /* string to hold helpful info */
static uint g_cpu_pc; /* program counter */
static uint g_cpu_ir; /* instruction register */
static uint g_cpu_type;
static uint g_opcode_type;
static const unsigned char* g_rawop;
static uint g_rawbasepc;
/* used by ops like asr, ror, addq, etc */
static uint g_3bit_qdata_table[8] = {8, 1, 2, 3, 4, 5, 6, 7};
static const uint g_3bit_qdata_table[8] = {8, 1, 2, 3, 4, 5, 6, 7};
static uint g_5bit_data_table[32] =
static const uint g_5bit_data_table[32] =
{
32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
};
static char* g_cc[16] =
static const char *const g_cc[16] =
{"t", "f", "hi", "ls", "cc", "cs", "ne", "eq", "vc", "vs", "pl", "mi", "ge", "lt", "gt", "le"};
static char* g_cpcc[64] =
static const char *const g_cpcc[64] =
{/* 000 001 010 011 100 101 110 111 */
"f", "eq", "ogt", "oge", "olt", "ole", "ogl", "or", /* 000 */
"un", "ueq", "ugt", "uge", "ult", "ule", "ne", "t", /* 001 */
@ -226,6 +247,16 @@ static char* g_cpcc[64] =
"?", "?", "?", "?", "?", "?", "?", "?" /* 111 */
};
static const char *const g_mmuregs[8] =
{
"tc", "drp", "srp", "crp", "cal", "val", "sccr", "acr"
};
static const char *const g_mmucond[16] =
{
"bs", "bc", "ls", "lc", "ss", "sc", "as", "ac",
"ws", "wc", "is", "ic", "gs", "gc", "cs", "cc"
};
/* ======================================================================== */
/* =========================== UTILITY FUNCTIONS ========================== */
@ -234,17 +265,56 @@ static char* g_cpcc[64] =
#define LIMIT_CPU_TYPES(ALLOWED_CPU_TYPES) \
if(!(g_cpu_type & ALLOWED_CPU_TYPES)) \
{ \
d68000_illegal(); \
if((g_cpu_ir & 0xf000) == 0xf000) \
d68000_1111(); \
else d68000_illegal(); \
return; \
}
#define read_imm_8() (m68k_read_disassembler_16(((g_cpu_pc+=2)-2)&g_address_mask)&0xff)
#define read_imm_16() m68k_read_disassembler_16(((g_cpu_pc+=2)-2)&g_address_mask)
#define read_imm_32() m68k_read_disassembler_32(((g_cpu_pc+=4)-4)&g_address_mask)
static uint dasm_read_imm_8(uint advance)
{
uint result;
if (g_rawop)
result = g_rawop[g_cpu_pc + 1 - g_rawbasepc];
else
result = m68k_read_disassembler_16(g_cpu_pc & g_address_mask) & 0xff;
g_cpu_pc += advance;
return result;
}
#define peek_imm_8() (m68k_read_disassembler_16(g_cpu_pc & g_address_mask)&0xff)
#define peek_imm_16() m68k_read_disassembler_16(g_cpu_pc & g_address_mask)
#define peek_imm_32() m68k_read_disassembler_32(g_cpu_pc & g_address_mask)
static uint dasm_read_imm_16(uint advance)
{
uint result;
if (g_rawop)
result = (g_rawop[g_cpu_pc + 0 - g_rawbasepc] << 8) |
g_rawop[g_cpu_pc + 1 - g_rawbasepc];
else
result = m68k_read_disassembler_16(g_cpu_pc & g_address_mask) & 0xffff;
g_cpu_pc += advance;
return result;
}
static uint dasm_read_imm_32(uint advance)
{
uint result;
if (g_rawop)
result = (g_rawop[g_cpu_pc + 0 - g_rawbasepc] << 24) |
(g_rawop[g_cpu_pc + 1 - g_rawbasepc] << 16) |
(g_rawop[g_cpu_pc + 2 - g_rawbasepc] << 8) |
g_rawop[g_cpu_pc + 3 - g_rawbasepc];
else
result = m68k_read_disassembler_32(g_cpu_pc & g_address_mask) & 0xffffffff;
g_cpu_pc += advance;
return result;
}
#define read_imm_8() dasm_read_imm_8(2)
#define read_imm_16() dasm_read_imm_16(2)
#define read_imm_32() dasm_read_imm_32(4)
#define peek_imm_8() dasm_read_imm_8(0)
#define peek_imm_16() dasm_read_imm_16(0)
#define peek_imm_32() dasm_read_imm_32(0)
/* Fake a split interface */
#define get_ea_mode_str_8(instruction) get_ea_mode_str(instruction, 0)
@ -259,6 +329,11 @@ static char* g_cpcc[64] =
#define get_imm_str_u16() get_imm_str_u(1)
#define get_imm_str_u32() get_imm_str_u(2)
static int sext_7bit_int(int value)
{
return (value & 0x40) ? (value | 0xffffff80) : (value & 0x7f);
}
/* 100% portable signed int generators */
static int make_int_8(int value)
@ -271,6 +346,10 @@ static int make_int_16(int value)
return (value & 0x8000) ? value | ~0xffff : value & 0xffff;
}
static int make_int_32(int value)
{
return (value & 0x80000000) ? value | ~0xffffffff : value & 0xffffffff;
}
/* Get string representation of hex values */
static char* make_signed_hex_str_8(uint val)
@ -424,8 +503,15 @@ static char* get_ea_mode_str(uint instruction, uint size)
if(preindex || postindex)
strcat(mode, "[");
if(base)
{
if (EXT_BASE_DISPLACEMENT_LONG(extension))
{
strcat(mode, make_signed_hex_str_32(base));
}
else
{
strcat(mode, make_signed_hex_str_16(base));
}
comma = 1;
}
if(*base_reg)
@ -875,20 +961,20 @@ static void d68000_asl_ea(void)
static void d68000_bcc_8(void)
{
uint temp_pc = g_cpu_pc;
sprintf(g_dasm_str, "b%-2s %x", g_cc[(g_cpu_ir>>8)&0xf], temp_pc + make_int_8(g_cpu_ir));
sprintf(g_dasm_str, "b%-2s $%x", g_cc[(g_cpu_ir>>8)&0xf], temp_pc + make_int_8(g_cpu_ir));
}
static void d68000_bcc_16(void)
{
uint temp_pc = g_cpu_pc;
sprintf(g_dasm_str, "b%-2s %x", g_cc[(g_cpu_ir>>8)&0xf], temp_pc + make_int_16(read_imm_16()));
sprintf(g_dasm_str, "b%-2s $%x", g_cc[(g_cpu_ir>>8)&0xf], temp_pc + make_int_16(read_imm_16()));
}
static void d68020_bcc_32(void)
{
uint temp_pc = g_cpu_pc;
LIMIT_CPU_TYPES(M68020_PLUS);
sprintf(g_dasm_str, "b%-2s %x; (2+)", g_cc[(g_cpu_ir>>8)&0xf], temp_pc + read_imm_32());
sprintf(g_dasm_str, "b%-2s $%x; (2+)", g_cc[(g_cpu_ir>>8)&0xf], temp_pc + read_imm_32());
}
static void d68000_bchg_r(void)
@ -1090,20 +1176,20 @@ static void d68020_bftst(void)
static void d68000_bra_8(void)
{
uint temp_pc = g_cpu_pc;
sprintf(g_dasm_str, "bra %x", temp_pc + make_int_8(g_cpu_ir));
sprintf(g_dasm_str, "bra $%x", temp_pc + make_int_8(g_cpu_ir));
}
static void d68000_bra_16(void)
{
uint temp_pc = g_cpu_pc;
sprintf(g_dasm_str, "bra %x", temp_pc + make_int_16(read_imm_16()));
sprintf(g_dasm_str, "bra $%x", temp_pc + make_int_16(read_imm_16()));
}
static void d68020_bra_32(void)
{
uint temp_pc = g_cpu_pc;
LIMIT_CPU_TYPES(M68020_PLUS);
sprintf(g_dasm_str, "bra %x; (2+)", temp_pc + read_imm_32());
sprintf(g_dasm_str, "bra $%x; (2+)", temp_pc + read_imm_32());
}
static void d68000_bset_r(void)
@ -1120,20 +1206,23 @@ static void d68000_bset_s(void)
static void d68000_bsr_8(void)
{
uint temp_pc = g_cpu_pc;
sprintf(g_dasm_str, "bsr %x", temp_pc + make_int_8(g_cpu_ir));
sprintf(g_dasm_str, "bsr $%x", temp_pc + make_int_8(g_cpu_ir));
SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER);
}
static void d68000_bsr_16(void)
{
uint temp_pc = g_cpu_pc;
sprintf(g_dasm_str, "bsr %x", temp_pc + make_int_16(read_imm_16()));
sprintf(g_dasm_str, "bsr $%x", temp_pc + make_int_16(read_imm_16()));
SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER);
}
static void d68020_bsr_32(void)
{
uint temp_pc = g_cpu_pc;
LIMIT_CPU_TYPES(M68020_PLUS);
sprintf(g_dasm_str, "bsr %x; (2+)", temp_pc + peek_imm_32());
sprintf(g_dasm_str, "bsr $%x; (2+)", temp_pc + read_imm_32());
SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER);
}
static void d68000_btst_r(void)
@ -1211,12 +1300,14 @@ static void d68020_cas2_32(void)
static void d68000_chk_16(void)
{
sprintf(g_dasm_str, "chk.w %s, D%d", get_ea_mode_str_16(g_cpu_ir), (g_cpu_ir>>9)&7);
SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER);
}
static void d68020_chk_32(void)
{
LIMIT_CPU_TYPES(M68020_PLUS);
sprintf(g_dasm_str, "chk.l %s, D%d; (2+)", get_ea_mode_str_32(g_cpu_ir), (g_cpu_ir>>9)&7);
SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER);
}
static void d68020_chk2_cmp2_8(void)
@ -1392,7 +1483,7 @@ static void d68020_cpbcc_16(void)
uint new_pc = g_cpu_pc;
LIMIT_CPU_TYPES(M68020_PLUS);
extension = read_imm_16();
new_pc += make_int_16(peek_imm_16());
new_pc += make_int_16(read_imm_16());
sprintf(g_dasm_str, "%db%-4s %s; %x (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[g_cpu_ir&0x3f], get_imm_str_s16(), new_pc, extension);
}
@ -1402,7 +1493,7 @@ static void d68020_cpbcc_32(void)
uint new_pc = g_cpu_pc;
LIMIT_CPU_TYPES(M68020_PLUS);
extension = read_imm_16();
new_pc += peek_imm_32();
new_pc += read_imm_32();
sprintf(g_dasm_str, "%db%-4s %s; %x (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[g_cpu_ir&0x3f], get_imm_str_s16(), new_pc, extension);
}
@ -1414,7 +1505,7 @@ static void d68020_cpdbcc(void)
LIMIT_CPU_TYPES(M68020_PLUS);
extension1 = read_imm_16();
extension2 = read_imm_16();
new_pc += make_int_16(peek_imm_16());
new_pc += make_int_16(read_imm_16());
sprintf(g_dasm_str, "%ddb%-4s D%d,%s; %x (extension = %x) (2-3)", (g_cpu_ir>>9)&7, g_cpcc[extension1&0x3f], g_cpu_ir&7, get_imm_str_s16(), new_pc, extension2);
}
@ -1427,14 +1518,28 @@ static void d68020_cpgen(void)
static void d68020_cprestore(void)
{
LIMIT_CPU_TYPES(M68020_PLUS);
if (((g_cpu_ir>>9)&7) == 1)
{
sprintf(g_dasm_str, "frestore %s", get_ea_mode_str_8(g_cpu_ir));
}
else
{
sprintf(g_dasm_str, "%drestore %s; (2-3)", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir));
}
}
static void d68020_cpsave(void)
{
LIMIT_CPU_TYPES(M68020_PLUS);
if (((g_cpu_ir>>9)&7) == 1)
{
sprintf(g_dasm_str, "fsave %s", get_ea_mode_str_8(g_cpu_ir));
}
else
{
sprintf(g_dasm_str, "%dsave %s; (2-3)", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir));
}
}
static void d68020_cpscc(void)
{
@ -1499,13 +1604,15 @@ static void d68040_cpush(void)
static void d68000_dbra(void)
{
uint temp_pc = g_cpu_pc;
sprintf(g_dasm_str, "dbra D%d, %x", g_cpu_ir & 7, temp_pc + make_int_16(read_imm_16()));
sprintf(g_dasm_str, "dbra D%d, $%x", g_cpu_ir & 7, temp_pc + make_int_16(read_imm_16()));
SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER);
}
static void d68000_dbcc(void)
{
uint temp_pc = g_cpu_pc;
sprintf(g_dasm_str, "db%-2s D%d, %x", g_cc[(g_cpu_ir>>8)&0xf], g_cpu_ir & 7, temp_pc + make_int_16(read_imm_16()));
sprintf(g_dasm_str, "db%-2s D%d, $%x", g_cc[(g_cpu_ir>>8)&0xf], g_cpu_ir & 7, temp_pc + make_int_16(read_imm_16()));
SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER);
}
static void d68000_divs(void)
@ -1606,6 +1713,220 @@ static void d68020_extb_32(void)
sprintf(g_dasm_str, "extb.l D%d; (2+)", g_cpu_ir&7);
}
static void d68040_fpu(void)
{
char float_data_format[8][3] =
{
".l", ".s", ".x", ".p", ".w", ".d", ".b", ".p"
};
char mnemonic[40];
uint32 w2, src, dst_reg;
LIMIT_CPU_TYPES(M68030_PLUS);
w2 = read_imm_16();
src = (w2 >> 10) & 0x7;
dst_reg = (w2 >> 7) & 0x7;
// special override for FMOVECR
if ((((w2 >> 13) & 0x7) == 2) && (((w2>>10)&0x7) == 7))
{
sprintf(g_dasm_str, "fmovecr #$%0x, fp%d", (w2&0x7f), dst_reg);
return;
}
switch ((w2 >> 13) & 0x7)
{
case 0x0:
case 0x2:
{
switch(w2 & 0x7f)
{
case 0x00: sprintf(mnemonic, "fmove"); break;
case 0x01: sprintf(mnemonic, "fint"); break;
case 0x02: sprintf(mnemonic, "fsinh"); break;
case 0x03: sprintf(mnemonic, "fintrz"); break;
case 0x04: sprintf(mnemonic, "fsqrt"); break;
case 0x06: sprintf(mnemonic, "flognp1"); break;
case 0x08: sprintf(mnemonic, "fetoxm1"); break;
case 0x09: sprintf(mnemonic, "ftanh1"); break;
case 0x0a: sprintf(mnemonic, "fatan"); break;
case 0x0c: sprintf(mnemonic, "fasin"); break;
case 0x0d: sprintf(mnemonic, "fatanh"); break;
case 0x0e: sprintf(mnemonic, "fsin"); break;
case 0x0f: sprintf(mnemonic, "ftan"); break;
case 0x10: sprintf(mnemonic, "fetox"); break;
case 0x11: sprintf(mnemonic, "ftwotox"); break;
case 0x12: sprintf(mnemonic, "ftentox"); break;
case 0x14: sprintf(mnemonic, "flogn"); break;
case 0x15: sprintf(mnemonic, "flog10"); break;
case 0x16: sprintf(mnemonic, "flog2"); break;
case 0x18: sprintf(mnemonic, "fabs"); break;
case 0x19: sprintf(mnemonic, "fcosh"); break;
case 0x1a: sprintf(mnemonic, "fneg"); break;
case 0x1c: sprintf(mnemonic, "facos"); break;
case 0x1d: sprintf(mnemonic, "fcos"); break;
case 0x1e: sprintf(mnemonic, "fgetexp"); break;
case 0x1f: sprintf(mnemonic, "fgetman"); break;
case 0x20: sprintf(mnemonic, "fdiv"); break;
case 0x21: sprintf(mnemonic, "fmod"); break;
case 0x22: sprintf(mnemonic, "fadd"); break;
case 0x23: sprintf(mnemonic, "fmul"); break;
case 0x24: sprintf(mnemonic, "fsgldiv"); break;
case 0x25: sprintf(mnemonic, "frem"); break;
case 0x26: sprintf(mnemonic, "fscale"); break;
case 0x27: sprintf(mnemonic, "fsglmul"); break;
case 0x28: sprintf(mnemonic, "fsub"); break;
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
sprintf(mnemonic, "fsincos"); break;
case 0x38: sprintf(mnemonic, "fcmp"); break;
case 0x3a: sprintf(mnemonic, "ftst"); break;
case 0x41: sprintf(mnemonic, "fssqrt"); break;
case 0x45: sprintf(mnemonic, "fdsqrt"); break;
case 0x58: sprintf(mnemonic, "fsabs"); break;
case 0x5a: sprintf(mnemonic, "fsneg"); break;
case 0x5c: sprintf(mnemonic, "fdabs"); break;
case 0x5e: sprintf(mnemonic, "fdneg"); break;
case 0x60: sprintf(mnemonic, "fsdiv"); break;
case 0x62: sprintf(mnemonic, "fsadd"); break;
case 0x63: sprintf(mnemonic, "fsmul"); break;
case 0x64: sprintf(mnemonic, "fddiv"); break;
case 0x66: sprintf(mnemonic, "fdadd"); break;
case 0x67: sprintf(mnemonic, "fdmul"); break;
case 0x68: sprintf(mnemonic, "fssub"); break;
case 0x6c: sprintf(mnemonic, "fdsub"); break;
default: sprintf(mnemonic, "FPU (?)"); break;
}
if (w2 & 0x4000)
{
sprintf(g_dasm_str, "%s%s %s, FP%d", mnemonic, float_data_format[src], get_ea_mode_str_32(g_cpu_ir), dst_reg);
}
else
{
sprintf(g_dasm_str, "%s.x FP%d, FP%d", mnemonic, src, dst_reg);
}
break;
}
case 0x3:
{
switch ((w2>>10)&7)
{
case 3: // packed decimal w/fixed k-factor
sprintf(g_dasm_str, "fmove%s FP%d, %s {#%d}", float_data_format[(w2>>10)&7], dst_reg, get_ea_mode_str_32(g_cpu_ir), sext_7bit_int(w2&0x7f));
break;
case 7: // packed decimal w/dynamic k-factor (register)
sprintf(g_dasm_str, "fmove%s FP%d, %s {D%d}", float_data_format[(w2>>10)&7], dst_reg, get_ea_mode_str_32(g_cpu_ir), (w2>>4)&7);
break;
default:
sprintf(g_dasm_str, "fmove%s FP%d, %s", float_data_format[(w2>>10)&7], dst_reg, get_ea_mode_str_32(g_cpu_ir));
break;
}
break;
}
case 0x4: // ea to control
{
sprintf(g_dasm_str, "fmovem.l %s, ", get_ea_mode_str_32(g_cpu_ir));
if (w2 & 0x1000) strcat(g_dasm_str, "fpcr");
if (w2 & 0x0800) strcat(g_dasm_str, "/fpsr");
if (w2 & 0x0400) strcat(g_dasm_str, "/fpiar");
break;
}
case 0x5: // control to ea
{
strcpy(g_dasm_str, "fmovem.l ");
if (w2 & 0x1000) strcat(g_dasm_str, "fpcr");
if (w2 & 0x0800) strcat(g_dasm_str, "/fpsr");
if (w2 & 0x0400) strcat(g_dasm_str, "/fpiar");
strcat(g_dasm_str, ", ");
strcat(g_dasm_str, get_ea_mode_str_32(g_cpu_ir));
break;
}
case 0x6: // memory to FPU, list
{
char temp[32];
if ((w2>>11) & 1) // dynamic register list
{
sprintf(g_dasm_str, "fmovem.x %s, D%d", get_ea_mode_str_32(g_cpu_ir), (w2>>4)&7);
}
else // static register list
{
int i;
sprintf(g_dasm_str, "fmovem.x %s, ", get_ea_mode_str_32(g_cpu_ir));
for (i = 0; i < 8; i++)
{
if (w2 & (1<<i))
{
if ((w2>>12) & 1) // postincrement or control
{
sprintf(temp, "FP%d ", 7-i);
}
else // predecrement
{
sprintf(temp, "FP%d ", i);
}
strcat(g_dasm_str, temp);
}
}
}
break;
}
case 0x7: // FPU to memory, list
{
char temp[32];
if ((w2>>11) & 1) // dynamic register list
{
sprintf(g_dasm_str, "fmovem.x D%d, %s", (w2>>4)&7, get_ea_mode_str_32(g_cpu_ir));
}
else // static register list
{
int i;
sprintf(g_dasm_str, "fmovem.x ");
for (i = 0; i < 8; i++)
{
if (w2 & (1<<i))
{
if ((w2>>12) & 1) // postincrement or control
{
sprintf(temp, "FP%d ", 7-i);
}
else // predecrement
{
sprintf(temp, "FP%d ", i);
}
strcat(g_dasm_str, temp);
}
}
strcat(g_dasm_str, ", ");
strcat(g_dasm_str, get_ea_mode_str_32(g_cpu_ir));
}
break;
}
default:
{
sprintf(g_dasm_str, "FPU (?) ");
break;
}
}
}
static void d68000_jmp(void)
{
sprintf(g_dasm_str, "jmp %s", get_ea_mode_str_32(g_cpu_ir));
@ -1614,6 +1935,7 @@ static void d68000_jmp(void)
static void d68000_jsr(void)
{
sprintf(g_dasm_str, "jsr %s", get_ea_mode_str_32(g_cpu_ir));
SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER);
}
static void d68000_lea(void)
@ -1840,7 +2162,7 @@ static void d68010_movec(void)
processor = "?";
}
if(BIT_1(g_cpu_ir))
if(BIT_0(g_cpu_ir))
sprintf(g_dasm_str, "movec %c%d, %s; (%s)", BIT_F(extension) ? 'A' : 'D', (extension>>12)&7, reg_name, processor);
else
sprintf(g_dasm_str, "movec %s, %c%d; (%s)", reg_name, BIT_F(extension) ? 'A' : 'D', (extension>>12)&7, processor);
@ -2374,6 +2696,21 @@ static void d68000_pea(void)
sprintf(g_dasm_str, "pea %s", get_ea_mode_str_32(g_cpu_ir));
}
// this is a 68040-specific form of PFLUSH
static void d68040_pflush(void)
{
LIMIT_CPU_TYPES(M68040_PLUS);
if (g_cpu_ir & 0x10)
{
sprintf(g_dasm_str, "pflusha%s", (g_cpu_ir & 8) ? "" : "n");
}
else
{
sprintf(g_dasm_str, "pflush%s(A%d)", (g_cpu_ir & 8) ? "" : "n", g_cpu_ir & 7);
}
}
static void d68000_reset(void)
{
sprintf(g_dasm_str, "reset");
@ -2524,27 +2861,32 @@ static void d68010_rtd(void)
{
LIMIT_CPU_TYPES(M68010_PLUS);
sprintf(g_dasm_str, "rtd %s; (1+)", get_imm_str_s16());
SET_OPCODE_FLAGS(DASMFLAG_STEP_OUT);
}
static void d68000_rte(void)
{
sprintf(g_dasm_str, "rte");
SET_OPCODE_FLAGS(DASMFLAG_STEP_OUT);
}
static void d68020_rtm(void)
{
LIMIT_CPU_TYPES(M68020_ONLY);
sprintf(g_dasm_str, "rtm %c%d; (2+)", BIT_3(g_cpu_ir) ? 'A' : 'D', g_cpu_ir&7);
SET_OPCODE_FLAGS(DASMFLAG_STEP_OUT);
}
static void d68000_rtr(void)
{
sprintf(g_dasm_str, "rtr");
SET_OPCODE_FLAGS(DASMFLAG_STEP_OUT);
}
static void d68000_rts(void)
{
sprintf(g_dasm_str, "rts");
SET_OPCODE_FLAGS(DASMFLAG_STEP_OUT);
}
static void d68000_sbcd_rr(void)
@ -2689,23 +3031,27 @@ static void d68020_trapcc_0(void)
{
LIMIT_CPU_TYPES(M68020_PLUS);
sprintf(g_dasm_str, "trap%-2s; (2+)", g_cc[(g_cpu_ir>>8)&0xf]);
SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER);
}
static void d68020_trapcc_16(void)
{
LIMIT_CPU_TYPES(M68020_PLUS);
sprintf(g_dasm_str, "trap%-2s %s; (2+)", g_cc[(g_cpu_ir>>8)&0xf], get_imm_str_u16());
SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER);
}
static void d68020_trapcc_32(void)
{
LIMIT_CPU_TYPES(M68020_PLUS);
sprintf(g_dasm_str, "trap%-2s %s; (2+)", g_cc[(g_cpu_ir>>8)&0xf], get_imm_str_u32());
SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER);
}
static void d68000_trapv(void)
{
sprintf(g_dasm_str, "trapv");
SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER);
}
static void d68000_tst_8(void)
@ -2807,6 +3153,137 @@ static void d68020_unpk_mm(void)
}
// PFLUSH: 001xxx0xxxxxxxxx
// PLOAD: 001000x0000xxxxx
// PVALID1: 0010100000000000
// PVALID2: 0010110000000xxx
// PMOVE 1: 010xxxx000000000
// PMOVE 2: 011xxxx0000xxx00
// PMOVE 3: 011xxxx000000000
// PTEST: 100xxxxxxxxxxxxx
// PFLUSHR: 1010000000000000
static void d68851_p000(void)
{
char* str;
uint modes = read_imm_16();
// do this after fetching the second PMOVE word so we properly get the 3rd if necessary
str = get_ea_mode_str_32(g_cpu_ir);
if ((modes & 0xfde0) == 0x2000) // PLOAD
{
if (modes & 0x0200)
{
sprintf(g_dasm_str, "pload #%d, %s", (modes>>10)&7, str);
}
else
{
sprintf(g_dasm_str, "pload %s, #%d", str, (modes>>10)&7);
}
return;
}
if ((modes & 0xe200) == 0x2000) // PFLUSH
{
sprintf(g_dasm_str, "pflushr %x, %x, %s", modes & 0x1f, (modes>>5)&0xf, str);
return;
}
if (modes == 0xa000) // PFLUSHR
{
sprintf(g_dasm_str, "pflushr %s", str);
}
if (modes == 0x2800) // PVALID (FORMAT 1)
{
sprintf(g_dasm_str, "pvalid VAL, %s", str);
return;
}
if ((modes & 0xfff8) == 0x2c00) // PVALID (FORMAT 2)
{
sprintf(g_dasm_str, "pvalid A%d, %s", modes & 0xf, str);
return;
}
if ((modes & 0xe000) == 0x8000) // PTEST
{
sprintf(g_dasm_str, "ptest #%d, %s", modes & 0x1f, str);
return;
}
switch ((modes>>13) & 0x7)
{
case 0: // MC68030/040 form with FD bit
case 2: // MC68881 form, FD never set
if (modes & 0x0100)
{
if (modes & 0x0200)
{
sprintf(g_dasm_str, "pmovefd %s, %s", g_mmuregs[(modes>>10)&7], str);
}
else
{
sprintf(g_dasm_str, "pmovefd %s, %s", str, g_mmuregs[(modes>>10)&7]);
}
}
else
{
if (modes & 0x0200)
{
sprintf(g_dasm_str, "pmove %s, %s", g_mmuregs[(modes>>10)&7], str);
}
else
{
sprintf(g_dasm_str, "pmove %s, %s", str, g_mmuregs[(modes>>10)&7]);
}
}
break;
case 3: // MC68030 to/from status reg
if (modes & 0x0200)
{
sprintf(g_dasm_str, "pmove mmusr, %s", str);
}
else
{
sprintf(g_dasm_str, "pmove %s, mmusr", str);
}
break;
default:
sprintf(g_dasm_str, "pmove [unknown form] %s", str);
break;
}
}
static void d68851_pbcc16(void)
{
uint32 temp_pc = g_cpu_pc;
sprintf(g_dasm_str, "pb%s %x", g_mmucond[g_cpu_ir&0xf], temp_pc + make_int_16(read_imm_16()));
}
static void d68851_pbcc32(void)
{
uint32 temp_pc = g_cpu_pc;
sprintf(g_dasm_str, "pb%s %x", g_mmucond[g_cpu_ir&0xf], temp_pc + make_int_32(read_imm_32()));
}
static void d68851_pdbcc(void)
{
uint32 temp_pc = g_cpu_pc;
uint16 modes = read_imm_16();
sprintf(g_dasm_str, "pb%s %x", g_mmucond[modes&0xf], temp_pc + make_int_16(read_imm_16()));
}
// PScc: 0000000000xxxxxx
static void d68851_p001(void)
{
sprintf(g_dasm_str, "MMU 001 group");
}
/* ======================================================================== */
/* ======================= INSTRUCTION TABLE BUILDER ====================== */
@ -2827,7 +3304,7 @@ static void d68020_unpk_mm(void)
1 = pc idx
*/
static opcode_struct g_opcode_info[] =
static const opcode_struct g_opcode_info[] =
{
/* opcode handler mask match ea mask */
{d68000_1010 , 0xf000, 0xa000, 0x000},
@ -2967,6 +3444,7 @@ static opcode_struct g_opcode_info[] =
{d68020_extb_32 , 0xfff8, 0x49c0, 0x000},
{d68000_ext_16 , 0xfff8, 0x4880, 0x000},
{d68000_ext_32 , 0xfff8, 0x48c0, 0x000},
{d68040_fpu , 0xffc0, 0xf200, 0x000},
{d68000_illegal , 0xffff, 0x4afc, 0x000},
{d68000_jmp , 0xffc0, 0x4ec0, 0x27b},
{d68000_jsr , 0xffc0, 0x4e80, 0x27b},
@ -3046,6 +3524,7 @@ static opcode_struct g_opcode_info[] =
{d68020_pack_rr , 0xf1f8, 0x8140, 0x000},
{d68020_pack_mm , 0xf1f8, 0x8148, 0x000},
{d68000_pea , 0xffc0, 0x4840, 0x27b},
{d68040_pflush , 0xffe0, 0xf500, 0x000},
{d68000_reset , 0xffff, 0x4e70, 0x000},
{d68000_ror_s_8 , 0xf1f8, 0xe018, 0x000},
{d68000_ror_s_16 , 0xf1f8, 0xe058, 0x000},
@ -3128,6 +3607,11 @@ static opcode_struct g_opcode_info[] =
{d68000_unlk , 0xfff8, 0x4e58, 0x000},
{d68020_unpk_rr , 0xf1f8, 0x8180, 0x000},
{d68020_unpk_mm , 0xf1f8, 0x8188, 0x000},
{d68851_p000 , 0xffc0, 0xf000, 0x000},
{d68851_pbcc16 , 0xffc0, 0xf080, 0x000},
{d68851_pbcc32 , 0xffc0, 0xf0c0, 0x000},
{d68851_pdbcc , 0xfff8, 0xf048, 0x000},
{d68851_p001 , 0xffc0, 0xf040, 0x000},
{0, 0, 0, 0}
};
@ -3200,19 +3684,17 @@ static void build_opcode_table(void)
uint i;
uint opcode;
opcode_struct* ostruct;
uint opcode_info_length = 0;
opcode_struct opcode_info[ARRAY_LENGTH(g_opcode_info)];
for(ostruct = g_opcode_info;ostruct->opcode_handler != 0;ostruct++)
opcode_info_length++;
qsort((void *)g_opcode_info, opcode_info_length, sizeof(g_opcode_info[0]), compare_nof_true_bits);
memcpy(opcode_info, g_opcode_info, sizeof(g_opcode_info));
qsort((void *)opcode_info, ARRAY_LENGTH(opcode_info)-1, sizeof(opcode_info[0]), compare_nof_true_bits);
for(i=0;i<0x10000;i++)
{
g_instruction_table[i] = d68000_illegal; /* default to illegal */
opcode = i;
/* search through opcode info for a match */
for(ostruct = g_opcode_info;ostruct->opcode_handler != 0;ostruct++)
for(ostruct = opcode_info;ostruct->opcode_handler != 0;ostruct++)
{
/* match opcode mask and allowed ea modes */
if((opcode & ostruct->mask) == ostruct->match)
@ -3265,11 +3747,14 @@ unsigned int m68k_disassemble(char* str_buff, unsigned int pc, unsigned int cpu_
g_cpu_type = TYPE_68020;
g_address_mask = 0xffffffff;
break;
case M68K_CPU_TYPE_68EC030:
case M68K_CPU_TYPE_68030:
g_cpu_type = TYPE_68030;
g_address_mask = 0xffffffff;
break;
case M68K_CPU_TYPE_68040:
case M68K_CPU_TYPE_68EC040:
case M68K_CPU_TYPE_68LC040:
g_cpu_type = TYPE_68040;
g_address_mask = 0xffffffff;
break;
@ -3280,9 +3765,10 @@ unsigned int m68k_disassemble(char* str_buff, unsigned int pc, unsigned int cpu_
g_cpu_pc = pc;
g_helper_str[0] = 0;
g_cpu_ir = read_imm_16();
g_opcode_type = 0;
g_instruction_table[g_cpu_ir]();
sprintf(str_buff, "%s%s", g_dasm_str, g_helper_str);
return g_cpu_pc - pc;
return COMBINE_OPCODE_FLAGS(g_cpu_pc - pc);
}
char* m68ki_disassemble_quick(unsigned int pc, unsigned int cpu_type)
@ -3293,6 +3779,18 @@ char* m68ki_disassemble_quick(unsigned int pc, unsigned int cpu_type)
return buff;
}
unsigned int m68k_disassemble_raw(char* str_buff, unsigned int pc, const unsigned char* opdata, const unsigned char* argdata, unsigned int cpu_type)
{
unsigned int result;
(void)argdata;
g_rawop = opdata;
g_rawbasepc = pc;
result = m68k_disassemble(str_buff, pc, cpu_type);
g_rawop = NULL;
return result;
}
/* Check if the instruction is a valid one */
unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cpu_type)
{
@ -3323,6 +3821,7 @@ unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cp
return 0;
if(g_instruction_table[instruction] == d68010_rtd)
return 0;
// Fallthrough
case M68K_CPU_TYPE_68010:
if(g_instruction_table[instruction] == d68020_bcc_32)
return 0;
@ -3444,9 +3943,11 @@ unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cp
return 0;
if(g_instruction_table[instruction] == d68020_unpk_mm)
return 0;
// Fallthrough
case M68K_CPU_TYPE_68EC020:
case M68K_CPU_TYPE_68020:
case M68K_CPU_TYPE_68030:
case M68K_CPU_TYPE_68EC030:
if(g_instruction_table[instruction] == d68040_cinv)
return 0;
if(g_instruction_table[instruction] == d68040_cpush)
@ -3461,6 +3962,32 @@ unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cp
return 0;
if(g_instruction_table[instruction] == d68040_move16_al_ai)
return 0;
// Fallthrough
case M68K_CPU_TYPE_68040:
case M68K_CPU_TYPE_68EC040:
case M68K_CPU_TYPE_68LC040:
if(g_instruction_table[instruction] == d68020_cpbcc_16)
return 0;
if(g_instruction_table[instruction] == d68020_cpbcc_32)
return 0;
if(g_instruction_table[instruction] == d68020_cpdbcc)
return 0;
if(g_instruction_table[instruction] == d68020_cpgen)
return 0;
if(g_instruction_table[instruction] == d68020_cprestore)
return 0;
if(g_instruction_table[instruction] == d68020_cpsave)
return 0;
if(g_instruction_table[instruction] == d68020_cpscc)
return 0;
if(g_instruction_table[instruction] == d68020_cptrapcc_0)
return 0;
if(g_instruction_table[instruction] == d68020_cptrapcc_16)
return 0;
if(g_instruction_table[instruction] == d68020_cptrapcc_32)
return 0;
if(g_instruction_table[instruction] == d68040_pflush)
return 0;
}
if(cpu_type != M68K_CPU_TYPE_68020 && cpu_type != M68K_CPU_TYPE_68EC020 &&
(g_instruction_table[instruction] == d68020_callm ||
@ -3470,7 +3997,7 @@ unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cp
return 1;
}
// f028 2215 0008
/* ======================================================================== */
/* ============================== END OF FILE ============================= */

File diff suppressed because it is too large Load diff

View file

@ -3,10 +3,11 @@
/* ======================================================================== */
/*
* MUSASHI
* Version 3.4
* Version 4.60
*
* A portable Motorola M680x0 processor emulation engine.
* Copyright 1998-2001 Karl Stenerud. All rights reserved.
* Copyright Karl Stenerud. All rights reserved.
* FPU and MMU by R. Belmont.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -56,7 +57,7 @@
*/
char* g_version = "3.3";
static const char g_version[] = "4.60";
/* ======================================================================== */
/* =============================== INCLUDES =============================== */
@ -77,7 +78,6 @@ char* g_version = "3.3";
#define M68K_MAX_PATH 1024
#define M68K_MAX_DIR 1024
#define NUM_CPUS 3 /* 000, 010, 020 */
#define MAX_LINE_LENGTH 200 /* length of 1 line */
#define MAX_BODY_LENGTH 300 /* Number of lines in 1 function */
#define MAX_REPLACE_LENGTH 30 /* Max number of replace strings */
@ -93,9 +93,6 @@ char* g_version = "3.3";
#define FILENAME_INPUT "m68k_in.c"
#define FILENAME_PROTOTYPE "m68kops.h"
#define FILENAME_TABLE "m68kops.c"
#define FILENAME_OPS_AC "m68kopac.c"
#define FILENAME_OPS_DM "m68kopdm.c"
#define FILENAME_OPS_NZ "m68kopnz.c"
/* Identifier sequences recognized by this program */
@ -135,9 +132,14 @@ char* g_version = "3.3";
/* ============================== PROTOTYPES ============================== */
/* ======================================================================== */
#define CPU_TYPE_000 0
#define CPU_TYPE_010 1
#define CPU_TYPE_020 2
enum {
CPU_TYPE_000=0,
CPU_TYPE_010,
CPU_TYPE_020,
CPU_TYPE_030,
CPU_TYPE_040,
NUM_CPUS
};
#define UNSPECIFIED "."
#define UNSPECIFIED_CH '.'
@ -185,7 +187,7 @@ typedef struct
char ea_allowed[EA_ALLOWED_LENGTH]; /* Effective addressing modes allowed */
char cpu_mode[NUM_CPUS]; /* User or supervisor mode */
char cpus[NUM_CPUS+1]; /* Allowed CPUs */
unsigned char cycles[NUM_CPUS]; /* cycles for 000, 010, 020 */
unsigned char cycles[NUM_CPUS]; /* cycles for 000, 010, 020, 030, 040 */
} opcode_struct;
@ -231,7 +233,6 @@ int extract_opcode_info(char* src, char* name, int* size, char* spec_proc, char*
void add_replace_string(replace_struct* replace, char* search_str, char* replace_str);
void write_body(FILE* filep, body_struct* body, replace_struct* replace);
void get_base_name(char* base_name, opcode_struct* op);
void write_prototype(FILE* filep, char* base_name);
void write_function_name(FILE* filep, char* base_name);
void add_opcode_output_table_entry(opcode_struct* op, char* name);
static int DECL_SPEC compare_nof_true_bits(const void* aptr, const void* bptr);
@ -241,7 +242,7 @@ void set_opcode_struct(opcode_struct* src, opcode_struct* dst, int ea_mode);
void generate_opcode_handler(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* opinfo, int ea_mode);
void generate_opcode_ea_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op);
void generate_opcode_cc_variants(FILE* filep, body_struct* body, replace_struct* replace, opcode_struct* op_in, int offset);
void process_opcode_handlers(void);
void process_opcode_handlers(FILE* filep);
void populate_table(void);
void read_insert(char* insert);
@ -258,9 +259,6 @@ char g_input_filename[M68K_MAX_PATH] = FILENAME_INPUT;
FILE* g_input_file = NULL;
FILE* g_prototype_file = NULL;
FILE* g_table_file = NULL;
FILE* g_ops_ac_file = NULL;
FILE* g_ops_dm_file = NULL;
FILE* g_ops_nz_file = NULL;
int g_num_functions = 0; /* Number of functions processed */
int g_num_primitives = 0; /* Number of function primitives read */
@ -272,7 +270,7 @@ opcode_struct g_opcode_input_table[MAX_OPCODE_INPUT_TABLE_LENGTH];
opcode_struct g_opcode_output_table[MAX_OPCODE_OUTPUT_TABLE_LENGTH];
int g_opcode_output_table_length = 0;
ea_info_struct g_ea_info_table[13] =
const ea_info_struct g_ea_info_table[13] =
{/* fname ea mask match */
{"", "", 0x00, 0x00}, /* EA_MODE_NONE */
{"ai", "AY_AI", 0x38, 0x10}, /* EA_MODE_AI */
@ -290,7 +288,7 @@ ea_info_struct g_ea_info_table[13] =
};
char* g_cc_table[16][2] =
const char *const g_cc_table[16][2] =
{
{ "t", "T"}, /* 0000 */
{ "f", "F"}, /* 0001 */
@ -311,7 +309,7 @@ char* g_cc_table[16][2] =
};
/* size to index translator (0 -> 0, 8 and 16 -> 1, 32 -> 2) */
int g_size_select_table[33] =
const int g_size_select_table[33] =
{
0, /* unsized */
0, 0, 0, 0, 0, 0, 0, 1, /* 8 */
@ -320,25 +318,26 @@ int g_size_select_table[33] =
};
/* Extra cycles required for certain EA modes */
int g_ea_cycle_table[13][NUM_CPUS][3] =
{/* 000 010 020 */
{{ 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}}, /* EA_MODE_NONE */
{{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}}, /* EA_MODE_AI */
{{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}}, /* EA_MODE_PI */
{{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}}, /* EA_MODE_PI7 */
{{ 0, 6, 10}, { 0, 6, 10}, { 0, 5, 5}}, /* EA_MODE_PD */
{{ 0, 6, 10}, { 0, 6, 10}, { 0, 5, 5}}, /* EA_MODE_PD7 */
{{ 0, 8, 12}, { 0, 8, 12}, { 0, 5, 5}}, /* EA_MODE_DI */
{{ 0, 10, 14}, { 0, 10, 14}, { 0, 7, 7}}, /* EA_MODE_IX */
{{ 0, 8, 12}, { 0, 8, 12}, { 0, 4, 4}}, /* EA_MODE_AW */
{{ 0, 12, 16}, { 0, 12, 16}, { 0, 4, 4}}, /* EA_MODE_AL */
{{ 0, 8, 12}, { 0, 8, 12}, { 0, 5, 5}}, /* EA_MODE_PCDI */
{{ 0, 10, 14}, { 0, 10, 14}, { 0, 7, 7}}, /* EA_MODE_PCIX */
{{ 0, 4, 8}, { 0, 4, 8}, { 0, 2, 4}}, /* EA_MODE_I */
/* TODO: correct timings for 030, 040 */
const int g_ea_cycle_table[13][NUM_CPUS][3] =
{/* 000 010 020 030 040 */
{{ 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}}, /* EA_MODE_NONE */
{{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_AI */
{{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_PI */
{{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_PI7 */
{{ 0, 6, 10}, { 0, 6, 10}, { 0, 5, 5}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_PD */
{{ 0, 6, 10}, { 0, 6, 10}, { 0, 5, 5}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_PD7 */
{{ 0, 8, 12}, { 0, 8, 12}, { 0, 5, 5}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_DI */
{{ 0, 10, 14}, { 0, 10, 14}, { 0, 7, 7}, { 0, 7, 7}, { 0, 7, 7}}, /* EA_MODE_IX */
{{ 0, 8, 12}, { 0, 8, 12}, { 0, 4, 4}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_AW */
{{ 0, 12, 16}, { 0, 12, 16}, { 0, 4, 4}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_AL */
{{ 0, 8, 12}, { 0, 8, 12}, { 0, 5, 5}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_PCDI */
{{ 0, 10, 14}, { 0, 10, 14}, { 0, 7, 7}, { 0, 7, 7}, { 0, 7, 7}}, /* EA_MODE_PCIX */
{{ 0, 4, 8}, { 0, 4, 8}, { 0, 2, 4}, { 0, 2, 4}, { 0, 2, 4}}, /* EA_MODE_I */
};
/* Extra cycles for JMP instruction (000, 010) */
int g_jmp_cycle_table[13] =
const int g_jmp_cycle_table[13] =
{
0, /* EA_MODE_NONE */
4, /* EA_MODE_AI */
@ -356,7 +355,7 @@ int g_jmp_cycle_table[13] =
};
/* Extra cycles for JSR instruction (000, 010) */
int g_jsr_cycle_table[13] =
const int g_jsr_cycle_table[13] =
{
0, /* EA_MODE_NONE */
4, /* EA_MODE_AI */
@ -374,7 +373,7 @@ int g_jsr_cycle_table[13] =
};
/* Extra cycles for LEA instruction (000, 010) */
int g_lea_cycle_table[13] =
const int g_lea_cycle_table[13] =
{
0, /* EA_MODE_NONE */
4, /* EA_MODE_AI */
@ -392,7 +391,7 @@ int g_lea_cycle_table[13] =
};
/* Extra cycles for PEA instruction (000, 010) */
int g_pea_cycle_table[13] =
const int g_pea_cycle_table[13] =
{
0, /* EA_MODE_NONE */
6, /* EA_MODE_AI */
@ -409,8 +408,26 @@ int g_pea_cycle_table[13] =
0, /* EA_MODE_I */
};
/* Extra cycles for MOVEM instruction (000, 010) */
const int g_movem_cycle_table[13] =
{
0, /* EA_MODE_NONE */
0, /* EA_MODE_AI */
0, /* EA_MODE_PI */
0, /* EA_MODE_PI7 */
0, /* EA_MODE_PD */
0, /* EA_MODE_PD7 */
4, /* EA_MODE_DI */
6, /* EA_MODE_IX */
4, /* EA_MODE_AW */
8, /* EA_MODE_AL */
0, /* EA_MODE_PCDI */
0, /* EA_MODE_PCIX */
0, /* EA_MODE_I */
};
/* Extra cycles for MOVES instruction (010) */
int g_moves_cycle_table[13][3] =
const int g_moves_cycle_table[13][3] =
{
{ 0, 0, 0}, /* EA_MODE_NONE */
{ 0, 4, 6}, /* EA_MODE_AI */
@ -428,7 +445,7 @@ int g_moves_cycle_table[13][3] =
};
/* Extra cycles for CLR instruction (010) */
int g_clr_cycle_table[13][3] =
const int g_clr_cycle_table[13][3] =
{
{ 0, 0, 0}, /* EA_MODE_NONE */
{ 0, 4, 6}, /* EA_MODE_AI */
@ -463,9 +480,6 @@ void error_exit(char* fmt, ...)
if(g_prototype_file) fclose(g_prototype_file);
if(g_table_file) fclose(g_table_file);
if(g_ops_ac_file) fclose(g_ops_ac_file);
if(g_ops_dm_file) fclose(g_ops_dm_file);
if(g_ops_nz_file) fclose(g_ops_nz_file);
if(g_input_file) fclose(g_input_file);
exit(EXIT_FAILURE);
@ -482,9 +496,6 @@ void perror_exit(char* fmt, ...)
if(g_prototype_file) fclose(g_prototype_file);
if(g_table_file) fclose(g_table_file);
if(g_ops_ac_file) fclose(g_ops_ac_file);
if(g_ops_dm_file) fclose(g_ops_dm_file);
if(g_ops_nz_file) fclose(g_ops_nz_file);
if(g_input_file) fclose(g_input_file);
exit(EXIT_FAILURE);
@ -586,7 +597,7 @@ int fgetline(char* buff, int nchars, FILE* file)
if(fgets(buff, nchars, file) == NULL)
return -1;
if(buff[0] == '\r')
memcpy(buff, buff + 1, nchars - 1);
memmove(buff, buff + 1, nchars - 1);
length = strlen(buff);
while(length && (buff[length-1] == '\r' || buff[length-1] == '\n'))
@ -639,6 +650,8 @@ int get_oper_cycles(opcode_struct* op, int ea_mode, int cpu_type)
return op->cycles[cpu_type] + g_lea_cycle_table[ea_mode];
if(strcmp(op->name, "pea") == 0)
return op->cycles[cpu_type] + g_pea_cycle_table[ea_mode];
if(strcmp(op->name, "movem") == 0)
return op->cycles[cpu_type] + g_movem_cycle_table[ea_mode];
}
return op->cycles[cpu_type] + g_ea_cycle_table[ea_mode][cpu_type][size];
}
@ -649,7 +662,7 @@ opcode_struct* find_opcode(char* name, int size, char* spec_proc, char* spec_ea)
opcode_struct* op;
for(op = g_opcode_input_table;op->name != NULL;op++)
for(op = g_opcode_input_table;op < &g_opcode_input_table[MAX_OPCODE_INPUT_TABLE_LENGTH];op++)
{
if( strcmp(name, op->name) == 0 &&
(size == op->size) &&
@ -665,7 +678,7 @@ opcode_struct* find_illegal_opcode(void)
{
opcode_struct* op;
for(op = g_opcode_input_table;op->name != NULL;op++)
for(op = g_opcode_input_table;op < &g_opcode_input_table[MAX_OPCODE_INPUT_TABLE_LENGTH];op++)
{
if(strcmp(op->name, "illegal") == 0)
return op;
@ -750,7 +763,7 @@ void write_body(FILE* filep, body_struct* body, replace_struct* replace)
}
/* Found a directive with no matching replace string */
if(!found)
error_exit("Unknown " ID_BASE " directive");
error_exit("Unknown " ID_BASE " directive [%s]", output);
}
fprintf(filep, "%s\n", output);
}
@ -769,16 +782,10 @@ void get_base_name(char* base_name, opcode_struct* op)
sprintf(base_name+strlen(base_name), "_%s", op->spec_ea);
}
/* Write the prototype of an opcode handler function */
void write_prototype(FILE* filep, char* base_name)
{
fprintf(filep, "void %s(void);\n", base_name);
}
/* Write the name of an opcode handler function */
void write_function_name(FILE* filep, char* base_name)
{
fprintf(filep, "void %s(void)\n", base_name);
fprintf(filep, "static void %s(void)\n", base_name);
}
void add_opcode_output_table_entry(opcode_struct* op, char* name)
@ -861,7 +868,6 @@ void generate_opcode_handler(FILE* filep, body_struct* body, replace_struct* rep
/* Set the opcode structure and write the tables, prototypes, etc */
set_opcode_struct(opinfo, op, ea_mode);
get_base_name(str, op);
write_prototype(g_prototype_file, str);
add_opcode_output_table_entry(op, str);
write_function_name(filep, str);
@ -980,10 +986,9 @@ void generate_opcode_cc_variants(FILE* filep, body_struct* body, replace_struct*
}
/* Process the opcode handlers section of the input file */
void process_opcode_handlers(void)
void process_opcode_handlers(FILE* filep)
{
FILE* input_file = g_input_file;
FILE* output_file;
char func_name[MAX_LINE_LENGTH+1];
char oper_name[MAX_LINE_LENGTH+1];
int oper_size;
@ -993,9 +998,6 @@ void process_opcode_handlers(void)
replace_struct* replace = malloc(sizeof(replace_struct));
body_struct* body = malloc(sizeof(body_struct));
output_file = g_ops_ac_file;
for(;;)
{
/* Find the first line of the function */
@ -1038,23 +1040,17 @@ void process_opcode_handlers(void)
if(opinfo == NULL)
error_exit("Unable to find matching table entry for %s", func_name);
/* Change output files if we pass 'c' or 'n' */
if(output_file == g_ops_ac_file && oper_name[0] > 'c')
output_file = g_ops_dm_file;
else if(output_file == g_ops_dm_file && oper_name[0] > 'm')
output_file = g_ops_nz_file;
replace->length = 0;
/* Generate opcode variants */
if(strcmp(opinfo->name, "bcc") == 0 || strcmp(opinfo->name, "scc") == 0)
generate_opcode_cc_variants(output_file, body, replace, opinfo, 1);
generate_opcode_cc_variants(filep, body, replace, opinfo, 1);
else if(strcmp(opinfo->name, "dbcc") == 0)
generate_opcode_cc_variants(output_file, body, replace, opinfo, 2);
generate_opcode_cc_variants(filep, body, replace, opinfo, 2);
else if(strcmp(opinfo->name, "trapcc") == 0)
generate_opcode_cc_variants(output_file, body, replace, opinfo, 4);
generate_opcode_cc_variants(filep, body, replace, opinfo, 4);
else
generate_opcode_ea_variants(output_file, body, replace, opinfo);
generate_opcode_ea_variants(filep, body, replace, opinfo);
}
free(replace);
@ -1077,13 +1073,13 @@ void populate_table(void)
/* Find the start of the table */
while(strcmp(buff, ID_TABLE_START) != 0)
if(fgetline(buff, MAX_LINE_LENGTH, g_input_file) < 0)
error_exit("Premature EOF while reading table");
error_exit("(table_start) Premature EOF while reading table");
/* Process the entire table */
for(op = g_opcode_input_table;;op++)
{
if(fgetline(buff, MAX_LINE_LENGTH, g_input_file) < 0)
error_exit("Premature EOF while reading table");
error_exit("(inline) Premature EOF while reading table");
if(strlen(buff) == 0)
continue;
/* We finish when we find an input separator */
@ -1221,13 +1217,15 @@ int main(int argc, char **argv)
{
/* File stuff */
char output_path[M68K_MAX_DIR] = "";
char filename[M68K_MAX_PATH];
char filename[M68K_MAX_PATH*2];
/* Section identifier */
char section_id[MAX_LINE_LENGTH+1];
/* Inserts */
char temp_insert[MAX_INSERT_LENGTH+1];
char prototype_footer_insert[MAX_INSERT_LENGTH+1];
char table_header_insert[MAX_INSERT_LENGTH+1];
char table_footer_insert[MAX_INSERT_LENGTH+1];
char ophandler_header_insert[MAX_INSERT_LENGTH+1];
char ophandler_footer_insert[MAX_INSERT_LENGTH+1];
/* Flags if we've processed certain parts already */
int prototype_header_read = 0;
@ -1239,8 +1237,8 @@ int main(int argc, char **argv)
int table_body_read = 0;
int ophandler_body_read = 0;
printf("\n\t\tMusashi v%s 68000, 68010, 68EC020, 68020 emulator\n", g_version);
printf("\t\tCopyright 1998-2000 Karl Stenerud (karl@mame.net)\n\n");
printf("\n\tMusashi v%s 68000, 68008, 68010, 68EC020, 68020, 68EC030, 68030, 68EC040, 68040 emulator\n", g_version);
printf("\t\tCopyright Karl Stenerud (kstenerud@gmail.com)\n\n");
/* Check if output path and source for the input file are given */
if(argc > 1)
@ -1266,18 +1264,6 @@ int main(int argc, char **argv)
if((g_table_file = fopen(filename, "wt")) == NULL)
perror_exit("Unable to create table file (%s)\n", filename);
sprintf(filename, "%s%s", output_path, FILENAME_OPS_AC);
if((g_ops_ac_file = fopen(filename, "wt")) == NULL)
perror_exit("Unable to create ops ac file (%s)\n", filename);
sprintf(filename, "%s%s", output_path, FILENAME_OPS_DM);
if((g_ops_dm_file = fopen(filename, "wt")) == NULL)
perror_exit("Unable to create ops dm file (%s)\n", filename);
sprintf(filename, "%s%s", output_path, FILENAME_OPS_NZ);
if((g_ops_nz_file = fopen(filename, "wt")) == NULL)
perror_exit("Unable to create ops nz file (%s)\n", filename);
if((g_input_file=fopen(g_input_filename, "rt")) == NULL)
perror_exit("can't open %s for input", g_input_filename);
@ -1305,18 +1291,14 @@ int main(int argc, char **argv)
{
if(table_header_read)
error_exit("Duplicate table header");
read_insert(temp_insert);
fprintf(g_table_file, "%s", temp_insert);
read_insert(table_header_insert);
table_header_read = 1;
}
else if(strcmp(section_id, ID_OPHANDLER_HEADER) == 0)
{
if(ophandler_header_read)
error_exit("Duplicate opcode handler header");
read_insert(temp_insert);
fprintf(g_ops_ac_file, "%s\n\n", temp_insert);
fprintf(g_ops_dm_file, "%s\n\n", temp_insert);
fprintf(g_ops_nz_file, "%s\n\n", temp_insert);
read_insert(ophandler_header_insert);
ophandler_header_read = 1;
}
else if(strcmp(section_id, ID_PROTOTYPE_FOOTER) == 0)
@ -1369,7 +1351,9 @@ int main(int argc, char **argv)
if(ophandler_body_read)
error_exit("Duplicate opcode handler section");
process_opcode_handlers();
fprintf(g_table_file, "%s\n\n", ophandler_header_insert);
process_opcode_handlers(g_table_file);
fprintf(g_table_file, "%s\n\n", ophandler_footer_insert);
ophandler_body_read = 1;
}
@ -1393,13 +1377,11 @@ int main(int argc, char **argv)
if(!ophandler_body_read)
error_exit("Missing opcode handler body");
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);
fprintf(g_prototype_file, "%s\n\n", prototype_footer_insert);
fprintf(g_table_file, "%s\n\n", table_footer_insert);
fprintf(g_ops_ac_file, "%s\n\n", ophandler_footer_insert);
fprintf(g_ops_dm_file, "%s\n\n", ophandler_footer_insert);
fprintf(g_ops_nz_file, "%s\n\n", ophandler_footer_insert);
break;
}
@ -1412,9 +1394,6 @@ int main(int argc, char **argv)
/* Close all files and exit */
fclose(g_prototype_file);
fclose(g_table_file);
fclose(g_ops_ac_file);
fclose(g_ops_dm_file);
fclose(g_ops_nz_file);
fclose(g_input_file);
printf("Generated %d opcode handlers from %d primitives\n", g_num_functions, g_num_primitives);

View file

@ -0,0 +1,321 @@
/*
m68kmmu.h - PMMU implementation for 68851/68030/68040
By R. Belmont
Copyright Nicola Salmoria and the MAME Team.
Visit http://mamedev.org for licensing and usage restrictions.
*/
/*
pmmu_translate_addr: perform 68851/68030-style PMMU address translation
*/
uint pmmu_translate_addr(uint addr_in)
{
uint32 addr_out, tbl_entry = 0, tbl_entry2, tamode = 0, tbmode = 0, tcmode = 0;
uint root_aptr, root_limit, tofs, is, abits, bbits, cbits;
uint resolved, tptr, shift;
resolved = 0;
addr_out = addr_in;
// if SRP is enabled and we're in supervisor mode, use it
if ((m68ki_cpu.mmu_tc & 0x02000000) && (m68ki_get_sr() & 0x2000))
{
root_aptr = m68ki_cpu.mmu_srp_aptr;
root_limit = m68ki_cpu.mmu_srp_limit;
}
else // else use the CRP
{
root_aptr = m68ki_cpu.mmu_crp_aptr;
root_limit = m68ki_cpu.mmu_crp_limit;
}
// get initial shift (# of top bits to ignore)
is = (m68ki_cpu.mmu_tc>>16) & 0xf;
abits = (m68ki_cpu.mmu_tc>>12)&0xf;
bbits = (m68ki_cpu.mmu_tc>>8)&0xf;
cbits = (m68ki_cpu.mmu_tc>>4)&0xf;
// fprintf(stderr,"PMMU: tcr %08x limit %08x aptr %08x is %x abits %d bbits %d cbits %d\n", m68ki_cpu.mmu_tc, root_limit, root_aptr, is, abits, bbits, cbits);
// get table A offset
tofs = (addr_in<<is)>>(32-abits);
// find out what format table A is
switch (root_limit & 3)
{
case 0: // invalid, should cause MMU exception
case 1: // page descriptor, should cause direct mapping
fatalerror("680x0 PMMU: Unhandled root mode\n");
break;
case 2: // valid 4 byte descriptors
tofs *= 4;
// fprintf(stderr,"PMMU: reading table A entry at %08x\n", tofs + (root_aptr & 0xfffffffc));
tbl_entry = m68k_read_memory_32( tofs + (root_aptr & 0xfffffffc));
tamode = tbl_entry & 3;
// fprintf(stderr,"PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tamode, tofs);
break;
case 3: // valid 8 byte descriptors
tofs *= 8;
// fprintf(stderr,"PMMU: reading table A entries at %08x\n", tofs + (root_aptr & 0xfffffffc));
tbl_entry2 = m68k_read_memory_32( tofs + (root_aptr & 0xfffffffc));
tbl_entry = m68k_read_memory_32( tofs + (root_aptr & 0xfffffffc)+4);
tamode = tbl_entry2 & 3;
// fprintf(stderr,"PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tamode, tofs);
break;
}
// get table B offset and pointer
tofs = (addr_in<<(is+abits))>>(32-bbits);
tptr = tbl_entry & 0xfffffff0;
// find out what format table B is, if any
switch (tamode)
{
case 0: // invalid, should cause MMU exception
fatalerror("680x0 PMMU: Unhandled Table A mode %d (addr_in %08x)\n", tamode, addr_in);
break;
case 2: // 4-byte table B descriptor
tofs *= 4;
// fprintf(stderr,"PMMU: reading table B entry at %08x\n", tofs + tptr);
tbl_entry = m68k_read_memory_32( tofs + tptr);
tbmode = tbl_entry & 3;
// fprintf(stderr,"PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tbmode, tofs);
break;
case 3: // 8-byte table B descriptor
tofs *= 8;
// fprintf(stderr,"PMMU: reading table B entries at %08x\n", tofs + tptr);
tbl_entry2 = m68k_read_memory_32( tofs + tptr);
tbl_entry = m68k_read_memory_32( tofs + tptr + 4);
tbmode = tbl_entry2 & 3;
// fprintf(stderr,"PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tbmode, tofs);
break;
case 1: // early termination descriptor
tbl_entry &= 0xffffff00;
shift = is+abits;
addr_out = ((addr_in<<shift)>>shift) + tbl_entry;
resolved = 1;
break;
}
// if table A wasn't early-out, continue to process table B
if (!resolved)
{
// get table C offset and pointer
tofs = (addr_in<<(is+abits+bbits))>>(32-cbits);
tptr = tbl_entry & 0xfffffff0;
switch (tbmode)
{
case 0: // invalid, should cause MMU exception
fatalerror("680x0 PMMU: Unhandled Table B mode %d (addr_in %08x PC %x)\n", tbmode, addr_in, REG_PC);
break;
case 2: // 4-byte table C descriptor
tofs *= 4;
// fprintf(stderr,"PMMU: reading table C entry at %08x\n", tofs + tptr);
tbl_entry = m68k_read_memory_32(tofs + tptr);
tcmode = tbl_entry & 3;
// fprintf(stderr,"PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tbmode, tofs);
break;
case 3: // 8-byte table C descriptor
tofs *= 8;
// fprintf(stderr,"PMMU: reading table C entries at %08x\n", tofs + tptr);
tbl_entry2 = m68k_read_memory_32(tofs + tptr);
tbl_entry = m68k_read_memory_32(tofs + tptr + 4);
tcmode = tbl_entry2 & 3;
// fprintf(stderr,"PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tbmode, tofs);
break;
case 1: // termination descriptor
tbl_entry &= 0xffffff00;
shift = is+abits+bbits;
addr_out = ((addr_in<<shift)>>shift) + tbl_entry;
resolved = 1;
break;
}
}
if (!resolved)
{
switch (tcmode)
{
case 0: // invalid, should cause MMU exception
case 2: // 4-byte ??? descriptor
case 3: // 8-byte ??? descriptor
fatalerror("680x0 PMMU: Unhandled Table B mode %d (addr_in %08x PC %x)\n", tbmode, addr_in, REG_PC);
break;
case 1: // termination descriptor
tbl_entry &= 0xffffff00;
shift = is+abits+bbits+cbits;
addr_out = ((addr_in<<shift)>>shift) + tbl_entry;
resolved = 1;
break;
}
}
// fprintf(stderr,"PMMU: [%08x] => [%08x]\n", addr_in, addr_out);
return addr_out;
}
/*
m68881_mmu_ops: COP 0 MMU opcode handling
*/
void m68881_mmu_ops()
{
uint16 modes;
uint32 ea = m68ki_cpu.ir & 0x3f;
uint64 temp64;
// catch the 2 "weird" encodings up front (PBcc)
if ((m68ki_cpu.ir & 0xffc0) == 0xf0c0)
{
fprintf(stderr,"680x0: unhandled PBcc\n");
return;
}
else if ((m68ki_cpu.ir & 0xffc0) == 0xf080)
{
fprintf(stderr,"680x0: unhandled PBcc\n");
return;
}
else // the rest are 1111000xxxXXXXXX where xxx is the instruction family
{
switch ((m68ki_cpu.ir>>9) & 0x7)
{
case 0:
modes = OPER_I_16();
if ((modes & 0xfde0) == 0x2000) // PLOAD
{
fprintf(stderr,"680x0: unhandled PLOAD\n");
return;
}
else if ((modes & 0xe200) == 0x2000) // PFLUSH
{
fprintf(stderr,"680x0: unhandled PFLUSH PC=%x\n", REG_PC);
return;
}
else if (modes == 0xa000) // PFLUSHR
{
fprintf(stderr,"680x0: unhandled PFLUSHR\n");
return;
}
else if (modes == 0x2800) // PVALID (FORMAT 1)
{
fprintf(stderr,"680x0: unhandled PVALID1\n");
return;
}
else if ((modes & 0xfff8) == 0x2c00) // PVALID (FORMAT 2)
{
fprintf(stderr,"680x0: unhandled PVALID2\n");
return;
}
else if ((modes & 0xe000) == 0x8000) // PTEST
{
fprintf(stderr,"680x0: unhandled PTEST\n");
return;
}
else
{
switch ((modes>>13) & 0x7)
{
case 0: // MC68030/040 form with FD bit
case 2: // MC68881 form, FD never set
if (modes & 0x200)
{
switch ((modes>>10) & 7)
{
case 0: // translation control register
WRITE_EA_32(ea, m68ki_cpu.mmu_tc);
break;
case 2: // supervisor root pointer
WRITE_EA_64(ea, (uint64)m68ki_cpu.mmu_srp_limit<<32 | (uint64)m68ki_cpu.mmu_srp_aptr);
break;
case 3: // CPU root pointer
WRITE_EA_64(ea, (uint64)m68ki_cpu.mmu_crp_limit<<32 | (uint64)m68ki_cpu.mmu_crp_aptr);
break;
default:
fprintf(stderr,"680x0: PMOVE from unknown MMU register %x, PC %x\n", (modes>>10) & 7, REG_PC);
break;
}
}
else
{
switch ((modes>>10) & 7)
{
case 0: // translation control register
m68ki_cpu.mmu_tc = READ_EA_32(ea);
if (m68ki_cpu.mmu_tc & 0x80000000)
{
m68ki_cpu.pmmu_enabled = 1;
}
else
{
m68ki_cpu.pmmu_enabled = 0;
}
break;
case 2: // supervisor root pointer
temp64 = READ_EA_64(ea);
m68ki_cpu.mmu_srp_limit = (temp64>>32) & 0xffffffff;
m68ki_cpu.mmu_srp_aptr = temp64 & 0xffffffff;
break;
case 3: // CPU root pointer
temp64 = READ_EA_64(ea);
m68ki_cpu.mmu_crp_limit = (temp64>>32) & 0xffffffff;
m68ki_cpu.mmu_crp_aptr = temp64 & 0xffffffff;
break;
default:
fprintf(stderr,"680x0: PMOVE to unknown MMU register %x, PC %x\n", (modes>>10) & 7, REG_PC);
break;
}
}
break;
case 3: // MC68030 to/from status reg
if (modes & 0x200)
{
WRITE_EA_32(ea, m68ki_cpu.mmu_sr);
}
else
{
m68ki_cpu.mmu_sr = READ_EA_32(ea);
}
break;
default:
fprintf(stderr,"680x0: unknown PMOVE mode %x (modes %04x) (PC %x)\n", (modes>>13) & 0x7, modes, REG_PC);
break;
}
}
break;
default:
fprintf(stderr,"680x0: unknown PMMU instruction group %d\n", (m68ki_cpu.ir>>9) & 0x7);
break;
}
}
}

View file

@ -1,7 +1,7 @@
MUSASHI
=======
Version 3.4
Version 4.10
A portable Motorola M680x0 processor emulation engine.
Copyright 1998-2002 Karl Stenerud. All rights reserved.
@ -11,8 +11,9 @@
INTRODUCTION:
------------
Musashi is a Motorola 68000, 68010, 68EC020, and 68020 emulator written in C.
This emulator was written with two goals in mind: portability and speed.
Musashi is a Motorola 68000, 68010, 68EC020, 68020, 68EC030, 68030, 68EC040 and
68040 emulator written in C. This emulator was written with two goals in mind:
portability and speed.
The emulator is written to ANSI C89 specifications. It also uses inline
functions, which are C9X compliant.
@ -146,11 +147,23 @@ To enable separate immediate reads:
unsigned int m68k_read_immediate_16(unsigned int address);
unsigned int m68k_read_immediate_32(unsigned int address);
Now you also have the pcrelative stuff:
unsigned int m68k_read_pcrelative_8(unsigned int address);
unsigned int m68k_read_pcrelative_16(unsigned int address);
unsigned int m68k_read_pcrelative_32(unsigned int address);
- If you need to know the current PC (for banking and such), set
M68K_MONITOR_PC to OPT_SPECIFY_HANDLER, and set M68K_SET_PC_CALLBACK(A) to
your routine.
- In the unlikely case where you need to emulate some PMMU in the immediate
reads and/or pcrealtive stuff, you'll need to explicitely call the
translation address mechanism from your user functions this way :
if (PMMU_ENABLED)
address = pmmu_translate_addr(address);
(this is handled automatically by normal memory accesses).
ADDRESS SPACES:
--------------
@ -212,9 +225,12 @@ To set the CPU type you want to use:
M68K_CPU_TYPE_68000,
M68K_CPU_TYPE_68010,
M68K_CPU_TYPE_68EC020,
M68K_CPU_TYPE_68020
M68K_CPU_TYPE_68020,
M68K_CPU_TYPE_68EC030,
M68K_CPU_TYPE_68030,
M68K_CPU_TYPE_68EC040,
M68K_CPU_TYPE_68040,
M68K_CPU_TYPE_SCC68070 (which is a 68010 with a 32 bit data bus).
CLOCK FREQUENCY:
---------------
@ -302,4 +318,25 @@ of the CPU.
EXAMPLE:
-------
The subdir example contains a full example (currently DOS only).
The subdir example contains a full example (currently linux & Dos only).
Compilation
-----------
You can use the default Makefile in Musashi's directory, it works like this :
1st build m68kmake, which will build m68kops.c and m68kops.h based on the
contents of m68k_in.c.
Then compile m68kcpu.o and m68kops.o. Add m68kdasm.o if you want the
disassemble functions. When linking this to your project you will need libm
for the fpu emulation of the 68040.
Using some custom m68kconf.h outside Musashi's directory
--------------------------------------------------------
It can be useful to keep an untouched musashi directory in a project (from
git for example) and maintain a separate m68kconf.h specific to the
project. For this, pass -DMUSASHI_CNF="mycustomconfig.h" to gcc (or whatever
compiler you use). Notice that if you use an unix shell (or make which uses
the shell to launch its commands), then you need to escape the quotes like
this : -DMUSASHI_CNF=\"mycustomconfig.h\"

View file

@ -0,0 +1,78 @@
MAME note: this package is derived from the following original SoftFloat
package and has been "re-packaged" to work with MAME's conventions and
build system. The source files come from bits64/ and bits64/templates
in the original distribution as MAME requires a compiler with a 64-bit
integer type.
Package Overview for SoftFloat Release 2b
John R. Hauser
2002 May 27
----------------------------------------------------------------------------
Overview
SoftFloat is a software implementation of floating-point that conforms to
the IEC/IEEE Standard for Binary Floating-Point Arithmetic. SoftFloat is
distributed in the form of C source code. Compiling the SoftFloat sources
generates two things:
-- A SoftFloat object file (typically `softfloat.o') containing the complete
set of IEC/IEEE floating-point routines.
-- A `timesoftfloat' program for evaluating the speed of the SoftFloat
routines. (The SoftFloat module is linked into this program.)
The SoftFloat package is documented in four text files:
SoftFloat.txt Documentation for using the SoftFloat functions.
SoftFloat-source.txt Documentation for compiling SoftFloat.
SoftFloat-history.txt History of major changes to SoftFloat.
timesoftfloat.txt Documentation for using `timesoftfloat'.
Other files in the package comprise the source code for SoftFloat.
Please be aware that some work is involved in porting this software to other
targets. It is not just a matter of getting `make' to complete without
error messages. I would have written the code that way if I could, but
there are fundamental differences between systems that can't be hidden.
You should not attempt to compile SoftFloat without first reading both
`SoftFloat.txt' and `SoftFloat-source.txt'.
----------------------------------------------------------------------------
Legal Notice
SoftFloat was written by me, John R. Hauser. This work was made possible in
part by the International Computer Science Institute, located at Suite 600,
1947 Center Street, Berkeley, California 94704. Funding was partially
provided by the National Science Foundation under grant MIP-9311980. The
original version of this code was written as part of a project to build
a fixed-point vector processor in collaboration with the University of
California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL
LOSSES, COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO
FURTHERMORE EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER
SCIENCE INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES,
COSTS, OR OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE
SOFTWARE.
Derivative works are acceptable, even for commercial purposes, provided
that the minimal documentation requirements stated in the source code are
satisfied.
----------------------------------------------------------------------------
Contact Information
At the time of this writing, the most up-to-date information about
SoftFloat and the latest release can be found at the Web page `http://
www.cs.berkeley.edu/~jhauser/arithmetic/SoftFloat.html'.

View file

@ -0,0 +1,61 @@
/*----------------------------------------------------------------------------
| One of the macros `BIGENDIAN' or `LITTLEENDIAN' must be defined.
*----------------------------------------------------------------------------*/
#ifdef LSB_FIRST
#define LITTLEENDIAN
#else
#define BIGENDIAN
#endif
/*----------------------------------------------------------------------------
| The macro `BITS64' can be defined to indicate that 64-bit integer types are
| supported by the compiler.
*----------------------------------------------------------------------------*/
#define BITS64
/*----------------------------------------------------------------------------
| Each of the following `typedef's defines the most convenient type that holds
| integers of at least as many bits as specified. For example, `uint8' should
| be the most convenient type that can hold unsigned integers of as many as
| 8 bits. The `flag' type must be able to hold either a 0 or 1. For most
| implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed
| to the same as `int'.
*----------------------------------------------------------------------------*/
typedef sint8 flag;
typedef sint8 int8;
typedef sint16 int16;
typedef sint32 int32;
typedef sint64 int64;
/*----------------------------------------------------------------------------
| Each of the following `typedef's defines a type that holds integers
| of _exactly_ the number of bits specified. For instance, for most
| implementation of C, `bits16' and `sbits16' should be `typedef'ed to
| `unsigned short int' and `signed short int' (or `short int'), respectively.
*----------------------------------------------------------------------------*/
typedef uint8 bits8;
typedef sint8 sbits8;
typedef uint16 bits16;
typedef sint16 sbits16;
typedef uint32 bits32;
typedef sint32 sbits32;
typedef uint64 bits64;
typedef sint64 sbits64;
/*----------------------------------------------------------------------------
| The `LIT64' macro takes as its argument a textual integer literal and
| if necessary ``marks'' the literal as having a 64-bit integer type.
| For example, the GNU C Compiler (`gcc') requires that 64-bit literals be
| appended with the letters `LL' standing for `long long', which is `gcc's
| name for the 64-bit integer type. Some compilers may allow `LIT64' to be
| defined as the identity macro: `#define LIT64( a ) a'.
*----------------------------------------------------------------------------*/
#define LIT64( a ) a##ULL
/*----------------------------------------------------------------------------
| The macro `INLINE' can be used before functions that should be inlined. If
| a compiler does not support explicit inlining, this macro should be defined
| to be `static'.
*----------------------------------------------------------------------------*/
// MAME defines INLINE

View file

@ -0,0 +1,42 @@
/*============================================================================
This C header file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic
Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*----------------------------------------------------------------------------
| Include common integer types and flags.
*----------------------------------------------------------------------------*/
#include "mamesf.h"
/*----------------------------------------------------------------------------
| Symbolic Boolean literals.
*----------------------------------------------------------------------------*/
#define FALSE 0
#define TRUE 1

View file

@ -0,0 +1,732 @@
/*============================================================================
This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal notice) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*----------------------------------------------------------------------------
| Shifts `a' right by the number of bits given in `count'. If any nonzero
| bits are shifted off, they are ``jammed'' into the least significant bit of
| the result by setting the least significant bit to 1. The value of `count'
| can be arbitrarily large; in particular, if `count' is greater than 32, the
| result will be either 0 or 1, depending on whether `a' is zero or nonzero.
| The result is stored in the location pointed to by `zPtr'.
*----------------------------------------------------------------------------*/
static inline void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr )
{
bits32 z;
if ( count == 0 ) {
z = a;
}
else if ( count < 32 ) {
z = ( a>>count ) | ( ( a<<( ( - count ) & 31 ) ) != 0 );
}
else {
z = ( a != 0 );
}
*zPtr = z;
}
/*----------------------------------------------------------------------------
| Shifts `a' right by the number of bits given in `count'. If any nonzero
| bits are shifted off, they are ``jammed'' into the least significant bit of
| the result by setting the least significant bit to 1. The value of `count'
| can be arbitrarily large; in particular, if `count' is greater than 64, the
| result will be either 0 or 1, depending on whether `a' is zero or nonzero.
| The result is stored in the location pointed to by `zPtr'.
*----------------------------------------------------------------------------*/
static inline void shift64RightJamming( bits64 a, int16 count, bits64 *zPtr )
{
bits64 z;
if ( count == 0 ) {
z = a;
}
else if ( count < 64 ) {
z = ( a>>count ) | ( ( a<<( ( - count ) & 63 ) ) != 0 );
}
else {
z = ( a != 0 );
}
*zPtr = z;
}
/*----------------------------------------------------------------------------
| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by 64
| _plus_ the number of bits given in `count'. The shifted result is at most
| 64 nonzero bits; this is stored at the location pointed to by `z0Ptr'. The
| bits shifted off form a second 64-bit result as follows: The _last_ bit
| shifted off is the most-significant bit of the extra result, and the other
| 63 bits of the extra result are all zero if and only if _all_but_the_last_
| bits shifted off were all zero. This extra result is stored in the location
| pointed to by `z1Ptr'. The value of `count' can be arbitrarily large.
| (This routine makes more sense if `a0' and `a1' are considered to form
| a fixed-point value with binary point between `a0' and `a1'. This fixed-
| point value is shifted right by the number of bits given in `count', and
| the integer part of the result is returned at the location pointed to by
| `z0Ptr'. The fractional part of the result may be slightly corrupted as
| described above, and is returned at the location pointed to by `z1Ptr'.)
*----------------------------------------------------------------------------*/
static inline void
shift64ExtraRightJamming(
bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits64 z0, z1;
int8 negCount = ( - count ) & 63;
if ( count == 0 ) {
z1 = a1;
z0 = a0;
}
else if ( count < 64 ) {
z1 = ( a0<<negCount ) | ( a1 != 0 );
z0 = a0>>count;
}
else {
if ( count == 64 ) {
z1 = a0 | ( a1 != 0 );
}
else {
z1 = ( ( a0 | a1 ) != 0 );
}
z0 = 0;
}
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
| number of bits given in `count'. Any bits shifted off are lost. The value
| of `count' can be arbitrarily large; in particular, if `count' is greater
| than 128, the result will be 0. The result is broken into two 64-bit pieces
| which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
static inline void
shift128Right(
bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits64 z0, z1;
int8 negCount = ( - count ) & 63;
if ( count == 0 ) {
z1 = a1;
z0 = a0;
}
else if ( count < 64 ) {
z1 = ( a0<<negCount ) | ( a1>>count );
z0 = a0>>count;
}
else {
z1 = ( count < 64 ) ? ( a0>>( count & 63 ) ) : 0;
z0 = 0;
}
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
| number of bits given in `count'. If any nonzero bits are shifted off, they
| are ``jammed'' into the least significant bit of the result by setting the
| least significant bit to 1. The value of `count' can be arbitrarily large;
| in particular, if `count' is greater than 128, the result will be either
| 0 or 1, depending on whether the concatenation of `a0' and `a1' is zero or
| nonzero. The result is broken into two 64-bit pieces which are stored at
| the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
static inline void
shift128RightJamming(
bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits64 z0, z1;
int8 negCount = ( - count ) & 63;
if ( count == 0 ) {
z1 = a1;
z0 = a0;
}
else if ( count < 64 ) {
z1 = ( a0<<negCount ) | ( a1>>count ) | ( ( a1<<negCount ) != 0 );
z0 = a0>>count;
}
else {
if ( count == 64 ) {
z1 = a0 | ( a1 != 0 );
}
else if ( count < 128 ) {
z1 = ( a0>>( count & 63 ) ) | ( ( ( a0<<negCount ) | a1 ) != 0 );
}
else {
z1 = ( ( a0 | a1 ) != 0 );
}
z0 = 0;
}
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' right
| by 64 _plus_ the number of bits given in `count'. The shifted result is
| at most 128 nonzero bits; these are broken into two 64-bit pieces which are
| stored at the locations pointed to by `z0Ptr' and `z1Ptr'. The bits shifted
| off form a third 64-bit result as follows: The _last_ bit shifted off is
| the most-significant bit of the extra result, and the other 63 bits of the
| extra result are all zero if and only if _all_but_the_last_ bits shifted off
| were all zero. This extra result is stored in the location pointed to by
| `z2Ptr'. The value of `count' can be arbitrarily large.
| (This routine makes more sense if `a0', `a1', and `a2' are considered
| to form a fixed-point value with binary point between `a1' and `a2'. This
| fixed-point value is shifted right by the number of bits given in `count',
| and the integer part of the result is returned at the locations pointed to
| by `z0Ptr' and `z1Ptr'. The fractional part of the result may be slightly
| corrupted as described above, and is returned at the location pointed to by
| `z2Ptr'.)
*----------------------------------------------------------------------------*/
static inline void
shift128ExtraRightJamming(
bits64 a0,
bits64 a1,
bits64 a2,
int16 count,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2;
int8 negCount = ( - count ) & 63;
if ( count == 0 ) {
z2 = a2;
z1 = a1;
z0 = a0;
}
else {
if ( count < 64 ) {
z2 = a1<<negCount;
z1 = ( a0<<negCount ) | ( a1>>count );
z0 = a0>>count;
}
else {
if ( count == 64 ) {
z2 = a1;
z1 = a0;
}
else {
a2 |= a1;
if ( count < 128 ) {
z2 = a0<<negCount;
z1 = a0>>( count & 63 );
}
else {
z2 = ( count == 128 ) ? a0 : ( a0 != 0 );
z1 = 0;
}
}
z0 = 0;
}
z2 |= ( a2 != 0 );
}
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Shifts the 128-bit value formed by concatenating `a0' and `a1' left by the
| number of bits given in `count'. Any bits shifted off are lost. The value
| of `count' must be less than 64. The result is broken into two 64-bit
| pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
static inline void
shortShift128Left(
bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
{
*z1Ptr = a1<<count;
*z0Ptr =
( count == 0 ) ? a0 : ( a0<<count ) | ( a1>>( ( - count ) & 63 ) );
}
/*----------------------------------------------------------------------------
| Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' left
| by the number of bits given in `count'. Any bits shifted off are lost.
| The value of `count' must be less than 64. The result is broken into three
| 64-bit pieces which are stored at the locations pointed to by `z0Ptr',
| `z1Ptr', and `z2Ptr'.
*----------------------------------------------------------------------------*/
static inline void
shortShift192Left(
bits64 a0,
bits64 a1,
bits64 a2,
int16 count,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2;
int8 negCount;
z2 = a2<<count;
z1 = a1<<count;
z0 = a0<<count;
if ( 0 < count ) {
negCount = ( ( - count ) & 63 );
z1 |= a2>>negCount;
z0 |= a1>>negCount;
}
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Adds the 128-bit value formed by concatenating `a0' and `a1' to the 128-bit
| value formed by concatenating `b0' and `b1'. Addition is modulo 2^128, so
| any carry out is lost. The result is broken into two 64-bit pieces which
| are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
static inline void
add128(
bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits64 z1;
z1 = a1 + b1;
*z1Ptr = z1;
*z0Ptr = a0 + b0 + ( z1 < a1 );
}
/*----------------------------------------------------------------------------
| Adds the 192-bit value formed by concatenating `a0', `a1', and `a2' to the
| 192-bit value formed by concatenating `b0', `b1', and `b2'. Addition is
| modulo 2^192, so any carry out is lost. The result is broken into three
| 64-bit pieces which are stored at the locations pointed to by `z0Ptr',
| `z1Ptr', and `z2Ptr'.
*----------------------------------------------------------------------------*/
static inline void
add192(
bits64 a0,
bits64 a1,
bits64 a2,
bits64 b0,
bits64 b1,
bits64 b2,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2;
uint8 carry0, carry1;
z2 = a2 + b2;
carry1 = ( z2 < a2 );
z1 = a1 + b1;
carry0 = ( z1 < a1 );
z0 = a0 + b0;
z1 += carry1;
z0 += ( z1 < carry1 );
z0 += carry0;
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Subtracts the 128-bit value formed by concatenating `b0' and `b1' from the
| 128-bit value formed by concatenating `a0' and `a1'. Subtraction is modulo
| 2^128, so any borrow out (carry out) is lost. The result is broken into two
| 64-bit pieces which are stored at the locations pointed to by `z0Ptr' and
| `z1Ptr'.
*----------------------------------------------------------------------------*/
static inline void
sub128(
bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr )
{
*z1Ptr = a1 - b1;
*z0Ptr = a0 - b0 - ( a1 < b1 );
}
/*----------------------------------------------------------------------------
| Subtracts the 192-bit value formed by concatenating `b0', `b1', and `b2'
| from the 192-bit value formed by concatenating `a0', `a1', and `a2'.
| Subtraction is modulo 2^192, so any borrow out (carry out) is lost. The
| result is broken into three 64-bit pieces which are stored at the locations
| pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'.
*----------------------------------------------------------------------------*/
static inline void
sub192(
bits64 a0,
bits64 a1,
bits64 a2,
bits64 b0,
bits64 b1,
bits64 b2,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2;
uint8 borrow0, borrow1;
z2 = a2 - b2;
borrow1 = ( a2 < b2 );
z1 = a1 - b1;
borrow0 = ( a1 < b1 );
z0 = a0 - b0;
z0 -= ( z1 < borrow1 );
z1 -= borrow1;
z0 -= borrow0;
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Multiplies `a' by `b' to obtain a 128-bit product. The product is broken
| into two 64-bit pieces which are stored at the locations pointed to by
| `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
static inline void mul64To128( bits64 a, bits64 b, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits32 aHigh, aLow, bHigh, bLow;
bits64 z0, zMiddleA, zMiddleB, z1;
aLow = a;
aHigh = a>>32;
bLow = b;
bHigh = b>>32;
z1 = ( (bits64) aLow ) * bLow;
zMiddleA = ( (bits64) aLow ) * bHigh;
zMiddleB = ( (bits64) aHigh ) * bLow;
z0 = ( (bits64) aHigh ) * bHigh;
zMiddleA += zMiddleB;
z0 += ( ( (bits64) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 );
zMiddleA <<= 32;
z1 += zMiddleA;
z0 += ( z1 < zMiddleA );
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Multiplies the 128-bit value formed by concatenating `a0' and `a1' by
| `b' to obtain a 192-bit product. The product is broken into three 64-bit
| pieces which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and
| `z2Ptr'.
*----------------------------------------------------------------------------*/
static inline void
mul128By64To192(
bits64 a0,
bits64 a1,
bits64 b,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2, more1;
mul64To128( a1, b, &z1, &z2 );
mul64To128( a0, b, &z0, &more1 );
add128( z0, more1, 0, z1, &z0, &z1 );
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Multiplies the 128-bit value formed by concatenating `a0' and `a1' to the
| 128-bit value formed by concatenating `b0' and `b1' to obtain a 256-bit
| product. The product is broken into four 64-bit pieces which are stored at
| the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'.
*----------------------------------------------------------------------------*/
static inline void
mul128To256(
bits64 a0,
bits64 a1,
bits64 b0,
bits64 b1,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr,
bits64 *z3Ptr
)
{
bits64 z0, z1, z2, z3;
bits64 more1, more2;
mul64To128( a1, b1, &z2, &z3 );
mul64To128( a1, b0, &z1, &more2 );
add128( z1, more2, 0, z2, &z1, &z2 );
mul64To128( a0, b0, &z0, &more1 );
add128( z0, more1, 0, z1, &z0, &z1 );
mul64To128( a0, b1, &more1, &more2 );
add128( more1, more2, 0, z2, &more1, &z2 );
add128( z0, z1, 0, more1, &z0, &z1 );
*z3Ptr = z3;
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Returns an approximation to the 64-bit integer quotient obtained by dividing
| `b' into the 128-bit value formed by concatenating `a0' and `a1'. The
| divisor `b' must be at least 2^63. If q is the exact quotient truncated
| toward zero, the approximation returned lies between q and q + 2 inclusive.
| If the exact quotient q is larger than 64 bits, the maximum positive 64-bit
| unsigned integer is returned.
*----------------------------------------------------------------------------*/
static inline bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b )
{
bits64 b0, b1;
bits64 rem0, rem1, term0, term1;
bits64 z;
if ( b <= a0 ) return LIT64( 0xFFFFFFFFFFFFFFFF );
b0 = b>>32;
z = ( b0<<32 <= a0 ) ? LIT64( 0xFFFFFFFF00000000 ) : ( a0 / b0 )<<32;
mul64To128( b, z, &term0, &term1 );
sub128( a0, a1, term0, term1, &rem0, &rem1 );
while ( ( (sbits64) rem0 ) < 0 ) {
z -= LIT64( 0x100000000 );
b1 = b<<32;
add128( rem0, rem1, b0, b1, &rem0, &rem1 );
}
rem0 = ( rem0<<32 ) | ( rem1>>32 );
z |= ( b0<<32 <= rem0 ) ? 0xFFFFFFFF : rem0 / b0;
return z;
}
/*----------------------------------------------------------------------------
| Returns an approximation to the square root of the 32-bit significand given
| by `a'. Considered as an integer, `a' must be at least 2^31. If bit 0 of
| `aExp' (the least significant bit) is 1, the integer returned approximates
| 2^31*sqrt(`a'/2^31), where `a' is considered an integer. If bit 0 of `aExp'
| is 0, the integer returned approximates 2^31*sqrt(`a'/2^30). In either
| case, the approximation returned lies strictly within +/-2 of the exact
| value.
*----------------------------------------------------------------------------*/
static inline bits32 estimateSqrt32( int16 aExp, bits32 a )
{
static const bits16 sqrtOddAdjustments[] = {
0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0,
0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67
};
static const bits16 sqrtEvenAdjustments[] = {
0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E,
0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002
};
int8 index;
bits32 z;
index = ( a>>27 ) & 15;
if ( aExp & 1 ) {
z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ index ];
z = ( ( a / z )<<14 ) + ( z<<15 );
a >>= 1;
}
else {
z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ index ];
z = a / z + z;
z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 );
if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 );
}
return ( (bits32) ( ( ( (bits64) a )<<31 ) / z ) ) + ( z>>1 );
}
/*----------------------------------------------------------------------------
| Returns the number of leading 0 bits before the most-significant 1 bit of
| `a'. If `a' is zero, 32 is returned.
*----------------------------------------------------------------------------*/
static int8 countLeadingZeros32( bits32 a )
{
static const int8 countLeadingZerosHigh[] = {
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
int8 shiftCount;
shiftCount = 0;
if ( a < 0x10000 ) {
shiftCount += 16;
a <<= 16;
}
if ( a < 0x1000000 ) {
shiftCount += 8;
a <<= 8;
}
shiftCount += countLeadingZerosHigh[ a>>24 ];
return shiftCount;
}
/*----------------------------------------------------------------------------
| Returns the number of leading 0 bits before the most-significant 1 bit of
| `a'. If `a' is zero, 64 is returned.
*----------------------------------------------------------------------------*/
static int8 countLeadingZeros64( bits64 a )
{
int8 shiftCount;
shiftCount = 0;
if ( a < ( (bits64) 1 )<<32 ) {
shiftCount += 32;
}
else {
a >>= 32;
}
shiftCount += countLeadingZeros32( a );
return shiftCount;
}
/*----------------------------------------------------------------------------
| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1'
| is equal to the 128-bit value formed by concatenating `b0' and `b1'.
| Otherwise, returns 0.
*----------------------------------------------------------------------------*/
static inline flag eq128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
{
return ( a0 == b0 ) && ( a1 == b1 );
}
/*----------------------------------------------------------------------------
| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
| than or equal to the 128-bit value formed by concatenating `b0' and `b1'.
| Otherwise, returns 0.
*----------------------------------------------------------------------------*/
static inline flag le128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
{
return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) );
}
/*----------------------------------------------------------------------------
| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
| than the 128-bit value formed by concatenating `b0' and `b1'. Otherwise,
| returns 0.
*----------------------------------------------------------------------------*/
static inline flag lt128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
{
return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) );
}
/*----------------------------------------------------------------------------
| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is
| not equal to the 128-bit value formed by concatenating `b0' and `b1'.
| Otherwise, returns 0.
*----------------------------------------------------------------------------*/
static inline flag ne128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
{
return ( a0 != b0 ) || ( a1 != b1 );
}
/*-----------------------------------------------------------------------------
| Changes the sign of the extended double-precision floating-point value 'a'.
| The operation is performed according to the IEC/IEEE Standard for Binary
| Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
static inline floatx80 floatx80_chs(floatx80 reg)
{
reg.high ^= 0x8000;
return reg;
}

View file

@ -0,0 +1,470 @@
/*============================================================================
This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*----------------------------------------------------------------------------
| Underflow tininess-detection mode, statically initialized to default value.
| (The declaration in `softfloat.h' must match the `int8' type here.)
*----------------------------------------------------------------------------*/
int8 float_detect_tininess = float_tininess_after_rounding;
/*----------------------------------------------------------------------------
| Raises the exceptions specified by `flags'. Floating-point traps can be
| defined here if desired. It is currently not possible for such a trap to
| substitute a result value. If traps are not implemented, this routine
| should be simply `float_exception_flags |= flags;'.
*----------------------------------------------------------------------------*/
void float_raise( int8 flags )
{
float_exception_flags |= flags;
}
/*----------------------------------------------------------------------------
| Internal canonical NaN format.
*----------------------------------------------------------------------------*/
typedef struct {
flag sign;
bits64 high, low;
} commonNaNT;
/*----------------------------------------------------------------------------
| The pattern for a default generated single-precision NaN.
*----------------------------------------------------------------------------*/
#define float32_default_nan 0xFFFFFFFF
/*----------------------------------------------------------------------------
| Returns 1 if the single-precision floating-point value `a' is a NaN;
| otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float32_is_nan( float32 a )
{
return ( 0xFF000000 < (bits32) ( a<<1 ) );
}
/*----------------------------------------------------------------------------
| Returns 1 if the single-precision floating-point value `a' is a signaling
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float32_is_signaling_nan( float32 a )
{
return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
}
/*----------------------------------------------------------------------------
| Returns the result of converting the single-precision floating-point NaN
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
| exception is raised.
*----------------------------------------------------------------------------*/
static commonNaNT float32ToCommonNaN( float32 a )
{
commonNaNT z;
if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
z.sign = a>>31;
z.low = 0;
z.high = ( (bits64) a )<<41;
return z;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the canonical NaN `a' to the single-
| precision floating-point format.
*----------------------------------------------------------------------------*/
static float32 commonNaNToFloat32( commonNaNT a )
{
return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 );
}
/*----------------------------------------------------------------------------
| Takes two single-precision floating-point values `a' and `b', one of which
| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
| signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
static float32 propagateFloat32NaN( float32 a, float32 b )
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = float32_is_nan( a );
aIsSignalingNaN = float32_is_signaling_nan( a );
bIsNaN = float32_is_nan( b );
bIsSignalingNaN = float32_is_signaling_nan( b );
a |= 0x00400000;
b |= 0x00400000;
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
if ( aIsNaN ) {
return ( aIsSignalingNaN & bIsNaN ) ? b : a;
}
else {
return b;
}
}
/*----------------------------------------------------------------------------
| The pattern for a default generated double-precision NaN.
*----------------------------------------------------------------------------*/
#define float64_default_nan LIT64( 0xFFFFFFFFFFFFFFFF )
/*----------------------------------------------------------------------------
| Returns 1 if the double-precision floating-point value `a' is a NaN;
| otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float64_is_nan( float64 a )
{
return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) );
}
/*----------------------------------------------------------------------------
| Returns 1 if the double-precision floating-point value `a' is a signaling
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float64_is_signaling_nan( float64 a )
{
return
( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
&& ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
}
/*----------------------------------------------------------------------------
| Returns the result of converting the double-precision floating-point NaN
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
| exception is raised.
*----------------------------------------------------------------------------*/
static commonNaNT float64ToCommonNaN( float64 a )
{
commonNaNT z;
if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
z.sign = a>>63;
z.low = 0;
z.high = a<<12;
return z;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the canonical NaN `a' to the double-
| precision floating-point format.
*----------------------------------------------------------------------------*/
static float64 commonNaNToFloat64( commonNaNT a )
{
return
( ( (bits64) a.sign )<<63 )
| LIT64( 0x7FF8000000000000 )
| ( a.high>>12 );
}
/*----------------------------------------------------------------------------
| Takes two double-precision floating-point values `a' and `b', one of which
| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
| signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
static float64 propagateFloat64NaN( float64 a, float64 b )
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = float64_is_nan( a );
aIsSignalingNaN = float64_is_signaling_nan( a );
bIsNaN = float64_is_nan( b );
bIsSignalingNaN = float64_is_signaling_nan( b );
a |= LIT64( 0x0008000000000000 );
b |= LIT64( 0x0008000000000000 );
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
if ( aIsNaN ) {
return ( aIsSignalingNaN & bIsNaN ) ? b : a;
}
else {
return b;
}
}
#ifdef FLOATX80
/*----------------------------------------------------------------------------
| The pattern for a default generated extended double-precision NaN. The
| `high' and `low' values hold the most- and least-significant bits,
| respectively.
*----------------------------------------------------------------------------*/
#define floatx80_default_nan_high 0xFFFF
#define floatx80_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF )
/*----------------------------------------------------------------------------
| Returns 1 if the extended double-precision floating-point value `a' is a
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
flag floatx80_is_nan( floatx80 a )
{
return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 );
}
/*----------------------------------------------------------------------------
| Returns 1 if the extended double-precision floating-point value `a' is a
| signaling NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
flag floatx80_is_signaling_nan( floatx80 a )
{
bits64 aLow;
aLow = a.low & ~ LIT64( 0x4000000000000000 );
return
( ( a.high & 0x7FFF ) == 0x7FFF )
&& (bits64) ( aLow<<1 )
&& ( a.low == aLow );
}
/*----------------------------------------------------------------------------
| Returns the result of converting the extended double-precision floating-
| point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the
| invalid exception is raised.
*----------------------------------------------------------------------------*/
static commonNaNT floatx80ToCommonNaN( floatx80 a )
{
commonNaNT z;
if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
z.sign = a.high>>15;
z.low = 0;
z.high = a.low<<1;
return z;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the canonical NaN `a' to the extended
| double-precision floating-point format.
*----------------------------------------------------------------------------*/
static floatx80 commonNaNToFloatx80( commonNaNT a )
{
floatx80 z;
z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 );
z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF;
return z;
}
/*----------------------------------------------------------------------------
| Takes two extended double-precision floating-point values `a' and `b', one
| of which is a NaN, and returns the appropriate NaN result. If either `a' or
| `b' is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b )
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = floatx80_is_nan( a );
aIsSignalingNaN = floatx80_is_signaling_nan( a );
bIsNaN = floatx80_is_nan( b );
bIsSignalingNaN = floatx80_is_signaling_nan( b );
a.low |= LIT64( 0xC000000000000000 );
b.low |= LIT64( 0xC000000000000000 );
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
if ( aIsNaN ) {
return ( aIsSignalingNaN & bIsNaN ) ? b : a;
}
else {
return b;
}
}
#define EXP_BIAS 0x3FFF
/*----------------------------------------------------------------------------
| Returns the fraction bits of the extended double-precision floating-point
| value `a'.
*----------------------------------------------------------------------------*/
static inline bits64 extractFloatx80Frac( floatx80 a )
{
return a.low;
}
/*----------------------------------------------------------------------------
| Returns the exponent bits of the extended double-precision floating-point
| value `a'.
*----------------------------------------------------------------------------*/
static inline int32 extractFloatx80Exp( floatx80 a )
{
return a.high & 0x7FFF;
}
/*----------------------------------------------------------------------------
| Returns the sign bit of the extended double-precision floating-point value
| `a'.
*----------------------------------------------------------------------------*/
static inline flag extractFloatx80Sign( floatx80 a )
{
return a.high>>15;
}
#endif
#ifdef FLOAT128
/*----------------------------------------------------------------------------
| The pattern for a default generated quadruple-precision NaN. The `high' and
| `low' values hold the most- and least-significant bits, respectively.
*----------------------------------------------------------------------------*/
#define float128_default_nan_high LIT64( 0xFFFFFFFFFFFFFFFF )
#define float128_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF )
/*----------------------------------------------------------------------------
| Returns 1 if the quadruple-precision floating-point value `a' is a NaN;
| otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float128_is_nan( float128 a )
{
return
( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) )
&& ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) );
}
/*----------------------------------------------------------------------------
| Returns 1 if the quadruple-precision floating-point value `a' is a
| signaling NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
flag float128_is_signaling_nan( float128 a )
{
return
( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE )
&& ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) );
}
/*----------------------------------------------------------------------------
| Returns the result of converting the quadruple-precision floating-point NaN
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
| exception is raised.
*----------------------------------------------------------------------------*/
static commonNaNT float128ToCommonNaN( float128 a )
{
commonNaNT z;
if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
z.sign = a.high>>63;
shortShift128Left( a.high, a.low, 16, &z.high, &z.low );
return z;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the canonical NaN `a' to the quadruple-
| precision floating-point format.
*----------------------------------------------------------------------------*/
static float128 commonNaNToFloat128( commonNaNT a )
{
float128 z;
shift128Right( a.high, a.low, 16, &z.high, &z.low );
z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 );
return z;
}
/*----------------------------------------------------------------------------
| Takes two quadruple-precision floating-point values `a' and `b', one of
| which is a NaN, and returns the appropriate NaN result. If either `a' or
| `b' is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
static float128 propagateFloat128NaN( float128 a, float128 b )
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = float128_is_nan( a );
aIsSignalingNaN = float128_is_signaling_nan( a );
bIsNaN = float128_is_nan( b );
bIsSignalingNaN = float128_is_signaling_nan( b );
a.high |= LIT64( 0x0000800000000000 );
b.high |= LIT64( 0x0000800000000000 );
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
if ( aIsNaN ) {
return ( aIsSignalingNaN & bIsNaN ) ? b : a;
}
else {
return b;
}
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,460 @@
/*============================================================================
This C header file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic
Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*----------------------------------------------------------------------------
| The macro `FLOATX80' must be defined to enable the extended double-precision
| floating-point format `floatx80'. If this macro is not defined, the
| `floatx80' type will not be defined, and none of the functions that either
| input or output the `floatx80' type will be defined. The same applies to
| the `FLOAT128' macro and the quadruple-precision format `float128'.
*----------------------------------------------------------------------------*/
#define FLOATX80
#define FLOAT128
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point types.
*----------------------------------------------------------------------------*/
typedef bits32 float32;
typedef bits64 float64;
#ifdef FLOATX80
typedef struct {
bits16 high;
bits64 low;
} floatx80;
#endif
#ifdef FLOAT128
typedef struct {
bits64 high, low;
} float128;
#endif
/*----------------------------------------------------------------------------
| Primitive arithmetic functions, including multi-word arithmetic, and
| division and square root approximations. (Can be specialized to target if
| desired.)
*----------------------------------------------------------------------------*/
#include "softfloat-macros"
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point underflow tininess-detection mode.
*----------------------------------------------------------------------------*/
extern int8 float_detect_tininess;
enum {
float_tininess_after_rounding = 0,
float_tininess_before_rounding = 1
};
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point rounding mode.
*----------------------------------------------------------------------------*/
extern int8 float_rounding_mode;
enum {
float_round_nearest_even = 0,
float_round_to_zero = 1,
float_round_down = 2,
float_round_up = 3
};
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point exception flags.
*----------------------------------------------------------------------------*/
extern int8 float_exception_flags;
enum {
float_flag_invalid = 0x01, float_flag_denormal = 0x02, float_flag_divbyzero = 0x04, float_flag_overflow = 0x08,
float_flag_underflow = 0x10, float_flag_inexact = 0x20
};
/*----------------------------------------------------------------------------
| Routine to raise any or all of the software IEC/IEEE floating-point
| exception flags.
*----------------------------------------------------------------------------*/
void float_raise( int8 );
/*----------------------------------------------------------------------------
| Software IEC/IEEE integer-to-floating-point conversion routines.
*----------------------------------------------------------------------------*/
float32 int32_to_float32( int32 );
float64 int32_to_float64( int32 );
#ifdef FLOATX80
floatx80 int32_to_floatx80( int32 );
#endif
#ifdef FLOAT128
float128 int32_to_float128( int32 );
#endif
float32 int64_to_float32( int64 );
float64 int64_to_float64( int64 );
#ifdef FLOATX80
floatx80 int64_to_floatx80( int64 );
#endif
#ifdef FLOAT128
float128 int64_to_float128( int64 );
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision conversion routines.
*----------------------------------------------------------------------------*/
int32 float32_to_int32( float32 );
int32 float32_to_int32_round_to_zero( float32 );
int64 float32_to_int64( float32 );
int64 float32_to_int64_round_to_zero( float32 );
float64 float32_to_float64( float32 );
#ifdef FLOATX80
floatx80 float32_to_floatx80( float32 );
#endif
#ifdef FLOAT128
float128 float32_to_float128( float32 );
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision operations.
*----------------------------------------------------------------------------*/
float32 float32_round_to_int( float32 );
float32 float32_add( float32, float32 );
float32 float32_sub( float32, float32 );
float32 float32_mul( float32, float32 );
float32 float32_div( float32, float32 );
float32 float32_rem( float32, float32 );
float32 float32_sqrt( float32 );
flag float32_eq( float32, float32 );
flag float32_le( float32, float32 );
flag float32_lt( float32, float32 );
flag float32_eq_signaling( float32, float32 );
flag float32_le_quiet( float32, float32 );
flag float32_lt_quiet( float32, float32 );
flag float32_is_signaling_nan( float32 );
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision conversion routines.
*----------------------------------------------------------------------------*/
int32 float64_to_int32( float64 );
int32 float64_to_int32_round_to_zero( float64 );
int64 float64_to_int64( float64 );
int64 float64_to_int64_round_to_zero( float64 );
float32 float64_to_float32( float64 );
#ifdef FLOATX80
floatx80 float64_to_floatx80( float64 );
#endif
#ifdef FLOAT128
float128 float64_to_float128( float64 );
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision operations.
*----------------------------------------------------------------------------*/
float64 float64_round_to_int( float64 );
float64 float64_add( float64, float64 );
float64 float64_sub( float64, float64 );
float64 float64_mul( float64, float64 );
float64 float64_div( float64, float64 );
float64 float64_rem( float64, float64 );
float64 float64_sqrt( float64 );
flag float64_eq( float64, float64 );
flag float64_le( float64, float64 );
flag float64_lt( float64, float64 );
flag float64_eq_signaling( float64, float64 );
flag float64_le_quiet( float64, float64 );
flag float64_lt_quiet( float64, float64 );
flag float64_is_signaling_nan( float64 );
#ifdef FLOATX80
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision conversion routines.
*----------------------------------------------------------------------------*/
int32 floatx80_to_int32( floatx80 );
int32 floatx80_to_int32_round_to_zero( floatx80 );
int64 floatx80_to_int64( floatx80 );
int64 floatx80_to_int64_round_to_zero( floatx80 );
float32 floatx80_to_float32( floatx80 );
float64 floatx80_to_float64( floatx80 );
#ifdef FLOAT128
float128 floatx80_to_float128( floatx80 );
#endif
floatx80 floatx80_scale(floatx80 a, floatx80 b);
/*----------------------------------------------------------------------------
| Packs the sign `zSign', exponent `zExp', and significand `zSig' into an
| extended double-precision floating-point value, returning the result.
*----------------------------------------------------------------------------*/
static inline floatx80 packFloatx80( flag zSign, int32 zExp, bits64 zSig )
{
floatx80 z;
z.low = zSig;
z.high = ( ( (bits16) zSign )<<15 ) + zExp;
return z;
}
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision rounding precision. Valid
| values are 32, 64, and 80.
*----------------------------------------------------------------------------*/
extern int8 floatx80_rounding_precision;
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision operations.
*----------------------------------------------------------------------------*/
floatx80 floatx80_round_to_int( floatx80 );
floatx80 floatx80_add( floatx80, floatx80 );
floatx80 floatx80_sub( floatx80, floatx80 );
floatx80 floatx80_mul( floatx80, floatx80 );
floatx80 floatx80_div( floatx80, floatx80 );
floatx80 floatx80_rem( floatx80, floatx80 );
floatx80 floatx80_sqrt( floatx80 );
flag floatx80_eq( floatx80, floatx80 );
flag floatx80_le( floatx80, floatx80 );
flag floatx80_lt( floatx80, floatx80 );
flag floatx80_eq_signaling( floatx80, floatx80 );
flag floatx80_le_quiet( floatx80, floatx80 );
flag floatx80_lt_quiet( floatx80, floatx80 );
flag floatx80_is_signaling_nan( floatx80 );
/* int floatx80_fsin(floatx80 &a);
int floatx80_fcos(floatx80 &a);
int floatx80_ftan(floatx80 &a); */
floatx80 floatx80_flognp1(floatx80 a);
floatx80 floatx80_flogn(floatx80 a);
floatx80 floatx80_flog2(floatx80 a);
floatx80 floatx80_flog10(floatx80 a);
// roundAndPackFloatx80 used to be in softfloat-round-pack, is now in softfloat.c
floatx80 roundAndPackFloatx80(int8 roundingPrecision, flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1);
#endif
#ifdef FLOAT128
/*----------------------------------------------------------------------------
| Software IEC/IEEE quadruple-precision conversion routines.
*----------------------------------------------------------------------------*/
int32 float128_to_int32( float128 );
int32 float128_to_int32_round_to_zero( float128 );
int64 float128_to_int64( float128 );
int64 float128_to_int64_round_to_zero( float128 );
float32 float128_to_float32( float128 );
float64 float128_to_float64( float128 );
#ifdef FLOATX80
floatx80 float128_to_floatx80( float128 );
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE quadruple-precision operations.
*----------------------------------------------------------------------------*/
float128 float128_round_to_int( float128 );
float128 float128_add( float128, float128 );
float128 float128_sub( float128, float128 );
float128 float128_mul( float128, float128 );
float128 float128_div( float128, float128 );
float128 float128_rem( float128, float128 );
float128 float128_sqrt( float128 );
flag float128_eq( float128, float128 );
flag float128_le( float128, float128 );
flag float128_lt( float128, float128 );
flag float128_eq_signaling( float128, float128 );
flag float128_le_quiet( float128, float128 );
flag float128_lt_quiet( float128, float128 );
flag float128_is_signaling_nan( float128 );
/*----------------------------------------------------------------------------
| Packs the sign `zSign', the exponent `zExp', and the significand formed
| by the concatenation of `zSig0' and `zSig1' into a quadruple-precision
| floating-point value, returning the result. After being shifted into the
| proper positions, the three fields `zSign', `zExp', and `zSig0' are simply
| added together to form the most significant 32 bits of the result. This
| means that any integer portion of `zSig0' will be added into the exponent.
| Since a properly normalized significand will have an integer portion equal
| to 1, the `zExp' input should be 1 less than the desired result exponent
| whenever `zSig0' and `zSig1' concatenated form a complete, normalized
| significand.
*----------------------------------------------------------------------------*/
static inline float128
packFloat128( flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1 )
{
float128 z;
z.low = zSig1;
z.high = ( ( (bits64) zSign )<<63 ) + ( ( (bits64) zExp )<<48 ) + zSig0;
return z;
}
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and extended significand formed by the concatenation of `zSig0', `zSig1',
| and `zSig2', and returns the proper quadruple-precision floating-point value
| corresponding to the abstract input. Ordinarily, the abstract value is
| simply rounded and packed into the quadruple-precision format, with the
| inexact exception raised if the abstract input cannot be represented
| exactly. However, if the abstract value is too large, the overflow and
| inexact exceptions are raised and an infinity or maximal finite value is
| returned. If the abstract value is too small, the input value is rounded to
| a subnormal number, and the underflow and inexact exceptions are raised if
| the abstract input cannot be represented exactly as a subnormal quadruple-
| precision floating-point number.
| The input significand must be normalized or smaller. If the input
| significand is not normalized, `zExp' must be 0; in that case, the result
| returned is a subnormal number, and it must not require rounding. In the
| usual case that the input significand is normalized, `zExp' must be 1 less
| than the ``true'' floating-point exponent. The handling of underflow and
| overflow follows the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
static inline float128
roundAndPackFloat128(
flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1, bits64 zSig2 )
{
int8 roundingMode;
flag roundNearestEven, increment, isTiny;
roundingMode = float_rounding_mode;
roundNearestEven = ( roundingMode == float_round_nearest_even );
increment = ( (sbits64) zSig2 < 0 );
if ( ! roundNearestEven ) {
if ( roundingMode == float_round_to_zero ) {
increment = 0;
}
else {
if ( zSign ) {
increment = ( roundingMode == float_round_down ) && zSig2;
}
else {
increment = ( roundingMode == float_round_up ) && zSig2;
}
}
}
if ( 0x7FFD <= (bits32) zExp ) {
if ( ( 0x7FFD < zExp )
|| ( ( zExp == 0x7FFD )
&& eq128(
LIT64( 0x0001FFFFFFFFFFFF ),
LIT64( 0xFFFFFFFFFFFFFFFF ),
zSig0,
zSig1
)
&& increment
)
) {
float_raise( float_flag_overflow | float_flag_inexact );
if ( ( roundingMode == float_round_to_zero )
|| ( zSign && ( roundingMode == float_round_up ) )
|| ( ! zSign && ( roundingMode == float_round_down ) )
) {
return
packFloat128(
zSign,
0x7FFE,
LIT64( 0x0000FFFFFFFFFFFF ),
LIT64( 0xFFFFFFFFFFFFFFFF )
);
}
return packFloat128( zSign, 0x7FFF, 0, 0 );
}
if ( zExp < 0 ) {
isTiny =
( float_detect_tininess == float_tininess_before_rounding )
|| ( zExp < -1 )
|| ! increment
|| lt128(
zSig0,
zSig1,
LIT64( 0x0001FFFFFFFFFFFF ),
LIT64( 0xFFFFFFFFFFFFFFFF )
);
shift128ExtraRightJamming(
zSig0, zSig1, zSig2, - zExp, &zSig0, &zSig1, &zSig2 );
zExp = 0;
if ( isTiny && zSig2 ) float_raise( float_flag_underflow );
if ( roundNearestEven ) {
increment = ( (sbits64) zSig2 < 0 );
}
else {
if ( zSign ) {
increment = ( roundingMode == float_round_down ) && zSig2;
}
else {
increment = ( roundingMode == float_round_up ) && zSig2;
}
}
}
}
if ( zSig2 ) float_exception_flags |= float_flag_inexact;
if ( increment ) {
add128( zSig0, zSig1, 0, 1, &zSig0, &zSig1 );
zSig1 &= ~ ( ( zSig2 + zSig2 == 0 ) & roundNearestEven );
}
else {
if ( ( zSig0 | zSig1 ) == 0 ) zExp = 0;
}
return packFloat128( zSign, zExp, zSig0, zSig1 );
}
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and significand formed by the concatenation of `zSig0' and `zSig1', and
| returns the proper quadruple-precision floating-point value corresponding
| to the abstract input. This routine is just like `roundAndPackFloat128'
| except that the input significand has fewer bits and does not have to be
| normalized. In all cases, `zExp' must be 1 less than the ``true'' floating-
| point exponent.
*----------------------------------------------------------------------------*/
static inline float128
normalizeRoundAndPackFloat128(
flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1 )
{
int8 shiftCount;
bits64 zSig2;
if ( zSig0 == 0 ) {
zSig0 = zSig1;
zSig1 = 0;
zExp -= 64;
}
shiftCount = countLeadingZeros64( zSig0 ) - 15;
if ( 0 <= shiftCount ) {
zSig2 = 0;
shortShift128Left( zSig0, zSig1, shiftCount, &zSig0, &zSig1 );
}
else {
shift128ExtraRightJamming(
zSig0, zSig1, 0, - shiftCount, &zSig0, &zSig1, &zSig2 );
}
zExp -= shiftCount;
return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
}
#endif

View file

@ -6,6 +6,9 @@
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include "sim.h"
#include "m68k.h"
@ -170,10 +173,12 @@ void disassemble_program()
char buff2[100];
pc = cpu_read_long_dasm(4);
printf("entry point is %0x\n", entrypoint);
printf("pc is %0x\n", pc);
while(pc <= 0x16e)
while(pc <= entrypoint + 0x16e)
{
instr_size = m68k_disassemble(buff, pc, M68K_CPU_TYPE_68000);
instr_size = m68k_disassemble(buff, pc, M68K_CPU_TYPE_68020);
make_hex(buff2, pc, instr_size);
printf("%03x: %-20s: %s\n", pc, buff2, buff);
pc += instr_size;
@ -181,8 +186,9 @@ void disassemble_program()
fflush(stdout);
}
void cpu_instr_callback()
void cpu_instr_callback(int apc)
{
(void)apc;
uint32_t pc = m68k_get_reg(NULL, M68K_REG_PC);
if (pc == 0xc)
exit_error("address exception");
@ -219,6 +225,10 @@ void cpu_instr_callback()
#endif
}
/**
* translate simulated linux syscall to native call on host
* see https://www.lurklurk.org/syscalls.html for m68k syscall numbers
**/
static void emulated_syscall(void)
{
int s = m68k_get_reg(NULL, M68K_REG_D0);
@ -227,6 +237,15 @@ static void emulated_syscall(void)
case 1: /* exit */
exit(m68k_get_reg(NULL, M68K_REG_D1));
case 3: /* read */
{
uint32_t fd = m68k_get_reg(NULL, M68K_REG_D1);
uint32_t ptr = m68k_get_reg(NULL, M68K_REG_D2);
uint32_t count = m68k_get_reg(NULL, M68K_REG_D3);
m68k_set_reg(M68K_REG_D0, read(fd, g_ram + transform_address(ptr), count));
break;
}
case 4: /* write */
{
uint32_t fd = m68k_get_reg(NULL, M68K_REG_D1);
@ -236,6 +255,38 @@ static void emulated_syscall(void)
break;
}
case 5: /* open */
{
uint32_t pathname = m68k_get_reg(NULL, M68K_REG_D1);
uint32_t flags = m68k_get_reg(NULL, M68K_REG_D2);
uint32_t mode = m68k_get_reg(NULL, M68K_REG_D3);
m68k_set_reg(M68K_REG_D0, open(g_ram + transform_address(pathname), flags, mode));
break;
}
case 6: /* close */
{
uint32_t fd = m68k_get_reg(NULL, M68K_REG_D1);
m68k_set_reg(M68K_REG_D0, close(fd));
break;
}
case 10: /* unlink */
{
uint32_t pathname = m68k_get_reg(NULL, M68K_REG_D1);
m68k_set_reg(M68K_REG_D0, unlink(g_ram + transform_address(pathname)));
break;
}
case 19: /* lseek */
{
uint32_t fd = m68k_get_reg(NULL, M68K_REG_D1);
uint32_t offset = m68k_get_reg(NULL, M68K_REG_D2);
uint32_t whence = m68k_get_reg(NULL, M68K_REG_D3);
m68k_set_reg(M68K_REG_D0, lseek(fd, offset, whence));
break;
}
case 45: /* brk */
{
uint32_t newpos = m68k_get_reg(NULL, M68K_REG_D1);
@ -312,9 +363,13 @@ int main(int argc, char* argv[])
//disassemble_program();
m68k_set_cpu_type(M68K_CPU_TYPE_68020);
//printf("now at line %d\n", __LINE__);
m68k_set_cpu_type(M68K_CPU_TYPE_68040);
//printf("now at line %d\n", __LINE__);
m68k_init();
//printf("initialising core\n");
m68k_pulse_reset();
//printf("now at line %d\n", __LINE__);
/* On entry, the Linux stack looks like this.
*
@ -337,11 +392,13 @@ int main(int argc, char* argv[])
unsigned long argv = sp;
cpu_write_long(sp -= 4, argv);
cpu_write_long(sp -= 4, 0);
m68k_set_reg(M68K_REG_SP, sp);
m68k_set_reg(M68K_REG_SP, sp); /* init sp is also addr 0 */
}
for (;;)
//printf("running program ");
for (;;) {
m68k_execute(100000);
}
return 0;
}

View file

@ -10,6 +10,6 @@ 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();
void cpu_instr_callback(int pc);
#endif /* SIM__HEADER */