From 033805fd3cf463b56f368e7347ad95f85e7d0a19 Mon Sep 17 00:00:00 2001 From: rfromafar Date: Sun, 18 Feb 2024 19:54:15 -0600 Subject: [PATCH 01/10] Richard Lukes - 18 FEB 2024 This is my initial commit of my swtp6809 emulator which is a modified version of the swtp6800 emulator. The following changes are still outstanding: - various code clean up tasks and removal of temporary comments - bootrom.c - reset() appears to be performing attach() funtion, I plan to clean up soon - mp-b3.c - want to add #define for 4 bytes per slot versus 16 bytes per slot - dc-4.c - trying to understand the changes I made from the original dc-4.c in the swtp6800 emulator - I will do additional testing, however, for now this boots Flex 9.0 and appears to be working fine --- makefile | 20 +- swtp6809/common/bootrom.c | 346 +++ swtp6809/common/dc-4.c | 657 ++++++ swtp6809/common/m6809.c | 3356 +++++++++++++++++++++++++++ swtp6809/common/mp-09.c | 283 +++ swtp6809/common/mp-1m.c | 221 ++ swtp6809/common/mp-b3.c | 287 +++ swtp6809/common/mp-s.c | 381 +++ swtp6809/swtp6809/mp-09_sys.c | 89 + swtp6809/swtp6809/swtp6809mp-09.ini | 16 + swtp6809/swtp6809/swtp_defs.h | 64 + swtp6809/swtp6809/swtp_sbuge_bin.h | 141 ++ 12 files changed, 5860 insertions(+), 1 deletion(-) create mode 100644 swtp6809/common/bootrom.c create mode 100644 swtp6809/common/dc-4.c create mode 100644 swtp6809/common/m6809.c create mode 100644 swtp6809/common/mp-09.c create mode 100644 swtp6809/common/mp-1m.c create mode 100644 swtp6809/common/mp-b3.c create mode 100644 swtp6809/common/mp-s.c create mode 100644 swtp6809/swtp6809/mp-09_sys.c create mode 100644 swtp6809/swtp6809/swtp6809mp-09.ini create mode 100644 swtp6809/swtp6809/swtp_defs.h create mode 100644 swtp6809/swtp6809/swtp_sbuge_bin.h diff --git a/makefile b/makefile index 1167f83aa..2236c2af0 100644 --- a/makefile +++ b/makefile @@ -1957,6 +1957,15 @@ SWTP6800MP-A2 = ${SWTP6800C}/mp-a2.c ${SWTP6800C}/m6800.c ${SWTP6800C}/m6810.c \ ${SWTP6800C}/mp-s.c ${SWTP6800C}/mp-b2.c SWTP6800_OPT = -I ${SWTP6800D} + +SWTP6809D = ${SIMHD}/swtp6809/swtp6809 +SWTP6809C = ${SIMHD}/swtp6809/common +SWTP6809MP-09 = ${SWTP6809C}/mp-09.c ${SWTP6809C}/m6809.c \ + ${SWTP6809C}/bootrom.c ${SWTP6809C}/dc-4.c ${SWTP6809D}/mp-09_sys.c \ + ${SWTP6809C}/mp-1m.c ${SWTP6809C}/mp-b3.c \ + ${SWTP6809C}/mp-s.c +SWTP6809_OPT = -I ${SWTP6809D} + INTELSYSD = ${SIMHD}/Intel-Systems INTELSYSC = ${SIMHD}/Intel-Systems/common @@ -2207,7 +2216,7 @@ ALL = pdp1 pdp4 pdp7 pdp8 pdp9 pdp15 pdp11 pdp10 \ microvax3100m80 vaxstation4000vlc infoserver1000 \ nd100 nova eclipse hp2100 hp3000 i1401 i1620 s3 altair altairz80 gri \ i7094 ibm1130 id16 id32 sds lgp h316 cdc1700 \ - swtp6800mp-a swtp6800mp-a2 tx-0 ssem b5500 intel-mds \ + swtp6800mp-a swtp6800mp-a2 swtp6809mp-09 tx-0 ssem b5500 intel-mds \ scelbi 3b2 3b2-700 i701 i704 i7010 i7070 i7080 i7090 \ sigma uc15 pdp10-ka pdp10-ki pdp10-kl pdp10-ks pdp6 i650 \ imlac tt2500 sel32 @@ -2745,6 +2754,15 @@ ifneq (,$(call find_test,${SWTP6800D},swtp6800mp-a2)) $@ $(call find_test,${SWTP6800D},swtp6800mp-a2) ${TEST_ARG} endif +swtp6809mp-09 : ${BIN}swtp6809mp-09${EXE} + +${BIN}swtp6809mp-09${EXE} : ${SWTP6809MP-09} ${SIM} ${BUILD_ROMS} + ${MKDIRBIN} + ${CC} ${SWTP6809MP-09} ${SIM} ${SWTP6809_OPT} ${CC_OUTSPEC} ${LDFLAGS} +ifneq (,$(call find_test,${SWTP6800D},swtp6800mp-a2)) + $@ $(call find_test,${SWTP6809D},swtp6800mp-09) ${TEST_ARG} +endif + intel-mds: ${BIN}intel-mds${EXE} ${BIN}intel-mds${EXE} : ${INTEL_MDS} ${SIM} ${BUILD_ROMS} diff --git a/swtp6809/common/bootrom.c b/swtp6809/common/bootrom.c new file mode 100644 index 000000000..d1ac5b5fd --- /dev/null +++ b/swtp6809/common/bootrom.c @@ -0,0 +1,346 @@ +/* bootrom.c: Boot ROM simulator for Motorola processors + + Copyright (c) 2010-2012, William A. 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. + + MODIFICATIONS: + + 23 Apr 15 -- Modified to use simh_debug + 19 Feb 24 -- Richard Lukes - Modified for swtp6809 emulator + + NOTES: + + These functions support a single simulated 2704 to 2764 EPROM device on + an 8-bit computer system.. This device allows the buffer to be loaded from + a binary file containing the emulated EPROM code. + + These functions support a simulated 2704(0.5KB), 2708(1KB), 2716(2KB), 2732(4KB) or 2764(8KB) EPROM + device at the top of the 16-bit address space. The base address of the ROM varies depends on the size. + For example, The 2764 BOOTROM is mapped from $E000 to $FFFF less the I/O range reserved by the MP-B3 motherboard. + The 2716 BOOTROM is mapped from $F800 to $FFFF. + The last byte of the ROM is always stored at $FFFF + + The device type is stored as a binary number in the first three unit flag bits. + + This device uses a statically allocated buffer to hold the EPROM image. All bytes are initialized to $FF. + A call to BOOTROM_attach will load the buffer with the EPROM image. + +*/ + +#include +#include "swtp_defs.h" + +#define DONT_USE_INTERNAL_ROM + +#if !defined(DONT_USE_INTERNAL_ROM) +#include "swtp_sbuge_bin.h" +#endif /* DONT_USE_INTERNAL_ROM */ + +#define UNIT_V_MSIZE (UNIT_V_UF) /* ROM Size */ +#define UNIT_MSIZE (0x7 << UNIT_V_MSIZE) +#define UNIT_NONE (0 << UNIT_V_MSIZE) /* No EPROM */ +#define UNIT_2704 (1 << UNIT_V_MSIZE) /* 2704 mode */ +#define UNIT_2708 (2 << UNIT_V_MSIZE) /* 2708 mode */ +#define UNIT_2716 (3 << UNIT_V_MSIZE) /* 2716 mode */ +#define UNIT_2732 (4 << UNIT_V_MSIZE) /* 2732 mode */ +#define UNIT_2764 (5 << UNIT_V_MSIZE) /* 2764 mode */ + +#define BOOTROM_2K 0x0800 +#define BOOTROM_4K 0x1000 +#define BOOTROM_8K 0x2000 + +/* function prototypes */ + +t_stat BOOTROM_attach (UNIT *uptr, CONST char *cptr); +t_stat BOOTROM_config (UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat BOOTROM_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); +t_stat BOOTROM_reset (DEVICE *dptr); +//t_stat BOOTROM_svc (UNIT *uptr); + +int32 BOOTROM_get_mbyte(int32 address); + +/* SIMH Standard I/O Data Structures */ + +UNIT BOOTROM_unit = { +#if defined(DONT_USE_INTERNAL_ROM) + UDATA (NULL, UNIT_ATTABLE+UNIT_BINK+UNIT_ROABLE+UNIT_RO, 0), +#else /* !defined(DONT_USE_INTERNAL_ROM) */ + UDATA (NULL, UNIT_ATTABLE+UNIT_BINK+UNIT_ROABLE+UNIT_RO+((BOOT_CODE_SIZE>>9)<= BOOTROM_8K) { + return SCPE_NXM; + } + if (eval_array != NULL) { + *eval_array = BOOTROM_memory_array[addr] & 0xFF; + } + return SCPE_OK; + +} /* BOOTROM_examin() */ + +/* BOOTROM_attach - attach file to EPROM unit */ +t_stat BOOTROM_attach (UNIT *uptr, CONST char *cptr) +{ + t_stat r; + t_addr image_size, capac; + int i; + +//RICHARD WAS HERE +printf("calling BOOTROM_attach\n"); + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_attach: cptr=%s\n", cptr); + if ((r = attach_unit (uptr, cptr)) != SCPE_OK) { + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_attach: Error\n"); + return r; + } + image_size = (t_addr)sim_fsize_ex (BOOTROM_unit.fileref); + if (image_size <= 0) { + sim_printf("BOOTROM_attach: File error\n"); + return SCPE_IOERR; + } + for (capac = 0x200, i=1; capac < image_size; capac <<= 1, i++); + if (i > (UNIT_2764>>UNIT_V_MSIZE)) { + detach_unit (uptr); + return SCPE_ARG; + } + uptr->flags &= ~UNIT_MSIZE; + uptr->flags |= (i << UNIT_V_MSIZE); + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_attach: Done\n"); +//RICHARD WAS HERE + return (BOOTROM_reset (NULL)); + return SCPE_OK; +} /* BOOTROM_attach() */ + +/* BOOTROM_config = None, 2704, 2708, 2716, 2732 or 2764 */ +t_stat BOOTROM_config (UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ +//RICHARD WAS HERE +printf("calling BOOTROM_config\n"); + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: val=%d\n", val); + if ((val < UNIT_NONE) || (val > UNIT_2764)) { /* valid param? */ + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: Parameter error\n"); + return SCPE_ARG; + } + if (val == UNIT_NONE) + BOOTROM_unit.capac = 0; /* set EPROM size */ + else + BOOTROM_unit.capac = 0x200 << ((val >> UNIT_V_MSIZE) - 1); /* set EPROM size */ + if (BOOTROM_unit.filebuf) { /* free buffer */ + //free (BOOTROM_unit.filebuf); + BOOTROM_unit.filebuf = NULL; + } + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: BOOTROM_unit.capac=%d\n", + BOOTROM_unit.capac); + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: Done\n"); + return SCPE_OK; +} /* BOOTROM config */ + +/* BOOTROM reset */ +t_stat BOOTROM_reset (DEVICE *dptr) +{ + t_addr i,j; + unsigned long c; + long count; + FILE *fp; + uint8 *pa; + +//RICHARD WAS HERE +printf("calling BOOTROM_reset\n"); + /* initialize array to $FF */ + for (i=0; i BOOTROM_unit.capac) { + printf("\tImage is too large - Load truncated!!!\n"); + j--; + break; + } + } + fclose(fp); + + /* warn if loaded ROM image is smaller than the specified ROM size */ + if (j < BOOTROM_unit.capac) { + printf("\tImage is smaller than specified ROM size!!!\n"); + } + + printf("\t%d bytes of ROM image %s loaded\n", j, BOOTROM_unit.filename); + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_reset: Done2\n"); + return SCPE_OK; +} /* BOOTROM_reset() */ + +/* get a byte from memory - from specified memory address */ +int32 BOOTROM_get_mbyte(int32 address) +{ + int32 val; + uint8 *pa; + + if (BOOTROM_unit.filebuf == NULL) { + sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: EPROM not configured\n"); + return 0xFF; + } + sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: address=%04X\n", address); + if ((t_addr)(0xFFFF - address) > BOOTROM_unit.capac) { + sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: EPROM reference beyond ROM size\n"); + return 0xFF; + } + pa = BOOTROM_unit.filebuf; + /* the following code is needed to calculate offsets so address $FFFF references the last byte of the ROM */ + val = 0xFF; + switch (BOOTROM_unit.capac) { + /* 2764 - $E000-$FFFF */ + case 0x2000: + val = pa[address - 0xE000]; + break; + /* 2732 - $F000-$FFFF */ + case 0x1000: + if (address >=0xF000) { + val = pa[address - 0xF000]; + } + break; + /* 2716 - $F800-$FFFF */ + case 0x0800: + if (address >= 0xF800) { + val = pa[address - 0xF800]; + } + break; + /* 2708 - $FC00-$FFFF */ + case 0x0400: + if (address >= 0xFC00) { + val = pa[address - 0xFC00]; + } + break; + /* 2704 - $FE00-$FFFF*/ + case 0x0200: + if (address >= 0xFE00) { + val = pa[address - 0xFE00]; + } + break; + default: + break; + } + val &= 0xFF; + sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: Normal val=%02X\n", val); + return val; +} /* BOOTROM_get_mbyte() */ + +/* end of bootrom.c */ diff --git a/swtp6809/common/dc-4.c b/swtp6809/common/dc-4.c new file mode 100644 index 000000000..5304358c1 --- /dev/null +++ b/swtp6809/common/dc-4.c @@ -0,0 +1,657 @@ +/* dc4.c: SWTP DC-4 FDC Simulator + + Copyright (c) 2005-2012, William A. 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. + + MODIFICATIONS: + + 23 Apr 15 -- Modified to use simh_debug + 19 Feb 24 -- Richard Lukes - Modified to work with swtp6809 emulator + + NOTES: + + The DC-4 is a 5-inch floppy controller which can control up + to 4 daisy-chained 5-inch floppy drives. The controller is based on + the Western Digital 1797 Floppy Disk Controller (FDC) chip. This + file only emulates the minimum DC-4 functionality to interface with + the virtual disk file. + + The floppy controller is interfaced to the CPU by use of 5 memory + addreses. These are SS-30 slot numbers 5 and 6 (0xE014-0xE01B) on a SWTPC 6809 computer. + + Address Mode Function + ------- ---- -------- + + 0xE014 Read Returns FDC interrupt status + 0xE014 Write Selects the drive/head/motor control + 0xE018 Read Returns status of FDC + 0xE018 Write FDC command register + 0xE019 Read Returns FDC track register + 0xE019 Write Set FDC track register + 0xE01A Read Returns FDC sector register + 0xE01A Write Set FDC sector register + 0xE01B Read Read data + 0xE01B Write Write data + + Drive Select Read (0xE014): + + +---+---+---+---+---+---+---+---+ + | I | D | X | X | X | X | X | X | + +---+---+---+---+---+---+---+---+ + + I = Set indicates an interrupt request from the FDC pending. + D = DRQ pending - same as bit 1 of FDC status register. + + Drive Select Write (0xE014): + + +---+---+---+---+---+---+---+---+ + | M | S | X | X | X | X | Device| + +---+---+---+---+---+---+---+---+ + + M = If this bit is 1, the one-shot is triggered/retriggered to + start/keep the motors on. + S = Side select. If set, side one is selected otherwise side zero + is selected. + X = not used + Device = value 0 thru 3, selects drive 0-3 to be controlled. + + Drive Status Read (0xE018): + + +---+---+---+---+---+---+---+---+ + | R | P | H | S | C | L | D | B | + +---+---+---+---+---+---+---+---+ + + B - When 1, the controller is busy. + D - When 1, index mark detected (type I) or data request - read data + ready/write data empty (type II or III). + H - When 1, track 0 (type I) or lost data (type II or III). + C - When 1, crc error detected. + S - When 1, seek (type I) or RNF (type II or III) error. + H - When 1, head is currently loaded (type I) or record type/ + write fault (type II or III). + P - When 1, indicates that diskette is write-protected. + R - When 1, drive is not ready. + + Drive Control Write (0xE018) for type I commands: + + +---+---+---+---+---+---+---+---+ + | 0 | S2| S1| S0| H | V | R1| R0| + +---+---+---+---+---+---+---+---+ + + R0/R1 - Selects the step rate. + V - When 1, verify on destination track. + H - When 1, loads head to drive surface. + S0/S1/S2 = 000 - home. + 001 - seek track in data register. + 010 - step without updating track register. + 011 - step and update track register. + 100 - step in without updating track register. + 101 - step in and update track register. + 110 - step out without updating track register. + 111 - step out and update track register. + + Drive Control Write (0xE018) for type II commands: + + +---+---+---+---+---+---+---+---+ + | 1 | 0 | T | M | S | E | B | A | + +---+---+---+---+---+---+---+---+ + + A - Zero for read, 1 on write deleted data mark else data mark. + B - When 1, shifts sector length field definitions one place. + E - When, delay operation 15 ms, 0 no delay. + S - When 1, select side 1, 0 select side 0. + M - When 1, multiple records, 0 for single record. + T - When 1, write command, 0 for read. + + Drive Control Write (0xE018) for type III commands: + + +---+---+---+---+---+---+---+---+ + | 1 | 1 | T0| T1| 0 | E | 0 | 0 | + +---+---+---+---+---+---+---+---+ + + E - When, delay operation 15 ms, 0 no delay. + T0/T1 - 00 - read address command. + 10 - read track command. + 11 - write track command. + + Tracks are numbered from 0 up to one minus the last track in the 1797! + + Track Register Read (0xE019): + + +---+---+---+---+---+---+---+---+ + | Track Number | + +---+---+---+---+---+---+---+---+ + + Reads the current 8-bit value from the track position. + + Track Register Write (0xE019): + + +---+---+---+---+---+---+---+---+ + | Track Number | + +---+---+---+---+---+---+---+---+ + + Writes the 8-bit value to the track register. + + Sectors are numbers from 1 up to the last sector in the 1797! + + Sector Register Read (0xE01A): + + +---+---+---+---+---+---+---+---+ + | Sector Number | + +---+---+---+---+---+---+---+---+ + + Reads the current 8-bit value from the sector position. + + Sector Register Write (0xE01A): + + +---+---+---+---+---+---+---+---+ + | Sector Number | + +---+---+---+---+---+---+---+---+ + + Writes the 8-bit value to the sector register. + + Data Register Read (0xE01B): + + +---+---+---+---+---+---+---+---+ + | Data | + +---+---+---+---+---+---+---+---+ + + Reads the current 8-bit value from the data register. + + Data Register Write (0xE01B): + + +---+---+---+---+---+---+---+---+ + | Data | + +---+---+---+---+---+---+---+---+ + + Writes the 8-bit value to the data register. + + A FLEX disk is defined as follows: + + Track Sector Use + 0 1 Boot sector + 0 2 Boot sector (cont) + 0 3 Unused (doesn't exist) + 0 4 System Identity Record (explained below) + 0 5 Unused + 0 6-last Directory - 10 entries/sector (explained below) + 1 1 First available data sector + last-1 last Last available data sector + + System Identity Record + + Byte Use + 0x00 Two bytes of zeroes (Clears forward link) + 0x10 Volume name in ASCII(11 bytes) + 0x1B Volume number in binary (2 bytes) + 0x1D Address of first free data sector (Track-Sector) (2 bytes) + 0x1F Address of last free data sector (Track-Sector) (2 bytes) + 0x21 Total number of data sectors in binary (2 bytes) + 0x23 Current date (Month-Day-Year) in binary + 0x26 Highest track number on disk in binary (byte) + 0x27 Highest sector number on a track in binary (byte) + + The following unit registers are used by this controller emulation: + + dsk_unit[cur_drv].u3 unit current flags + dsk_unit[cur_drv].u4 unit current track + dsk_unit[cur_drv].u5 unit current sector + dsk_unit[cur_drv].pos unit current sector byte index into buffer + dsk_unit[cur_drv].filebuf unit current sector buffer + dsk_unit[cur_drv].fileref unit current attached file reference +*/ + +#include +#include "swtp_defs.h" + +#define DEBUG 0 + +#define UNIT_V_ENABLE (UNIT_V_UF + 0) /* Write Enable */ +#define UNIT_ENABLE (1 << UNIT_V_ENABLE) + +/* maximum of 4 disks, sector size is fixed at 256 bytes */ + +#define NUM_DISK 4 /* standard 1797 maximum */ +#define SECT_SIZE 256 /* standard FLEX sector */ + +/* SIR offsets */ +#define MAXCYL 0x26 /* last cylinder # */ +#define MAXSEC 0x27 /* last sector # */ + +/* 1797 status bits */ + +#define BUSY 0x01 +#define DRQ 0x02 +#define WRPROT 0x40 +#define NOTRDY 0x80 + +/* function prototypes */ + +t_stat dsk_reset (DEVICE *dptr); + +/* SS-50 I/O address space functions */ + +int32 fdcdrv(int32 io, int32 data); +int32 fdccmd(int32 io, int32 data); +int32 fdctrk(int32 io, int32 data); +int32 fdcsec(int32 io, int32 data); +int32 fdcdata(int32 io, int32 data); + +/* Local Variables */ + +int32 fdcbyte; +int32 intrq = 0; /* interrupt request flag */ +int32 cur_dsk; /* Currently selected drive */ +int32 wrt_flag = 0; /* FDC write flag */ + +int32 spt; /* sectors/track */ +int32 trksiz; /* trk size (bytes) */ +int32 heds; /* number of heads */ +int32 cpd; /* cylinders/disk */ +int32 dsksiz; /* dsk size (bytes) */ + +/* Floppy Disk Controller data structures + + dsk_dev Mother Board device descriptor + dsk_unit Mother Board unit descriptor + dsk_reg Mother Board register list + dsk_mod Mother Board modifiers list +*/ + +UNIT dsk_unit[] = { + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) } +}; + +REG dsk_reg[] = { + { HRDATA (DISK, cur_dsk, 4) }, + { NULL } +}; + +MTAB dsk_mod[] = { + { UNIT_ENABLE, UNIT_ENABLE, "RW", "RW", NULL }, + { UNIT_ENABLE, 0, "RO", "RO", NULL }, + { 0 } +}; + +DEBTAB dsk_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE dsk_dev = { + "DC-4", //name + dsk_unit, //units + dsk_reg, //registers + dsk_mod, //modifiers + NUM_DISK, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + &dsk_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + dsk_debug, /* debflags */ + NULL, //msize + NULL //lname +}; + +/* Reset routine */ + +t_stat dsk_reset (DEVICE *dptr) +{ + int i; + +// RICHARD WAS HERE + cur_dsk = 5; /* force initial SIR read, use a drive # that can't be selected */ + + for (i=0; i Accumulator A + B<0:7> Accumulator B + IX<0:15> Index Register + IY<0:15> Index Register + CCR<0:7> Condition Code Register + EF Entire flag + FF FIRQ flag + HF half-carry flag + IF IRQ flag + NF negative flag + ZF zero flag + VF overflow flag + CF carry flag + PC<0:15> program counter + UP<0:15> User Stack Pointer + SP<0:15> Stack Pointer + + The M6809 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 M6809. + It is called from the CPU board simulator 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 6809, reads to non-existent memory + return 0FFH, and writes are ignored. +*/ + +#include + +#include "swtp_defs.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) + +/* Flag values to set proper positions in CCR */ +#define EF 0x80 +#define FF 0x40 +#define HF 0x20 +#define IF 0x10 +#define NF 0x08 +#define ZF 0x04 +#define VF 0x02 +#define CF 0x01 + +/* PSH/PUL Post Byte register positions */ +#define PSH_PUL_Post_Byte_PC 0x80 +#define PSH_PUL_Post_Byte_S_U 0x40 +#define PSH_PUL_Post_Byte_Y 0x20 +#define PSH_PUL_Post_Byte_X 0x10 +#define PSH_PUL_Post_Byte_DP 0x08 +#define PSH_PUL_Post_Byte_B 0x04 +#define PSH_PUL_Post_Byte_A 0x02 +#define PSH_PUL_Post_Byte_CC 0x01 + +#define TFR_EXG_Post_Nybble_D 0 +#define TFR_EXG_Post_Nybble_X 1 +#define TFR_EXG_Post_Nybble_Y 2 +#define TFR_EXG_Post_Nybble_U 3 +#define TFR_EXG_Post_Nybble_S 4 +#define TFR_EXG_Post_Nybble_PC 5 +#define TFR_EXG_Post_Nybble_A 8 +#define TFR_EXG_Post_Nybble_B 9 +#define TFR_EXG_Post_Nybble_CC 10 +#define TFR_EXG_Post_Nybble_DP 11 + + +/* Macros to handle the flags in the CCR */ +#define CCR_MSK (EF|FF|HF|IF|NF|ZF|VF|CF) +#define TOGGLE_FLAG(FLAG) (CCR ^= (FLAG)) +#define SET_FLAG(FLAG) (CCR |= (FLAG)) +#define CLR_FLAG(FLAG) (CCR &= ~(FLAG)) +#define GET_FLAG(FLAG) (CCR & (FLAG)) + +#define COND_SET_FLAG(COND,FLAG) \ + if (COND) SET_FLAG(FLAG); else CLR_FLAG(FLAG) + +#define COND_SET_FLAG_N(VAR) \ + if ((VAR) & 0x80) SET_FLAG(NF); else CLR_FLAG(NF) +#define COND_SET_FLAG_N_16(VAR) \ + if ((VAR) & 0x8000) SET_FLAG(NF); else CLR_FLAG(NF) + +#define COND_SET_FLAG_Z(VAR) \ + if ((VAR) == 0) SET_FLAG(ZF); else CLR_FLAG(ZF) +#define COND_SET_FLAG_Z_16(VAR) \ + if ((VAR) == 0) SET_FLAG(ZF); else CLR_FLAG(ZF) + +#define COND_SET_FLAG_H(VAR) \ + if ((VAR) & 0x10) SET_FLAG(HF); else CLR_FLAG(HF) + +#define COND_SET_FLAG_C(VAR) \ + if ((VAR) & 0x100) SET_FLAG(CF); else CLR_FLAG(CF) +#define COND_SET_FLAG_C_16(VAR) \ + if ((VAR) & 0x10000) SET_FLAG(CF); else CLR_FLAG(CF) + +#define COND_SET_FLAG_V(COND) \ + if (COND) SET_FLAG(VF); else CLR_FLAG(VF) + +/* local global variables */ + +int32 A = 0; /* Accumulator A */ +int32 B = 0; /* Accumulator B */ +int32 D = 0; /* Accumulator D */ +int32 DP = 0; /* Direct Page Register */ +int32 IX = 0; /* Index register X */ +int32 IY = 0; /* Index register Y */ +int32 UP = 0; /* User Stack pointer */ +int32 SP = 0; /* Hardware Stack pointer */ +int32 CCR = EF|FF|IF; /* Condition Code Register */ +int32 saved_PC = 0; /* Saved Program counter */ +int32 previous_PC = 0; /* Previous previous Program counter */ +int32 last_PC = 0; /* Last Program counter */ +int32 PC; /* Program counter */ +int32 INTE = 0; /* Interrupt Enable */ +int32 int_req = 0; /* Interrupt request */ + +int32 mem_fault = 0; /* memory fault flag */ + +/* function prototypes */ + +t_stat m6809_reset (DEVICE *dptr); +void dump_regs(void); +void dump_regs1(void); +int32 fetch_byte(int32 flag); +int32 fetch_word(); +uint8 pop_sp_byte(void); +uint8 pop_up_byte(void); +uint16 pop_sp_word(void); +uint16 pop_up_word(void); +void push_sp_byte(uint8 val); +void push_up_byte(uint8 val); +void push_sp_word(uint16 val); +void push_up_word(uint16 val); +void go_rel(int32 cond); +void go_long_rel(int32 cond); +int32 get_rel_addr(void); +int32 get_long_rel_addr(void); +int32 get_dir_byte_val(void); +int32 get_dir_word_val(void); +int32 get_imm_byte_val(void); +int32 get_imm_word_val(void); +int32 get_dir_addr(void); + +/* needs to be removed later! */ +int32 get_indexed_byte_val(void); +int32 get_indexed_word_val(void); +int32 get_indexed_addr(void); +int32 get_ext_addr(void); +int32 get_ext_byte_val(void); +int32 get_ext_word_val(void); +int32 get_flag(int32 flag); +void condevalVa(int32 op1, int32 op2); +void condevalVa16(int32 op1, int32 op2); +void condevalVs(int32 op1, int32 op2); +void condevalVs16(int32 op1, int32 op2); +void condevalHa(int32 op1, int32 op2); + +/* external routines */ + +extern void CPU_BD_put_mbyte(int32 addr, int32 val); +extern void CPU_BD_put_mword(int32 addr, int32 val); +extern int32 CPU_BD_get_mbyte(int32 addr); +extern int32 CPU_BD_get_mword(int32 addr); + +/* CPU data structures + + m6809_dev CPU device descriptor + m6809_unit CPU unit descriptor + m6809_reg CPU register list + m6809_mod CPU modifiers list */ + +UNIT m6809_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, 65536) }; + +REG m6809_reg[] = { + { HRDATA (PC, saved_PC, 16) }, + { HRDATA (A, A, 8) }, + { HRDATA (B, B, 8) }, + { HRDATA (DP, DP, 8) }, + { HRDATA (IX, IX, 16) }, + { HRDATA (IY, IY, 16) }, + { HRDATA (SP, SP, 16) }, + { HRDATA (UP, UP, 16) }, + { HRDATA (CCR, CCR, 8) }, + { FLDATA (INTE, INTE, 16) }, + { ORDATA (WRU, sim_int_char, 8) }, + { NULL } }; + +MTAB m6809_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 }, + { 0 } }; + +DEBTAB m6809_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { "REG", DEBUG_reg }, + { "ASM", DEBUG_asm }, + { NULL } +}; + +DEVICE m6809_dev = { + "CPU", //name + &m6809_unit, //units + m6809_reg, //registers + m6809_mod, //modifiers + 1, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + &m6809_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + m6809_debug, //debflags + NULL, //msize + NULL //lname +}; + +static const char *opcode[] = { +"NEG", "???", "???", "COM", //0x00 +"LSR", "???", "ROR", "ASR", +"ASL", "ROL", "DEC", "???", +"INC", "TST", "JMP", "CLR", +"PG2", "PG3", "NOP", "SYNC", //0x10 +"???", "???", "LBRA", "LBSR", +"???", "DAA", "ORCC", "???", +"ANDCC", "SEX", "EXG", "TFR", +"BRA", "BRN", "BHI", "BLS", //0x20 +"BCC", "BLO", "BNE", "BEQ", +"BVC", "BVS", "BPL", "BMI", +"BGE", "BLT", "BGT", "BLE", +"LEAX", "LEAY", "LEAS", "LEAU", //0x30 +"PSHS", "PULS", "PSHU", "PULU", +"???", "RTS", "ABX", "RTI", +"CWAI", "MUL", "???", "SWI", +"NEGA", "???", "???", "COMA", //0x40 +"LSRA", "???", "RORA", "ASRA", +"LSLA", "ROLA", "DECA", "???", +"INCA", "TSTA", "???", "CLRA", +"NEGB", "???", "???", "COMB", //0x50 +"LSRB", "???", "RORB", "ASRB", +"LSLB", "ROLB", "DECB", "???", +"INCB", "TSTB", "???", "CLRB", +"NEG", "???", "???", "COM", //0x60 +"LSR", "???", "ROR", "ASR", +"ASL", "ROL", "DEC", "???", +"INC", "TST", "JMP", "CLR", +"NEG", "???", "???", "COM", //0x70 +"LSR", "???", "ROR", "ASR", +"ASL", "ROL", "DEC", "???", +"INC", "TST", "JMP", "CLR", +"SUBA", "CMPA", "SBCA", "SUBD", //0x80 +"ANDA", "BITA", "LDA", "???", +"EORA", "ADCA", "ORAA", "ADDA", +"CMPX", "BSR", "LDX", "???", +"SUBA", "CMPA", "SBCA", "SUBD", //0x90 +"ANDA", "BITA", "LDA", "STA", +"EORA", "ADCA", "ORA", "ADDA", +"CMPX", "JSR", "LDX", "STX", +"SUBA", "CMPA", "SBCA", "SUBD", //0xA0 +"ANDA", "BITA", "LDA", "STA", +"EORA", "ADCA", "ORA", "ADDA", +"CMPX", "JSR", "LDX", "STX", +"SUBA", "CMPA", "SBCA", "SUBD", //0xB0 +"ANDA", "BITA", "LDA", "STA", +"EORA", "ADCA", "ORA", "ADDA", +"CMPX", "JSR", "LDX", "STX", +"SUBB", "CMPB", "SBCB", "ADDD", //0xC0 +"ANDB", "BITB", "LDB", "???", +"EORB", "ADCB", "ORB", "ADDB", +"LDD", "???", "LDU", "???", +"SUBB", "CMPB", "SBCB", "ADDD", //0xD0 +"ANDB", "BITB", "LDB", "STB", +"EORB", "ADCB", "ORB", "ADDB", +"LDD", "STD", "LDU", "STU", +"SUBB", "CMPB", "SBCB", "ADDD", //0xE0 +"ANDB", "BITB", "LDB", "STB", +"EORB", "ADCB", "ORB", "ADDB", +"LDD", "STD", "LDU", "STU", +"SUBB", "CMPB", "SBCB", "ADDD", //0xF0 +"ANDB", "BITB", "LDB", "STB", +"EORB", "ADCB", "ORB", "ADDB", +"LDD", "STD", "LDU", "STU" +}; + +static const char *opcode6800[] = { +"???", "NOP", "???", "???", //0x00 +"???", "???", "TAP", "TPA", +"INX", "DEX", "CLV", "SEV", +"CLC", "SEC", "CLI", "SEI", +"SBA", "CBA", "???", "???", //0x10 +"???", "???", "TAB", "TBA", +"???", "DAA", "???", "ABA", +"???", "???", "???", "???", +"BRA", "???", "BHI", "BLS", //0x20 +"BCC", "BCS", "BNE", "BEQ", +"BVC", "BVS", "BPL", "BMI", +"BGE", "BLT", "BGT", "BLE", +"TSX", "INS", "PULA", "PULB", //0x30 +"DES", "TXS", "PSHA", "PSHB", +"???", "RTS", "???", "RTI", +"???", "???", "WAI", "SWI", +"NEGA", "???", "???", "COMA", //0x40 +"LSRA", "???", "RORA", "ASRA", +"ASLA", "ROLA", "DECA", "???", +"INCA", "TSTA", "???", "CLRA", +"NEGB", "???", "???", "COMB", //0x50 +"LSRB", "???", "RORB", "ASRB", +"ASLB", "ROLB", "DECB", "???", +"INCB", "TSTB", "???", "CLRB", +"NEG", "???", "???", "COM", //0x60 +"LSR", "???", "ROR", "ASR", +"ASL", "ROL", "DEC", "???", +"INC", "TST", "JMP", "CLR", +"NEG", "???", "???", "COM", //0x70 +"LSR", "???", "ROR", "ASR", +"ASL", "ROL", "DEC", "???", +"INC", "TST", "JMP", "CLR", +"SUBA", "CMPA", "SBCA", "???", //0x80 +"ANDA", "BITA", "LDAA", "???", +"EORA", "ADCA", "ORAA", "ADDA", +"CMPX", "BSR", "LDS", "???", +"SUBA", "CMPA", "SBCA", "???", //0x90 +"ANDA", "BITA", "LDAA", "STAA", +"EORA", "ADCA", "ORAA", "ADDA", +"CMPX", "???", "LDS", "STS", +"SUBA", "CMPA", "SBCA", "???", //0xA0 +"ANDA", "BITA", "LDAA", "STAA", +"EORA", "ADCA", "ORAA", "ADDA", +"CMPX X", "JSR X", "LDS X", "STS X", +"SUBA", "CMPA", "SBCA", "???", //0xB0 +"ANDA", "BITA", "LDAA", "STAA", +"EORA", "ADCA", "ORAA", "ADDA", +"CPX", "JSR", "LDS", "STS", +"SUBB", "CMPB", "SBCB", "???", //0xC0 +"ANDB", "BITB", "LDAB", "???", +"EORB", "ADCB", "ORAB", "ADDB", +"???", "???", "LDX", "???", +"SUBB", "CMPB", "SBCB", "???", //0xD0 +"ANDB", "BITB", "LDAB", "STAB", +"EORB", "ADCB", "ORAB", "ADDB", +"???", "???", "LDX", "STX", +"SUBB", "CMPB", "SBCB", "???", //0xE0 +"ANDB", "BITB", "LDAB", "STAB", +"EORB", "ADCB", "ORAB", "ADDB", +"???", "???", "LDX", "STX", +"SUBB", "CMPB", "SBCB", "???", //0xF0 +"ANDB", "BITB", "LDAB", "STAB", +"EORB", "ADCB", "ORAB", "ADDB", +"???", "???", "LDX", "STX" +}; + +int32 oplen[256] = { +0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1, //0x00 +1,1,0,0,0,0,1,1,0,1,0,1,0,0,0,0, +2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +1,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1, +1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, //0x40 +1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, +2,0,0,2,2,0,2,2,2,2,2,0,2,2,2,2, +3,0,0,3,3,0,3,3,3,3,3,0,3,3,3,3, +2,2,2,0,2,2,2,0,2,2,2,2,3,2,3,0, //0x80 +2,2,2,0,2,2,2,2,2,2,2,2,2,0,2,2, +2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2, +3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3, +2,2,2,0,2,2,2,0,2,2,2,2,0,0,3,0, //0xC0 +2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, +2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, +3,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3 +}; + +int32 oplen6800[256] = { +0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1, //0x00 +1,1,0,0,0,0,1,1,0,1,0,1,0,0,0,0, +2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +1,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1, +1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, //0x40 +1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, +2,0,0,2,2,0,2,2,2,2,2,0,2,2,2,2, +3,0,0,3,3,0,3,3,3,3,3,0,3,3,3,3, +2,2,2,0,2,2,2,0,2,2,2,2,3,2,3,0, //0x80 +2,2,2,0,2,2,2,2,2,2,2,2,2,0,2,2, +2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2, +3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3, +2,2,2,0,2,2,2,0,2,2,2,2,0,0,3,0, //0xC0 +2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, +2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, +3,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3 +}; + +t_stat sim_instr (void) +{ + int32 reason; + int32 IR; + int32 OP; + int32 OP2; /* Used for 2-byte opcodes */ + + int32 hi; /* hi bit/nybble/byte */ + int32 lo; /* lo bit/nybble/byte */ + int32 op1; /* operand #1 */ + int32 op2; /* operand #2 - used for CC evaluation */ + int32 result; /* temporary value */ + int32 addr; /* temporary address value */ + + /* used for 6809 instruction decoding - TFT, EXG, PSH, PUL*/ + int32 Post_Byte = 0; + int32 Src_Nybble = 0; + int32 Dest_Nybble = 0; + int32 Src_Value = 0; + int32 Dest_Value = 0; + + PC = saved_PC & ADDRMASK; /* load local PC */ + reason = 0; + + /* Main instruction fetch/decode loop */ + + while (reason == 0) { /* loop until halted */ +// dump_regs1(); + 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? */ + /* 6809 interrupts not implemented yet. None were used, + on a standard SWTP 6809. All I/O is programmed. */ +// RICHARD WAS HERE +printf("m6809.c: int_req > 0!!!\n"); +fflush(stdout); + } /* end interrupt */ + if (sim_brk_summ && + sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; + } + + sim_interval--; + last_PC = previous_PC; + previous_PC = PC; + IR = OP = fetch_byte(0); /* fetch instruction */ + + /* The Big Instruction Decode Switch */ + + switch (IR) { + +/* 0x00 - direct mode */ + case 0x00: /* NEG dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 != 0, CF); + COND_SET_FLAG(op1 == 0x80, VF); + result = 0 - op1; + result &= 0xFF; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0x03: /* COM dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = ~op1; + result &= 0xFF; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + CLR_FLAG(VF); + SET_FLAG(CF); + break; + case 0x04: /* LSR dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 & 0x01, CF); + result = op1 >> 1; + CPU_BD_put_mbyte(addr, result); + CLR_FLAG(NF); + COND_SET_FLAG_Z(result); + /* H,V not affected */ + break; + case 0x06: /* ROR dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = op1 >> 1; + if (get_flag(CF)) { + result |= 0x80; + } + CPU_BD_put_mbyte(addr, result); + /* H,V unaffected */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(op1 & 0x01, CF); + break; + case 0x07: /* ASR dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 >> 1) | (op1 & 0x80); + CPU_BD_put_mbyte(addr, result); + /* H undefined */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + /* V not affected */ + COND_SET_FLAG(op1 & 0x01, CF); + break; + case 0x08: /* ASL dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 & 0x80, CF); + result = (op1 << 1) & 0xFF; + CPU_BD_put_mbyte(addr, result); + /* H is undefined */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x09: /* ROL dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 << 1) & 0xFF; + if (get_flag(CF)) { + result |= 0x01; + } + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG((op1 & 0x80) ^ (op1 & 0x40), VF); + COND_SET_FLAG(op1 & 0x80, CF); + break; + case 0x0A: /* DEC dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1-1) & 0xFF; + CPU_BD_put_mbyte(addr, result); + /* H not affected */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(op1 == 0x80, VF); + /* C not affected */ + break; + case 0x0C: /* INC dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 == 0x7F, VF); + op1 = (op1 + 1) & 0xFF; + CPU_BD_put_mbyte(addr, op1); + COND_SET_FLAG_N(op1); + COND_SET_FLAG_Z(op1); + break; + case 0x0D: /* TST dir */ + result = get_dir_byte_val(); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + CLR_FLAG(VF); + break; + case 0x0E: /* JMP dir */ + PC = get_dir_addr(); + break; + case 0x0F: /* CLR dir */ + CPU_BD_put_mbyte(get_dir_addr(), 0); + /* H not affected */ + CLR_FLAG(NF); + SET_FLAG(ZF); + CLR_FLAG(VF); + CLR_FLAG(CF); + break; + +/* 0x10 */ + case 0x10: /* 2-byte opcodes */ + /* fetch second byte of opcode */ + OP2 = fetch_byte(0); +//fprintf(stdout,"-->OP2=%08X\n", OP2); +//fprintf(stdout,"-->NF=%08X,VF=%08X,LBLT=%08X\n", get_flag(NF), get_flag(VF), get_flag(NF) ^ get_flag(VF)); +//fflush(stdout); + switch (OP2) { + case 0x21: /* LBRN rel */ + /* Branch Never - essentially a NOP */ + go_long_rel(0); + break; + case 0x22: /* LBHI rel */ + go_long_rel(!(get_flag(CF) | get_flag(ZF))); + break; + case 0x23: /* LBLS rel */ + go_long_rel(get_flag(CF) | get_flag(ZF)); + break; + case 0x24: /* LBCC rel */ + go_long_rel(!get_flag(CF)); + break; + case 0x25: /* LBCS rel */ + go_long_rel(get_flag(CF)); + break; + case 0x26: /* LBNE rel */ + go_long_rel(!get_flag(ZF)); + break; + case 0x27: /* LBEQ rel */ + go_long_rel(get_flag(ZF)); + break; + case 0x28: /* LBVC rel */ + go_long_rel(!get_flag(VF)); + break; + case 0x29: /* LBVS rel */ + go_long_rel(get_flag(VF)); + break; + case 0x2A: /* LBPL rel */ + go_long_rel(!get_flag(NF)); + break; + case 0x2B: /* LBMI rel */ + go_long_rel(get_flag(NF)); + break; + case 0x2C: /* LBGE rel */ + go_long_rel( !( get_flag(NF) ^ get_flag(VF) ) ); + break; + case 0x2D: /* LBLT rel */ + go_long_rel( get_flag(NF) ^ get_flag(VF) ); + break; + case 0x2E: /* LBGT rel */ + go_long_rel(!( get_flag(ZF) | (get_flag(NF) ^ get_flag(VF)))); + break; + case 0x2F: /* LBLE rel */ + go_long_rel(get_flag(ZF) | (get_flag(NF) ^ get_flag(VF))); + break; + case 0x3F: /* SWI2 */ + SET_FLAG(EF); + push_sp_word(PC); + push_sp_word(UP); + push_sp_word(IY); + push_sp_word(IX); + push_sp_byte(DP); + push_sp_byte(B); + push_sp_byte(A); + push_sp_byte(CCR); + PC = CPU_BD_get_mword(0xFFF4) & ADDRMASK; + break; + case 0x83: /* CMPD imm */ + D = (A << 8) | (B & 0xFF); + op2 = get_imm_word_val(); + result = D - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x8C: /* CMPY imm */ + op2 = get_imm_word_val(); + result = IY - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IY, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x8E: /* LDY imm */ + IY = get_imm_word_val(); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0x93: /* CMPD dir */ + D = (A << 8) | (B & 0xFF); + op2 = get_dir_word_val(); + result = D - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x9C: /* CMPY dir */ + op2 = get_dir_word_val(); + result = IY - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IY, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x9E: /* LDY dir */ + IY = get_dir_word_val(); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0x9F: /* STY dir */ + CPU_BD_put_mword(get_dir_addr(), IY); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0xA3: /* CMPD ind */ + D = (A << 8) | (B & 0xFF); + op2 = get_indexed_word_val(); + result = D - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xAC: /* CMPY ind */ + op2 = get_indexed_word_val(); + result = IY - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IY, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xAE: /* LDY ind */ + IY = get_indexed_word_val(); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0xAF: /* STY ind */ + CPU_BD_put_mword(get_indexed_addr(), IY); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0xB3: /* CMPD ext */ + D = (A << 8) | (B & 0xFF); + op2 = get_ext_word_val(); + result = D - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xBC: /* CMPY ext */ + op2 = get_ext_word_val(); + result = IY - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IY, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xBE: /* LDY ext */ + IY = get_ext_word_val(); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0xBF: /* STY ext */ + CPU_BD_put_mword(get_ext_addr(), IY); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0xCE: /* LDS imm */ + SP = get_imm_word_val(); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + case 0xDE: /* LDS dir */ + SP = get_dir_word_val(); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + case 0xDF: /* STS dir */ + CPU_BD_put_mword(get_dir_addr(), SP); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + case 0xEE: /* LDS ind */ + SP = get_indexed_word_val(); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + case 0xEF: /* STS ind */ + CPU_BD_put_mword(get_indexed_addr(), SP); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + case 0xFE: /* LDS ext */ + SP = get_ext_word_val(); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + case 0xFF: /* STS ext */ + CPU_BD_put_mword(get_ext_addr(), SP); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + } + break; + +/* Ox11 */ + case 0x11: /* 2-byte opcodes */ + /* fetch second byte of opcode */ + OP2 = fetch_byte(0); + switch (OP2) { + case 0x3F: /* SWI3 */ + SET_FLAG(EF); + push_sp_word(PC); + push_sp_word(UP); + push_sp_word(IY); + push_sp_word(IX); + push_sp_byte(DP); + push_sp_byte(B); + push_sp_byte(A); + push_sp_byte(CCR); + PC = CPU_BD_get_mword(0xFFF2) & ADDRMASK; + break; + case 0x83: /* CMPU imm */ + op2 = get_imm_word_val(); + result = UP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(UP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x8C: /* CMPS imm */ + op2 = get_imm_word_val(); + result = SP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(SP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x93: /* CMPU dir */ + op2 = get_dir_word_val(); + result = UP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(UP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x9C: /* CMPS dir */ + op2 = get_dir_word_val(); + result = SP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(SP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xA3: /* CMPU ind */ + op2 = get_indexed_word_val(); + result = UP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(UP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xAC: /* CMPS ind */ + op2 = get_indexed_word_val(); + result = SP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(SP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xB3: /* CMPU ext */ + op2 = get_ext_word_val(); + result = UP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(UP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xBC: /* CMPS ext */ + op2 = get_ext_word_val(); + result = SP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(SP, op2); + COND_SET_FLAG_C_16(result); + break; + } + break; + case 0x12: /* NOP */ + break; + case 0x13: /* SYNC inherent*/ +/* RICHARD WAS HERE */ +/* interrupts are not implemented */ + break; + case 0x16: /* LBRA relative */ + go_long_rel(1); + break; + case 0x17: /* LBSR relative */ + addr = get_long_rel_addr(); + push_sp_word(PC); + PC = (PC + addr) & ADDRMASK; + break; + case 0x19: /* DAA inherent */ + lo = A & 0x0F; + if ((lo > 9) || get_flag(HF)) { + lo += 6; + A = (A & 0xF0) + lo; + COND_SET_FLAG(lo & 0x10, HF); + } + hi = (A >> 4) & 0x0F; + if ((hi > 9) || get_flag(CF)) { + hi += 6; + A = (A & 0x0F) | (hi << 4) | 0x100; + } + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + + case 0x1A: /* ORCC imm */ + CCR = CCR | get_imm_byte_val(); + break; + case 0x1C: /* ANDCC imm */ + CCR = CCR & get_imm_byte_val(); + break; + case 0x1D: /* SEX inherent */ + if (B & 0x80) { + A = 0xFF; + } else { + A = 0; + } + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0x1E: /* EXG imm */ + Post_Byte = get_imm_byte_val(); + Src_Nybble = (Post_Byte >> 4) & 0x0F; + Dest_Nybble = Post_Byte & 0x0F; + if ((Src_Nybble <= 5 && Dest_Nybble > 5) || (Src_Nybble > 5 && Dest_Nybble <= 5)) { + // EXG with unaligned register sizes + reason = STOP_OPCODE; + } + + /* read register values */ + if (Src_Nybble <= 5 && Dest_Nybble <= 5) { + /* 16-bit register */ + /* read source register */ + switch (Src_Nybble) { + case TFR_EXG_Post_Nybble_D: Src_Value = (A << 8) | (B & 0xFF); break; + case TFR_EXG_Post_Nybble_X: Src_Value = IX; break; + case TFR_EXG_Post_Nybble_Y: Src_Value = IY; break; + case TFR_EXG_Post_Nybble_U: Src_Value = UP; break; + case TFR_EXG_Post_Nybble_S: Src_Value = SP; break; + case TFR_EXG_Post_Nybble_PC: Src_Value = PC; break; + default: break; + } + /* read destination register */ + switch (Dest_Nybble) { + case TFR_EXG_Post_Nybble_D: Dest_Value = (A << 8) | (B & 0xFF); break; + case TFR_EXG_Post_Nybble_X: Dest_Value = IX; break; + case TFR_EXG_Post_Nybble_Y: Dest_Value = IY; break; + case TFR_EXG_Post_Nybble_U: Dest_Value = UP; break; + case TFR_EXG_Post_Nybble_S: Dest_Value = SP; break; + case TFR_EXG_Post_Nybble_PC: Dest_Value = PC; break; + default: break; + } + } + if ((Src_Nybble >= 8 && Src_Nybble <= 11) && (Dest_Nybble >= 8 && Dest_Nybble <= 11)) { + /* 8-bit register read */ + /* read source register */ + switch (Src_Nybble) { + case TFR_EXG_Post_Nybble_A: Src_Value = A; break; + case TFR_EXG_Post_Nybble_B: Src_Value = B; break; + case TFR_EXG_Post_Nybble_CC: Src_Value = CCR; break; + case TFR_EXG_Post_Nybble_DP: Src_Value = DP; break; + default: break; + } + /* read destination register */ + switch (Dest_Nybble) { + case TFR_EXG_Post_Nybble_A: Dest_Value = A; break; + case TFR_EXG_Post_Nybble_B: Dest_Value = B; break; + case TFR_EXG_Post_Nybble_CC: Dest_Value = CCR; break; + case TFR_EXG_Post_Nybble_DP: Dest_Value = DP; break; + default: break; + } + } + /* write register values */ + if (Src_Nybble <= 5 && Dest_Nybble <= 5) { + /* 16-bit register */ + /* write source register */ + switch (Src_Nybble) { + case TFR_EXG_Post_Nybble_D: + A = Dest_Value >> 8; + B = Dest_Value & 0XFF; + break; + case TFR_EXG_Post_Nybble_X: IX = Dest_Value; break; + case TFR_EXG_Post_Nybble_Y: IY = Dest_Value; break; + case TFR_EXG_Post_Nybble_U: UP = Dest_Value; break; + case TFR_EXG_Post_Nybble_S: SP = Dest_Value; break; + case TFR_EXG_Post_Nybble_PC: PC = Dest_Value; break; + default: break; + } + /* write destination register */ + switch (Dest_Nybble) { + case TFR_EXG_Post_Nybble_D: + A = Src_Value >> 8; + B = Src_Value & 0XFF; + break; + case TFR_EXG_Post_Nybble_X: IX = Src_Value; break; + case TFR_EXG_Post_Nybble_Y: IY = Src_Value; break; + case TFR_EXG_Post_Nybble_U: UP = Src_Value; break; + case TFR_EXG_Post_Nybble_S: SP = Src_Value; break; + case TFR_EXG_Post_Nybble_PC: PC = Src_Value; break; + default: break; + } + } + if ((Src_Nybble >= 8 && Src_Nybble <= 11) && (Dest_Nybble >= 8 && Dest_Nybble <= 11)) { + /* 8-bit register */ + /* write source register */ + switch (Src_Nybble) { + case TFR_EXG_Post_Nybble_A: A = Dest_Value; break; + case TFR_EXG_Post_Nybble_B: B = Dest_Value; break; + case TFR_EXG_Post_Nybble_CC: CCR = Dest_Value; break; + case TFR_EXG_Post_Nybble_DP: DP = Dest_Value; break; + default: break; + } + /* write destination register */ + switch (Dest_Nybble) { + case TFR_EXG_Post_Nybble_A: A = Src_Value; break; + case TFR_EXG_Post_Nybble_B: B = Src_Value; break; + case TFR_EXG_Post_Nybble_CC: CCR = Src_Value; break; + case TFR_EXG_Post_Nybble_DP: DP = Src_Value; break; + default: break; + } + } + break; + + case 0x1F: /* TFR imm */ + Post_Byte = get_imm_byte_val(); + Dest_Nybble = Post_Byte & 0x0F; + Src_Nybble = Post_Byte >> 4; + if ((Src_Nybble <= 5 && Dest_Nybble > 5) || (Src_Nybble > 5 && Dest_Nybble <= 5)) { + // TFR with unaligned register sizes + reason = STOP_OPCODE; + } + + + if ((Src_Nybble <= 5) && (Dest_Nybble <= 5)) { + /* 16-bit registers */ + /* read source register */ + switch (Src_Nybble) { + case TFR_EXG_Post_Nybble_D: Src_Value = (A << 8) | (B & 0xFF); break; + case TFR_EXG_Post_Nybble_X: Src_Value = IX; break; + case TFR_EXG_Post_Nybble_Y: Src_Value = IY; break; + case TFR_EXG_Post_Nybble_U: Src_Value = UP; break; + case TFR_EXG_Post_Nybble_S: Src_Value = SP; break; + case TFR_EXG_Post_Nybble_PC: Src_Value = PC; break; + break; + } + /* write source register */ + switch (Dest_Nybble) { + case TFR_EXG_Post_Nybble_D: + A = Src_Value >> 8; + B = Src_Value & 0XFF; + break; + case TFR_EXG_Post_Nybble_X: IX = Src_Value; break; + case TFR_EXG_Post_Nybble_Y: IY = Src_Value; break; + case TFR_EXG_Post_Nybble_U: UP = Src_Value; break; + case TFR_EXG_Post_Nybble_S: SP = Src_Value; break; + case TFR_EXG_Post_Nybble_PC: PC = Src_Value;; break; + break; + } + } + if ((Src_Nybble >= 8 && Src_Nybble <= 11) && (Dest_Nybble >= 8 && Dest_Nybble <= 11)) { + /* 8-bit registers */ + /* read the source register */ + switch (Src_Nybble) { + case TFR_EXG_Post_Nybble_A: Src_Value = A; break; + case TFR_EXG_Post_Nybble_B: Src_Value = B; break; + case TFR_EXG_Post_Nybble_CC: Src_Value = CCR; break; + case TFR_EXG_Post_Nybble_DP: Src_Value = DP; break; + break; + } + /* write the destination register */ + switch (Dest_Nybble) { + case TFR_EXG_Post_Nybble_A: A = Src_Value; break; + case TFR_EXG_Post_Nybble_B: B = Src_Value; break; + case TFR_EXG_Post_Nybble_CC: CCR = Src_Value; break; + case TFR_EXG_Post_Nybble_DP: DP = Src_Value; break; + break; + } + } + break; + +/* 0x20 - relative mode */ + case 0x20: /* BRA rel */ + go_rel(1); + break; + case 0x21: /* BRN rel */ + /* Branch Never - essentially a NOP */ + go_rel(0); + break; + case 0x22: /* BHI rel */ + go_rel(!(get_flag(CF) | get_flag(ZF))); + break; + case 0x23: /* BLS rel */ + go_rel(get_flag(CF) | get_flag(ZF)); + break; + case 0x24: /* BCC rel */ + go_rel(!get_flag(CF)); + break; + case 0x25: /* BCS rel */ + go_rel(get_flag(CF)); + break; + case 0x26: /* BNE rel */ + go_rel(!get_flag(ZF)); + break; + case 0x27: /* BEQ rel */ + go_rel(get_flag(ZF)); + break; + case 0x28: /* BVC rel */ + go_rel(!get_flag(VF)); + break; + case 0x29: /* BVS rel */ + go_rel(get_flag(VF)); + break; + case 0x2A: /* BPL rel */ + go_rel(!get_flag(NF)); + break; + case 0x2B: /* BMI rel */ + go_rel(get_flag(NF)); + break; + case 0x2C: /* BGE rel */ + go_rel(!(get_flag(NF) ^ get_flag(VF))); + break; + case 0x2D: /* BLT rel */ + go_rel(get_flag(NF) ^ get_flag(VF)); + break; + case 0x2E: /* BGT rel */ + go_rel( !( get_flag(ZF) | (get_flag(NF) ^ get_flag(VF)) ) ); + break; + case 0x2F: /* BLE rel */ + go_rel( get_flag(ZF) | (get_flag(NF) ^ get_flag(VF)) ); + break; + +/* 0x30 */ + case 0x30: /* LEAX */ + IX = get_indexed_addr(); + COND_SET_FLAG_Z_16(IX); + break; + + case 0x31: /* LEAY */ + IY = get_indexed_addr(); + COND_SET_FLAG_Z_16(IY); + break; + + case 0x32: /* LEAS */ + SP = get_indexed_addr(); + /* does not affect CCR */ + break; + + case 0x33: /* LEAU */ + UP = get_indexed_addr(); + /* does not affect CCR */ + break; + + case 0x34: /* PSHS */ + Post_Byte = get_imm_byte_val(); + if (Post_Byte & PSH_PUL_Post_Byte_PC) push_sp_word(PC); + if (Post_Byte & PSH_PUL_Post_Byte_S_U) push_sp_word(UP); + if (Post_Byte & PSH_PUL_Post_Byte_Y) push_sp_word(IY); + if (Post_Byte & PSH_PUL_Post_Byte_X) push_sp_word(IX); + if (Post_Byte & PSH_PUL_Post_Byte_DP) push_sp_byte(DP); + if (Post_Byte & PSH_PUL_Post_Byte_B) push_sp_byte(B); + if (Post_Byte & PSH_PUL_Post_Byte_A) push_sp_byte(A); + if (Post_Byte & PSH_PUL_Post_Byte_CC) push_sp_byte(CCR); + break; + + case 0x35: /* PULS */ + Post_Byte = get_imm_byte_val(); + if (Post_Byte & PSH_PUL_Post_Byte_CC) CCR = pop_sp_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_A) A = pop_sp_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_B) B = pop_sp_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_DP) DP = pop_sp_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_X) IX = pop_sp_word(); + if (Post_Byte & PSH_PUL_Post_Byte_Y) IY = pop_sp_word(); + if (Post_Byte & PSH_PUL_Post_Byte_S_U) UP = pop_sp_word(); + if (Post_Byte & PSH_PUL_Post_Byte_PC) PC = pop_sp_word(); + break; + + case 0x36: /* PSHU */ + Post_Byte = get_imm_byte_val(); + if (Post_Byte & PSH_PUL_Post_Byte_PC) push_up_word(PC); + if (Post_Byte & PSH_PUL_Post_Byte_S_U) push_up_word(SP); + if (Post_Byte & PSH_PUL_Post_Byte_Y) push_up_word(IY); + if (Post_Byte & PSH_PUL_Post_Byte_X) push_up_word(IX); + if (Post_Byte & PSH_PUL_Post_Byte_DP) push_up_byte(DP); + if (Post_Byte & PSH_PUL_Post_Byte_B) push_up_byte(B); + if (Post_Byte & PSH_PUL_Post_Byte_A) push_up_byte(A); + if (Post_Byte & PSH_PUL_Post_Byte_CC) push_up_byte(CCR); + break; + + case 0x37: /* PULU */ + Post_Byte = get_imm_byte_val(); + if (Post_Byte & PSH_PUL_Post_Byte_CC) CCR = pop_up_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_A) A = pop_up_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_B) B = pop_up_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_DP) DP = pop_up_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_X) IX = pop_up_word(); + if (Post_Byte & PSH_PUL_Post_Byte_Y) IY = pop_up_word(); + if (Post_Byte & PSH_PUL_Post_Byte_S_U) SP = pop_up_word(); + if (Post_Byte & PSH_PUL_Post_Byte_PC) PC = pop_up_word(); + break; + + case 0x39: /* RTS */ + PC = pop_sp_word(); + break; + + case 0x3A: /* ABX */ + /* this is an UNSIGNED operation! */ + IX = (IX + B) & 0xFFFF; + /* no changes to CCR */ + break; + + case 0x3B: /* RTI */ + CCR = pop_sp_byte(); + if (GET_FLAG(EF)) { + /* entire state flag */ + A = pop_sp_byte(); + B = pop_sp_byte(); + DP = pop_sp_byte(); + IX = pop_sp_word(); + IY = pop_sp_word(); + UP = pop_sp_word(); + } + PC = pop_sp_word(); + break; + + case 0x3C: /* CWAI */ + /* AND immediate byte with CCR + CCR &= get_imm_byte_val(); + SET_FLAG(EF); + /* push register state */ + push_sp_word(PC); + push_sp_word(UP); + push_sp_word(IY); + push_sp_word(IX); + push_sp_byte(DP); + push_sp_byte(B); + push_sp_byte(A); + push_sp_byte(CCR); + if (get_flag(IF)) { + reason = STOP_HALT; + continue; + } else { + SET_FLAG(IF); + PC = CPU_BD_get_mword(0xFFFE) & ADDRMASK; + } + break; + + case 0x3D: /* MUL */ + D = A * B; + A = D >> 8; + B = D & 0xFF; + COND_SET_FLAG_Z_16(D); + COND_SET_FLAG(B & 0x80, CF); + break; + + case 0x3F: /* SWI */ + SET_FLAG(EF); + push_sp_word(PC); + push_sp_word(UP); + push_sp_word(IY); + push_sp_word(IX); + push_sp_byte(DP); + push_sp_byte(B); + push_sp_byte(A); + push_sp_byte(CCR); + SET_FLAG(FF); + SET_FLAG(IF); + PC = CPU_BD_get_mword(0xFFFA) & ADDRMASK; + break; + +/* 0x40 - inherent mode */ + case 0x40: /* NEGA */ + COND_SET_FLAG(A != 0, CF); + COND_SET_FLAG(A == 0x80, VF); + A = 0 - A; + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x43: /* COMA */ + A = ~A; + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + SET_FLAG(CF); + break; + case 0x44: /* LSRA */ + COND_SET_FLAG(A & 0x01, CF); + A = (A >> 1) & 0xFF; + CLR_FLAG(NF); + COND_SET_FLAG_Z(A); + /* H,V unaffected */ + break; + case 0x46: /* RORA */ + hi = get_flag(CF); + COND_SET_FLAG(A & 0x01, CF); + A = A >> 1; + if (hi) + A |= 0x80; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + /* H,V unaffected */ + break; + case 0x47: /* ASRA */ + COND_SET_FLAG(A & 0x01, CF); + A = (A >> 1) | (A & 0x80); + /* H undefined */ + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + /* V unaffected */ + break; + case 0x48: /* ASLA */ + COND_SET_FLAG(A & 0x80, CF); + A = (A << 1) & 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x49: /* ROLA */ + hi = get_flag(CF); + COND_SET_FLAG(A & 0x80, CF); + A = (A << 1) & 0xFF; + if (hi) + A |= 0x01; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x4A: /* DECA */ + COND_SET_FLAG(A == 0x80, VF); + A = (A - 1) & 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x4C: /* INCA */ + COND_SET_FLAG(A == 0x7F, VF); + A = (A + 1) & 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x4D: /* TSTA */ + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + /* C not affected */ + break; + case 0x4F: /* CLRA */ + A = 0; + CLR_FLAG(NF); + SET_FLAG(ZF); + CLR_FLAG(VF); + CLR_FLAG(CF); + break; + +/* 0x50 - inherent modes */ + case 0x50: /* NEGB */ + COND_SET_FLAG(B != 0, CF); + COND_SET_FLAG(B == 0x80, VF); + B = (0 - B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0x53: /* COMB */ + B = ~B; + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + SET_FLAG(CF); + break; + case 0x54: /* LSRB */ + COND_SET_FLAG(B & 0x01, CF); + B = (B >> 1) & 0xFF; + CLR_FLAG(NF); + COND_SET_FLAG_Z(B); + /* H,V unaffected */ + break; + case 0x56: /* RORB */ + hi = get_flag(CF); + COND_SET_FLAG(B & 0x01, CF); + B = B >> 1; + if (hi) + B |= 0x80; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + /* H,V unaffected */ + break; + case 0x57: /* ASRB */ + COND_SET_FLAG(B & 0x01, CF); + B = (B >> 1) | (B & 0x80); + /* H undefined */ + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + /* C unaffected */ + break; + case 0x58: /* ASLB */ + COND_SET_FLAG(B & 0x80, CF); + B = (B << 1) & 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x59: /* ROLB */ + hi = get_flag(CF); + COND_SET_FLAG(B & 0x80, CF); + B = (B << 1) & 0xFF; + if (hi) + B |= 0x01; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x5A: /* DECB */ + COND_SET_FLAG(B == 0x80, VF); + B = (B - 1) & 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0x5C: /* INCB */ + COND_SET_FLAG(B == 0x7F, VF); + B = (B + 1) & 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0x5D: /* TSTB */ + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + /* C not affected */ + break; + case 0x5F: /* CLRB */ + B = 0; + CLR_FLAG(NF); + SET_FLAG(ZF); + CLR_FLAG(VF); + CLR_FLAG(CF); + break; + +/* 0x60 - index mode */ + case 0x60: /* NEG ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 != 0, CF); + COND_SET_FLAG(op1 == 0x80, VF); + result = (0 - op1) & 0xFF; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0x63: /* COM ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = ~op1; + result &= 0xFF; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + CLR_FLAG(VF); + SET_FLAG(CF); + break; + case 0x64: /* LSR ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 & 0x01, CF); + result = op1 >> 1; + CPU_BD_put_mbyte(addr, result); + CLR_FLAG(NF); + COND_SET_FLAG_Z(result); + /* H,V unaffected */ + break; + case 0x66: /* ROR ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = op1 >> 1; + if (get_flag(CF)) + result |= 0x80; + CPU_BD_put_mbyte(addr, result); + /* H,V unaffected */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(op1 & 0x01, CF); + break; + case 0x67: /* ASR ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 >> 1) | (op1 & 0x80); + CPU_BD_put_mbyte(addr, result); + /* H undefined */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + /* V unaffected */ + COND_SET_FLAG(op1 & 0x01, CF); + break; + case 0x68: /* ASL ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 & 0x80, CF); + result = (op1 << 1) & 0xFF; + CPU_BD_put_mbyte(addr, result); + /* H is undefined */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x69: /* ROL ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 << 1) & 0xFF; + if (get_flag(CF)) + result |= 0x01; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG((op1 & 0x80) ^ (op1 & 0x40), VF); + COND_SET_FLAG(op1 & 0x80, CF); + break; + case 0x6A: /* DEC ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 - 1) & 0xFF; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(op1 == 0x80, VF); + break; + case 0x6C: /* INC ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 == 0x7F, VF); + op1 = (op1 + 1) & 0xFF; + CPU_BD_put_mbyte(addr, op1); + COND_SET_FLAG_N(op1); + COND_SET_FLAG_Z(op1); + break; + case 0x6D: /* TST ind */ + result = get_indexed_byte_val(); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + CLR_FLAG(VF); + break; + case 0x6E: /* JMP ind */ + PC = get_indexed_addr(); + break; + case 0x6F: /* CLR ind */ + CPU_BD_put_mbyte(get_indexed_addr(), 0); + /* H not affected */ + CLR_FLAG(NF); + SET_FLAG(ZF); + CLR_FLAG(VF); + CLR_FLAG(CF); + break; + +/* 0x70 - extended modes */ + case 0x70: /* NEG ext */ + addr= get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 != 0, CF); + COND_SET_FLAG(op1 == 0x80, VF) ; + result = (0 - op1) & 0xFF; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0x73: /* COM ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = ~op1; + result &= 0xFF; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + CLR_FLAG(VF); + SET_FLAG(CF); + break; + case 0x74: /* LSR ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 & 0x01, CF); + result = op1 >> 1; + CPU_BD_put_mbyte(addr, result); + CLR_FLAG(NF); + COND_SET_FLAG_Z(result); + /* H,V unaffected */ + break; + case 0x76: /* ROR ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = op1 >> 1; + if (get_flag(CF)) + result |= 0x80; + CPU_BD_put_mbyte(addr, result); + /* H,V unaffected */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(op1 & 0x01, CF); + break; + case 0x77: /* ASR ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 >> 1) | (op1 & 0x80); + CPU_BD_put_mbyte(addr, result); + /* H undefined */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + /* V unaffected */ + COND_SET_FLAG(op1 & 0x01, CF); + break; + case 0x78: /* ASL ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 & 0x80, CF); + result = (op1 << 1) & 0xFF; + CPU_BD_put_mbyte(addr, result); + /* H is undefined */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x79: /* ROL ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 << 1) & 0xFF; + if (get_flag(CF)) + result |= 0x01; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG((op1 & 0x80) ^ (op1 & 0x40), VF); + COND_SET_FLAG(op1 & 0x80, CF); + break; + case 0x7A: /* DEC ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 - 1) & 0xFF; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(op1 == 0x80, VF); + break; + case 0x7C: /* INC ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 == 0x7F, VF); + op1 = (op1 + 1) & 0xFF; + CPU_BD_put_mbyte(addr, op1); + COND_SET_FLAG_N(op1); + COND_SET_FLAG_Z(op1); + break; + case 0x7D: /* TST ext */ + result = get_ext_byte_val(); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + CLR_FLAG(VF); + break; + case 0x7E: /* JMP ext */ + PC = get_ext_addr(); + break; + case 0x7F: /* CLR ext */ + CPU_BD_put_mbyte(get_ext_addr(), 0); + /* H not affected */ + CLR_FLAG(NF); + SET_FLAG(ZF); + CLR_FLAG(VF); + CLR_FLAG(CF); + break; + +/* 0x80 - immediate mode (except for BSR) */ + case 0x80: /* SUBA imm */ + op1 = get_imm_byte_val(); + op2 = A; + A = A - op1; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0x81: /* CMPA imm */ + op2 = get_imm_byte_val(); + result = A - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(A, op2); + break; + case 0x82: /* SBCA imm */ + op1 = A; + op2 = get_imm_byte_val() + get_flag(CF); + A = A - op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0x83: /* SUBD imm */ + D = (A << 8) | (B & 0xFF); + op2 = get_imm_word_val(); + result = D - op2; + COND_SET_FLAG_C_16(result); + result &= 0xFFFF; + A = result >> 8; + B = result & 0xFF; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + break; + case 0x84: /* ANDA imm */ + A = (A & get_imm_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x85: /* BITA imm */ + result = (A & get_imm_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0x86: /* LDA imm */ + A = get_imm_byte_val(); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x88: /* EORA imm */ + A = (A ^ get_imm_byte_val()) & 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x89: /* ADCA imm */ + op1 = A; + op2 = get_imm_byte_val() + get_flag(CF); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0x8A: /* ORA imm */ + A = A | get_imm_byte_val(); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x8B: /* ADDA imm */ + op1 = A; + op2 = get_imm_byte_val(); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0x8C: /* CMPX imm */ + op2 = get_imm_word_val(); + result = IX - op2; + COND_SET_FLAG_C_16(result); + result = result & 0xFFFF; + COND_SET_FLAG_Z_16(result); + COND_SET_FLAG_N_16(result); + condevalVs16(IX, op2); + break; + case 0x8D: /* BSR rel */ + addr = get_rel_addr(); + push_sp_word(PC); + PC = (PC + addr) & ADDRMASK; + break; + case 0x8E: /* LDX imm */ + IX = get_imm_word_val(); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + +/* 0x90 - direct mode */ + case 0x90: /* SUBA dir */ + op1 = A; + op2 = get_dir_byte_val(); + A = A - op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0x91: /* CMPA dir */ + op2 = get_dir_byte_val(); + result = A - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(A, op2); + break; + case 0x92: /* SBCA dir */ + op1 = A; + op2 = get_dir_byte_val() + get_flag(CF); + A = A - op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0x93: /* SUBD dir */ + D = (A << 8) | (B & 0xFF); + op2 = get_dir_word_val(); + result = D - op2; + COND_SET_FLAG_C_16(result); + result &= 0xFFFF; + A = result >> 8; + B = result & 0xFF; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + break; + case 0x94: /* ANDA dir */ + A = (A & get_dir_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x95: /* BITA dir */ + result = (A & get_dir_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0x96: /* LDA dir */ + A = get_dir_byte_val(); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x97: /* STA dir */ + CPU_BD_put_mbyte(get_dir_addr(), A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x98: /* EORA dir */ + A = (A ^ get_dir_byte_val()) & 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x99: /* ADCA dir */ + op1 = A; + op2 = get_dir_byte_val() + get_flag(CF); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0x9A: /* ORA dir */ + A = A | get_dir_byte_val(); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x9B: /* ADDA dir */ + op1 = A; + op2 = get_dir_byte_val(); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0x9C: /* CMPX dir */ + op2 = get_dir_word_val(); + result = IX - op2; + COND_SET_FLAG_C_16(result); + result &= 0xFFFF; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IX, op2); + break; + case 0x9D: /* JSR dir */ + addr = get_dir_addr(); + push_sp_word(PC); + PC = addr; + break; + case 0x9E: /* LDX dir */ + IX = get_dir_word_val(); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + case 0x9F: /* STX dir */ + CPU_BD_put_mword(get_dir_addr(), IX); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + +/* 0xA0 - indexed mode */ + case 0xA0: /* SUBA ind */ + op1 = get_indexed_byte_val(); + result = A - op1; + A = result; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, result); + break; + case 0xA1: /* CMPA ind */ + op2 = get_indexed_byte_val(); + result = A - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(A, op2); + break; + case 0xA2: /* SBCA ind */ + op1 = A; + op2 = get_indexed_byte_val() + get_flag(CF); + A = A - op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0xA3: /* SUBD ind */ + D = (A << 8) | (B & 0xFF); + op2 = get_indexed_word_val(); + result = D - op2; + COND_SET_FLAG_C_16(result); + result &= 0xFFFF; + A = result >> 8; + B = result & 0xFF; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + break; + case 0xA4: /* ANDA ind */ + A = (A & get_indexed_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xA5: /* BITA ind */ + result = (A & get_indexed_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0xA6: /* LDA ind */ + A = get_indexed_byte_val(); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xA7: /* STA ind */ + CPU_BD_put_mbyte(get_indexed_addr(), A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xA8: /* EORA ind */ + A = (A ^ get_indexed_byte_val()) & 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xA9: /* ADCA ind */ + op1 = A; + op2 = get_indexed_byte_val() + get_flag(CF); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0xAA: /* ORA ind */ + A = A | get_indexed_byte_val(); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xAB: /* ADDA ind */ + op1 = A; + op2 = get_indexed_byte_val(); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0xAC: /* CMPX ind */ + op2 = get_indexed_word_val(); + result = (IX - op2) & ADDRMASK; + COND_SET_FLAG_C_16(result); + result &= 0xFFFF; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IX, op2); + break; + case 0xAD: /* JSR ind */ + addr = get_indexed_addr(); + push_sp_word(PC); + PC = addr; + break; + case 0xAE: /* LDX ind */ + IX = get_indexed_word_val(); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + case 0xAF: /* STX ind */ + CPU_BD_put_mword(get_indexed_addr(), IX); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + +/* 0xB0 - extended mode */ + case 0xB0: /* SUBA ext */ + op1 = A; + op2 = get_ext_byte_val(); + A = A - op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0xB1: /* CMPA ext */ + op2 = get_ext_byte_val(); + result = A - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(A, op2); + break; + case 0xB2: /* SBCA ext */ + op1 = A; + op2 = get_ext_byte_val() + get_flag(CF); + A = A - op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0xB3: /* SUBD ext */ + D = (A << 8) | (B & 0xFF); + op2 = get_ext_word_val(); + result = D - op2; + COND_SET_FLAG_C_16(result); + result &= 0xFFFF; + A = result >> 8; + B = result & 0xFF; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + break; + case 0xB4: /* ANDA ext */ + A = (A & get_ext_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xB5: /* BITA ext */ + result = (A & get_ext_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0xB6: /* LDA ext */ + A = get_ext_byte_val(); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xB7: /* STA ext */ + CPU_BD_put_mbyte(get_ext_addr(), A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xB8: /* EORA ext */ + A = (A ^ get_ext_byte_val()) & 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xB9: /* ADCA ext */ + op1 = A; + op2 = get_ext_byte_val() + get_flag(CF); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0xBA: /* ORA ext */ + A = A | get_ext_byte_val(); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xBB: /* ADDA ext */ + op1 = A; + op2 = get_ext_byte_val(); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0xBC: /* CMPX ext */ + op2 = get_ext_word_val(); + result = (IX - op2); + COND_SET_FLAG_C_16(result); + result = result & 0xFFFF; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IX, op2); + break; + case 0xBD: /* JSR ext */ + addr = get_ext_addr(); + push_sp_word(PC); + PC = addr; + break; + case 0xBE: /* LDX ext */ + IX = get_ext_word_val(); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + case 0xBF: /* STX ext */ + CPU_BD_put_mword(get_ext_addr(), IX); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + +/* 0xC0 - immediate mode */ + case 0xC0: /* SUBB imm */ + op1 = B; + op2 = get_imm_byte_val(); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xC1: /* CMPB imm */ + op2 = get_imm_byte_val(); + result = B - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(B, op2); + break; + case 0xC2: /* SBCB imm */ + op1 = B; + op2 = get_imm_byte_val() + get_flag(CF); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xC3: /* ADDD imm */ + op1 = (A << 8) | (B & 0xFF); + op2 = get_imm_word_val(); + D = op1 + op2; + COND_SET_FLAG_C_16(D); + D &= 0xFFFF; + A = D >> 8; + B = D & 0xFF; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + condevalVa16(op1,op2); + break; + case 0xC4: /* ANDB imm */ + B = (B & get_imm_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xC5: /* BITB imm */ + result = (B & get_imm_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0xC6: /* LDB imm */ + B = get_imm_byte_val(); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xC8: /* EORB imm */ + B = (B ^ get_imm_byte_val()) & 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xC9: /* ADCB imm */ + op1 = B; + op2 = get_imm_byte_val() + get_flag(CF); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xCA: /* ORB imm */ + B = B | get_imm_byte_val(); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xCB: /* ADDB imm */ + op1 = B; + op2 = get_imm_byte_val(); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xCC: /* LDD imm */ + D = get_imm_word_val(); + A = D >> 8; + B = D & 0xFF; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xCE: /* LDU imm */ + UP = get_imm_word_val(); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + +/* 0xD0 - direct modes */ + case 0xD0: /* SUBB dir */ + op1 = B; + op2 = get_dir_byte_val(); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xD1: /* CMPB dir */ + op2 = get_dir_byte_val(); + result = B - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(B, op2); + break; + case 0xD2: /* SBCB dir */ + op1 = B; + op2 = get_dir_byte_val() + get_flag(CF); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xD3: /* ADDD dir */ + op1 = (A << 8) | (B & 0xFF); + op2 = get_dir_word_val(); + D = op1 + op2; + COND_SET_FLAG_C_16(D); + D &= 0xFFFF; + A = D >> 8; + B = D & 0xFF; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + condevalVa16(op1, op2); + break; + case 0xD4: /* ANDB dir */ + B = (B & get_dir_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xD5: /* BITB dir */ + result = (B & get_dir_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0xD6: /* LDB dir */ + B = get_dir_byte_val(); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xD7: /* STB dir */ + CPU_BD_put_mbyte(get_dir_addr(), B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xD8: /* EORB dir */ + B = (B ^ get_dir_byte_val()) & 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xD9: /* ADCB dir */ + op1 = B; + op2 = get_dir_byte_val() + get_flag(CF); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xDA: /* ORB dir */ + B = B | get_dir_byte_val(); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xDB: /* ADDB dir */ + op1 = B; + op2 = get_dir_byte_val(); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xDC: /* LDD dir */ + D = get_dir_word_val(); + A = D >> 8; + B = D & 0xFF; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xDD: /* STD dir */ + D = (A << 8) | (B & 0xFF); + CPU_BD_put_mword(get_dir_addr(), D); + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xDE: /* LDU dir */ + UP = get_dir_word_val(); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + case 0xDF: /* STU dir */ + CPU_BD_put_mword(get_dir_addr(), UP); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + +/* 0xE0 - indexed mode */ + case 0xE0: /* SUBB ind */ + op1 = B; + op2 = get_indexed_byte_val(); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xE1: /* CMPB ind */ + op2 = get_indexed_byte_val(); + result = B - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(B, op2); + break; + case 0xE2: /* SBCB ind */ + op1 = B; + op2 = get_indexed_byte_val() + get_flag(CF); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xE3: /* ADDD ind */ + op1 = (A << 8) | (B & 0xFF); + op2 = get_indexed_word_val(); + D = op1 + op2; + COND_SET_FLAG_C_16(D); + D &= 0xFFFF; + A = D >> 8; + B = D & 0xFF; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + condevalVa16(op1, op2); + break; + case 0xE4: /* ANDB ind */ + B = (B & get_indexed_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xE5: /* BITB ind */ + result = (B & get_indexed_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0xE6: /* LDB ind */ + B = get_indexed_byte_val(); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xE7: /* STB ind */ + CPU_BD_put_mbyte(get_indexed_addr(), B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xE8: /* EORB ind */ + B = (B ^ get_indexed_byte_val()) & 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xE9: /* ADCB ind */ + op1 = B; + op2 = get_indexed_byte_val() + get_flag(CF); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xEA: /* ORB ind */ + B = B | get_indexed_byte_val(); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xEB: /* ADDB ind */ + op1 = B; + op2 = get_indexed_byte_val(); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xEC: /* LDD ind */ + D = get_indexed_word_val(); + A = D >> 8; + B = D & 0xFF; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xED: /* STD ind */ + D = (A << 8) | (B & 0xFF); + CPU_BD_put_mword(get_indexed_addr(), D); + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xEE: /* LDU ind */ + UP = get_indexed_word_val(); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + case 0xEF: /* STU ind */ + CPU_BD_put_mword(get_indexed_addr(), UP); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + +/* 0xF0 - extended mode */ + case 0xF0: /* SUBB ext */ + op1 = B; + op2 = get_ext_byte_val(); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xF1: /* CMPB ext */ + op2 = get_ext_byte_val(); + result = B - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(B, op2); + break; + case 0xF2: /* SBCB ext */ + op1 = B; + op2 = get_ext_byte_val() + get_flag(CF); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xF3: /* ADDD ext */ + op1 = (A << 8) | (B & 0xFF); + op2 = get_ext_word_val(); + D = op1 + op2; + COND_SET_FLAG_C_16(D); + D &= 0xFFFF; + A = D >> 8; + B = D & 0xFF; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + condevalVa16(op1, op2); + break; + case 0xF4: /* ANDB ext */ + B = (B & get_ext_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xF5: /* BITB ext */ + result = (B & get_ext_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0xF6: /* LDB ext */ + B = get_ext_byte_val(); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xF7: /* STB ext */ + CPU_BD_put_mbyte(get_ext_addr(), B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xF8: /* EORB ext */ + B = (B ^ get_ext_byte_val()) & 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xF9: /* ADCB ext */ + op1 = B; + op2 = get_ext_byte_val() + get_flag(CF); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xFA: /* ORB ext */ + B = B | get_ext_byte_val(); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xFB: /* ADDB ext */ + op1 = B; + op2 = get_ext_byte_val(); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xFC: /* LDD ext */ + D = get_ext_word_val(); + A = D >> 8; + B = D & 0xFF; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xFD: /* STD ext */ + D = (A << 8) | (B & 0xFF); + CPU_BD_put_mword(get_ext_addr(), D); + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xFE: /* LDU ext */ + UP = get_ext_word_val(); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + case 0xFF: /* STU ext */ + CPU_BD_put_mword(get_ext_addr(), UP); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + + default: /* Unassigned */ + if (m6809_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(void) +{ + printf("\r\nPC=%04X SP=%04X UP=%04X IX=%04X IY=%04X ", PC, SP, UP, IX, IY); + printf("A=%02X B=%02X DP=%02X CCR=%02X", A, B, DP, CCR); +} + +void dump_regs1(void) +{ + printf("PC=%04X SP=%04X UP=%04X IX=%04X IY=%04X ", PC, SP, UP, IX, IY); + printf("A=%02X B=%02X DP=%02X CCR=%02X\n", A, B, DP, CCR); +} + +/* fetch an instruction or byte */ +int32 fetch_byte(int32 flag) +{ + uint8 val; + + val = CPU_BD_get_mbyte(PC); /* fetch byte */ + switch (flag) { + case 0: /* opcode fetch */ + sim_debug (DEBUG_asm, &m6809_dev, "%04X %s\n", PC, opcode[val]); + break; + case 1: /* byte operand fetch */ + sim_debug (DEBUG_asm, &m6809_dev, "0x%02XH\n", val); + break; + } + PC = (PC + 1) & ADDRMASK; /* increment PC */ + return val; +} + +/* fetch a word - big endian */ +int32 fetch_word() +{ + uint16 val; + + val = CPU_BD_get_mbyte(PC) << 8; /* fetch high byte */ + val |= (CPU_BD_get_mbyte(PC + 1)); /* fetch low byte */ + + /* 2-byte operand fetch */ + sim_debug (DEBUG_asm, &m6809_dev, "0x%04XH\n", val); + + PC = (PC + 2) & ADDRMASK; /* increment PC */ + return val; +} + +/* push a byte using the hardware stack pointer (SP) */ +void push_sp_byte(uint8 val) +{ + SP = (SP - 1) & ADDRMASK; + CPU_BD_put_mbyte(SP, val & 0xFF); +} + +/* push a byte using the user stack pointer (UP) */ +void push_up_byte(uint8 val) +{ + UP = (UP - 1) & ADDRMASK; + CPU_BD_put_mbyte(UP, val & 0xFF); +} + +/* push a word using the hardware stack pointer (SP) */ +void push_sp_word(uint16 val) +{ + push_sp_byte(val & 0xFF); + push_sp_byte(val >> 8); +} + +/* push a word using the user stack pointer (UP) */ +void push_up_word(uint16 val) +{ + push_up_byte(val & 0xFF); + push_up_byte(val >> 8); +} + +/* pop a byte using the hardware stack pointer (SP) */ +uint8 pop_sp_byte(void) +{ + register uint8 res; + + res = CPU_BD_get_mbyte(SP); + SP = (SP + 1) & ADDRMASK; + return res; +} + +/* pop a byte using the user stack pointer (UP) */ +uint8 pop_up_byte(void) +{ + register uint8 res; + + res = CPU_BD_get_mbyte(UP); + UP = (UP + 1) & ADDRMASK; + return res; +} + +/* pop a word using the hardware stack pointer (SP) */ +uint16 pop_sp_word(void) +{ + register uint16 res; + + res = pop_sp_byte() << 8; + res |= pop_sp_byte(); + return res; +} + +/* pop a word using the user stack pointer (UP) */ +uint16 pop_up_word(void) +{ + register uint16 res; + + res = pop_up_byte() << 8; + res |= pop_up_byte(); + return res; +} + +/* 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; + } +} + +/* this routine does the jump to long relative offset if the condition is met. Otherwise, execution continues at the current PC. */ +void go_long_rel(int32 cond) +{ + int32 temp; + + temp = get_long_rel_addr(); + if (cond != 0) { + PC += temp; + PC &= ADDRMASK; + } +} + +/* returns the relative offset sign-extended */ +int32 get_rel_addr(void) +{ + int32 temp; + + temp = fetch_byte(1); + if (temp & 0x80) + temp |= 0xFF00; + return temp & ADDRMASK; +} + +/* returns the long relative offset sign-extended */ +int32 get_long_rel_addr(void) +{ + return fetch_word(); +} + +/* returns the byte value at the direct address pointed to by PC */ +int32 get_dir_byte_val(void) +{ + return CPU_BD_get_mbyte(get_dir_addr()); +} + +/* returns the word value at the direct address pointed to by PC */ +int32 get_dir_word_val(void) +{ + return CPU_BD_get_mword(get_dir_addr()); +} + +/* returns the immediate byte value pointed to by PC */ +int32 get_imm_byte_val(void) +{ + return fetch_byte(1); +} + +/* returns the immediate word value pointed to by PC */ +int32 get_imm_word_val(void) +{ + return fetch_word(); +} + +/* returns the direct address pointed to by PC */ +/* use the Direct Page register as the high byte of the address */ +int32 get_dir_addr(void) +{ + int32 temp; + + temp = (DP << 8) + fetch_byte(1); + return temp & 0xFFFF; +} + +/* returns the byte value at the indexed address pointed to by PC */ +int32 get_indexed_byte_val(void) +{ + return CPU_BD_get_mbyte(get_indexed_addr()); +} + +/* returns the word value at the indexed address pointed to by PC */ +int32 get_indexed_word_val(void) +{ + return CPU_BD_get_mword(get_indexed_addr()); +} + +/* returns the indexed address. Note this also handles the indirect indexed mode */ +int32 get_indexed_addr(void) +{ + int32 temp; + int32 offset; + uint8 post_byte; + + /* fetch the index mode post-byte */ + post_byte = fetch_byte(1); + + if ((post_byte & 0x80) == 0) { + /* R +- 4-bit offset (non indirect only) */ + /* read register value */ + switch (post_byte & 0x60) { + case 0b00000000: temp = IX; break; + case 0b00100000: temp = IY; break; + case 0b01000000: temp = UP; break; + case 0b01100000: temp = SP; break; + default: break; + } + /* add 4 bit signed offset */ + if (post_byte & 0x10) { + /* subtract offset */ + offset = (post_byte | 0xFFF0); + temp += offset; + } else { + /* add offset */ + temp += (post_byte & 0x0F); + } + } else { + switch ( post_byte & 0x0F ) { + case 0b0000: + /* .R+ post increment by 1 (non indirect) */ + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX++; IX &= 0xFFFF; break; + case 0b00100000: temp = IY++; IY &= 0xFFFF; break; + case 0b01000000: temp = UP++; UP &= 0xFFFF; break; + case 0b01100000: temp = SP++; SP &= 0xFFFF; break; + default: break; + }; + break; + case 0b0001: + /* .R+ post increment by 2 (non indirect) */ + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX; IX=IX+2; IX &= 0xFFFF; break; + case 0b00100000: temp = IY; IY=IY+2; IY &= 0xFFFF; break; + case 0b01000000: temp = UP; UP=UP+2; UP &= 0xFFFF; break; + case 0b01100000: temp = SP; SP=SP+2; SP &= 0xFFFF; break; + default: break; + }; + break; + case 0b0010: + /* .-R pre decrement by 1 (non indirect) */ + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = --IX; IX &= 0xFFFF; break; + case 0b00100000: temp = --IY; IY &= 0xFFFF; break; + case 0b01000000: temp = --UP; UP &= 0xFFFF; break; + case 0b01100000: temp = --SP; SP &= 0xFFFF; break; + default: break; + }; + break; + case 0b0011: + /* .--R pre decrement by 2 (non indirect) */ + switch ( post_byte & 0x60 ) { + case 0b00000000: IX-=2; temp = IX; IX &= 0xFFFF; break; + case 0b00100000: IY-=2; temp = IY; IY &= 0xFFFF; break; + case 0b01000000: UP-=2; temp = UP; UP &= 0xFFFF; break; + case 0b01100000: SP-=2; temp = SP; SP &= 0xFFFF; break; + default: break; + }; + break; + case 0b0100: + /* R+0 zero offset (non indirect) */ + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX; break; + case 0b00100000: temp = IY; break; + case 0b01000000: temp = UP; break; + case 0b01100000: temp = SP; break; + default: break; + }; + break; + case 0b0101: + /* R+-ACCB (non indirect)*/ + if (B & 0x80) { + offset = B | 0xFF80; + } else { + offset = B; + } + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX; break; + case 0b00100000: temp = IY; break; + case 0b01000000: temp = UP; break; + case 0b01100000: temp = SP; break; + default: break; + }; + temp += offset; + break; + case 0b0110: + /* R+-ACCA (non indirect)*/ + if (A & 0x80) { + offset = A | 0xFF80; + } else { + offset = A; + } + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX; break; + case 0b00100000: temp = IY; break; + case 0b01000000: temp = UP; break; + case 0b01100000: temp = SP; break; + default: break; + }; + temp += offset; + break; + case 0b1000: + /* R+- 8-bit offset */ + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX; break; + case 0b00100000: temp = IY; break; + case 0b01000000: temp = UP; break; + case 0b01100000: temp = SP; break; + default: break; + }; + /* need to fetch 8-bit operand */ + offset = fetch_byte(1); + + /* add 7 bit signed offset */ + if (offset & 0x80) { + /* subtract offset */ + offset |= 0xFF00; + } + temp += offset; + break; + case 0b1001: + /* R+- 16-bit offset */ + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX; break; + case 0b00100000: temp = IY; break; + case 0b01000000: temp = UP; break; + case 0b01100000: temp = SP; break; + default: break; + }; + /* need to fetch 16-bit operand */ + offset = fetch_word(); + + /* add 16 bit signed offset */ + temp += offset; + break; + case 0b1011: + /* R+- ACCD */ + D = (A << 8) + (B & 0xFF); + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX + D; break; + case 0b00100000: temp = IY + D; break; + case 0b01000000: temp = UP + D; break; + case 0b01100000: temp = SP + D; break; + default: break; + }; + break; + case 0b1100: + /* PC+- 7-bit offset (non indirect) */ + /* need to fetch 8-bit operand */ + offset = fetch_byte(1); + // PC value after fetch!!! + temp = PC; + + /* add 7 bit signed offset */ + if (offset & 0x80) { + /* subtract offset */ + offset |= 0xFF00; + } + temp += offset; + break; + case 0b1101: + /* PC+- 15-bit offset (non indirect)*/ + /* need to fetch 16-bit operand */ + offset = fetch_word(); + // PC value after fetch!!! + temp = PC; + + /* add 15 bit signed offset */ + temp += offset; + break; + case 0b1111: + // Extended indirect - fetch 16-bit address + temp = fetch_word(); + break; + } + switch ( post_byte & 0x1F ) { + /* perform the indirection - 11 valid post-byte opcodes */ + case 0b10001: + case 0b10011: + case 0b10100: + case 0b10101: + case 0b10110: + case 0b11000: + case 0b11001: + case 0b11011: + case 0b11100: + case 0b11101: + case 0b11111: + temp = temp & 0xFFFF; + temp = CPU_BD_get_mword(temp); + break; + default: break; + } + } + /* make sure to truncate to 16-bit value */ + return temp & 0xFFFF; +} + +/* returns the value at the extended address pointed to by PC */ +int32 get_ext_byte_val(void) +{ + return CPU_BD_get_mbyte(get_ext_addr()); +} + +/* returns the value at the extended address pointed to by PC */ +int32 get_ext_word_val(void) +{ + return CPU_BD_get_mword(get_ext_addr()); +} + +/* returns the extended address pointed to by PC or immediate word */ +int32 get_ext_addr(void) +{ + int32 temp; + + temp = fetch_word(); + return temp; +} + +/* return 1 for flag set or 0 for flag clear */ +int32 get_flag(int32 flg) +{ + if (CCR & flg) { + return 1; + } + else { + return 0; + } +} + +/* test and set V for 8-addition */ +void condevalVa(int32 op1, int32 op2) +{ + if (((op1 & 0x80) == (op2 & 0x80)) && + (((op1 + op2) & 0x80) != (op1 & 0x80))) + SET_FLAG(VF); + else + CLR_FLAG(VF); +} + +/* test and set V for 16-bit addition */ +void condevalVa16(int32 op1, int32 op2) +{ + /* + IF (the sign of the 2 operands are the same) + AND + (the sum of the operands has a different sign than both of the 2 operands) + THEN set the Overflow flag + ELSE clear the Overflow flag + */ + if (((op1 & 0x8000) == (op2 & 0x8000)) && + (((op1 + op2) & 0x8000) != (op1 & 0x8000))) + SET_FLAG(VF); + else + CLR_FLAG(VF); +} + +/* test and set V for 8-bit subtraction */ +void condevalVs(int32 op1, int32 op2) +{ + if (((op1 & 0x80) != (op2 & 0x80)) && + (((op1 - op2) & 0x80) == (op2 & 0x80))) + SET_FLAG(VF); + else + CLR_FLAG(VF); + +} + +/* test and set V for 16-bit subtraction */ +void condevalVs16(int32 op1, int32 op2) +{ + if (((op1 & 0x8000) != (op2 & 0x8000)) && + (((op1 - op2) & 0x8000) == (op2 & 0x8000))) + SET_FLAG(VF); + else + CLR_FLAG(VF); + +} + +/* test and set H for addition (8-bit only) */ +void condevalHa(int32 op1, int32 op2) +{ + if (((op1 & 0x0f) + (op2 & 0x0f)) & 0x10) + SET_FLAG(HF); + else + CLR_FLAG(HF); +} + +/* calls from the simulator */ + +/* Reset routine */ +t_stat m6809_reset (DEVICE *dptr) +{ + CCR = EF | FF | IF; + DP = 0; + int_req = 0; + sim_brk_types = sim_brk_dflt = SWMASK ('E'); + saved_PC = CPU_BD_get_mword(0xFFFE); +// if (saved_PC == 0xFFFF) +// printf("No EPROM image found - M6809 reset incomplete!\n"); +// else +// printf("EPROM vector=%04X\n", saved_PC); + return SCPE_OK; +} + + +/* This is the dumper/loader. This command uses the -h to signify a + hex dump/load vice a binary one. If no address is given to load, it + takes the address from the hex record or the current PC for binary. +*/ + +t_stat sim_load (FILE *fileref, CONST char *cptr, CONST char *fnam, int flag) +{ + int32 i, addr = 0, cnt = 0; + + if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; + addr = saved_PC; + while ((i = getc (fileref)) != EOF) { + CPU_BD_put_mbyte(addr, i); + addr++; + cnt++; + } // end while + printf ("%d Bytes loaded.\n", cnt); + return (SCPE_OK); +} + +/* Symbolic output + + Inputs: + *of = output stream + addr = current PC + *val = pointer to values + *uptr = pointer to unit + sw = switches + Outputs: + status = error code + for M6809 +*/ +t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) +{ + int32 i, inst, inst1; + + if (sw & SWMASK ('D')) { // dump memory + for (i=0; i<16; i++) + fprintf(of, "%02X ", val[i]); + fprintf(of, " "); + for (i=0; i<16; i++) + if (isprint(val[i])) + fprintf(of, "%c", val[i]); + else + fprintf(of, "."); + return -15; + } else if (sw & SWMASK ('M')) { // dump instruction mnemonic + inst = val[0]; + if (!oplen[inst]) { // invalid opcode + fprintf(of, "%02X", inst); + return 0; + } + inst1 = inst & 0xF0; + fprintf (of, "%s", opcode[inst]); // mnemonic + if (strlen(opcode[inst]) == 3) + fprintf(of, " "); + if (inst1 == 0x20 || inst == 0x8D) { // rel operand + inst1 = val[1]; + if (val[1] & 0x80) + inst1 |= 0xFF00; + fprintf(of, " $%04X", (addr + inst1 + 2) & ADDRMASK); + } else if (inst1 == 0x80 || inst1 == 0xC0) { // imm operand + if ((inst & 0x0F) < 0x0C) + fprintf(of, " #$%02X", val[1]); + else + fprintf(of, " #$%02X%02X", val[1], val[2]); + } else if (inst1 == 0x60 || inst1 == 0xA0 || inst1 == 0xE0) // ind operand + fprintf(of, " %d,X", val[1]); + else if (inst1 == 0x70 || inst1 == 0xb0 || inst1 == 0xF0) // ext operand + fprintf(of, " $%02X%02X", val[1], val[2]); + return (-(oplen[inst] - 1)); + } else + return SCPE_ARG; +} + +/* Symbolic input + + Inputs: + *cptr = pointer to input string + addr = current PC + *uptr = pointer to unit + *val = pointer to output values + sw = switches + Outputs: + status = error status +*/ +t_stat parse_sym (CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) +{ + return (-2); +} + +/* end of m6809.c */ diff --git a/swtp6809/common/mp-09.c b/swtp6809/common/mp-09.c new file mode 100644 index 000000000..5a6c6e55d --- /dev/null +++ b/swtp6809/common/mp-09.c @@ -0,0 +1,283 @@ +/* mp-09.c: SWTP MP-09 M6809 CPU simulator + + Copyright (c) 2011-2012, 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. + + MODIFICATIONS: + + 24 Apr 15 -- Modified to use simh_debug + 19 Feb 24 -- Richard Lukes - modified SWTPC mp-a2 emulator to create mp-09 emulator. + + NOTES: + + The MP-09 CPU Board includes the SWTP Dynamic Address Translation (DAT) logic which + is used to create a 20-bit virtual address space (1MB of RAM). + + The MP-09 CPU Board contains the following devices [mp-09.c]: + M6809 processor [m6809.c]. + SWTPC SBUG-E, or custom boot ROM at top of 16-bit address space [bootrom.c]. + Interface to the SS-50 bus and the MP-B3 Mother Board for I/O + and memory boards [mp-b3.c]. +*/ + +#include +#include "swtp_defs.h" + +#define UNIT_V_USER_D (UNIT_V_UF) /* user defined switch */ +#define UNIT_USER_D (1 << UNIT_V_USER_D) +#define UNIT_V_4K_8K (UNIT_V_UF+1) /* off if HI_PROM and only 2K EPROM */ +#define UNIT_4K_8K (1 << UNIT_V_4K_8K) +#define UNIT_V_SWT (UNIT_V_UF+2) /* on SWTBUG, off MIKBUG */ +#define UNIT_SWT (1 << UNIT_V_SWT) +#define UNIT_V_8K (UNIT_V_UF+3) /* off if HI_PROM and only 2K or 4k EPROM */ +#define UNIT_8K (1 << UNIT_V_8K) +#define UNIT_V_RAM (UNIT_V_UF+4) /* off disables 6810 RAM */ +#define UNIT_RAM (1 << UNIT_V_RAM) +#define UNIT_V_LO_PROM (UNIT_V_UF+5) /* on EPROMS @ C000-CFFFH, off no EPROMS */ +#define UNIT_LO_PROM (1 << UNIT_V_LO_PROM) +#define UNIT_V_HI_PROM (UNIT_V_UF+6) /* on EPROMS @ F000-FFFFH, off fo LO_PROM, MON, or no EPROMS */ +#define UNIT_HI_PROM (1 << UNIT_V_HI_PROM) +#define UNIT_V_MON (UNIT_V_UF+7) /* on for monitor vectors in high memory */ +#define UNIT_MON (1 << UNIT_V_MON) + +/* local global variables */ +unsigned char DAT_RAM[16]; +unsigned char DAT_RAM_CACHE[16]; + +/* function prototypes */ + +t_stat CPU_BD_reset (DEVICE *dptr); +t_stat CPU_BD_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches); +t_stat CPU_BD_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); +int32 DAT_Xlate(int32 logical_addr); +int32 CPU_BD_get_mbyte(int32 addr); +int32 CPU_BD_get_mword(int32 addr); +void CPU_BD_put_mbyte(int32 addr, int32 val); +void CPU_BD_put_mword(int32 addr, int32 val); + +/* external routines */ + +/* MP-B3 bus routines */ +extern int32 MB_get_mbyte(int32 addr); +extern int32 MB_get_mword(int32 addr); +extern void MB_put_mbyte(int32 addr, int32 val); +extern void MB_put_mword(int32 addr, int32 val); + +/* MP-09 data structures + + CPU_BD_dev MP-09 device descriptor + CPU_BD_unit MP-09 unit descriptor + CPU_BD_reg MP-09 register list + CPU_BD_mod MP-09 modifiers list +*/ + +UNIT CPU_BD_unit = { UDATA (NULL, 0, 0) }; + +REG CPU_BD_reg[] = { + { NULL } +}; + +MTAB CPU_BD_mod[] = { + { UNIT_USER_D, UNIT_USER_D, "USER_D", "USER_D", NULL }, + { UNIT_USER_D, 0, "NOUSER_D", "NOUSER_D", NULL }, + { UNIT_4K_8K, UNIT_4K_8K, "4K_8K", "4K_8K", NULL }, + { UNIT_4K_8K, 0, "NO4K_8K", "NO4K_8K", NULL }, + { UNIT_SWT, UNIT_SWT, "SWT", "SWT", NULL }, + { UNIT_SWT, 0, "NOSWT", "NOSWT", NULL }, + { UNIT_8K, UNIT_8K, "8K", "8K", NULL }, + { UNIT_8K, 0, "NO8K", "NO8K", NULL }, + { UNIT_RAM, UNIT_RAM, "RAM", "RAM", NULL }, + { UNIT_RAM, 0, "NORAM", "NORAM", NULL }, + { UNIT_LO_PROM, UNIT_LO_PROM, "LO_PROM", "LO_PROM", NULL }, + { UNIT_LO_PROM, 0, "NOLO_PROM", "NOLO_PROM", NULL }, + { UNIT_HI_PROM, UNIT_HI_PROM, "HI_PROM", "HI_PROM", NULL }, + { UNIT_HI_PROM, 0, "NOHI_PROM", "NOHI_PROM", NULL }, + { UNIT_MON, UNIT_MON, "MON", "MON", NULL }, + { UNIT_MON, 0, "NOMON", "NOMON", NULL }, + { 0 } +}; + +DEBTAB CPU_BD_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE CPU_BD_dev = { + "MP-09", //name + &CPU_BD_unit, //units + CPU_BD_reg, //registers + CPU_BD_mod, //modifiers + 1, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + &CPU_BD_examine, //examine + &CPU_BD_deposit, //deposit + &CPU_BD_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + CPU_BD_debug, /* debflags */ + NULL, //msize + NULL //lname +}; + +/* reset */ +t_stat CPU_BD_reset (DEVICE *dptr) +{ + int32 i; + + // initialize DAT RAM + for (i=0; i<16; i++) { + DAT_RAM[i] = (~i) & 0x0F; + DAT_RAM_CACHE[i] = i; + } + return SCPE_OK; +} + +/* Deposit routine */ +t_stat CPU_BD_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= 0x10000) { + return SCPE_NXM; + } else { + CPU_BD_put_mbyte(addr, val); + return SCPE_OK; + } +} + +/* Examine routine */ +t_stat CPU_BD_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= 0x10000) { + return SCPE_NXM; + } + if (eval_array != NULL) { + *eval_array = CPU_BD_get_mbyte(addr); + } + return SCPE_OK; +} + +/* Perform adress translation from 16-bit logical address to 20-bit physical address using DAT mapping RAM */ +int32 DAT_Xlate(int32 logi_addr) +{ + int32 DAT_index; /* which of the 16 mapping registers to index */ + int32 DAT_byte; /* the lookup value from DAT RAM */ + int32 DAT_block; /* A13-A14-A15-A16 */ + + /* translation from 16-bit logical address to 20-bit physical address */ + DAT_index = (logi_addr & 0xF000) >> 12; + DAT_byte = DAT_RAM_CACHE[DAT_index]; + if (DAT_index >= 0xE) { + /* for logical addresses $E000-$FFFF */ + // Bank address (A17-A20) is 0b0000 + return((logi_addr & 0xFFF) + ((DAT_byte & 0x0F)<<12)); + } else { + // Bank address (A17-A20) is the high order 4-bits of DAT_byte + return((logi_addr & 0xFFF) + (DAT_byte<<12)); + } +} + +/* get a byte from memory */ +int32 CPU_BD_get_mbyte(int32 addr) +{ + int32 val = 0; + int32 phy_addr; + + sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mbyte: addr=%04X\n", addr); + switch(addr & 0xF000) { + case 0xE000: + case 0xF000: + /* ROM is mapped to logical address $E000-$FFFF at all times! Unaffected by DAT */ + val = MB_get_mbyte(addr); + sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mbyte: mp_b3 val=%02X\n", val); + break; + default: + /* access the resources on the motherboard - 16-bit addressing */ + /* 56K of RAM from 0000-DFFF */ + /* 8K of I/O space from E000-EFFF */ + /* 2K of scratchpad RAM from F000-F7FF ??? */ + phy_addr = DAT_Xlate(addr); + val = MB_get_mbyte(phy_addr); + sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mbyte: mp_b3 val=%02X\n", val); + break; + } + return val; +} + +/* get a word from memory */ +int32 CPU_BD_get_mword(int32 addr) +{ + int32 val; + + sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mword: addr=%04X\n", addr); + val = (CPU_BD_get_mbyte(addr) << 8); + val |= CPU_BD_get_mbyte(addr+1); + val &= 0xFFFF; + sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mword: val=%04X\n", val); + return val; +} + +/* put a byte to memory */ +void CPU_BD_put_mbyte(int32 addr, int32 val) +{ + int32 phy_addr; + + sim_debug (DEBUG_write, &CPU_BD_dev, "CPU_BD_put_mbyte: addr=%04X, val=%02X\n", addr, val); + + if ((addr & 0xFFF0) == 0xFFF0) { + DAT_RAM[addr & 0x0F] = val; + DAT_RAM_CACHE[addr & 0x0F] = (val & 0xF0) | (~val & 0x0F); + } else { + switch(addr & 0xF800) { + case 0xF800: + /* do not write to ROM area */ + break; + default: + phy_addr = DAT_Xlate(addr); + MB_put_mbyte(phy_addr, val); + break; + } + } +} + +/* put a word to memory */ +void CPU_BD_put_mword(int32 addr, int32 val) +{ + sim_debug (DEBUG_write, &CPU_BD_dev, "CPU_BD_put_mword: addr=%04X, val=%04X\n", + addr, val); + CPU_BD_put_mbyte(addr, val >> 8); + CPU_BD_put_mbyte(addr+1, val & 0xFF); +} + +/* end of mp-09.c */ diff --git a/swtp6809/common/mp-1m.c b/swtp6809/common/mp-1m.c new file mode 100644 index 000000000..ba3fa9442 --- /dev/null +++ b/swtp6809/common/mp-1m.c @@ -0,0 +1,221 @@ +/* mp-1m.c: SWTP 1M Byte Memory Card emulator + + Copyright (c) 2011-2012, William A. 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 O + 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. + + MODIFICATIONS: + + 24 Apr 15 -- Modified to use simh_debug + 19 Feb 24 -- Richard Lukes - Modified mp-8m.c to use for 1MB memory for swtp6809 emulator + + NOTES: + + These functions support 1MB of memory on an SS-50 system as a single 1MB memory card. + Due to the way DAT works, the upper 8KB of each 64KB address space is allocated to I/O ($E000) and ROM ($F000) space. + Therefore, the maximum usable RAM is 16 x 56KB = 896KB. + + The unit uses a statically allocated 1MB byte buffer. This makes for a fast implementation. + No effort was made to make available memory variable in size (e.g. limit to only 32KB, 64KB, 96KB, 128KB, etc.). +*/ + +#include +#include "swtp_defs.h" + +/* there is only one of these devices */ +#define ONE_MEGABYTE 0x100000 + +/* prototypes */ + +t_stat mp_1m_reset (DEVICE *dptr); +t_stat mp_1m_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches); +t_stat mp_1m_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); +int32 mp_1m_get_mbyte(int32 addr); +int32 mp_1m_get_mword(int32 addr); +void mp_1m_put_mbyte(int32 addr, int32 val); +void mp_1m_put_mword(int32 addr, int32 val); + +/* isbc064 Standard I/O Data Structures */ + +UNIT mp_1m_unit = { + UDATA (NULL, UNIT_FIX + UNIT_BINK, ONE_MEGABYTE) +}; + +MTAB mp_1m_mod[] = { + { 0 } +}; + +DEBTAB mp_1m_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE mp_1m_dev = { + "MP-1M", //name + &mp_1m_unit, //units + NULL, //registers + mp_1m_mod, //modifiers + 1, //numunits + 16, //aradix + 20, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + &mp_1m_examine, //examine + &mp_1m_deposit, //deposit + &mp_1m_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + mp_1m_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* Pre-allocate 1MB array of bytes */ +uint8 mp_1m_ram_memory_array[ONE_MEGABYTE]; + +/* Deposit routine */ +t_stat mp_1m_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= ONE_MEGABYTE) { + return SCPE_NXM; + } else { + mp_1m_ram_memory_array[addr] = val & 0xFF; + return SCPE_OK; + } +} + +/* Examine routine */ +t_stat mp_1m_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= ONE_MEGABYTE) { + return SCPE_NXM; + } + if (eval_array != NULL) { + *eval_array = mp_1m_ram_memory_array[addr]; + } + return SCPE_OK; +} + +/* Reset routine */ + +t_stat mp_1m_reset (DEVICE *dptr) +{ + int32 i, j, val; + UNIT *uptr; + + sim_debug (DEBUG_flow, &mp_1m_dev, "mp_1m_reset: \n"); + uptr = mp_1m_dev.units; + sim_debug (DEBUG_flow, &mp_1m_dev, "MP-1M %d unit.flags=%08X\n", i, uptr->flags); + + // capacity + uptr->capac = ONE_MEGABYTE; + // starting address + uptr->u3 = 0; + + if (uptr->filebuf == NULL) { + uptr->filebuf = &mp_1m_ram_memory_array; + if (uptr->filebuf == NULL) { + printf("mp_1m_reset: Malloc error\n"); + return SCPE_MEM; + } + for (j=0; j < uptr->capac; j++) { /* fill pattern for testing */ + i = j & 0xF; + val = (0xA0 | i) & 0xFF; + *((uint8 *)(uptr->filebuf) + j) = val; + } + sim_debug (DEBUG_flow, &mp_1m_dev, "MP-1M %d initialized at [%05X-%05XH]\n", i, uptr->u3, uptr->u3 + uptr->capac - 1); + } + sim_debug (DEBUG_flow, &mp_1m_dev, "mp_1m_reset: Done\n"); + return SCPE_OK; +} + +/* + I/O instruction handlers, called from the mp-b3 module when an + external memory read or write is issued. +*/ + +/* get a byte from memory */ + +int32 mp_1m_get_mbyte(int32 addr) +{ + //UNIT *uptr; + int32 val; + + //uptr = mp_1m_dev.units; + sim_debug (DEBUG_read, &mp_1m_dev, "mp_1m_get_mbyte: addr=%05X", addr); + if (addr >= ONE_MEGABYTE) { + sim_debug (DEBUG_read, &mp_1m_dev, "mp_1m_get_mbyte: addr=%08X Out of range\n", addr); + return 0xFF; + } else { + val = mp_1m_ram_memory_array[addr]; + sim_debug (DEBUG_read, &mp_1m_dev, " addr=%05x val=%02X\n", addr, val); + return val; + } +} + +/* get a word from memory */ + +int32 mp_1m_get_mword(int32 addr) +{ + int32 val; + + val = (mp_1m_get_mbyte(addr) << 8); + val |= mp_1m_get_mbyte(addr+1); + return val; +} + +/* put a byte into memory */ + +void mp_1m_put_mbyte(int32 addr, int32 val) +{ + //UNIT *uptr; + + //uptr = mp_1m_dev.units; + sim_debug (DEBUG_write, &mp_1m_dev, "mp_1m_put_mbyte: addr=%05X, val=%02X", addr, val); + + if (addr >= ONE_MEGABYTE) { + sim_debug (DEBUG_write, &mp_1m_dev, "mp_1m_put_mbyte: Address out of range, addr=%08x\n", addr); + } else { + mp_1m_ram_memory_array[addr] = val; + sim_debug (DEBUG_write, &mp_1m_dev, "\n"); + } +} + +/* put a word into memory */ + +void mp_1m_put_mword(int32 addr, int32 val) +{ + mp_1m_put_mbyte(addr, val >> 8); + mp_1m_put_mbyte(addr+1, val & 0xFF); +} + +/* end of mp-1m.c */ diff --git a/swtp6809/common/mp-b3.c b/swtp6809/common/mp-b3.c new file mode 100644 index 000000000..21936f197 --- /dev/null +++ b/swtp6809/common/mp-b3.c @@ -0,0 +1,287 @@ +/* mp-b3.c: SWTP SS-50/SS-30 MP-B3 Mother Board + + Copyright (c) 2011-2012, William A. 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. + + MODIFICATIONS: + + 24 Apr 15 -- Modified to use simh_debug + 19 Feb 24 -- Richard Lukes - Modified to emulate MP-B3 motherboard for swtp6809 emulator + + NOTES: + +*/ + +#include +#include "swtp_defs.h" + +#define UNIT_V_RAM_1MB (UNIT_V_UF) /* MP-1M board enable */ +#define UNIT_RAM_1MB (1 << UNIT_V_RAM_1MB) + +/* function prototypes */ + +/* empty I/O device routine */ +int32 nulldev(int32 io, int32 data); + +/* SS-50 bus routines */ +t_stat MB_reset (DEVICE *dptr); +t_stat MB_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches); +t_stat MB_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); +int32 MB_get_mbyte(int32 addr); +int32 MB_get_mword(int32 addr); +void MB_put_mbyte(int32 addr, int32 val); +void MB_put_mword(int32 addr, int32 val); + +/* BOOTROM memory access routines */ +extern int32 BOOTROM_get_mbyte(int32 offset); + +/* MP-1M memory access routines */ +extern int32 mp_1m_get_mbyte(int32 addr); +extern void mp_1m_put_mbyte(int32 addr, int32 val); + +/* SS-50 I/O address space functions */ + +/* MP-S serial I/O 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); + +/* DC-4 FDC I/O routines */ +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); + +/* +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 E000-E003 */ + {&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /*Port 0 E000-E003 */ + {&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /*Port 1 E004-E007 */ +/* 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 E008-E00B*/ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 3 E00C-E00F*/ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* Port 4 E010-E013*/ + {&fdcdrv}, {&nulldev}, {&nulldev}, {&nulldev}, /* Port 5 E014-E017 */ + {&fdccmd}, {&fdctrk}, {&fdcsec}, {&fdcdata}, /* Port 6 E018-E01B */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev} /*Port 7 E01C-E01F*/ +}; + +/* dummy i/o device */ + +int32 nulldev(int32 io, int32 data) +{ + if (io == 0) { + return (0xFF); + } else { + return 0; + } +} + +/* Mother Board data structures + + MB_dev Mother Board device descriptor + MB_unit Mother Board unit descriptor + MB_reg Mother Board register list + MB_mod Mother Board modifiers list +*/ + +UNIT MB_unit = { + UDATA (NULL, 0, 0) +}; + +REG MB_reg[] = { + { NULL } +}; + +MTAB MB_mod[] = { + { UNIT_RAM_1MB, UNIT_RAM_1MB, "1MB On", "1MB", NULL, NULL }, + { UNIT_RAM_1MB, 0, "1MB Off", "NO1MB", NULL, NULL }, + { 0 } +}; + +DEBTAB MB_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE MB_dev = { + "MP-B3", //name + &MB_unit, //units + MB_reg, //registers + MB_mod, //modifiers + 1, //numunits + 16, //aradix + 20, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + &MB_examine, //examine + &MB_deposit, //deposit + &MB_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + MB_debug, /* debflags */ + NULL, //msize + NULL //lname +}; + +/* reset */ +t_stat MB_reset (DEVICE *dptr) +{ + return SCPE_OK; +} + +/* Deposit routine */ +t_stat MB_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= 0x100000) { + return SCPE_NXM; + } else { + MB_put_mbyte(addr, val); + return SCPE_OK; + } +} + +/* Examine routine */ +t_stat MB_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= 0x100000) { + return SCPE_NXM; + } + if (eval_array != NULL) { + *eval_array = MB_get_mbyte(addr); + } + return SCPE_OK; +} + +/* get a byte from memory */ + +int32 MB_get_mbyte(int32 addr) +{ + int32 val; + + // 20-bit physical addresses + sim_debug (DEBUG_read, &MB_dev, "MB_get_mbyte: addr=%05X\n", addr); + switch (addr & 0x0F800) { + case 0x0E000: + /* reserved I/O space from $E000-$E01F */ + if ((addr & 0xFFFF) < 0xE020) { + val = (dev_table[(addr & 0xFFFF) - 0xE000].routine(0, 0)) & 0xFF; + break; + } + case 0x0E800: + case 0x0F000: + case 0x0F800: + /* Up to 8KB of boot ROM from $E000-$FFFF */ + val = BOOTROM_get_mbyte(addr & 0xFFFF); + sim_debug (DEBUG_read, &MB_dev, "MB_get_mbyte: EPROM=%02X\n", val); + break; + default: + /* all the rest is RAM */ + if (MB_unit.flags & UNIT_RAM_1MB) { + val = mp_1m_get_mbyte(addr); + if (MB_dev.dctrl & DEBUG_read) { + printf("MB_get_mbyte: mp_1m add=%05x val=%02X\n", addr, val); + } + } else { + ; // No RAM configured at this addresS + } + break; + } + sim_debug (DEBUG_read, &MB_dev, "MB_get_mbyte: I/O addr=%05X val=%02X\n", addr, val); + return val; +} + +/* get a word from memory */ + +int32 MB_get_mword(int32 addr) +{ + int32 val; + + sim_debug (DEBUG_read, &MB_dev, "MB_get_mword: addr=%04X\n", addr); + val = (MB_get_mbyte(addr) << 8); + val |= MB_get_mbyte(addr+1); + val &= 0xFFFF; + sim_debug (DEBUG_read, &MB_dev, "MB_get_mword: val=%04X\n", val); + return val; +} + +/* put a byte to memory */ + +void MB_put_mbyte(int32 addr, int32 val) +{ + // 20-bit physical addresses + sim_debug (DEBUG_write, &MB_dev, "MB_put_mbyte: addr=%05X, val=%02X\n", addr, val); + + switch(addr & 0xF000) { + case 0xE000: + /* I/O space */ + if ((addr & 0xFFFF) < 0xE020) { + dev_table[(addr & 0xFFFF) - 0xE000].routine(1, val); + } + break; + case 0xF000: + /* ROM space */ + break; + default: + /* RAM */ + if (MB_unit.flags & UNIT_RAM_1MB) { + mp_1m_put_mbyte(addr, val); + } else { + ; // No RAM conigured at this addresS + } + break; + } +} + +/* put a word to memory */ + +void MB_put_mword(int32 addr, int32 val) +{ + sim_debug (DEBUG_write, &MB_dev, "MB_ptt_mword: addr=%04X, val=%04X\n", addr, val); + MB_put_mbyte(addr, val >> 8); + MB_put_mbyte(addr+1, val & 0xFF); +} + +/* end of mp-b3.c */ diff --git a/swtp6809/common/mp-s.c b/swtp6809/common/mp-s.c new file mode 100644 index 000000000..7267d1951 --- /dev/null +++ b/swtp6809/common/mp-s.c @@ -0,0 +1,381 @@ +/* mp-s.c: SWTP MP-S serial I/O card simulator + + Copyright (c) 2005-2012, 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 + Willaim 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. + + MODIFICATIONS: + + 28 May 22 -- Roberto Sancho Villa (RSV) fixes for DEL and BS + + NOTES: + + These functions support a simulated SWTP MP-S interface card. + The card contains one M6850 ACIA. The ACIA implements one complete + serial port. It provides 7 or 8-bit ASCII RS-232 interface to Terminals + or 20 mA current loop interface to a model 33 or 37 Teletype. It is not + compatible with baudot Teletypes. Baud rates from 110 to 1200 are + switch selectable from S! on the MP-S. The ACIA ports appear at all + 4 addresses. This fact is used by SWTBUG to determine the presence of the + MP-S vice MP-C serial card. The ACIA interrupt request line can be connected + to the IRQ or NMI interrupt lines by a jumper on the MP-S. + + All I/O is via either programmed I/O or interrupt controlled I/O. + It has a status port and a data port. A write to the status port + can select some options for the device (0x03 will reset the port). + A read of the status port gets the port status: + + +---+---+---+---+---+---+---+---+ + | I | P | O | F |CTS|DCD|TXE|RXF| + +---+---+---+---+---+---+---+---+ + + RXF - A 1 in this bit position means a character has been received + on the data port and is ready to be read. + TXE - A 1 in this bit means the port is ready to receive a character + on the data port and transmit it out over the serial line. + + A read to the data port gets the buffered character, a write + to the data port writes the character to the device. +*/ + +#include +#include +#include "swtp_defs.h" + +#define UNIT_V_TTY (UNIT_V_UF) // TTY or ANSI mode +#define UNIT_TTY (1 << UNIT_V_TTY) + +#define RXF 0x01 +#define TXE 0x02 +#define DCD 0x04 +#define CTS 0x08 + +/* local global variables */ + +int32 ptr_stopioe = 0; // stop on error +int32 ptp_stopioe = 0; // stop on error +int32 odata; +int32 status; + +int32 ptp_flag = 0; +int32 ptr_flag = 0; + +/* function prototypes */ + +t_stat sio_svc (UNIT *uptr); +t_stat ptr_svc (UNIT *uptr); +t_stat ptp_svc (UNIT *uptr); +t_stat sio_reset (DEVICE *dptr); +t_stat ptr_reset (DEVICE *dptr); +t_stat ptp_reset (DEVICE *dptr); +int32 sio0s(int32 io, int32 data); +int32 sio0d(int32 io, int32 data); +int32 sio1s(int32 io, int32 data); +int32 sio1d(int32 io, int32 data); + +/* sio data structures + + sio_dev SIO device descriptor + sio_unit SIO unit descriptor + sio_reg SIO register list + sio_mod SIO modifiers list */ + +UNIT sio_unit = { + UDATA (&sio_svc, 0, 0), KBD_POLL_WAIT +}; + +REG sio_reg[] = { + { ORDATA (DATA, sio_unit.buf, 8) }, + { ORDATA (STAT, sio_unit.u3, 8) }, + { NULL } +}; + +MTAB sio_mod[] = { + { UNIT_TTY, UNIT_TTY, "TTY", "TTY", NULL }, + { UNIT_TTY, 0, "ANSI", "ANSI", NULL }, + { 0 } +}; + +DEVICE sio_dev = { + "MP-S", //name + &sio_unit, //units + sio_reg, //registers + sio_mod, //modifiers + 1, //numunits + 10, //aradix + 31, //awidth + 1, //aincr + 8, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + &sio_reset, //reset + NULL, //boot + NULL, //attach + NULL //detach +}; + +/* paper tape reader data structures + + ptr_dev PTR device descriptor + ptr_unit PTR unit descriptor + ptr_reg PTR register list + ptr_mod PTR modifiers list */ + +UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ + UNIT_ATTABLE, 0), KBD_POLL_WAIT +}; + +DEVICE ptr_dev = { + "PTR", //name + &ptr_unit, //units + NULL, //registers + NULL, //modifiers + 1, //numunits + 10, //aradix + 31, //awidth + 1, //aincr + 8, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + &ptr_reset, //reset + NULL, //boot + NULL, //attach + NULL //detach +}; + +/* paper tape punch data structures + + ptp_dev PTP device descriptor + ptp_unit PTP unit descriptor + ptp_reg PTP register list + ptp_mod PTP modifiers list */ + +UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ + UNIT_ATTABLE, 0), KBD_POLL_WAIT +}; +DEVICE ptp_dev = { + "PTP", //name + &ptp_unit, //units + NULL, //registers + NULL, //modifiers + 1, //numunits + 10, //aradix + 31, //awidth + 1, //aincr + 8, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + &ptp_reset, //reset + NULL, //boot + NULL, //attach + NULL //detach +}; + +/* console input service routine */ + +t_stat sio_svc (UNIT *uptr) +{ + int32 temp; + + sim_activate (&sio_unit, sio_unit.wait); // continue poll + if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) + return temp; // no char or error? + sio_unit.buf = temp & BYTEMASK; // Save char + if (sio_unit.buf==127) { + // convert BackSpace (ascii 127) so del char (ascii 8) for swtbug + sio_unit.buf=8; + } + sio_unit.u3 |= RXF; // Set RXF flag + /* Do any special character handling here */ + sio_unit.pos++; // step character count + return SCPE_OK; +} + +/* paper tape reader input service routine */ + +t_stat ptr_svc (UNIT *uptr) +{ + int32 temp; + + sim_activate (&ptr_unit, ptr_unit.wait); // continue poll + if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) + return temp; // no char or error? + ptr_unit.buf = temp & BYTEMASK; // Save char + ptr_unit.u3 |= RXF; // Set RXF flag + /* Do any special character handling here */ + ptr_unit.pos++; // step character count + return SCPE_OK; +} + +/* paper tape punch output service routine */ + +t_stat ptp_svc (UNIT *uptr) +{ + return SCPE_OK; +} + +/* Reset console */ + +t_stat sio_reset (DEVICE *dptr) +{ + sio_unit.buf = 0; //clear data buffer + sio_unit.u3 = TXE; //set TXE flag + sio_unit.wait = 10000; + sim_activate (&sio_unit, sio_unit.wait); // activate unit + return SCPE_OK; +} + +/* Reset paper tape reader */ + +t_stat ptr_reset (DEVICE *dptr) +{ + ptr_unit.buf = 0; //clear data buffer + ptr_unit.u3 = TXE; //set TXE flag + sim_cancel (&ptr_unit); // deactivate unit + return SCPE_OK; +} + +/* Reset paper tape punch */ + +t_stat ptp_reset (DEVICE *dptr) +{ + ptp_unit.buf = 0; //clear data buffer + ptp_unit.u3 = TXE; //set TXE flag + sim_cancel (&ptp_unit); // deactivate unit + return SCPE_OK; +} + +/* I/O instruction handlers, called from the MP-B2 module when a + read or write occur to addresses 0x8004-0x8007. */ + +int32 sio0s(int32 io, int32 data) +{ + if (io == 0) { // control register read + if (ptr_flag) { // reader enabled? + if ((ptr_unit.flags & UNIT_ATT) == 0) { // attached? + ptr_unit.u3 &= ~RXF; // no, clear RXF flag + ptr_flag = 0; // clear reader flag + printf("Reader not attached to file\n"); + } else { // attached + if (feof(ptr_unit.fileref)) { // EOF + ptr_unit.u3 &= ~RXF; // clear RXF flag + ptr_flag = 0; // clear reader flag + } else // not EOF + ptr_unit.u3 |= RXF; // set ready + } + return (status = ptr_unit.u3); // return ptr status + } else { + return (status = sio_unit.u3); // return console status + } + } else { // control register write + if (data == 0x03) { // reset port! + sio_unit.u3 = TXE; // reset console + sio_unit.buf = 0; + sio_unit.pos = 0; + ptr_unit.u3 = TXE; // reset reader + ptr_unit.buf = 0; + ptr_unit.pos = 0; + ptp_unit.u3 = TXE; // reset punch + ptp_unit.buf = 0; + ptp_unit.pos = 0; + } + return (status = 0); // invalid io + } +} + +int32 sio0d(int32 io, int32 data) +{ + if (io == 0) { // data register read + if (ptr_flag) { // RDR enabled? + if ((ptr_unit.flags & UNIT_ATT) == 0) // attached? + return 0; // no, done + if ((ptr_unit.u3 & RXF) == 0) // yes, more data? + return (odata & BYTEMASK); + if ((odata = getc(ptr_unit.fileref)) == EOF) { // end of file? + printf("Got EOF\n"); + ptr_unit.u3 &= 0xFE; // clear RXF flag + return (odata = 0); // no data + } + ptr_unit.pos++; // step character count + ptr_unit.u3 &= ~RXF; // clear RXF flag + return (odata & BYTEMASK); // return character + } else { + sio_unit.u3 &= ~RXF; // clear RXF flag + return (odata = sio_unit.buf); // return next char + } + } else { // data register write + if (isprint(data) || data == '\r' || data == '\n') { // printable? + sim_putchar(data); // print character on console + if (ptp_flag && ptp_unit.flags & UNIT_ATT) { // PTP enabled & attached? + putc(data, ptp_unit.fileref); + ptp_unit.pos++; // step character counter + } + } else { // DC1-DC4 control Reader/Punch + switch (data) { + case 0x11: // PTR on + ptr_flag = 1; + ptr_unit.u3 |= RXF; + printf("Reader on\n"); + break; + case 0x12: // PTP on + ptp_flag = 1; + ptp_unit.u3 |= TXE; + printf("Punch on\n"); + break; + case 0x13: // PTR off + ptr_flag = 0; + if (ptr_unit.pos) + printf("Reader off-%d bytes read\n", ptr_unit.pos); + ptr_unit.pos = 0; + break; + case 0x14: // PTP off + ptp_flag = 0; + if (ptp_unit.pos) + printf("Punch off-%d bytes written\n", ptp_unit.pos); + ptp_unit.pos = 0; + break; + default: // ignore all other characters + break; + } + } + } + return (odata = 0); +} + +/* because each port appears at 2 addresses and this fact is used + to determine if it is a MP-C or MP-S repeatedly in the SWTBUG + monitor, this code assures that reads of the high ports return + the same data as was read the last time on the low ports. +*/ + +int32 sio1s(int32 io, int32 data) +{ + return status; +} + +int32 sio1d(int32 io, int32 data) +{ + return odata; +} + +/* end of mp-s.c */ diff --git a/swtp6809/swtp6809/mp-09_sys.c b/swtp6809/swtp6809/mp-09_sys.c new file mode 100644 index 000000000..bf2e30293 --- /dev/null +++ b/swtp6809/swtp6809/mp-09_sys.c @@ -0,0 +1,89 @@ +/* mp09_sys.c: SWTP 6809 system interface + + Copyright (c) 2005-2012, 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. + + MODIFICATIONS + + 19 Feb 24 -- Richard Lukes - Modified mp-a2_sys.c for SWTP MP-09 emulation +*/ + +#include +#include +#include "swtp_defs.h" + +/* externals */ + +extern DEVICE CPU_BD_dev; +extern DEVICE m6809_dev; +extern REG m6809_reg[]; +extern DEVICE BOOTROM_dev; + +extern DEVICE MB_dev; +extern DEVICE sio_dev; +extern DEVICE ptr_dev; +extern DEVICE ptp_dev; +extern DEVICE mp_1m_dev; +extern DEVICE dsk_dev; + +/* SCP data structures + + sim_name simulator name string + sim_PC pointer to saved PC register descriptor + sim_emax number of words needed for examine + sim_devices array of pointers to simulated devices + sim_stop_messages array of pointers to stop messages + sim_load binary loader +*/ + +char sim_name[] = "SWTP 6809, V0.7, MP-09 CPU Board"; + +REG *sim_PC = &m6809_reg[0]; + +// maximum number of words needed for examine +int32 sim_emax = 4; + +DEVICE *sim_devices[] = { + &m6809_dev, + &CPU_BD_dev, + &BOOTROM_dev, + &MB_dev, + &sio_dev, + &ptr_dev, + &ptp_dev, + &mp_1m_dev, + &dsk_dev, + NULL +}; + +const char *sim_stop_messages[] = { + "Unknown error", + "RESERVED", + "Halt instruction", + "Breakpoint" + "Invalid opcode", + "Invalid memory", + "Unknown error" +}; + +/* end of mp09_sys.c */ diff --git a/swtp6809/swtp6809/swtp6809mp-09.ini b/swtp6809/swtp6809/swtp6809mp-09.ini new file mode 100644 index 000000000..00451a952 --- /dev/null +++ b/swtp6809/swtp6809/swtp6809mp-09.ini @@ -0,0 +1,16 @@ +set bootrom debug +set bootrom 2716 +attach bootrom sbuge.bin +set mp-b3 1MB +set cpu hex +set cpu itrap +set cpu mtrap +attach dc-40 FULL.DSK +set dc-40 RO +;attach dc-41 FULL2.DSK +;set dc-41 RO +;attach dc-42 FULL3.DSK +;set dc-42 RO +;attach dc-43 FULL4.DSK +;set dc-43 RW +reset diff --git a/swtp6809/swtp6809/swtp_defs.h b/swtp6809/swtp6809/swtp_defs.h new file mode 100644 index 000000000..a0b341d46 --- /dev/null +++ b/swtp6809/swtp6809/swtp_defs.h @@ -0,0 +1,64 @@ +/* swtp_defs.h: SWTP 6809 simulator definitions + + Copyright (c) 2005-2012, 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 SHAL + 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 I + 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. + + MODIFICATIONS + + 19 Feb 24 - Richard Lukes - Modified for swtp6809 emulator +*/ + +#include +#include "sim_defs.h" // simulator defs + +/* Rename of global PC variable to avoid namespace conflicts on some platforms */ + +#define PC PC_Global + +/* Memory */ + +#define MAXMEMSIZE 65536 // max memory size +#define MEMSIZE (m6809_unit.capac) // actual memory size +#define ADDRMASK (MAXMEMSIZE - 1) // address mask +#define BYTEMASK 0xFF +#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) + +/* debug definitions */ + +#define DEBUG_flow 0x0001 +#define DEBUG_read 0x0002 +#define DEBUG_write 0x0004 +#define DEBUG_level1 0x0008 +#define DEBUG_level2 0x0010 +#define DEBUG_reg 0x0020 +#define DEBUG_asm 0x0040 +#define DEBUG_all 0xFFFF + +/* Simulator stop codes */ + +#define STOP_RSRV 1 // must be 1 +#define STOP_HALT 2 // HALT-really WAI +#define STOP_IBKPT 3 // breakpoint +#define STOP_OPCODE 4 // invalid opcode +#define STOP_MEMORY 5 // invalid memory address + diff --git a/swtp6809/swtp6809/swtp_sbuge_bin.h b/swtp6809/swtp6809/swtp_sbuge_bin.h new file mode 100644 index 000000000..30c153b96 --- /dev/null +++ b/swtp6809/swtp6809/swtp_sbuge_bin.h @@ -0,0 +1,141 @@ +#ifndef ROM_swtp_sbuge_bin_H +#define ROM_swtp_sbuge_bin_H 0 +/* + This file is a generated file and should NOT be edited or changed by hand. + + SWTPC SBUG-E 2KB Monitor ROM +*/ +#define BOOT_CODE_SIZE 0x800 +#define BOOT_CODE_FILENAME "sbuge.bin" +#define BOOT_CODE_ARRAY swtp_sbuge_bin +unsigned char swtp_sbuge_bin[] = { +0xf8, 0x14, 0xf8, 0x61, 0xfd, 0xcf, 0xfd, 0xc9, 0xfd, 0xdf, 0xfd, 0xee, 0xfd, 0xbd, 0xfd, 0xb1, +0xfd, 0xad, 0xfb, 0x81, 0x8e, 0xfe, 0x4f, 0x10, 0x8e, 0xdf, 0xc0, 0xc6, 0x10, 0xa6, 0x80, 0xa7, +0xa0, 0x5a, 0x26, 0xf9, 0x8e, 0xe0, 0x04, 0xbf, 0xdf, 0xe0, 0x17, 0x02, 0x7a, 0xc6, 0x0c, 0x6f, +0xe2, 0x5a, 0x26, 0xfb, 0x30, 0x8c, 0xdd, 0xaf, 0x6a, 0x86, 0xd0, 0xa7, 0xe4, 0x1f, 0x43, 0x17, +0x05, 0xbe, 0x8e, 0xfe, 0x5f, 0x17, 0x05, 0x75, 0x8e, 0xdf, 0xd0, 0x4f, 0xc6, 0x0d, 0x6d, 0x85, +0x27, 0x03, 0x8b, 0x04, 0x19, 0x5a, 0x2a, 0xf6, 0x17, 0x05, 0x26, 0x8e, 0xfe, 0x74, 0x17, 0x05, +0x5c, 0x8e, 0xfe, 0x7b, 0x17, 0x05, 0x46, 0x17, 0x05, 0x65, 0x84, 0x7f, 0x81, 0x0d, 0x27, 0xf1, +0x1f, 0x89, 0x81, 0x20, 0x2c, 0x09, 0x86, 0x5e, 0x17, 0x05, 0x73, 0x1f, 0x98, 0x8b, 0x40, 0x17, +0x05, 0x6c, 0x17, 0x05, 0x67, 0xc1, 0x60, 0x2f, 0x02, 0xc0, 0x20, 0x8e, 0xfe, 0x13, 0xe1, 0x80, +0x27, 0x0f, 0x30, 0x02, 0x8c, 0xfe, 0x4f, 0x26, 0xf5, 0x8e, 0xfe, 0x7d, 0x17, 0x05, 0x1e, 0x20, +0xc0, 0xad, 0x94, 0x20, 0xbc, 0x1f, 0x34, 0x3b, 0x8e, 0xfe, 0x83, 0x17, 0x04, 0xff, 0x17, 0x04, +0x11, 0x17, 0x04, 0x19, 0x17, 0x04, 0x21, 0x17, 0x04, 0x29, 0x17, 0x04, 0x31, 0x8e, 0xfe, 0x83, +0x17, 0x04, 0xea, 0x17, 0x04, 0x33, 0x17, 0x04, 0x3a, 0x17, 0x04, 0x41, 0x16, 0x04, 0x48, 0x17, +0x04, 0x27, 0x17, 0x05, 0x17, 0x17, 0x04, 0x57, 0x29, 0x02, 0xaf, 0x4a, 0x39, 0x17, 0x03, 0xed, +0x17, 0x05, 0x09, 0x17, 0x04, 0x49, 0x29, 0x02, 0xaf, 0x48, 0x39, 0x17, 0x04, 0x00, 0x17, 0x04, +0xfb, 0x17, 0x04, 0x3b, 0x29, 0x02, 0xaf, 0x46, 0x39, 0x17, 0x03, 0xe7, 0x17, 0x04, 0xed, 0x17, +0x04, 0x2d, 0x29, 0x02, 0xaf, 0x44, 0x39, 0x17, 0x03, 0xce, 0x17, 0x04, 0xdf, 0x17, 0x04, 0x30, +0x29, 0x02, 0xa7, 0x43, 0x39, 0x17, 0x03, 0xf5, 0x17, 0x04, 0xd1, 0x17, 0x04, 0x22, 0x29, 0x02, +0xa7, 0x42, 0x39, 0x17, 0x03, 0xdd, 0x17, 0x04, 0xc3, 0x17, 0x04, 0x14, 0x29, 0x02, 0xa7, 0x41, +0x39, 0x17, 0x03, 0xe3, 0x17, 0x04, 0xb5, 0x17, 0x04, 0x06, 0x29, 0x04, 0x8a, 0x80, 0xa7, 0xc4, +0x39, 0x17, 0x03, 0xeb, 0x29, 0x2d, 0x1f, 0x12, 0x8e, 0xfe, 0x83, 0x17, 0x04, 0x5f, 0x1f, 0x21, +0x17, 0x04, 0x26, 0x17, 0x04, 0x96, 0xa6, 0xa4, 0x17, 0x04, 0x26, 0x17, 0x04, 0x8e, 0x17, 0x03, +0xdf, 0x28, 0x11, 0x81, 0x08, 0x27, 0xe1, 0x81, 0x18, 0x27, 0xdd, 0x81, 0x5e, 0x27, 0x17, 0x81, +0x0d, 0x26, 0x0f, 0x39, 0xa7, 0xa4, 0xa1, 0xa4, 0x27, 0x08, 0x17, 0x04, 0x6f, 0x86, 0x3f, 0x17, +0x04, 0x6c, 0x31, 0x21, 0x20, 0xc2, 0x31, 0x3f, 0x20, 0xbe, 0x17, 0x03, 0x35, 0x1f, 0x32, 0x8e, +0xdf, 0xc0, 0x30, 0x1f, 0x20, 0x05, 0x17, 0x03, 0x8b, 0x29, 0x06, 0x34, 0x20, 0xac, 0xe1, 0x24, +0x01, 0x39, 0x1f, 0x10, 0xc3, 0x00, 0x10, 0xc4, 0xf0, 0x34, 0x06, 0x1f, 0x20, 0xc4, 0xf0, 0x1f, +0x01, 0xac, 0xe4, 0x27, 0x05, 0x17, 0x04, 0x27, 0x27, 0x03, 0x32, 0x62, 0x39, 0x34, 0x10, 0x8e, +0xfe, 0x83, 0x17, 0x03, 0xe8, 0xae, 0xe4, 0x17, 0x03, 0xaf, 0xc6, 0x10, 0xa6, 0x80, 0x17, 0x03, +0xb0, 0x17, 0x04, 0x18, 0x5a, 0x26, 0xf5, 0x17, 0x04, 0x10, 0xae, 0xe1, 0xc6, 0x10, 0xa6, 0x80, +0x81, 0x20, 0x25, 0x04, 0x81, 0x7e, 0x23, 0x02, 0x86, 0x2e, 0x17, 0x04, 0x01, 0x5a, 0x26, 0xee, +0x20, 0xbf, 0x6f, 0xe2, 0x6f, 0xe2, 0x17, 0x03, 0x2b, 0x34, 0x30, 0x29, 0x7b, 0xac, 0x62, 0x25, +0x77, 0x17, 0x03, 0xe8, 0x1f, 0x20, 0xe3, 0x64, 0x34, 0x04, 0xab, 0xe0, 0xa7, 0xa0, 0x10, 0xac, +0xe4, 0x25, 0xf1, 0x10, 0xae, 0x62, 0x1f, 0x20, 0xe3, 0x64, 0x34, 0x02, 0xeb, 0xe0, 0xe8, 0xa0, +0x27, 0x3c, 0x8e, 0xfe, 0x83, 0x17, 0x03, 0x85, 0x30, 0x3f, 0x17, 0x03, 0x4c, 0x34, 0x10, 0x8e, +0xfe, 0xa1, 0x17, 0x03, 0x88, 0x35, 0x10, 0x17, 0x01, 0x47, 0x17, 0x03, 0x50, 0x17, 0x03, 0x39, +0x8e, 0xfe, 0x87, 0x17, 0x03, 0x77, 0xae, 0x64, 0x17, 0x03, 0x2e, 0x8e, 0xfe, 0x8f, 0x17, 0x03, +0x6c, 0x1f, 0x98, 0x8e, 0xfe, 0xa6, 0x17, 0x03, 0x3e, 0x17, 0x03, 0x83, 0x26, 0x1a, 0x10, 0xac, +0xe4, 0x25, 0xb3, 0x86, 0x2b, 0x17, 0x03, 0x86, 0x17, 0x03, 0x74, 0x26, 0x0b, 0x10, 0xae, 0x62, +0x6c, 0x65, 0x26, 0x90, 0x6c, 0x64, 0x26, 0x8c, 0x32, 0x66, 0x39, 0x17, 0x02, 0xb1, 0x29, 0x1e, +0x8c, 0xdf, 0xc0, 0x24, 0x1a, 0x34, 0x10, 0x8e, 0xff, 0xff, 0x8d, 0x55, 0x35, 0x10, 0x27, 0x0f, +0xa6, 0x84, 0x81, 0x3f, 0x27, 0x09, 0xa7, 0xa0, 0xaf, 0xa4, 0x86, 0x3f, 0xa7, 0x84, 0x39, 0x17, +0x03, 0x4a, 0x86, 0x3f, 0x16, 0x03, 0x47, 0x10, 0x8e, 0xdf, 0xe3, 0xc6, 0x08, 0x8d, 0x18, 0x5a, +0x26, 0xfb, 0x39, 0x1f, 0x43, 0xae, 0x4a, 0x30, 0x1f, 0x8d, 0x26, 0x27, 0x04, 0xaf, 0x4a, 0x8d, +0x06, 0x17, 0xfd, 0xe4, 0x16, 0xfd, 0x9a, 0xae, 0x21, 0x8c, 0xdf, 0xc0, 0x24, 0x0a, 0xa6, 0x84, +0x81, 0x3f, 0x26, 0x04, 0xa6, 0xa4, 0xa7, 0x84, 0x86, 0xff, 0xa7, 0xa0, 0xa7, 0xa0, 0xa7, 0xa0, +0x39, 0x10, 0x8e, 0xdf, 0xe3, 0xc6, 0x08, 0xa6, 0xa0, 0xac, 0xa1, 0x27, 0x04, 0x5a, 0x26, 0xf7, +0x39, 0x31, 0x3d, 0x39, 0x86, 0xde, 0xb7, 0xf0, 0x24, 0x86, 0xff, 0xb7, 0xf0, 0x14, 0xb7, 0xf0, +0x10, 0xb7, 0xf0, 0x15, 0xb7, 0xf0, 0x16, 0x7d, 0xf0, 0x10, 0x86, 0xd8, 0xb7, 0xf0, 0x20, 0x17, +0x00, 0x97, 0xb6, 0xf0, 0x20, 0x2b, 0xfb, 0x86, 0x09, 0xb7, 0xf0, 0x20, 0x17, 0x00, 0x8a, 0xb6, +0xf0, 0x20, 0x85, 0x01, 0x26, 0xf9, 0x85, 0x10, 0x26, 0xca, 0x8e, 0xc0, 0x00, 0x8d, 0x52, 0x8a, +0x10, 0xb7, 0xf0, 0x40, 0x1f, 0x10, 0x43, 0x53, 0xfd, 0xf0, 0x00, 0x8e, 0xfe, 0xff, 0xbf, 0xf0, +0x02, 0x86, 0xff, 0xb7, 0xf0, 0x10, 0x86, 0xfe, 0xb7, 0xf0, 0x14, 0x86, 0x01, 0xb7, 0xf0, 0x22, +0x86, 0x8c, 0xb7, 0xf0, 0x20, 0x8d, 0x52, 0x5f, 0x34, 0x04, 0x5f, 0x7d, 0xf0, 0x10, 0x2a, 0x0a, +0x5a, 0x26, 0xf8, 0x35, 0x04, 0x5a, 0x26, 0xf0, 0x20, 0x8a, 0x35, 0x04, 0xb6, 0xf0, 0x20, 0x85, +0x1c, 0x27, 0x01, 0x39, 0xc6, 0xde, 0xf7, 0xf0, 0x24, 0x8e, 0xc0, 0x00, 0xaf, 0x4a, 0x1f, 0x34, +0x3b, 0x34, 0x36, 0xa6, 0x62, 0x44, 0x44, 0x44, 0x44, 0x10, 0x8e, 0xdf, 0xd0, 0xe6, 0xa6, 0x54, +0x54, 0x54, 0x54, 0xe7, 0xe4, 0xe6, 0xa6, 0x53, 0x58, 0x58, 0x58, 0x58, 0xa6, 0x62, 0x84, 0x0f, +0xa7, 0x62, 0xea, 0x62, 0xe7, 0x62, 0x35, 0x36, 0x39, 0x34, 0x04, 0xc6, 0x20, 0x5a, 0x26, 0xfd, +0x35, 0x04, 0x39, 0x7d, 0xe0, 0x18, 0x7f, 0xe0, 0x14, 0xc6, 0x03, 0x8e, 0x00, 0x00, 0x30, 0x01, +0x8c, 0x00, 0x00, 0x26, 0xf9, 0x5a, 0x26, 0xf6, 0x86, 0x0f, 0xb7, 0xe0, 0x18, 0x8d, 0x37, 0xf6, +0xe0, 0x18, 0xc5, 0x01, 0x26, 0xf9, 0x86, 0x01, 0xb7, 0xe0, 0x1a, 0x8d, 0x29, 0x86, 0x8c, 0xb7, +0xe0, 0x18, 0x8d, 0x22, 0x8e, 0xc0, 0x00, 0x20, 0x09, 0xc5, 0x02, 0x27, 0x05, 0xb6, 0xe0, 0x1b, +0xa7, 0x80, 0xf6, 0xe0, 0x18, 0xc5, 0x01, 0x26, 0xf0, 0xc5, 0x2c, 0x27, 0x01, 0x39, 0x8e, 0xc0, +0x00, 0xaf, 0x4a, 0x1f, 0x34, 0x3b, 0xc6, 0x20, 0x5a, 0x26, 0xfd, 0x39, 0x86, 0x11, 0x17, 0x01, +0xdd, 0x7f, 0xdf, 0xe2, 0x17, 0x01, 0xad, 0x81, 0x53, 0x26, 0xf9, 0x17, 0x01, 0xa6, 0x81, 0x39, +0x27, 0x3d, 0x81, 0x31, 0x26, 0xf1, 0x17, 0x01, 0x17, 0x34, 0x02, 0x29, 0x26, 0x17, 0x00, 0xff, +0x29, 0x21, 0x34, 0x10, 0xe6, 0xe0, 0xeb, 0xe0, 0xeb, 0xe4, 0x6a, 0xe4, 0x6a, 0xe4, 0x34, 0x04, +0x17, 0x00, 0xfd, 0x35, 0x04, 0x29, 0x0c, 0x34, 0x02, 0xeb, 0xe0, 0x6a, 0xe4, 0x27, 0x05, 0xa7, +0x80, 0x20, 0xeb, 0x5f, 0x35, 0x02, 0xc1, 0xff, 0x27, 0xb2, 0x86, 0x3f, 0x17, 0x01, 0x8f, 0x73, +0xdf, 0xe2, 0x86, 0x13, 0x16, 0x01, 0x87, 0x6f, 0xe2, 0x17, 0x00, 0xb8, 0x34, 0x30, 0x29, 0x4a, +0xac, 0x62, 0x25, 0x46, 0x30, 0x01, 0xaf, 0xe4, 0x86, 0x12, 0x17, 0x01, 0x71, 0xec, 0xe4, 0xa3, +0x62, 0x27, 0x06, 0x10, 0x83, 0x00, 0x20, 0x23, 0x02, 0xc6, 0x20, 0xe7, 0x64, 0x8e, 0xfe, 0xeb, +0x17, 0x01, 0x1a, 0xcb, 0x03, 0x1f, 0x98, 0x17, 0x00, 0xe7, 0xae, 0x62, 0x17, 0x00, 0xda, 0xeb, +0x62, 0xeb, 0x63, 0xeb, 0x84, 0xa6, 0x80, 0x17, 0x00, 0xd7, 0x6a, 0x64, 0x26, 0xf5, 0x53, 0x1f, +0x98, 0x17, 0x00, 0xcd, 0xaf, 0x62, 0xac, 0xe4, 0x26, 0xc3, 0x86, 0x14, 0x17, 0x01, 0x2f, 0x32, +0x65, 0x39, 0x8e, 0xfe, 0xae, 0x17, 0x00, 0xf5, 0x1f, 0x31, 0x16, 0x00, 0xac, 0x8e, 0xfe, 0xba, +0x17, 0x00, 0xea, 0xae, 0x48, 0x16, 0x00, 0xa1, 0x8e, 0xfe, 0xcc, 0x17, 0x00, 0xdf, 0xa6, 0x43, +0x16, 0x00, 0x9e, 0x8e, 0xfe, 0xc6, 0x17, 0x00, 0xd4, 0xae, 0x44, 0x16, 0x00, 0x8b, 0x8e, 0xfe, +0xc0, 0x17, 0x00, 0xc9, 0xae, 0x46, 0x16, 0x00, 0x80, 0x8e, 0xfe, 0xb4, 0x17, 0x00, 0xbe, 0xae, +0x4a, 0x20, 0x76, 0x8e, 0xfe, 0xd2, 0x17, 0x00, 0xb4, 0xa6, 0x41, 0x20, 0x74, 0x8e, 0xfe, 0xd7, +0x17, 0x00, 0xaa, 0xa6, 0x42, 0x20, 0x6a, 0x8e, 0xfe, 0xdc, 0x17, 0x00, 0xa0, 0xa6, 0xc4, 0x8e, +0xfe, 0xe3, 0x20, 0x73, 0x8d, 0x09, 0x29, 0x4e, 0x1f, 0x12, 0x86, 0x2d, 0x17, 0x00, 0xbf, 0x8d, +0x0f, 0x29, 0x43, 0x1f, 0x01, 0x8d, 0x09, 0x29, 0x3d, 0x34, 0x10, 0xa7, 0x61, 0x35, 0x10, 0x39, +0x8d, 0x11, 0x29, 0x32, 0x48, 0x48, 0x48, 0x48, 0x1f, 0x89, 0x8d, 0x07, 0x29, 0x28, 0x34, 0x04, +0xab, 0xe0, 0x39, 0x8d, 0x6f, 0x81, 0x30, 0x25, 0x1d, 0x81, 0x39, 0x22, 0x03, 0x80, 0x30, 0x39, +0x81, 0x41, 0x25, 0x12, 0x81, 0x46, 0x22, 0x03, 0x80, 0x37, 0x39, 0x81, 0x61, 0x25, 0x07, 0x81, +0x66, 0x22, 0x03, 0x80, 0x57, 0x39, 0x1a, 0x02, 0x39, 0x34, 0x10, 0x35, 0x02, 0x8d, 0x02, 0x35, +0x02, 0x34, 0x02, 0x44, 0x44, 0x44, 0x44, 0x8d, 0x04, 0x35, 0x02, 0x84, 0x0f, 0x8b, 0x30, 0x81, +0x39, 0x2f, 0x02, 0x8b, 0x07, 0x20, 0x57, 0x34, 0x02, 0xc6, 0x08, 0xa6, 0x80, 0x68, 0xe4, 0x25, +0x02, 0x86, 0x2d, 0x8d, 0x49, 0x8d, 0x45, 0x5a, 0x26, 0xf1, 0x35, 0x02, 0x39, 0x8d, 0x02, 0x20, +0x0c, 0x34, 0x10, 0x8e, 0xfe, 0x75, 0x8d, 0x05, 0x35, 0x10, 0x39, 0x8d, 0x31, 0xa6, 0x80, 0x81, +0x04, 0x26, 0xf8, 0x39, 0x7d, 0xdf, 0xe2, 0x27, 0x06, 0x8d, 0x04, 0x84, 0x7f, 0x20, 0x1f, 0x34, +0x10, 0xbe, 0xdf, 0xe0, 0xa6, 0x84, 0x85, 0x01, 0x27, 0xfa, 0xa6, 0x01, 0x35, 0x10, 0x39, 0x34, +0x02, 0xa6, 0x9f, 0xdf, 0xe0, 0x85, 0x01, 0x35, 0x02, 0x39, 0x8d, 0x00, 0x86, 0x20, 0x34, 0x12, +0xbe, 0xdf, 0xe0, 0xa6, 0x84, 0x85, 0x02, 0x27, 0xfa, 0x35, 0x02, 0xa7, 0x01, 0x35, 0x10, 0x39, +0xbe, 0xdf, 0xe0, 0x86, 0x03, 0xa7, 0x84, 0x86, 0x11, 0xa7, 0x84, 0x6d, 0x01, 0x86, 0xff, 0xb7, +0xdf, 0xe2, 0x39, 0x01, 0xf9, 0x23, 0x02, 0xf9, 0x15, 0x03, 0xf9, 0x31, 0x04, 0xf9, 0x07, 0x10, +0xf8, 0xcf, 0x15, 0xf8, 0xdd, 0x18, 0xf8, 0xf9, 0x19, 0xf8, 0xeb, 0x42, 0xfa, 0x7b, 0x44, 0xfa, +0xf4, 0x45, 0xf9, 0x96, 0x47, 0xf8, 0xa5, 0x4c, 0xfc, 0x0c, 0x4d, 0xf9, 0x41, 0x50, 0xfc, 0x67, +0x51, 0xf9, 0xf2, 0x52, 0xf8, 0xa8, 0x53, 0xf9, 0x8a, 0x55, 0xfb, 0xb3, 0x58, 0xfa, 0xa7, 0xfa, +0xb3, 0xf8, 0xa7, 0xf8, 0xa7, 0xf8, 0xa7, 0xf8, 0xa7, 0xfa, 0xb3, 0xff, 0xff, 0xff, 0xff, 0x00, +0x00, 0x00, 0x0d, 0x0a, 0x00, 0x00, 0x00, 0x53, 0x2d, 0x42, 0x55, 0x47, 0x20, 0x31, 0x2e, 0x38, +0x20, 0x2d, 0x20, 0x04, 0x4b, 0x0d, 0x0a, 0x00, 0x00, 0x00, 0x04, 0x3e, 0x04, 0x57, 0x48, 0x41, +0x54, 0x3f, 0x04, 0x20, 0x2d, 0x20, 0x04, 0x2c, 0x20, 0x50, 0x41, 0x53, 0x53, 0x20, 0x04, 0x2c, +0x20, 0x42, 0x49, 0x54, 0x53, 0x20, 0x49, 0x4e, 0x20, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x3a, 0x20, +0x04, 0x20, 0x3d, 0x3e, 0x20, 0x04, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x20, 0x20, +0x53, 0x50, 0x3d, 0x04, 0x20, 0x20, 0x50, 0x43, 0x3d, 0x04, 0x20, 0x20, 0x55, 0x53, 0x3d, 0x04, +0x20, 0x20, 0x49, 0x59, 0x3d, 0x04, 0x20, 0x20, 0x49, 0x58, 0x3d, 0x04, 0x20, 0x20, 0x44, 0x50, +0x3d, 0x04, 0x20, 0x20, 0x41, 0x3d, 0x04, 0x20, 0x20, 0x42, 0x3d, 0x04, 0x20, 0x20, 0x43, 0x43, +0x3a, 0x20, 0x04, 0x45, 0x46, 0x48, 0x49, 0x4e, 0x5a, 0x56, 0x43, 0x53, 0x31, 0x04, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, +0x8e, 0xff, 0xf0, 0x86, 0x0f, 0xa7, 0x80, 0x4a, 0x26, 0xfb, 0x86, 0xf0, 0xa7, 0x84, 0x8e, 0xd0, +0xa0, 0x10, 0x8e, 0x55, 0xaa, 0xee, 0x84, 0x10, 0xaf, 0x84, 0x10, 0xac, 0x84, 0x27, 0x0b, 0x30, +0x89, 0xf0, 0x00, 0x8c, 0xf0, 0xa0, 0x26, 0xed, 0x20, 0xd6, 0xef, 0x84, 0x1f, 0x10, 0x43, 0x44, +0x44, 0x44, 0x44, 0xb7, 0xff, 0xfd, 0x10, 0xce, 0xdf, 0xc0, 0x10, 0x8e, 0xdf, 0xd0, 0xa7, 0x2d, +0x6f, 0x2e, 0x86, 0xf0, 0xa7, 0x2f, 0x86, 0x0c, 0x6f, 0xa6, 0x4a, 0x2a, 0xfb, 0x30, 0x89, 0xf0, +0x00, 0x8c, 0xf0, 0xa0, 0x27, 0x22, 0xee, 0x84, 0x10, 0x8e, 0x55, 0xaa, 0x10, 0xaf, 0x84, 0x10, +0xac, 0x84, 0x26, 0xe9, 0xef, 0x84, 0x10, 0x8e, 0xdf, 0xd0, 0x1f, 0x10, 0x44, 0x44, 0x44, 0x44, +0x1f, 0x89, 0x88, 0x0f, 0xa7, 0xa5, 0x20, 0xd5, 0x86, 0xf1, 0x10, 0x8e, 0xdf, 0xd0, 0xa7, 0x2e, +0x86, 0x0c, 0xe6, 0xa6, 0x26, 0x05, 0x4a, 0x2a, 0xf9, 0x20, 0x14, 0x6f, 0xa6, 0xe7, 0x2c, 0x4f, +0x1f, 0x21, 0xe6, 0xa6, 0x27, 0x04, 0x6f, 0xa6, 0xe7, 0x80, 0x4c, 0x81, 0x0c, 0x2d, 0xf3, 0x8e, +0xff, 0xf0, 0xc6, 0x10, 0xa6, 0xa0, 0xa7, 0x80, 0x5a, 0x26, 0xf9, 0x53, 0xf7, 0xdf, 0xe2, 0x16, +0xf8, 0x62, 0x6e, 0x9f, 0xdf, 0xc0, 0x6e, 0x9f, 0xdf, 0xc4, 0x6e, 0x9f, 0xdf, 0xc6, 0x6e, 0x9f, +0xdf, 0xc8, 0x6e, 0x9f, 0xdf, 0xca, 0x1f, 0x43, 0xae, 0x4a, 0xe6, 0x80, 0xaf, 0x4a, 0x4f, 0x58, +0x49, 0xbe, 0xdf, 0xcc, 0x8c, 0xff, 0xff, 0x27, 0x0f, 0x30, 0x8b, 0xbc, 0xdf, 0xce, 0x22, 0x08, +0x34, 0x10, 0xec, 0xc4, 0xae, 0x44, 0x6e, 0xf1, 0x37, 0x1f, 0xee, 0x42, 0x6e, 0x9f, 0xdf, 0xc2, +0xff, 0xb2, 0xff, 0xc6, 0xff, 0xb6, 0xff, 0xba, 0xff, 0xbe, 0xff, 0xc2, 0xff, 0xb2, 0xff, 0x00 +}; +#endif /* ROM_swtp_sbuge_bin_H */ From 6d7bebf272229e54938c18b1887a3c80d83d1b34 Mon Sep 17 00:00:00 2001 From: rfromafar Date: Wed, 21 Feb 2024 16:55:35 -0600 Subject: [PATCH 02/10] In preparation of presenting for contribution as a "pull request". General clean up of code. Removed unneeded test prints that were used for debugging. Removed swtp_sbuge_bin.h which implemented BOOTROM code internally. Users should use "ATTACH BOOTROM ". Added reset() routine to CPU. If last line in INI file is "RESET CPU" then simulator goes straight into BOOTROM from reset vector at $FFFE. Tested with several FLEX 9 DSK files. Known issues are: 1) Backspace (BS) does not seem to work when running Flex 9. 2) When simulator starts up the PC has a value of $FFFF (and not $FFFE). 3) No DMAF1/DMAF2 disk emulation which is required for support of UniFlex. 4) No documentation has been written yet. However, I am more than willing to put something together. Note this code was developed using Debian on Raspberry Pi 4. There may be Unix/DOS file conversion issues. --- swtp6809/common/bootrom.c | 179 ++++++++++++---------------- swtp6809/common/dc-4.c | 28 ++--- swtp6809/common/m6809.c | 73 +++++++++--- swtp6809/common/mp-09.c | 5 +- swtp6809/common/mp-1m.c | 7 +- swtp6809/common/mp-b3.c | 21 ++-- swtp6809/swtp6809/mp-09_sys.c | 2 +- swtp6809/swtp6809/swtp6809mp-09.ini | 19 ++- swtp6809/swtp6809/swtp_defs.h | 2 +- swtp6809/swtp6809/swtp_sbuge_bin.h | 141 ---------------------- 10 files changed, 165 insertions(+), 312 deletions(-) delete mode 100644 swtp6809/swtp6809/swtp_sbuge_bin.h diff --git a/swtp6809/common/bootrom.c b/swtp6809/common/bootrom.c index d1ac5b5fd..06674c62c 100644 --- a/swtp6809/common/bootrom.c +++ b/swtp6809/common/bootrom.c @@ -26,7 +26,7 @@ MODIFICATIONS: 23 Apr 15 -- Modified to use simh_debug - 19 Feb 24 -- Richard Lukes - Modified for swtp6809 emulator + 20 Feb 24 -- Richard Lukes - Modified for swtp6809 emulator NOTES: @@ -50,12 +50,6 @@ #include #include "swtp_defs.h" -#define DONT_USE_INTERNAL_ROM - -#if !defined(DONT_USE_INTERNAL_ROM) -#include "swtp_sbuge_bin.h" -#endif /* DONT_USE_INTERNAL_ROM */ - #define UNIT_V_MSIZE (UNIT_V_UF) /* ROM Size */ #define UNIT_MSIZE (0x7 << UNIT_V_MSIZE) #define UNIT_NONE (0 << UNIT_V_MSIZE) /* No EPROM */ @@ -69,24 +63,22 @@ #define BOOTROM_4K 0x1000 #define BOOTROM_8K 0x2000 +// this value is used when referencing BOOTROM memory that is not populated (i.e. not loaded by BOOTROM attach) +#define DEFAULT_NO_ROM_BYTE_VALUE 0xFF + /* function prototypes */ -t_stat BOOTROM_attach (UNIT *uptr, CONST char *cptr); -t_stat BOOTROM_config (UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat BOOTROM_attach(UNIT *uptr, CONST char *cptr); +t_stat BOOTROM_config(UNIT *uptr, int32 val, CONST char *cptr, void *desc); t_stat BOOTROM_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); -t_stat BOOTROM_reset (DEVICE *dptr); -//t_stat BOOTROM_svc (UNIT *uptr); +t_stat BOOTROM_reset(DEVICE *dptr); int32 BOOTROM_get_mbyte(int32 address); /* SIMH Standard I/O Data Structures */ UNIT BOOTROM_unit = { -#if defined(DONT_USE_INTERNAL_ROM) UDATA (NULL, UNIT_ATTABLE+UNIT_BINK+UNIT_ROABLE+UNIT_RO, 0), -#else /* !defined(DONT_USE_INTERNAL_ROM) */ - UDATA (NULL, UNIT_ATTABLE+UNIT_BINK+UNIT_ROABLE+UNIT_RO+((BOOT_CODE_SIZE>>9)<fileref); if (image_size <= 0) { sim_printf("BOOTROM_attach: File error\n"); + detach_unit(uptr); return SCPE_IOERR; - } - for (capac = 0x200, i=1; capac < image_size; capac <<= 1, i++); - if (i > (UNIT_2764>>UNIT_V_MSIZE)) { - detach_unit (uptr); - return SCPE_ARG; + } else { + if (image_size > BOOTROM_8K) { + sim_printf("BOOTROM_attach: Error. File size exceeds ROM capacity\n"); + detach_unit(uptr); + return SCPE_ARG; + } } - uptr->flags &= ~UNIT_MSIZE; - uptr->flags |= (i << UNIT_V_MSIZE); + + /* open EPROM file */ + fp = fopen(BOOTROM_unit.filename, "rb"); + if (fp == NULL) { + printf("Bootrom: Unable to open ROM file %s\n",BOOTROM_unit.filename); + printf("Bootrom: No ROM image loaded!!!\n"); + return SCPE_OK; + } + + /* load EPROM file */ + j = 0; + items_read = sim_fread(&byte_val, (size_t)1, (size_t)1, fp); + while (items_read != 0) { + BOOTROM_memory[j++] = byte_val; + items_read = sim_fread(&byte_val, (size_t)1, (size_t)1,fp); + if (j > BOOTROM_unit.capac) { + printf("Bootrom: Image is too large - Load truncated!!!\n"); + j--; + break; + } + } + fclose(fp); + printf("Bootrom: %d bytes of ROM image %s loaded\n", j, BOOTROM_unit.filename); + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_attach: Done\n"); -//RICHARD WAS HERE - return (BOOTROM_reset (NULL)); return SCPE_OK; + } /* BOOTROM_attach() */ /* BOOTROM_config = None, 2704, 2708, 2716, 2732 or 2764 */ t_stat BOOTROM_config (UNIT *uptr, int32 val, CONST char *cptr, void *desc) { -//RICHARD WAS HERE -printf("calling BOOTROM_config\n"); + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: val=%d\n", val); if ((val < UNIT_NONE) || (val > UNIT_2764)) { /* valid param? */ sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: Parameter error\n"); @@ -201,91 +225,35 @@ printf("calling BOOTROM_config\n"); BOOTROM_unit.capac = 0; /* set EPROM size */ else BOOTROM_unit.capac = 0x200 << ((val >> UNIT_V_MSIZE) - 1); /* set EPROM size */ - if (BOOTROM_unit.filebuf) { /* free buffer */ - //free (BOOTROM_unit.filebuf); - BOOTROM_unit.filebuf = NULL; + + if (!BOOTROM_unit.filebuf) { /* point buffer to static array */ + BOOTROM_unit.filebuf = BOOTROM_memory; } + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: BOOTROM_unit.capac=%d\n", BOOTROM_unit.capac); sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: Done\n"); + return SCPE_OK; } /* BOOTROM config */ /* BOOTROM reset */ t_stat BOOTROM_reset (DEVICE *dptr) { - t_addr i,j; - unsigned long c; - long count; - FILE *fp; - uint8 *pa; + t_addr i; -//RICHARD WAS HERE -printf("calling BOOTROM_reset\n"); - /* initialize array to $FF */ - for (i=0; i BOOTROM_unit.capac) { - printf("\tImage is too large - Load truncated!!!\n"); - j--; - break; - } - } - fclose(fp); - - /* warn if loaded ROM image is smaller than the specified ROM size */ - if (j < BOOTROM_unit.capac) { - printf("\tImage is smaller than specified ROM size!!!\n"); - } - - printf("\t%d bytes of ROM image %s loaded\n", j, BOOTROM_unit.filename); - sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_reset: Done2\n"); return SCPE_OK; + } /* BOOTROM_reset() */ /* get a byte from memory - from specified memory address */ @@ -296,16 +264,17 @@ int32 BOOTROM_get_mbyte(int32 address) if (BOOTROM_unit.filebuf == NULL) { sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: EPROM not configured\n"); - return 0xFF; + return DEFAULT_NO_ROM_BYTE_VALUE; } sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: address=%04X\n", address); if ((t_addr)(0xFFFF - address) > BOOTROM_unit.capac) { sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: EPROM reference beyond ROM size\n"); - return 0xFF; + return DEFAULT_NO_ROM_BYTE_VALUE; } + pa = BOOTROM_unit.filebuf; /* the following code is needed to calculate offsets so address $FFFF references the last byte of the ROM */ - val = 0xFF; + val = DEFAULT_NO_ROM_BYTE_VALUE; switch (BOOTROM_unit.capac) { /* 2764 - $E000-$FFFF */ case 0x2000: diff --git a/swtp6809/common/dc-4.c b/swtp6809/common/dc-4.c index 5304358c1..e080423ef 100644 --- a/swtp6809/common/dc-4.c +++ b/swtp6809/common/dc-4.c @@ -337,7 +337,6 @@ t_stat dsk_reset (DEVICE *dptr) { int i; -// RICHARD WAS HERE cur_dsk = 5; /* force initial SIR read, use a drive # that can't be selected */ for (i=0; i 0) { /* interrupt? */ /* 6809 interrupts not implemented yet. None were used, on a standard SWTP 6809. All I/O is programmed. */ -// RICHARD WAS HERE -printf("m6809.c: int_req > 0!!!\n"); -fflush(stdout); + reason = STOP_HALT; /* stop simulation */ + break; + } /* end interrupt */ if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ @@ -637,9 +639,6 @@ fflush(stdout); case 0x10: /* 2-byte opcodes */ /* fetch second byte of opcode */ OP2 = fetch_byte(0); -//fprintf(stdout,"-->OP2=%08X\n", OP2); -//fprintf(stdout,"-->NF=%08X,VF=%08X,LBLT=%08X\n", get_flag(NF), get_flag(VF), get_flag(NF) ^ get_flag(VF)); -//fflush(stdout); switch (OP2) { case 0x21: /* LBRN rel */ /* Branch Never - essentially a NOP */ @@ -940,8 +939,8 @@ fflush(stdout); case 0x12: /* NOP */ break; case 0x13: /* SYNC inherent*/ -/* RICHARD WAS HERE */ -/* interrupts are not implemented */ + /* Interrupts are not implemented */ + reason = STOP_HALT; /* stop simulation */ break; case 0x16: /* LBRA relative */ go_long_rel(1); @@ -3246,6 +3245,17 @@ void condevalHa(int32 op1, int32 op2) /* calls from the simulator */ +/* Boot routine */ +t_stat m6809_boot(int32 unit_num, DEVICE *dptr) +{ + /* retrieve the reset vector at $FFFE */ + saved_PC = CPU_BD_get_mword(0xFFFE); + if (saved_PC == 0xFFFF) { + ; // No BOOT ROM detected! + } + return SCPE_OK; +} + /* Reset routine */ t_stat m6809_reset (DEVICE *dptr) { @@ -3253,14 +3263,39 @@ t_stat m6809_reset (DEVICE *dptr) DP = 0; int_req = 0; sim_brk_types = sim_brk_dflt = SWMASK ('E'); + + /* retrieve the reset vector at $FFFE */ saved_PC = CPU_BD_get_mword(0xFFFE); -// if (saved_PC == 0xFFFF) -// printf("No EPROM image found - M6809 reset incomplete!\n"); -// else -// printf("EPROM vector=%04X\n", saved_PC); + if (saved_PC == 0xFFFF) { + ; // No BOOT ROM detected! + } return SCPE_OK; } +/* examine routine */ +t_stat m6809_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= 0x10000) { + /* exceed 16-bit address space */ + return SCPE_NXM; + } else { + *eval_array = CPU_BD_get_mbyte(addr); + return SCPE_OK; + } +} + +/* deposit routine */ +t_stat m6809_deposit(t_value value, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= 0x10000) { + /* exceed 16-bit address space */ + return SCPE_NXM; + } else { + CPU_BD_put_mbyte(addr, value); + return SCPE_OK; + } +} + /* This is the dumper/loader. This command uses the -h to signify a hex dump/load vice a binary one. If no address is given to load, it diff --git a/swtp6809/common/mp-09.c b/swtp6809/common/mp-09.c index 5a6c6e55d..4baa68ef5 100644 --- a/swtp6809/common/mp-09.c +++ b/swtp6809/common/mp-09.c @@ -26,7 +26,7 @@ MODIFICATIONS: 24 Apr 15 -- Modified to use simh_debug - 19 Feb 24 -- Richard Lukes - modified SWTPC mp-a2 emulator to create mp-09 emulator. + 20 Feb 24 -- Richard Lukes - modified SWTPC mp-a2 emulator to create mp-09 emulator. NOTES: @@ -274,8 +274,7 @@ void CPU_BD_put_mbyte(int32 addr, int32 val) /* put a word to memory */ void CPU_BD_put_mword(int32 addr, int32 val) { - sim_debug (DEBUG_write, &CPU_BD_dev, "CPU_BD_put_mword: addr=%04X, val=%04X\n", - addr, val); + sim_debug (DEBUG_write, &CPU_BD_dev, "CPU_BD_put_mword: addr=%04X, val=%04X\n", addr, val); CPU_BD_put_mbyte(addr, val >> 8); CPU_BD_put_mbyte(addr+1, val & 0xFF); } diff --git a/swtp6809/common/mp-1m.c b/swtp6809/common/mp-1m.c index ba3fa9442..0f7244788 100644 --- a/swtp6809/common/mp-1m.c +++ b/swtp6809/common/mp-1m.c @@ -26,7 +26,7 @@ MODIFICATIONS: 24 Apr 15 -- Modified to use simh_debug - 19 Feb 24 -- Richard Lukes - Modified mp-8m.c to use for 1MB memory for swtp6809 emulator + 20 Feb 24 -- Richard Lukes - Modified mp-8m.c to use for 1MB memory for swtp6809 emulator NOTES: @@ -147,7 +147,7 @@ t_stat mp_1m_reset (DEVICE *dptr) printf("mp_1m_reset: Malloc error\n"); return SCPE_MEM; } - for (j=0; j < uptr->capac; j++) { /* fill pattern for testing */ + for (j=0; j < uptr->capac; j++) { /* populate memory with fill pattern */ i = j & 0xF; val = (0xA0 | i) & 0xFF; *((uint8 *)(uptr->filebuf) + j) = val; @@ -197,9 +197,6 @@ int32 mp_1m_get_mword(int32 addr) void mp_1m_put_mbyte(int32 addr, int32 val) { - //UNIT *uptr; - - //uptr = mp_1m_dev.units; sim_debug (DEBUG_write, &mp_1m_dev, "mp_1m_put_mbyte: addr=%05X, val=%02X", addr, val); if (addr >= ONE_MEGABYTE) { diff --git a/swtp6809/common/mp-b3.c b/swtp6809/common/mp-b3.c index 21936f197..9d444a2c2 100644 --- a/swtp6809/common/mp-b3.c +++ b/swtp6809/common/mp-b3.c @@ -26,7 +26,7 @@ MODIFICATIONS: 24 Apr 15 -- Modified to use simh_debug - 19 Feb 24 -- Richard Lukes - Modified to emulate MP-B3 motherboard for swtp6809 emulator + 20 Feb 24 -- Richard Lukes - Modified to emulate MP-B3 motherboard for swtp6809 emulator NOTES: @@ -35,6 +35,7 @@ #include #include "swtp_defs.h" + #define UNIT_V_RAM_1MB (UNIT_V_UF) /* MP-1M board enable */ #define UNIT_RAM_1MB (1 << UNIT_V_RAM_1MB) @@ -75,6 +76,8 @@ extern int32 fdcsec(int32 io, int32 data); extern int32 fdcdata(int32 io, int32 data); /* +MP-B3 configured with 4 address per SS-30 slot (x8). + 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 @@ -85,17 +88,16 @@ struct idev { }; struct idev dev_table[32] = { -/* {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, Port 0 E000-E003 */ - {&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /*Port 0 E000-E003 */ - {&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /*Port 1 E004-E007 */ + {&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /* Port 0 E000-E003 */ + {&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /* Port 1 E004-E007 */ /* 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 E008-E00B*/ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 3 E00C-E00F*/ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* Port 4 E010-E013*/ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* Port 2 E008-E00B */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* Port 3 E00C-E00F */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* Port 4 E010-E013 */ {&fdcdrv}, {&nulldev}, {&nulldev}, {&nulldev}, /* Port 5 E014-E017 */ {&fdccmd}, {&fdctrk}, {&fdcsec}, {&fdcdata}, /* Port 6 E018-E01B */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev} /*Port 7 E01C-E01F*/ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev} /* Port 7 E01C-E01F */ }; /* dummy i/o device */ @@ -176,6 +178,7 @@ t_stat MB_reset (DEVICE *dptr) t_stat MB_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches) { if (addr >= 0x100000) { + /* exceed 20-bit address space */ return SCPE_NXM; } else { MB_put_mbyte(addr, val); @@ -269,7 +272,7 @@ void MB_put_mbyte(int32 addr, int32 val) if (MB_unit.flags & UNIT_RAM_1MB) { mp_1m_put_mbyte(addr, val); } else { - ; // No RAM conigured at this addresS + ; // No RAM conigured at this address } break; } diff --git a/swtp6809/swtp6809/mp-09_sys.c b/swtp6809/swtp6809/mp-09_sys.c index bf2e30293..e99486838 100644 --- a/swtp6809/swtp6809/mp-09_sys.c +++ b/swtp6809/swtp6809/mp-09_sys.c @@ -25,7 +25,7 @@ MODIFICATIONS - 19 Feb 24 -- Richard Lukes - Modified mp-a2_sys.c for SWTP MP-09 emulation + 20 Feb 24 -- Richard Lukes - Modified mp-a2_sys.c for SWTP MP-09 emulation */ #include diff --git a/swtp6809/swtp6809/swtp6809mp-09.ini b/swtp6809/swtp6809/swtp6809mp-09.ini index 00451a952..0a7167c2e 100644 --- a/swtp6809/swtp6809/swtp6809mp-09.ini +++ b/swtp6809/swtp6809/swtp6809mp-09.ini @@ -1,16 +1,13 @@ -set bootrom debug -set bootrom 2716 -attach bootrom sbuge.bin +reset set mp-b3 1MB set cpu hex set cpu itrap set cpu mtrap -attach dc-40 FULL.DSK set dc-40 RO -;attach dc-41 FULL2.DSK -;set dc-41 RO -;attach dc-42 FULL3.DSK -;set dc-42 RO -;attach dc-43 FULL4.DSK -;set dc-43 RW -reset +set dc-41 RO +set mp-s TTY +set bootrom 2716 +attach bootrom sbuge.bin +attach dc-40 FULL.DSK +attach dc-41 FULL2.DSK +boot cpu diff --git a/swtp6809/swtp6809/swtp_defs.h b/swtp6809/swtp6809/swtp_defs.h index a0b341d46..c0c58549e 100644 --- a/swtp6809/swtp6809/swtp_defs.h +++ b/swtp6809/swtp6809/swtp_defs.h @@ -25,7 +25,7 @@ MODIFICATIONS - 19 Feb 24 - Richard Lukes - Modified for swtp6809 emulator + 20 Feb 24 - Richard Lukes - Modified for swtp6809 emulator */ #include diff --git a/swtp6809/swtp6809/swtp_sbuge_bin.h b/swtp6809/swtp6809/swtp_sbuge_bin.h deleted file mode 100644 index 30c153b96..000000000 --- a/swtp6809/swtp6809/swtp_sbuge_bin.h +++ /dev/null @@ -1,141 +0,0 @@ -#ifndef ROM_swtp_sbuge_bin_H -#define ROM_swtp_sbuge_bin_H 0 -/* - This file is a generated file and should NOT be edited or changed by hand. - - SWTPC SBUG-E 2KB Monitor ROM -*/ -#define BOOT_CODE_SIZE 0x800 -#define BOOT_CODE_FILENAME "sbuge.bin" -#define BOOT_CODE_ARRAY swtp_sbuge_bin -unsigned char swtp_sbuge_bin[] = { -0xf8, 0x14, 0xf8, 0x61, 0xfd, 0xcf, 0xfd, 0xc9, 0xfd, 0xdf, 0xfd, 0xee, 0xfd, 0xbd, 0xfd, 0xb1, -0xfd, 0xad, 0xfb, 0x81, 0x8e, 0xfe, 0x4f, 0x10, 0x8e, 0xdf, 0xc0, 0xc6, 0x10, 0xa6, 0x80, 0xa7, -0xa0, 0x5a, 0x26, 0xf9, 0x8e, 0xe0, 0x04, 0xbf, 0xdf, 0xe0, 0x17, 0x02, 0x7a, 0xc6, 0x0c, 0x6f, -0xe2, 0x5a, 0x26, 0xfb, 0x30, 0x8c, 0xdd, 0xaf, 0x6a, 0x86, 0xd0, 0xa7, 0xe4, 0x1f, 0x43, 0x17, -0x05, 0xbe, 0x8e, 0xfe, 0x5f, 0x17, 0x05, 0x75, 0x8e, 0xdf, 0xd0, 0x4f, 0xc6, 0x0d, 0x6d, 0x85, -0x27, 0x03, 0x8b, 0x04, 0x19, 0x5a, 0x2a, 0xf6, 0x17, 0x05, 0x26, 0x8e, 0xfe, 0x74, 0x17, 0x05, -0x5c, 0x8e, 0xfe, 0x7b, 0x17, 0x05, 0x46, 0x17, 0x05, 0x65, 0x84, 0x7f, 0x81, 0x0d, 0x27, 0xf1, -0x1f, 0x89, 0x81, 0x20, 0x2c, 0x09, 0x86, 0x5e, 0x17, 0x05, 0x73, 0x1f, 0x98, 0x8b, 0x40, 0x17, -0x05, 0x6c, 0x17, 0x05, 0x67, 0xc1, 0x60, 0x2f, 0x02, 0xc0, 0x20, 0x8e, 0xfe, 0x13, 0xe1, 0x80, -0x27, 0x0f, 0x30, 0x02, 0x8c, 0xfe, 0x4f, 0x26, 0xf5, 0x8e, 0xfe, 0x7d, 0x17, 0x05, 0x1e, 0x20, -0xc0, 0xad, 0x94, 0x20, 0xbc, 0x1f, 0x34, 0x3b, 0x8e, 0xfe, 0x83, 0x17, 0x04, 0xff, 0x17, 0x04, -0x11, 0x17, 0x04, 0x19, 0x17, 0x04, 0x21, 0x17, 0x04, 0x29, 0x17, 0x04, 0x31, 0x8e, 0xfe, 0x83, -0x17, 0x04, 0xea, 0x17, 0x04, 0x33, 0x17, 0x04, 0x3a, 0x17, 0x04, 0x41, 0x16, 0x04, 0x48, 0x17, -0x04, 0x27, 0x17, 0x05, 0x17, 0x17, 0x04, 0x57, 0x29, 0x02, 0xaf, 0x4a, 0x39, 0x17, 0x03, 0xed, -0x17, 0x05, 0x09, 0x17, 0x04, 0x49, 0x29, 0x02, 0xaf, 0x48, 0x39, 0x17, 0x04, 0x00, 0x17, 0x04, -0xfb, 0x17, 0x04, 0x3b, 0x29, 0x02, 0xaf, 0x46, 0x39, 0x17, 0x03, 0xe7, 0x17, 0x04, 0xed, 0x17, -0x04, 0x2d, 0x29, 0x02, 0xaf, 0x44, 0x39, 0x17, 0x03, 0xce, 0x17, 0x04, 0xdf, 0x17, 0x04, 0x30, -0x29, 0x02, 0xa7, 0x43, 0x39, 0x17, 0x03, 0xf5, 0x17, 0x04, 0xd1, 0x17, 0x04, 0x22, 0x29, 0x02, -0xa7, 0x42, 0x39, 0x17, 0x03, 0xdd, 0x17, 0x04, 0xc3, 0x17, 0x04, 0x14, 0x29, 0x02, 0xa7, 0x41, -0x39, 0x17, 0x03, 0xe3, 0x17, 0x04, 0xb5, 0x17, 0x04, 0x06, 0x29, 0x04, 0x8a, 0x80, 0xa7, 0xc4, -0x39, 0x17, 0x03, 0xeb, 0x29, 0x2d, 0x1f, 0x12, 0x8e, 0xfe, 0x83, 0x17, 0x04, 0x5f, 0x1f, 0x21, -0x17, 0x04, 0x26, 0x17, 0x04, 0x96, 0xa6, 0xa4, 0x17, 0x04, 0x26, 0x17, 0x04, 0x8e, 0x17, 0x03, -0xdf, 0x28, 0x11, 0x81, 0x08, 0x27, 0xe1, 0x81, 0x18, 0x27, 0xdd, 0x81, 0x5e, 0x27, 0x17, 0x81, -0x0d, 0x26, 0x0f, 0x39, 0xa7, 0xa4, 0xa1, 0xa4, 0x27, 0x08, 0x17, 0x04, 0x6f, 0x86, 0x3f, 0x17, -0x04, 0x6c, 0x31, 0x21, 0x20, 0xc2, 0x31, 0x3f, 0x20, 0xbe, 0x17, 0x03, 0x35, 0x1f, 0x32, 0x8e, -0xdf, 0xc0, 0x30, 0x1f, 0x20, 0x05, 0x17, 0x03, 0x8b, 0x29, 0x06, 0x34, 0x20, 0xac, 0xe1, 0x24, -0x01, 0x39, 0x1f, 0x10, 0xc3, 0x00, 0x10, 0xc4, 0xf0, 0x34, 0x06, 0x1f, 0x20, 0xc4, 0xf0, 0x1f, -0x01, 0xac, 0xe4, 0x27, 0x05, 0x17, 0x04, 0x27, 0x27, 0x03, 0x32, 0x62, 0x39, 0x34, 0x10, 0x8e, -0xfe, 0x83, 0x17, 0x03, 0xe8, 0xae, 0xe4, 0x17, 0x03, 0xaf, 0xc6, 0x10, 0xa6, 0x80, 0x17, 0x03, -0xb0, 0x17, 0x04, 0x18, 0x5a, 0x26, 0xf5, 0x17, 0x04, 0x10, 0xae, 0xe1, 0xc6, 0x10, 0xa6, 0x80, -0x81, 0x20, 0x25, 0x04, 0x81, 0x7e, 0x23, 0x02, 0x86, 0x2e, 0x17, 0x04, 0x01, 0x5a, 0x26, 0xee, -0x20, 0xbf, 0x6f, 0xe2, 0x6f, 0xe2, 0x17, 0x03, 0x2b, 0x34, 0x30, 0x29, 0x7b, 0xac, 0x62, 0x25, -0x77, 0x17, 0x03, 0xe8, 0x1f, 0x20, 0xe3, 0x64, 0x34, 0x04, 0xab, 0xe0, 0xa7, 0xa0, 0x10, 0xac, -0xe4, 0x25, 0xf1, 0x10, 0xae, 0x62, 0x1f, 0x20, 0xe3, 0x64, 0x34, 0x02, 0xeb, 0xe0, 0xe8, 0xa0, -0x27, 0x3c, 0x8e, 0xfe, 0x83, 0x17, 0x03, 0x85, 0x30, 0x3f, 0x17, 0x03, 0x4c, 0x34, 0x10, 0x8e, -0xfe, 0xa1, 0x17, 0x03, 0x88, 0x35, 0x10, 0x17, 0x01, 0x47, 0x17, 0x03, 0x50, 0x17, 0x03, 0x39, -0x8e, 0xfe, 0x87, 0x17, 0x03, 0x77, 0xae, 0x64, 0x17, 0x03, 0x2e, 0x8e, 0xfe, 0x8f, 0x17, 0x03, -0x6c, 0x1f, 0x98, 0x8e, 0xfe, 0xa6, 0x17, 0x03, 0x3e, 0x17, 0x03, 0x83, 0x26, 0x1a, 0x10, 0xac, -0xe4, 0x25, 0xb3, 0x86, 0x2b, 0x17, 0x03, 0x86, 0x17, 0x03, 0x74, 0x26, 0x0b, 0x10, 0xae, 0x62, -0x6c, 0x65, 0x26, 0x90, 0x6c, 0x64, 0x26, 0x8c, 0x32, 0x66, 0x39, 0x17, 0x02, 0xb1, 0x29, 0x1e, -0x8c, 0xdf, 0xc0, 0x24, 0x1a, 0x34, 0x10, 0x8e, 0xff, 0xff, 0x8d, 0x55, 0x35, 0x10, 0x27, 0x0f, -0xa6, 0x84, 0x81, 0x3f, 0x27, 0x09, 0xa7, 0xa0, 0xaf, 0xa4, 0x86, 0x3f, 0xa7, 0x84, 0x39, 0x17, -0x03, 0x4a, 0x86, 0x3f, 0x16, 0x03, 0x47, 0x10, 0x8e, 0xdf, 0xe3, 0xc6, 0x08, 0x8d, 0x18, 0x5a, -0x26, 0xfb, 0x39, 0x1f, 0x43, 0xae, 0x4a, 0x30, 0x1f, 0x8d, 0x26, 0x27, 0x04, 0xaf, 0x4a, 0x8d, -0x06, 0x17, 0xfd, 0xe4, 0x16, 0xfd, 0x9a, 0xae, 0x21, 0x8c, 0xdf, 0xc0, 0x24, 0x0a, 0xa6, 0x84, -0x81, 0x3f, 0x26, 0x04, 0xa6, 0xa4, 0xa7, 0x84, 0x86, 0xff, 0xa7, 0xa0, 0xa7, 0xa0, 0xa7, 0xa0, -0x39, 0x10, 0x8e, 0xdf, 0xe3, 0xc6, 0x08, 0xa6, 0xa0, 0xac, 0xa1, 0x27, 0x04, 0x5a, 0x26, 0xf7, -0x39, 0x31, 0x3d, 0x39, 0x86, 0xde, 0xb7, 0xf0, 0x24, 0x86, 0xff, 0xb7, 0xf0, 0x14, 0xb7, 0xf0, -0x10, 0xb7, 0xf0, 0x15, 0xb7, 0xf0, 0x16, 0x7d, 0xf0, 0x10, 0x86, 0xd8, 0xb7, 0xf0, 0x20, 0x17, -0x00, 0x97, 0xb6, 0xf0, 0x20, 0x2b, 0xfb, 0x86, 0x09, 0xb7, 0xf0, 0x20, 0x17, 0x00, 0x8a, 0xb6, -0xf0, 0x20, 0x85, 0x01, 0x26, 0xf9, 0x85, 0x10, 0x26, 0xca, 0x8e, 0xc0, 0x00, 0x8d, 0x52, 0x8a, -0x10, 0xb7, 0xf0, 0x40, 0x1f, 0x10, 0x43, 0x53, 0xfd, 0xf0, 0x00, 0x8e, 0xfe, 0xff, 0xbf, 0xf0, -0x02, 0x86, 0xff, 0xb7, 0xf0, 0x10, 0x86, 0xfe, 0xb7, 0xf0, 0x14, 0x86, 0x01, 0xb7, 0xf0, 0x22, -0x86, 0x8c, 0xb7, 0xf0, 0x20, 0x8d, 0x52, 0x5f, 0x34, 0x04, 0x5f, 0x7d, 0xf0, 0x10, 0x2a, 0x0a, -0x5a, 0x26, 0xf8, 0x35, 0x04, 0x5a, 0x26, 0xf0, 0x20, 0x8a, 0x35, 0x04, 0xb6, 0xf0, 0x20, 0x85, -0x1c, 0x27, 0x01, 0x39, 0xc6, 0xde, 0xf7, 0xf0, 0x24, 0x8e, 0xc0, 0x00, 0xaf, 0x4a, 0x1f, 0x34, -0x3b, 0x34, 0x36, 0xa6, 0x62, 0x44, 0x44, 0x44, 0x44, 0x10, 0x8e, 0xdf, 0xd0, 0xe6, 0xa6, 0x54, -0x54, 0x54, 0x54, 0xe7, 0xe4, 0xe6, 0xa6, 0x53, 0x58, 0x58, 0x58, 0x58, 0xa6, 0x62, 0x84, 0x0f, -0xa7, 0x62, 0xea, 0x62, 0xe7, 0x62, 0x35, 0x36, 0x39, 0x34, 0x04, 0xc6, 0x20, 0x5a, 0x26, 0xfd, -0x35, 0x04, 0x39, 0x7d, 0xe0, 0x18, 0x7f, 0xe0, 0x14, 0xc6, 0x03, 0x8e, 0x00, 0x00, 0x30, 0x01, -0x8c, 0x00, 0x00, 0x26, 0xf9, 0x5a, 0x26, 0xf6, 0x86, 0x0f, 0xb7, 0xe0, 0x18, 0x8d, 0x37, 0xf6, -0xe0, 0x18, 0xc5, 0x01, 0x26, 0xf9, 0x86, 0x01, 0xb7, 0xe0, 0x1a, 0x8d, 0x29, 0x86, 0x8c, 0xb7, -0xe0, 0x18, 0x8d, 0x22, 0x8e, 0xc0, 0x00, 0x20, 0x09, 0xc5, 0x02, 0x27, 0x05, 0xb6, 0xe0, 0x1b, -0xa7, 0x80, 0xf6, 0xe0, 0x18, 0xc5, 0x01, 0x26, 0xf0, 0xc5, 0x2c, 0x27, 0x01, 0x39, 0x8e, 0xc0, -0x00, 0xaf, 0x4a, 0x1f, 0x34, 0x3b, 0xc6, 0x20, 0x5a, 0x26, 0xfd, 0x39, 0x86, 0x11, 0x17, 0x01, -0xdd, 0x7f, 0xdf, 0xe2, 0x17, 0x01, 0xad, 0x81, 0x53, 0x26, 0xf9, 0x17, 0x01, 0xa6, 0x81, 0x39, -0x27, 0x3d, 0x81, 0x31, 0x26, 0xf1, 0x17, 0x01, 0x17, 0x34, 0x02, 0x29, 0x26, 0x17, 0x00, 0xff, -0x29, 0x21, 0x34, 0x10, 0xe6, 0xe0, 0xeb, 0xe0, 0xeb, 0xe4, 0x6a, 0xe4, 0x6a, 0xe4, 0x34, 0x04, -0x17, 0x00, 0xfd, 0x35, 0x04, 0x29, 0x0c, 0x34, 0x02, 0xeb, 0xe0, 0x6a, 0xe4, 0x27, 0x05, 0xa7, -0x80, 0x20, 0xeb, 0x5f, 0x35, 0x02, 0xc1, 0xff, 0x27, 0xb2, 0x86, 0x3f, 0x17, 0x01, 0x8f, 0x73, -0xdf, 0xe2, 0x86, 0x13, 0x16, 0x01, 0x87, 0x6f, 0xe2, 0x17, 0x00, 0xb8, 0x34, 0x30, 0x29, 0x4a, -0xac, 0x62, 0x25, 0x46, 0x30, 0x01, 0xaf, 0xe4, 0x86, 0x12, 0x17, 0x01, 0x71, 0xec, 0xe4, 0xa3, -0x62, 0x27, 0x06, 0x10, 0x83, 0x00, 0x20, 0x23, 0x02, 0xc6, 0x20, 0xe7, 0x64, 0x8e, 0xfe, 0xeb, -0x17, 0x01, 0x1a, 0xcb, 0x03, 0x1f, 0x98, 0x17, 0x00, 0xe7, 0xae, 0x62, 0x17, 0x00, 0xda, 0xeb, -0x62, 0xeb, 0x63, 0xeb, 0x84, 0xa6, 0x80, 0x17, 0x00, 0xd7, 0x6a, 0x64, 0x26, 0xf5, 0x53, 0x1f, -0x98, 0x17, 0x00, 0xcd, 0xaf, 0x62, 0xac, 0xe4, 0x26, 0xc3, 0x86, 0x14, 0x17, 0x01, 0x2f, 0x32, -0x65, 0x39, 0x8e, 0xfe, 0xae, 0x17, 0x00, 0xf5, 0x1f, 0x31, 0x16, 0x00, 0xac, 0x8e, 0xfe, 0xba, -0x17, 0x00, 0xea, 0xae, 0x48, 0x16, 0x00, 0xa1, 0x8e, 0xfe, 0xcc, 0x17, 0x00, 0xdf, 0xa6, 0x43, -0x16, 0x00, 0x9e, 0x8e, 0xfe, 0xc6, 0x17, 0x00, 0xd4, 0xae, 0x44, 0x16, 0x00, 0x8b, 0x8e, 0xfe, -0xc0, 0x17, 0x00, 0xc9, 0xae, 0x46, 0x16, 0x00, 0x80, 0x8e, 0xfe, 0xb4, 0x17, 0x00, 0xbe, 0xae, -0x4a, 0x20, 0x76, 0x8e, 0xfe, 0xd2, 0x17, 0x00, 0xb4, 0xa6, 0x41, 0x20, 0x74, 0x8e, 0xfe, 0xd7, -0x17, 0x00, 0xaa, 0xa6, 0x42, 0x20, 0x6a, 0x8e, 0xfe, 0xdc, 0x17, 0x00, 0xa0, 0xa6, 0xc4, 0x8e, -0xfe, 0xe3, 0x20, 0x73, 0x8d, 0x09, 0x29, 0x4e, 0x1f, 0x12, 0x86, 0x2d, 0x17, 0x00, 0xbf, 0x8d, -0x0f, 0x29, 0x43, 0x1f, 0x01, 0x8d, 0x09, 0x29, 0x3d, 0x34, 0x10, 0xa7, 0x61, 0x35, 0x10, 0x39, -0x8d, 0x11, 0x29, 0x32, 0x48, 0x48, 0x48, 0x48, 0x1f, 0x89, 0x8d, 0x07, 0x29, 0x28, 0x34, 0x04, -0xab, 0xe0, 0x39, 0x8d, 0x6f, 0x81, 0x30, 0x25, 0x1d, 0x81, 0x39, 0x22, 0x03, 0x80, 0x30, 0x39, -0x81, 0x41, 0x25, 0x12, 0x81, 0x46, 0x22, 0x03, 0x80, 0x37, 0x39, 0x81, 0x61, 0x25, 0x07, 0x81, -0x66, 0x22, 0x03, 0x80, 0x57, 0x39, 0x1a, 0x02, 0x39, 0x34, 0x10, 0x35, 0x02, 0x8d, 0x02, 0x35, -0x02, 0x34, 0x02, 0x44, 0x44, 0x44, 0x44, 0x8d, 0x04, 0x35, 0x02, 0x84, 0x0f, 0x8b, 0x30, 0x81, -0x39, 0x2f, 0x02, 0x8b, 0x07, 0x20, 0x57, 0x34, 0x02, 0xc6, 0x08, 0xa6, 0x80, 0x68, 0xe4, 0x25, -0x02, 0x86, 0x2d, 0x8d, 0x49, 0x8d, 0x45, 0x5a, 0x26, 0xf1, 0x35, 0x02, 0x39, 0x8d, 0x02, 0x20, -0x0c, 0x34, 0x10, 0x8e, 0xfe, 0x75, 0x8d, 0x05, 0x35, 0x10, 0x39, 0x8d, 0x31, 0xa6, 0x80, 0x81, -0x04, 0x26, 0xf8, 0x39, 0x7d, 0xdf, 0xe2, 0x27, 0x06, 0x8d, 0x04, 0x84, 0x7f, 0x20, 0x1f, 0x34, -0x10, 0xbe, 0xdf, 0xe0, 0xa6, 0x84, 0x85, 0x01, 0x27, 0xfa, 0xa6, 0x01, 0x35, 0x10, 0x39, 0x34, -0x02, 0xa6, 0x9f, 0xdf, 0xe0, 0x85, 0x01, 0x35, 0x02, 0x39, 0x8d, 0x00, 0x86, 0x20, 0x34, 0x12, -0xbe, 0xdf, 0xe0, 0xa6, 0x84, 0x85, 0x02, 0x27, 0xfa, 0x35, 0x02, 0xa7, 0x01, 0x35, 0x10, 0x39, -0xbe, 0xdf, 0xe0, 0x86, 0x03, 0xa7, 0x84, 0x86, 0x11, 0xa7, 0x84, 0x6d, 0x01, 0x86, 0xff, 0xb7, -0xdf, 0xe2, 0x39, 0x01, 0xf9, 0x23, 0x02, 0xf9, 0x15, 0x03, 0xf9, 0x31, 0x04, 0xf9, 0x07, 0x10, -0xf8, 0xcf, 0x15, 0xf8, 0xdd, 0x18, 0xf8, 0xf9, 0x19, 0xf8, 0xeb, 0x42, 0xfa, 0x7b, 0x44, 0xfa, -0xf4, 0x45, 0xf9, 0x96, 0x47, 0xf8, 0xa5, 0x4c, 0xfc, 0x0c, 0x4d, 0xf9, 0x41, 0x50, 0xfc, 0x67, -0x51, 0xf9, 0xf2, 0x52, 0xf8, 0xa8, 0x53, 0xf9, 0x8a, 0x55, 0xfb, 0xb3, 0x58, 0xfa, 0xa7, 0xfa, -0xb3, 0xf8, 0xa7, 0xf8, 0xa7, 0xf8, 0xa7, 0xf8, 0xa7, 0xfa, 0xb3, 0xff, 0xff, 0xff, 0xff, 0x00, -0x00, 0x00, 0x0d, 0x0a, 0x00, 0x00, 0x00, 0x53, 0x2d, 0x42, 0x55, 0x47, 0x20, 0x31, 0x2e, 0x38, -0x20, 0x2d, 0x20, 0x04, 0x4b, 0x0d, 0x0a, 0x00, 0x00, 0x00, 0x04, 0x3e, 0x04, 0x57, 0x48, 0x41, -0x54, 0x3f, 0x04, 0x20, 0x2d, 0x20, 0x04, 0x2c, 0x20, 0x50, 0x41, 0x53, 0x53, 0x20, 0x04, 0x2c, -0x20, 0x42, 0x49, 0x54, 0x53, 0x20, 0x49, 0x4e, 0x20, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x3a, 0x20, -0x04, 0x20, 0x3d, 0x3e, 0x20, 0x04, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x20, 0x20, -0x53, 0x50, 0x3d, 0x04, 0x20, 0x20, 0x50, 0x43, 0x3d, 0x04, 0x20, 0x20, 0x55, 0x53, 0x3d, 0x04, -0x20, 0x20, 0x49, 0x59, 0x3d, 0x04, 0x20, 0x20, 0x49, 0x58, 0x3d, 0x04, 0x20, 0x20, 0x44, 0x50, -0x3d, 0x04, 0x20, 0x20, 0x41, 0x3d, 0x04, 0x20, 0x20, 0x42, 0x3d, 0x04, 0x20, 0x20, 0x43, 0x43, -0x3a, 0x20, 0x04, 0x45, 0x46, 0x48, 0x49, 0x4e, 0x5a, 0x56, 0x43, 0x53, 0x31, 0x04, 0xff, 0xff, -0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, -0x8e, 0xff, 0xf0, 0x86, 0x0f, 0xa7, 0x80, 0x4a, 0x26, 0xfb, 0x86, 0xf0, 0xa7, 0x84, 0x8e, 0xd0, -0xa0, 0x10, 0x8e, 0x55, 0xaa, 0xee, 0x84, 0x10, 0xaf, 0x84, 0x10, 0xac, 0x84, 0x27, 0x0b, 0x30, -0x89, 0xf0, 0x00, 0x8c, 0xf0, 0xa0, 0x26, 0xed, 0x20, 0xd6, 0xef, 0x84, 0x1f, 0x10, 0x43, 0x44, -0x44, 0x44, 0x44, 0xb7, 0xff, 0xfd, 0x10, 0xce, 0xdf, 0xc0, 0x10, 0x8e, 0xdf, 0xd0, 0xa7, 0x2d, -0x6f, 0x2e, 0x86, 0xf0, 0xa7, 0x2f, 0x86, 0x0c, 0x6f, 0xa6, 0x4a, 0x2a, 0xfb, 0x30, 0x89, 0xf0, -0x00, 0x8c, 0xf0, 0xa0, 0x27, 0x22, 0xee, 0x84, 0x10, 0x8e, 0x55, 0xaa, 0x10, 0xaf, 0x84, 0x10, -0xac, 0x84, 0x26, 0xe9, 0xef, 0x84, 0x10, 0x8e, 0xdf, 0xd0, 0x1f, 0x10, 0x44, 0x44, 0x44, 0x44, -0x1f, 0x89, 0x88, 0x0f, 0xa7, 0xa5, 0x20, 0xd5, 0x86, 0xf1, 0x10, 0x8e, 0xdf, 0xd0, 0xa7, 0x2e, -0x86, 0x0c, 0xe6, 0xa6, 0x26, 0x05, 0x4a, 0x2a, 0xf9, 0x20, 0x14, 0x6f, 0xa6, 0xe7, 0x2c, 0x4f, -0x1f, 0x21, 0xe6, 0xa6, 0x27, 0x04, 0x6f, 0xa6, 0xe7, 0x80, 0x4c, 0x81, 0x0c, 0x2d, 0xf3, 0x8e, -0xff, 0xf0, 0xc6, 0x10, 0xa6, 0xa0, 0xa7, 0x80, 0x5a, 0x26, 0xf9, 0x53, 0xf7, 0xdf, 0xe2, 0x16, -0xf8, 0x62, 0x6e, 0x9f, 0xdf, 0xc0, 0x6e, 0x9f, 0xdf, 0xc4, 0x6e, 0x9f, 0xdf, 0xc6, 0x6e, 0x9f, -0xdf, 0xc8, 0x6e, 0x9f, 0xdf, 0xca, 0x1f, 0x43, 0xae, 0x4a, 0xe6, 0x80, 0xaf, 0x4a, 0x4f, 0x58, -0x49, 0xbe, 0xdf, 0xcc, 0x8c, 0xff, 0xff, 0x27, 0x0f, 0x30, 0x8b, 0xbc, 0xdf, 0xce, 0x22, 0x08, -0x34, 0x10, 0xec, 0xc4, 0xae, 0x44, 0x6e, 0xf1, 0x37, 0x1f, 0xee, 0x42, 0x6e, 0x9f, 0xdf, 0xc2, -0xff, 0xb2, 0xff, 0xc6, 0xff, 0xb6, 0xff, 0xba, 0xff, 0xbe, 0xff, 0xc2, 0xff, 0xb2, 0xff, 0x00 -}; -#endif /* ROM_swtp_sbuge_bin_H */ From 131b599b97ed6d9e42dcf496b7c4a4708e5f839d Mon Sep 17 00:00:00 2001 From: Richard Lukes Date: Sat, 24 Feb 2024 21:29:10 -0600 Subject: [PATCH 03/10] The user doc file for the swtp6809 simulator SWTP 6809 Simulator Usage guide. --- doc/swtp6809_doc.doc | Bin 0 -> 183296 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/swtp6809_doc.doc diff --git a/doc/swtp6809_doc.doc b/doc/swtp6809_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..ea0078712df9646ed7e6803d2c395d9679169957 GIT binary patch literal 183296 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 Date: Sat, 24 Feb 2024 21:48:49 -0600 Subject: [PATCH 04/10] swtp6809 simulator being contributed to open-simh project #357 (Pull Request) - updates to code while writing the simulator usage guide - added copyright notice to relevant source code modules - used unix2dos to format source files for DOS line terminator conventions - source code files from swtp6800 with some changes: swtp_defs.h, dc-4.c - source code files from swtp6800 that are unchanged: mp-s. --- swtp6809/common/bootrom.c | 658 +-- swtp6809/common/dc-4.c | 1302 ++--- swtp6809/common/m6809.c | 6804 ++++++++++++++------------- swtp6809/common/mp-09.c | 578 +-- swtp6809/common/mp-1m.c | 529 ++- swtp6809/common/mp-b3.c | 598 +-- swtp6809/swtp6809/mp-09_sys.c | 204 +- swtp6809/swtp6809/sbuge.bin | Bin 0 -> 2048 bytes swtp6809/swtp6809/swtp6809mp-09.ini | 26 +- swtp6809/swtp6809/swtp_defs.h | 128 +- 10 files changed, 5514 insertions(+), 5313 deletions(-) create mode 100644 swtp6809/swtp6809/sbuge.bin diff --git a/swtp6809/common/bootrom.c b/swtp6809/common/bootrom.c index 06674c62c..401f8c9a4 100644 --- a/swtp6809/common/bootrom.c +++ b/swtp6809/common/bootrom.c @@ -1,315 +1,343 @@ -/* bootrom.c: Boot ROM simulator for Motorola processors - - Copyright (c) 2010-2012, William A. 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. - - MODIFICATIONS: - - 23 Apr 15 -- Modified to use simh_debug - 20 Feb 24 -- Richard Lukes - Modified for swtp6809 emulator - - NOTES: - - These functions support a single simulated 2704 to 2764 EPROM device on - an 8-bit computer system.. This device allows the buffer to be loaded from - a binary file containing the emulated EPROM code. - - These functions support a simulated 2704(0.5KB), 2708(1KB), 2716(2KB), 2732(4KB) or 2764(8KB) EPROM - device at the top of the 16-bit address space. The base address of the ROM varies depends on the size. - For example, The 2764 BOOTROM is mapped from $E000 to $FFFF less the I/O range reserved by the MP-B3 motherboard. - The 2716 BOOTROM is mapped from $F800 to $FFFF. - The last byte of the ROM is always stored at $FFFF - - The device type is stored as a binary number in the first three unit flag bits. - - This device uses a statically allocated buffer to hold the EPROM image. All bytes are initialized to $FF. - A call to BOOTROM_attach will load the buffer with the EPROM image. - -*/ - -#include -#include "swtp_defs.h" - -#define UNIT_V_MSIZE (UNIT_V_UF) /* ROM Size */ -#define UNIT_MSIZE (0x7 << UNIT_V_MSIZE) -#define UNIT_NONE (0 << UNIT_V_MSIZE) /* No EPROM */ -#define UNIT_2704 (1 << UNIT_V_MSIZE) /* 2704 mode */ -#define UNIT_2708 (2 << UNIT_V_MSIZE) /* 2708 mode */ -#define UNIT_2716 (3 << UNIT_V_MSIZE) /* 2716 mode */ -#define UNIT_2732 (4 << UNIT_V_MSIZE) /* 2732 mode */ -#define UNIT_2764 (5 << UNIT_V_MSIZE) /* 2764 mode */ - -#define BOOTROM_2K 0x0800 -#define BOOTROM_4K 0x1000 -#define BOOTROM_8K 0x2000 - -// this value is used when referencing BOOTROM memory that is not populated (i.e. not loaded by BOOTROM attach) -#define DEFAULT_NO_ROM_BYTE_VALUE 0xFF - -/* function prototypes */ - -t_stat BOOTROM_attach(UNIT *uptr, CONST char *cptr); -t_stat BOOTROM_config(UNIT *uptr, int32 val, CONST char *cptr, void *desc); -t_stat BOOTROM_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); -t_stat BOOTROM_reset(DEVICE *dptr); - -int32 BOOTROM_get_mbyte(int32 address); - -/* SIMH Standard I/O Data Structures */ - -UNIT BOOTROM_unit = { - UDATA (NULL, UNIT_ATTABLE+UNIT_BINK+UNIT_ROABLE+UNIT_RO, 0), - KBD_POLL_WAIT }; - -MTAB BOOTROM_mod[] = { - { UNIT_MSIZE, UNIT_NONE, "None", "NONE", &BOOTROM_config }, - { UNIT_MSIZE, UNIT_2704, "2704", "2704", &BOOTROM_config }, - { UNIT_MSIZE, UNIT_2708, "2708", "2708", &BOOTROM_config }, - { UNIT_MSIZE, UNIT_2716, "2716", "2716", &BOOTROM_config }, - { UNIT_MSIZE, UNIT_2732, "2732", "2732", &BOOTROM_config }, - { UNIT_MSIZE, UNIT_2764, "2764", "2764", &BOOTROM_config }, - { 0 } -}; - -DEBTAB BOOTROM_debug[] = { - { "ALL", DEBUG_all }, - { "FLOW", DEBUG_flow }, - { "READ", DEBUG_read }, - { "WRITE", DEBUG_write }, - { "LEV1", DEBUG_level1 }, - { "LEV2", DEBUG_level2 }, - { NULL } -}; - -DEVICE BOOTROM_dev = { - "BOOTROM", /* name */ - &BOOTROM_unit, /* units */ - NULL, /* registers */ - BOOTROM_mod, /* modifiers */ - 1, /* numunits */ - 16, /* aradix */ - 16, /* awidth */ - 1, /* aincr */ - 16, /* dradix */ - 8, /* dwidth */ - &BOOTROM_examine, /* examine */ - NULL, /* deposit */ - &BOOTROM_reset, /* reset */ - NULL, /* boot */ - &BOOTROM_attach, /* attach */ - NULL, /* detach */ - NULL, /* ctxt */ - DEV_DEBUG, /* flags */ - 0, /* dctrl */ - BOOTROM_debug, /* debflags */ - NULL, /* msize */ - NULL /* lname */ -}; - -/* global variables */ - -/* MP-09 actually has 4 x 2KB EPROM sockets at $E000, $E800, $F000, $F800 */ -/* This will be emulated as a single BOOTROM having a high address of $FFFF and variable start address depending on size */ -/* Available sizes are None=0, 512B=2704, 1KB=2708, 2KB=2716, 4KB=2732, 8KB=2764 */ - -/* Pre-allocate 8KB array of bytes to accomodate largest BOOTROM */ -uint8 BOOTROM_memory[BOOTROM_8K]; - -t_stat BOOTROM_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) -{ - if (addr >= BOOTROM_8K) { - return SCPE_NXM; - } - if (eval_array != NULL) { - *eval_array = BOOTROM_get_mbyte(addr); - } - return SCPE_OK; - -} /* BOOTROM_examine() */ - -/* BOOTROM_attach - attach file to EPROM unit */ -t_stat BOOTROM_attach(UNIT *uptr, CONST char *cptr) -{ - t_stat r; - t_addr image_size; - int i,j; - FILE *fp; - uint8 byte_val; - size_t items_read; - - if (BOOTROM_unit.filebuf == NULL) { /* no buffer allocated */ - BOOTROM_unit.filebuf = BOOTROM_memory; - } - if ((BOOTROM_unit.flags & UNIT_MSIZE) == 0) { /* if none selected */ - BOOTROM_unit.capac = 0; /* set EPROM size to 0 */ - return SCPE_OK; - } - - sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_attach: cptr=%s\n", cptr); - if ((r = attach_unit(uptr, cptr)) != SCPE_OK) { - sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_attach: Error %d\n", r); - return r; - } - - image_size = (t_addr) sim_fsize_ex(uptr->fileref); - if (image_size <= 0) { - sim_printf("BOOTROM_attach: File error\n"); - detach_unit(uptr); - return SCPE_IOERR; - } else { - if (image_size > BOOTROM_8K) { - sim_printf("BOOTROM_attach: Error. File size exceeds ROM capacity\n"); - detach_unit(uptr); - return SCPE_ARG; - } - } - - /* open EPROM file */ - fp = fopen(BOOTROM_unit.filename, "rb"); - if (fp == NULL) { - printf("Bootrom: Unable to open ROM file %s\n",BOOTROM_unit.filename); - printf("Bootrom: No ROM image loaded!!!\n"); - return SCPE_OK; - } - - /* load EPROM file */ - j = 0; - items_read = sim_fread(&byte_val, (size_t)1, (size_t)1, fp); - while (items_read != 0) { - BOOTROM_memory[j++] = byte_val; - items_read = sim_fread(&byte_val, (size_t)1, (size_t)1,fp); - if (j > BOOTROM_unit.capac) { - printf("Bootrom: Image is too large - Load truncated!!!\n"); - j--; - break; - } - } - fclose(fp); - printf("Bootrom: %d bytes of ROM image %s loaded\n", j, BOOTROM_unit.filename); - - sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_attach: Done\n"); - return SCPE_OK; - -} /* BOOTROM_attach() */ - -/* BOOTROM_config = None, 2704, 2708, 2716, 2732 or 2764 */ -t_stat BOOTROM_config (UNIT *uptr, int32 val, CONST char *cptr, void *desc) -{ - - sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: val=%d\n", val); - if ((val < UNIT_NONE) || (val > UNIT_2764)) { /* valid param? */ - sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: Parameter error\n"); - return SCPE_ARG; - } - if (val == UNIT_NONE) - BOOTROM_unit.capac = 0; /* set EPROM size */ - else - BOOTROM_unit.capac = 0x200 << ((val >> UNIT_V_MSIZE) - 1); /* set EPROM size */ - - if (!BOOTROM_unit.filebuf) { /* point buffer to static array */ - BOOTROM_unit.filebuf = BOOTROM_memory; - } - - sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: BOOTROM_unit.capac=%d\n", - BOOTROM_unit.capac); - sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: Done\n"); - - return SCPE_OK; -} /* BOOTROM config */ - -/* BOOTROM reset */ -t_stat BOOTROM_reset (DEVICE *dptr) -{ - t_addr i; - - sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_reset: \n"); - - /* allocate filebuf */ - if (BOOTROM_unit.filebuf == NULL) { /* no buffer allocated */ - //BOOTROM_unit.filebuf = calloc(1, BOOTROM_unit.capac); /* allocate EPROM buffer */ - BOOTROM_unit.filebuf = BOOTROM_memory; - if (BOOTROM_unit.filebuf == NULL) { - return SCPE_MEM; - } - } - return SCPE_OK; - -} /* BOOTROM_reset() */ - -/* get a byte from memory - from specified memory address */ -int32 BOOTROM_get_mbyte(int32 address) -{ - int32 val; - uint8 *pa; - - if (BOOTROM_unit.filebuf == NULL) { - sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: EPROM not configured\n"); - return DEFAULT_NO_ROM_BYTE_VALUE; - } - sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: address=%04X\n", address); - if ((t_addr)(0xFFFF - address) > BOOTROM_unit.capac) { - sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: EPROM reference beyond ROM size\n"); - return DEFAULT_NO_ROM_BYTE_VALUE; - } - - pa = BOOTROM_unit.filebuf; - /* the following code is needed to calculate offsets so address $FFFF references the last byte of the ROM */ - val = DEFAULT_NO_ROM_BYTE_VALUE; - switch (BOOTROM_unit.capac) { - /* 2764 - $E000-$FFFF */ - case 0x2000: - val = pa[address - 0xE000]; - break; - /* 2732 - $F000-$FFFF */ - case 0x1000: - if (address >=0xF000) { - val = pa[address - 0xF000]; - } - break; - /* 2716 - $F800-$FFFF */ - case 0x0800: - if (address >= 0xF800) { - val = pa[address - 0xF800]; - } - break; - /* 2708 - $FC00-$FFFF */ - case 0x0400: - if (address >= 0xFC00) { - val = pa[address - 0xFC00]; - } - break; - /* 2704 - $FE00-$FFFF*/ - case 0x0200: - if (address >= 0xFE00) { - val = pa[address - 0xFE00]; - } - break; - default: - break; - } - val &= 0xFF; - sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: Normal val=%02X\n", val); - return val; -} /* BOOTROM_get_mbyte() */ - -/* end of bootrom.c */ +/* bootrom.c: Boot ROM simulator for Motorola processors + + Copyright (c) 2010-2012, William A. 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. + + The following copyright notice applies to the SWTP 6809 source, binary, and documentation: + + Original code published in 2024, written by Richard F Lukes + Copyright (c) 2024, Richard F Lukes + + 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 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 names of The Authors shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the Authors. + + MODIFICATIONS: + + 23 Apr 15 -- Modified to use simh_debug + 24 Feb 24 -- Richard Lukes - Modified for swtp6809 emulator + + NOTES: + + These functions support a single simulated 2704 to 2764 EPROM device on + an 8-bit computer system.. This device allows the buffer to be loaded from + a binary file containing the emulated EPROM code. + + These functions support a simulated 2704(0.5KB), 2708(1KB), 2716(2KB), 2732(4KB) or 2764(8KB) EPROM + device at the top of the 16-bit address space. The base address of the ROM varies depends on the size. + For example, The 2764 BOOTROM is mapped from $E000 to $FFFF less the I/O range reserved by the MP-B3 motherboard. + The 2716 BOOTROM is mapped from $F800 to $FFFF. + The last byte of the ROM is always stored at $FFFF + + The device type is stored as a binary number in the first three unit flag bits. + + This device uses a statically allocated buffer to hold the EPROM image. All bytes are initialized to $FF. + A call to BOOTROM_attach will load the buffer with the EPROM image. + +*/ + +#include +#include "swtp_defs.h" + +#define UNIT_V_MSIZE (UNIT_V_UF) /* ROM Size */ +#define UNIT_MSIZE (0x2F << UNIT_V_MSIZE) +#define UNIT_NONE (0x1 << UNIT_V_MSIZE) /* No EPROM */ +#define UNIT_2704 (0x2 << UNIT_V_MSIZE) /* 2704 mode */ +#define UNIT_2708 (0x4 << UNIT_V_MSIZE) /* 2708 mode */ +#define UNIT_2716 (0x8 << UNIT_V_MSIZE) /* 2716 mode */ +#define UNIT_2732 (0x10 << UNIT_V_MSIZE) /* 2732 mode */ +#define UNIT_2764 (0x20 << UNIT_V_MSIZE) /* 2764 mode */ + +/* Maximum size of bootrom is 8KB from $E000-$FFFF */ +#define MAX_BOOTROM_SIZE (8*1024) + +// this value is used when referencing BOOTROM memory that is not populated (i.e. not loaded by BOOTROM attach) +#define DEFAULT_NO_ROM_BYTE_VALUE 0xFF + +/* function prototypes */ + +t_stat BOOTROM_attach(UNIT *uptr, CONST char *cptr); +t_stat BOOTROM_config(UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat BOOTROM_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); +t_stat BOOTROM_reset(DEVICE *dptr); + +int32 BOOTROM_get_mbyte(int32 address); + +/* SIMH Standard I/O Data Structures */ + +UNIT BOOTROM_unit = { + UDATA (NULL, UNIT_ATTABLE+UNIT_BINK+UNIT_ROABLE+UNIT_RO, 0), + KBD_POLL_WAIT }; + +MTAB BOOTROM_mod[] = { + { UNIT_MSIZE, UNIT_NONE, "None", "NONE", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_2704, "2704", "2704", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_2708, "2708", "2708", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_2716, "2716", "2716", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_2732, "2732", "2732", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_2764, "2764", "2764", &BOOTROM_config }, + { 0 } +}; + +DEBTAB BOOTROM_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE BOOTROM_dev = { + "BOOTROM", /* name */ + &BOOTROM_unit, /* units */ + NULL, /* registers */ + BOOTROM_mod, /* modifiers */ + 1, /* numunits */ + 16, /* aradix */ + 16, /* awidth */ + 1, /* aincr */ + 16, /* dradix */ + 8, /* dwidth */ + &BOOTROM_examine, /* examine */ + NULL, /* deposit */ + &BOOTROM_reset, /* reset */ + NULL, /* boot */ + &BOOTROM_attach, /* attach */ + NULL, /* detach */ + NULL, /* ctxt */ + DEV_DEBUG, /* flags */ + 0, /* dctrl */ + BOOTROM_debug, /* debflags */ + NULL, /* msize */ + NULL /* lname */ +}; + +/* global variables */ + +/* MP-09 actually has 4 x 2KB EPROM sockets at $E000, $E800, $F000, $F800 */ +/* This will be emulated as a single BOOTROM having a high address of $FFFF and variable start address depending on size */ +/* Available sizes are None=0, 512B=2704, 1KB=2708, 2KB=2716, 4KB=2732, 8KB=2764 */ + +/* Pre-allocate 8KB array of bytes to accomodate largest BOOTROM */ +uint8 BOOTROM_memory[MAX_BOOTROM_SIZE]; + +/* BOOTROM_examine routine */ +t_stat BOOTROM_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= BOOTROM_unit.capac || addr >= MAX_BOOTROM_SIZE) { + return SCPE_NXM; + } + if (eval_array != NULL) { + *eval_array = BOOTROM_memory[addr]; + } + return SCPE_OK; + +} /* BOOTROM_examine() */ + +/* BOOTROM_attach - attach file to EPROM unit */ +t_stat BOOTROM_attach(UNIT *uptr, CONST char *cptr) +{ + t_stat r; + t_addr image_size; + int i,j; + FILE *fp; + uint8 byte_val; + size_t items_read; + + if (BOOTROM_unit.filebuf == NULL) { /* no buffer allocated */ + BOOTROM_unit.filebuf = BOOTROM_memory; + } + if ((BOOTROM_unit.flags & UNIT_MSIZE) == 0) { /* if none selected */ + BOOTROM_unit.capac = 0; /* set EPROM size to 0 */ + return SCPE_OK; + } + + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_attach: cptr=%s\n", cptr); + if ((r = attach_unit(uptr, cptr)) != SCPE_OK) { + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_attach: Error %d\n", r); + return r; + } + + image_size = (t_addr) sim_fsize_ex(uptr->fileref); + if (image_size <= 0) { + sim_printf("BOOTROM_attach: File error\n"); + detach_unit(uptr); + return SCPE_IOERR; + } else { + if (image_size > MAX_BOOTROM_SIZE) { + sim_printf("BOOTROM_attach: Error. File size exceeds ROM capacity\n"); + detach_unit(uptr); + return SCPE_ARG; + } + } + + /* open EPROM file */ + fp = fopen(BOOTROM_unit.filename, "rb"); + if (fp == NULL) { + printf("Bootrom: Unable to open ROM file %s\n",BOOTROM_unit.filename); + printf("Bootrom: No ROM image loaded!!!\n"); + return SCPE_OK; + } + + /* load EPROM file */ + j = 0; + items_read = sim_fread(&byte_val, (size_t)1, (size_t)1, fp); + while (items_read != 0) { + BOOTROM_memory[j++] = byte_val; + items_read = sim_fread(&byte_val, (size_t)1, (size_t)1,fp); + if (j > BOOTROM_unit.capac) { + printf("Bootrom: Image is too large - Load truncated!!!\n"); + j--; + break; + } + } + fclose(fp); + printf("Bootrom: %d bytes of ROM image %s loaded\n", j, BOOTROM_unit.filename); + + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_attach: Done\n"); + return SCPE_OK; + +} /* BOOTROM_attach() */ + +/* BOOTROM_config = None, 2704, 2708, 2716, 2732 or 2764 */ +t_stat BOOTROM_config (UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: val=%d\n", val); + if ((val < UNIT_NONE) || (val > UNIT_2764)) { /* valid param? */ + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: Parameter error\n"); + return SCPE_ARG; + } + if (val == UNIT_NONE) { + BOOTROM_unit.capac = 0; /* set EPROM size */ + } else { + //BOOTROM_unit.capac = 0x200 ((val >> UNIT_V_MSIZE) - 1); /* set EPROM size */ + BOOTROM_unit.capac = 0x100 * (val >> UNIT_V_MSIZE); /* set EPROM size */ + } + + if (!BOOTROM_unit.filebuf) { /* point buffer to static array */ + BOOTROM_unit.filebuf = BOOTROM_memory; + } + + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: BOOTROM_unit.capac=%d\n", + BOOTROM_unit.capac); + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: Done\n"); + + return SCPE_OK; +} /* BOOTROM config */ + +/* BOOTROM reset */ +t_stat BOOTROM_reset (DEVICE *dptr) +{ + t_addr i; + + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_reset: \n"); + + /* allocate filebuf */ + if (BOOTROM_unit.filebuf == NULL) { /* no buffer allocated */ + //BOOTROM_unit.filebuf = calloc(1, BOOTROM_unit.capac); /* allocate EPROM buffer */ + BOOTROM_unit.filebuf = BOOTROM_memory; + if (BOOTROM_unit.filebuf == NULL) { + return SCPE_MEM; + } + } + return SCPE_OK; + +} /* BOOTROM_reset() */ + +/* get a byte from memory - from specified memory address */ +int32 BOOTROM_get_mbyte(int32 address) +{ + int32 val; + uint8 *pa; + + if (BOOTROM_unit.filebuf == NULL) { + sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: EPROM not configured\n"); + return DEFAULT_NO_ROM_BYTE_VALUE; + } + sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: address=%04X\n", address); + if ((t_addr)(0xFFFF - address) > BOOTROM_unit.capac) { + sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: EPROM reference beyond ROM size\n"); + return DEFAULT_NO_ROM_BYTE_VALUE; + } + + pa = BOOTROM_unit.filebuf; + /* the following code is needed to calculate offsets so address $FFFF references the last byte of the ROM */ + val = DEFAULT_NO_ROM_BYTE_VALUE; + switch (BOOTROM_unit.capac) { + /* 2764 - $E000-$FFFF */ + case 0x2000: + val = pa[address - 0xE000]; + break; + /* 2732 - $F000-$FFFF */ + case 0x1000: + if (address >=0xF000) { + val = pa[address - 0xF000]; + } + break; + /* 2716 - $F800-$FFFF */ + case 0x0800: + if (address >= 0xF800) { + val = pa[address - 0xF800]; + } + break; + /* 2708 - $FC00-$FFFF */ + case 0x0400: + if (address >= 0xFC00) { + val = pa[address - 0xFC00]; + } + break; + /* 2704 - $FE00-$FFFF*/ + case 0x0200: + if (address >= 0xFE00) { + val = pa[address - 0xFE00]; + } + break; + default: + break; + } + val &= 0xFF; + sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: Normal val=%02X\n", val); + return val; +} /* BOOTROM_get_mbyte() */ + +/* end of bootrom.c */ diff --git a/swtp6809/common/dc-4.c b/swtp6809/common/dc-4.c index e080423ef..f37e530ab 100644 --- a/swtp6809/common/dc-4.c +++ b/swtp6809/common/dc-4.c @@ -1,651 +1,651 @@ -/* dc4.c: SWTP DC-4 FDC Simulator - - Copyright (c) 2005-2012, William A. 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. - - MODIFICATIONS: - - 23 Apr 15 -- Modified to use simh_debug - 19 Feb 24 -- Richard Lukes - Modified to work with swtp6809 emulator - - NOTES: - - The DC-4 is a 5-inch floppy controller which can control up - to 4 daisy-chained 5-inch floppy drives. The controller is based on - the Western Digital 1797 Floppy Disk Controller (FDC) chip. This - file only emulates the minimum DC-4 functionality to interface with - the virtual disk file. - - The floppy controller is interfaced to the CPU by use of 5 memory - addreses. These are SS-30 slot numbers 5 and 6 (0xE014-0xE01B) on a SWTPC 6809 computer. - - Address Mode Function - ------- ---- -------- - - 0xE014 Read Returns FDC interrupt status - 0xE014 Write Selects the drive/head/motor control - 0xE018 Read Returns status of FDC - 0xE018 Write FDC command register - 0xE019 Read Returns FDC track register - 0xE019 Write Set FDC track register - 0xE01A Read Returns FDC sector register - 0xE01A Write Set FDC sector register - 0xE01B Read Read data - 0xE01B Write Write data - - Drive Select Read (0xE014): - - +---+---+---+---+---+---+---+---+ - | I | D | X | X | X | X | X | X | - +---+---+---+---+---+---+---+---+ - - I = Set indicates an interrupt request from the FDC pending. - D = DRQ pending - same as bit 1 of FDC status register. - - Drive Select Write (0xE014): - - +---+---+---+---+---+---+---+---+ - | M | S | X | X | X | X | Device| - +---+---+---+---+---+---+---+---+ - - M = If this bit is 1, the one-shot is triggered/retriggered to - start/keep the motors on. - S = Side select. If set, side one is selected otherwise side zero - is selected. - X = not used - Device = value 0 thru 3, selects drive 0-3 to be controlled. - - Drive Status Read (0xE018): - - +---+---+---+---+---+---+---+---+ - | R | P | H | S | C | L | D | B | - +---+---+---+---+---+---+---+---+ - - B - When 1, the controller is busy. - D - When 1, index mark detected (type I) or data request - read data - ready/write data empty (type II or III). - H - When 1, track 0 (type I) or lost data (type II or III). - C - When 1, crc error detected. - S - When 1, seek (type I) or RNF (type II or III) error. - H - When 1, head is currently loaded (type I) or record type/ - write fault (type II or III). - P - When 1, indicates that diskette is write-protected. - R - When 1, drive is not ready. - - Drive Control Write (0xE018) for type I commands: - - +---+---+---+---+---+---+---+---+ - | 0 | S2| S1| S0| H | V | R1| R0| - +---+---+---+---+---+---+---+---+ - - R0/R1 - Selects the step rate. - V - When 1, verify on destination track. - H - When 1, loads head to drive surface. - S0/S1/S2 = 000 - home. - 001 - seek track in data register. - 010 - step without updating track register. - 011 - step and update track register. - 100 - step in without updating track register. - 101 - step in and update track register. - 110 - step out without updating track register. - 111 - step out and update track register. - - Drive Control Write (0xE018) for type II commands: - - +---+---+---+---+---+---+---+---+ - | 1 | 0 | T | M | S | E | B | A | - +---+---+---+---+---+---+---+---+ - - A - Zero for read, 1 on write deleted data mark else data mark. - B - When 1, shifts sector length field definitions one place. - E - When, delay operation 15 ms, 0 no delay. - S - When 1, select side 1, 0 select side 0. - M - When 1, multiple records, 0 for single record. - T - When 1, write command, 0 for read. - - Drive Control Write (0xE018) for type III commands: - - +---+---+---+---+---+---+---+---+ - | 1 | 1 | T0| T1| 0 | E | 0 | 0 | - +---+---+---+---+---+---+---+---+ - - E - When, delay operation 15 ms, 0 no delay. - T0/T1 - 00 - read address command. - 10 - read track command. - 11 - write track command. - - Tracks are numbered from 0 up to one minus the last track in the 1797! - - Track Register Read (0xE019): - - +---+---+---+---+---+---+---+---+ - | Track Number | - +---+---+---+---+---+---+---+---+ - - Reads the current 8-bit value from the track position. - - Track Register Write (0xE019): - - +---+---+---+---+---+---+---+---+ - | Track Number | - +---+---+---+---+---+---+---+---+ - - Writes the 8-bit value to the track register. - - Sectors are numbers from 1 up to the last sector in the 1797! - - Sector Register Read (0xE01A): - - +---+---+---+---+---+---+---+---+ - | Sector Number | - +---+---+---+---+---+---+---+---+ - - Reads the current 8-bit value from the sector position. - - Sector Register Write (0xE01A): - - +---+---+---+---+---+---+---+---+ - | Sector Number | - +---+---+---+---+---+---+---+---+ - - Writes the 8-bit value to the sector register. - - Data Register Read (0xE01B): - - +---+---+---+---+---+---+---+---+ - | Data | - +---+---+---+---+---+---+---+---+ - - Reads the current 8-bit value from the data register. - - Data Register Write (0xE01B): - - +---+---+---+---+---+---+---+---+ - | Data | - +---+---+---+---+---+---+---+---+ - - Writes the 8-bit value to the data register. - - A FLEX disk is defined as follows: - - Track Sector Use - 0 1 Boot sector - 0 2 Boot sector (cont) - 0 3 Unused (doesn't exist) - 0 4 System Identity Record (explained below) - 0 5 Unused - 0 6-last Directory - 10 entries/sector (explained below) - 1 1 First available data sector - last-1 last Last available data sector - - System Identity Record - - Byte Use - 0x00 Two bytes of zeroes (Clears forward link) - 0x10 Volume name in ASCII(11 bytes) - 0x1B Volume number in binary (2 bytes) - 0x1D Address of first free data sector (Track-Sector) (2 bytes) - 0x1F Address of last free data sector (Track-Sector) (2 bytes) - 0x21 Total number of data sectors in binary (2 bytes) - 0x23 Current date (Month-Day-Year) in binary - 0x26 Highest track number on disk in binary (byte) - 0x27 Highest sector number on a track in binary (byte) - - The following unit registers are used by this controller emulation: - - dsk_unit[cur_drv].u3 unit current flags - dsk_unit[cur_drv].u4 unit current track - dsk_unit[cur_drv].u5 unit current sector - dsk_unit[cur_drv].pos unit current sector byte index into buffer - dsk_unit[cur_drv].filebuf unit current sector buffer - dsk_unit[cur_drv].fileref unit current attached file reference -*/ - -#include -#include "swtp_defs.h" - -#define DEBUG 0 - -#define UNIT_V_ENABLE (UNIT_V_UF + 0) /* Write Enable */ -#define UNIT_ENABLE (1 << UNIT_V_ENABLE) - -/* maximum of 4 disks, sector size is fixed at 256 bytes */ - -#define NUM_DISK 4 /* standard 1797 maximum */ -#define SECT_SIZE 256 /* standard FLEX sector */ - -/* SIR offsets */ -#define MAXCYL 0x26 /* last cylinder # */ -#define MAXSEC 0x27 /* last sector # */ - -/* 1797 status bits */ - -#define BUSY 0x01 -#define DRQ 0x02 -#define WRPROT 0x40 -#define NOTRDY 0x80 - -/* function prototypes */ - -t_stat dsk_reset (DEVICE *dptr); - -/* SS-50 I/O address space functions */ - -int32 fdcdrv(int32 io, int32 data); -int32 fdccmd(int32 io, int32 data); -int32 fdctrk(int32 io, int32 data); -int32 fdcsec(int32 io, int32 data); -int32 fdcdata(int32 io, int32 data); - -/* Local Variables */ - -int32 fdcbyte; -int32 intrq = 0; /* interrupt request flag */ -int32 cur_dsk; /* Currently selected drive */ -int32 wrt_flag = 0; /* FDC write flag */ - -int32 spt; /* sectors/track */ -int32 trksiz; /* trk size (bytes) */ -int32 heds; /* number of heads */ -int32 cpd; /* cylinders/disk */ -int32 dsksiz; /* dsk size (bytes) */ - -/* Floppy Disk Controller data structures - - dsk_dev Mother Board device descriptor - dsk_unit Mother Board unit descriptor - dsk_reg Mother Board register list - dsk_mod Mother Board modifiers list -*/ - -UNIT dsk_unit[] = { - { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, - { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, - { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, - { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) } -}; - -REG dsk_reg[] = { - { HRDATA (DISK, cur_dsk, 4) }, - { NULL } -}; - -MTAB dsk_mod[] = { - { UNIT_ENABLE, UNIT_ENABLE, "RW", "RW", NULL }, - { UNIT_ENABLE, 0, "RO", "RO", NULL }, - { 0 } -}; - -DEBTAB dsk_debug[] = { - { "ALL", DEBUG_all }, - { "FLOW", DEBUG_flow }, - { "READ", DEBUG_read }, - { "WRITE", DEBUG_write }, - { "LEV1", DEBUG_level1 }, - { "LEV2", DEBUG_level2 }, - { NULL } -}; - -DEVICE dsk_dev = { - "DC-4", //name - dsk_unit, //units - dsk_reg, //registers - dsk_mod, //modifiers - NUM_DISK, //numunits - 16, //aradix - 16, //awidth - 1, //aincr - 16, //dradix - 8, //dwidth - NULL, //examine - NULL, //deposit - &dsk_reset, //reset - NULL, //boot - NULL, //attach - NULL, //detach - NULL, //ctxt - DEV_DEBUG, //flags - 0, //dctrl - dsk_debug, /* debflags */ - NULL, //msize - NULL //lname -}; - -/* Reset routine */ - -t_stat dsk_reset (DEVICE *dptr) -{ - int i; - - cur_dsk = 5; /* force initial SIR read, use a drive # that can't be selected */ - - for (i=0; i +#include "swtp_defs.h" + +#define DEBUG 0 + +#define UNIT_V_ENABLE (UNIT_V_UF + 0) /* Write Enable */ +#define UNIT_ENABLE (1 << UNIT_V_ENABLE) + +/* maximum of 4 disks, sector size is fixed at 256 bytes */ + +#define NUM_DISK 4 /* standard 1797 maximum */ +#define SECT_SIZE 256 /* standard FLEX sector */ + +/* SIR offsets */ +#define MAXCYL 0x26 /* last cylinder # */ +#define MAXSEC 0x27 /* last sector # */ + +/* 1797 status bits */ + +#define BUSY 0x01 +#define DRQ 0x02 +#define WRPROT 0x40 +#define NOTRDY 0x80 + +/* function prototypes */ + +t_stat dsk_reset (DEVICE *dptr); + +/* SS-50 I/O address space functions */ + +int32 fdcdrv(int32 io, int32 data); +int32 fdccmd(int32 io, int32 data); +int32 fdctrk(int32 io, int32 data); +int32 fdcsec(int32 io, int32 data); +int32 fdcdata(int32 io, int32 data); + +/* Local Variables */ + +int32 fdcbyte; +int32 intrq = 0; /* interrupt request flag */ +int32 cur_dsk; /* Currently selected drive */ +int32 wrt_flag = 0; /* FDC write flag */ + +int32 spt; /* sectors/track */ +int32 trksiz; /* trk size (bytes) */ +int32 heds; /* number of heads */ +int32 cpd; /* cylinders/disk */ +int32 dsksiz; /* dsk size (bytes) */ + +/* Floppy Disk Controller data structures + + dsk_dev Mother Board device descriptor + dsk_unit Mother Board unit descriptor + dsk_reg Mother Board register list + dsk_mod Mother Board modifiers list +*/ + +UNIT dsk_unit[] = { + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) } +}; + +REG dsk_reg[] = { + { HRDATA (DISK, cur_dsk, 4) }, + { NULL } +}; + +MTAB dsk_mod[] = { + { UNIT_ENABLE, UNIT_ENABLE, "RW", "RW", NULL }, + { UNIT_ENABLE, 0, "RO", "RO", NULL }, + { 0 } +}; + +DEBTAB dsk_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE dsk_dev = { + "DC-4", //name + dsk_unit, //units + dsk_reg, //registers + dsk_mod, //modifiers + NUM_DISK, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + &dsk_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + dsk_debug, /* debflags */ + NULL, //msize + NULL //lname +}; + +/* Reset routine */ + +t_stat dsk_reset (DEVICE *dptr) +{ + int i; + + cur_dsk = 5; /* force initial SIR read, use a drive # that can't be selected */ + + for (i=0; i Accumulator A - B<0:7> Accumulator B - IX<0:15> Index Register - IY<0:15> Index Register - CCR<0:7> Condition Code Register - EF Entire flag - FF FIRQ flag - HF half-carry flag - IF IRQ flag - NF negative flag - ZF zero flag - VF overflow flag - CF carry flag - PC<0:15> program counter - UP<0:15> User Stack Pointer - SP<0:15> Stack Pointer - - The M6809 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 M6809. - It is called from the CPU board simulator 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 6809, reads to non-existent memory - return 0FFH, and writes are ignored. -*/ - -#include - -#include "swtp_defs.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) - -/* Flag values to set proper positions in CCR */ -#define EF 0x80 -#define FF 0x40 -#define HF 0x20 -#define IF 0x10 -#define NF 0x08 -#define ZF 0x04 -#define VF 0x02 -#define CF 0x01 - -/* PSH/PUL Post Byte register positions */ -#define PSH_PUL_Post_Byte_PC 0x80 -#define PSH_PUL_Post_Byte_S_U 0x40 -#define PSH_PUL_Post_Byte_Y 0x20 -#define PSH_PUL_Post_Byte_X 0x10 -#define PSH_PUL_Post_Byte_DP 0x08 -#define PSH_PUL_Post_Byte_B 0x04 -#define PSH_PUL_Post_Byte_A 0x02 -#define PSH_PUL_Post_Byte_CC 0x01 - -#define TFR_EXG_Post_Nybble_D 0 -#define TFR_EXG_Post_Nybble_X 1 -#define TFR_EXG_Post_Nybble_Y 2 -#define TFR_EXG_Post_Nybble_U 3 -#define TFR_EXG_Post_Nybble_S 4 -#define TFR_EXG_Post_Nybble_PC 5 -#define TFR_EXG_Post_Nybble_A 8 -#define TFR_EXG_Post_Nybble_B 9 -#define TFR_EXG_Post_Nybble_CC 10 -#define TFR_EXG_Post_Nybble_DP 11 - - -/* Macros to handle the flags in the CCR */ -#define CCR_MSK (EF|FF|HF|IF|NF|ZF|VF|CF) -#define TOGGLE_FLAG(FLAG) (CCR ^= (FLAG)) -#define SET_FLAG(FLAG) (CCR |= (FLAG)) -#define CLR_FLAG(FLAG) (CCR &= ~(FLAG)) -#define GET_FLAG(FLAG) (CCR & (FLAG)) - -#define COND_SET_FLAG(COND,FLAG) \ - if (COND) SET_FLAG(FLAG); else CLR_FLAG(FLAG) - -#define COND_SET_FLAG_N(VAR) \ - if ((VAR) & 0x80) SET_FLAG(NF); else CLR_FLAG(NF) -#define COND_SET_FLAG_N_16(VAR) \ - if ((VAR) & 0x8000) SET_FLAG(NF); else CLR_FLAG(NF) - -#define COND_SET_FLAG_Z(VAR) \ - if ((VAR) == 0) SET_FLAG(ZF); else CLR_FLAG(ZF) -#define COND_SET_FLAG_Z_16(VAR) \ - if ((VAR) == 0) SET_FLAG(ZF); else CLR_FLAG(ZF) - -#define COND_SET_FLAG_H(VAR) \ - if ((VAR) & 0x10) SET_FLAG(HF); else CLR_FLAG(HF) - -#define COND_SET_FLAG_C(VAR) \ - if ((VAR) & 0x100) SET_FLAG(CF); else CLR_FLAG(CF) -#define COND_SET_FLAG_C_16(VAR) \ - if ((VAR) & 0x10000) SET_FLAG(CF); else CLR_FLAG(CF) - -#define COND_SET_FLAG_V(COND) \ - if (COND) SET_FLAG(VF); else CLR_FLAG(VF) - -/* local global variables */ - -int32 A = 0; /* Accumulator A */ -int32 B = 0; /* Accumulator B */ -int32 D = 0; /* Accumulator D */ -int32 DP = 0; /* Direct Page Register */ -int32 IX = 0; /* Index register X */ -int32 IY = 0; /* Index register Y */ -int32 UP = 0; /* User Stack pointer */ -int32 SP = 0; /* Hardware Stack pointer */ -int32 CCR = EF|FF|IF; /* Condition Code Register */ -int32 saved_PC = 0; /* Saved Program counter */ -int32 previous_PC = 0; /* Previous previous Program counter */ -int32 last_PC = 0; /* Last Program counter */ -int32 PC; /* Program counter */ -int32 INTE = 0; /* Interrupt Enable */ -int32 int_req = 0; /* Interrupt request */ - -int32 mem_fault = 0; /* memory fault flag */ - -/* function prototypes */ - -t_stat m6809_reset(DEVICE *dptr); -t_stat m6809_boot(int32 unit_num, DEVICE *dptr); -t_stat m6809_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); -t_stat m6809_deposit(t_value value, t_addr addr, UNIT *uptr, int32 switches); - -void dump_regs(void); -void dump_regs1(void); -int32 fetch_byte(int32 flag); -int32 fetch_word(); -uint8 pop_sp_byte(void); -uint8 pop_up_byte(void); -uint16 pop_sp_word(void); -uint16 pop_up_word(void); -void push_sp_byte(uint8 val); -void push_up_byte(uint8 val); -void push_sp_word(uint16 val); -void push_up_word(uint16 val); -void go_rel(int32 cond); -void go_long_rel(int32 cond); -int32 get_rel_addr(void); -int32 get_long_rel_addr(void); -int32 get_dir_byte_val(void); -int32 get_dir_word_val(void); -int32 get_imm_byte_val(void); -int32 get_imm_word_val(void); -int32 get_dir_addr(void); -int32 get_indexed_byte_val(void); -int32 get_indexed_word_val(void); -int32 get_indexed_addr(void); -int32 get_ext_addr(void); -int32 get_ext_byte_val(void); -int32 get_ext_word_val(void); -int32 get_flag(int32 flag); -void condevalVa(int32 op1, int32 op2); -void condevalVa16(int32 op1, int32 op2); -void condevalVs(int32 op1, int32 op2); -void condevalVs16(int32 op1, int32 op2); -void condevalHa(int32 op1, int32 op2); - -/* external routines */ - -extern void CPU_BD_put_mbyte(int32 addr, int32 val); -extern void CPU_BD_put_mword(int32 addr, int32 val); -extern int32 CPU_BD_get_mbyte(int32 addr); -extern int32 CPU_BD_get_mword(int32 addr); - -/* CPU data structures - - m6809_dev CPU device descriptor - m6809_unit CPU unit descriptor - m6809_reg CPU register list - m6809_mod CPU modifiers list */ - -UNIT m6809_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, 65536) }; - -REG m6809_reg[] = { - { HRDATA (PC, saved_PC, 16) }, - { HRDATA (A, A, 8) }, - { HRDATA (B, B, 8) }, - { HRDATA (DP, DP, 8) }, - { HRDATA (IX, IX, 16) }, - { HRDATA (IY, IY, 16) }, - { HRDATA (SP, SP, 16) }, - { HRDATA (UP, UP, 16) }, - { HRDATA (CCR, CCR, 8) }, - { FLDATA (INTE, INTE, 16) }, - { ORDATA (WRU, sim_int_char, 8) }, - { NULL } }; - -MTAB m6809_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 }, - { 0 } }; - -DEBTAB m6809_debug[] = { - { "ALL", DEBUG_all }, - { "FLOW", DEBUG_flow }, - { "READ", DEBUG_read }, - { "WRITE", DEBUG_write }, - { "LEV1", DEBUG_level1 }, - { "LEV2", DEBUG_level2 }, - { "REG", DEBUG_reg }, - { "ASM", DEBUG_asm }, - { NULL } -}; - -DEVICE m6809_dev = { - "CPU", //name - &m6809_unit, //units - m6809_reg, //registers - m6809_mod, //modifiers - 1, //numunits - 16, //aradix - 16, //awidth - 1, //aincr - 16, //dradix - 8, //dwidth - &m6809_examine, //examine - &m6809_deposit, //deposit - &m6809_reset, //reset - &m6809_boot, //boot - NULL, //attach - NULL, //detach - NULL, //ctxt - DEV_DEBUG, //flags - 0, //dctrl - m6809_debug, //debflags - NULL, //msize - NULL //lname -}; - -static const char *opcode[] = { -"NEG", "???", "???", "COM", //0x00 -"LSR", "???", "ROR", "ASR", -"ASL", "ROL", "DEC", "???", -"INC", "TST", "JMP", "CLR", -"PG2", "PG3", "NOP", "SYNC", //0x10 -"???", "???", "LBRA", "LBSR", -"???", "DAA", "ORCC", "???", -"ANDCC", "SEX", "EXG", "TFR", -"BRA", "BRN", "BHI", "BLS", //0x20 -"BCC", "BLO", "BNE", "BEQ", -"BVC", "BVS", "BPL", "BMI", -"BGE", "BLT", "BGT", "BLE", -"LEAX", "LEAY", "LEAS", "LEAU", //0x30 -"PSHS", "PULS", "PSHU", "PULU", -"???", "RTS", "ABX", "RTI", -"CWAI", "MUL", "???", "SWI", -"NEGA", "???", "???", "COMA", //0x40 -"LSRA", "???", "RORA", "ASRA", -"LSLA", "ROLA", "DECA", "???", -"INCA", "TSTA", "???", "CLRA", -"NEGB", "???", "???", "COMB", //0x50 -"LSRB", "???", "RORB", "ASRB", -"LSLB", "ROLB", "DECB", "???", -"INCB", "TSTB", "???", "CLRB", -"NEG", "???", "???", "COM", //0x60 -"LSR", "???", "ROR", "ASR", -"ASL", "ROL", "DEC", "???", -"INC", "TST", "JMP", "CLR", -"NEG", "???", "???", "COM", //0x70 -"LSR", "???", "ROR", "ASR", -"ASL", "ROL", "DEC", "???", -"INC", "TST", "JMP", "CLR", -"SUBA", "CMPA", "SBCA", "SUBD", //0x80 -"ANDA", "BITA", "LDA", "???", -"EORA", "ADCA", "ORAA", "ADDA", -"CMPX", "BSR", "LDX", "???", -"SUBA", "CMPA", "SBCA", "SUBD", //0x90 -"ANDA", "BITA", "LDA", "STA", -"EORA", "ADCA", "ORA", "ADDA", -"CMPX", "JSR", "LDX", "STX", -"SUBA", "CMPA", "SBCA", "SUBD", //0xA0 -"ANDA", "BITA", "LDA", "STA", -"EORA", "ADCA", "ORA", "ADDA", -"CMPX", "JSR", "LDX", "STX", -"SUBA", "CMPA", "SBCA", "SUBD", //0xB0 -"ANDA", "BITA", "LDA", "STA", -"EORA", "ADCA", "ORA", "ADDA", -"CMPX", "JSR", "LDX", "STX", -"SUBB", "CMPB", "SBCB", "ADDD", //0xC0 -"ANDB", "BITB", "LDB", "???", -"EORB", "ADCB", "ORB", "ADDB", -"LDD", "???", "LDU", "???", -"SUBB", "CMPB", "SBCB", "ADDD", //0xD0 -"ANDB", "BITB", "LDB", "STB", -"EORB", "ADCB", "ORB", "ADDB", -"LDD", "STD", "LDU", "STU", -"SUBB", "CMPB", "SBCB", "ADDD", //0xE0 -"ANDB", "BITB", "LDB", "STB", -"EORB", "ADCB", "ORB", "ADDB", -"LDD", "STD", "LDU", "STU", -"SUBB", "CMPB", "SBCB", "ADDD", //0xF0 -"ANDB", "BITB", "LDB", "STB", -"EORB", "ADCB", "ORB", "ADDB", -"LDD", "STD", "LDU", "STU" -}; - -static const char *opcode6800[] = { -"???", "NOP", "???", "???", //0x00 -"???", "???", "TAP", "TPA", -"INX", "DEX", "CLV", "SEV", -"CLC", "SEC", "CLI", "SEI", -"SBA", "CBA", "???", "???", //0x10 -"???", "???", "TAB", "TBA", -"???", "DAA", "???", "ABA", -"???", "???", "???", "???", -"BRA", "???", "BHI", "BLS", //0x20 -"BCC", "BCS", "BNE", "BEQ", -"BVC", "BVS", "BPL", "BMI", -"BGE", "BLT", "BGT", "BLE", -"TSX", "INS", "PULA", "PULB", //0x30 -"DES", "TXS", "PSHA", "PSHB", -"???", "RTS", "???", "RTI", -"???", "???", "WAI", "SWI", -"NEGA", "???", "???", "COMA", //0x40 -"LSRA", "???", "RORA", "ASRA", -"ASLA", "ROLA", "DECA", "???", -"INCA", "TSTA", "???", "CLRA", -"NEGB", "???", "???", "COMB", //0x50 -"LSRB", "???", "RORB", "ASRB", -"ASLB", "ROLB", "DECB", "???", -"INCB", "TSTB", "???", "CLRB", -"NEG", "???", "???", "COM", //0x60 -"LSR", "???", "ROR", "ASR", -"ASL", "ROL", "DEC", "???", -"INC", "TST", "JMP", "CLR", -"NEG", "???", "???", "COM", //0x70 -"LSR", "???", "ROR", "ASR", -"ASL", "ROL", "DEC", "???", -"INC", "TST", "JMP", "CLR", -"SUBA", "CMPA", "SBCA", "???", //0x80 -"ANDA", "BITA", "LDAA", "???", -"EORA", "ADCA", "ORAA", "ADDA", -"CMPX", "BSR", "LDS", "???", -"SUBA", "CMPA", "SBCA", "???", //0x90 -"ANDA", "BITA", "LDAA", "STAA", -"EORA", "ADCA", "ORAA", "ADDA", -"CMPX", "???", "LDS", "STS", -"SUBA", "CMPA", "SBCA", "???", //0xA0 -"ANDA", "BITA", "LDAA", "STAA", -"EORA", "ADCA", "ORAA", "ADDA", -"CMPX X", "JSR X", "LDS X", "STS X", -"SUBA", "CMPA", "SBCA", "???", //0xB0 -"ANDA", "BITA", "LDAA", "STAA", -"EORA", "ADCA", "ORAA", "ADDA", -"CPX", "JSR", "LDS", "STS", -"SUBB", "CMPB", "SBCB", "???", //0xC0 -"ANDB", "BITB", "LDAB", "???", -"EORB", "ADCB", "ORAB", "ADDB", -"???", "???", "LDX", "???", -"SUBB", "CMPB", "SBCB", "???", //0xD0 -"ANDB", "BITB", "LDAB", "STAB", -"EORB", "ADCB", "ORAB", "ADDB", -"???", "???", "LDX", "STX", -"SUBB", "CMPB", "SBCB", "???", //0xE0 -"ANDB", "BITB", "LDAB", "STAB", -"EORB", "ADCB", "ORAB", "ADDB", -"???", "???", "LDX", "STX", -"SUBB", "CMPB", "SBCB", "???", //0xF0 -"ANDB", "BITB", "LDAB", "STAB", -"EORB", "ADCB", "ORAB", "ADDB", -"???", "???", "LDX", "STX" -}; - -int32 oplen[256] = { -0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1, //0x00 -1,1,0,0,0,0,1,1,0,1,0,1,0,0,0,0, -2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, -1,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1, -1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, //0x40 -1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, -2,0,0,2,2,0,2,2,2,2,2,0,2,2,2,2, -3,0,0,3,3,0,3,3,3,3,3,0,3,3,3,3, -2,2,2,0,2,2,2,0,2,2,2,2,3,2,3,0, //0x80 -2,2,2,0,2,2,2,2,2,2,2,2,2,0,2,2, -2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2, -3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3, -2,2,2,0,2,2,2,0,2,2,2,2,0,0,3,0, //0xC0 -2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, -2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, -3,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3 -}; - -int32 oplen6800[256] = { -0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1, //0x00 -1,1,0,0,0,0,1,1,0,1,0,1,0,0,0,0, -2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, -1,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1, -1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, //0x40 -1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, -2,0,0,2,2,0,2,2,2,2,2,0,2,2,2,2, -3,0,0,3,3,0,3,3,3,3,3,0,3,3,3,3, -2,2,2,0,2,2,2,0,2,2,2,2,3,2,3,0, //0x80 -2,2,2,0,2,2,2,2,2,2,2,2,2,0,2,2, -2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2, -3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3, -2,2,2,0,2,2,2,0,2,2,2,2,0,0,3,0, //0xC0 -2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, -2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, -3,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3 -}; - -t_stat sim_instr (void) -{ - int32 reason; - int32 IR; - int32 OP; - int32 OP2; /* Used for 2-byte opcodes */ - - int32 hi; /* hi bit/nybble/byte */ - int32 lo; /* lo bit/nybble/byte */ - int32 op1; /* operand #1 */ - int32 op2; /* operand #2 - used for CC evaluation */ - int32 result; /* temporary value */ - int32 addr; /* temporary address value */ - - /* used for 6809 instruction decoding - TFT, EXG, PSH, PUL*/ - int32 Post_Byte = 0; - int32 Src_Nybble = 0; - int32 Dest_Nybble = 0; - int32 Src_Value = 0; - int32 Dest_Value = 0; - - PC = saved_PC & ADDRMASK; /* load local PC */ - reason = 0; - - /* Main instruction fetch/decode loop */ - - while (reason == 0) { /* loop until halted */ -// dump_regs1(); - 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? */ - /* 6809 interrupts not implemented yet. None were used, - on a standard SWTP 6809. All I/O is programmed. */ - reason = STOP_HALT; /* stop simulation */ - break; - - } /* end interrupt */ - if (sim_brk_summ && - sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ - break; - } - - sim_interval--; - last_PC = previous_PC; - previous_PC = PC; - IR = OP = fetch_byte(0); /* fetch instruction */ - - /* The Big Instruction Decode Switch */ - - switch (IR) { - -/* 0x00 - direct mode */ - case 0x00: /* NEG dir */ - addr = get_dir_addr(); - op1 = CPU_BD_get_mbyte(addr); - COND_SET_FLAG(op1 != 0, CF); - COND_SET_FLAG(op1 == 0x80, VF); - result = 0 - op1; - result &= 0xFF; - CPU_BD_put_mbyte(addr, result); - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - break; - case 0x03: /* COM dir */ - addr = get_dir_addr(); - op1 = CPU_BD_get_mbyte(addr); - result = ~op1; - result &= 0xFF; - CPU_BD_put_mbyte(addr, result); - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - CLR_FLAG(VF); - SET_FLAG(CF); - break; - case 0x04: /* LSR dir */ - addr = get_dir_addr(); - op1 = CPU_BD_get_mbyte(addr); - COND_SET_FLAG(op1 & 0x01, CF); - result = op1 >> 1; - CPU_BD_put_mbyte(addr, result); - CLR_FLAG(NF); - COND_SET_FLAG_Z(result); - /* H,V not affected */ - break; - case 0x06: /* ROR dir */ - addr = get_dir_addr(); - op1 = CPU_BD_get_mbyte(addr); - result = op1 >> 1; - if (get_flag(CF)) { - result |= 0x80; - } - CPU_BD_put_mbyte(addr, result); - /* H,V unaffected */ - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - COND_SET_FLAG(op1 & 0x01, CF); - break; - case 0x07: /* ASR dir */ - addr = get_dir_addr(); - op1 = CPU_BD_get_mbyte(addr); - result = (op1 >> 1) | (op1 & 0x80); - CPU_BD_put_mbyte(addr, result); - /* H undefined */ - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - /* V not affected */ - COND_SET_FLAG(op1 & 0x01, CF); - break; - case 0x08: /* ASL dir */ - addr = get_dir_addr(); - op1 = CPU_BD_get_mbyte(addr); - COND_SET_FLAG(op1 & 0x80, CF); - result = (op1 << 1) & 0xFF; - CPU_BD_put_mbyte(addr, result); - /* H is undefined */ - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); - break; - case 0x09: /* ROL dir */ - addr = get_dir_addr(); - op1 = CPU_BD_get_mbyte(addr); - result = (op1 << 1) & 0xFF; - if (get_flag(CF)) { - result |= 0x01; - } - CPU_BD_put_mbyte(addr, result); - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - COND_SET_FLAG((op1 & 0x80) ^ (op1 & 0x40), VF); - COND_SET_FLAG(op1 & 0x80, CF); - break; - case 0x0A: /* DEC dir */ - addr = get_dir_addr(); - op1 = CPU_BD_get_mbyte(addr); - result = (op1-1) & 0xFF; - CPU_BD_put_mbyte(addr, result); - /* H not affected */ - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - COND_SET_FLAG(op1 == 0x80, VF); - /* C not affected */ - break; - case 0x0C: /* INC dir */ - addr = get_dir_addr(); - op1 = CPU_BD_get_mbyte(addr); - COND_SET_FLAG(op1 == 0x7F, VF); - op1 = (op1 + 1) & 0xFF; - CPU_BD_put_mbyte(addr, op1); - COND_SET_FLAG_N(op1); - COND_SET_FLAG_Z(op1); - break; - case 0x0D: /* TST dir */ - result = get_dir_byte_val(); - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - CLR_FLAG(VF); - break; - case 0x0E: /* JMP dir */ - PC = get_dir_addr(); - break; - case 0x0F: /* CLR dir */ - CPU_BD_put_mbyte(get_dir_addr(), 0); - /* H not affected */ - CLR_FLAG(NF); - SET_FLAG(ZF); - CLR_FLAG(VF); - CLR_FLAG(CF); - break; - -/* 0x10 */ - case 0x10: /* 2-byte opcodes */ - /* fetch second byte of opcode */ - OP2 = fetch_byte(0); - switch (OP2) { - case 0x21: /* LBRN rel */ - /* Branch Never - essentially a NOP */ - go_long_rel(0); - break; - case 0x22: /* LBHI rel */ - go_long_rel(!(get_flag(CF) | get_flag(ZF))); - break; - case 0x23: /* LBLS rel */ - go_long_rel(get_flag(CF) | get_flag(ZF)); - break; - case 0x24: /* LBCC rel */ - go_long_rel(!get_flag(CF)); - break; - case 0x25: /* LBCS rel */ - go_long_rel(get_flag(CF)); - break; - case 0x26: /* LBNE rel */ - go_long_rel(!get_flag(ZF)); - break; - case 0x27: /* LBEQ rel */ - go_long_rel(get_flag(ZF)); - break; - case 0x28: /* LBVC rel */ - go_long_rel(!get_flag(VF)); - break; - case 0x29: /* LBVS rel */ - go_long_rel(get_flag(VF)); - break; - case 0x2A: /* LBPL rel */ - go_long_rel(!get_flag(NF)); - break; - case 0x2B: /* LBMI rel */ - go_long_rel(get_flag(NF)); - break; - case 0x2C: /* LBGE rel */ - go_long_rel( !( get_flag(NF) ^ get_flag(VF) ) ); - break; - case 0x2D: /* LBLT rel */ - go_long_rel( get_flag(NF) ^ get_flag(VF) ); - break; - case 0x2E: /* LBGT rel */ - go_long_rel(!( get_flag(ZF) | (get_flag(NF) ^ get_flag(VF)))); - break; - case 0x2F: /* LBLE rel */ - go_long_rel(get_flag(ZF) | (get_flag(NF) ^ get_flag(VF))); - break; - case 0x3F: /* SWI2 */ - SET_FLAG(EF); - push_sp_word(PC); - push_sp_word(UP); - push_sp_word(IY); - push_sp_word(IX); - push_sp_byte(DP); - push_sp_byte(B); - push_sp_byte(A); - push_sp_byte(CCR); - PC = CPU_BD_get_mword(0xFFF4) & ADDRMASK; - break; - case 0x83: /* CMPD imm */ - D = (A << 8) | (B & 0xFF); - op2 = get_imm_word_val(); - result = D - op2; - COND_SET_FLAG_N_16(result); - COND_SET_FLAG_Z_16(result); - condevalVs16(D, op2); - COND_SET_FLAG_C_16(result); - break; - case 0x8C: /* CMPY imm */ - op2 = get_imm_word_val(); - result = IY - op2; - COND_SET_FLAG_N_16(result); - COND_SET_FLAG_Z_16(result); - condevalVs16(IY, op2); - COND_SET_FLAG_C_16(result); - break; - case 0x8E: /* LDY imm */ - IY = get_imm_word_val(); - COND_SET_FLAG_N_16(IY); - COND_SET_FLAG_Z_16(IY); - CLR_FLAG(VF); - break; - case 0x93: /* CMPD dir */ - D = (A << 8) | (B & 0xFF); - op2 = get_dir_word_val(); - result = D - op2; - COND_SET_FLAG_N_16(result); - COND_SET_FLAG_Z_16(result); - condevalVs16(D, op2); - COND_SET_FLAG_C_16(result); - break; - case 0x9C: /* CMPY dir */ - op2 = get_dir_word_val(); - result = IY - op2; - COND_SET_FLAG_N_16(result); - COND_SET_FLAG_Z_16(result); - condevalVs16(IY, op2); - COND_SET_FLAG_C_16(result); - break; - case 0x9E: /* LDY dir */ - IY = get_dir_word_val(); - COND_SET_FLAG_N_16(IY); - COND_SET_FLAG_Z_16(IY); - CLR_FLAG(VF); - break; - case 0x9F: /* STY dir */ - CPU_BD_put_mword(get_dir_addr(), IY); - COND_SET_FLAG_N_16(IY); - COND_SET_FLAG_Z_16(IY); - CLR_FLAG(VF); - break; - case 0xA3: /* CMPD ind */ - D = (A << 8) | (B & 0xFF); - op2 = get_indexed_word_val(); - result = D - op2; - COND_SET_FLAG_N_16(result); - COND_SET_FLAG_Z_16(result); - condevalVs16(D, op2); - COND_SET_FLAG_C_16(result); - break; - case 0xAC: /* CMPY ind */ - op2 = get_indexed_word_val(); - result = IY - op2; - COND_SET_FLAG_N_16(result); - COND_SET_FLAG_Z_16(result); - condevalVs16(IY, op2); - COND_SET_FLAG_C_16(result); - break; - case 0xAE: /* LDY ind */ - IY = get_indexed_word_val(); - COND_SET_FLAG_N_16(IY); - COND_SET_FLAG_Z_16(IY); - CLR_FLAG(VF); - break; - case 0xAF: /* STY ind */ - CPU_BD_put_mword(get_indexed_addr(), IY); - COND_SET_FLAG_N_16(IY); - COND_SET_FLAG_Z_16(IY); - CLR_FLAG(VF); - break; - case 0xB3: /* CMPD ext */ - D = (A << 8) | (B & 0xFF); - op2 = get_ext_word_val(); - result = D - op2; - COND_SET_FLAG_N_16(result); - COND_SET_FLAG_Z_16(result); - condevalVs16(D, op2); - COND_SET_FLAG_C_16(result); - break; - case 0xBC: /* CMPY ext */ - op2 = get_ext_word_val(); - result = IY - op2; - COND_SET_FLAG_N_16(result); - COND_SET_FLAG_Z_16(result); - condevalVs16(IY, op2); - COND_SET_FLAG_C_16(result); - break; - case 0xBE: /* LDY ext */ - IY = get_ext_word_val(); - COND_SET_FLAG_N_16(IY); - COND_SET_FLAG_Z_16(IY); - CLR_FLAG(VF); - break; - case 0xBF: /* STY ext */ - CPU_BD_put_mword(get_ext_addr(), IY); - COND_SET_FLAG_N_16(IY); - COND_SET_FLAG_Z_16(IY); - CLR_FLAG(VF); - break; - case 0xCE: /* LDS imm */ - SP = get_imm_word_val(); - COND_SET_FLAG_N_16(SP); - COND_SET_FLAG_Z_16(SP); - CLR_FLAG(VF); - break; - case 0xDE: /* LDS dir */ - SP = get_dir_word_val(); - COND_SET_FLAG_N_16(SP); - COND_SET_FLAG_Z_16(SP); - CLR_FLAG(VF); - break; - case 0xDF: /* STS dir */ - CPU_BD_put_mword(get_dir_addr(), SP); - COND_SET_FLAG_N_16(SP); - COND_SET_FLAG_Z_16(SP); - CLR_FLAG(VF); - break; - case 0xEE: /* LDS ind */ - SP = get_indexed_word_val(); - COND_SET_FLAG_N_16(SP); - COND_SET_FLAG_Z_16(SP); - CLR_FLAG(VF); - break; - case 0xEF: /* STS ind */ - CPU_BD_put_mword(get_indexed_addr(), SP); - COND_SET_FLAG_N_16(SP); - COND_SET_FLAG_Z_16(SP); - CLR_FLAG(VF); - break; - case 0xFE: /* LDS ext */ - SP = get_ext_word_val(); - COND_SET_FLAG_N_16(SP); - COND_SET_FLAG_Z_16(SP); - CLR_FLAG(VF); - break; - case 0xFF: /* STS ext */ - CPU_BD_put_mword(get_ext_addr(), SP); - COND_SET_FLAG_N_16(SP); - COND_SET_FLAG_Z_16(SP); - CLR_FLAG(VF); - break; - } - break; - -/* Ox11 */ - case 0x11: /* 2-byte opcodes */ - /* fetch second byte of opcode */ - OP2 = fetch_byte(0); - switch (OP2) { - case 0x3F: /* SWI3 */ - SET_FLAG(EF); - push_sp_word(PC); - push_sp_word(UP); - push_sp_word(IY); - push_sp_word(IX); - push_sp_byte(DP); - push_sp_byte(B); - push_sp_byte(A); - push_sp_byte(CCR); - PC = CPU_BD_get_mword(0xFFF2) & ADDRMASK; - break; - case 0x83: /* CMPU imm */ - op2 = get_imm_word_val(); - result = UP - op2; - COND_SET_FLAG_N_16(result); - COND_SET_FLAG_Z_16(result); - condevalVs16(UP, op2); - COND_SET_FLAG_C_16(result); - break; - case 0x8C: /* CMPS imm */ - op2 = get_imm_word_val(); - result = SP - op2; - COND_SET_FLAG_N_16(result); - COND_SET_FLAG_Z_16(result); - condevalVs16(SP, op2); - COND_SET_FLAG_C_16(result); - break; - case 0x93: /* CMPU dir */ - op2 = get_dir_word_val(); - result = UP - op2; - COND_SET_FLAG_N_16(result); - COND_SET_FLAG_Z_16(result); - condevalVs16(UP, op2); - COND_SET_FLAG_C_16(result); - break; - case 0x9C: /* CMPS dir */ - op2 = get_dir_word_val(); - result = SP - op2; - COND_SET_FLAG_N_16(result); - COND_SET_FLAG_Z_16(result); - condevalVs16(SP, op2); - COND_SET_FLAG_C_16(result); - break; - case 0xA3: /* CMPU ind */ - op2 = get_indexed_word_val(); - result = UP - op2; - COND_SET_FLAG_N_16(result); - COND_SET_FLAG_Z_16(result); - condevalVs16(UP, op2); - COND_SET_FLAG_C_16(result); - break; - case 0xAC: /* CMPS ind */ - op2 = get_indexed_word_val(); - result = SP - op2; - COND_SET_FLAG_N_16(result); - COND_SET_FLAG_Z_16(result); - condevalVs16(SP, op2); - COND_SET_FLAG_C_16(result); - break; - case 0xB3: /* CMPU ext */ - op2 = get_ext_word_val(); - result = UP - op2; - COND_SET_FLAG_N_16(result); - COND_SET_FLAG_Z_16(result); - condevalVs16(UP, op2); - COND_SET_FLAG_C_16(result); - break; - case 0xBC: /* CMPS ext */ - op2 = get_ext_word_val(); - result = SP - op2; - COND_SET_FLAG_N_16(result); - COND_SET_FLAG_Z_16(result); - condevalVs16(SP, op2); - COND_SET_FLAG_C_16(result); - break; - } - break; - case 0x12: /* NOP */ - break; - case 0x13: /* SYNC inherent*/ - /* Interrupts are not implemented */ - reason = STOP_HALT; /* stop simulation */ - break; - case 0x16: /* LBRA relative */ - go_long_rel(1); - break; - case 0x17: /* LBSR relative */ - addr = get_long_rel_addr(); - push_sp_word(PC); - PC = (PC + addr) & ADDRMASK; - break; - case 0x19: /* DAA inherent */ - lo = A & 0x0F; - if ((lo > 9) || get_flag(HF)) { - lo += 6; - A = (A & 0xF0) + lo; - COND_SET_FLAG(lo & 0x10, HF); - } - hi = (A >> 4) & 0x0F; - if ((hi > 9) || get_flag(CF)) { - hi += 6; - A = (A & 0x0F) | (hi << 4) | 0x100; - } - COND_SET_FLAG_C(A); - A &= 0xFF; - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - break; - - case 0x1A: /* ORCC imm */ - CCR = CCR | get_imm_byte_val(); - break; - case 0x1C: /* ANDCC imm */ - CCR = CCR & get_imm_byte_val(); - break; - case 0x1D: /* SEX inherent */ - if (B & 0x80) { - A = 0xFF; - } else { - A = 0; - } - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - break; - case 0x1E: /* EXG imm */ - Post_Byte = get_imm_byte_val(); - Src_Nybble = (Post_Byte >> 4) & 0x0F; - Dest_Nybble = Post_Byte & 0x0F; - if ((Src_Nybble <= 5 && Dest_Nybble > 5) || (Src_Nybble > 5 && Dest_Nybble <= 5)) { - // EXG with unaligned register sizes - reason = STOP_OPCODE; - } - - /* read register values */ - if (Src_Nybble <= 5 && Dest_Nybble <= 5) { - /* 16-bit register */ - /* read source register */ - switch (Src_Nybble) { - case TFR_EXG_Post_Nybble_D: Src_Value = (A << 8) | (B & 0xFF); break; - case TFR_EXG_Post_Nybble_X: Src_Value = IX; break; - case TFR_EXG_Post_Nybble_Y: Src_Value = IY; break; - case TFR_EXG_Post_Nybble_U: Src_Value = UP; break; - case TFR_EXG_Post_Nybble_S: Src_Value = SP; break; - case TFR_EXG_Post_Nybble_PC: Src_Value = PC; break; - default: break; - } - /* read destination register */ - switch (Dest_Nybble) { - case TFR_EXG_Post_Nybble_D: Dest_Value = (A << 8) | (B & 0xFF); break; - case TFR_EXG_Post_Nybble_X: Dest_Value = IX; break; - case TFR_EXG_Post_Nybble_Y: Dest_Value = IY; break; - case TFR_EXG_Post_Nybble_U: Dest_Value = UP; break; - case TFR_EXG_Post_Nybble_S: Dest_Value = SP; break; - case TFR_EXG_Post_Nybble_PC: Dest_Value = PC; break; - default: break; - } - } - if ((Src_Nybble >= 8 && Src_Nybble <= 11) && (Dest_Nybble >= 8 && Dest_Nybble <= 11)) { - /* 8-bit register read */ - /* read source register */ - switch (Src_Nybble) { - case TFR_EXG_Post_Nybble_A: Src_Value = A; break; - case TFR_EXG_Post_Nybble_B: Src_Value = B; break; - case TFR_EXG_Post_Nybble_CC: Src_Value = CCR; break; - case TFR_EXG_Post_Nybble_DP: Src_Value = DP; break; - default: break; - } - /* read destination register */ - switch (Dest_Nybble) { - case TFR_EXG_Post_Nybble_A: Dest_Value = A; break; - case TFR_EXG_Post_Nybble_B: Dest_Value = B; break; - case TFR_EXG_Post_Nybble_CC: Dest_Value = CCR; break; - case TFR_EXG_Post_Nybble_DP: Dest_Value = DP; break; - default: break; - } - } - /* write register values */ - if (Src_Nybble <= 5 && Dest_Nybble <= 5) { - /* 16-bit register */ - /* write source register */ - switch (Src_Nybble) { - case TFR_EXG_Post_Nybble_D: - A = Dest_Value >> 8; - B = Dest_Value & 0XFF; - break; - case TFR_EXG_Post_Nybble_X: IX = Dest_Value; break; - case TFR_EXG_Post_Nybble_Y: IY = Dest_Value; break; - case TFR_EXG_Post_Nybble_U: UP = Dest_Value; break; - case TFR_EXG_Post_Nybble_S: SP = Dest_Value; break; - case TFR_EXG_Post_Nybble_PC: PC = Dest_Value; break; - default: break; - } - /* write destination register */ - switch (Dest_Nybble) { - case TFR_EXG_Post_Nybble_D: - A = Src_Value >> 8; - B = Src_Value & 0XFF; - break; - case TFR_EXG_Post_Nybble_X: IX = Src_Value; break; - case TFR_EXG_Post_Nybble_Y: IY = Src_Value; break; - case TFR_EXG_Post_Nybble_U: UP = Src_Value; break; - case TFR_EXG_Post_Nybble_S: SP = Src_Value; break; - case TFR_EXG_Post_Nybble_PC: PC = Src_Value; break; - default: break; - } - } - if ((Src_Nybble >= 8 && Src_Nybble <= 11) && (Dest_Nybble >= 8 && Dest_Nybble <= 11)) { - /* 8-bit register */ - /* write source register */ - switch (Src_Nybble) { - case TFR_EXG_Post_Nybble_A: A = Dest_Value; break; - case TFR_EXG_Post_Nybble_B: B = Dest_Value; break; - case TFR_EXG_Post_Nybble_CC: CCR = Dest_Value; break; - case TFR_EXG_Post_Nybble_DP: DP = Dest_Value; break; - default: break; - } - /* write destination register */ - switch (Dest_Nybble) { - case TFR_EXG_Post_Nybble_A: A = Src_Value; break; - case TFR_EXG_Post_Nybble_B: B = Src_Value; break; - case TFR_EXG_Post_Nybble_CC: CCR = Src_Value; break; - case TFR_EXG_Post_Nybble_DP: DP = Src_Value; break; - default: break; - } - } - break; - - case 0x1F: /* TFR imm */ - Post_Byte = get_imm_byte_val(); - Dest_Nybble = Post_Byte & 0x0F; - Src_Nybble = Post_Byte >> 4; - if ((Src_Nybble <= 5 && Dest_Nybble > 5) || (Src_Nybble > 5 && Dest_Nybble <= 5)) { - // TFR with unaligned register sizes - reason = STOP_OPCODE; - } - - - if ((Src_Nybble <= 5) && (Dest_Nybble <= 5)) { - /* 16-bit registers */ - /* read source register */ - switch (Src_Nybble) { - case TFR_EXG_Post_Nybble_D: Src_Value = (A << 8) | (B & 0xFF); break; - case TFR_EXG_Post_Nybble_X: Src_Value = IX; break; - case TFR_EXG_Post_Nybble_Y: Src_Value = IY; break; - case TFR_EXG_Post_Nybble_U: Src_Value = UP; break; - case TFR_EXG_Post_Nybble_S: Src_Value = SP; break; - case TFR_EXG_Post_Nybble_PC: Src_Value = PC; break; - break; - } - /* write source register */ - switch (Dest_Nybble) { - case TFR_EXG_Post_Nybble_D: - A = Src_Value >> 8; - B = Src_Value & 0XFF; - break; - case TFR_EXG_Post_Nybble_X: IX = Src_Value; break; - case TFR_EXG_Post_Nybble_Y: IY = Src_Value; break; - case TFR_EXG_Post_Nybble_U: UP = Src_Value; break; - case TFR_EXG_Post_Nybble_S: SP = Src_Value; break; - case TFR_EXG_Post_Nybble_PC: PC = Src_Value;; break; - break; - } - } - if ((Src_Nybble >= 8 && Src_Nybble <= 11) && (Dest_Nybble >= 8 && Dest_Nybble <= 11)) { - /* 8-bit registers */ - /* read the source register */ - switch (Src_Nybble) { - case TFR_EXG_Post_Nybble_A: Src_Value = A; break; - case TFR_EXG_Post_Nybble_B: Src_Value = B; break; - case TFR_EXG_Post_Nybble_CC: Src_Value = CCR; break; - case TFR_EXG_Post_Nybble_DP: Src_Value = DP; break; - break; - } - /* write the destination register */ - switch (Dest_Nybble) { - case TFR_EXG_Post_Nybble_A: A = Src_Value; break; - case TFR_EXG_Post_Nybble_B: B = Src_Value; break; - case TFR_EXG_Post_Nybble_CC: CCR = Src_Value; break; - case TFR_EXG_Post_Nybble_DP: DP = Src_Value; break; - break; - } - } - break; - -/* 0x20 - relative mode */ - case 0x20: /* BRA rel */ - go_rel(1); - break; - case 0x21: /* BRN rel */ - /* Branch Never - essentially a NOP */ - go_rel(0); - break; - case 0x22: /* BHI rel */ - go_rel(!(get_flag(CF) | get_flag(ZF))); - break; - case 0x23: /* BLS rel */ - go_rel(get_flag(CF) | get_flag(ZF)); - break; - case 0x24: /* BCC rel */ - go_rel(!get_flag(CF)); - break; - case 0x25: /* BCS rel */ - go_rel(get_flag(CF)); - break; - case 0x26: /* BNE rel */ - go_rel(!get_flag(ZF)); - break; - case 0x27: /* BEQ rel */ - go_rel(get_flag(ZF)); - break; - case 0x28: /* BVC rel */ - go_rel(!get_flag(VF)); - break; - case 0x29: /* BVS rel */ - go_rel(get_flag(VF)); - break; - case 0x2A: /* BPL rel */ - go_rel(!get_flag(NF)); - break; - case 0x2B: /* BMI rel */ - go_rel(get_flag(NF)); - break; - case 0x2C: /* BGE rel */ - go_rel(!(get_flag(NF) ^ get_flag(VF))); - break; - case 0x2D: /* BLT rel */ - go_rel(get_flag(NF) ^ get_flag(VF)); - break; - case 0x2E: /* BGT rel */ - go_rel( !( get_flag(ZF) | (get_flag(NF) ^ get_flag(VF)) ) ); - break; - case 0x2F: /* BLE rel */ - go_rel( get_flag(ZF) | (get_flag(NF) ^ get_flag(VF)) ); - break; - -/* 0x30 */ - case 0x30: /* LEAX */ - IX = get_indexed_addr(); - COND_SET_FLAG_Z_16(IX); - break; - - case 0x31: /* LEAY */ - IY = get_indexed_addr(); - COND_SET_FLAG_Z_16(IY); - break; - - case 0x32: /* LEAS */ - SP = get_indexed_addr(); - /* does not affect CCR */ - break; - - case 0x33: /* LEAU */ - UP = get_indexed_addr(); - /* does not affect CCR */ - break; - - case 0x34: /* PSHS */ - Post_Byte = get_imm_byte_val(); - if (Post_Byte & PSH_PUL_Post_Byte_PC) push_sp_word(PC); - if (Post_Byte & PSH_PUL_Post_Byte_S_U) push_sp_word(UP); - if (Post_Byte & PSH_PUL_Post_Byte_Y) push_sp_word(IY); - if (Post_Byte & PSH_PUL_Post_Byte_X) push_sp_word(IX); - if (Post_Byte & PSH_PUL_Post_Byte_DP) push_sp_byte(DP); - if (Post_Byte & PSH_PUL_Post_Byte_B) push_sp_byte(B); - if (Post_Byte & PSH_PUL_Post_Byte_A) push_sp_byte(A); - if (Post_Byte & PSH_PUL_Post_Byte_CC) push_sp_byte(CCR); - break; - - case 0x35: /* PULS */ - Post_Byte = get_imm_byte_val(); - if (Post_Byte & PSH_PUL_Post_Byte_CC) CCR = pop_sp_byte(); - if (Post_Byte & PSH_PUL_Post_Byte_A) A = pop_sp_byte(); - if (Post_Byte & PSH_PUL_Post_Byte_B) B = pop_sp_byte(); - if (Post_Byte & PSH_PUL_Post_Byte_DP) DP = pop_sp_byte(); - if (Post_Byte & PSH_PUL_Post_Byte_X) IX = pop_sp_word(); - if (Post_Byte & PSH_PUL_Post_Byte_Y) IY = pop_sp_word(); - if (Post_Byte & PSH_PUL_Post_Byte_S_U) UP = pop_sp_word(); - if (Post_Byte & PSH_PUL_Post_Byte_PC) PC = pop_sp_word(); - break; - - case 0x36: /* PSHU */ - Post_Byte = get_imm_byte_val(); - if (Post_Byte & PSH_PUL_Post_Byte_PC) push_up_word(PC); - if (Post_Byte & PSH_PUL_Post_Byte_S_U) push_up_word(SP); - if (Post_Byte & PSH_PUL_Post_Byte_Y) push_up_word(IY); - if (Post_Byte & PSH_PUL_Post_Byte_X) push_up_word(IX); - if (Post_Byte & PSH_PUL_Post_Byte_DP) push_up_byte(DP); - if (Post_Byte & PSH_PUL_Post_Byte_B) push_up_byte(B); - if (Post_Byte & PSH_PUL_Post_Byte_A) push_up_byte(A); - if (Post_Byte & PSH_PUL_Post_Byte_CC) push_up_byte(CCR); - break; - - case 0x37: /* PULU */ - Post_Byte = get_imm_byte_val(); - if (Post_Byte & PSH_PUL_Post_Byte_CC) CCR = pop_up_byte(); - if (Post_Byte & PSH_PUL_Post_Byte_A) A = pop_up_byte(); - if (Post_Byte & PSH_PUL_Post_Byte_B) B = pop_up_byte(); - if (Post_Byte & PSH_PUL_Post_Byte_DP) DP = pop_up_byte(); - if (Post_Byte & PSH_PUL_Post_Byte_X) IX = pop_up_word(); - if (Post_Byte & PSH_PUL_Post_Byte_Y) IY = pop_up_word(); - if (Post_Byte & PSH_PUL_Post_Byte_S_U) SP = pop_up_word(); - if (Post_Byte & PSH_PUL_Post_Byte_PC) PC = pop_up_word(); - break; - - case 0x39: /* RTS */ - PC = pop_sp_word(); - break; - - case 0x3A: /* ABX */ - /* this is an UNSIGNED operation! */ - IX = (IX + B) & 0xFFFF; - /* no changes to CCR */ - break; - - case 0x3B: /* RTI */ - CCR = pop_sp_byte(); - if (GET_FLAG(EF)) { - /* entire state flag */ - A = pop_sp_byte(); - B = pop_sp_byte(); - DP = pop_sp_byte(); - IX = pop_sp_word(); - IY = pop_sp_word(); - UP = pop_sp_word(); - } - PC = pop_sp_word(); - break; - - case 0x3C: /* CWAI */ - /* AND immediate byte with CCR - CCR &= get_imm_byte_val(); - SET_FLAG(EF); - /* push register state */ - push_sp_word(PC); - push_sp_word(UP); - push_sp_word(IY); - push_sp_word(IX); - push_sp_byte(DP); - push_sp_byte(B); - push_sp_byte(A); - push_sp_byte(CCR); - if (get_flag(IF)) { - reason = STOP_HALT; - continue; - } else { - SET_FLAG(IF); - PC = CPU_BD_get_mword(0xFFFE) & ADDRMASK; - } - break; - - case 0x3D: /* MUL */ - D = A * B; - A = D >> 8; - B = D & 0xFF; - COND_SET_FLAG_Z_16(D); - COND_SET_FLAG(B & 0x80, CF); - break; - - case 0x3F: /* SWI */ - SET_FLAG(EF); - push_sp_word(PC); - push_sp_word(UP); - push_sp_word(IY); - push_sp_word(IX); - push_sp_byte(DP); - push_sp_byte(B); - push_sp_byte(A); - push_sp_byte(CCR); - SET_FLAG(FF); - SET_FLAG(IF); - PC = CPU_BD_get_mword(0xFFFA) & ADDRMASK; - break; - -/* 0x40 - inherent mode */ - case 0x40: /* NEGA */ - COND_SET_FLAG(A != 0, CF); - COND_SET_FLAG(A == 0x80, VF); - A = 0 - A; - A &= 0xFF; - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - break; - case 0x43: /* COMA */ - A = ~A; - A &= 0xFF; - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - CLR_FLAG(VF); - SET_FLAG(CF); - break; - case 0x44: /* LSRA */ - COND_SET_FLAG(A & 0x01, CF); - A = (A >> 1) & 0xFF; - CLR_FLAG(NF); - COND_SET_FLAG_Z(A); - /* H,V unaffected */ - break; - case 0x46: /* RORA */ - hi = get_flag(CF); - COND_SET_FLAG(A & 0x01, CF); - A = A >> 1; - if (hi) - A |= 0x80; - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - /* H,V unaffected */ - break; - case 0x47: /* ASRA */ - COND_SET_FLAG(A & 0x01, CF); - A = (A >> 1) | (A & 0x80); - /* H undefined */ - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - /* V unaffected */ - break; - case 0x48: /* ASLA */ - COND_SET_FLAG(A & 0x80, CF); - A = (A << 1) & 0xFF; - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); - break; - case 0x49: /* ROLA */ - hi = get_flag(CF); - COND_SET_FLAG(A & 0x80, CF); - A = (A << 1) & 0xFF; - if (hi) - A |= 0x01; - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); - break; - case 0x4A: /* DECA */ - COND_SET_FLAG(A == 0x80, VF); - A = (A - 1) & 0xFF; - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - break; - case 0x4C: /* INCA */ - COND_SET_FLAG(A == 0x7F, VF); - A = (A + 1) & 0xFF; - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - break; - case 0x4D: /* TSTA */ - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - CLR_FLAG(VF); - /* C not affected */ - break; - case 0x4F: /* CLRA */ - A = 0; - CLR_FLAG(NF); - SET_FLAG(ZF); - CLR_FLAG(VF); - CLR_FLAG(CF); - break; - -/* 0x50 - inherent modes */ - case 0x50: /* NEGB */ - COND_SET_FLAG(B != 0, CF); - COND_SET_FLAG(B == 0x80, VF); - B = (0 - B); - B &= 0xFF; - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - break; - case 0x53: /* COMB */ - B = ~B; - B &= 0xFF; - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - CLR_FLAG(VF); - SET_FLAG(CF); - break; - case 0x54: /* LSRB */ - COND_SET_FLAG(B & 0x01, CF); - B = (B >> 1) & 0xFF; - CLR_FLAG(NF); - COND_SET_FLAG_Z(B); - /* H,V unaffected */ - break; - case 0x56: /* RORB */ - hi = get_flag(CF); - COND_SET_FLAG(B & 0x01, CF); - B = B >> 1; - if (hi) - B |= 0x80; - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - /* H,V unaffected */ - break; - case 0x57: /* ASRB */ - COND_SET_FLAG(B & 0x01, CF); - B = (B >> 1) | (B & 0x80); - /* H undefined */ - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - /* C unaffected */ - break; - case 0x58: /* ASLB */ - COND_SET_FLAG(B & 0x80, CF); - B = (B << 1) & 0xFF; - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); - break; - case 0x59: /* ROLB */ - hi = get_flag(CF); - COND_SET_FLAG(B & 0x80, CF); - B = (B << 1) & 0xFF; - if (hi) - B |= 0x01; - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); - break; - case 0x5A: /* DECB */ - COND_SET_FLAG(B == 0x80, VF); - B = (B - 1) & 0xFF; - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - break; - case 0x5C: /* INCB */ - COND_SET_FLAG(B == 0x7F, VF); - B = (B + 1) & 0xFF; - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - break; - case 0x5D: /* TSTB */ - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - CLR_FLAG(VF); - /* C not affected */ - break; - case 0x5F: /* CLRB */ - B = 0; - CLR_FLAG(NF); - SET_FLAG(ZF); - CLR_FLAG(VF); - CLR_FLAG(CF); - break; - -/* 0x60 - index mode */ - case 0x60: /* NEG ind */ - addr = get_indexed_addr(); - op1 = CPU_BD_get_mbyte(addr); - COND_SET_FLAG(op1 != 0, CF); - COND_SET_FLAG(op1 == 0x80, VF); - result = (0 - op1) & 0xFF; - CPU_BD_put_mbyte(addr, result); - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - break; - case 0x63: /* COM ind */ - addr = get_indexed_addr(); - op1 = CPU_BD_get_mbyte(addr); - result = ~op1; - result &= 0xFF; - CPU_BD_put_mbyte(addr, result); - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - CLR_FLAG(VF); - SET_FLAG(CF); - break; - case 0x64: /* LSR ind */ - addr = get_indexed_addr(); - op1 = CPU_BD_get_mbyte(addr); - COND_SET_FLAG(op1 & 0x01, CF); - result = op1 >> 1; - CPU_BD_put_mbyte(addr, result); - CLR_FLAG(NF); - COND_SET_FLAG_Z(result); - /* H,V unaffected */ - break; - case 0x66: /* ROR ind */ - addr = get_indexed_addr(); - op1 = CPU_BD_get_mbyte(addr); - result = op1 >> 1; - if (get_flag(CF)) - result |= 0x80; - CPU_BD_put_mbyte(addr, result); - /* H,V unaffected */ - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - COND_SET_FLAG(op1 & 0x01, CF); - break; - case 0x67: /* ASR ind */ - addr = get_indexed_addr(); - op1 = CPU_BD_get_mbyte(addr); - result = (op1 >> 1) | (op1 & 0x80); - CPU_BD_put_mbyte(addr, result); - /* H undefined */ - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - /* V unaffected */ - COND_SET_FLAG(op1 & 0x01, CF); - break; - case 0x68: /* ASL ind */ - addr = get_indexed_addr(); - op1 = CPU_BD_get_mbyte(addr); - COND_SET_FLAG(op1 & 0x80, CF); - result = (op1 << 1) & 0xFF; - CPU_BD_put_mbyte(addr, result); - /* H is undefined */ - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); - break; - case 0x69: /* ROL ind */ - addr = get_indexed_addr(); - op1 = CPU_BD_get_mbyte(addr); - result = (op1 << 1) & 0xFF; - if (get_flag(CF)) - result |= 0x01; - CPU_BD_put_mbyte(addr, result); - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - COND_SET_FLAG((op1 & 0x80) ^ (op1 & 0x40), VF); - COND_SET_FLAG(op1 & 0x80, CF); - break; - case 0x6A: /* DEC ind */ - addr = get_indexed_addr(); - op1 = CPU_BD_get_mbyte(addr); - result = (op1 - 1) & 0xFF; - CPU_BD_put_mbyte(addr, result); - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - COND_SET_FLAG(op1 == 0x80, VF); - break; - case 0x6C: /* INC ind */ - addr = get_indexed_addr(); - op1 = CPU_BD_get_mbyte(addr); - COND_SET_FLAG(op1 == 0x7F, VF); - op1 = (op1 + 1) & 0xFF; - CPU_BD_put_mbyte(addr, op1); - COND_SET_FLAG_N(op1); - COND_SET_FLAG_Z(op1); - break; - case 0x6D: /* TST ind */ - result = get_indexed_byte_val(); - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - CLR_FLAG(VF); - break; - case 0x6E: /* JMP ind */ - PC = get_indexed_addr(); - break; - case 0x6F: /* CLR ind */ - CPU_BD_put_mbyte(get_indexed_addr(), 0); - /* H not affected */ - CLR_FLAG(NF); - SET_FLAG(ZF); - CLR_FLAG(VF); - CLR_FLAG(CF); - break; - -/* 0x70 - extended modes */ - case 0x70: /* NEG ext */ - addr= get_ext_addr(); - op1 = CPU_BD_get_mbyte(addr); - COND_SET_FLAG(op1 != 0, CF); - COND_SET_FLAG(op1 == 0x80, VF) ; - result = (0 - op1) & 0xFF; - CPU_BD_put_mbyte(addr, result); - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - break; - case 0x73: /* COM ext */ - addr = get_ext_addr(); - op1 = CPU_BD_get_mbyte(addr); - result = ~op1; - result &= 0xFF; - CPU_BD_put_mbyte(addr, result); - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - CLR_FLAG(VF); - SET_FLAG(CF); - break; - case 0x74: /* LSR ext */ - addr = get_ext_addr(); - op1 = CPU_BD_get_mbyte(addr); - COND_SET_FLAG(op1 & 0x01, CF); - result = op1 >> 1; - CPU_BD_put_mbyte(addr, result); - CLR_FLAG(NF); - COND_SET_FLAG_Z(result); - /* H,V unaffected */ - break; - case 0x76: /* ROR ext */ - addr = get_ext_addr(); - op1 = CPU_BD_get_mbyte(addr); - result = op1 >> 1; - if (get_flag(CF)) - result |= 0x80; - CPU_BD_put_mbyte(addr, result); - /* H,V unaffected */ - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - COND_SET_FLAG(op1 & 0x01, CF); - break; - case 0x77: /* ASR ext */ - addr = get_ext_addr(); - op1 = CPU_BD_get_mbyte(addr); - result = (op1 >> 1) | (op1 & 0x80); - CPU_BD_put_mbyte(addr, result); - /* H undefined */ - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - /* V unaffected */ - COND_SET_FLAG(op1 & 0x01, CF); - break; - case 0x78: /* ASL ext */ - addr = get_ext_addr(); - op1 = CPU_BD_get_mbyte(addr); - COND_SET_FLAG(op1 & 0x80, CF); - result = (op1 << 1) & 0xFF; - CPU_BD_put_mbyte(addr, result); - /* H is undefined */ - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); - break; - case 0x79: /* ROL ext */ - addr = get_ext_addr(); - op1 = CPU_BD_get_mbyte(addr); - result = (op1 << 1) & 0xFF; - if (get_flag(CF)) - result |= 0x01; - CPU_BD_put_mbyte(addr, result); - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - COND_SET_FLAG((op1 & 0x80) ^ (op1 & 0x40), VF); - COND_SET_FLAG(op1 & 0x80, CF); - break; - case 0x7A: /* DEC ext */ - addr = get_ext_addr(); - op1 = CPU_BD_get_mbyte(addr); - result = (op1 - 1) & 0xFF; - CPU_BD_put_mbyte(addr, result); - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - COND_SET_FLAG(op1 == 0x80, VF); - break; - case 0x7C: /* INC ext */ - addr = get_ext_addr(); - op1 = CPU_BD_get_mbyte(addr); - COND_SET_FLAG(op1 == 0x7F, VF); - op1 = (op1 + 1) & 0xFF; - CPU_BD_put_mbyte(addr, op1); - COND_SET_FLAG_N(op1); - COND_SET_FLAG_Z(op1); - break; - case 0x7D: /* TST ext */ - result = get_ext_byte_val(); - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - CLR_FLAG(VF); - break; - case 0x7E: /* JMP ext */ - PC = get_ext_addr(); - break; - case 0x7F: /* CLR ext */ - CPU_BD_put_mbyte(get_ext_addr(), 0); - /* H not affected */ - CLR_FLAG(NF); - SET_FLAG(ZF); - CLR_FLAG(VF); - CLR_FLAG(CF); - break; - -/* 0x80 - immediate mode (except for BSR) */ - case 0x80: /* SUBA imm */ - op1 = get_imm_byte_val(); - op2 = A; - A = A - op1; - COND_SET_FLAG_C(A); - A &= 0xFF; - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - condevalVs(op1, op2); - break; - case 0x81: /* CMPA imm */ - op2 = get_imm_byte_val(); - result = A - op2; - COND_SET_FLAG_C(result); - result &= 0xFF; - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - condevalVs(A, op2); - break; - case 0x82: /* SBCA imm */ - op1 = A; - op2 = get_imm_byte_val() + get_flag(CF); - A = A - op2; - COND_SET_FLAG_C(A); - A &= 0xFF; - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - condevalVs(op1, op2); - break; - case 0x83: /* SUBD imm */ - D = (A << 8) | (B & 0xFF); - op2 = get_imm_word_val(); - result = D - op2; - COND_SET_FLAG_C_16(result); - result &= 0xFFFF; - A = result >> 8; - B = result & 0xFF; - COND_SET_FLAG_N_16(result); - COND_SET_FLAG_Z_16(result); - condevalVs16(D, op2); - break; - case 0x84: /* ANDA imm */ - A = (A & get_imm_byte_val()) & 0xFF; - CLR_FLAG(VF); - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - break; - case 0x85: /* BITA imm */ - result = (A & get_imm_byte_val()) & 0xFF; - CLR_FLAG(VF); - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - break; - case 0x86: /* LDA imm */ - A = get_imm_byte_val(); - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - CLR_FLAG(VF); - break; - case 0x88: /* EORA imm */ - A = (A ^ get_imm_byte_val()) & 0xFF; - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - CLR_FLAG(VF); - break; - case 0x89: /* ADCA imm */ - op1 = A; - op2 = get_imm_byte_val() + get_flag(CF); - A = A + op2; - COND_SET_FLAG_C(A); - A &= 0xFF; - condevalHa(op1, op2); - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - condevalVa(op1, op2); - break; - case 0x8A: /* ORA imm */ - A = A | get_imm_byte_val(); - A &= 0xFF; - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - CLR_FLAG(VF); - break; - case 0x8B: /* ADDA imm */ - op1 = A; - op2 = get_imm_byte_val(); - A = A + op2; - COND_SET_FLAG_C(A); - A &= 0xFF; - condevalHa(op1, op2); - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - condevalVa(op1, op2); - break; - case 0x8C: /* CMPX imm */ - op2 = get_imm_word_val(); - result = IX - op2; - COND_SET_FLAG_C_16(result); - result = result & 0xFFFF; - COND_SET_FLAG_Z_16(result); - COND_SET_FLAG_N_16(result); - condevalVs16(IX, op2); - break; - case 0x8D: /* BSR rel */ - addr = get_rel_addr(); - push_sp_word(PC); - PC = (PC + addr) & ADDRMASK; - break; - case 0x8E: /* LDX imm */ - IX = get_imm_word_val(); - COND_SET_FLAG_N_16(IX); - COND_SET_FLAG_Z_16(IX); - CLR_FLAG(VF); - break; - -/* 0x90 - direct mode */ - case 0x90: /* SUBA dir */ - op1 = A; - op2 = get_dir_byte_val(); - A = A - op2; - COND_SET_FLAG_C(A); - A &= 0xFF; - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - condevalVs(op1, op2); - break; - case 0x91: /* CMPA dir */ - op2 = get_dir_byte_val(); - result = A - op2; - COND_SET_FLAG_C(result); - result &= 0xFF; - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - condevalVs(A, op2); - break; - case 0x92: /* SBCA dir */ - op1 = A; - op2 = get_dir_byte_val() + get_flag(CF); - A = A - op2; - COND_SET_FLAG_C(A); - A &= 0xFF; - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - condevalVs(op1, op2); - break; - case 0x93: /* SUBD dir */ - D = (A << 8) | (B & 0xFF); - op2 = get_dir_word_val(); - result = D - op2; - COND_SET_FLAG_C_16(result); - result &= 0xFFFF; - A = result >> 8; - B = result & 0xFF; - COND_SET_FLAG_N_16(result); - COND_SET_FLAG_Z_16(result); - condevalVs16(D, op2); - break; - case 0x94: /* ANDA dir */ - A = (A & get_dir_byte_val()) & 0xFF; - CLR_FLAG(VF); - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - break; - case 0x95: /* BITA dir */ - result = (A & get_dir_byte_val()) & 0xFF; - CLR_FLAG(VF); - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - break; - case 0x96: /* LDA dir */ - A = get_dir_byte_val(); - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - CLR_FLAG(VF); - break; - case 0x97: /* STA dir */ - CPU_BD_put_mbyte(get_dir_addr(), A); - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - CLR_FLAG(VF); - break; - case 0x98: /* EORA dir */ - A = (A ^ get_dir_byte_val()) & 0xFF; - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - CLR_FLAG(VF); - break; - case 0x99: /* ADCA dir */ - op1 = A; - op2 = get_dir_byte_val() + get_flag(CF); - A = A + op2; - COND_SET_FLAG_C(A); - A &= 0xFF; - condevalHa(op1, op2); - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - condevalVa(op1, op2); - break; - case 0x9A: /* ORA dir */ - A = A | get_dir_byte_val(); - A &= 0xFF; - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - CLR_FLAG(VF); - break; - case 0x9B: /* ADDA dir */ - op1 = A; - op2 = get_dir_byte_val(); - A = A + op2; - COND_SET_FLAG_C(A); - A &= 0xFF; - condevalHa(op1, op2); - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - condevalVa(op1, op2); - break; - case 0x9C: /* CMPX dir */ - op2 = get_dir_word_val(); - result = IX - op2; - COND_SET_FLAG_C_16(result); - result &= 0xFFFF; - COND_SET_FLAG_N_16(result); - COND_SET_FLAG_Z_16(result); - condevalVs16(IX, op2); - break; - case 0x9D: /* JSR dir */ - addr = get_dir_addr(); - push_sp_word(PC); - PC = addr; - break; - case 0x9E: /* LDX dir */ - IX = get_dir_word_val(); - COND_SET_FLAG_N_16(IX); - COND_SET_FLAG_Z_16(IX); - CLR_FLAG(VF); - break; - case 0x9F: /* STX dir */ - CPU_BD_put_mword(get_dir_addr(), IX); - COND_SET_FLAG_N_16(IX); - COND_SET_FLAG_Z_16(IX); - CLR_FLAG(VF); - break; - -/* 0xA0 - indexed mode */ - case 0xA0: /* SUBA ind */ - op1 = get_indexed_byte_val(); - result = A - op1; - A = result; - COND_SET_FLAG_C(A); - A &= 0xFF; - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - condevalVs(op1, result); - break; - case 0xA1: /* CMPA ind */ - op2 = get_indexed_byte_val(); - result = A - op2; - COND_SET_FLAG_C(result); - result &= 0xFF; - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - condevalVs(A, op2); - break; - case 0xA2: /* SBCA ind */ - op1 = A; - op2 = get_indexed_byte_val() + get_flag(CF); - A = A - op2; - COND_SET_FLAG_C(A); - A &= 0xFF; - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - condevalVs(op1, op2); - break; - case 0xA3: /* SUBD ind */ - D = (A << 8) | (B & 0xFF); - op2 = get_indexed_word_val(); - result = D - op2; - COND_SET_FLAG_C_16(result); - result &= 0xFFFF; - A = result >> 8; - B = result & 0xFF; - COND_SET_FLAG_N_16(result); - COND_SET_FLAG_Z_16(result); - condevalVs16(D, op2); - break; - case 0xA4: /* ANDA ind */ - A = (A & get_indexed_byte_val()) & 0xFF; - CLR_FLAG(VF); - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - break; - case 0xA5: /* BITA ind */ - result = (A & get_indexed_byte_val()) & 0xFF; - CLR_FLAG(VF); - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - break; - case 0xA6: /* LDA ind */ - A = get_indexed_byte_val(); - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - CLR_FLAG(VF); - break; - case 0xA7: /* STA ind */ - CPU_BD_put_mbyte(get_indexed_addr(), A); - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - CLR_FLAG(VF); - break; - case 0xA8: /* EORA ind */ - A = (A ^ get_indexed_byte_val()) & 0xFF; - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - CLR_FLAG(VF); - break; - case 0xA9: /* ADCA ind */ - op1 = A; - op2 = get_indexed_byte_val() + get_flag(CF); - A = A + op2; - COND_SET_FLAG_C(A); - A &= 0xFF; - condevalHa(op1, op2); - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - condevalVa(op1, op2); - break; - case 0xAA: /* ORA ind */ - A = A | get_indexed_byte_val(); - A &= 0xFF; - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - CLR_FLAG(VF); - break; - case 0xAB: /* ADDA ind */ - op1 = A; - op2 = get_indexed_byte_val(); - A = A + op2; - COND_SET_FLAG_C(A); - A &= 0xFF; - condevalHa(op1, op2); - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - condevalVa(op1, op2); - break; - case 0xAC: /* CMPX ind */ - op2 = get_indexed_word_val(); - result = (IX - op2) & ADDRMASK; - COND_SET_FLAG_C_16(result); - result &= 0xFFFF; - COND_SET_FLAG_N_16(result); - COND_SET_FLAG_Z_16(result); - condevalVs16(IX, op2); - break; - case 0xAD: /* JSR ind */ - addr = get_indexed_addr(); - push_sp_word(PC); - PC = addr; - break; - case 0xAE: /* LDX ind */ - IX = get_indexed_word_val(); - COND_SET_FLAG_N_16(IX); - COND_SET_FLAG_Z_16(IX); - CLR_FLAG(VF); - break; - case 0xAF: /* STX ind */ - CPU_BD_put_mword(get_indexed_addr(), IX); - COND_SET_FLAG_N_16(IX); - COND_SET_FLAG_Z_16(IX); - CLR_FLAG(VF); - break; - -/* 0xB0 - extended mode */ - case 0xB0: /* SUBA ext */ - op1 = A; - op2 = get_ext_byte_val(); - A = A - op2; - COND_SET_FLAG_C(A); - A &= 0xFF; - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - condevalVs(op1, op2); - break; - case 0xB1: /* CMPA ext */ - op2 = get_ext_byte_val(); - result = A - op2; - COND_SET_FLAG_C(result); - result &= 0xFF; - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - condevalVs(A, op2); - break; - case 0xB2: /* SBCA ext */ - op1 = A; - op2 = get_ext_byte_val() + get_flag(CF); - A = A - op2; - COND_SET_FLAG_C(A); - A &= 0xFF; - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - condevalVs(op1, op2); - break; - case 0xB3: /* SUBD ext */ - D = (A << 8) | (B & 0xFF); - op2 = get_ext_word_val(); - result = D - op2; - COND_SET_FLAG_C_16(result); - result &= 0xFFFF; - A = result >> 8; - B = result & 0xFF; - COND_SET_FLAG_N_16(result); - COND_SET_FLAG_Z_16(result); - condevalVs16(D, op2); - break; - case 0xB4: /* ANDA ext */ - A = (A & get_ext_byte_val()) & 0xFF; - CLR_FLAG(VF); - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - break; - case 0xB5: /* BITA ext */ - result = (A & get_ext_byte_val()) & 0xFF; - CLR_FLAG(VF); - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - break; - case 0xB6: /* LDA ext */ - A = get_ext_byte_val(); - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - CLR_FLAG(VF); - break; - case 0xB7: /* STA ext */ - CPU_BD_put_mbyte(get_ext_addr(), A); - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - CLR_FLAG(VF); - break; - case 0xB8: /* EORA ext */ - A = (A ^ get_ext_byte_val()) & 0xFF; - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - CLR_FLAG(VF); - break; - case 0xB9: /* ADCA ext */ - op1 = A; - op2 = get_ext_byte_val() + get_flag(CF); - A = A + op2; - COND_SET_FLAG_C(A); - A &= 0xFF; - condevalHa(op1, op2); - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - condevalVa(op1, op2); - break; - case 0xBA: /* ORA ext */ - A = A | get_ext_byte_val(); - A &= 0xFF; - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - CLR_FLAG(VF); - break; - case 0xBB: /* ADDA ext */ - op1 = A; - op2 = get_ext_byte_val(); - A = A + op2; - COND_SET_FLAG_C(A); - A &= 0xFF; - condevalHa(op1, op2); - COND_SET_FLAG_N(A); - COND_SET_FLAG_Z(A); - condevalVa(op1, op2); - break; - case 0xBC: /* CMPX ext */ - op2 = get_ext_word_val(); - result = (IX - op2); - COND_SET_FLAG_C_16(result); - result = result & 0xFFFF; - COND_SET_FLAG_N_16(result); - COND_SET_FLAG_Z_16(result); - condevalVs16(IX, op2); - break; - case 0xBD: /* JSR ext */ - addr = get_ext_addr(); - push_sp_word(PC); - PC = addr; - break; - case 0xBE: /* LDX ext */ - IX = get_ext_word_val(); - COND_SET_FLAG_N_16(IX); - COND_SET_FLAG_Z_16(IX); - CLR_FLAG(VF); - break; - case 0xBF: /* STX ext */ - CPU_BD_put_mword(get_ext_addr(), IX); - COND_SET_FLAG_N_16(IX); - COND_SET_FLAG_Z_16(IX); - CLR_FLAG(VF); - break; - -/* 0xC0 - immediate mode */ - case 0xC0: /* SUBB imm */ - op1 = B; - op2 = get_imm_byte_val(); - B = B - op2; - COND_SET_FLAG_C(B); - B &= 0xFF; - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - condevalVs(op1, op2); - break; - case 0xC1: /* CMPB imm */ - op2 = get_imm_byte_val(); - result = B - op2; - COND_SET_FLAG_C(result); - result &= 0xFF; - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - condevalVs(B, op2); - break; - case 0xC2: /* SBCB imm */ - op1 = B; - op2 = get_imm_byte_val() + get_flag(CF); - B = B - op2; - COND_SET_FLAG_C(B); - B &= 0xFF; - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - condevalVs(op1, op2); - break; - case 0xC3: /* ADDD imm */ - op1 = (A << 8) | (B & 0xFF); - op2 = get_imm_word_val(); - D = op1 + op2; - COND_SET_FLAG_C_16(D); - D &= 0xFFFF; - A = D >> 8; - B = D & 0xFF; - COND_SET_FLAG_N_16(D); - COND_SET_FLAG_Z_16(D); - condevalVa16(op1,op2); - break; - case 0xC4: /* ANDB imm */ - B = (B & get_imm_byte_val()) & 0xFF; - CLR_FLAG(VF); - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - break; - case 0xC5: /* BITB imm */ - result = (B & get_imm_byte_val()) & 0xFF; - CLR_FLAG(VF); - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - break; - case 0xC6: /* LDB imm */ - B = get_imm_byte_val(); - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - CLR_FLAG(VF); - break; - case 0xC8: /* EORB imm */ - B = (B ^ get_imm_byte_val()) & 0xFF; - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - CLR_FLAG(VF); - break; - case 0xC9: /* ADCB imm */ - op1 = B; - op2 = get_imm_byte_val() + get_flag(CF); - B = B + op2; - COND_SET_FLAG_C(B); - B &= 0xFF; - condevalHa(op1, op2); - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - condevalVa(op1, op2); - break; - case 0xCA: /* ORB imm */ - B = B | get_imm_byte_val(); - B &= 0xFF; - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - CLR_FLAG(VF); - break; - case 0xCB: /* ADDB imm */ - op1 = B; - op2 = get_imm_byte_val(); - B = B + op2; - COND_SET_FLAG_C(B); - B &= 0xFF; - condevalHa(op1, op2); - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - condevalVa(op1, op2); - break; - case 0xCC: /* LDD imm */ - D = get_imm_word_val(); - A = D >> 8; - B = D & 0xFF; - COND_SET_FLAG_N_16(D); - COND_SET_FLAG_Z_16(D); - CLR_FLAG(VF); - break; - case 0xCE: /* LDU imm */ - UP = get_imm_word_val(); - COND_SET_FLAG_N_16(UP); - COND_SET_FLAG_Z_16(UP); - CLR_FLAG(VF); - break; - -/* 0xD0 - direct modes */ - case 0xD0: /* SUBB dir */ - op1 = B; - op2 = get_dir_byte_val(); - B = B - op2; - COND_SET_FLAG_C(B); - B &= 0xFF; - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - condevalVs(op1, op2); - break; - case 0xD1: /* CMPB dir */ - op2 = get_dir_byte_val(); - result = B - op2; - COND_SET_FLAG_C(result); - result &= 0xFF; - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - condevalVs(B, op2); - break; - case 0xD2: /* SBCB dir */ - op1 = B; - op2 = get_dir_byte_val() + get_flag(CF); - B = B - op2; - COND_SET_FLAG_C(B); - B &= 0xFF; - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - condevalVs(op1, op2); - break; - case 0xD3: /* ADDD dir */ - op1 = (A << 8) | (B & 0xFF); - op2 = get_dir_word_val(); - D = op1 + op2; - COND_SET_FLAG_C_16(D); - D &= 0xFFFF; - A = D >> 8; - B = D & 0xFF; - COND_SET_FLAG_N_16(D); - COND_SET_FLAG_Z_16(D); - condevalVa16(op1, op2); - break; - case 0xD4: /* ANDB dir */ - B = (B & get_dir_byte_val()) & 0xFF; - CLR_FLAG(VF); - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - break; - case 0xD5: /* BITB dir */ - result = (B & get_dir_byte_val()) & 0xFF; - CLR_FLAG(VF); - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - break; - case 0xD6: /* LDB dir */ - B = get_dir_byte_val(); - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - CLR_FLAG(VF); - break; - case 0xD7: /* STB dir */ - CPU_BD_put_mbyte(get_dir_addr(), B); - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - CLR_FLAG(VF); - break; - case 0xD8: /* EORB dir */ - B = (B ^ get_dir_byte_val()) & 0xFF; - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - CLR_FLAG(VF); - break; - case 0xD9: /* ADCB dir */ - op1 = B; - op2 = get_dir_byte_val() + get_flag(CF); - B = B + op2; - COND_SET_FLAG_C(B); - B &= 0xFF; - condevalHa(op1, op2); - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - condevalVa(op1, op2); - break; - case 0xDA: /* ORB dir */ - B = B | get_dir_byte_val(); - B &= 0xFF; - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - CLR_FLAG(VF); - break; - case 0xDB: /* ADDB dir */ - op1 = B; - op2 = get_dir_byte_val(); - B = B + op2; - COND_SET_FLAG_C(B); - B &= 0xFF; - condevalHa(op1, op2); - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - condevalVa(op1, op2); - break; - case 0xDC: /* LDD dir */ - D = get_dir_word_val(); - A = D >> 8; - B = D & 0xFF; - COND_SET_FLAG_N_16(D); - COND_SET_FLAG_Z_16(D); - CLR_FLAG(VF); - break; - case 0xDD: /* STD dir */ - D = (A << 8) | (B & 0xFF); - CPU_BD_put_mword(get_dir_addr(), D); - COND_SET_FLAG_N_16(D); - COND_SET_FLAG_Z_16(D); - CLR_FLAG(VF); - break; - case 0xDE: /* LDU dir */ - UP = get_dir_word_val(); - COND_SET_FLAG_N_16(UP); - COND_SET_FLAG_Z_16(UP); - CLR_FLAG(VF); - break; - case 0xDF: /* STU dir */ - CPU_BD_put_mword(get_dir_addr(), UP); - COND_SET_FLAG_N_16(UP); - COND_SET_FLAG_Z_16(UP); - CLR_FLAG(VF); - break; - -/* 0xE0 - indexed mode */ - case 0xE0: /* SUBB ind */ - op1 = B; - op2 = get_indexed_byte_val(); - B = B - op2; - COND_SET_FLAG_C(B); - B &= 0xFF; - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - condevalVs(op1, op2); - break; - case 0xE1: /* CMPB ind */ - op2 = get_indexed_byte_val(); - result = B - op2; - COND_SET_FLAG_C(result); - result &= 0xFF; - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - condevalVs(B, op2); - break; - case 0xE2: /* SBCB ind */ - op1 = B; - op2 = get_indexed_byte_val() + get_flag(CF); - B = B - op2; - COND_SET_FLAG_C(B); - B &= 0xFF; - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - condevalVs(op1, op2); - break; - case 0xE3: /* ADDD ind */ - op1 = (A << 8) | (B & 0xFF); - op2 = get_indexed_word_val(); - D = op1 + op2; - COND_SET_FLAG_C_16(D); - D &= 0xFFFF; - A = D >> 8; - B = D & 0xFF; - COND_SET_FLAG_N_16(D); - COND_SET_FLAG_Z_16(D); - condevalVa16(op1, op2); - break; - case 0xE4: /* ANDB ind */ - B = (B & get_indexed_byte_val()) & 0xFF; - CLR_FLAG(VF); - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - break; - case 0xE5: /* BITB ind */ - result = (B & get_indexed_byte_val()) & 0xFF; - CLR_FLAG(VF); - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - break; - case 0xE6: /* LDB ind */ - B = get_indexed_byte_val(); - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - CLR_FLAG(VF); - break; - case 0xE7: /* STB ind */ - CPU_BD_put_mbyte(get_indexed_addr(), B); - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - CLR_FLAG(VF); - break; - case 0xE8: /* EORB ind */ - B = (B ^ get_indexed_byte_val()) & 0xFF; - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - CLR_FLAG(VF); - break; - case 0xE9: /* ADCB ind */ - op1 = B; - op2 = get_indexed_byte_val() + get_flag(CF); - B = B + op2; - COND_SET_FLAG_C(B); - B &= 0xFF; - condevalHa(op1, op2); - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - condevalVa(op1, op2); - break; - case 0xEA: /* ORB ind */ - B = B | get_indexed_byte_val(); - B &= 0xFF; - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - CLR_FLAG(VF); - break; - case 0xEB: /* ADDB ind */ - op1 = B; - op2 = get_indexed_byte_val(); - B = B + op2; - COND_SET_FLAG_C(B); - B &= 0xFF; - condevalHa(op1, op2); - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - condevalVa(op1, op2); - break; - case 0xEC: /* LDD ind */ - D = get_indexed_word_val(); - A = D >> 8; - B = D & 0xFF; - COND_SET_FLAG_N_16(D); - COND_SET_FLAG_Z_16(D); - CLR_FLAG(VF); - break; - case 0xED: /* STD ind */ - D = (A << 8) | (B & 0xFF); - CPU_BD_put_mword(get_indexed_addr(), D); - COND_SET_FLAG_N_16(D); - COND_SET_FLAG_Z_16(D); - CLR_FLAG(VF); - break; - case 0xEE: /* LDU ind */ - UP = get_indexed_word_val(); - COND_SET_FLAG_N_16(UP); - COND_SET_FLAG_Z_16(UP); - CLR_FLAG(VF); - break; - case 0xEF: /* STU ind */ - CPU_BD_put_mword(get_indexed_addr(), UP); - COND_SET_FLAG_N_16(UP); - COND_SET_FLAG_Z_16(UP); - CLR_FLAG(VF); - break; - -/* 0xF0 - extended mode */ - case 0xF0: /* SUBB ext */ - op1 = B; - op2 = get_ext_byte_val(); - B = B - op2; - COND_SET_FLAG_C(B); - B &= 0xFF; - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - condevalVs(op1, op2); - break; - case 0xF1: /* CMPB ext */ - op2 = get_ext_byte_val(); - result = B - op2; - COND_SET_FLAG_C(result); - result &= 0xFF; - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - condevalVs(B, op2); - break; - case 0xF2: /* SBCB ext */ - op1 = B; - op2 = get_ext_byte_val() + get_flag(CF); - B = B - op2; - COND_SET_FLAG_C(B); - B &= 0xFF; - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - condevalVs(op1, op2); - break; - case 0xF3: /* ADDD ext */ - op1 = (A << 8) | (B & 0xFF); - op2 = get_ext_word_val(); - D = op1 + op2; - COND_SET_FLAG_C_16(D); - D &= 0xFFFF; - A = D >> 8; - B = D & 0xFF; - COND_SET_FLAG_N_16(D); - COND_SET_FLAG_Z_16(D); - condevalVa16(op1, op2); - break; - case 0xF4: /* ANDB ext */ - B = (B & get_ext_byte_val()) & 0xFF; - CLR_FLAG(VF); - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - break; - case 0xF5: /* BITB ext */ - result = (B & get_ext_byte_val()) & 0xFF; - CLR_FLAG(VF); - COND_SET_FLAG_N(result); - COND_SET_FLAG_Z(result); - break; - case 0xF6: /* LDB ext */ - B = get_ext_byte_val(); - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - CLR_FLAG(VF); - break; - case 0xF7: /* STB ext */ - CPU_BD_put_mbyte(get_ext_addr(), B); - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - CLR_FLAG(VF); - break; - case 0xF8: /* EORB ext */ - B = (B ^ get_ext_byte_val()) & 0xFF; - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - CLR_FLAG(VF); - break; - case 0xF9: /* ADCB ext */ - op1 = B; - op2 = get_ext_byte_val() + get_flag(CF); - B = B + op2; - COND_SET_FLAG_C(B); - B &= 0xFF; - condevalHa(op1, op2); - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - condevalVa(op1, op2); - break; - case 0xFA: /* ORB ext */ - B = B | get_ext_byte_val(); - B &= 0xFF; - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - CLR_FLAG(VF); - break; - case 0xFB: /* ADDB ext */ - op1 = B; - op2 = get_ext_byte_val(); - B = B + op2; - COND_SET_FLAG_C(B); - B &= 0xFF; - condevalHa(op1, op2); - COND_SET_FLAG_N(B); - COND_SET_FLAG_Z(B); - condevalVa(op1, op2); - break; - case 0xFC: /* LDD ext */ - D = get_ext_word_val(); - A = D >> 8; - B = D & 0xFF; - COND_SET_FLAG_N_16(D); - COND_SET_FLAG_Z_16(D); - CLR_FLAG(VF); - break; - case 0xFD: /* STD ext */ - D = (A << 8) | (B & 0xFF); - CPU_BD_put_mword(get_ext_addr(), D); - COND_SET_FLAG_N_16(D); - COND_SET_FLAG_Z_16(D); - CLR_FLAG(VF); - break; - case 0xFE: /* LDU ext */ - UP = get_ext_word_val(); - COND_SET_FLAG_N_16(UP); - COND_SET_FLAG_Z_16(UP); - CLR_FLAG(VF); - break; - case 0xFF: /* STU ext */ - CPU_BD_put_mword(get_ext_addr(), UP); - COND_SET_FLAG_N_16(UP); - COND_SET_FLAG_Z_16(UP); - CLR_FLAG(VF); - break; - - default: /* Unassigned */ - if (m6809_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(void) -{ - printf("\r\nPC=%04X SP=%04X UP=%04X IX=%04X IY=%04X ", PC, SP, UP, IX, IY); - printf("A=%02X B=%02X DP=%02X CCR=%02X", A, B, DP, CCR); -} - -void dump_regs1(void) -{ - printf("PC=%04X SP=%04X UP=%04X IX=%04X IY=%04X ", PC, SP, UP, IX, IY); - printf("A=%02X B=%02X DP=%02X CCR=%02X\n", A, B, DP, CCR); -} - -/* fetch an instruction or byte */ -int32 fetch_byte(int32 flag) -{ - uint8 val; - - val = CPU_BD_get_mbyte(PC); /* fetch byte */ - switch (flag) { - case 0: /* opcode fetch */ - sim_debug (DEBUG_asm, &m6809_dev, "%04X %s\n", PC, opcode[val]); - break; - case 1: /* byte operand fetch */ - sim_debug (DEBUG_asm, &m6809_dev, "0x%02XH\n", val); - break; - } - PC = (PC + 1) & ADDRMASK; /* increment PC */ - return val; -} - -/* fetch a word - big endian */ -int32 fetch_word() -{ - uint16 val; - - val = CPU_BD_get_mbyte(PC) << 8; /* fetch high byte */ - val |= (CPU_BD_get_mbyte(PC + 1)); /* fetch low byte */ - - /* 2-byte operand fetch */ - sim_debug (DEBUG_asm, &m6809_dev, "0x%04XH\n", val); - - PC = (PC + 2) & ADDRMASK; /* increment PC */ - return val; -} - -/* push a byte using the hardware stack pointer (SP) */ -void push_sp_byte(uint8 val) -{ - SP = (SP - 1) & ADDRMASK; - CPU_BD_put_mbyte(SP, val & 0xFF); -} - -/* push a byte using the user stack pointer (UP) */ -void push_up_byte(uint8 val) -{ - UP = (UP - 1) & ADDRMASK; - CPU_BD_put_mbyte(UP, val & 0xFF); -} - -/* push a word using the hardware stack pointer (SP) */ -void push_sp_word(uint16 val) -{ - push_sp_byte(val & 0xFF); - push_sp_byte(val >> 8); -} - -/* push a word using the user stack pointer (UP) */ -void push_up_word(uint16 val) -{ - push_up_byte(val & 0xFF); - push_up_byte(val >> 8); -} - -/* pop a byte using the hardware stack pointer (SP) */ -uint8 pop_sp_byte(void) -{ - register uint8 res; - - res = CPU_BD_get_mbyte(SP); - SP = (SP + 1) & ADDRMASK; - return res; -} - -/* pop a byte using the user stack pointer (UP) */ -uint8 pop_up_byte(void) -{ - register uint8 res; - - res = CPU_BD_get_mbyte(UP); - UP = (UP + 1) & ADDRMASK; - return res; -} - -/* pop a word using the hardware stack pointer (SP) */ -uint16 pop_sp_word(void) -{ - register uint16 res; - - res = pop_sp_byte() << 8; - res |= pop_sp_byte(); - return res; -} - -/* pop a word using the user stack pointer (UP) */ -uint16 pop_up_word(void) -{ - register uint16 res; - - res = pop_up_byte() << 8; - res |= pop_up_byte(); - return res; -} - -/* 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; - } -} - -/* this routine does the jump to long relative offset if the condition is met. Otherwise, execution continues at the current PC. */ -void go_long_rel(int32 cond) -{ - int32 temp; - - temp = get_long_rel_addr(); - if (cond != 0) { - PC += temp; - PC &= ADDRMASK; - } -} - -/* returns the relative offset sign-extended */ -int32 get_rel_addr(void) -{ - int32 temp; - - temp = fetch_byte(1); - if (temp & 0x80) - temp |= 0xFF00; - return temp & ADDRMASK; -} - -/* returns the long relative offset sign-extended */ -int32 get_long_rel_addr(void) -{ - return fetch_word(); -} - -/* returns the byte value at the direct address pointed to by PC */ -int32 get_dir_byte_val(void) -{ - return CPU_BD_get_mbyte(get_dir_addr()); -} - -/* returns the word value at the direct address pointed to by PC */ -int32 get_dir_word_val(void) -{ - return CPU_BD_get_mword(get_dir_addr()); -} - -/* returns the immediate byte value pointed to by PC */ -int32 get_imm_byte_val(void) -{ - return fetch_byte(1); -} - -/* returns the immediate word value pointed to by PC */ -int32 get_imm_word_val(void) -{ - return fetch_word(); -} - -/* returns the direct address pointed to by PC */ -/* use the Direct Page register as the high byte of the address */ -int32 get_dir_addr(void) -{ - int32 temp; - - temp = (DP << 8) + fetch_byte(1); - return temp & 0xFFFF; -} - -/* returns the byte value at the indexed address pointed to by PC */ -int32 get_indexed_byte_val(void) -{ - return CPU_BD_get_mbyte(get_indexed_addr()); -} - -/* returns the word value at the indexed address pointed to by PC */ -int32 get_indexed_word_val(void) -{ - return CPU_BD_get_mword(get_indexed_addr()); -} - -/* returns the indexed address. Note this also handles the indirect indexed mode */ -int32 get_indexed_addr(void) -{ - int32 temp; - int32 offset; - uint8 post_byte; - - /* fetch the index mode post-byte */ - post_byte = fetch_byte(1); - - if ((post_byte & 0x80) == 0) { - /* R +- 4-bit offset (non indirect only) */ - /* read register value */ - switch (post_byte & 0x60) { - case 0b00000000: temp = IX; break; - case 0b00100000: temp = IY; break; - case 0b01000000: temp = UP; break; - case 0b01100000: temp = SP; break; - default: break; - } - /* add 4 bit signed offset */ - if (post_byte & 0x10) { - /* subtract offset */ - offset = (post_byte | 0xFFF0); - temp += offset; - } else { - /* add offset */ - temp += (post_byte & 0x0F); - } - } else { - switch ( post_byte & 0x0F ) { - case 0b0000: - /* .R+ post increment by 1 (non indirect) */ - switch ( post_byte & 0x60 ) { - case 0b00000000: temp = IX++; IX &= 0xFFFF; break; - case 0b00100000: temp = IY++; IY &= 0xFFFF; break; - case 0b01000000: temp = UP++; UP &= 0xFFFF; break; - case 0b01100000: temp = SP++; SP &= 0xFFFF; break; - default: break; - }; - break; - case 0b0001: - /* .R+ post increment by 2 (non indirect) */ - switch ( post_byte & 0x60 ) { - case 0b00000000: temp = IX; IX=IX+2; IX &= 0xFFFF; break; - case 0b00100000: temp = IY; IY=IY+2; IY &= 0xFFFF; break; - case 0b01000000: temp = UP; UP=UP+2; UP &= 0xFFFF; break; - case 0b01100000: temp = SP; SP=SP+2; SP &= 0xFFFF; break; - default: break; - }; - break; - case 0b0010: - /* .-R pre decrement by 1 (non indirect) */ - switch ( post_byte & 0x60 ) { - case 0b00000000: temp = --IX; IX &= 0xFFFF; break; - case 0b00100000: temp = --IY; IY &= 0xFFFF; break; - case 0b01000000: temp = --UP; UP &= 0xFFFF; break; - case 0b01100000: temp = --SP; SP &= 0xFFFF; break; - default: break; - }; - break; - case 0b0011: - /* .--R pre decrement by 2 (non indirect) */ - switch ( post_byte & 0x60 ) { - case 0b00000000: IX-=2; temp = IX; IX &= 0xFFFF; break; - case 0b00100000: IY-=2; temp = IY; IY &= 0xFFFF; break; - case 0b01000000: UP-=2; temp = UP; UP &= 0xFFFF; break; - case 0b01100000: SP-=2; temp = SP; SP &= 0xFFFF; break; - default: break; - }; - break; - case 0b0100: - /* R+0 zero offset (non indirect) */ - switch ( post_byte & 0x60 ) { - case 0b00000000: temp = IX; break; - case 0b00100000: temp = IY; break; - case 0b01000000: temp = UP; break; - case 0b01100000: temp = SP; break; - default: break; - }; - break; - case 0b0101: - /* R+-ACCB (non indirect)*/ - if (B & 0x80) { - offset = B | 0xFF80; - } else { - offset = B; - } - switch ( post_byte & 0x60 ) { - case 0b00000000: temp = IX; break; - case 0b00100000: temp = IY; break; - case 0b01000000: temp = UP; break; - case 0b01100000: temp = SP; break; - default: break; - }; - temp += offset; - break; - case 0b0110: - /* R+-ACCA (non indirect)*/ - if (A & 0x80) { - offset = A | 0xFF80; - } else { - offset = A; - } - switch ( post_byte & 0x60 ) { - case 0b00000000: temp = IX; break; - case 0b00100000: temp = IY; break; - case 0b01000000: temp = UP; break; - case 0b01100000: temp = SP; break; - default: break; - }; - temp += offset; - break; - case 0b1000: - /* R+- 8-bit offset */ - switch ( post_byte & 0x60 ) { - case 0b00000000: temp = IX; break; - case 0b00100000: temp = IY; break; - case 0b01000000: temp = UP; break; - case 0b01100000: temp = SP; break; - default: break; - }; - /* need to fetch 8-bit operand */ - offset = fetch_byte(1); - - /* add 7 bit signed offset */ - if (offset & 0x80) { - /* subtract offset */ - offset |= 0xFF00; - } - temp += offset; - break; - case 0b1001: - /* R+- 16-bit offset */ - switch ( post_byte & 0x60 ) { - case 0b00000000: temp = IX; break; - case 0b00100000: temp = IY; break; - case 0b01000000: temp = UP; break; - case 0b01100000: temp = SP; break; - default: break; - }; - /* need to fetch 16-bit operand */ - offset = fetch_word(); - - /* add 16 bit signed offset */ - temp += offset; - break; - case 0b1011: - /* R+- ACCD */ - D = (A << 8) + (B & 0xFF); - switch ( post_byte & 0x60 ) { - case 0b00000000: temp = IX + D; break; - case 0b00100000: temp = IY + D; break; - case 0b01000000: temp = UP + D; break; - case 0b01100000: temp = SP + D; break; - default: break; - }; - break; - case 0b1100: - /* PC+- 7-bit offset (non indirect) */ - /* need to fetch 8-bit operand */ - offset = fetch_byte(1); - // PC value after fetch!!! - temp = PC; - - /* add 7 bit signed offset */ - if (offset & 0x80) { - /* subtract offset */ - offset |= 0xFF00; - } - temp += offset; - break; - case 0b1101: - /* PC+- 15-bit offset (non indirect)*/ - /* need to fetch 16-bit operand */ - offset = fetch_word(); - // PC value after fetch!!! - temp = PC; - - /* add 15 bit signed offset */ - temp += offset; - break; - case 0b1111: - // Extended indirect - fetch 16-bit address - temp = fetch_word(); - break; - } - switch ( post_byte & 0x1F ) { - /* perform the indirection - 11 valid post-byte opcodes */ - case 0b10001: - case 0b10011: - case 0b10100: - case 0b10101: - case 0b10110: - case 0b11000: - case 0b11001: - case 0b11011: - case 0b11100: - case 0b11101: - case 0b11111: - temp = temp & 0xFFFF; - temp = CPU_BD_get_mword(temp); - break; - default: break; - } - } - /* make sure to truncate to 16-bit value */ - return temp & 0xFFFF; -} - -/* returns the value at the extended address pointed to by PC */ -int32 get_ext_byte_val(void) -{ - return CPU_BD_get_mbyte(get_ext_addr()); -} - -/* returns the value at the extended address pointed to by PC */ -int32 get_ext_word_val(void) -{ - return CPU_BD_get_mword(get_ext_addr()); -} - -/* returns the extended address pointed to by PC or immediate word */ -int32 get_ext_addr(void) -{ - int32 temp; - - temp = fetch_word(); - return temp; -} - -/* return 1 for flag set or 0 for flag clear */ -int32 get_flag(int32 flg) -{ - if (CCR & flg) { - return 1; - } - else { - return 0; - } -} - -/* test and set V for 8-addition */ -void condevalVa(int32 op1, int32 op2) -{ - if (((op1 & 0x80) == (op2 & 0x80)) && - (((op1 + op2) & 0x80) != (op1 & 0x80))) - SET_FLAG(VF); - else - CLR_FLAG(VF); -} - -/* test and set V for 16-bit addition */ -void condevalVa16(int32 op1, int32 op2) -{ - /* - IF (the sign of the 2 operands are the same) - AND - (the sum of the operands has a different sign than both of the 2 operands) - THEN set the Overflow flag - ELSE clear the Overflow flag - */ - if (((op1 & 0x8000) == (op2 & 0x8000)) && - (((op1 + op2) & 0x8000) != (op1 & 0x8000))) - SET_FLAG(VF); - else - CLR_FLAG(VF); -} - -/* test and set V for 8-bit subtraction */ -void condevalVs(int32 op1, int32 op2) -{ - if (((op1 & 0x80) != (op2 & 0x80)) && - (((op1 - op2) & 0x80) == (op2 & 0x80))) - SET_FLAG(VF); - else - CLR_FLAG(VF); - -} - -/* test and set V for 16-bit subtraction */ -void condevalVs16(int32 op1, int32 op2) -{ - if (((op1 & 0x8000) != (op2 & 0x8000)) && - (((op1 - op2) & 0x8000) == (op2 & 0x8000))) - SET_FLAG(VF); - else - CLR_FLAG(VF); - -} - -/* test and set H for addition (8-bit only) */ -void condevalHa(int32 op1, int32 op2) -{ - if (((op1 & 0x0f) + (op2 & 0x0f)) & 0x10) - SET_FLAG(HF); - else - CLR_FLAG(HF); -} - -/* calls from the simulator */ - -/* Boot routine */ -t_stat m6809_boot(int32 unit_num, DEVICE *dptr) -{ - /* retrieve the reset vector at $FFFE */ - saved_PC = CPU_BD_get_mword(0xFFFE); - if (saved_PC == 0xFFFF) { - ; // No BOOT ROM detected! - } - return SCPE_OK; -} - -/* Reset routine */ -t_stat m6809_reset (DEVICE *dptr) -{ - CCR = EF | FF | IF; - DP = 0; - int_req = 0; - sim_brk_types = sim_brk_dflt = SWMASK ('E'); - - /* retrieve the reset vector at $FFFE */ - saved_PC = CPU_BD_get_mword(0xFFFE); - if (saved_PC == 0xFFFF) { - ; // No BOOT ROM detected! - } - return SCPE_OK; -} - -/* examine routine */ -t_stat m6809_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) -{ - if (addr >= 0x10000) { - /* exceed 16-bit address space */ - return SCPE_NXM; - } else { - *eval_array = CPU_BD_get_mbyte(addr); - return SCPE_OK; - } -} - -/* deposit routine */ -t_stat m6809_deposit(t_value value, t_addr addr, UNIT *uptr, int32 switches) -{ - if (addr >= 0x10000) { - /* exceed 16-bit address space */ - return SCPE_NXM; - } else { - CPU_BD_put_mbyte(addr, value); - return SCPE_OK; - } -} - - -/* This is the dumper/loader. This command uses the -h to signify a - hex dump/load vice a binary one. If no address is given to load, it - takes the address from the hex record or the current PC for binary. -*/ - -t_stat sim_load (FILE *fileref, CONST char *cptr, CONST char *fnam, int flag) -{ - int32 i, addr = 0, cnt = 0; - - if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; - addr = saved_PC; - while ((i = getc (fileref)) != EOF) { - CPU_BD_put_mbyte(addr, i); - addr++; - cnt++; - } // end while - printf ("%d Bytes loaded.\n", cnt); - return (SCPE_OK); -} - -/* Symbolic output - - Inputs: - *of = output stream - addr = current PC - *val = pointer to values - *uptr = pointer to unit - sw = switches - Outputs: - status = error code - for M6809 -*/ -t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) -{ - int32 i, inst, inst1; - - if (sw & SWMASK ('D')) { // dump memory - for (i=0; i<16; i++) - fprintf(of, "%02X ", val[i]); - fprintf(of, " "); - for (i=0; i<16; i++) - if (isprint(val[i])) - fprintf(of, "%c", val[i]); - else - fprintf(of, "."); - return -15; - } else if (sw & SWMASK ('M')) { // dump instruction mnemonic - inst = val[0]; - if (!oplen[inst]) { // invalid opcode - fprintf(of, "%02X", inst); - return 0; - } - inst1 = inst & 0xF0; - fprintf (of, "%s", opcode[inst]); // mnemonic - if (strlen(opcode[inst]) == 3) - fprintf(of, " "); - if (inst1 == 0x20 || inst == 0x8D) { // rel operand - inst1 = val[1]; - if (val[1] & 0x80) - inst1 |= 0xFF00; - fprintf(of, " $%04X", (addr + inst1 + 2) & ADDRMASK); - } else if (inst1 == 0x80 || inst1 == 0xC0) { // imm operand - if ((inst & 0x0F) < 0x0C) - fprintf(of, " #$%02X", val[1]); - else - fprintf(of, " #$%02X%02X", val[1], val[2]); - } else if (inst1 == 0x60 || inst1 == 0xA0 || inst1 == 0xE0) // ind operand - fprintf(of, " %d,X", val[1]); - else if (inst1 == 0x70 || inst1 == 0xb0 || inst1 == 0xF0) // ext operand - fprintf(of, " $%02X%02X", val[1], val[2]); - return (-(oplen[inst] - 1)); - } else - return SCPE_ARG; -} - -/* Symbolic input - - Inputs: - *cptr = pointer to input string - addr = current PC - *uptr = pointer to unit - *val = pointer to output values - sw = switches - Outputs: - status = error status -*/ -t_stat parse_sym (CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) -{ - return (-2); -} - -/* end of m6809.c */ +/* 6809.c: SWTP 6809 CPU simulator + + Copyright (c) 2005-2012, William Beech + + Permission is hereby granted, free of charge, to any person obtaining a + /opy 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. + + The following copyright notice applies to the SWTP 6809 source, binary, and documentation: + + Original code published in 2024, written by Richard F Lukes + Copyright (c) 2024, Richard F Lukes + + 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 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 names of The Authors shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the Authors. + + MODIFICATIONS: + + 23 Apr 15 -- Modified to use simh_debug + 21 Apr 20 -- Richard Brinegar numerous fixes for flag errors + 24 Feb 24 -- Richard Lukes - modified for 6809 + + NOTES: + cpu Motorola M6809 CPU + + The register state for the M6809 CPU is: + + A<0:7> Accumulator A + B<0:7> Accumulator B + IX<0:15> Index Register + IY<0:15> Index Register + CCR<0:7> Condition Code Register + EF Entire flag + FF FIRQ flag + HF half-carry flag + IF IRQ flag + NF negative flag + ZF zero flag + VF overflow flag + CF carry flag + PC<0:15> program counter + UP<0:15> User Stack Pointer + SP<0:15> Stack Pointer + + The M6809 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 M6809. + It is called from the CPU board simulator 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 6809, reads to non-existent memory + return 0FFH, and writes are ignored. +*/ + +#include + +#include "swtp_defs.h" + +#define UNIT_V_OPSTOP (UNIT_V_UF) /* Stop on Invalid Opcode */ +#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP) + +/* Flag values to set proper positions in CCR */ +#define EF 0x80 +#define FF 0x40 +#define HF 0x20 +#define IF 0x10 +#define NF 0x08 +#define ZF 0x04 +#define VF 0x02 +#define CF 0x01 + +/* PSH/PUL Post Byte register positions */ +#define PSH_PUL_Post_Byte_PC 0x80 +#define PSH_PUL_Post_Byte_S_U 0x40 +#define PSH_PUL_Post_Byte_Y 0x20 +#define PSH_PUL_Post_Byte_X 0x10 +#define PSH_PUL_Post_Byte_DP 0x08 +#define PSH_PUL_Post_Byte_B 0x04 +#define PSH_PUL_Post_Byte_A 0x02 +#define PSH_PUL_Post_Byte_CC 0x01 + +#define TFR_EXG_Post_Nybble_D 0 +#define TFR_EXG_Post_Nybble_X 1 +#define TFR_EXG_Post_Nybble_Y 2 +#define TFR_EXG_Post_Nybble_U 3 +#define TFR_EXG_Post_Nybble_S 4 +#define TFR_EXG_Post_Nybble_PC 5 +#define TFR_EXG_Post_Nybble_A 8 +#define TFR_EXG_Post_Nybble_B 9 +#define TFR_EXG_Post_Nybble_CC 10 +#define TFR_EXG_Post_Nybble_DP 11 + + +/* Macros to handle the flags in the CCR */ +#define CCR_MSK (EF|FF|HF|IF|NF|ZF|VF|CF) +#define TOGGLE_FLAG(FLAG) (CCR ^= (FLAG)) +#define SET_FLAG(FLAG) (CCR |= (FLAG)) +#define CLR_FLAG(FLAG) (CCR &= ~(FLAG)) +#define GET_FLAG(FLAG) (CCR & (FLAG)) + +#define COND_SET_FLAG(COND,FLAG) \ + if (COND) SET_FLAG(FLAG); else CLR_FLAG(FLAG) + +#define COND_SET_FLAG_N(VAR) \ + if ((VAR) & 0x80) SET_FLAG(NF); else CLR_FLAG(NF) +#define COND_SET_FLAG_N_16(VAR) \ + if ((VAR) & 0x8000) SET_FLAG(NF); else CLR_FLAG(NF) + +#define COND_SET_FLAG_Z(VAR) \ + if ((VAR) == 0) SET_FLAG(ZF); else CLR_FLAG(ZF) +#define COND_SET_FLAG_Z_16(VAR) \ + if ((VAR) == 0) SET_FLAG(ZF); else CLR_FLAG(ZF) + +#define COND_SET_FLAG_H(VAR) \ + if ((VAR) & 0x10) SET_FLAG(HF); else CLR_FLAG(HF) + +#define COND_SET_FLAG_C(VAR) \ + if ((VAR) & 0x100) SET_FLAG(CF); else CLR_FLAG(CF) +#define COND_SET_FLAG_C_16(VAR) \ + if ((VAR) & 0x10000) SET_FLAG(CF); else CLR_FLAG(CF) + +#define COND_SET_FLAG_V(COND) \ + if (COND) SET_FLAG(VF); else CLR_FLAG(VF) + +/* local global variables */ + +int32 A = 0; /* Accumulator A */ +int32 B = 0; /* Accumulator B */ +int32 D = 0; /* Accumulator D */ +int32 DP = 0; /* Direct Page Register */ +int32 IX = 0; /* Index register X */ +int32 IY = 0; /* Index register Y */ +int32 UP = 0; /* User Stack pointer */ +int32 SP = 0; /* Hardware Stack pointer */ +int32 CCR = EF|FF|IF; /* Condition Code Register */ +int32 saved_PC = 0; /* Saved Program counter */ +int32 previous_PC = 0; /* Previous previous Program counter */ +int32 last_PC = 0; /* Last Program counter */ +int32 PC; /* Program counter */ +int32 INTE = 0; /* Interrupt Enable */ +int32 int_req = 0; /* Interrupt request */ + +int32 mem_fault = 0; /* memory fault flag */ + +/* function prototypes */ + +t_stat m6809_reset(DEVICE *dptr); +t_stat m6809_boot(int32 unit_num, DEVICE *dptr); +t_stat m6809_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); +t_stat m6809_deposit(t_value value, t_addr addr, UNIT *uptr, int32 switches); + +void dump_regs(void); +void dump_regs1(void); +int32 fetch_byte(int32 flag); +int32 fetch_word(); +uint8 pop_sp_byte(void); +uint8 pop_up_byte(void); +uint16 pop_sp_word(void); +uint16 pop_up_word(void); +void push_sp_byte(uint8 val); +void push_up_byte(uint8 val); +void push_sp_word(uint16 val); +void push_up_word(uint16 val); +void go_rel(int32 cond); +void go_long_rel(int32 cond); +int32 get_rel_addr(void); +int32 get_long_rel_addr(void); +int32 get_dir_byte_val(void); +int32 get_dir_word_val(void); +int32 get_imm_byte_val(void); +int32 get_imm_word_val(void); +int32 get_dir_addr(void); +int32 get_indexed_byte_val(void); +int32 get_indexed_word_val(void); +int32 get_indexed_addr(void); +int32 get_ext_addr(void); +int32 get_ext_byte_val(void); +int32 get_ext_word_val(void); +int32 get_flag(int32 flag); +void condevalVa(int32 op1, int32 op2); +void condevalVa16(int32 op1, int32 op2); +void condevalVs(int32 op1, int32 op2); +void condevalVs16(int32 op1, int32 op2); +void condevalHa(int32 op1, int32 op2); + +/* external routines */ + +extern void CPU_BD_put_mbyte(int32 addr, int32 val); +extern void CPU_BD_put_mword(int32 addr, int32 val); +extern int32 CPU_BD_get_mbyte(int32 addr); +extern int32 CPU_BD_get_mword(int32 addr); + +/* CPU data structures + + m6809_dev CPU device descriptor + m6809_unit CPU unit descriptor + m6809_reg CPU register list + m6809_mod CPU modifiers list */ + +UNIT m6809_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, 65536) }; + +REG m6809_reg[] = { + { HRDATA (PC, saved_PC, 16) }, + { HRDATA (A, A, 8) }, + { HRDATA (B, B, 8) }, + { HRDATA (DP, DP, 8) }, + { HRDATA (IX, IX, 16) }, + { HRDATA (IY, IY, 16) }, + { HRDATA (SP, SP, 16) }, + { HRDATA (UP, UP, 16) }, + { HRDATA (CCR, CCR, 8) }, + { FLDATA (INTE, INTE, 16) }, + { ORDATA (WRU, sim_int_char, 8) }, + { NULL } }; + +MTAB m6809_mod[] = { + { UNIT_OPSTOP, UNIT_OPSTOP, "ITRAP", "ITRAP", NULL }, + { UNIT_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL }, + { 0 } }; + +DEBTAB m6809_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { "REG", DEBUG_reg }, + { "ASM", DEBUG_asm }, + { NULL } +}; + +DEVICE m6809_dev = { + "CPU", //name + &m6809_unit, //units + m6809_reg, //registers + m6809_mod, //modifiers + 1, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + &m6809_examine, //examine + &m6809_deposit, //deposit + &m6809_reset, //reset + &m6809_boot, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + m6809_debug, //debflags + NULL, //msize + NULL //lname +}; + +static const char *opcode[] = { +"NEG", "???", "???", "COM", //0x00 +"LSR", "???", "ROR", "ASR", +"ASL", "ROL", "DEC", "???", +"INC", "TST", "JMP", "CLR", +"PG2", "PG3", "NOP", "SYNC", //0x10 +"???", "???", "LBRA", "LBSR", +"???", "DAA", "ORCC", "???", +"ANDCC", "SEX", "EXG", "TFR", +"BRA", "BRN", "BHI", "BLS", //0x20 +"BCC", "BLO", "BNE", "BEQ", +"BVC", "BVS", "BPL", "BMI", +"BGE", "BLT", "BGT", "BLE", +"LEAX", "LEAY", "LEAS", "LEAU", //0x30 +"PSHS", "PULS", "PSHU", "PULU", +"???", "RTS", "ABX", "RTI", +"CWAI", "MUL", "???", "SWI", +"NEGA", "???", "???", "COMA", //0x40 +"LSRA", "???", "RORA", "ASRA", +"LSLA", "ROLA", "DECA", "???", +"INCA", "TSTA", "???", "CLRA", +"NEGB", "???", "???", "COMB", //0x50 +"LSRB", "???", "RORB", "ASRB", +"LSLB", "ROLB", "DECB", "???", +"INCB", "TSTB", "???", "CLRB", +"NEG", "???", "???", "COM", //0x60 +"LSR", "???", "ROR", "ASR", +"ASL", "ROL", "DEC", "???", +"INC", "TST", "JMP", "CLR", +"NEG", "???", "???", "COM", //0x70 +"LSR", "???", "ROR", "ASR", +"ASL", "ROL", "DEC", "???", +"INC", "TST", "JMP", "CLR", +"SUBA", "CMPA", "SBCA", "SUBD", //0x80 +"ANDA", "BITA", "LDA", "???", +"EORA", "ADCA", "ORAA", "ADDA", +"CMPX", "BSR", "LDX", "???", +"SUBA", "CMPA", "SBCA", "SUBD", //0x90 +"ANDA", "BITA", "LDA", "STA", +"EORA", "ADCA", "ORA", "ADDA", +"CMPX", "JSR", "LDX", "STX", +"SUBA", "CMPA", "SBCA", "SUBD", //0xA0 +"ANDA", "BITA", "LDA", "STA", +"EORA", "ADCA", "ORA", "ADDA", +"CMPX", "JSR", "LDX", "STX", +"SUBA", "CMPA", "SBCA", "SUBD", //0xB0 +"ANDA", "BITA", "LDA", "STA", +"EORA", "ADCA", "ORA", "ADDA", +"CMPX", "JSR", "LDX", "STX", +"SUBB", "CMPB", "SBCB", "ADDD", //0xC0 +"ANDB", "BITB", "LDB", "???", +"EORB", "ADCB", "ORB", "ADDB", +"LDD", "???", "LDU", "???", +"SUBB", "CMPB", "SBCB", "ADDD", //0xD0 +"ANDB", "BITB", "LDB", "STB", +"EORB", "ADCB", "ORB", "ADDB", +"LDD", "STD", "LDU", "STU", +"SUBB", "CMPB", "SBCB", "ADDD", //0xE0 +"ANDB", "BITB", "LDB", "STB", +"EORB", "ADCB", "ORB", "ADDB", +"LDD", "STD", "LDU", "STU", +"SUBB", "CMPB", "SBCB", "ADDD", //0xF0 +"ANDB", "BITB", "LDB", "STB", +"EORB", "ADCB", "ORB", "ADDB", +"LDD", "STD", "LDU", "STU" +}; + +static const char *opcode6800[] = { +"???", "NOP", "???", "???", //0x00 +"???", "???", "TAP", "TPA", +"INX", "DEX", "CLV", "SEV", +"CLC", "SEC", "CLI", "SEI", +"SBA", "CBA", "???", "???", //0x10 +"???", "???", "TAB", "TBA", +"???", "DAA", "???", "ABA", +"???", "???", "???", "???", +"BRA", "???", "BHI", "BLS", //0x20 +"BCC", "BCS", "BNE", "BEQ", +"BVC", "BVS", "BPL", "BMI", +"BGE", "BLT", "BGT", "BLE", +"TSX", "INS", "PULA", "PULB", //0x30 +"DES", "TXS", "PSHA", "PSHB", +"???", "RTS", "???", "RTI", +"???", "???", "WAI", "SWI", +"NEGA", "???", "???", "COMA", //0x40 +"LSRA", "???", "RORA", "ASRA", +"ASLA", "ROLA", "DECA", "???", +"INCA", "TSTA", "???", "CLRA", +"NEGB", "???", "???", "COMB", //0x50 +"LSRB", "???", "RORB", "ASRB", +"ASLB", "ROLB", "DECB", "???", +"INCB", "TSTB", "???", "CLRB", +"NEG", "???", "???", "COM", //0x60 +"LSR", "???", "ROR", "ASR", +"ASL", "ROL", "DEC", "???", +"INC", "TST", "JMP", "CLR", +"NEG", "???", "???", "COM", //0x70 +"LSR", "???", "ROR", "ASR", +"ASL", "ROL", "DEC", "???", +"INC", "TST", "JMP", "CLR", +"SUBA", "CMPA", "SBCA", "???", //0x80 +"ANDA", "BITA", "LDAA", "???", +"EORA", "ADCA", "ORAA", "ADDA", +"CMPX", "BSR", "LDS", "???", +"SUBA", "CMPA", "SBCA", "???", //0x90 +"ANDA", "BITA", "LDAA", "STAA", +"EORA", "ADCA", "ORAA", "ADDA", +"CMPX", "???", "LDS", "STS", +"SUBA", "CMPA", "SBCA", "???", //0xA0 +"ANDA", "BITA", "LDAA", "STAA", +"EORA", "ADCA", "ORAA", "ADDA", +"CMPX X", "JSR X", "LDS X", "STS X", +"SUBA", "CMPA", "SBCA", "???", //0xB0 +"ANDA", "BITA", "LDAA", "STAA", +"EORA", "ADCA", "ORAA", "ADDA", +"CPX", "JSR", "LDS", "STS", +"SUBB", "CMPB", "SBCB", "???", //0xC0 +"ANDB", "BITB", "LDAB", "???", +"EORB", "ADCB", "ORAB", "ADDB", +"???", "???", "LDX", "???", +"SUBB", "CMPB", "SBCB", "???", //0xD0 +"ANDB", "BITB", "LDAB", "STAB", +"EORB", "ADCB", "ORAB", "ADDB", +"???", "???", "LDX", "STX", +"SUBB", "CMPB", "SBCB", "???", //0xE0 +"ANDB", "BITB", "LDAB", "STAB", +"EORB", "ADCB", "ORAB", "ADDB", +"???", "???", "LDX", "STX", +"SUBB", "CMPB", "SBCB", "???", //0xF0 +"ANDB", "BITB", "LDAB", "STAB", +"EORB", "ADCB", "ORAB", "ADDB", +"???", "???", "LDX", "STX" +}; + +int32 oplen[256] = { +0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1, //0x00 +1,1,0,0,0,0,1,1,0,1,0,1,0,0,0,0, +2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +1,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1, +1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, //0x40 +1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, +2,0,0,2,2,0,2,2,2,2,2,0,2,2,2,2, +3,0,0,3,3,0,3,3,3,3,3,0,3,3,3,3, +2,2,2,0,2,2,2,0,2,2,2,2,3,2,3,0, //0x80 +2,2,2,0,2,2,2,2,2,2,2,2,2,0,2,2, +2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2, +3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3, +2,2,2,0,2,2,2,0,2,2,2,2,0,0,3,0, //0xC0 +2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, +2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, +3,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3 +}; + +int32 oplen6800[256] = { +0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1, //0x00 +1,1,0,0,0,0,1,1,0,1,0,1,0,0,0,0, +2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +1,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1, +1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, //0x40 +1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, +2,0,0,2,2,0,2,2,2,2,2,0,2,2,2,2, +3,0,0,3,3,0,3,3,3,3,3,0,3,3,3,3, +2,2,2,0,2,2,2,0,2,2,2,2,3,2,3,0, //0x80 +2,2,2,0,2,2,2,2,2,2,2,2,2,0,2,2, +2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2, +3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3, +2,2,2,0,2,2,2,0,2,2,2,2,0,0,3,0, //0xC0 +2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, +2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, +3,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3 +}; + +t_stat sim_instr (void) +{ + int32 reason; + int32 IR; + int32 OP; + int32 OP2; /* Used for 2-byte opcodes */ + + int32 hi; /* hi bit/nybble/byte */ + int32 lo; /* lo bit/nybble/byte */ + int32 op1; /* operand #1 */ + int32 op2; /* operand #2 - used for CC evaluation */ + int32 result; /* temporary value */ + int32 addr; /* temporary address value */ + + /* used for 6809 instruction decoding - TFT, EXG, PSH, PUL*/ + int32 Post_Byte = 0; + int32 Src_Nybble = 0; + int32 Dest_Nybble = 0; + int32 Src_Value = 0; + int32 Dest_Value = 0; + + PC = saved_PC & ADDRMASK; /* load local PC */ + reason = 0; + + /* Main instruction fetch/decode loop */ + + while (reason == 0) { /* loop until halted */ +// dump_regs1(); + 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? */ + /* 6809 interrupts not implemented yet. None were used, + on a standard SWTP 6809. All I/O is programmed. */ + reason = STOP_HALT; /* stop simulation */ + break; + + } /* end interrupt */ + if (sim_brk_summ && + sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; + } + + sim_interval--; + last_PC = previous_PC; + previous_PC = PC; + IR = OP = fetch_byte(0); /* fetch instruction */ + + /* The Big Instruction Decode Switch */ + + switch (IR) { + +/* 0x00 - direct mode */ + case 0x00: /* NEG dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 != 0, CF); + COND_SET_FLAG(op1 == 0x80, VF); + result = 0 - op1; + result &= 0xFF; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0x03: /* COM dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = ~op1; + result &= 0xFF; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + CLR_FLAG(VF); + SET_FLAG(CF); + break; + case 0x04: /* LSR dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 & 0x01, CF); + result = op1 >> 1; + CPU_BD_put_mbyte(addr, result); + CLR_FLAG(NF); + COND_SET_FLAG_Z(result); + /* H,V not affected */ + break; + case 0x06: /* ROR dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = op1 >> 1; + if (get_flag(CF)) { + result |= 0x80; + } + CPU_BD_put_mbyte(addr, result); + /* H,V unaffected */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(op1 & 0x01, CF); + break; + case 0x07: /* ASR dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 >> 1) | (op1 & 0x80); + CPU_BD_put_mbyte(addr, result); + /* H undefined */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + /* V not affected */ + COND_SET_FLAG(op1 & 0x01, CF); + break; + case 0x08: /* ASL dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 & 0x80, CF); + result = (op1 << 1) & BYTEMASK; + CPU_BD_put_mbyte(addr, result); + /* H is undefined */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x09: /* ROL dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 << 1) & BYTEMASK; + if (get_flag(CF)) { + result |= 0x01; + } + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG((op1 & 0x80) ^ (op1 & 0x40), VF); + COND_SET_FLAG(op1 & 0x80, CF); + break; + case 0x0A: /* DEC dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1-1) & BYTEMASK; + CPU_BD_put_mbyte(addr, result); + /* H not affected */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(op1 == 0x80, VF); + /* C not affected */ + break; + case 0x0C: /* INC dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 == 0x7F, VF); + op1 = (op1 + 1) & BYTEMASK; + CPU_BD_put_mbyte(addr, op1); + COND_SET_FLAG_N(op1); + COND_SET_FLAG_Z(op1); + break; + case 0x0D: /* TST dir */ + result = get_dir_byte_val(); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + CLR_FLAG(VF); + break; + case 0x0E: /* JMP dir */ + PC = get_dir_addr(); + break; + case 0x0F: /* CLR dir */ + CPU_BD_put_mbyte(get_dir_addr(), 0); + /* H not affected */ + CLR_FLAG(NF); + SET_FLAG(ZF); + CLR_FLAG(VF); + CLR_FLAG(CF); + break; + +/* 0x10 */ + case 0x10: /* 2-byte opcodes */ + /* fetch second byte of opcode */ + OP2 = fetch_byte(0); + switch (OP2) { + case 0x21: /* LBRN rel */ + /* Branch Never - essentially a NOP */ + go_long_rel(0); + break; + case 0x22: /* LBHI rel */ + go_long_rel(!(get_flag(CF) | get_flag(ZF))); + break; + case 0x23: /* LBLS rel */ + go_long_rel(get_flag(CF) | get_flag(ZF)); + break; + case 0x24: /* LBCC rel */ + go_long_rel(!get_flag(CF)); + break; + case 0x25: /* LBCS rel */ + go_long_rel(get_flag(CF)); + break; + case 0x26: /* LBNE rel */ + go_long_rel(!get_flag(ZF)); + break; + case 0x27: /* LBEQ rel */ + go_long_rel(get_flag(ZF)); + break; + case 0x28: /* LBVC rel */ + go_long_rel(!get_flag(VF)); + break; + case 0x29: /* LBVS rel */ + go_long_rel(get_flag(VF)); + break; + case 0x2A: /* LBPL rel */ + go_long_rel(!get_flag(NF)); + break; + case 0x2B: /* LBMI rel */ + go_long_rel(get_flag(NF)); + break; + case 0x2C: /* LBGE rel */ + go_long_rel( !( get_flag(NF) ^ get_flag(VF) ) ); + break; + case 0x2D: /* LBLT rel */ + go_long_rel( get_flag(NF) ^ get_flag(VF) ); + break; + case 0x2E: /* LBGT rel */ + go_long_rel(!( get_flag(ZF) | (get_flag(NF) ^ get_flag(VF)))); + break; + case 0x2F: /* LBLE rel */ + go_long_rel(get_flag(ZF) | (get_flag(NF) ^ get_flag(VF))); + break; + case 0x3F: /* SWI2 */ + SET_FLAG(EF); + push_sp_word(PC); + push_sp_word(UP); + push_sp_word(IY); + push_sp_word(IX); + push_sp_byte(DP); + push_sp_byte(B); + push_sp_byte(A); + push_sp_byte(CCR); + PC = CPU_BD_get_mword(0xFFF4) & ADDRMASK; + break; + case 0x83: /* CMPD imm */ + D = (A << 8) | (B & BYTEMASK); + op2 = get_imm_word_val(); + result = D - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x8C: /* CMPY imm */ + op2 = get_imm_word_val(); + result = IY - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IY, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x8E: /* LDY imm */ + IY = get_imm_word_val(); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0x93: /* CMPD dir */ + D = (A << 8) | (B & BYTEMASK); + op2 = get_dir_word_val(); + result = D - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x9C: /* CMPY dir */ + op2 = get_dir_word_val(); + result = IY - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IY, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x9E: /* LDY dir */ + IY = get_dir_word_val(); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0x9F: /* STY dir */ + CPU_BD_put_mword(get_dir_addr(), IY); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0xA3: /* CMPD ind */ + D = (A << 8) | (B & BYTEMASK); + op2 = get_indexed_word_val(); + result = D - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xAC: /* CMPY ind */ + op2 = get_indexed_word_val(); + result = IY - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IY, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xAE: /* LDY ind */ + IY = get_indexed_word_val(); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0xAF: /* STY ind */ + CPU_BD_put_mword(get_indexed_addr(), IY); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0xB3: /* CMPD ext */ + D = (A << 8) | (B & BYTEMASK); + op2 = get_ext_word_val(); + result = D - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xBC: /* CMPY ext */ + op2 = get_ext_word_val(); + result = IY - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IY, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xBE: /* LDY ext */ + IY = get_ext_word_val(); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0xBF: /* STY ext */ + CPU_BD_put_mword(get_ext_addr(), IY); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0xCE: /* LDS imm */ + SP = get_imm_word_val(); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + case 0xDE: /* LDS dir */ + SP = get_dir_word_val(); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + case 0xDF: /* STS dir */ + CPU_BD_put_mword(get_dir_addr(), SP); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + case 0xEE: /* LDS ind */ + SP = get_indexed_word_val(); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + case 0xEF: /* STS ind */ + CPU_BD_put_mword(get_indexed_addr(), SP); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + case 0xFE: /* LDS ext */ + SP = get_ext_word_val(); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + case 0xFF: /* STS ext */ + CPU_BD_put_mword(get_ext_addr(), SP); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + } + break; + +/* Ox11 */ + case 0x11: /* 2-byte opcodes */ + /* fetch second byte of opcode */ + OP2 = fetch_byte(0); + switch (OP2) { + case 0x3F: /* SWI3 */ + SET_FLAG(EF); + push_sp_word(PC); + push_sp_word(UP); + push_sp_word(IY); + push_sp_word(IX); + push_sp_byte(DP); + push_sp_byte(B); + push_sp_byte(A); + push_sp_byte(CCR); + PC = CPU_BD_get_mword(0xFFF2) & ADDRMASK; + break; + case 0x83: /* CMPU imm */ + op2 = get_imm_word_val(); + result = UP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(UP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x8C: /* CMPS imm */ + op2 = get_imm_word_val(); + result = SP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(SP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x93: /* CMPU dir */ + op2 = get_dir_word_val(); + result = UP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(UP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x9C: /* CMPS dir */ + op2 = get_dir_word_val(); + result = SP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(SP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xA3: /* CMPU ind */ + op2 = get_indexed_word_val(); + result = UP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(UP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xAC: /* CMPS ind */ + op2 = get_indexed_word_val(); + result = SP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(SP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xB3: /* CMPU ext */ + op2 = get_ext_word_val(); + result = UP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(UP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xBC: /* CMPS ext */ + op2 = get_ext_word_val(); + result = SP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(SP, op2); + COND_SET_FLAG_C_16(result); + break; + } + break; + case 0x12: /* NOP */ + break; + case 0x13: /* SYNC inherent*/ + /* Interrupts are not implemented */ + reason = STOP_HALT; /* stop simulation */ + break; + case 0x16: /* LBRA relative */ + go_long_rel(1); + break; + case 0x17: /* LBSR relative */ + addr = get_long_rel_addr(); + push_sp_word(PC); + PC = (PC + addr) & ADDRMASK; + break; + case 0x19: /* DAA inherent */ + lo = A & 0x0F; + if ((lo > 9) || get_flag(HF)) { + lo += 6; + A = (A & 0xF0) + lo; + COND_SET_FLAG(lo & 0x10, HF); + } + hi = (A >> 4) & 0x0F; + if ((hi > 9) || get_flag(CF)) { + hi += 6; + A = (A & 0x0F) | (hi << 4) | 0x100; + } + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + + case 0x1A: /* ORCC imm */ + CCR = CCR | get_imm_byte_val(); + break; + case 0x1C: /* ANDCC imm */ + CCR = CCR & get_imm_byte_val(); + break; + case 0x1D: /* SEX inherent */ + if (B & 0x80) { + A = 0xFF; + } else { + A = 0; + } + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0x1E: /* EXG imm */ + Post_Byte = get_imm_byte_val(); + Src_Nybble = (Post_Byte >> 4) & 0x0F; + Dest_Nybble = Post_Byte & 0x0F; + if ((Src_Nybble <= 5 && Dest_Nybble > 5) || (Src_Nybble > 5 && Dest_Nybble <= 5)) { + // EXG with unaligned register sizes + reason = STOP_OPCODE; + } + + /* read register values */ + if (Src_Nybble <= 5 && Dest_Nybble <= 5) { + /* 16-bit register */ + /* read source register */ + switch (Src_Nybble) { + case TFR_EXG_Post_Nybble_D: Src_Value = (A << 8) | (B & BYTEMASK); break; + case TFR_EXG_Post_Nybble_X: Src_Value = IX; break; + case TFR_EXG_Post_Nybble_Y: Src_Value = IY; break; + case TFR_EXG_Post_Nybble_U: Src_Value = UP; break; + case TFR_EXG_Post_Nybble_S: Src_Value = SP; break; + case TFR_EXG_Post_Nybble_PC: Src_Value = PC; break; + default: break; + } + /* read destination register */ + switch (Dest_Nybble) { + case TFR_EXG_Post_Nybble_D: Dest_Value = (A << 8) | (B & BYTEMASK); break; + case TFR_EXG_Post_Nybble_X: Dest_Value = IX; break; + case TFR_EXG_Post_Nybble_Y: Dest_Value = IY; break; + case TFR_EXG_Post_Nybble_U: Dest_Value = UP; break; + case TFR_EXG_Post_Nybble_S: Dest_Value = SP; break; + case TFR_EXG_Post_Nybble_PC: Dest_Value = PC; break; + default: break; + } + } + if ((Src_Nybble >= 8 && Src_Nybble <= 11) && (Dest_Nybble >= 8 && Dest_Nybble <= 11)) { + /* 8-bit register read */ + /* read source register */ + switch (Src_Nybble) { + case TFR_EXG_Post_Nybble_A: Src_Value = A; break; + case TFR_EXG_Post_Nybble_B: Src_Value = B; break; + case TFR_EXG_Post_Nybble_CC: Src_Value = CCR; break; + case TFR_EXG_Post_Nybble_DP: Src_Value = DP; break; + default: break; + } + /* read destination register */ + switch (Dest_Nybble) { + case TFR_EXG_Post_Nybble_A: Dest_Value = A; break; + case TFR_EXG_Post_Nybble_B: Dest_Value = B; break; + case TFR_EXG_Post_Nybble_CC: Dest_Value = CCR; break; + case TFR_EXG_Post_Nybble_DP: Dest_Value = DP; break; + default: break; + } + } + /* write register values */ + if (Src_Nybble <= 5 && Dest_Nybble <= 5) { + /* 16-bit register */ + /* write source register */ + switch (Src_Nybble) { + case TFR_EXG_Post_Nybble_D: + A = Dest_Value >> 8; + B = Dest_Value & 0XFF; + break; + case TFR_EXG_Post_Nybble_X: IX = Dest_Value; break; + case TFR_EXG_Post_Nybble_Y: IY = Dest_Value; break; + case TFR_EXG_Post_Nybble_U: UP = Dest_Value; break; + case TFR_EXG_Post_Nybble_S: SP = Dest_Value; break; + case TFR_EXG_Post_Nybble_PC: PC = Dest_Value; break; + default: break; + } + /* write destination register */ + switch (Dest_Nybble) { + case TFR_EXG_Post_Nybble_D: + A = Src_Value >> 8; + B = Src_Value & 0XFF; + break; + case TFR_EXG_Post_Nybble_X: IX = Src_Value; break; + case TFR_EXG_Post_Nybble_Y: IY = Src_Value; break; + case TFR_EXG_Post_Nybble_U: UP = Src_Value; break; + case TFR_EXG_Post_Nybble_S: SP = Src_Value; break; + case TFR_EXG_Post_Nybble_PC: PC = Src_Value; break; + default: break; + } + } + if ((Src_Nybble >= 8 && Src_Nybble <= 11) && (Dest_Nybble >= 8 && Dest_Nybble <= 11)) { + /* 8-bit register */ + /* write source register */ + switch (Src_Nybble) { + case TFR_EXG_Post_Nybble_A: A = Dest_Value; break; + case TFR_EXG_Post_Nybble_B: B = Dest_Value; break; + case TFR_EXG_Post_Nybble_CC: CCR = Dest_Value; break; + case TFR_EXG_Post_Nybble_DP: DP = Dest_Value; break; + default: break; + } + /* write destination register */ + switch (Dest_Nybble) { + case TFR_EXG_Post_Nybble_A: A = Src_Value; break; + case TFR_EXG_Post_Nybble_B: B = Src_Value; break; + case TFR_EXG_Post_Nybble_CC: CCR = Src_Value; break; + case TFR_EXG_Post_Nybble_DP: DP = Src_Value; break; + default: break; + } + } + break; + + case 0x1F: /* TFR imm */ + Post_Byte = get_imm_byte_val(); + Dest_Nybble = Post_Byte & 0x0F; + Src_Nybble = Post_Byte >> 4; + if ((Src_Nybble <= 5 && Dest_Nybble > 5) || (Src_Nybble > 5 && Dest_Nybble <= 5)) { + // TFR with unaligned register sizes + reason = STOP_OPCODE; + } + + + if ((Src_Nybble <= 5) && (Dest_Nybble <= 5)) { + /* 16-bit registers */ + /* read source register */ + switch (Src_Nybble) { + case TFR_EXG_Post_Nybble_D: Src_Value = (A << 8) | (B & BYTEMASK); break; + case TFR_EXG_Post_Nybble_X: Src_Value = IX; break; + case TFR_EXG_Post_Nybble_Y: Src_Value = IY; break; + case TFR_EXG_Post_Nybble_U: Src_Value = UP; break; + case TFR_EXG_Post_Nybble_S: Src_Value = SP; break; + case TFR_EXG_Post_Nybble_PC: Src_Value = PC; break; + break; + } + /* write source register */ + switch (Dest_Nybble) { + case TFR_EXG_Post_Nybble_D: + A = Src_Value >> 8; + B = Src_Value & 0XFF; + break; + case TFR_EXG_Post_Nybble_X: IX = Src_Value; break; + case TFR_EXG_Post_Nybble_Y: IY = Src_Value; break; + case TFR_EXG_Post_Nybble_U: UP = Src_Value; break; + case TFR_EXG_Post_Nybble_S: SP = Src_Value; break; + case TFR_EXG_Post_Nybble_PC: PC = Src_Value;; break; + break; + } + } + if ((Src_Nybble >= 8 && Src_Nybble <= 11) && (Dest_Nybble >= 8 && Dest_Nybble <= 11)) { + /* 8-bit registers */ + /* read the source register */ + switch (Src_Nybble) { + case TFR_EXG_Post_Nybble_A: Src_Value = A; break; + case TFR_EXG_Post_Nybble_B: Src_Value = B; break; + case TFR_EXG_Post_Nybble_CC: Src_Value = CCR; break; + case TFR_EXG_Post_Nybble_DP: Src_Value = DP; break; + break; + } + /* write the destination register */ + switch (Dest_Nybble) { + case TFR_EXG_Post_Nybble_A: A = Src_Value; break; + case TFR_EXG_Post_Nybble_B: B = Src_Value; break; + case TFR_EXG_Post_Nybble_CC: CCR = Src_Value; break; + case TFR_EXG_Post_Nybble_DP: DP = Src_Value; break; + break; + } + } + break; + +/* 0x20 - relative mode */ + case 0x20: /* BRA rel */ + go_rel(1); + break; + case 0x21: /* BRN rel */ + /* Branch Never - essentially a NOP */ + go_rel(0); + break; + case 0x22: /* BHI rel */ + go_rel(!(get_flag(CF) | get_flag(ZF))); + break; + case 0x23: /* BLS rel */ + go_rel(get_flag(CF) | get_flag(ZF)); + break; + case 0x24: /* BCC rel */ + go_rel(!get_flag(CF)); + break; + case 0x25: /* BCS rel */ + go_rel(get_flag(CF)); + break; + case 0x26: /* BNE rel */ + go_rel(!get_flag(ZF)); + break; + case 0x27: /* BEQ rel */ + go_rel(get_flag(ZF)); + break; + case 0x28: /* BVC rel */ + go_rel(!get_flag(VF)); + break; + case 0x29: /* BVS rel */ + go_rel(get_flag(VF)); + break; + case 0x2A: /* BPL rel */ + go_rel(!get_flag(NF)); + break; + case 0x2B: /* BMI rel */ + go_rel(get_flag(NF)); + break; + case 0x2C: /* BGE rel */ + go_rel(!(get_flag(NF) ^ get_flag(VF))); + break; + case 0x2D: /* BLT rel */ + go_rel(get_flag(NF) ^ get_flag(VF)); + break; + case 0x2E: /* BGT rel */ + go_rel( !( get_flag(ZF) | (get_flag(NF) ^ get_flag(VF)) ) ); + break; + case 0x2F: /* BLE rel */ + go_rel( get_flag(ZF) | (get_flag(NF) ^ get_flag(VF)) ); + break; + +/* 0x30 */ + case 0x30: /* LEAX */ + IX = get_indexed_addr(); + COND_SET_FLAG_Z_16(IX); + break; + + case 0x31: /* LEAY */ + IY = get_indexed_addr(); + COND_SET_FLAG_Z_16(IY); + break; + + case 0x32: /* LEAS */ + SP = get_indexed_addr(); + /* does not affect CCR */ + break; + + case 0x33: /* LEAU */ + UP = get_indexed_addr(); + /* does not affect CCR */ + break; + + case 0x34: /* PSHS */ + Post_Byte = get_imm_byte_val(); + if (Post_Byte & PSH_PUL_Post_Byte_PC) push_sp_word(PC); + if (Post_Byte & PSH_PUL_Post_Byte_S_U) push_sp_word(UP); + if (Post_Byte & PSH_PUL_Post_Byte_Y) push_sp_word(IY); + if (Post_Byte & PSH_PUL_Post_Byte_X) push_sp_word(IX); + if (Post_Byte & PSH_PUL_Post_Byte_DP) push_sp_byte(DP); + if (Post_Byte & PSH_PUL_Post_Byte_B) push_sp_byte(B); + if (Post_Byte & PSH_PUL_Post_Byte_A) push_sp_byte(A); + if (Post_Byte & PSH_PUL_Post_Byte_CC) push_sp_byte(CCR); + break; + + case 0x35: /* PULS */ + Post_Byte = get_imm_byte_val(); + if (Post_Byte & PSH_PUL_Post_Byte_CC) CCR = pop_sp_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_A) A = pop_sp_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_B) B = pop_sp_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_DP) DP = pop_sp_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_X) IX = pop_sp_word(); + if (Post_Byte & PSH_PUL_Post_Byte_Y) IY = pop_sp_word(); + if (Post_Byte & PSH_PUL_Post_Byte_S_U) UP = pop_sp_word(); + if (Post_Byte & PSH_PUL_Post_Byte_PC) PC = pop_sp_word(); + break; + + case 0x36: /* PSHU */ + Post_Byte = get_imm_byte_val(); + if (Post_Byte & PSH_PUL_Post_Byte_PC) push_up_word(PC); + if (Post_Byte & PSH_PUL_Post_Byte_S_U) push_up_word(SP); + if (Post_Byte & PSH_PUL_Post_Byte_Y) push_up_word(IY); + if (Post_Byte & PSH_PUL_Post_Byte_X) push_up_word(IX); + if (Post_Byte & PSH_PUL_Post_Byte_DP) push_up_byte(DP); + if (Post_Byte & PSH_PUL_Post_Byte_B) push_up_byte(B); + if (Post_Byte & PSH_PUL_Post_Byte_A) push_up_byte(A); + if (Post_Byte & PSH_PUL_Post_Byte_CC) push_up_byte(CCR); + break; + + case 0x37: /* PULU */ + Post_Byte = get_imm_byte_val(); + if (Post_Byte & PSH_PUL_Post_Byte_CC) CCR = pop_up_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_A) A = pop_up_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_B) B = pop_up_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_DP) DP = pop_up_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_X) IX = pop_up_word(); + if (Post_Byte & PSH_PUL_Post_Byte_Y) IY = pop_up_word(); + if (Post_Byte & PSH_PUL_Post_Byte_S_U) SP = pop_up_word(); + if (Post_Byte & PSH_PUL_Post_Byte_PC) PC = pop_up_word(); + break; + + case 0x39: /* RTS */ + PC = pop_sp_word(); + break; + + case 0x3A: /* ABX */ + /* this is an UNSIGNED operation! */ + IX = (IX + B) & 0xFFFF; + /* no changes to CCR */ + break; + + case 0x3B: /* RTI */ + CCR = pop_sp_byte(); + if (GET_FLAG(EF)) { + /* entire state flag */ + A = pop_sp_byte(); + B = pop_sp_byte(); + DP = pop_sp_byte(); + IX = pop_sp_word(); + IY = pop_sp_word(); + UP = pop_sp_word(); + } + PC = pop_sp_word(); + break; + + case 0x3C: /* CWAI */ + /* AND immediate byte with CCR + CCR &= get_imm_byte_val(); + SET_FLAG(EF); + /* push register state */ + push_sp_word(PC); + push_sp_word(UP); + push_sp_word(IY); + push_sp_word(IX); + push_sp_byte(DP); + push_sp_byte(B); + push_sp_byte(A); + push_sp_byte(CCR); + if (get_flag(IF)) { + reason = STOP_HALT; + continue; + } else { + SET_FLAG(IF); + PC = CPU_BD_get_mword(0xFFFE) & ADDRMASK; + } + break; + + case 0x3D: /* MUL */ + D = A * B; + A = D >> 8; + B = D & BYTEMASK; + COND_SET_FLAG_Z_16(D); + COND_SET_FLAG(B & 0x80, CF); + break; + + case 0x3F: /* SWI */ + SET_FLAG(EF); + push_sp_word(PC); + push_sp_word(UP); + push_sp_word(IY); + push_sp_word(IX); + push_sp_byte(DP); + push_sp_byte(B); + push_sp_byte(A); + push_sp_byte(CCR); + SET_FLAG(FF); + SET_FLAG(IF); + PC = CPU_BD_get_mword(0xFFFA) & ADDRMASK; + break; + +/* 0x40 - inherent mode */ + case 0x40: /* NEGA */ + COND_SET_FLAG(A != 0, CF); + COND_SET_FLAG(A == 0x80, VF); + A = 0 - A; + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x43: /* COMA */ + A = ~A; + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + SET_FLAG(CF); + break; + case 0x44: /* LSRA */ + COND_SET_FLAG(A & 0x01, CF); + A = (A >> 1) & BYTEMASK; + CLR_FLAG(NF); + COND_SET_FLAG_Z(A); + /* H,V unaffected */ + break; + case 0x46: /* RORA */ + hi = get_flag(CF); + COND_SET_FLAG(A & 0x01, CF); + A = A >> 1; + if (hi) + A |= 0x80; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + /* H,V unaffected */ + break; + case 0x47: /* ASRA */ + COND_SET_FLAG(A & 0x01, CF); + A = (A >> 1) | (A & 0x80); + /* H undefined */ + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + /* V unaffected */ + break; + case 0x48: /* ASLA */ + COND_SET_FLAG(A & 0x80, CF); + A = (A << 1) & BYTEMASK; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x49: /* ROLA */ + hi = get_flag(CF); + COND_SET_FLAG(A & 0x80, CF); + A = (A << 1) & BYTEMASK; + if (hi) + A |= 0x01; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x4A: /* DECA */ + COND_SET_FLAG(A == 0x80, VF); + A = (A - 1) & BYTEMASK; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x4C: /* INCA */ + COND_SET_FLAG(A == 0x7F, VF); + A = (A + 1) & BYTEMASK; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x4D: /* TSTA */ + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + /* C not affected */ + break; + case 0x4F: /* CLRA */ + A = 0; + CLR_FLAG(NF); + SET_FLAG(ZF); + CLR_FLAG(VF); + CLR_FLAG(CF); + break; + +/* 0x50 - inherent modes */ + case 0x50: /* NEGB */ + COND_SET_FLAG(B != 0, CF); + COND_SET_FLAG(B == 0x80, VF); + B = (0 - B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0x53: /* COMB */ + B = ~B; + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + SET_FLAG(CF); + break; + case 0x54: /* LSRB */ + COND_SET_FLAG(B & 0x01, CF); + B = (B >> 1) & BYTEMASK; + CLR_FLAG(NF); + COND_SET_FLAG_Z(B); + /* H,V unaffected */ + break; + case 0x56: /* RORB */ + hi = get_flag(CF); + COND_SET_FLAG(B & 0x01, CF); + B = B >> 1; + if (hi) + B |= 0x80; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + /* H,V unaffected */ + break; + case 0x57: /* ASRB */ + COND_SET_FLAG(B & 0x01, CF); + B = (B >> 1) | (B & 0x80); + /* H undefined */ + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + /* C unaffected */ + break; + case 0x58: /* ASLB */ + COND_SET_FLAG(B & 0x80, CF); + B = (B << 1) & BYTEMASK; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x59: /* ROLB */ + hi = get_flag(CF); + COND_SET_FLAG(B & 0x80, CF); + B = (B << 1) & BYTEMASK; + if (hi) + B |= 0x01; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x5A: /* DECB */ + COND_SET_FLAG(B == 0x80, VF); + B = (B - 1) & BYTEMASK; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0x5C: /* INCB */ + COND_SET_FLAG(B == 0x7F, VF); + B = (B + 1) & BYTEMASK; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0x5D: /* TSTB */ + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + /* C not affected */ + break; + case 0x5F: /* CLRB */ + B = 0; + CLR_FLAG(NF); + SET_FLAG(ZF); + CLR_FLAG(VF); + CLR_FLAG(CF); + break; + +/* 0x60 - index mode */ + case 0x60: /* NEG ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 != 0, CF); + COND_SET_FLAG(op1 == 0x80, VF); + result = (0 - op1) & BYTEMASK; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0x63: /* COM ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = ~op1; + result &= 0xFF; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + CLR_FLAG(VF); + SET_FLAG(CF); + break; + case 0x64: /* LSR ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 & 0x01, CF); + result = op1 >> 1; + CPU_BD_put_mbyte(addr, result); + CLR_FLAG(NF); + COND_SET_FLAG_Z(result); + /* H,V unaffected */ + break; + case 0x66: /* ROR ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = op1 >> 1; + if (get_flag(CF)) + result |= 0x80; + CPU_BD_put_mbyte(addr, result); + /* H,V unaffected */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(op1 & 0x01, CF); + break; + case 0x67: /* ASR ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 >> 1) | (op1 & 0x80); + CPU_BD_put_mbyte(addr, result); + /* H undefined */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + /* V unaffected */ + COND_SET_FLAG(op1 & 0x01, CF); + break; + case 0x68: /* ASL ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 & 0x80, CF); + result = (op1 << 1) & BYTEMASK; + CPU_BD_put_mbyte(addr, result); + /* H is undefined */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x69: /* ROL ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 << 1) & BYTEMASK; + if (get_flag(CF)) + result |= 0x01; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG((op1 & 0x80) ^ (op1 & 0x40), VF); + COND_SET_FLAG(op1 & 0x80, CF); + break; + case 0x6A: /* DEC ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 - 1) & BYTEMASK; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(op1 == 0x80, VF); + break; + case 0x6C: /* INC ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 == 0x7F, VF); + op1 = (op1 + 1) & BYTEMASK; + CPU_BD_put_mbyte(addr, op1); + COND_SET_FLAG_N(op1); + COND_SET_FLAG_Z(op1); + break; + case 0x6D: /* TST ind */ + result = get_indexed_byte_val(); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + CLR_FLAG(VF); + break; + case 0x6E: /* JMP ind */ + PC = get_indexed_addr(); + break; + case 0x6F: /* CLR ind */ + CPU_BD_put_mbyte(get_indexed_addr(), 0); + /* H not affected */ + CLR_FLAG(NF); + SET_FLAG(ZF); + CLR_FLAG(VF); + CLR_FLAG(CF); + break; + +/* 0x70 - extended modes */ + case 0x70: /* NEG ext */ + addr= get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 != 0, CF); + COND_SET_FLAG(op1 == 0x80, VF) ; + result = (0 - op1) & BYTEMASK; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0x73: /* COM ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = ~op1; + result &= 0xFF; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + CLR_FLAG(VF); + SET_FLAG(CF); + break; + case 0x74: /* LSR ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 & 0x01, CF); + result = op1 >> 1; + CPU_BD_put_mbyte(addr, result); + CLR_FLAG(NF); + COND_SET_FLAG_Z(result); + /* H,V unaffected */ + break; + case 0x76: /* ROR ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = op1 >> 1; + if (get_flag(CF)) + result |= 0x80; + CPU_BD_put_mbyte(addr, result); + /* H,V unaffected */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(op1 & 0x01, CF); + break; + case 0x77: /* ASR ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 >> 1) | (op1 & 0x80); + CPU_BD_put_mbyte(addr, result); + /* H undefined */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + /* V unaffected */ + COND_SET_FLAG(op1 & 0x01, CF); + break; + case 0x78: /* ASL ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 & 0x80, CF); + result = (op1 << 1) & BYTEMASK; + CPU_BD_put_mbyte(addr, result); + /* H is undefined */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x79: /* ROL ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 << 1) & BYTEMASK; + if (get_flag(CF)) + result |= 0x01; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG((op1 & 0x80) ^ (op1 & 0x40), VF); + COND_SET_FLAG(op1 & 0x80, CF); + break; + case 0x7A: /* DEC ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 - 1) & BYTEMASK; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(op1 == 0x80, VF); + break; + case 0x7C: /* INC ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 == 0x7F, VF); + op1 = (op1 + 1) & BYTEMASK; + CPU_BD_put_mbyte(addr, op1); + COND_SET_FLAG_N(op1); + COND_SET_FLAG_Z(op1); + break; + case 0x7D: /* TST ext */ + result = get_ext_byte_val(); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + CLR_FLAG(VF); + break; + case 0x7E: /* JMP ext */ + PC = get_ext_addr(); + break; + case 0x7F: /* CLR ext */ + CPU_BD_put_mbyte(get_ext_addr(), 0); + /* H not affected */ + CLR_FLAG(NF); + SET_FLAG(ZF); + CLR_FLAG(VF); + CLR_FLAG(CF); + break; + +/* 0x80 - immediate mode (except for BSR) */ + case 0x80: /* SUBA imm */ + op1 = get_imm_byte_val(); + op2 = A; + A = A - op1; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0x81: /* CMPA imm */ + op2 = get_imm_byte_val(); + result = A - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(A, op2); + break; + case 0x82: /* SBCA imm */ + op1 = A; + op2 = get_imm_byte_val() + get_flag(CF); + A = A - op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0x83: /* SUBD imm */ + D = (A << 8) | (B & BYTEMASK); + op2 = get_imm_word_val(); + result = D - op2; + COND_SET_FLAG_C_16(result); + result &= 0xFFFF; + A = result >> 8; + B = result & BYTEMASK; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + break; + case 0x84: /* ANDA imm */ + A = (A & get_imm_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x85: /* BITA imm */ + result = (A & get_imm_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0x86: /* LDA imm */ + A = get_imm_byte_val(); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x88: /* EORA imm */ + A = (A ^ get_imm_byte_val()) & BYTEMASK; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x89: /* ADCA imm */ + op1 = A; + op2 = get_imm_byte_val() + get_flag(CF); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0x8A: /* ORA imm */ + A = A | get_imm_byte_val(); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x8B: /* ADDA imm */ + op1 = A; + op2 = get_imm_byte_val(); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0x8C: /* CMPX imm */ + op2 = get_imm_word_val(); + result = IX - op2; + COND_SET_FLAG_C_16(result); + result = result & 0xFFFF; + COND_SET_FLAG_Z_16(result); + COND_SET_FLAG_N_16(result); + condevalVs16(IX, op2); + break; + case 0x8D: /* BSR rel */ + addr = get_rel_addr(); + push_sp_word(PC); + PC = (PC + addr) & ADDRMASK; + break; + case 0x8E: /* LDX imm */ + IX = get_imm_word_val(); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + +/* 0x90 - direct mode */ + case 0x90: /* SUBA dir */ + op1 = A; + op2 = get_dir_byte_val(); + A = A - op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0x91: /* CMPA dir */ + op2 = get_dir_byte_val(); + result = A - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(A, op2); + break; + case 0x92: /* SBCA dir */ + op1 = A; + op2 = get_dir_byte_val() + get_flag(CF); + A = A - op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0x93: /* SUBD dir */ + D = (A << 8) | (B & BYTEMASK); + op2 = get_dir_word_val(); + result = D - op2; + COND_SET_FLAG_C_16(result); + result &= 0xFFFF; + A = result >> 8; + B = result & BYTEMASK; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + break; + case 0x94: /* ANDA dir */ + A = (A & get_dir_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x95: /* BITA dir */ + result = (A & get_dir_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0x96: /* LDA dir */ + A = get_dir_byte_val(); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x97: /* STA dir */ + CPU_BD_put_mbyte(get_dir_addr(), A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x98: /* EORA dir */ + A = (A ^ get_dir_byte_val()) & BYTEMASK; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x99: /* ADCA dir */ + op1 = A; + op2 = get_dir_byte_val() + get_flag(CF); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0x9A: /* ORA dir */ + A = A | get_dir_byte_val(); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x9B: /* ADDA dir */ + op1 = A; + op2 = get_dir_byte_val(); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0x9C: /* CMPX dir */ + op2 = get_dir_word_val(); + result = IX - op2; + COND_SET_FLAG_C_16(result); + result &= 0xFFFF; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IX, op2); + break; + case 0x9D: /* JSR dir */ + addr = get_dir_addr(); + push_sp_word(PC); + PC = addr; + break; + case 0x9E: /* LDX dir */ + IX = get_dir_word_val(); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + case 0x9F: /* STX dir */ + CPU_BD_put_mword(get_dir_addr(), IX); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + +/* 0xA0 - indexed mode */ + case 0xA0: /* SUBA ind */ + op1 = get_indexed_byte_val(); + result = A - op1; + A = result; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, result); + break; + case 0xA1: /* CMPA ind */ + op2 = get_indexed_byte_val(); + result = A - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(A, op2); + break; + case 0xA2: /* SBCA ind */ + op1 = A; + op2 = get_indexed_byte_val() + get_flag(CF); + A = A - op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0xA3: /* SUBD ind */ + D = (A << 8) | (B & BYTEMASK); + op2 = get_indexed_word_val(); + result = D - op2; + COND_SET_FLAG_C_16(result); + result &= 0xFFFF; + A = result >> 8; + B = result & BYTEMASK; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + break; + case 0xA4: /* ANDA ind */ + A = (A & get_indexed_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xA5: /* BITA ind */ + result = (A & get_indexed_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0xA6: /* LDA ind */ + A = get_indexed_byte_val(); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xA7: /* STA ind */ + CPU_BD_put_mbyte(get_indexed_addr(), A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xA8: /* EORA ind */ + A = (A ^ get_indexed_byte_val()) & BYTEMASK; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xA9: /* ADCA ind */ + op1 = A; + op2 = get_indexed_byte_val() + get_flag(CF); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0xAA: /* ORA ind */ + A = A | get_indexed_byte_val(); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xAB: /* ADDA ind */ + op1 = A; + op2 = get_indexed_byte_val(); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0xAC: /* CMPX ind */ + op2 = get_indexed_word_val(); + result = (IX - op2) & ADDRMASK; + COND_SET_FLAG_C_16(result); + result &= 0xFFFF; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IX, op2); + break; + case 0xAD: /* JSR ind */ + addr = get_indexed_addr(); + push_sp_word(PC); + PC = addr; + break; + case 0xAE: /* LDX ind */ + IX = get_indexed_word_val(); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + case 0xAF: /* STX ind */ + CPU_BD_put_mword(get_indexed_addr(), IX); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + +/* 0xB0 - extended mode */ + case 0xB0: /* SUBA ext */ + op1 = A; + op2 = get_ext_byte_val(); + A = A - op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0xB1: /* CMPA ext */ + op2 = get_ext_byte_val(); + result = A - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(A, op2); + break; + case 0xB2: /* SBCA ext */ + op1 = A; + op2 = get_ext_byte_val() + get_flag(CF); + A = A - op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0xB3: /* SUBD ext */ + D = (A << 8) | (B & BYTEMASK); + op2 = get_ext_word_val(); + result = D - op2; + COND_SET_FLAG_C_16(result); + result &= 0xFFFF; + A = result >> 8; + B = result & BYTEMASK; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + break; + case 0xB4: /* ANDA ext */ + A = (A & get_ext_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xB5: /* BITA ext */ + result = (A & get_ext_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0xB6: /* LDA ext */ + A = get_ext_byte_val(); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xB7: /* STA ext */ + CPU_BD_put_mbyte(get_ext_addr(), A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xB8: /* EORA ext */ + A = (A ^ get_ext_byte_val()) & BYTEMASK; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xB9: /* ADCA ext */ + op1 = A; + op2 = get_ext_byte_val() + get_flag(CF); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0xBA: /* ORA ext */ + A = A | get_ext_byte_val(); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xBB: /* ADDA ext */ + op1 = A; + op2 = get_ext_byte_val(); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0xBC: /* CMPX ext */ + op2 = get_ext_word_val(); + result = (IX - op2); + COND_SET_FLAG_C_16(result); + result = result & 0xFFFF; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IX, op2); + break; + case 0xBD: /* JSR ext */ + addr = get_ext_addr(); + push_sp_word(PC); + PC = addr; + break; + case 0xBE: /* LDX ext */ + IX = get_ext_word_val(); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + case 0xBF: /* STX ext */ + CPU_BD_put_mword(get_ext_addr(), IX); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + +/* 0xC0 - immediate mode */ + case 0xC0: /* SUBB imm */ + op1 = B; + op2 = get_imm_byte_val(); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xC1: /* CMPB imm */ + op2 = get_imm_byte_val(); + result = B - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(B, op2); + break; + case 0xC2: /* SBCB imm */ + op1 = B; + op2 = get_imm_byte_val() + get_flag(CF); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xC3: /* ADDD imm */ + op1 = (A << 8) | (B & BYTEMASK); + op2 = get_imm_word_val(); + D = op1 + op2; + COND_SET_FLAG_C_16(D); + D &= 0xFFFF; + A = D >> 8; + B = D & BYTEMASK; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + condevalVa16(op1,op2); + break; + case 0xC4: /* ANDB imm */ + B = (B & get_imm_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xC5: /* BITB imm */ + result = (B & get_imm_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0xC6: /* LDB imm */ + B = get_imm_byte_val(); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xC8: /* EORB imm */ + B = (B ^ get_imm_byte_val()) & BYTEMASK; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xC9: /* ADCB imm */ + op1 = B; + op2 = get_imm_byte_val() + get_flag(CF); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xCA: /* ORB imm */ + B = B | get_imm_byte_val(); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xCB: /* ADDB imm */ + op1 = B; + op2 = get_imm_byte_val(); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xCC: /* LDD imm */ + D = get_imm_word_val(); + A = D >> 8; + B = D & BYTEMASK; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xCE: /* LDU imm */ + UP = get_imm_word_val(); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + +/* 0xD0 - direct modes */ + case 0xD0: /* SUBB dir */ + op1 = B; + op2 = get_dir_byte_val(); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xD1: /* CMPB dir */ + op2 = get_dir_byte_val(); + result = B - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(B, op2); + break; + case 0xD2: /* SBCB dir */ + op1 = B; + op2 = get_dir_byte_val() + get_flag(CF); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xD3: /* ADDD dir */ + op1 = (A << 8) | (B & BYTEMASK); + op2 = get_dir_word_val(); + D = op1 + op2; + COND_SET_FLAG_C_16(D); + D &= 0xFFFF; + A = D >> 8; + B = D & BYTEMASK; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + condevalVa16(op1, op2); + break; + case 0xD4: /* ANDB dir */ + B = (B & get_dir_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xD5: /* BITB dir */ + result = (B & get_dir_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0xD6: /* LDB dir */ + B = get_dir_byte_val(); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xD7: /* STB dir */ + CPU_BD_put_mbyte(get_dir_addr(), B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xD8: /* EORB dir */ + B = (B ^ get_dir_byte_val()) & BYTEMASK; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xD9: /* ADCB dir */ + op1 = B; + op2 = get_dir_byte_val() + get_flag(CF); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xDA: /* ORB dir */ + B = B | get_dir_byte_val(); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xDB: /* ADDB dir */ + op1 = B; + op2 = get_dir_byte_val(); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xDC: /* LDD dir */ + D = get_dir_word_val(); + A = D >> 8; + B = D & BYTEMASK; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xDD: /* STD dir */ + D = (A << 8) | (B & BYTEMASK); + CPU_BD_put_mword(get_dir_addr(), D); + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xDE: /* LDU dir */ + UP = get_dir_word_val(); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + case 0xDF: /* STU dir */ + CPU_BD_put_mword(get_dir_addr(), UP); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + +/* 0xE0 - indexed mode */ + case 0xE0: /* SUBB ind */ + op1 = B; + op2 = get_indexed_byte_val(); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xE1: /* CMPB ind */ + op2 = get_indexed_byte_val(); + result = B - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(B, op2); + break; + case 0xE2: /* SBCB ind */ + op1 = B; + op2 = get_indexed_byte_val() + get_flag(CF); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xE3: /* ADDD ind */ + op1 = (A << 8) | (B & BYTEMASK); + op2 = get_indexed_word_val(); + D = op1 + op2; + COND_SET_FLAG_C_16(D); + D &= 0xFFFF; + A = D >> 8; + B = D & BYTEMASK; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + condevalVa16(op1, op2); + break; + case 0xE4: /* ANDB ind */ + B = (B & get_indexed_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xE5: /* BITB ind */ + result = (B & get_indexed_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0xE6: /* LDB ind */ + B = get_indexed_byte_val(); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xE7: /* STB ind */ + CPU_BD_put_mbyte(get_indexed_addr(), B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xE8: /* EORB ind */ + B = (B ^ get_indexed_byte_val()) & BYTEMASK; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xE9: /* ADCB ind */ + op1 = B; + op2 = get_indexed_byte_val() + get_flag(CF); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xEA: /* ORB ind */ + B = B | get_indexed_byte_val(); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xEB: /* ADDB ind */ + op1 = B; + op2 = get_indexed_byte_val(); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xEC: /* LDD ind */ + D = get_indexed_word_val(); + A = D >> 8; + B = D & BYTEMASK; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xED: /* STD ind */ + D = (A << 8) | (B & BYTEMASK); + CPU_BD_put_mword(get_indexed_addr(), D); + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xEE: /* LDU ind */ + UP = get_indexed_word_val(); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + case 0xEF: /* STU ind */ + CPU_BD_put_mword(get_indexed_addr(), UP); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + +/* 0xF0 - extended mode */ + case 0xF0: /* SUBB ext */ + op1 = B; + op2 = get_ext_byte_val(); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xF1: /* CMPB ext */ + op2 = get_ext_byte_val(); + result = B - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(B, op2); + break; + case 0xF2: /* SBCB ext */ + op1 = B; + op2 = get_ext_byte_val() + get_flag(CF); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xF3: /* ADDD ext */ + op1 = (A << 8) | (B & BYTEMASK); + op2 = get_ext_word_val(); + D = op1 + op2; + COND_SET_FLAG_C_16(D); + D &= 0xFFFF; + A = D >> 8; + B = D & BYTEMASK; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + condevalVa16(op1, op2); + break; + case 0xF4: /* ANDB ext */ + B = (B & get_ext_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xF5: /* BITB ext */ + result = (B & get_ext_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0xF6: /* LDB ext */ + B = get_ext_byte_val(); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xF7: /* STB ext */ + CPU_BD_put_mbyte(get_ext_addr(), B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xF8: /* EORB ext */ + B = (B ^ get_ext_byte_val()) & BYTEMASK; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xF9: /* ADCB ext */ + op1 = B; + op2 = get_ext_byte_val() + get_flag(CF); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xFA: /* ORB ext */ + B = B | get_ext_byte_val(); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xFB: /* ADDB ext */ + op1 = B; + op2 = get_ext_byte_val(); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xFC: /* LDD ext */ + D = get_ext_word_val(); + A = D >> 8; + B = D & BYTEMASK; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xFD: /* STD ext */ + D = (A << 8) | (B & BYTEMASK); + CPU_BD_put_mword(get_ext_addr(), D); + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xFE: /* LDU ext */ + UP = get_ext_word_val(); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + case 0xFF: /* STU ext */ + CPU_BD_put_mword(get_ext_addr(), UP); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + + default: /* Unassigned */ + if (m6809_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(void) +{ + printf("\r\nPC=%04X SP=%04X UP=%04X IX=%04X IY=%04X ", PC, SP, UP, IX, IY); + printf("A=%02X B=%02X DP=%02X CCR=%02X", A, B, DP, CCR); +} + +void dump_regs1(void) +{ + printf("PC=%04X SP=%04X UP=%04X IX=%04X IY=%04X ", PC, SP, UP, IX, IY); + printf("A=%02X B=%02X DP=%02X CCR=%02X\n", A, B, DP, CCR); +} + +/* fetch an instruction or byte */ +int32 fetch_byte(int32 flag) +{ + uint8 val; + + val = CPU_BD_get_mbyte(PC); /* fetch byte */ + switch (flag) { + case 0: /* opcode fetch */ + sim_debug (DEBUG_asm, &m6809_dev, "%04X %s\n", PC, opcode[val]); + break; + case 1: /* byte operand fetch */ + sim_debug (DEBUG_asm, &m6809_dev, "0x%02XH\n", val); + break; + } + PC = (PC + 1) & ADDRMASK; /* increment PC */ + return val; +} + +/* fetch a word - big endian */ +int32 fetch_word() +{ + uint16 val; + + val = CPU_BD_get_mbyte(PC) << 8; /* fetch high byte */ + val |= (CPU_BD_get_mbyte(PC + 1)); /* fetch low byte */ + + /* 2-byte operand fetch */ + sim_debug (DEBUG_asm, &m6809_dev, "0x%04XH\n", val); + + PC = (PC + 2) & ADDRMASK; /* increment PC */ + return val; +} + +/* push a byte using the hardware stack pointer (SP) */ +void push_sp_byte(uint8 val) +{ + SP = (SP - 1) & ADDRMASK; + CPU_BD_put_mbyte(SP, val & BYTEMASK); +} + +/* push a byte using the user stack pointer (UP) */ +void push_up_byte(uint8 val) +{ + UP = (UP - 1) & ADDRMASK; + CPU_BD_put_mbyte(UP, val & BYTEMASK); +} + +/* push a word using the hardware stack pointer (SP) */ +void push_sp_word(uint16 val) +{ + push_sp_byte(val & BYTEMASK); + push_sp_byte(val >> 8); +} + +/* push a word using the user stack pointer (UP) */ +void push_up_word(uint16 val) +{ + push_up_byte(val & BYTEMASK); + push_up_byte(val >> 8); +} + +/* pop a byte using the hardware stack pointer (SP) */ +uint8 pop_sp_byte(void) +{ + register uint8 res; + + res = CPU_BD_get_mbyte(SP); + SP = (SP + 1) & ADDRMASK; + return res; +} + +/* pop a byte using the user stack pointer (UP) */ +uint8 pop_up_byte(void) +{ + register uint8 res; + + res = CPU_BD_get_mbyte(UP); + UP = (UP + 1) & ADDRMASK; + return res; +} + +/* pop a word using the hardware stack pointer (SP) */ +uint16 pop_sp_word(void) +{ + register uint16 res; + + res = pop_sp_byte() << 8; + res |= pop_sp_byte(); + return res; +} + +/* pop a word using the user stack pointer (UP) */ +uint16 pop_up_word(void) +{ + register uint16 res; + + res = pop_up_byte() << 8; + res |= pop_up_byte(); + return res; +} + +/* 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; + } +} + +/* this routine does the jump to long relative offset if the condition is met. Otherwise, execution continues at the current PC. */ +void go_long_rel(int32 cond) +{ + int32 temp; + + temp = get_long_rel_addr(); + if (cond != 0) { + PC += temp; + PC &= ADDRMASK; + } +} + +/* returns the relative offset sign-extended */ +int32 get_rel_addr(void) +{ + int32 temp; + + temp = fetch_byte(1); + if (temp & 0x80) + temp |= 0xFF00; + return temp & ADDRMASK; +} + +/* returns the long relative offset sign-extended */ +int32 get_long_rel_addr(void) +{ + return fetch_word(); +} + +/* returns the byte value at the direct address pointed to by PC */ +int32 get_dir_byte_val(void) +{ + return CPU_BD_get_mbyte(get_dir_addr()); +} + +/* returns the word value at the direct address pointed to by PC */ +int32 get_dir_word_val(void) +{ + return CPU_BD_get_mword(get_dir_addr()); +} + +/* returns the immediate byte value pointed to by PC */ +int32 get_imm_byte_val(void) +{ + return fetch_byte(1); +} + +/* returns the immediate word value pointed to by PC */ +int32 get_imm_word_val(void) +{ + return fetch_word(); +} + +/* returns the direct address pointed to by PC */ +/* use the Direct Page register as the high byte of the address */ +int32 get_dir_addr(void) +{ + int32 temp; + + temp = (DP << 8) + fetch_byte(1); + return temp & 0xFFFF; +} + +/* returns the byte value at the indexed address pointed to by PC */ +int32 get_indexed_byte_val(void) +{ + return CPU_BD_get_mbyte(get_indexed_addr()); +} + +/* returns the word value at the indexed address pointed to by PC */ +int32 get_indexed_word_val(void) +{ + return CPU_BD_get_mword(get_indexed_addr()); +} + +/* returns the indexed address. Note this also handles the indirect indexed mode */ +int32 get_indexed_addr(void) +{ + int32 temp; + int32 offset; + uint8 post_byte; + + /* fetch the index mode post-byte */ + post_byte = fetch_byte(1); + + if ((post_byte & 0x80) == 0) { + /* R +- 4-bit offset (non indirect only) */ + /* read register value */ + switch (post_byte & 0x60) { + case 0b00000000: temp = IX; break; + case 0b00100000: temp = IY; break; + case 0b01000000: temp = UP; break; + case 0b01100000: temp = SP; break; + default: break; + } + /* add 4 bit signed offset */ + if (post_byte & 0x10) { + /* subtract offset */ + offset = (post_byte | 0xFFF0); + temp += offset; + } else { + /* add offset */ + temp += (post_byte & 0x0F); + } + } else { + switch ( post_byte & 0x0F ) { + case 0b0000: + /* .R+ post increment by 1 (non indirect) */ + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX++; IX &= 0xFFFF; break; + case 0b00100000: temp = IY++; IY &= 0xFFFF; break; + case 0b01000000: temp = UP++; UP &= 0xFFFF; break; + case 0b01100000: temp = SP++; SP &= 0xFFFF; break; + default: break; + }; + break; + case 0b0001: + /* .R+ post increment by 2 (non indirect) */ + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX; IX=IX+2; IX &= 0xFFFF; break; + case 0b00100000: temp = IY; IY=IY+2; IY &= 0xFFFF; break; + case 0b01000000: temp = UP; UP=UP+2; UP &= 0xFFFF; break; + case 0b01100000: temp = SP; SP=SP+2; SP &= 0xFFFF; break; + default: break; + }; + break; + case 0b0010: + /* .-R pre decrement by 1 (non indirect) */ + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = --IX; IX &= 0xFFFF; break; + case 0b00100000: temp = --IY; IY &= 0xFFFF; break; + case 0b01000000: temp = --UP; UP &= 0xFFFF; break; + case 0b01100000: temp = --SP; SP &= 0xFFFF; break; + default: break; + }; + break; + case 0b0011: + /* .--R pre decrement by 2 (non indirect) */ + switch ( post_byte & 0x60 ) { + case 0b00000000: IX-=2; temp = IX; IX &= 0xFFFF; break; + case 0b00100000: IY-=2; temp = IY; IY &= 0xFFFF; break; + case 0b01000000: UP-=2; temp = UP; UP &= 0xFFFF; break; + case 0b01100000: SP-=2; temp = SP; SP &= 0xFFFF; break; + default: break; + }; + break; + case 0b0100: + /* R+0 zero offset (non indirect) */ + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX; break; + case 0b00100000: temp = IY; break; + case 0b01000000: temp = UP; break; + case 0b01100000: temp = SP; break; + default: break; + }; + break; + case 0b0101: + /* R+-ACCB (non indirect)*/ + if (B & 0x80) { + offset = B | 0xFF80; + } else { + offset = B; + } + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX; break; + case 0b00100000: temp = IY; break; + case 0b01000000: temp = UP; break; + case 0b01100000: temp = SP; break; + default: break; + }; + temp += offset; + break; + case 0b0110: + /* R+-ACCA (non indirect)*/ + if (A & 0x80) { + offset = A | 0xFF80; + } else { + offset = A; + } + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX; break; + case 0b00100000: temp = IY; break; + case 0b01000000: temp = UP; break; + case 0b01100000: temp = SP; break; + default: break; + }; + temp += offset; + break; + case 0b1000: + /* R+- 8-bit offset */ + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX; break; + case 0b00100000: temp = IY; break; + case 0b01000000: temp = UP; break; + case 0b01100000: temp = SP; break; + default: break; + }; + /* need to fetch 8-bit operand */ + offset = fetch_byte(1); + + /* add 7 bit signed offset */ + if (offset & 0x80) { + /* subtract offset */ + offset |= 0xFF00; + } + temp += offset; + break; + case 0b1001: + /* R+- 16-bit offset */ + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX; break; + case 0b00100000: temp = IY; break; + case 0b01000000: temp = UP; break; + case 0b01100000: temp = SP; break; + default: break; + }; + /* need to fetch 16-bit operand */ + offset = fetch_word(); + + /* add 16 bit signed offset */ + temp += offset; + break; + case 0b1011: + /* R+- ACCD */ + D = (A << 8) + (B & BYTEMASK); + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX + D; break; + case 0b00100000: temp = IY + D; break; + case 0b01000000: temp = UP + D; break; + case 0b01100000: temp = SP + D; break; + default: break; + }; + break; + case 0b1100: + /* PC+- 7-bit offset (non indirect) */ + /* need to fetch 8-bit operand */ + offset = fetch_byte(1); + // PC value after fetch!!! + temp = PC; + + /* add 7 bit signed offset */ + if (offset & 0x80) { + /* subtract offset */ + offset |= 0xFF00; + } + temp += offset; + break; + case 0b1101: + /* PC+- 15-bit offset (non indirect)*/ + /* need to fetch 16-bit operand */ + offset = fetch_word(); + // PC value after fetch!!! + temp = PC; + + /* add 15 bit signed offset */ + temp += offset; + break; + case 0b1111: + // Extended indirect - fetch 16-bit address + temp = fetch_word(); + break; + } + switch ( post_byte & 0x1F ) { + /* perform the indirection - 11 valid post-byte opcodes */ + case 0b10001: + case 0b10011: + case 0b10100: + case 0b10101: + case 0b10110: + case 0b11000: + case 0b11001: + case 0b11011: + case 0b11100: + case 0b11101: + case 0b11111: + temp = temp & 0xFFFF; + temp = CPU_BD_get_mword(temp); + break; + default: break; + } + } + /* make sure to truncate to 16-bit value */ + return temp & 0xFFFF; +} + +/* returns the value at the extended address pointed to by PC */ +int32 get_ext_byte_val(void) +{ + return CPU_BD_get_mbyte(get_ext_addr()); +} + +/* returns the value at the extended address pointed to by PC */ +int32 get_ext_word_val(void) +{ + return CPU_BD_get_mword(get_ext_addr()); +} + +/* returns the extended address pointed to by PC or immediate word */ +int32 get_ext_addr(void) +{ + int32 temp; + + temp = fetch_word(); + return temp; +} + +/* return 1 for flag set or 0 for flag clear */ +int32 get_flag(int32 flg) +{ + if (CCR & flg) { + return 1; + } + else { + return 0; + } +} + +/* test and set V for 8-addition */ +void condevalVa(int32 op1, int32 op2) +{ + if (((op1 & 0x80) == (op2 & 0x80)) && + (((op1 + op2) & 0x80) != (op1 & 0x80))) + SET_FLAG(VF); + else + CLR_FLAG(VF); +} + +/* test and set V for 16-bit addition */ +void condevalVa16(int32 op1, int32 op2) +{ + /* + IF (the sign of the 2 operands are the same) + AND + (the sum of the operands has a different sign than both of the 2 operands) + THEN set the Overflow flag + ELSE clear the Overflow flag + */ + if (((op1 & 0x8000) == (op2 & 0x8000)) && + (((op1 + op2) & 0x8000) != (op1 & 0x8000))) + SET_FLAG(VF); + else + CLR_FLAG(VF); +} + +/* test and set V for 8-bit subtraction */ +void condevalVs(int32 op1, int32 op2) +{ + if (((op1 & 0x80) != (op2 & 0x80)) && + (((op1 - op2) & 0x80) == (op2 & 0x80))) + SET_FLAG(VF); + else + CLR_FLAG(VF); + +} + +/* test and set V for 16-bit subtraction */ +void condevalVs16(int32 op1, int32 op2) +{ + if (((op1 & 0x8000) != (op2 & 0x8000)) && + (((op1 - op2) & 0x8000) == (op2 & 0x8000))) + SET_FLAG(VF); + else + CLR_FLAG(VF); + +} + +/* test and set H for addition (8-bit only) */ +void condevalHa(int32 op1, int32 op2) +{ + if (((op1 & 0x0f) + (op2 & 0x0f)) & 0x10) + SET_FLAG(HF); + else + CLR_FLAG(HF); +} + +/* calls from the simulator */ + +/* Boot routine */ +t_stat m6809_boot(int32 unit_num, DEVICE *dptr) +{ + /* retrieve the reset vector at $FFFE */ + saved_PC = CPU_BD_get_mword(0xFFFE); + if (saved_PC == 0xFFFF) { + ; // No BOOT ROM detected! + } + return SCPE_OK; +} + +/* Reset routine */ +t_stat m6809_reset (DEVICE *dptr) +{ + CCR = EF | FF | IF; + DP = 0; + int_req = 0; + sim_brk_types = sim_brk_dflt = SWMASK ('E'); + + /* retrieve the reset vector at $FFFE */ + saved_PC = CPU_BD_get_mword(0xFFFE); + if (saved_PC == 0xFFFF) { + ; // No BOOT ROM detected! + } + return SCPE_OK; +} + +/* examine routine */ +t_stat m6809_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= 0x10000) { + /* exceed 16-bit address space */ + return SCPE_NXM; + } else { + *eval_array = CPU_BD_get_mbyte(addr); + return SCPE_OK; + } +} + +/* deposit routine */ +t_stat m6809_deposit(t_value value, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= 0x10000) { + /* exceed 16-bit address space */ + return SCPE_NXM; + } else { + CPU_BD_put_mbyte(addr, value); + return SCPE_OK; + } +} + + +/* This is the dumper/loader. This command uses the -h to signify a + hex dump/load vice a binary one. If no address is given to load, it + takes the address from the hex record or the current PC for binary. +*/ + +t_stat sim_load (FILE *fileref, CONST char *cptr, CONST char *fnam, int flag) +{ + int32 i, addr = 0, cnt = 0; + + if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; + addr = saved_PC; + while ((i = getc (fileref)) != EOF) { + CPU_BD_put_mbyte(addr, i); + addr++; + cnt++; + } // end while + printf ("%d Bytes loaded.\n", cnt); + return (SCPE_OK); +} + +/* Symbolic output + + Inputs: + *of = output stream + addr = current PC + *val = pointer to values + *uptr = pointer to unit + sw = switches + Outputs: + status = error code + for M6809 +*/ +t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) +{ + int32 i, inst, inst1; + + if (sw & SWMASK ('D')) { // dump memory + for (i=0; i<16; i++) + fprintf(of, "%02X ", val[i]); + fprintf(of, " "); + for (i=0; i<16; i++) + if (isprint(val[i])) + fprintf(of, "%c", val[i]); + else + fprintf(of, "."); + return -15; + } else if (sw & SWMASK ('M')) { // dump instruction mnemonic + inst = val[0]; + if (!oplen[inst]) { // invalid opcode + fprintf(of, "%02X", inst); + return 0; + } + inst1 = inst & 0xF0; + fprintf (of, "%s", opcode[inst]); // mnemonic + if (strlen(opcode[inst]) == 3) + fprintf(of, " "); + if (inst1 == 0x20 || inst == 0x8D) { // rel operand + inst1 = val[1]; + if (val[1] & 0x80) + inst1 |= 0xFF00; + fprintf(of, " $%04X", (addr + inst1 + 2) & ADDRMASK); + } else if (inst1 == 0x80 || inst1 == 0xC0) { // imm operand + if ((inst & 0x0F) < 0x0C) + fprintf(of, " #$%02X", val[1]); + else + fprintf(of, " #$%02X%02X", val[1], val[2]); + } else if (inst1 == 0x60 || inst1 == 0xA0 || inst1 == 0xE0) // ind operand + fprintf(of, " %d,X", val[1]); + else if (inst1 == 0x70 || inst1 == 0xb0 || inst1 == 0xF0) // ext operand + fprintf(of, " $%02X%02X", val[1], val[2]); + return (-(oplen[inst] - 1)); + } else + return SCPE_ARG; +} + +/* Symbolic input + + Inputs: + *cptr = pointer to input string + addr = current PC + *uptr = pointer to unit + *val = pointer to output values + sw = switches + Outputs: + status = error status +*/ +t_stat parse_sym (CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) +{ + return (-2); +} + +/* end of m6809.c */ diff --git a/swtp6809/common/mp-09.c b/swtp6809/common/mp-09.c index 4baa68ef5..756435c96 100644 --- a/swtp6809/common/mp-09.c +++ b/swtp6809/common/mp-09.c @@ -1,282 +1,296 @@ -/* mp-09.c: SWTP MP-09 M6809 CPU simulator - - Copyright (c) 2011-2012, 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. - - MODIFICATIONS: - - 24 Apr 15 -- Modified to use simh_debug - 20 Feb 24 -- Richard Lukes - modified SWTPC mp-a2 emulator to create mp-09 emulator. - - NOTES: - - The MP-09 CPU Board includes the SWTP Dynamic Address Translation (DAT) logic which - is used to create a 20-bit virtual address space (1MB of RAM). - - The MP-09 CPU Board contains the following devices [mp-09.c]: - M6809 processor [m6809.c]. - SWTPC SBUG-E, or custom boot ROM at top of 16-bit address space [bootrom.c]. - Interface to the SS-50 bus and the MP-B3 Mother Board for I/O - and memory boards [mp-b3.c]. -*/ - -#include -#include "swtp_defs.h" - -#define UNIT_V_USER_D (UNIT_V_UF) /* user defined switch */ -#define UNIT_USER_D (1 << UNIT_V_USER_D) -#define UNIT_V_4K_8K (UNIT_V_UF+1) /* off if HI_PROM and only 2K EPROM */ -#define UNIT_4K_8K (1 << UNIT_V_4K_8K) -#define UNIT_V_SWT (UNIT_V_UF+2) /* on SWTBUG, off MIKBUG */ -#define UNIT_SWT (1 << UNIT_V_SWT) -#define UNIT_V_8K (UNIT_V_UF+3) /* off if HI_PROM and only 2K or 4k EPROM */ -#define UNIT_8K (1 << UNIT_V_8K) -#define UNIT_V_RAM (UNIT_V_UF+4) /* off disables 6810 RAM */ -#define UNIT_RAM (1 << UNIT_V_RAM) -#define UNIT_V_LO_PROM (UNIT_V_UF+5) /* on EPROMS @ C000-CFFFH, off no EPROMS */ -#define UNIT_LO_PROM (1 << UNIT_V_LO_PROM) -#define UNIT_V_HI_PROM (UNIT_V_UF+6) /* on EPROMS @ F000-FFFFH, off fo LO_PROM, MON, or no EPROMS */ -#define UNIT_HI_PROM (1 << UNIT_V_HI_PROM) -#define UNIT_V_MON (UNIT_V_UF+7) /* on for monitor vectors in high memory */ -#define UNIT_MON (1 << UNIT_V_MON) - -/* local global variables */ -unsigned char DAT_RAM[16]; -unsigned char DAT_RAM_CACHE[16]; - -/* function prototypes */ - -t_stat CPU_BD_reset (DEVICE *dptr); -t_stat CPU_BD_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches); -t_stat CPU_BD_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); -int32 DAT_Xlate(int32 logical_addr); -int32 CPU_BD_get_mbyte(int32 addr); -int32 CPU_BD_get_mword(int32 addr); -void CPU_BD_put_mbyte(int32 addr, int32 val); -void CPU_BD_put_mword(int32 addr, int32 val); - -/* external routines */ - -/* MP-B3 bus routines */ -extern int32 MB_get_mbyte(int32 addr); -extern int32 MB_get_mword(int32 addr); -extern void MB_put_mbyte(int32 addr, int32 val); -extern void MB_put_mword(int32 addr, int32 val); - -/* MP-09 data structures - - CPU_BD_dev MP-09 device descriptor - CPU_BD_unit MP-09 unit descriptor - CPU_BD_reg MP-09 register list - CPU_BD_mod MP-09 modifiers list -*/ - -UNIT CPU_BD_unit = { UDATA (NULL, 0, 0) }; - -REG CPU_BD_reg[] = { - { NULL } -}; - -MTAB CPU_BD_mod[] = { - { UNIT_USER_D, UNIT_USER_D, "USER_D", "USER_D", NULL }, - { UNIT_USER_D, 0, "NOUSER_D", "NOUSER_D", NULL }, - { UNIT_4K_8K, UNIT_4K_8K, "4K_8K", "4K_8K", NULL }, - { UNIT_4K_8K, 0, "NO4K_8K", "NO4K_8K", NULL }, - { UNIT_SWT, UNIT_SWT, "SWT", "SWT", NULL }, - { UNIT_SWT, 0, "NOSWT", "NOSWT", NULL }, - { UNIT_8K, UNIT_8K, "8K", "8K", NULL }, - { UNIT_8K, 0, "NO8K", "NO8K", NULL }, - { UNIT_RAM, UNIT_RAM, "RAM", "RAM", NULL }, - { UNIT_RAM, 0, "NORAM", "NORAM", NULL }, - { UNIT_LO_PROM, UNIT_LO_PROM, "LO_PROM", "LO_PROM", NULL }, - { UNIT_LO_PROM, 0, "NOLO_PROM", "NOLO_PROM", NULL }, - { UNIT_HI_PROM, UNIT_HI_PROM, "HI_PROM", "HI_PROM", NULL }, - { UNIT_HI_PROM, 0, "NOHI_PROM", "NOHI_PROM", NULL }, - { UNIT_MON, UNIT_MON, "MON", "MON", NULL }, - { UNIT_MON, 0, "NOMON", "NOMON", NULL }, - { 0 } -}; - -DEBTAB CPU_BD_debug[] = { - { "ALL", DEBUG_all }, - { "FLOW", DEBUG_flow }, - { "READ", DEBUG_read }, - { "WRITE", DEBUG_write }, - { "LEV1", DEBUG_level1 }, - { "LEV2", DEBUG_level2 }, - { NULL } -}; - -DEVICE CPU_BD_dev = { - "MP-09", //name - &CPU_BD_unit, //units - CPU_BD_reg, //registers - CPU_BD_mod, //modifiers - 1, //numunits - 16, //aradix - 16, //awidth - 1, //aincr - 16, //dradix - 8, //dwidth - &CPU_BD_examine, //examine - &CPU_BD_deposit, //deposit - &CPU_BD_reset, //reset - NULL, //boot - NULL, //attach - NULL, //detach - NULL, //ctxt - DEV_DEBUG, //flags - 0, //dctrl - CPU_BD_debug, /* debflags */ - NULL, //msize - NULL //lname -}; - -/* reset */ -t_stat CPU_BD_reset (DEVICE *dptr) -{ - int32 i; - - // initialize DAT RAM - for (i=0; i<16; i++) { - DAT_RAM[i] = (~i) & 0x0F; - DAT_RAM_CACHE[i] = i; - } - return SCPE_OK; -} - -/* Deposit routine */ -t_stat CPU_BD_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches) -{ - if (addr >= 0x10000) { - return SCPE_NXM; - } else { - CPU_BD_put_mbyte(addr, val); - return SCPE_OK; - } -} - -/* Examine routine */ -t_stat CPU_BD_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) -{ - if (addr >= 0x10000) { - return SCPE_NXM; - } - if (eval_array != NULL) { - *eval_array = CPU_BD_get_mbyte(addr); - } - return SCPE_OK; -} - -/* Perform adress translation from 16-bit logical address to 20-bit physical address using DAT mapping RAM */ -int32 DAT_Xlate(int32 logi_addr) -{ - int32 DAT_index; /* which of the 16 mapping registers to index */ - int32 DAT_byte; /* the lookup value from DAT RAM */ - int32 DAT_block; /* A13-A14-A15-A16 */ - - /* translation from 16-bit logical address to 20-bit physical address */ - DAT_index = (logi_addr & 0xF000) >> 12; - DAT_byte = DAT_RAM_CACHE[DAT_index]; - if (DAT_index >= 0xE) { - /* for logical addresses $E000-$FFFF */ - // Bank address (A17-A20) is 0b0000 - return((logi_addr & 0xFFF) + ((DAT_byte & 0x0F)<<12)); - } else { - // Bank address (A17-A20) is the high order 4-bits of DAT_byte - return((logi_addr & 0xFFF) + (DAT_byte<<12)); - } -} - -/* get a byte from memory */ -int32 CPU_BD_get_mbyte(int32 addr) -{ - int32 val = 0; - int32 phy_addr; - - sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mbyte: addr=%04X\n", addr); - switch(addr & 0xF000) { - case 0xE000: - case 0xF000: - /* ROM is mapped to logical address $E000-$FFFF at all times! Unaffected by DAT */ - val = MB_get_mbyte(addr); - sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mbyte: mp_b3 val=%02X\n", val); - break; - default: - /* access the resources on the motherboard - 16-bit addressing */ - /* 56K of RAM from 0000-DFFF */ - /* 8K of I/O space from E000-EFFF */ - /* 2K of scratchpad RAM from F000-F7FF ??? */ - phy_addr = DAT_Xlate(addr); - val = MB_get_mbyte(phy_addr); - sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mbyte: mp_b3 val=%02X\n", val); - break; - } - return val; -} - -/* get a word from memory */ -int32 CPU_BD_get_mword(int32 addr) -{ - int32 val; - - sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mword: addr=%04X\n", addr); - val = (CPU_BD_get_mbyte(addr) << 8); - val |= CPU_BD_get_mbyte(addr+1); - val &= 0xFFFF; - sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mword: val=%04X\n", val); - return val; -} - -/* put a byte to memory */ -void CPU_BD_put_mbyte(int32 addr, int32 val) -{ - int32 phy_addr; - - sim_debug (DEBUG_write, &CPU_BD_dev, "CPU_BD_put_mbyte: addr=%04X, val=%02X\n", addr, val); - - if ((addr & 0xFFF0) == 0xFFF0) { - DAT_RAM[addr & 0x0F] = val; - DAT_RAM_CACHE[addr & 0x0F] = (val & 0xF0) | (~val & 0x0F); - } else { - switch(addr & 0xF800) { - case 0xF800: - /* do not write to ROM area */ - break; - default: - phy_addr = DAT_Xlate(addr); - MB_put_mbyte(phy_addr, val); - break; - } - } -} - -/* put a word to memory */ -void CPU_BD_put_mword(int32 addr, int32 val) -{ - sim_debug (DEBUG_write, &CPU_BD_dev, "CPU_BD_put_mword: addr=%04X, val=%04X\n", addr, val); - CPU_BD_put_mbyte(addr, val >> 8); - CPU_BD_put_mbyte(addr+1, val & 0xFF); -} - -/* end of mp-09.c */ +/* mp-09.c: SWTP MP-09 M6809 CPU simulator + + Copyright (c) 2011-2012, 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. + + The following copyright notice applies to the SWTP 6809 source, binary, and documentation: + + Original code published in 2024, written by Richard F Lukes + Copyright (c) 2024, Richard F Lukes + + 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 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 names of The Authors shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the Authors. + + MODIFICATIONS: + + 24 Apr 15 -- Modified to use simh_debug + 24 Feb 24 -- Richard Lukes - modified SWTPC mp-a2 emulator to create mp-09 emulator. + + NOTES: + + The MP-09 CPU Board includes the SWTP Dynamic Address Translation (DAT) logic which + is used to create a 20-bit virtual address space (1MB of RAM). + + The MP-09 CPU Board contains the following devices [mp-09.c]: + M6809 processor [m6809.c]. + SWTPC SBUG-E, or custom boot ROM at top of 16-bit address space [bootrom.c]. + Interface to the SS-50 bus and the MP-B3 Mother Board for I/O + and memory boards [mp-b3.c]. +*/ + +#include +#include "swtp_defs.h" + +#define UNIT_V_DAT (UNIT_V_UF) /* Dynamic Address Translation setting */ +#define UNIT_DAT (1 << UNIT_V_DAT) + + +/* local global variables */ +unsigned char DAT_RAM[16]; +unsigned char DAT_RAM_CACHE[16]; + +/* function prototypes */ + +t_stat CPU_BD_reset (DEVICE *dptr); +t_stat CPU_BD_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches); +t_stat CPU_BD_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); +int32 DAT_Xlate(int32 logical_addr); +int32 CPU_BD_get_mbyte(int32 addr); +int32 CPU_BD_get_mword(int32 addr); +void CPU_BD_put_mbyte(int32 addr, int32 val); +void CPU_BD_put_mword(int32 addr, int32 val); + +/* external routines */ + +/* MP-B3 bus routines */ +extern int32 MB_get_mbyte(int32 addr); +extern int32 MB_get_mword(int32 addr); +extern void MB_put_mbyte(int32 addr, int32 val); +extern void MB_put_mword(int32 addr, int32 val); + +/* MP-09 data structures + + CPU_BD_dev MP-09 device descriptor + CPU_BD_unit MP-09 unit descriptor + CPU_BD_reg MP-09 register list + CPU_BD_mod MP-09 modifiers list +*/ + +UNIT CPU_BD_unit = { UDATA (NULL, 0, 0) }; + +REG CPU_BD_reg[] = { + { NULL } +}; + +MTAB CPU_BD_mod[] = { + { UNIT_DAT, UNIT_DAT, "DAT enabled", "DAT", NULL }, + { UNIT_DAT, 0, "DAT disabled", "NODAT", NULL }, + { 0 } +}; + +DEBTAB CPU_BD_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE CPU_BD_dev = { + "MP-09", //name + &CPU_BD_unit, //units + CPU_BD_reg, //registers + CPU_BD_mod, //modifiers + 1, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + &CPU_BD_examine, //examine + &CPU_BD_deposit, //deposit + &CPU_BD_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + CPU_BD_debug, /* debflags */ + NULL, //msize + NULL //lname +}; + +/* reset */ +t_stat CPU_BD_reset (DEVICE *dptr) +{ + int32 i; + + /* this is performed whether DAT is enabled or not */ + // initialize DAT RAM + for (i=0; i<16; i++) { + DAT_RAM[i] = (~i) & 0x0F; + DAT_RAM_CACHE[i] = i; + } + return SCPE_OK; +} + +/* Deposit routine */ +t_stat CPU_BD_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= 0x10000) { + return SCPE_NXM; + } else { + CPU_BD_put_mbyte(addr, val); + return SCPE_OK; + } +} + +/* Examine routine */ +t_stat CPU_BD_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= 0x10000) { + return SCPE_NXM; + } + if (eval_array != NULL) { + *eval_array = CPU_BD_get_mbyte(addr); + } + return SCPE_OK; +} + +/* Perform adress translation from 16-bit logical address to 20-bit physical address using DAT mapping RAM */ +int32 DAT_Xlate(int32 logi_addr) +{ + + /* if DAT is enabled perform the Dynamic Address Translation */ + if (CPU_BD_unit.flags & UNIT_DAT) { + + int32 DAT_index; /* which of the 16 mapping registers to index */ + int32 DAT_byte; /* the lookup value from DAT RAM */ + int32 DAT_block; /* A13-A14-A15-A16 */ + + /* translation from 16-bit logical address to 20-bit physical address */ + DAT_index = (logi_addr & 0xF000) >> 12; + DAT_byte = DAT_RAM_CACHE[DAT_index]; + if (DAT_index >= 0xE) { + /* for logical addresses $E000-$FFFF */ + // Bank address (A17-A20) is 0b0000 + return((logi_addr & 0xFFF) + ((DAT_byte & 0x0F)<<12)); + } else { + // Bank address (A17-A20) is the high order 4-bits of DAT_byte + return((logi_addr & 0xFFF) + (DAT_byte<<12)); + } + + } else { + /* DAT is disabled */ + return(logi_addr); + } +} + +/* get a byte from memory */ +int32 CPU_BD_get_mbyte(int32 addr) +{ + int32 val = 0; + int32 phy_addr; + + sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mbyte: addr=%04X\n", addr); + switch(addr & 0xF000) { + case 0xE000: + case 0xF000: + /* ROM is mapped to logical address $E000-$FFFF at all times! Unaffected by DAT */ + val = MB_get_mbyte(addr); + sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mbyte: mp_b3 val=%02X\n", val); + break; + default: + /* access the resources on the motherboard - 16-bit addressing */ + /* 56K of RAM from 0000-DFFF */ + /* 8K of I/O space from E000-EFFF */ + /* 2K of scratchpad RAM from F000-F7FF ??? */ + if (CPU_BD_unit.flags & UNIT_DAT) { + phy_addr = DAT_Xlate(addr); + } else { + phy_addr = addr; + } + val = MB_get_mbyte(phy_addr); + sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mbyte: mp_b3 val=%02X\n", val); + break; + } + return val; +} + +/* get a word from memory */ +int32 CPU_BD_get_mword(int32 addr) +{ + int32 val; + + sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mword: addr=%04X\n", addr); + val = (CPU_BD_get_mbyte(addr) << 8); + val |= CPU_BD_get_mbyte(addr+1); + val &= 0xFFFF; + sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mword: val=%04X\n", val); + return val; +} + +/* put a byte to memory */ +void CPU_BD_put_mbyte(int32 addr, int32 val) +{ + int32 phy_addr; + + sim_debug (DEBUG_write, &CPU_BD_dev, "CPU_BD_put_mbyte: addr=%04X, val=%02X\n", addr, val); + + if ((addr & 0xFFF0) == 0xFFF0) { + /* this is performed whether DAT is enabled or not */ + DAT_RAM[addr & 0x0F] = val; + DAT_RAM_CACHE[addr & 0x0F] = (val & 0xF0) | (~val & 0x0F); + } else { + switch(addr & 0xF800) { + case 0xF800: + /* do not write to ROM area */ + break; + default: + phy_addr = DAT_Xlate(addr); + MB_put_mbyte(phy_addr, val); + break; + } + } +} + +/* put a word to memory */ +void CPU_BD_put_mword(int32 addr, int32 val) +{ + sim_debug (DEBUG_write, &CPU_BD_dev, "CPU_BD_put_mword: addr=%04X, val=%04X\n", addr, val); + CPU_BD_put_mbyte(addr, val >> 8); + CPU_BD_put_mbyte(addr+1, val & 0xFF); +} + +/* end of mp-09.c */ diff --git a/swtp6809/common/mp-1m.c b/swtp6809/common/mp-1m.c index 0f7244788..2560d6375 100644 --- a/swtp6809/common/mp-1m.c +++ b/swtp6809/common/mp-1m.c @@ -1,218 +1,311 @@ -/* mp-1m.c: SWTP 1M Byte Memory Card emulator - - Copyright (c) 2011-2012, William A. 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 O - 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. - - MODIFICATIONS: - - 24 Apr 15 -- Modified to use simh_debug - 20 Feb 24 -- Richard Lukes - Modified mp-8m.c to use for 1MB memory for swtp6809 emulator - - NOTES: - - These functions support 1MB of memory on an SS-50 system as a single 1MB memory card. - Due to the way DAT works, the upper 8KB of each 64KB address space is allocated to I/O ($E000) and ROM ($F000) space. - Therefore, the maximum usable RAM is 16 x 56KB = 896KB. - - The unit uses a statically allocated 1MB byte buffer. This makes for a fast implementation. - No effort was made to make available memory variable in size (e.g. limit to only 32KB, 64KB, 96KB, 128KB, etc.). -*/ - -#include -#include "swtp_defs.h" - -/* there is only one of these devices */ -#define ONE_MEGABYTE 0x100000 - -/* prototypes */ - -t_stat mp_1m_reset (DEVICE *dptr); -t_stat mp_1m_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches); -t_stat mp_1m_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); -int32 mp_1m_get_mbyte(int32 addr); -int32 mp_1m_get_mword(int32 addr); -void mp_1m_put_mbyte(int32 addr, int32 val); -void mp_1m_put_mword(int32 addr, int32 val); - -/* isbc064 Standard I/O Data Structures */ - -UNIT mp_1m_unit = { - UDATA (NULL, UNIT_FIX + UNIT_BINK, ONE_MEGABYTE) -}; - -MTAB mp_1m_mod[] = { - { 0 } -}; - -DEBTAB mp_1m_debug[] = { - { "ALL", DEBUG_all }, - { "FLOW", DEBUG_flow }, - { "READ", DEBUG_read }, - { "WRITE", DEBUG_write }, - { "LEV1", DEBUG_level1 }, - { "LEV2", DEBUG_level2 }, - { NULL } -}; - -DEVICE mp_1m_dev = { - "MP-1M", //name - &mp_1m_unit, //units - NULL, //registers - mp_1m_mod, //modifiers - 1, //numunits - 16, //aradix - 20, //awidth - 1, //aincr - 16, //dradix - 8, //dwidth - &mp_1m_examine, //examine - &mp_1m_deposit, //deposit - &mp_1m_reset, //reset - NULL, //boot - NULL, //attach - NULL, //detach - NULL, //ctxt - DEV_DEBUG, //flags - 0, //dctrl - mp_1m_debug, //debflags - NULL, //msize - NULL //lname -}; - -/* Pre-allocate 1MB array of bytes */ -uint8 mp_1m_ram_memory_array[ONE_MEGABYTE]; - -/* Deposit routine */ -t_stat mp_1m_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches) -{ - if (addr >= ONE_MEGABYTE) { - return SCPE_NXM; - } else { - mp_1m_ram_memory_array[addr] = val & 0xFF; - return SCPE_OK; - } -} - -/* Examine routine */ -t_stat mp_1m_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) -{ - if (addr >= ONE_MEGABYTE) { - return SCPE_NXM; - } - if (eval_array != NULL) { - *eval_array = mp_1m_ram_memory_array[addr]; - } - return SCPE_OK; -} - -/* Reset routine */ - -t_stat mp_1m_reset (DEVICE *dptr) -{ - int32 i, j, val; - UNIT *uptr; - - sim_debug (DEBUG_flow, &mp_1m_dev, "mp_1m_reset: \n"); - uptr = mp_1m_dev.units; - sim_debug (DEBUG_flow, &mp_1m_dev, "MP-1M %d unit.flags=%08X\n", i, uptr->flags); - - // capacity - uptr->capac = ONE_MEGABYTE; - // starting address - uptr->u3 = 0; - - if (uptr->filebuf == NULL) { - uptr->filebuf = &mp_1m_ram_memory_array; - if (uptr->filebuf == NULL) { - printf("mp_1m_reset: Malloc error\n"); - return SCPE_MEM; - } - for (j=0; j < uptr->capac; j++) { /* populate memory with fill pattern */ - i = j & 0xF; - val = (0xA0 | i) & 0xFF; - *((uint8 *)(uptr->filebuf) + j) = val; - } - sim_debug (DEBUG_flow, &mp_1m_dev, "MP-1M %d initialized at [%05X-%05XH]\n", i, uptr->u3, uptr->u3 + uptr->capac - 1); - } - sim_debug (DEBUG_flow, &mp_1m_dev, "mp_1m_reset: Done\n"); - return SCPE_OK; -} - -/* - I/O instruction handlers, called from the mp-b3 module when an - external memory read or write is issued. -*/ - -/* get a byte from memory */ - -int32 mp_1m_get_mbyte(int32 addr) -{ - //UNIT *uptr; - int32 val; - - //uptr = mp_1m_dev.units; - sim_debug (DEBUG_read, &mp_1m_dev, "mp_1m_get_mbyte: addr=%05X", addr); - if (addr >= ONE_MEGABYTE) { - sim_debug (DEBUG_read, &mp_1m_dev, "mp_1m_get_mbyte: addr=%08X Out of range\n", addr); - return 0xFF; - } else { - val = mp_1m_ram_memory_array[addr]; - sim_debug (DEBUG_read, &mp_1m_dev, " addr=%05x val=%02X\n", addr, val); - return val; - } -} - -/* get a word from memory */ - -int32 mp_1m_get_mword(int32 addr) -{ - int32 val; - - val = (mp_1m_get_mbyte(addr) << 8); - val |= mp_1m_get_mbyte(addr+1); - return val; -} - -/* put a byte into memory */ - -void mp_1m_put_mbyte(int32 addr, int32 val) -{ - sim_debug (DEBUG_write, &mp_1m_dev, "mp_1m_put_mbyte: addr=%05X, val=%02X", addr, val); - - if (addr >= ONE_MEGABYTE) { - sim_debug (DEBUG_write, &mp_1m_dev, "mp_1m_put_mbyte: Address out of range, addr=%08x\n", addr); - } else { - mp_1m_ram_memory_array[addr] = val; - sim_debug (DEBUG_write, &mp_1m_dev, "\n"); - } -} - -/* put a word into memory */ - -void mp_1m_put_mword(int32 addr, int32 val) -{ - mp_1m_put_mbyte(addr, val >> 8); - mp_1m_put_mbyte(addr+1, val & 0xFF); -} - -/* end of mp-1m.c */ +/* mp-1m.c: SWTP 1M Byte Memory Card emulator + + Copyright (c) 2011-2012, William A. 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 O + 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. + + The following copyright notice applies to the SWTP 6809 source, binary, and documentation: + + Original code published in 2024, written by Richard F Lukes + Copyright (c) 2024, Richard F Lukes + + 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 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 names of The Authors shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the Authors. + + MODIFICATIONS: + + 24 Apr 15 -- Modified to use simh_debug + 24 Feb 24 -- Richard Lukes - Modified mp-8m.c to use for 1MB memory for swtp6809 emulator + + NOTES: + + These functions support 1MB of memory on an SS-50 system as a single 1MB memory card. + Due to the way Dynamic Address Translation (DAT) works, the upper 8KB of each 64KB address space is allocated + to I/O ($E000) and ROM ($F000) space. Therefore, the maximum usable RAM is 16 x 56KB = 896KB. + + The unit uses a statically allocated 1MB byte buffer. This makes for a fast implementation. + No effort was made to make available memory variable in size (e.g. limit to only 32KB, 64KB, 96KB, 128KB, etc.). +*/ + +#include +#include "swtp_defs.h" + +/* this is the maximum size of the physical address space */ +#define ONE_MEGABYTE 0x100000 + +/* this is the value returned when reading a byte of non-existant memory */ +#define BLANK_MEMORY_BYTE_VALUE 0xFF + +#define UNIT_V_MSIZE (UNIT_V_UF) /* user defined options */ +#define UNIT_MSIZE (0xFF << UNIT_V_MSIZE) +#define UNIT_8KB (0x01 << UNIT_V_MSIZE) /* 8KB */ +#define UNIT_16KB (0x02 << UNIT_V_MSIZE) /* 16KB */ +#define UNIT_32KB (0x04 << UNIT_V_MSIZE) /* 32KB */ +#define UNIT_56KB (0x08 << UNIT_V_MSIZE) /* 56KB */ +#define UNIT_128KB (0x10 << UNIT_V_MSIZE) /* 128KB */ +#define UNIT_256KB (0x20 << UNIT_V_MSIZE) /* 256KB */ +#define UNIT_512KB (0x30 << UNIT_V_MSIZE) /* 512KB */ +#define UNIT_1024KB (0x40 << UNIT_V_MSIZE) /* 1024KB */ + +/* prototypes */ + +t_stat mp_1m_reset (DEVICE *dptr); +t_stat mp_1m_config(UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat mp_1m_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches); +t_stat mp_1m_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); +int32 mp_1m_get_mbyte(int32 addr); +int32 mp_1m_get_mword(int32 addr); +void mp_1m_put_mbyte(int32 addr, int32 val); +void mp_1m_put_mword(int32 addr, int32 val); + +UNIT mp_1m_unit = { + UDATA (NULL, UNIT_FIX + UNIT_BINK, ONE_MEGABYTE) +}; + +MTAB mp_1m_mod[] = { + { UNIT_MSIZE, UNIT_1024KB, "1MB of RAM", "1024KB", &mp_1m_config }, + { UNIT_MSIZE, UNIT_512KB, "512KB of RAM", "512KB", &mp_1m_config }, + { UNIT_MSIZE, UNIT_256KB, "256KB of RAM", "256KB", &mp_1m_config }, + { UNIT_MSIZE, UNIT_128KB, "128KB of RAM", "128KB", &mp_1m_config }, + { UNIT_MSIZE, UNIT_56KB, "56KB of RAM", "56KB", &mp_1m_config }, + { UNIT_MSIZE, UNIT_32KB, "32KB of RAM", "32KB", &mp_1m_config }, + { UNIT_MSIZE, UNIT_16KB, "16KB of RAM", "16KB", &mp_1m_config }, + { UNIT_MSIZE, UNIT_8KB, "8KB of RAM", "8KB", &mp_1m_config }, + { 0 } +}; + +DEBTAB mp_1m_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE mp_1m_dev = { + "MP-1M", //name + &mp_1m_unit, //units + NULL, //registers + mp_1m_mod, //modifiers + 1, //numunits + 16, //aradix + 20, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + &mp_1m_examine, //examine + &mp_1m_deposit, //deposit + &mp_1m_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + mp_1m_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* Pre-allocate 1MB array of bytes */ +uint8 mp_1m_ram_memory_array[ONE_MEGABYTE]; + +/* mp_1m_config */ +t_stat mp_1m_config (UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + + sim_debug (DEBUG_flow, &mp_1m_dev, "mp_1m_config: val=%d\n", val); + if ((val > UNIT_1024KB) || (val < UNIT_8KB)) { /* valid param? */ + sim_debug (DEBUG_flow, &mp_1m_dev, "mp_1m_config: Parameter error\n"); + return SCPE_ARG; + } + + /* set RAM size. All RAM starts with a base address of 00000H */ + switch ( val ) { + case UNIT_8KB: + mp_1m_unit.capac = 8 * 1024; + break; + case UNIT_16KB: + mp_1m_unit.capac = 16 * 1024; + break; + case UNIT_32KB: + mp_1m_unit.capac = 32 * 1024; + break; + case UNIT_56KB: + mp_1m_unit.capac = 56 * 1024; + break; + case UNIT_128KB: + mp_1m_unit.capac = 128 * 1024; + break; + case UNIT_256KB: + mp_1m_unit.capac = 256 * 1024; + break; + case UNIT_512KB: + mp_1m_unit.capac = 512 * 1024; + break; + case UNIT_1024KB: + mp_1m_unit.capac = 1024 * 1024; + break; + default: + /* what to do? default to 1024KB */ + mp_1m_unit.capac = 1024 * 1024; + } + sim_debug (DEBUG_flow, &mp_1m_dev, "mp_1m_config: mp_1m_unit.capac=%d\n", mp_1m_unit.capac); + sim_debug (DEBUG_flow, &mp_1m_dev, "mp_1m_config: Done\n"); + + return SCPE_OK; +} /* mp-1m config */ + +/* Deposit routine */ +t_stat mp_1m_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= mp_1m_unit.capac) { + return SCPE_NXM; + } else { + mp_1m_ram_memory_array[addr] = val & 0xFF; + return SCPE_OK; + } +} + +/* Examine routine */ +t_stat mp_1m_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= mp_1m_unit.capac) { + return SCPE_NXM; + } + if (eval_array != NULL) { + *eval_array = mp_1m_ram_memory_array[addr]; + } + return SCPE_OK; +} + +/* Reset routine */ + +t_stat mp_1m_reset (DEVICE *dptr) +{ + int32 i, j, val; + UNIT *uptr; + + sim_debug (DEBUG_flow, &mp_1m_dev, "mp_1m_reset: \n"); + uptr = mp_1m_dev.units; + sim_debug (DEBUG_flow, &mp_1m_dev, "MP-1M %d unit.flags=%08X\n", i, uptr->flags); + + // capacity + uptr->capac = ONE_MEGABYTE; + // starting address + uptr->u3 = 0; + + if (uptr->filebuf == NULL) { + uptr->filebuf = &mp_1m_ram_memory_array; + if (uptr->filebuf == NULL) { + printf("mp_1m_reset: Malloc error\n"); + return SCPE_MEM; + } + for (j=0; j < uptr->capac; j++) { /* populate memory with fill pattern */ + i = j & 0xF; + val = (0xA0 | i) & BYTEMASK; + *((uint8 *)(uptr->filebuf) + j) = val; + } + sim_debug (DEBUG_flow, &mp_1m_dev, "MP-1M %d initialized at [%05X-%05XH]\n", i, uptr->u3, uptr->u3 + uptr->capac - 1); + } + sim_debug (DEBUG_flow, &mp_1m_dev, "mp_1m_reset: Done\n"); + return SCPE_OK; +} + +/* + I/O instruction handlers, called from the mp-b3 module when an + external memory read or write is issued. +*/ + +/* get a byte from memory */ + +int32 mp_1m_get_mbyte(int32 addr) +{ + //UNIT *uptr; + int32 val; + + //uptr = mp_1m_dev.units; + sim_debug (DEBUG_read, &mp_1m_dev, "mp_1m_get_mbyte: addr=%05X", addr); + if (addr >= mp_1m_unit.capac) { + sim_debug (DEBUG_read, &mp_1m_dev, "mp_1m_get_mbyte: addr=%08X Out of range\n", addr); + return BLANK_MEMORY_BYTE_VALUE; + } else { + val = mp_1m_ram_memory_array[addr]; + sim_debug (DEBUG_read, &mp_1m_dev, " addr=%05x val=%02X\n", addr, val); + return val; + } +} + +/* get a word from memory */ + +int32 mp_1m_get_mword(int32 addr) +{ + int32 val; + + val = (mp_1m_get_mbyte(addr) << 8); + val |= mp_1m_get_mbyte(addr+1); + return val; +} + +/* put a byte into memory */ + +void mp_1m_put_mbyte(int32 addr, int32 val) +{ + sim_debug (DEBUG_write, &mp_1m_dev, "mp_1m_put_mbyte: addr=%05X, val=%02X", addr, val); + + if (addr >= mp_1m_unit.capac) { + sim_debug (DEBUG_write, &mp_1m_dev, "mp_1m_put_mbyte: Address out of range, addr=%08x\n", addr); + } else { + mp_1m_ram_memory_array[addr] = val; + sim_debug (DEBUG_write, &mp_1m_dev, "\n"); + } +} + +/* put a word into memory */ + +void mp_1m_put_mword(int32 addr, int32 val) +{ + mp_1m_put_mbyte(addr, val >> 8); + mp_1m_put_mbyte(addr+1, val & BYTEMASK); +} + +/* end of mp-1m.c */ diff --git a/swtp6809/common/mp-b3.c b/swtp6809/common/mp-b3.c index 9d444a2c2..244251b31 100644 --- a/swtp6809/common/mp-b3.c +++ b/swtp6809/common/mp-b3.c @@ -1,290 +1,308 @@ -/* mp-b3.c: SWTP SS-50/SS-30 MP-B3 Mother Board - - Copyright (c) 2011-2012, William A. 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. - - MODIFICATIONS: - - 24 Apr 15 -- Modified to use simh_debug - 20 Feb 24 -- Richard Lukes - Modified to emulate MP-B3 motherboard for swtp6809 emulator - - NOTES: - -*/ - -#include -#include "swtp_defs.h" - - -#define UNIT_V_RAM_1MB (UNIT_V_UF) /* MP-1M board enable */ -#define UNIT_RAM_1MB (1 << UNIT_V_RAM_1MB) - -/* function prototypes */ - -/* empty I/O device routine */ -int32 nulldev(int32 io, int32 data); - -/* SS-50 bus routines */ -t_stat MB_reset (DEVICE *dptr); -t_stat MB_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches); -t_stat MB_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); -int32 MB_get_mbyte(int32 addr); -int32 MB_get_mword(int32 addr); -void MB_put_mbyte(int32 addr, int32 val); -void MB_put_mword(int32 addr, int32 val); - -/* BOOTROM memory access routines */ -extern int32 BOOTROM_get_mbyte(int32 offset); - -/* MP-1M memory access routines */ -extern int32 mp_1m_get_mbyte(int32 addr); -extern void mp_1m_put_mbyte(int32 addr, int32 val); - -/* SS-50 I/O address space functions */ - -/* MP-S serial I/O 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); - -/* DC-4 FDC I/O routines */ -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); - -/* -MP-B3 configured with 4 address per SS-30 slot (x8). - -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] = { - {&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /* Port 0 E000-E003 */ - {&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /* Port 1 E004-E007 */ -/* 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 E008-E00B */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* Port 3 E00C-E00F */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* Port 4 E010-E013 */ - {&fdcdrv}, {&nulldev}, {&nulldev}, {&nulldev}, /* Port 5 E014-E017 */ - {&fdccmd}, {&fdctrk}, {&fdcsec}, {&fdcdata}, /* Port 6 E018-E01B */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev} /* Port 7 E01C-E01F */ -}; - -/* dummy i/o device */ - -int32 nulldev(int32 io, int32 data) -{ - if (io == 0) { - return (0xFF); - } else { - return 0; - } -} - -/* Mother Board data structures - - MB_dev Mother Board device descriptor - MB_unit Mother Board unit descriptor - MB_reg Mother Board register list - MB_mod Mother Board modifiers list -*/ - -UNIT MB_unit = { - UDATA (NULL, 0, 0) -}; - -REG MB_reg[] = { - { NULL } -}; - -MTAB MB_mod[] = { - { UNIT_RAM_1MB, UNIT_RAM_1MB, "1MB On", "1MB", NULL, NULL }, - { UNIT_RAM_1MB, 0, "1MB Off", "NO1MB", NULL, NULL }, - { 0 } -}; - -DEBTAB MB_debug[] = { - { "ALL", DEBUG_all }, - { "FLOW", DEBUG_flow }, - { "READ", DEBUG_read }, - { "WRITE", DEBUG_write }, - { "LEV1", DEBUG_level1 }, - { "LEV2", DEBUG_level2 }, - { NULL } -}; - -DEVICE MB_dev = { - "MP-B3", //name - &MB_unit, //units - MB_reg, //registers - MB_mod, //modifiers - 1, //numunits - 16, //aradix - 20, //awidth - 1, //aincr - 16, //dradix - 8, //dwidth - &MB_examine, //examine - &MB_deposit, //deposit - &MB_reset, //reset - NULL, //boot - NULL, //attach - NULL, //detach - NULL, //ctxt - DEV_DEBUG, //flags - 0, //dctrl - MB_debug, /* debflags */ - NULL, //msize - NULL //lname -}; - -/* reset */ -t_stat MB_reset (DEVICE *dptr) -{ - return SCPE_OK; -} - -/* Deposit routine */ -t_stat MB_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches) -{ - if (addr >= 0x100000) { - /* exceed 20-bit address space */ - return SCPE_NXM; - } else { - MB_put_mbyte(addr, val); - return SCPE_OK; - } -} - -/* Examine routine */ -t_stat MB_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) -{ - if (addr >= 0x100000) { - return SCPE_NXM; - } - if (eval_array != NULL) { - *eval_array = MB_get_mbyte(addr); - } - return SCPE_OK; -} - -/* get a byte from memory */ - -int32 MB_get_mbyte(int32 addr) -{ - int32 val; - - // 20-bit physical addresses - sim_debug (DEBUG_read, &MB_dev, "MB_get_mbyte: addr=%05X\n", addr); - switch (addr & 0x0F800) { - case 0x0E000: - /* reserved I/O space from $E000-$E01F */ - if ((addr & 0xFFFF) < 0xE020) { - val = (dev_table[(addr & 0xFFFF) - 0xE000].routine(0, 0)) & 0xFF; - break; - } - case 0x0E800: - case 0x0F000: - case 0x0F800: - /* Up to 8KB of boot ROM from $E000-$FFFF */ - val = BOOTROM_get_mbyte(addr & 0xFFFF); - sim_debug (DEBUG_read, &MB_dev, "MB_get_mbyte: EPROM=%02X\n", val); - break; - default: - /* all the rest is RAM */ - if (MB_unit.flags & UNIT_RAM_1MB) { - val = mp_1m_get_mbyte(addr); - if (MB_dev.dctrl & DEBUG_read) { - printf("MB_get_mbyte: mp_1m add=%05x val=%02X\n", addr, val); - } - } else { - ; // No RAM configured at this addresS - } - break; - } - sim_debug (DEBUG_read, &MB_dev, "MB_get_mbyte: I/O addr=%05X val=%02X\n", addr, val); - return val; -} - -/* get a word from memory */ - -int32 MB_get_mword(int32 addr) -{ - int32 val; - - sim_debug (DEBUG_read, &MB_dev, "MB_get_mword: addr=%04X\n", addr); - val = (MB_get_mbyte(addr) << 8); - val |= MB_get_mbyte(addr+1); - val &= 0xFFFF; - sim_debug (DEBUG_read, &MB_dev, "MB_get_mword: val=%04X\n", val); - return val; -} - -/* put a byte to memory */ - -void MB_put_mbyte(int32 addr, int32 val) -{ - // 20-bit physical addresses - sim_debug (DEBUG_write, &MB_dev, "MB_put_mbyte: addr=%05X, val=%02X\n", addr, val); - - switch(addr & 0xF000) { - case 0xE000: - /* I/O space */ - if ((addr & 0xFFFF) < 0xE020) { - dev_table[(addr & 0xFFFF) - 0xE000].routine(1, val); - } - break; - case 0xF000: - /* ROM space */ - break; - default: - /* RAM */ - if (MB_unit.flags & UNIT_RAM_1MB) { - mp_1m_put_mbyte(addr, val); - } else { - ; // No RAM conigured at this address - } - break; - } -} - -/* put a word to memory */ - -void MB_put_mword(int32 addr, int32 val) -{ - sim_debug (DEBUG_write, &MB_dev, "MB_ptt_mword: addr=%04X, val=%04X\n", addr, val); - MB_put_mbyte(addr, val >> 8); - MB_put_mbyte(addr+1, val & 0xFF); -} - -/* end of mp-b3.c */ +/* mp-b3.c: SWTP SS-50/SS-30 MP-B3 Mother Board + + Copyright (c) 2011-2012, William A. 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. + + The following copyright notice applies to the SWTP 6809 source, binary, and documentation: + + Original code published in 2024, written by Richard F Lukes + Copyright (c) 2024, Richard F Lukes + + 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 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 names of The Authors shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the Authors. + + MODIFICATIONS: + + 24 Apr 15 -- Modified to use simh_debug + 24 Feb 24 -- Richard Lukes - Modified to emulate MP-B3 motherboard for swtp6809 emulator + + NOTES: + +*/ + +#include +#include "swtp_defs.h" + + +#define UNIT_V_4BYTESPERSLOT (UNIT_V_UF) /* MP-1M board enable */ +#define UNIT_4BYTESPERSLOT (1 << UNIT_V_4BYTESPERSLOT) + +/* function prototypes */ + +/* empty I/O device routine */ +int32 nulldev(int32 io, int32 data); + +/* SS-50 bus routines */ +t_stat MB_reset (DEVICE *dptr); +t_stat MB_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches); +t_stat MB_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); +int32 MB_get_mbyte(int32 addr); +int32 MB_get_mword(int32 addr); +void MB_put_mbyte(int32 addr, int32 val); +void MB_put_mword(int32 addr, int32 val); + +/* BOOTROM memory access routines */ +extern int32 BOOTROM_get_mbyte(int32 offset); + +/* MP-1M memory access routines */ +extern int32 mp_1m_get_mbyte(int32 addr); +extern void mp_1m_put_mbyte(int32 addr, int32 val); + +/* SS-50 I/O address space functions */ + +/* MP-S serial I/O 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); + +/* DC-4 FDC I/O routines */ +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); + +/* +MP-B3 configured with 4 address per SS-30 slot (x8). + +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] = { + {&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /* Port 0 E000-E003 */ + {&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /* Port 1 E004-E007 */ +/* 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 E008-E00B */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* Port 3 E00C-E00F */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* Port 4 E010-E013 */ + {&fdcdrv}, {&nulldev}, {&nulldev}, {&nulldev}, /* Port 5 E014-E017 */ + {&fdccmd}, {&fdctrk}, {&fdcsec}, {&fdcdata}, /* Port 6 E018-E01B */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev} /* Port 7 E01C-E01F */ +}; + +/* dummy i/o device */ + +int32 nulldev(int32 io, int32 data) +{ + if (io == 0) { + return (0xFF); + } else { + return 0; + } +} + +/* Mother Board data structures + + MB_dev Mother Board device descriptor + MB_unit Mother Board unit descriptor + MB_reg Mother Board register list + MB_mod Mother Board modifiers list +*/ + +UNIT MB_unit = { + UDATA (NULL, 0, 0) +}; + +REG MB_reg[] = { + { NULL } +}; + +MTAB MB_mod[] = { + { UNIT_4BYTESPERSLOT, UNIT_4BYTESPERSLOT, "I/O port size of 4 bytes", "4BYTE", NULL, NULL }, + { UNIT_4BYTESPERSLOT, 0, "I/O port size of 16 bytes is not supported", "16BYTE", NULL, NULL }, + { 0 } +}; + +DEBTAB MB_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE MB_dev = { + "MP-B3", //name + &MB_unit, //units + MB_reg, //registers + MB_mod, //modifiers + 1, //numunits + 16, //aradix + 20, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + &MB_examine, //examine + &MB_deposit, //deposit + &MB_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + MB_debug, /* debflags */ + NULL, //msize + NULL //lname +}; + +/* reset */ +t_stat MB_reset (DEVICE *dptr) +{ + return SCPE_OK; +} + +/* Deposit routine */ +t_stat MB_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= 0x100000) { + /* exceed 20-bit address space */ + return SCPE_NXM; + } else { + MB_put_mbyte(addr, val); + return SCPE_OK; + } +} + +/* Examine routine */ +t_stat MB_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= 0x100000) { + return SCPE_NXM; + } + if (eval_array != NULL) { + *eval_array = MB_get_mbyte(addr); + } + return SCPE_OK; +} + +/* get a byte from memory */ + +int32 MB_get_mbyte(int32 addr) +{ + int32 val; + + // 20-bit physical addresses + sim_debug (DEBUG_read, &MB_dev, "MB_get_mbyte: addr=%05X\n", addr); + switch (addr & 0x0F800) { + case 0x0E000: + /* reserved I/O space from $E000-$E01F */ + if ((addr & 0xFFFF) < 0xE020) { + val = (dev_table[(addr & 0xFFFF) - 0xE000].routine(0, 0)) & 0xFF; + break; + } + case 0x0E800: + case 0x0F000: + case 0x0F800: + /* Up to 8KB of boot ROM from $E000-$FFFF */ + val = BOOTROM_get_mbyte(addr & 0xFFFF); + sim_debug (DEBUG_read, &MB_dev, "MB_get_mbyte: EPROM=%02X\n", val); + break; + default: + /* all the rest is RAM */ + val = mp_1m_get_mbyte(addr); + if (MB_dev.dctrl & DEBUG_read) { + printf("MB_get_mbyte: mp_1m add=%05x val=%02X\n", addr, val); + } + break; + } + sim_debug (DEBUG_read, &MB_dev, "MB_get_mbyte: I/O addr=%05X val=%02X\n", addr, val); + return val; +} + +/* get a word from memory */ + +int32 MB_get_mword(int32 addr) +{ + int32 val; + + sim_debug (DEBUG_read, &MB_dev, "MB_get_mword: addr=%04X\n", addr); + val = (MB_get_mbyte(addr) << 8); + val |= MB_get_mbyte(addr+1); + val &= 0xFFFF; + sim_debug (DEBUG_read, &MB_dev, "MB_get_mword: val=%04X\n", val); + return val; +} + +/* put a byte to memory */ + +void MB_put_mbyte(int32 addr, int32 val) +{ + // 20-bit physical addresses + sim_debug (DEBUG_write, &MB_dev, "MB_put_mbyte: addr=%05X, val=%02X\n", addr, val); + + switch(addr & 0xF000) { + case 0xE000: + /* I/O and ROM space */ + if ((addr & 0xFFFF) < 0xE020) { + dev_table[(addr & 0xFFFF) - 0xE000].routine(1, val); + } + break; + case 0xF000: + /* ROM space */ + break; + default: + /* RAM */ + mp_1m_put_mbyte(addr, val); + break; + } +} + +/* put a word to memory */ + +void MB_put_mword(int32 addr, int32 val) +{ + sim_debug (DEBUG_write, &MB_dev, "MB_ptt_mword: addr=%04X, val=%04X\n", addr, val); + MB_put_mbyte(addr, val >> 8); + MB_put_mbyte(addr+1, val & 0xFF); +} + +/* end of mp-b3.c */ diff --git a/swtp6809/swtp6809/mp-09_sys.c b/swtp6809/swtp6809/mp-09_sys.c index e99486838..3c0f79298 100644 --- a/swtp6809/swtp6809/mp-09_sys.c +++ b/swtp6809/swtp6809/mp-09_sys.c @@ -1,89 +1,115 @@ -/* mp09_sys.c: SWTP 6809 system interface - - Copyright (c) 2005-2012, 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. - - MODIFICATIONS - - 20 Feb 24 -- Richard Lukes - Modified mp-a2_sys.c for SWTP MP-09 emulation -*/ - -#include -#include -#include "swtp_defs.h" - -/* externals */ - -extern DEVICE CPU_BD_dev; -extern DEVICE m6809_dev; -extern REG m6809_reg[]; -extern DEVICE BOOTROM_dev; - -extern DEVICE MB_dev; -extern DEVICE sio_dev; -extern DEVICE ptr_dev; -extern DEVICE ptp_dev; -extern DEVICE mp_1m_dev; -extern DEVICE dsk_dev; - -/* SCP data structures - - sim_name simulator name string - sim_PC pointer to saved PC register descriptor - sim_emax number of words needed for examine - sim_devices array of pointers to simulated devices - sim_stop_messages array of pointers to stop messages - sim_load binary loader -*/ - -char sim_name[] = "SWTP 6809, V0.7, MP-09 CPU Board"; - -REG *sim_PC = &m6809_reg[0]; - -// maximum number of words needed for examine -int32 sim_emax = 4; - -DEVICE *sim_devices[] = { - &m6809_dev, - &CPU_BD_dev, - &BOOTROM_dev, - &MB_dev, - &sio_dev, - &ptr_dev, - &ptp_dev, - &mp_1m_dev, - &dsk_dev, - NULL -}; - -const char *sim_stop_messages[] = { - "Unknown error", - "RESERVED", - "Halt instruction", - "Breakpoint" - "Invalid opcode", - "Invalid memory", - "Unknown error" -}; - -/* end of mp09_sys.c */ +/* mp09_sys.c: SWTP 6809 system interface + + Copyright (c) 2005-2012, 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. + + The following copyright notice applies to the SWTP 6809 source, binary, and documentation: + + Original code published in 2024, written by Richard F Lukes + Copyright (c) 2024, Richard F Lukes + + 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 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 names of The Authors shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the Authors. + + MODIFICATIONS + + 24 Feb 24 -- Richard Lukes - Modified mp-a2_sys.c for SWTP MP-09 emulation +*/ + +#include +#include +#include "swtp_defs.h" + +/* externals */ + +extern DEVICE CPU_BD_dev; +extern DEVICE m6809_dev; +extern REG m6809_reg[]; +extern DEVICE BOOTROM_dev; + +extern DEVICE MB_dev; +extern DEVICE sio_dev; +extern DEVICE ptr_dev; +extern DEVICE ptp_dev; +extern DEVICE mp_1m_dev; +extern DEVICE dsk_dev; + +/* SCP data structures + + sim_name simulator name string + sim_PC pointer to saved PC register descriptor + sim_emax number of words needed for examine + sim_devices array of pointers to simulated devices + sim_stop_messages array of pointers to stop messages + sim_load binary loader +*/ + +char sim_name[] = "SWTP 6809, V1.0, MP-09 CPU Board"; + +REG *sim_PC = &m6809_reg[0]; + +// maximum number of words needed for examine +int32 sim_emax = 4; + +DEVICE *sim_devices[] = { + &m6809_dev, + &CPU_BD_dev, + &BOOTROM_dev, + &MB_dev, + &sio_dev, + &ptr_dev, + &ptp_dev, + &mp_1m_dev, + &dsk_dev, + NULL +}; + +const char *sim_stop_messages[] = { + "Unknown error", + "RESERVED", + "Halt instruction", + "Breakpoint" + "Invalid opcode", + "Invalid memory", + "Unknown error" +}; + +/* end of mp09_sys.c */ diff --git a/swtp6809/swtp6809/sbuge.bin b/swtp6809/swtp6809/sbuge.bin new file mode 100644 index 0000000000000000000000000000000000000000..8c772c07a9594210390443855f357ad620f5300a GIT binary patch literal 2048 zcmYjSe@q+q6~7-}6G(}CVZ@KJZuf=2T}^=4^qlmz5eg;*+$>=@ESdjk7LQgHN{hBu zO{FP`t(sc{__|F~oBp#p8ok>xYTB&A)szvE5NqwamQC$8RZ4AK3%bzKLlcP&^?BcO zR%zd_zVE)D_kHj4-rc=-m#fa5DEz(fZXr`xE6f$%EWExMQOyBPP0b}aEu_Z+LS9Xy zE2%Uvr<0WC0n`qt+kqYi)C9I#KmjK+?UR8u zz*Y(9AVIw{AQq4bXdgj6C1_$^rTSP$NNI1f>Bb0Rcgs z1T6u23s8j)g_d{rrxAYTW_3Fu{QvUL3gu$lX}hs(vqaE*8~{D=tQZGv6a zCofEj<$!*obO0K0*WqjK4m=C&gM1r#>@FVLfK{Dk5}sOYpkwRL0|ZgQusm zqK(|8$hHM#iL=78EAcF_mjGewjRE^QpqhZN4v32{TADC!MBy_#8Ko5v9S~OW<&n%t z2H0Ja%lXr(VB;xZKjrZ!LlXLZT90v4*~T?49xQ2?mGq}E@jIm`qpl8M4_YB7fqmY? z0et}2eqd$Q90T@LdV&~1j2#KXaoXUNe@p1IHzFoNzX64G1|8iEH3753%m*W<)CMeETJS02n7$4Pp50nrmK^zN>MI) zf}(_cK)9{g6X}}h-rMP#8zf(nO1d`cB*_qEJqd*?ZZM*4CjE6ibl1eV(M&S=Dv1)c ztZWDR=GjyR=-0x2ArG_`mc{n4TUY}cB*rNKRdm)#+){cay^v7T3S)~f-AAgqpO;9Z3o}=(i zCW)7aRC5*R+P|>;d7zf#L7+Zb39kHTB|-|D`seVFugR0^CO@xYF&6(HB&&vw0YHB!cRpjoQL=-r3I)fQM=R2(?roOary}l zCr7tC+j`01&qcR5@3*>0j*f&~jo%2%^=!x`hdUdq!aZcWR}P&#d3~65v z6JcPXB6d%oNF>C~DhQBK$2~g9os?^+DW%(ZeMb+J}zz zb{^?KmZ}-|cl!O-wX5%lANL)?`v(RN4}1$F+`bQ^y?Z>;18r^>#{T|xgmJ&ul7oIr z_WhtFk6E(2blPccyDZ`L5{CUfy?uuQ-}n06$V%z|hFUZfyB_ihn~I@F)P)$Q4qjZ1 zaMKZPDk9$FI%iN5Mojn||Kp1YX?p8LC5i>^z0{o5t$NEyEAiW{RE}uArp^CZi}i$n z(A*^v{{00(sRf?1ocVLl+x1uRhss*Xzg4MR(gd5YDUYj1wB_c*eBF{JBC-t~3|F@N zhonb7;W0f#e#8Ddsf;5ReDaml99i>ZCCU0TS?^fi!==!)@9?p{+0?re#UlBQj$cl_ kS6?o1pUua+pIqC^uXYj3YsE{&WO1hW$Kq`98ky980S-DW-~a#s literal 0 HcmV?d00001 diff --git a/swtp6809/swtp6809/swtp6809mp-09.ini b/swtp6809/swtp6809/swtp6809mp-09.ini index 0a7167c2e..8a33ff309 100644 --- a/swtp6809/swtp6809/swtp6809mp-09.ini +++ b/swtp6809/swtp6809/swtp6809mp-09.ini @@ -1,13 +1,13 @@ -reset -set mp-b3 1MB -set cpu hex -set cpu itrap -set cpu mtrap -set dc-40 RO -set dc-41 RO -set mp-s TTY -set bootrom 2716 -attach bootrom sbuge.bin -attach dc-40 FULL.DSK -attach dc-41 FULL2.DSK -boot cpu +reset +set mp-09 DAT +set mp-1m 1MB +set cpu hex +set cpu itrap +set dc-40 RO +set dc-41 RO +set mp-s TTY +set bootrom 2716 +attach bootrom sbuge.bin +attach dc-40 FULL.DSK +attach dc-41 FULL2.DSK +boot cpu diff --git a/swtp6809/swtp6809/swtp_defs.h b/swtp6809/swtp6809/swtp_defs.h index c0c58549e..6b91e4629 100644 --- a/swtp6809/swtp6809/swtp_defs.h +++ b/swtp6809/swtp6809/swtp_defs.h @@ -1,64 +1,64 @@ -/* swtp_defs.h: SWTP 6809 simulator definitions - - Copyright (c) 2005-2012, 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 SHAL - 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 I - 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. - - MODIFICATIONS - - 20 Feb 24 - Richard Lukes - Modified for swtp6809 emulator -*/ - -#include -#include "sim_defs.h" // simulator defs - -/* Rename of global PC variable to avoid namespace conflicts on some platforms */ - -#define PC PC_Global - -/* Memory */ - -#define MAXMEMSIZE 65536 // max memory size -#define MEMSIZE (m6809_unit.capac) // actual memory size -#define ADDRMASK (MAXMEMSIZE - 1) // address mask -#define BYTEMASK 0xFF -#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) - -/* debug definitions */ - -#define DEBUG_flow 0x0001 -#define DEBUG_read 0x0002 -#define DEBUG_write 0x0004 -#define DEBUG_level1 0x0008 -#define DEBUG_level2 0x0010 -#define DEBUG_reg 0x0020 -#define DEBUG_asm 0x0040 -#define DEBUG_all 0xFFFF - -/* Simulator stop codes */ - -#define STOP_RSRV 1 // must be 1 -#define STOP_HALT 2 // HALT-really WAI -#define STOP_IBKPT 3 // breakpoint -#define STOP_OPCODE 4 // invalid opcode -#define STOP_MEMORY 5 // invalid memory address - +/* swtp_defs.h: SWTP 6809 simulator definitions + + Copyright (c) 2005-2012, 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 SHAL + 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 I + 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. + + MODIFICATIONS + + 24 Feb 24 - Richard Lukes - Modified for swtp6809 emulator +*/ + +#include +#include "sim_defs.h" // simulator defs + +/* Rename of global PC variable to avoid namespace conflicts on some platforms */ + +#define PC PC_Global + +/* Memory */ + +#define MAXMEMSIZE 65536 // max memory size +#define MEMSIZE (m6809_unit.capac) // actual memory size +#define ADDRMASK (MAXMEMSIZE - 1) // address mask +#define BYTEMASK 0xFF +#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) + +/* debug definitions */ + +#define DEBUG_flow 0x0001 +#define DEBUG_read 0x0002 +#define DEBUG_write 0x0004 +#define DEBUG_level1 0x0008 +#define DEBUG_level2 0x0010 +#define DEBUG_reg 0x0020 +#define DEBUG_asm 0x0040 +#define DEBUG_all 0xFFFF + +/* Simulator stop codes */ + +#define STOP_RSRV 1 // must be 1 +#define STOP_HALT 2 // HALT-really WAI +#define STOP_IBKPT 3 // breakpoint +#define STOP_OPCODE 4 // invalid opcode +#define STOP_MEMORY 5 // invalid memory address + From 3917cf8d3bdac18d362cb247bd5a5cee92ebf787 Mon Sep 17 00:00:00 2001 From: rfromafar Date: Sun, 18 Feb 2024 19:54:15 -0600 Subject: [PATCH 05/10] # This is a combination of 5 commits. # This is the 1st commit message: Richard Lukes - 18 FEB 2024 This is my initial commit of my swtp6809 emulator which is a modified version of the swtp6800 emulator. The following changes are still outstanding: - various code clean up tasks and removal of temporary comments - bootrom.c - reset() appears to be performing attach() funtion, I plan to clean up soon - mp-b3.c - want to add #define for 4 bytes per slot versus 16 bytes per slot - dc-4.c - trying to understand the changes I made from the original dc-4.c in the swtp6800 emulator - I will do additional testing, however, for now this boots Flex 9.0 and appears to be working fine # This is the commit message #2: In preparation of presenting for contribution as a "pull request". General clean up of code. Removed unneeded test prints that were used for debugging. Removed swtp_sbuge_bin.h which implemented BOOTROM code internally. Users should use "ATTACH BOOTROM ". Added reset() routine to CPU. If last line in INI file is "RESET CPU" then simulator goes straight into BOOTROM from reset vector at $FFFE. Tested with several FLEX 9 DSK files. Known issues are: 1) Backspace (BS) does not seem to work when running Flex 9. 2) When simulator starts up the PC has a value of $FFFF (and not $FFFE). 3) No DMAF1/DMAF2 disk emulation which is required for support of UniFlex. 4) No documentation has been written yet. However, I am more than willing to put something together. Note this code was developed using Debian on Raspberry Pi 4. There may be Unix/DOS file conversion issues. # This is the commit message #3: swtp6809 simulator being contributed to open-simh project #357 (Pull Request) - updates to code while writing the simulator usage guide - added copyright notice to relevant source code modules - used unix2dos to format source files for DOS line terminator conventions - source code files from swtp6800 with some changes: swtp_defs.h, dc-4.c - source code files from swtp6800 that are unchanged: mp-s. # This is the commit message #4: CMake: Reduce excess quoting cmake/cmake-builder.ps1 added quotes to arguments that contained spaces, so that arguments printed correctly for progress output. This introduced excess quotes that caused CMake (and likely other MS apps) confusion or argument misinterpretation. Instead of CMake seeing a single "Visual Studio 17 2022", CMake was actually seeing "\"Visual Studio 17 2022\"". This patch only adds the additional quotes when reporting progress or emitting debug output. Otherwise, command line arguments are passed unmolested. # This is the commit message #5: The user doc file for the swtp6809 simulator SWTP 6809 Simulator Usage guide. --- cmake/cmake-builder.ps1 | 10 +- doc/swtp6809_doc.doc | Bin 0 -> 183296 bytes makefile | 20 +- swtp6809/common/bootrom.c | 343 +++ swtp6809/common/dc-4.c | 651 +++++ swtp6809/common/m6809.c | 3413 +++++++++++++++++++++++++++ swtp6809/common/mp-09.c | 296 +++ swtp6809/common/mp-1m.c | 311 +++ swtp6809/common/mp-b3.c | 308 +++ swtp6809/common/mp-s.c | 381 +++ swtp6809/swtp6809/mp-09_sys.c | 115 + swtp6809/swtp6809/sbuge.bin | Bin 0 -> 2048 bytes swtp6809/swtp6809/swtp6809mp-09.ini | 13 + swtp6809/swtp6809/swtp_defs.h | 64 + 14 files changed, 5919 insertions(+), 6 deletions(-) create mode 100644 doc/swtp6809_doc.doc create mode 100644 swtp6809/common/bootrom.c create mode 100644 swtp6809/common/dc-4.c create mode 100644 swtp6809/common/m6809.c create mode 100644 swtp6809/common/mp-09.c create mode 100644 swtp6809/common/mp-1m.c create mode 100644 swtp6809/common/mp-b3.c create mode 100644 swtp6809/common/mp-s.c create mode 100644 swtp6809/swtp6809/mp-09_sys.c create mode 100644 swtp6809/swtp6809/sbuge.bin create mode 100644 swtp6809/swtp6809/swtp6809mp-09.ini create mode 100644 swtp6809/swtp6809/swtp_defs.h diff --git a/cmake/cmake-builder.ps1 b/cmake/cmake-builder.ps1 index 947ca3e14..2e67676da 100644 --- a/cmake/cmake-builder.ps1 +++ b/cmake/cmake-builder.ps1 @@ -495,14 +495,14 @@ foreach ($phase in $scriptPhases) { Write-Host "** ${scriptName}: Configuring and generating" $phaseCommand = ${cmakeCmd} - $argList = Quote-Args $generateArgs + $argList = $generateArgs } "build" { Write-Host "** ${scriptName}: Building simulators." $phaseCommand = ${cmakeCmd} - $argList = $(Quote-Args $buildArgs) + $(Quote-Args $buildSpecificArgs) + $argList = $buildArgs + $buildSpecificArgs } "test" { @@ -529,7 +529,7 @@ foreach ($phase in $scriptPhases) { } $phaseCommand = ${ctestCmd} - $argList = Quote-Args $testArgs + $argList = $testArgs $env:PATH = $modPath @@ -556,13 +556,13 @@ foreach ($phase in $scriptPhases) { } $phaseCommand = ${cmakeCmd} - $argList = Quote-Args @( "--install", "${buildDir}", "--config", "${config}") + $argList = @( "--install", "${buildDir}", "--config", "${config}") } } try { Push-Location ${buildDir} - Write-Host "** ${phaseCommand} ${argList}" + Write-Host "** ${phaseCommand} $(Quote-Args ${argList})" & $phaseCommand @arglist if ($LastExitCode -gt 0) { $printPhase = (Get-Culture).TextInfo.ToTitleCase($phase) diff --git a/doc/swtp6809_doc.doc b/doc/swtp6809_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..ea0078712df9646ed7e6803d2c395d9679169957 GIT binary patch literal 183296 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 +#include "swtp_defs.h" + +#define UNIT_V_MSIZE (UNIT_V_UF) /* ROM Size */ +#define UNIT_MSIZE (0x2F << UNIT_V_MSIZE) +#define UNIT_NONE (0x1 << UNIT_V_MSIZE) /* No EPROM */ +#define UNIT_2704 (0x2 << UNIT_V_MSIZE) /* 2704 mode */ +#define UNIT_2708 (0x4 << UNIT_V_MSIZE) /* 2708 mode */ +#define UNIT_2716 (0x8 << UNIT_V_MSIZE) /* 2716 mode */ +#define UNIT_2732 (0x10 << UNIT_V_MSIZE) /* 2732 mode */ +#define UNIT_2764 (0x20 << UNIT_V_MSIZE) /* 2764 mode */ + +/* Maximum size of bootrom is 8KB from $E000-$FFFF */ +#define MAX_BOOTROM_SIZE (8*1024) + +// this value is used when referencing BOOTROM memory that is not populated (i.e. not loaded by BOOTROM attach) +#define DEFAULT_NO_ROM_BYTE_VALUE 0xFF + +/* function prototypes */ + +t_stat BOOTROM_attach(UNIT *uptr, CONST char *cptr); +t_stat BOOTROM_config(UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat BOOTROM_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); +t_stat BOOTROM_reset(DEVICE *dptr); + +int32 BOOTROM_get_mbyte(int32 address); + +/* SIMH Standard I/O Data Structures */ + +UNIT BOOTROM_unit = { + UDATA (NULL, UNIT_ATTABLE+UNIT_BINK+UNIT_ROABLE+UNIT_RO, 0), + KBD_POLL_WAIT }; + +MTAB BOOTROM_mod[] = { + { UNIT_MSIZE, UNIT_NONE, "None", "NONE", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_2704, "2704", "2704", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_2708, "2708", "2708", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_2716, "2716", "2716", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_2732, "2732", "2732", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_2764, "2764", "2764", &BOOTROM_config }, + { 0 } +}; + +DEBTAB BOOTROM_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE BOOTROM_dev = { + "BOOTROM", /* name */ + &BOOTROM_unit, /* units */ + NULL, /* registers */ + BOOTROM_mod, /* modifiers */ + 1, /* numunits */ + 16, /* aradix */ + 16, /* awidth */ + 1, /* aincr */ + 16, /* dradix */ + 8, /* dwidth */ + &BOOTROM_examine, /* examine */ + NULL, /* deposit */ + &BOOTROM_reset, /* reset */ + NULL, /* boot */ + &BOOTROM_attach, /* attach */ + NULL, /* detach */ + NULL, /* ctxt */ + DEV_DEBUG, /* flags */ + 0, /* dctrl */ + BOOTROM_debug, /* debflags */ + NULL, /* msize */ + NULL /* lname */ +}; + +/* global variables */ + +/* MP-09 actually has 4 x 2KB EPROM sockets at $E000, $E800, $F000, $F800 */ +/* This will be emulated as a single BOOTROM having a high address of $FFFF and variable start address depending on size */ +/* Available sizes are None=0, 512B=2704, 1KB=2708, 2KB=2716, 4KB=2732, 8KB=2764 */ + +/* Pre-allocate 8KB array of bytes to accomodate largest BOOTROM */ +uint8 BOOTROM_memory[MAX_BOOTROM_SIZE]; + +/* BOOTROM_examine routine */ +t_stat BOOTROM_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= BOOTROM_unit.capac || addr >= MAX_BOOTROM_SIZE) { + return SCPE_NXM; + } + if (eval_array != NULL) { + *eval_array = BOOTROM_memory[addr]; + } + return SCPE_OK; + +} /* BOOTROM_examine() */ + +/* BOOTROM_attach - attach file to EPROM unit */ +t_stat BOOTROM_attach(UNIT *uptr, CONST char *cptr) +{ + t_stat r; + t_addr image_size; + int i,j; + FILE *fp; + uint8 byte_val; + size_t items_read; + + if (BOOTROM_unit.filebuf == NULL) { /* no buffer allocated */ + BOOTROM_unit.filebuf = BOOTROM_memory; + } + if ((BOOTROM_unit.flags & UNIT_MSIZE) == 0) { /* if none selected */ + BOOTROM_unit.capac = 0; /* set EPROM size to 0 */ + return SCPE_OK; + } + + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_attach: cptr=%s\n", cptr); + if ((r = attach_unit(uptr, cptr)) != SCPE_OK) { + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_attach: Error %d\n", r); + return r; + } + + image_size = (t_addr) sim_fsize_ex(uptr->fileref); + if (image_size <= 0) { + sim_printf("BOOTROM_attach: File error\n"); + detach_unit(uptr); + return SCPE_IOERR; + } else { + if (image_size > MAX_BOOTROM_SIZE) { + sim_printf("BOOTROM_attach: Error. File size exceeds ROM capacity\n"); + detach_unit(uptr); + return SCPE_ARG; + } + } + + /* open EPROM file */ + fp = fopen(BOOTROM_unit.filename, "rb"); + if (fp == NULL) { + printf("Bootrom: Unable to open ROM file %s\n",BOOTROM_unit.filename); + printf("Bootrom: No ROM image loaded!!!\n"); + return SCPE_OK; + } + + /* load EPROM file */ + j = 0; + items_read = sim_fread(&byte_val, (size_t)1, (size_t)1, fp); + while (items_read != 0) { + BOOTROM_memory[j++] = byte_val; + items_read = sim_fread(&byte_val, (size_t)1, (size_t)1,fp); + if (j > BOOTROM_unit.capac) { + printf("Bootrom: Image is too large - Load truncated!!!\n"); + j--; + break; + } + } + fclose(fp); + printf("Bootrom: %d bytes of ROM image %s loaded\n", j, BOOTROM_unit.filename); + + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_attach: Done\n"); + return SCPE_OK; + +} /* BOOTROM_attach() */ + +/* BOOTROM_config = None, 2704, 2708, 2716, 2732 or 2764 */ +t_stat BOOTROM_config (UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: val=%d\n", val); + if ((val < UNIT_NONE) || (val > UNIT_2764)) { /* valid param? */ + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: Parameter error\n"); + return SCPE_ARG; + } + if (val == UNIT_NONE) { + BOOTROM_unit.capac = 0; /* set EPROM size */ + } else { + //BOOTROM_unit.capac = 0x200 ((val >> UNIT_V_MSIZE) - 1); /* set EPROM size */ + BOOTROM_unit.capac = 0x100 * (val >> UNIT_V_MSIZE); /* set EPROM size */ + } + + if (!BOOTROM_unit.filebuf) { /* point buffer to static array */ + BOOTROM_unit.filebuf = BOOTROM_memory; + } + + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: BOOTROM_unit.capac=%d\n", + BOOTROM_unit.capac); + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: Done\n"); + + return SCPE_OK; +} /* BOOTROM config */ + +/* BOOTROM reset */ +t_stat BOOTROM_reset (DEVICE *dptr) +{ + t_addr i; + + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_reset: \n"); + + /* allocate filebuf */ + if (BOOTROM_unit.filebuf == NULL) { /* no buffer allocated */ + //BOOTROM_unit.filebuf = calloc(1, BOOTROM_unit.capac); /* allocate EPROM buffer */ + BOOTROM_unit.filebuf = BOOTROM_memory; + if (BOOTROM_unit.filebuf == NULL) { + return SCPE_MEM; + } + } + return SCPE_OK; + +} /* BOOTROM_reset() */ + +/* get a byte from memory - from specified memory address */ +int32 BOOTROM_get_mbyte(int32 address) +{ + int32 val; + uint8 *pa; + + if (BOOTROM_unit.filebuf == NULL) { + sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: EPROM not configured\n"); + return DEFAULT_NO_ROM_BYTE_VALUE; + } + sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: address=%04X\n", address); + if ((t_addr)(0xFFFF - address) > BOOTROM_unit.capac) { + sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: EPROM reference beyond ROM size\n"); + return DEFAULT_NO_ROM_BYTE_VALUE; + } + + pa = BOOTROM_unit.filebuf; + /* the following code is needed to calculate offsets so address $FFFF references the last byte of the ROM */ + val = DEFAULT_NO_ROM_BYTE_VALUE; + switch (BOOTROM_unit.capac) { + /* 2764 - $E000-$FFFF */ + case 0x2000: + val = pa[address - 0xE000]; + break; + /* 2732 - $F000-$FFFF */ + case 0x1000: + if (address >=0xF000) { + val = pa[address - 0xF000]; + } + break; + /* 2716 - $F800-$FFFF */ + case 0x0800: + if (address >= 0xF800) { + val = pa[address - 0xF800]; + } + break; + /* 2708 - $FC00-$FFFF */ + case 0x0400: + if (address >= 0xFC00) { + val = pa[address - 0xFC00]; + } + break; + /* 2704 - $FE00-$FFFF*/ + case 0x0200: + if (address >= 0xFE00) { + val = pa[address - 0xFE00]; + } + break; + default: + break; + } + val &= 0xFF; + sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: Normal val=%02X\n", val); + return val; +} /* BOOTROM_get_mbyte() */ + +/* end of bootrom.c */ diff --git a/swtp6809/common/dc-4.c b/swtp6809/common/dc-4.c new file mode 100644 index 000000000..f37e530ab --- /dev/null +++ b/swtp6809/common/dc-4.c @@ -0,0 +1,651 @@ +/* dc4.c: SWTP DC-4 FDC Simulator + + Copyright (c) 2005-2012, William A. 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. + + MODIFICATIONS: + + 23 Apr 15 -- Modified to use simh_debug + 24 Feb 24 -- Richard Lukes - Modified to work with swtp6809 emulator + + NOTES: + + The DC-4 is a 5-inch floppy controller which can control up + to 4 daisy-chained 5-inch floppy drives. The controller is based on + the Western Digital 1797 Floppy Disk Controller (FDC) chip. This + file only emulates the minimum DC-4 functionality to interface with + the virtual disk file. + + The floppy controller is interfaced to the CPU by use of 5 memory + addreses. These are SS-30 slot numbers 5 and 6 (0xE014-0xE01B) on a SWTPC 6809 computer. + + Address Mode Function + ------- ---- -------- + + 0xE014 Read Returns FDC interrupt status + 0xE014 Write Selects the drive/head/motor control + 0xE018 Read Returns status of FDC + 0xE018 Write FDC command register + 0xE019 Read Returns FDC track register + 0xE019 Write Set FDC track register + 0xE01A Read Returns FDC sector register + 0xE01A Write Set FDC sector register + 0xE01B Read Read data + 0xE01B Write Write data + + Drive Select Read (0xE014): + + +---+---+---+---+---+---+---+---+ + | I | D | X | X | X | X | X | X | + +---+---+---+---+---+---+---+---+ + + I = Set indicates an interrupt request from the FDC pending. + D = DRQ pending - same as bit 1 of FDC status register. + + Drive Select Write (0xE014): + + +---+---+---+---+---+---+---+---+ + | M | S | X | X | X | X | Device| + +---+---+---+---+---+---+---+---+ + + M = If this bit is 1, the one-shot is triggered/retriggered to + start/keep the motors on. + S = Side select. If set, side one is selected otherwise side zero + is selected. + X = not used + Device = value 0 thru 3, selects drive 0-3 to be controlled. + + Drive Status Read (0xE018): + + +---+---+---+---+---+---+---+---+ + | R | P | H | S | C | L | D | B | + +---+---+---+---+---+---+---+---+ + + B - When 1, the controller is busy. + D - When 1, index mark detected (type I) or data request - read data + ready/write data empty (type II or III). + H - When 1, track 0 (type I) or lost data (type II or III). + C - When 1, crc error detected. + S - When 1, seek (type I) or RNF (type II or III) error. + H - When 1, head is currently loaded (type I) or record type/ + write fault (type II or III). + P - When 1, indicates that diskette is write-protected. + R - When 1, drive is not ready. + + Drive Control Write (0xE018) for type I commands: + + +---+---+---+---+---+---+---+---+ + | 0 | S2| S1| S0| H | V | R1| R0| + +---+---+---+---+---+---+---+---+ + + R0/R1 - Selects the step rate. + V - When 1, verify on destination track. + H - When 1, loads head to drive surface. + S0/S1/S2 = 000 - home. + 001 - seek track in data register. + 010 - step without updating track register. + 011 - step and update track register. + 100 - step in without updating track register. + 101 - step in and update track register. + 110 - step out without updating track register. + 111 - step out and update track register. + + Drive Control Write (0xE018) for type II commands: + + +---+---+---+---+---+---+---+---+ + | 1 | 0 | T | M | S | E | B | A | + +---+---+---+---+---+---+---+---+ + + A - Zero for read, 1 on write deleted data mark else data mark. + B - When 1, shifts sector length field definitions one place. + E - When, delay operation 15 ms, 0 no delay. + S - When 1, select side 1, 0 select side 0. + M - When 1, multiple records, 0 for single record. + T - When 1, write command, 0 for read. + + Drive Control Write (0xE018) for type III commands: + + +---+---+---+---+---+---+---+---+ + | 1 | 1 | T0| T1| 0 | E | 0 | 0 | + +---+---+---+---+---+---+---+---+ + + E - When, delay operation 15 ms, 0 no delay. + T0/T1 - 00 - read address command. + 10 - read track command. + 11 - write track command. + + Tracks are numbered from 0 up to one minus the last track in the 1797! + + Track Register Read (0xE019): + + +---+---+---+---+---+---+---+---+ + | Track Number | + +---+---+---+---+---+---+---+---+ + + Reads the current 8-bit value from the track position. + + Track Register Write (0xE019): + + +---+---+---+---+---+---+---+---+ + | Track Number | + +---+---+---+---+---+---+---+---+ + + Writes the 8-bit value to the track register. + + Sectors are numbers from 1 up to the last sector in the 1797! + + Sector Register Read (0xE01A): + + +---+---+---+---+---+---+---+---+ + | Sector Number | + +---+---+---+---+---+---+---+---+ + + Reads the current 8-bit value from the sector position. + + Sector Register Write (0xE01A): + + +---+---+---+---+---+---+---+---+ + | Sector Number | + +---+---+---+---+---+---+---+---+ + + Writes the 8-bit value to the sector register. + + Data Register Read (0xE01B): + + +---+---+---+---+---+---+---+---+ + | Data | + +---+---+---+---+---+---+---+---+ + + Reads the current 8-bit value from the data register. + + Data Register Write (0xE01B): + + +---+---+---+---+---+---+---+---+ + | Data | + +---+---+---+---+---+---+---+---+ + + Writes the 8-bit value to the data register. + + A FLEX disk is defined as follows: + + Track Sector Use + 0 1 Boot sector + 0 2 Boot sector (cont) + 0 3 Unused (doesn't exist) + 0 4 System Identity Record (explained below) + 0 5 Unused + 0 6-last Directory - 10 entries/sector (explained below) + 1 1 First available data sector + last-1 last Last available data sector + + System Identity Record + + Byte Use + 0x00 Two bytes of zeroes (Clears forward link) + 0x10 Volume name in ASCII(11 bytes) + 0x1B Volume number in binary (2 bytes) + 0x1D Address of first free data sector (Track-Sector) (2 bytes) + 0x1F Address of last free data sector (Track-Sector) (2 bytes) + 0x21 Total number of data sectors in binary (2 bytes) + 0x23 Current date (Month-Day-Year) in binary + 0x26 Highest track number on disk in binary (byte) + 0x27 Highest sector number on a track in binary (byte) + + The following unit registers are used by this controller emulation: + + dsk_unit[cur_drv].u3 unit current flags + dsk_unit[cur_drv].u4 unit current track + dsk_unit[cur_drv].u5 unit current sector + dsk_unit[cur_drv].pos unit current sector byte index into buffer + dsk_unit[cur_drv].filebuf unit current sector buffer + dsk_unit[cur_drv].fileref unit current attached file reference +*/ + +#include +#include "swtp_defs.h" + +#define DEBUG 0 + +#define UNIT_V_ENABLE (UNIT_V_UF + 0) /* Write Enable */ +#define UNIT_ENABLE (1 << UNIT_V_ENABLE) + +/* maximum of 4 disks, sector size is fixed at 256 bytes */ + +#define NUM_DISK 4 /* standard 1797 maximum */ +#define SECT_SIZE 256 /* standard FLEX sector */ + +/* SIR offsets */ +#define MAXCYL 0x26 /* last cylinder # */ +#define MAXSEC 0x27 /* last sector # */ + +/* 1797 status bits */ + +#define BUSY 0x01 +#define DRQ 0x02 +#define WRPROT 0x40 +#define NOTRDY 0x80 + +/* function prototypes */ + +t_stat dsk_reset (DEVICE *dptr); + +/* SS-50 I/O address space functions */ + +int32 fdcdrv(int32 io, int32 data); +int32 fdccmd(int32 io, int32 data); +int32 fdctrk(int32 io, int32 data); +int32 fdcsec(int32 io, int32 data); +int32 fdcdata(int32 io, int32 data); + +/* Local Variables */ + +int32 fdcbyte; +int32 intrq = 0; /* interrupt request flag */ +int32 cur_dsk; /* Currently selected drive */ +int32 wrt_flag = 0; /* FDC write flag */ + +int32 spt; /* sectors/track */ +int32 trksiz; /* trk size (bytes) */ +int32 heds; /* number of heads */ +int32 cpd; /* cylinders/disk */ +int32 dsksiz; /* dsk size (bytes) */ + +/* Floppy Disk Controller data structures + + dsk_dev Mother Board device descriptor + dsk_unit Mother Board unit descriptor + dsk_reg Mother Board register list + dsk_mod Mother Board modifiers list +*/ + +UNIT dsk_unit[] = { + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) } +}; + +REG dsk_reg[] = { + { HRDATA (DISK, cur_dsk, 4) }, + { NULL } +}; + +MTAB dsk_mod[] = { + { UNIT_ENABLE, UNIT_ENABLE, "RW", "RW", NULL }, + { UNIT_ENABLE, 0, "RO", "RO", NULL }, + { 0 } +}; + +DEBTAB dsk_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE dsk_dev = { + "DC-4", //name + dsk_unit, //units + dsk_reg, //registers + dsk_mod, //modifiers + NUM_DISK, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + &dsk_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + dsk_debug, /* debflags */ + NULL, //msize + NULL //lname +}; + +/* Reset routine */ + +t_stat dsk_reset (DEVICE *dptr) +{ + int i; + + cur_dsk = 5; /* force initial SIR read, use a drive # that can't be selected */ + + for (i=0; i Accumulator A + B<0:7> Accumulator B + IX<0:15> Index Register + IY<0:15> Index Register + CCR<0:7> Condition Code Register + EF Entire flag + FF FIRQ flag + HF half-carry flag + IF IRQ flag + NF negative flag + ZF zero flag + VF overflow flag + CF carry flag + PC<0:15> program counter + UP<0:15> User Stack Pointer + SP<0:15> Stack Pointer + + The M6809 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 M6809. + It is called from the CPU board simulator 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 6809, reads to non-existent memory + return 0FFH, and writes are ignored. +*/ + +#include + +#include "swtp_defs.h" + +#define UNIT_V_OPSTOP (UNIT_V_UF) /* Stop on Invalid Opcode */ +#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP) + +/* Flag values to set proper positions in CCR */ +#define EF 0x80 +#define FF 0x40 +#define HF 0x20 +#define IF 0x10 +#define NF 0x08 +#define ZF 0x04 +#define VF 0x02 +#define CF 0x01 + +/* PSH/PUL Post Byte register positions */ +#define PSH_PUL_Post_Byte_PC 0x80 +#define PSH_PUL_Post_Byte_S_U 0x40 +#define PSH_PUL_Post_Byte_Y 0x20 +#define PSH_PUL_Post_Byte_X 0x10 +#define PSH_PUL_Post_Byte_DP 0x08 +#define PSH_PUL_Post_Byte_B 0x04 +#define PSH_PUL_Post_Byte_A 0x02 +#define PSH_PUL_Post_Byte_CC 0x01 + +#define TFR_EXG_Post_Nybble_D 0 +#define TFR_EXG_Post_Nybble_X 1 +#define TFR_EXG_Post_Nybble_Y 2 +#define TFR_EXG_Post_Nybble_U 3 +#define TFR_EXG_Post_Nybble_S 4 +#define TFR_EXG_Post_Nybble_PC 5 +#define TFR_EXG_Post_Nybble_A 8 +#define TFR_EXG_Post_Nybble_B 9 +#define TFR_EXG_Post_Nybble_CC 10 +#define TFR_EXG_Post_Nybble_DP 11 + + +/* Macros to handle the flags in the CCR */ +#define CCR_MSK (EF|FF|HF|IF|NF|ZF|VF|CF) +#define TOGGLE_FLAG(FLAG) (CCR ^= (FLAG)) +#define SET_FLAG(FLAG) (CCR |= (FLAG)) +#define CLR_FLAG(FLAG) (CCR &= ~(FLAG)) +#define GET_FLAG(FLAG) (CCR & (FLAG)) + +#define COND_SET_FLAG(COND,FLAG) \ + if (COND) SET_FLAG(FLAG); else CLR_FLAG(FLAG) + +#define COND_SET_FLAG_N(VAR) \ + if ((VAR) & 0x80) SET_FLAG(NF); else CLR_FLAG(NF) +#define COND_SET_FLAG_N_16(VAR) \ + if ((VAR) & 0x8000) SET_FLAG(NF); else CLR_FLAG(NF) + +#define COND_SET_FLAG_Z(VAR) \ + if ((VAR) == 0) SET_FLAG(ZF); else CLR_FLAG(ZF) +#define COND_SET_FLAG_Z_16(VAR) \ + if ((VAR) == 0) SET_FLAG(ZF); else CLR_FLAG(ZF) + +#define COND_SET_FLAG_H(VAR) \ + if ((VAR) & 0x10) SET_FLAG(HF); else CLR_FLAG(HF) + +#define COND_SET_FLAG_C(VAR) \ + if ((VAR) & 0x100) SET_FLAG(CF); else CLR_FLAG(CF) +#define COND_SET_FLAG_C_16(VAR) \ + if ((VAR) & 0x10000) SET_FLAG(CF); else CLR_FLAG(CF) + +#define COND_SET_FLAG_V(COND) \ + if (COND) SET_FLAG(VF); else CLR_FLAG(VF) + +/* local global variables */ + +int32 A = 0; /* Accumulator A */ +int32 B = 0; /* Accumulator B */ +int32 D = 0; /* Accumulator D */ +int32 DP = 0; /* Direct Page Register */ +int32 IX = 0; /* Index register X */ +int32 IY = 0; /* Index register Y */ +int32 UP = 0; /* User Stack pointer */ +int32 SP = 0; /* Hardware Stack pointer */ +int32 CCR = EF|FF|IF; /* Condition Code Register */ +int32 saved_PC = 0; /* Saved Program counter */ +int32 previous_PC = 0; /* Previous previous Program counter */ +int32 last_PC = 0; /* Last Program counter */ +int32 PC; /* Program counter */ +int32 INTE = 0; /* Interrupt Enable */ +int32 int_req = 0; /* Interrupt request */ + +int32 mem_fault = 0; /* memory fault flag */ + +/* function prototypes */ + +t_stat m6809_reset(DEVICE *dptr); +t_stat m6809_boot(int32 unit_num, DEVICE *dptr); +t_stat m6809_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); +t_stat m6809_deposit(t_value value, t_addr addr, UNIT *uptr, int32 switches); + +void dump_regs(void); +void dump_regs1(void); +int32 fetch_byte(int32 flag); +int32 fetch_word(); +uint8 pop_sp_byte(void); +uint8 pop_up_byte(void); +uint16 pop_sp_word(void); +uint16 pop_up_word(void); +void push_sp_byte(uint8 val); +void push_up_byte(uint8 val); +void push_sp_word(uint16 val); +void push_up_word(uint16 val); +void go_rel(int32 cond); +void go_long_rel(int32 cond); +int32 get_rel_addr(void); +int32 get_long_rel_addr(void); +int32 get_dir_byte_val(void); +int32 get_dir_word_val(void); +int32 get_imm_byte_val(void); +int32 get_imm_word_val(void); +int32 get_dir_addr(void); +int32 get_indexed_byte_val(void); +int32 get_indexed_word_val(void); +int32 get_indexed_addr(void); +int32 get_ext_addr(void); +int32 get_ext_byte_val(void); +int32 get_ext_word_val(void); +int32 get_flag(int32 flag); +void condevalVa(int32 op1, int32 op2); +void condevalVa16(int32 op1, int32 op2); +void condevalVs(int32 op1, int32 op2); +void condevalVs16(int32 op1, int32 op2); +void condevalHa(int32 op1, int32 op2); + +/* external routines */ + +extern void CPU_BD_put_mbyte(int32 addr, int32 val); +extern void CPU_BD_put_mword(int32 addr, int32 val); +extern int32 CPU_BD_get_mbyte(int32 addr); +extern int32 CPU_BD_get_mword(int32 addr); + +/* CPU data structures + + m6809_dev CPU device descriptor + m6809_unit CPU unit descriptor + m6809_reg CPU register list + m6809_mod CPU modifiers list */ + +UNIT m6809_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, 65536) }; + +REG m6809_reg[] = { + { HRDATA (PC, saved_PC, 16) }, + { HRDATA (A, A, 8) }, + { HRDATA (B, B, 8) }, + { HRDATA (DP, DP, 8) }, + { HRDATA (IX, IX, 16) }, + { HRDATA (IY, IY, 16) }, + { HRDATA (SP, SP, 16) }, + { HRDATA (UP, UP, 16) }, + { HRDATA (CCR, CCR, 8) }, + { FLDATA (INTE, INTE, 16) }, + { ORDATA (WRU, sim_int_char, 8) }, + { NULL } }; + +MTAB m6809_mod[] = { + { UNIT_OPSTOP, UNIT_OPSTOP, "ITRAP", "ITRAP", NULL }, + { UNIT_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL }, + { 0 } }; + +DEBTAB m6809_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { "REG", DEBUG_reg }, + { "ASM", DEBUG_asm }, + { NULL } +}; + +DEVICE m6809_dev = { + "CPU", //name + &m6809_unit, //units + m6809_reg, //registers + m6809_mod, //modifiers + 1, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + &m6809_examine, //examine + &m6809_deposit, //deposit + &m6809_reset, //reset + &m6809_boot, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + m6809_debug, //debflags + NULL, //msize + NULL //lname +}; + +static const char *opcode[] = { +"NEG", "???", "???", "COM", //0x00 +"LSR", "???", "ROR", "ASR", +"ASL", "ROL", "DEC", "???", +"INC", "TST", "JMP", "CLR", +"PG2", "PG3", "NOP", "SYNC", //0x10 +"???", "???", "LBRA", "LBSR", +"???", "DAA", "ORCC", "???", +"ANDCC", "SEX", "EXG", "TFR", +"BRA", "BRN", "BHI", "BLS", //0x20 +"BCC", "BLO", "BNE", "BEQ", +"BVC", "BVS", "BPL", "BMI", +"BGE", "BLT", "BGT", "BLE", +"LEAX", "LEAY", "LEAS", "LEAU", //0x30 +"PSHS", "PULS", "PSHU", "PULU", +"???", "RTS", "ABX", "RTI", +"CWAI", "MUL", "???", "SWI", +"NEGA", "???", "???", "COMA", //0x40 +"LSRA", "???", "RORA", "ASRA", +"LSLA", "ROLA", "DECA", "???", +"INCA", "TSTA", "???", "CLRA", +"NEGB", "???", "???", "COMB", //0x50 +"LSRB", "???", "RORB", "ASRB", +"LSLB", "ROLB", "DECB", "???", +"INCB", "TSTB", "???", "CLRB", +"NEG", "???", "???", "COM", //0x60 +"LSR", "???", "ROR", "ASR", +"ASL", "ROL", "DEC", "???", +"INC", "TST", "JMP", "CLR", +"NEG", "???", "???", "COM", //0x70 +"LSR", "???", "ROR", "ASR", +"ASL", "ROL", "DEC", "???", +"INC", "TST", "JMP", "CLR", +"SUBA", "CMPA", "SBCA", "SUBD", //0x80 +"ANDA", "BITA", "LDA", "???", +"EORA", "ADCA", "ORAA", "ADDA", +"CMPX", "BSR", "LDX", "???", +"SUBA", "CMPA", "SBCA", "SUBD", //0x90 +"ANDA", "BITA", "LDA", "STA", +"EORA", "ADCA", "ORA", "ADDA", +"CMPX", "JSR", "LDX", "STX", +"SUBA", "CMPA", "SBCA", "SUBD", //0xA0 +"ANDA", "BITA", "LDA", "STA", +"EORA", "ADCA", "ORA", "ADDA", +"CMPX", "JSR", "LDX", "STX", +"SUBA", "CMPA", "SBCA", "SUBD", //0xB0 +"ANDA", "BITA", "LDA", "STA", +"EORA", "ADCA", "ORA", "ADDA", +"CMPX", "JSR", "LDX", "STX", +"SUBB", "CMPB", "SBCB", "ADDD", //0xC0 +"ANDB", "BITB", "LDB", "???", +"EORB", "ADCB", "ORB", "ADDB", +"LDD", "???", "LDU", "???", +"SUBB", "CMPB", "SBCB", "ADDD", //0xD0 +"ANDB", "BITB", "LDB", "STB", +"EORB", "ADCB", "ORB", "ADDB", +"LDD", "STD", "LDU", "STU", +"SUBB", "CMPB", "SBCB", "ADDD", //0xE0 +"ANDB", "BITB", "LDB", "STB", +"EORB", "ADCB", "ORB", "ADDB", +"LDD", "STD", "LDU", "STU", +"SUBB", "CMPB", "SBCB", "ADDD", //0xF0 +"ANDB", "BITB", "LDB", "STB", +"EORB", "ADCB", "ORB", "ADDB", +"LDD", "STD", "LDU", "STU" +}; + +static const char *opcode6800[] = { +"???", "NOP", "???", "???", //0x00 +"???", "???", "TAP", "TPA", +"INX", "DEX", "CLV", "SEV", +"CLC", "SEC", "CLI", "SEI", +"SBA", "CBA", "???", "???", //0x10 +"???", "???", "TAB", "TBA", +"???", "DAA", "???", "ABA", +"???", "???", "???", "???", +"BRA", "???", "BHI", "BLS", //0x20 +"BCC", "BCS", "BNE", "BEQ", +"BVC", "BVS", "BPL", "BMI", +"BGE", "BLT", "BGT", "BLE", +"TSX", "INS", "PULA", "PULB", //0x30 +"DES", "TXS", "PSHA", "PSHB", +"???", "RTS", "???", "RTI", +"???", "???", "WAI", "SWI", +"NEGA", "???", "???", "COMA", //0x40 +"LSRA", "???", "RORA", "ASRA", +"ASLA", "ROLA", "DECA", "???", +"INCA", "TSTA", "???", "CLRA", +"NEGB", "???", "???", "COMB", //0x50 +"LSRB", "???", "RORB", "ASRB", +"ASLB", "ROLB", "DECB", "???", +"INCB", "TSTB", "???", "CLRB", +"NEG", "???", "???", "COM", //0x60 +"LSR", "???", "ROR", "ASR", +"ASL", "ROL", "DEC", "???", +"INC", "TST", "JMP", "CLR", +"NEG", "???", "???", "COM", //0x70 +"LSR", "???", "ROR", "ASR", +"ASL", "ROL", "DEC", "???", +"INC", "TST", "JMP", "CLR", +"SUBA", "CMPA", "SBCA", "???", //0x80 +"ANDA", "BITA", "LDAA", "???", +"EORA", "ADCA", "ORAA", "ADDA", +"CMPX", "BSR", "LDS", "???", +"SUBA", "CMPA", "SBCA", "???", //0x90 +"ANDA", "BITA", "LDAA", "STAA", +"EORA", "ADCA", "ORAA", "ADDA", +"CMPX", "???", "LDS", "STS", +"SUBA", "CMPA", "SBCA", "???", //0xA0 +"ANDA", "BITA", "LDAA", "STAA", +"EORA", "ADCA", "ORAA", "ADDA", +"CMPX X", "JSR X", "LDS X", "STS X", +"SUBA", "CMPA", "SBCA", "???", //0xB0 +"ANDA", "BITA", "LDAA", "STAA", +"EORA", "ADCA", "ORAA", "ADDA", +"CPX", "JSR", "LDS", "STS", +"SUBB", "CMPB", "SBCB", "???", //0xC0 +"ANDB", "BITB", "LDAB", "???", +"EORB", "ADCB", "ORAB", "ADDB", +"???", "???", "LDX", "???", +"SUBB", "CMPB", "SBCB", "???", //0xD0 +"ANDB", "BITB", "LDAB", "STAB", +"EORB", "ADCB", "ORAB", "ADDB", +"???", "???", "LDX", "STX", +"SUBB", "CMPB", "SBCB", "???", //0xE0 +"ANDB", "BITB", "LDAB", "STAB", +"EORB", "ADCB", "ORAB", "ADDB", +"???", "???", "LDX", "STX", +"SUBB", "CMPB", "SBCB", "???", //0xF0 +"ANDB", "BITB", "LDAB", "STAB", +"EORB", "ADCB", "ORAB", "ADDB", +"???", "???", "LDX", "STX" +}; + +int32 oplen[256] = { +0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1, //0x00 +1,1,0,0,0,0,1,1,0,1,0,1,0,0,0,0, +2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +1,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1, +1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, //0x40 +1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, +2,0,0,2,2,0,2,2,2,2,2,0,2,2,2,2, +3,0,0,3,3,0,3,3,3,3,3,0,3,3,3,3, +2,2,2,0,2,2,2,0,2,2,2,2,3,2,3,0, //0x80 +2,2,2,0,2,2,2,2,2,2,2,2,2,0,2,2, +2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2, +3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3, +2,2,2,0,2,2,2,0,2,2,2,2,0,0,3,0, //0xC0 +2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, +2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, +3,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3 +}; + +int32 oplen6800[256] = { +0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1, //0x00 +1,1,0,0,0,0,1,1,0,1,0,1,0,0,0,0, +2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +1,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1, +1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, //0x40 +1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, +2,0,0,2,2,0,2,2,2,2,2,0,2,2,2,2, +3,0,0,3,3,0,3,3,3,3,3,0,3,3,3,3, +2,2,2,0,2,2,2,0,2,2,2,2,3,2,3,0, //0x80 +2,2,2,0,2,2,2,2,2,2,2,2,2,0,2,2, +2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2, +3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3, +2,2,2,0,2,2,2,0,2,2,2,2,0,0,3,0, //0xC0 +2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, +2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, +3,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3 +}; + +t_stat sim_instr (void) +{ + int32 reason; + int32 IR; + int32 OP; + int32 OP2; /* Used for 2-byte opcodes */ + + int32 hi; /* hi bit/nybble/byte */ + int32 lo; /* lo bit/nybble/byte */ + int32 op1; /* operand #1 */ + int32 op2; /* operand #2 - used for CC evaluation */ + int32 result; /* temporary value */ + int32 addr; /* temporary address value */ + + /* used for 6809 instruction decoding - TFT, EXG, PSH, PUL*/ + int32 Post_Byte = 0; + int32 Src_Nybble = 0; + int32 Dest_Nybble = 0; + int32 Src_Value = 0; + int32 Dest_Value = 0; + + PC = saved_PC & ADDRMASK; /* load local PC */ + reason = 0; + + /* Main instruction fetch/decode loop */ + + while (reason == 0) { /* loop until halted */ +// dump_regs1(); + 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? */ + /* 6809 interrupts not implemented yet. None were used, + on a standard SWTP 6809. All I/O is programmed. */ + reason = STOP_HALT; /* stop simulation */ + break; + + } /* end interrupt */ + if (sim_brk_summ && + sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; + } + + sim_interval--; + last_PC = previous_PC; + previous_PC = PC; + IR = OP = fetch_byte(0); /* fetch instruction */ + + /* The Big Instruction Decode Switch */ + + switch (IR) { + +/* 0x00 - direct mode */ + case 0x00: /* NEG dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 != 0, CF); + COND_SET_FLAG(op1 == 0x80, VF); + result = 0 - op1; + result &= 0xFF; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0x03: /* COM dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = ~op1; + result &= 0xFF; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + CLR_FLAG(VF); + SET_FLAG(CF); + break; + case 0x04: /* LSR dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 & 0x01, CF); + result = op1 >> 1; + CPU_BD_put_mbyte(addr, result); + CLR_FLAG(NF); + COND_SET_FLAG_Z(result); + /* H,V not affected */ + break; + case 0x06: /* ROR dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = op1 >> 1; + if (get_flag(CF)) { + result |= 0x80; + } + CPU_BD_put_mbyte(addr, result); + /* H,V unaffected */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(op1 & 0x01, CF); + break; + case 0x07: /* ASR dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 >> 1) | (op1 & 0x80); + CPU_BD_put_mbyte(addr, result); + /* H undefined */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + /* V not affected */ + COND_SET_FLAG(op1 & 0x01, CF); + break; + case 0x08: /* ASL dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 & 0x80, CF); + result = (op1 << 1) & BYTEMASK; + CPU_BD_put_mbyte(addr, result); + /* H is undefined */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x09: /* ROL dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 << 1) & BYTEMASK; + if (get_flag(CF)) { + result |= 0x01; + } + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG((op1 & 0x80) ^ (op1 & 0x40), VF); + COND_SET_FLAG(op1 & 0x80, CF); + break; + case 0x0A: /* DEC dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1-1) & BYTEMASK; + CPU_BD_put_mbyte(addr, result); + /* H not affected */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(op1 == 0x80, VF); + /* C not affected */ + break; + case 0x0C: /* INC dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 == 0x7F, VF); + op1 = (op1 + 1) & BYTEMASK; + CPU_BD_put_mbyte(addr, op1); + COND_SET_FLAG_N(op1); + COND_SET_FLAG_Z(op1); + break; + case 0x0D: /* TST dir */ + result = get_dir_byte_val(); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + CLR_FLAG(VF); + break; + case 0x0E: /* JMP dir */ + PC = get_dir_addr(); + break; + case 0x0F: /* CLR dir */ + CPU_BD_put_mbyte(get_dir_addr(), 0); + /* H not affected */ + CLR_FLAG(NF); + SET_FLAG(ZF); + CLR_FLAG(VF); + CLR_FLAG(CF); + break; + +/* 0x10 */ + case 0x10: /* 2-byte opcodes */ + /* fetch second byte of opcode */ + OP2 = fetch_byte(0); + switch (OP2) { + case 0x21: /* LBRN rel */ + /* Branch Never - essentially a NOP */ + go_long_rel(0); + break; + case 0x22: /* LBHI rel */ + go_long_rel(!(get_flag(CF) | get_flag(ZF))); + break; + case 0x23: /* LBLS rel */ + go_long_rel(get_flag(CF) | get_flag(ZF)); + break; + case 0x24: /* LBCC rel */ + go_long_rel(!get_flag(CF)); + break; + case 0x25: /* LBCS rel */ + go_long_rel(get_flag(CF)); + break; + case 0x26: /* LBNE rel */ + go_long_rel(!get_flag(ZF)); + break; + case 0x27: /* LBEQ rel */ + go_long_rel(get_flag(ZF)); + break; + case 0x28: /* LBVC rel */ + go_long_rel(!get_flag(VF)); + break; + case 0x29: /* LBVS rel */ + go_long_rel(get_flag(VF)); + break; + case 0x2A: /* LBPL rel */ + go_long_rel(!get_flag(NF)); + break; + case 0x2B: /* LBMI rel */ + go_long_rel(get_flag(NF)); + break; + case 0x2C: /* LBGE rel */ + go_long_rel( !( get_flag(NF) ^ get_flag(VF) ) ); + break; + case 0x2D: /* LBLT rel */ + go_long_rel( get_flag(NF) ^ get_flag(VF) ); + break; + case 0x2E: /* LBGT rel */ + go_long_rel(!( get_flag(ZF) | (get_flag(NF) ^ get_flag(VF)))); + break; + case 0x2F: /* LBLE rel */ + go_long_rel(get_flag(ZF) | (get_flag(NF) ^ get_flag(VF))); + break; + case 0x3F: /* SWI2 */ + SET_FLAG(EF); + push_sp_word(PC); + push_sp_word(UP); + push_sp_word(IY); + push_sp_word(IX); + push_sp_byte(DP); + push_sp_byte(B); + push_sp_byte(A); + push_sp_byte(CCR); + PC = CPU_BD_get_mword(0xFFF4) & ADDRMASK; + break; + case 0x83: /* CMPD imm */ + D = (A << 8) | (B & BYTEMASK); + op2 = get_imm_word_val(); + result = D - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x8C: /* CMPY imm */ + op2 = get_imm_word_val(); + result = IY - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IY, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x8E: /* LDY imm */ + IY = get_imm_word_val(); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0x93: /* CMPD dir */ + D = (A << 8) | (B & BYTEMASK); + op2 = get_dir_word_val(); + result = D - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x9C: /* CMPY dir */ + op2 = get_dir_word_val(); + result = IY - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IY, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x9E: /* LDY dir */ + IY = get_dir_word_val(); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0x9F: /* STY dir */ + CPU_BD_put_mword(get_dir_addr(), IY); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0xA3: /* CMPD ind */ + D = (A << 8) | (B & BYTEMASK); + op2 = get_indexed_word_val(); + result = D - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xAC: /* CMPY ind */ + op2 = get_indexed_word_val(); + result = IY - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IY, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xAE: /* LDY ind */ + IY = get_indexed_word_val(); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0xAF: /* STY ind */ + CPU_BD_put_mword(get_indexed_addr(), IY); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0xB3: /* CMPD ext */ + D = (A << 8) | (B & BYTEMASK); + op2 = get_ext_word_val(); + result = D - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xBC: /* CMPY ext */ + op2 = get_ext_word_val(); + result = IY - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IY, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xBE: /* LDY ext */ + IY = get_ext_word_val(); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0xBF: /* STY ext */ + CPU_BD_put_mword(get_ext_addr(), IY); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0xCE: /* LDS imm */ + SP = get_imm_word_val(); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + case 0xDE: /* LDS dir */ + SP = get_dir_word_val(); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + case 0xDF: /* STS dir */ + CPU_BD_put_mword(get_dir_addr(), SP); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + case 0xEE: /* LDS ind */ + SP = get_indexed_word_val(); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + case 0xEF: /* STS ind */ + CPU_BD_put_mword(get_indexed_addr(), SP); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + case 0xFE: /* LDS ext */ + SP = get_ext_word_val(); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + case 0xFF: /* STS ext */ + CPU_BD_put_mword(get_ext_addr(), SP); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + } + break; + +/* Ox11 */ + case 0x11: /* 2-byte opcodes */ + /* fetch second byte of opcode */ + OP2 = fetch_byte(0); + switch (OP2) { + case 0x3F: /* SWI3 */ + SET_FLAG(EF); + push_sp_word(PC); + push_sp_word(UP); + push_sp_word(IY); + push_sp_word(IX); + push_sp_byte(DP); + push_sp_byte(B); + push_sp_byte(A); + push_sp_byte(CCR); + PC = CPU_BD_get_mword(0xFFF2) & ADDRMASK; + break; + case 0x83: /* CMPU imm */ + op2 = get_imm_word_val(); + result = UP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(UP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x8C: /* CMPS imm */ + op2 = get_imm_word_val(); + result = SP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(SP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x93: /* CMPU dir */ + op2 = get_dir_word_val(); + result = UP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(UP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x9C: /* CMPS dir */ + op2 = get_dir_word_val(); + result = SP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(SP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xA3: /* CMPU ind */ + op2 = get_indexed_word_val(); + result = UP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(UP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xAC: /* CMPS ind */ + op2 = get_indexed_word_val(); + result = SP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(SP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xB3: /* CMPU ext */ + op2 = get_ext_word_val(); + result = UP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(UP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xBC: /* CMPS ext */ + op2 = get_ext_word_val(); + result = SP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(SP, op2); + COND_SET_FLAG_C_16(result); + break; + } + break; + case 0x12: /* NOP */ + break; + case 0x13: /* SYNC inherent*/ + /* Interrupts are not implemented */ + reason = STOP_HALT; /* stop simulation */ + break; + case 0x16: /* LBRA relative */ + go_long_rel(1); + break; + case 0x17: /* LBSR relative */ + addr = get_long_rel_addr(); + push_sp_word(PC); + PC = (PC + addr) & ADDRMASK; + break; + case 0x19: /* DAA inherent */ + lo = A & 0x0F; + if ((lo > 9) || get_flag(HF)) { + lo += 6; + A = (A & 0xF0) + lo; + COND_SET_FLAG(lo & 0x10, HF); + } + hi = (A >> 4) & 0x0F; + if ((hi > 9) || get_flag(CF)) { + hi += 6; + A = (A & 0x0F) | (hi << 4) | 0x100; + } + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + + case 0x1A: /* ORCC imm */ + CCR = CCR | get_imm_byte_val(); + break; + case 0x1C: /* ANDCC imm */ + CCR = CCR & get_imm_byte_val(); + break; + case 0x1D: /* SEX inherent */ + if (B & 0x80) { + A = 0xFF; + } else { + A = 0; + } + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0x1E: /* EXG imm */ + Post_Byte = get_imm_byte_val(); + Src_Nybble = (Post_Byte >> 4) & 0x0F; + Dest_Nybble = Post_Byte & 0x0F; + if ((Src_Nybble <= 5 && Dest_Nybble > 5) || (Src_Nybble > 5 && Dest_Nybble <= 5)) { + // EXG with unaligned register sizes + reason = STOP_OPCODE; + } + + /* read register values */ + if (Src_Nybble <= 5 && Dest_Nybble <= 5) { + /* 16-bit register */ + /* read source register */ + switch (Src_Nybble) { + case TFR_EXG_Post_Nybble_D: Src_Value = (A << 8) | (B & BYTEMASK); break; + case TFR_EXG_Post_Nybble_X: Src_Value = IX; break; + case TFR_EXG_Post_Nybble_Y: Src_Value = IY; break; + case TFR_EXG_Post_Nybble_U: Src_Value = UP; break; + case TFR_EXG_Post_Nybble_S: Src_Value = SP; break; + case TFR_EXG_Post_Nybble_PC: Src_Value = PC; break; + default: break; + } + /* read destination register */ + switch (Dest_Nybble) { + case TFR_EXG_Post_Nybble_D: Dest_Value = (A << 8) | (B & BYTEMASK); break; + case TFR_EXG_Post_Nybble_X: Dest_Value = IX; break; + case TFR_EXG_Post_Nybble_Y: Dest_Value = IY; break; + case TFR_EXG_Post_Nybble_U: Dest_Value = UP; break; + case TFR_EXG_Post_Nybble_S: Dest_Value = SP; break; + case TFR_EXG_Post_Nybble_PC: Dest_Value = PC; break; + default: break; + } + } + if ((Src_Nybble >= 8 && Src_Nybble <= 11) && (Dest_Nybble >= 8 && Dest_Nybble <= 11)) { + /* 8-bit register read */ + /* read source register */ + switch (Src_Nybble) { + case TFR_EXG_Post_Nybble_A: Src_Value = A; break; + case TFR_EXG_Post_Nybble_B: Src_Value = B; break; + case TFR_EXG_Post_Nybble_CC: Src_Value = CCR; break; + case TFR_EXG_Post_Nybble_DP: Src_Value = DP; break; + default: break; + } + /* read destination register */ + switch (Dest_Nybble) { + case TFR_EXG_Post_Nybble_A: Dest_Value = A; break; + case TFR_EXG_Post_Nybble_B: Dest_Value = B; break; + case TFR_EXG_Post_Nybble_CC: Dest_Value = CCR; break; + case TFR_EXG_Post_Nybble_DP: Dest_Value = DP; break; + default: break; + } + } + /* write register values */ + if (Src_Nybble <= 5 && Dest_Nybble <= 5) { + /* 16-bit register */ + /* write source register */ + switch (Src_Nybble) { + case TFR_EXG_Post_Nybble_D: + A = Dest_Value >> 8; + B = Dest_Value & 0XFF; + break; + case TFR_EXG_Post_Nybble_X: IX = Dest_Value; break; + case TFR_EXG_Post_Nybble_Y: IY = Dest_Value; break; + case TFR_EXG_Post_Nybble_U: UP = Dest_Value; break; + case TFR_EXG_Post_Nybble_S: SP = Dest_Value; break; + case TFR_EXG_Post_Nybble_PC: PC = Dest_Value; break; + default: break; + } + /* write destination register */ + switch (Dest_Nybble) { + case TFR_EXG_Post_Nybble_D: + A = Src_Value >> 8; + B = Src_Value & 0XFF; + break; + case TFR_EXG_Post_Nybble_X: IX = Src_Value; break; + case TFR_EXG_Post_Nybble_Y: IY = Src_Value; break; + case TFR_EXG_Post_Nybble_U: UP = Src_Value; break; + case TFR_EXG_Post_Nybble_S: SP = Src_Value; break; + case TFR_EXG_Post_Nybble_PC: PC = Src_Value; break; + default: break; + } + } + if ((Src_Nybble >= 8 && Src_Nybble <= 11) && (Dest_Nybble >= 8 && Dest_Nybble <= 11)) { + /* 8-bit register */ + /* write source register */ + switch (Src_Nybble) { + case TFR_EXG_Post_Nybble_A: A = Dest_Value; break; + case TFR_EXG_Post_Nybble_B: B = Dest_Value; break; + case TFR_EXG_Post_Nybble_CC: CCR = Dest_Value; break; + case TFR_EXG_Post_Nybble_DP: DP = Dest_Value; break; + default: break; + } + /* write destination register */ + switch (Dest_Nybble) { + case TFR_EXG_Post_Nybble_A: A = Src_Value; break; + case TFR_EXG_Post_Nybble_B: B = Src_Value; break; + case TFR_EXG_Post_Nybble_CC: CCR = Src_Value; break; + case TFR_EXG_Post_Nybble_DP: DP = Src_Value; break; + default: break; + } + } + break; + + case 0x1F: /* TFR imm */ + Post_Byte = get_imm_byte_val(); + Dest_Nybble = Post_Byte & 0x0F; + Src_Nybble = Post_Byte >> 4; + if ((Src_Nybble <= 5 && Dest_Nybble > 5) || (Src_Nybble > 5 && Dest_Nybble <= 5)) { + // TFR with unaligned register sizes + reason = STOP_OPCODE; + } + + + if ((Src_Nybble <= 5) && (Dest_Nybble <= 5)) { + /* 16-bit registers */ + /* read source register */ + switch (Src_Nybble) { + case TFR_EXG_Post_Nybble_D: Src_Value = (A << 8) | (B & BYTEMASK); break; + case TFR_EXG_Post_Nybble_X: Src_Value = IX; break; + case TFR_EXG_Post_Nybble_Y: Src_Value = IY; break; + case TFR_EXG_Post_Nybble_U: Src_Value = UP; break; + case TFR_EXG_Post_Nybble_S: Src_Value = SP; break; + case TFR_EXG_Post_Nybble_PC: Src_Value = PC; break; + break; + } + /* write source register */ + switch (Dest_Nybble) { + case TFR_EXG_Post_Nybble_D: + A = Src_Value >> 8; + B = Src_Value & 0XFF; + break; + case TFR_EXG_Post_Nybble_X: IX = Src_Value; break; + case TFR_EXG_Post_Nybble_Y: IY = Src_Value; break; + case TFR_EXG_Post_Nybble_U: UP = Src_Value; break; + case TFR_EXG_Post_Nybble_S: SP = Src_Value; break; + case TFR_EXG_Post_Nybble_PC: PC = Src_Value;; break; + break; + } + } + if ((Src_Nybble >= 8 && Src_Nybble <= 11) && (Dest_Nybble >= 8 && Dest_Nybble <= 11)) { + /* 8-bit registers */ + /* read the source register */ + switch (Src_Nybble) { + case TFR_EXG_Post_Nybble_A: Src_Value = A; break; + case TFR_EXG_Post_Nybble_B: Src_Value = B; break; + case TFR_EXG_Post_Nybble_CC: Src_Value = CCR; break; + case TFR_EXG_Post_Nybble_DP: Src_Value = DP; break; + break; + } + /* write the destination register */ + switch (Dest_Nybble) { + case TFR_EXG_Post_Nybble_A: A = Src_Value; break; + case TFR_EXG_Post_Nybble_B: B = Src_Value; break; + case TFR_EXG_Post_Nybble_CC: CCR = Src_Value; break; + case TFR_EXG_Post_Nybble_DP: DP = Src_Value; break; + break; + } + } + break; + +/* 0x20 - relative mode */ + case 0x20: /* BRA rel */ + go_rel(1); + break; + case 0x21: /* BRN rel */ + /* Branch Never - essentially a NOP */ + go_rel(0); + break; + case 0x22: /* BHI rel */ + go_rel(!(get_flag(CF) | get_flag(ZF))); + break; + case 0x23: /* BLS rel */ + go_rel(get_flag(CF) | get_flag(ZF)); + break; + case 0x24: /* BCC rel */ + go_rel(!get_flag(CF)); + break; + case 0x25: /* BCS rel */ + go_rel(get_flag(CF)); + break; + case 0x26: /* BNE rel */ + go_rel(!get_flag(ZF)); + break; + case 0x27: /* BEQ rel */ + go_rel(get_flag(ZF)); + break; + case 0x28: /* BVC rel */ + go_rel(!get_flag(VF)); + break; + case 0x29: /* BVS rel */ + go_rel(get_flag(VF)); + break; + case 0x2A: /* BPL rel */ + go_rel(!get_flag(NF)); + break; + case 0x2B: /* BMI rel */ + go_rel(get_flag(NF)); + break; + case 0x2C: /* BGE rel */ + go_rel(!(get_flag(NF) ^ get_flag(VF))); + break; + case 0x2D: /* BLT rel */ + go_rel(get_flag(NF) ^ get_flag(VF)); + break; + case 0x2E: /* BGT rel */ + go_rel( !( get_flag(ZF) | (get_flag(NF) ^ get_flag(VF)) ) ); + break; + case 0x2F: /* BLE rel */ + go_rel( get_flag(ZF) | (get_flag(NF) ^ get_flag(VF)) ); + break; + +/* 0x30 */ + case 0x30: /* LEAX */ + IX = get_indexed_addr(); + COND_SET_FLAG_Z_16(IX); + break; + + case 0x31: /* LEAY */ + IY = get_indexed_addr(); + COND_SET_FLAG_Z_16(IY); + break; + + case 0x32: /* LEAS */ + SP = get_indexed_addr(); + /* does not affect CCR */ + break; + + case 0x33: /* LEAU */ + UP = get_indexed_addr(); + /* does not affect CCR */ + break; + + case 0x34: /* PSHS */ + Post_Byte = get_imm_byte_val(); + if (Post_Byte & PSH_PUL_Post_Byte_PC) push_sp_word(PC); + if (Post_Byte & PSH_PUL_Post_Byte_S_U) push_sp_word(UP); + if (Post_Byte & PSH_PUL_Post_Byte_Y) push_sp_word(IY); + if (Post_Byte & PSH_PUL_Post_Byte_X) push_sp_word(IX); + if (Post_Byte & PSH_PUL_Post_Byte_DP) push_sp_byte(DP); + if (Post_Byte & PSH_PUL_Post_Byte_B) push_sp_byte(B); + if (Post_Byte & PSH_PUL_Post_Byte_A) push_sp_byte(A); + if (Post_Byte & PSH_PUL_Post_Byte_CC) push_sp_byte(CCR); + break; + + case 0x35: /* PULS */ + Post_Byte = get_imm_byte_val(); + if (Post_Byte & PSH_PUL_Post_Byte_CC) CCR = pop_sp_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_A) A = pop_sp_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_B) B = pop_sp_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_DP) DP = pop_sp_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_X) IX = pop_sp_word(); + if (Post_Byte & PSH_PUL_Post_Byte_Y) IY = pop_sp_word(); + if (Post_Byte & PSH_PUL_Post_Byte_S_U) UP = pop_sp_word(); + if (Post_Byte & PSH_PUL_Post_Byte_PC) PC = pop_sp_word(); + break; + + case 0x36: /* PSHU */ + Post_Byte = get_imm_byte_val(); + if (Post_Byte & PSH_PUL_Post_Byte_PC) push_up_word(PC); + if (Post_Byte & PSH_PUL_Post_Byte_S_U) push_up_word(SP); + if (Post_Byte & PSH_PUL_Post_Byte_Y) push_up_word(IY); + if (Post_Byte & PSH_PUL_Post_Byte_X) push_up_word(IX); + if (Post_Byte & PSH_PUL_Post_Byte_DP) push_up_byte(DP); + if (Post_Byte & PSH_PUL_Post_Byte_B) push_up_byte(B); + if (Post_Byte & PSH_PUL_Post_Byte_A) push_up_byte(A); + if (Post_Byte & PSH_PUL_Post_Byte_CC) push_up_byte(CCR); + break; + + case 0x37: /* PULU */ + Post_Byte = get_imm_byte_val(); + if (Post_Byte & PSH_PUL_Post_Byte_CC) CCR = pop_up_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_A) A = pop_up_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_B) B = pop_up_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_DP) DP = pop_up_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_X) IX = pop_up_word(); + if (Post_Byte & PSH_PUL_Post_Byte_Y) IY = pop_up_word(); + if (Post_Byte & PSH_PUL_Post_Byte_S_U) SP = pop_up_word(); + if (Post_Byte & PSH_PUL_Post_Byte_PC) PC = pop_up_word(); + break; + + case 0x39: /* RTS */ + PC = pop_sp_word(); + break; + + case 0x3A: /* ABX */ + /* this is an UNSIGNED operation! */ + IX = (IX + B) & 0xFFFF; + /* no changes to CCR */ + break; + + case 0x3B: /* RTI */ + CCR = pop_sp_byte(); + if (GET_FLAG(EF)) { + /* entire state flag */ + A = pop_sp_byte(); + B = pop_sp_byte(); + DP = pop_sp_byte(); + IX = pop_sp_word(); + IY = pop_sp_word(); + UP = pop_sp_word(); + } + PC = pop_sp_word(); + break; + + case 0x3C: /* CWAI */ + /* AND immediate byte with CCR + CCR &= get_imm_byte_val(); + SET_FLAG(EF); + /* push register state */ + push_sp_word(PC); + push_sp_word(UP); + push_sp_word(IY); + push_sp_word(IX); + push_sp_byte(DP); + push_sp_byte(B); + push_sp_byte(A); + push_sp_byte(CCR); + if (get_flag(IF)) { + reason = STOP_HALT; + continue; + } else { + SET_FLAG(IF); + PC = CPU_BD_get_mword(0xFFFE) & ADDRMASK; + } + break; + + case 0x3D: /* MUL */ + D = A * B; + A = D >> 8; + B = D & BYTEMASK; + COND_SET_FLAG_Z_16(D); + COND_SET_FLAG(B & 0x80, CF); + break; + + case 0x3F: /* SWI */ + SET_FLAG(EF); + push_sp_word(PC); + push_sp_word(UP); + push_sp_word(IY); + push_sp_word(IX); + push_sp_byte(DP); + push_sp_byte(B); + push_sp_byte(A); + push_sp_byte(CCR); + SET_FLAG(FF); + SET_FLAG(IF); + PC = CPU_BD_get_mword(0xFFFA) & ADDRMASK; + break; + +/* 0x40 - inherent mode */ + case 0x40: /* NEGA */ + COND_SET_FLAG(A != 0, CF); + COND_SET_FLAG(A == 0x80, VF); + A = 0 - A; + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x43: /* COMA */ + A = ~A; + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + SET_FLAG(CF); + break; + case 0x44: /* LSRA */ + COND_SET_FLAG(A & 0x01, CF); + A = (A >> 1) & BYTEMASK; + CLR_FLAG(NF); + COND_SET_FLAG_Z(A); + /* H,V unaffected */ + break; + case 0x46: /* RORA */ + hi = get_flag(CF); + COND_SET_FLAG(A & 0x01, CF); + A = A >> 1; + if (hi) + A |= 0x80; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + /* H,V unaffected */ + break; + case 0x47: /* ASRA */ + COND_SET_FLAG(A & 0x01, CF); + A = (A >> 1) | (A & 0x80); + /* H undefined */ + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + /* V unaffected */ + break; + case 0x48: /* ASLA */ + COND_SET_FLAG(A & 0x80, CF); + A = (A << 1) & BYTEMASK; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x49: /* ROLA */ + hi = get_flag(CF); + COND_SET_FLAG(A & 0x80, CF); + A = (A << 1) & BYTEMASK; + if (hi) + A |= 0x01; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x4A: /* DECA */ + COND_SET_FLAG(A == 0x80, VF); + A = (A - 1) & BYTEMASK; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x4C: /* INCA */ + COND_SET_FLAG(A == 0x7F, VF); + A = (A + 1) & BYTEMASK; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x4D: /* TSTA */ + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + /* C not affected */ + break; + case 0x4F: /* CLRA */ + A = 0; + CLR_FLAG(NF); + SET_FLAG(ZF); + CLR_FLAG(VF); + CLR_FLAG(CF); + break; + +/* 0x50 - inherent modes */ + case 0x50: /* NEGB */ + COND_SET_FLAG(B != 0, CF); + COND_SET_FLAG(B == 0x80, VF); + B = (0 - B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0x53: /* COMB */ + B = ~B; + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + SET_FLAG(CF); + break; + case 0x54: /* LSRB */ + COND_SET_FLAG(B & 0x01, CF); + B = (B >> 1) & BYTEMASK; + CLR_FLAG(NF); + COND_SET_FLAG_Z(B); + /* H,V unaffected */ + break; + case 0x56: /* RORB */ + hi = get_flag(CF); + COND_SET_FLAG(B & 0x01, CF); + B = B >> 1; + if (hi) + B |= 0x80; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + /* H,V unaffected */ + break; + case 0x57: /* ASRB */ + COND_SET_FLAG(B & 0x01, CF); + B = (B >> 1) | (B & 0x80); + /* H undefined */ + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + /* C unaffected */ + break; + case 0x58: /* ASLB */ + COND_SET_FLAG(B & 0x80, CF); + B = (B << 1) & BYTEMASK; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x59: /* ROLB */ + hi = get_flag(CF); + COND_SET_FLAG(B & 0x80, CF); + B = (B << 1) & BYTEMASK; + if (hi) + B |= 0x01; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x5A: /* DECB */ + COND_SET_FLAG(B == 0x80, VF); + B = (B - 1) & BYTEMASK; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0x5C: /* INCB */ + COND_SET_FLAG(B == 0x7F, VF); + B = (B + 1) & BYTEMASK; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0x5D: /* TSTB */ + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + /* C not affected */ + break; + case 0x5F: /* CLRB */ + B = 0; + CLR_FLAG(NF); + SET_FLAG(ZF); + CLR_FLAG(VF); + CLR_FLAG(CF); + break; + +/* 0x60 - index mode */ + case 0x60: /* NEG ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 != 0, CF); + COND_SET_FLAG(op1 == 0x80, VF); + result = (0 - op1) & BYTEMASK; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0x63: /* COM ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = ~op1; + result &= 0xFF; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + CLR_FLAG(VF); + SET_FLAG(CF); + break; + case 0x64: /* LSR ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 & 0x01, CF); + result = op1 >> 1; + CPU_BD_put_mbyte(addr, result); + CLR_FLAG(NF); + COND_SET_FLAG_Z(result); + /* H,V unaffected */ + break; + case 0x66: /* ROR ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = op1 >> 1; + if (get_flag(CF)) + result |= 0x80; + CPU_BD_put_mbyte(addr, result); + /* H,V unaffected */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(op1 & 0x01, CF); + break; + case 0x67: /* ASR ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 >> 1) | (op1 & 0x80); + CPU_BD_put_mbyte(addr, result); + /* H undefined */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + /* V unaffected */ + COND_SET_FLAG(op1 & 0x01, CF); + break; + case 0x68: /* ASL ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 & 0x80, CF); + result = (op1 << 1) & BYTEMASK; + CPU_BD_put_mbyte(addr, result); + /* H is undefined */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x69: /* ROL ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 << 1) & BYTEMASK; + if (get_flag(CF)) + result |= 0x01; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG((op1 & 0x80) ^ (op1 & 0x40), VF); + COND_SET_FLAG(op1 & 0x80, CF); + break; + case 0x6A: /* DEC ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 - 1) & BYTEMASK; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(op1 == 0x80, VF); + break; + case 0x6C: /* INC ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 == 0x7F, VF); + op1 = (op1 + 1) & BYTEMASK; + CPU_BD_put_mbyte(addr, op1); + COND_SET_FLAG_N(op1); + COND_SET_FLAG_Z(op1); + break; + case 0x6D: /* TST ind */ + result = get_indexed_byte_val(); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + CLR_FLAG(VF); + break; + case 0x6E: /* JMP ind */ + PC = get_indexed_addr(); + break; + case 0x6F: /* CLR ind */ + CPU_BD_put_mbyte(get_indexed_addr(), 0); + /* H not affected */ + CLR_FLAG(NF); + SET_FLAG(ZF); + CLR_FLAG(VF); + CLR_FLAG(CF); + break; + +/* 0x70 - extended modes */ + case 0x70: /* NEG ext */ + addr= get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 != 0, CF); + COND_SET_FLAG(op1 == 0x80, VF) ; + result = (0 - op1) & BYTEMASK; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0x73: /* COM ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = ~op1; + result &= 0xFF; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + CLR_FLAG(VF); + SET_FLAG(CF); + break; + case 0x74: /* LSR ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 & 0x01, CF); + result = op1 >> 1; + CPU_BD_put_mbyte(addr, result); + CLR_FLAG(NF); + COND_SET_FLAG_Z(result); + /* H,V unaffected */ + break; + case 0x76: /* ROR ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = op1 >> 1; + if (get_flag(CF)) + result |= 0x80; + CPU_BD_put_mbyte(addr, result); + /* H,V unaffected */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(op1 & 0x01, CF); + break; + case 0x77: /* ASR ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 >> 1) | (op1 & 0x80); + CPU_BD_put_mbyte(addr, result); + /* H undefined */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + /* V unaffected */ + COND_SET_FLAG(op1 & 0x01, CF); + break; + case 0x78: /* ASL ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 & 0x80, CF); + result = (op1 << 1) & BYTEMASK; + CPU_BD_put_mbyte(addr, result); + /* H is undefined */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x79: /* ROL ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 << 1) & BYTEMASK; + if (get_flag(CF)) + result |= 0x01; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG((op1 & 0x80) ^ (op1 & 0x40), VF); + COND_SET_FLAG(op1 & 0x80, CF); + break; + case 0x7A: /* DEC ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 - 1) & BYTEMASK; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(op1 == 0x80, VF); + break; + case 0x7C: /* INC ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 == 0x7F, VF); + op1 = (op1 + 1) & BYTEMASK; + CPU_BD_put_mbyte(addr, op1); + COND_SET_FLAG_N(op1); + COND_SET_FLAG_Z(op1); + break; + case 0x7D: /* TST ext */ + result = get_ext_byte_val(); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + CLR_FLAG(VF); + break; + case 0x7E: /* JMP ext */ + PC = get_ext_addr(); + break; + case 0x7F: /* CLR ext */ + CPU_BD_put_mbyte(get_ext_addr(), 0); + /* H not affected */ + CLR_FLAG(NF); + SET_FLAG(ZF); + CLR_FLAG(VF); + CLR_FLAG(CF); + break; + +/* 0x80 - immediate mode (except for BSR) */ + case 0x80: /* SUBA imm */ + op1 = get_imm_byte_val(); + op2 = A; + A = A - op1; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0x81: /* CMPA imm */ + op2 = get_imm_byte_val(); + result = A - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(A, op2); + break; + case 0x82: /* SBCA imm */ + op1 = A; + op2 = get_imm_byte_val() + get_flag(CF); + A = A - op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0x83: /* SUBD imm */ + D = (A << 8) | (B & BYTEMASK); + op2 = get_imm_word_val(); + result = D - op2; + COND_SET_FLAG_C_16(result); + result &= 0xFFFF; + A = result >> 8; + B = result & BYTEMASK; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + break; + case 0x84: /* ANDA imm */ + A = (A & get_imm_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x85: /* BITA imm */ + result = (A & get_imm_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0x86: /* LDA imm */ + A = get_imm_byte_val(); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x88: /* EORA imm */ + A = (A ^ get_imm_byte_val()) & BYTEMASK; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x89: /* ADCA imm */ + op1 = A; + op2 = get_imm_byte_val() + get_flag(CF); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0x8A: /* ORA imm */ + A = A | get_imm_byte_val(); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x8B: /* ADDA imm */ + op1 = A; + op2 = get_imm_byte_val(); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0x8C: /* CMPX imm */ + op2 = get_imm_word_val(); + result = IX - op2; + COND_SET_FLAG_C_16(result); + result = result & 0xFFFF; + COND_SET_FLAG_Z_16(result); + COND_SET_FLAG_N_16(result); + condevalVs16(IX, op2); + break; + case 0x8D: /* BSR rel */ + addr = get_rel_addr(); + push_sp_word(PC); + PC = (PC + addr) & ADDRMASK; + break; + case 0x8E: /* LDX imm */ + IX = get_imm_word_val(); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + +/* 0x90 - direct mode */ + case 0x90: /* SUBA dir */ + op1 = A; + op2 = get_dir_byte_val(); + A = A - op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0x91: /* CMPA dir */ + op2 = get_dir_byte_val(); + result = A - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(A, op2); + break; + case 0x92: /* SBCA dir */ + op1 = A; + op2 = get_dir_byte_val() + get_flag(CF); + A = A - op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0x93: /* SUBD dir */ + D = (A << 8) | (B & BYTEMASK); + op2 = get_dir_word_val(); + result = D - op2; + COND_SET_FLAG_C_16(result); + result &= 0xFFFF; + A = result >> 8; + B = result & BYTEMASK; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + break; + case 0x94: /* ANDA dir */ + A = (A & get_dir_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x95: /* BITA dir */ + result = (A & get_dir_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0x96: /* LDA dir */ + A = get_dir_byte_val(); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x97: /* STA dir */ + CPU_BD_put_mbyte(get_dir_addr(), A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x98: /* EORA dir */ + A = (A ^ get_dir_byte_val()) & BYTEMASK; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x99: /* ADCA dir */ + op1 = A; + op2 = get_dir_byte_val() + get_flag(CF); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0x9A: /* ORA dir */ + A = A | get_dir_byte_val(); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x9B: /* ADDA dir */ + op1 = A; + op2 = get_dir_byte_val(); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0x9C: /* CMPX dir */ + op2 = get_dir_word_val(); + result = IX - op2; + COND_SET_FLAG_C_16(result); + result &= 0xFFFF; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IX, op2); + break; + case 0x9D: /* JSR dir */ + addr = get_dir_addr(); + push_sp_word(PC); + PC = addr; + break; + case 0x9E: /* LDX dir */ + IX = get_dir_word_val(); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + case 0x9F: /* STX dir */ + CPU_BD_put_mword(get_dir_addr(), IX); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + +/* 0xA0 - indexed mode */ + case 0xA0: /* SUBA ind */ + op1 = get_indexed_byte_val(); + result = A - op1; + A = result; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, result); + break; + case 0xA1: /* CMPA ind */ + op2 = get_indexed_byte_val(); + result = A - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(A, op2); + break; + case 0xA2: /* SBCA ind */ + op1 = A; + op2 = get_indexed_byte_val() + get_flag(CF); + A = A - op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0xA3: /* SUBD ind */ + D = (A << 8) | (B & BYTEMASK); + op2 = get_indexed_word_val(); + result = D - op2; + COND_SET_FLAG_C_16(result); + result &= 0xFFFF; + A = result >> 8; + B = result & BYTEMASK; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + break; + case 0xA4: /* ANDA ind */ + A = (A & get_indexed_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xA5: /* BITA ind */ + result = (A & get_indexed_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0xA6: /* LDA ind */ + A = get_indexed_byte_val(); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xA7: /* STA ind */ + CPU_BD_put_mbyte(get_indexed_addr(), A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xA8: /* EORA ind */ + A = (A ^ get_indexed_byte_val()) & BYTEMASK; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xA9: /* ADCA ind */ + op1 = A; + op2 = get_indexed_byte_val() + get_flag(CF); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0xAA: /* ORA ind */ + A = A | get_indexed_byte_val(); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xAB: /* ADDA ind */ + op1 = A; + op2 = get_indexed_byte_val(); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0xAC: /* CMPX ind */ + op2 = get_indexed_word_val(); + result = (IX - op2) & ADDRMASK; + COND_SET_FLAG_C_16(result); + result &= 0xFFFF; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IX, op2); + break; + case 0xAD: /* JSR ind */ + addr = get_indexed_addr(); + push_sp_word(PC); + PC = addr; + break; + case 0xAE: /* LDX ind */ + IX = get_indexed_word_val(); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + case 0xAF: /* STX ind */ + CPU_BD_put_mword(get_indexed_addr(), IX); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + +/* 0xB0 - extended mode */ + case 0xB0: /* SUBA ext */ + op1 = A; + op2 = get_ext_byte_val(); + A = A - op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0xB1: /* CMPA ext */ + op2 = get_ext_byte_val(); + result = A - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(A, op2); + break; + case 0xB2: /* SBCA ext */ + op1 = A; + op2 = get_ext_byte_val() + get_flag(CF); + A = A - op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0xB3: /* SUBD ext */ + D = (A << 8) | (B & BYTEMASK); + op2 = get_ext_word_val(); + result = D - op2; + COND_SET_FLAG_C_16(result); + result &= 0xFFFF; + A = result >> 8; + B = result & BYTEMASK; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + break; + case 0xB4: /* ANDA ext */ + A = (A & get_ext_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xB5: /* BITA ext */ + result = (A & get_ext_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0xB6: /* LDA ext */ + A = get_ext_byte_val(); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xB7: /* STA ext */ + CPU_BD_put_mbyte(get_ext_addr(), A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xB8: /* EORA ext */ + A = (A ^ get_ext_byte_val()) & BYTEMASK; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xB9: /* ADCA ext */ + op1 = A; + op2 = get_ext_byte_val() + get_flag(CF); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0xBA: /* ORA ext */ + A = A | get_ext_byte_val(); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xBB: /* ADDA ext */ + op1 = A; + op2 = get_ext_byte_val(); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0xBC: /* CMPX ext */ + op2 = get_ext_word_val(); + result = (IX - op2); + COND_SET_FLAG_C_16(result); + result = result & 0xFFFF; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IX, op2); + break; + case 0xBD: /* JSR ext */ + addr = get_ext_addr(); + push_sp_word(PC); + PC = addr; + break; + case 0xBE: /* LDX ext */ + IX = get_ext_word_val(); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + case 0xBF: /* STX ext */ + CPU_BD_put_mword(get_ext_addr(), IX); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + +/* 0xC0 - immediate mode */ + case 0xC0: /* SUBB imm */ + op1 = B; + op2 = get_imm_byte_val(); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xC1: /* CMPB imm */ + op2 = get_imm_byte_val(); + result = B - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(B, op2); + break; + case 0xC2: /* SBCB imm */ + op1 = B; + op2 = get_imm_byte_val() + get_flag(CF); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xC3: /* ADDD imm */ + op1 = (A << 8) | (B & BYTEMASK); + op2 = get_imm_word_val(); + D = op1 + op2; + COND_SET_FLAG_C_16(D); + D &= 0xFFFF; + A = D >> 8; + B = D & BYTEMASK; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + condevalVa16(op1,op2); + break; + case 0xC4: /* ANDB imm */ + B = (B & get_imm_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xC5: /* BITB imm */ + result = (B & get_imm_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0xC6: /* LDB imm */ + B = get_imm_byte_val(); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xC8: /* EORB imm */ + B = (B ^ get_imm_byte_val()) & BYTEMASK; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xC9: /* ADCB imm */ + op1 = B; + op2 = get_imm_byte_val() + get_flag(CF); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xCA: /* ORB imm */ + B = B | get_imm_byte_val(); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xCB: /* ADDB imm */ + op1 = B; + op2 = get_imm_byte_val(); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xCC: /* LDD imm */ + D = get_imm_word_val(); + A = D >> 8; + B = D & BYTEMASK; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xCE: /* LDU imm */ + UP = get_imm_word_val(); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + +/* 0xD0 - direct modes */ + case 0xD0: /* SUBB dir */ + op1 = B; + op2 = get_dir_byte_val(); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xD1: /* CMPB dir */ + op2 = get_dir_byte_val(); + result = B - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(B, op2); + break; + case 0xD2: /* SBCB dir */ + op1 = B; + op2 = get_dir_byte_val() + get_flag(CF); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xD3: /* ADDD dir */ + op1 = (A << 8) | (B & BYTEMASK); + op2 = get_dir_word_val(); + D = op1 + op2; + COND_SET_FLAG_C_16(D); + D &= 0xFFFF; + A = D >> 8; + B = D & BYTEMASK; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + condevalVa16(op1, op2); + break; + case 0xD4: /* ANDB dir */ + B = (B & get_dir_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xD5: /* BITB dir */ + result = (B & get_dir_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0xD6: /* LDB dir */ + B = get_dir_byte_val(); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xD7: /* STB dir */ + CPU_BD_put_mbyte(get_dir_addr(), B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xD8: /* EORB dir */ + B = (B ^ get_dir_byte_val()) & BYTEMASK; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xD9: /* ADCB dir */ + op1 = B; + op2 = get_dir_byte_val() + get_flag(CF); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xDA: /* ORB dir */ + B = B | get_dir_byte_val(); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xDB: /* ADDB dir */ + op1 = B; + op2 = get_dir_byte_val(); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xDC: /* LDD dir */ + D = get_dir_word_val(); + A = D >> 8; + B = D & BYTEMASK; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xDD: /* STD dir */ + D = (A << 8) | (B & BYTEMASK); + CPU_BD_put_mword(get_dir_addr(), D); + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xDE: /* LDU dir */ + UP = get_dir_word_val(); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + case 0xDF: /* STU dir */ + CPU_BD_put_mword(get_dir_addr(), UP); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + +/* 0xE0 - indexed mode */ + case 0xE0: /* SUBB ind */ + op1 = B; + op2 = get_indexed_byte_val(); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xE1: /* CMPB ind */ + op2 = get_indexed_byte_val(); + result = B - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(B, op2); + break; + case 0xE2: /* SBCB ind */ + op1 = B; + op2 = get_indexed_byte_val() + get_flag(CF); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xE3: /* ADDD ind */ + op1 = (A << 8) | (B & BYTEMASK); + op2 = get_indexed_word_val(); + D = op1 + op2; + COND_SET_FLAG_C_16(D); + D &= 0xFFFF; + A = D >> 8; + B = D & BYTEMASK; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + condevalVa16(op1, op2); + break; + case 0xE4: /* ANDB ind */ + B = (B & get_indexed_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xE5: /* BITB ind */ + result = (B & get_indexed_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0xE6: /* LDB ind */ + B = get_indexed_byte_val(); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xE7: /* STB ind */ + CPU_BD_put_mbyte(get_indexed_addr(), B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xE8: /* EORB ind */ + B = (B ^ get_indexed_byte_val()) & BYTEMASK; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xE9: /* ADCB ind */ + op1 = B; + op2 = get_indexed_byte_val() + get_flag(CF); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xEA: /* ORB ind */ + B = B | get_indexed_byte_val(); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xEB: /* ADDB ind */ + op1 = B; + op2 = get_indexed_byte_val(); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xEC: /* LDD ind */ + D = get_indexed_word_val(); + A = D >> 8; + B = D & BYTEMASK; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xED: /* STD ind */ + D = (A << 8) | (B & BYTEMASK); + CPU_BD_put_mword(get_indexed_addr(), D); + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xEE: /* LDU ind */ + UP = get_indexed_word_val(); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + case 0xEF: /* STU ind */ + CPU_BD_put_mword(get_indexed_addr(), UP); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + +/* 0xF0 - extended mode */ + case 0xF0: /* SUBB ext */ + op1 = B; + op2 = get_ext_byte_val(); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xF1: /* CMPB ext */ + op2 = get_ext_byte_val(); + result = B - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(B, op2); + break; + case 0xF2: /* SBCB ext */ + op1 = B; + op2 = get_ext_byte_val() + get_flag(CF); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xF3: /* ADDD ext */ + op1 = (A << 8) | (B & BYTEMASK); + op2 = get_ext_word_val(); + D = op1 + op2; + COND_SET_FLAG_C_16(D); + D &= 0xFFFF; + A = D >> 8; + B = D & BYTEMASK; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + condevalVa16(op1, op2); + break; + case 0xF4: /* ANDB ext */ + B = (B & get_ext_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xF5: /* BITB ext */ + result = (B & get_ext_byte_val()) & BYTEMASK; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0xF6: /* LDB ext */ + B = get_ext_byte_val(); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xF7: /* STB ext */ + CPU_BD_put_mbyte(get_ext_addr(), B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xF8: /* EORB ext */ + B = (B ^ get_ext_byte_val()) & BYTEMASK; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xF9: /* ADCB ext */ + op1 = B; + op2 = get_ext_byte_val() + get_flag(CF); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xFA: /* ORB ext */ + B = B | get_ext_byte_val(); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xFB: /* ADDB ext */ + op1 = B; + op2 = get_ext_byte_val(); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xFC: /* LDD ext */ + D = get_ext_word_val(); + A = D >> 8; + B = D & BYTEMASK; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xFD: /* STD ext */ + D = (A << 8) | (B & BYTEMASK); + CPU_BD_put_mword(get_ext_addr(), D); + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xFE: /* LDU ext */ + UP = get_ext_word_val(); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + case 0xFF: /* STU ext */ + CPU_BD_put_mword(get_ext_addr(), UP); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + + default: /* Unassigned */ + if (m6809_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(void) +{ + printf("\r\nPC=%04X SP=%04X UP=%04X IX=%04X IY=%04X ", PC, SP, UP, IX, IY); + printf("A=%02X B=%02X DP=%02X CCR=%02X", A, B, DP, CCR); +} + +void dump_regs1(void) +{ + printf("PC=%04X SP=%04X UP=%04X IX=%04X IY=%04X ", PC, SP, UP, IX, IY); + printf("A=%02X B=%02X DP=%02X CCR=%02X\n", A, B, DP, CCR); +} + +/* fetch an instruction or byte */ +int32 fetch_byte(int32 flag) +{ + uint8 val; + + val = CPU_BD_get_mbyte(PC); /* fetch byte */ + switch (flag) { + case 0: /* opcode fetch */ + sim_debug (DEBUG_asm, &m6809_dev, "%04X %s\n", PC, opcode[val]); + break; + case 1: /* byte operand fetch */ + sim_debug (DEBUG_asm, &m6809_dev, "0x%02XH\n", val); + break; + } + PC = (PC + 1) & ADDRMASK; /* increment PC */ + return val; +} + +/* fetch a word - big endian */ +int32 fetch_word() +{ + uint16 val; + + val = CPU_BD_get_mbyte(PC) << 8; /* fetch high byte */ + val |= (CPU_BD_get_mbyte(PC + 1)); /* fetch low byte */ + + /* 2-byte operand fetch */ + sim_debug (DEBUG_asm, &m6809_dev, "0x%04XH\n", val); + + PC = (PC + 2) & ADDRMASK; /* increment PC */ + return val; +} + +/* push a byte using the hardware stack pointer (SP) */ +void push_sp_byte(uint8 val) +{ + SP = (SP - 1) & ADDRMASK; + CPU_BD_put_mbyte(SP, val & BYTEMASK); +} + +/* push a byte using the user stack pointer (UP) */ +void push_up_byte(uint8 val) +{ + UP = (UP - 1) & ADDRMASK; + CPU_BD_put_mbyte(UP, val & BYTEMASK); +} + +/* push a word using the hardware stack pointer (SP) */ +void push_sp_word(uint16 val) +{ + push_sp_byte(val & BYTEMASK); + push_sp_byte(val >> 8); +} + +/* push a word using the user stack pointer (UP) */ +void push_up_word(uint16 val) +{ + push_up_byte(val & BYTEMASK); + push_up_byte(val >> 8); +} + +/* pop a byte using the hardware stack pointer (SP) */ +uint8 pop_sp_byte(void) +{ + register uint8 res; + + res = CPU_BD_get_mbyte(SP); + SP = (SP + 1) & ADDRMASK; + return res; +} + +/* pop a byte using the user stack pointer (UP) */ +uint8 pop_up_byte(void) +{ + register uint8 res; + + res = CPU_BD_get_mbyte(UP); + UP = (UP + 1) & ADDRMASK; + return res; +} + +/* pop a word using the hardware stack pointer (SP) */ +uint16 pop_sp_word(void) +{ + register uint16 res; + + res = pop_sp_byte() << 8; + res |= pop_sp_byte(); + return res; +} + +/* pop a word using the user stack pointer (UP) */ +uint16 pop_up_word(void) +{ + register uint16 res; + + res = pop_up_byte() << 8; + res |= pop_up_byte(); + return res; +} + +/* 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; + } +} + +/* this routine does the jump to long relative offset if the condition is met. Otherwise, execution continues at the current PC. */ +void go_long_rel(int32 cond) +{ + int32 temp; + + temp = get_long_rel_addr(); + if (cond != 0) { + PC += temp; + PC &= ADDRMASK; + } +} + +/* returns the relative offset sign-extended */ +int32 get_rel_addr(void) +{ + int32 temp; + + temp = fetch_byte(1); + if (temp & 0x80) + temp |= 0xFF00; + return temp & ADDRMASK; +} + +/* returns the long relative offset sign-extended */ +int32 get_long_rel_addr(void) +{ + return fetch_word(); +} + +/* returns the byte value at the direct address pointed to by PC */ +int32 get_dir_byte_val(void) +{ + return CPU_BD_get_mbyte(get_dir_addr()); +} + +/* returns the word value at the direct address pointed to by PC */ +int32 get_dir_word_val(void) +{ + return CPU_BD_get_mword(get_dir_addr()); +} + +/* returns the immediate byte value pointed to by PC */ +int32 get_imm_byte_val(void) +{ + return fetch_byte(1); +} + +/* returns the immediate word value pointed to by PC */ +int32 get_imm_word_val(void) +{ + return fetch_word(); +} + +/* returns the direct address pointed to by PC */ +/* use the Direct Page register as the high byte of the address */ +int32 get_dir_addr(void) +{ + int32 temp; + + temp = (DP << 8) + fetch_byte(1); + return temp & 0xFFFF; +} + +/* returns the byte value at the indexed address pointed to by PC */ +int32 get_indexed_byte_val(void) +{ + return CPU_BD_get_mbyte(get_indexed_addr()); +} + +/* returns the word value at the indexed address pointed to by PC */ +int32 get_indexed_word_val(void) +{ + return CPU_BD_get_mword(get_indexed_addr()); +} + +/* returns the indexed address. Note this also handles the indirect indexed mode */ +int32 get_indexed_addr(void) +{ + int32 temp; + int32 offset; + uint8 post_byte; + + /* fetch the index mode post-byte */ + post_byte = fetch_byte(1); + + if ((post_byte & 0x80) == 0) { + /* R +- 4-bit offset (non indirect only) */ + /* read register value */ + switch (post_byte & 0x60) { + case 0b00000000: temp = IX; break; + case 0b00100000: temp = IY; break; + case 0b01000000: temp = UP; break; + case 0b01100000: temp = SP; break; + default: break; + } + /* add 4 bit signed offset */ + if (post_byte & 0x10) { + /* subtract offset */ + offset = (post_byte | 0xFFF0); + temp += offset; + } else { + /* add offset */ + temp += (post_byte & 0x0F); + } + } else { + switch ( post_byte & 0x0F ) { + case 0b0000: + /* .R+ post increment by 1 (non indirect) */ + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX++; IX &= 0xFFFF; break; + case 0b00100000: temp = IY++; IY &= 0xFFFF; break; + case 0b01000000: temp = UP++; UP &= 0xFFFF; break; + case 0b01100000: temp = SP++; SP &= 0xFFFF; break; + default: break; + }; + break; + case 0b0001: + /* .R+ post increment by 2 (non indirect) */ + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX; IX=IX+2; IX &= 0xFFFF; break; + case 0b00100000: temp = IY; IY=IY+2; IY &= 0xFFFF; break; + case 0b01000000: temp = UP; UP=UP+2; UP &= 0xFFFF; break; + case 0b01100000: temp = SP; SP=SP+2; SP &= 0xFFFF; break; + default: break; + }; + break; + case 0b0010: + /* .-R pre decrement by 1 (non indirect) */ + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = --IX; IX &= 0xFFFF; break; + case 0b00100000: temp = --IY; IY &= 0xFFFF; break; + case 0b01000000: temp = --UP; UP &= 0xFFFF; break; + case 0b01100000: temp = --SP; SP &= 0xFFFF; break; + default: break; + }; + break; + case 0b0011: + /* .--R pre decrement by 2 (non indirect) */ + switch ( post_byte & 0x60 ) { + case 0b00000000: IX-=2; temp = IX; IX &= 0xFFFF; break; + case 0b00100000: IY-=2; temp = IY; IY &= 0xFFFF; break; + case 0b01000000: UP-=2; temp = UP; UP &= 0xFFFF; break; + case 0b01100000: SP-=2; temp = SP; SP &= 0xFFFF; break; + default: break; + }; + break; + case 0b0100: + /* R+0 zero offset (non indirect) */ + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX; break; + case 0b00100000: temp = IY; break; + case 0b01000000: temp = UP; break; + case 0b01100000: temp = SP; break; + default: break; + }; + break; + case 0b0101: + /* R+-ACCB (non indirect)*/ + if (B & 0x80) { + offset = B | 0xFF80; + } else { + offset = B; + } + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX; break; + case 0b00100000: temp = IY; break; + case 0b01000000: temp = UP; break; + case 0b01100000: temp = SP; break; + default: break; + }; + temp += offset; + break; + case 0b0110: + /* R+-ACCA (non indirect)*/ + if (A & 0x80) { + offset = A | 0xFF80; + } else { + offset = A; + } + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX; break; + case 0b00100000: temp = IY; break; + case 0b01000000: temp = UP; break; + case 0b01100000: temp = SP; break; + default: break; + }; + temp += offset; + break; + case 0b1000: + /* R+- 8-bit offset */ + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX; break; + case 0b00100000: temp = IY; break; + case 0b01000000: temp = UP; break; + case 0b01100000: temp = SP; break; + default: break; + }; + /* need to fetch 8-bit operand */ + offset = fetch_byte(1); + + /* add 7 bit signed offset */ + if (offset & 0x80) { + /* subtract offset */ + offset |= 0xFF00; + } + temp += offset; + break; + case 0b1001: + /* R+- 16-bit offset */ + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX; break; + case 0b00100000: temp = IY; break; + case 0b01000000: temp = UP; break; + case 0b01100000: temp = SP; break; + default: break; + }; + /* need to fetch 16-bit operand */ + offset = fetch_word(); + + /* add 16 bit signed offset */ + temp += offset; + break; + case 0b1011: + /* R+- ACCD */ + D = (A << 8) + (B & BYTEMASK); + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX + D; break; + case 0b00100000: temp = IY + D; break; + case 0b01000000: temp = UP + D; break; + case 0b01100000: temp = SP + D; break; + default: break; + }; + break; + case 0b1100: + /* PC+- 7-bit offset (non indirect) */ + /* need to fetch 8-bit operand */ + offset = fetch_byte(1); + // PC value after fetch!!! + temp = PC; + + /* add 7 bit signed offset */ + if (offset & 0x80) { + /* subtract offset */ + offset |= 0xFF00; + } + temp += offset; + break; + case 0b1101: + /* PC+- 15-bit offset (non indirect)*/ + /* need to fetch 16-bit operand */ + offset = fetch_word(); + // PC value after fetch!!! + temp = PC; + + /* add 15 bit signed offset */ + temp += offset; + break; + case 0b1111: + // Extended indirect - fetch 16-bit address + temp = fetch_word(); + break; + } + switch ( post_byte & 0x1F ) { + /* perform the indirection - 11 valid post-byte opcodes */ + case 0b10001: + case 0b10011: + case 0b10100: + case 0b10101: + case 0b10110: + case 0b11000: + case 0b11001: + case 0b11011: + case 0b11100: + case 0b11101: + case 0b11111: + temp = temp & 0xFFFF; + temp = CPU_BD_get_mword(temp); + break; + default: break; + } + } + /* make sure to truncate to 16-bit value */ + return temp & 0xFFFF; +} + +/* returns the value at the extended address pointed to by PC */ +int32 get_ext_byte_val(void) +{ + return CPU_BD_get_mbyte(get_ext_addr()); +} + +/* returns the value at the extended address pointed to by PC */ +int32 get_ext_word_val(void) +{ + return CPU_BD_get_mword(get_ext_addr()); +} + +/* returns the extended address pointed to by PC or immediate word */ +int32 get_ext_addr(void) +{ + int32 temp; + + temp = fetch_word(); + return temp; +} + +/* return 1 for flag set or 0 for flag clear */ +int32 get_flag(int32 flg) +{ + if (CCR & flg) { + return 1; + } + else { + return 0; + } +} + +/* test and set V for 8-addition */ +void condevalVa(int32 op1, int32 op2) +{ + if (((op1 & 0x80) == (op2 & 0x80)) && + (((op1 + op2) & 0x80) != (op1 & 0x80))) + SET_FLAG(VF); + else + CLR_FLAG(VF); +} + +/* test and set V for 16-bit addition */ +void condevalVa16(int32 op1, int32 op2) +{ + /* + IF (the sign of the 2 operands are the same) + AND + (the sum of the operands has a different sign than both of the 2 operands) + THEN set the Overflow flag + ELSE clear the Overflow flag + */ + if (((op1 & 0x8000) == (op2 & 0x8000)) && + (((op1 + op2) & 0x8000) != (op1 & 0x8000))) + SET_FLAG(VF); + else + CLR_FLAG(VF); +} + +/* test and set V for 8-bit subtraction */ +void condevalVs(int32 op1, int32 op2) +{ + if (((op1 & 0x80) != (op2 & 0x80)) && + (((op1 - op2) & 0x80) == (op2 & 0x80))) + SET_FLAG(VF); + else + CLR_FLAG(VF); + +} + +/* test and set V for 16-bit subtraction */ +void condevalVs16(int32 op1, int32 op2) +{ + if (((op1 & 0x8000) != (op2 & 0x8000)) && + (((op1 - op2) & 0x8000) == (op2 & 0x8000))) + SET_FLAG(VF); + else + CLR_FLAG(VF); + +} + +/* test and set H for addition (8-bit only) */ +void condevalHa(int32 op1, int32 op2) +{ + if (((op1 & 0x0f) + (op2 & 0x0f)) & 0x10) + SET_FLAG(HF); + else + CLR_FLAG(HF); +} + +/* calls from the simulator */ + +/* Boot routine */ +t_stat m6809_boot(int32 unit_num, DEVICE *dptr) +{ + /* retrieve the reset vector at $FFFE */ + saved_PC = CPU_BD_get_mword(0xFFFE); + if (saved_PC == 0xFFFF) { + ; // No BOOT ROM detected! + } + return SCPE_OK; +} + +/* Reset routine */ +t_stat m6809_reset (DEVICE *dptr) +{ + CCR = EF | FF | IF; + DP = 0; + int_req = 0; + sim_brk_types = sim_brk_dflt = SWMASK ('E'); + + /* retrieve the reset vector at $FFFE */ + saved_PC = CPU_BD_get_mword(0xFFFE); + if (saved_PC == 0xFFFF) { + ; // No BOOT ROM detected! + } + return SCPE_OK; +} + +/* examine routine */ +t_stat m6809_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= 0x10000) { + /* exceed 16-bit address space */ + return SCPE_NXM; + } else { + *eval_array = CPU_BD_get_mbyte(addr); + return SCPE_OK; + } +} + +/* deposit routine */ +t_stat m6809_deposit(t_value value, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= 0x10000) { + /* exceed 16-bit address space */ + return SCPE_NXM; + } else { + CPU_BD_put_mbyte(addr, value); + return SCPE_OK; + } +} + + +/* This is the dumper/loader. This command uses the -h to signify a + hex dump/load vice a binary one. If no address is given to load, it + takes the address from the hex record or the current PC for binary. +*/ + +t_stat sim_load (FILE *fileref, CONST char *cptr, CONST char *fnam, int flag) +{ + int32 i, addr = 0, cnt = 0; + + if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; + addr = saved_PC; + while ((i = getc (fileref)) != EOF) { + CPU_BD_put_mbyte(addr, i); + addr++; + cnt++; + } // end while + printf ("%d Bytes loaded.\n", cnt); + return (SCPE_OK); +} + +/* Symbolic output + + Inputs: + *of = output stream + addr = current PC + *val = pointer to values + *uptr = pointer to unit + sw = switches + Outputs: + status = error code + for M6809 +*/ +t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) +{ + int32 i, inst, inst1; + + if (sw & SWMASK ('D')) { // dump memory + for (i=0; i<16; i++) + fprintf(of, "%02X ", val[i]); + fprintf(of, " "); + for (i=0; i<16; i++) + if (isprint(val[i])) + fprintf(of, "%c", val[i]); + else + fprintf(of, "."); + return -15; + } else if (sw & SWMASK ('M')) { // dump instruction mnemonic + inst = val[0]; + if (!oplen[inst]) { // invalid opcode + fprintf(of, "%02X", inst); + return 0; + } + inst1 = inst & 0xF0; + fprintf (of, "%s", opcode[inst]); // mnemonic + if (strlen(opcode[inst]) == 3) + fprintf(of, " "); + if (inst1 == 0x20 || inst == 0x8D) { // rel operand + inst1 = val[1]; + if (val[1] & 0x80) + inst1 |= 0xFF00; + fprintf(of, " $%04X", (addr + inst1 + 2) & ADDRMASK); + } else if (inst1 == 0x80 || inst1 == 0xC0) { // imm operand + if ((inst & 0x0F) < 0x0C) + fprintf(of, " #$%02X", val[1]); + else + fprintf(of, " #$%02X%02X", val[1], val[2]); + } else if (inst1 == 0x60 || inst1 == 0xA0 || inst1 == 0xE0) // ind operand + fprintf(of, " %d,X", val[1]); + else if (inst1 == 0x70 || inst1 == 0xb0 || inst1 == 0xF0) // ext operand + fprintf(of, " $%02X%02X", val[1], val[2]); + return (-(oplen[inst] - 1)); + } else + return SCPE_ARG; +} + +/* Symbolic input + + Inputs: + *cptr = pointer to input string + addr = current PC + *uptr = pointer to unit + *val = pointer to output values + sw = switches + Outputs: + status = error status +*/ +t_stat parse_sym (CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) +{ + return (-2); +} + +/* end of m6809.c */ diff --git a/swtp6809/common/mp-09.c b/swtp6809/common/mp-09.c new file mode 100644 index 000000000..756435c96 --- /dev/null +++ b/swtp6809/common/mp-09.c @@ -0,0 +1,296 @@ +/* mp-09.c: SWTP MP-09 M6809 CPU simulator + + Copyright (c) 2011-2012, 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. + + The following copyright notice applies to the SWTP 6809 source, binary, and documentation: + + Original code published in 2024, written by Richard F Lukes + Copyright (c) 2024, Richard F Lukes + + 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 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 names of The Authors shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the Authors. + + MODIFICATIONS: + + 24 Apr 15 -- Modified to use simh_debug + 24 Feb 24 -- Richard Lukes - modified SWTPC mp-a2 emulator to create mp-09 emulator. + + NOTES: + + The MP-09 CPU Board includes the SWTP Dynamic Address Translation (DAT) logic which + is used to create a 20-bit virtual address space (1MB of RAM). + + The MP-09 CPU Board contains the following devices [mp-09.c]: + M6809 processor [m6809.c]. + SWTPC SBUG-E, or custom boot ROM at top of 16-bit address space [bootrom.c]. + Interface to the SS-50 bus and the MP-B3 Mother Board for I/O + and memory boards [mp-b3.c]. +*/ + +#include +#include "swtp_defs.h" + +#define UNIT_V_DAT (UNIT_V_UF) /* Dynamic Address Translation setting */ +#define UNIT_DAT (1 << UNIT_V_DAT) + + +/* local global variables */ +unsigned char DAT_RAM[16]; +unsigned char DAT_RAM_CACHE[16]; + +/* function prototypes */ + +t_stat CPU_BD_reset (DEVICE *dptr); +t_stat CPU_BD_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches); +t_stat CPU_BD_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); +int32 DAT_Xlate(int32 logical_addr); +int32 CPU_BD_get_mbyte(int32 addr); +int32 CPU_BD_get_mword(int32 addr); +void CPU_BD_put_mbyte(int32 addr, int32 val); +void CPU_BD_put_mword(int32 addr, int32 val); + +/* external routines */ + +/* MP-B3 bus routines */ +extern int32 MB_get_mbyte(int32 addr); +extern int32 MB_get_mword(int32 addr); +extern void MB_put_mbyte(int32 addr, int32 val); +extern void MB_put_mword(int32 addr, int32 val); + +/* MP-09 data structures + + CPU_BD_dev MP-09 device descriptor + CPU_BD_unit MP-09 unit descriptor + CPU_BD_reg MP-09 register list + CPU_BD_mod MP-09 modifiers list +*/ + +UNIT CPU_BD_unit = { UDATA (NULL, 0, 0) }; + +REG CPU_BD_reg[] = { + { NULL } +}; + +MTAB CPU_BD_mod[] = { + { UNIT_DAT, UNIT_DAT, "DAT enabled", "DAT", NULL }, + { UNIT_DAT, 0, "DAT disabled", "NODAT", NULL }, + { 0 } +}; + +DEBTAB CPU_BD_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE CPU_BD_dev = { + "MP-09", //name + &CPU_BD_unit, //units + CPU_BD_reg, //registers + CPU_BD_mod, //modifiers + 1, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + &CPU_BD_examine, //examine + &CPU_BD_deposit, //deposit + &CPU_BD_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + CPU_BD_debug, /* debflags */ + NULL, //msize + NULL //lname +}; + +/* reset */ +t_stat CPU_BD_reset (DEVICE *dptr) +{ + int32 i; + + /* this is performed whether DAT is enabled or not */ + // initialize DAT RAM + for (i=0; i<16; i++) { + DAT_RAM[i] = (~i) & 0x0F; + DAT_RAM_CACHE[i] = i; + } + return SCPE_OK; +} + +/* Deposit routine */ +t_stat CPU_BD_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= 0x10000) { + return SCPE_NXM; + } else { + CPU_BD_put_mbyte(addr, val); + return SCPE_OK; + } +} + +/* Examine routine */ +t_stat CPU_BD_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= 0x10000) { + return SCPE_NXM; + } + if (eval_array != NULL) { + *eval_array = CPU_BD_get_mbyte(addr); + } + return SCPE_OK; +} + +/* Perform adress translation from 16-bit logical address to 20-bit physical address using DAT mapping RAM */ +int32 DAT_Xlate(int32 logi_addr) +{ + + /* if DAT is enabled perform the Dynamic Address Translation */ + if (CPU_BD_unit.flags & UNIT_DAT) { + + int32 DAT_index; /* which of the 16 mapping registers to index */ + int32 DAT_byte; /* the lookup value from DAT RAM */ + int32 DAT_block; /* A13-A14-A15-A16 */ + + /* translation from 16-bit logical address to 20-bit physical address */ + DAT_index = (logi_addr & 0xF000) >> 12; + DAT_byte = DAT_RAM_CACHE[DAT_index]; + if (DAT_index >= 0xE) { + /* for logical addresses $E000-$FFFF */ + // Bank address (A17-A20) is 0b0000 + return((logi_addr & 0xFFF) + ((DAT_byte & 0x0F)<<12)); + } else { + // Bank address (A17-A20) is the high order 4-bits of DAT_byte + return((logi_addr & 0xFFF) + (DAT_byte<<12)); + } + + } else { + /* DAT is disabled */ + return(logi_addr); + } +} + +/* get a byte from memory */ +int32 CPU_BD_get_mbyte(int32 addr) +{ + int32 val = 0; + int32 phy_addr; + + sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mbyte: addr=%04X\n", addr); + switch(addr & 0xF000) { + case 0xE000: + case 0xF000: + /* ROM is mapped to logical address $E000-$FFFF at all times! Unaffected by DAT */ + val = MB_get_mbyte(addr); + sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mbyte: mp_b3 val=%02X\n", val); + break; + default: + /* access the resources on the motherboard - 16-bit addressing */ + /* 56K of RAM from 0000-DFFF */ + /* 8K of I/O space from E000-EFFF */ + /* 2K of scratchpad RAM from F000-F7FF ??? */ + if (CPU_BD_unit.flags & UNIT_DAT) { + phy_addr = DAT_Xlate(addr); + } else { + phy_addr = addr; + } + val = MB_get_mbyte(phy_addr); + sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mbyte: mp_b3 val=%02X\n", val); + break; + } + return val; +} + +/* get a word from memory */ +int32 CPU_BD_get_mword(int32 addr) +{ + int32 val; + + sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mword: addr=%04X\n", addr); + val = (CPU_BD_get_mbyte(addr) << 8); + val |= CPU_BD_get_mbyte(addr+1); + val &= 0xFFFF; + sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mword: val=%04X\n", val); + return val; +} + +/* put a byte to memory */ +void CPU_BD_put_mbyte(int32 addr, int32 val) +{ + int32 phy_addr; + + sim_debug (DEBUG_write, &CPU_BD_dev, "CPU_BD_put_mbyte: addr=%04X, val=%02X\n", addr, val); + + if ((addr & 0xFFF0) == 0xFFF0) { + /* this is performed whether DAT is enabled or not */ + DAT_RAM[addr & 0x0F] = val; + DAT_RAM_CACHE[addr & 0x0F] = (val & 0xF0) | (~val & 0x0F); + } else { + switch(addr & 0xF800) { + case 0xF800: + /* do not write to ROM area */ + break; + default: + phy_addr = DAT_Xlate(addr); + MB_put_mbyte(phy_addr, val); + break; + } + } +} + +/* put a word to memory */ +void CPU_BD_put_mword(int32 addr, int32 val) +{ + sim_debug (DEBUG_write, &CPU_BD_dev, "CPU_BD_put_mword: addr=%04X, val=%04X\n", addr, val); + CPU_BD_put_mbyte(addr, val >> 8); + CPU_BD_put_mbyte(addr+1, val & 0xFF); +} + +/* end of mp-09.c */ diff --git a/swtp6809/common/mp-1m.c b/swtp6809/common/mp-1m.c new file mode 100644 index 000000000..2560d6375 --- /dev/null +++ b/swtp6809/common/mp-1m.c @@ -0,0 +1,311 @@ +/* mp-1m.c: SWTP 1M Byte Memory Card emulator + + Copyright (c) 2011-2012, William A. 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 O + 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. + + The following copyright notice applies to the SWTP 6809 source, binary, and documentation: + + Original code published in 2024, written by Richard F Lukes + Copyright (c) 2024, Richard F Lukes + + 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 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 names of The Authors shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the Authors. + + MODIFICATIONS: + + 24 Apr 15 -- Modified to use simh_debug + 24 Feb 24 -- Richard Lukes - Modified mp-8m.c to use for 1MB memory for swtp6809 emulator + + NOTES: + + These functions support 1MB of memory on an SS-50 system as a single 1MB memory card. + Due to the way Dynamic Address Translation (DAT) works, the upper 8KB of each 64KB address space is allocated + to I/O ($E000) and ROM ($F000) space. Therefore, the maximum usable RAM is 16 x 56KB = 896KB. + + The unit uses a statically allocated 1MB byte buffer. This makes for a fast implementation. + No effort was made to make available memory variable in size (e.g. limit to only 32KB, 64KB, 96KB, 128KB, etc.). +*/ + +#include +#include "swtp_defs.h" + +/* this is the maximum size of the physical address space */ +#define ONE_MEGABYTE 0x100000 + +/* this is the value returned when reading a byte of non-existant memory */ +#define BLANK_MEMORY_BYTE_VALUE 0xFF + +#define UNIT_V_MSIZE (UNIT_V_UF) /* user defined options */ +#define UNIT_MSIZE (0xFF << UNIT_V_MSIZE) +#define UNIT_8KB (0x01 << UNIT_V_MSIZE) /* 8KB */ +#define UNIT_16KB (0x02 << UNIT_V_MSIZE) /* 16KB */ +#define UNIT_32KB (0x04 << UNIT_V_MSIZE) /* 32KB */ +#define UNIT_56KB (0x08 << UNIT_V_MSIZE) /* 56KB */ +#define UNIT_128KB (0x10 << UNIT_V_MSIZE) /* 128KB */ +#define UNIT_256KB (0x20 << UNIT_V_MSIZE) /* 256KB */ +#define UNIT_512KB (0x30 << UNIT_V_MSIZE) /* 512KB */ +#define UNIT_1024KB (0x40 << UNIT_V_MSIZE) /* 1024KB */ + +/* prototypes */ + +t_stat mp_1m_reset (DEVICE *dptr); +t_stat mp_1m_config(UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat mp_1m_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches); +t_stat mp_1m_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); +int32 mp_1m_get_mbyte(int32 addr); +int32 mp_1m_get_mword(int32 addr); +void mp_1m_put_mbyte(int32 addr, int32 val); +void mp_1m_put_mword(int32 addr, int32 val); + +UNIT mp_1m_unit = { + UDATA (NULL, UNIT_FIX + UNIT_BINK, ONE_MEGABYTE) +}; + +MTAB mp_1m_mod[] = { + { UNIT_MSIZE, UNIT_1024KB, "1MB of RAM", "1024KB", &mp_1m_config }, + { UNIT_MSIZE, UNIT_512KB, "512KB of RAM", "512KB", &mp_1m_config }, + { UNIT_MSIZE, UNIT_256KB, "256KB of RAM", "256KB", &mp_1m_config }, + { UNIT_MSIZE, UNIT_128KB, "128KB of RAM", "128KB", &mp_1m_config }, + { UNIT_MSIZE, UNIT_56KB, "56KB of RAM", "56KB", &mp_1m_config }, + { UNIT_MSIZE, UNIT_32KB, "32KB of RAM", "32KB", &mp_1m_config }, + { UNIT_MSIZE, UNIT_16KB, "16KB of RAM", "16KB", &mp_1m_config }, + { UNIT_MSIZE, UNIT_8KB, "8KB of RAM", "8KB", &mp_1m_config }, + { 0 } +}; + +DEBTAB mp_1m_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE mp_1m_dev = { + "MP-1M", //name + &mp_1m_unit, //units + NULL, //registers + mp_1m_mod, //modifiers + 1, //numunits + 16, //aradix + 20, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + &mp_1m_examine, //examine + &mp_1m_deposit, //deposit + &mp_1m_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + mp_1m_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* Pre-allocate 1MB array of bytes */ +uint8 mp_1m_ram_memory_array[ONE_MEGABYTE]; + +/* mp_1m_config */ +t_stat mp_1m_config (UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + + sim_debug (DEBUG_flow, &mp_1m_dev, "mp_1m_config: val=%d\n", val); + if ((val > UNIT_1024KB) || (val < UNIT_8KB)) { /* valid param? */ + sim_debug (DEBUG_flow, &mp_1m_dev, "mp_1m_config: Parameter error\n"); + return SCPE_ARG; + } + + /* set RAM size. All RAM starts with a base address of 00000H */ + switch ( val ) { + case UNIT_8KB: + mp_1m_unit.capac = 8 * 1024; + break; + case UNIT_16KB: + mp_1m_unit.capac = 16 * 1024; + break; + case UNIT_32KB: + mp_1m_unit.capac = 32 * 1024; + break; + case UNIT_56KB: + mp_1m_unit.capac = 56 * 1024; + break; + case UNIT_128KB: + mp_1m_unit.capac = 128 * 1024; + break; + case UNIT_256KB: + mp_1m_unit.capac = 256 * 1024; + break; + case UNIT_512KB: + mp_1m_unit.capac = 512 * 1024; + break; + case UNIT_1024KB: + mp_1m_unit.capac = 1024 * 1024; + break; + default: + /* what to do? default to 1024KB */ + mp_1m_unit.capac = 1024 * 1024; + } + sim_debug (DEBUG_flow, &mp_1m_dev, "mp_1m_config: mp_1m_unit.capac=%d\n", mp_1m_unit.capac); + sim_debug (DEBUG_flow, &mp_1m_dev, "mp_1m_config: Done\n"); + + return SCPE_OK; +} /* mp-1m config */ + +/* Deposit routine */ +t_stat mp_1m_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= mp_1m_unit.capac) { + return SCPE_NXM; + } else { + mp_1m_ram_memory_array[addr] = val & 0xFF; + return SCPE_OK; + } +} + +/* Examine routine */ +t_stat mp_1m_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= mp_1m_unit.capac) { + return SCPE_NXM; + } + if (eval_array != NULL) { + *eval_array = mp_1m_ram_memory_array[addr]; + } + return SCPE_OK; +} + +/* Reset routine */ + +t_stat mp_1m_reset (DEVICE *dptr) +{ + int32 i, j, val; + UNIT *uptr; + + sim_debug (DEBUG_flow, &mp_1m_dev, "mp_1m_reset: \n"); + uptr = mp_1m_dev.units; + sim_debug (DEBUG_flow, &mp_1m_dev, "MP-1M %d unit.flags=%08X\n", i, uptr->flags); + + // capacity + uptr->capac = ONE_MEGABYTE; + // starting address + uptr->u3 = 0; + + if (uptr->filebuf == NULL) { + uptr->filebuf = &mp_1m_ram_memory_array; + if (uptr->filebuf == NULL) { + printf("mp_1m_reset: Malloc error\n"); + return SCPE_MEM; + } + for (j=0; j < uptr->capac; j++) { /* populate memory with fill pattern */ + i = j & 0xF; + val = (0xA0 | i) & BYTEMASK; + *((uint8 *)(uptr->filebuf) + j) = val; + } + sim_debug (DEBUG_flow, &mp_1m_dev, "MP-1M %d initialized at [%05X-%05XH]\n", i, uptr->u3, uptr->u3 + uptr->capac - 1); + } + sim_debug (DEBUG_flow, &mp_1m_dev, "mp_1m_reset: Done\n"); + return SCPE_OK; +} + +/* + I/O instruction handlers, called from the mp-b3 module when an + external memory read or write is issued. +*/ + +/* get a byte from memory */ + +int32 mp_1m_get_mbyte(int32 addr) +{ + //UNIT *uptr; + int32 val; + + //uptr = mp_1m_dev.units; + sim_debug (DEBUG_read, &mp_1m_dev, "mp_1m_get_mbyte: addr=%05X", addr); + if (addr >= mp_1m_unit.capac) { + sim_debug (DEBUG_read, &mp_1m_dev, "mp_1m_get_mbyte: addr=%08X Out of range\n", addr); + return BLANK_MEMORY_BYTE_VALUE; + } else { + val = mp_1m_ram_memory_array[addr]; + sim_debug (DEBUG_read, &mp_1m_dev, " addr=%05x val=%02X\n", addr, val); + return val; + } +} + +/* get a word from memory */ + +int32 mp_1m_get_mword(int32 addr) +{ + int32 val; + + val = (mp_1m_get_mbyte(addr) << 8); + val |= mp_1m_get_mbyte(addr+1); + return val; +} + +/* put a byte into memory */ + +void mp_1m_put_mbyte(int32 addr, int32 val) +{ + sim_debug (DEBUG_write, &mp_1m_dev, "mp_1m_put_mbyte: addr=%05X, val=%02X", addr, val); + + if (addr >= mp_1m_unit.capac) { + sim_debug (DEBUG_write, &mp_1m_dev, "mp_1m_put_mbyte: Address out of range, addr=%08x\n", addr); + } else { + mp_1m_ram_memory_array[addr] = val; + sim_debug (DEBUG_write, &mp_1m_dev, "\n"); + } +} + +/* put a word into memory */ + +void mp_1m_put_mword(int32 addr, int32 val) +{ + mp_1m_put_mbyte(addr, val >> 8); + mp_1m_put_mbyte(addr+1, val & BYTEMASK); +} + +/* end of mp-1m.c */ diff --git a/swtp6809/common/mp-b3.c b/swtp6809/common/mp-b3.c new file mode 100644 index 000000000..244251b31 --- /dev/null +++ b/swtp6809/common/mp-b3.c @@ -0,0 +1,308 @@ +/* mp-b3.c: SWTP SS-50/SS-30 MP-B3 Mother Board + + Copyright (c) 2011-2012, William A. 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. + + The following copyright notice applies to the SWTP 6809 source, binary, and documentation: + + Original code published in 2024, written by Richard F Lukes + Copyright (c) 2024, Richard F Lukes + + 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 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 names of The Authors shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the Authors. + + MODIFICATIONS: + + 24 Apr 15 -- Modified to use simh_debug + 24 Feb 24 -- Richard Lukes - Modified to emulate MP-B3 motherboard for swtp6809 emulator + + NOTES: + +*/ + +#include +#include "swtp_defs.h" + + +#define UNIT_V_4BYTESPERSLOT (UNIT_V_UF) /* MP-1M board enable */ +#define UNIT_4BYTESPERSLOT (1 << UNIT_V_4BYTESPERSLOT) + +/* function prototypes */ + +/* empty I/O device routine */ +int32 nulldev(int32 io, int32 data); + +/* SS-50 bus routines */ +t_stat MB_reset (DEVICE *dptr); +t_stat MB_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches); +t_stat MB_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); +int32 MB_get_mbyte(int32 addr); +int32 MB_get_mword(int32 addr); +void MB_put_mbyte(int32 addr, int32 val); +void MB_put_mword(int32 addr, int32 val); + +/* BOOTROM memory access routines */ +extern int32 BOOTROM_get_mbyte(int32 offset); + +/* MP-1M memory access routines */ +extern int32 mp_1m_get_mbyte(int32 addr); +extern void mp_1m_put_mbyte(int32 addr, int32 val); + +/* SS-50 I/O address space functions */ + +/* MP-S serial I/O 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); + +/* DC-4 FDC I/O routines */ +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); + +/* +MP-B3 configured with 4 address per SS-30 slot (x8). + +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] = { + {&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /* Port 0 E000-E003 */ + {&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /* Port 1 E004-E007 */ +/* 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 E008-E00B */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* Port 3 E00C-E00F */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* Port 4 E010-E013 */ + {&fdcdrv}, {&nulldev}, {&nulldev}, {&nulldev}, /* Port 5 E014-E017 */ + {&fdccmd}, {&fdctrk}, {&fdcsec}, {&fdcdata}, /* Port 6 E018-E01B */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev} /* Port 7 E01C-E01F */ +}; + +/* dummy i/o device */ + +int32 nulldev(int32 io, int32 data) +{ + if (io == 0) { + return (0xFF); + } else { + return 0; + } +} + +/* Mother Board data structures + + MB_dev Mother Board device descriptor + MB_unit Mother Board unit descriptor + MB_reg Mother Board register list + MB_mod Mother Board modifiers list +*/ + +UNIT MB_unit = { + UDATA (NULL, 0, 0) +}; + +REG MB_reg[] = { + { NULL } +}; + +MTAB MB_mod[] = { + { UNIT_4BYTESPERSLOT, UNIT_4BYTESPERSLOT, "I/O port size of 4 bytes", "4BYTE", NULL, NULL }, + { UNIT_4BYTESPERSLOT, 0, "I/O port size of 16 bytes is not supported", "16BYTE", NULL, NULL }, + { 0 } +}; + +DEBTAB MB_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE MB_dev = { + "MP-B3", //name + &MB_unit, //units + MB_reg, //registers + MB_mod, //modifiers + 1, //numunits + 16, //aradix + 20, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + &MB_examine, //examine + &MB_deposit, //deposit + &MB_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + MB_debug, /* debflags */ + NULL, //msize + NULL //lname +}; + +/* reset */ +t_stat MB_reset (DEVICE *dptr) +{ + return SCPE_OK; +} + +/* Deposit routine */ +t_stat MB_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= 0x100000) { + /* exceed 20-bit address space */ + return SCPE_NXM; + } else { + MB_put_mbyte(addr, val); + return SCPE_OK; + } +} + +/* Examine routine */ +t_stat MB_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= 0x100000) { + return SCPE_NXM; + } + if (eval_array != NULL) { + *eval_array = MB_get_mbyte(addr); + } + return SCPE_OK; +} + +/* get a byte from memory */ + +int32 MB_get_mbyte(int32 addr) +{ + int32 val; + + // 20-bit physical addresses + sim_debug (DEBUG_read, &MB_dev, "MB_get_mbyte: addr=%05X\n", addr); + switch (addr & 0x0F800) { + case 0x0E000: + /* reserved I/O space from $E000-$E01F */ + if ((addr & 0xFFFF) < 0xE020) { + val = (dev_table[(addr & 0xFFFF) - 0xE000].routine(0, 0)) & 0xFF; + break; + } + case 0x0E800: + case 0x0F000: + case 0x0F800: + /* Up to 8KB of boot ROM from $E000-$FFFF */ + val = BOOTROM_get_mbyte(addr & 0xFFFF); + sim_debug (DEBUG_read, &MB_dev, "MB_get_mbyte: EPROM=%02X\n", val); + break; + default: + /* all the rest is RAM */ + val = mp_1m_get_mbyte(addr); + if (MB_dev.dctrl & DEBUG_read) { + printf("MB_get_mbyte: mp_1m add=%05x val=%02X\n", addr, val); + } + break; + } + sim_debug (DEBUG_read, &MB_dev, "MB_get_mbyte: I/O addr=%05X val=%02X\n", addr, val); + return val; +} + +/* get a word from memory */ + +int32 MB_get_mword(int32 addr) +{ + int32 val; + + sim_debug (DEBUG_read, &MB_dev, "MB_get_mword: addr=%04X\n", addr); + val = (MB_get_mbyte(addr) << 8); + val |= MB_get_mbyte(addr+1); + val &= 0xFFFF; + sim_debug (DEBUG_read, &MB_dev, "MB_get_mword: val=%04X\n", val); + return val; +} + +/* put a byte to memory */ + +void MB_put_mbyte(int32 addr, int32 val) +{ + // 20-bit physical addresses + sim_debug (DEBUG_write, &MB_dev, "MB_put_mbyte: addr=%05X, val=%02X\n", addr, val); + + switch(addr & 0xF000) { + case 0xE000: + /* I/O and ROM space */ + if ((addr & 0xFFFF) < 0xE020) { + dev_table[(addr & 0xFFFF) - 0xE000].routine(1, val); + } + break; + case 0xF000: + /* ROM space */ + break; + default: + /* RAM */ + mp_1m_put_mbyte(addr, val); + break; + } +} + +/* put a word to memory */ + +void MB_put_mword(int32 addr, int32 val) +{ + sim_debug (DEBUG_write, &MB_dev, "MB_ptt_mword: addr=%04X, val=%04X\n", addr, val); + MB_put_mbyte(addr, val >> 8); + MB_put_mbyte(addr+1, val & 0xFF); +} + +/* end of mp-b3.c */ diff --git a/swtp6809/common/mp-s.c b/swtp6809/common/mp-s.c new file mode 100644 index 000000000..7267d1951 --- /dev/null +++ b/swtp6809/common/mp-s.c @@ -0,0 +1,381 @@ +/* mp-s.c: SWTP MP-S serial I/O card simulator + + Copyright (c) 2005-2012, 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 + Willaim 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. + + MODIFICATIONS: + + 28 May 22 -- Roberto Sancho Villa (RSV) fixes for DEL and BS + + NOTES: + + These functions support a simulated SWTP MP-S interface card. + The card contains one M6850 ACIA. The ACIA implements one complete + serial port. It provides 7 or 8-bit ASCII RS-232 interface to Terminals + or 20 mA current loop interface to a model 33 or 37 Teletype. It is not + compatible with baudot Teletypes. Baud rates from 110 to 1200 are + switch selectable from S! on the MP-S. The ACIA ports appear at all + 4 addresses. This fact is used by SWTBUG to determine the presence of the + MP-S vice MP-C serial card. The ACIA interrupt request line can be connected + to the IRQ or NMI interrupt lines by a jumper on the MP-S. + + All I/O is via either programmed I/O or interrupt controlled I/O. + It has a status port and a data port. A write to the status port + can select some options for the device (0x03 will reset the port). + A read of the status port gets the port status: + + +---+---+---+---+---+---+---+---+ + | I | P | O | F |CTS|DCD|TXE|RXF| + +---+---+---+---+---+---+---+---+ + + RXF - A 1 in this bit position means a character has been received + on the data port and is ready to be read. + TXE - A 1 in this bit means the port is ready to receive a character + on the data port and transmit it out over the serial line. + + A read to the data port gets the buffered character, a write + to the data port writes the character to the device. +*/ + +#include +#include +#include "swtp_defs.h" + +#define UNIT_V_TTY (UNIT_V_UF) // TTY or ANSI mode +#define UNIT_TTY (1 << UNIT_V_TTY) + +#define RXF 0x01 +#define TXE 0x02 +#define DCD 0x04 +#define CTS 0x08 + +/* local global variables */ + +int32 ptr_stopioe = 0; // stop on error +int32 ptp_stopioe = 0; // stop on error +int32 odata; +int32 status; + +int32 ptp_flag = 0; +int32 ptr_flag = 0; + +/* function prototypes */ + +t_stat sio_svc (UNIT *uptr); +t_stat ptr_svc (UNIT *uptr); +t_stat ptp_svc (UNIT *uptr); +t_stat sio_reset (DEVICE *dptr); +t_stat ptr_reset (DEVICE *dptr); +t_stat ptp_reset (DEVICE *dptr); +int32 sio0s(int32 io, int32 data); +int32 sio0d(int32 io, int32 data); +int32 sio1s(int32 io, int32 data); +int32 sio1d(int32 io, int32 data); + +/* sio data structures + + sio_dev SIO device descriptor + sio_unit SIO unit descriptor + sio_reg SIO register list + sio_mod SIO modifiers list */ + +UNIT sio_unit = { + UDATA (&sio_svc, 0, 0), KBD_POLL_WAIT +}; + +REG sio_reg[] = { + { ORDATA (DATA, sio_unit.buf, 8) }, + { ORDATA (STAT, sio_unit.u3, 8) }, + { NULL } +}; + +MTAB sio_mod[] = { + { UNIT_TTY, UNIT_TTY, "TTY", "TTY", NULL }, + { UNIT_TTY, 0, "ANSI", "ANSI", NULL }, + { 0 } +}; + +DEVICE sio_dev = { + "MP-S", //name + &sio_unit, //units + sio_reg, //registers + sio_mod, //modifiers + 1, //numunits + 10, //aradix + 31, //awidth + 1, //aincr + 8, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + &sio_reset, //reset + NULL, //boot + NULL, //attach + NULL //detach +}; + +/* paper tape reader data structures + + ptr_dev PTR device descriptor + ptr_unit PTR unit descriptor + ptr_reg PTR register list + ptr_mod PTR modifiers list */ + +UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ + UNIT_ATTABLE, 0), KBD_POLL_WAIT +}; + +DEVICE ptr_dev = { + "PTR", //name + &ptr_unit, //units + NULL, //registers + NULL, //modifiers + 1, //numunits + 10, //aradix + 31, //awidth + 1, //aincr + 8, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + &ptr_reset, //reset + NULL, //boot + NULL, //attach + NULL //detach +}; + +/* paper tape punch data structures + + ptp_dev PTP device descriptor + ptp_unit PTP unit descriptor + ptp_reg PTP register list + ptp_mod PTP modifiers list */ + +UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ + UNIT_ATTABLE, 0), KBD_POLL_WAIT +}; +DEVICE ptp_dev = { + "PTP", //name + &ptp_unit, //units + NULL, //registers + NULL, //modifiers + 1, //numunits + 10, //aradix + 31, //awidth + 1, //aincr + 8, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + &ptp_reset, //reset + NULL, //boot + NULL, //attach + NULL //detach +}; + +/* console input service routine */ + +t_stat sio_svc (UNIT *uptr) +{ + int32 temp; + + sim_activate (&sio_unit, sio_unit.wait); // continue poll + if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) + return temp; // no char or error? + sio_unit.buf = temp & BYTEMASK; // Save char + if (sio_unit.buf==127) { + // convert BackSpace (ascii 127) so del char (ascii 8) for swtbug + sio_unit.buf=8; + } + sio_unit.u3 |= RXF; // Set RXF flag + /* Do any special character handling here */ + sio_unit.pos++; // step character count + return SCPE_OK; +} + +/* paper tape reader input service routine */ + +t_stat ptr_svc (UNIT *uptr) +{ + int32 temp; + + sim_activate (&ptr_unit, ptr_unit.wait); // continue poll + if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) + return temp; // no char or error? + ptr_unit.buf = temp & BYTEMASK; // Save char + ptr_unit.u3 |= RXF; // Set RXF flag + /* Do any special character handling here */ + ptr_unit.pos++; // step character count + return SCPE_OK; +} + +/* paper tape punch output service routine */ + +t_stat ptp_svc (UNIT *uptr) +{ + return SCPE_OK; +} + +/* Reset console */ + +t_stat sio_reset (DEVICE *dptr) +{ + sio_unit.buf = 0; //clear data buffer + sio_unit.u3 = TXE; //set TXE flag + sio_unit.wait = 10000; + sim_activate (&sio_unit, sio_unit.wait); // activate unit + return SCPE_OK; +} + +/* Reset paper tape reader */ + +t_stat ptr_reset (DEVICE *dptr) +{ + ptr_unit.buf = 0; //clear data buffer + ptr_unit.u3 = TXE; //set TXE flag + sim_cancel (&ptr_unit); // deactivate unit + return SCPE_OK; +} + +/* Reset paper tape punch */ + +t_stat ptp_reset (DEVICE *dptr) +{ + ptp_unit.buf = 0; //clear data buffer + ptp_unit.u3 = TXE; //set TXE flag + sim_cancel (&ptp_unit); // deactivate unit + return SCPE_OK; +} + +/* I/O instruction handlers, called from the MP-B2 module when a + read or write occur to addresses 0x8004-0x8007. */ + +int32 sio0s(int32 io, int32 data) +{ + if (io == 0) { // control register read + if (ptr_flag) { // reader enabled? + if ((ptr_unit.flags & UNIT_ATT) == 0) { // attached? + ptr_unit.u3 &= ~RXF; // no, clear RXF flag + ptr_flag = 0; // clear reader flag + printf("Reader not attached to file\n"); + } else { // attached + if (feof(ptr_unit.fileref)) { // EOF + ptr_unit.u3 &= ~RXF; // clear RXF flag + ptr_flag = 0; // clear reader flag + } else // not EOF + ptr_unit.u3 |= RXF; // set ready + } + return (status = ptr_unit.u3); // return ptr status + } else { + return (status = sio_unit.u3); // return console status + } + } else { // control register write + if (data == 0x03) { // reset port! + sio_unit.u3 = TXE; // reset console + sio_unit.buf = 0; + sio_unit.pos = 0; + ptr_unit.u3 = TXE; // reset reader + ptr_unit.buf = 0; + ptr_unit.pos = 0; + ptp_unit.u3 = TXE; // reset punch + ptp_unit.buf = 0; + ptp_unit.pos = 0; + } + return (status = 0); // invalid io + } +} + +int32 sio0d(int32 io, int32 data) +{ + if (io == 0) { // data register read + if (ptr_flag) { // RDR enabled? + if ((ptr_unit.flags & UNIT_ATT) == 0) // attached? + return 0; // no, done + if ((ptr_unit.u3 & RXF) == 0) // yes, more data? + return (odata & BYTEMASK); + if ((odata = getc(ptr_unit.fileref)) == EOF) { // end of file? + printf("Got EOF\n"); + ptr_unit.u3 &= 0xFE; // clear RXF flag + return (odata = 0); // no data + } + ptr_unit.pos++; // step character count + ptr_unit.u3 &= ~RXF; // clear RXF flag + return (odata & BYTEMASK); // return character + } else { + sio_unit.u3 &= ~RXF; // clear RXF flag + return (odata = sio_unit.buf); // return next char + } + } else { // data register write + if (isprint(data) || data == '\r' || data == '\n') { // printable? + sim_putchar(data); // print character on console + if (ptp_flag && ptp_unit.flags & UNIT_ATT) { // PTP enabled & attached? + putc(data, ptp_unit.fileref); + ptp_unit.pos++; // step character counter + } + } else { // DC1-DC4 control Reader/Punch + switch (data) { + case 0x11: // PTR on + ptr_flag = 1; + ptr_unit.u3 |= RXF; + printf("Reader on\n"); + break; + case 0x12: // PTP on + ptp_flag = 1; + ptp_unit.u3 |= TXE; + printf("Punch on\n"); + break; + case 0x13: // PTR off + ptr_flag = 0; + if (ptr_unit.pos) + printf("Reader off-%d bytes read\n", ptr_unit.pos); + ptr_unit.pos = 0; + break; + case 0x14: // PTP off + ptp_flag = 0; + if (ptp_unit.pos) + printf("Punch off-%d bytes written\n", ptp_unit.pos); + ptp_unit.pos = 0; + break; + default: // ignore all other characters + break; + } + } + } + return (odata = 0); +} + +/* because each port appears at 2 addresses and this fact is used + to determine if it is a MP-C or MP-S repeatedly in the SWTBUG + monitor, this code assures that reads of the high ports return + the same data as was read the last time on the low ports. +*/ + +int32 sio1s(int32 io, int32 data) +{ + return status; +} + +int32 sio1d(int32 io, int32 data) +{ + return odata; +} + +/* end of mp-s.c */ diff --git a/swtp6809/swtp6809/mp-09_sys.c b/swtp6809/swtp6809/mp-09_sys.c new file mode 100644 index 000000000..3c0f79298 --- /dev/null +++ b/swtp6809/swtp6809/mp-09_sys.c @@ -0,0 +1,115 @@ +/* mp09_sys.c: SWTP 6809 system interface + + Copyright (c) 2005-2012, 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. + + The following copyright notice applies to the SWTP 6809 source, binary, and documentation: + + Original code published in 2024, written by Richard F Lukes + Copyright (c) 2024, Richard F Lukes + + 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 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 names of The Authors shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the Authors. + + MODIFICATIONS + + 24 Feb 24 -- Richard Lukes - Modified mp-a2_sys.c for SWTP MP-09 emulation +*/ + +#include +#include +#include "swtp_defs.h" + +/* externals */ + +extern DEVICE CPU_BD_dev; +extern DEVICE m6809_dev; +extern REG m6809_reg[]; +extern DEVICE BOOTROM_dev; + +extern DEVICE MB_dev; +extern DEVICE sio_dev; +extern DEVICE ptr_dev; +extern DEVICE ptp_dev; +extern DEVICE mp_1m_dev; +extern DEVICE dsk_dev; + +/* SCP data structures + + sim_name simulator name string + sim_PC pointer to saved PC register descriptor + sim_emax number of words needed for examine + sim_devices array of pointers to simulated devices + sim_stop_messages array of pointers to stop messages + sim_load binary loader +*/ + +char sim_name[] = "SWTP 6809, V1.0, MP-09 CPU Board"; + +REG *sim_PC = &m6809_reg[0]; + +// maximum number of words needed for examine +int32 sim_emax = 4; + +DEVICE *sim_devices[] = { + &m6809_dev, + &CPU_BD_dev, + &BOOTROM_dev, + &MB_dev, + &sio_dev, + &ptr_dev, + &ptp_dev, + &mp_1m_dev, + &dsk_dev, + NULL +}; + +const char *sim_stop_messages[] = { + "Unknown error", + "RESERVED", + "Halt instruction", + "Breakpoint" + "Invalid opcode", + "Invalid memory", + "Unknown error" +}; + +/* end of mp09_sys.c */ diff --git a/swtp6809/swtp6809/sbuge.bin b/swtp6809/swtp6809/sbuge.bin new file mode 100644 index 0000000000000000000000000000000000000000..8c772c07a9594210390443855f357ad620f5300a GIT binary patch literal 2048 zcmYjSe@q+q6~7-}6G(}CVZ@KJZuf=2T}^=4^qlmz5eg;*+$>=@ESdjk7LQgHN{hBu zO{FP`t(sc{__|F~oBp#p8ok>xYTB&A)szvE5NqwamQC$8RZ4AK3%bzKLlcP&^?BcO zR%zd_zVE)D_kHj4-rc=-m#fa5DEz(fZXr`xE6f$%EWExMQOyBPP0b}aEu_Z+LS9Xy zE2%Uvr<0WC0n`qt+kqYi)C9I#KmjK+?UR8u zz*Y(9AVIw{AQq4bXdgj6C1_$^rTSP$NNI1f>Bb0Rcgs z1T6u23s8j)g_d{rrxAYTW_3Fu{QvUL3gu$lX}hs(vqaE*8~{D=tQZGv6a zCofEj<$!*obO0K0*WqjK4m=C&gM1r#>@FVLfK{Dk5}sOYpkwRL0|ZgQusm zqK(|8$hHM#iL=78EAcF_mjGewjRE^QpqhZN4v32{TADC!MBy_#8Ko5v9S~OW<&n%t z2H0Ja%lXr(VB;xZKjrZ!LlXLZT90v4*~T?49xQ2?mGq}E@jIm`qpl8M4_YB7fqmY? z0et}2eqd$Q90T@LdV&~1j2#KXaoXUNe@p1IHzFoNzX64G1|8iEH3753%m*W<)CMeETJS02n7$4Pp50nrmK^zN>MI) zf}(_cK)9{g6X}}h-rMP#8zf(nO1d`cB*_qEJqd*?ZZM*4CjE6ibl1eV(M&S=Dv1)c ztZWDR=GjyR=-0x2ArG_`mc{n4TUY}cB*rNKRdm)#+){cay^v7T3S)~f-AAgqpO;9Z3o}=(i zCW)7aRC5*R+P|>;d7zf#L7+Zb39kHTB|-|D`seVFugR0^CO@xYF&6(HB&&vw0YHB!cRpjoQL=-r3I)fQM=R2(?roOary}l zCr7tC+j`01&qcR5@3*>0j*f&~jo%2%^=!x`hdUdq!aZcWR}P&#d3~65v z6JcPXB6d%oNF>C~DhQBK$2~g9os?^+DW%(ZeMb+J}zz zb{^?KmZ}-|cl!O-wX5%lANL)?`v(RN4}1$F+`bQ^y?Z>;18r^>#{T|xgmJ&ul7oIr z_WhtFk6E(2blPccyDZ`L5{CUfy?uuQ-}n06$V%z|hFUZfyB_ihn~I@F)P)$Q4qjZ1 zaMKZPDk9$FI%iN5Mojn||Kp1YX?p8LC5i>^z0{o5t$NEyEAiW{RE}uArp^CZi}i$n z(A*^v{{00(sRf?1ocVLl+x1uRhss*Xzg4MR(gd5YDUYj1wB_c*eBF{JBC-t~3|F@N zhonb7;W0f#e#8Ddsf;5ReDaml99i>ZCCU0TS?^fi!==!)@9?p{+0?re#UlBQj$cl_ kS6?o1pUua+pIqC^uXYj3YsE{&WO1hW$Kq`98ky980S-DW-~a#s literal 0 HcmV?d00001 diff --git a/swtp6809/swtp6809/swtp6809mp-09.ini b/swtp6809/swtp6809/swtp6809mp-09.ini new file mode 100644 index 000000000..8a33ff309 --- /dev/null +++ b/swtp6809/swtp6809/swtp6809mp-09.ini @@ -0,0 +1,13 @@ +reset +set mp-09 DAT +set mp-1m 1MB +set cpu hex +set cpu itrap +set dc-40 RO +set dc-41 RO +set mp-s TTY +set bootrom 2716 +attach bootrom sbuge.bin +attach dc-40 FULL.DSK +attach dc-41 FULL2.DSK +boot cpu diff --git a/swtp6809/swtp6809/swtp_defs.h b/swtp6809/swtp6809/swtp_defs.h new file mode 100644 index 000000000..6b91e4629 --- /dev/null +++ b/swtp6809/swtp6809/swtp_defs.h @@ -0,0 +1,64 @@ +/* swtp_defs.h: SWTP 6809 simulator definitions + + Copyright (c) 2005-2012, 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 SHAL + 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 I + 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. + + MODIFICATIONS + + 24 Feb 24 - Richard Lukes - Modified for swtp6809 emulator +*/ + +#include +#include "sim_defs.h" // simulator defs + +/* Rename of global PC variable to avoid namespace conflicts on some platforms */ + +#define PC PC_Global + +/* Memory */ + +#define MAXMEMSIZE 65536 // max memory size +#define MEMSIZE (m6809_unit.capac) // actual memory size +#define ADDRMASK (MAXMEMSIZE - 1) // address mask +#define BYTEMASK 0xFF +#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) + +/* debug definitions */ + +#define DEBUG_flow 0x0001 +#define DEBUG_read 0x0002 +#define DEBUG_write 0x0004 +#define DEBUG_level1 0x0008 +#define DEBUG_level2 0x0010 +#define DEBUG_reg 0x0020 +#define DEBUG_asm 0x0040 +#define DEBUG_all 0xFFFF + +/* Simulator stop codes */ + +#define STOP_RSRV 1 // must be 1 +#define STOP_HALT 2 // HALT-really WAI +#define STOP_IBKPT 3 // breakpoint +#define STOP_OPCODE 4 // invalid opcode +#define STOP_MEMORY 5 // invalid memory address + From c2ba2023211da376424c8219d368379212410ad6 Mon Sep 17 00:00:00 2001 From: rfromafar Date: Sun, 25 Feb 2024 10:49:59 -0600 Subject: [PATCH 06/10] swtp6809: simulator being contributed to open-simh project #357 (Pull Request) --- swtp6809/common/bootrom.c | 318 +++ swtp6809/common/dc-4.c | 654 ++++++ swtp6809/common/m6809.c | 3394 +++++++++++++++++++++++++++ swtp6809/common/mp-09.c | 285 +++ swtp6809/common/mp-1m.c | 221 ++ swtp6809/common/mp-b3.c | 293 +++ swtp6809/swtp6809/mp-09_sys.c | 92 + swtp6809/swtp6809/swtp6809mp-09.ini | 32 + swtp6809/swtp6809/swtp_defs.h | 67 + 9 files changed, 5356 insertions(+) diff --git a/swtp6809/common/bootrom.c b/swtp6809/common/bootrom.c index 401f8c9a4..02c378490 100644 --- a/swtp6809/common/bootrom.c +++ b/swtp6809/common/bootrom.c @@ -1,3 +1,4 @@ +<<<<<<< HEAD /* bootrom.c: Boot ROM simulator for Motorola processors Copyright (c) 2010-2012, William A. Beech @@ -341,3 +342,320 @@ int32 BOOTROM_get_mbyte(int32 address) } /* BOOTROM_get_mbyte() */ /* end of bootrom.c */ +======= +/* bootrom.c: Boot ROM simulator for Motorola processors + + Copyright (c) 2010-2012, William A. 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. + + MODIFICATIONS: + + 23 Apr 15 -- Modified to use simh_debug + 20 Feb 24 -- Richard Lukes - Modified for swtp6809 emulator + + NOTES: + + These functions support a single simulated 2704 to 2764 EPROM device on + an 8-bit computer system.. This device allows the buffer to be loaded from + a binary file containing the emulated EPROM code. + + These functions support a simulated 2704(0.5KB), 2708(1KB), 2716(2KB), 2732(4KB) or 2764(8KB) EPROM + device at the top of the 16-bit address space. The base address of the ROM varies depends on the size. + For example, The 2764 BOOTROM is mapped from $E000 to $FFFF less the I/O range reserved by the MP-B3 motherboard. + The 2716 BOOTROM is mapped from $F800 to $FFFF. + The last byte of the ROM is always stored at $FFFF + + The device type is stored as a binary number in the first three unit flag bits. + + This device uses a statically allocated buffer to hold the EPROM image. All bytes are initialized to $FF. + A call to BOOTROM_attach will load the buffer with the EPROM image. + +*/ + +#include +#include "swtp_defs.h" + +#define UNIT_V_MSIZE (UNIT_V_UF) /* ROM Size */ +#define UNIT_MSIZE (0x7 << UNIT_V_MSIZE) +#define UNIT_NONE (0 << UNIT_V_MSIZE) /* No EPROM */ +#define UNIT_2704 (1 << UNIT_V_MSIZE) /* 2704 mode */ +#define UNIT_2708 (2 << UNIT_V_MSIZE) /* 2708 mode */ +#define UNIT_2716 (3 << UNIT_V_MSIZE) /* 2716 mode */ +#define UNIT_2732 (4 << UNIT_V_MSIZE) /* 2732 mode */ +#define UNIT_2764 (5 << UNIT_V_MSIZE) /* 2764 mode */ + +#define BOOTROM_2K 0x0800 +#define BOOTROM_4K 0x1000 +#define BOOTROM_8K 0x2000 + +// this value is used when referencing BOOTROM memory that is not populated (i.e. not loaded by BOOTROM attach) +#define DEFAULT_NO_ROM_BYTE_VALUE 0xFF + +/* function prototypes */ + +t_stat BOOTROM_attach(UNIT *uptr, CONST char *cptr); +t_stat BOOTROM_config(UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat BOOTROM_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); +t_stat BOOTROM_reset(DEVICE *dptr); + +int32 BOOTROM_get_mbyte(int32 address); + +/* SIMH Standard I/O Data Structures */ + +UNIT BOOTROM_unit = { + UDATA (NULL, UNIT_ATTABLE+UNIT_BINK+UNIT_ROABLE+UNIT_RO, 0), + KBD_POLL_WAIT }; + +MTAB BOOTROM_mod[] = { + { UNIT_MSIZE, UNIT_NONE, "None", "NONE", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_2704, "2704", "2704", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_2708, "2708", "2708", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_2716, "2716", "2716", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_2732, "2732", "2732", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_2764, "2764", "2764", &BOOTROM_config }, + { 0 } +}; + +DEBTAB BOOTROM_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE BOOTROM_dev = { + "BOOTROM", /* name */ + &BOOTROM_unit, /* units */ + NULL, /* registers */ + BOOTROM_mod, /* modifiers */ + 1, /* numunits */ + 16, /* aradix */ + 16, /* awidth */ + 1, /* aincr */ + 16, /* dradix */ + 8, /* dwidth */ + &BOOTROM_examine, /* examine */ + NULL, /* deposit */ + &BOOTROM_reset, /* reset */ + NULL, /* boot */ + &BOOTROM_attach, /* attach */ + NULL, /* detach */ + NULL, /* ctxt */ + DEV_DEBUG, /* flags */ + 0, /* dctrl */ + BOOTROM_debug, /* debflags */ + NULL, /* msize */ + NULL /* lname */ +}; + +/* global variables */ + +/* MP-09 actually has 4 x 2KB EPROM sockets at $E000, $E800, $F000, $F800 */ +/* This will be emulated as a single BOOTROM having a high address of $FFFF and variable start address depending on size */ +/* Available sizes are None=0, 512B=2704, 1KB=2708, 2KB=2716, 4KB=2732, 8KB=2764 */ + +/* Pre-allocate 8KB array of bytes to accomodate largest BOOTROM */ +uint8 BOOTROM_memory[BOOTROM_8K]; + +t_stat BOOTROM_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= BOOTROM_8K) { + return SCPE_NXM; + } + if (eval_array != NULL) { + *eval_array = BOOTROM_get_mbyte(addr); + } + return SCPE_OK; + +} /* BOOTROM_examine() */ + +/* BOOTROM_attach - attach file to EPROM unit */ +t_stat BOOTROM_attach(UNIT *uptr, CONST char *cptr) +{ + t_stat r; + t_addr image_size; + int i,j; + FILE *fp; + uint8 byte_val; + size_t items_read; + + if (BOOTROM_unit.filebuf == NULL) { /* no buffer allocated */ + BOOTROM_unit.filebuf = BOOTROM_memory; + } + if ((BOOTROM_unit.flags & UNIT_MSIZE) == 0) { /* if none selected */ + BOOTROM_unit.capac = 0; /* set EPROM size to 0 */ + return SCPE_OK; + } + + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_attach: cptr=%s\n", cptr); + if ((r = attach_unit(uptr, cptr)) != SCPE_OK) { + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_attach: Error %d\n", r); + return r; + } + + image_size = (t_addr) sim_fsize_ex(uptr->fileref); + if (image_size <= 0) { + sim_printf("BOOTROM_attach: File error\n"); + detach_unit(uptr); + return SCPE_IOERR; + } else { + if (image_size > BOOTROM_8K) { + sim_printf("BOOTROM_attach: Error. File size exceeds ROM capacity\n"); + detach_unit(uptr); + return SCPE_ARG; + } + } + + /* open EPROM file */ + fp = fopen(BOOTROM_unit.filename, "rb"); + if (fp == NULL) { + printf("Bootrom: Unable to open ROM file %s\n",BOOTROM_unit.filename); + printf("Bootrom: No ROM image loaded!!!\n"); + return SCPE_OK; + } + + /* load EPROM file */ + j = 0; + items_read = sim_fread(&byte_val, (size_t)1, (size_t)1, fp); + while (items_read != 0) { + BOOTROM_memory[j++] = byte_val; + items_read = sim_fread(&byte_val, (size_t)1, (size_t)1,fp); + if (j > BOOTROM_unit.capac) { + printf("Bootrom: Image is too large - Load truncated!!!\n"); + j--; + break; + } + } + fclose(fp); + printf("Bootrom: %d bytes of ROM image %s loaded\n", j, BOOTROM_unit.filename); + + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_attach: Done\n"); + return SCPE_OK; + +} /* BOOTROM_attach() */ + +/* BOOTROM_config = None, 2704, 2708, 2716, 2732 or 2764 */ +t_stat BOOTROM_config (UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: val=%d\n", val); + if ((val < UNIT_NONE) || (val > UNIT_2764)) { /* valid param? */ + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: Parameter error\n"); + return SCPE_ARG; + } + if (val == UNIT_NONE) + BOOTROM_unit.capac = 0; /* set EPROM size */ + else + BOOTROM_unit.capac = 0x200 << ((val >> UNIT_V_MSIZE) - 1); /* set EPROM size */ + + if (!BOOTROM_unit.filebuf) { /* point buffer to static array */ + BOOTROM_unit.filebuf = BOOTROM_memory; + } + + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: BOOTROM_unit.capac=%d\n", + BOOTROM_unit.capac); + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: Done\n"); + + return SCPE_OK; +} /* BOOTROM config */ + +/* BOOTROM reset */ +t_stat BOOTROM_reset (DEVICE *dptr) +{ + t_addr i; + + sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_reset: \n"); + + /* allocate filebuf */ + if (BOOTROM_unit.filebuf == NULL) { /* no buffer allocated */ + //BOOTROM_unit.filebuf = calloc(1, BOOTROM_unit.capac); /* allocate EPROM buffer */ + BOOTROM_unit.filebuf = BOOTROM_memory; + if (BOOTROM_unit.filebuf == NULL) { + return SCPE_MEM; + } + } + return SCPE_OK; + +} /* BOOTROM_reset() */ + +/* get a byte from memory - from specified memory address */ +int32 BOOTROM_get_mbyte(int32 address) +{ + int32 val; + uint8 *pa; + + if (BOOTROM_unit.filebuf == NULL) { + sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: EPROM not configured\n"); + return DEFAULT_NO_ROM_BYTE_VALUE; + } + sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: address=%04X\n", address); + if ((t_addr)(0xFFFF - address) > BOOTROM_unit.capac) { + sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: EPROM reference beyond ROM size\n"); + return DEFAULT_NO_ROM_BYTE_VALUE; + } + + pa = BOOTROM_unit.filebuf; + /* the following code is needed to calculate offsets so address $FFFF references the last byte of the ROM */ + val = DEFAULT_NO_ROM_BYTE_VALUE; + switch (BOOTROM_unit.capac) { + /* 2764 - $E000-$FFFF */ + case 0x2000: + val = pa[address - 0xE000]; + break; + /* 2732 - $F000-$FFFF */ + case 0x1000: + if (address >=0xF000) { + val = pa[address - 0xF000]; + } + break; + /* 2716 - $F800-$FFFF */ + case 0x0800: + if (address >= 0xF800) { + val = pa[address - 0xF800]; + } + break; + /* 2708 - $FC00-$FFFF */ + case 0x0400: + if (address >= 0xFC00) { + val = pa[address - 0xFC00]; + } + break; + /* 2704 - $FE00-$FFFF*/ + case 0x0200: + if (address >= 0xFE00) { + val = pa[address - 0xFE00]; + } + break; + default: + break; + } + val &= 0xFF; + sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: Normal val=%02X\n", val); + return val; +} /* BOOTROM_get_mbyte() */ + +/* end of bootrom.c */ +>>>>>>> 033805fd... Richard Lukes - 18 FEB 2024 diff --git a/swtp6809/common/dc-4.c b/swtp6809/common/dc-4.c index f37e530ab..d64b33ec1 100644 --- a/swtp6809/common/dc-4.c +++ b/swtp6809/common/dc-4.c @@ -1,3 +1,4 @@ +<<<<<<< HEAD /* dc4.c: SWTP DC-4 FDC Simulator Copyright (c) 2005-2012, William A. Beech @@ -649,3 +650,656 @@ int32 fdcdata(int32 io, int32 data) } /* end of dc-4.c */ +======= +/* dc4.c: SWTP DC-4 FDC Simulator + + Copyright (c) 2005-2012, William A. 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. + + MODIFICATIONS: + + 23 Apr 15 -- Modified to use simh_debug + 19 Feb 24 -- Richard Lukes - Modified to work with swtp6809 emulator + + NOTES: + + The DC-4 is a 5-inch floppy controller which can control up + to 4 daisy-chained 5-inch floppy drives. The controller is based on + the Western Digital 1797 Floppy Disk Controller (FDC) chip. This + file only emulates the minimum DC-4 functionality to interface with + the virtual disk file. + + The floppy controller is interfaced to the CPU by use of 5 memory + addreses. These are SS-30 slot numbers 5 and 6 (0xE014-0xE01B) on a SWTPC 6809 computer. + + Address Mode Function + ------- ---- -------- + + 0xE014 Read Returns FDC interrupt status + 0xE014 Write Selects the drive/head/motor control + 0xE018 Read Returns status of FDC + 0xE018 Write FDC command register + 0xE019 Read Returns FDC track register + 0xE019 Write Set FDC track register + 0xE01A Read Returns FDC sector register + 0xE01A Write Set FDC sector register + 0xE01B Read Read data + 0xE01B Write Write data + + Drive Select Read (0xE014): + + +---+---+---+---+---+---+---+---+ + | I | D | X | X | X | X | X | X | + +---+---+---+---+---+---+---+---+ + + I = Set indicates an interrupt request from the FDC pending. + D = DRQ pending - same as bit 1 of FDC status register. + + Drive Select Write (0xE014): + + +---+---+---+---+---+---+---+---+ + | M | S | X | X | X | X | Device| + +---+---+---+---+---+---+---+---+ + + M = If this bit is 1, the one-shot is triggered/retriggered to + start/keep the motors on. + S = Side select. If set, side one is selected otherwise side zero + is selected. + X = not used + Device = value 0 thru 3, selects drive 0-3 to be controlled. + + Drive Status Read (0xE018): + + +---+---+---+---+---+---+---+---+ + | R | P | H | S | C | L | D | B | + +---+---+---+---+---+---+---+---+ + + B - When 1, the controller is busy. + D - When 1, index mark detected (type I) or data request - read data + ready/write data empty (type II or III). + H - When 1, track 0 (type I) or lost data (type II or III). + C - When 1, crc error detected. + S - When 1, seek (type I) or RNF (type II or III) error. + H - When 1, head is currently loaded (type I) or record type/ + write fault (type II or III). + P - When 1, indicates that diskette is write-protected. + R - When 1, drive is not ready. + + Drive Control Write (0xE018) for type I commands: + + +---+---+---+---+---+---+---+---+ + | 0 | S2| S1| S0| H | V | R1| R0| + +---+---+---+---+---+---+---+---+ + + R0/R1 - Selects the step rate. + V - When 1, verify on destination track. + H - When 1, loads head to drive surface. + S0/S1/S2 = 000 - home. + 001 - seek track in data register. + 010 - step without updating track register. + 011 - step and update track register. + 100 - step in without updating track register. + 101 - step in and update track register. + 110 - step out without updating track register. + 111 - step out and update track register. + + Drive Control Write (0xE018) for type II commands: + + +---+---+---+---+---+---+---+---+ + | 1 | 0 | T | M | S | E | B | A | + +---+---+---+---+---+---+---+---+ + + A - Zero for read, 1 on write deleted data mark else data mark. + B - When 1, shifts sector length field definitions one place. + E - When, delay operation 15 ms, 0 no delay. + S - When 1, select side 1, 0 select side 0. + M - When 1, multiple records, 0 for single record. + T - When 1, write command, 0 for read. + + Drive Control Write (0xE018) for type III commands: + + +---+---+---+---+---+---+---+---+ + | 1 | 1 | T0| T1| 0 | E | 0 | 0 | + +---+---+---+---+---+---+---+---+ + + E - When, delay operation 15 ms, 0 no delay. + T0/T1 - 00 - read address command. + 10 - read track command. + 11 - write track command. + + Tracks are numbered from 0 up to one minus the last track in the 1797! + + Track Register Read (0xE019): + + +---+---+---+---+---+---+---+---+ + | Track Number | + +---+---+---+---+---+---+---+---+ + + Reads the current 8-bit value from the track position. + + Track Register Write (0xE019): + + +---+---+---+---+---+---+---+---+ + | Track Number | + +---+---+---+---+---+---+---+---+ + + Writes the 8-bit value to the track register. + + Sectors are numbers from 1 up to the last sector in the 1797! + + Sector Register Read (0xE01A): + + +---+---+---+---+---+---+---+---+ + | Sector Number | + +---+---+---+---+---+---+---+---+ + + Reads the current 8-bit value from the sector position. + + Sector Register Write (0xE01A): + + +---+---+---+---+---+---+---+---+ + | Sector Number | + +---+---+---+---+---+---+---+---+ + + Writes the 8-bit value to the sector register. + + Data Register Read (0xE01B): + + +---+---+---+---+---+---+---+---+ + | Data | + +---+---+---+---+---+---+---+---+ + + Reads the current 8-bit value from the data register. + + Data Register Write (0xE01B): + + +---+---+---+---+---+---+---+---+ + | Data | + +---+---+---+---+---+---+---+---+ + + Writes the 8-bit value to the data register. + + A FLEX disk is defined as follows: + + Track Sector Use + 0 1 Boot sector + 0 2 Boot sector (cont) + 0 3 Unused (doesn't exist) + 0 4 System Identity Record (explained below) + 0 5 Unused + 0 6-last Directory - 10 entries/sector (explained below) + 1 1 First available data sector + last-1 last Last available data sector + + System Identity Record + + Byte Use + 0x00 Two bytes of zeroes (Clears forward link) + 0x10 Volume name in ASCII(11 bytes) + 0x1B Volume number in binary (2 bytes) + 0x1D Address of first free data sector (Track-Sector) (2 bytes) + 0x1F Address of last free data sector (Track-Sector) (2 bytes) + 0x21 Total number of data sectors in binary (2 bytes) + 0x23 Current date (Month-Day-Year) in binary + 0x26 Highest track number on disk in binary (byte) + 0x27 Highest sector number on a track in binary (byte) + + The following unit registers are used by this controller emulation: + + dsk_unit[cur_drv].u3 unit current flags + dsk_unit[cur_drv].u4 unit current track + dsk_unit[cur_drv].u5 unit current sector + dsk_unit[cur_drv].pos unit current sector byte index into buffer + dsk_unit[cur_drv].filebuf unit current sector buffer + dsk_unit[cur_drv].fileref unit current attached file reference +*/ + +#include +#include "swtp_defs.h" + +#define DEBUG 0 + +#define UNIT_V_ENABLE (UNIT_V_UF + 0) /* Write Enable */ +#define UNIT_ENABLE (1 << UNIT_V_ENABLE) + +/* maximum of 4 disks, sector size is fixed at 256 bytes */ + +#define NUM_DISK 4 /* standard 1797 maximum */ +#define SECT_SIZE 256 /* standard FLEX sector */ + +/* SIR offsets */ +#define MAXCYL 0x26 /* last cylinder # */ +#define MAXSEC 0x27 /* last sector # */ + +/* 1797 status bits */ + +#define BUSY 0x01 +#define DRQ 0x02 +#define WRPROT 0x40 +#define NOTRDY 0x80 + +/* function prototypes */ + +t_stat dsk_reset (DEVICE *dptr); + +/* SS-50 I/O address space functions */ + +int32 fdcdrv(int32 io, int32 data); +int32 fdccmd(int32 io, int32 data); +int32 fdctrk(int32 io, int32 data); +int32 fdcsec(int32 io, int32 data); +int32 fdcdata(int32 io, int32 data); + +/* Local Variables */ + +int32 fdcbyte; +int32 intrq = 0; /* interrupt request flag */ +int32 cur_dsk; /* Currently selected drive */ +int32 wrt_flag = 0; /* FDC write flag */ + +int32 spt; /* sectors/track */ +int32 trksiz; /* trk size (bytes) */ +int32 heds; /* number of heads */ +int32 cpd; /* cylinders/disk */ +int32 dsksiz; /* dsk size (bytes) */ + +/* Floppy Disk Controller data structures + + dsk_dev Mother Board device descriptor + dsk_unit Mother Board unit descriptor + dsk_reg Mother Board register list + dsk_mod Mother Board modifiers list +*/ + +UNIT dsk_unit[] = { + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) } +}; + +REG dsk_reg[] = { + { HRDATA (DISK, cur_dsk, 4) }, + { NULL } +}; + +MTAB dsk_mod[] = { + { UNIT_ENABLE, UNIT_ENABLE, "RW", "RW", NULL }, + { UNIT_ENABLE, 0, "RO", "RO", NULL }, + { 0 } +}; + +DEBTAB dsk_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE dsk_dev = { + "DC-4", //name + dsk_unit, //units + dsk_reg, //registers + dsk_mod, //modifiers + NUM_DISK, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + &dsk_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + dsk_debug, /* debflags */ + NULL, //msize + NULL //lname +}; + +/* Reset routine */ + +t_stat dsk_reset (DEVICE *dptr) +{ + int i; + + cur_dsk = 5; /* force initial SIR read, use a drive # that can't be selected */ + + for (i=0; i>>>>>> 033805fd... Richard Lukes - 18 FEB 2024 diff --git a/swtp6809/common/m6809.c b/swtp6809/common/m6809.c index d92e500d6..f3f11322a 100644 --- a/swtp6809/common/m6809.c +++ b/swtp6809/common/m6809.c @@ -1,3 +1,4 @@ +<<<<<<< HEAD /* 6809.c: SWTP 6809 CPU simulator Copyright (c) 2005-2012, William Beech @@ -3411,3 +3412,3396 @@ t_stat parse_sym (CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 } /* end of m6809.c */ +======= +/* 6809.c: SWTP 6809 CPU simulator + + Copyright (c) 2005-2012, William Beech + + Permission is hereby granted, free of charge, to any person obtaining a + /opy 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. + + MODIFICATIONS: + + 23 Apr 15 -- Modified to use simh_debug + 21 Apr 20 -- Richard Brinegar numerous fixes for flag errors + 20 Feb 24 -- Richard Lukes - modified for 6809 + + NOTES: + cpu Motorola M6809 CPU + + The register state for the M6809 CPU is: + + A<0:7> Accumulator A + B<0:7> Accumulator B + IX<0:15> Index Register + IY<0:15> Index Register + CCR<0:7> Condition Code Register + EF Entire flag + FF FIRQ flag + HF half-carry flag + IF IRQ flag + NF negative flag + ZF zero flag + VF overflow flag + CF carry flag + PC<0:15> program counter + UP<0:15> User Stack Pointer + SP<0:15> Stack Pointer + + The M6809 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 M6809. + It is called from the CPU board simulator 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 6809, reads to non-existent memory + return 0FFH, and writes are ignored. +*/ + +#include + +#include "swtp_defs.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) + +/* Flag values to set proper positions in CCR */ +#define EF 0x80 +#define FF 0x40 +#define HF 0x20 +#define IF 0x10 +#define NF 0x08 +#define ZF 0x04 +#define VF 0x02 +#define CF 0x01 + +/* PSH/PUL Post Byte register positions */ +#define PSH_PUL_Post_Byte_PC 0x80 +#define PSH_PUL_Post_Byte_S_U 0x40 +#define PSH_PUL_Post_Byte_Y 0x20 +#define PSH_PUL_Post_Byte_X 0x10 +#define PSH_PUL_Post_Byte_DP 0x08 +#define PSH_PUL_Post_Byte_B 0x04 +#define PSH_PUL_Post_Byte_A 0x02 +#define PSH_PUL_Post_Byte_CC 0x01 + +#define TFR_EXG_Post_Nybble_D 0 +#define TFR_EXG_Post_Nybble_X 1 +#define TFR_EXG_Post_Nybble_Y 2 +#define TFR_EXG_Post_Nybble_U 3 +#define TFR_EXG_Post_Nybble_S 4 +#define TFR_EXG_Post_Nybble_PC 5 +#define TFR_EXG_Post_Nybble_A 8 +#define TFR_EXG_Post_Nybble_B 9 +#define TFR_EXG_Post_Nybble_CC 10 +#define TFR_EXG_Post_Nybble_DP 11 + + +/* Macros to handle the flags in the CCR */ +#define CCR_MSK (EF|FF|HF|IF|NF|ZF|VF|CF) +#define TOGGLE_FLAG(FLAG) (CCR ^= (FLAG)) +#define SET_FLAG(FLAG) (CCR |= (FLAG)) +#define CLR_FLAG(FLAG) (CCR &= ~(FLAG)) +#define GET_FLAG(FLAG) (CCR & (FLAG)) + +#define COND_SET_FLAG(COND,FLAG) \ + if (COND) SET_FLAG(FLAG); else CLR_FLAG(FLAG) + +#define COND_SET_FLAG_N(VAR) \ + if ((VAR) & 0x80) SET_FLAG(NF); else CLR_FLAG(NF) +#define COND_SET_FLAG_N_16(VAR) \ + if ((VAR) & 0x8000) SET_FLAG(NF); else CLR_FLAG(NF) + +#define COND_SET_FLAG_Z(VAR) \ + if ((VAR) == 0) SET_FLAG(ZF); else CLR_FLAG(ZF) +#define COND_SET_FLAG_Z_16(VAR) \ + if ((VAR) == 0) SET_FLAG(ZF); else CLR_FLAG(ZF) + +#define COND_SET_FLAG_H(VAR) \ + if ((VAR) & 0x10) SET_FLAG(HF); else CLR_FLAG(HF) + +#define COND_SET_FLAG_C(VAR) \ + if ((VAR) & 0x100) SET_FLAG(CF); else CLR_FLAG(CF) +#define COND_SET_FLAG_C_16(VAR) \ + if ((VAR) & 0x10000) SET_FLAG(CF); else CLR_FLAG(CF) + +#define COND_SET_FLAG_V(COND) \ + if (COND) SET_FLAG(VF); else CLR_FLAG(VF) + +/* local global variables */ + +int32 A = 0; /* Accumulator A */ +int32 B = 0; /* Accumulator B */ +int32 D = 0; /* Accumulator D */ +int32 DP = 0; /* Direct Page Register */ +int32 IX = 0; /* Index register X */ +int32 IY = 0; /* Index register Y */ +int32 UP = 0; /* User Stack pointer */ +int32 SP = 0; /* Hardware Stack pointer */ +int32 CCR = EF|FF|IF; /* Condition Code Register */ +int32 saved_PC = 0; /* Saved Program counter */ +int32 previous_PC = 0; /* Previous previous Program counter */ +int32 last_PC = 0; /* Last Program counter */ +int32 PC; /* Program counter */ +int32 INTE = 0; /* Interrupt Enable */ +int32 int_req = 0; /* Interrupt request */ + +int32 mem_fault = 0; /* memory fault flag */ + +/* function prototypes */ + +t_stat m6809_reset(DEVICE *dptr); +t_stat m6809_boot(int32 unit_num, DEVICE *dptr); +t_stat m6809_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); +t_stat m6809_deposit(t_value value, t_addr addr, UNIT *uptr, int32 switches); + +void dump_regs(void); +void dump_regs1(void); +int32 fetch_byte(int32 flag); +int32 fetch_word(); +uint8 pop_sp_byte(void); +uint8 pop_up_byte(void); +uint16 pop_sp_word(void); +uint16 pop_up_word(void); +void push_sp_byte(uint8 val); +void push_up_byte(uint8 val); +void push_sp_word(uint16 val); +void push_up_word(uint16 val); +void go_rel(int32 cond); +void go_long_rel(int32 cond); +int32 get_rel_addr(void); +int32 get_long_rel_addr(void); +int32 get_dir_byte_val(void); +int32 get_dir_word_val(void); +int32 get_imm_byte_val(void); +int32 get_imm_word_val(void); +int32 get_dir_addr(void); +int32 get_indexed_byte_val(void); +int32 get_indexed_word_val(void); +int32 get_indexed_addr(void); +int32 get_ext_addr(void); +int32 get_ext_byte_val(void); +int32 get_ext_word_val(void); +int32 get_flag(int32 flag); +void condevalVa(int32 op1, int32 op2); +void condevalVa16(int32 op1, int32 op2); +void condevalVs(int32 op1, int32 op2); +void condevalVs16(int32 op1, int32 op2); +void condevalHa(int32 op1, int32 op2); + +/* external routines */ + +extern void CPU_BD_put_mbyte(int32 addr, int32 val); +extern void CPU_BD_put_mword(int32 addr, int32 val); +extern int32 CPU_BD_get_mbyte(int32 addr); +extern int32 CPU_BD_get_mword(int32 addr); + +/* CPU data structures + + m6809_dev CPU device descriptor + m6809_unit CPU unit descriptor + m6809_reg CPU register list + m6809_mod CPU modifiers list */ + +UNIT m6809_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, 65536) }; + +REG m6809_reg[] = { + { HRDATA (PC, saved_PC, 16) }, + { HRDATA (A, A, 8) }, + { HRDATA (B, B, 8) }, + { HRDATA (DP, DP, 8) }, + { HRDATA (IX, IX, 16) }, + { HRDATA (IY, IY, 16) }, + { HRDATA (SP, SP, 16) }, + { HRDATA (UP, UP, 16) }, + { HRDATA (CCR, CCR, 8) }, + { FLDATA (INTE, INTE, 16) }, + { ORDATA (WRU, sim_int_char, 8) }, + { NULL } }; + +MTAB m6809_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 }, + { 0 } }; + +DEBTAB m6809_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { "REG", DEBUG_reg }, + { "ASM", DEBUG_asm }, + { NULL } +}; + +DEVICE m6809_dev = { + "CPU", //name + &m6809_unit, //units + m6809_reg, //registers + m6809_mod, //modifiers + 1, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + &m6809_examine, //examine + &m6809_deposit, //deposit + &m6809_reset, //reset + &m6809_boot, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + m6809_debug, //debflags + NULL, //msize + NULL //lname +}; + +static const char *opcode[] = { +"NEG", "???", "???", "COM", //0x00 +"LSR", "???", "ROR", "ASR", +"ASL", "ROL", "DEC", "???", +"INC", "TST", "JMP", "CLR", +"PG2", "PG3", "NOP", "SYNC", //0x10 +"???", "???", "LBRA", "LBSR", +"???", "DAA", "ORCC", "???", +"ANDCC", "SEX", "EXG", "TFR", +"BRA", "BRN", "BHI", "BLS", //0x20 +"BCC", "BLO", "BNE", "BEQ", +"BVC", "BVS", "BPL", "BMI", +"BGE", "BLT", "BGT", "BLE", +"LEAX", "LEAY", "LEAS", "LEAU", //0x30 +"PSHS", "PULS", "PSHU", "PULU", +"???", "RTS", "ABX", "RTI", +"CWAI", "MUL", "???", "SWI", +"NEGA", "???", "???", "COMA", //0x40 +"LSRA", "???", "RORA", "ASRA", +"LSLA", "ROLA", "DECA", "???", +"INCA", "TSTA", "???", "CLRA", +"NEGB", "???", "???", "COMB", //0x50 +"LSRB", "???", "RORB", "ASRB", +"LSLB", "ROLB", "DECB", "???", +"INCB", "TSTB", "???", "CLRB", +"NEG", "???", "???", "COM", //0x60 +"LSR", "???", "ROR", "ASR", +"ASL", "ROL", "DEC", "???", +"INC", "TST", "JMP", "CLR", +"NEG", "???", "???", "COM", //0x70 +"LSR", "???", "ROR", "ASR", +"ASL", "ROL", "DEC", "???", +"INC", "TST", "JMP", "CLR", +"SUBA", "CMPA", "SBCA", "SUBD", //0x80 +"ANDA", "BITA", "LDA", "???", +"EORA", "ADCA", "ORAA", "ADDA", +"CMPX", "BSR", "LDX", "???", +"SUBA", "CMPA", "SBCA", "SUBD", //0x90 +"ANDA", "BITA", "LDA", "STA", +"EORA", "ADCA", "ORA", "ADDA", +"CMPX", "JSR", "LDX", "STX", +"SUBA", "CMPA", "SBCA", "SUBD", //0xA0 +"ANDA", "BITA", "LDA", "STA", +"EORA", "ADCA", "ORA", "ADDA", +"CMPX", "JSR", "LDX", "STX", +"SUBA", "CMPA", "SBCA", "SUBD", //0xB0 +"ANDA", "BITA", "LDA", "STA", +"EORA", "ADCA", "ORA", "ADDA", +"CMPX", "JSR", "LDX", "STX", +"SUBB", "CMPB", "SBCB", "ADDD", //0xC0 +"ANDB", "BITB", "LDB", "???", +"EORB", "ADCB", "ORB", "ADDB", +"LDD", "???", "LDU", "???", +"SUBB", "CMPB", "SBCB", "ADDD", //0xD0 +"ANDB", "BITB", "LDB", "STB", +"EORB", "ADCB", "ORB", "ADDB", +"LDD", "STD", "LDU", "STU", +"SUBB", "CMPB", "SBCB", "ADDD", //0xE0 +"ANDB", "BITB", "LDB", "STB", +"EORB", "ADCB", "ORB", "ADDB", +"LDD", "STD", "LDU", "STU", +"SUBB", "CMPB", "SBCB", "ADDD", //0xF0 +"ANDB", "BITB", "LDB", "STB", +"EORB", "ADCB", "ORB", "ADDB", +"LDD", "STD", "LDU", "STU" +}; + +static const char *opcode6800[] = { +"???", "NOP", "???", "???", //0x00 +"???", "???", "TAP", "TPA", +"INX", "DEX", "CLV", "SEV", +"CLC", "SEC", "CLI", "SEI", +"SBA", "CBA", "???", "???", //0x10 +"???", "???", "TAB", "TBA", +"???", "DAA", "???", "ABA", +"???", "???", "???", "???", +"BRA", "???", "BHI", "BLS", //0x20 +"BCC", "BCS", "BNE", "BEQ", +"BVC", "BVS", "BPL", "BMI", +"BGE", "BLT", "BGT", "BLE", +"TSX", "INS", "PULA", "PULB", //0x30 +"DES", "TXS", "PSHA", "PSHB", +"???", "RTS", "???", "RTI", +"???", "???", "WAI", "SWI", +"NEGA", "???", "???", "COMA", //0x40 +"LSRA", "???", "RORA", "ASRA", +"ASLA", "ROLA", "DECA", "???", +"INCA", "TSTA", "???", "CLRA", +"NEGB", "???", "???", "COMB", //0x50 +"LSRB", "???", "RORB", "ASRB", +"ASLB", "ROLB", "DECB", "???", +"INCB", "TSTB", "???", "CLRB", +"NEG", "???", "???", "COM", //0x60 +"LSR", "???", "ROR", "ASR", +"ASL", "ROL", "DEC", "???", +"INC", "TST", "JMP", "CLR", +"NEG", "???", "???", "COM", //0x70 +"LSR", "???", "ROR", "ASR", +"ASL", "ROL", "DEC", "???", +"INC", "TST", "JMP", "CLR", +"SUBA", "CMPA", "SBCA", "???", //0x80 +"ANDA", "BITA", "LDAA", "???", +"EORA", "ADCA", "ORAA", "ADDA", +"CMPX", "BSR", "LDS", "???", +"SUBA", "CMPA", "SBCA", "???", //0x90 +"ANDA", "BITA", "LDAA", "STAA", +"EORA", "ADCA", "ORAA", "ADDA", +"CMPX", "???", "LDS", "STS", +"SUBA", "CMPA", "SBCA", "???", //0xA0 +"ANDA", "BITA", "LDAA", "STAA", +"EORA", "ADCA", "ORAA", "ADDA", +"CMPX X", "JSR X", "LDS X", "STS X", +"SUBA", "CMPA", "SBCA", "???", //0xB0 +"ANDA", "BITA", "LDAA", "STAA", +"EORA", "ADCA", "ORAA", "ADDA", +"CPX", "JSR", "LDS", "STS", +"SUBB", "CMPB", "SBCB", "???", //0xC0 +"ANDB", "BITB", "LDAB", "???", +"EORB", "ADCB", "ORAB", "ADDB", +"???", "???", "LDX", "???", +"SUBB", "CMPB", "SBCB", "???", //0xD0 +"ANDB", "BITB", "LDAB", "STAB", +"EORB", "ADCB", "ORAB", "ADDB", +"???", "???", "LDX", "STX", +"SUBB", "CMPB", "SBCB", "???", //0xE0 +"ANDB", "BITB", "LDAB", "STAB", +"EORB", "ADCB", "ORAB", "ADDB", +"???", "???", "LDX", "STX", +"SUBB", "CMPB", "SBCB", "???", //0xF0 +"ANDB", "BITB", "LDAB", "STAB", +"EORB", "ADCB", "ORAB", "ADDB", +"???", "???", "LDX", "STX" +}; + +int32 oplen[256] = { +0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1, //0x00 +1,1,0,0,0,0,1,1,0,1,0,1,0,0,0,0, +2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +1,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1, +1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, //0x40 +1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, +2,0,0,2,2,0,2,2,2,2,2,0,2,2,2,2, +3,0,0,3,3,0,3,3,3,3,3,0,3,3,3,3, +2,2,2,0,2,2,2,0,2,2,2,2,3,2,3,0, //0x80 +2,2,2,0,2,2,2,2,2,2,2,2,2,0,2,2, +2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2, +3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3, +2,2,2,0,2,2,2,0,2,2,2,2,0,0,3,0, //0xC0 +2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, +2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, +3,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3 +}; + +int32 oplen6800[256] = { +0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1, //0x00 +1,1,0,0,0,0,1,1,0,1,0,1,0,0,0,0, +2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +1,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1, +1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, //0x40 +1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, +2,0,0,2,2,0,2,2,2,2,2,0,2,2,2,2, +3,0,0,3,3,0,3,3,3,3,3,0,3,3,3,3, +2,2,2,0,2,2,2,0,2,2,2,2,3,2,3,0, //0x80 +2,2,2,0,2,2,2,2,2,2,2,2,2,0,2,2, +2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2, +3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3, +2,2,2,0,2,2,2,0,2,2,2,2,0,0,3,0, //0xC0 +2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, +2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, +3,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3 +}; + +t_stat sim_instr (void) +{ + int32 reason; + int32 IR; + int32 OP; + int32 OP2; /* Used for 2-byte opcodes */ + + int32 hi; /* hi bit/nybble/byte */ + int32 lo; /* lo bit/nybble/byte */ + int32 op1; /* operand #1 */ + int32 op2; /* operand #2 - used for CC evaluation */ + int32 result; /* temporary value */ + int32 addr; /* temporary address value */ + + /* used for 6809 instruction decoding - TFT, EXG, PSH, PUL*/ + int32 Post_Byte = 0; + int32 Src_Nybble = 0; + int32 Dest_Nybble = 0; + int32 Src_Value = 0; + int32 Dest_Value = 0; + + PC = saved_PC & ADDRMASK; /* load local PC */ + reason = 0; + + /* Main instruction fetch/decode loop */ + + while (reason == 0) { /* loop until halted */ +// dump_regs1(); + 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? */ + /* 6809 interrupts not implemented yet. None were used, + on a standard SWTP 6809. All I/O is programmed. */ + reason = STOP_HALT; /* stop simulation */ + break; + + } /* end interrupt */ + if (sim_brk_summ && + sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; + } + + sim_interval--; + last_PC = previous_PC; + previous_PC = PC; + IR = OP = fetch_byte(0); /* fetch instruction */ + + /* The Big Instruction Decode Switch */ + + switch (IR) { + +/* 0x00 - direct mode */ + case 0x00: /* NEG dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 != 0, CF); + COND_SET_FLAG(op1 == 0x80, VF); + result = 0 - op1; + result &= 0xFF; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0x03: /* COM dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = ~op1; + result &= 0xFF; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + CLR_FLAG(VF); + SET_FLAG(CF); + break; + case 0x04: /* LSR dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 & 0x01, CF); + result = op1 >> 1; + CPU_BD_put_mbyte(addr, result); + CLR_FLAG(NF); + COND_SET_FLAG_Z(result); + /* H,V not affected */ + break; + case 0x06: /* ROR dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = op1 >> 1; + if (get_flag(CF)) { + result |= 0x80; + } + CPU_BD_put_mbyte(addr, result); + /* H,V unaffected */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(op1 & 0x01, CF); + break; + case 0x07: /* ASR dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 >> 1) | (op1 & 0x80); + CPU_BD_put_mbyte(addr, result); + /* H undefined */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + /* V not affected */ + COND_SET_FLAG(op1 & 0x01, CF); + break; + case 0x08: /* ASL dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 & 0x80, CF); + result = (op1 << 1) & 0xFF; + CPU_BD_put_mbyte(addr, result); + /* H is undefined */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x09: /* ROL dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 << 1) & 0xFF; + if (get_flag(CF)) { + result |= 0x01; + } + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG((op1 & 0x80) ^ (op1 & 0x40), VF); + COND_SET_FLAG(op1 & 0x80, CF); + break; + case 0x0A: /* DEC dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1-1) & 0xFF; + CPU_BD_put_mbyte(addr, result); + /* H not affected */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(op1 == 0x80, VF); + /* C not affected */ + break; + case 0x0C: /* INC dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 == 0x7F, VF); + op1 = (op1 + 1) & 0xFF; + CPU_BD_put_mbyte(addr, op1); + COND_SET_FLAG_N(op1); + COND_SET_FLAG_Z(op1); + break; + case 0x0D: /* TST dir */ + result = get_dir_byte_val(); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + CLR_FLAG(VF); + break; + case 0x0E: /* JMP dir */ + PC = get_dir_addr(); + break; + case 0x0F: /* CLR dir */ + CPU_BD_put_mbyte(get_dir_addr(), 0); + /* H not affected */ + CLR_FLAG(NF); + SET_FLAG(ZF); + CLR_FLAG(VF); + CLR_FLAG(CF); + break; + +/* 0x10 */ + case 0x10: /* 2-byte opcodes */ + /* fetch second byte of opcode */ + OP2 = fetch_byte(0); + switch (OP2) { + case 0x21: /* LBRN rel */ + /* Branch Never - essentially a NOP */ + go_long_rel(0); + break; + case 0x22: /* LBHI rel */ + go_long_rel(!(get_flag(CF) | get_flag(ZF))); + break; + case 0x23: /* LBLS rel */ + go_long_rel(get_flag(CF) | get_flag(ZF)); + break; + case 0x24: /* LBCC rel */ + go_long_rel(!get_flag(CF)); + break; + case 0x25: /* LBCS rel */ + go_long_rel(get_flag(CF)); + break; + case 0x26: /* LBNE rel */ + go_long_rel(!get_flag(ZF)); + break; + case 0x27: /* LBEQ rel */ + go_long_rel(get_flag(ZF)); + break; + case 0x28: /* LBVC rel */ + go_long_rel(!get_flag(VF)); + break; + case 0x29: /* LBVS rel */ + go_long_rel(get_flag(VF)); + break; + case 0x2A: /* LBPL rel */ + go_long_rel(!get_flag(NF)); + break; + case 0x2B: /* LBMI rel */ + go_long_rel(get_flag(NF)); + break; + case 0x2C: /* LBGE rel */ + go_long_rel( !( get_flag(NF) ^ get_flag(VF) ) ); + break; + case 0x2D: /* LBLT rel */ + go_long_rel( get_flag(NF) ^ get_flag(VF) ); + break; + case 0x2E: /* LBGT rel */ + go_long_rel(!( get_flag(ZF) | (get_flag(NF) ^ get_flag(VF)))); + break; + case 0x2F: /* LBLE rel */ + go_long_rel(get_flag(ZF) | (get_flag(NF) ^ get_flag(VF))); + break; + case 0x3F: /* SWI2 */ + SET_FLAG(EF); + push_sp_word(PC); + push_sp_word(UP); + push_sp_word(IY); + push_sp_word(IX); + push_sp_byte(DP); + push_sp_byte(B); + push_sp_byte(A); + push_sp_byte(CCR); + PC = CPU_BD_get_mword(0xFFF4) & ADDRMASK; + break; + case 0x83: /* CMPD imm */ + D = (A << 8) | (B & 0xFF); + op2 = get_imm_word_val(); + result = D - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x8C: /* CMPY imm */ + op2 = get_imm_word_val(); + result = IY - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IY, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x8E: /* LDY imm */ + IY = get_imm_word_val(); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0x93: /* CMPD dir */ + D = (A << 8) | (B & 0xFF); + op2 = get_dir_word_val(); + result = D - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x9C: /* CMPY dir */ + op2 = get_dir_word_val(); + result = IY - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IY, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x9E: /* LDY dir */ + IY = get_dir_word_val(); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0x9F: /* STY dir */ + CPU_BD_put_mword(get_dir_addr(), IY); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0xA3: /* CMPD ind */ + D = (A << 8) | (B & 0xFF); + op2 = get_indexed_word_val(); + result = D - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xAC: /* CMPY ind */ + op2 = get_indexed_word_val(); + result = IY - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IY, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xAE: /* LDY ind */ + IY = get_indexed_word_val(); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0xAF: /* STY ind */ + CPU_BD_put_mword(get_indexed_addr(), IY); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0xB3: /* CMPD ext */ + D = (A << 8) | (B & 0xFF); + op2 = get_ext_word_val(); + result = D - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xBC: /* CMPY ext */ + op2 = get_ext_word_val(); + result = IY - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IY, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xBE: /* LDY ext */ + IY = get_ext_word_val(); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0xBF: /* STY ext */ + CPU_BD_put_mword(get_ext_addr(), IY); + COND_SET_FLAG_N_16(IY); + COND_SET_FLAG_Z_16(IY); + CLR_FLAG(VF); + break; + case 0xCE: /* LDS imm */ + SP = get_imm_word_val(); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + case 0xDE: /* LDS dir */ + SP = get_dir_word_val(); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + case 0xDF: /* STS dir */ + CPU_BD_put_mword(get_dir_addr(), SP); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + case 0xEE: /* LDS ind */ + SP = get_indexed_word_val(); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + case 0xEF: /* STS ind */ + CPU_BD_put_mword(get_indexed_addr(), SP); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + case 0xFE: /* LDS ext */ + SP = get_ext_word_val(); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + case 0xFF: /* STS ext */ + CPU_BD_put_mword(get_ext_addr(), SP); + COND_SET_FLAG_N_16(SP); + COND_SET_FLAG_Z_16(SP); + CLR_FLAG(VF); + break; + } + break; + +/* Ox11 */ + case 0x11: /* 2-byte opcodes */ + /* fetch second byte of opcode */ + OP2 = fetch_byte(0); + switch (OP2) { + case 0x3F: /* SWI3 */ + SET_FLAG(EF); + push_sp_word(PC); + push_sp_word(UP); + push_sp_word(IY); + push_sp_word(IX); + push_sp_byte(DP); + push_sp_byte(B); + push_sp_byte(A); + push_sp_byte(CCR); + PC = CPU_BD_get_mword(0xFFF2) & ADDRMASK; + break; + case 0x83: /* CMPU imm */ + op2 = get_imm_word_val(); + result = UP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(UP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x8C: /* CMPS imm */ + op2 = get_imm_word_val(); + result = SP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(SP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x93: /* CMPU dir */ + op2 = get_dir_word_val(); + result = UP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(UP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0x9C: /* CMPS dir */ + op2 = get_dir_word_val(); + result = SP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(SP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xA3: /* CMPU ind */ + op2 = get_indexed_word_val(); + result = UP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(UP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xAC: /* CMPS ind */ + op2 = get_indexed_word_val(); + result = SP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(SP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xB3: /* CMPU ext */ + op2 = get_ext_word_val(); + result = UP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(UP, op2); + COND_SET_FLAG_C_16(result); + break; + case 0xBC: /* CMPS ext */ + op2 = get_ext_word_val(); + result = SP - op2; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(SP, op2); + COND_SET_FLAG_C_16(result); + break; + } + break; + case 0x12: /* NOP */ + break; + case 0x13: /* SYNC inherent*/ + /* Interrupts are not implemented */ + reason = STOP_HALT; /* stop simulation */ + break; + case 0x16: /* LBRA relative */ + go_long_rel(1); + break; + case 0x17: /* LBSR relative */ + addr = get_long_rel_addr(); + push_sp_word(PC); + PC = (PC + addr) & ADDRMASK; + break; + case 0x19: /* DAA inherent */ + lo = A & 0x0F; + if ((lo > 9) || get_flag(HF)) { + lo += 6; + A = (A & 0xF0) + lo; + COND_SET_FLAG(lo & 0x10, HF); + } + hi = (A >> 4) & 0x0F; + if ((hi > 9) || get_flag(CF)) { + hi += 6; + A = (A & 0x0F) | (hi << 4) | 0x100; + } + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + + case 0x1A: /* ORCC imm */ + CCR = CCR | get_imm_byte_val(); + break; + case 0x1C: /* ANDCC imm */ + CCR = CCR & get_imm_byte_val(); + break; + case 0x1D: /* SEX inherent */ + if (B & 0x80) { + A = 0xFF; + } else { + A = 0; + } + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0x1E: /* EXG imm */ + Post_Byte = get_imm_byte_val(); + Src_Nybble = (Post_Byte >> 4) & 0x0F; + Dest_Nybble = Post_Byte & 0x0F; + if ((Src_Nybble <= 5 && Dest_Nybble > 5) || (Src_Nybble > 5 && Dest_Nybble <= 5)) { + // EXG with unaligned register sizes + reason = STOP_OPCODE; + } + + /* read register values */ + if (Src_Nybble <= 5 && Dest_Nybble <= 5) { + /* 16-bit register */ + /* read source register */ + switch (Src_Nybble) { + case TFR_EXG_Post_Nybble_D: Src_Value = (A << 8) | (B & 0xFF); break; + case TFR_EXG_Post_Nybble_X: Src_Value = IX; break; + case TFR_EXG_Post_Nybble_Y: Src_Value = IY; break; + case TFR_EXG_Post_Nybble_U: Src_Value = UP; break; + case TFR_EXG_Post_Nybble_S: Src_Value = SP; break; + case TFR_EXG_Post_Nybble_PC: Src_Value = PC; break; + default: break; + } + /* read destination register */ + switch (Dest_Nybble) { + case TFR_EXG_Post_Nybble_D: Dest_Value = (A << 8) | (B & 0xFF); break; + case TFR_EXG_Post_Nybble_X: Dest_Value = IX; break; + case TFR_EXG_Post_Nybble_Y: Dest_Value = IY; break; + case TFR_EXG_Post_Nybble_U: Dest_Value = UP; break; + case TFR_EXG_Post_Nybble_S: Dest_Value = SP; break; + case TFR_EXG_Post_Nybble_PC: Dest_Value = PC; break; + default: break; + } + } + if ((Src_Nybble >= 8 && Src_Nybble <= 11) && (Dest_Nybble >= 8 && Dest_Nybble <= 11)) { + /* 8-bit register read */ + /* read source register */ + switch (Src_Nybble) { + case TFR_EXG_Post_Nybble_A: Src_Value = A; break; + case TFR_EXG_Post_Nybble_B: Src_Value = B; break; + case TFR_EXG_Post_Nybble_CC: Src_Value = CCR; break; + case TFR_EXG_Post_Nybble_DP: Src_Value = DP; break; + default: break; + } + /* read destination register */ + switch (Dest_Nybble) { + case TFR_EXG_Post_Nybble_A: Dest_Value = A; break; + case TFR_EXG_Post_Nybble_B: Dest_Value = B; break; + case TFR_EXG_Post_Nybble_CC: Dest_Value = CCR; break; + case TFR_EXG_Post_Nybble_DP: Dest_Value = DP; break; + default: break; + } + } + /* write register values */ + if (Src_Nybble <= 5 && Dest_Nybble <= 5) { + /* 16-bit register */ + /* write source register */ + switch (Src_Nybble) { + case TFR_EXG_Post_Nybble_D: + A = Dest_Value >> 8; + B = Dest_Value & 0XFF; + break; + case TFR_EXG_Post_Nybble_X: IX = Dest_Value; break; + case TFR_EXG_Post_Nybble_Y: IY = Dest_Value; break; + case TFR_EXG_Post_Nybble_U: UP = Dest_Value; break; + case TFR_EXG_Post_Nybble_S: SP = Dest_Value; break; + case TFR_EXG_Post_Nybble_PC: PC = Dest_Value; break; + default: break; + } + /* write destination register */ + switch (Dest_Nybble) { + case TFR_EXG_Post_Nybble_D: + A = Src_Value >> 8; + B = Src_Value & 0XFF; + break; + case TFR_EXG_Post_Nybble_X: IX = Src_Value; break; + case TFR_EXG_Post_Nybble_Y: IY = Src_Value; break; + case TFR_EXG_Post_Nybble_U: UP = Src_Value; break; + case TFR_EXG_Post_Nybble_S: SP = Src_Value; break; + case TFR_EXG_Post_Nybble_PC: PC = Src_Value; break; + default: break; + } + } + if ((Src_Nybble >= 8 && Src_Nybble <= 11) && (Dest_Nybble >= 8 && Dest_Nybble <= 11)) { + /* 8-bit register */ + /* write source register */ + switch (Src_Nybble) { + case TFR_EXG_Post_Nybble_A: A = Dest_Value; break; + case TFR_EXG_Post_Nybble_B: B = Dest_Value; break; + case TFR_EXG_Post_Nybble_CC: CCR = Dest_Value; break; + case TFR_EXG_Post_Nybble_DP: DP = Dest_Value; break; + default: break; + } + /* write destination register */ + switch (Dest_Nybble) { + case TFR_EXG_Post_Nybble_A: A = Src_Value; break; + case TFR_EXG_Post_Nybble_B: B = Src_Value; break; + case TFR_EXG_Post_Nybble_CC: CCR = Src_Value; break; + case TFR_EXG_Post_Nybble_DP: DP = Src_Value; break; + default: break; + } + } + break; + + case 0x1F: /* TFR imm */ + Post_Byte = get_imm_byte_val(); + Dest_Nybble = Post_Byte & 0x0F; + Src_Nybble = Post_Byte >> 4; + if ((Src_Nybble <= 5 && Dest_Nybble > 5) || (Src_Nybble > 5 && Dest_Nybble <= 5)) { + // TFR with unaligned register sizes + reason = STOP_OPCODE; + } + + + if ((Src_Nybble <= 5) && (Dest_Nybble <= 5)) { + /* 16-bit registers */ + /* read source register */ + switch (Src_Nybble) { + case TFR_EXG_Post_Nybble_D: Src_Value = (A << 8) | (B & 0xFF); break; + case TFR_EXG_Post_Nybble_X: Src_Value = IX; break; + case TFR_EXG_Post_Nybble_Y: Src_Value = IY; break; + case TFR_EXG_Post_Nybble_U: Src_Value = UP; break; + case TFR_EXG_Post_Nybble_S: Src_Value = SP; break; + case TFR_EXG_Post_Nybble_PC: Src_Value = PC; break; + break; + } + /* write source register */ + switch (Dest_Nybble) { + case TFR_EXG_Post_Nybble_D: + A = Src_Value >> 8; + B = Src_Value & 0XFF; + break; + case TFR_EXG_Post_Nybble_X: IX = Src_Value; break; + case TFR_EXG_Post_Nybble_Y: IY = Src_Value; break; + case TFR_EXG_Post_Nybble_U: UP = Src_Value; break; + case TFR_EXG_Post_Nybble_S: SP = Src_Value; break; + case TFR_EXG_Post_Nybble_PC: PC = Src_Value;; break; + break; + } + } + if ((Src_Nybble >= 8 && Src_Nybble <= 11) && (Dest_Nybble >= 8 && Dest_Nybble <= 11)) { + /* 8-bit registers */ + /* read the source register */ + switch (Src_Nybble) { + case TFR_EXG_Post_Nybble_A: Src_Value = A; break; + case TFR_EXG_Post_Nybble_B: Src_Value = B; break; + case TFR_EXG_Post_Nybble_CC: Src_Value = CCR; break; + case TFR_EXG_Post_Nybble_DP: Src_Value = DP; break; + break; + } + /* write the destination register */ + switch (Dest_Nybble) { + case TFR_EXG_Post_Nybble_A: A = Src_Value; break; + case TFR_EXG_Post_Nybble_B: B = Src_Value; break; + case TFR_EXG_Post_Nybble_CC: CCR = Src_Value; break; + case TFR_EXG_Post_Nybble_DP: DP = Src_Value; break; + break; + } + } + break; + +/* 0x20 - relative mode */ + case 0x20: /* BRA rel */ + go_rel(1); + break; + case 0x21: /* BRN rel */ + /* Branch Never - essentially a NOP */ + go_rel(0); + break; + case 0x22: /* BHI rel */ + go_rel(!(get_flag(CF) | get_flag(ZF))); + break; + case 0x23: /* BLS rel */ + go_rel(get_flag(CF) | get_flag(ZF)); + break; + case 0x24: /* BCC rel */ + go_rel(!get_flag(CF)); + break; + case 0x25: /* BCS rel */ + go_rel(get_flag(CF)); + break; + case 0x26: /* BNE rel */ + go_rel(!get_flag(ZF)); + break; + case 0x27: /* BEQ rel */ + go_rel(get_flag(ZF)); + break; + case 0x28: /* BVC rel */ + go_rel(!get_flag(VF)); + break; + case 0x29: /* BVS rel */ + go_rel(get_flag(VF)); + break; + case 0x2A: /* BPL rel */ + go_rel(!get_flag(NF)); + break; + case 0x2B: /* BMI rel */ + go_rel(get_flag(NF)); + break; + case 0x2C: /* BGE rel */ + go_rel(!(get_flag(NF) ^ get_flag(VF))); + break; + case 0x2D: /* BLT rel */ + go_rel(get_flag(NF) ^ get_flag(VF)); + break; + case 0x2E: /* BGT rel */ + go_rel( !( get_flag(ZF) | (get_flag(NF) ^ get_flag(VF)) ) ); + break; + case 0x2F: /* BLE rel */ + go_rel( get_flag(ZF) | (get_flag(NF) ^ get_flag(VF)) ); + break; + +/* 0x30 */ + case 0x30: /* LEAX */ + IX = get_indexed_addr(); + COND_SET_FLAG_Z_16(IX); + break; + + case 0x31: /* LEAY */ + IY = get_indexed_addr(); + COND_SET_FLAG_Z_16(IY); + break; + + case 0x32: /* LEAS */ + SP = get_indexed_addr(); + /* does not affect CCR */ + break; + + case 0x33: /* LEAU */ + UP = get_indexed_addr(); + /* does not affect CCR */ + break; + + case 0x34: /* PSHS */ + Post_Byte = get_imm_byte_val(); + if (Post_Byte & PSH_PUL_Post_Byte_PC) push_sp_word(PC); + if (Post_Byte & PSH_PUL_Post_Byte_S_U) push_sp_word(UP); + if (Post_Byte & PSH_PUL_Post_Byte_Y) push_sp_word(IY); + if (Post_Byte & PSH_PUL_Post_Byte_X) push_sp_word(IX); + if (Post_Byte & PSH_PUL_Post_Byte_DP) push_sp_byte(DP); + if (Post_Byte & PSH_PUL_Post_Byte_B) push_sp_byte(B); + if (Post_Byte & PSH_PUL_Post_Byte_A) push_sp_byte(A); + if (Post_Byte & PSH_PUL_Post_Byte_CC) push_sp_byte(CCR); + break; + + case 0x35: /* PULS */ + Post_Byte = get_imm_byte_val(); + if (Post_Byte & PSH_PUL_Post_Byte_CC) CCR = pop_sp_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_A) A = pop_sp_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_B) B = pop_sp_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_DP) DP = pop_sp_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_X) IX = pop_sp_word(); + if (Post_Byte & PSH_PUL_Post_Byte_Y) IY = pop_sp_word(); + if (Post_Byte & PSH_PUL_Post_Byte_S_U) UP = pop_sp_word(); + if (Post_Byte & PSH_PUL_Post_Byte_PC) PC = pop_sp_word(); + break; + + case 0x36: /* PSHU */ + Post_Byte = get_imm_byte_val(); + if (Post_Byte & PSH_PUL_Post_Byte_PC) push_up_word(PC); + if (Post_Byte & PSH_PUL_Post_Byte_S_U) push_up_word(SP); + if (Post_Byte & PSH_PUL_Post_Byte_Y) push_up_word(IY); + if (Post_Byte & PSH_PUL_Post_Byte_X) push_up_word(IX); + if (Post_Byte & PSH_PUL_Post_Byte_DP) push_up_byte(DP); + if (Post_Byte & PSH_PUL_Post_Byte_B) push_up_byte(B); + if (Post_Byte & PSH_PUL_Post_Byte_A) push_up_byte(A); + if (Post_Byte & PSH_PUL_Post_Byte_CC) push_up_byte(CCR); + break; + + case 0x37: /* PULU */ + Post_Byte = get_imm_byte_val(); + if (Post_Byte & PSH_PUL_Post_Byte_CC) CCR = pop_up_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_A) A = pop_up_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_B) B = pop_up_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_DP) DP = pop_up_byte(); + if (Post_Byte & PSH_PUL_Post_Byte_X) IX = pop_up_word(); + if (Post_Byte & PSH_PUL_Post_Byte_Y) IY = pop_up_word(); + if (Post_Byte & PSH_PUL_Post_Byte_S_U) SP = pop_up_word(); + if (Post_Byte & PSH_PUL_Post_Byte_PC) PC = pop_up_word(); + break; + + case 0x39: /* RTS */ + PC = pop_sp_word(); + break; + + case 0x3A: /* ABX */ + /* this is an UNSIGNED operation! */ + IX = (IX + B) & 0xFFFF; + /* no changes to CCR */ + break; + + case 0x3B: /* RTI */ + CCR = pop_sp_byte(); + if (GET_FLAG(EF)) { + /* entire state flag */ + A = pop_sp_byte(); + B = pop_sp_byte(); + DP = pop_sp_byte(); + IX = pop_sp_word(); + IY = pop_sp_word(); + UP = pop_sp_word(); + } + PC = pop_sp_word(); + break; + + case 0x3C: /* CWAI */ + /* AND immediate byte with CCR + CCR &= get_imm_byte_val(); + SET_FLAG(EF); + /* push register state */ + push_sp_word(PC); + push_sp_word(UP); + push_sp_word(IY); + push_sp_word(IX); + push_sp_byte(DP); + push_sp_byte(B); + push_sp_byte(A); + push_sp_byte(CCR); + if (get_flag(IF)) { + reason = STOP_HALT; + continue; + } else { + SET_FLAG(IF); + PC = CPU_BD_get_mword(0xFFFE) & ADDRMASK; + } + break; + + case 0x3D: /* MUL */ + D = A * B; + A = D >> 8; + B = D & 0xFF; + COND_SET_FLAG_Z_16(D); + COND_SET_FLAG(B & 0x80, CF); + break; + + case 0x3F: /* SWI */ + SET_FLAG(EF); + push_sp_word(PC); + push_sp_word(UP); + push_sp_word(IY); + push_sp_word(IX); + push_sp_byte(DP); + push_sp_byte(B); + push_sp_byte(A); + push_sp_byte(CCR); + SET_FLAG(FF); + SET_FLAG(IF); + PC = CPU_BD_get_mword(0xFFFA) & ADDRMASK; + break; + +/* 0x40 - inherent mode */ + case 0x40: /* NEGA */ + COND_SET_FLAG(A != 0, CF); + COND_SET_FLAG(A == 0x80, VF); + A = 0 - A; + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x43: /* COMA */ + A = ~A; + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + SET_FLAG(CF); + break; + case 0x44: /* LSRA */ + COND_SET_FLAG(A & 0x01, CF); + A = (A >> 1) & 0xFF; + CLR_FLAG(NF); + COND_SET_FLAG_Z(A); + /* H,V unaffected */ + break; + case 0x46: /* RORA */ + hi = get_flag(CF); + COND_SET_FLAG(A & 0x01, CF); + A = A >> 1; + if (hi) + A |= 0x80; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + /* H,V unaffected */ + break; + case 0x47: /* ASRA */ + COND_SET_FLAG(A & 0x01, CF); + A = (A >> 1) | (A & 0x80); + /* H undefined */ + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + /* V unaffected */ + break; + case 0x48: /* ASLA */ + COND_SET_FLAG(A & 0x80, CF); + A = (A << 1) & 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x49: /* ROLA */ + hi = get_flag(CF); + COND_SET_FLAG(A & 0x80, CF); + A = (A << 1) & 0xFF; + if (hi) + A |= 0x01; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x4A: /* DECA */ + COND_SET_FLAG(A == 0x80, VF); + A = (A - 1) & 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x4C: /* INCA */ + COND_SET_FLAG(A == 0x7F, VF); + A = (A + 1) & 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x4D: /* TSTA */ + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + /* C not affected */ + break; + case 0x4F: /* CLRA */ + A = 0; + CLR_FLAG(NF); + SET_FLAG(ZF); + CLR_FLAG(VF); + CLR_FLAG(CF); + break; + +/* 0x50 - inherent modes */ + case 0x50: /* NEGB */ + COND_SET_FLAG(B != 0, CF); + COND_SET_FLAG(B == 0x80, VF); + B = (0 - B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0x53: /* COMB */ + B = ~B; + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + SET_FLAG(CF); + break; + case 0x54: /* LSRB */ + COND_SET_FLAG(B & 0x01, CF); + B = (B >> 1) & 0xFF; + CLR_FLAG(NF); + COND_SET_FLAG_Z(B); + /* H,V unaffected */ + break; + case 0x56: /* RORB */ + hi = get_flag(CF); + COND_SET_FLAG(B & 0x01, CF); + B = B >> 1; + if (hi) + B |= 0x80; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + /* H,V unaffected */ + break; + case 0x57: /* ASRB */ + COND_SET_FLAG(B & 0x01, CF); + B = (B >> 1) | (B & 0x80); + /* H undefined */ + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + /* C unaffected */ + break; + case 0x58: /* ASLB */ + COND_SET_FLAG(B & 0x80, CF); + B = (B << 1) & 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x59: /* ROLB */ + hi = get_flag(CF); + COND_SET_FLAG(B & 0x80, CF); + B = (B << 1) & 0xFF; + if (hi) + B |= 0x01; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x5A: /* DECB */ + COND_SET_FLAG(B == 0x80, VF); + B = (B - 1) & 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0x5C: /* INCB */ + COND_SET_FLAG(B == 0x7F, VF); + B = (B + 1) & 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0x5D: /* TSTB */ + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + /* C not affected */ + break; + case 0x5F: /* CLRB */ + B = 0; + CLR_FLAG(NF); + SET_FLAG(ZF); + CLR_FLAG(VF); + CLR_FLAG(CF); + break; + +/* 0x60 - index mode */ + case 0x60: /* NEG ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 != 0, CF); + COND_SET_FLAG(op1 == 0x80, VF); + result = (0 - op1) & 0xFF; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0x63: /* COM ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = ~op1; + result &= 0xFF; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + CLR_FLAG(VF); + SET_FLAG(CF); + break; + case 0x64: /* LSR ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 & 0x01, CF); + result = op1 >> 1; + CPU_BD_put_mbyte(addr, result); + CLR_FLAG(NF); + COND_SET_FLAG_Z(result); + /* H,V unaffected */ + break; + case 0x66: /* ROR ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = op1 >> 1; + if (get_flag(CF)) + result |= 0x80; + CPU_BD_put_mbyte(addr, result); + /* H,V unaffected */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(op1 & 0x01, CF); + break; + case 0x67: /* ASR ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 >> 1) | (op1 & 0x80); + CPU_BD_put_mbyte(addr, result); + /* H undefined */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + /* V unaffected */ + COND_SET_FLAG(op1 & 0x01, CF); + break; + case 0x68: /* ASL ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 & 0x80, CF); + result = (op1 << 1) & 0xFF; + CPU_BD_put_mbyte(addr, result); + /* H is undefined */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x69: /* ROL ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 << 1) & 0xFF; + if (get_flag(CF)) + result |= 0x01; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG((op1 & 0x80) ^ (op1 & 0x40), VF); + COND_SET_FLAG(op1 & 0x80, CF); + break; + case 0x6A: /* DEC ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 - 1) & 0xFF; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(op1 == 0x80, VF); + break; + case 0x6C: /* INC ind */ + addr = get_indexed_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 == 0x7F, VF); + op1 = (op1 + 1) & 0xFF; + CPU_BD_put_mbyte(addr, op1); + COND_SET_FLAG_N(op1); + COND_SET_FLAG_Z(op1); + break; + case 0x6D: /* TST ind */ + result = get_indexed_byte_val(); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + CLR_FLAG(VF); + break; + case 0x6E: /* JMP ind */ + PC = get_indexed_addr(); + break; + case 0x6F: /* CLR ind */ + CPU_BD_put_mbyte(get_indexed_addr(), 0); + /* H not affected */ + CLR_FLAG(NF); + SET_FLAG(ZF); + CLR_FLAG(VF); + CLR_FLAG(CF); + break; + +/* 0x70 - extended modes */ + case 0x70: /* NEG ext */ + addr= get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 != 0, CF); + COND_SET_FLAG(op1 == 0x80, VF) ; + result = (0 - op1) & 0xFF; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0x73: /* COM ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = ~op1; + result &= 0xFF; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + CLR_FLAG(VF); + SET_FLAG(CF); + break; + case 0x74: /* LSR ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 & 0x01, CF); + result = op1 >> 1; + CPU_BD_put_mbyte(addr, result); + CLR_FLAG(NF); + COND_SET_FLAG_Z(result); + /* H,V unaffected */ + break; + case 0x76: /* ROR ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = op1 >> 1; + if (get_flag(CF)) + result |= 0x80; + CPU_BD_put_mbyte(addr, result); + /* H,V unaffected */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(op1 & 0x01, CF); + break; + case 0x77: /* ASR ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 >> 1) | (op1 & 0x80); + CPU_BD_put_mbyte(addr, result); + /* H undefined */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + /* V unaffected */ + COND_SET_FLAG(op1 & 0x01, CF); + break; + case 0x78: /* ASL ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 & 0x80, CF); + result = (op1 << 1) & 0xFF; + CPU_BD_put_mbyte(addr, result); + /* H is undefined */ + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + break; + case 0x79: /* ROL ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 << 1) & 0xFF; + if (get_flag(CF)) + result |= 0x01; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG((op1 & 0x80) ^ (op1 & 0x40), VF); + COND_SET_FLAG(op1 & 0x80, CF); + break; + case 0x7A: /* DEC ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + result = (op1 - 1) & 0xFF; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(op1 == 0x80, VF); + break; + case 0x7C: /* INC ext */ + addr = get_ext_addr(); + op1 = CPU_BD_get_mbyte(addr); + COND_SET_FLAG(op1 == 0x7F, VF); + op1 = (op1 + 1) & 0xFF; + CPU_BD_put_mbyte(addr, op1); + COND_SET_FLAG_N(op1); + COND_SET_FLAG_Z(op1); + break; + case 0x7D: /* TST ext */ + result = get_ext_byte_val(); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + CLR_FLAG(VF); + break; + case 0x7E: /* JMP ext */ + PC = get_ext_addr(); + break; + case 0x7F: /* CLR ext */ + CPU_BD_put_mbyte(get_ext_addr(), 0); + /* H not affected */ + CLR_FLAG(NF); + SET_FLAG(ZF); + CLR_FLAG(VF); + CLR_FLAG(CF); + break; + +/* 0x80 - immediate mode (except for BSR) */ + case 0x80: /* SUBA imm */ + op1 = get_imm_byte_val(); + op2 = A; + A = A - op1; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0x81: /* CMPA imm */ + op2 = get_imm_byte_val(); + result = A - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(A, op2); + break; + case 0x82: /* SBCA imm */ + op1 = A; + op2 = get_imm_byte_val() + get_flag(CF); + A = A - op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0x83: /* SUBD imm */ + D = (A << 8) | (B & 0xFF); + op2 = get_imm_word_val(); + result = D - op2; + COND_SET_FLAG_C_16(result); + result &= 0xFFFF; + A = result >> 8; + B = result & 0xFF; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + break; + case 0x84: /* ANDA imm */ + A = (A & get_imm_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x85: /* BITA imm */ + result = (A & get_imm_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0x86: /* LDA imm */ + A = get_imm_byte_val(); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x88: /* EORA imm */ + A = (A ^ get_imm_byte_val()) & 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x89: /* ADCA imm */ + op1 = A; + op2 = get_imm_byte_val() + get_flag(CF); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0x8A: /* ORA imm */ + A = A | get_imm_byte_val(); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x8B: /* ADDA imm */ + op1 = A; + op2 = get_imm_byte_val(); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0x8C: /* CMPX imm */ + op2 = get_imm_word_val(); + result = IX - op2; + COND_SET_FLAG_C_16(result); + result = result & 0xFFFF; + COND_SET_FLAG_Z_16(result); + COND_SET_FLAG_N_16(result); + condevalVs16(IX, op2); + break; + case 0x8D: /* BSR rel */ + addr = get_rel_addr(); + push_sp_word(PC); + PC = (PC + addr) & ADDRMASK; + break; + case 0x8E: /* LDX imm */ + IX = get_imm_word_val(); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + +/* 0x90 - direct mode */ + case 0x90: /* SUBA dir */ + op1 = A; + op2 = get_dir_byte_val(); + A = A - op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0x91: /* CMPA dir */ + op2 = get_dir_byte_val(); + result = A - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(A, op2); + break; + case 0x92: /* SBCA dir */ + op1 = A; + op2 = get_dir_byte_val() + get_flag(CF); + A = A - op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0x93: /* SUBD dir */ + D = (A << 8) | (B & 0xFF); + op2 = get_dir_word_val(); + result = D - op2; + COND_SET_FLAG_C_16(result); + result &= 0xFFFF; + A = result >> 8; + B = result & 0xFF; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + break; + case 0x94: /* ANDA dir */ + A = (A & get_dir_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0x95: /* BITA dir */ + result = (A & get_dir_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0x96: /* LDA dir */ + A = get_dir_byte_val(); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x97: /* STA dir */ + CPU_BD_put_mbyte(get_dir_addr(), A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x98: /* EORA dir */ + A = (A ^ get_dir_byte_val()) & 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x99: /* ADCA dir */ + op1 = A; + op2 = get_dir_byte_val() + get_flag(CF); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0x9A: /* ORA dir */ + A = A | get_dir_byte_val(); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0x9B: /* ADDA dir */ + op1 = A; + op2 = get_dir_byte_val(); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0x9C: /* CMPX dir */ + op2 = get_dir_word_val(); + result = IX - op2; + COND_SET_FLAG_C_16(result); + result &= 0xFFFF; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IX, op2); + break; + case 0x9D: /* JSR dir */ + addr = get_dir_addr(); + push_sp_word(PC); + PC = addr; + break; + case 0x9E: /* LDX dir */ + IX = get_dir_word_val(); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + case 0x9F: /* STX dir */ + CPU_BD_put_mword(get_dir_addr(), IX); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + +/* 0xA0 - indexed mode */ + case 0xA0: /* SUBA ind */ + op1 = get_indexed_byte_val(); + result = A - op1; + A = result; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, result); + break; + case 0xA1: /* CMPA ind */ + op2 = get_indexed_byte_val(); + result = A - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(A, op2); + break; + case 0xA2: /* SBCA ind */ + op1 = A; + op2 = get_indexed_byte_val() + get_flag(CF); + A = A - op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0xA3: /* SUBD ind */ + D = (A << 8) | (B & 0xFF); + op2 = get_indexed_word_val(); + result = D - op2; + COND_SET_FLAG_C_16(result); + result &= 0xFFFF; + A = result >> 8; + B = result & 0xFF; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + break; + case 0xA4: /* ANDA ind */ + A = (A & get_indexed_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xA5: /* BITA ind */ + result = (A & get_indexed_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0xA6: /* LDA ind */ + A = get_indexed_byte_val(); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xA7: /* STA ind */ + CPU_BD_put_mbyte(get_indexed_addr(), A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xA8: /* EORA ind */ + A = (A ^ get_indexed_byte_val()) & 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xA9: /* ADCA ind */ + op1 = A; + op2 = get_indexed_byte_val() + get_flag(CF); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0xAA: /* ORA ind */ + A = A | get_indexed_byte_val(); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xAB: /* ADDA ind */ + op1 = A; + op2 = get_indexed_byte_val(); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0xAC: /* CMPX ind */ + op2 = get_indexed_word_val(); + result = (IX - op2) & ADDRMASK; + COND_SET_FLAG_C_16(result); + result &= 0xFFFF; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IX, op2); + break; + case 0xAD: /* JSR ind */ + addr = get_indexed_addr(); + push_sp_word(PC); + PC = addr; + break; + case 0xAE: /* LDX ind */ + IX = get_indexed_word_val(); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + case 0xAF: /* STX ind */ + CPU_BD_put_mword(get_indexed_addr(), IX); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + +/* 0xB0 - extended mode */ + case 0xB0: /* SUBA ext */ + op1 = A; + op2 = get_ext_byte_val(); + A = A - op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0xB1: /* CMPA ext */ + op2 = get_ext_byte_val(); + result = A - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(A, op2); + break; + case 0xB2: /* SBCA ext */ + op1 = A; + op2 = get_ext_byte_val() + get_flag(CF); + A = A - op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVs(op1, op2); + break; + case 0xB3: /* SUBD ext */ + D = (A << 8) | (B & 0xFF); + op2 = get_ext_word_val(); + result = D - op2; + COND_SET_FLAG_C_16(result); + result &= 0xFFFF; + A = result >> 8; + B = result & 0xFF; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(D, op2); + break; + case 0xB4: /* ANDA ext */ + A = (A & get_ext_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + break; + case 0xB5: /* BITA ext */ + result = (A & get_ext_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0xB6: /* LDA ext */ + A = get_ext_byte_val(); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xB7: /* STA ext */ + CPU_BD_put_mbyte(get_ext_addr(), A); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xB8: /* EORA ext */ + A = (A ^ get_ext_byte_val()) & 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xB9: /* ADCA ext */ + op1 = A; + op2 = get_ext_byte_val() + get_flag(CF); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0xBA: /* ORA ext */ + A = A | get_ext_byte_val(); + A &= 0xFF; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + CLR_FLAG(VF); + break; + case 0xBB: /* ADDA ext */ + op1 = A; + op2 = get_ext_byte_val(); + A = A + op2; + COND_SET_FLAG_C(A); + A &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + condevalVa(op1, op2); + break; + case 0xBC: /* CMPX ext */ + op2 = get_ext_word_val(); + result = (IX - op2); + COND_SET_FLAG_C_16(result); + result = result & 0xFFFF; + COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); + condevalVs16(IX, op2); + break; + case 0xBD: /* JSR ext */ + addr = get_ext_addr(); + push_sp_word(PC); + PC = addr; + break; + case 0xBE: /* LDX ext */ + IX = get_ext_word_val(); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + case 0xBF: /* STX ext */ + CPU_BD_put_mword(get_ext_addr(), IX); + COND_SET_FLAG_N_16(IX); + COND_SET_FLAG_Z_16(IX); + CLR_FLAG(VF); + break; + +/* 0xC0 - immediate mode */ + case 0xC0: /* SUBB imm */ + op1 = B; + op2 = get_imm_byte_val(); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xC1: /* CMPB imm */ + op2 = get_imm_byte_val(); + result = B - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(B, op2); + break; + case 0xC2: /* SBCB imm */ + op1 = B; + op2 = get_imm_byte_val() + get_flag(CF); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xC3: /* ADDD imm */ + op1 = (A << 8) | (B & 0xFF); + op2 = get_imm_word_val(); + D = op1 + op2; + COND_SET_FLAG_C_16(D); + D &= 0xFFFF; + A = D >> 8; + B = D & 0xFF; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + condevalVa16(op1,op2); + break; + case 0xC4: /* ANDB imm */ + B = (B & get_imm_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xC5: /* BITB imm */ + result = (B & get_imm_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0xC6: /* LDB imm */ + B = get_imm_byte_val(); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xC8: /* EORB imm */ + B = (B ^ get_imm_byte_val()) & 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xC9: /* ADCB imm */ + op1 = B; + op2 = get_imm_byte_val() + get_flag(CF); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xCA: /* ORB imm */ + B = B | get_imm_byte_val(); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xCB: /* ADDB imm */ + op1 = B; + op2 = get_imm_byte_val(); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xCC: /* LDD imm */ + D = get_imm_word_val(); + A = D >> 8; + B = D & 0xFF; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xCE: /* LDU imm */ + UP = get_imm_word_val(); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + +/* 0xD0 - direct modes */ + case 0xD0: /* SUBB dir */ + op1 = B; + op2 = get_dir_byte_val(); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xD1: /* CMPB dir */ + op2 = get_dir_byte_val(); + result = B - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(B, op2); + break; + case 0xD2: /* SBCB dir */ + op1 = B; + op2 = get_dir_byte_val() + get_flag(CF); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xD3: /* ADDD dir */ + op1 = (A << 8) | (B & 0xFF); + op2 = get_dir_word_val(); + D = op1 + op2; + COND_SET_FLAG_C_16(D); + D &= 0xFFFF; + A = D >> 8; + B = D & 0xFF; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + condevalVa16(op1, op2); + break; + case 0xD4: /* ANDB dir */ + B = (B & get_dir_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xD5: /* BITB dir */ + result = (B & get_dir_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0xD6: /* LDB dir */ + B = get_dir_byte_val(); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xD7: /* STB dir */ + CPU_BD_put_mbyte(get_dir_addr(), B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xD8: /* EORB dir */ + B = (B ^ get_dir_byte_val()) & 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xD9: /* ADCB dir */ + op1 = B; + op2 = get_dir_byte_val() + get_flag(CF); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xDA: /* ORB dir */ + B = B | get_dir_byte_val(); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xDB: /* ADDB dir */ + op1 = B; + op2 = get_dir_byte_val(); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xDC: /* LDD dir */ + D = get_dir_word_val(); + A = D >> 8; + B = D & 0xFF; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xDD: /* STD dir */ + D = (A << 8) | (B & 0xFF); + CPU_BD_put_mword(get_dir_addr(), D); + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xDE: /* LDU dir */ + UP = get_dir_word_val(); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + case 0xDF: /* STU dir */ + CPU_BD_put_mword(get_dir_addr(), UP); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + +/* 0xE0 - indexed mode */ + case 0xE0: /* SUBB ind */ + op1 = B; + op2 = get_indexed_byte_val(); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xE1: /* CMPB ind */ + op2 = get_indexed_byte_val(); + result = B - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(B, op2); + break; + case 0xE2: /* SBCB ind */ + op1 = B; + op2 = get_indexed_byte_val() + get_flag(CF); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xE3: /* ADDD ind */ + op1 = (A << 8) | (B & 0xFF); + op2 = get_indexed_word_val(); + D = op1 + op2; + COND_SET_FLAG_C_16(D); + D &= 0xFFFF; + A = D >> 8; + B = D & 0xFF; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + condevalVa16(op1, op2); + break; + case 0xE4: /* ANDB ind */ + B = (B & get_indexed_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xE5: /* BITB ind */ + result = (B & get_indexed_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0xE6: /* LDB ind */ + B = get_indexed_byte_val(); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xE7: /* STB ind */ + CPU_BD_put_mbyte(get_indexed_addr(), B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xE8: /* EORB ind */ + B = (B ^ get_indexed_byte_val()) & 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xE9: /* ADCB ind */ + op1 = B; + op2 = get_indexed_byte_val() + get_flag(CF); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xEA: /* ORB ind */ + B = B | get_indexed_byte_val(); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xEB: /* ADDB ind */ + op1 = B; + op2 = get_indexed_byte_val(); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xEC: /* LDD ind */ + D = get_indexed_word_val(); + A = D >> 8; + B = D & 0xFF; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xED: /* STD ind */ + D = (A << 8) | (B & 0xFF); + CPU_BD_put_mword(get_indexed_addr(), D); + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xEE: /* LDU ind */ + UP = get_indexed_word_val(); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + case 0xEF: /* STU ind */ + CPU_BD_put_mword(get_indexed_addr(), UP); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + +/* 0xF0 - extended mode */ + case 0xF0: /* SUBB ext */ + op1 = B; + op2 = get_ext_byte_val(); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xF1: /* CMPB ext */ + op2 = get_ext_byte_val(); + result = B - op2; + COND_SET_FLAG_C(result); + result &= 0xFF; + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + condevalVs(B, op2); + break; + case 0xF2: /* SBCB ext */ + op1 = B; + op2 = get_ext_byte_val() + get_flag(CF); + B = B - op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVs(op1, op2); + break; + case 0xF3: /* ADDD ext */ + op1 = (A << 8) | (B & 0xFF); + op2 = get_ext_word_val(); + D = op1 + op2; + COND_SET_FLAG_C_16(D); + D &= 0xFFFF; + A = D >> 8; + B = D & 0xFF; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + condevalVa16(op1, op2); + break; + case 0xF4: /* ANDB ext */ + B = (B & get_ext_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + break; + case 0xF5: /* BITB ext */ + result = (B & get_ext_byte_val()) & 0xFF; + CLR_FLAG(VF); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + break; + case 0xF6: /* LDB ext */ + B = get_ext_byte_val(); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xF7: /* STB ext */ + CPU_BD_put_mbyte(get_ext_addr(), B); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xF8: /* EORB ext */ + B = (B ^ get_ext_byte_val()) & 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xF9: /* ADCB ext */ + op1 = B; + op2 = get_ext_byte_val() + get_flag(CF); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xFA: /* ORB ext */ + B = B | get_ext_byte_val(); + B &= 0xFF; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + CLR_FLAG(VF); + break; + case 0xFB: /* ADDB ext */ + op1 = B; + op2 = get_ext_byte_val(); + B = B + op2; + COND_SET_FLAG_C(B); + B &= 0xFF; + condevalHa(op1, op2); + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + condevalVa(op1, op2); + break; + case 0xFC: /* LDD ext */ + D = get_ext_word_val(); + A = D >> 8; + B = D & 0xFF; + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xFD: /* STD ext */ + D = (A << 8) | (B & 0xFF); + CPU_BD_put_mword(get_ext_addr(), D); + COND_SET_FLAG_N_16(D); + COND_SET_FLAG_Z_16(D); + CLR_FLAG(VF); + break; + case 0xFE: /* LDU ext */ + UP = get_ext_word_val(); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + case 0xFF: /* STU ext */ + CPU_BD_put_mword(get_ext_addr(), UP); + COND_SET_FLAG_N_16(UP); + COND_SET_FLAG_Z_16(UP); + CLR_FLAG(VF); + break; + + default: /* Unassigned */ + if (m6809_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(void) +{ + printf("\r\nPC=%04X SP=%04X UP=%04X IX=%04X IY=%04X ", PC, SP, UP, IX, IY); + printf("A=%02X B=%02X DP=%02X CCR=%02X", A, B, DP, CCR); +} + +void dump_regs1(void) +{ + printf("PC=%04X SP=%04X UP=%04X IX=%04X IY=%04X ", PC, SP, UP, IX, IY); + printf("A=%02X B=%02X DP=%02X CCR=%02X\n", A, B, DP, CCR); +} + +/* fetch an instruction or byte */ +int32 fetch_byte(int32 flag) +{ + uint8 val; + + val = CPU_BD_get_mbyte(PC); /* fetch byte */ + switch (flag) { + case 0: /* opcode fetch */ + sim_debug (DEBUG_asm, &m6809_dev, "%04X %s\n", PC, opcode[val]); + break; + case 1: /* byte operand fetch */ + sim_debug (DEBUG_asm, &m6809_dev, "0x%02XH\n", val); + break; + } + PC = (PC + 1) & ADDRMASK; /* increment PC */ + return val; +} + +/* fetch a word - big endian */ +int32 fetch_word() +{ + uint16 val; + + val = CPU_BD_get_mbyte(PC) << 8; /* fetch high byte */ + val |= (CPU_BD_get_mbyte(PC + 1)); /* fetch low byte */ + + /* 2-byte operand fetch */ + sim_debug (DEBUG_asm, &m6809_dev, "0x%04XH\n", val); + + PC = (PC + 2) & ADDRMASK; /* increment PC */ + return val; +} + +/* push a byte using the hardware stack pointer (SP) */ +void push_sp_byte(uint8 val) +{ + SP = (SP - 1) & ADDRMASK; + CPU_BD_put_mbyte(SP, val & 0xFF); +} + +/* push a byte using the user stack pointer (UP) */ +void push_up_byte(uint8 val) +{ + UP = (UP - 1) & ADDRMASK; + CPU_BD_put_mbyte(UP, val & 0xFF); +} + +/* push a word using the hardware stack pointer (SP) */ +void push_sp_word(uint16 val) +{ + push_sp_byte(val & 0xFF); + push_sp_byte(val >> 8); +} + +/* push a word using the user stack pointer (UP) */ +void push_up_word(uint16 val) +{ + push_up_byte(val & 0xFF); + push_up_byte(val >> 8); +} + +/* pop a byte using the hardware stack pointer (SP) */ +uint8 pop_sp_byte(void) +{ + register uint8 res; + + res = CPU_BD_get_mbyte(SP); + SP = (SP + 1) & ADDRMASK; + return res; +} + +/* pop a byte using the user stack pointer (UP) */ +uint8 pop_up_byte(void) +{ + register uint8 res; + + res = CPU_BD_get_mbyte(UP); + UP = (UP + 1) & ADDRMASK; + return res; +} + +/* pop a word using the hardware stack pointer (SP) */ +uint16 pop_sp_word(void) +{ + register uint16 res; + + res = pop_sp_byte() << 8; + res |= pop_sp_byte(); + return res; +} + +/* pop a word using the user stack pointer (UP) */ +uint16 pop_up_word(void) +{ + register uint16 res; + + res = pop_up_byte() << 8; + res |= pop_up_byte(); + return res; +} + +/* 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; + } +} + +/* this routine does the jump to long relative offset if the condition is met. Otherwise, execution continues at the current PC. */ +void go_long_rel(int32 cond) +{ + int32 temp; + + temp = get_long_rel_addr(); + if (cond != 0) { + PC += temp; + PC &= ADDRMASK; + } +} + +/* returns the relative offset sign-extended */ +int32 get_rel_addr(void) +{ + int32 temp; + + temp = fetch_byte(1); + if (temp & 0x80) + temp |= 0xFF00; + return temp & ADDRMASK; +} + +/* returns the long relative offset sign-extended */ +int32 get_long_rel_addr(void) +{ + return fetch_word(); +} + +/* returns the byte value at the direct address pointed to by PC */ +int32 get_dir_byte_val(void) +{ + return CPU_BD_get_mbyte(get_dir_addr()); +} + +/* returns the word value at the direct address pointed to by PC */ +int32 get_dir_word_val(void) +{ + return CPU_BD_get_mword(get_dir_addr()); +} + +/* returns the immediate byte value pointed to by PC */ +int32 get_imm_byte_val(void) +{ + return fetch_byte(1); +} + +/* returns the immediate word value pointed to by PC */ +int32 get_imm_word_val(void) +{ + return fetch_word(); +} + +/* returns the direct address pointed to by PC */ +/* use the Direct Page register as the high byte of the address */ +int32 get_dir_addr(void) +{ + int32 temp; + + temp = (DP << 8) + fetch_byte(1); + return temp & 0xFFFF; +} + +/* returns the byte value at the indexed address pointed to by PC */ +int32 get_indexed_byte_val(void) +{ + return CPU_BD_get_mbyte(get_indexed_addr()); +} + +/* returns the word value at the indexed address pointed to by PC */ +int32 get_indexed_word_val(void) +{ + return CPU_BD_get_mword(get_indexed_addr()); +} + +/* returns the indexed address. Note this also handles the indirect indexed mode */ +int32 get_indexed_addr(void) +{ + int32 temp; + int32 offset; + uint8 post_byte; + + /* fetch the index mode post-byte */ + post_byte = fetch_byte(1); + + if ((post_byte & 0x80) == 0) { + /* R +- 4-bit offset (non indirect only) */ + /* read register value */ + switch (post_byte & 0x60) { + case 0b00000000: temp = IX; break; + case 0b00100000: temp = IY; break; + case 0b01000000: temp = UP; break; + case 0b01100000: temp = SP; break; + default: break; + } + /* add 4 bit signed offset */ + if (post_byte & 0x10) { + /* subtract offset */ + offset = (post_byte | 0xFFF0); + temp += offset; + } else { + /* add offset */ + temp += (post_byte & 0x0F); + } + } else { + switch ( post_byte & 0x0F ) { + case 0b0000: + /* .R+ post increment by 1 (non indirect) */ + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX++; IX &= 0xFFFF; break; + case 0b00100000: temp = IY++; IY &= 0xFFFF; break; + case 0b01000000: temp = UP++; UP &= 0xFFFF; break; + case 0b01100000: temp = SP++; SP &= 0xFFFF; break; + default: break; + }; + break; + case 0b0001: + /* .R+ post increment by 2 (non indirect) */ + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX; IX=IX+2; IX &= 0xFFFF; break; + case 0b00100000: temp = IY; IY=IY+2; IY &= 0xFFFF; break; + case 0b01000000: temp = UP; UP=UP+2; UP &= 0xFFFF; break; + case 0b01100000: temp = SP; SP=SP+2; SP &= 0xFFFF; break; + default: break; + }; + break; + case 0b0010: + /* .-R pre decrement by 1 (non indirect) */ + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = --IX; IX &= 0xFFFF; break; + case 0b00100000: temp = --IY; IY &= 0xFFFF; break; + case 0b01000000: temp = --UP; UP &= 0xFFFF; break; + case 0b01100000: temp = --SP; SP &= 0xFFFF; break; + default: break; + }; + break; + case 0b0011: + /* .--R pre decrement by 2 (non indirect) */ + switch ( post_byte & 0x60 ) { + case 0b00000000: IX-=2; temp = IX; IX &= 0xFFFF; break; + case 0b00100000: IY-=2; temp = IY; IY &= 0xFFFF; break; + case 0b01000000: UP-=2; temp = UP; UP &= 0xFFFF; break; + case 0b01100000: SP-=2; temp = SP; SP &= 0xFFFF; break; + default: break; + }; + break; + case 0b0100: + /* R+0 zero offset (non indirect) */ + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX; break; + case 0b00100000: temp = IY; break; + case 0b01000000: temp = UP; break; + case 0b01100000: temp = SP; break; + default: break; + }; + break; + case 0b0101: + /* R+-ACCB (non indirect)*/ + if (B & 0x80) { + offset = B | 0xFF80; + } else { + offset = B; + } + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX; break; + case 0b00100000: temp = IY; break; + case 0b01000000: temp = UP; break; + case 0b01100000: temp = SP; break; + default: break; + }; + temp += offset; + break; + case 0b0110: + /* R+-ACCA (non indirect)*/ + if (A & 0x80) { + offset = A | 0xFF80; + } else { + offset = A; + } + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX; break; + case 0b00100000: temp = IY; break; + case 0b01000000: temp = UP; break; + case 0b01100000: temp = SP; break; + default: break; + }; + temp += offset; + break; + case 0b1000: + /* R+- 8-bit offset */ + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX; break; + case 0b00100000: temp = IY; break; + case 0b01000000: temp = UP; break; + case 0b01100000: temp = SP; break; + default: break; + }; + /* need to fetch 8-bit operand */ + offset = fetch_byte(1); + + /* add 7 bit signed offset */ + if (offset & 0x80) { + /* subtract offset */ + offset |= 0xFF00; + } + temp += offset; + break; + case 0b1001: + /* R+- 16-bit offset */ + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX; break; + case 0b00100000: temp = IY; break; + case 0b01000000: temp = UP; break; + case 0b01100000: temp = SP; break; + default: break; + }; + /* need to fetch 16-bit operand */ + offset = fetch_word(); + + /* add 16 bit signed offset */ + temp += offset; + break; + case 0b1011: + /* R+- ACCD */ + D = (A << 8) + (B & 0xFF); + switch ( post_byte & 0x60 ) { + case 0b00000000: temp = IX + D; break; + case 0b00100000: temp = IY + D; break; + case 0b01000000: temp = UP + D; break; + case 0b01100000: temp = SP + D; break; + default: break; + }; + break; + case 0b1100: + /* PC+- 7-bit offset (non indirect) */ + /* need to fetch 8-bit operand */ + offset = fetch_byte(1); + // PC value after fetch!!! + temp = PC; + + /* add 7 bit signed offset */ + if (offset & 0x80) { + /* subtract offset */ + offset |= 0xFF00; + } + temp += offset; + break; + case 0b1101: + /* PC+- 15-bit offset (non indirect)*/ + /* need to fetch 16-bit operand */ + offset = fetch_word(); + // PC value after fetch!!! + temp = PC; + + /* add 15 bit signed offset */ + temp += offset; + break; + case 0b1111: + // Extended indirect - fetch 16-bit address + temp = fetch_word(); + break; + } + switch ( post_byte & 0x1F ) { + /* perform the indirection - 11 valid post-byte opcodes */ + case 0b10001: + case 0b10011: + case 0b10100: + case 0b10101: + case 0b10110: + case 0b11000: + case 0b11001: + case 0b11011: + case 0b11100: + case 0b11101: + case 0b11111: + temp = temp & 0xFFFF; + temp = CPU_BD_get_mword(temp); + break; + default: break; + } + } + /* make sure to truncate to 16-bit value */ + return temp & 0xFFFF; +} + +/* returns the value at the extended address pointed to by PC */ +int32 get_ext_byte_val(void) +{ + return CPU_BD_get_mbyte(get_ext_addr()); +} + +/* returns the value at the extended address pointed to by PC */ +int32 get_ext_word_val(void) +{ + return CPU_BD_get_mword(get_ext_addr()); +} + +/* returns the extended address pointed to by PC or immediate word */ +int32 get_ext_addr(void) +{ + int32 temp; + + temp = fetch_word(); + return temp; +} + +/* return 1 for flag set or 0 for flag clear */ +int32 get_flag(int32 flg) +{ + if (CCR & flg) { + return 1; + } + else { + return 0; + } +} + +/* test and set V for 8-addition */ +void condevalVa(int32 op1, int32 op2) +{ + if (((op1 & 0x80) == (op2 & 0x80)) && + (((op1 + op2) & 0x80) != (op1 & 0x80))) + SET_FLAG(VF); + else + CLR_FLAG(VF); +} + +/* test and set V for 16-bit addition */ +void condevalVa16(int32 op1, int32 op2) +{ + /* + IF (the sign of the 2 operands are the same) + AND + (the sum of the operands has a different sign than both of the 2 operands) + THEN set the Overflow flag + ELSE clear the Overflow flag + */ + if (((op1 & 0x8000) == (op2 & 0x8000)) && + (((op1 + op2) & 0x8000) != (op1 & 0x8000))) + SET_FLAG(VF); + else + CLR_FLAG(VF); +} + +/* test and set V for 8-bit subtraction */ +void condevalVs(int32 op1, int32 op2) +{ + if (((op1 & 0x80) != (op2 & 0x80)) && + (((op1 - op2) & 0x80) == (op2 & 0x80))) + SET_FLAG(VF); + else + CLR_FLAG(VF); + +} + +/* test and set V for 16-bit subtraction */ +void condevalVs16(int32 op1, int32 op2) +{ + if (((op1 & 0x8000) != (op2 & 0x8000)) && + (((op1 - op2) & 0x8000) == (op2 & 0x8000))) + SET_FLAG(VF); + else + CLR_FLAG(VF); + +} + +/* test and set H for addition (8-bit only) */ +void condevalHa(int32 op1, int32 op2) +{ + if (((op1 & 0x0f) + (op2 & 0x0f)) & 0x10) + SET_FLAG(HF); + else + CLR_FLAG(HF); +} + +/* calls from the simulator */ + +/* Boot routine */ +t_stat m6809_boot(int32 unit_num, DEVICE *dptr) +{ + /* retrieve the reset vector at $FFFE */ + saved_PC = CPU_BD_get_mword(0xFFFE); + if (saved_PC == 0xFFFF) { + ; // No BOOT ROM detected! + } + return SCPE_OK; +} + +/* Reset routine */ +t_stat m6809_reset (DEVICE *dptr) +{ + CCR = EF | FF | IF; + DP = 0; + int_req = 0; + sim_brk_types = sim_brk_dflt = SWMASK ('E'); + + /* retrieve the reset vector at $FFFE */ + saved_PC = CPU_BD_get_mword(0xFFFE); + if (saved_PC == 0xFFFF) { + ; // No BOOT ROM detected! + } + return SCPE_OK; +} + +/* examine routine */ +t_stat m6809_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= 0x10000) { + /* exceed 16-bit address space */ + return SCPE_NXM; + } else { + *eval_array = CPU_BD_get_mbyte(addr); + return SCPE_OK; + } +} + +/* deposit routine */ +t_stat m6809_deposit(t_value value, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= 0x10000) { + /* exceed 16-bit address space */ + return SCPE_NXM; + } else { + CPU_BD_put_mbyte(addr, value); + return SCPE_OK; + } +} + + +/* This is the dumper/loader. This command uses the -h to signify a + hex dump/load vice a binary one. If no address is given to load, it + takes the address from the hex record or the current PC for binary. +*/ + +t_stat sim_load (FILE *fileref, CONST char *cptr, CONST char *fnam, int flag) +{ + int32 i, addr = 0, cnt = 0; + + if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; + addr = saved_PC; + while ((i = getc (fileref)) != EOF) { + CPU_BD_put_mbyte(addr, i); + addr++; + cnt++; + } // end while + printf ("%d Bytes loaded.\n", cnt); + return (SCPE_OK); +} + +/* Symbolic output + + Inputs: + *of = output stream + addr = current PC + *val = pointer to values + *uptr = pointer to unit + sw = switches + Outputs: + status = error code + for M6809 +*/ +t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) +{ + int32 i, inst, inst1; + + if (sw & SWMASK ('D')) { // dump memory + for (i=0; i<16; i++) + fprintf(of, "%02X ", val[i]); + fprintf(of, " "); + for (i=0; i<16; i++) + if (isprint(val[i])) + fprintf(of, "%c", val[i]); + else + fprintf(of, "."); + return -15; + } else if (sw & SWMASK ('M')) { // dump instruction mnemonic + inst = val[0]; + if (!oplen[inst]) { // invalid opcode + fprintf(of, "%02X", inst); + return 0; + } + inst1 = inst & 0xF0; + fprintf (of, "%s", opcode[inst]); // mnemonic + if (strlen(opcode[inst]) == 3) + fprintf(of, " "); + if (inst1 == 0x20 || inst == 0x8D) { // rel operand + inst1 = val[1]; + if (val[1] & 0x80) + inst1 |= 0xFF00; + fprintf(of, " $%04X", (addr + inst1 + 2) & ADDRMASK); + } else if (inst1 == 0x80 || inst1 == 0xC0) { // imm operand + if ((inst & 0x0F) < 0x0C) + fprintf(of, " #$%02X", val[1]); + else + fprintf(of, " #$%02X%02X", val[1], val[2]); + } else if (inst1 == 0x60 || inst1 == 0xA0 || inst1 == 0xE0) // ind operand + fprintf(of, " %d,X", val[1]); + else if (inst1 == 0x70 || inst1 == 0xb0 || inst1 == 0xF0) // ext operand + fprintf(of, " $%02X%02X", val[1], val[2]); + return (-(oplen[inst] - 1)); + } else + return SCPE_ARG; +} + +/* Symbolic input + + Inputs: + *cptr = pointer to input string + addr = current PC + *uptr = pointer to unit + *val = pointer to output values + sw = switches + Outputs: + status = error status +*/ +t_stat parse_sym (CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) +{ + return (-2); +} + +/* end of m6809.c */ +>>>>>>> 033805fd... Richard Lukes - 18 FEB 2024 diff --git a/swtp6809/common/mp-09.c b/swtp6809/common/mp-09.c index 756435c96..1fd0bbda0 100644 --- a/swtp6809/common/mp-09.c +++ b/swtp6809/common/mp-09.c @@ -1,3 +1,4 @@ +<<<<<<< HEAD /* mp-09.c: SWTP MP-09 M6809 CPU simulator Copyright (c) 2011-2012, William Beech @@ -294,3 +295,287 @@ void CPU_BD_put_mword(int32 addr, int32 val) } /* end of mp-09.c */ +======= +/* mp-09.c: SWTP MP-09 M6809 CPU simulator + + Copyright (c) 2011-2012, 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. + + MODIFICATIONS: + + 24 Apr 15 -- Modified to use simh_debug + 20 Feb 24 -- Richard Lukes - modified SWTPC mp-a2 emulator to create mp-09 emulator. + + NOTES: + + The MP-09 CPU Board includes the SWTP Dynamic Address Translation (DAT) logic which + is used to create a 20-bit virtual address space (1MB of RAM). + + The MP-09 CPU Board contains the following devices [mp-09.c]: + M6809 processor [m6809.c]. + SWTPC SBUG-E, or custom boot ROM at top of 16-bit address space [bootrom.c]. + Interface to the SS-50 bus and the MP-B3 Mother Board for I/O + and memory boards [mp-b3.c]. +*/ + +#include +#include "swtp_defs.h" + +#define UNIT_V_USER_D (UNIT_V_UF) /* user defined switch */ +#define UNIT_USER_D (1 << UNIT_V_USER_D) +#define UNIT_V_4K_8K (UNIT_V_UF+1) /* off if HI_PROM and only 2K EPROM */ +#define UNIT_4K_8K (1 << UNIT_V_4K_8K) +#define UNIT_V_SWT (UNIT_V_UF+2) /* on SWTBUG, off MIKBUG */ +#define UNIT_SWT (1 << UNIT_V_SWT) +#define UNIT_V_8K (UNIT_V_UF+3) /* off if HI_PROM and only 2K or 4k EPROM */ +#define UNIT_8K (1 << UNIT_V_8K) +#define UNIT_V_RAM (UNIT_V_UF+4) /* off disables 6810 RAM */ +#define UNIT_RAM (1 << UNIT_V_RAM) +#define UNIT_V_LO_PROM (UNIT_V_UF+5) /* on EPROMS @ C000-CFFFH, off no EPROMS */ +#define UNIT_LO_PROM (1 << UNIT_V_LO_PROM) +#define UNIT_V_HI_PROM (UNIT_V_UF+6) /* on EPROMS @ F000-FFFFH, off fo LO_PROM, MON, or no EPROMS */ +#define UNIT_HI_PROM (1 << UNIT_V_HI_PROM) +#define UNIT_V_MON (UNIT_V_UF+7) /* on for monitor vectors in high memory */ +#define UNIT_MON (1 << UNIT_V_MON) + +/* local global variables */ +unsigned char DAT_RAM[16]; +unsigned char DAT_RAM_CACHE[16]; + +/* function prototypes */ + +t_stat CPU_BD_reset (DEVICE *dptr); +t_stat CPU_BD_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches); +t_stat CPU_BD_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); +int32 DAT_Xlate(int32 logical_addr); +int32 CPU_BD_get_mbyte(int32 addr); +int32 CPU_BD_get_mword(int32 addr); +void CPU_BD_put_mbyte(int32 addr, int32 val); +void CPU_BD_put_mword(int32 addr, int32 val); + +/* external routines */ + +/* MP-B3 bus routines */ +extern int32 MB_get_mbyte(int32 addr); +extern int32 MB_get_mword(int32 addr); +extern void MB_put_mbyte(int32 addr, int32 val); +extern void MB_put_mword(int32 addr, int32 val); + +/* MP-09 data structures + + CPU_BD_dev MP-09 device descriptor + CPU_BD_unit MP-09 unit descriptor + CPU_BD_reg MP-09 register list + CPU_BD_mod MP-09 modifiers list +*/ + +UNIT CPU_BD_unit = { UDATA (NULL, 0, 0) }; + +REG CPU_BD_reg[] = { + { NULL } +}; + +MTAB CPU_BD_mod[] = { + { UNIT_USER_D, UNIT_USER_D, "USER_D", "USER_D", NULL }, + { UNIT_USER_D, 0, "NOUSER_D", "NOUSER_D", NULL }, + { UNIT_4K_8K, UNIT_4K_8K, "4K_8K", "4K_8K", NULL }, + { UNIT_4K_8K, 0, "NO4K_8K", "NO4K_8K", NULL }, + { UNIT_SWT, UNIT_SWT, "SWT", "SWT", NULL }, + { UNIT_SWT, 0, "NOSWT", "NOSWT", NULL }, + { UNIT_8K, UNIT_8K, "8K", "8K", NULL }, + { UNIT_8K, 0, "NO8K", "NO8K", NULL }, + { UNIT_RAM, UNIT_RAM, "RAM", "RAM", NULL }, + { UNIT_RAM, 0, "NORAM", "NORAM", NULL }, + { UNIT_LO_PROM, UNIT_LO_PROM, "LO_PROM", "LO_PROM", NULL }, + { UNIT_LO_PROM, 0, "NOLO_PROM", "NOLO_PROM", NULL }, + { UNIT_HI_PROM, UNIT_HI_PROM, "HI_PROM", "HI_PROM", NULL }, + { UNIT_HI_PROM, 0, "NOHI_PROM", "NOHI_PROM", NULL }, + { UNIT_MON, UNIT_MON, "MON", "MON", NULL }, + { UNIT_MON, 0, "NOMON", "NOMON", NULL }, + { 0 } +}; + +DEBTAB CPU_BD_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE CPU_BD_dev = { + "MP-09", //name + &CPU_BD_unit, //units + CPU_BD_reg, //registers + CPU_BD_mod, //modifiers + 1, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + &CPU_BD_examine, //examine + &CPU_BD_deposit, //deposit + &CPU_BD_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + CPU_BD_debug, /* debflags */ + NULL, //msize + NULL //lname +}; + +/* reset */ +t_stat CPU_BD_reset (DEVICE *dptr) +{ + int32 i; + + // initialize DAT RAM + for (i=0; i<16; i++) { + DAT_RAM[i] = (~i) & 0x0F; + DAT_RAM_CACHE[i] = i; + } + return SCPE_OK; +} + +/* Deposit routine */ +t_stat CPU_BD_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= 0x10000) { + return SCPE_NXM; + } else { + CPU_BD_put_mbyte(addr, val); + return SCPE_OK; + } +} + +/* Examine routine */ +t_stat CPU_BD_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= 0x10000) { + return SCPE_NXM; + } + if (eval_array != NULL) { + *eval_array = CPU_BD_get_mbyte(addr); + } + return SCPE_OK; +} + +/* Perform adress translation from 16-bit logical address to 20-bit physical address using DAT mapping RAM */ +int32 DAT_Xlate(int32 logi_addr) +{ + int32 DAT_index; /* which of the 16 mapping registers to index */ + int32 DAT_byte; /* the lookup value from DAT RAM */ + int32 DAT_block; /* A13-A14-A15-A16 */ + + /* translation from 16-bit logical address to 20-bit physical address */ + DAT_index = (logi_addr & 0xF000) >> 12; + DAT_byte = DAT_RAM_CACHE[DAT_index]; + if (DAT_index >= 0xE) { + /* for logical addresses $E000-$FFFF */ + // Bank address (A17-A20) is 0b0000 + return((logi_addr & 0xFFF) + ((DAT_byte & 0x0F)<<12)); + } else { + // Bank address (A17-A20) is the high order 4-bits of DAT_byte + return((logi_addr & 0xFFF) + (DAT_byte<<12)); + } +} + +/* get a byte from memory */ +int32 CPU_BD_get_mbyte(int32 addr) +{ + int32 val = 0; + int32 phy_addr; + + sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mbyte: addr=%04X\n", addr); + switch(addr & 0xF000) { + case 0xE000: + case 0xF000: + /* ROM is mapped to logical address $E000-$FFFF at all times! Unaffected by DAT */ + val = MB_get_mbyte(addr); + sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mbyte: mp_b3 val=%02X\n", val); + break; + default: + /* access the resources on the motherboard - 16-bit addressing */ + /* 56K of RAM from 0000-DFFF */ + /* 8K of I/O space from E000-EFFF */ + /* 2K of scratchpad RAM from F000-F7FF ??? */ + phy_addr = DAT_Xlate(addr); + val = MB_get_mbyte(phy_addr); + sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mbyte: mp_b3 val=%02X\n", val); + break; + } + return val; +} + +/* get a word from memory */ +int32 CPU_BD_get_mword(int32 addr) +{ + int32 val; + + sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mword: addr=%04X\n", addr); + val = (CPU_BD_get_mbyte(addr) << 8); + val |= CPU_BD_get_mbyte(addr+1); + val &= 0xFFFF; + sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mword: val=%04X\n", val); + return val; +} + +/* put a byte to memory */ +void CPU_BD_put_mbyte(int32 addr, int32 val) +{ + int32 phy_addr; + + sim_debug (DEBUG_write, &CPU_BD_dev, "CPU_BD_put_mbyte: addr=%04X, val=%02X\n", addr, val); + + if ((addr & 0xFFF0) == 0xFFF0) { + DAT_RAM[addr & 0x0F] = val; + DAT_RAM_CACHE[addr & 0x0F] = (val & 0xF0) | (~val & 0x0F); + } else { + switch(addr & 0xF800) { + case 0xF800: + /* do not write to ROM area */ + break; + default: + phy_addr = DAT_Xlate(addr); + MB_put_mbyte(phy_addr, val); + break; + } + } +} + +/* put a word to memory */ +void CPU_BD_put_mword(int32 addr, int32 val) +{ + sim_debug (DEBUG_write, &CPU_BD_dev, "CPU_BD_put_mword: addr=%04X, val=%04X\n", addr, val); + CPU_BD_put_mbyte(addr, val >> 8); + CPU_BD_put_mbyte(addr+1, val & 0xFF); +} + +/* end of mp-09.c */ +>>>>>>> 033805fd... Richard Lukes - 18 FEB 2024 diff --git a/swtp6809/common/mp-1m.c b/swtp6809/common/mp-1m.c index 2560d6375..2b7913df9 100644 --- a/swtp6809/common/mp-1m.c +++ b/swtp6809/common/mp-1m.c @@ -1,3 +1,4 @@ +<<<<<<< HEAD /* mp-1m.c: SWTP 1M Byte Memory Card emulator Copyright (c) 2011-2012, William A. Beech @@ -309,3 +310,223 @@ void mp_1m_put_mword(int32 addr, int32 val) } /* end of mp-1m.c */ +======= +/* mp-1m.c: SWTP 1M Byte Memory Card emulator + + Copyright (c) 2011-2012, William A. 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 O + 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. + + MODIFICATIONS: + + 24 Apr 15 -- Modified to use simh_debug + 20 Feb 24 -- Richard Lukes - Modified mp-8m.c to use for 1MB memory for swtp6809 emulator + + NOTES: + + These functions support 1MB of memory on an SS-50 system as a single 1MB memory card. + Due to the way DAT works, the upper 8KB of each 64KB address space is allocated to I/O ($E000) and ROM ($F000) space. + Therefore, the maximum usable RAM is 16 x 56KB = 896KB. + + The unit uses a statically allocated 1MB byte buffer. This makes for a fast implementation. + No effort was made to make available memory variable in size (e.g. limit to only 32KB, 64KB, 96KB, 128KB, etc.). +*/ + +#include +#include "swtp_defs.h" + +/* there is only one of these devices */ +#define ONE_MEGABYTE 0x100000 + +/* prototypes */ + +t_stat mp_1m_reset (DEVICE *dptr); +t_stat mp_1m_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches); +t_stat mp_1m_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); +int32 mp_1m_get_mbyte(int32 addr); +int32 mp_1m_get_mword(int32 addr); +void mp_1m_put_mbyte(int32 addr, int32 val); +void mp_1m_put_mword(int32 addr, int32 val); + +/* isbc064 Standard I/O Data Structures */ + +UNIT mp_1m_unit = { + UDATA (NULL, UNIT_FIX + UNIT_BINK, ONE_MEGABYTE) +}; + +MTAB mp_1m_mod[] = { + { 0 } +}; + +DEBTAB mp_1m_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE mp_1m_dev = { + "MP-1M", //name + &mp_1m_unit, //units + NULL, //registers + mp_1m_mod, //modifiers + 1, //numunits + 16, //aradix + 20, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + &mp_1m_examine, //examine + &mp_1m_deposit, //deposit + &mp_1m_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + mp_1m_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* Pre-allocate 1MB array of bytes */ +uint8 mp_1m_ram_memory_array[ONE_MEGABYTE]; + +/* Deposit routine */ +t_stat mp_1m_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= ONE_MEGABYTE) { + return SCPE_NXM; + } else { + mp_1m_ram_memory_array[addr] = val & 0xFF; + return SCPE_OK; + } +} + +/* Examine routine */ +t_stat mp_1m_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= ONE_MEGABYTE) { + return SCPE_NXM; + } + if (eval_array != NULL) { + *eval_array = mp_1m_ram_memory_array[addr]; + } + return SCPE_OK; +} + +/* Reset routine */ + +t_stat mp_1m_reset (DEVICE *dptr) +{ + int32 i, j, val; + UNIT *uptr; + + sim_debug (DEBUG_flow, &mp_1m_dev, "mp_1m_reset: \n"); + uptr = mp_1m_dev.units; + sim_debug (DEBUG_flow, &mp_1m_dev, "MP-1M %d unit.flags=%08X\n", i, uptr->flags); + + // capacity + uptr->capac = ONE_MEGABYTE; + // starting address + uptr->u3 = 0; + + if (uptr->filebuf == NULL) { + uptr->filebuf = &mp_1m_ram_memory_array; + if (uptr->filebuf == NULL) { + printf("mp_1m_reset: Malloc error\n"); + return SCPE_MEM; + } + for (j=0; j < uptr->capac; j++) { /* populate memory with fill pattern */ + i = j & 0xF; + val = (0xA0 | i) & 0xFF; + *((uint8 *)(uptr->filebuf) + j) = val; + } + sim_debug (DEBUG_flow, &mp_1m_dev, "MP-1M %d initialized at [%05X-%05XH]\n", i, uptr->u3, uptr->u3 + uptr->capac - 1); + } + sim_debug (DEBUG_flow, &mp_1m_dev, "mp_1m_reset: Done\n"); + return SCPE_OK; +} + +/* + I/O instruction handlers, called from the mp-b3 module when an + external memory read or write is issued. +*/ + +/* get a byte from memory */ + +int32 mp_1m_get_mbyte(int32 addr) +{ + //UNIT *uptr; + int32 val; + + //uptr = mp_1m_dev.units; + sim_debug (DEBUG_read, &mp_1m_dev, "mp_1m_get_mbyte: addr=%05X", addr); + if (addr >= ONE_MEGABYTE) { + sim_debug (DEBUG_read, &mp_1m_dev, "mp_1m_get_mbyte: addr=%08X Out of range\n", addr); + return 0xFF; + } else { + val = mp_1m_ram_memory_array[addr]; + sim_debug (DEBUG_read, &mp_1m_dev, " addr=%05x val=%02X\n", addr, val); + return val; + } +} + +/* get a word from memory */ + +int32 mp_1m_get_mword(int32 addr) +{ + int32 val; + + val = (mp_1m_get_mbyte(addr) << 8); + val |= mp_1m_get_mbyte(addr+1); + return val; +} + +/* put a byte into memory */ + +void mp_1m_put_mbyte(int32 addr, int32 val) +{ + sim_debug (DEBUG_write, &mp_1m_dev, "mp_1m_put_mbyte: addr=%05X, val=%02X", addr, val); + + if (addr >= ONE_MEGABYTE) { + sim_debug (DEBUG_write, &mp_1m_dev, "mp_1m_put_mbyte: Address out of range, addr=%08x\n", addr); + } else { + mp_1m_ram_memory_array[addr] = val; + sim_debug (DEBUG_write, &mp_1m_dev, "\n"); + } +} + +/* put a word into memory */ + +void mp_1m_put_mword(int32 addr, int32 val) +{ + mp_1m_put_mbyte(addr, val >> 8); + mp_1m_put_mbyte(addr+1, val & 0xFF); +} + +/* end of mp-1m.c */ +>>>>>>> 033805fd... Richard Lukes - 18 FEB 2024 diff --git a/swtp6809/common/mp-b3.c b/swtp6809/common/mp-b3.c index 244251b31..4422546cb 100644 --- a/swtp6809/common/mp-b3.c +++ b/swtp6809/common/mp-b3.c @@ -1,3 +1,4 @@ +<<<<<<< HEAD /* mp-b3.c: SWTP SS-50/SS-30 MP-B3 Mother Board Copyright (c) 2011-2012, William A. Beech @@ -306,3 +307,295 @@ void MB_put_mword(int32 addr, int32 val) } /* end of mp-b3.c */ +======= +/* mp-b3.c: SWTP SS-50/SS-30 MP-B3 Mother Board + + Copyright (c) 2011-2012, William A. 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. + + MODIFICATIONS: + + 24 Apr 15 -- Modified to use simh_debug + 20 Feb 24 -- Richard Lukes - Modified to emulate MP-B3 motherboard for swtp6809 emulator + + NOTES: + +*/ + +#include +#include "swtp_defs.h" + + +#define UNIT_V_RAM_1MB (UNIT_V_UF) /* MP-1M board enable */ +#define UNIT_RAM_1MB (1 << UNIT_V_RAM_1MB) + +/* function prototypes */ + +/* empty I/O device routine */ +int32 nulldev(int32 io, int32 data); + +/* SS-50 bus routines */ +t_stat MB_reset (DEVICE *dptr); +t_stat MB_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches); +t_stat MB_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); +int32 MB_get_mbyte(int32 addr); +int32 MB_get_mword(int32 addr); +void MB_put_mbyte(int32 addr, int32 val); +void MB_put_mword(int32 addr, int32 val); + +/* BOOTROM memory access routines */ +extern int32 BOOTROM_get_mbyte(int32 offset); + +/* MP-1M memory access routines */ +extern int32 mp_1m_get_mbyte(int32 addr); +extern void mp_1m_put_mbyte(int32 addr, int32 val); + +/* SS-50 I/O address space functions */ + +/* MP-S serial I/O 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); + +/* DC-4 FDC I/O routines */ +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); + +/* +MP-B3 configured with 4 address per SS-30 slot (x8). + +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] = { + {&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /* Port 0 E000-E003 */ + {&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /* Port 1 E004-E007 */ +/* 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 E008-E00B */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* Port 3 E00C-E00F */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* Port 4 E010-E013 */ + {&fdcdrv}, {&nulldev}, {&nulldev}, {&nulldev}, /* Port 5 E014-E017 */ + {&fdccmd}, {&fdctrk}, {&fdcsec}, {&fdcdata}, /* Port 6 E018-E01B */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev} /* Port 7 E01C-E01F */ +}; + +/* dummy i/o device */ + +int32 nulldev(int32 io, int32 data) +{ + if (io == 0) { + return (0xFF); + } else { + return 0; + } +} + +/* Mother Board data structures + + MB_dev Mother Board device descriptor + MB_unit Mother Board unit descriptor + MB_reg Mother Board register list + MB_mod Mother Board modifiers list +*/ + +UNIT MB_unit = { + UDATA (NULL, 0, 0) +}; + +REG MB_reg[] = { + { NULL } +}; + +MTAB MB_mod[] = { + { UNIT_RAM_1MB, UNIT_RAM_1MB, "1MB On", "1MB", NULL, NULL }, + { UNIT_RAM_1MB, 0, "1MB Off", "NO1MB", NULL, NULL }, + { 0 } +}; + +DEBTAB MB_debug[] = { + { "ALL", DEBUG_all }, + { "FLOW", DEBUG_flow }, + { "READ", DEBUG_read }, + { "WRITE", DEBUG_write }, + { "LEV1", DEBUG_level1 }, + { "LEV2", DEBUG_level2 }, + { NULL } +}; + +DEVICE MB_dev = { + "MP-B3", //name + &MB_unit, //units + MB_reg, //registers + MB_mod, //modifiers + 1, //numunits + 16, //aradix + 20, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + &MB_examine, //examine + &MB_deposit, //deposit + &MB_reset, //reset + NULL, //boot + NULL, //attach + NULL, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + MB_debug, /* debflags */ + NULL, //msize + NULL //lname +}; + +/* reset */ +t_stat MB_reset (DEVICE *dptr) +{ + return SCPE_OK; +} + +/* Deposit routine */ +t_stat MB_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= 0x100000) { + /* exceed 20-bit address space */ + return SCPE_NXM; + } else { + MB_put_mbyte(addr, val); + return SCPE_OK; + } +} + +/* Examine routine */ +t_stat MB_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) +{ + if (addr >= 0x100000) { + return SCPE_NXM; + } + if (eval_array != NULL) { + *eval_array = MB_get_mbyte(addr); + } + return SCPE_OK; +} + +/* get a byte from memory */ + +int32 MB_get_mbyte(int32 addr) +{ + int32 val; + + // 20-bit physical addresses + sim_debug (DEBUG_read, &MB_dev, "MB_get_mbyte: addr=%05X\n", addr); + switch (addr & 0x0F800) { + case 0x0E000: + /* reserved I/O space from $E000-$E01F */ + if ((addr & 0xFFFF) < 0xE020) { + val = (dev_table[(addr & 0xFFFF) - 0xE000].routine(0, 0)) & 0xFF; + break; + } + case 0x0E800: + case 0x0F000: + case 0x0F800: + /* Up to 8KB of boot ROM from $E000-$FFFF */ + val = BOOTROM_get_mbyte(addr & 0xFFFF); + sim_debug (DEBUG_read, &MB_dev, "MB_get_mbyte: EPROM=%02X\n", val); + break; + default: + /* all the rest is RAM */ + if (MB_unit.flags & UNIT_RAM_1MB) { + val = mp_1m_get_mbyte(addr); + if (MB_dev.dctrl & DEBUG_read) { + printf("MB_get_mbyte: mp_1m add=%05x val=%02X\n", addr, val); + } + } else { + ; // No RAM configured at this addresS + } + break; + } + sim_debug (DEBUG_read, &MB_dev, "MB_get_mbyte: I/O addr=%05X val=%02X\n", addr, val); + return val; +} + +/* get a word from memory */ + +int32 MB_get_mword(int32 addr) +{ + int32 val; + + sim_debug (DEBUG_read, &MB_dev, "MB_get_mword: addr=%04X\n", addr); + val = (MB_get_mbyte(addr) << 8); + val |= MB_get_mbyte(addr+1); + val &= 0xFFFF; + sim_debug (DEBUG_read, &MB_dev, "MB_get_mword: val=%04X\n", val); + return val; +} + +/* put a byte to memory */ + +void MB_put_mbyte(int32 addr, int32 val) +{ + // 20-bit physical addresses + sim_debug (DEBUG_write, &MB_dev, "MB_put_mbyte: addr=%05X, val=%02X\n", addr, val); + + switch(addr & 0xF000) { + case 0xE000: + /* I/O space */ + if ((addr & 0xFFFF) < 0xE020) { + dev_table[(addr & 0xFFFF) - 0xE000].routine(1, val); + } + break; + case 0xF000: + /* ROM space */ + break; + default: + /* RAM */ + if (MB_unit.flags & UNIT_RAM_1MB) { + mp_1m_put_mbyte(addr, val); + } else { + ; // No RAM conigured at this address + } + break; + } +} + +/* put a word to memory */ + +void MB_put_mword(int32 addr, int32 val) +{ + sim_debug (DEBUG_write, &MB_dev, "MB_ptt_mword: addr=%04X, val=%04X\n", addr, val); + MB_put_mbyte(addr, val >> 8); + MB_put_mbyte(addr+1, val & 0xFF); +} + +/* end of mp-b3.c */ +>>>>>>> 033805fd... Richard Lukes - 18 FEB 2024 diff --git a/swtp6809/swtp6809/mp-09_sys.c b/swtp6809/swtp6809/mp-09_sys.c index 3c0f79298..c4fab1253 100644 --- a/swtp6809/swtp6809/mp-09_sys.c +++ b/swtp6809/swtp6809/mp-09_sys.c @@ -1,3 +1,4 @@ +<<<<<<< HEAD /* mp09_sys.c: SWTP 6809 system interface Copyright (c) 2005-2012, William Beech @@ -113,3 +114,94 @@ const char *sim_stop_messages[] = { }; /* end of mp09_sys.c */ +======= +/* mp09_sys.c: SWTP 6809 system interface + + Copyright (c) 2005-2012, 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. + + MODIFICATIONS + + 20 Feb 24 -- Richard Lukes - Modified mp-a2_sys.c for SWTP MP-09 emulation +*/ + +#include +#include +#include "swtp_defs.h" + +/* externals */ + +extern DEVICE CPU_BD_dev; +extern DEVICE m6809_dev; +extern REG m6809_reg[]; +extern DEVICE BOOTROM_dev; + +extern DEVICE MB_dev; +extern DEVICE sio_dev; +extern DEVICE ptr_dev; +extern DEVICE ptp_dev; +extern DEVICE mp_1m_dev; +extern DEVICE dsk_dev; + +/* SCP data structures + + sim_name simulator name string + sim_PC pointer to saved PC register descriptor + sim_emax number of words needed for examine + sim_devices array of pointers to simulated devices + sim_stop_messages array of pointers to stop messages + sim_load binary loader +*/ + +char sim_name[] = "SWTP 6809, V0.7, MP-09 CPU Board"; + +REG *sim_PC = &m6809_reg[0]; + +// maximum number of words needed for examine +int32 sim_emax = 4; + +DEVICE *sim_devices[] = { + &m6809_dev, + &CPU_BD_dev, + &BOOTROM_dev, + &MB_dev, + &sio_dev, + &ptr_dev, + &ptp_dev, + &mp_1m_dev, + &dsk_dev, + NULL +}; + +const char *sim_stop_messages[] = { + "Unknown error", + "RESERVED", + "Halt instruction", + "Breakpoint" + "Invalid opcode", + "Invalid memory", + "Unknown error" +}; + +/* end of mp09_sys.c */ +>>>>>>> 033805fd... Richard Lukes - 18 FEB 2024 diff --git a/swtp6809/swtp6809/swtp6809mp-09.ini b/swtp6809/swtp6809/swtp6809mp-09.ini index 8a33ff309..7da6c18bb 100644 --- a/swtp6809/swtp6809/swtp6809mp-09.ini +++ b/swtp6809/swtp6809/swtp6809mp-09.ini @@ -1,3 +1,5 @@ +<<<<<<< HEAD +<<<<<<< HEAD reset set mp-09 DAT set mp-1m 1MB @@ -11,3 +13,33 @@ attach bootrom sbuge.bin attach dc-40 FULL.DSK attach dc-41 FULL2.DSK boot cpu +======= +set bootrom debug +set bootrom 2716 +attach bootrom sbuge.bin +======= +reset +>>>>>>> 6d7bebf2... In preparation of presenting for contribution as a "pull request". +set mp-b3 1MB +set cpu hex +set cpu itrap +set cpu mtrap +set dc-40 RO +<<<<<<< HEAD +;attach dc-41 FULL2.DSK +;set dc-41 RO +;attach dc-42 FULL3.DSK +;set dc-42 RO +;attach dc-43 FULL4.DSK +;set dc-43 RW +reset +>>>>>>> 033805fd... Richard Lukes - 18 FEB 2024 +======= +set dc-41 RO +set mp-s TTY +set bootrom 2716 +attach bootrom sbuge.bin +attach dc-40 FULL.DSK +attach dc-41 FULL2.DSK +boot cpu +>>>>>>> 6d7bebf2... In preparation of presenting for contribution as a "pull request". diff --git a/swtp6809/swtp6809/swtp_defs.h b/swtp6809/swtp6809/swtp_defs.h index 6b91e4629..f1f7e2bc4 100644 --- a/swtp6809/swtp6809/swtp_defs.h +++ b/swtp6809/swtp6809/swtp_defs.h @@ -1,3 +1,4 @@ +<<<<<<< HEAD /* swtp_defs.h: SWTP 6809 simulator definitions Copyright (c) 2005-2012, William Beech @@ -62,3 +63,69 @@ #define STOP_OPCODE 4 // invalid opcode #define STOP_MEMORY 5 // invalid memory address +======= +/* swtp_defs.h: SWTP 6809 simulator definitions + + Copyright (c) 2005-2012, 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 SHAL + 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 I + 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. + + MODIFICATIONS + + 20 Feb 24 - Richard Lukes - Modified for swtp6809 emulator +*/ + +#include +#include "sim_defs.h" // simulator defs + +/* Rename of global PC variable to avoid namespace conflicts on some platforms */ + +#define PC PC_Global + +/* Memory */ + +#define MAXMEMSIZE 65536 // max memory size +#define MEMSIZE (m6809_unit.capac) // actual memory size +#define ADDRMASK (MAXMEMSIZE - 1) // address mask +#define BYTEMASK 0xFF +#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) + +/* debug definitions */ + +#define DEBUG_flow 0x0001 +#define DEBUG_read 0x0002 +#define DEBUG_write 0x0004 +#define DEBUG_level1 0x0008 +#define DEBUG_level2 0x0010 +#define DEBUG_reg 0x0020 +#define DEBUG_asm 0x0040 +#define DEBUG_all 0xFFFF + +/* Simulator stop codes */ + +#define STOP_RSRV 1 // must be 1 +#define STOP_HALT 2 // HALT-really WAI +#define STOP_IBKPT 3 // breakpoint +#define STOP_OPCODE 4 // invalid opcode +#define STOP_MEMORY 5 // invalid memory address + +>>>>>>> 033805fd... Richard Lukes - 18 FEB 2024 From a1af415b1359fbf385f45f80b99206ebbdf2e743 Mon Sep 17 00:00:00 2001 From: rfromafar Date: Sun, 25 Feb 2024 11:05:41 -0600 Subject: [PATCH 07/10] swtp6809: simulator being contributed to open-simh project #357 (Pull Request) --- swtp6809/common/bootrom.c | 6 ++++++ swtp6809/common/dc-4.c | 6 ++++++ swtp6809/common/m6809.c | 6 ++++++ swtp6809/common/mp-09.c | 6 ++++++ swtp6809/common/mp-1m.c | 6 ++++++ swtp6809/common/mp-b3.c | 6 ++++++ swtp6809/swtp6809/mp-09_sys.c | 6 ++++++ swtp6809/swtp6809/swtp6809mp-09.ini | 6 ++++++ swtp6809/swtp6809/swtp_defs.h | 6 ++++++ 9 files changed, 54 insertions(+) diff --git a/swtp6809/common/bootrom.c b/swtp6809/common/bootrom.c index 02c378490..cdbc24a26 100644 --- a/swtp6809/common/bootrom.c +++ b/swtp6809/common/bootrom.c @@ -1,4 +1,7 @@ <<<<<<< HEAD +<<<<<<< HEAD +======= +>>>>>>> b50c876f... swtp6809 simulator being contributed to open-simh project #357 (Pull Request) /* bootrom.c: Boot ROM simulator for Motorola processors Copyright (c) 2010-2012, William A. Beech @@ -342,6 +345,7 @@ int32 BOOTROM_get_mbyte(int32 address) } /* BOOTROM_get_mbyte() */ /* end of bootrom.c */ +<<<<<<< HEAD ======= /* bootrom.c: Boot ROM simulator for Motorola processors @@ -659,3 +663,5 @@ int32 BOOTROM_get_mbyte(int32 address) /* end of bootrom.c */ >>>>>>> 033805fd... Richard Lukes - 18 FEB 2024 +======= +>>>>>>> b50c876f... swtp6809 simulator being contributed to open-simh project #357 (Pull Request) diff --git a/swtp6809/common/dc-4.c b/swtp6809/common/dc-4.c index d64b33ec1..f9e2e412c 100644 --- a/swtp6809/common/dc-4.c +++ b/swtp6809/common/dc-4.c @@ -1,4 +1,7 @@ <<<<<<< HEAD +<<<<<<< HEAD +======= +>>>>>>> b50c876f... swtp6809 simulator being contributed to open-simh project #357 (Pull Request) /* dc4.c: SWTP DC-4 FDC Simulator Copyright (c) 2005-2012, William A. Beech @@ -650,6 +653,7 @@ int32 fdcdata(int32 io, int32 data) } /* end of dc-4.c */ +<<<<<<< HEAD ======= /* dc4.c: SWTP DC-4 FDC Simulator @@ -1303,3 +1307,5 @@ int32 fdcdata(int32 io, int32 data) /* end of dc-4.c */ >>>>>>> 033805fd... Richard Lukes - 18 FEB 2024 +======= +>>>>>>> b50c876f... swtp6809 simulator being contributed to open-simh project #357 (Pull Request) diff --git a/swtp6809/common/m6809.c b/swtp6809/common/m6809.c index f3f11322a..464b5f3cc 100644 --- a/swtp6809/common/m6809.c +++ b/swtp6809/common/m6809.c @@ -1,4 +1,7 @@ <<<<<<< HEAD +<<<<<<< HEAD +======= +>>>>>>> b50c876f... swtp6809 simulator being contributed to open-simh project #357 (Pull Request) /* 6809.c: SWTP 6809 CPU simulator Copyright (c) 2005-2012, William Beech @@ -3412,6 +3415,7 @@ t_stat parse_sym (CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 } /* end of m6809.c */ +<<<<<<< HEAD ======= /* 6809.c: SWTP 6809 CPU simulator @@ -6805,3 +6809,5 @@ t_stat parse_sym (CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 /* end of m6809.c */ >>>>>>> 033805fd... Richard Lukes - 18 FEB 2024 +======= +>>>>>>> b50c876f... swtp6809 simulator being contributed to open-simh project #357 (Pull Request) diff --git a/swtp6809/common/mp-09.c b/swtp6809/common/mp-09.c index 1fd0bbda0..4247252f6 100644 --- a/swtp6809/common/mp-09.c +++ b/swtp6809/common/mp-09.c @@ -1,4 +1,7 @@ <<<<<<< HEAD +<<<<<<< HEAD +======= +>>>>>>> b50c876f... swtp6809 simulator being contributed to open-simh project #357 (Pull Request) /* mp-09.c: SWTP MP-09 M6809 CPU simulator Copyright (c) 2011-2012, William Beech @@ -295,6 +298,7 @@ void CPU_BD_put_mword(int32 addr, int32 val) } /* end of mp-09.c */ +<<<<<<< HEAD ======= /* mp-09.c: SWTP MP-09 M6809 CPU simulator @@ -579,3 +583,5 @@ void CPU_BD_put_mword(int32 addr, int32 val) /* end of mp-09.c */ >>>>>>> 033805fd... Richard Lukes - 18 FEB 2024 +======= +>>>>>>> b50c876f... swtp6809 simulator being contributed to open-simh project #357 (Pull Request) diff --git a/swtp6809/common/mp-1m.c b/swtp6809/common/mp-1m.c index 2b7913df9..2df8b48ad 100644 --- a/swtp6809/common/mp-1m.c +++ b/swtp6809/common/mp-1m.c @@ -1,4 +1,7 @@ <<<<<<< HEAD +<<<<<<< HEAD +======= +>>>>>>> b50c876f... swtp6809 simulator being contributed to open-simh project #357 (Pull Request) /* mp-1m.c: SWTP 1M Byte Memory Card emulator Copyright (c) 2011-2012, William A. Beech @@ -310,6 +313,7 @@ void mp_1m_put_mword(int32 addr, int32 val) } /* end of mp-1m.c */ +<<<<<<< HEAD ======= /* mp-1m.c: SWTP 1M Byte Memory Card emulator @@ -530,3 +534,5 @@ void mp_1m_put_mword(int32 addr, int32 val) /* end of mp-1m.c */ >>>>>>> 033805fd... Richard Lukes - 18 FEB 2024 +======= +>>>>>>> b50c876f... swtp6809 simulator being contributed to open-simh project #357 (Pull Request) diff --git a/swtp6809/common/mp-b3.c b/swtp6809/common/mp-b3.c index 4422546cb..df7b8dd56 100644 --- a/swtp6809/common/mp-b3.c +++ b/swtp6809/common/mp-b3.c @@ -1,4 +1,7 @@ <<<<<<< HEAD +<<<<<<< HEAD +======= +>>>>>>> b50c876f... swtp6809 simulator being contributed to open-simh project #357 (Pull Request) /* mp-b3.c: SWTP SS-50/SS-30 MP-B3 Mother Board Copyright (c) 2011-2012, William A. Beech @@ -307,6 +310,7 @@ void MB_put_mword(int32 addr, int32 val) } /* end of mp-b3.c */ +<<<<<<< HEAD ======= /* mp-b3.c: SWTP SS-50/SS-30 MP-B3 Mother Board @@ -599,3 +603,5 @@ void MB_put_mword(int32 addr, int32 val) /* end of mp-b3.c */ >>>>>>> 033805fd... Richard Lukes - 18 FEB 2024 +======= +>>>>>>> b50c876f... swtp6809 simulator being contributed to open-simh project #357 (Pull Request) diff --git a/swtp6809/swtp6809/mp-09_sys.c b/swtp6809/swtp6809/mp-09_sys.c index c4fab1253..cd404d6a5 100644 --- a/swtp6809/swtp6809/mp-09_sys.c +++ b/swtp6809/swtp6809/mp-09_sys.c @@ -1,4 +1,7 @@ <<<<<<< HEAD +<<<<<<< HEAD +======= +>>>>>>> b50c876f... swtp6809 simulator being contributed to open-simh project #357 (Pull Request) /* mp09_sys.c: SWTP 6809 system interface Copyright (c) 2005-2012, William Beech @@ -114,6 +117,7 @@ const char *sim_stop_messages[] = { }; /* end of mp09_sys.c */ +<<<<<<< HEAD ======= /* mp09_sys.c: SWTP 6809 system interface @@ -205,3 +209,5 @@ const char *sim_stop_messages[] = { /* end of mp09_sys.c */ >>>>>>> 033805fd... Richard Lukes - 18 FEB 2024 +======= +>>>>>>> b50c876f... swtp6809 simulator being contributed to open-simh project #357 (Pull Request) diff --git a/swtp6809/swtp6809/swtp6809mp-09.ini b/swtp6809/swtp6809/swtp6809mp-09.ini index 7da6c18bb..35827d544 100644 --- a/swtp6809/swtp6809/swtp6809mp-09.ini +++ b/swtp6809/swtp6809/swtp6809mp-09.ini @@ -1,5 +1,8 @@ <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD +======= +>>>>>>> b50c876f... swtp6809 simulator being contributed to open-simh project #357 (Pull Request) reset set mp-09 DAT set mp-1m 1MB @@ -13,6 +16,7 @@ attach bootrom sbuge.bin attach dc-40 FULL.DSK attach dc-41 FULL2.DSK boot cpu +<<<<<<< HEAD ======= set bootrom debug set bootrom 2716 @@ -43,3 +47,5 @@ attach dc-40 FULL.DSK attach dc-41 FULL2.DSK boot cpu >>>>>>> 6d7bebf2... In preparation of presenting for contribution as a "pull request". +======= +>>>>>>> b50c876f... swtp6809 simulator being contributed to open-simh project #357 (Pull Request) diff --git a/swtp6809/swtp6809/swtp_defs.h b/swtp6809/swtp6809/swtp_defs.h index f1f7e2bc4..773071888 100644 --- a/swtp6809/swtp6809/swtp_defs.h +++ b/swtp6809/swtp6809/swtp_defs.h @@ -1,4 +1,7 @@ <<<<<<< HEAD +<<<<<<< HEAD +======= +>>>>>>> b50c876f... swtp6809 simulator being contributed to open-simh project #357 (Pull Request) /* swtp_defs.h: SWTP 6809 simulator definitions Copyright (c) 2005-2012, William Beech @@ -63,6 +66,7 @@ #define STOP_OPCODE 4 // invalid opcode #define STOP_MEMORY 5 // invalid memory address +<<<<<<< HEAD ======= /* swtp_defs.h: SWTP 6809 simulator definitions @@ -129,3 +133,5 @@ #define STOP_MEMORY 5 // invalid memory address >>>>>>> 033805fd... Richard Lukes - 18 FEB 2024 +======= +>>>>>>> b50c876f... swtp6809 simulator being contributed to open-simh project #357 (Pull Request) From 6fe18812141498f24dda5b34337c9222e67d087f Mon Sep 17 00:00:00 2001 From: Richard Lukes Date: Wed, 3 Apr 2024 20:25:19 -0500 Subject: [PATCH 08/10] Add files via upload swtp6809: updated documentation after numerous bug fixes and enhancements to swtp6809 simulator --- doc/swtp6809_doc.doc | Bin 0 -> 182272 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/swtp6809_doc.doc diff --git a/doc/swtp6809_doc.doc b/doc/swtp6809_doc.doc new file mode 100644 index 0000000000000000000000000000000000000000..101dbc8281fac5833ffdb265a02a03844280b3e4 GIT binary patch literal 182272 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∈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 literal 0 HcmV?d00001 From 06638ce8469c24ca2c81219a25bb695674f9a53a Mon Sep 17 00:00:00 2001 From: rfromafar Date: Wed, 3 Apr 2024 21:02:59 -0500 Subject: [PATCH 09/10] swtp6809: numerous bug fixes and enhanced features. Updated doc file. --- makefile | 2 +- swtp6809/common/bootrom.c | 69 +- swtp6809/common/dc-4.c | 758 +++++++++++++++------- swtp6809/common/m6809.c | 944 +++++++++++++++++----------- swtp6809/common/mp-09.c | 8 +- swtp6809/common/mp-1m.c | 4 +- swtp6809/common/mp-b3.c | 86 ++- swtp6809/swtp6809/mp-09_sys.c | 14 +- swtp6809/swtp6809/swtp6809mp-09.ini | 33 +- swtp6809/swtp6809/swtp_defs.h | 15 +- 10 files changed, 1236 insertions(+), 697 deletions(-) diff --git a/makefile b/makefile index 2236c2af0..87f8a5304 100644 --- a/makefile +++ b/makefile @@ -2759,7 +2759,7 @@ swtp6809mp-09 : ${BIN}swtp6809mp-09${EXE} ${BIN}swtp6809mp-09${EXE} : ${SWTP6809MP-09} ${SIM} ${BUILD_ROMS} ${MKDIRBIN} ${CC} ${SWTP6809MP-09} ${SIM} ${SWTP6809_OPT} ${CC_OUTSPEC} ${LDFLAGS} -ifneq (,$(call find_test,${SWTP6800D},swtp6800mp-a2)) +ifneq (,$(call find_test,${SWTP6809D},swtp6809mp-09)) $@ $(call find_test,${SWTP6809D},swtp6800mp-09) ${TEST_ARG} endif diff --git a/swtp6809/common/bootrom.c b/swtp6809/common/bootrom.c index 401f8c9a4..47a0dda1c 100644 --- a/swtp6809/common/bootrom.c +++ b/swtp6809/common/bootrom.c @@ -52,7 +52,7 @@ MODIFICATIONS: 23 Apr 15 -- Modified to use simh_debug - 24 Feb 24 -- Richard Lukes - Modified for swtp6809 emulator + 04 Apr 24 -- Richard Lukes - Modified for swtp6809 emulator NOTES: @@ -76,14 +76,14 @@ #include #include "swtp_defs.h" -#define UNIT_V_MSIZE (UNIT_V_UF) /* ROM Size */ +#define UNIT_V_MSIZE (UNIT_V_UF + 0) /* ROM Size */ #define UNIT_MSIZE (0x2F << UNIT_V_MSIZE) -#define UNIT_NONE (0x1 << UNIT_V_MSIZE) /* No EPROM */ -#define UNIT_2704 (0x2 << UNIT_V_MSIZE) /* 2704 mode */ -#define UNIT_2708 (0x4 << UNIT_V_MSIZE) /* 2708 mode */ -#define UNIT_2716 (0x8 << UNIT_V_MSIZE) /* 2716 mode */ -#define UNIT_2732 (0x10 << UNIT_V_MSIZE) /* 2732 mode */ -#define UNIT_2764 (0x20 << UNIT_V_MSIZE) /* 2764 mode */ +#define UNIT_NONE (0 << UNIT_V_MSIZE) /* No EPROM */ +#define UNIT_2704 (1 << UNIT_V_MSIZE) /* 2704 mode */ +#define UNIT_2708 (2 << UNIT_V_MSIZE) /* 2708 mode */ +#define UNIT_2716 (3 << UNIT_V_MSIZE) /* 2716 mode */ +#define UNIT_2732 (4 << UNIT_V_MSIZE) /* 2732 mode */ +#define UNIT_2764 (5 << UNIT_V_MSIZE) /* 2764 mode */ /* Maximum size of bootrom is 8KB from $E000-$FFFF */ #define MAX_BOOTROM_SIZE (8*1024) @@ -107,7 +107,7 @@ UNIT BOOTROM_unit = { KBD_POLL_WAIT }; MTAB BOOTROM_mod[] = { - { UNIT_MSIZE, UNIT_NONE, "None", "NONE", &BOOTROM_config }, + { UNIT_MSIZE, UNIT_NONE, "NONE", "NONE", &BOOTROM_config }, { UNIT_MSIZE, UNIT_2704, "2704", "2704", &BOOTROM_config }, { UNIT_MSIZE, UNIT_2708, "2708", "2708", &BOOTROM_config }, { UNIT_MSIZE, UNIT_2716, "2716", "2716", &BOOTROM_config }, @@ -117,12 +117,12 @@ MTAB BOOTROM_mod[] = { }; DEBTAB BOOTROM_debug[] = { - { "ALL", DEBUG_all }, - { "FLOW", DEBUG_flow }, - { "READ", DEBUG_read }, - { "WRITE", DEBUG_write }, - { "LEV1", DEBUG_level1 }, - { "LEV2", DEBUG_level2 }, + { "ALL", DEBUG_all, "Debug all"}, + { "FLOW", DEBUG_flow, "Debug flow of control" }, + { "READ", DEBUG_read, "Debug device reads" }, + { "WRITE", DEBUG_write, "Debug device writes" }, + { "LEV1", DEBUG_level1, "Debug level 1" }, + { "LEV2", DEBUG_level2, "Debug level 2" }, { NULL } }; @@ -148,7 +148,10 @@ DEVICE BOOTROM_dev = { 0, /* dctrl */ BOOTROM_debug, /* debflags */ NULL, /* msize */ - NULL /* lname */ + NULL, /* help */ + NULL, /* attach help */ + NULL, /* help context */ + NULL /* device description */ }; /* global variables */ @@ -163,11 +166,13 @@ uint8 BOOTROM_memory[MAX_BOOTROM_SIZE]; /* BOOTROM_examine routine */ t_stat BOOTROM_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) { - if (addr >= BOOTROM_unit.capac || addr >= MAX_BOOTROM_SIZE) { + sim_debug(DEBUG_flow, &BOOTROM_dev, "BOOTROM_examine: addr=%08x\n", addr); + + if (addr >= uptr->capac || addr >= MAX_BOOTROM_SIZE) { return SCPE_NXM; } if (eval_array != NULL) { - *eval_array = BOOTROM_memory[addr]; + *eval_array = BOOTROM_memory[addr]; } return SCPE_OK; @@ -191,9 +196,9 @@ t_stat BOOTROM_attach(UNIT *uptr, CONST char *cptr) return SCPE_OK; } - sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_attach: cptr=%s\n", cptr); + sim_debug(DEBUG_flow, &BOOTROM_dev, "BOOTROM_attach: cptr=%s\n", cptr); if ((r = attach_unit(uptr, cptr)) != SCPE_OK) { - sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_attach: Error %d\n", r); + sim_debug(DEBUG_flow, &BOOTROM_dev, "BOOTROM_attach: Error %d\n", r); return r; } @@ -233,7 +238,7 @@ t_stat BOOTROM_attach(UNIT *uptr, CONST char *cptr) fclose(fp); printf("Bootrom: %d bytes of ROM image %s loaded\n", j, BOOTROM_unit.filename); - sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_attach: Done\n"); + sim_debug(DEBUG_flow, &BOOTROM_dev, "BOOTROM_attach: Done\n"); return SCPE_OK; } /* BOOTROM_attach() */ @@ -242,25 +247,23 @@ t_stat BOOTROM_attach(UNIT *uptr, CONST char *cptr) t_stat BOOTROM_config (UNIT *uptr, int32 val, CONST char *cptr, void *desc) { - sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: val=%d\n", val); + sim_debug(DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: val=%d\n", val); if ((val < UNIT_NONE) || (val > UNIT_2764)) { /* valid param? */ - sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: Parameter error\n"); + sim_debug(DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: Parameter error\n"); return SCPE_ARG; } if (val == UNIT_NONE) { BOOTROM_unit.capac = 0; /* set EPROM size */ } else { - //BOOTROM_unit.capac = 0x200 ((val >> UNIT_V_MSIZE) - 1); /* set EPROM size */ - BOOTROM_unit.capac = 0x100 * (val >> UNIT_V_MSIZE); /* set EPROM size */ + BOOTROM_unit.capac = 0x100 << (val >> UNIT_V_MSIZE); /* set EPROM size */ } if (!BOOTROM_unit.filebuf) { /* point buffer to static array */ BOOTROM_unit.filebuf = BOOTROM_memory; } - sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: BOOTROM_unit.capac=%d\n", - BOOTROM_unit.capac); - sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: Done\n"); + sim_debug(DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: BOOTROM_unit.capac=%d\n", BOOTROM_unit.capac); + sim_debug(DEBUG_flow, &BOOTROM_dev, "BOOTROM_config: Done\n"); return SCPE_OK; } /* BOOTROM config */ @@ -270,7 +273,7 @@ t_stat BOOTROM_reset (DEVICE *dptr) { t_addr i; - sim_debug (DEBUG_flow, &BOOTROM_dev, "BOOTROM_reset: \n"); + sim_debug(DEBUG_flow, &BOOTROM_dev, "BOOTROM_reset: \n"); /* allocate filebuf */ if (BOOTROM_unit.filebuf == NULL) { /* no buffer allocated */ @@ -291,12 +294,12 @@ int32 BOOTROM_get_mbyte(int32 address) uint8 *pa; if (BOOTROM_unit.filebuf == NULL) { - sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: EPROM not configured\n"); + sim_debug(DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: EPROM not configured\n"); return DEFAULT_NO_ROM_BYTE_VALUE; } - sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: address=%04X\n", address); + sim_debug(DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: address=%04X\n", address); if ((t_addr)(0xFFFF - address) > BOOTROM_unit.capac) { - sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: EPROM reference beyond ROM size\n"); + sim_debug(DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: EPROM reference beyond ROM size\n"); return DEFAULT_NO_ROM_BYTE_VALUE; } @@ -336,7 +339,7 @@ int32 BOOTROM_get_mbyte(int32 address) break; } val &= 0xFF; - sim_debug (DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: Normal val=%02X\n", val); + sim_debug(DEBUG_read, &BOOTROM_dev, "BOOTROM_get_mbyte: Normal val=%02X\n", val); return val; } /* BOOTROM_get_mbyte() */ diff --git a/swtp6809/common/dc-4.c b/swtp6809/common/dc-4.c index f37e530ab..b700915c5 100644 --- a/swtp6809/common/dc-4.c +++ b/swtp6809/common/dc-4.c @@ -26,7 +26,7 @@ MODIFICATIONS: 23 Apr 15 -- Modified to use simh_debug - 24 Feb 24 -- Richard Lukes - Modified to work with swtp6809 emulator + 04 Apr 24 -- Richard Lukes - Modified to work with swtp6809 emulator NOTES: @@ -36,8 +36,9 @@ file only emulates the minimum DC-4 functionality to interface with the virtual disk file. - The floppy controller is interfaced to the CPU by use of 5 memory - addreses. These are SS-30 slot numbers 5 and 6 (0xE014-0xE01B) on a SWTPC 6809 computer. + The floppy controller is interfaced to the CPU by use of 5 memory addreses. + These are SS-30 slot numbers 5 and 6 (0xE014-0xE01B) on a SWTPC 6809 computer. + These are SS-30 slot numbers 5 and 6 (0x8014-0x801B) on a SWTPC 6800 computer. Address Mode Function ------- ---- -------- @@ -55,12 +56,13 @@ Drive Select Read (0xE014): - +---+---+---+---+---+---+---+---+ - | I | D | X | X | X | X | X | X | - +---+---+---+---+---+---+---+---+ + +---+---+---+---+---+---+----+----+ + | I | D | X | X | X | X | d1 | d0 | + +---+---+---+---+---+---+----+----+ I = Set indicates an interrupt request from the FDC pending. D = DRQ pending - same as bit 1 of FDC status register. + d1,d0 = current drive selected Drive Select Write (0xE014): @@ -198,7 +200,7 @@ 1 1 First available data sector last-1 last Last available data sector - System Identity Record + FLEX System Identity Record Byte Use 0x00 Two bytes of zeroes (Clears forward link) @@ -213,41 +215,64 @@ The following unit registers are used by this controller emulation: + dsk_unit[cur_drv].pos unit current sector byte index into file + dsk_unit[cur_drv].filebuf unit current sector buffer + dsk_unit[cur_drv].fileref unit current attached file reference + dsk_unit[cur_drv].capac capacity dsk_unit[cur_drv].u3 unit current flags dsk_unit[cur_drv].u4 unit current track dsk_unit[cur_drv].u5 unit current sector - dsk_unit[cur_drv].pos unit current sector byte index into buffer - dsk_unit[cur_drv].filebuf unit current sector buffer - dsk_unit[cur_drv].fileref unit current attached file reference + dsk_unit[cur_drv].u6 sectors per track + dsk_unit[cur_drv].up7 points to "Flex string" or NULL + dsk_unit[cur_drv].wait cylinder per disk */ #include #include "swtp_defs.h" -#define DEBUG 0 +/* Unit settings*/ -#define UNIT_V_ENABLE (UNIT_V_UF + 0) /* Write Enable */ -#define UNIT_ENABLE (1 << UNIT_V_ENABLE) +#define UNIT_V_DC4_READONLY (UNIT_V_UF + 0) +#define UNIT_DC4_READONLY (0x1 << UNIT_V_DC4_READONLY) -/* maximum of 4 disks, sector size is fixed at 256 bytes */ +#define UNIT_V_DC4_SPT (UNIT_V_UF + 1) +#define UNIT_DC4_SPT (0xF << UNIT_V_DC4_SPT) +#define UNIT_DC4_SPT_UNKNOWN (0x1 << UNIT_V_DC4_SPT) +#define UNIT_DC4_SPT_FLEX_SIR (0x2 << UNIT_V_DC4_SPT) +#define UNIT_DC4_SPT_10SPT (0x3 << UNIT_V_DC4_SPT) +#define UNIT_DC4_SPT_20SPT (0x4 << UNIT_V_DC4_SPT) +#define UNIT_DC4_SPT_30SPT (0x5 << UNIT_V_DC4_SPT) +#define UNIT_DC4_SPT_36SPT (0x6 << UNIT_V_DC4_SPT) +#define UNIT_DC4_SPT_72SPT (0x8 << UNIT_V_DC4_SPT) +#define UNIT_DC4_SPT_255SPT (0x9 << UNIT_V_DC4_SPT) + +/* maximum of 4 disks, sector size is fixed at SECTOR_SIZE bytes */ #define NUM_DISK 4 /* standard 1797 maximum */ -#define SECT_SIZE 256 /* standard FLEX sector */ +#define SECTOR_SIZE 256 /* standard FLEX sector is 256 bytes */ -/* SIR offsets */ +/* Flex OS SIR offsets */ #define MAXCYL 0x26 /* last cylinder # */ #define MAXSEC 0x27 /* last sector # */ /* 1797 status bits */ - #define BUSY 0x01 #define DRQ 0x02 #define WRPROT 0x40 #define NOTRDY 0x80 +/* drive register status bit */ +#define FDCDRV_INTRQ 0x80 +#define FDCDRV_DRQ 0x40 +#define FDCDRV_D1 0x02 +#define FDCDRV_D0 0x01 + /* function prototypes */ -t_stat dsk_reset (DEVICE *dptr); +t_stat dsk_reset(DEVICE *dptr); +t_stat dsk_config(UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat dsk_detach(UNIT *uptr); +t_stat dsk_attach(UNIT *uptr, CONST char *cptr); /* SS-50 I/O address space functions */ @@ -259,16 +284,18 @@ int32 fdcdata(int32 io, int32 data); /* Local Variables */ -int32 fdcbyte; -int32 intrq = 0; /* interrupt request flag */ +int32 fdc_data_byte; /* fdc data register */ + +// this counter is used to emulate write sector VERIFY +// a write sector VERIFY, re-reads the sector, but +// only updates the CRC_ERROR and RECORD_NOT_FOUND flags +// (which don't exist in the emulation) +int32 read_w_drq_busy_counter = 0; /* if DRQ=1,BUSY=1 then increment counter else zero it. Also zero whenever reading from data register on sector read command */ + int32 cur_dsk; /* Currently selected drive */ -int32 wrt_flag = 0; /* FDC write flag */ +int32 prev_dsk; /* previously selected drive */ -int32 spt; /* sectors/track */ -int32 trksiz; /* trk size (bytes) */ -int32 heds; /* number of heads */ -int32 cpd; /* cylinders/disk */ -int32 dsksiz; /* dsk size (bytes) */ +char flex_flag_str[5] = { 'F', 'L', 'E', 'X', 0 }; /* Floppy Disk Controller data structures @@ -278,11 +305,15 @@ int32 dsksiz; /* dsk size (bytes) */ dsk_mod Mother Board modifiers list */ -UNIT dsk_unit[] = { - { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, - { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, - { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, - { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) } +UNIT dsk_unit[NUM_DISK] = { + //{ UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, + //{ UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, + //{ UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) }, + //{ UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, 0) } + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE, 0) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE, 0) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE, 0) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE, 0) } }; REG dsk_reg[] = { @@ -291,18 +322,26 @@ REG dsk_reg[] = { }; MTAB dsk_mod[] = { - { UNIT_ENABLE, UNIT_ENABLE, "RW", "RW", NULL }, - { UNIT_ENABLE, 0, "RO", "RO", NULL }, + { UNIT_DC4_READONLY, UNIT_DC4_READONLY, "RO", "RO", &dsk_config }, + { UNIT_DC4_READONLY, 0, "RW", "RW", &dsk_config }, + { UNIT_DC4_SPT, UNIT_DC4_SPT_UNKNOWN, "Unknown sectors per track", "UNKNOWN", &dsk_config }, + { UNIT_DC4_SPT, UNIT_DC4_SPT_FLEX_SIR, "Read Flex SIR for disk info", "FLEX", &dsk_config }, + { UNIT_DC4_SPT, UNIT_DC4_SPT_10SPT, "10 sectors per track", "10SPT", &dsk_config }, + { UNIT_DC4_SPT, UNIT_DC4_SPT_20SPT, "20 sectors per track", "20SPT", &dsk_config }, + { UNIT_DC4_SPT, UNIT_DC4_SPT_30SPT, "30 sectors per track", "30SPT", &dsk_config }, + { UNIT_DC4_SPT, UNIT_DC4_SPT_36SPT, "36 sectors per track", "36SPT", &dsk_config }, + { UNIT_DC4_SPT, UNIT_DC4_SPT_72SPT, "72 sectors per track", "72SPT", &dsk_config }, + { UNIT_DC4_SPT, UNIT_DC4_SPT_255SPT, "255 sectors per track", "255SPT", &dsk_config }, { 0 } }; DEBTAB dsk_debug[] = { - { "ALL", DEBUG_all }, - { "FLOW", DEBUG_flow }, - { "READ", DEBUG_read }, - { "WRITE", DEBUG_write }, - { "LEV1", DEBUG_level1 }, - { "LEV2", DEBUG_level2 }, + { "ALL", DEBUG_all, "Debug all" }, + { "FLOW", DEBUG_flow, "Debug flow of control" }, + { "READ", DEBUG_read, "Debug device reads" }, + { "WRITE", DEBUG_write, "Debug device writes" }, + { "LEV1", DEBUG_level1, "Debug level 1" }, + { "LEV2", DEBUG_level2, "Debug level 2" }, { NULL } }; @@ -313,7 +352,7 @@ DEVICE dsk_dev = { dsk_mod, //modifiers NUM_DISK, //numunits 16, //aradix - 16, //awidth + 8, //awidth 1, //aincr 16, //dradix 8, //dwidth @@ -321,44 +360,195 @@ DEVICE dsk_dev = { NULL, //deposit &dsk_reset, //reset NULL, //boot - NULL, //attach - NULL, //detach + &dsk_attach, //attach + &dsk_detach, //detach NULL, //ctxt DEV_DEBUG, //flags 0, //dctrl - dsk_debug, /* debflags */ + dsk_debug, /* debug flags defined in DEBTAB */ NULL, //msize - NULL //lname + NULL, //help + NULL, //attach help + NULL, //help context + NULL //device description }; /* Reset routine */ -t_stat dsk_reset (DEVICE *dptr) +t_stat dsk_reset(DEVICE *dptr) { int i; - cur_dsk = 5; /* force initial SIR read, use a drive # that can't be selected */ + sim_printf("dsk_reset: call to reset routine\n"); + + cur_dsk = 0; /* force initial SIR read in FLEX mode, use a drive # that can't be selected */ + prev_dsk = 5; for (i=0; iunits[i].u3 = NOTRDY; /* clear current flags */ + dptr->units[i].u4 = 0; /* clear current cylinder # */ + dptr->units[i].u5 = 0; /* clear current sector # */ + dptr->units[i].pos = 0; /* clear current byte ptr */ + + if (dptr->units[i].filebuf == NULL) { + dptr->units[i].filebuf = malloc(SECTOR_SIZE); /* allocate buffer */ + if (dptr->units[i].filebuf == NULL) { + sim_printf("dc-4_reset: Malloc error\n"); return SCPE_MEM; + } else { + sim_debug(DEBUG_flow, dptr, "dsk_reset: allocated file buffer\n"); } } } - spt = 0; - trksiz = 0; - heds = 0; - cpd = 0; - dsksiz = 0; + + // initialize data register + fdc_data_byte = 0; + return SCPE_OK; -} + +} /* dsk_reset() */ + +/* attach */ +t_stat dsk_attach(UNIT *uptr, CONST char *cptr) +{ + off_t fsize = 0; /* size of attached file */ + int32 temp_cpd; /* cylinders per disk */ + int32 temp_spt; /* sectors per track */ + t_stat r; + int32 err; + int32 pos; + + r = attach_unit(uptr, cptr); + sim_debug(DEBUG_flow, &dsk_dev, "dsk_attach: attach returns %d\n", r); + if (r == SCPE_OK) { + /* determine the size of the attached file and populate the UNIT capac value (capacity) */ + err = sim_fseek(uptr->fileref, 0, SEEK_END); /* seek to offset */ + if (err == -1) { + sim_debug(DEBUG_flow, &dsk_dev, "dsk_attach: fseek returns %d\n", err); + return (SCPE_IOERR); + } + fsize = sim_ftell(uptr->fileref); + uptr->capac = fsize; + + if (uptr->up7 == flex_flag_str) { + sim_printf("dsk_attach: Reading disk geometry from SIR of Flex disk named %s\n", cptr); + sim_debug(DEBUG_flow, &dsk_dev, "dsk_attach: Reading disk geometry from SIR of Flex disk name %d\n", cptr); + + // whenever a new file is attached - re-read the SIR + pos = 0x200; /* Location of Flex System Information Record (SIR) */ + + sim_debug(DEBUG_read, &dsk_dev, "dsk_attach: Read pos = %ld ($%04X)\n", pos, (unsigned int) pos); + err = sim_fseek(uptr->fileref, pos, SEEK_SET); /* seek to offset */ + if (err) { + sim_debug(DEBUG_read, &dsk_dev, "dsk_attach: Seek error read in SIR\n"); + sim_printf("dsk_attach: Seek error read in SIR\n"); + return SCPE_IOERR; + } + err = sim_fread(uptr->filebuf, SECTOR_SIZE, 1, uptr->fileref); /* read in buffer */ + if (err != 1) { + sim_debug(DEBUG_read, &dsk_dev, "dsk_attach: Seek error read in SIR\n"); + sim_printf("dsk_attach: File error read in SIR\n"); + return SCPE_IOERR; + } + + /* retrieve parameters from SIR */ + temp_spt = *((uint8 *)(uptr->filebuf) + MAXSEC) & 0xFF; + temp_cpd = *((uint8 *)(uptr->filebuf) + MAXCYL) & 0xFF; + + /* zero based track numbering */ + temp_cpd++; + + sim_printf("dsk_attach: SIR was read. SPT=%d. CPD=%d. Capacity=%d\n", temp_spt, temp_cpd, fsize); + sim_debug(DEBUG_flow, &dsk_dev, "dsk_attach: SIR was read. SPT=%d. CPD=%d. Capacity=%d\n", temp_spt, temp_cpd, fsize); + + /* confirm that geometry aligns with size */ + if (fsize == (temp_cpd * temp_spt * SECTOR_SIZE)) { + uptr->u6 = temp_spt; + uptr->wait = temp_cpd; + sim_printf("dsk_attach: sectors per track is %d, cylinders per disk is %d\n", temp_spt, temp_cpd); + sim_debug(DEBUG_flow, &dsk_dev, "dsk_attach: WARNING: sectors per track is %d, cylinders per disk is %d\n", temp_spt, temp_cpd); + } else { + sim_printf("dsk_attach: Disk geometry does not align with file size!\n"); + sim_debug(DEBUG_flow, &dsk_dev, "dsk_attach: WARNING: disk geometry does not align with file size!\n"); + } + } else { + /* if sectors per track != 0, calculate cylinders per disk based on file capacity */ + temp_spt = uptr->u6; + if (temp_spt != 0) { + temp_cpd = fsize / (temp_spt * SECTOR_SIZE); + if (fsize == (temp_cpd * temp_spt * SECTOR_SIZE)) { + uptr->wait = temp_cpd; + sim_printf("dsk_attach: cylinders per disk calculated as %d\n", temp_cpd); + sim_debug(DEBUG_flow, &dsk_dev, "dsk_attach: WARNING: cylinders per disk calculated as %d\n", temp_cpd); + /* clear any pre-existing flags */ + uptr->u3 = 0; + } else { + uptr->wait = 0; + sim_printf("dsk_attach: cylinders per disk could not be determined. %d\n", temp_cpd); + sim_debug(DEBUG_flow, &dsk_dev, "dsk_attach: WARNING: cylinders per disk could not be determined. %d\n", temp_cpd); + } + } + } + } + return(r); + +} /* dsk_attach() */ + +/* detach */ +t_stat dsk_detach(UNIT *uptr) +{ + t_stat r; + + uptr->capac = 0; + r = detach_unit(uptr); + sim_debug(DEBUG_flow, &dsk_dev, "dsk_detach: detach return %d\n", r); + return(r); + +} /* dsk_detach */ + +/* disk config */ +t_stat dsk_config(UNIT *uptr, int32 val, CONST char *cptr, void *desc) +{ + sim_debug(DEBUG_flow, &dsk_dev, "dsk_config: val=%d\n", val); + + if ((val & UNIT_DC4_READONLY) != 0) { + uptr->u3 |= WRPROT; /* set write protect */ + } else { + uptr->u3 &= (~WRPROT & 0xFF); /* unset EPROM size */ + } + + if ((val & UNIT_DC4_SPT) == UNIT_DC4_SPT_FLEX_SIR) { + uptr->up7 = flex_flag_str; + sim_debug(DEBUG_flow, &dsk_dev, "dsk_config: disk geometry to be determined from Flex disk\n"); + } + if ((val & UNIT_DC4_SPT) == UNIT_DC4_SPT_10SPT) { + uptr->u6 = 10; + sim_debug(DEBUG_flow, &dsk_dev, "dsk_config: sectors per track set to %d\n", uptr->u6); + } + if ((val & UNIT_DC4_SPT) == UNIT_DC4_SPT_20SPT) { + uptr->u6 = 20; + sim_debug(DEBUG_flow, &dsk_dev, "dsk_config: sectors per track set to %d\n", uptr->u6); + } + if ((val & UNIT_DC4_SPT) == UNIT_DC4_SPT_30SPT) { + uptr->u6 = 30; + sim_debug(DEBUG_flow, &dsk_dev, "dsk_config: sectors per track set to %d\n", uptr->u6); + } + if ((val & UNIT_DC4_SPT) == UNIT_DC4_SPT_36SPT) { + uptr->u6 = 36; + sim_debug(DEBUG_flow, &dsk_dev, "dsk_config: sectors per track set to %d\n", uptr->u6); + } + if ((val & UNIT_DC4_SPT) == UNIT_DC4_SPT_72SPT) { + uptr->u6 = 72; + sim_debug(DEBUG_flow, &dsk_dev, "dsk_config: sectors per track set to %d\n", uptr->u6); + } + if ((val & UNIT_DC4_SPT) == UNIT_DC4_SPT_255SPT) { + uptr->u6 = 255; + sim_debug(DEBUG_flow, &dsk_dev, "dsk_config: sectors per track set to %d\n", uptr->u6); + } + return(SCPE_OK); +} /* dsk_config */ /* I/O instruction handlers, called from the MP-B3 module when a @@ -373,83 +563,95 @@ int32 fdcdrv(int32 io, int32 data) { static long pos; static int32 err; + int32 cpd; + int32 spt; + int32 temp_return; + -//sim_printf("\nfdcdrv: io=%d, data=%d\n", io, data); + sim_debug(DEBUG_flow, &dsk_dev, "fdcdrv: io=%02X, data=%02X\n", io, data); - if (io) { /* write to DC-4 drive register */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcdrv: Drive selected %d cur_dsk=%d", data & 0x03, cur_dsk); - if (cur_dsk == (data & 0x03)) - return 0; /* already selected */ + if (io) { + /* write to DC-4 drive register */ cur_dsk = data & 0x03; /* only 2 drive select bits */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcdrv: Drive set to %d", cur_dsk); - if ((dsk_unit[cur_dsk].flags & UNIT_ENABLE) == 0) { - dsk_unit[cur_dsk].u3 |= WRPROT; /* set 1797 WPROT */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcdrv: Drive write protected"); - } else { - dsk_unit[cur_dsk].u3 &= ~WRPROT; /* set 1797 not WPROT */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcdrv: Drive NOT write protected"); + if (cur_dsk != prev_dsk) { /* did the disk change? */ + prev_dsk = cur_dsk; } + sim_debug(DEBUG_read, &dsk_dev, "fdcdrv: Drive selected %d cur_dsk=%d\n", data & 0x03, cur_dsk); + sim_debug(DEBUG_write, &dsk_dev, "fdcdrv: Drive set to %d\n", cur_dsk); -//sim_printf("\nfdcdrv: reading the SIR\n"); - // whenever a new drive is selected - re-read the SIR - pos = 0x200; /* Read in SIR */ - - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcdrv: Read pos = %ld ($%04X)", - pos, (unsigned int) pos); - err = sim_fseek(dsk_unit[cur_dsk].fileref, pos, SEEK_SET); /* seek to offset */ - if (err) { - sim_printf("\nfdccmd: Seek error read in SIR\n"); - return SCPE_IOERR; - } - err = sim_fread(dsk_unit[cur_dsk].filebuf, SECT_SIZE, 1, dsk_unit[cur_dsk].fileref); /* read in buffer */ - if (err != 1) { - sim_printf("\nfdccmd: File error read in SIR\n"); - return SCPE_IOERR; + if ((dsk_unit[cur_dsk].flags & UNIT_DC4_READONLY) != 0) { + dsk_unit[cur_dsk].u3 |= WRPROT; /* RO - set 1797 WPROT */ + sim_debug(DEBUG_write, &dsk_dev, "fdcdrv: Disk is write protected\n"); } else { - ; -//sim_printf("\nfdcdrv: SIR was read\n"); + dsk_unit[cur_dsk].u3 &= ((~WRPROT) & 0xFF); /* RW - unset 1797 WPROT */ + sim_debug(DEBUG_write, &dsk_dev, "fdcdrv: Disk is not write protected\n"); } - - dsk_unit[cur_dsk].u3 |= BUSY | DRQ; /* set DRQ & BUSY */ - dsk_unit[cur_dsk].pos = 0; /* clear counter */ - spt = *((uint8 *)(dsk_unit[cur_dsk].filebuf) + MAXSEC) & 0xFF; - heds = 0; - cpd = *((uint8 *)(dsk_unit[cur_dsk].filebuf) + MAXCYL) & 0xFF; - trksiz = spt * SECT_SIZE; - dsksiz = trksiz * cpd; - -//sim_printf("\nfdcdrv: spt=%d heds=%d cpd=%d trksiz=%d dsksiz=%d flags=%08X u3=%08X\n", spt, heds, cpd, trksiz, dsksiz, dsk_unit[cur_dsk].flags, dsk_unit[cur_dsk].u3); - - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcdrv: spt=%d heds=%d cpd=%d trksiz=%d dsksiz=%d flags=%08X u3=%08X", - spt, heds, cpd, trksiz, dsksiz, dsk_unit[cur_dsk].flags, dsk_unit[cur_dsk].u3); - return 0; - } else { /* read from DC-4 drive register */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcdrv: Drive read as %02X", intrq); - return intrq; + if ((dsk_unit[cur_dsk].flags & UNIT_ATT) == 0) { /* device is not attached */ + /* set NOTRDY flag */ + dsk_unit[cur_dsk].u3 |= NOTRDY; + sim_debug(DEBUG_write, &dsk_dev, "fdcdrv: Drive is NOT READY\n"); + } + } else { + /* read from DC-4 drive register */ + /* least significant 2 bits are the selected drive */ + temp_return = cur_dsk & 0x03; + if (((dsk_unit[cur_dsk].u3 & BUSY) != 0) && ((dsk_unit[cur_dsk].u3 & DRQ) == 0)) { + /* if BUSY indicates that there is a command and DRQ is unset, set DRQ now */ + dsk_unit[cur_dsk].u3 |= DRQ; /* enable DRQ now */ + } + sim_debug(DEBUG_read, &dsk_dev, "fdcdrv: Drive register read as %02X\n", temp_return ); + return temp_return; } -} + return SCPE_OK; +} /* fdcdrv */ /* WD 1797 FDC command register routine */ int32 fdccmd(int32 io, int32 data) { - static int32 val = 0, val1 = NOTRDY; + static int32 val = 0; static long pos; static int32 err; + sim_debug(DEBUG_flow, &dsk_dev, "fdccmd: io=%02X, data=%02X\n", io, data); + + /* check for NOTRDY */ if ((dsk_unit[cur_dsk].flags & UNIT_ATT) == 0) { /* not attached */ dsk_unit[cur_dsk].u3 |= NOTRDY; /* set not ready flag */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdccmd: Drive %d is not attached", cur_dsk); - return 0; + sim_debug(DEBUG_flow, &dsk_dev, "fdccmd: Drive %d is not attached\n", cur_dsk); } else { + /* drive is attached */ dsk_unit[cur_dsk].u3 &= ~NOTRDY; /* clear not ready flag */ + sim_debug(DEBUG_flow, &dsk_dev, "fdccmd: Drive %d is attached\n", cur_dsk); + } + + /* check for WRPROT */ + if ((dsk_unit[cur_dsk].flags & UNIT_DC4_READONLY) != 0) { + dsk_unit[cur_dsk].u3 |= WRPROT; /* RO - set write protect flag */ + sim_debug(DEBUG_flow, &dsk_dev, "fdccmd: Drive %d is write protected\n", cur_dsk); + } else { + dsk_unit[cur_dsk].u3 &= ~WRPROT; /* RW - unset write protect flag */ + sim_debug(DEBUG_flow, &dsk_dev, "fdccmd: Drive %d is not write protected\n", cur_dsk); } - if (io) { /* write command to fdc */ -//sim_printf("fdccmd: command = %02X\n", data); + if (io) { + + /* write command to fdc */ + if ((dsk_unit[cur_dsk].u3 & BUSY) != 0) { + /* do not write to command register if device is BUSY */ + sim_debug(DEBUG_write, &dsk_dev, "fdccmd: Cannot write to command register, device is BUSY\n", cur_dsk); + return(SCPE_OK); + } + if ((dsk_unit[cur_dsk].u3 & NOTRDY) != 0) { + /* do not write to command register if device is NOTRDY */ + sim_debug(DEBUG_write, &dsk_dev, "fdccmd: Cannot write to command register, device is NOT READY\n", cur_dsk); + return(SCPE_OK); + } switch(data) { - /* restore command */ + /* restore command - type I command */ + + /* ignored: head load flag, verify flag, stepping motor rate*/ case 0x00: case 0x01: case 0x02: @@ -458,7 +660,6 @@ int32 fdccmd(int32 io, int32 data) case 0x05: case 0x06: case 0x07: - case 0x08: case 0x09: case 0x0A: case 0x0B: @@ -466,14 +667,16 @@ int32 fdccmd(int32 io, int32 data) case 0x0D: case 0x0E: case 0x0F: - /* ignored: head load flag, verify flag, stepping motor rate*/ - dsk_unit[cur_dsk].u4 = 0; /* home the drive */ + dsk_unit[cur_dsk].u4 = 0; /* home the drive, track = 0 */ dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* clear flags */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdccmd: Drive %d homed", cur_dsk); + sim_debug(DEBUG_write, &dsk_dev, "fdccmd: restore of drive %d\n", cur_dsk); break; - case 0x10: /* seek command */ + /* seek command - type I command */ + + /* ignored: head load flag, verify flag, stepping motor rate*/ + case 0x10: case 0x11: case 0x12: case 0x13: @@ -489,90 +692,142 @@ int32 fdccmd(int32 io, int32 data) case 0x1D: case 0x1E: case 0x1F: - /* ignored: head load flag, verify flag, stepping motor rate*/ - dsk_unit[cur_dsk].u4 = fdcbyte; /* set track */ + /* set track */ + dsk_unit[cur_dsk].u4 = fdc_data_byte; dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* clear flags */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdccmd: Seek of disk %d, track %d", - cur_dsk, fdcbyte); + sim_debug(DEBUG_write, &dsk_dev, "fdccmd: Seek of disk %d, track %d\n", cur_dsk, fdc_data_byte); break; - case 0x80: /* read command */ + /* read sector command - type II command (m=0, SSO=0) */ + case 0x80: + case 0x84: case 0x88: case 0x8C: - case 0x9C: - -//sim_printf("\nfdccmd: Read of disk %d, track %d, sector %d\n", cur_dsk, dsk_unit[cur_dsk].u4, dsk_unit[cur_dsk].u5); - - sim_debug (DEBUG_flow, &dsk_dev, "\nfdccmd: Read of disk %d, track %d, sector %d", - cur_dsk, dsk_unit[cur_dsk].u4, dsk_unit[cur_dsk].u5); - pos = trksiz * dsk_unit[cur_dsk].u4; /* calculate file offset */ - pos += SECT_SIZE * (dsk_unit[cur_dsk].u5 - 1); - sim_debug (DEBUG_flow, &dsk_dev, "\nfdccmd: Read pos = %ld ($%08X)", - pos, (unsigned int) pos); - err = sim_fseek(dsk_unit[cur_dsk].fileref, pos, SEEK_SET); /* seek to offset */ - if (err) { - sim_printf("\nfdccmd: Seek error in read command\n"); - return SCPE_IOERR; - } - err = sim_fread(dsk_unit[cur_dsk].filebuf, SECT_SIZE, 1, dsk_unit[cur_dsk].fileref); /* read in buffer */ - if (err != 1) { + /* read sector command - type II command (m=0, SSO=1) */ + case 0x82: + case 0x86: + case 0x8A: + case 0x8E: + + /* only execute command if disk is READY */ + if ((dsk_unit[cur_dsk].u3 & NOTRDY) != 0) { + sim_debug(DEBUG_write, &dsk_dev, "fdccmd: Read sector command, but, disk is NOT READY\n"); + } else { - /* display error information */ - sim_printf("\nfdccmd: err = %d\n", err); - sim_printf("\nfdccmd: errno = %d\n", errno); + sim_debug(DEBUG_write, &dsk_dev, "fdccmd: Read of disk %d, track %d, sector %d\n", + cur_dsk, dsk_unit[cur_dsk].u4, dsk_unit[cur_dsk].u5); + + /* sectors for track 0 are numbered 0,1,3,4, ... 10 */ + if (dsk_unit[cur_dsk].u4 == 0) { + /* Track 0 Sector 0 --> pos = 0 */ + /* Track 0 Sector 1 --> pos = 256 */ + if (dsk_unit[cur_dsk].u5 == 0) { + pos = 0; + } else { + if (dsk_unit[cur_dsk].u5 == 1) { + pos = 0; + } else { + pos = (SECTOR_SIZE * (dsk_unit[cur_dsk].u5 - 1)); + } + } + } else { + /* calculate file offset. u4 is track. u5 is sector. u6 is sectors per track. */ + pos = (dsk_unit[cur_dsk].u6 * SECTOR_SIZE) * dsk_unit[cur_dsk].u4; + pos += (SECTOR_SIZE * (dsk_unit[cur_dsk].u5 - 1)); + } + sim_debug(DEBUG_write, &dsk_dev, "fdccmd: Read pos = %ld ($%08X)\n", + pos, (unsigned int) pos); + err = sim_fseek(dsk_unit[cur_dsk].fileref, pos, SEEK_SET); /* seek to offset */ + if (err) { + sim_printf("fdccmd: sim_fseek error = %d\n", err); + sim_debug(DEBUG_write, &dsk_dev, "fdccmd: sim_fseek error = %d\n", err); + return SCPE_IOERR; + } + err = sim_fread(dsk_unit[cur_dsk].filebuf, SECTOR_SIZE, 1, dsk_unit[cur_dsk].fileref); /* read into sector buffer */ + if (err != 1) { + + /* display error information */ + sim_printf("fdccmd: sim_fread error = %d\n", err); + sim_printf("fdccmd: errno = %d\n", errno); + sim_debug(DEBUG_write, &dsk_dev, "fdccmd: sim_fread error = %d\n", err); + return SCPE_IOERR; + } - sim_printf("\nfdccmd: File error in read command\n"); - return SCPE_IOERR; + /* set BUSY to indicate that type II command is in progress */ + dsk_unit[cur_dsk].u3 |= BUSY; /* set BUSY */ + dsk_unit[cur_dsk].u3 &= ~DRQ; /* unset DRQ */ + dsk_unit[cur_dsk].pos = 0; /* clear buffer pointer */ } - dsk_unit[cur_dsk].u3 |= BUSY | DRQ; /* set DRQ & BUSY */ - dsk_unit[cur_dsk].pos = 0; /* clear counter */ break; - /* write command */ + /* write sector command - type II command */ case 0xA8: case 0xAC: - sim_debug (DEBUG_flow, &dsk_dev, "\nfdccmd: Write of disk %d, track %d, sector %d", - cur_dsk, dsk_unit[cur_dsk].u4, dsk_unit[cur_dsk].u5); - if (dsk_unit[cur_dsk].u3 & WRPROT) { - sim_printf("\nfdccmd: Drive %d is write-protected", cur_dsk); + + /* only execute command if disk is READY */ + if ((dsk_unit[cur_dsk].u3 & NOTRDY) != 0) { + sim_debug (DEBUG_write, &dsk_dev, "fdccmd: Write sector command, but, disk is NOT READY\n"); } else { - pos = trksiz * dsk_unit[cur_dsk].u4; /* calculate file offset */ - pos += SECT_SIZE * (dsk_unit[cur_dsk].u5 - 1); - sim_debug (DEBUG_flow, &dsk_dev, "\nfdccmd: Write pos = %ld ($%08X)", - pos, (unsigned int) pos); - err = sim_fseek(dsk_unit[cur_dsk].fileref, pos, SEEK_SET); /* seek to offset */ - if (err) { - sim_printf("\nfdccmd: Seek error in write command\n"); - return SCPE_IOERR; - } - wrt_flag = 1; /* set write flag */ - dsk_unit[cur_dsk].u3 |= BUSY | DRQ;/* set DRQ & BUSY */ - dsk_unit[cur_dsk].pos = 0; /* clear counter */ + + sim_debug (DEBUG_write, &dsk_dev, "fdccmd: Write of disk %d, track %d, sector %d\n", + cur_dsk, dsk_unit[cur_dsk].u4, dsk_unit[cur_dsk].u5); + if ((dsk_unit[cur_dsk].u3 & WRPROT) != 0) { + sim_printf("fdccmd: Drive %d is write-protected\n", cur_dsk); + } else { + /* calculate file offset. u4 is track. u5 is sector. u6 is sectors per track. */ + pos = (dsk_unit[cur_dsk].u6 * SECTOR_SIZE) * dsk_unit[cur_dsk].u4; + pos += SECTOR_SIZE * (dsk_unit[cur_dsk].u5 - 1); + sim_debug(DEBUG_write, &dsk_dev, "fdccmd: Write pos = %ld ($%08X)\n", pos, (unsigned int) pos); + err = sim_fseek(dsk_unit[cur_dsk].fileref, pos, SEEK_SET); /* seek to offset */ + if (err) { + sim_printf("fdccmd: sim_fseek error = %d\n", err); + sim_debug(DEBUG_write, &dsk_dev, "fdccmd: sim_fseek error = %d\n", err); + return SCPE_IOERR; + } + /* set BUSY to indicate that type II command is in progress */ + dsk_unit[cur_dsk].u3 |= BUSY; /* set BUSY */ + dsk_unit[cur_dsk].u3 &= ~DRQ; /* unset DRQ */ + dsk_unit[cur_dsk].pos = 0; /* clear buffer pointer */ + } } break; - case 0xF0: /* write track command */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdccmd: Write track command for drive %d", - cur_dsk); - break; default: - sim_printf("Unknown FDC command %02XH\n\r", data); + sim_printf("Unknown or unimplemented FDC command %02XH\n", data); + sim_debug(DEBUG_write, &dsk_dev, "fdccmd: Unknown or unimplemented command %02X\n", cur_dsk, data); } - } else { /* read status from fdc */ + return(SCPE_OK); + + } else { + /* read status from fdc */ + val = dsk_unit[cur_dsk].u3; /* set return value */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdccmd: Exit Drive %d status=%02X", - cur_dsk, val); - sim_debug (DEBUG_flow, &dsk_dev, "\n%02X", val); //even this short fails it! - if (val1 == 0 && ((val & (BUSY + DRQ)) == (BUSY + DRQ))) /* delay BUSY going high */ - val &= ~BUSY; - if (val != val1) /* now allow BUSY after one read */ - val1 = val; - sim_debug (DEBUG_flow, &dsk_dev, "\nfdccmd: Exit Drive %d status=%02X", - cur_dsk, val); + + if (((val & BUSY) != 0) && ((val & DRQ) == 0)) { + /* if BUSY indicates that there is a command and DRQ is unset, set DRQ now */ + dsk_unit[cur_dsk].u3 = val | DRQ; /* enable DRQ for next time */ + } + + /* handle write VERIFY - as done by Flex */ + if (((val & BUSY) !=0) && ((val & DRQ) != 0)) { + /* Re-read the sector, with read sector command but don't read any data to update the CRC_ERROR and RECORD_NOT_FOUND flags (not emulated) */ + read_w_drq_busy_counter++; + if (read_w_drq_busy_counter > 50) { + /* wait for enough status reads to be confident that this a VERIFY */ + read_w_drq_busy_counter = 0; + /* reset BUSY and DRQ flags, we do not implement CRC_ERROR or RECORD_NOT_FOUND flags */ + dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); + val = dsk_unit[cur_dsk].u3; + sim_debug (DEBUG_write, &dsk_dev, "fdccmd: detected write verify\n"); + } + } else { + read_w_drq_busy_counter = 0; + } + sim_debug (DEBUG_read, &dsk_dev, "fdccmd: Exit Drive %d status=%02X\n", cur_dsk, val); + return val; } - return val; -} +} /* fdccmd */ /* WD 1797 FDC track register routine */ @@ -580,72 +835,121 @@ int32 fdctrk(int32 io, int32 data) { //sim_printf("\nfdctrk: io=%d, data=%d\n", io, data); + sim_debug(DEBUG_flow, &dsk_dev, "fdctrk: io=%02X, data=%02X\n", io, data); + if (io) { - dsk_unit[cur_dsk].u4 = data & 0xFF; - sim_debug (DEBUG_flow, &dsk_dev, "\nfdctrk: Drive %d track set to %d", - cur_dsk, dsk_unit[cur_dsk].u4); + /* write to track register */ + /* do not load when device is BUSY or NOT READY */ + if (((dsk_unit[cur_dsk].u3 & BUSY) == 0) && ((dsk_unit[cur_dsk].u3 & NOTRDY) == 0)) { +// RICHARD WAS HERE +// SEEK ERROR! + if (data >= dsk_unit[cur_dsk].wait) { +sim_printf("Seek error! cur_dsk=%d, tracks per disk is %d, requested track is %d\n", cur_dsk, dsk_unit[cur_dsk].wait, data); + } + dsk_unit[cur_dsk].u4 = data & 0xFF; + sim_debug (DEBUG_write, &dsk_dev, "fdctrk: Drive %d track set to %d\n", cur_dsk, dsk_unit[cur_dsk].u4); + } + return(SCPE_OK); + } else { + /* read from to track register */ + sim_debug (DEBUG_read, &dsk_dev, "fdctrk: Drive %d track read as %d\n", cur_dsk, dsk_unit[cur_dsk].u4); + return(dsk_unit[cur_dsk].u4); } - sim_debug (DEBUG_flow, &dsk_dev, "\nfdctrk: Drive %d track read as %d", - cur_dsk, dsk_unit[cur_dsk].u4); - return dsk_unit[cur_dsk].u4; -} +} /* fdctrk */ /* WD 1797 FDC sector register routine */ int32 fdcsec(int32 io, int32 data) { -//sim_printf("\nfdcsec: io=%d, data=%d\n", io, data); + sim_debug(DEBUG_flow, &dsk_dev, "fdcsec: io=%02X, data=%02X\n", io, data); if (io) { - dsk_unit[cur_dsk].u5 = data & 0xFF; - if (dsk_unit[cur_dsk].u5 == 0) /* fix for swtp boot! */ - dsk_unit[cur_dsk].u5 = 1; - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcsec: Drive %d sector set to %d", - cur_dsk, dsk_unit[cur_dsk].u5); - } - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcsec: Drive %d sector read as %d", - cur_dsk, dsk_unit[cur_dsk].u5); - return dsk_unit[cur_dsk].u5; -} + /* write to sector register */ + /* do not load when device is BUSY or NOT READY */ + if (((dsk_unit[cur_dsk].u3 & BUSY) == 0) && ((dsk_unit[cur_dsk].u3 & NOTRDY) == 0)) { + dsk_unit[cur_dsk].u5 = data & 0xFF; + sim_debug(DEBUG_write, &dsk_dev, "fdcsec: Drive %d sector set to %d\n", cur_dsk, dsk_unit[cur_dsk].u5); + } + return(SCPE_OK); + } else { + /* read sector register */ + sim_debug (DEBUG_read, &dsk_dev, "fdcsec: Drive %d sector read as %d\n", cur_dsk, dsk_unit[cur_dsk].u5); + return(dsk_unit[cur_dsk].u5); + } +} /* fdcsec */ /* WD 1797 FDC data register routine */ int32 fdcdata(int32 io, int32 data) { int32 val; + static int32 err; - if (io) { /* write byte to fdc */ - fdcbyte = data; /* save for seek */ - if (dsk_unit[cur_dsk].pos < SECT_SIZE) { /* copy bytes to buffer */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcdata: Writing byte %d of %02X", - dsk_unit[cur_dsk].pos, data); - *((uint8 *)(dsk_unit[cur_dsk].filebuf) + dsk_unit[cur_dsk].pos) = data; /* byte into buffer */ - dsk_unit[cur_dsk].pos++; /* step counter */ - if (dsk_unit[cur_dsk].pos == SECT_SIZE) { - dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); - if (wrt_flag) { /* if initiated by FDC write command */ - sim_fwrite(dsk_unit[cur_dsk].filebuf, SECT_SIZE, 1, dsk_unit[cur_dsk].fileref); /* write it */ - wrt_flag = 0; /* clear write flag */ + sim_debug(DEBUG_flow, &dsk_dev, "fdcdata: io=%02X, data=%02X\n", io, data); + + if (io) { + /* write byte to fdc */ + if ((dsk_unit[cur_dsk].u3 & BUSY) == 0) { + /* NOT BUSY - write to data register fdc_data_byte */ + sim_debug(DEBUG_write, &dsk_dev, "fdcdata: Writing %02X to data register\n", data); + fdc_data_byte = data; + } else { + /* BUSY - a command is being processed */ + if (dsk_unit[cur_dsk].pos < SECTOR_SIZE) { /* copy bytes to buffer */ + + /* reset the counter used for write verify */ + read_w_drq_busy_counter = 0; + + sim_debug (DEBUG_flow, &dsk_dev, "fdcdata: Writing byte pos=%d val=%02X\n", dsk_unit[cur_dsk].pos, data); + *((uint8 *)(dsk_unit[cur_dsk].filebuf) + dsk_unit[cur_dsk].pos) = data; /* byte into buffer */ + dsk_unit[cur_dsk].pos++; /* increment buffer pointer */ + + /* if this is last byte in sector then update statuses */ + if (dsk_unit[cur_dsk].pos >= SECTOR_SIZE) { /* done? */ + err = sim_fwrite(dsk_unit[cur_dsk].filebuf, SECTOR_SIZE, 1, dsk_unit[cur_dsk].fileref); /* write it */ + if (err != 1) { + /* display error information */ + sim_printf("fdcdata: sim_fwrite error = %d\n", err); + sim_printf("fdcdata: errno = %d\n", errno); + sim_debug(DEBUG_write, &dsk_dev, "fdcdata: sim_fwrite error = %d\n", err); + return SCPE_IOERR; + } + dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* reset flags */ + dsk_unit[cur_dsk].pos = 0; /* reset counter */ + sim_debug(DEBUG_write, &dsk_dev, "fdcdata: Sector write complete\n"); } - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcdata: Sector write complete"); } } - return 0; - } else { /* read byte from fdc */ - - if (dsk_unit[cur_dsk].pos < SECT_SIZE) { /* copy bytes from buffer */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcdata: Reading byte %d u3=%02X", - dsk_unit[cur_dsk].pos, dsk_unit[cur_dsk].u3); - val = *((uint8 *)(dsk_unit[cur_dsk].filebuf) + dsk_unit[cur_dsk].pos) & 0xFF; - dsk_unit[cur_dsk].pos++; /* step counter */ - if (dsk_unit[cur_dsk].pos == SECT_SIZE) { /* done? */ - dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* clear flags */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcdata: Sector read complete"); + return(SCPE_OK); + } else { + /* read byte from fdc */ + + if ((dsk_unit[cur_dsk].u3 & BUSY) == 0) { + /* NOT BUSY - read from data register fdc_data_byte */ + val = fdc_data_byte; + sim_debug(DEBUG_read, &dsk_dev, "fdcdata: Reading data register value of %02X\n", val); + } else { + /* BUSY - a read command is being processed */ + if (dsk_unit[cur_dsk].pos < SECTOR_SIZE) { /* copy bytes from buffer */ + + /* reset the counter used for write verify */ + read_w_drq_busy_counter = 0; + + /* read a byte into the sector buffer */ + val = *((uint8 *)(dsk_unit[cur_dsk].filebuf) + dsk_unit[cur_dsk].pos) & 0xFF; + sim_debug(DEBUG_read, &dsk_dev, "fdcdata: Reading byte pos=%d val=%02X\n", dsk_unit[cur_dsk].pos, val); + dsk_unit[cur_dsk].pos++; /* step counter */ + + /* if this is last byte in sector then update statuses */ + if (dsk_unit[cur_dsk].pos >= SECTOR_SIZE) { /* done? */ + dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* clear flags */ + dsk_unit[cur_dsk].pos = 0; /* reset step counter */ + sim_debug(DEBUG_read, &dsk_dev, "fdcdata: Sector read complete\n"); + } } - return val; - } else - return 0; + } + return(val); } -} +} /* fdcdata() */ /* end of dc-4.c */ diff --git a/swtp6809/common/m6809.c b/swtp6809/common/m6809.c index d92e500d6..b406465a5 100644 --- a/swtp6809/common/m6809.c +++ b/swtp6809/common/m6809.c @@ -1,4 +1,4 @@ -/* 6809.c: SWTP 6809 CPU simulator +/* 6809.c: SWTP 6809 CPU simulator^ Copyright (c) 2005-2012, William Beech @@ -53,7 +53,7 @@ 23 Apr 15 -- Modified to use simh_debug 21 Apr 20 -- Richard Brinegar numerous fixes for flag errors - 24 Feb 24 -- Richard Lukes - modified for 6809 + 04 Apr 24 -- Richard Lukes - modified for 6809 NOTES: cpu Motorola M6809 CPU @@ -143,6 +143,8 @@ #define TFR_EXG_Post_Nybble_CC 10 #define TFR_EXG_Post_Nybble_DP 11 +/* Exclusive OR macro for logical expressions */ +#define EXOR(a,b) (((a)!=0) != ((b)!=0)) /* Macros to handle the flags in the CCR */ #define CCR_MSK (EF|FF|HF|IF|NF|ZF|VF|CF) @@ -164,17 +166,11 @@ #define COND_SET_FLAG_Z_16(VAR) \ if ((VAR) == 0) SET_FLAG(ZF); else CLR_FLAG(ZF) -#define COND_SET_FLAG_H(VAR) \ - if ((VAR) & 0x10) SET_FLAG(HF); else CLR_FLAG(HF) - #define COND_SET_FLAG_C(VAR) \ if ((VAR) & 0x100) SET_FLAG(CF); else CLR_FLAG(CF) #define COND_SET_FLAG_C_16(VAR) \ if ((VAR) & 0x10000) SET_FLAG(CF); else CLR_FLAG(CF) -#define COND_SET_FLAG_V(COND) \ - if (COND) SET_FLAG(VF); else CLR_FLAG(VF) - /* local global variables */ int32 A = 0; /* Accumulator A */ @@ -191,16 +187,20 @@ int32 previous_PC = 0; /* Previous previous Program counter */ int32 last_PC = 0; /* Last Program counter */ int32 PC; /* Program counter */ int32 INTE = 0; /* Interrupt Enable */ -int32 int_req = 0; /* Interrupt request */ +int32 int_req = 0; /* Interrupt request */ int32 mem_fault = 0; /* memory fault flag */ +#define m6809_NAME "Motorola M6809 Processor Chip" + /* function prototypes */ t_stat m6809_reset(DEVICE *dptr); t_stat m6809_boot(int32 unit_num, DEVICE *dptr); t_stat m6809_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); t_stat m6809_deposit(t_value value, t_addr addr, UNIT *uptr, int32 switches); +static const char* m6809_desc(DEVICE *dptr) { return m6809_NAME; } + void dump_regs(void); void dump_regs1(void); @@ -250,7 +250,7 @@ extern int32 CPU_BD_get_mword(int32 addr); m6809_reg CPU register list m6809_mod CPU modifiers list */ -UNIT m6809_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, 65536) }; +UNIT m6809_unit = { UDATA (NULL, 0, 0) }; REG m6809_reg[] = { { HRDATA (PC, saved_PC, 16) }, @@ -305,46 +305,50 @@ DEVICE m6809_dev = { 0, //dctrl m6809_debug, //debflags NULL, //msize - NULL //lname + NULL, //lname + NULL, //help routine + NULL, //attach help routine + NULL, //help context + &m6809_desc //device description }; static const char *opcode[] = { -"NEG", "???", "???", "COM", //0x00 -"LSR", "???", "ROR", "ASR", +"NEG", "?01?", "?02?", "COM", //0x00 +"LSR", "?05?", "ROR", "ASR", "ASL", "ROL", "DEC", "???", "INC", "TST", "JMP", "CLR", -"PG2", "PG3", "NOP", "SYNC", //0x10 -"???", "???", "LBRA", "LBSR", -"???", "DAA", "ORCC", "???", +"PG2", "PG3", "NOP", "SYNC", //0x10 +"?14?", "?15?", "LBRA", "LBSR", +"?18?", "DAA", "ORCC", "?1B?", "ANDCC", "SEX", "EXG", "TFR", "BRA", "BRN", "BHI", "BLS", //0x20 -"BCC", "BLO", "BNE", "BEQ", +"BCC", "BCS", "BNE", "BEQ", "BVC", "BVS", "BPL", "BMI", "BGE", "BLT", "BGT", "BLE", "LEAX", "LEAY", "LEAS", "LEAU", //0x30 "PSHS", "PULS", "PSHU", "PULU", -"???", "RTS", "ABX", "RTI", -"CWAI", "MUL", "???", "SWI", -"NEGA", "???", "???", "COMA", //0x40 -"LSRA", "???", "RORA", "ASRA", -"LSLA", "ROLA", "DECA", "???", -"INCA", "TSTA", "???", "CLRA", -"NEGB", "???", "???", "COMB", //0x50 -"LSRB", "???", "RORB", "ASRB", -"LSLB", "ROLB", "DECB", "???", -"INCB", "TSTB", "???", "CLRB", -"NEG", "???", "???", "COM", //0x60 -"LSR", "???", "ROR", "ASR", -"ASL", "ROL", "DEC", "???", +"?38?", "RTS", "ABX", "RTI", +"CWAI", "MUL", "?3E?", "SWI", +"NEGA", "?41?", "?42?", "COMA", //0x40 +"LSRA", "?45?", "RORA", "ASRA", +"ASLA", "ROLA", "DECA", "?4B?", +"INCA", "TSTA", "?4E?", "CLRA", +"NEGB", "?51?", "?52?", "COMB", //0x50 +"LSRB", "?55?", "RORB", "ASRB", +"ASLB", "ROLB", "DECB", "?5B?", +"INCB", "TSTB", "?5E?", "CLRB", +"NEG", "?61?", "?62?", "COM", //0x60 +"LSR", "?65?", "ROR", "ASR", +"ASL", "ROL", "DEC", "?6B?", "INC", "TST", "JMP", "CLR", -"NEG", "???", "???", "COM", //0x70 -"LSR", "???", "ROR", "ASR", -"ASL", "ROL", "DEC", "???", +"NEG", "?71?", "?72?", "COM", //0x70 +"LSR", "?75?", "ROR", "ASR", +"ASL", "ROL", "DEC", "?7B?", "INC", "TST", "JMP", "CLR", "SUBA", "CMPA", "SBCA", "SUBD", //0x80 -"ANDA", "BITA", "LDA", "???", +"ANDA", "BITA", "LDA", "?87?", "EORA", "ADCA", "ORAA", "ADDA", -"CMPX", "BSR", "LDX", "???", +"CMPX", "BSR", "LDX", "?8F?", "SUBA", "CMPA", "SBCA", "SUBD", //0x90 "ANDA", "BITA", "LDA", "STA", "EORA", "ADCA", "ORA", "ADDA", @@ -358,9 +362,9 @@ static const char *opcode[] = { "EORA", "ADCA", "ORA", "ADDA", "CMPX", "JSR", "LDX", "STX", "SUBB", "CMPB", "SBCB", "ADDD", //0xC0 -"ANDB", "BITB", "LDB", "???", +"ANDB", "BITB", "LDB", "?C7?", "EORB", "ADCB", "ORB", "ADDB", -"LDD", "???", "LDU", "???", +"LDD", "?CD?", "LDU", "?CF?", "SUBB", "CMPB", "SBCB", "ADDD", //0xD0 "ANDB", "BITB", "LDB", "STB", "EORB", "ADCB", "ORB", "ADDB", @@ -375,109 +379,23 @@ static const char *opcode[] = { "LDD", "STD", "LDU", "STU" }; -static const char *opcode6800[] = { -"???", "NOP", "???", "???", //0x00 -"???", "???", "TAP", "TPA", -"INX", "DEX", "CLV", "SEV", -"CLC", "SEC", "CLI", "SEI", -"SBA", "CBA", "???", "???", //0x10 -"???", "???", "TAB", "TBA", -"???", "DAA", "???", "ABA", -"???", "???", "???", "???", -"BRA", "???", "BHI", "BLS", //0x20 -"BCC", "BCS", "BNE", "BEQ", -"BVC", "BVS", "BPL", "BMI", -"BGE", "BLT", "BGT", "BLE", -"TSX", "INS", "PULA", "PULB", //0x30 -"DES", "TXS", "PSHA", "PSHB", -"???", "RTS", "???", "RTI", -"???", "???", "WAI", "SWI", -"NEGA", "???", "???", "COMA", //0x40 -"LSRA", "???", "RORA", "ASRA", -"ASLA", "ROLA", "DECA", "???", -"INCA", "TSTA", "???", "CLRA", -"NEGB", "???", "???", "COMB", //0x50 -"LSRB", "???", "RORB", "ASRB", -"ASLB", "ROLB", "DECB", "???", -"INCB", "TSTB", "???", "CLRB", -"NEG", "???", "???", "COM", //0x60 -"LSR", "???", "ROR", "ASR", -"ASL", "ROL", "DEC", "???", -"INC", "TST", "JMP", "CLR", -"NEG", "???", "???", "COM", //0x70 -"LSR", "???", "ROR", "ASR", -"ASL", "ROL", "DEC", "???", -"INC", "TST", "JMP", "CLR", -"SUBA", "CMPA", "SBCA", "???", //0x80 -"ANDA", "BITA", "LDAA", "???", -"EORA", "ADCA", "ORAA", "ADDA", -"CMPX", "BSR", "LDS", "???", -"SUBA", "CMPA", "SBCA", "???", //0x90 -"ANDA", "BITA", "LDAA", "STAA", -"EORA", "ADCA", "ORAA", "ADDA", -"CMPX", "???", "LDS", "STS", -"SUBA", "CMPA", "SBCA", "???", //0xA0 -"ANDA", "BITA", "LDAA", "STAA", -"EORA", "ADCA", "ORAA", "ADDA", -"CMPX X", "JSR X", "LDS X", "STS X", -"SUBA", "CMPA", "SBCA", "???", //0xB0 -"ANDA", "BITA", "LDAA", "STAA", -"EORA", "ADCA", "ORAA", "ADDA", -"CPX", "JSR", "LDS", "STS", -"SUBB", "CMPB", "SBCB", "???", //0xC0 -"ANDB", "BITB", "LDAB", "???", -"EORB", "ADCB", "ORAB", "ADDB", -"???", "???", "LDX", "???", -"SUBB", "CMPB", "SBCB", "???", //0xD0 -"ANDB", "BITB", "LDAB", "STAB", -"EORB", "ADCB", "ORAB", "ADDB", -"???", "???", "LDX", "STX", -"SUBB", "CMPB", "SBCB", "???", //0xE0 -"ANDB", "BITB", "LDAB", "STAB", -"EORB", "ADCB", "ORAB", "ADDB", -"???", "???", "LDX", "STX", -"SUBB", "CMPB", "SBCB", "???", //0xF0 -"ANDB", "BITB", "LDAB", "STAB", -"EORB", "ADCB", "ORAB", "ADDB", -"???", "???", "LDX", "STX" -}; - int32 oplen[256] = { -0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1, //0x00 -1,1,0,0,0,0,1,1,0,1,0,1,0,0,0,0, -2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, -1,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1, +2,0,0,2,2,0,2,2,2,2,2,0,2,2,2,2, //0x00 +2,2,1,1,0,0,3,3,0,1,2,0,2,1,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,0,1,1,1,2,1,0,1, 1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, //0x40 1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, 2,0,0,2,2,0,2,2,2,2,2,0,2,2,2,2, 3,0,0,3,3,0,3,3,3,3,3,0,3,3,3,3, -2,2,2,0,2,2,2,0,2,2,2,2,3,2,3,0, //0x80 -2,2,2,0,2,2,2,2,2,2,2,2,2,0,2,2, -2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2, -3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3, -2,2,2,0,2,2,2,0,2,2,2,2,0,0,3,0, //0xC0 -2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, -2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, -3,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3 -}; - -int32 oplen6800[256] = { -0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1, //0x00 -1,1,0,0,0,0,1,1,0,1,0,1,0,0,0,0, -2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, -1,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1, -1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, //0x40 -1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, -2,0,0,2,2,0,2,2,2,2,2,0,2,2,2,2, -3,0,0,3,3,0,3,3,3,3,3,0,3,3,3,3, -2,2,2,0,2,2,2,0,2,2,2,2,3,2,3,0, //0x80 -2,2,2,0,2,2,2,2,2,2,2,2,2,0,2,2, -2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2, -3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3, -2,2,2,0,2,2,2,0,2,2,2,2,0,0,3,0, //0xC0 -2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, -2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, -3,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3 +2,2,2,3,2,2,2,0,2,2,2,2,3,2,3,0, //0x80 +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, +2,2,2,3,2,2,2,0,2,2,2,2,3,0,3,0, //0xC0 +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 }; t_stat sim_instr (void) @@ -507,19 +425,19 @@ t_stat sim_instr (void) /* Main instruction fetch/decode loop */ while (reason == 0) { /* loop until halted */ -// dump_regs1(); if (sim_interval <= 0) /* check clock queue */ - if ((reason = sim_process_event ())) + if ((reason = sim_process_event ())) { break; - if (mem_fault) { /* memory fault? */ - mem_fault = 0; /* reset fault flag */ + } + if (mem_fault != 0) { /* memory fault? */ + mem_fault = 0; /* reset fault flag */ reason = STOP_MEMORY; break; } if (int_req > 0) { /* interrupt? */ /* 6809 interrupts not implemented yet. None were used, on a standard SWTP 6809. All I/O is programmed. */ - reason = STOP_HALT; /* stop simulation */ + reason = STOP_HALT; /* stop simulation */ break; } /* end interrupt */ @@ -550,27 +468,29 @@ t_stat sim_instr (void) COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); break; + case 0x03: /* COM dir */ addr = get_dir_addr(); op1 = CPU_BD_get_mbyte(addr); - result = ~op1; - result &= 0xFF; + result = (~op1) & 0xFF; CPU_BD_put_mbyte(addr, result); COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); CLR_FLAG(VF); SET_FLAG(CF); break; + case 0x04: /* LSR dir */ addr = get_dir_addr(); op1 = CPU_BD_get_mbyte(addr); - COND_SET_FLAG(op1 & 0x01, CF); result = op1 >> 1; CPU_BD_put_mbyte(addr, result); CLR_FLAG(NF); COND_SET_FLAG_Z(result); /* H,V not affected */ + COND_SET_FLAG(op1 & 0x01, CF); break; + case 0x06: /* ROR dir */ addr = get_dir_addr(); op1 = CPU_BD_get_mbyte(addr); @@ -579,11 +499,12 @@ t_stat sim_instr (void) result |= 0x80; } CPU_BD_put_mbyte(addr, result); - /* H,V unaffected */ COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); + /* H,V unaffected */ COND_SET_FLAG(op1 & 0x01, CF); break; + case 0x07: /* ASR dir */ addr = get_dir_addr(); op1 = CPU_BD_get_mbyte(addr); @@ -592,20 +513,22 @@ t_stat sim_instr (void) /* H undefined */ COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); - /* V not affected */ + /* V unaffected */ COND_SET_FLAG(op1 & 0x01, CF); break; + case 0x08: /* ASL dir */ addr = get_dir_addr(); op1 = CPU_BD_get_mbyte(addr); - COND_SET_FLAG(op1 & 0x80, CF); result = (op1 << 1) & BYTEMASK; CPU_BD_put_mbyte(addr, result); /* H is undefined */ COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); - COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + COND_SET_FLAG(op1 & 0x80, CF); + COND_SET_FLAG(EXOR(get_flag(NF),get_flag(CF)), VF); break; + case 0x09: /* ROL dir */ addr = get_dir_addr(); op1 = CPU_BD_get_mbyte(addr); @@ -616,38 +539,44 @@ t_stat sim_instr (void) CPU_BD_put_mbyte(addr, result); COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); - COND_SET_FLAG((op1 & 0x80) ^ (op1 & 0x40), VF); COND_SET_FLAG(op1 & 0x80, CF); + COND_SET_FLAG(EXOR(get_flag(NF),get_flag(CF)), VF); break; + case 0x0A: /* DEC dir */ addr = get_dir_addr(); op1 = CPU_BD_get_mbyte(addr); - result = (op1-1) & BYTEMASK; + result = (op1 - 1) & BYTEMASK; CPU_BD_put_mbyte(addr, result); - /* H not affected */ COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); COND_SET_FLAG(op1 == 0x80, VF); - /* C not affected */ + /* C unaffected */ break; + case 0x0C: /* INC dir */ addr = get_dir_addr(); op1 = CPU_BD_get_mbyte(addr); + result = (op1 + 1) & BYTEMASK; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); COND_SET_FLAG(op1 == 0x7F, VF); - op1 = (op1 + 1) & BYTEMASK; - CPU_BD_put_mbyte(addr, op1); - COND_SET_FLAG_N(op1); - COND_SET_FLAG_Z(op1); + /* C unaffected */ break; + case 0x0D: /* TST dir */ result = get_dir_byte_val(); COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); CLR_FLAG(VF); + /* C unaffected */ break; + case 0x0E: /* JMP dir */ PC = get_dir_addr(); break; + case 0x0F: /* CLR dir */ CPU_BD_put_mbyte(get_dir_addr(), 0); /* H not affected */ @@ -660,17 +589,17 @@ t_stat sim_instr (void) /* 0x10 */ case 0x10: /* 2-byte opcodes */ /* fetch second byte of opcode */ - OP2 = fetch_byte(0); + OP2 = fetch_byte(1); switch (OP2) { case 0x21: /* LBRN rel */ /* Branch Never - essentially a NOP */ go_long_rel(0); break; case 0x22: /* LBHI rel */ - go_long_rel(!(get_flag(CF) | get_flag(ZF))); + go_long_rel(!(get_flag(CF) || get_flag(ZF))); break; case 0x23: /* LBLS rel */ - go_long_rel(get_flag(CF) | get_flag(ZF)); + go_long_rel(get_flag(CF) || get_flag(ZF)); break; case 0x24: /* LBCC rel */ go_long_rel(!get_flag(CF)); @@ -697,17 +626,18 @@ t_stat sim_instr (void) go_long_rel(get_flag(NF)); break; case 0x2C: /* LBGE rel */ - go_long_rel( !( get_flag(NF) ^ get_flag(VF) ) ); + go_long_rel(get_flag(NF) == get_flag(VF)); break; case 0x2D: /* LBLT rel */ - go_long_rel( get_flag(NF) ^ get_flag(VF) ); + go_long_rel(get_flag(NF) != get_flag(VF)); break; case 0x2E: /* LBGT rel */ - go_long_rel(!( get_flag(ZF) | (get_flag(NF) ^ get_flag(VF)))); + go_long_rel((get_flag(ZF) == 0) && (get_flag(NF) == get_flag(VF))); break; case 0x2F: /* LBLE rel */ - go_long_rel(get_flag(ZF) | (get_flag(NF) ^ get_flag(VF))); + go_long_rel(get_flag(ZF) || (get_flag(NF) != get_flag(VF))); break; + case 0x3F: /* SWI2 */ SET_FLAG(EF); push_sp_word(PC); @@ -718,9 +648,11 @@ t_stat sim_instr (void) push_sp_byte(B); push_sp_byte(A); push_sp_byte(CCR); - PC = CPU_BD_get_mword(0xFFF4) & ADDRMASK; + PC = CPU_BD_get_mword(0xFFF4); break; + case 0x83: /* CMPD imm */ + /* do not modify D|A|B */ D = (A << 8) | (B & BYTEMASK); op2 = get_imm_word_val(); result = D - op2; @@ -729,7 +661,9 @@ t_stat sim_instr (void) condevalVs16(D, op2); COND_SET_FLAG_C_16(result); break; + case 0x8C: /* CMPY imm */ + /* do not modify Y */ op2 = get_imm_word_val(); result = IY - op2; COND_SET_FLAG_N_16(result); @@ -737,13 +671,16 @@ t_stat sim_instr (void) condevalVs16(IY, op2); COND_SET_FLAG_C_16(result); break; + case 0x8E: /* LDY imm */ IY = get_imm_word_val(); COND_SET_FLAG_N_16(IY); COND_SET_FLAG_Z_16(IY); CLR_FLAG(VF); break; + case 0x93: /* CMPD dir */ + /* do not modify D|A|B */ D = (A << 8) | (B & BYTEMASK); op2 = get_dir_word_val(); result = D - op2; @@ -752,7 +689,9 @@ t_stat sim_instr (void) condevalVs16(D, op2); COND_SET_FLAG_C_16(result); break; + case 0x9C: /* CMPY dir */ + /* do not modify Y */ op2 = get_dir_word_val(); result = IY - op2; COND_SET_FLAG_N_16(result); @@ -760,19 +699,23 @@ t_stat sim_instr (void) condevalVs16(IY, op2); COND_SET_FLAG_C_16(result); break; + case 0x9E: /* LDY dir */ IY = get_dir_word_val(); COND_SET_FLAG_N_16(IY); COND_SET_FLAG_Z_16(IY); CLR_FLAG(VF); break; + case 0x9F: /* STY dir */ CPU_BD_put_mword(get_dir_addr(), IY); COND_SET_FLAG_N_16(IY); COND_SET_FLAG_Z_16(IY); CLR_FLAG(VF); break; + case 0xA3: /* CMPD ind */ + /* do not modify D|A|B */ D = (A << 8) | (B & BYTEMASK); op2 = get_indexed_word_val(); result = D - op2; @@ -781,7 +724,9 @@ t_stat sim_instr (void) condevalVs16(D, op2); COND_SET_FLAG_C_16(result); break; + case 0xAC: /* CMPY ind */ + /* do not modify Y */ op2 = get_indexed_word_val(); result = IY - op2; COND_SET_FLAG_N_16(result); @@ -789,19 +734,23 @@ t_stat sim_instr (void) condevalVs16(IY, op2); COND_SET_FLAG_C_16(result); break; + case 0xAE: /* LDY ind */ IY = get_indexed_word_val(); COND_SET_FLAG_N_16(IY); COND_SET_FLAG_Z_16(IY); CLR_FLAG(VF); break; + case 0xAF: /* STY ind */ CPU_BD_put_mword(get_indexed_addr(), IY); COND_SET_FLAG_N_16(IY); COND_SET_FLAG_Z_16(IY); CLR_FLAG(VF); break; + case 0xB3: /* CMPD ext */ + /* Do not modify D|A|B */ D = (A << 8) | (B & BYTEMASK); op2 = get_ext_word_val(); result = D - op2; @@ -810,7 +759,9 @@ t_stat sim_instr (void) condevalVs16(D, op2); COND_SET_FLAG_C_16(result); break; + case 0xBC: /* CMPY ext */ + /* Do not modify D|A|B */ op2 = get_ext_word_val(); result = IY - op2; COND_SET_FLAG_N_16(result); @@ -818,54 +769,63 @@ t_stat sim_instr (void) condevalVs16(IY, op2); COND_SET_FLAG_C_16(result); break; + case 0xBE: /* LDY ext */ IY = get_ext_word_val(); COND_SET_FLAG_N_16(IY); COND_SET_FLAG_Z_16(IY); CLR_FLAG(VF); break; + case 0xBF: /* STY ext */ CPU_BD_put_mword(get_ext_addr(), IY); COND_SET_FLAG_N_16(IY); COND_SET_FLAG_Z_16(IY); CLR_FLAG(VF); break; + case 0xCE: /* LDS imm */ SP = get_imm_word_val(); COND_SET_FLAG_N_16(SP); COND_SET_FLAG_Z_16(SP); CLR_FLAG(VF); break; + case 0xDE: /* LDS dir */ SP = get_dir_word_val(); COND_SET_FLAG_N_16(SP); COND_SET_FLAG_Z_16(SP); CLR_FLAG(VF); break; + case 0xDF: /* STS dir */ CPU_BD_put_mword(get_dir_addr(), SP); COND_SET_FLAG_N_16(SP); COND_SET_FLAG_Z_16(SP); CLR_FLAG(VF); break; + case 0xEE: /* LDS ind */ SP = get_indexed_word_val(); COND_SET_FLAG_N_16(SP); COND_SET_FLAG_Z_16(SP); CLR_FLAG(VF); break; + case 0xEF: /* STS ind */ CPU_BD_put_mword(get_indexed_addr(), SP); COND_SET_FLAG_N_16(SP); COND_SET_FLAG_Z_16(SP); CLR_FLAG(VF); break; + case 0xFE: /* LDS ext */ SP = get_ext_word_val(); COND_SET_FLAG_N_16(SP); COND_SET_FLAG_Z_16(SP); CLR_FLAG(VF); break; + case 0xFF: /* STS ext */ CPU_BD_put_mword(get_ext_addr(), SP); COND_SET_FLAG_N_16(SP); @@ -878,8 +838,9 @@ t_stat sim_instr (void) /* Ox11 */ case 0x11: /* 2-byte opcodes */ /* fetch second byte of opcode */ - OP2 = fetch_byte(0); + OP2 = fetch_byte(1); switch (OP2) { + case 0x3F: /* SWI3 */ SET_FLAG(EF); push_sp_word(PC); @@ -890,9 +851,11 @@ t_stat sim_instr (void) push_sp_byte(B); push_sp_byte(A); push_sp_byte(CCR); - PC = CPU_BD_get_mword(0xFFF2) & ADDRMASK; + PC = CPU_BD_get_mword(0xFFF2); break; + case 0x83: /* CMPU imm */ + /* Do not modify UP */ op2 = get_imm_word_val(); result = UP - op2; COND_SET_FLAG_N_16(result); @@ -900,7 +863,9 @@ t_stat sim_instr (void) condevalVs16(UP, op2); COND_SET_FLAG_C_16(result); break; + case 0x8C: /* CMPS imm */ + /* Do not modify SP */ op2 = get_imm_word_val(); result = SP - op2; COND_SET_FLAG_N_16(result); @@ -908,7 +873,9 @@ t_stat sim_instr (void) condevalVs16(SP, op2); COND_SET_FLAG_C_16(result); break; + case 0x93: /* CMPU dir */ + /* Do not modify UP */ op2 = get_dir_word_val(); result = UP - op2; COND_SET_FLAG_N_16(result); @@ -916,7 +883,9 @@ t_stat sim_instr (void) condevalVs16(UP, op2); COND_SET_FLAG_C_16(result); break; + case 0x9C: /* CMPS dir */ + /* Do not modify SP */ op2 = get_dir_word_val(); result = SP - op2; COND_SET_FLAG_N_16(result); @@ -924,7 +893,9 @@ t_stat sim_instr (void) condevalVs16(SP, op2); COND_SET_FLAG_C_16(result); break; + case 0xA3: /* CMPU ind */ + /* Do not modify UP */ op2 = get_indexed_word_val(); result = UP - op2; COND_SET_FLAG_N_16(result); @@ -932,7 +903,9 @@ t_stat sim_instr (void) condevalVs16(UP, op2); COND_SET_FLAG_C_16(result); break; + case 0xAC: /* CMPS ind */ + /* Do not modify SP */ op2 = get_indexed_word_val(); result = SP - op2; COND_SET_FLAG_N_16(result); @@ -940,7 +913,9 @@ t_stat sim_instr (void) condevalVs16(SP, op2); COND_SET_FLAG_C_16(result); break; + case 0xB3: /* CMPU ext */ + /* Do not modify UP */ op2 = get_ext_word_val(); result = UP - op2; COND_SET_FLAG_N_16(result); @@ -948,7 +923,9 @@ t_stat sim_instr (void) condevalVs16(UP, op2); COND_SET_FLAG_C_16(result); break; + case 0xBC: /* CMPS ext */ + /* Do not modify SP */ op2 = get_ext_word_val(); result = SP - op2; COND_SET_FLAG_N_16(result); @@ -956,36 +933,45 @@ t_stat sim_instr (void) condevalVs16(SP, op2); COND_SET_FLAG_C_16(result); break; + + default: + reason = STOP_OPCODE; /* stop simulation */ + break; } break; + case 0x12: /* NOP */ break; + case 0x13: /* SYNC inherent*/ /* Interrupts are not implemented */ reason = STOP_HALT; /* stop simulation */ break; + case 0x16: /* LBRA relative */ go_long_rel(1); break; + case 0x17: /* LBSR relative */ addr = get_long_rel_addr(); push_sp_word(PC); PC = (PC + addr) & ADDRMASK; break; + case 0x19: /* DAA inherent */ lo = A & 0x0F; + hi = (A >> 4) & 0x0F; if ((lo > 9) || get_flag(HF)) { - lo += 6; - A = (A & 0xF0) + lo; - COND_SET_FLAG(lo & 0x10, HF); + /* add correction factor of 0x06 for lower nybble */ + A += 0x06; } - hi = (A >> 4) & 0x0F; - if ((hi > 9) || get_flag(CF)) { - hi += 6; - A = (A & 0x0F) | (hi << 4) | 0x100; + if ((hi > 9) || get_flag(CF) || ((hi > 8) && (lo > 9))) { + /* add correction factor of 0x60 for upper nybble */ + A += 0x60; + A |= 0x100; /* set the C flag */ } COND_SET_FLAG_C(A); - A &= 0xFF; + A = A & BYTEMASK; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); break; @@ -993,9 +979,11 @@ t_stat sim_instr (void) case 0x1A: /* ORCC imm */ CCR = CCR | get_imm_byte_val(); break; + case 0x1C: /* ANDCC imm */ CCR = CCR & get_imm_byte_val(); break; + case 0x1D: /* SEX inherent */ if (B & 0x80) { A = 0xFF; @@ -1005,6 +993,7 @@ t_stat sim_instr (void) COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); break; + case 0x1E: /* EXG imm */ Post_Byte = get_imm_byte_val(); Src_Nybble = (Post_Byte >> 4) & 0x0F; @@ -1013,7 +1002,6 @@ t_stat sim_instr (void) // EXG with unaligned register sizes reason = STOP_OPCODE; } - /* read register values */ if (Src_Nybble <= 5 && Dest_Nybble <= 5) { /* 16-bit register */ @@ -1114,10 +1102,9 @@ t_stat sim_instr (void) Src_Nybble = Post_Byte >> 4; if ((Src_Nybble <= 5 && Dest_Nybble > 5) || (Src_Nybble > 5 && Dest_Nybble <= 5)) { // TFR with unaligned register sizes + // NOTE: Hitachi 6809 documentation does describe some scenarios for mis-matched register sizes! reason = STOP_OPCODE; } - - if ((Src_Nybble <= 5) && (Dest_Nybble <= 5)) { /* 16-bit registers */ /* read source register */ @@ -1171,13 +1158,12 @@ t_stat sim_instr (void) break; case 0x21: /* BRN rel */ /* Branch Never - essentially a NOP */ - go_rel(0); break; case 0x22: /* BHI rel */ - go_rel(!(get_flag(CF) | get_flag(ZF))); + go_rel(!(get_flag(CF) || get_flag(ZF))); break; case 0x23: /* BLS rel */ - go_rel(get_flag(CF) | get_flag(ZF)); + go_rel(get_flag(CF) || get_flag(ZF)); break; case 0x24: /* BCC rel */ go_rel(!get_flag(CF)); @@ -1204,35 +1190,34 @@ t_stat sim_instr (void) go_rel(get_flag(NF)); break; case 0x2C: /* BGE rel */ - go_rel(!(get_flag(NF) ^ get_flag(VF))); + go_rel(get_flag(NF) == get_flag(VF)); break; case 0x2D: /* BLT rel */ - go_rel(get_flag(NF) ^ get_flag(VF)); + go_rel(get_flag(NF) != get_flag(VF)); break; case 0x2E: /* BGT rel */ - go_rel( !( get_flag(ZF) | (get_flag(NF) ^ get_flag(VF)) ) ); + go_rel((get_flag(ZF) == 0) && (get_flag(NF) == get_flag(VF))); break; case 0x2F: /* BLE rel */ - go_rel( get_flag(ZF) | (get_flag(NF) ^ get_flag(VF)) ); + go_rel(get_flag(ZF) || (get_flag(NF) != get_flag(VF))); break; - /* 0x30 */ - case 0x30: /* LEAX */ + case 0x30: /* LEAX ind */ IX = get_indexed_addr(); COND_SET_FLAG_Z_16(IX); break; - case 0x31: /* LEAY */ + case 0x31: /* LEAY ind */ IY = get_indexed_addr(); COND_SET_FLAG_Z_16(IY); break; - case 0x32: /* LEAS */ + case 0x32: /* LEAS ind */ SP = get_indexed_addr(); /* does not affect CCR */ break; - case 0x33: /* LEAU */ + case 0x33: /* LEAU ind */ UP = get_indexed_addr(); /* does not affect CCR */ break; @@ -1297,7 +1282,7 @@ t_stat sim_instr (void) case 0x3B: /* RTI */ CCR = pop_sp_byte(); - if (GET_FLAG(EF)) { + if (get_flag(EF)) { /* entire state flag */ A = pop_sp_byte(); B = pop_sp_byte(); @@ -1322,19 +1307,14 @@ t_stat sim_instr (void) push_sp_byte(B); push_sp_byte(A); push_sp_byte(CCR); - if (get_flag(IF)) { - reason = STOP_HALT; - continue; - } else { - SET_FLAG(IF); - PC = CPU_BD_get_mword(0xFFFE) & ADDRMASK; - } + /* wait for an interrupt */ + reason = STOP_HALT; break; case 0x3D: /* MUL */ D = A * B; - A = D >> 8; B = D & BYTEMASK; + A = D >> 8; COND_SET_FLAG_Z_16(D); COND_SET_FLAG(B & 0x80, CF); break; @@ -1351,18 +1331,19 @@ t_stat sim_instr (void) push_sp_byte(CCR); SET_FLAG(FF); SET_FLAG(IF); - PC = CPU_BD_get_mword(0xFFFA) & ADDRMASK; + PC = CPU_BD_get_mword(0xFFFA); break; /* 0x40 - inherent mode */ case 0x40: /* NEGA */ COND_SET_FLAG(A != 0, CF); COND_SET_FLAG(A == 0x80, VF); - A = 0 - A; + A = 0 - A; A &= 0xFF; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); break; + case 0x43: /* COMA */ A = ~A; A &= 0xFF; @@ -1371,6 +1352,7 @@ t_stat sim_instr (void) CLR_FLAG(VF); SET_FLAG(CF); break; + case 0x44: /* LSRA */ COND_SET_FLAG(A & 0x01, CF); A = (A >> 1) & BYTEMASK; @@ -1378,16 +1360,19 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(A); /* H,V unaffected */ break; + case 0x46: /* RORA */ - hi = get_flag(CF); - COND_SET_FLAG(A & 0x01, CF); + op1 = A; A = A >> 1; - if (hi) + if (get_flag(CF)) { A |= 0x80; + } COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); /* H,V unaffected */ + COND_SET_FLAG(op1 & 0x01, CF); break; + case 0x47: /* ASRA */ COND_SET_FLAG(A & 0x01, CF); A = (A >> 1) | (A & 0x80); @@ -1396,41 +1381,51 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(A); /* V unaffected */ break; + case 0x48: /* ASLA */ - COND_SET_FLAG(A & 0x80, CF); + op1 = A; A = (A << 1) & BYTEMASK; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); - COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + COND_SET_FLAG(op1 & 0x80, CF); + COND_SET_FLAG(EXOR(get_flag(NF),get_flag(CF)), VF); break; + case 0x49: /* ROLA */ - hi = get_flag(CF); - COND_SET_FLAG(A & 0x80, CF); + op1 = A; A = (A << 1) & BYTEMASK; - if (hi) + if (get_flag(CF)) { A |= 0x01; + } COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); - COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + COND_SET_FLAG(op1 & 0x80, CF); + COND_SET_FLAG(EXOR(get_flag(NF),get_flag(CF)), VF); break; + case 0x4A: /* DECA */ COND_SET_FLAG(A == 0x80, VF); A = (A - 1) & BYTEMASK; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); + /* C unaffected */ break; + case 0x4C: /* INCA */ COND_SET_FLAG(A == 0x7F, VF); A = (A + 1) & BYTEMASK; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); + /* C unaffected */ break; + case 0x4D: /* TSTA */ COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); CLR_FLAG(VF); - /* C not affected */ + /* C unaffected */ break; + case 0x4F: /* CLRA */ A = 0; CLR_FLAG(NF); @@ -1443,11 +1438,12 @@ t_stat sim_instr (void) case 0x50: /* NEGB */ COND_SET_FLAG(B != 0, CF); COND_SET_FLAG(B == 0x80, VF); - B = (0 - B); + B = 0 - B; B &= 0xFF; COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); break; + case 0x53: /* COMB */ B = ~B; B &= 0xFF; @@ -1456,6 +1452,7 @@ t_stat sim_instr (void) CLR_FLAG(VF); SET_FLAG(CF); break; + case 0x54: /* LSRB */ COND_SET_FLAG(B & 0x01, CF); B = (B >> 1) & BYTEMASK; @@ -1463,16 +1460,19 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(B); /* H,V unaffected */ break; + case 0x56: /* RORB */ - hi = get_flag(CF); - COND_SET_FLAG(B & 0x01, CF); + op1 = B; B = B >> 1; - if (hi) + if (get_flag(CF)) { B |= 0x80; + } COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); /* H,V unaffected */ + COND_SET_FLAG(op1 & 0x01, CF); break; + case 0x57: /* ASRB */ COND_SET_FLAG(B & 0x01, CF); B = (B >> 1) | (B & 0x80); @@ -1481,41 +1481,51 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(B); /* C unaffected */ break; + case 0x58: /* ASLB */ - COND_SET_FLAG(B & 0x80, CF); + op1 = B; B = (B << 1) & BYTEMASK; COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); - COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + COND_SET_FLAG(op1 & 0x80, CF); + COND_SET_FLAG(EXOR(get_flag(NF),get_flag(CF)), VF); break; + case 0x59: /* ROLB */ - hi = get_flag(CF); - COND_SET_FLAG(B & 0x80, CF); + op1 = B; B = (B << 1) & BYTEMASK; - if (hi) + if (get_flag(CF)) { B |= 0x01; + } COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); - COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + COND_SET_FLAG(op1 & 0x80, CF); + COND_SET_FLAG(EXOR(get_flag(NF),get_flag(CF)), VF); break; + case 0x5A: /* DECB */ COND_SET_FLAG(B == 0x80, VF); B = (B - 1) & BYTEMASK; COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); + /* C unaffected */ break; + case 0x5C: /* INCB */ COND_SET_FLAG(B == 0x7F, VF); B = (B + 1) & BYTEMASK; COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); + /* C unaffected */ break; + case 0x5D: /* TSTB */ COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); CLR_FLAG(VF); - /* C not affected */ + /* C unaffected */ break; + case 0x5F: /* CLRB */ B = 0; CLR_FLAG(NF); @@ -1535,39 +1545,43 @@ t_stat sim_instr (void) COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); break; + case 0x63: /* COM ind */ addr = get_indexed_addr(); op1 = CPU_BD_get_mbyte(addr); - result = ~op1; - result &= 0xFF; + result = (~op1) & 0xFF; CPU_BD_put_mbyte(addr, result); COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); CLR_FLAG(VF); SET_FLAG(CF); break; + case 0x64: /* LSR ind */ addr = get_indexed_addr(); op1 = CPU_BD_get_mbyte(addr); - COND_SET_FLAG(op1 & 0x01, CF); result = op1 >> 1; CPU_BD_put_mbyte(addr, result); CLR_FLAG(NF); COND_SET_FLAG_Z(result); /* H,V unaffected */ + COND_SET_FLAG(op1 & 0x01, CF); break; + case 0x66: /* ROR ind */ addr = get_indexed_addr(); op1 = CPU_BD_get_mbyte(addr); result = op1 >> 1; - if (get_flag(CF)) + if (get_flag(CF)) { result |= 0x80; + } CPU_BD_put_mbyte(addr, result); - /* H,V unaffected */ COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); + /* H,V unaffected */ COND_SET_FLAG(op1 & 0x01, CF); break; + case 0x67: /* ASR ind */ addr = get_indexed_addr(); op1 = CPU_BD_get_mbyte(addr); @@ -1579,29 +1593,33 @@ t_stat sim_instr (void) /* V unaffected */ COND_SET_FLAG(op1 & 0x01, CF); break; + case 0x68: /* ASL ind */ addr = get_indexed_addr(); op1 = CPU_BD_get_mbyte(addr); - COND_SET_FLAG(op1 & 0x80, CF); result = (op1 << 1) & BYTEMASK; CPU_BD_put_mbyte(addr, result); /* H is undefined */ COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); - COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + COND_SET_FLAG(op1 & 0x80, CF); + COND_SET_FLAG(EXOR(get_flag(NF),get_flag(CF)), VF); break; + case 0x69: /* ROL ind */ addr = get_indexed_addr(); op1 = CPU_BD_get_mbyte(addr); result = (op1 << 1) & BYTEMASK; - if (get_flag(CF)) + if (get_flag(CF)) { result |= 0x01; + } CPU_BD_put_mbyte(addr, result); COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); - COND_SET_FLAG((op1 & 0x80) ^ (op1 & 0x40), VF); COND_SET_FLAG(op1 & 0x80, CF); + COND_SET_FLAG(EXOR(get_flag(NF),get_flag(CF)), VF); break; + case 0x6A: /* DEC ind */ addr = get_indexed_addr(); op1 = CPU_BD_get_mbyte(addr); @@ -1610,25 +1628,32 @@ t_stat sim_instr (void) COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); COND_SET_FLAG(op1 == 0x80, VF); + /* C unaffected */ break; + case 0x6C: /* INC ind */ addr = get_indexed_addr(); op1 = CPU_BD_get_mbyte(addr); + result = (op1 + 1) & BYTEMASK; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); COND_SET_FLAG(op1 == 0x7F, VF); - op1 = (op1 + 1) & BYTEMASK; - CPU_BD_put_mbyte(addr, op1); - COND_SET_FLAG_N(op1); - COND_SET_FLAG_Z(op1); + /* C unaffected */ break; + case 0x6D: /* TST ind */ result = get_indexed_byte_val(); COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); CLR_FLAG(VF); + /* C unaffected */ break; + case 0x6E: /* JMP ind */ PC = get_indexed_addr(); break; + case 0x6F: /* CLR ind */ CPU_BD_put_mbyte(get_indexed_addr(), 0); /* H not affected */ @@ -1649,39 +1674,43 @@ t_stat sim_instr (void) COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); break; + case 0x73: /* COM ext */ addr = get_ext_addr(); op1 = CPU_BD_get_mbyte(addr); - result = ~op1; - result &= 0xFF; + result = (~op1) & 0xFF; CPU_BD_put_mbyte(addr, result); COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); CLR_FLAG(VF); SET_FLAG(CF); break; + case 0x74: /* LSR ext */ addr = get_ext_addr(); op1 = CPU_BD_get_mbyte(addr); - COND_SET_FLAG(op1 & 0x01, CF); result = op1 >> 1; CPU_BD_put_mbyte(addr, result); CLR_FLAG(NF); COND_SET_FLAG_Z(result); /* H,V unaffected */ + COND_SET_FLAG(op1 & 0x01, CF); break; + case 0x76: /* ROR ext */ addr = get_ext_addr(); op1 = CPU_BD_get_mbyte(addr); result = op1 >> 1; - if (get_flag(CF)) + if (get_flag(CF)) { result |= 0x80; + } CPU_BD_put_mbyte(addr, result); - /* H,V unaffected */ COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); + /* H,V unaffected */ COND_SET_FLAG(op1 & 0x01, CF); break; + case 0x77: /* ASR ext */ addr = get_ext_addr(); op1 = CPU_BD_get_mbyte(addr); @@ -1693,29 +1722,33 @@ t_stat sim_instr (void) /* V unaffected */ COND_SET_FLAG(op1 & 0x01, CF); break; + case 0x78: /* ASL ext */ addr = get_ext_addr(); op1 = CPU_BD_get_mbyte(addr); - COND_SET_FLAG(op1 & 0x80, CF); result = (op1 << 1) & BYTEMASK; CPU_BD_put_mbyte(addr, result); /* H is undefined */ COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); - COND_SET_FLAG(get_flag(NF) ^ get_flag(CF), VF); + COND_SET_FLAG(op1 & 0x80, CF); + COND_SET_FLAG(EXOR(get_flag(NF),get_flag(CF)), VF); break; + case 0x79: /* ROL ext */ addr = get_ext_addr(); op1 = CPU_BD_get_mbyte(addr); result = (op1 << 1) & BYTEMASK; - if (get_flag(CF)) + if (get_flag(CF)) { result |= 0x01; + } CPU_BD_put_mbyte(addr, result); COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); - COND_SET_FLAG((op1 & 0x80) ^ (op1 & 0x40), VF); COND_SET_FLAG(op1 & 0x80, CF); + COND_SET_FLAG(EXOR(get_flag(NF),get_flag(CF)), VF); break; + case 0x7A: /* DEC ext */ addr = get_ext_addr(); op1 = CPU_BD_get_mbyte(addr); @@ -1724,25 +1757,33 @@ t_stat sim_instr (void) COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); COND_SET_FLAG(op1 == 0x80, VF); + /* C unaffected */ break; + case 0x7C: /* INC ext */ addr = get_ext_addr(); op1 = CPU_BD_get_mbyte(addr); + result = (op1 + 1) & BYTEMASK; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); COND_SET_FLAG(op1 == 0x7F, VF); - op1 = (op1 + 1) & BYTEMASK; - CPU_BD_put_mbyte(addr, op1); - COND_SET_FLAG_N(op1); - COND_SET_FLAG_Z(op1); + /* C unaffected */ break; + + /* C unaffected */ case 0x7D: /* TST ext */ result = get_ext_byte_val(); COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); CLR_FLAG(VF); + /* C unaffected */ break; + case 0x7E: /* JMP ext */ PC = get_ext_addr(); break; + case 0x7F: /* CLR ext */ CPU_BD_put_mbyte(get_ext_addr(), 0); /* H not affected */ @@ -1751,19 +1792,20 @@ t_stat sim_instr (void) CLR_FLAG(VF); CLR_FLAG(CF); break; - /* 0x80 - immediate mode (except for BSR) */ case 0x80: /* SUBA imm */ - op1 = get_imm_byte_val(); - op2 = A; - A = A - op1; + op1 = A; + op2 = get_imm_byte_val(); + A = A - op2; COND_SET_FLAG_C(A); A &= 0xFF; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); condevalVs(op1, op2); break; + case 0x81: /* CMPA imm */ + /* Do not modify A */ op2 = get_imm_byte_val(); result = A - op2; COND_SET_FLAG_C(result); @@ -1772,6 +1814,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(result); condevalVs(A, op2); break; + case 0x82: /* SBCA imm */ op1 = A; op2 = get_imm_byte_val() + get_flag(CF); @@ -1782,6 +1825,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(A); condevalVs(op1, op2); break; + case 0x83: /* SUBD imm */ D = (A << 8) | (B & BYTEMASK); op2 = get_imm_word_val(); @@ -1794,30 +1838,36 @@ t_stat sim_instr (void) COND_SET_FLAG_Z_16(result); condevalVs16(D, op2); break; + case 0x84: /* ANDA imm */ A = (A & get_imm_byte_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); break; + case 0x85: /* BITA imm */ + /* Do not modify A */ result = (A & get_imm_byte_val()) & BYTEMASK; - CLR_FLAG(VF); COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); + CLR_FLAG(VF); break; + case 0x86: /* LDA imm */ A = get_imm_byte_val(); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); CLR_FLAG(VF); break; + case 0x88: /* EORA imm */ A = (A ^ get_imm_byte_val()) & BYTEMASK; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); CLR_FLAG(VF); break; + case 0x89: /* ADCA imm */ op1 = A; op2 = get_imm_byte_val() + get_flag(CF); @@ -1829,6 +1879,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(A); condevalVa(op1, op2); break; + case 0x8A: /* ORA imm */ A = A | get_imm_byte_val(); A &= 0xFF; @@ -1836,6 +1887,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(A); CLR_FLAG(VF); break; + case 0x8B: /* ADDA imm */ op1 = A; op2 = get_imm_byte_val(); @@ -1847,20 +1899,24 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(A); condevalVa(op1, op2); break; + case 0x8C: /* CMPX imm */ + /* Do not modify X */ op2 = get_imm_word_val(); result = IX - op2; COND_SET_FLAG_C_16(result); - result = result & 0xFFFF; - COND_SET_FLAG_Z_16(result); + result &= 0xFFFF; COND_SET_FLAG_N_16(result); + COND_SET_FLAG_Z_16(result); condevalVs16(IX, op2); break; + case 0x8D: /* BSR rel */ addr = get_rel_addr(); push_sp_word(PC); PC = (PC + addr) & ADDRMASK; break; + case 0x8E: /* LDX imm */ IX = get_imm_word_val(); COND_SET_FLAG_N_16(IX); @@ -1872,14 +1928,16 @@ t_stat sim_instr (void) case 0x90: /* SUBA dir */ op1 = A; op2 = get_dir_byte_val(); - A = A - op2; + A = A - op2; COND_SET_FLAG_C(A); A &= 0xFF; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); condevalVs(op1, op2); break; + case 0x91: /* CMPA dir */ + /* Do not modify A */ op2 = get_dir_byte_val(); result = A - op2; COND_SET_FLAG_C(result); @@ -1888,6 +1946,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(result); condevalVs(A, op2); break; + case 0x92: /* SBCA dir */ op1 = A; op2 = get_dir_byte_val() + get_flag(CF); @@ -1898,6 +1957,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(A); condevalVs(op1, op2); break; + case 0x93: /* SUBD dir */ D = (A << 8) | (B & BYTEMASK); op2 = get_dir_word_val(); @@ -1910,36 +1970,43 @@ t_stat sim_instr (void) COND_SET_FLAG_Z_16(result); condevalVs16(D, op2); break; + case 0x94: /* ANDA dir */ A = (A & get_dir_byte_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); break; + case 0x95: /* BITA dir */ + /* Do not modify A */ result = (A & get_dir_byte_val()) & BYTEMASK; - CLR_FLAG(VF); COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); + CLR_FLAG(VF); break; + case 0x96: /* LDA dir */ A = get_dir_byte_val(); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); CLR_FLAG(VF); break; + case 0x97: /* STA dir */ CPU_BD_put_mbyte(get_dir_addr(), A); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); CLR_FLAG(VF); break; + case 0x98: /* EORA dir */ A = (A ^ get_dir_byte_val()) & BYTEMASK; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); CLR_FLAG(VF); break; + case 0x99: /* ADCA dir */ op1 = A; op2 = get_dir_byte_val() + get_flag(CF); @@ -1951,6 +2018,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(A); condevalVa(op1, op2); break; + case 0x9A: /* ORA dir */ A = A | get_dir_byte_val(); A &= 0xFF; @@ -1958,6 +2026,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(A); CLR_FLAG(VF); break; + case 0x9B: /* ADDA dir */ op1 = A; op2 = get_dir_byte_val(); @@ -1969,7 +2038,9 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(A); condevalVa(op1, op2); break; + case 0x9C: /* CMPX dir */ + /* Do not modify X */ op2 = get_dir_word_val(); result = IX - op2; COND_SET_FLAG_C_16(result); @@ -1978,17 +2049,20 @@ t_stat sim_instr (void) COND_SET_FLAG_Z_16(result); condevalVs16(IX, op2); break; + case 0x9D: /* JSR dir */ addr = get_dir_addr(); push_sp_word(PC); PC = addr; break; + case 0x9E: /* LDX dir */ IX = get_dir_word_val(); COND_SET_FLAG_N_16(IX); COND_SET_FLAG_Z_16(IX); CLR_FLAG(VF); break; + case 0x9F: /* STX dir */ CPU_BD_put_mword(get_dir_addr(), IX); COND_SET_FLAG_N_16(IX); @@ -1998,16 +2072,18 @@ t_stat sim_instr (void) /* 0xA0 - indexed mode */ case 0xA0: /* SUBA ind */ - op1 = get_indexed_byte_val(); - result = A - op1; - A = result; + op1 = A; + op2 = get_indexed_byte_val(); + A = A - op2; COND_SET_FLAG_C(A); A &= 0xFF; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); - condevalVs(op1, result); + condevalVs(op1, op2); break; + case 0xA1: /* CMPA ind */ + /* Do not modify A */ op2 = get_indexed_byte_val(); result = A - op2; COND_SET_FLAG_C(result); @@ -2016,6 +2092,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(result); condevalVs(A, op2); break; + case 0xA2: /* SBCA ind */ op1 = A; op2 = get_indexed_byte_val() + get_flag(CF); @@ -2026,6 +2103,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(A); condevalVs(op1, op2); break; + case 0xA3: /* SUBD ind */ D = (A << 8) | (B & BYTEMASK); op2 = get_indexed_word_val(); @@ -2038,36 +2116,43 @@ t_stat sim_instr (void) COND_SET_FLAG_Z_16(result); condevalVs16(D, op2); break; + case 0xA4: /* ANDA ind */ A = (A & get_indexed_byte_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); break; + case 0xA5: /* BITA ind */ + /* Do not modify A */ result = (A & get_indexed_byte_val()) & BYTEMASK; - CLR_FLAG(VF); COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); + CLR_FLAG(VF); break; + case 0xA6: /* LDA ind */ A = get_indexed_byte_val(); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); CLR_FLAG(VF); break; + case 0xA7: /* STA ind */ CPU_BD_put_mbyte(get_indexed_addr(), A); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); CLR_FLAG(VF); break; + case 0xA8: /* EORA ind */ A = (A ^ get_indexed_byte_val()) & BYTEMASK; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); CLR_FLAG(VF); break; + case 0xA9: /* ADCA ind */ op1 = A; op2 = get_indexed_byte_val() + get_flag(CF); @@ -2079,6 +2164,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(A); condevalVa(op1, op2); break; + case 0xAA: /* ORA ind */ A = A | get_indexed_byte_val(); A &= 0xFF; @@ -2086,6 +2172,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(A); CLR_FLAG(VF); break; + case 0xAB: /* ADDA ind */ op1 = A; op2 = get_indexed_byte_val(); @@ -2097,26 +2184,31 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(A); condevalVa(op1, op2); break; + case 0xAC: /* CMPX ind */ + /* Do not modify X */ op2 = get_indexed_word_val(); - result = (IX - op2) & ADDRMASK; + result = IX - op2; COND_SET_FLAG_C_16(result); result &= 0xFFFF; COND_SET_FLAG_N_16(result); COND_SET_FLAG_Z_16(result); condevalVs16(IX, op2); break; + case 0xAD: /* JSR ind */ addr = get_indexed_addr(); push_sp_word(PC); PC = addr; break; + case 0xAE: /* LDX ind */ IX = get_indexed_word_val(); COND_SET_FLAG_N_16(IX); COND_SET_FLAG_Z_16(IX); CLR_FLAG(VF); break; + case 0xAF: /* STX ind */ CPU_BD_put_mword(get_indexed_addr(), IX); COND_SET_FLAG_N_16(IX); @@ -2135,7 +2227,9 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(A); condevalVs(op1, op2); break; + case 0xB1: /* CMPA ext */ + /* Do not modify A */ op2 = get_ext_byte_val(); result = A - op2; COND_SET_FLAG_C(result); @@ -2144,6 +2238,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(result); condevalVs(A, op2); break; + case 0xB2: /* SBCA ext */ op1 = A; op2 = get_ext_byte_val() + get_flag(CF); @@ -2154,6 +2249,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(A); condevalVs(op1, op2); break; + case 0xB3: /* SUBD ext */ D = (A << 8) | (B & BYTEMASK); op2 = get_ext_word_val(); @@ -2166,36 +2262,43 @@ t_stat sim_instr (void) COND_SET_FLAG_Z_16(result); condevalVs16(D, op2); break; + case 0xB4: /* ANDA ext */ A = (A & get_ext_byte_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); break; + case 0xB5: /* BITA ext */ + /* Do not modify A */ result = (A & get_ext_byte_val()) & BYTEMASK; - CLR_FLAG(VF); COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); + CLR_FLAG(VF); break; + case 0xB6: /* LDA ext */ A = get_ext_byte_val(); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); CLR_FLAG(VF); break; + case 0xB7: /* STA ext */ CPU_BD_put_mbyte(get_ext_addr(), A); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); CLR_FLAG(VF); break; + case 0xB8: /* EORA ext */ A = (A ^ get_ext_byte_val()) & BYTEMASK; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); CLR_FLAG(VF); break; + case 0xB9: /* ADCA ext */ op1 = A; op2 = get_ext_byte_val() + get_flag(CF); @@ -2207,6 +2310,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(A); condevalVa(op1, op2); break; + case 0xBA: /* ORA ext */ A = A | get_ext_byte_val(); A &= 0xFF; @@ -2214,6 +2318,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(A); CLR_FLAG(VF); break; + case 0xBB: /* ADDA ext */ op1 = A; op2 = get_ext_byte_val(); @@ -2225,26 +2330,31 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(A); condevalVa(op1, op2); break; + case 0xBC: /* CMPX ext */ + /* Do not modify X */ op2 = get_ext_word_val(); - result = (IX - op2); + result = IX - op2; COND_SET_FLAG_C_16(result); - result = result & 0xFFFF; + result &= 0xFFFF; COND_SET_FLAG_N_16(result); COND_SET_FLAG_Z_16(result); condevalVs16(IX, op2); break; + case 0xBD: /* JSR ext */ addr = get_ext_addr(); push_sp_word(PC); PC = addr; break; + case 0xBE: /* LDX ext */ IX = get_ext_word_val(); COND_SET_FLAG_N_16(IX); COND_SET_FLAG_Z_16(IX); CLR_FLAG(VF); break; + case 0xBF: /* STX ext */ CPU_BD_put_mword(get_ext_addr(), IX); COND_SET_FLAG_N_16(IX); @@ -2263,7 +2373,9 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(B); condevalVs(op1, op2); break; + case 0xC1: /* CMPB imm */ + /* Do not modify B */ op2 = get_imm_byte_val(); result = B - op2; COND_SET_FLAG_C(result); @@ -2272,6 +2384,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(result); condevalVs(B, op2); break; + case 0xC2: /* SBCB imm */ op1 = B; op2 = get_imm_byte_val() + get_flag(CF); @@ -2282,6 +2395,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(B); condevalVs(op1, op2); break; + case 0xC3: /* ADDD imm */ op1 = (A << 8) | (B & BYTEMASK); op2 = get_imm_word_val(); @@ -2292,32 +2406,38 @@ t_stat sim_instr (void) B = D & BYTEMASK; COND_SET_FLAG_N_16(D); COND_SET_FLAG_Z_16(D); - condevalVa16(op1,op2); + condevalVa16(op1, op2); break; + case 0xC4: /* ANDB imm */ B = (B & get_imm_byte_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); break; + case 0xC5: /* BITB imm */ + /* Do not modify B */ result = (B & get_imm_byte_val()) & BYTEMASK; - CLR_FLAG(VF); COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); + CLR_FLAG(VF); break; + case 0xC6: /* LDB imm */ B = get_imm_byte_val(); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); CLR_FLAG(VF); break; + case 0xC8: /* EORB imm */ B = (B ^ get_imm_byte_val()) & BYTEMASK; COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); CLR_FLAG(VF); break; + case 0xC9: /* ADCB imm */ op1 = B; op2 = get_imm_byte_val() + get_flag(CF); @@ -2329,6 +2449,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(B); condevalVa(op1, op2); break; + case 0xCA: /* ORB imm */ B = B | get_imm_byte_val(); B &= 0xFF; @@ -2336,6 +2457,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(B); CLR_FLAG(VF); break; + case 0xCB: /* ADDB imm */ op1 = B; op2 = get_imm_byte_val(); @@ -2347,14 +2469,16 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(B); condevalVa(op1, op2); break; + case 0xCC: /* LDD imm */ D = get_imm_word_val(); - A = D >> 8; B = D & BYTEMASK; + A = D >> 8; COND_SET_FLAG_N_16(D); COND_SET_FLAG_Z_16(D); CLR_FLAG(VF); break; + case 0xCE: /* LDU imm */ UP = get_imm_word_val(); COND_SET_FLAG_N_16(UP); @@ -2373,7 +2497,9 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(B); condevalVs(op1, op2); break; + case 0xD1: /* CMPB dir */ + /* Do not modify B */ op2 = get_dir_byte_val(); result = B - op2; COND_SET_FLAG_C(result); @@ -2382,6 +2508,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(result); condevalVs(B, op2); break; + case 0xD2: /* SBCB dir */ op1 = B; op2 = get_dir_byte_val() + get_flag(CF); @@ -2392,6 +2519,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(B); condevalVs(op1, op2); break; + case 0xD3: /* ADDD dir */ op1 = (A << 8) | (B & BYTEMASK); op2 = get_dir_word_val(); @@ -2404,36 +2532,43 @@ t_stat sim_instr (void) COND_SET_FLAG_Z_16(D); condevalVa16(op1, op2); break; + case 0xD4: /* ANDB dir */ B = (B & get_dir_byte_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); break; + case 0xD5: /* BITB dir */ + /* Do not modify B */ result = (B & get_dir_byte_val()) & BYTEMASK; - CLR_FLAG(VF); COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); + CLR_FLAG(VF); break; + case 0xD6: /* LDB dir */ B = get_dir_byte_val(); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); CLR_FLAG(VF); break; + case 0xD7: /* STB dir */ CPU_BD_put_mbyte(get_dir_addr(), B); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); CLR_FLAG(VF); break; + case 0xD8: /* EORB dir */ B = (B ^ get_dir_byte_val()) & BYTEMASK; COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); CLR_FLAG(VF); break; + case 0xD9: /* ADCB dir */ op1 = B; op2 = get_dir_byte_val() + get_flag(CF); @@ -2445,6 +2580,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(B); condevalVa(op1, op2); break; + case 0xDA: /* ORB dir */ B = B | get_dir_byte_val(); B &= 0xFF; @@ -2452,6 +2588,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(B); CLR_FLAG(VF); break; + case 0xDB: /* ADDB dir */ op1 = B; op2 = get_dir_byte_val(); @@ -2463,14 +2600,16 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(B); condevalVa(op1, op2); break; + case 0xDC: /* LDD dir */ D = get_dir_word_val(); - A = D >> 8; B = D & BYTEMASK; + A = D >> 8; COND_SET_FLAG_N_16(D); COND_SET_FLAG_Z_16(D); CLR_FLAG(VF); break; + case 0xDD: /* STD dir */ D = (A << 8) | (B & BYTEMASK); CPU_BD_put_mword(get_dir_addr(), D); @@ -2478,12 +2617,14 @@ t_stat sim_instr (void) COND_SET_FLAG_Z_16(D); CLR_FLAG(VF); break; + case 0xDE: /* LDU dir */ UP = get_dir_word_val(); COND_SET_FLAG_N_16(UP); COND_SET_FLAG_Z_16(UP); CLR_FLAG(VF); break; + case 0xDF: /* STU dir */ CPU_BD_put_mword(get_dir_addr(), UP); COND_SET_FLAG_N_16(UP); @@ -2502,7 +2643,9 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(B); condevalVs(op1, op2); break; + case 0xE1: /* CMPB ind */ + /* do not modify B */ op2 = get_indexed_byte_val(); result = B - op2; COND_SET_FLAG_C(result); @@ -2511,6 +2654,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(result); condevalVs(B, op2); break; + case 0xE2: /* SBCB ind */ op1 = B; op2 = get_indexed_byte_val() + get_flag(CF); @@ -2521,6 +2665,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(B); condevalVs(op1, op2); break; + case 0xE3: /* ADDD ind */ op1 = (A << 8) | (B & BYTEMASK); op2 = get_indexed_word_val(); @@ -2533,36 +2678,43 @@ t_stat sim_instr (void) COND_SET_FLAG_Z_16(D); condevalVa16(op1, op2); break; + case 0xE4: /* ANDB ind */ B = (B & get_indexed_byte_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); break; + case 0xE5: /* BITB ind */ + /* Do not modify B */ result = (B & get_indexed_byte_val()) & BYTEMASK; - CLR_FLAG(VF); COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); + CLR_FLAG(VF); break; + case 0xE6: /* LDB ind */ B = get_indexed_byte_val(); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); CLR_FLAG(VF); break; + case 0xE7: /* STB ind */ CPU_BD_put_mbyte(get_indexed_addr(), B); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); CLR_FLAG(VF); break; + case 0xE8: /* EORB ind */ B = (B ^ get_indexed_byte_val()) & BYTEMASK; COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); CLR_FLAG(VF); break; + case 0xE9: /* ADCB ind */ op1 = B; op2 = get_indexed_byte_val() + get_flag(CF); @@ -2574,6 +2726,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(B); condevalVa(op1, op2); break; + case 0xEA: /* ORB ind */ B = B | get_indexed_byte_val(); B &= 0xFF; @@ -2581,6 +2734,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(B); CLR_FLAG(VF); break; + case 0xEB: /* ADDB ind */ op1 = B; op2 = get_indexed_byte_val(); @@ -2592,14 +2746,16 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(B); condevalVa(op1, op2); break; + case 0xEC: /* LDD ind */ D = get_indexed_word_val(); - A = D >> 8; B = D & BYTEMASK; + A = D >> 8; COND_SET_FLAG_N_16(D); COND_SET_FLAG_Z_16(D); CLR_FLAG(VF); break; + case 0xED: /* STD ind */ D = (A << 8) | (B & BYTEMASK); CPU_BD_put_mword(get_indexed_addr(), D); @@ -2607,12 +2763,14 @@ t_stat sim_instr (void) COND_SET_FLAG_Z_16(D); CLR_FLAG(VF); break; + case 0xEE: /* LDU ind */ UP = get_indexed_word_val(); COND_SET_FLAG_N_16(UP); COND_SET_FLAG_Z_16(UP); CLR_FLAG(VF); break; + case 0xEF: /* STU ind */ CPU_BD_put_mword(get_indexed_addr(), UP); COND_SET_FLAG_N_16(UP); @@ -2631,7 +2789,9 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(B); condevalVs(op1, op2); break; + case 0xF1: /* CMPB ext */ + /* Do not modify B */ op2 = get_ext_byte_val(); result = B - op2; COND_SET_FLAG_C(result); @@ -2640,6 +2800,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(result); condevalVs(B, op2); break; + case 0xF2: /* SBCB ext */ op1 = B; op2 = get_ext_byte_val() + get_flag(CF); @@ -2650,6 +2811,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(B); condevalVs(op1, op2); break; + case 0xF3: /* ADDD ext */ op1 = (A << 8) | (B & BYTEMASK); op2 = get_ext_word_val(); @@ -2662,36 +2824,43 @@ t_stat sim_instr (void) COND_SET_FLAG_Z_16(D); condevalVa16(op1, op2); break; + case 0xF4: /* ANDB ext */ B = (B & get_ext_byte_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); break; + case 0xF5: /* BITB ext */ + /* Do not modify B */ result = (B & get_ext_byte_val()) & BYTEMASK; - CLR_FLAG(VF); COND_SET_FLAG_N(result); COND_SET_FLAG_Z(result); + CLR_FLAG(VF); break; + case 0xF6: /* LDB ext */ B = get_ext_byte_val(); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); CLR_FLAG(VF); break; + case 0xF7: /* STB ext */ CPU_BD_put_mbyte(get_ext_addr(), B); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); CLR_FLAG(VF); break; + case 0xF8: /* EORB ext */ B = (B ^ get_ext_byte_val()) & BYTEMASK; COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); CLR_FLAG(VF); break; + case 0xF9: /* ADCB ext */ op1 = B; op2 = get_ext_byte_val() + get_flag(CF); @@ -2703,6 +2872,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(B); condevalVa(op1, op2); break; + case 0xFA: /* ORB ext */ B = B | get_ext_byte_val(); B &= 0xFF; @@ -2710,6 +2880,7 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(B); CLR_FLAG(VF); break; + case 0xFB: /* ADDB ext */ op1 = B; op2 = get_ext_byte_val(); @@ -2721,14 +2892,16 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(B); condevalVa(op1, op2); break; + case 0xFC: /* LDD ext */ D = get_ext_word_val(); - A = D >> 8; B = D & BYTEMASK; + A = D >> 8; COND_SET_FLAG_N_16(D); COND_SET_FLAG_Z_16(D); CLR_FLAG(VF); break; + case 0xFD: /* STD ext */ D = (A << 8) | (B & BYTEMASK); CPU_BD_put_mword(get_ext_addr(), D); @@ -2736,12 +2909,14 @@ t_stat sim_instr (void) COND_SET_FLAG_Z_16(D); CLR_FLAG(VF); break; + case 0xFE: /* LDU ext */ UP = get_ext_word_val(); COND_SET_FLAG_N_16(UP); COND_SET_FLAG_Z_16(UP); CLR_FLAG(VF); break; + case 0xFF: /* STU ext */ CPU_BD_put_mword(get_ext_addr(), UP); COND_SET_FLAG_N_16(UP); @@ -2749,7 +2924,7 @@ t_stat sim_instr (void) CLR_FLAG(VF); break; - default: /* Unassigned */ + default: /* Unassigned opcode */ if (m6809_unit.flags & UNIT_OPSTOP) { reason = STOP_OPCODE; PC--; @@ -2780,16 +2955,15 @@ void dump_regs1(void) /* fetch an instruction or byte */ int32 fetch_byte(int32 flag) { - uint8 val; + int32 val; val = CPU_BD_get_mbyte(PC); /* fetch byte */ - switch (flag) { - case 0: /* opcode fetch */ - sim_debug (DEBUG_asm, &m6809_dev, "%04X %s\n", PC, opcode[val]); - break; - case 1: /* byte operand fetch */ - sim_debug (DEBUG_asm, &m6809_dev, "0x%02XH\n", val); - break; + if (flag == 0) { + /* opcode fetch */ + sim_debug(DEBUG_asm, &m6809_dev, "%04X: %s\n", PC, opcode[val]); + } else { + /* byte operand fetch */ + sim_debug(DEBUG_asm, &m6809_dev, "%04X: 0x%02XH\n", PC, val); } PC = (PC + 1) & ADDRMASK; /* increment PC */ return val; @@ -2798,15 +2972,16 @@ int32 fetch_byte(int32 flag) /* fetch a word - big endian */ int32 fetch_word() { - uint16 val; + int32 val; + int32 temp_pc = PC; val = CPU_BD_get_mbyte(PC) << 8; /* fetch high byte */ - val |= (CPU_BD_get_mbyte(PC + 1)); /* fetch low byte */ + PC = (PC + 1) & ADDRMASK; + val = val | CPU_BD_get_mbyte(PC); /* fetch low byte */ + PC = (PC + 1) & ADDRMASK; /* 2-byte operand fetch */ - sim_debug (DEBUG_asm, &m6809_dev, "0x%04XH\n", val); - - PC = (PC + 2) & ADDRMASK; /* increment PC */ + sim_debug(DEBUG_asm, &m6809_dev, "%04X: 0x%04XH\n", temp_pc, val); return val; } @@ -2884,7 +3059,7 @@ void go_rel(int32 cond) int32 temp; temp = get_rel_addr(); - if (cond) { + if (cond != 0) { PC += temp; PC &= ADDRMASK; } @@ -2910,37 +3085,37 @@ int32 get_rel_addr(void) temp = fetch_byte(1); if (temp & 0x80) temp |= 0xFF00; - return temp & ADDRMASK; + return(temp & ADDRMASK); } /* returns the long relative offset sign-extended */ int32 get_long_rel_addr(void) { - return fetch_word(); + return(fetch_word()); } /* returns the byte value at the direct address pointed to by PC */ int32 get_dir_byte_val(void) { - return CPU_BD_get_mbyte(get_dir_addr()); + return(CPU_BD_get_mbyte(get_dir_addr())); } /* returns the word value at the direct address pointed to by PC */ int32 get_dir_word_val(void) { - return CPU_BD_get_mword(get_dir_addr()); + return(CPU_BD_get_mword(get_dir_addr())); } /* returns the immediate byte value pointed to by PC */ int32 get_imm_byte_val(void) { - return fetch_byte(1); + return(fetch_byte(1)); } /* returns the immediate word value pointed to by PC */ int32 get_imm_word_val(void) { - return fetch_word(); + return(fetch_word()); } /* returns the direct address pointed to by PC */ @@ -2950,19 +3125,19 @@ int32 get_dir_addr(void) int32 temp; temp = (DP << 8) + fetch_byte(1); - return temp & 0xFFFF; + return(temp & ADDRMASK); } /* returns the byte value at the indexed address pointed to by PC */ int32 get_indexed_byte_val(void) { - return CPU_BD_get_mbyte(get_indexed_addr()); + return(CPU_BD_get_mbyte(get_indexed_addr())); } /* returns the word value at the indexed address pointed to by PC */ int32 get_indexed_word_val(void) { - return CPU_BD_get_mword(get_indexed_addr()); + return(CPU_BD_get_mword(get_indexed_addr())); } /* returns the indexed address. Note this also handles the indirect indexed mode */ @@ -2987,11 +3162,8 @@ int32 get_indexed_addr(void) } /* add 4 bit signed offset */ if (post_byte & 0x10) { - /* subtract offset */ - offset = (post_byte | 0xFFF0); - temp += offset; + temp += (post_byte | 0xFFF0); } else { - /* add offset */ temp += (post_byte & 0x0F); } } else { @@ -3048,11 +3220,6 @@ int32 get_indexed_addr(void) break; case 0b0101: /* R+-ACCB (non indirect)*/ - if (B & 0x80) { - offset = B | 0xFF80; - } else { - offset = B; - } switch ( post_byte & 0x60 ) { case 0b00000000: temp = IX; break; case 0b00100000: temp = IY; break; @@ -3060,15 +3227,15 @@ int32 get_indexed_addr(void) case 0b01100000: temp = SP; break; default: break; }; + if (B & 0x80) { + offset = B | 0xFF80; + } else { + offset = B; + } temp += offset; break; case 0b0110: /* R+-ACCA (non indirect)*/ - if (A & 0x80) { - offset = A | 0xFF80; - } else { - offset = A; - } switch ( post_byte & 0x60 ) { case 0b00000000: temp = IX; break; case 0b00100000: temp = IY; break; @@ -3076,6 +3243,11 @@ int32 get_indexed_addr(void) case 0b01100000: temp = SP; break; default: break; }; + if (A & 0x80) { + offset = A | 0xFF80; + } else { + offset = A; + } temp += offset; break; case 0b1000: @@ -3089,13 +3261,12 @@ int32 get_indexed_addr(void) }; /* need to fetch 8-bit operand */ offset = fetch_byte(1); - /* add 7 bit signed offset */ if (offset & 0x80) { - /* subtract offset */ - offset |= 0xFF00; - } - temp += offset; + temp += offset | 0xFF80; + } else { + temp += offset; + } break; case 0b1001: /* R+- 16-bit offset */ @@ -3108,8 +3279,8 @@ int32 get_indexed_addr(void) }; /* need to fetch 16-bit operand */ offset = fetch_word(); - /* add 16 bit signed offset */ + /* calculation is the same for negative or positive offset! */ temp += offset; break; case 0b1011: @@ -3127,25 +3298,23 @@ int32 get_indexed_addr(void) /* PC+- 7-bit offset (non indirect) */ /* need to fetch 8-bit operand */ offset = fetch_byte(1); - // PC value after fetch!!! - temp = PC; + // PC value updated after fetch!!! /* add 7 bit signed offset */ if (offset & 0x80) { - /* subtract offset */ - offset |= 0xFF00; + temp = PC + (offset | 0xFF80); + } else { + temp = PC + offset; } - temp += offset; break; case 0b1101: /* PC+- 15-bit offset (non indirect)*/ /* need to fetch 16-bit operand */ offset = fetch_word(); - // PC value after fetch!!! - temp = PC; + // PC value updated after fetch!!! /* add 15 bit signed offset */ - temp += offset; + temp = PC + offset; break; case 0b1111: // Extended indirect - fetch 16-bit address @@ -3172,7 +3341,7 @@ int32 get_indexed_addr(void) } } /* make sure to truncate to 16-bit value */ - return temp & 0xFFFF; + return(temp & 0xFFFF); } /* returns the value at the extended address pointed to by PC */ @@ -3197,7 +3366,7 @@ int32 get_ext_addr(void) } /* return 1 for flag set or 0 for flag clear */ -int32 get_flag(int32 flg) +inline int32 get_flag(int32 flg) { if (CCR & flg) { return 1; @@ -3210,56 +3379,73 @@ int32 get_flag(int32 flg) /* test and set V for 8-addition */ void condevalVa(int32 op1, int32 op2) { - if (((op1 & 0x80) == (op2 & 0x80)) && - (((op1 + op2) & 0x80) != (op1 & 0x80))) + int32 temp; + + /* op1 + op2 */ + // If 2 Two's Complement numbers are added, and they both have the same sign (both positive or both negative), + // then overflow occurs if and only if the result has the opposite sign. + // Overflow never occurs when adding operands with different signs. + temp = op1 + op2; + if ( ((op1 & 0x80) == (op2 & 0x80)) && ((temp & 0x80) != (op1 & 0x80)) ) { SET_FLAG(VF); - else + } else { CLR_FLAG(VF); + } } /* test and set V for 16-bit addition */ void condevalVa16(int32 op1, int32 op2) { - /* - IF (the sign of the 2 operands are the same) - AND - (the sum of the operands has a different sign than both of the 2 operands) - THEN set the Overflow flag - ELSE clear the Overflow flag - */ - if (((op1 & 0x8000) == (op2 & 0x8000)) && - (((op1 + op2) & 0x8000) != (op1 & 0x8000))) + int32 temp; + + /* op1 + op2 */ + // If 2 Two's Complement numbers are added, and they both have the same sign (both positive or both negative), + // then overflow occurs if and only if the result has the opposite sign. + // Overflow never occurs when adding operands with different signs. + temp = op1 + op2; + if ( ((op1 & 0x8000) == (op2 & 0x8000)) && ((temp & 0x8000) != (op1 & 0x8000)) ) { SET_FLAG(VF); - else + } else { CLR_FLAG(VF); + } } /* test and set V for 8-bit subtraction */ void condevalVs(int32 op1, int32 op2) { - if (((op1 & 0x80) != (op2 & 0x80)) && - (((op1 - op2) & 0x80) == (op2 & 0x80))) + int32 temp; + + /* op1 - op2 */ + // If 2 Two's Complement numbers are subtracted, and their signs are different, + // then overflow occurs if and only if the result has the same sign as the subtrahend (op2). + temp = op1 - op2; + if ( ((op1 & 0x80) != (op2 & 0x80)) && ((temp & 0x80) == (op2 & 0x80)) ) { SET_FLAG(VF); - else + } else { CLR_FLAG(VF); - + } } /* test and set V for 16-bit subtraction */ void condevalVs16(int32 op1, int32 op2) { - if (((op1 & 0x8000) != (op2 & 0x8000)) && - (((op1 - op2) & 0x8000) == (op2 & 0x8000))) + int32 temp; + + /* op1 - op2 */ + // If 2 Two's Complement numbers are subtracted, and their signs are different, + // then overflow occurs if and only if the result has the same sign as the subtrahend (op2). + temp = op1 - op2; + if ( ((op1 & 0x8000) != (op2 & 0x8000)) && ((temp & 0x8000) == (op2 & 0x8000)) ) { SET_FLAG(VF); - else + } else { CLR_FLAG(VF); - + } } /* test and set H for addition (8-bit only) */ void condevalHa(int32 op1, int32 op2) { - if (((op1 & 0x0f) + (op2 & 0x0f)) & 0x10) + if (((op1 & 0x0F) + (op2 & 0x0F)) > 0x0F) SET_FLAG(HF); else CLR_FLAG(HF); @@ -3270,6 +3456,8 @@ void condevalHa(int32 op1, int32 op2) /* Boot routine */ t_stat m6809_boot(int32 unit_num, DEVICE *dptr) { + sim_debug(DEBUG_flow, &m6809_dev, "Call to m6809_boot()\n"); + /* retrieve the reset vector at $FFFE */ saved_PC = CPU_BD_get_mword(0xFFFE); if (saved_PC == 0xFFFF) { @@ -3281,6 +3469,8 @@ t_stat m6809_boot(int32 unit_num, DEVICE *dptr) /* Reset routine */ t_stat m6809_reset (DEVICE *dptr) { + sim_debug(DEBUG_flow, &m6809_dev, "Call to m6809_reset()\n"); + CCR = EF | FF | IF; DP = 0; int_req = 0; @@ -3297,11 +3487,15 @@ t_stat m6809_reset (DEVICE *dptr) /* examine routine */ t_stat m6809_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) { - if (addr >= 0x10000) { + sim_debug(DEBUG_flow, &m6809_dev, "Call to m6809_examine()\n"); + + if (addr > ADDRMASK) { /* exceed 16-bit address space */ return SCPE_NXM; } else { - *eval_array = CPU_BD_get_mbyte(addr); + if (eval_array != NULL) { + *eval_array = CPU_BD_get_mbyte(addr); + } return SCPE_OK; } } @@ -3309,7 +3503,9 @@ t_stat m6809_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switche /* deposit routine */ t_stat m6809_deposit(t_value value, t_addr addr, UNIT *uptr, int32 switches) { - if (addr >= 0x10000) { + sim_debug(DEBUG_flow, &m6809_dev, "Call to m6809_deposit()\n"); + + if (addr > ADDRMASK) { /* exceed 16-bit address space */ return SCPE_NXM; } else { @@ -3328,6 +3524,8 @@ t_stat sim_load (FILE *fileref, CONST char *cptr, CONST char *fnam, int flag) { int32 i, addr = 0, cnt = 0; + sim_debug(DEBUG_flow, &m6809_dev, "Call to sim_load()\n"); + if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; addr = saved_PC; while ((i = getc (fileref)) != EOF) { @@ -3353,7 +3551,9 @@ t_stat sim_load (FILE *fileref, CONST char *cptr, CONST char *fnam, int flag) */ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) { - int32 i, inst, inst1; + int32 i, inst; + + sim_debug(DEBUG_flow, &m6809_dev, "Call to fprint_sym()\n"); if (sw & SWMASK ('D')) { // dump memory for (i=0; i<16; i++) @@ -3371,27 +3571,31 @@ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) fprintf(of, "%02X", inst); return 0; } - inst1 = inst & 0xF0; + + /* lookup mnemonic in table */ fprintf (of, "%s", opcode[inst]); // mnemonic if (strlen(opcode[inst]) == 3) fprintf(of, " "); - if (inst1 == 0x20 || inst == 0x8D) { // rel operand - inst1 = val[1]; - if (val[1] & 0x80) - inst1 |= 0xFF00; - fprintf(of, " $%04X", (addr + inst1 + 2) & ADDRMASK); - } else if (inst1 == 0x80 || inst1 == 0xC0) { // imm operand - if ((inst & 0x0F) < 0x0C) - fprintf(of, " #$%02X", val[1]); - else - fprintf(of, " #$%02X%02X", val[1], val[2]); - } else if (inst1 == 0x60 || inst1 == 0xA0 || inst1 == 0xE0) // ind operand - fprintf(of, " %d,X", val[1]); - else if (inst1 == 0x70 || inst1 == 0xb0 || inst1 == 0xF0) // ext operand - fprintf(of, " $%02X%02X", val[1], val[2]); + + /* display some potential operands - this is not exact! */ + switch (oplen[inst]) { + case 0: + case 1: + break; + case 2: + fprintf(of, " $%02X", val[1]); + break; + case 3: + fprintf(of, " $%02X $%02X", val[1], val[2]); + break; + case 4: + fprintf(of, " $%02X $%02X $%02x", val[1], val[2], val[3]); + break; + } return (-(oplen[inst] - 1)); - } else + } else { return SCPE_ARG; + } } /* Symbolic input @@ -3407,7 +3611,7 @@ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) */ t_stat parse_sym (CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) { - return (-2); + return (1); } /* end of m6809.c */ diff --git a/swtp6809/common/mp-09.c b/swtp6809/common/mp-09.c index 756435c96..ec9c52791 100644 --- a/swtp6809/common/mp-09.c +++ b/swtp6809/common/mp-09.c @@ -52,7 +52,7 @@ MODIFICATIONS: 24 Apr 15 -- Modified to use simh_debug - 24 Feb 24 -- Richard Lukes - modified SWTPC mp-a2 emulator to create mp-09 emulator. + 04 Apr 24 -- Richard Lukes - modified SWTPC mp-a2 emulator to create mp-09 emulator. NOTES: @@ -133,7 +133,7 @@ DEVICE CPU_BD_dev = { CPU_BD_mod, //modifiers 1, //numunits 16, //aradix - 16, //awidth + 8, //awidth 1, //aincr 16, //dradix 8, //dwidth @@ -168,7 +168,7 @@ t_stat CPU_BD_reset (DEVICE *dptr) /* Deposit routine */ t_stat CPU_BD_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches) { - if (addr >= 0x10000) { + if (addr > ADDRMASK) { return SCPE_NXM; } else { CPU_BD_put_mbyte(addr, val); @@ -179,7 +179,7 @@ t_stat CPU_BD_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches) /* Examine routine */ t_stat CPU_BD_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) { - if (addr >= 0x10000) { + if (addr > ADDRMASK) { return SCPE_NXM; } if (eval_array != NULL) { diff --git a/swtp6809/common/mp-1m.c b/swtp6809/common/mp-1m.c index 2560d6375..89348535c 100644 --- a/swtp6809/common/mp-1m.c +++ b/swtp6809/common/mp-1m.c @@ -52,7 +52,7 @@ MODIFICATIONS: 24 Apr 15 -- Modified to use simh_debug - 24 Feb 24 -- Richard Lukes - Modified mp-8m.c to use for 1MB memory for swtp6809 emulator + 04 Apr 24 -- Richard Lukes - Modified mp-8m.c to use for 1MB memory for swtp6809 emulator NOTES: @@ -96,7 +96,7 @@ void mp_1m_put_mbyte(int32 addr, int32 val); void mp_1m_put_mword(int32 addr, int32 val); UNIT mp_1m_unit = { - UDATA (NULL, UNIT_FIX + UNIT_BINK, ONE_MEGABYTE) + UDATA (NULL, UNIT_FIX + UNIT_BUF + UNIT_BINK, ONE_MEGABYTE) }; MTAB mp_1m_mod[] = { diff --git a/swtp6809/common/mp-b3.c b/swtp6809/common/mp-b3.c index 244251b31..5bbf91f27 100644 --- a/swtp6809/common/mp-b3.c +++ b/swtp6809/common/mp-b3.c @@ -52,7 +52,7 @@ MODIFICATIONS: 24 Apr 15 -- Modified to use simh_debug - 24 Feb 24 -- Richard Lukes - Modified to emulate MP-B3 motherboard for swtp6809 emulator + 04 Apr 24 -- Richard Lukes - Modified to emulate MP-B3 motherboard for swtp6809 emulator NOTES: @@ -62,8 +62,11 @@ #include "swtp_defs.h" -#define UNIT_V_4BYTESPERSLOT (UNIT_V_UF) /* MP-1M board enable */ -#define UNIT_4BYTESPERSLOT (1 << UNIT_V_4BYTESPERSLOT) +#define UNIT_V_16BYTESPERSLOT (UNIT_V_UF) /* MP-1M board enable */ +#define UNIT_16BYTESPERSLOT (1 << UNIT_V_16BYTESPERSLOT) + +#define MASK_20BIT 0xFFFFF +#define MASK_16BIT 0xFFFF /* function prototypes */ @@ -154,8 +157,8 @@ REG MB_reg[] = { }; MTAB MB_mod[] = { - { UNIT_4BYTESPERSLOT, UNIT_4BYTESPERSLOT, "I/O port size of 4 bytes", "4BYTE", NULL, NULL }, - { UNIT_4BYTESPERSLOT, 0, "I/O port size of 16 bytes is not supported", "16BYTE", NULL, NULL }, + { UNIT_16BYTESPERSLOT, UNIT_16BYTESPERSLOT, "I/O port size of 16 bytes not implemented", "16BYTE", NULL, NULL }, + { UNIT_16BYTESPERSLOT, 0, "I/O port size of 4 bytes", "4BYTE", NULL, NULL }, { 0 } }; @@ -191,7 +194,11 @@ DEVICE MB_dev = { 0, //dctrl MB_debug, /* debflags */ NULL, //msize - NULL //lname + NULL, //logical name + NULL, //help routine + NULL, //attach help routine + NULL, //help context + NULL //device description }; /* reset */ @@ -203,7 +210,7 @@ t_stat MB_reset (DEVICE *dptr) /* Deposit routine */ t_stat MB_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches) { - if (addr >= 0x100000) { + if (addr > MASK_20BIT) { /* exceed 20-bit address space */ return SCPE_NXM; } else { @@ -215,7 +222,7 @@ t_stat MB_deposit(t_value val, t_addr addr, UNIT *uptr, int32 switches) /* Examine routine */ t_stat MB_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) { - if (addr >= 0x100000) { + if (addr > MASK_20BIT) { return SCPE_NXM; } if (eval_array != NULL) { @@ -226,83 +233,94 @@ t_stat MB_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) /* get a byte from memory */ -int32 MB_get_mbyte(int32 addr) +int32 MB_get_mbyte(int32 addr20) { int32 val; + int32 addr16; + + addr16 = addr20 & MASK_16BIT; // 20-bit physical addresses - sim_debug (DEBUG_read, &MB_dev, "MB_get_mbyte: addr=%05X\n", addr); - switch (addr & 0x0F800) { + sim_debug (DEBUG_read, &MB_dev, "MB_get_mbyte: addr=%05X\n", addr20); + switch (addr20 & 0x0F800) { case 0x0E000: /* reserved I/O space from $E000-$E01F */ - if ((addr & 0xFFFF) < 0xE020) { - val = (dev_table[(addr & 0xFFFF) - 0xE000].routine(0, 0)) & 0xFF; + /* read byte value from device */ + if (addr16 < 0xE020) { + val = (dev_table[addr16 - 0xE000].routine(0, 0)) & 0xFF; break; } case 0x0E800: case 0x0F000: case 0x0F800: /* Up to 8KB of boot ROM from $E000-$FFFF */ - val = BOOTROM_get_mbyte(addr & 0xFFFF); + val = BOOTROM_get_mbyte(addr16); sim_debug (DEBUG_read, &MB_dev, "MB_get_mbyte: EPROM=%02X\n", val); break; default: /* all the rest is RAM */ - val = mp_1m_get_mbyte(addr); + val = mp_1m_get_mbyte(addr20); if (MB_dev.dctrl & DEBUG_read) { - printf("MB_get_mbyte: mp_1m add=%05x val=%02X\n", addr, val); + printf("MB_get_mbyte: mp_1m add=%05x val=%02X\n", addr20, val); } break; } - sim_debug (DEBUG_read, &MB_dev, "MB_get_mbyte: I/O addr=%05X val=%02X\n", addr, val); + sim_debug (DEBUG_read, &MB_dev, "MB_get_mbyte: I/O addr=%05X val=%02X\n", addr20, val); return val; } /* get a word from memory */ -int32 MB_get_mword(int32 addr) +int32 MB_get_mword(int32 addr20) { int32 val; - sim_debug (DEBUG_read, &MB_dev, "MB_get_mword: addr=%04X\n", addr); - val = (MB_get_mbyte(addr) << 8); - val |= MB_get_mbyte(addr+1); - val &= 0xFFFF; - sim_debug (DEBUG_read, &MB_dev, "MB_get_mword: val=%04X\n", val); + sim_debug (DEBUG_read, &MB_dev, "MB_get_mword: addr=%05X\n", addr20); + val = (MB_get_mbyte(addr20) << 8); + val |= MB_get_mbyte(addr20+1); + val &= MASK_16BIT; + sim_debug (DEBUG_read, &MB_dev, "MB_get_mword: val=%05X\n", val); return val; } /* put a byte to memory */ -void MB_put_mbyte(int32 addr, int32 val) +void MB_put_mbyte(int32 addr20, int32 val) { + int32 retval; + int32 addr16; + + addr16 = addr20 & MASK_16BIT; + // 20-bit physical addresses - sim_debug (DEBUG_write, &MB_dev, "MB_put_mbyte: addr=%05X, val=%02X\n", addr, val); + sim_debug (DEBUG_write, &MB_dev, "MB_put_mbyte: addr=%05X, val=%02X\n", addr20, val); - switch(addr & 0xF000) { + switch(addr16 & 0xF000) { case 0xE000: /* I/O and ROM space */ - if ((addr & 0xFFFF) < 0xE020) { - dev_table[(addr & 0xFFFF) - 0xE000].routine(1, val); + if (addr16 < 0xE020) { + /* reserved I/O space from $E000-$E01F */ + /* write byte value to device */ + retval = dev_table[addr16 - 0xE000].routine(1, val); } break; case 0xF000: - /* ROM space */ + /* ROM space - READ ONLY! */ break; default: /* RAM */ - mp_1m_put_mbyte(addr, val); + mp_1m_put_mbyte(addr20, val); break; } } /* put a word to memory */ -void MB_put_mword(int32 addr, int32 val) +void MB_put_mword(int32 addr20, int32 val) { - sim_debug (DEBUG_write, &MB_dev, "MB_ptt_mword: addr=%04X, val=%04X\n", addr, val); - MB_put_mbyte(addr, val >> 8); - MB_put_mbyte(addr+1, val & 0xFF); + sim_debug (DEBUG_write, &MB_dev, "MB_ptt_mword: addr=%05X, val=%04X\n", addr20, val); + MB_put_mbyte(addr20, val >> 8); + MB_put_mbyte(addr20+1, val & 0xFF); } /* end of mp-b3.c */ diff --git a/swtp6809/swtp6809/mp-09_sys.c b/swtp6809/swtp6809/mp-09_sys.c index 3c0f79298..614f40d9c 100644 --- a/swtp6809/swtp6809/mp-09_sys.c +++ b/swtp6809/swtp6809/mp-09_sys.c @@ -60,17 +60,17 @@ /* externals */ -extern DEVICE CPU_BD_dev; -extern DEVICE m6809_dev; extern REG m6809_reg[]; -extern DEVICE BOOTROM_dev; +extern DEVICE m6809_dev; +extern DEVICE BOOTROM_dev; +extern DEVICE CPU_BD_dev; extern DEVICE MB_dev; +extern DEVICE mp_1m_dev; +extern DEVICE dsk_dev; extern DEVICE sio_dev; extern DEVICE ptr_dev; extern DEVICE ptp_dev; -extern DEVICE mp_1m_dev; -extern DEVICE dsk_dev; /* SCP data structures @@ -94,10 +94,10 @@ DEVICE *sim_devices[] = { &CPU_BD_dev, &BOOTROM_dev, &MB_dev, + &mp_1m_dev, &sio_dev, &ptr_dev, &ptp_dev, - &mp_1m_dev, &dsk_dev, NULL }; @@ -106,7 +106,7 @@ const char *sim_stop_messages[] = { "Unknown error", "RESERVED", "Halt instruction", - "Breakpoint" + "Breakpoint", "Invalid opcode", "Invalid memory", "Unknown error" diff --git a/swtp6809/swtp6809/swtp6809mp-09.ini b/swtp6809/swtp6809/swtp6809mp-09.ini index 8a33ff309..eccf97055 100644 --- a/swtp6809/swtp6809/swtp6809mp-09.ini +++ b/swtp6809/swtp6809/swtp6809mp-09.ini @@ -1,13 +1,20 @@ -reset -set mp-09 DAT -set mp-1m 1MB -set cpu hex -set cpu itrap -set dc-40 RO -set dc-41 RO -set mp-s TTY -set bootrom 2716 -attach bootrom sbuge.bin -attach dc-40 FULL.DSK -attach dc-41 FULL2.DSK -boot cpu +set mp-09 DAT +set mp-1m 1024KB +set cpu hex +set cpu itrap +set mp-s TTY +set bootrom 2716 +attach bootrom sbuge.bin +set dc-40 rw +set dc-41 rw +set dc-40 FLEX +set dc-41 FLEX +attach dc-40 FLEX292F.dsk +attach dc-40 FLEX09BT.DSK +;attach ptr exbasrom.s19 +; +;set bootrom debug=ALL +;set dc-4 debug=all +;set CPU debug=flow;asm +;set debug debug.out +SHOW DC-4 diff --git a/swtp6809/swtp6809/swtp_defs.h b/swtp6809/swtp6809/swtp_defs.h index c6e862b6a..0a9182c2f 100644 --- a/swtp6809/swtp6809/swtp_defs.h +++ b/swtp6809/swtp6809/swtp_defs.h @@ -52,12 +52,15 @@ #define DEBUG_level2 0x0010 #define DEBUG_reg 0x0020 #define DEBUG_asm 0x0040 -#define DEBUG_all 0xFFFF +#define DEBUG_all 0x007F /* Simulator stop codes */ -#define STOP_RSRV 1 // must be 1 -#define STOP_HALT 2 // HALT-really WAI -#define STOP_IBKPT 3 // breakpoint -#define STOP_OPCODE 4 // invalid opcode -#define STOP_MEMORY 5 // invalid memory address +#define STOP_UNKNOWN 0 // unknown error +#define STOP_RSRV 1 // must be 1 +#define STOP_HALT 2 // HALT-really WAI +#define STOP_IBKPT 3 // breakpoint +#define STOP_OPCODE 4 // invalid opcode +#define STOP_MEMORY 5 // invalid memory address +#define STOP_UNKNOWN2 6 // unknown error + From 55071d763985daf1cb73e6048dc24aad46b48af8 Mon Sep 17 00:00:00 2001 From: Richard Lukes Date: Wed, 3 Apr 2024 21:10:31 -0500 Subject: [PATCH 10/10] Add files via upload swtp6809: simulator doc file; updated table of contents --- doc/swtp6809_doc.doc | Bin 182272 -> 181760 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/doc/swtp6809_doc.doc b/doc/swtp6809_doc.doc index 101dbc8281fac5833ffdb265a02a03844280b3e4..05b1b7c5a68885c48fca23fa23ff3fbbeb0aa4ea 100644 GIT binary patch delta 12624 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 delta 13492 zcmcKB30zcF-@x%ZBOoZa0s;a8F1Tgvh$|HCOO}+luLPQ!CRl1Z;*zPQ!Xd{B%oQyG z5ll2(aLZjvO-<1hH5DjxK~kv1VW=MR}j;Vm9C)5-b|lT4pL@O)n-Ly}~@0 z%Mj)vKNY2>SLJbWkSMR=u2TzaoN25;2@@JB>d4sB+c>A{SZ>aRa;SS%w^MamR@8h@ zw`0l^ldW65pcd_U%gS|@vBGEmiV`D6Tldjr1sK;?_eujBS~#=${+n$+xJ1B>gPQM2 z=q8Y*Wj#7Z#gIkm?3rprZDq5_=9NPOmRrMk8&Q_SQr6c}TRH8aC^eL<0Lsz-C3U`G zAwJaF8_LJ>YR%NKT6=Zc&{i$Ho=zG!q)yAml>=>+V9~FIqHiURRy)7#8E9u@4a2 z8at^A1c;f9TRxrms&Nx_B2awa*t=pP(Y0bmknna5P-g_0%?K7tTz%CU!Dchsiz3&i zYAMLs`-lX$W~NOuvBymDEr2<7+<0PlUM-ROk4a z&+!)r-QP0pF4*6=yAWBP_QpsB2Y3-DzjlG`{B63&#m2o8aBwwcg`4{GIEOHsBW6ED`L3&Yb^QSRdxoUv1sv+xx0;f)+T z>G@%J3HxyXo+3TGiN;f$3isA{W)9hGT?S z+}qtfa>9%W`3v$DrK#3BzQ%;vbR{cmO?~Tl$C&GGi9+*A;~H}8JJ7+Eu`;QrVlf$U z)*7XwLyV1mykcB%!0SFvtqq%yosmsA#P~#RFwM;DWA9$yu$=h@8k;Y&tdFye`3fuC z^_-+X#VK6DRn&49Ddb8RquUl)(Dr~IYLrzc6 zR!Z2UT$w)&o4~6U_&Bi^u_Og~e;G z-H%ZJ2e%%a*?uN9B_(yynbhs6w;tSzQ?pV>nsQ{*aaA-lb2`JKFlXv%Tzxm0Lz>CfdH%Gch6{=>FBSSM%28B`r;g z%S&39boT1mu@yP}@{Bbru&l0Tos2abX`HFZUg_1Rc`-mm5rs1GM3~y zrKKohGa%7dxUDH%Mkw4h&-yZZn zw&ukZl}~$|1-g7^47ypI40Wp9;oUd5D#}KrViPvw5E6%Yh_*wT^&G*;awJA!G~Prs z;xHZWA_4dF@9*Eaf8G84`TO-B>ZgCG|InB-%9KNIa20v4SvANz*o_moi~?N6HQd8}l;8=<@h58W0A`CiaDp>hp$%SWqEi$< z68;E7A4Fm-CSxWRVg*w0C9<&xkM9=TJ#+MEE~BR@G7LFSXQ;CoAI&fujLj(Y7L9D3 z9AeJA8O{w2pJMNjM#6WvJtpe9I#U4|Nf|*kYBFHvL6QMdgCYYW10e$-E3Q`dpVm*_ zCsYhi5=VxLzea?a*l|xZPvnpE9c>kR9<()vV*$RvQIz6Wg!7y`6Y{xt zE!N>jxOpjxFZ?i0j2`1AmUOqvo-?MtM&$RXDb|l2u9HDmcXyQZ8C-+9>-(gC!DIXm z4ZG9A3bkPmSv(JT!V7-r2wCKCbVE<{LO=A!D;VgZj5O3~920M1JSJcg-bO6uL)Li_ ze!E+6vf$*ttj$@gvsNc$C1hnSTAh_J+c3RZPHxUxgoN2s6w@GLqkP2PD0^{oh>b{R z+#+%&u?1CJ|0Vq=tZ0Xt zu!aq6J#`#6Bpl#~RtQ1|bV6sm4B4m=cpdLy2GmAgK>G1r4wn3a!v(p>AXTs-SAH^e zxL|`J|1&;U6c`pLn6Ib<7c9ddl1DcYb)%YB#HVvqOA#{Kg*eqW#H%E#o;We2me3Km zBXRX~K61Cqum);BODCOy9mv5h?8QMG!f{-L?2k8b3wKb25|pDB{j)9{;RIL6zUvN8 zw1Br)->029h>R}iigAd-gBuUdpFhdpf%7{LoX^NOnQm8Mp~D?T@%V;@3g!;+7mm>{(>a=pH=^5#4bd)QL39)M7V5TR+5Q~pFcHr+!i$CHju##;JXctlmwhfZbzNR|-m1Lpq(Yfy5ntfj2s7vj|^&SLl!JJIzWJ27C2m-Yi&LnPZy zb<#GG$z3j1=AkeTL8X;7F9^H0n`HLU`x|HTSjjl4p?PfBbJxi(jxSVH z!H_Vtr&pbdQsml+?o)TRv#F~%Hq-QaQ^P{hN{P+IL6lWScv~4Nc$y`8LlBP2q@TyklUFgU_$YqHidC@_V<(OoGv@VI6>)S% zu-F>wt{qfY1hU#{Rb}mDtz_wCsbz^| zNi29RZwXhpAsDaVO}vjpq~j>=qNt_Vzv^XSH!DEcEwvL@R@sq`Nu1>^;%2$f9qWqa z?^=q?Sp#&kj{kJ)8I|_Hoo6dW>5IX56VnijjY!4U*nzz`fKxb)^C-f-R(y@{h=gZr zjsc9uM9hO8tFRs$uo+wMTS>)m^X5(Cl>EGO{L-b8Z%g?1ZEogfy;wf)J)YJatT<23 znf;Mhm zg{JUBSA?P`dZ9OFVix8i9!szkEAY7ZryqVg@l)~sob>(c`OC@4S)Y^hY0moPIm?T4 z_%MwY=G2lC#fCp&9e-Ao#McuS;_Y<-ax)3|7UysgH_?Ewy1*0Oh=mSn$gh(A3Ab?v zMJPrIv^0YiYQh1n&<-8Z6)&R)hP3PPwC#qIu>!_6RFuz2uR{j5A`{!N13U4!xbSgd zvHUB(cu{;iuZiYeackaVQ8K@txEF8#)(e7#)Da4D|RGM_|j>Om^@_OLX-&bvWZ$f%_}*-GZCq@WKu{7g^A~*oO;{<@ga- zaScD?Hp=h>3T3GewXBUvH$h9N2eSM_FdoyO)@1|fjcDyNf{;_GF6fDPY(W~- z3hyR;428IXGL)B<78U(mR9IG8SXx+g@$}x)+qY+?Wv*ShZ1#+}H2!A9O^us6HBJOw=!Ibzj#$J6W{+92 zTBDOSQ@7QTbU6CqRZK-9)O~Cwt?p+F>8;3z+~@Z=j|(V-EW=I6a{LZimRgYIX#!cM zfIv>LvS7XODk3lxYC)q&kB70qbU4y!NXH(Om+-`JvG8ovnOj$R(Y1$ zkdd`1CFSFkl*Ji~=a}MeHnMlf{_`V^Cc0gmX`@AqYxDK27lxrO-yGLN00I$?*Dw$Q zN%#V5u(3TCd*t94e!z7U!aIbP3o+cB_v>Moy?ohJjZRizFAm`_F5+k0g)B!c_OF&D znDkInnRYPF!A|VLH#i9SV}moehB}nze<^#nN`?2QkQ*Q?QTE_Y*`2ZrXHOnIly{Un ziyGv*JQkP5SKsl&^50v7}wZ# z<$!ScBru)O8Ovecfol&MAsFFk*O3z}I-?u9qZfK362mYYqc9Fp9XY*BBN2;PScM$y z!#P~TBm53cCvN-D0&UO-1MoU#V-8keBQ_xoS;)aI?8Z4*@_N@9jZxmE+%RxgTvoS~!-Z5-CETen&fFN@tec}DmxaH`U! zC1I%=CN)HAXk;j&pw`-zQnLuHY)JqYytsM)nTwp#;C;H$222D92w=h`0sRRwyt3_1Am%Zr>}v zR$hL){I+pWldmzU=9y;w!%=xfqjIUw4cg14UVbW8qOoYJdo?Cb8D!oE-k?N-@Ft@1 z33lNe3UCWHT{)kj2l}8d`e6dz#azVWBV^zXY(qJ`(GD-d2jQVQPNF0Z;1EvX0xsf5 zT*74(;0mtdCtSmI6ygSM;x3Bt0Hyd9zoERm;z3C!Ze6}`HvjB}vu977IC12N|B)j{ z4jwtOdwXVP#lN(al_^V7I0)Y3Tg>$U&%S*=?ro=e? z(&!+06v^nBN3Lqb)M%+ukd;*{s#a31pjx?_VLal)2DQQrSCRn}cyslv?C)0jXgbP@ z|Bf=$U>yrs!U~nQ#Z`v9^7}vYPNcm2{FxKkqpgQ(MAGN=n;YuLdB|cQ&Ga|X@UK<7 z7Tb{9d6EgXc~!RceQMQh zkyB+`&$dBuHSH3t7~);uJU--c&y$xnF1ut)phlEzIi1}s{YQ<>=XDhZTer}x%=Q{< zjtRpLGezh&Cyzl)wAJu#iy!O_A>D?w{MBY>Q=WKl+e5oi;fD=B?in?S>kdBtP+T_^7*6kZr8JkuNUdH7ZS+%~$8CTr)l8n*v2<;r5uFV4*=&eiN} zZ`0aT_%8bNhnlXALizDh&GZo~C!=V*PMpXmUGnJlFLe2zAl`}n8FH~px}HrgAuQDq^X=G1K%#(vc; z#B*b%h1yoP5D%uNg&G*fEuLK{i1Jll$fLT2xG$}=C70?J;*Pq~LiW`y#I1Lwh3Ztd z5cl?#7P78xAr7`m3uz4tRXUpG88yM;#hlQ2+PRvQ3$(GC7W%jaTAd~Dfs}XTFKWe# zL)QAf3$@$zdGocQJ3i3nX?A?5^|jG>>u zP8#9N<-&zGCkSoKZ4KmaOA_dJ^4A0M>)b^ie5>JU{8G&DLZ5fI@-3=-XD8oJ$+sx- z^?`iEln*=dnLyq|%9{;&d6Jh4R_8}r37Jjn%jT5rE<1>Img+Wh}9%JTKsH<^}%Eyr93C z7p(i6neG2(UdVIj$;0JgQGPSf zir!Y6R`fz=I+1ONe)gBzcI^sS$A@*?S>BOOvy^q@_nz}uCy;eKSzf+`US?e9$1k-l zbPXN(ZWwOxMq7lS3woj-24NVYF%fZ?i6vN$RY*ZPvXF~B97jGb;~I)kg8$%8*fioX zr%odZ05`P63-E(KLJ@}E=z}*9i7^<9Ntlcon27~gh~-#;WTap-zC;$Xu?N3HaiV{p z);sYYK3>P^bF5xn+;40K-`WvKg!iK|)=!b35?tD3dXb(fQ2XFS^BqNT0 zz8ytBF^zM8Y=+~%Q{VV03>1sO>hy?rP|s1pUmEGoGUvU~X<3OdZg z$1XI<2@*wU%vsPA!!QO5u>?nP3istfPG6IKvZ~bYQsa8@>Xz*94 zX0ApF;HFKIgN8pft&X)^Bn*SRphf01*r!d=cCF!dD7xF%2Nqc>J(wr&sfKgCu~BFr z%2cCX^fS3KM-HAfln3>AA_~#yy$@<#ta7PRZhQG3ClXIu=ocT3;xMtnsP<