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? # 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 # 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 # install it and just want to run the ACK from the build directory
@ -31,6 +32,7 @@ LDFLAGS =
AR = ar AR = ar
CC = gcc CC = gcc
#CC = clang
# Which build system to use; use 'ninja' or 'make' (in lower case). Leave # Which build system to use; use 'ninja' or 'make' (in lower case). Leave
# blank to autodetect. # blank to autodetect.

View file

@ -11,15 +11,15 @@ normalrule {
"+m68kmake", "+m68kmake",
"./musashi/m68k_in.c", "./musashi/m68k_in.c",
"./musashi/m68kcpu.h", "./musashi/m68kcpu.h",
"./musashi/m68kmmu.h",
"./m68kconf.h", "./m68kconf.h",
"./musashi/m68kcpu.c", "./musashi/m68kcpu.c",
"./musashi/m68kfpu.c",
"./musashi/m68kdasm.c", "./musashi/m68kdasm.c",
"./musashi/m68k.h", "./musashi/m68k.h",
"./musashi/softfloat",
}, },
outleaves = { outleaves = {
"m68kopac.c",
"m68kopdm.c",
"m68kopnz.c",
"m68kops.c", "m68kops.c",
"m68kops.h", "m68kops.h",
"m68kcpu.h", "m68kcpu.h",
@ -29,7 +29,7 @@ normalrule {
"m68k.h", "m68k.h",
}, },
commands = { 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]}" "cd %{dir} && %{ins[1]}"
} }
} }
@ -50,9 +50,9 @@ cprogram {
srcs = { srcs = {
"./sim.c", "./sim.c",
matching(filenamesof("+m68k_engine"), "%.c$"), matching(filenamesof("+m68k_engine"), "%.c$"),
"./musashi/softfloat/softfloat.c",
}, },
deps = { deps = {
"+headers", "+headers",
} }
} }

View file

@ -3,20 +3,28 @@
/* ======================================================================== */ /* ======================================================================== */
/* /*
* MUSASHI * MUSASHI
* Version 3.4 * Version 3.32
* *
* A portable Motorola M680x0 processor emulation engine. * 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* copyright notice remains unaltered in the source code and any binary files * of this software and associated documentation files (the "Software"), to deal
* containing this code in compiled form. * 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 * The above copyright notice and this permission notice shall be included in
* (Karl Stenerud). * all copies or substantial portions of the Software.
*
* The latest version of this code can be obtained at: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* http://kstenerud.cjb.net * 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_010 OPT_ON
#define M68K_EMULATE_EC020 OPT_ON #define M68K_EMULATE_EC020 OPT_ON
#define M68K_EMULATE_020 OPT_ON #define M68K_EMULATE_020 OPT_ON
#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 /* 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_EMULATE_RESET OPT_OFF
#define M68K_RESET_CALLBACK() cpu_pulse_reset() #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 /* If ON, CPU will call the set fc callback on every memory access to
* differentiate between user/supervisor, program/data access like a real * differentiate between user/supervisor, program/data access like a real
@ -111,7 +150,6 @@
#define M68K_EMULATE_FC OPT_OFF #define M68K_EMULATE_FC OPT_OFF
#define M68K_SET_FC_CALLBACK(A) cpu_set_fc(A) #define M68K_SET_FC_CALLBACK(A) cpu_set_fc(A)
/* If ON, CPU will call the pc changed callback when it changes the PC by a /* If ON, CPU will call the pc changed callback when it changes the PC by a
* large value. This allows host programs to be nicer when it comes to * large value. This allows host programs to be nicer when it comes to
* fetching immediate data and instructions on a banked memory system. * fetching immediate data and instructions on a banked memory system.
@ -124,11 +162,11 @@
* instruction. * instruction.
*/ */
#define M68K_INSTRUCTION_HOOK OPT_SPECIFY_HANDLER #define M68K_INSTRUCTION_HOOK OPT_SPECIFY_HANDLER
#define M68K_INSTRUCTION_CALLBACK() cpu_instr_callback() #define M68K_INSTRUCTION_CALLBACK(pc) cpu_instr_callback(pc)
/* If ON, the CPU will emulate the 4-byte prefetch queue of a real 68000 */ /* If ON, the CPU will emulate the 4-byte prefetch queue of a real 68000 */
#define M68K_EMULATE_PREFETCH OPT_ON #define M68K_EMULATE_PREFETCH OPT_OFF /*xxx*/
/* If ON, the CPU will generate address error exceptions if it tries to /* If ON, the CPU will generate address error exceptions if it tries to
@ -146,6 +184,9 @@
#define M68K_LOG_1010_1111 OPT_OFF #define M68K_LOG_1010_1111 OPT_OFF
#define M68K_LOG_FILEHANDLE stderr #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 ---------------------------- */ /* ----------------------------- COMPATIBILITY ---------------------------- */
@ -157,19 +198,9 @@
/* If ON, the enulation core will use 64-bit integers to speed up some /* If ON, the enulation core will use 64-bit integers to speed up some
* operations. * operations.
*/ */
#define M68K_USE_64_BIT OPT_OFF #define M68K_USE_64_BIT OPT_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 */ #endif /* M68K_COMPILE_FOR_MAME */
#include "sim.h" #include "sim.h"
@ -185,7 +216,6 @@
#define m68k_write_memory_16(A, V) cpu_write_word(A, V) #define m68k_write_memory_16(A, V) cpu_write_word(A, V)
#define m68k_write_memory_32(A, V) cpu_write_long(A, V) #define m68k_write_memory_32(A, V) cpu_write_long(A, V)
/* ======================================================================== */ /* ======================================================================== */
/* ============================== END OF FILE ============================= */ /* ============================== END OF FILE ============================= */
/* ======================================================================== */ /* ======================================================================== */

View file

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

View file

@ -1,290 +1,290 @@
EXAMPLE: EXAMPLE:
------- -------
As an example, I'll build an imaginary hardware platform. As an example, I'll build an imaginary hardware platform.
The system is fairly simple, comprising a 68000, an input device, an output The system is fairly simple, comprising a 68000, an input device, an output
device, a non-maskable-interrupt device, and an interrupt controller. device, a non-maskable-interrupt device, and an interrupt controller.
The input device receives input from the user and asserts its interrupt The input device receives input from the user and asserts its interrupt
request line until its value is read. Reading from the input device's request line until its value is read. Reading from the input device's
memory-mapped port will both clear its interrupt request and read an ASCII memory-mapped port will both clear its interrupt request and read an ASCII
representation (8 bits) of what the user entered. representation (8 bits) of what the user entered.
The output device reads value when it is selected through its memory-mapped The output device reads value when it is selected through its memory-mapped
port and outputs it to a display. The value it reads will be interpreted as port and outputs it to a display. The value it reads will be interpreted as
an ASCII value and output to the display. The output device is fairly slow an ASCII value and output to the display. The output device is fairly slow
(it can only process 1 byte per second), and so it asserts its interrupt (it can only process 1 byte per second), and so it asserts its interrupt
request line when it is ready to receive a byte. Writing to the output device request line when it is ready to receive a byte. Writing to the output device
sends a byte to it. If the output device is not ready, the write is ignored. sends a byte to it. If the output device is not ready, the write is ignored.
Reading from the output device returns 0 and clears its interrupt request line Reading from the output device returns 0 and clears its interrupt request line
until another byte is written to it and 1 second elapses. until another byte is written to it and 1 second elapses.
The non-maskable-interrupt (NMI) device, as can be surmised from the name, The non-maskable-interrupt (NMI) device, as can be surmised from the name,
generates a non-maskable-interrupt. This is connected to some kind of external generates a non-maskable-interrupt. This is connected to some kind of external
switch that the user can push to generate a NMI. switch that the user can push to generate a NMI.
Since there are 3 devices interrupting the CPU, an interrupt controller is Since there are 3 devices interrupting the CPU, an interrupt controller is
needed. The interrupt controller takes 7 inputs and encodes the highest needed. The interrupt controller takes 7 inputs and encodes the highest
priority asserted line on the 3 output pins. the input device is wired to IN2 priority asserted line on the 3 output pins. the input device is wired to IN2
and the output device is wired to IN1 on the controller. The NMI device is and the output device is wired to IN1 on the controller. The NMI device is
wired to IN7 and all the other inputs are wired low. wired to IN7 and all the other inputs are wired low.
The bus is also connected to a 1K ROM and a 256 byte RAM. The bus is also connected to a 1K ROM and a 256 byte RAM.
Beware: This platform places ROM and RAM in the same address range and uses Beware: This platform places ROM and RAM in the same address range and uses
the FC pins to select the correct address space! the FC pins to select the correct address space!
(You didn't expect me to make it easy, did you? =) (You didn't expect me to make it easy, did you? =)
Here is the schematic in all its ASCII splendour: Here is the schematic in all its ASCII splendour:
------------------------------------------------- -------------------------------------------------
NMI TIED NMI TIED
SWITCH LOW SWITCH LOW
| | | |
| +-+-+-+ | +-+-+-+
| | | | | +------------------------------------------------+ | | | | | +------------------------------------------------+
| | | | | | +------------------------------------+ | | | | | | | +------------------------------------+ |
| | | | | | | | | | | | | | | | | |
+-------------+ | | +-------------+ | |
|7 6 5 4 3 2 1| | | |7 6 5 4 3 2 1| | |
| | | | | | | |
| INT CONTRLR | | | | INT CONTRLR | | |
| | | | | | | |
|i i i | | | |i i i | | |
|2 1 0 | | | |2 1 0 | | |
+-------------+ | | +-------------+ | |
| | | | | | | | | |
| | | +--------------------------------+--+ | | | | | +--------------------------------+--+ | |
o o o | | | | | o o o | | | | |
+--------------+ +-------+ +----------+ +---------+ +----------+ +--------------+ +-------+ +----------+ +---------+ +----------+
| I I I a | | | | | | r a i | | i | | I I I a | | | | | | r a i | | i |
| 2 1 0 23 | | | | | | e c | | | | 2 1 0 23 | | | | | | e c | | |
| | | | | | | a k | | | | | | | | | | a k | | |
| | | | | | | d | | | | | | | | | | d | | |
| | | | | | | | | | | | | | | | | | | |
| M68000 | | ROM | | RAM | | IN | | OUT | | M68000 | | ROM | | RAM | | IN | | OUT |
| | | | | | | | | | | | | | | | | | | |
| a9|--|a9 |--| |--| |--| | | a9|--|a9 |--| |--| |--| |
| a8|--|a8 |--| |--| |--| | | a8|--|a8 |--| |--| |--| |
| a7|--|a7 |--|a7 |--| |--| | | a7|--|a7 |--|a7 |--| |--| |
| a6|--|a6 |--|a6 |--| |--| | | a6|--|a6 |--|a6 |--| |--| |
| a5|--|a5 |--|a5 |--| |--| | | a5|--|a5 |--|a5 |--| |--| |
| a4|--|a4 |--|a4 |--| |--| | | a4|--|a4 |--|a4 |--| |--| |
| a3|--|a3 |--|a3 |--| |--| | | a3|--|a3 |--|a3 |--| |--| |
| a2|--|a2 |--|a2 |--| |--| | | a2|--|a2 |--|a2 |--| |--| |
| a1|--|a1 |--|a1 |--| |--| | | a1|--|a1 |--|a1 |--| |--| |
| a0|--|a0 |--|a0 |--| |--| | | a0|--|a0 |--|a0 |--| |--| |
| | | | | | | | | | | | | | | | | | | |
| d15|--|d15 |--|d15 |--| |--| | | d15|--|d15 |--|d15 |--| |--| |
| d14|--|d14 |--|d14 |--| |--| | | d14|--|d14 |--|d14 |--| |--| |
| d13|--|d13 |--|d13 |--| |--| | | d13|--|d13 |--|d13 |--| |--| |
| d12|--|d12 |--|d12 |--| |--| | | d12|--|d12 |--|d12 |--| |--| |
| d11|--|d11 |--|d11 |--| |--| | | d11|--|d11 |--|d11 |--| |--| |
| d10|--|d10 |--|d10 |--| |--| | | d10|--|d10 |--|d10 |--| |--| |
| d9|--|d9 |--|d9 |--| |--| | | d9|--|d9 |--|d9 |--| |--| |
| d8|--|d8 |--|d8 |--| |--| | | d8|--|d8 |--|d8 |--| |--| |
| d7|--|d7 |--|d7 |--|d7 |--|d7 | | d7|--|d7 |--|d7 |--|d7 |--|d7 |
| d6|--|d6 |--|d6 |--|d6 |--|d6 | | d6|--|d6 |--|d6 |--|d6 |--|d6 |
| d5|--|d5 |--|d5 |--|d5 |--|d5 | | d5|--|d5 |--|d5 |--|d5 |--|d5 |
| d4|--|d4 |--|d4 |--|d4 |--|d4 | | d4|--|d4 |--|d4 |--|d4 |--|d4 |
| d3|--|d3 |--|d3 |--|d3 |--|d3 | | d3|--|d3 |--|d3 |--|d3 |--|d3 |
| d2|--|d2 |--|d2 |--|d2 |--|d2 | | d2|--|d2 |--|d2 |--|d2 |--|d2 |
| d1|--|d1 |--|d1 |--|d1 |--|d1 w | | d1|--|d1 |--|d1 |--|d1 |--|d1 w |
| d0|--|d0 |--|d0 |--|d0 |--|d0 r | | d0|--|d0 |--|d0 |--|d0 |--|d0 r |
| | | | | | | | | i a | | | | | | | | | | i a |
| a F F F | | | | | | | | t c | | a F F F | | | | | | | | t c |
|22 rW 2 1 0 | | cs | | cs rW | | | | e k | |22 rW 2 1 0 | | cs | | cs rW | | | | e k |
+--------------+ +-------+ +----------+ +---------+ +----------+ +--------------+ +-------+ +----------+ +---------+ +----------+
| | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | |
| | | | | +-------+ +-----+ | +---+ | | | | | | +-------+ +-----+ | +---+ |
| | | | | | IC1 | | IC2 | | |AND| | | | | | | | IC1 | | IC2 | | |AND| |
| | | | | |a b c d| |a b c| | +---+ | | | | | | |a b c d| |a b c| | +---+ |
| | | | | +-------+ +-----+ | | | | | | | | | +-------+ +-----+ | | | |
| | | | | | | | | | | | | | +--+ | | | | | | | | | | | | | | +--+
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
| | | | +-----)-)-+-)----)-)-+ | | | | | | | +-----)-)-+-)----)-)-+ | | |
| | | +-------)-+---)----)-+ | | | | | | +-------)-+---)----)-+ | | |
| | +---------+-----)----+ | | | | | +---------+-----)----+ | | |
| | | | | | | | | | | |
| +------------------+-----------+----------------------+ | | +------------------+-----------+----------------------+ |
| | | |
+-----------------------------------------------------------+ +-----------------------------------------------------------+
IC1: output=1 if a=0 and b=1 and c=0 and d=0 IC1: output=1 if a=0 and b=1 and c=0 and d=0
IC2: output=1 if a=0 and b=0 and c=1 IC2: output=1 if a=0 and b=0 and c=1
Here is the listing for program.bin: Here is the listing for program.bin:
----------------------------------- -----------------------------------
INPUT_ADDRESS equ $800000 INPUT_ADDRESS equ $800000
OUTPUT_ADDRESS equ $400000 OUTPUT_ADDRESS equ $400000
CIRCULAR_BUFFER equ $c0 CIRCULAR_BUFFER equ $c0
CAN_OUTPUT equ $d0 CAN_OUTPUT equ $d0
STACK_AREA equ $100 STACK_AREA equ $100
vector_table: vector_table:
00000000 0000 0100 dc.l STACK_AREA * 0: SP 00000000 0000 0100 dc.l STACK_AREA * 0: SP
00000004 0000 00c0 dc.l init * 1: PC 00000004 0000 00c0 dc.l init * 1: PC
00000008 0000 0148 dc.l unhandled_exception * 2: bus error 00000008 0000 0148 dc.l unhandled_exception * 2: bus error
0000000c 0000 0148 dc.l unhandled_exception * 3: address error 0000000c 0000 0148 dc.l unhandled_exception * 3: address error
00000010 0000 0148 dc.l unhandled_exception * 4: illegal instruction 00000010 0000 0148 dc.l unhandled_exception * 4: illegal instruction
00000014 0000 0148 dc.l unhandled_exception * 5: zero divide 00000014 0000 0148 dc.l unhandled_exception * 5: zero divide
00000018 0000 0148 dc.l unhandled_exception * 6: chk 00000018 0000 0148 dc.l unhandled_exception * 6: chk
0000001c 0000 0148 dc.l unhandled_exception * 7: trapv 0000001c 0000 0148 dc.l unhandled_exception * 7: trapv
00000020 0000 0148 dc.l unhandled_exception * 8: privilege violation 00000020 0000 0148 dc.l unhandled_exception * 8: privilege violation
00000024 0000 0148 dc.l unhandled_exception * 9: trace 00000024 0000 0148 dc.l unhandled_exception * 9: trace
00000028 0000 0148 dc.l unhandled_exception * 10: 1010 00000028 0000 0148 dc.l unhandled_exception * 10: 1010
0000002c 0000 0148 dc.l unhandled_exception * 11: 1111 0000002c 0000 0148 dc.l unhandled_exception * 11: 1111
00000030 0000 0148 dc.l unhandled_exception * 12: - 00000030 0000 0148 dc.l unhandled_exception * 12: -
00000034 0000 0148 dc.l unhandled_exception * 13: - 00000034 0000 0148 dc.l unhandled_exception * 13: -
00000038 0000 0148 dc.l unhandled_exception * 14: - 00000038 0000 0148 dc.l unhandled_exception * 14: -
0000003c 0000 0148 dc.l unhandled_exception * 15: uninitialized interrupt 0000003c 0000 0148 dc.l unhandled_exception * 15: uninitialized interrupt
00000040 0000 0148 dc.l unhandled_exception * 16: - 00000040 0000 0148 dc.l unhandled_exception * 16: -
00000044 0000 0148 dc.l unhandled_exception * 17: - 00000044 0000 0148 dc.l unhandled_exception * 17: -
00000048 0000 0148 dc.l unhandled_exception * 18: - 00000048 0000 0148 dc.l unhandled_exception * 18: -
0000004c 0000 0148 dc.l unhandled_exception * 19: - 0000004c 0000 0148 dc.l unhandled_exception * 19: -
00000050 0000 0148 dc.l unhandled_exception * 20: - 00000050 0000 0148 dc.l unhandled_exception * 20: -
00000054 0000 0148 dc.l unhandled_exception * 21: - 00000054 0000 0148 dc.l unhandled_exception * 21: -
00000058 0000 0148 dc.l unhandled_exception * 22: - 00000058 0000 0148 dc.l unhandled_exception * 22: -
0000005c 0000 0148 dc.l unhandled_exception * 23: - 0000005c 0000 0148 dc.l unhandled_exception * 23: -
00000060 0000 0148 dc.l unhandled_exception * 24: spurious interrupt 00000060 0000 0148 dc.l unhandled_exception * 24: spurious interrupt
00000064 0000 0136 dc.l output_ready * 25: l1 irq 00000064 0000 0136 dc.l output_ready * 25: l1 irq
00000068 0000 010e dc.l input_ready * 26: l2 irq 00000068 0000 010e dc.l input_ready * 26: l2 irq
0000006c 0000 0148 dc.l unhandled_exception * 27: l3 irq 0000006c 0000 0148 dc.l unhandled_exception * 27: l3 irq
00000070 0000 0148 dc.l unhandled_exception * 28: l4 irq 00000070 0000 0148 dc.l unhandled_exception * 28: l4 irq
00000074 0000 0148 dc.l unhandled_exception * 29: l5 irq 00000074 0000 0148 dc.l unhandled_exception * 29: l5 irq
00000078 0000 0148 dc.l unhandled_exception * 30: l6 irq 00000078 0000 0148 dc.l unhandled_exception * 30: l6 irq
0000007c 0000 014e dc.l nmi * 31: l7 irq 0000007c 0000 014e dc.l nmi * 31: l7 irq
00000080 0000 0148 dc.l unhandled_exception * 32: trap 0 00000080 0000 0148 dc.l unhandled_exception * 32: trap 0
00000084 0000 0148 dc.l unhandled_exception * 33: trap 1 00000084 0000 0148 dc.l unhandled_exception * 33: trap 1
00000088 0000 0148 dc.l unhandled_exception * 34: trap 2 00000088 0000 0148 dc.l unhandled_exception * 34: trap 2
0000008c 0000 0148 dc.l unhandled_exception * 35: trap 3 0000008c 0000 0148 dc.l unhandled_exception * 35: trap 3
00000090 0000 0148 dc.l unhandled_exception * 36: trap 4 00000090 0000 0148 dc.l unhandled_exception * 36: trap 4
00000094 0000 0148 dc.l unhandled_exception * 37: trap 5 00000094 0000 0148 dc.l unhandled_exception * 37: trap 5
00000098 0000 0148 dc.l unhandled_exception * 38: trap 6 00000098 0000 0148 dc.l unhandled_exception * 38: trap 6
0000009c 0000 0148 dc.l unhandled_exception * 39: trap 7 0000009c 0000 0148 dc.l unhandled_exception * 39: trap 7
000000a0 0000 0148 dc.l unhandled_exception * 40: trap 8 000000a0 0000 0148 dc.l unhandled_exception * 40: trap 8
000000a4 0000 0148 dc.l unhandled_exception * 41: trap 9 000000a4 0000 0148 dc.l unhandled_exception * 41: trap 9
000000a8 0000 0148 dc.l unhandled_exception * 42: trap 10 000000a8 0000 0148 dc.l unhandled_exception * 42: trap 10
000000ac 0000 0148 dc.l unhandled_exception * 43: trap 11 000000ac 0000 0148 dc.l unhandled_exception * 43: trap 11
000000b0 0000 0148 dc.l unhandled_exception * 44: trap 12 000000b0 0000 0148 dc.l unhandled_exception * 44: trap 12
000000b4 0000 0148 dc.l unhandled_exception * 45: trap 13 000000b4 0000 0148 dc.l unhandled_exception * 45: trap 13
000000b8 0000 0148 dc.l unhandled_exception * 46: trap 14 000000b8 0000 0148 dc.l unhandled_exception * 46: trap 14
000000bc 0000 0148 dc.l unhandled_exception * 47: trap 15 000000bc 0000 0148 dc.l unhandled_exception * 47: trap 15
* This is the end of the useful part of the table. * This is the end of the useful part of the table.
* We will now do the Capcom thing and put code starting at $c0. * We will now do the Capcom thing and put code starting at $c0.
init: init:
* Copy the exception vector table to RAM. * Copy the exception vector table to RAM.
000000c0 227c 0000 0000 move.l #0, a1 * a1 is RAM index 000000c0 227c 0000 0000 move.l #0, a1 * a1 is RAM index
000000c6 303c 002f move.w #47, d0 * d0 is counter (48 vectors) 000000c6 303c 002f move.w #47, d0 * d0 is counter (48 vectors)
000000ca 41fa 0006 lea.l (copy_table,PC), a0 * a0 is scratch 000000ca 41fa 0006 lea.l (copy_table,PC), a0 * a0 is scratch
000000ce 2208 move.l a0, d1 * d1 is ROM index 000000ce 2208 move.l a0, d1 * d1 is ROM index
000000d0 4481 neg.l d1 000000d0 4481 neg.l d1
copy_table: copy_table:
000000d2 22fb 18fe dc.l $22fb18fe * stoopid as68k generates 020 code here 000000d2 22fb 18fe dc.l $22fb18fe * stoopid as68k generates 020 code here
* move.l (copy_table,PC,d1.l), (a1)+ * move.l (copy_table,PC,d1.l), (a1)+
000000d6 5841 addq #4, d1 000000d6 5841 addq #4, d1
000000d8 51c8 fff8 dbf d0, copy_table 000000d8 51c8 fff8 dbf d0, copy_table
main_init: main_init:
* Initialize main program * Initialize main program
000000dc 11fc 0000 00d0 move.b #0, CAN_OUTPUT 000000dc 11fc 0000 00d0 move.b #0, CAN_OUTPUT
000000e2 4df8 00c0 lea.l CIRCULAR_BUFFER, a6 000000e2 4df8 00c0 lea.l CIRCULAR_BUFFER, a6
000000e6 7c00 moveq #0, d6 * output buffer ptr 000000e6 7c00 moveq #0, d6 * output buffer ptr
000000e8 7e00 moveq #0, d7 * input buffer ptr 000000e8 7e00 moveq #0, d7 * input buffer ptr
000000ea 027c f8ff andi #$f8ff, SR * clear interrupt mask 000000ea 027c f8ff andi #$f8ff, SR * clear interrupt mask
main: main:
* Main program * Main program
000000ee 4a38 00d0 tst.b CAN_OUTPUT * can we output? 000000ee 4a38 00d0 tst.b CAN_OUTPUT * can we output?
000000f2 67fa beq main 000000f2 67fa beq main
000000f4 be06 cmp.b d6, d7 * is there data? 000000f4 be06 cmp.b d6, d7 * is there data?
000000f6 67f6 beq main 000000f6 67f6 beq main
000000f8 11fc 0000 00d0 move.b #0, CAN_OUTPUT 000000f8 11fc 0000 00d0 move.b #0, CAN_OUTPUT
000000fe 13f6 6000 0040 move.b (0,a6,d6.w), OUTPUT_ADDRESS * write data 000000fe 13f6 6000 0040 move.b (0,a6,d6.w), OUTPUT_ADDRESS * write data
0000 0000
00000106 5246 addq #1, d6 00000106 5246 addq #1, d6
00000108 0206 000f andi.b #15, d6 * update circular buffer 00000108 0206 000f andi.b #15, d6 * update circular buffer
0000010c 60e0 bra main 0000010c 60e0 bra main
input_ready: input_ready:
0000010e 2f00 move.l d0, -(a7) 0000010e 2f00 move.l d0, -(a7)
00000110 2f01 move.l d1, -(a7) 00000110 2f01 move.l d1, -(a7)
00000112 1239 0080 0000 move.b INPUT_ADDRESS, d1 * read data 00000112 1239 0080 0000 move.b INPUT_ADDRESS, d1 * read data
00000118 1007 move.b d7, d0 * check if buffer full 00000118 1007 move.b d7, d0 * check if buffer full
0000011a 5240 addq #1, d0 0000011a 5240 addq #1, d0
0000011c 0200 000f andi.b #15, d0 0000011c 0200 000f andi.b #15, d0
00000120 bc00 cmp.b d0, d6 00000120 bc00 cmp.b d0, d6
00000122 6700 000c beq input_ready_quit * throw away if full 00000122 6700 000c beq input_ready_quit * throw away if full
00000126 1d81 7000 move.b d1, (0,a6,d7.w) * store the data 00000126 1d81 7000 move.b d1, (0,a6,d7.w) * store the data
0000012a 5247 addq #1, d7 0000012a 5247 addq #1, d7
0000012c 0207 000f andi.b #15, d7 * update circular buffer 0000012c 0207 000f andi.b #15, d7 * update circular buffer
input_ready_quit: input_ready_quit:
00000130 221f move.l (a7)+, d1 00000130 221f move.l (a7)+, d1
00000132 201f move.l (a7)+, d0 00000132 201f move.l (a7)+, d0
00000134 4e73 rte 00000134 4e73 rte
output_ready: output_ready:
00000136 2f00 move.l d0, -(a7) 00000136 2f00 move.l d0, -(a7)
00000138 11fc 0001 00d0 move.b #1, CAN_OUTPUT 00000138 11fc 0001 00d0 move.b #1, CAN_OUTPUT
0000013e 1039 0040 0000 move.b OUTPUT_ADDRESS, d0 * acknowledge the interrupt 0000013e 1039 0040 0000 move.b OUTPUT_ADDRESS, d0 * acknowledge the interrupt
00000144 201f move.l (a7)+, d0 00000144 201f move.l (a7)+, d0
00000146 4e73 rte 00000146 4e73 rte
unhandled_exception: unhandled_exception:
00000148 4e72 2700 stop #$2700 * wait for NMI 00000148 4e72 2700 stop #$2700 * wait for NMI
0000014c 60fa bra unhandled_exception * shouldn't get here 0000014c 60fa bra unhandled_exception * shouldn't get here
nmi: nmi:
* perform a soft reset * perform a soft reset
0000014e 46fc 2700 move #$2700, SR * set status register 0000014e 46fc 2700 move #$2700, SR * set status register
00000152 2e7a feac move.l (vector_table,PC), a7 * reset stack pointer 00000152 2e7a feac move.l (vector_table,PC), a7 * reset stack pointer
00000156 4e70 reset * reset peripherals 00000156 4e70 reset * reset peripherals
00000158 4efa feaa jmp (vector_table+4,PC) * reset program counter 00000158 4efa feaa jmp (vector_table+4,PC) * reset program counter
END END
Compiling the example host environment: Compiling the example host environment:
-------------------------------------- --------------------------------------
I've only put in an os-dependant portion for dos/windows, so you'll either I've only put in an os-dependant portion for dos/windows, so you'll either
have to compile for that system or make your own osd code based on osd_dos.c have to compile for that system or make your own osd code based on osd_dos.c
and modify the makefile accordingly. and modify the makefile accordingly.
I compiled this example using the compiler from mingw (www.mingw.org) but you I compiled this example using the compiler from mingw (www.mingw.org) but you
could also use djgpp (www.delorie.com). could also use djgpp (www.delorie.com).
- Copy the m68k files to a directory. Then extract the files from example.zip to - Copy the m68k files to a directory. Then extract the files from example.zip to
the same directory, overwriting m68kconf.h. program.bin is the actual 68000 the same directory, overwriting m68kconf.h. program.bin is the actual 68000
program you will be running. program you will be running.
- Make your own osd_get_key() in the same fashion as in osd_dos.c if you're not - Make your own osd_get_key() in the same fashion as in osd_dos.c if you're not
compiling for dos/windows. compiling for dos/windows.
- Type make - Type make
- Perform the necessary animal sacrifices. - Perform the necessary animal sacrifices.
- Type sim program.bin - Type sim program.bin
Keys: Keys:
ESC - quits the simulator ESC - quits the simulator
~ - generates an NMI interrupt ~ - generates an NMI interrupt
Any other key - Genearate input for the input device Any other key - Genearate input for the input device
Note: I've cheated a bit in the emulation. There is no speed control Note: I've cheated a bit in the emulation. There is no speed control
to set the speed the CPU runs at; it simply runs as fast as your to set the speed the CPU runs at; it simply runs as fast as your
processor can run it. processor can run it.
To add speed control, you will need a high-precision timestamp To add speed control, you will need a high-precision timestamp
function (like the RDTSC instruction for newer Pentium CPUs) function (like the RDTSC instruction for newer Pentium CPUs)
and a bit of arithmetic to make the cycles argument for m68k_execute(). and a bit of arithmetic to make the cycles argument for m68k_execute().
I'll leave that as an excercise to the reader. I'll leave that as an excercise to the reader.

View file

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

View file

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

View file

@ -1,192 +1,220 @@
/* ======================================================================== */ /* ======================================================================== */
/* ========================= LICENSING & COPYRIGHT ======================== */ /* ========================= LICENSING & COPYRIGHT ======================== */
/* ======================================================================== */ /* ======================================================================== */
/* /*
* MUSASHI * MUSASHI
* Version 3.4 * Version 3.32
* *
* A portable Motorola M680x0 processor emulation engine. * 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* copyright notice remains unaltered in the source code and any binary files * of this software and associated documentation files (the "Software"), to deal
* containing this code in compiled form. * in the Software without restriction, including without limitation the rights
* * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* All other lisencing terms must be negotiated with the author * copies of the Software, and to permit persons to whom the Software is
* (Karl Stenerud). * furnished to do so, subject to the following conditions:
* *
* The latest version of this code can be obtained at: * The above copyright notice and this permission notice shall be included in
* http://kstenerud.cjb.net * 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
#ifndef M68KCONF__HEADER * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#define M68KCONF__HEADER * 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.
/* Configuration switches. */
* Use OPT_SPECIFY_HANDLER for configuration options that allow callbacks.
* OPT_SPECIFY_HANDLER causes the core to link directly to the function
* or macro you specify, rather than using callback functions whose pointer
* must be passed in using m68k_set_xxx_callback(). #ifndef M68KCONF__HEADER
*/ #define M68KCONF__HEADER
#define OPT_OFF 0
#define OPT_ON 1
#define OPT_SPECIFY_HANDLER 2 /* Configuration switches.
* Use OPT_SPECIFY_HANDLER for configuration options that allow callbacks.
* OPT_SPECIFY_HANDLER causes the core to link directly to the function
/* ======================================================================== */ * or macro you specify, rather than using callback functions whose pointer
/* ============================== MAME STUFF ============================== */ * must be passed in using m68k_set_xxx_callback().
/* ======================================================================== */ */
#define OPT_OFF 0
/* If you're compiling this for MAME, only change M68K_COMPILE_FOR_MAME #define OPT_ON 1
* to OPT_ON and use m68kmame.h to configure the 68k core. #define OPT_SPECIFY_HANDLER 2
*/
#ifndef M68K_COMPILE_FOR_MAME
#define M68K_COMPILE_FOR_MAME OPT_OFF /* ======================================================================== */
#endif /* M68K_COMPILE_FOR_MAME */ /* ============================== MAME STUFF ============================== */
/* ======================================================================== */
#if M68K_COMPILE_FOR_MAME == OPT_OFF /* If you're compiling this for MAME, only change M68K_COMPILE_FOR_MAME
* to OPT_ON and use m68kmame.h to configure the 68k core.
*/
/* ======================================================================== */ #ifndef M68K_COMPILE_FOR_MAME
/* ============================= CONFIGURATION ============================ */ #define M68K_COMPILE_FOR_MAME OPT_OFF
/* ======================================================================== */ #endif /* M68K_COMPILE_FOR_MAME */
/* Turn ON if you want to use the following M68K variants */
#define M68K_EMULATE_010 OPT_ON #if M68K_COMPILE_FOR_MAME == OPT_OFF
#define M68K_EMULATE_EC020 OPT_ON
#define M68K_EMULATE_020 OPT_ON
/* ======================================================================== */
/* ============================= CONFIGURATION ============================ */
/* If ON, the CPU will call m68k_read_immediate_xx() for immediate addressing /* ======================================================================== */
* and m68k_read_pcrelative_xx() for PC-relative addressing.
* If off, all read requests from the CPU will be redirected to m68k_read_xx() /* Turn ON if you want to use the following M68K variants */
*/ #define M68K_EMULATE_010 OPT_ON
#define M68K_SEPARATE_READS OPT_OFF #define M68K_EMULATE_EC020 OPT_ON
#define M68K_EMULATE_020 OPT_ON
/* If ON, the CPU will call m68k_write_32_pd() when it executes move.l with a #define M68K_EMULATE_040 OPT_ON
* predecrement destination EA mode instead of m68k_write_32().
* To simulate real 68k behavior, m68k_write_32_pd() must first write the high
* word to [address+2], and then write the low word to [address]. /* If ON, the CPU will call m68k_read_immediate_xx() for immediate addressing
*/ * and m68k_read_pcrelative_xx() for PC-relative addressing.
#define M68K_SIMULATE_PD_WRITES OPT_OFF * If off, all read requests from the CPU will be redirected to m68k_read_xx()
*/
/* If ON, CPU will call the interrupt acknowledge callback when it services an #define M68K_SEPARATE_READS OPT_OFF
* interrupt.
* If off, all interrupts will be autovectored and all interrupt requests will /* If ON, the CPU will call m68k_write_32_pd() when it executes move.l with a
* auto-clear when the interrupt is serviced. * predecrement destination EA mode instead of m68k_write_32().
*/ * To simulate real 68k behavior, m68k_write_32_pd() must first write the high
#define M68K_EMULATE_INT_ACK OPT_SPECIFY_HANDLER * word to [address+2], and then write the low word to [address].
#define M68K_INT_ACK_CALLBACK(A) cpu_irq_ack(A) */
#define M68K_SIMULATE_PD_WRITES OPT_OFF
/* If ON, CPU will call the breakpoint acknowledge callback when it encounters /* If ON, CPU will call the interrupt acknowledge callback when it services an
* a breakpoint instruction and it is running a 68010+. * interrupt.
*/ * If off, all interrupts will be autovectored and all interrupt requests will
#define M68K_EMULATE_BKPT_ACK OPT_OFF * auto-clear when the interrupt is serviced.
#define M68K_BKPT_ACK_CALLBACK() your_bkpt_ack_handler_function() */
#define M68K_EMULATE_INT_ACK OPT_SPECIFY_HANDLER
#define M68K_INT_ACK_CALLBACK(A) cpu_irq_ack(A)
/* If ON, the CPU will monitor the trace flags and take trace exceptions
*/
#define M68K_EMULATE_TRACE OPT_OFF /* If ON, CPU will call the breakpoint acknowledge callback when it encounters
* a breakpoint instruction and it is running a 68010+.
*/
/* If ON, CPU will call the output reset callback when it encounters a reset #define M68K_EMULATE_BKPT_ACK OPT_OFF
* instruction. #define M68K_BKPT_ACK_CALLBACK() your_bkpt_ack_handler_function()
*/
#define M68K_EMULATE_RESET OPT_SPECIFY_HANDLER
#define M68K_RESET_CALLBACK() cpu_pulse_reset() /* If ON, the CPU will monitor the trace flags and take trace exceptions
*/
#define M68K_EMULATE_TRACE OPT_OFF
/* If ON, CPU will call the set fc callback on every memory access to
* differentiate between user/supervisor, program/data access like a real
* 68000 would. This should be enabled and the callback should be set if you /* If ON, CPU will call the output reset callback when it encounters a reset
* want to properly emulate the m68010 or higher. (moves uses function codes * instruction.
* to read/write data from different address spaces) */
*/ #define M68K_EMULATE_RESET OPT_SPECIFY_HANDLER
#define M68K_EMULATE_FC OPT_SPECIFY_HANDLER #define M68K_RESET_CALLBACK() cpu_pulse_reset()
#define M68K_SET_FC_CALLBACK(A) cpu_set_fc(A)
/* If ON, CPU will call the callback when it encounters a cmpi.l #v, dn
* instruction.
/* 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 #define M68K_CMPILD_HAS_CALLBACK OPT_OFF
* fetching immediate data and instructions on a banked memory system. #define M68K_CMPILD_CALLBACK(v,r) your_cmpild_handler_function(v,r)
*/
#define M68K_MONITOR_PC OPT_OFF
#define M68K_SET_PC_CALLBACK(A) your_pc_changed_handler_function(A) /* If ON, CPU will call the callback when it encounters a rte
* instruction.
*/
/* If ON, CPU will call the instruction hook callback before every #define M68K_RTE_HAS_CALLBACK OPT_OFF
* instruction. #define M68K_RTE_CALLBACK() your_rte_handler_function()
*/
#define M68K_INSTRUCTION_HOOK OPT_SPECIFY_HANDLER /* If ON, CPU will call the callback when it encounters a tas
#define M68K_INSTRUCTION_CALLBACK() cpu_instr_callback() * instruction.
*/
#define M68K_TAS_HAS_CALLBACK OPT_OFF
/* If ON, the CPU will emulate the 4-byte prefetch queue of a real 68000 */ #define M68K_TAS_CALLBACK() your_tas_handler_function()
#define M68K_EMULATE_PREFETCH OPT_ON
/* 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
/* If ON, the CPU will generate address error exceptions if it tries to * as a normal instruction, and the illegal exception in canceled. If it returns 0,
* access a word or longword at an odd address. * the exception occurs normally.
* NOTE: This is only emulated properly for 68000 mode. * The callback looks like int callback(int opcode)
*/ * You should put OPT_SPECIFY_HANDLER here if you cant to use it, otherwise it will
#define M68K_EMULATE_ADDRESS_ERROR OPT_ON * use a dummy default handler and you'll have to call m68k_set_illg_instr_callback explicitely
*/
#define M68K_ILLG_HAS_CALLBACK OPT_OFF
/* Turn ON to enable logging of illegal instruction calls. #define M68K_ILLG_CALLBACK(opcode) op_illg(opcode)
* M68K_LOG_FILEHANDLE must be #defined to a stdio file stream.
* Turn on M68K_LOG_1010_1111 to log all 1010 and 1111 calls. /* If ON, CPU will call the set fc callback on every memory access to
*/ * differentiate between user/supervisor, program/data access like a real
#define M68K_LOG_ENABLE OPT_OFF * 68000 would. This should be enabled and the callback should be set if you
#define M68K_LOG_1010_1111 OPT_OFF * want to properly emulate the m68010 or higher. (moves uses function codes
#define M68K_LOG_FILEHANDLE some_file_handle * to read/write data from different address spaces)
*/
#define M68K_EMULATE_FC OPT_SPECIFY_HANDLER
/* ----------------------------- COMPATIBILITY ---------------------------- */ #define M68K_SET_FC_CALLBACK(A) cpu_set_fc(A)
/* The following options set optimizations that violate the current ANSI /* If ON, CPU will call the pc changed callback when it changes the PC by a
* standard, but will be compliant under the forthcoming C9X standard. * large value. This allows host programs to be nicer when it comes to
*/ * fetching immediate data and instructions on a banked memory system.
*/
#define M68K_MONITOR_PC OPT_OFF
/* If ON, the enulation core will use 64-bit integers to speed up some #define M68K_SET_PC_CALLBACK(A) your_pc_changed_handler_function(A)
* operations.
*/
#define M68K_USE_64_BIT OPT_OFF /* If ON, CPU will call the instruction hook callback before every
* instruction.
*/
/* Set to your compiler's static inline keyword to enable it, or #define M68K_INSTRUCTION_HOOK OPT_SPECIFY_HANDLER
* set it to blank to disable it. #define M68K_INSTRUCTION_CALLBACK(pc) cpu_instr_callback(pc)
* If you define INLINE in the makefile, it will override this value.
* NOTE: not enabling inline functions will SEVERELY slow down emulation.
*/ /* If ON, the CPU will emulate the 4-byte prefetch queue of a real 68000 */
#ifndef INLINE #define M68K_EMULATE_PREFETCH OPT_ON
#define INLINE static __inline__
#endif /* INLINE */
/* If ON, the CPU will generate address error exceptions if it tries to
#endif /* M68K_COMPILE_FOR_MAME */ * access a word or longword at an odd address.
* NOTE: This is only emulated properly for 68000 mode.
#include "sim.h" */
#define M68K_EMULATE_ADDRESS_ERROR OPT_ON
#define m68k_read_memory_8(A) cpu_read_byte(A)
#define m68k_read_memory_16(A) cpu_read_word(A)
#define m68k_read_memory_32(A) cpu_read_long(A) /* Turn ON to enable logging of illegal instruction calls.
* M68K_LOG_FILEHANDLE must be #defined to a stdio file stream.
#define m68k_read_disassembler_16(A) cpu_read_word_dasm(A) * Turn on M68K_LOG_1010_1111 to log all 1010 and 1111 calls.
#define m68k_read_disassembler_32(A) cpu_read_long_dasm(A) */
#define M68K_LOG_ENABLE OPT_OFF
#define m68k_write_memory_8(A, V) cpu_write_byte(A, V) #define M68K_LOG_1010_1111 OPT_OFF
#define m68k_write_memory_16(A, V) cpu_write_word(A, V) #define M68K_LOG_FILEHANDLE some_file_handle
#define m68k_write_memory_32(A, V) cpu_write_long(A, V)
/* ----------------------------- COMPATIBILITY ---------------------------- */
/* ======================================================================== */
/* ============================== END OF FILE ============================= */ /* The following options set optimizations that violate the current ANSI
/* ======================================================================== */ * standard, but will be compliant under the forthcoming C9X standard.
*/
#endif /* M68KCONF__HEADER */
/* If ON, the enulation core will use 64-bit integers to speed up some
* operations.
*/
#define M68K_USE_64_BIT OPT_ON
#include "sim.h"
#define m68k_read_memory_8(A) cpu_read_byte(A)
#define m68k_read_memory_16(A) cpu_read_word(A)
#define m68k_read_memory_32(A) cpu_read_long(A)
#define m68k_read_disassembler_16(A) cpu_read_word_dasm(A)
#define m68k_read_disassembler_32(A) cpu_read_long_dasm(A)
#define m68k_write_memory_8(A, V) cpu_write_byte(A, V)
#define m68k_write_memory_16(A, V) cpu_write_word(A, V)
#define m68k_write_memory_32(A, V) cpu_write_long(A, V)
#endif /* M68K_COMPILE_FOR_MAME */
/* ======================================================================== */
/* ============================== END OF FILE ============================= */
/* ======================================================================== */
#endif /* M68KCONF__HEADER */

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

@ -1,6 +1,6 @@
#ifndef HEADER__OSD #ifndef HEADER__OSD
#define HEADER__OSD #define HEADER__OSD
int osd_get_char(void); int osd_get_char(void);
#endif /* HEADER__OSD */ #endif /* HEADER__OSD */

View file

@ -1,16 +1,16 @@
#include "osd.h" #include "osd.h"
/* OS-dependant code to get a character from the user. /* OS-dependant code to get a character from the user.
* This function must not block, and must either return an ASCII code or -1. * This function must not block, and must either return an ASCII code or -1.
*/ */
#include <conio.h> #include <conio.h>
int osd_get_char(void) int osd_get_char(void)
{ {
int ch = -1; int ch = -1;
if(kbhit()) if(kbhit())
{ {
while(kbhit()) while(kbhit())
ch = getch(); ch = getch();
} }
return ch; return ch;
} }

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;
}

File diff suppressed because it is too large Load diff

View file

@ -1,15 +1,15 @@
#ifndef SIM__HEADER #ifndef SIM__HEADER
#define SIM__HEADER #define SIM__HEADER
unsigned int cpu_read_byte(unsigned int address); unsigned int cpu_read_byte(unsigned int address);
unsigned int cpu_read_word(unsigned int address); unsigned int cpu_read_word(unsigned int address);
unsigned int cpu_read_long(unsigned int address); unsigned int cpu_read_long(unsigned int address);
void cpu_write_byte(unsigned int address, unsigned int value); void cpu_write_byte(unsigned int address, unsigned int value);
void cpu_write_word(unsigned int address, unsigned int value); void cpu_write_word(unsigned int address, unsigned int value);
void cpu_write_long(unsigned int address, unsigned int value); void cpu_write_long(unsigned int address, unsigned int value);
void cpu_pulse_reset(void); void cpu_pulse_reset(void);
void cpu_set_fc(unsigned int fc); void cpu_set_fc(unsigned int fc);
int cpu_irq_ack(int level); int cpu_irq_ack(int level);
void cpu_instr_callback(); void cpu_instr_callback(int pc);
#endif /* SIM__HEADER */ #endif /* SIM__HEADER */

View file

@ -3,10 +3,10 @@
/* ======================================================================== */ /* ======================================================================== */
/* /*
* MUSASHI * MUSASHI
* Version 3.4 * Version 3.32
* *
* A portable Motorola M680x0 processor emulation engine. * 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -30,14 +30,29 @@
#ifndef M68K__HEADER #ifndef M68K__HEADER
#define 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 ============================ */ /* ============================= CONFIGURATION ============================ */
/* ======================================================================== */ /* ======================================================================== */
/* Import the configuration for this build */ /* Import the configuration for this build */
#ifdef MUSASHI_CNF
#include MUSASHI_CNF
#else
#include "m68kconf.h" #include "m68kconf.h"
#endif
/* ======================================================================== */ /* ======================================================================== */
/* ============================ GENERAL DEFINES =========================== */ /* ============================ GENERAL DEFINES =========================== */
@ -83,8 +98,12 @@ enum
M68K_CPU_TYPE_68010, M68K_CPU_TYPE_68010,
M68K_CPU_TYPE_68EC020, M68K_CPU_TYPE_68EC020,
M68K_CPU_TYPE_68020, M68K_CPU_TYPE_68020,
M68K_CPU_TYPE_68030, /* Supported by disassembler ONLY */ M68K_CPU_TYPE_68EC030,
M68K_CPU_TYPE_68040 /* Supported by disassembler ONLY */ 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() */ /* 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)); 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. /* Set the callback for CPU function code changes.
* You must enable M68K_EMULATE_FC in m68kconf.h. * 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. * instruction cycle.
* Default behavior: do nothing. * 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); 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. */ /* Halt the CPU as if you pulsed the HALT pin. */
void m68k_pulse_halt(void); void m68k_pulse_halt(void);
/* Trigger a bus error exception */
void m68k_pulse_bus_error(void);
/* Context switching to allow multiple CPUs */ /* Context switching to allow multiple CPUs */
/* Get the size of the cpu context in bytes */ /* 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); void m68k_set_context(void* dst);
/* Register the CPU state information */ /* 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 /* 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); 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 ============================== */ /* ============================== MAME STUFF ============================== */
@ -355,4 +403,9 @@ unsigned int m68k_disassemble(char* str_buff, unsigned int pc, unsigned int cpu_
/* ============================== END OF FILE ============================= */ /* ============================== END OF FILE ============================= */
/* ======================================================================== */ /* ======================================================================== */
#ifdef __cplusplus
}
#endif
#endif /* M68K__HEADER */ #endif /* M68K__HEADER */

File diff suppressed because it is too large Load diff

View file

@ -3,10 +3,10 @@
/* ======================================================================== */ /* ======================================================================== */
/* /*
* MUSASHI * MUSASHI
* Version 3.4 * Version 3.32
* *
* A portable Motorola M680x0 processor emulation engine. * 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * 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. * to OPT_ON and use m68kmame.h to configure the 68k core.
*/ */
#ifndef M68K_COMPILE_FOR_MAME #ifndef M68K_COMPILE_FOR_MAME
#define M68K_COMPILE_FOR_MAME OPT_ON #define M68K_COMPILE_FOR_MAME OPT_OFF
#endif /* M68K_COMPILE_FOR_MAME */ #endif /* M68K_COMPILE_FOR_MAME */
@ -67,6 +67,8 @@
#define M68K_EMULATE_010 OPT_ON #define M68K_EMULATE_010 OPT_ON
#define M68K_EMULATE_EC020 OPT_ON #define M68K_EMULATE_EC020 OPT_ON
#define M68K_EMULATE_020 OPT_ON #define M68K_EMULATE_020 OPT_ON
#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 /* 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_EMULATE_RESET OPT_OFF
#define M68K_RESET_CALLBACK() your_reset_handler_function() #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 /* If ON, CPU will call the set fc callback on every memory access to
* differentiate between user/supervisor, program/data access like a real * differentiate between user/supervisor, program/data access like a real
@ -119,7 +150,6 @@
#define M68K_EMULATE_FC OPT_OFF #define M68K_EMULATE_FC OPT_OFF
#define M68K_SET_FC_CALLBACK(A) your_set_fc_handler_function(A) #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 /* If ON, CPU will call the pc changed callback when it changes the PC by a
* large value. This allows host programs to be nicer when it comes to * large value. This allows host programs to be nicer when it comes to
* fetching immediate data and instructions on a banked memory system. * fetching immediate data and instructions on a banked memory system.
@ -132,7 +162,7 @@
* instruction. * instruction.
*/ */
#define M68K_INSTRUCTION_HOOK OPT_OFF #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 */ /* 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_1010_1111 OPT_OFF
#define M68K_LOG_FILEHANDLE some_file_handle #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 ---------------------------- */ /* ----------------------------- COMPATIBILITY ---------------------------- */
@ -165,21 +198,11 @@
/* If ON, the enulation core will use 64-bit integers to speed up some /* If ON, the enulation core will use 64-bit integers to speed up some
* operations. * operations.
*/ */
#define M68K_USE_64_BIT OPT_OFF #define M68K_USE_64_BIT OPT_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 */ #endif /* M68K_COMPILE_FOR_MAME */
/* ======================================================================== */ /* ======================================================================== */
/* ============================== END OF FILE ============================= */ /* ============================== END OF FILE ============================= */
/* ======================================================================== */ /* ======================================================================== */

View file

@ -3,10 +3,10 @@
/* ======================================================================== */ /* ======================================================================== */
/* /*
* MUSASHI * MUSASHI
* Version 3.4 * Version 4.60
* *
* A portable Motorola M680x0 processor emulation engine. * 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -38,9 +38,19 @@
/* ================================ INCLUDES ============================== */ /* ================================ 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 "m68kops.h"
#include "m68kcpu.h" #include "m68kcpu.h"
#include "m68kfpu.c"
#include "m68kmmu.h" // uses some functions from m68kfpu.c which are static !
/* ======================================================================== */ /* ======================================================================== */
/* ================================= DATA ================================= */ /* ================================= DATA ================================= */
/* ======================================================================== */ /* ======================================================================== */
@ -51,7 +61,7 @@ uint m68ki_tracing = 0;
uint m68ki_address_space; uint m68ki_address_space;
#ifdef M68K_LOG_ENABLE #ifdef M68K_LOG_ENABLE
char* m68ki_cpu_names[9] = const char *const m68ki_cpu_names[] =
{ {
"Invalid CPU", "Invalid CPU",
"M68000", "M68000",
@ -69,15 +79,21 @@ char* m68ki_cpu_names[9] =
m68ki_cpu_core m68ki_cpu = {0}; m68ki_cpu_core m68ki_cpu = {0};
#if M68K_EMULATE_ADDRESS_ERROR #if M68K_EMULATE_ADDRESS_ERROR
#ifdef _BSD_SETJMP_H
sigjmp_buf m68ki_aerr_trap;
#else
jmp_buf m68ki_aerr_trap; jmp_buf m68ki_aerr_trap;
#endif
#endif /* M68K_EMULATE_ADDRESS_ERROR */ #endif /* M68K_EMULATE_ADDRESS_ERROR */
uint m68ki_aerr_address; uint m68ki_aerr_address;
uint m68ki_aerr_write_mode; uint m68ki_aerr_write_mode;
uint m68ki_aerr_fc; uint m68ki_aerr_fc;
jmp_buf m68ki_bus_error_jmp_buf;
/* Used by shift & rotate instructions */ /* 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, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 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, 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, 0x0000, 0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff, 0xffff, 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, 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, 0x00000000, 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 0xf8000000,
0xfc000000, 0xfe000000, 0xff000000, 0xff800000, 0xffc00000, 0xffe00000, 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. /* Number of clock cycles to use for exception processing.
* I used 4 for any vectors that are undocumented for processing times. * 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 */ { /* 000 */
4, /* 0: Reset - Initial Stack Pointer */ 40, /* 0: Reset - Initial Stack Pointer */
4, /* 1: Reset - Initial Program Counter */ 4, /* 1: Reset - Initial Program Counter */
50, /* 2: Bus Error (unemulated) */ 50, /* 2: Bus Error (unemulated) */
50, /* 3: Address Error (unemulated) */ 50, /* 3: Address Error (unemulated) */
34, /* 4: Illegal Instruction */ 34, /* 4: Illegal Instruction */
38, /* 5: Divide by Zero -- ASG: changed from 42 */ 38, /* 5: Divide by Zero */
40, /* 6: CHK -- ASG: chanaged from 44 */ 40, /* 6: CHK */
34, /* 7: TRAPV */ 34, /* 7: TRAPV */
34, /* 8: Privilege Violation */ 34, /* 8: Privilege Violation */
34, /* 9: Trace */ 34, /* 9: Trace */
@ -151,7 +167,7 @@ uint8 m68ki_exception_cycle_table[3][256] =
44, /* 29: Level 5 Interrupt Autovector */ 44, /* 29: Level 5 Interrupt Autovector */
44, /* 30: Level 6 Interrupt Autovector */ 44, /* 30: Level 6 Interrupt Autovector */
44, /* 31: Level 7 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, /* 33: TRAP #1 */
34, /* 34: TRAP #2 */ 34, /* 34: TRAP #2 */
34, /* 35: TRAP #3 */ 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 4,4,4,4,4,4,4,4,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 */ { /* 010 */
4, /* 0: Reset - Initial Stack Pointer */ 40, /* 0: Reset - Initial Stack Pointer */
4, /* 1: Reset - Initial Program Counter */ 4, /* 1: Reset - Initial Program Counter */
126, /* 2: Bus Error (unemulated) */ 126, /* 2: Bus Error (unemulated) */
126, /* 3: Address 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, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 4,4,4,4,4,4,4,4,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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, /* ..01.000 no memory indirect, base NULL */ 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 */ /* Called when the program counter changed by a large value */
static unsigned int default_pc_changed_callback_data; static unsigned int default_pc_changed_callback_data;
static void default_pc_changed_callback(unsigned int new_pc) 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 */ /* 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; jmp_buf m68ki_aerr_trap;
#endif /* M68K_EMULATE_ADDRESS_ERROR */ #endif /* M68K_EMULATE_ADDRESS_ERROR */
/* ======================================================================== */ /* ======================================================================== */
/* ================================= API ================================== */ /* ================================= 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_010: return (unsigned int)M68K_CPU_TYPE_68010;
case CPU_TYPE_EC020: return (unsigned int)M68K_CPU_TYPE_68EC020; 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_020: return (unsigned int)M68K_CPU_TYPE_68020;
case CPU_TYPE_040: return (unsigned int)M68K_CPU_TYPE_68040;
} }
return M68K_CPU_TYPE_INVALID; return M68K_CPU_TYPE_INVALID;
default: return 0; 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_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_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_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_SP: REG_SP = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_USP: if(FLAG_S) case M68K_REG_USP: if(FLAG_S)
REG_USP = MASK_OUT_ABOVE_32(value); 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; 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)) void m68k_set_pc_changed_callback(void (*callback)(unsigned int new_pc))
{ {
CALLBACK_PC_CHANGED = callback ? callback : default_pc_changed_callback; 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; 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; 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_MOVEM_L = 3;
CYC_SHIFT = 1; CYC_SHIFT = 1;
CYC_RESET = 132; 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; return;
case M68K_CPU_TYPE_68010: case M68K_CPU_TYPE_68010:
CPU_TYPE = CPU_TYPE_010; CPU_TYPE = CPU_TYPE_010;
@ -598,6 +812,7 @@ void m68k_set_cpu_type(unsigned int cpu_type)
CYC_MOVEM_L = 3; CYC_MOVEM_L = 3;
CYC_SHIFT = 1; CYC_SHIFT = 1;
CYC_RESET = 130; CYC_RESET = 130;
HAS_PMMU = 0;
return; return;
case M68K_CPU_TYPE_68EC020: case M68K_CPU_TYPE_68EC020:
CPU_TYPE = CPU_TYPE_EC020; CPU_TYPE = CPU_TYPE_EC020;
@ -614,6 +829,7 @@ void m68k_set_cpu_type(unsigned int cpu_type)
CYC_MOVEM_L = 2; CYC_MOVEM_L = 2;
CYC_SHIFT = 0; CYC_SHIFT = 0;
CYC_RESET = 518; CYC_RESET = 518;
HAS_PMMU = 0;
return; return;
case M68K_CPU_TYPE_68020: case M68K_CPU_TYPE_68020:
CPU_TYPE = CPU_TYPE_020; CPU_TYPE = CPU_TYPE_020;
@ -630,6 +846,91 @@ void m68k_set_cpu_type(unsigned int cpu_type)
CYC_MOVEM_L = 2; CYC_MOVEM_L = 2;
CYC_SHIFT = 0; CYC_SHIFT = 0;
CYC_RESET = 518; 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; return;
} }
} }
@ -638,23 +939,34 @@ void m68k_set_cpu_type(unsigned int cpu_type)
/* ASG: removed per-instruction interrupt checks */ /* ASG: removed per-instruction interrupt checks */
int m68k_execute(int num_cycles) int m68k_execute(int num_cycles)
{ {
/* 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;
/* See if interrupts came in */
m68ki_check_interrupts();
/* Make sure we're not stopped */ /* Make sure we're not stopped */
if(!CPU_STOPPED) if(!CPU_STOPPED)
{ {
/* 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;
/* Return point if we had an address error */ /* Return point if we had an address error */
m68ki_set_address_error_trap(); /* auto-disable (see m68kcpu.h) */ 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 */ /* Main loop. Keep going until we run out of clock cycles */
do do
{ {
int i;
/* Set tracing accodring to T1. (T0 is done inside instruction) */ /* Set tracing accodring to T1. (T0 is done inside instruction) */
m68ki_trace_t1(); /* auto-disable (see m68kcpu.h) */ 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) */ m68ki_use_data_space(); /* auto-disable (see m68kcpu.h) */
/* Call external hook to peek at CPU */ /* 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 */ /* Record previous program counter */
REG_PPC = REG_PC; 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 */ /* Read an instruction and call its handler */
REG_IR = m68ki_read_imm_16(); REG_IR = m68ki_read_imm_16();
m68ki_instruction_jump_table[REG_IR](); m68ki_instruction_jump_table[REG_IR]();
@ -678,20 +995,12 @@ int m68k_execute(int num_cycles)
/* set previous PC to current PC for the next entry into the loop */ /* set previous PC to current PC for the next entry into the loop */
REG_PPC = REG_PC; REG_PPC = REG_PC;
/* ASG: update cycles */
USE_CYCLES(CPU_INT_CYCLES);
CPU_INT_CYCLES = 0;
/* return how many clocks we used */
return m68ki_initial_cycles - GET_CYCLES();
} }
else
SET_CYCLES(0);
/* We get here if the CPU is stopped or halted */ /* return how many clocks we used */
SET_CYCLES(0); return m68ki_initial_cycles - GET_CYCLES();
CPU_INT_CYCLES = 0;
return num_cycles;
} }
@ -732,9 +1041,29 @@ void m68k_set_irq(unsigned int int_level)
/* A transition from < 7 to 7 always interrupts (NMI) */ /* A transition from < 7 to 7 always interrupts (NMI) */
/* Note: Level 7 can also level trigger like a normal IRQ */ /* Note: Level 7 can also level trigger like a normal IRQ */
if(old_level != 0x0700 && CPU_INT_LEVEL == 0x0700) 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 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) void m68k_init(void)
@ -751,14 +1080,27 @@ void m68k_init(void)
m68k_set_int_ack_callback(NULL); m68k_set_int_ack_callback(NULL);
m68k_set_bkpt_ack_callback(NULL); m68k_set_bkpt_ack_callback(NULL);
m68k_set_reset_instr_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_pc_changed_callback(NULL);
m68k_set_fc_callback(NULL); m68k_set_fc_callback(NULL);
m68k_set_instr_hook_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 */ /* Pulse the RESET line on the CPU */
void m68k_pulse_reset(void) 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 */ /* Clear all stop levels and eat up all remaining cycles */
CPU_STOPPED = 0; CPU_STOPPED = 0;
SET_CYCLES(0); SET_CYCLES(0);
@ -771,6 +1113,8 @@ void m68k_pulse_reset(void)
m68ki_clear_trace(); m68ki_clear_trace();
/* Interrupt mask to level 7 */ /* Interrupt mask to level 7 */
FLAG_INT_MASK = 0x0700; FLAG_INT_MASK = 0x0700;
CPU_INT_LEVEL = 0;
m68ki_cpu.virq_state = 0;
/* Reset VBR */ /* Reset VBR */
REG_VBR = 0; REG_VBR = 0;
/* Go to supervisor mode */ /* Go to supervisor mode */
@ -789,6 +1133,8 @@ void m68k_pulse_reset(void)
m68ki_jump(REG_PC); m68ki_jump(REG_PC);
CPU_RUN_MODE = RUN_MODE_NORMAL; CPU_RUN_MODE = RUN_MODE_NORMAL;
RESET_CYCLES = CYC_EXCEPTION[EXCEPTION_RESET];
} }
/* Pulse the HALT line on the CPU */ /* Pulse the HALT line on the CPU */
@ -797,7 +1143,6 @@ void m68k_pulse_halt(void)
CPU_STOPPED |= STOP_LEVEL_HALT; CPU_STOPPED |= STOP_LEVEL_HALT;
} }
/* Get and set the current CPU context */ /* Get and set the current CPU context */
/* This is to allow for multiple CPUs */ /* This is to allow for multiple CPUs */
unsigned int m68k_context_size() unsigned int m68k_context_size()
@ -816,20 +1161,16 @@ void m68k_set_context(void* src)
if(src) m68ki_cpu = *(m68ki_cpu_core*)src; if(src) m68ki_cpu = *(m68ki_cpu_core*)src;
} }
/* ======================================================================== */ /* ======================================================================== */
/* ============================== MAME STUFF ============================== */ /* ============================== MAME STUFF ============================== */
/* ======================================================================== */ /* ======================================================================== */
#if M68K_COMPILE_FOR_MAME == OPT_ON #if M68K_COMPILE_FOR_MAME == OPT_ON
#include "state.h"
static struct { static struct {
UINT16 sr; UINT16 sr;
int stopped; UINT8 stopped;
int halted; UINT8 halted;
} m68k_substate; } m68k_substate;
static void m68k_prepare_substate(void) static void m68k_prepare_substate(void)
@ -847,29 +1188,26 @@ static void m68k_post_load(void)
m68ki_jump(REG_PC); m68ki_jump(REG_PC);
} }
void m68k_state_register(const char *type) void m68k_state_register(const char *type, int index)
{ {
int cpu = cpu_getactivecpu(); /* 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_UINT32(type, cpu, "D" , REG_D, 8); state_save_register_item(type, index, REG_PPC);
state_save_register_UINT32(type, cpu, "A" , REG_A, 8); state_save_register_item(type, index, REG_PC);
state_save_register_UINT32(type, cpu, "PPC" , &REG_PPC, 1); state_save_register_item(type, index, REG_USP);
state_save_register_UINT32(type, cpu, "PC" , &REG_PC, 1); state_save_register_item(type, index, REG_ISP);
state_save_register_UINT32(type, cpu, "USP" , &REG_USP, 1); state_save_register_item(type, index, REG_MSP);
state_save_register_UINT32(type, cpu, "ISP" , &REG_ISP, 1); state_save_register_item(type, index, REG_VBR);
state_save_register_UINT32(type, cpu, "MSP" , &REG_MSP, 1); state_save_register_item(type, index, REG_SFC);
state_save_register_UINT32(type, cpu, "VBR" , &REG_VBR, 1); state_save_register_item(type, index, REG_DFC);
state_save_register_UINT32(type, cpu, "SFC" , &REG_SFC, 1); state_save_register_item(type, index, REG_CACR);
state_save_register_UINT32(type, cpu, "DFC" , &REG_DFC, 1); state_save_register_item(type, index, REG_CAAR);
state_save_register_UINT32(type, cpu, "CACR" , &REG_CACR, 1); state_save_register_item(type, index, m68k_substate.sr);
state_save_register_UINT32(type, cpu, "CAAR" , &REG_CAAR, 1); state_save_register_item(type, index, CPU_INT_LEVEL);
state_save_register_UINT16(type, cpu, "SR" , &m68k_substate.sr, 1); state_save_register_item(type, index, m68k_substate.stopped);
state_save_register_UINT32(type, cpu, "INT_LEVEL" , &CPU_INT_LEVEL, 1); state_save_register_item(type, index, m68k_substate.halted);
state_save_register_UINT32(type, cpu, "INT_CYCLES", &CPU_INT_CYCLES, 1); state_save_register_item(type, index, CPU_PREF_ADDR);
state_save_register_int (type, cpu, "STOPPED" , &m68k_substate.stopped); state_save_register_item(type, index, CPU_PREF_DATA);
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);
state_save_register_func_presave(m68k_prepare_substate); state_save_register_func_presave(m68k_prepare_substate);
state_save_register_func_postload(m68k_post_load); 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 * MUSASHI
* Version 3.4 * Version 3.32
* *
* A portable Motorola M680x0 processor emulation engine. * 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -38,6 +38,14 @@
#include <string.h> #include <string.h>
#include "m68k.h" #include "m68k.h"
#ifndef uint32
#define uint32 uint
#endif
#ifndef uint16
#define uint16 unsigned short
#endif
#ifndef DECL_SPEC #ifndef DECL_SPEC
#define DECL_SPEC #define DECL_SPEC
#endif #endif
@ -129,6 +137,15 @@
#define EXT_OUTER_DISPLACEMENT_LONG(A) (((A)&3) == 3 && ((A)&0x47) < 0x44) #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 ============================= */ /* =============================== PROTOTYPES ============================= */
@ -147,6 +164,7 @@ uint peek_imm_32(void);
/* make signed integers 100% portably */ /* make signed integers 100% portably */
static int make_int_8(int value); static int make_int_8(int value);
static int make_int_16(int value); static int make_int_16(int value);
static int make_int_32(int value);
/* make a string of a hex value */ /* make a string of a hex value */
static char* make_signed_hex_str_8(uint val); 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_pc; /* program counter */
static uint g_cpu_ir; /* instruction register */ static uint g_cpu_ir; /* instruction register */
static uint g_cpu_type; 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 */ /* 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, 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 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"}; {"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 */ {/* 000 001 010 011 100 101 110 111 */
"f", "eq", "ogt", "oge", "olt", "ole", "ogl", "or", /* 000 */ "f", "eq", "ogt", "oge", "olt", "ole", "ogl", "or", /* 000 */
"un", "ueq", "ugt", "uge", "ult", "ule", "ne", "t", /* 001 */ "un", "ueq", "ugt", "uge", "ult", "ule", "ne", "t", /* 001 */
@ -226,6 +247,16 @@ static char* g_cpcc[64] =
"?", "?", "?", "?", "?", "?", "?", "?" /* 111 */ "?", "?", "?", "?", "?", "?", "?", "?" /* 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 ========================== */ /* =========================== UTILITY FUNCTIONS ========================== */
@ -234,17 +265,56 @@ static char* g_cpcc[64] =
#define LIMIT_CPU_TYPES(ALLOWED_CPU_TYPES) \ #define LIMIT_CPU_TYPES(ALLOWED_CPU_TYPES) \
if(!(g_cpu_type & ALLOWED_CPU_TYPES)) \ if(!(g_cpu_type & ALLOWED_CPU_TYPES)) \
{ \ { \
d68000_illegal(); \ if((g_cpu_ir & 0xf000) == 0xf000) \
d68000_1111(); \
else d68000_illegal(); \
return; \ return; \
} }
#define read_imm_8() (m68k_read_disassembler_16(((g_cpu_pc+=2)-2)&g_address_mask)&0xff) static uint dasm_read_imm_8(uint advance)
#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) 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) static uint dasm_read_imm_16(uint advance)
#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) 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 */ /* Fake a split interface */
#define get_ea_mode_str_8(instruction) get_ea_mode_str(instruction, 0) #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_u16() get_imm_str_u(1)
#define get_imm_str_u32() get_imm_str_u(2) #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 */ /* 100% portable signed int generators */
static int make_int_8(int value) 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; 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 */ /* Get string representation of hex values */
static char* make_signed_hex_str_8(uint val) static char* make_signed_hex_str_8(uint val)
@ -425,7 +504,14 @@ static char* get_ea_mode_str(uint instruction, uint size)
strcat(mode, "["); strcat(mode, "[");
if(base) if(base)
{ {
strcat(mode, make_signed_hex_str_16(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; comma = 1;
} }
if(*base_reg) if(*base_reg)
@ -875,20 +961,20 @@ static void d68000_asl_ea(void)
static void d68000_bcc_8(void) static void d68000_bcc_8(void)
{ {
uint temp_pc = g_cpu_pc; 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) static void d68000_bcc_16(void)
{ {
uint temp_pc = g_cpu_pc; 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) static void d68020_bcc_32(void)
{ {
uint temp_pc = g_cpu_pc; uint temp_pc = g_cpu_pc;
LIMIT_CPU_TYPES(M68020_PLUS); 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) static void d68000_bchg_r(void)
@ -1090,20 +1176,20 @@ static void d68020_bftst(void)
static void d68000_bra_8(void) static void d68000_bra_8(void)
{ {
uint temp_pc = g_cpu_pc; 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) static void d68000_bra_16(void)
{ {
uint temp_pc = g_cpu_pc; 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) static void d68020_bra_32(void)
{ {
uint temp_pc = g_cpu_pc; uint temp_pc = g_cpu_pc;
LIMIT_CPU_TYPES(M68020_PLUS); 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) static void d68000_bset_r(void)
@ -1120,20 +1206,23 @@ static void d68000_bset_s(void)
static void d68000_bsr_8(void) static void d68000_bsr_8(void)
{ {
uint temp_pc = g_cpu_pc; 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) static void d68000_bsr_16(void)
{ {
uint temp_pc = g_cpu_pc; 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) static void d68020_bsr_32(void)
{ {
uint temp_pc = g_cpu_pc; uint temp_pc = g_cpu_pc;
LIMIT_CPU_TYPES(M68020_PLUS); 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) static void d68000_btst_r(void)
@ -1211,12 +1300,14 @@ static void d68020_cas2_32(void)
static void d68000_chk_16(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); 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) static void d68020_chk_32(void)
{ {
LIMIT_CPU_TYPES(M68020_PLUS); 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); 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) static void d68020_chk2_cmp2_8(void)
@ -1392,7 +1483,7 @@ static void d68020_cpbcc_16(void)
uint new_pc = g_cpu_pc; uint new_pc = g_cpu_pc;
LIMIT_CPU_TYPES(M68020_PLUS); LIMIT_CPU_TYPES(M68020_PLUS);
extension = read_imm_16(); 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); 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; uint new_pc = g_cpu_pc;
LIMIT_CPU_TYPES(M68020_PLUS); LIMIT_CPU_TYPES(M68020_PLUS);
extension = read_imm_16(); 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); 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); LIMIT_CPU_TYPES(M68020_PLUS);
extension1 = read_imm_16(); extension1 = read_imm_16();
extension2 = 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); 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,13 +1518,27 @@ static void d68020_cpgen(void)
static void d68020_cprestore(void) static void d68020_cprestore(void)
{ {
LIMIT_CPU_TYPES(M68020_PLUS); LIMIT_CPU_TYPES(M68020_PLUS);
sprintf(g_dasm_str, "%drestore %s; (2-3)", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); 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) static void d68020_cpsave(void)
{ {
LIMIT_CPU_TYPES(M68020_PLUS); LIMIT_CPU_TYPES(M68020_PLUS);
sprintf(g_dasm_str, "%dsave %s; (2-3)", (g_cpu_ir>>9)&7, get_ea_mode_str_8(g_cpu_ir)); 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) static void d68020_cpscc(void)
@ -1499,13 +1604,15 @@ static void d68040_cpush(void)
static void d68000_dbra(void) static void d68000_dbra(void)
{ {
uint temp_pc = g_cpu_pc; 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) static void d68000_dbcc(void)
{ {
uint temp_pc = g_cpu_pc; 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) 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); 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) static void d68000_jmp(void)
{ {
sprintf(g_dasm_str, "jmp %s", get_ea_mode_str_32(g_cpu_ir)); 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) static void d68000_jsr(void)
{ {
sprintf(g_dasm_str, "jsr %s", get_ea_mode_str_32(g_cpu_ir)); 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) static void d68000_lea(void)
@ -1840,7 +2162,7 @@ static void d68010_movec(void)
processor = "?"; 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); sprintf(g_dasm_str, "movec %c%d, %s; (%s)", BIT_F(extension) ? 'A' : 'D', (extension>>12)&7, reg_name, processor);
else else
sprintf(g_dasm_str, "movec %s, %c%d; (%s)", reg_name, BIT_F(extension) ? 'A' : 'D', (extension>>12)&7, processor); 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)); 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) static void d68000_reset(void)
{ {
sprintf(g_dasm_str, "reset"); sprintf(g_dasm_str, "reset");
@ -2524,27 +2861,32 @@ static void d68010_rtd(void)
{ {
LIMIT_CPU_TYPES(M68010_PLUS); LIMIT_CPU_TYPES(M68010_PLUS);
sprintf(g_dasm_str, "rtd %s; (1+)", get_imm_str_s16()); sprintf(g_dasm_str, "rtd %s; (1+)", get_imm_str_s16());
SET_OPCODE_FLAGS(DASMFLAG_STEP_OUT);
} }
static void d68000_rte(void) static void d68000_rte(void)
{ {
sprintf(g_dasm_str, "rte"); sprintf(g_dasm_str, "rte");
SET_OPCODE_FLAGS(DASMFLAG_STEP_OUT);
} }
static void d68020_rtm(void) static void d68020_rtm(void)
{ {
LIMIT_CPU_TYPES(M68020_ONLY); LIMIT_CPU_TYPES(M68020_ONLY);
sprintf(g_dasm_str, "rtm %c%d; (2+)", BIT_3(g_cpu_ir) ? 'A' : 'D', g_cpu_ir&7); 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) static void d68000_rtr(void)
{ {
sprintf(g_dasm_str, "rtr"); sprintf(g_dasm_str, "rtr");
SET_OPCODE_FLAGS(DASMFLAG_STEP_OUT);
} }
static void d68000_rts(void) static void d68000_rts(void)
{ {
sprintf(g_dasm_str, "rts"); sprintf(g_dasm_str, "rts");
SET_OPCODE_FLAGS(DASMFLAG_STEP_OUT);
} }
static void d68000_sbcd_rr(void) static void d68000_sbcd_rr(void)
@ -2689,23 +3031,27 @@ static void d68020_trapcc_0(void)
{ {
LIMIT_CPU_TYPES(M68020_PLUS); LIMIT_CPU_TYPES(M68020_PLUS);
sprintf(g_dasm_str, "trap%-2s; (2+)", g_cc[(g_cpu_ir>>8)&0xf]); 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) static void d68020_trapcc_16(void)
{ {
LIMIT_CPU_TYPES(M68020_PLUS); LIMIT_CPU_TYPES(M68020_PLUS);
sprintf(g_dasm_str, "trap%-2s %s; (2+)", g_cc[(g_cpu_ir>>8)&0xf], get_imm_str_u16()); 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) static void d68020_trapcc_32(void)
{ {
LIMIT_CPU_TYPES(M68020_PLUS); LIMIT_CPU_TYPES(M68020_PLUS);
sprintf(g_dasm_str, "trap%-2s %s; (2+)", g_cc[(g_cpu_ir>>8)&0xf], get_imm_str_u32()); 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) static void d68000_trapv(void)
{ {
sprintf(g_dasm_str, "trapv"); sprintf(g_dasm_str, "trapv");
SET_OPCODE_FLAGS(DASMFLAG_STEP_OVER);
} }
static void d68000_tst_8(void) 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 ====================== */ /* ======================= INSTRUCTION TABLE BUILDER ====================== */
@ -2827,9 +3304,9 @@ static void d68020_unpk_mm(void)
1 = pc idx 1 = pc idx
*/ */
static opcode_struct g_opcode_info[] = static const opcode_struct g_opcode_info[] =
{ {
/* opcode handler mask match ea mask */ /* opcode handler mask match ea mask */
{d68000_1010 , 0xf000, 0xa000, 0x000}, {d68000_1010 , 0xf000, 0xa000, 0x000},
{d68000_1111 , 0xf000, 0xf000, 0x000}, {d68000_1111 , 0xf000, 0xf000, 0x000},
{d68000_abcd_rr , 0xf1f8, 0xc100, 0x000}, {d68000_abcd_rr , 0xf1f8, 0xc100, 0x000},
@ -2967,6 +3444,7 @@ static opcode_struct g_opcode_info[] =
{d68020_extb_32 , 0xfff8, 0x49c0, 0x000}, {d68020_extb_32 , 0xfff8, 0x49c0, 0x000},
{d68000_ext_16 , 0xfff8, 0x4880, 0x000}, {d68000_ext_16 , 0xfff8, 0x4880, 0x000},
{d68000_ext_32 , 0xfff8, 0x48c0, 0x000}, {d68000_ext_32 , 0xfff8, 0x48c0, 0x000},
{d68040_fpu , 0xffc0, 0xf200, 0x000},
{d68000_illegal , 0xffff, 0x4afc, 0x000}, {d68000_illegal , 0xffff, 0x4afc, 0x000},
{d68000_jmp , 0xffc0, 0x4ec0, 0x27b}, {d68000_jmp , 0xffc0, 0x4ec0, 0x27b},
{d68000_jsr , 0xffc0, 0x4e80, 0x27b}, {d68000_jsr , 0xffc0, 0x4e80, 0x27b},
@ -3046,6 +3524,7 @@ static opcode_struct g_opcode_info[] =
{d68020_pack_rr , 0xf1f8, 0x8140, 0x000}, {d68020_pack_rr , 0xf1f8, 0x8140, 0x000},
{d68020_pack_mm , 0xf1f8, 0x8148, 0x000}, {d68020_pack_mm , 0xf1f8, 0x8148, 0x000},
{d68000_pea , 0xffc0, 0x4840, 0x27b}, {d68000_pea , 0xffc0, 0x4840, 0x27b},
{d68040_pflush , 0xffe0, 0xf500, 0x000},
{d68000_reset , 0xffff, 0x4e70, 0x000}, {d68000_reset , 0xffff, 0x4e70, 0x000},
{d68000_ror_s_8 , 0xf1f8, 0xe018, 0x000}, {d68000_ror_s_8 , 0xf1f8, 0xe018, 0x000},
{d68000_ror_s_16 , 0xf1f8, 0xe058, 0x000}, {d68000_ror_s_16 , 0xf1f8, 0xe058, 0x000},
@ -3128,6 +3607,11 @@ static opcode_struct g_opcode_info[] =
{d68000_unlk , 0xfff8, 0x4e58, 0x000}, {d68000_unlk , 0xfff8, 0x4e58, 0x000},
{d68020_unpk_rr , 0xf1f8, 0x8180, 0x000}, {d68020_unpk_rr , 0xf1f8, 0x8180, 0x000},
{d68020_unpk_mm , 0xf1f8, 0x8188, 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} {0, 0, 0, 0}
}; };
@ -3200,19 +3684,17 @@ static void build_opcode_table(void)
uint i; uint i;
uint opcode; uint opcode;
opcode_struct* ostruct; 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++) memcpy(opcode_info, g_opcode_info, sizeof(g_opcode_info));
opcode_info_length++; qsort((void *)opcode_info, ARRAY_LENGTH(opcode_info)-1, sizeof(opcode_info[0]), compare_nof_true_bits);
qsort((void *)g_opcode_info, opcode_info_length, sizeof(g_opcode_info[0]), compare_nof_true_bits);
for(i=0;i<0x10000;i++) for(i=0;i<0x10000;i++)
{ {
g_instruction_table[i] = d68000_illegal; /* default to illegal */ g_instruction_table[i] = d68000_illegal; /* default to illegal */
opcode = i; opcode = i;
/* search through opcode info for a match */ /* 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 */ /* match opcode mask and allowed ea modes */
if((opcode & ostruct->mask) == ostruct->match) 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_cpu_type = TYPE_68020;
g_address_mask = 0xffffffff; g_address_mask = 0xffffffff;
break; break;
case M68K_CPU_TYPE_68EC030:
case M68K_CPU_TYPE_68030: case M68K_CPU_TYPE_68030:
g_cpu_type = TYPE_68030; g_cpu_type = TYPE_68030;
g_address_mask = 0xffffffff; g_address_mask = 0xffffffff;
break; break;
case M68K_CPU_TYPE_68040: case M68K_CPU_TYPE_68040:
case M68K_CPU_TYPE_68EC040:
case M68K_CPU_TYPE_68LC040:
g_cpu_type = TYPE_68040; g_cpu_type = TYPE_68040;
g_address_mask = 0xffffffff; g_address_mask = 0xffffffff;
break; break;
@ -3280,9 +3765,10 @@ unsigned int m68k_disassemble(char* str_buff, unsigned int pc, unsigned int cpu_
g_cpu_pc = pc; g_cpu_pc = pc;
g_helper_str[0] = 0; g_helper_str[0] = 0;
g_cpu_ir = read_imm_16(); g_cpu_ir = read_imm_16();
g_opcode_type = 0;
g_instruction_table[g_cpu_ir](); g_instruction_table[g_cpu_ir]();
sprintf(str_buff, "%s%s", g_dasm_str, g_helper_str); 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) 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; 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 */ /* Check if the instruction is a valid one */
unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cpu_type) 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; return 0;
if(g_instruction_table[instruction] == d68010_rtd) if(g_instruction_table[instruction] == d68010_rtd)
return 0; return 0;
// Fallthrough
case M68K_CPU_TYPE_68010: case M68K_CPU_TYPE_68010:
if(g_instruction_table[instruction] == d68020_bcc_32) if(g_instruction_table[instruction] == d68020_bcc_32)
return 0; return 0;
@ -3444,9 +3943,11 @@ unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cp
return 0; return 0;
if(g_instruction_table[instruction] == d68020_unpk_mm) if(g_instruction_table[instruction] == d68020_unpk_mm)
return 0; return 0;
// Fallthrough
case M68K_CPU_TYPE_68EC020: case M68K_CPU_TYPE_68EC020:
case M68K_CPU_TYPE_68020: case M68K_CPU_TYPE_68020:
case M68K_CPU_TYPE_68030: case M68K_CPU_TYPE_68030:
case M68K_CPU_TYPE_68EC030:
if(g_instruction_table[instruction] == d68040_cinv) if(g_instruction_table[instruction] == d68040_cinv)
return 0; return 0;
if(g_instruction_table[instruction] == d68040_cpush) 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; return 0;
if(g_instruction_table[instruction] == d68040_move16_al_ai) if(g_instruction_table[instruction] == d68040_move16_al_ai)
return 0; 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 && if(cpu_type != M68K_CPU_TYPE_68020 && cpu_type != M68K_CPU_TYPE_68EC020 &&
(g_instruction_table[instruction] == d68020_callm || (g_instruction_table[instruction] == d68020_callm ||
@ -3470,7 +3997,7 @@ unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cp
return 1; return 1;
} }
// f028 2215 0008
/* ======================================================================== */ /* ======================================================================== */
/* ============================== END OF FILE ============================= */ /* ============================== END OF FILE ============================= */

File diff suppressed because it is too large Load diff

View file

@ -3,10 +3,11 @@
/* ======================================================================== */ /* ======================================================================== */
/* /*
* MUSASHI * MUSASHI
* Version 3.4 * Version 4.60
* *
* A portable Motorola M680x0 processor emulation engine. * 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 * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * 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 =============================== */ /* =============================== INCLUDES =============================== */
@ -77,7 +78,6 @@ char* g_version = "3.3";
#define M68K_MAX_PATH 1024 #define M68K_MAX_PATH 1024
#define M68K_MAX_DIR 1024 #define M68K_MAX_DIR 1024
#define NUM_CPUS 3 /* 000, 010, 020 */
#define MAX_LINE_LENGTH 200 /* length of 1 line */ #define MAX_LINE_LENGTH 200 /* length of 1 line */
#define MAX_BODY_LENGTH 300 /* Number of lines in 1 function */ #define MAX_BODY_LENGTH 300 /* Number of lines in 1 function */
#define MAX_REPLACE_LENGTH 30 /* Max number of replace strings */ #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_INPUT "m68k_in.c"
#define FILENAME_PROTOTYPE "m68kops.h" #define FILENAME_PROTOTYPE "m68kops.h"
#define FILENAME_TABLE "m68kops.c" #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 */ /* Identifier sequences recognized by this program */
@ -135,9 +132,14 @@ char* g_version = "3.3";
/* ============================== PROTOTYPES ============================== */ /* ============================== PROTOTYPES ============================== */
/* ======================================================================== */ /* ======================================================================== */
#define CPU_TYPE_000 0 enum {
#define CPU_TYPE_010 1 CPU_TYPE_000=0,
#define CPU_TYPE_020 2 CPU_TYPE_010,
CPU_TYPE_020,
CPU_TYPE_030,
CPU_TYPE_040,
NUM_CPUS
};
#define UNSPECIFIED "." #define UNSPECIFIED "."
#define UNSPECIFIED_CH '.' #define UNSPECIFIED_CH '.'
@ -185,7 +187,7 @@ typedef struct
char ea_allowed[EA_ALLOWED_LENGTH]; /* Effective addressing modes allowed */ char ea_allowed[EA_ALLOWED_LENGTH]; /* Effective addressing modes allowed */
char cpu_mode[NUM_CPUS]; /* User or supervisor mode */ char cpu_mode[NUM_CPUS]; /* User or supervisor mode */
char cpus[NUM_CPUS+1]; /* Allowed CPUs */ 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; } 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 add_replace_string(replace_struct* replace, char* search_str, char* replace_str);
void write_body(FILE* filep, body_struct* body, replace_struct* replace); void write_body(FILE* filep, body_struct* body, replace_struct* replace);
void get_base_name(char* base_name, opcode_struct* op); 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 write_function_name(FILE* filep, char* base_name);
void add_opcode_output_table_entry(opcode_struct* op, char* 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); 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_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_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 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 populate_table(void);
void read_insert(char* insert); 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_input_file = NULL;
FILE* g_prototype_file = NULL; FILE* g_prototype_file = NULL;
FILE* g_table_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_functions = 0; /* Number of functions processed */
int g_num_primitives = 0; /* Number of function primitives read */ 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]; opcode_struct g_opcode_output_table[MAX_OPCODE_OUTPUT_TABLE_LENGTH];
int g_opcode_output_table_length = 0; 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 */ {/* fname ea mask match */
{"", "", 0x00, 0x00}, /* EA_MODE_NONE */ {"", "", 0x00, 0x00}, /* EA_MODE_NONE */
{"ai", "AY_AI", 0x38, 0x10}, /* EA_MODE_AI */ {"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 */ { "t", "T"}, /* 0000 */
{ "f", "F"}, /* 0001 */ { "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) */ /* 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, /* unsized */
0, 0, 0, 0, 0, 0, 0, 1, /* 8 */ 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 */ /* Extra cycles required for certain EA modes */
int g_ea_cycle_table[13][NUM_CPUS][3] = /* TODO: correct timings for 030, 040 */
{/* 000 010 020 */ const int g_ea_cycle_table[13][NUM_CPUS][3] =
{{ 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}}, /* EA_MODE_NONE */ {/* 000 010 020 030 040 */
{{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}}, /* EA_MODE_AI */ {{ 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}}, /* EA_MODE_PI */ {{ 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}}, /* EA_MODE_PI7 */ {{ 0, 4, 8}, { 0, 4, 8}, { 0, 4, 4}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_PI */
{{ 0, 6, 10}, { 0, 6, 10}, { 0, 5, 5}}, /* EA_MODE_PD */ {{ 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}}, /* EA_MODE_PD7 */ {{ 0, 6, 10}, { 0, 6, 10}, { 0, 5, 5}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_PD */
{{ 0, 8, 12}, { 0, 8, 12}, { 0, 5, 5}}, /* EA_MODE_DI */ {{ 0, 6, 10}, { 0, 6, 10}, { 0, 5, 5}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_PD7 */
{{ 0, 10, 14}, { 0, 10, 14}, { 0, 7, 7}}, /* EA_MODE_IX */ {{ 0, 8, 12}, { 0, 8, 12}, { 0, 5, 5}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_DI */
{{ 0, 8, 12}, { 0, 8, 12}, { 0, 4, 4}}, /* EA_MODE_AW */ {{ 0, 10, 14}, { 0, 10, 14}, { 0, 7, 7}, { 0, 7, 7}, { 0, 7, 7}}, /* EA_MODE_IX */
{{ 0, 12, 16}, { 0, 12, 16}, { 0, 4, 4}}, /* EA_MODE_AL */ {{ 0, 8, 12}, { 0, 8, 12}, { 0, 4, 4}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_AW */
{{ 0, 8, 12}, { 0, 8, 12}, { 0, 5, 5}}, /* EA_MODE_PCDI */ {{ 0, 12, 16}, { 0, 12, 16}, { 0, 4, 4}, { 0, 4, 4}, { 0, 4, 4}}, /* EA_MODE_AL */
{{ 0, 10, 14}, { 0, 10, 14}, { 0, 7, 7}}, /* EA_MODE_PCIX */ {{ 0, 8, 12}, { 0, 8, 12}, { 0, 5, 5}, { 0, 5, 5}, { 0, 5, 5}}, /* EA_MODE_PCDI */
{{ 0, 4, 8}, { 0, 4, 8}, { 0, 2, 4}}, /* EA_MODE_I */ {{ 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) */ /* Extra cycles for JMP instruction (000, 010) */
int g_jmp_cycle_table[13] = const int g_jmp_cycle_table[13] =
{ {
0, /* EA_MODE_NONE */ 0, /* EA_MODE_NONE */
4, /* EA_MODE_AI */ 4, /* EA_MODE_AI */
@ -356,7 +355,7 @@ int g_jmp_cycle_table[13] =
}; };
/* Extra cycles for JSR instruction (000, 010) */ /* Extra cycles for JSR instruction (000, 010) */
int g_jsr_cycle_table[13] = const int g_jsr_cycle_table[13] =
{ {
0, /* EA_MODE_NONE */ 0, /* EA_MODE_NONE */
4, /* EA_MODE_AI */ 4, /* EA_MODE_AI */
@ -374,7 +373,7 @@ int g_jsr_cycle_table[13] =
}; };
/* Extra cycles for LEA instruction (000, 010) */ /* Extra cycles for LEA instruction (000, 010) */
int g_lea_cycle_table[13] = const int g_lea_cycle_table[13] =
{ {
0, /* EA_MODE_NONE */ 0, /* EA_MODE_NONE */
4, /* EA_MODE_AI */ 4, /* EA_MODE_AI */
@ -392,7 +391,7 @@ int g_lea_cycle_table[13] =
}; };
/* Extra cycles for PEA instruction (000, 010) */ /* Extra cycles for PEA instruction (000, 010) */
int g_pea_cycle_table[13] = const int g_pea_cycle_table[13] =
{ {
0, /* EA_MODE_NONE */ 0, /* EA_MODE_NONE */
6, /* EA_MODE_AI */ 6, /* EA_MODE_AI */
@ -409,8 +408,26 @@ int g_pea_cycle_table[13] =
0, /* EA_MODE_I */ 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) */ /* 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, 0, 0}, /* EA_MODE_NONE */
{ 0, 4, 6}, /* EA_MODE_AI */ { 0, 4, 6}, /* EA_MODE_AI */
@ -428,7 +445,7 @@ int g_moves_cycle_table[13][3] =
}; };
/* Extra cycles for CLR instruction (010) */ /* 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, 0, 0}, /* EA_MODE_NONE */
{ 0, 4, 6}, /* EA_MODE_AI */ { 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_prototype_file) fclose(g_prototype_file);
if(g_table_file) fclose(g_table_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); if(g_input_file) fclose(g_input_file);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@ -482,9 +496,6 @@ void perror_exit(char* fmt, ...)
if(g_prototype_file) fclose(g_prototype_file); if(g_prototype_file) fclose(g_prototype_file);
if(g_table_file) fclose(g_table_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); if(g_input_file) fclose(g_input_file);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@ -586,7 +597,7 @@ int fgetline(char* buff, int nchars, FILE* file)
if(fgets(buff, nchars, file) == NULL) if(fgets(buff, nchars, file) == NULL)
return -1; return -1;
if(buff[0] == '\r') if(buff[0] == '\r')
memcpy(buff, buff + 1, nchars - 1); memmove(buff, buff + 1, nchars - 1);
length = strlen(buff); length = strlen(buff);
while(length && (buff[length-1] == '\r' || buff[length-1] == '\n')) 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]; return op->cycles[cpu_type] + g_lea_cycle_table[ea_mode];
if(strcmp(op->name, "pea") == 0) if(strcmp(op->name, "pea") == 0)
return op->cycles[cpu_type] + g_pea_cycle_table[ea_mode]; 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]; 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; 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 && if( strcmp(name, op->name) == 0 &&
(size == op->size) && (size == op->size) &&
@ -665,7 +678,7 @@ opcode_struct* find_illegal_opcode(void)
{ {
opcode_struct* op; 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) if(strcmp(op->name, "illegal") == 0)
return op; 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 */ /* Found a directive with no matching replace string */
if(!found) if(!found)
error_exit("Unknown " ID_BASE " directive"); error_exit("Unknown " ID_BASE " directive [%s]", output);
} }
fprintf(filep, "%s\n", 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); 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 */ /* Write the name of an opcode handler function */
void write_function_name(FILE* filep, char* base_name) 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) 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 the opcode structure and write the tables, prototypes, etc */
set_opcode_struct(opinfo, op, ea_mode); set_opcode_struct(opinfo, op, ea_mode);
get_base_name(str, op); get_base_name(str, op);
write_prototype(g_prototype_file, str);
add_opcode_output_table_entry(op, str); add_opcode_output_table_entry(op, str);
write_function_name(filep, 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 */ /* 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* input_file = g_input_file;
FILE* output_file;
char func_name[MAX_LINE_LENGTH+1]; char func_name[MAX_LINE_LENGTH+1];
char oper_name[MAX_LINE_LENGTH+1]; char oper_name[MAX_LINE_LENGTH+1];
int oper_size; int oper_size;
@ -993,9 +998,6 @@ void process_opcode_handlers(void)
replace_struct* replace = malloc(sizeof(replace_struct)); replace_struct* replace = malloc(sizeof(replace_struct));
body_struct* body = malloc(sizeof(body_struct)); body_struct* body = malloc(sizeof(body_struct));
output_file = g_ops_ac_file;
for(;;) for(;;)
{ {
/* Find the first line of the function */ /* Find the first line of the function */
@ -1038,23 +1040,17 @@ void process_opcode_handlers(void)
if(opinfo == NULL) if(opinfo == NULL)
error_exit("Unable to find matching table entry for %s", func_name); 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; replace->length = 0;
/* Generate opcode variants */ /* Generate opcode variants */
if(strcmp(opinfo->name, "bcc") == 0 || strcmp(opinfo->name, "scc") == 0) 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) 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) 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 else
generate_opcode_ea_variants(output_file, body, replace, opinfo); generate_opcode_ea_variants(filep, body, replace, opinfo);
} }
free(replace); free(replace);
@ -1077,13 +1073,13 @@ void populate_table(void)
/* Find the start of the table */ /* Find the start of the table */
while(strcmp(buff, ID_TABLE_START) != 0) while(strcmp(buff, ID_TABLE_START) != 0)
if(fgetline(buff, MAX_LINE_LENGTH, g_input_file) < 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 */ /* Process the entire table */
for(op = g_opcode_input_table;;op++) for(op = g_opcode_input_table;;op++)
{ {
if(fgetline(buff, MAX_LINE_LENGTH, g_input_file) < 0) 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) if(strlen(buff) == 0)
continue; continue;
/* We finish when we find an input separator */ /* We finish when we find an input separator */
@ -1221,13 +1217,15 @@ int main(int argc, char **argv)
{ {
/* File stuff */ /* File stuff */
char output_path[M68K_MAX_DIR] = ""; char output_path[M68K_MAX_DIR] = "";
char filename[M68K_MAX_PATH]; char filename[M68K_MAX_PATH*2];
/* Section identifier */ /* Section identifier */
char section_id[MAX_LINE_LENGTH+1]; char section_id[MAX_LINE_LENGTH+1];
/* Inserts */ /* Inserts */
char temp_insert[MAX_INSERT_LENGTH+1]; char temp_insert[MAX_INSERT_LENGTH+1];
char prototype_footer_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 table_footer_insert[MAX_INSERT_LENGTH+1];
char ophandler_header_insert[MAX_INSERT_LENGTH+1];
char ophandler_footer_insert[MAX_INSERT_LENGTH+1]; char ophandler_footer_insert[MAX_INSERT_LENGTH+1];
/* Flags if we've processed certain parts already */ /* Flags if we've processed certain parts already */
int prototype_header_read = 0; int prototype_header_read = 0;
@ -1239,8 +1237,8 @@ int main(int argc, char **argv)
int table_body_read = 0; int table_body_read = 0;
int ophandler_body_read = 0; int ophandler_body_read = 0;
printf("\n\t\tMusashi v%s 68000, 68010, 68EC020, 68020 emulator\n", g_version); printf("\n\tMusashi v%s 68000, 68008, 68010, 68EC020, 68020, 68EC030, 68030, 68EC040, 68040 emulator\n", g_version);
printf("\t\tCopyright 1998-2000 Karl Stenerud (karl@mame.net)\n\n"); printf("\t\tCopyright Karl Stenerud (kstenerud@gmail.com)\n\n");
/* Check if output path and source for the input file are given */ /* Check if output path and source for the input file are given */
if(argc > 1) if(argc > 1)
@ -1266,18 +1264,6 @@ int main(int argc, char **argv)
if((g_table_file = fopen(filename, "wt")) == NULL) if((g_table_file = fopen(filename, "wt")) == NULL)
perror_exit("Unable to create table file (%s)\n", filename); 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) if((g_input_file=fopen(g_input_filename, "rt")) == NULL)
perror_exit("can't open %s for input", g_input_filename); 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) if(table_header_read)
error_exit("Duplicate table header"); error_exit("Duplicate table header");
read_insert(temp_insert); read_insert(table_header_insert);
fprintf(g_table_file, "%s", temp_insert);
table_header_read = 1; table_header_read = 1;
} }
else if(strcmp(section_id, ID_OPHANDLER_HEADER) == 0) else if(strcmp(section_id, ID_OPHANDLER_HEADER) == 0)
{ {
if(ophandler_header_read) if(ophandler_header_read)
error_exit("Duplicate opcode handler header"); error_exit("Duplicate opcode handler header");
read_insert(temp_insert); read_insert(ophandler_header_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);
ophandler_header_read = 1; ophandler_header_read = 1;
} }
else if(strcmp(section_id, ID_PROTOTYPE_FOOTER) == 0) else if(strcmp(section_id, ID_PROTOTYPE_FOOTER) == 0)
@ -1369,7 +1351,9 @@ int main(int argc, char **argv)
if(ophandler_body_read) if(ophandler_body_read)
error_exit("Duplicate opcode handler section"); 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; ophandler_body_read = 1;
} }
@ -1393,13 +1377,11 @@ int main(int argc, char **argv)
if(!ophandler_body_read) if(!ophandler_body_read)
error_exit("Missing opcode handler body"); error_exit("Missing opcode handler body");
fprintf(g_table_file, "%s\n\n", table_header_insert);
print_opcode_output_table(g_table_file); 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_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; break;
} }
@ -1412,9 +1394,6 @@ int main(int argc, char **argv)
/* Close all files and exit */ /* Close all files and exit */
fclose(g_prototype_file); fclose(g_prototype_file);
fclose(g_table_file); fclose(g_table_file);
fclose(g_ops_ac_file);
fclose(g_ops_dm_file);
fclose(g_ops_nz_file);
fclose(g_input_file); fclose(g_input_file);
printf("Generated %d opcode handlers from %d primitives\n", g_num_functions, g_num_primitives); 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 MUSASHI
======= =======
Version 3.4 Version 4.10
A portable Motorola M680x0 processor emulation engine. A portable Motorola M680x0 processor emulation engine.
Copyright 1998-2002 Karl Stenerud. All rights reserved. Copyright 1998-2002 Karl Stenerud. All rights reserved.
@ -11,8 +11,9 @@
INTRODUCTION: INTRODUCTION:
------------ ------------
Musashi is a Motorola 68000, 68010, 68EC020, and 68020 emulator written in C. Musashi is a Motorola 68000, 68010, 68EC020, 68020, 68EC030, 68030, 68EC040 and
This emulator was written with two goals in mind: portability and speed. 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 The emulator is written to ANSI C89 specifications. It also uses inline
functions, which are C9X compliant. 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_16(unsigned int address);
unsigned int m68k_read_immediate_32(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 - 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 M68K_MONITOR_PC to OPT_SPECIFY_HANDLER, and set M68K_SET_PC_CALLBACK(A) to
your routine. 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: ADDRESS SPACES:
-------------- --------------
@ -212,9 +225,12 @@ To set the CPU type you want to use:
M68K_CPU_TYPE_68000, M68K_CPU_TYPE_68000,
M68K_CPU_TYPE_68010, M68K_CPU_TYPE_68010,
M68K_CPU_TYPE_68EC020, 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: CLOCK FREQUENCY:
--------------- ---------------
@ -302,4 +318,25 @@ of the CPU.
EXAMPLE: 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 <time.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include "sim.h" #include "sim.h"
#include "m68k.h" #include "m68k.h"
@ -72,7 +75,7 @@ void exit_error(char* fmt, ...)
fprintf(stderr, "\n"); fprintf(stderr, "\n");
pc = m68k_get_reg(NULL, M68K_REG_PPC); pc = m68k_get_reg(NULL, M68K_REG_PPC);
m68k_disassemble(buff, pc, M68K_CPU_TYPE_68020); m68k_disassemble(buff, pc, M68K_CPU_TYPE_68020);
fprintf(stderr, "At %04x: %s\n", pc, buff); fprintf(stderr, "At %04x: %s\n", pc, buff);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -90,7 +93,7 @@ uint32_t cpu_read_long(uint32_t address)
switch (address) switch (address)
{ {
case 0x00: return INIT_SP; case 0x00: return INIT_SP;
case 0x04: return entrypoint; case 0x04: return entrypoint;
case 0x80: emulated_syscall(); return 0x10000; case 0x80: emulated_syscall(); return 0x10000;
case 0x10000: return 0x4e734e73; /* rte; rte */ case 0x10000: return 0x4e734e73; /* rte; rte */
case 0x10004: return 0; case 0x10004: return 0;
@ -170,10 +173,12 @@ void disassemble_program()
char buff2[100]; char buff2[100];
pc = cpu_read_long_dasm(4); 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); make_hex(buff2, pc, instr_size);
printf("%03x: %-20s: %s\n", pc, buff2, buff); printf("%03x: %-20s: %s\n", pc, buff2, buff);
pc += instr_size; pc += instr_size;
@ -181,8 +186,9 @@ void disassemble_program()
fflush(stdout); fflush(stdout);
} }
void cpu_instr_callback() void cpu_instr_callback(int apc)
{ {
(void)apc;
uint32_t pc = m68k_get_reg(NULL, M68K_REG_PC); uint32_t pc = m68k_get_reg(NULL, M68K_REG_PC);
if (pc == 0xc) if (pc == 0xc)
exit_error("address exception"); exit_error("address exception");
@ -219,6 +225,10 @@ void cpu_instr_callback()
#endif #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) static void emulated_syscall(void)
{ {
int s = m68k_get_reg(NULL, M68K_REG_D0); int s = m68k_get_reg(NULL, M68K_REG_D0);
@ -227,16 +237,57 @@ static void emulated_syscall(void)
case 1: /* exit */ case 1: /* exit */
exit(m68k_get_reg(NULL, M68K_REG_D1)); exit(m68k_get_reg(NULL, M68K_REG_D1));
case 4: /* write */ case 3: /* read */
{ {
uint32_t fd = m68k_get_reg(NULL, M68K_REG_D1); uint32_t fd = m68k_get_reg(NULL, M68K_REG_D1);
uint32_t ptr = m68k_get_reg(NULL, M68K_REG_D2); uint32_t ptr = m68k_get_reg(NULL, M68K_REG_D2);
uint32_t len = m68k_get_reg(NULL, M68K_REG_D3); uint32_t count = m68k_get_reg(NULL, M68K_REG_D3);
m68k_set_reg(M68K_REG_D0, write(fd, g_ram + transform_address(ptr), len)); m68k_set_reg(M68K_REG_D0, read(fd, g_ram + transform_address(ptr), count));
break; break;
} }
case 45: /* brk */ case 4: /* write */
{
uint32_t fd = m68k_get_reg(NULL, M68K_REG_D1);
uint32_t ptr = m68k_get_reg(NULL, M68K_REG_D2);
uint32_t len = m68k_get_reg(NULL, M68K_REG_D3);
m68k_set_reg(M68K_REG_D0, write(fd, g_ram + transform_address(ptr), len));
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); uint32_t newpos = m68k_get_reg(NULL, M68K_REG_D1);
if (newpos == 0) if (newpos == 0)
@ -251,8 +302,8 @@ static void emulated_syscall(void)
break; break;
} }
case 20: /* getpid */ case 20: /* getpid */
case 48: /* signal */ case 48: /* signal */
case 54: /* ioctl */ case 54: /* ioctl */
case 78: /* gettimeofday */ case 78: /* gettimeofday */
m68k_set_reg(M68K_REG_D0, 0); m68k_set_reg(M68K_REG_D0, 0);
@ -280,9 +331,9 @@ static void load_program(FILE* fd)
if (fread(g_ram, 1, phentsize, fd) != phentsize) if (fread(g_ram, 1, phentsize, fd) != phentsize)
exit_error("couldn't read program header"); exit_error("couldn't read program header");
uint32_t offset = READ_LONG(g_ram, 0x04); uint32_t offset = READ_LONG(g_ram, 0x04);
uint32_t vaddr = READ_LONG(g_ram, 0x08); uint32_t vaddr = READ_LONG(g_ram, 0x08);
uint32_t filesz = READ_LONG(g_ram, 0x10); uint32_t filesz = READ_LONG(g_ram, 0x10);
uint32_t memsz = READ_LONG(g_ram, 0x14); uint32_t memsz = READ_LONG(g_ram, 0x14);
brkbase = brkpos = vaddr + memsz; brkbase = brkpos = vaddr + memsz;
@ -310,11 +361,15 @@ int main(int argc, char* argv[])
load_program(fhandle); load_program(fhandle);
// disassemble_program(); //disassemble_program();
m68k_set_cpu_type(M68K_CPU_TYPE_68020); //printf("now at line %d\n", __LINE__);
m68k_init(); m68k_set_cpu_type(M68K_CPU_TYPE_68040);
m68k_pulse_reset(); //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. /* On entry, the Linux stack looks like this.
* *
@ -337,11 +392,13 @@ int main(int argc, char* argv[])
unsigned long argv = sp; unsigned long argv = sp;
cpu_write_long(sp -= 4, argv); cpu_write_long(sp -= 4, argv);
cpu_write_long(sp -= 4, 0); 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 ");
m68k_execute(100000); for (;;) {
m68k_execute(100000);
}
return 0; 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_pulse_reset(void);
void cpu_set_fc(unsigned int fc); void cpu_set_fc(unsigned int fc);
int cpu_irq_ack(int level); int cpu_irq_ack(int level);
void cpu_instr_callback(); void cpu_instr_callback(int pc);
#endif /* SIM__HEADER */ #endif /* SIM__HEADER */