Very minor in all cases, but the strange case of swtp_cpu.c This module used expressions of the form: PC = ++PC & ADDRMASK; Officially, the C language says that expressions which modify the same variable in more than one place have undefined behavior. These were changed to the legal form which performs the desired action: PC = (PC + 1) & ADDRMASK;
2293 lines
53 KiB
C
2293 lines
53 KiB
C
/* swtp_6800_cpu.c: SWTP 6800 Motorola 6800 CPU simulator
|
|
|
|
Copyright (c) 2005, 2007, William Beech
|
|
|
|
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
|
|
WILLIAM A. BEECH 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.
|
|
|
|
Except as contained in this notice, the name of William A. Beech shall not
|
|
be used in advertising or otherwise to promote the sale, use or other dealings
|
|
in this Software without prior written authorization from William A. Beech.
|
|
|
|
Based on work by Charles E Owen (c) 1997 and Peter Schorn (c) 2002-2005
|
|
|
|
cpu 6800 CPU
|
|
|
|
The register state for the 6800 CPU is:
|
|
|
|
A<0:7> Accumulator A
|
|
B<0:7> Accumulator B
|
|
IX<0:15> Index Register
|
|
H half-carry flag
|
|
I interrupt flag
|
|
N negative flag
|
|
Z zero flag
|
|
V overflow flag
|
|
C carry flag
|
|
PC<0:15> program counter
|
|
SP<0:15> Stack Pointer
|
|
|
|
The 6800 is an 8-bit CPU, which uses 16-bit registers to address
|
|
up to 64KB of memory.
|
|
|
|
The 72 basic instructions come in 1, 2, and 3-byte flavors.
|
|
|
|
This routine is the instruction decode routine for the 6800.
|
|
It is called from the simulator control program to execute
|
|
instructions in simulated memory, starting at the simulated PC.
|
|
It runs until 'reason' is set non-zero.
|
|
|
|
General notes:
|
|
|
|
1. Reasons to stop. The simulator can be stopped by:
|
|
|
|
WAI instruction
|
|
I/O error in I/O simulator
|
|
Invalid OP code (if ITRAP is set on CPU)
|
|
Invalid mamory address (if MTRAP is set on CPU)
|
|
|
|
2. Interrupts.
|
|
There are 4 types of interrupt, and in effect they do a
|
|
hardware CALL instruction to one of 4 possible high memory addresses.
|
|
|
|
3. Non-existent memory. On the SWTP 6800, reads to non-existent memory
|
|
return 0FFH, and writes are ignored. In the simulator, the
|
|
largest possible memory is instantiated and initialized to zero.
|
|
Thus, only writes need be checked against actual memory size.
|
|
|
|
4. Adding I/O devices. These modules must be modified:
|
|
|
|
swtp_6800_cpu.c add I/O service routines to dev_table
|
|
swtp_sys.c add pointer to data structures in sim_devices
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "swtp_defs.h"
|
|
|
|
//#include <windows.h>
|
|
//#include <mmsystem.h>
|
|
|
|
#define UNIT_V_OPSTOP (UNIT_V_UF) /* Stop on Invalid OP? */
|
|
#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP)
|
|
#define UNIT_V_MSTOP (UNIT_V_UF+1) /* Stop on Invalid memory? */
|
|
#define UNIT_MSTOP (1 << UNIT_V_MSTOP)
|
|
#define UNIT_V_MSIZE (UNIT_V_UF+2) /* Memory Size */
|
|
#define UNIT_MSIZE (1 << UNIT_V_MSIZE)
|
|
#define UNIT_V_MA000 (UNIT_V_UF+2) /* 128B or 8kB at 0xA000 */
|
|
#define UNIT_MA000 (1 << UNIT_V_MA000)
|
|
|
|
uint8 M[MAXMEMSIZE]; /* Memory */
|
|
int32 A = 0; /* Accumulator A */
|
|
int32 B = 0; /* Accumulator B */
|
|
int32 IX = 0; /* Index register */
|
|
int32 SP = 0; /* Stack pointer */
|
|
int32 H = 0; /* Half-carry flag */
|
|
int32 I = 1; /* Interrupt flag */
|
|
int32 N = 0; /* Negative flag */
|
|
int32 Z = 0; /* Zero flag */
|
|
int32 V = 0; /* Overflow flag */
|
|
int32 C = 0; /* Carry flag */
|
|
int32 saved_PC = 0; /* Program counter */
|
|
int32 INTE = 0; /* Interrupt Enable */
|
|
int32 int_req = 0; /* Interrupt request */
|
|
|
|
int32 mem_fault = 0; /* memory fault flag */
|
|
|
|
extern int32 sim_int_char;
|
|
extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
|
|
|
|
/* function prototypes */
|
|
|
|
t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
|
|
t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
|
|
t_stat cpu_reset (DEVICE *dptr);
|
|
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
|
|
void dump_regs();
|
|
void go_rel(int32 cond);
|
|
int32 get_rel_addr();
|
|
int32 get_dir_val();
|
|
int32 get_dir_addr();
|
|
int32 get_indir_val();
|
|
int32 get_indir_addr();
|
|
int32 get_ext_val();
|
|
int32 get_ext_addr();
|
|
int32 get_psw();
|
|
void set_psw(int32 psw);
|
|
void condevalH(int32 res);
|
|
void condevalN(int32 res);
|
|
void condevalZ(int32 res);
|
|
void condevalC(int32 res);
|
|
void condevalVa(int32 op1, int32 op2);
|
|
void condevalVs(int32 op1, int32 op2);
|
|
void mem_put_byte(int32 addr, int32 val);
|
|
void mem_put_word(int32 addr, int32 val);
|
|
int32 mem_get_byte(int32 addr);
|
|
int32 mem_get_word(int32 addr);
|
|
int32 nulldev(int32 io, int32 data);
|
|
|
|
/* external routines */
|
|
|
|
extern int32 sio0s(int32 io, int32 data);
|
|
extern int32 sio0d(int32 io, int32 data);
|
|
extern int32 sio1s(int32 io, int32 data);
|
|
extern int32 sio1d(int32 io, int32 data);
|
|
extern int32 fdcdrv(int32 io, int32 data);
|
|
extern int32 fdccmd(int32 io, int32 data);
|
|
extern int32 fdctrk(int32 io, int32 data);
|
|
extern int32 fdcsec(int32 io, int32 data);
|
|
extern int32 fdcdata(int32 io, int32 data);
|
|
extern int32 fprint_sym (FILE *of, int32 addr, uint32 *val,
|
|
UNIT *uptr, int32 sw);
|
|
|
|
|
|
/* This is the I/O configuration table. There are 32 possible
|
|
device addresses, if a device is plugged into a port it's routine
|
|
address is here, 'nulldev' means no device is available
|
|
*/
|
|
|
|
struct idev {
|
|
int32 (*routine)(int32, int32);
|
|
};
|
|
|
|
struct idev dev_table[32] = {
|
|
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 0 8000-8003*/
|
|
{&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /*Port 1 8004-8007*/
|
|
/* sio1x routines just return the last value read on the matching
|
|
sio0x routine. SWTBUG tests for the MP-C with most port reads! */
|
|
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 2 8008-800B*/
|
|
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 3 800C-800F*/
|
|
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 4 8010-8013*/
|
|
{&fdcdrv}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 5 8014-8017*/
|
|
{&fdccmd}, {&fdctrk}, {&fdcsec}, {&fdcdata}, /*Port 6 8018-801B*/
|
|
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev} /*Port 7 801C-801F*/
|
|
};
|
|
|
|
/* SWTP 6800 SWTBUG BOOT EPROM, fits at 0E000-0E3FFH and replicated
|
|
at 0FC000-0FFFF for the interrupt vectors */
|
|
|
|
#define BOOTLEN 1024
|
|
|
|
int32 bootrom[BOOTLEN] = {
|
|
0xFE,0xA0,0x00,0x6E,0x00,0x8D,0x40,0x6E,
|
|
0x00,0x10,0x16,0x04,0xBD,0xE3,0x34,0x8D,
|
|
0x67,0x81,0x53,0x26,0xFA,0x8D,0x61,0x81,
|
|
0x39,0x27,0x29,0x81,0x31,0x26,0xF0,0x7F,
|
|
0xA0,0x0F,0x8D,0x31,0x80,0x02,0xB7,0xA0,
|
|
0x47,0x8D,0x1C,0x8D,0x28,0x7A,0xA0,0x47,
|
|
0x27,0x09,0xA7,0x00,0xA1,0x00,0x26,0x08,
|
|
0x08,0x20,0xF0,0x7C,0xA0,0x0F,0x27,0xCF,
|
|
0x86,0x3F,0x8D,0x31,0x7E,0xE2,0xD4,0x8D,
|
|
0x0C,0xB7,0xA0,0x0D,0x8D,0x07,0xB7,0xA0,
|
|
0x0E,0xFE,0xA0,0x0D,0x39,0x8D,0x53,0x48,
|
|
0x48,0x48,0x48,0x16,0x8D,0x4C,0x1B,0x16,
|
|
0xFB,0xA0,0x0F,0xF7,0xA0,0x0F,0x39,0x44,
|
|
0x44,0x44,0x44,0x84,0x0F,0x8B,0x30,0x81,
|
|
0x39,0x23,0x02,0x8B,0x07,0x7E,0xE1,0xD1,
|
|
0x7E,0xE1,0xAC,0x8D,0xF8,0x08,0xA6,0x00,
|
|
0x81,0x04,0x26,0xF7,0x39,0x7E,0xE1,0x4A,
|
|
0x8D,0xBD,0xCE,0xE1,0x9D,0x8D,0xEF,0xCE,
|
|
0xA0,0x0D,0x8D,0x34,0xFE,0xA0,0x0D,0x8D,
|
|
0x31,0x8D,0x31,0x8D,0xDB,0x81,0x20,0x27,
|
|
0xFA,0x81,0x0D,0x27,0xE0,0x81,0x5E,0x20,
|
|
0x2C,0x01,0x8D,0xCC,0x80,0x30,0x2B,0x4C,
|
|
0x81,0x09,0x2F,0x0A,0x81,0x11,0x2B,0x44,
|
|
0x81,0x16,0x2E,0x40,0x80,0x07,0x39,0xA6,
|
|
0x00,0x8D,0xA4,0xA6,0x00,0x08,0x20,0xA3,
|
|
0x8D,0xF5,0x8D,0xF3,0x86,0x20,0x20,0xA5,
|
|
0x8E,0xA0,0x42,0x20,0x2C,0x26,0x07,0x09,
|
|
0x09,0xFF,0xA0,0x0D,0x20,0xAC,0xFF,0xA0,
|
|
0x0D,0x20,0x02,0x20,0x6D,0x81,0x30,0x25,
|
|
0xA1,0x81,0x46,0x22,0x9D,0x8D,0xBD,0xBD,
|
|
0xE0,0x57,0x09,0xA7,0x00,0xA1,0x00,0x27,
|
|
0x91,0x7E,0xE0,0x40,0xBE,0xA0,0x08,0x20,
|
|
0x49,0xBF,0xA0,0x08,0x86,0xFF,0xBD,0xE3,
|
|
0x08,0xCE,0x80,0x04,0xBD,0xE2,0x84,0xA6,
|
|
0x00,0xA1,0x02,0x20,0x02,0x20,0x19,0x26,
|
|
0x39,0x86,0x03,0xA7,0x00,0x86,0x11,0xA7,
|
|
0x00,0x20,0x2F,0x01,0xBF,0xA0,0x08,0x30,
|
|
0x6D,0x06,0x26,0x02,0x6A,0x05,0x6A,0x06,
|
|
0xCE,0xE1,0x9D,0xBD,0xE0,0x7E,0xFE,0xA0,
|
|
0x08,0x08,0x8D,0x8E,0x8D,0x8C,0x8D,0x8A,
|
|
0x8D,0x86,0x8D,0x84,0xCE,0xA0,0x08,0xBD,
|
|
0xE0,0xC8,0xFE,0xA0,0x12,0x8C,0xE1,0x23,
|
|
0x27,0x19,0x8E,0xA0,0x42,0xCE,0x80,0x04,
|
|
0xFF,0xA0,0x0A,0x7F,0xA0,0x0C,0x8D,0x73,
|
|
0x27,0x03,0xBD,0xE2,0x7D,0xBD,0xE3,0x53,
|
|
0xBD,0xE3,0x47,0xCE,0xE1,0x9C,0xBD,0xE0,
|
|
0x7E,0x8D,0x39,0xCE,0xE3,0xD1,0xA1,0x00,
|
|
0x26,0x07,0xBD,0xE0,0xCC,0xEE,0x01,0x6E,
|
|
0x00,0x08,0x08,0x08,0x8C,0xE3,0xF8,0x26,
|
|
0xED,0x20,0xBF,0xFE,0xA0,0x12,0x6E,0x00,
|
|
0x53,0x39,0x04,0x0D,0x0A,0x15,0x00,0x00,
|
|
0x00,0x53,0x31,0x04,0x13,0x0D,0x0A,0x15,
|
|
0x00,0x00,0x00,0x24,0x04,0x20,0x4C,0xFE,
|
|
0xA0,0x06,0x6E,0x00,0x20,0x40,0xBD,0xE0,
|
|
0x47,0xFF,0xA0,0x04,0xBD,0xE0,0x47,0xBD,
|
|
0xE0,0x55,0x16,0xA6,0x00,0xFF,0xA0,0x0D,
|
|
0x11,0x27,0x02,0x20,0x21,0xCE,0xE1,0x9D,
|
|
0xBD,0xE0,0x7E,0xCE,0xA0,0x0D,0x20,0x10,
|
|
0x3B,0x20,0x3A,0xFF,0xA0,0x10,0xFE,0xA0,
|
|
0x0A,0x37,0xE6,0x01,0xE1,0x03,0x33,0x39,
|
|
0xBD,0xE0,0xC8,0xFE,0xA0,0x0D,0xBC,0xA0,
|
|
0x04,0x27,0x9E,0x08,0x20,0xCD,0x8D,0x06,
|
|
0x84,0x7F,0x39,0x31,0x31,0x31,0x37,0x8D,
|
|
0xDA,0x26,0x28,0x86,0x15,0xA7,0x00,0xA6,
|
|
0x00,0x47,0x24,0xFB,0xA6,0x01,0xF6,0xA0,
|
|
0x0C,0x27,0x07,0x20,0x11,0x37,0x8D,0xC3,
|
|
0x26,0x2E,0xC6,0x11,0xE7,0x00,0xE6,0x00,
|
|
0x57,0x57,0x24,0xFA,0xA7,0x01,0x33,0xFE,
|
|
0xA0,0x10,0x39,0xA6,0x00,0x2B,0xFC,0x8D,
|
|
0x3A,0xC6,0x04,0xE7,0x02,0x58,0x8D,0x2A,
|
|
0x0D,0x69,0x00,0x46,0x5A,0x26,0xF7,0x8D,
|
|
0x21,0xF6,0xA0,0x0C,0x27,0x13,0x20,0xDE,
|
|
0x8D,0x23,0xC6,0x0A,0x6A,0x00,0x8D,0x16,
|
|
0x8D,0x10,0xA7,0x00,0x0D,0x46,0x5A,0x26,
|
|
0xF7,0xE6,0x02,0x58,0x2A,0xC8,0x8D,0x02,
|
|
0x20,0xC4,0x6D,0x02,0x2A,0xFC,0x6C,0x02,
|
|
0x6A,0x02,0x39,0x6F,0x02,0x8D,0xF7,0x20,
|
|
0xF1,0x8D,0x83,0x16,0x7F,0xA0,0x0B,0xFE,
|
|
0xA0,0x0A,0x8D,0x10,0x8D,0x07,0xCE,0xE3,
|
|
0xEF,0x17,0x7E,0xE1,0x76,0x86,0x34,0xA7,
|
|
0x03,0xA7,0x02,0x39,0x6C,0x00,0x86,0x07,
|
|
0xA7,0x01,0x6C,0x00,0xA7,0x02,0x39,0x7F,
|
|
0x80,0x14,0x8D,0x2E,0xC6,0x0B,0x8D,0x25,
|
|
0xE6,0x04,0xC5,0x01,0x26,0xFA,0x6F,0x06,
|
|
0x8D,0x1D,0xC6,0x9C,0x8D,0x17,0xCE,0x24,
|
|
0x00,0xC5,0x02,0x27,0x06,0xB6,0x80,0x1B,
|
|
0xA7,0x00,0x08,0xF6,0x80,0x18,0xC5,0x01,
|
|
0x26,0xEF,0x7E,0x24,0x00,0xE7,0x04,0x8D,
|
|
0x00,0x39,0xCE,0xFF,0xFF,0x09,0x8C,0x80,
|
|
0x14,0x26,0xFA,0x39,0xCE,0xE0,0x09,0xBD,
|
|
0xE0,0x7E,0x8D,0xF1,0xBD,0xE3,0x47,0x20,
|
|
0x58,0xCE,0xE1,0x23,0xBC,0xA0,0x12,0x27,
|
|
0x1A,0x08,0x8D,0x32,0xBD,0xE0,0x47,0xFF,
|
|
0xA0,0x14,0xA6,0x00,0xB7,0xA0,0x16,0x86,
|
|
0x3F,0xA7,0x00,0xCE,0xE1,0x23,0x8D,0x1E,
|
|
0x7E,0xE1,0x6B,0xFE,0xA0,0x14,0xB6,0xA0,
|
|
0x16,0xA7,0x00,0xCE,0xE1,0x24,0x20,0xDA,
|
|
0xB7,0xA0,0x43,0xFE,0xA0,0x12,0x8C,0xE1,
|
|
0x23,0x27,0x06,0xCE,0xE1,0x24,0xFF,0xA0,
|
|
0x12,0x39,0x8D,0x5A,0x20,0x0F,0xCE,0xA0,
|
|
0x49,0xFF,0xA0,0x04,0x09,0x8D,0x52,0xCE,
|
|
0xE1,0x90,0xBD,0xE0,0x7E,0x8D,0x24,0x8D,
|
|
0x91,0x7E,0xE1,0x52,0x73,0xA0,0x0C,0x86,
|
|
0x11,0xC6,0x20,0x8D,0x1A,0xBD,0xE1,0xD9,
|
|
0x27,0x04,0x86,0x3C,0xA7,0x03,0x39,0x86,
|
|
0x13,0xC6,0x10,0x20,0x0A,0x86,0x12,0xC6,
|
|
0x04,0x20,0x04,0x86,0x14,0xC6,0x08,0xBD,
|
|
0xE0,0x75,0xBD,0xE1,0xD6,0x27,0x16,0x86,
|
|
0x02,0xCA,0x01,0x8D,0x0C,0x8D,0x08,0x86,
|
|
0x02,0xC6,0x01,0xE7,0x00,0x8D,0x02,0x86,
|
|
0x06,0xA7,0x01,0xE7,0x00,0x39,0xFE,0xA0,
|
|
0x02,0xFF,0xA0,0x44,0x8D,0xCF,0xB6,0xA0,
|
|
0x05,0xB0,0xA0,0x45,0xF6,0xA0,0x04,0xF2,
|
|
0xA0,0x44,0x26,0x04,0x81,0x10,0x25,0x02,
|
|
0x86,0x0F,0x8B,0x04,0xB7,0xA0,0x47,0x80,
|
|
0x03,0xB7,0xA0,0x46,0xCE,0xE1,0x93,0xBD,
|
|
0xE0,0x7E,0x5F,0xCE,0xA0,0x47,0x8D,0x24,
|
|
0xCE,0xA0,0x44,0x8D,0x1F,0x8D,0x1D,0xFE,
|
|
0xA0,0x44,0x8D,0x18,0x7A,0xA0,0x46,0x26,
|
|
0xF9,0xFF,0xA0,0x44,0x53,0x37,0x30,0x8D,
|
|
0x0B,0x33,0xFE,0xA0,0x44,0x09,0xBC,0xA0,
|
|
0x04,0x26,0xB3,0x39,0xEB,0x00,0x7E,0xE0,
|
|
0xBF,0x47,0xE1,0xD0,0x5A,0xC0,0x00,0x4D,
|
|
0xE0,0x88,0x46,0xE1,0xAE,0x52,0xE1,0x30,
|
|
0x4A,0xE0,0x05,0x43,0xE2,0xCC,0x44,0xE2,
|
|
0x8F,0x42,0xE2,0xD9,0x4F,0xE2,0x69,0x50,
|
|
0xE3,0x1A,0x4C,0xE0,0x0C,0x45,0xE3,0x1E,
|
|
0xE0,0x00,0xE1,0x8B,0xE1,0xA7,0xE0,0xD0
|
|
};
|
|
|
|
/* CPU data structures
|
|
|
|
cpu_dev CPU device descriptor
|
|
cpu_unit CPU unit descriptor
|
|
cpu_reg CPU register list
|
|
cpu_mod CPU modifiers list */
|
|
|
|
UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK,
|
|
32768) };
|
|
|
|
REG cpu_reg[] = {
|
|
{ HRDATA (PC, saved_PC, 16) },
|
|
{ HRDATA (A, A, 8) },
|
|
{ HRDATA (B, B, 8) },
|
|
{ HRDATA (IX, IX, 16) },
|
|
{ HRDATA (SP, SP, 16) },
|
|
{ FLDATA (H, H, 16) },
|
|
{ FLDATA (I, I, 16) },
|
|
{ FLDATA (N, N, 16) },
|
|
{ FLDATA (Z, Z, 16) },
|
|
{ FLDATA (V, V, 16) },
|
|
{ FLDATA (C, C, 16) },
|
|
{ FLDATA (INTE, INTE, 16) },
|
|
{ ORDATA (WRU, sim_int_char, 8) },
|
|
{ NULL } };
|
|
|
|
MTAB cpu_mod[] = {
|
|
{ UNIT_OPSTOP, UNIT_OPSTOP, "ITRAP", "ITRAP", NULL },
|
|
{ UNIT_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL },
|
|
{ UNIT_MSTOP, UNIT_MSTOP, "MTRAP", "MTRAP", NULL },
|
|
{ UNIT_MSTOP, 0, "NOMTRAP", "NOMTRAP", NULL },
|
|
{ UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size },
|
|
{ UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size },
|
|
{ UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size },
|
|
{ UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size },
|
|
{ UNIT_MSIZE, 20480, NULL, "20K", &cpu_set_size },
|
|
{ UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size },
|
|
{ UNIT_MSIZE, 28672, NULL, "28K", &cpu_set_size },
|
|
{ UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size },
|
|
{ UNIT_MA000, UNIT_MA000, "MA000", "MA000", NULL },
|
|
{ UNIT_MA000, 0, "NOMA000", "NOMA000", NULL },
|
|
{ 0 } };
|
|
|
|
DEVICE cpu_dev = {
|
|
"CPU", &cpu_unit, cpu_reg, cpu_mod,
|
|
1, 16, 16, 1, 16, 8,
|
|
&cpu_ex, &cpu_dep, &cpu_reset,
|
|
NULL, NULL, NULL };
|
|
|
|
int32 PC; /* global for the helper routines */
|
|
|
|
int32 sim_instr (void)
|
|
{
|
|
extern int32 sim_interval;
|
|
int32 IR, OP, DAR, reason, hi, lo, op1;
|
|
// uint32 val1[3];
|
|
|
|
PC = saved_PC & ADDRMASK; /* load local PC */
|
|
reason = 0;
|
|
|
|
/* Main instruction fetch/decode loop */
|
|
|
|
while (reason == 0) { /* loop until halted */
|
|
if (sim_interval <= 0) /* check clock queue */
|
|
if (reason = sim_process_event ())
|
|
break;
|
|
if (mem_fault) { /* memory fault? */
|
|
mem_fault = 0; /* reset fault flag */
|
|
reason = STOP_MEMORY;
|
|
break;
|
|
}
|
|
if (int_req > 0) { /* interrupt? */
|
|
/* 6800 interrupts not implemented yet. None were used,
|
|
on a standard SWTP 6800. All I/O is programmed. */
|
|
} /* end interrupt */
|
|
if (sim_brk_summ &&
|
|
sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
|
|
reason = STOP_IBKPT; /* stop simulation */
|
|
break;
|
|
}
|
|
/* transient routine area - trace */
|
|
/*
|
|
if (PC >= 0xa100 && PC < 0xa400) {
|
|
dump_regs();
|
|
printf("\n\r%04X: ", PC);
|
|
val1[0] = M[PC];
|
|
val1[1] = M[PC+1];
|
|
val1[2] = M[PC+2];
|
|
fprint_sym(stdout, PC, val1, NULL, SWMASK ('M'));
|
|
}
|
|
*/
|
|
IR = OP = mem_get_byte(PC); /* fetch instruction */
|
|
PC = (PC + 1) & ADDRMASK; /* increment PC */
|
|
sim_interval--;
|
|
|
|
/* The Big Instruction Decode Switch */
|
|
|
|
switch (IR) {
|
|
|
|
case 0x01: /* NOP */
|
|
break;
|
|
case 0x06: /* TAP */
|
|
set_psw(A);
|
|
break;
|
|
case 0x07: /* TPA */
|
|
A = get_psw();
|
|
break;
|
|
case 0x08: /* INX */
|
|
IX = (IX + 1) & ADDRMASK;
|
|
condevalZ(IX);
|
|
break;
|
|
case 0x09: /* DEX */
|
|
IX = (IX + 1) & ADDRMASK;
|
|
condevalZ(IX);
|
|
break;
|
|
case 0x0A: /* CLV */
|
|
V = 0;
|
|
break;
|
|
case 0x0B: /* SEV */
|
|
V = 0x10000;
|
|
break;
|
|
case 0x0C: /* CLC */
|
|
C = 0;
|
|
break;
|
|
case 0x0D: /* SEC */
|
|
C = 0x10000;
|
|
break;
|
|
case 0x0E: /* CLI */
|
|
I = 0;
|
|
break;
|
|
case 0x0F: /* SEI */
|
|
I = 0x10000;
|
|
break;
|
|
case 0x10: /* SBA */
|
|
op1 = A;
|
|
A = A - B;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
condevalC(A);
|
|
condevalVs(B, op1);
|
|
A &= 0xFF;
|
|
break;
|
|
case 0x11: /* CBA */
|
|
lo = A - B;
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
condevalC(lo);
|
|
condevalVs(B, A);
|
|
break;
|
|
case 0x16: /* TAB */
|
|
B = A;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
V = 0;
|
|
break;
|
|
case 0x17: /* TBA */
|
|
A = B;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
V = 0;
|
|
break;
|
|
case 0x19: /* DAA */
|
|
DAR = A & 0x0F;
|
|
op1 = C;
|
|
if (DAR > 9 || C) {
|
|
DAR += 6;
|
|
A &= 0xF0;
|
|
A |= DAR & 0x0F;
|
|
C = 0;
|
|
if (DAR & 0x10)
|
|
C = 0x10000;
|
|
}
|
|
DAR = (A >> 4) & 0x0F;
|
|
if (DAR > 9 || C) {
|
|
DAR += 6;
|
|
if (C)
|
|
DAR++;
|
|
A &= 0x0F;
|
|
A |= (DAR << 4);
|
|
}
|
|
C = op1;
|
|
if ((DAR << 4) & 0x100)
|
|
C = 0x10000;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
A &= 0xFF;
|
|
break;
|
|
case 0x1B: /* ABA */
|
|
A += B;
|
|
condevalH(A);
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
condevalC(A);
|
|
condevalVa(A, B);
|
|
A &= 0xFF;
|
|
break;
|
|
case 0x20: /* BRA rel */
|
|
go_rel(1);
|
|
break;
|
|
case 0x22: /* BHI rel */
|
|
go_rel(!(C | Z));
|
|
break;
|
|
case 0x23: /* BLS rel */
|
|
go_rel(C | Z);
|
|
break;
|
|
case 0x24: /* BCC rel */
|
|
go_rel(!C);
|
|
break;
|
|
case 0x25: /* BCS rel */
|
|
go_rel(C);
|
|
break;
|
|
case 0x26: /* BNE rel */
|
|
go_rel(!Z);
|
|
break;
|
|
case 0x27: /* BEQ rel */
|
|
go_rel(Z);
|
|
break;
|
|
case 0x28: /* BVC rel */
|
|
go_rel(!V);
|
|
break;
|
|
case 0x29: /* BVS rel */
|
|
go_rel(V);
|
|
break;
|
|
case 0x2A: /* BPL rel */
|
|
go_rel(!N);
|
|
break;
|
|
case 0x2B: /* BMI rel */
|
|
go_rel(N);
|
|
break;
|
|
case 0x2C: /* BGE rel */
|
|
go_rel(!(N ^ V));
|
|
break;
|
|
case 0x2D: /* BLT rel */
|
|
go_rel(N ^ V);
|
|
break;
|
|
case 0x2E: /* BGT rel */
|
|
go_rel(!(Z | (N ^ V)));
|
|
break;
|
|
case 0x2F: /* BLE rel */
|
|
go_rel(Z | (N ^ V));
|
|
break;
|
|
case 0x30: /* TSX */
|
|
IX = (SP + 1) & ADDRMASK;
|
|
break;
|
|
case 0x31: /* INS */
|
|
SP = (SP + 1) & ADDRMASK;
|
|
break;
|
|
case 0x32: /* PUL A */
|
|
SP = (SP + 1) & ADDRMASK;
|
|
A = mem_get_byte(SP);
|
|
break;
|
|
case 0x33: /* PUL B */
|
|
SP = (SP + 1) & ADDRMASK;
|
|
B = mem_get_byte(SP);
|
|
break;
|
|
case 0x34: /* DES */
|
|
SP = (SP - 1) & ADDRMASK;
|
|
break;
|
|
case 0x35: /* TXS */
|
|
SP = (IX - 1) & ADDRMASK;
|
|
break;
|
|
case 0x36: /* PSH A */
|
|
mem_put_byte(SP, A);
|
|
SP = (SP - 1) & ADDRMASK;
|
|
break;
|
|
case 0x37: /* PSH B */
|
|
mem_put_byte(SP, B);
|
|
SP = (SP - 1) & ADDRMASK;
|
|
break;
|
|
case 0x39: /* RTS */
|
|
SP = (SP + 1) & ADDRMASK;
|
|
PC = mem_get_word(SP) & ADDRMASK;
|
|
SP = (SP + 1) & ADDRMASK;
|
|
break;
|
|
case 0x3B: /* RTI */
|
|
SP = (SP + 1) & ADDRMASK;
|
|
set_psw(mem_get_byte(SP));
|
|
SP = (SP + 1) & ADDRMASK;
|
|
B = mem_get_byte(SP);
|
|
SP = (SP + 1) & ADDRMASK;
|
|
A = mem_get_byte(SP);
|
|
SP = (SP + 1) & ADDRMASK;
|
|
IX = mem_get_word(SP);
|
|
SP = (SP + 2) & ADDRMASK;
|
|
PC = mem_get_word(SP) & ADDRMASK;
|
|
SP = (SP + 1) & ADDRMASK;
|
|
break;
|
|
case 0x3E: /* WAI */
|
|
SP = (SP - 1) & ADDRMASK;
|
|
mem_put_word(SP, PC);
|
|
SP = (SP - 2) & ADDRMASK;
|
|
mem_put_word(SP, IX);
|
|
SP = (SP - 1) & ADDRMASK;
|
|
mem_put_byte(SP, A);
|
|
SP = (SP - 1) & ADDRMASK;
|
|
mem_put_byte(SP, B);
|
|
SP = (SP - 1) & ADDRMASK;
|
|
mem_put_byte(SP, get_psw());
|
|
SP = (SP - 1) & ADDRMASK;
|
|
if (I) {
|
|
reason = STOP_HALT;
|
|
continue;
|
|
} else {
|
|
I = 0x10000;
|
|
PC = mem_get_word(0xFFFE) & ADDRMASK;
|
|
}
|
|
break;
|
|
case 0x3F: /* SWI */
|
|
SP = (SP - 1) & ADDRMASK;
|
|
mem_put_word(SP, PC);
|
|
SP = (SP - 2) & ADDRMASK;
|
|
mem_put_word(SP, IX);
|
|
SP = (SP - 1) & ADDRMASK;
|
|
mem_put_byte(SP, A);
|
|
SP = (SP - 1) & ADDRMASK;
|
|
mem_put_byte(SP, B);
|
|
SP = (SP - 1) & ADDRMASK;
|
|
mem_put_byte(SP, get_psw());
|
|
SP = (SP - 1) & ADDRMASK;
|
|
I = 0x10000;
|
|
PC = mem_get_word(0xFFFB) & ADDRMASK;
|
|
break;
|
|
case 0x40: /* NEG A */
|
|
A = (0 - A) & 0xFF;
|
|
V = 0;
|
|
if (A & 0x80)
|
|
V = 0x10000;
|
|
C = 0;
|
|
if (A)
|
|
C = 0x10000;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
break;
|
|
case 0x43: /* COM A */
|
|
A = ~A & 0xFF;
|
|
V = 0;
|
|
C = 0x10000;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
break;
|
|
case 0x44: /* LSR A */
|
|
C = 0;
|
|
if (A & 0x01)
|
|
C = 0x10000;
|
|
A = (A >> 1) & 0xFF;
|
|
N = 0;
|
|
condevalZ(A);
|
|
V = 0;
|
|
if (N ^ C)
|
|
V = 0x10000;
|
|
break;
|
|
case 0x46: /* ROR A */
|
|
hi = C;
|
|
C = 0;
|
|
if (A & 0x01)
|
|
C = 0x10000;
|
|
A = (A >> 1) & 0xFF;
|
|
if (hi)
|
|
A |= 0x80;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
V = 0;
|
|
if (N ^ C)
|
|
V = 0x10000;
|
|
break;
|
|
case 0x47: /* ASR A */
|
|
C = 0;
|
|
if (A & 0x01)
|
|
C = 0x10000;
|
|
lo = A & 0x8000;
|
|
A = (A >> 1) & 0xFF;
|
|
A |= lo;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
V = 0;
|
|
if (N ^ C)
|
|
V = 0x10000;
|
|
break;
|
|
case 0x48: /* ASL A */
|
|
C = 0;
|
|
if (A & 0x80)
|
|
C = 0x10000;
|
|
A = (A << 1) & 0xFF;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
V = 0;
|
|
if (N ^ C)
|
|
V = 0x10000;
|
|
break;
|
|
case 0x49: /* ROL A */
|
|
hi = C;
|
|
C = 0;
|
|
if (A & 0x80)
|
|
C = 0x10000;
|
|
A = (A << 1) & 0xFF;
|
|
if (hi)
|
|
A |= 0x01;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
V = 0;
|
|
if (N ^ C)
|
|
V = 0x10000;
|
|
break;
|
|
case 0x4A: /* DEC A */
|
|
V = 0;
|
|
if (A == 0x80)
|
|
V = 0x10000;
|
|
A = (A - 1) & 0xFF;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
break;
|
|
case 0x4C: /* INC A */
|
|
V = 0;
|
|
if (A == 0x7F)
|
|
V = 0x10000;
|
|
A = (A + 1) & 0xFF;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
break;
|
|
case 0x4D: /* TST A */
|
|
lo = (A - 0) & 0xFF;
|
|
V = 0;
|
|
C = 0;
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
break;
|
|
case 0x4F: /* CLR A */
|
|
A = 0;
|
|
N = V = C = 0;
|
|
Z = 0x10000;
|
|
break;
|
|
case 0x50: /* NEG B */
|
|
B = (0 - V) & 0xFF;
|
|
V = 0;
|
|
if (B & 0x8000)
|
|
V = 0x10000;
|
|
C = 0;
|
|
if (B)
|
|
C = 0x10000;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
break;
|
|
case 0x53: /* COM B */
|
|
B = ~B & 0xFF;
|
|
V = 0;
|
|
C = 0x10000;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
break;
|
|
case 0x54: /* LSR B */
|
|
C = 0;
|
|
if (B & 0x01)
|
|
C = 0x10000;
|
|
B = (B >> 1) & 0xFF;
|
|
N = 0;
|
|
condevalZ(B);
|
|
V = 0;
|
|
if (N ^ C)
|
|
V = 0x10000;
|
|
break;
|
|
case 0x56: /* ROR B */
|
|
hi = C;
|
|
C = 0;
|
|
if (B & 0x01)
|
|
C = 0x10000;
|
|
B = (B >> 1) & 0xFF;
|
|
if (hi)
|
|
B |= 0x80;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
V = 0;
|
|
if (N ^ C)
|
|
V = 0x10000;
|
|
break;
|
|
case 0x57: /* ASR B */
|
|
C = 0;
|
|
if (B & 0x01)
|
|
C = 0x10000;
|
|
lo = B & 0x8000;
|
|
B = (B >> 1) & 0xFF;
|
|
B |= lo;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
V = 0;
|
|
if (N ^ C)
|
|
V = 0x10000;
|
|
break;
|
|
case 0x58: /* ASL B */
|
|
C = 0;
|
|
if (B & 0x80)
|
|
C = 0x10000;
|
|
B = (B << 1) & 0xFF;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
V = 0;
|
|
if (N ^ C)
|
|
V = 0x10000;
|
|
break;
|
|
case 0x59: /* ROL B */
|
|
hi = C;
|
|
C = 0;
|
|
if (B & 0x80)
|
|
C = 0x10000;
|
|
B = (B << 1) & 0xFF;
|
|
if (hi)
|
|
B |= 0x01;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
V = 0;
|
|
if (N ^ C)
|
|
V = 0x10000;
|
|
break;
|
|
case 0x5A: /* DEC B */
|
|
V = 0;
|
|
if (B == 0x80)
|
|
V = 0x10000;
|
|
B = (B - 1) & 0xFF;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
break;
|
|
case 0x5C: /* INC B */
|
|
V = 0;
|
|
if (B == 0x7F)
|
|
V = 0x10000;
|
|
B = (B + 1) & 0xFF;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
break;
|
|
case 0x5D: /* TST B */
|
|
lo = (B - 0) & 0xFF;
|
|
V = 0;
|
|
C = 0;
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
break;
|
|
case 0x5F: /* CLR B */
|
|
B = 0;
|
|
N = V = C = 0;
|
|
Z = 0x10000;
|
|
break;
|
|
case 0x60: /* NEG ind */
|
|
DAR = get_indir_addr();
|
|
lo = (0 - mem_get_byte(DAR)) & 0xFF;
|
|
mem_put_byte(DAR, lo);
|
|
V = 0;
|
|
if (lo & 0x80)
|
|
V = 0x10000;
|
|
C = 0;
|
|
if (lo)
|
|
C = 0x10000;
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
break;
|
|
case 0x63: /* COM ind */
|
|
DAR = get_indir_addr();
|
|
lo = ~mem_get_byte(DAR) & 0xFF;
|
|
mem_put_byte(DAR, lo);
|
|
V = 0;
|
|
C = 0x10000;
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
break;
|
|
case 0x64: /* LSR ind */
|
|
DAR = get_indir_addr();
|
|
lo = mem_get_byte(DAR);
|
|
C = 0;
|
|
if (lo & 0x01)
|
|
C = 0x10000;
|
|
lo >>= 1;
|
|
mem_put_byte(DAR, lo);
|
|
N = 0;
|
|
condevalZ(lo);
|
|
V = 0;
|
|
if (N ^ C)
|
|
V = 0x10000;
|
|
break;
|
|
case 0x66: /* ROR ind */
|
|
DAR = get_indir_addr();
|
|
lo = mem_get_byte(DAR);
|
|
hi = C;
|
|
C = 0;
|
|
if (lo & 0x01)
|
|
C = 0x10000;
|
|
lo >>= 1;
|
|
if (hi)
|
|
lo |= 0x80;
|
|
mem_put_byte(DAR, lo);
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
V = 0;
|
|
if (N ^ C)
|
|
V = 0x10000;
|
|
break;
|
|
case 0x67: /* ASR ind */
|
|
DAR = get_indir_addr();
|
|
lo = mem_get_byte(DAR);
|
|
C = 0;
|
|
if (lo & 0x01)
|
|
C = 0x10000;
|
|
lo = (lo & 0x80) | (lo >> 1);
|
|
mem_put_byte(DAR, lo);
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
V = 0;
|
|
if (N ^ C)
|
|
V = 0x10000;
|
|
break;
|
|
case 0x68: /* ASL ind */
|
|
DAR = get_indir_addr();
|
|
lo = mem_get_byte(DAR);
|
|
C = 0;
|
|
if (lo & 0x80)
|
|
C = 0x10000;
|
|
lo <<= 1;
|
|
mem_put_byte(DAR, lo);
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
V = 0;
|
|
if (N ^ C)
|
|
V = 0x10000;
|
|
break;
|
|
case 0x69: /* ROL ind */
|
|
DAR = get_indir_addr();
|
|
lo = mem_get_byte(DAR);
|
|
hi = C;
|
|
C = 0;
|
|
if (lo & 0x80)
|
|
C = 0x10000;
|
|
lo <<= 1;
|
|
if (hi)
|
|
lo |= 0x01;
|
|
mem_put_byte(DAR, lo);
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
V = 0;
|
|
if (N ^ C)
|
|
V = 0x10000;
|
|
break;
|
|
case 0x6A: /* DEC ind */
|
|
DAR = get_indir_addr();
|
|
lo = mem_get_byte(DAR);
|
|
V = 0;
|
|
if (lo == 0x80)
|
|
V = 0x10000;
|
|
lo = (lo - 1) & 0xFF;
|
|
mem_put_byte(DAR, lo);
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
break;
|
|
case 0x6C: /* INC ind */
|
|
DAR= get_indir_addr();
|
|
lo = mem_get_byte(DAR);
|
|
V = 0;
|
|
if (lo == 0x7F)
|
|
V = 0x10000;
|
|
lo = (lo + 1) & 0xFF;
|
|
mem_put_byte(DAR, lo);
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
break;
|
|
case 0x6D: /* TST ind */
|
|
lo = (get_indir_val() - 0) & 0xFF;
|
|
V = 0;
|
|
C = 0;
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
break;
|
|
case 0x6E: /* JMP ind */
|
|
PC = get_indir_addr();
|
|
break;
|
|
case 0x6F: /* CLR ind */
|
|
mem_put_byte(get_indir_addr(), 0);
|
|
N = V = C = 0;
|
|
Z = 0x10000;
|
|
break;
|
|
case 0x70: /* NEG ext */
|
|
DAR = get_ext_addr(PC);
|
|
lo = (0 - mem_get_byte(DAR)) & 0xFF;
|
|
mem_put_byte(DAR, lo);
|
|
V = 0;
|
|
if (lo & 0x80)
|
|
V = 0x10000;
|
|
C = 0;
|
|
if (lo)
|
|
C = 0x10000;
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
break;
|
|
case 0x73: /* COM ext */
|
|
DAR = get_ext_addr();
|
|
lo = ~mem_get_byte(DAR) & 0xFF;
|
|
mem_put_byte(DAR, lo);
|
|
V = 0;
|
|
C = 0x10000;
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
break;
|
|
case 0x74: /* LSR ext */
|
|
DAR = get_ext_addr();
|
|
lo = mem_get_byte(DAR);
|
|
C = 0;
|
|
if (lo & 0x01)
|
|
C = 0x10000;
|
|
lo >>= 1;
|
|
mem_put_byte(DAR, lo);
|
|
N = 0;
|
|
condevalZ(lo);
|
|
V = 0;
|
|
if (N ^ C)
|
|
V = 0x10000;
|
|
break;
|
|
case 0x76: /* ROR ext */
|
|
DAR = get_ext_addr();
|
|
hi = C;
|
|
lo = mem_get_byte(DAR);
|
|
C = 0;
|
|
if (lo & 0x01)
|
|
C = 0x10000;
|
|
lo >>= 1;
|
|
if (hi)
|
|
lo |= 0x80;
|
|
mem_put_byte(DAR, lo);
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
V = 0;
|
|
if (N ^ C)
|
|
V = 0x10000;
|
|
break;
|
|
case 0x77: /* ASR ext */
|
|
DAR = get_ext_addr();
|
|
lo = mem_get_byte(DAR);
|
|
C = 0;
|
|
if (lo & 0x01)
|
|
C = 0x10000;
|
|
hi = lo & 0x80;
|
|
lo >>= 1;
|
|
lo |= hi;
|
|
mem_put_byte(DAR, lo);
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
V = 0;
|
|
if (N ^ C)
|
|
V = 0x10000;
|
|
break;
|
|
case 0x78: /* ASL ext */
|
|
DAR = get_ext_addr();
|
|
lo = mem_get_byte(DAR);
|
|
C = 0;
|
|
if (lo & 0x80)
|
|
C = 0x10000;
|
|
lo <<= 1;
|
|
mem_put_byte(DAR, lo);
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
V = 0;
|
|
if (N ^ C)
|
|
V = 0x10000;
|
|
break;
|
|
case 0x79: /* ROL ext */
|
|
DAR = get_ext_addr();
|
|
lo = mem_get_byte(DAR);
|
|
hi = C;
|
|
C = 0;
|
|
if (lo & 0x80)
|
|
C = 0x10000;
|
|
lo <<= 1;
|
|
if (hi)
|
|
lo |= 0x01;
|
|
mem_put_byte(DAR, lo);
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
V = 0;
|
|
if (N ^ C)
|
|
V = 0x10000;
|
|
break;
|
|
case 0x7A: /* DEC ext */
|
|
DAR = get_ext_addr();
|
|
lo = mem_get_byte(DAR);
|
|
V = 0;
|
|
if (lo == 0x80)
|
|
V = 0x10000;
|
|
lo = (lo - 1) & 0xFF;
|
|
mem_put_byte(DAR, lo);
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
break;
|
|
case 0x7C: /* INC ext */
|
|
DAR = get_ext_addr();
|
|
lo = mem_get_byte(DAR);
|
|
V = 0;
|
|
if (lo == 0x7F)
|
|
V = 0x10000;
|
|
lo = (lo + 1) & 0xFF;
|
|
mem_put_byte(DAR, lo);
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
break;
|
|
case 0x7D: /* TST ext */
|
|
lo = mem_get_byte(get_ext_addr()) - 0;
|
|
V = 0;
|
|
C = 0;
|
|
condevalN(lo);
|
|
condevalZ(lo & 0xFF);
|
|
break;
|
|
case 0x7E: /* JMP ext */
|
|
PC = get_ext_addr() & ADDRMASK;
|
|
break;
|
|
case 0x7F: /* CLR ext */
|
|
mem_put_byte(get_ext_addr(), 0);
|
|
N = V = C = 0;
|
|
Z = 0x10000;
|
|
break;
|
|
case 0x80: /* SUB A imm */
|
|
op1 = get_dir_addr();
|
|
A = A - op1;
|
|
condevalN(A);
|
|
condevalC(A);
|
|
condevalVs(A, op1);
|
|
A &= 0xFF;
|
|
condevalZ(A);
|
|
break;
|
|
case 0x81: /* CMP A imm */
|
|
op1 = get_dir_addr();
|
|
lo = A - op1;
|
|
condevalN(lo);
|
|
condevalZ(lo & 0xFF);
|
|
condevalC(lo);
|
|
condevalVs(lo, op1);
|
|
break;
|
|
case 0x82: /* SBC A imm */
|
|
op1 = get_dir_addr();
|
|
if (C)
|
|
A = A - op1 - 1;
|
|
else
|
|
A = A - op1;
|
|
condevalN(A);
|
|
condevalC(A);
|
|
condevalVs(A, op1);
|
|
A &= 0xFF;
|
|
condevalZ(A);
|
|
break;
|
|
case 0x84: /* AND A imm */
|
|
A = (A & get_dir_addr()) & 0xFF;
|
|
V = 0;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
break;
|
|
case 0x85: /* BIT A imm */
|
|
lo = (A & get_dir_addr()) & 0xFF;
|
|
V = 0;
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
break;
|
|
case 0x86: /* LDA A imm */
|
|
A = get_dir_addr();
|
|
V = 0;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
break;
|
|
case 0x88: /* EOR A imm */
|
|
A = (A ^ get_dir_addr()) & 0xFF;
|
|
V = 0;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
break;
|
|
case 0x89: /* ADC A imm */
|
|
op1 = get_dir_addr();
|
|
if (C)
|
|
A = A + op1 + 1;
|
|
else
|
|
A = A + op1;
|
|
condevalH(A);
|
|
condevalN(A);
|
|
condevalC(A);
|
|
condevalVa(A, op1);
|
|
A &= 0xFF;
|
|
condevalZ(A);
|
|
break;
|
|
case 0x8A: /* ORA A imm */
|
|
A = (A | get_dir_addr()) & 0xFF;
|
|
V = 0;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
break;
|
|
case 0x8B: /* ADD A imm */
|
|
op1 = get_dir_addr();
|
|
A = A + op1;
|
|
condevalH(A);
|
|
condevalN(A);
|
|
condevalC(A);
|
|
condevalVa(A, op1);
|
|
A &= 0xFF;
|
|
condevalZ(A);
|
|
break;
|
|
case 0x8C: /* CPX imm */
|
|
op1 = IX - get_ext_addr();
|
|
condevalZ(op1);
|
|
condevalN(op1 >> 8);
|
|
V = op1 & 0x10000;
|
|
break;
|
|
case 0x8D: /* BSR rel */
|
|
lo = get_rel_addr();
|
|
SP = (SP - 1) & ADDRMASK;
|
|
mem_put_word(SP, PC);
|
|
SP = (SP - 1) & ADDRMASK;
|
|
PC = PC + lo;
|
|
PC &= ADDRMASK;
|
|
break;
|
|
case 0x8E: /* LDS imm */
|
|
SP = get_ext_addr();
|
|
condevalN(SP >> 8);
|
|
condevalZ(SP);
|
|
V = 0;
|
|
break;
|
|
case 0x90: /* SUB A dir */
|
|
op1 = get_dir_val();
|
|
A = A - op1;
|
|
condevalN(A);
|
|
condevalC(A);
|
|
condevalVs(A, op1);
|
|
A &= 0xFF;
|
|
condevalZ(A);
|
|
break;
|
|
case 0x91: /* CMP A dir */
|
|
op1 = get_dir_val();
|
|
lo = A - op1;
|
|
condevalN(lo);
|
|
condevalZ(lo & 0xff);
|
|
condevalC(lo);
|
|
condevalVs(A, op1);
|
|
break;
|
|
case 0x92: /* SBC A dir */
|
|
op1 = get_dir_val();
|
|
if (C)
|
|
A = A - op1 - 1;
|
|
else
|
|
A = A - op1;
|
|
condevalN(A);
|
|
condevalC(A);
|
|
condevalVs(A, op1);
|
|
A &= 0xFF;
|
|
condevalZ(A);
|
|
break;
|
|
case 0x94: /* AND A dir */
|
|
A = (A & get_dir_val()) & 0xFF;
|
|
V = 0;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
break;
|
|
case 0x95: /* BIT A dir */
|
|
lo = (A & get_dir_val()) & 0xFF;
|
|
V = 0;
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
break;
|
|
case 0x96: /* LDA A dir */
|
|
A = get_dir_val();
|
|
V = 0;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
break;
|
|
case 0x97: /* STA A dir */
|
|
mem_put_byte(get_dir_addr(), A);
|
|
V = 0;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
break;
|
|
case 0x98: /* EOR A dir */
|
|
A = (A ^ get_dir_val()) & 0xFF;
|
|
V = 0;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
break;
|
|
case 0x99: /* ADC A dir */
|
|
op1 = get_dir_val();
|
|
if (C)
|
|
A = A + op1 + 1;
|
|
else
|
|
A = A + op1;
|
|
condevalH(A);
|
|
condevalN(A);
|
|
condevalC(A);
|
|
condevalVa(A, op1);
|
|
A &= 0xFF;
|
|
condevalZ(A);
|
|
break;
|
|
case 0x9A: /* ORA A dir */
|
|
A = (A | get_dir_val()) & 0xFF;
|
|
V = 0;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
break;
|
|
case 0x9B: /* ADD A dir */
|
|
op1 = get_dir_val();
|
|
A = A + op1;
|
|
condevalH(A);
|
|
condevalN(A);
|
|
condevalC(A);
|
|
condevalVa(A, op1);
|
|
A &= 0xFF;
|
|
condevalZ(A);
|
|
break;
|
|
case 0x9C: /* CPX dir */
|
|
op1 = IX - mem_get_word(get_dir_addr());
|
|
condevalZ(op1);
|
|
condevalN(op1 >> 8);
|
|
V = op1 & 0x10000;
|
|
break;
|
|
case 0x9E: /* LDS dir */
|
|
SP = mem_get_word(get_dir_addr());
|
|
condevalN(SP >> 8);
|
|
condevalZ(SP);
|
|
V = 0;
|
|
break;
|
|
case 0x9F: /* STS dir */
|
|
mem_put_word(get_dir_addr(), SP);
|
|
condevalN(SP >> 8);
|
|
condevalZ(SP);
|
|
V = 0;
|
|
break;
|
|
case 0xA0: /* SUB A ind */
|
|
op1 = get_indir_val();
|
|
A = A - op1;
|
|
condevalN(A);
|
|
condevalC(A);
|
|
condevalVs(A, op1);
|
|
A &= 0xFF;
|
|
condevalZ(A);
|
|
break;
|
|
case 0xA1: /* CMP A ind */
|
|
op1 = get_indir_val();
|
|
lo = A - op1;
|
|
condevalN(lo);
|
|
condevalZ(lo & 0xFF);
|
|
condevalC(lo);
|
|
condevalVs(A, op1);
|
|
break;
|
|
case 0xA2: /* SBC A ind */
|
|
op1 = get_indir_val();
|
|
if (C)
|
|
A = A - op1 - 1;
|
|
else
|
|
A = A - op1;
|
|
condevalN(A);
|
|
condevalC(A);
|
|
condevalVs(A, op1);
|
|
A &= 0xFF;
|
|
condevalZ(A);
|
|
break;
|
|
case 0xA4: /* AND A ind */
|
|
A = (A & get_indir_val()) & 0xFF;
|
|
V = 0;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
break;
|
|
case 0xA5: /* BIT A ind */
|
|
lo = (A & get_indir_val()) & 0xFF;
|
|
V = 0;
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
break;
|
|
case 0xA6: /* LDA A ind */
|
|
A = get_indir_val();
|
|
V = 0;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
break;
|
|
case 0xA7: /* STA A ind */
|
|
mem_put_byte(get_indir_addr(), A);
|
|
V = 0;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
break;
|
|
case 0xA8: /* EOR A ind */
|
|
A = (A ^ get_indir_val()) & 0xFF;
|
|
V = 0;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
break;
|
|
case 0xA9: /* ADC A ind */
|
|
op1 = get_indir_val();
|
|
if (C)
|
|
A = A + op1 + 1;
|
|
else
|
|
A = A + op1;
|
|
condevalH(A);
|
|
condevalN(A);
|
|
condevalC(A);
|
|
condevalVa(A, op1);
|
|
A &= 0xFF;
|
|
condevalZ(A);
|
|
break;
|
|
case 0xAA: /* ORA A ind */
|
|
A = (A | get_indir_val()) & 0xFF;
|
|
V = 0;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
break;
|
|
case 0xAB: /* ADD A ind */
|
|
op1 = get_indir_val();
|
|
A = A + op1;
|
|
condevalH(A);
|
|
condevalN(A);
|
|
condevalC(A);
|
|
condevalVa(A, op1);
|
|
A &= 0xFF;
|
|
condevalZ(A);
|
|
break;
|
|
case 0xAC: /* CPX ind */
|
|
op1 = (IX - get_indir_addr()) & ADDRMASK;
|
|
condevalZ(op1);
|
|
condevalN(op1 >> 8);
|
|
V = op1 & 0x10000;
|
|
break;
|
|
case 0xAD: /* JSR ind */
|
|
DAR = get_indir_addr();
|
|
SP = (SP - 1) & ADDRMASK;
|
|
mem_put_word(SP, PC);
|
|
SP = (SP - 1) & ADDRMASK;
|
|
PC = DAR;
|
|
break;
|
|
case 0xAE: /* LDS ind */
|
|
SP = mem_get_word(get_indir_addr());
|
|
condevalN(SP >> 8);
|
|
condevalZ(SP);
|
|
V = 0;
|
|
break;
|
|
case 0xAF: /* STS ind */
|
|
mem_put_word(get_indir_addr(), SP);
|
|
condevalN(SP >> 8);
|
|
condevalZ(SP);
|
|
V = 0;
|
|
break;
|
|
case 0xB0: /* SUB A ext */
|
|
op1 = get_ext_val();
|
|
A = A - op1;
|
|
condevalN(A);
|
|
condevalC(A);
|
|
condevalVs(A, op1);
|
|
A &= 0xFF;
|
|
condevalZ(A);
|
|
break;
|
|
case 0xB1: /* CMP A ext */
|
|
op1 = get_ext_val();
|
|
lo = A - op1;
|
|
condevalN(lo);
|
|
condevalZ(lo & 0xFF);
|
|
condevalC(lo);
|
|
condevalVs(A, op1);
|
|
break;
|
|
case 0xB2: /* SBC A ext */
|
|
op1 = get_ext_val();
|
|
if (C)
|
|
A = A - op1 - 1;
|
|
else
|
|
A = A - op1;
|
|
condevalN(A);
|
|
condevalC(A);
|
|
condevalVs(A, op1);
|
|
A &= 0xFF;
|
|
condevalZ(A);
|
|
break;
|
|
case 0xB4: /* AND A ext */
|
|
A = (A & get_ext_val()) & 0xFF;
|
|
V = 0;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
break;
|
|
case 0xB5: /* BIT A ext */
|
|
lo = (A & get_ext_val()) & 0xFF;
|
|
V = 0;
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
break;
|
|
case 0xB6: /* LDA A ext */
|
|
A = get_ext_val();
|
|
V = 0;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
break;
|
|
case 0xB7: /* STA A ext */
|
|
mem_put_byte(get_ext_addr(), A);
|
|
V = 0;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
break;
|
|
case 0xB8: /* EOR A ext */
|
|
A = (A ^ get_ext_val()) & 0xFF;
|
|
V = 0;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
break;
|
|
case 0xB9: /* ADC A ext */
|
|
op1 = get_ext_val();
|
|
if (C)
|
|
A = A + op1 + 1;
|
|
else
|
|
A = A + op1;
|
|
condevalH(A);
|
|
condevalN(A);
|
|
condevalC(A);
|
|
condevalVa(A, op1);
|
|
A &= 0xFF;
|
|
condevalZ(A);
|
|
break;
|
|
case 0xBA: /* ORA A ext */
|
|
A = (A | get_ext_val()) & 0xFF;
|
|
V = 0;
|
|
condevalN(A);
|
|
condevalZ(A);
|
|
break;
|
|
case 0xBB: /* ADD A ext */
|
|
op1 = get_ext_val();
|
|
A = A + op1;
|
|
condevalH(A);
|
|
condevalN(A);
|
|
condevalC(A);
|
|
condevalVa(A, op1);
|
|
A &= 0xFF;
|
|
condevalZ(A);
|
|
break;
|
|
case 0xBC: /* CPX ext */
|
|
op1 = (IX - mem_get_word(get_ext_addr())) & ADDRMASK;
|
|
condevalZ(op1);
|
|
condevalN(op1 >> 8);
|
|
V = op1 & 0x10000;
|
|
break;
|
|
case 0xBD: /* JSR ext */
|
|
DAR = get_ext_addr();
|
|
SP = (SP - 1) & ADDRMASK;
|
|
mem_put_word(SP, PC);
|
|
SP = (SP - 1) & ADDRMASK;
|
|
PC = DAR;
|
|
break;
|
|
case 0xBE: /* LDS ext */
|
|
SP = mem_get_word(get_ext_addr());
|
|
condevalN(SP >> 8);
|
|
condevalZ(SP);
|
|
V = 0;
|
|
break;
|
|
case 0xBF: /* STS ext */
|
|
mem_put_word(get_ext_addr(), SP);
|
|
condevalN(SP >> 8);
|
|
condevalZ(SP);
|
|
V = 0;
|
|
break;
|
|
case 0xC0: /* SUB B imm */
|
|
op1 = get_dir_addr();
|
|
B = B - op1;
|
|
condevalN(B);
|
|
condevalC(B);
|
|
condevalVs(B, op1);
|
|
B &= 0xFF;
|
|
condevalZ(B);
|
|
break;
|
|
case 0xC1: /* CMP B imm */
|
|
op1 = get_dir_addr();
|
|
lo = B - op1;
|
|
condevalN(lo);
|
|
condevalZ(lo & 0xFF);
|
|
condevalC(lo);
|
|
condevalVs(B, op1);
|
|
break;
|
|
case 0xC2: /* SBC B imm */
|
|
op1 = get_dir_addr();
|
|
if (C)
|
|
B = B - op1 - 1;
|
|
else
|
|
B = B - op1;
|
|
condevalN(B);
|
|
condevalC(B);
|
|
condevalVs(B, op1);
|
|
B &= 0xFF;
|
|
condevalZ(B);
|
|
break;
|
|
case 0xC4: /* AND B imm */
|
|
B = (B & get_dir_addr()) & 0xFF;
|
|
V = 0;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
break;
|
|
case 0xC5: /* BIT B imm */
|
|
lo = (B & get_dir_addr()) & 0xFF;
|
|
V = 0;
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
break;
|
|
case 0xC6: /* LDA B imm */
|
|
B = get_dir_addr();
|
|
V = 0;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
break;
|
|
case 0xC8: /* EOR B imm */
|
|
B = (B ^ get_dir_addr()) & 0xFF;
|
|
V = 0;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
break;
|
|
case 0xC9: /* ADC B imm */
|
|
op1 = get_dir_addr();
|
|
if (C)
|
|
B = B + op1 + 1;
|
|
else
|
|
B = B + op1;
|
|
condevalH(B);
|
|
condevalN(B);
|
|
condevalC(B);
|
|
condevalVa(B, op1);
|
|
B &= 0xFF;
|
|
condevalZ(B);
|
|
break;
|
|
case 0xCA: /* ORA B imm */
|
|
B = (B | get_dir_addr()) & 0xFF;
|
|
V = 0;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
break;
|
|
case 0xCB: /* ADD B imm */
|
|
op1 = get_dir_addr();
|
|
B = B + op1;
|
|
condevalH(B);
|
|
condevalN(B);
|
|
condevalC(B);
|
|
condevalVa(B, op1);
|
|
B &= 0xFF;
|
|
condevalZ(B);
|
|
break;
|
|
case 0xCE: /* LDX imm */
|
|
IX = get_ext_addr();
|
|
condevalN(IX >> 8);
|
|
condevalZ(IX);
|
|
V = 0;
|
|
break;
|
|
case 0xD0: /* SUB B dir */
|
|
op1 = get_dir_val();
|
|
B = B - op1;
|
|
condevalN(B);
|
|
condevalC(B);
|
|
condevalVs(B, op1);
|
|
B &= 0xFF;
|
|
condevalZ(B);
|
|
break;
|
|
case 0xD1: /* CMP B dir */
|
|
op1 = get_dir_val();
|
|
lo = B - op1;
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
condevalC(lo);
|
|
condevalVs(B, op1);
|
|
break;
|
|
case 0xD2: /* SBC B dir */
|
|
op1 = get_dir_val();
|
|
if (C)
|
|
B = B - op1 - 1;
|
|
else
|
|
B = B - op1;
|
|
condevalN(B);
|
|
condevalC(B);
|
|
condevalVs(B, op1);
|
|
B &= 0xFF;
|
|
condevalZ(B);
|
|
break;
|
|
case 0xD4: /* AND B dir */
|
|
B = (B & get_dir_val()) & 0xFF;
|
|
V = 0;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
break;
|
|
case 0xD5: /* BIT B dir */
|
|
lo = (B & get_dir_val()) & 0xFF;
|
|
V = 0;
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
break;
|
|
case 0xD6: /* LDA B dir */
|
|
B = get_dir_val();
|
|
V = 0;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
break;
|
|
case 0xD7: /* STA B dir */
|
|
mem_put_byte(get_dir_addr(), B);
|
|
V = 0;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
break;
|
|
case 0xD8: /* EOR B dir */
|
|
B = (B ^ get_dir_val()) & 0xFF;
|
|
V = 0;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
break;
|
|
case 0xD9: /* ADC B dir */
|
|
op1 = get_dir_val();
|
|
if (C)
|
|
B = B + op1 + 1;
|
|
else
|
|
B = B + op1;
|
|
condevalH(B);
|
|
condevalN(B);
|
|
condevalC(B);
|
|
condevalVa(B, op1);
|
|
B &= 0xFF;
|
|
condevalZ(B);
|
|
break;
|
|
case 0xDA: /* ORA B dir */
|
|
B = (B | get_dir_val()) & 0xFF;
|
|
V = 0;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
break;
|
|
case 0xDB: /* ADD B dir */
|
|
op1 = get_dir_val();
|
|
B = B + op1;
|
|
condevalH(B);
|
|
condevalN(B);
|
|
condevalC(B);
|
|
condevalVa(B, op1);
|
|
B &= 0xFF;
|
|
condevalZ(B);
|
|
break;
|
|
case 0xDE: /* LDX dir */
|
|
IX = mem_get_word(get_dir_addr());
|
|
condevalN(IX >> 8);
|
|
condevalZ(IX);
|
|
V = 0;
|
|
break;
|
|
case 0xDF: /* STX dir */
|
|
mem_put_word(get_dir_addr(), IX);
|
|
condevalN(IX >> 8);
|
|
condevalZ(IX);
|
|
V = 0;
|
|
break;
|
|
case 0xE0: /* SUB B ind */
|
|
op1 = get_indir_val();
|
|
B = B - op1;
|
|
condevalN(B);
|
|
condevalC(B);
|
|
condevalVs(B, op1);
|
|
B &= 0xFF;
|
|
condevalZ(B);
|
|
break;
|
|
case 0xE1: /* CMP B ind */
|
|
op1 = get_indir_val();
|
|
lo = B - op1;
|
|
condevalN(lo);
|
|
condevalZ(lo & 0xFF);
|
|
condevalC(lo);
|
|
condevalVs(B, op1);
|
|
break;
|
|
case 0xE2: /* SBC B ind */
|
|
op1 = get_indir_val();
|
|
if (C)
|
|
B = B - op1 - 1;
|
|
else
|
|
B = B - op1;
|
|
condevalN(B);
|
|
condevalC(B);
|
|
condevalVs(B, op1);
|
|
B &= 0xFF;
|
|
condevalZ(B);
|
|
break;
|
|
case 0xE4: /* AND B ind */
|
|
B = (B & get_indir_val()) & 0xFF;
|
|
V = 0;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
break;
|
|
case 0xE5: /* BIT B ind */
|
|
lo = (B & get_indir_val()) & 0xFF;
|
|
V = 0;
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
break;
|
|
case 0xE6: /* LDA B ind */
|
|
B = get_indir_val();
|
|
V = 0;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
break;
|
|
case 0xE7: /* STA B ind */
|
|
mem_put_byte(get_indir_addr(), B);
|
|
V = 0;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
break;
|
|
case 0xE8: /* EOR B ind */
|
|
B = (B ^ get_indir_val()) & 0xFF;
|
|
V = 0;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
break;
|
|
case 0xE9: /* ADC B ind */
|
|
op1 = get_indir_val();
|
|
if (C)
|
|
B = B + op1 + 1;
|
|
else
|
|
B = B + op1;
|
|
condevalH(B);
|
|
condevalN(B);
|
|
condevalC(B);
|
|
condevalVa(B, op1);
|
|
B &= 0xFF;
|
|
condevalZ(B);
|
|
break;
|
|
case 0xEA: /* ORA B ind */
|
|
B = (B | get_indir_val()) & 0xFF;
|
|
V = 0;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
break;
|
|
case 0xEB: /* ADD B ind */
|
|
op1 = get_indir_val();
|
|
B = B + op1;
|
|
condevalH(B);
|
|
condevalN(B);
|
|
condevalC(B);
|
|
condevalVa(B, op1);
|
|
B &= 0xFF;
|
|
condevalZ(B);
|
|
break;
|
|
case 0xEE: /* LDX ind */
|
|
IX = mem_get_word(get_indir_addr());
|
|
condevalN(IX >> 8);
|
|
condevalZ(IX);
|
|
V = 0;
|
|
break;
|
|
case 0xEF: /* STX ind */
|
|
mem_put_word(get_indir_addr(), IX);
|
|
condevalN(IX >> 8);
|
|
condevalZ(IX);
|
|
V = 0;
|
|
break;
|
|
case 0xF0: /* SUB B ext */
|
|
op1 = get_ext_val();
|
|
B = B - op1;
|
|
condevalN(B);
|
|
condevalC(B);
|
|
condevalVs(B, op1);
|
|
B &= 0xFF;
|
|
condevalZ(B);
|
|
break;
|
|
case 0xF1: /* CMP B ext */
|
|
op1 = get_ext_val();
|
|
lo = B - op1;
|
|
condevalN(lo);
|
|
condevalZ(lo & 0xFF);
|
|
condevalC(lo);
|
|
condevalVs(B, op1);
|
|
break;
|
|
case 0xF2: /* SBC B ext */
|
|
op1 = get_ext_val();
|
|
if (C)
|
|
B = B - op1 - 1;
|
|
else
|
|
B = B - op1;
|
|
condevalN(B);
|
|
condevalC(B);
|
|
condevalVs(B, op1);
|
|
B &= 0xFF;
|
|
condevalZ(B);
|
|
break;
|
|
case 0xF4: /* AND B ext */
|
|
B = (B & get_ext_val()) & 0xFF;
|
|
V = 0;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
break;
|
|
case 0xF5: /* BIT B ext */
|
|
lo = (B & get_ext_val()) & 0xFF;
|
|
V = 0;
|
|
condevalN(lo);
|
|
condevalZ(lo);
|
|
break;
|
|
case 0xF6: /* LDA B ext */
|
|
B = get_ext_val();
|
|
V = 0;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
break;
|
|
case 0xF7: /* STA B ext */
|
|
mem_put_byte(get_ext_addr(), B);
|
|
V = 0;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
break;
|
|
case 0xF8: /* EOR B ext */
|
|
B = (B ^ get_ext_val()) & 0xFF;
|
|
V = 0;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
break;
|
|
case 0xF9: /* ADC B ext */
|
|
op1 = get_ext_val();
|
|
if (C)
|
|
B = B + op1 + 1;
|
|
else
|
|
B = B + op1;
|
|
condevalH(B);
|
|
condevalN(B);
|
|
condevalC(B);
|
|
condevalVa(B, op1);
|
|
B &= 0xFF;
|
|
condevalZ(B);
|
|
break;
|
|
case 0xFA: /* ORA B ext */
|
|
B = (B | get_ext_val()) & 0xFF;
|
|
V = 0;
|
|
condevalN(B);
|
|
condevalZ(B);
|
|
break;
|
|
case 0xFB: /* ADD B ext */
|
|
op1 = get_ext_val();
|
|
B = B + op1;
|
|
condevalH(B);
|
|
condevalN(B);
|
|
condevalC(B);
|
|
condevalVa(B, op1);
|
|
B &= 0xFF;
|
|
condevalZ(B);
|
|
break;
|
|
case 0xFE: /* LDX ext */
|
|
IX = mem_get_word(get_ext_addr());
|
|
condevalN(IX >> 8);
|
|
condevalZ(IX);
|
|
V = 0;
|
|
break;
|
|
case 0xFF: /* STX ext */
|
|
mem_put_word(get_ext_addr(), IX);
|
|
condevalN(IX >> 8);
|
|
condevalZ(IX);
|
|
V = 0;
|
|
break;
|
|
|
|
default: { /* Unassigned */
|
|
if (cpu_unit.flags & UNIT_OPSTOP) {
|
|
reason = STOP_OPCODE;
|
|
PC--;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/* Simulation halted - lets dump all the registers! */
|
|
dump_regs();
|
|
saved_PC = PC;
|
|
return reason;
|
|
}
|
|
|
|
/* dump the working registers */
|
|
|
|
void dump_regs()
|
|
{
|
|
printf("\r\nPC=%04X SP=%04X IX=%04X ", PC, SP, IX);
|
|
printf("A=%02X B=%02X PSW=%02X", A, B, get_psw());
|
|
}
|
|
|
|
/* this routine does the jump to relative offset if the condition is
|
|
met. Otherwise, execution continues at the current PC. */
|
|
|
|
void go_rel(int32 cond)
|
|
{
|
|
int32 temp;
|
|
|
|
temp = get_rel_addr();
|
|
if (cond)
|
|
PC += temp;
|
|
PC &= ADDRMASK;
|
|
}
|
|
|
|
/* returns the relative offset sign-extended */
|
|
|
|
int32 get_rel_addr()
|
|
{
|
|
int32 temp;
|
|
|
|
temp = mem_get_byte(PC++);
|
|
if (temp & 0x80)
|
|
temp |= 0xFF00;
|
|
return temp & ADDRMASK;
|
|
}
|
|
|
|
/* returns the value at the direct address pointed to by PC */
|
|
|
|
int32 get_dir_val()
|
|
{
|
|
return mem_get_byte(get_dir_addr());
|
|
}
|
|
|
|
/* returns the direct address pointed to by PC */
|
|
|
|
int32 get_dir_addr()
|
|
{
|
|
int32 temp;
|
|
|
|
temp = mem_get_byte(PC);
|
|
PC = (PC + 1) & ADDRMASK;
|
|
return temp & 0xFF;
|
|
}
|
|
|
|
/* returns the value at the indirect address pointed to by PC */
|
|
|
|
int32 get_indir_val()
|
|
{
|
|
return mem_get_byte(get_indir_addr());
|
|
}
|
|
|
|
/* returns the indirect address pointed to by PC or immediate byte */
|
|
|
|
int32 get_indir_addr()
|
|
{
|
|
int32 temp;
|
|
|
|
temp = (mem_get_byte(PC++) + IX) & ADDRMASK;
|
|
PC &= ADDRMASK;
|
|
return temp;
|
|
}
|
|
|
|
/* returns the value at the extended address pointed to by PC */
|
|
|
|
int32 get_ext_val()
|
|
{
|
|
return mem_get_byte(get_ext_addr());
|
|
}
|
|
|
|
/* returns the extended address pointed to by PC or immediate word */
|
|
|
|
int32 get_ext_addr()
|
|
{
|
|
int32 temp;
|
|
|
|
temp = (mem_get_byte(PC) << 8) | mem_get_byte(PC+1);
|
|
PC = (PC +2) & ADDRMASK;
|
|
return temp;
|
|
}
|
|
|
|
/* return a PSW from the current flags */
|
|
|
|
int32 get_psw()
|
|
{
|
|
int32 psw;
|
|
|
|
psw = 0xC0;
|
|
if (H)
|
|
psw |= 0x20;
|
|
if (I)
|
|
psw |= 0x10;
|
|
if (N)
|
|
psw |= 0x08;
|
|
if (Z)
|
|
psw |= 0x04;
|
|
if (V)
|
|
psw |= 0x02;
|
|
if (C)
|
|
psw |= 0x01;
|
|
return psw;
|
|
}
|
|
|
|
/* set the current flags from a PSW */
|
|
|
|
void set_psw(int32 psw)
|
|
{
|
|
H = 0;
|
|
if (psw & 0x20)
|
|
H = 0x10000;
|
|
I = 0;
|
|
if (psw & 0x10)
|
|
I = 0x10000;
|
|
N = 0;
|
|
if (psw & 0x08)
|
|
N = 0x10000;
|
|
Z = 0;
|
|
if (psw & 0x04)
|
|
Z = 0x10000;
|
|
V = 0;
|
|
if (psw & 0x02)
|
|
V = 0x10000;
|
|
C = 0;
|
|
if (psw & 0x01)
|
|
C = 0x10000;
|
|
}
|
|
|
|
/* test and set H */
|
|
|
|
void condevalH(int32 res)
|
|
{
|
|
H = (res & 0x10) << 12;
|
|
}
|
|
|
|
/* test and set N */
|
|
|
|
void condevalN(int32 res)
|
|
{
|
|
N = 0;
|
|
if (res & 0x80)
|
|
N = 0x10000;
|
|
}
|
|
|
|
/* test and set Z */
|
|
|
|
void condevalZ(int32 res)
|
|
{
|
|
Z = 0;
|
|
if (res == 0)
|
|
Z = 0x10000;
|
|
}
|
|
|
|
/* test and set V for addition */
|
|
|
|
void condevalVa(int32 op1, int32 op2)
|
|
{
|
|
if (C) {
|
|
V = 0;
|
|
if (((op1 & 0x80) && (op2 & 0x80)) ||
|
|
(((op1 & 0x80) == 0) && ((op2 & 0x80) == 0)))
|
|
V = 0x10000;
|
|
}
|
|
}
|
|
|
|
/* test and set V for subtraction */
|
|
|
|
void condevalVs(int32 op1, int32 op2)
|
|
{
|
|
if (C) {
|
|
V = 0;
|
|
if (((op1 & 0x80) && ((op2 & 0x80) == 0)) ||
|
|
(((op1 & 0x80) == 0) && (op2 & 0x80)))
|
|
V = 0x10000;
|
|
}
|
|
}
|
|
|
|
/* test and set C */
|
|
|
|
void condevalC(int32 res)
|
|
{
|
|
C = (res & 0x100) << 8;
|
|
}
|
|
|
|
/* memory write operations */
|
|
|
|
/* put word */
|
|
|
|
void mem_put_word(int32 addr, int32 val)
|
|
{
|
|
mem_put_byte(addr,val >> 8);
|
|
mem_put_byte(addr + 1, val);
|
|
}
|
|
|
|
/* put byte */
|
|
|
|
void mem_put_byte(int32 addr, int32 val)
|
|
{
|
|
if (addr >= 0x0000 && addr < (int32) MEMSIZE) /* memory cards */
|
|
M[addr] = val & 0xFF;
|
|
else if (addr >= 0x8000 && addr < 0x8020) /* memory mapped I/O */
|
|
dev_table[addr - 0x8000].routine(1, val);
|
|
else if (addr >= 0xA000 && addr < 0xA080) /* CPU memory */
|
|
M[addr] = val & 0xFF;
|
|
else if ((addr >= 0xA080 && addr < 0xC000) && /* extended CPU memory */
|
|
cpu_unit.flags & UNIT_MA000)
|
|
M[addr] = val & 0xFF;
|
|
else {
|
|
if (cpu_unit.flags & UNIT_MSTOP)
|
|
mem_fault = 1;
|
|
printf("Invalid write to %04X\n\r", addr);
|
|
}
|
|
}
|
|
|
|
/* memory read operations */
|
|
|
|
/* get word */
|
|
|
|
int32 mem_get_word(int32 addr)
|
|
{
|
|
int32 temp;
|
|
|
|
temp = (mem_get_byte(addr) << 8) | mem_get_byte(addr+1);
|
|
return temp;
|
|
}
|
|
|
|
/* get byte */
|
|
|
|
int32 mem_get_byte(int32 addr)
|
|
{
|
|
int32 val;
|
|
|
|
if (addr >= 0x0000 && addr < (int32) MEMSIZE) /* memory cards */
|
|
val = M[addr];
|
|
else if (addr >= 0x8000 && addr < 0x8020) /* memory mapped I/O */
|
|
val = dev_table[addr - 0x8000].routine(0, 0);
|
|
else if (addr >= 0xA000 && addr < 0xA080) /* CPU memory */
|
|
val = M[addr];
|
|
else if ((addr >= 0xA080 && addr < 0xC000) && /* extended CPU memory */
|
|
cpu_unit.flags & UNIT_MA000)
|
|
val = M[addr];
|
|
else if (addr >= 0xE000 && addr < 0x10000) /* ROM memory */
|
|
val = M[addr];
|
|
else {
|
|
if (cpu_unit.flags & UNIT_MSTOP)
|
|
mem_fault = 1;
|
|
val = 0xFF; /* default for no memory at address */
|
|
printf("Invalid read of %04X\n\r", addr);
|
|
}
|
|
return val & 0xFF;
|
|
}
|
|
|
|
/* calls from the simulator */
|
|
|
|
/* Reset routine */
|
|
|
|
t_stat cpu_reset (DEVICE *dptr)
|
|
{
|
|
int i;
|
|
|
|
I = 0x10000;
|
|
saved_PC = (M[0xFFFE] << 8) | M[0xFFFF];
|
|
int_req = 0;
|
|
sim_brk_types = sim_brk_dflt = SWMASK ('E');
|
|
/* copy in rom image at E000 */
|
|
for (i = 0; i < BOOTLEN; i++) {
|
|
M[i + 0xE000] = bootrom[i] & 0xFF;
|
|
}
|
|
/* copy in rom image at FC00 for vectors! */
|
|
for (i = 0; i < BOOTLEN; i++) {
|
|
M[i + 0xFC00] = bootrom[i] & 0xFF;
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Memory examine */
|
|
|
|
t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
|
|
{
|
|
if (addr >= MAXMEMSIZE)
|
|
return SCPE_NXM;
|
|
if (vptr != NULL)
|
|
*vptr = mem_get_byte(addr);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Memory deposit */
|
|
|
|
t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
|
|
{
|
|
if (addr >= MAXMEMSIZE)
|
|
return SCPE_NXM;
|
|
mem_put_byte(addr, val);
|
|
// printf("Deposit to %04X of %02X\n\r", addr, val);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* adjust the memory size for the emulator 4k to 32k in 4k steps */
|
|
|
|
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
|
|
{
|
|
int32 mc = 0;
|
|
uint32 i;
|
|
|
|
if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 0x0FFF) != 0))
|
|
return SCPE_ARG;
|
|
for (i = val; i < MEMSIZE; i++)
|
|
mc = mc | M[i];
|
|
if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
|
|
return SCPE_OK;
|
|
MEMSIZE = val;
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* dummy i/o device */
|
|
|
|
int32 nulldev(int32 io, int32 data)
|
|
{
|
|
if (io == 0)
|
|
return (0xFF);
|
|
return 0;
|
|
}
|
|
|