GithubHelp home page GithubHelp logo

musashi's Introduction

                                    MUSASHI
                                    =======

                                  Version 4.10

             A portable Motorola M680x0 processor emulation engine.
            Copyright 1998-2002 Karl Stenerud.  All rights reserved.



INTRODUCTION:
------------

Musashi is a Motorola 68000, 68010, 68EC020, 68020, 68EC030, 68030, 68EC040 and
68040 emulator written in C.  This emulator was written with two goals in mind:
portability and speed.

The emulator is written to ANSI C89 specifications.  It also uses inline
functions, which are C9X compliant.

It has been successfully running in the MAME project (www.mame.net) for years
and so has had time to mature.



LICENSE AND COPYRIGHT:
---------------------

Copyright © 1998-2001 Karl Stenerud

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.



AVAILABILITY:
------------
The latest version of this code can be obtained at:
https://github.com/kstenerud/Musashi



CONTACTING THE AUTHOR:
---------------------
I can be reached at [email protected]



BASIC CONFIGURATION:
-------------------
The basic configuration will give you a standard 68000 that has sufficient
functionality to work in a primitive environment.

This setup assumes that you only have 1 device interrupting it, that the
device will always request an autovectored interrupt, and it will always clear
the interrupt before the interrupt service routine finishes (but could
possibly re-assert the interrupt).
You will have only one address space, no tracing, and no instruction prefetch.

To implement the basic configuration:

- Open m68kconf.h and verify that the settings for INLINE will work with your
  compiler. (Currently set to "static __inline__", which works in gcc 2.9.
  For C9X compliance, it should be "inline")

- In your host program, implement the following functions:
    unsigned int  m68k_read_memory_8(unsigned int address);
    unsigned int  m68k_read_memory_16(unsigned int address);
    unsigned int  m68k_read_memory_32(unsigned int address);
    void m68k_write_memory_8(unsigned int address, unsigned int value);
    void m68k_write_memory_16(unsigned int address, unsigned int value);
    void m68k_write_memory_32(unsigned int address, unsigned int value);

- In your host program, be sure to call m68k_pulse_reset() once before calling
  any of the other functions as this initializes the core.

- Use m68k_execute() to execute instructions and m68k_set_irq() to cause an
  interrupt.



ADDING PROPER INTERRUPT HANDLING:
--------------------------------
The interrupt handling in the basic configuration doesn't emulate the
interrupt acknowledge phase of the CPU and automatically clears an interrupt
request during interrupt processing.
While this works for most systems, you may need more accurate interrupt
handling.

To add proper interrupt handling:

- In m68kconf.h, set M68K_EMULATE_INT_ACK to OPT_SPECIFY_HANDLER

- In m68kconf.h, set M68K_INT_ACK_CALLBACK(A) to your interrupt acknowledge
  routine

- Your interrupt acknowledge routine must return an interrupt vector,
  M68K_INT_ACK_AUTOVECTOR, or M68K_INT_ACK_SPURIOUS.  most m68k
  implementations just use autovectored interrupts.

- When the interrupting device is satisfied, you must call m68k_set_irq(0) to
  remove the interrupt request.



MULTIPLE INTERRUPTS:
-------------------
The above system will work if you have only one device interrupting the CPU,
but if you have more than one device, you must do a bit more.

To add multiple interrupts:

- You must make an interrupt arbitration device that will take the highest
  priority interrupt and encode it onto the IRQ pins on the CPU.

- The interrupt arbitration device should use m68k_set_irq() to set the
  highest pending interrupt, or 0 for no interrupts pending.



SEPARATE IMMEDIATE READS:
------------------------
You can write faster memory access functions if you know whether you are
fetching from ROM or RAM.  Immediate reads are always from the program space
(Always in ROM unless it is running self-modifying code).

To enable separate immediate reads:

- In m68kconf.h, turn on M68K_SEPARATE_READ_IMM.

- In your host program, implement the following functions:
    unsigned int  m68k_read_immediate_16(unsigned int address);
    unsigned int  m68k_read_immediate_32(unsigned int address);

    Now you also have the pcrelative stuff:
    unsigned int  m68k_read_pcrelative_8(unsigned int address);
    unsigned int  m68k_read_pcrelative_16(unsigned int address);
    unsigned int  m68k_read_pcrelative_32(unsigned int address);

- If you need to know the current PC (for banking and such), set
  M68K_MONITOR_PC to OPT_SPECIFY_HANDLER, and set M68K_SET_PC_CALLBACK(A) to
  your routine.

- In the unlikely case where you need to emulate some PMMU in the immediate
  reads and/or pcrealtive stuff, you'll need to explicitely call the
  translation address mechanism from your user functions this way :

    if (PMMU_ENABLED)
        address = pmmu_translate_addr(address);

  (this is handled automatically by normal memory accesses).

ADDRESS SPACES:
--------------
Most systems will only implement one address space, placing ROM at the lower
addresses and RAM at the higher.  However, there is the possibility that a
system will implement ROM and RAM in the same address range, but in different
address spaces.

In this case, you might get away with assuming that immediate reads are in the
program space and all other reads are in the data space, if it weren't for the
fact that the exception vectors are fetched from the data space.  As a result,
anyone implementing this kind of system will have to copy the vector table
from ROM to RAM using pc-relative instructions.

This makes things bad for emulation, because this means that a non-immediate
read is not necessarily in the data space.
The m68k deals with this by encoding the requested address space on the
function code pins:

                       FC
    Address Space      210
    ------------------ ---
    USER DATA          001
    USER PROGRAM       010
    SUPERVISOR DATA    101
    SUPERVISOR PROGRAM 110
    CPU SPACE          111 <-- not emulated in this core since we emulate
                               interrupt acknowledge in another way.

To emulate the function code pins:

- In m68kconf.h, set M68K_EMULATE_FC to OPT_SPECIFY_HANDLER and set
  M68K_SET_FC_CALLBACK(A) to your function code handler function.

- Your function code handler should select the proper address space for
  subsequent calls to m68k_read_xx (and m68k_write_xx for 68010+).

Note: immediate reads are always done from program space, so technically you
      don't need to implement the separate immediate reads, although you could
      gain more speed improvements leaving them in and doing some clever
      programming.



USING DIFFERENT CPU TYPES:
-------------------------
The default is to enable only the 68000 cpu type.  To change this, change the
settings for M68K_EMULATE_010 etc in m68kconf.h.

To set the CPU type you want to use:

- Make sure it is enabled in m68kconf.h.  Current switches are:
    M68K_EMULATE_010
    M68K_EMULATE_EC020
    M68K_EMULATE_020

- In your host program, call m68k_set_cpu_type() and then call
  m68k_pulse_reset().  Valid CPU types are:
    M68K_CPU_TYPE_68000,
    M68K_CPU_TYPE_68010,
    M68K_CPU_TYPE_68EC020,
    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:
---------------
In order to emulate the correct clock frequency, you will have to calculate
how long it takes the emulation to execute a certain number of "cycles" and
vary your calls to m68k_execute() accordingly.
As well, it is a good idea to take away the CPU's timeslice when it writes to
a memory-mapped port in order to give the device it wrote to a chance to
react.

You can use the functions m68k_cycles_run(), m68k_cycles_remaining(),
m68k_modify_timeslice(), and m68k_end_timeslice() to do this.
Try to use large cycle values in your calls to m68k_execute() since it will
increase throughput.  You can always take away the timeslice later.



MORE CORRECT EMULATION:
----------------------
You may need to enable these in order to properly emulate some of the more
obscure functions of the m68k:

- M68K_EMULATE_BKPT_ACK causes the CPU to call a breakpoint handler on a BKPT
  instruction

- M68K_EMULATE_TRACE causes the CPU to generate trace exceptions when the
  trace bits are set

- M68K_EMULATE_RESET causes the CPU to call a reset handler on a RESET
  instruction.

- M68K_EMULATE_PREFETCH emulates the 4-word instruction prefetch that is part
  of the 68000/68010 (needed for Amiga emulation).
  NOTE: if the CPU fetches a word or longword at an odd address when this
  option is on, it will yield unpredictable results, which is why a real
  68000 will generate an address error exception.

- M68K_EMULATE_ADDRESS_ERROR will cause the CPU to generate address error
  exceptions if it attempts to read a word or longword at an odd address.

- call m68k_pulse_halt() to emulate the HALT pin.



CONVENIENCE FUNCTIONS:
---------------------
These are in here for programmer convenience:

- M68K_INSTRUCTION_HOOK lets you call a handler before each instruction.

- M68K_LOG_ENABLE and M68K_LOG_1010_1111 lets you log illegal and A/F-line
  instructions.



MULTIPLE CPU EMULATION:
----------------------
The default is to use only one CPU.  To use more than one CPU in this core,
there are some things to keep in mind:

- To have different cpus call different functions, use OPT_ON instead of
  OPT_SPECIFY_HANDLER, and use the m68k_set_xxx_callback() functions to set
  your callback handlers on a per-cpu basis.

- Be sure to call set_cpu_type() for each CPU you use.

- Use m68k_set_context() and m68k_get_context() to switch to another CPU.



LOAD AND SAVE CPU CONTEXTS FROM DISK:
------------------------------------
You can use them68k_load_context() and m68k_save_context() functions to load
and save the CPU state to disk.



GET/SET INFORMATION FROM THE CPU:
--------------------------------
You can use m68k_get_reg() and m68k_set_reg() to gain access to the internals
of the CPU.



EXAMPLE:
-------

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\"

musashi's People

Contributors

aaronsgiles avatar agentbooth avatar angelosa avatar arnaudcarre avatar bebbo avatar bsdphk avatar dfawcus avatar domesticmouse avatar emoon avatar jotd666 avatar kernigh avatar kstenerud avatar marhel avatar philpem avatar rb6502 avatar stevekwok avatar tyfkda avatar zelurker avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

musashi's Issues

m68k_pulse_reset(), make boot PC + SSP optional

In some cases, such as when not emulating an actual system but e g providing userland emulation for 68k stuff, it may be beneficial to skip the boot PC + SSP (address 0 + address 4) sequence in m68kk_pulse_reset().

It would be neat if this could be optional (but perhaps enabled by default), e g:

#ifdef M68K_RESET_PC_SSP
/* Read the initial stack pointer and program counter */
m68ki_jump(0);
REG_SP = m68ki_read_imm_32();
REG_PC = m68ki_read_imm_32();
m68ki_jump(REG_PC);
#endif

Wasm port

Hi, i'm making a web editor to write code in m68k and MIPS online and run client side for a university project , i was searching a interpreter/emulator for m68k and found this, i was wondering if anyone has an idea if it's possibile to port this to WASM/emscripten/asm.js. I would give it a shot myself but i'm not really keen on C and wasm so before i try, i wanted to know if it was doable. I dont need graphics or floating point math etc, just need the simple instructions

CHK instruction, N flag

I’ve started to run Toni Wilen’s 'cputester' in vAmiga.

Toni's test CHK.W fails due to a wrong value of the N flag if an exception happens.

Musashi sets the N flag as follows:

FLAG_N = (src < 0)<<7;

The correct logic of CHK <ea>,Dn seems to be:

IF ([Dn] > [ea]) N := 'Negative-bit of Dn' ELSE IF ([Dn] < 0) N := 1

useless & CPU intensive operation could be avoided

at line 982 of m68kcpu.c there's this loop

		/* Record previous D/A register state (in case of bus error) */
		for (i = 15; i >= 0; i--){
			REG_DA_SAVE[i] = REG_DA[i];
		}

problem is: it's executed at each instruction. Its purpose is to save data & address registers in case of a bus error as the comment states.

But it's not used anywhere else (the da_save data is only written), so I suppose that's a feature for a monitor or something. The fact that at EACH instruction, the CPU copies 32*8 bytes of memory certainly hinders performance.

I suggest to add a configuration macro to enable it only if needed (who has bus errors in a working app anyway ?)

[BUG] X flag of ASR and LSR

Hi Karl,

The document says "The X-bit is set to the last bit shifted out of the operand and is
equal to the C-bit. However, a zero shift count leaves the X-bit
unaffected and the C-bit cleared."

The current implementation of Musashi certainly clears the X flag when shift count is zero (when it is stored in a data register).

FLAG_X = FLAG_C = src << (9-shift);

It should be like the following

FLAG_C = src << (9-shift);
if (shift)
{
    FLAG_X = FLAG_C;
}

I'm sorry for creating this issue instead of making a pull request.

Regards,
Steve

Incorrect used clocks returned by m68k_execute(int num_cycles) after a call to m68k_end_timeslice(void)

I have noticed that the number of used clocks is incorrectly calculated by int m68k_execute(int num_cycles) (in m68kcpu.c) once a call is made to void m68k_end_timeslice(void) during the call to m68k_execute.
The proposed solution would be to change:

void m68k_end_timeslice(void)
{
	m68ki_initial_cycles = GET_CYCLES();
	SET_CYCLES(0);
}

into:

void m68k_end_timeslice(void)
{
	m68ki_initial_cycles -= GET_CYCLES();
	SET_CYCLES(0);
}

(please note -= in stead of =)

Best regards, elmerucr

Disassembler: Incorrect disassembly of mnemonics

In 68020 mode, and maybe others too, the assemble is incorrectly disassembling some instructions. Using as an example the following code in ROM, the assembler reports the assembled code as:

F00:0330       	MOVE.L	#vector_table, A0                 ; Destination address
               S03:FFFFFFFFFFFF0200:  91 C8
F00:0331       	MOVE.L	#bios_address, A1                 ; Source address
               S03:FFFFFFFFFFFF0202:  22 7C FF FF 00 00
F00:0332       	MOVE.W	#$3F, D0                          ; Number of system vectors minus one
               S03:FFFFFFFFFFFF0208:  30 3C 00 3F
F00:0333       init_sysvectors
F00:0334       	MOVE.L	(A1)+, (A0)+                      ; Move data
               S03:FFFFFFFFFFFF020C:  20 D9
F00:0335       	DBF	D0, init_sysvectors
               S03:FFFFFFFFFFFF020E:  51 C8 FF FC
F00:0336       	                                          ; Set all user vectors to 'Unknown Exception' handler
F00:0337       	MOVE.W	#$BF, D0                          ; Number of user vectors minus one
               S03:FFFFFFFFFFFF0212:  30 3C 00 BF
F00:0338       init_uservectors
F00:0339       	MOVE.L	#unknown_exception, (A0)+         ; Move data
               S03:FFFFFFFFFFFF0216:  20 FC FF FF 07 34
F00:0340       	DBF	D0, init_uservectors
               S03:FFFFFFFFFFFF021C:  51 C8 FF F8
F00:0341       
F00:0342       	MOVE.W	#$3F, D0                          ; Number of words minus one
               S03:FFFFFFFFFFFF0220:  30 3C 00 3F

In each case the generated output is on the line immediately after the line being assembled. This is written to an ROM being emulated in an emulator with the corresponding section of the ROM having the following hexdump:

00000200 - 91 C8 22 7C FF FF 00 00 30 3C 00 3F 20 D9 51 C8 .."|....0<.? .Q.
00000210 - FF FC 30 3C 00 BF 20 FC FF FF 07 34 51 C8 FF F8 ..0<.. ....4Q...
00000220 - 30 3C 00 3F

The m68kdasm module disassembles this as:

    FFFF0200: dc.w $00c8; ILLEGAL
    FFFF0202: ori     #$ff, SR
    FFFF0206: ori.b   #$3c, D0
    FFFF020A: dc.w $003f; ILLEGAL
    FFFF020C: dc.w $00d9; ILLEGAL
    FFFF020E: dc.w $00c8; ILLEGAL
    FFFF0210: dc.w $00fc; ILLEGAL
    FFFF0212: ori     #$bf, CCR
    FFFF0216: dc.w $00fc; ILLEGAL
    FFFF0218: dc.w $00ff; ILLEGAL
    FFFF021A: ori.b   #$c8, (-$8,A4,D0.w)
    FFFF0220: ori     #$3f, CCR

There is some similarity suggesting it is looking at the right region in memory but seems to be getting the instruction mnemonics completely wrong.

Bitfield mask for 5th byte is wrong

The instruction
bfset mem{1:32}

writes 32 bits 0x7fffffff and then 8 bits of a fifth byte with 0xff while it should be writing 0x80 (only the last missing bit from the first 32 bit write).

The problem is in m68k_in.c at:

    mask_base = MASK_OUT_ABOVE_32(0xffffffff << (32 - width));
  ...
    if((width + offset) > 32)
    {
        mask_byte = MASK_OUT_ABOVE_8(mask_base);
   ...
        m68ki_write_8((mc68kcpu), ea+4, data_byte | mask_byte);
    }

The mask_byte imho needs to be generated like this:
mask_byte = MASK_OUT_ABOVE_8(mask_base) << (8-offset);

This fix is not tested as i am actually not working on Musashi but instead tried to use Musashi to verify another core.

SUB.B / SUB.W timing mismatch

Instructions: sub.b #$0, D0, sub.w #$0, D0

Test case: sub1

https://github.com/dirkwhoffmann/vAmigaTS/tree/master/CPU/SUB/sub1

Musashi (vAmiga):

sub1_vAmiga

A real Amiga 500+ 🥰:

sub1_A500+

Conclusion:

	{m68k_op_sub_8_er_i          , 0xf1ff, 0x903c, { 10,   8,   4,   4}},
	{m68k_op_add_8_er_i          , 0xf1ff, 0xd03c, { 10,   8,   4,   4}},

	{m68k_op_add_16_er_i         , 0xf1ff, 0xd07c, { 10,   8,   4,   4}},
	{m68k_op_sub_16_er_i         , 0xf1ff, 0x907c, { 10,   8,   4,   4}},

must be:

	{m68k_op_sub_8_er_i          , 0xf1ff, 0x903c, { 8,   8,   4,   4}},
	{m68k_op_add_8_er_i          , 0xf1ff, 0xd03c, { 8,   8,   4,   4}},

	{m68k_op_add_16_er_i         , 0xf1ff, 0xd07c, { 8,   8,   4,   4}},
	{m68k_op_sub_16_er_i         , 0xf1ff, 0x907c, { 8,   8,   4,   4}},

Tagging releases

Would it be possible for you to tag releases please? It's really helpful for dependency management so instead of saying I require Musashi, I can say we build against version 3.3, and when 3.4 is released I can test run a build with that knowing if I need to do any work to integrate.

BTST and BCLR with immediate word address gives wrong address

I'm not sure if I'm doing something wrong but I was trying to run a program with the 2 following op codes and I'm getting the wrong address.

0838 0004 fa01 BTST #4,$0000fa01
08b8 0006 fa11 BCLR #6,$0000fa11

The address is a 16 bit word immediate constant.
I'm getting an 8 bit read from $fffa01 and $fffa11

After looking through the Musashi code I noticed that its using a function called:
EA_AW_8()
which in turn calls:
MAKE_INT_16()

This routine is changing the address into a signed number when I'm sure is should be unsigned, unless I have done something wrong.

% instead of & in the write byte define in the example application.

I noticed this ages ago but I only just noticed that you had pushed musashi to github. There is an issue with the example application:

example/sim.c:37

define WRITE_BYTE(BASE, ADDR, VAL) (BASE)[ADDR] = (VAL)%0xff

I presume that % is meant to be an &. This causes some really weird and hard to debug issues. :)

Disassembler inconsistency

The disassembler produces

movep.w ($ffff,A0), D0

To make it consistent with the other instructions, it should be changed to:

movep.w ($-1,A0), D0

Long Double Constant assigned to Double breaks Win Compile

When compiling with Visual Studio:

musashi/m68kfpu.c(775): error C2177: constant too big
musashi/m68kfpu.c(776): error C2177: constant too big
musashi/m68kfpu.c(777): error C2177: constant too big
musashi/m68kfpu.c(778): error C2177: constant too big

The long double constants can't be assigned to a double with loosing precision.

Bug in MOVEC implementation

This code is part of m68k_op_movec_32_cr

			case 0x802:			   /* CAAR */
				if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
				{
					REG_DA[(word2 >> 12) & 15] = REG_CAAR;
					return;
				}
				m68ki_exception_illegal();
				break;

In the last line, break needs to be replaced by return. Otherwise, a privilege exception is executed in addition to the illegal exception.

FPU support?

I notice that the version of Musashi in mame has support for more architectures, and the FPU; are there any plans to import that version here? (I'm using the emulator to run compiler tests, and some of them use floating point.)

Negligible documentation error

To quote readme.txt:

M68K_EMULATE_PREFETCH emulates the 4-word instruction prefetch

That should probably be either:

  • 2-word instruction prefetch; or
  • 4-byte instruction prefetch.

I didn't look into it especially thoroughly, but I noted you use uint pref_data so I'm very confident this is just a documentation typo.

Possible buggy MOVE emulation

Hi crews,

I detected a bug in the emulation of the following instruction:

move $358.W, $46(A0)

Judging by the corresponding opcode 0x2178/0x358/0x0046, it's emulated by this macro:

Musashi/m68k_in.c

Lines 6475 to 6486 in fc7a6fc

M68KMAKE_OP(move, 32, di, .)
{
uint res = M68KMAKE_GET_OPER_AY_32;
uint ea = EA_AX_DI_32();
m68ki_write_32(ea, res);
FLAG_N = NFLAG_32(res);
FLAG_Z = res;
FLAG_V = VFLAG_CLEAR;
FLAG_C = CFLAG_CLEAR;
}

It looks like the above macro always grabs a DWORD from the absolute address $358 but it should actually be a WORD:
m68k MOVE opcode format

OPCODE = 0x2178 = %0010.000.101.111.000
size = %10 aka LONG
DST MODE=%101 aka (d16, An)
DST REG = 0 aka A0
SRC MODE = %111 --> (xxx).w or (xxx).l
SRC REG = 0 --> (xxx).w

The semantic of the said instruction is as follows: it should grab a WORD at $358, extend it to a DWORD and write the result to the destination.
The difference between absolute WORD and DWORD operands is specified in the SRC REG field and should be taken into account during the emulation.

I discovered this problem indirectly by using the bare68k Python emulator. I can't change its code because the accompanying Python project doesn't build. My bug report is therefore based on assumptions/results I'm getting with bare68k.

Please correct me if I'm wrong...

DIVU / DIVS: N flag is wrong

Sorry to bother you again. This time, I have tested DIVU and DIVS and encountered an issue with the N flag.

Test cases divu5:
https://github.com/dirkwhoffmann/vAmigaTS/tree/master/CPU/DIV/divu5

This test case creates some alien art by performing divisions with certain operands 👽:

divu5_A500+

Good news: Musashi performs all calculations correctly 🖖:

Bildschirmfoto 2019-12-29 um 09 37 38

Test case divu6:
https://github.com/dirkwhoffmann/vAmigaTS/tree/master/CPU/DIV/divu6

This test case visualises the value of the V flag (left) and the N flag (right). Solid means „flag set“, striped means „flag cleared“.

divu6_A500+

Musashi gets the N flag wrong:

divu6_vAmiga

I know that some references state that the N flag remains untouched when an overflow occurs, but the test case falsifies this statement. The test case shows that the N flag is set together with the V flag when an overflow happens.

I’ve set up similar test cases for DIVS, too. The issue is the same there.

Issues with NBCD instruction

The implementation of NBCD doesn’t seem to be correct.

To verify this instruction, I’ve written four test cases:

https://github.com/dirkwhoffmann/vAmigaTS/tree/master/CPU/NBCD

nbcd1

Draws two 16 x 16 squares. In each square, the NBCD command is run for all 256 possible source values. The left square has the X flag cleared and the right square set. Each 8 x 8 pixel box shows the bit pattern of value computed by the instruction under test.

nbcd2

Displays the value of the N flag after NBCD has been executed.

nbcd3

Displays the value of the V flag after NBCD has been executed.

nbcd4

Displays the value of the X,Z, and V flag after NBCD has been executed.

Here are the results:

Musashi (vAmiga):

Bildschirmfoto 2019-12-25 um 10 18 34

A real Amiga (A500+ 🥰):

nbcd1_A500+

The left image (NBCD executed with X = 0) seems to be correct. The right image differs.

The flags show discrepancies, too:

Musashi (vAmiga):

Bildschirmfoto 2019-12-25 um 10 22 17

Bildschirmfoto 2019-12-25 um 10 21 15

Bildschirmfoto 2019-12-25 um 10 21 39

A500+:

nbcd2_A500+
nbcd3_A500+
nbcd4_A500+

I've also run the test cases in UAE. As far as I could see, UAE does it right. I didn't look into the UAE code yet, but it might help to fix the instruction.

License has been changed?

Hi, I've noticed that the license of Musashi has been changed. I wonder if it's OK to use Musashi in a commercial product now?

SUB.L timing mismatch

Instruction: sub.l D0,D0

Test case: sub2

https://github.com/dirkwhoffmann/vAmigaTS/tree/master/CPU/SUB/sub2

Musashi (vAmiga):

sub2_vAmiga

A real Amiga 500+ 🥰:

sub2_A500+

Conclusion:

	{m68k_op_sub_32_er_d         , 0xf1f8, 0x9080, {  6,   6,   2,   2}},
	{m68k_op_sub_32_er_a         , 0xf1f8, 0x9088, {  6,   6,   2,   2}},
	{m68k_op_add_32_er_d         , 0xf1f8, 0xd080, {  6,   6,   2,   2}},
	{m68k_op_add_32_er_a         , 0xf1f8, 0xd088, {  6,   6,   2,   2}},

must be:

	{m68k_op_sub_32_er_d         , 0xf1f8, 0x9080, {  8,   6,   2,   2}},
	{m68k_op_sub_32_er_a         , 0xf1f8, 0x9088, {  8,   6,   2,   2}},
	{m68k_op_add_32_er_d         , 0xf1f8, 0xd080, {  8,   6,   2,   2}},
	{m68k_op_add_32_er_a         , 0xf1f8, 0xd088, {  8,   6,   2,   2}},

I cannot say anything reliable about 68010 timing though.

CHK2 instructions use signed, not unsigned

the code for CHK2 is incorrect. It "works" for bounds like 0 => 10 for instance. But as soon as sign comes into play it fails.

I have an application that performs sanity checks and it fails with the original code. It works perfectly on the real board of course, and also with Basilisk/WinUAE core. Ex: chk2.w where the bounds are -1 => 10 ($FFFF => $A). Of course, treating lower bound as unsigned short fails big time.

Problem in musashi is that lower & upper bound tests should just be read into signed types, and tested as such. It makes the testing code less complicated and compliant to 1) winuae code 2) motorola specs.

Recent bogus cycle count PR

Hi, I’m trying to understand the recent PR to fix bogus cycle counts being reported.
I can’t workout from the comment how to reproduce the sawtooth effect described.
Can someone explain please?

It looks like it’s to correct the cycles reported when m68k_end_timeslice() is used ?
But I think it breaks the value reported when m68k_modify_timesclice() is used.
Would a better fix be to change m68k_end_timeslice() from
m68ki_initial_cycles = CYCLES(); to
m68ki_initial_cycles -= CYCLES();?

sorry if I’ve completely misunderstood what it’s fixing

Opcodes $60FF, $61FF, $F518

More findings:

  • Opcode $60FF:

    In 68000 mode, opcode $60FF disassembles to ILLEGAL, because this bit bittern marks the BRA 32-bit-displacement instruction on the 68020+. On the 68000/68010, it should execute a BRA with a byte-displacement of $FF, I think.

The emulation code does the right thing. Hence, only the disassembler output is wrong.

static void m68k_op_bra_32(void)
{
	if(CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
	{
	...
	}
	else
	{
		m68ki_trace_t0();				   /* auto-disable (see m68kcpu.h) */
		m68ki_branch_8(MASK_OUT_ABOVE_8(REG_IR));
		if(REG_PC == REG_PPC)
			USE_ALL_CYCLES();
	}
}
  • Opcode $61FF: Same as $60FF, just for BSR.

  • Opcode $f518: (PFLUSH on 68040+)

static void m68k_op_pflush_32(void)
{
	if(CPU_TYPE_IS_040_PLUS(CPU_TYPE))
	{
		// Nothing to do, unless address translation cache is emulated
		return;
	}
         m68ki_exception_illegal();
}

On models 68030-, this opcode should trigger a line F exception (m68ki_exception_1111), not an illegal exception (m68ki_exception_illegal).

Issues compiling the latest version on macOS

Greetings,

first of all, I want to thank you for writing this awesome m68k emulator. I am using it with great success in a new Amiga emulator called vAmiga.

https://github.com/dirkwhoffmann/vAMIGA

To be honest, I'm not sure if I had started vAmiga at all if I hadn't found this core.

I'm developing on macOS and had no problems compiling Musashi until now. Unfortunately, I encountered problems when trying to update to the latest version (the head revision on the master branch).

My main issue is a linker problem. Xcode refuses to build the project now (I am using Musashi inside a C++ project).

Bildschirmfoto 2019-11-03 um 10 57 13

While comparing the old code with the new code, I notice the following difference: The old m68kops.h contained declarations for all functions of the opcode handler:

…
void m68k_op_unpk_16_rr(void);
void m68k_op_unpk_16_mm_ax7(void);
void m68k_op_unpk_16_mm_ay7(void);
void m68k_op_unpk_16_mm_axy7(void);
void m68k_op_unpk_16_mm(void);
/* Build the opcode handler table */
void m68ki_build_opcode_table(void);

extern void (*m68ki_instruction_jump_table[0x10000])(void); /* opcode handler jump table */
extern unsigned char m68ki_cycles[][0x10000];

The latest m68kmake doesn’t seem to create these declarations any more:

#ifndef M68KOPS__HEADER
#define M68KOPS__HEADER

/* ======================================================================== */
/* ============================ OPCODE HANDLERS =========================== */
/* ======================================================================== */


/* Build the opcode handler table */
void m68ki_build_opcode_table(void);

extern void (*m68ki_instruction_jump_table[0x10000])(void); /* opcode handler jump table */
extern unsigned char m68ki_cycles[][0x10000];


/* ======================================================================== */
/* ============================== END OF FILE ============================= */
/* ======================================================================== */

#endif /* M68KOPS__HEADER */

In addition, I stumbled across the following (minor) issues:

  1. Xcode produces warnings about uninitialised variables:

Bildschirmfoto 2019-11-03 um 10 49 31

All warnings are due to the usage of fatalerror() which terminates the execution branch (which my compiler doesn’t recognise).

  1. File m68kfpu.c

My compiler breaks here, because it doesn’t recognise the INLINE keyword (m68kcpu.h is not included in this file)

Hope this is useful!

FPU instructions missing parts & bugs

There are quite a few errors/missing stuff in the FPU module. I have corrected the ones that prevented me to run my app.

  • fatalerror message fprintf => vfprintf
  • added address register + displacement mode (mode 5, READ_EA_FPE/WRITE_EA_FPE), also changed prototype to it can be called with this mode
    from FMOVEM loop
  • added immediate mode (READ_EA_FPE)
  • fpgen_rm_reg (FMOVE to register): added a lot of missing condition code update (SET_CONDITION_CODES(REG_FP[dst]))
  • added FSDIVS and FSMULS (easy as it's the same case as FDIV and FMUL). Updated condition codes for FDIV
  • fmove_fpcr: connected softfloat 4 rounding modes to this instruction, that didn't set rounding at all, when it's
    perfectly emulated in softfloat module (just added: float_rounding_mode = (REG_FPCR >> 4) & 0x3;)
  • fmovem: added address register+displacement mode (READ_EA_FPE/WRITE_EA_FPE interface had to be changed)
  • added FScc instruction

here's the fixed file:

m68kfpu.zip

Instruction timing mismatch

In order to test vAmiga (which is powered by Musashi), I started to write some basic CPU timing tests:

https://github.com/dirkwhoffmann/vAmigaTS/tree/master/CPU/ANDI/andi1
https://github.com/dirkwhoffmann/vAmigaTS/tree/master/CPU/BCHG/bchg1

Here is how test "and1" looks like in vAmiga (using Musashi):

Bildschirmfoto 2019-12-24 um 11 14 08

Explanation:

Blue area: The Copper is used to trigger an interrupt.
Red area: The interrupt handler takes over.
Yellow area: The instruction under test is executed several times.

Lines:
1 and 2: Several NOPs are executed to generate reference timelines.
3: andi.l #$80008010,D0 is executed 8 times.
4: ori.l #$80008010,D0 is executed 8 times.
5: andi.w #$8010,D0 is executed 8 times.
6: ori.w #$8010,D0 is executed 8 times.

The picture shows that Musashi consumes 14 cycles for andi.l (which is wrong) and 16 cycles for ori.l (which is correct).

Here is how the test looks on the real machine (andi.l and ori.l both consume 16 cycles).

andi1_A500+

Hence, line

andi      32  .     d     0000001010000...  ..........  U U U U U  14  14   2   2   2

should be replaced by

andi      32  .     d     0000001010000...  ..........  U U U U U  16  14   2   2   2

There is another mismatch for commands BCHG and BCLR. These consume two cycles less if the bit number is smaller than $10:

bchg1_A500+

Lines:
1 and 2: NOPs are executed to generate reference timelines.
3: bchg d0,d0 with d0 == $0 is executed several times.
4: bchg d0,d0 with d0 == $10 is executed several times.

The latter issue might be hard to fix, because I understand that Musashi is reading the cycle counts from a table that has a single row for each instruction and addressing mode. Apparently, for some commands, the cycle counts depend on the operands, too.

AND.L / OR.L timing mismatch

Tested: or.l D0, D0

Test case: https://github.com/dirkwhoffmann/vAmigaTS/tree/master/CPU/OR/or2

Musashi (vAmiga):

Bildschirmfoto 2019-12-26 um 13 32 40

A real Amiga 500+ 🥰:

or2_A500+

Conclusion:

Current:

{m68k_op_and_32_er_d         , 0xf1f8, 0xc080, {  6,   6,   2,   2}},
{m68k_op_or_32_er_d          , 0xf1f8, 0x8080, {  6,   6,   2,   2}},

Correct:

{m68k_op_and_32_er_d         , 0xf1f8, 0xc080, {  8,   6,   2,   2}},
{m68k_op_or_32_er_d          , 0xf1f8, 0x8080, {  8,   6,   2,   2}},

I cannot say anything about the 68010 timing, because I don’t have a real 68010 CPU available.

ADDA instruction with post-increment stack register operands (and possibly pre-decrement)

I spent this evening creating a board simulation for the 68 Katy computer (http://www.bigmessowires.com/category/68katy/) and booting the "monitor-plus-linux-pcb.bin" uClinux image. There was an issue in the exception handling return code where the stack was off by 4 bytes versus delivery. I narrowed it down to the following instruction on the "ret_from_exception" path which appears to behave incorrectly:

00005552: dfdf                 adda.l  (A7)+, A7

According to http://www.verycomputer.com/154_d3e3e1d2b2176a76_1.htm this case is well-defined and with a slight alteration to "m68k_op_adda_32_pi" (please excuse the hack!) I was able to boot the uClinux image successfully, i.e.

M68KMAKE_OP(adda, 32, ., .)
{
    uint* r_dst = &AX;

    *r_dst = MASK_OUT_ABOVE_32(*r_dst + M68KMAKE_GET_OPER_AY_32);

    if (REG_IR == 0xdfdf)
            *r_dst += 4;
}

I expect the pre-decrement form to also be affected.

SoftFloat License

I have decided to incorporate Musashi into one of my projects. The main codebase seems to be MIT, but the SoftFloat licensing seems to be some custom license that is effectively a BSD or MIT style license, but with some terms that are slightly awkward:
https://github.com/kstenerud/Musashi/blob/master/softfloat/README.txt#L58

Have these terms ever posed problems for Linux/BSD distributions that distribute software containing Musashi?

Is it feasible/desirable to update SoftFloat to a newer release, which has the 3 Clause BSD license rather than the custom one?
http://www.jhauser.us/arithmetic/SoftFloat.html

Further research suggests this version of SoftFloat is not compatible with the GPL (not an issue for me but perhaps for others):
https://wiki.qemu.org/Features/SoftFloatRelicensing

This is the where it was added it to the codebase:
#53

Undefined behaviour

Under some circumstances, Musashi uses too large bit-shift values. This results in undefined behaviour.

This is what the UndefinedBehaviorSanitizer (which is part of clang) reports:

Bildschirmfoto 2020-01-10 um 18 33 03

Bildschirmfoto 2020-01-10 um 18 33 39

Bildschirmfoto 2020-01-10 um 18 34 27

The problem with undefined behaviour shouldn't be underestimated, because some modern compilers (such as clang) make use of it to aggressively optimise code. Code with undefined behaviour can behave differently when compiled with "clang -O0" or "clang -O1", respectively (even on the same machine).

branch_8 and branch_16 dont call pc changed

I can see branch_8 and branch_16 dont call pc changed

I'm looking to be able to tell when the PC had reached a certain point, by checking pc in cpu_instr_callback i catch most cases except jumps, (by looking ahead pc+instruction size) and I was hoping the pc callback would let me catch the address when jumped to....

For now I've added the calls to 16/8 branches on my own copy, but what impact might this have for more advanced 68k's with some kind of more advanced "mmu" code relying on pc changed for only for branch_32

example program.bin corrupted

Hi,

don't know why nobody noticed that, but it seems that the example program.bin is corrupted.
The reset vector is 0xC1, it should be 0xC0.

Regards,
G

ADDQ timing is wrong if destination is an address register

Command ADDQ.w ##, An consumes 4 cycles in Musashi, but 8 cycles on a real machine.

Line

{m68k_op_addq_16_a , 0xf1f8, 0x5048, { 4, 4, 2, 2}},

must be:

{m68k_op_addq_16_a , 0xf1f8, 0x5048, { 8, 4, 2, 2}},

Instruction SUBQ is fine, only ADDQ is affected.

My test case is located here:

https://github.com/dirkwhoffmann/vAmigaTS/tree/master/CPU/ADDQ/addq1

The last line in the test picture visualises the timing properties of addq.w with an address register as destination:

Musashi (vAmiga):

Bildschirmfoto 2019-12-26 um 11 34 23

A real Amiga 500+ 🥰:

addq1_A500+

Documentation change

It would be helpful if the documentation mentioned the requirement to call m68k_init()

Disassembler bug in get_ea_mode_str

This code fragment always truncates variable outer to 16 bit:

				if(outer)
				{
					if(comma)
						strcat(mode, ",");
					strcat(mode, make_signed_hex_str_16(outer));
				}
				strcat(mode, ")");

I think it should be something like this:

				if(outer)
				{
					if(comma)
						strcat(mode, ",");
				        if (EXT_OUTER_DISPLACEMENT_LONG(extension)) {
				                strcat(mode, make_signed_hex_str_32(outer));
				        } else {
				                strcat(mode, make_signed_hex_str_16(outer));
				        }
				}
				strcat(mode, ")");

Disassembler: Buffer overflow warnings reported by gcc 9.1.0

Compiling Musahi with gcc 9.1.0 gives warning about potential string overflows as follows:

  CC       musahi/b_em-m68kdasm.o
musahi/m68kdasm.c: In function ‘d68020_link_32’:
musahi/m68kdasm.c:385:18: warning: ‘%s’ directive writing up to 19 bytes into a region of size 14 [-Wformat-overflow=]
  372 |  return str;
      |         ~~~       
......
  385 |   sprintf(str, "#%s", make_signed_hex_str_32(read_imm_32()));
      |                  ^~
musahi/m68kdasm.c:385:3: note: ‘sprintf’ output between 2 and 21 bytes into a destination of size 15
  385 |   sprintf(str, "#%s", make_signed_hex_str_32(read_imm_32()));
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
musahi/m68kdasm.c: In function ‘d68000_stop’:
musahi/m68kdasm.c:383:18: warning: ‘%s’ directive writing up to 19 bytes into a region of size 14 [-Wformat-overflow=]
  356 |  return str;
      |         ~~~       
......
  383 |   sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16()));
      |                  ^~
musahi/m68kdasm.c:383:3: note: ‘sprintf’ output between 2 and 21 bytes into a destination of size 15
  383 |   sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16()));
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
musahi/m68kdasm.c: In function ‘d68000_link_16’:
musahi/m68kdasm.c:383:18: warning: ‘%s’ directive writing up to 19 bytes into a region of size 14 [-Wformat-overflow=]
  356 |  return str;
      |         ~~~       
......
  383 |   sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16()));
      |                  ^~
musahi/m68kdasm.c:383:3: note: ‘sprintf’ output between 2 and 21 bytes into a destination of size 15
  383 |   sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16()));
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
musahi/m68kdasm.c: In function ‘d68010_rtd’:
musahi/m68kdasm.c:383:18: warning: ‘%s’ directive writing up to 19 bytes into a region of size 14 [-Wformat-overflow=]
  356 |  return str;
      |         ~~~       
......
  383 |   sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16()));
      |                  ^~
musahi/m68kdasm.c:383:3: note: ‘sprintf’ output between 2 and 21 bytes into a destination of size 15
  383 |   sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16()));
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
musahi/m68kdasm.c: In function ‘d68020_cpbcc_32’:
musahi/m68kdasm.c:383:18: warning: ‘%s’ directive writing up to 19 bytes into a region of size 14 [-Wformat-overflow=]
  356 |  return str;
      |         ~~~       
......
  383 |   sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16()));
      |                  ^~
musahi/m68kdasm.c:383:3: note: ‘sprintf’ output between 2 and 21 bytes into a destination of size 15
  383 |   sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16()));
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
musahi/m68kdasm.c: In function ‘d68020_cpbcc_16’:
musahi/m68kdasm.c:383:18: warning: ‘%s’ directive writing up to 19 bytes into a region of size 14 [-Wformat-overflow=]
  356 |  return str;
      |         ~~~       
......
  383 |   sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16()));
      |                  ^~
musahi/m68kdasm.c:383:3: note: ‘sprintf’ output between 2 and 21 bytes into a destination of size 15
  383 |   sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16()));
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
musahi/m68kdasm.c: In function ‘d68020_cpdbcc’:
musahi/m68kdasm.c:383:18: warning: ‘%s’ directive writing up to 19 bytes into a region of size 14 [-Wformat-overflow=]
  356 |  return str;
      |         ~~~       
......
  383 |   sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16()));
      |                  ^~
musahi/m68kdasm.c:383:3: note: ‘sprintf’ output between 2 and 21 bytes into a destination of size 15
  383 |   sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16()));
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
musahi/m68kdasm.c: In function ‘d68000_subi_32’:
musahi/m68kdasm.c:385:18: warning: ‘%s’ directive writing up to 19 bytes into a region of size 14 [-Wformat-overflow=]
  372 |  return str;
      |         ~~~       
......
  385 |   sprintf(str, "#%s", make_signed_hex_str_32(read_imm_32()));
      |                  ^~
musahi/m68kdasm.c:385:3: note: ‘sprintf’ output between 2 and 21 bytes into a destination of size 15
  385 |   sprintf(str, "#%s", make_signed_hex_str_32(read_imm_32()));
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
musahi/m68kdasm.c: In function ‘d68000_subi_16’:
musahi/m68kdasm.c:383:18: warning: ‘%s’ directive writing up to 19 bytes into a region of size 14 [-Wformat-overflow=]
  356 |  return str;
      |         ~~~       
......
  383 |   sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16()));
      |                  ^~
musahi/m68kdasm.c:383:3: note: ‘sprintf’ output between 2 and 21 bytes into a destination of size 15
  383 |   sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16()));
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
musahi/m68kdasm.c: In function ‘d68000_subi_8’:
musahi/m68kdasm.c:381:18: warning: ‘%s’ directive writing up to 19 bytes into a region of size 14 [-Wformat-overflow=]
  340 |  return str;
      |         ~~~       
......
  381 |   sprintf(str, "#%s", make_signed_hex_str_8(read_imm_8()));
      |                  ^~
musahi/m68kdasm.c:381:3: note: ‘sprintf’ output between 2 and 21 bytes into a destination of size 15
  381 |   sprintf(str, "#%s", make_signed_hex_str_8(read_imm_8()));
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
musahi/m68kdasm.c: In function ‘d68020_cmpi_pcix_32’:
musahi/m68kdasm.c:385:18: warning: ‘%s’ directive writing up to 19 bytes into a region of size 14 [-Wformat-overflow=]
  372 |  return str;
      |         ~~~       
......
  385 |   sprintf(str, "#%s", make_signed_hex_str_32(read_imm_32()));
      |                  ^~
musahi/m68kdasm.c:385:3: note: ‘sprintf’ output between 2 and 21 bytes into a destination of size 15
  385 |   sprintf(str, "#%s", make_signed_hex_str_32(read_imm_32()));
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
musahi/m68kdasm.c: In function ‘d68000_cmpi_32’:
musahi/m68kdasm.c:385:18: warning: ‘%s’ directive writing up to 19 bytes into a region of size 14 [-Wformat-overflow=]
  372 |  return str;
      |         ~~~       
......
  385 |   sprintf(str, "#%s", make_signed_hex_str_32(read_imm_32()));
      |                  ^~
musahi/m68kdasm.c:385:3: note: ‘sprintf’ output between 2 and 21 bytes into a destination of size 15
  385 |   sprintf(str, "#%s", make_signed_hex_str_32(read_imm_32()));
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
musahi/m68kdasm.c: In function ‘d68020_cmpi_pcdi_16’:
musahi/m68kdasm.c:383:18: warning: ‘%s’ directive writing up to 19 bytes into a region of size 14 [-Wformat-overflow=]
  356 |  return str;
      |         ~~~       
......
  383 |   sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16()));
      |                  ^~
musahi/m68kdasm.c:383:3: note: ‘sprintf’ output between 2 and 21 bytes into a destination of size 15
  383 |   sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16()));
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
musahi/m68kdasm.c: In function ‘d68000_cmpi_16’:
musahi/m68kdasm.c:383:18: warning: ‘%s’ directive writing up to 19 bytes into a region of size 14 [-Wformat-overflow=]
  356 |  return str;
      |         ~~~       
......
  383 |   sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16()));
      |                  ^~
musahi/m68kdasm.c:383:3: note: ‘sprintf’ output between 2 and 21 bytes into a destination of size 15
  383 |   sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16()));
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
musahi/m68kdasm.c: In function ‘d68020_cmpi_pcix_8’:
musahi/m68kdasm.c:381:18: warning: ‘%s’ directive writing up to 19 bytes into a region of size 14 [-Wformat-overflow=]
  340 |  return str;
      |         ~~~       
......
  381 |   sprintf(str, "#%s", make_signed_hex_str_8(read_imm_8()));
      |                  ^~
musahi/m68kdasm.c:381:3: note: ‘sprintf’ output between 2 and 21 bytes into a destination of size 15
  381 |   sprintf(str, "#%s", make_signed_hex_str_8(read_imm_8()));
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
musahi/m68kdasm.c: In function ‘d68000_cmpi_8’:
musahi/m68kdasm.c:381:18: warning: ‘%s’ directive writing up to 19 bytes into a region of size 14 [-Wformat-overflow=]
  340 |  return str;
      |         ~~~       
......
  381 |   sprintf(str, "#%s", make_signed_hex_str_8(read_imm_8()));
      |                  ^~
musahi/m68kdasm.c:381:3: note: ‘sprintf’ output between 2 and 21 bytes into a destination of size 15
  381 |   sprintf(str, "#%s", make_signed_hex_str_8(read_imm_8()));
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
musahi/m68kdasm.c: In function ‘d68000_addi_32’:
musahi/m68kdasm.c:385:18: warning: ‘%s’ directive writing up to 19 bytes into a region of size 14 [-Wformat-overflow=]
  372 |  return str;
      |         ~~~       
......
  385 |   sprintf(str, "#%s", make_signed_hex_str_32(read_imm_32()));
      |                  ^~
musahi/m68kdasm.c:385:3: note: ‘sprintf’ output between 2 and 21 bytes into a destination of size 15
  385 |   sprintf(str, "#%s", make_signed_hex_str_32(read_imm_32()));
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
musahi/m68kdasm.c: In function ‘d68000_addi_16’:
musahi/m68kdasm.c:383:18: warning: ‘%s’ directive writing up to 19 bytes into a region of size 14 [-Wformat-overflow=]
  356 |  return str;
      |         ~~~       
......
  383 |   sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16()));
      |                  ^~
musahi/m68kdasm.c:383:3: note: ‘sprintf’ output between 2 and 21 bytes into a destination of size 15
  383 |   sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16()));
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
musahi/m68kdasm.c: In function ‘d68000_addi_8’:
musahi/m68kdasm.c:381:18: warning: ‘%s’ directive writing up to 19 bytes into a region of size 14 [-Wformat-overflow=]
  340 |  return str;
      |         ~~~       
......
  381 |   sprintf(str, "#%s", make_signed_hex_str_8(read_imm_8()));
      |                  ^~
musahi/m68kdasm.c:381:3: note: ‘sprintf’ output between 2 and 21 bytes into a destination of size 15
  381 |   sprintf(str, "#%s", make_signed_hex_str_8(read_imm_8()));
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
musahi/m68kdasm.c: In function ‘d68020_cmpi_pcix_16’:
musahi/m68kdasm.c:383:18: warning: ‘%s’ directive writing up to 19 bytes into a region of size 14 [-Wformat-overflow=]
  356 |  return str;
      |         ~~~       
......
  383 |   sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16()));
      |                  ^~
musahi/m68kdasm.c:383:3: note: ‘sprintf’ output between 2 and 21 bytes into a destination of size 15
  383 |   sprintf(str, "#%s", make_signed_hex_str_16(read_imm_16()));
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
musahi/m68kdasm.c: In function ‘d68020_cmpi_pcdi_32’:
musahi/m68kdasm.c:385:18: warning: ‘%s’ directive writing up to 19 bytes into a region of size 14 [-Wformat-overflow=]
  372 |  return str;
      |         ~~~       
......
  385 |   sprintf(str, "#%s", make_signed_hex_str_32(read_imm_32()));
      |                  ^~
musahi/m68kdasm.c:385:3: note: ‘sprintf’ output between 2 and 21 bytes into a destination of size 15
  385 |   sprintf(str, "#%s", make_signed_hex_str_32(read_imm_32()));
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
musahi/m68kdasm.c: In function ‘d68020_cmpi_pcdi_8’:
musahi/m68kdasm.c:381:18: warning: ‘%s’ directive writing up to 19 bytes into a region of size 14 [-Wformat-overflow=]
  340 |  return str;
      |         ~~~       
......
  381 |   sprintf(str, "#%s", make_signed_hex_str_8(read_imm_8()));
      |                  ^~
musahi/m68kdasm.c:381:3: note: ‘sprintf’ output between 2 and 21 bytes into a destination of size 15
  381 |   sprintf(str, "#%s", make_signed_hex_str_8(read_imm_8()));
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
musahi/m68kdasm.c: In function ‘m68ki_disassemble_quick’:
musahi/m68kdasm.c:3485:23: warning: ‘%s’ directive writing up to 99 bytes into a region of size between 1 and 100 [-Wformat-overflow=]
 3485 |  sprintf(str_buff, "%s%s", g_dasm_str, g_helper_str);
      |                       ^~               ~~~~~~~~~~~~
musahi/m68kdasm.c:3485:2: note: ‘sprintf’ output between 1 and 199 bytes into a destination of size 100
 3485 |  sprintf(str_buff, "%s%s", g_dasm_str, g_helper_str);
      |  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Opcode $f620 (move16 on 68040)

According to

{m68k_op_move16_32           , 0xfff8, 0xf620, {  0,   0,   0,   4}},

move16_32 is only available on the 68040, but there is no CPU type check inside the execution handler:

static void m68k_op_move16_32(void)
{
	uint16 w2 = OPER_I_16();
	int ax = REG_IR & 7;
	int ay = (w2 >> 12) & 7;

	m68ki_write_32(REG_A[ay],    m68ki_read_32(REG_A[ax]));
	m68ki_write_32(REG_A[ay]+4,  m68ki_read_32(REG_A[ax]+4));
	m68ki_write_32(REG_A[ay]+8,  m68ki_read_32(REG_A[ax]+8));
	m68ki_write_32(REG_A[ay]+12, m68ki_read_32(REG_A[ax]+12));

	REG_A[ax] += 16;
	REG_A[ay] += 16;
}

I guess, it should be something like this:

static void m68k_op_move16_32(void)
{
    if(CPU_TYPE_IS_040_PLUS(CPU_TYPE))
    {
        uint16 w2 = OPER_I_16();
        int ax = REG_IR & 7;
        int ay = (w2 >> 12) & 7;

        m68ki_write_32(REG_A[ay],    m68ki_read_32(REG_A[ax]));
        m68ki_write_32(REG_A[ay]+4,  m68ki_read_32(REG_A[ax]+4));
        m68ki_write_32(REG_A[ay]+8,  m68ki_read_32(REG_A[ax]+8));
        m68ki_write_32(REG_A[ay]+12, m68ki_read_32(REG_A[ax]+12));

        REG_A[ax] += 16;
        REG_A[ay] += 16;
        return;
    }

    m68ki_exception_1111();
}

68010 emulation bug cause some Amiga CPU detection code to fail

The instruction

 MOVEC CACR,Dn

acts as a no-op in the emulator on a 68010 rather than trapping with an illegal. It behaves correctly on all other CPU types.

I think there is an m68ki_exception_illegal() missing in the switch. Writing CACR behaves correctly.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.