diff --git a/doc/swtp6809_doc.doc b/doc/swtp6809_doc.doc new file mode 100644 index 000000000..05b1b7c5a Binary files /dev/null and b/doc/swtp6809_doc.doc differ diff --git a/makefile b/makefile index 1167f83aa..87f8a5304 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,${SWTP6809D},swtp6809mp-09)) + $@ $(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..47a0dda1c --- /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. + + 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 + 04 Apr 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 + 0) /* ROM Size */ +#define UNIT_MSIZE (0x2F << 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 */ + +/* 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, "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 } +}; + +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, /* help */ + NULL, /* attach help */ + NULL, /* help context */ + NULL /* device description */ +}; + +/* 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) +{ + 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]; + } + 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 = 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..b700915c5 --- /dev/null +++ b/swtp6809/common/dc-4.c @@ -0,0 +1,955 @@ +/* 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 + 04 Apr 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. + These are SS-30 slot numbers 5 and 6 (0x8014-0x801B) on a SWTPC 6800 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 | 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): + + +---+---+---+---+---+---+---+---+ + | 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 + + FLEX 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].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].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" + +/* Unit settings*/ + +#define UNIT_V_DC4_READONLY (UNIT_V_UF + 0) +#define UNIT_DC4_READONLY (0x1 << UNIT_V_DC4_READONLY) + +#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 SECTOR_SIZE 256 /* standard FLEX sector is 256 bytes */ + +/* 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_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 */ + +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 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 prev_dsk; /* previously selected drive */ + +char flex_flag_str[5] = { 'F', 'L', 'E', 'X', 0 }; + +/* 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[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[] = { + { HRDATA (DISK, cur_dsk, 4) }, + { NULL } +}; + +MTAB dsk_mod[] = { + { 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, "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 } +}; + +DEVICE dsk_dev = { + "DC-4", //name + dsk_unit, //units + dsk_reg, //registers + dsk_mod, //modifiers + NUM_DISK, //numunits + 16, //aradix + 8, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + &dsk_reset, //reset + NULL, //boot + &dsk_attach, //attach + &dsk_detach, //detach + NULL, //ctxt + DEV_DEBUG, //flags + 0, //dctrl + dsk_debug, /* debug flags defined in DEBTAB */ + NULL, //msize + NULL, //help + NULL, //attach help + NULL, //help context + NULL //device description +}; + +/* Reset routine */ + +t_stat dsk_reset(DEVICE *dptr) +{ + int i; + + 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"); + } + } + } + + // 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 + read or write occur to addresses 0xE004-0xE007. +*/ + +/* + DC-4 drive select register routine - this register is not part of the 1797 +*/ + +int32 fdcdrv(int32 io, int32 data) +{ + static long pos; + static int32 err; + int32 cpd; + int32 spt; + int32 temp_return; + + + sim_debug(DEBUG_flow, &dsk_dev, "fdcdrv: io=%02X, data=%02X\n", io, data); + + if (io) { + /* write to DC-4 drive register */ + cur_dsk = data & 0x03; /* only 2 drive select bits */ + 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); + + 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 { + dsk_unit[cur_dsk].u3 &= ((~WRPROT) & 0xFF); /* RW - unset 1797 WPROT */ + sim_debug(DEBUG_write, &dsk_dev, "fdcdrv: Disk is not write protected\n"); + } + 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; + 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, "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 */ + 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 - type I command */ + + /* ignored: head load flag, verify flag, stepping motor rate*/ + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + + dsk_unit[cur_dsk].u4 = 0; /* home the drive, track = 0 */ + dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* clear flags */ + sim_debug(DEBUG_write, &dsk_dev, "fdccmd: restore of drive %d\n", cur_dsk); + break; + + /* seek command - type I command */ + + /* ignored: head load flag, verify flag, stepping motor rate*/ + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + + /* set track */ + dsk_unit[cur_dsk].u4 = fdc_data_byte; + dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* clear flags */ + sim_debug(DEBUG_write, &dsk_dev, "fdccmd: Seek of disk %d, track %d\n", cur_dsk, fdc_data_byte); + break; + + /* read sector command - type II command (m=0, SSO=0) */ + case 0x80: + case 0x84: + case 0x88: + case 0x8C: + /* 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 { + + 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; + } + + /* 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; + + /* write sector command - type II command */ + case 0xA8: + case 0xAC: + + /* 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 { + + 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; + + default: + 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); + } + return(SCPE_OK); + + } else { + /* read status from fdc */ + + val = dsk_unit[cur_dsk].u3; /* set return value */ + + 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; + } +} /* fdccmd */ + +/* WD 1797 FDC track register routine */ + +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) { + /* 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); + } +} /* fdctrk */ + +/* WD 1797 FDC sector register routine */ + +int32 fdcsec(int32 io, int32 data) +{ + sim_debug(DEBUG_flow, &dsk_dev, "fdcsec: io=%02X, data=%02X\n", io, data); + + if (io) { + /* 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; + + 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"); + } + } + } + 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); + } +} /* fdcdata() */ + +/* end of dc-4.c */ diff --git a/swtp6809/common/m6809.c b/swtp6809/common/m6809.c new file mode 100644 index 000000000..b406465a5 --- /dev/null +++ b/swtp6809/common/m6809.c @@ -0,0 +1,3617 @@ +/* 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 + 04 Apr 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 + +/* 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) +#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_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) + +/* 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 */ + +#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); +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, 0, 0) }; + +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 + NULL, //help routine + NULL, //attach help routine + NULL, //help context + &m6809_desc //device description +}; + +static const char *opcode[] = { +"NEG", "?01?", "?02?", "COM", //0x00 +"LSR", "?05?", "ROR", "ASR", +"ASL", "ROL", "DEC", "???", +"INC", "TST", "JMP", "CLR", +"PG2", "PG3", "NOP", "SYNC", //0x10 +"?14?", "?15?", "LBRA", "LBSR", +"?18?", "DAA", "ORCC", "?1B?", +"ANDCC", "SEX", "EXG", "TFR", +"BRA", "BRN", "BHI", "BLS", //0x20 +"BCC", "BCS", "BNE", "BEQ", +"BVC", "BVS", "BPL", "BMI", +"BGE", "BLT", "BGT", "BLE", +"LEAX", "LEAY", "LEAS", "LEAU", //0x30 +"PSHS", "PULS", "PSHU", "PULU", +"?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", "?71?", "?72?", "COM", //0x70 +"LSR", "?75?", "ROR", "ASR", +"ASL", "ROL", "DEC", "?7B?", +"INC", "TST", "JMP", "CLR", +"SUBA", "CMPA", "SBCA", "SUBD", //0x80 +"ANDA", "BITA", "LDA", "?87?", +"EORA", "ADCA", "ORAA", "ADDA", +"CMPX", "BSR", "LDX", "?8F?", +"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", "?C7?", +"EORB", "ADCB", "ORB", "ADDB", +"LDD", "?CD?", "LDU", "?CF?", +"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" +}; + +int32 oplen[256] = { +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,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) +{ + 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 */ + if (sim_interval <= 0) /* check clock queue */ + if ((reason = sim_process_event ())) { + break; + } + 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 */ + 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) & 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); + 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); + result = op1 >> 1; + if (get_flag(CF)) { + result |= 0x80; + } + CPU_BD_put_mbyte(addr, result); + 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); + 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 0x08: /* ASL dir */ + addr = get_dir_addr(); + op1 = CPU_BD_get_mbyte(addr); + 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(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); + 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, 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; + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + COND_SET_FLAG(op1 == 0x80, VF); + /* 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); + /* 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 */ + 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(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))); + 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) == 0) && (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); + break; + + case 0x83: /* CMPD imm */ + /* do not modify D|A|B */ + 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 */ + /* do not modify Y */ + 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 */ + /* do not modify D|A|B */ + 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 */ + /* do not modify Y */ + 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 */ + /* do not modify D|A|B */ + 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 */ + /* do not modify Y */ + 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 */ + /* Do not modify D|A|B */ + 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 */ + /* Do not modify D|A|B */ + 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(1); + 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); + break; + + case 0x83: /* CMPU imm */ + /* Do not modify UP */ + 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 */ + /* Do not modify SP */ + 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 */ + /* Do not modify UP */ + 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 */ + /* Do not modify SP */ + 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 */ + /* Do not modify UP */ + 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 */ + /* Do not modify SP */ + 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 */ + /* Do not modify UP */ + 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 */ + /* Do not modify SP */ + 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; + + 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)) { + /* add correction factor of 0x06 for lower nybble */ + A += 0x06; + } + 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 = A & BYTEMASK; + 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 + // 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 */ + 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 */ + 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) == 0) && (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 ind */ + IX = get_indexed_addr(); + COND_SET_FLAG_Z_16(IX); + break; + + case 0x31: /* LEAY ind */ + IY = get_indexed_addr(); + COND_SET_FLAG_Z_16(IY); + break; + + case 0x32: /* LEAS ind */ + SP = get_indexed_addr(); + /* does not affect CCR */ + break; + + case 0x33: /* LEAU ind */ + 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); + /* wait for an interrupt */ + reason = STOP_HALT; + break; + + case 0x3D: /* MUL */ + D = A * B; + B = D & BYTEMASK; + A = D >> 8; + 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); + 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 */ + op1 = A; + A = A >> 1; + 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); + /* H undefined */ + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + /* V unaffected */ + break; + + case 0x48: /* ASLA */ + op1 = A; + A = (A << 1) & BYTEMASK; + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + COND_SET_FLAG(op1 & 0x80, CF); + COND_SET_FLAG(EXOR(get_flag(NF),get_flag(CF)), VF); + break; + + case 0x49: /* ROLA */ + op1 = A; + A = (A << 1) & BYTEMASK; + if (get_flag(CF)) { + A |= 0x01; + } + COND_SET_FLAG_N(A); + COND_SET_FLAG_Z(A); + 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 unaffected */ + 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 */ + op1 = B; + B = B >> 1; + 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); + /* H undefined */ + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + /* C unaffected */ + break; + + case 0x58: /* ASLB */ + op1 = B; + B = (B << 1) & BYTEMASK; + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + COND_SET_FLAG(op1 & 0x80, CF); + COND_SET_FLAG(EXOR(get_flag(NF),get_flag(CF)), VF); + break; + + case 0x59: /* ROLB */ + op1 = B; + B = (B << 1) & BYTEMASK; + if (get_flag(CF)) { + B |= 0x01; + } + COND_SET_FLAG_N(B); + COND_SET_FLAG_Z(B); + 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 unaffected */ + 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) & 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); + 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)) { + result |= 0x80; + } + CPU_BD_put_mbyte(addr, result); + 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); + 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); + 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(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)) { + result |= 0x01; + } + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + 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); + 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); + /* 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); + /* 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 */ + 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) & 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); + 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)) { + result |= 0x80; + } + CPU_BD_put_mbyte(addr, result); + 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); + 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); + 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(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)) { + result |= 0x01; + } + CPU_BD_put_mbyte(addr, result); + COND_SET_FLAG_N(result); + COND_SET_FLAG_Z(result); + 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); + 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); + /* 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); + /* 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 */ + CLR_FLAG(NF); + SET_FLAG(ZF); + CLR_FLAG(VF); + CLR_FLAG(CF); + break; +/* 0x80 - immediate mode (except for BSR) */ + case 0x80: /* SUBA imm */ + 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); + 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 */ + /* Do not modify A */ + result = (A & get_imm_byte_val()) & BYTEMASK; + 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); + 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 */ + /* Do not modify X */ + op2 = get_imm_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 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 */ + /* Do not modify A */ + 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 */ + /* Do not modify A */ + result = (A & get_dir_byte_val()) & BYTEMASK; + 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); + 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 */ + /* Do not modify X */ + 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 = 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, op2); + break; + + case 0xA1: /* CMPA ind */ + /* Do not modify A */ + 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 */ + /* Do not modify A */ + result = (A & get_indexed_byte_val()) & BYTEMASK; + 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); + 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 */ + /* Do not modify X */ + op2 = get_indexed_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 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 */ + /* Do not modify A */ + 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 */ + /* Do not modify A */ + result = (A & get_ext_byte_val()) & BYTEMASK; + 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); + 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 */ + /* Do not modify X */ + op2 = get_ext_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 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 */ + /* Do not modify B */ + 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 */ + /* Do not modify B */ + result = (B & get_imm_byte_val()) & BYTEMASK; + 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); + 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(); + 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); + 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 */ + /* Do not modify B */ + 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 */ + /* Do not modify B */ + result = (B & get_dir_byte_val()) & BYTEMASK; + 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); + 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(); + 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); + 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 */ + /* do not modify B */ + 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 */ + /* Do not modify B */ + result = (B & get_indexed_byte_val()) & BYTEMASK; + 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); + 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(); + 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); + 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 */ + /* Do not modify B */ + 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 */ + /* Do not modify B */ + result = (B & get_ext_byte_val()) & BYTEMASK; + 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); + 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(); + 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); + 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 opcode */ + 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) +{ + int32 val; + + val = CPU_BD_get_mbyte(PC); /* fetch byte */ + 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; +} + +/* fetch a word - big endian */ +int32 fetch_word() +{ + int32 val; + int32 temp_pc = PC; + + val = CPU_BD_get_mbyte(PC) << 8; /* fetch high 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, "%04X: 0x%04XH\n", temp_pc, val); + 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 != 0) { + 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 & 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())); +} + +/* 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) { + temp += (post_byte | 0xFFF0); + } else { + 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)*/ + 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; + }; + if (B & 0x80) { + offset = B | 0xFF80; + } else { + offset = B; + } + temp += offset; + break; + case 0b0110: + /* R+-ACCA (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; + }; + if (A & 0x80) { + offset = A | 0xFF80; + } else { + offset = A; + } + 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) { + temp += offset | 0xFF80; + } else { + 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 */ + /* calculation is the same for negative or positive 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 updated after fetch!!! + + /* add 7 bit signed offset */ + if (offset & 0x80) { + temp = PC + (offset | 0xFF80); + } else { + temp = PC + offset; + } + break; + case 0b1101: + /* PC+- 15-bit offset (non indirect)*/ + /* need to fetch 16-bit operand */ + offset = fetch_word(); + // PC value updated after fetch!!! + + /* add 15 bit signed offset */ + temp = PC + 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 */ +inline 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) +{ + 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 { + CLR_FLAG(VF); + } +} + +/* test and set V for 16-bit addition */ +void condevalVa16(int32 op1, int32 op2) +{ + 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 { + CLR_FLAG(VF); + } +} + +/* test and set V for 8-bit subtraction */ +void condevalVs(int32 op1, int32 op2) +{ + 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 { + CLR_FLAG(VF); + } +} + +/* test and set V for 16-bit subtraction */ +void condevalVs16(int32 op1, int32 op2) +{ + 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 { + CLR_FLAG(VF); + } +} + +/* test and set H for addition (8-bit only) */ +void condevalHa(int32 op1, int32 op2) +{ + if (((op1 & 0x0F) + (op2 & 0x0F)) > 0x0F) + SET_FLAG(HF); + else + CLR_FLAG(HF); +} + +/* calls from the simulator */ + +/* 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) { + ; // No BOOT ROM detected! + } + return SCPE_OK; +} + +/* 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; + 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) +{ + sim_debug(DEBUG_flow, &m6809_dev, "Call to m6809_examine()\n"); + + if (addr > ADDRMASK) { + /* exceed 16-bit address space */ + return SCPE_NXM; + } else { + if (eval_array != NULL) { + *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) +{ + sim_debug(DEBUG_flow, &m6809_dev, "Call to m6809_deposit()\n"); + + if (addr > ADDRMASK) { + /* 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; + + 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) { + 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; + + sim_debug(DEBUG_flow, &m6809_dev, "Call to fprint_sym()\n"); + + 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; + } + + /* lookup mnemonic in table */ + fprintf (of, "%s", opcode[inst]); // mnemonic + if (strlen(opcode[inst]) == 3) + fprintf(of, " "); + + /* 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 { + 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 (1); +} + +/* end of m6809.c */ diff --git a/swtp6809/common/mp-09.c b/swtp6809/common/mp-09.c new file mode 100644 index 000000000..ec9c52791 --- /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 + 04 Apr 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 + 8, //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 > ADDRMASK) { + 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 > ADDRMASK) { + 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..89348535c --- /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 + 04 Apr 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_BUF + 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..5bbf91f27 --- /dev/null +++ b/swtp6809/common/mp-b3.c @@ -0,0 +1,326 @@ +/* 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 + 04 Apr 24 -- Richard Lukes - Modified to emulate MP-B3 motherboard for swtp6809 emulator + + NOTES: + +*/ + +#include +#include "swtp_defs.h" + + +#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 */ + +/* 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_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 } +}; + +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, //logical name + NULL, //help routine + NULL, //attach help routine + NULL, //help context + NULL //device description +}; + +/* 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 > MASK_20BIT) { + /* 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 > MASK_20BIT) { + 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 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", addr20); + switch (addr20 & 0x0F800) { + case 0x0E000: + /* reserved I/O space from $E000-$E01F */ + /* 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(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(addr20); + if (MB_dev.dctrl & DEBUG_read) { + 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", addr20, val); + return val; +} + +/* get a word from memory */ + +int32 MB_get_mword(int32 addr20) +{ + int32 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 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", addr20, val); + + switch(addr16 & 0xF000) { + case 0xE000: + /* I/O and ROM space */ + 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 - READ ONLY! */ + break; + default: + /* RAM */ + mp_1m_put_mbyte(addr20, val); + break; + } +} + +/* put a word to memory */ + +void MB_put_mword(int32 addr20, int32 val) +{ + 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/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..614f40d9c --- /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 REG m6809_reg[]; + +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; + +/* 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, + &mp_1m_dev, + &sio_dev, + &ptr_dev, + &ptp_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 000000000..8c772c07a Binary files /dev/null and b/swtp6809/swtp6809/sbuge.bin differ diff --git a/swtp6809/swtp6809/swtp6809mp-09.ini b/swtp6809/swtp6809/swtp6809mp-09.ini new file mode 100644 index 000000000..eccf97055 --- /dev/null +++ b/swtp6809/swtp6809/swtp6809mp-09.ini @@ -0,0 +1,20 @@ +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 new file mode 100644 index 000000000..0a9182c2f --- /dev/null +++ b/swtp6809/swtp6809/swtp_defs.h @@ -0,0 +1,66 @@ +/* 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 0x007F + +/* Simulator stop codes */ + +#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 +