From 44428e53b655a2c41293ea10735f716fc2e81d71 Mon Sep 17 00:00:00 2001 From: Bill Beech Date: Thu, 9 Jun 2022 14:28:04 -0700 Subject: [PATCH] SWTP6800: Update to simulators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - General cleanup of codebase - Fixed condition codes m6800.c from Roberto Sancho Villa - Add additional FDC lfd-400 from Roberto Sancho Villa - Add additional OS's (FLEX 1.0, FDOS 1.0, DOS68, MiniDOS, and MiniDOS-MPX) to software support - Add additional disk formats to software support dc-4.c from Roberto Sancho Villa - Add CPU history - Fix LOAD/DUMP to support binary and hex - Fix fprintf_sym to disassemble 6800 code correctly - Add EXAMINE/DEPOSIT to CPU Memory - Fixed disasm to space the register - Add SET_FLAG(IF) to IRQ – fixed error in handling IRQ from Roberto Sancho Villa --- Visual Studio Projects/swtp6800mp-a.vcproj | 4 + Visual Studio Projects/swtp6800mp-a2.vcproj | 4 + descrip.mms | 4 +- doc/swtp6800_doc.doc | Bin 77824 -> 105984 bytes makefile | 10 +- swtp6800/common/dc-4.c | 339 +++++---- swtp6800/common/fd400.c | 519 ++++++++++++++ swtp6800/common/i2716.c | 25 +- swtp6800/common/m6800.c | 757 +++++++++++++------- swtp6800/common/m6810.c | 42 +- swtp6800/common/mp-8m.c | 27 +- swtp6800/common/mp-a.c | 48 +- swtp6800/common/mp-a2.c | 62 +- swtp6800/common/mp-b2.c | 98 ++- swtp6800/common/mp-s.c | 140 ++-- swtp6800/swtp6800/mp-a2_sys.c | 13 +- swtp6800/swtp6800/mp-a_sys.c | 13 +- 17 files changed, 1410 insertions(+), 695 deletions(-) create mode 100644 swtp6800/common/fd400.c diff --git a/Visual Studio Projects/swtp6800mp-a.vcproj b/Visual Studio Projects/swtp6800mp-a.vcproj index ed54076c..14a0cbb6 100644 --- a/Visual Studio Projects/swtp6800mp-a.vcproj +++ b/Visual Studio Projects/swtp6800mp-a.vcproj @@ -199,6 +199,10 @@ RelativePath="..\swtp6800\common\dc-4.c" > + + diff --git a/Visual Studio Projects/swtp6800mp-a2.vcproj b/Visual Studio Projects/swtp6800mp-a2.vcproj index 85543fcd..5f0d5721 100644 --- a/Visual Studio Projects/swtp6800mp-a2.vcproj +++ b/Visual Studio Projects/swtp6800mp-a2.vcproj @@ -199,6 +199,10 @@ RelativePath="..\swtp6800\common\dc-4.c" > + + diff --git a/descrip.mms b/descrip.mms index f51d924c..482ef691 100644 --- a/descrip.mms +++ b/descrip.mms @@ -739,7 +739,7 @@ SWTP6800MP_A_LIB = $(LIB_DIR)SWTP6800MP-A-$(ARCH).OLB SWTP6800MP_A_SOURCE = $(SWTP6800MP_A_COMMON)mp-a.c,$(SWTP6800MP_A_COMMON)m6800.c,\ $(SWTP6800MP_A_COMMON)m6810.c,$(SWTP6800MP_A_COMMON)bootrom.c,$(SWTP6800MP_A_COMMON)dc-4.c,\ $(SWTP6800MP_A_COMMON)mp-s.c,$(SWTP6800MP_A_DIR)mp-a_sys.c,$(SWTP6800MP_A_COMMON)mp-b2.c,\ - $(SWTP6800MP_A_COMMON)mp-8m.c + $(SWTP6800MP_A_COMMON)mp-8m.c,$(SWTP6800MP_A_COMMON)fd400.c SWTP6800MP_A_OPTIONS = /INCL=($(SIMH_DIR),$(SWTP6800MP_A_DIR))/DEF=($(CC_DEFS)) # @@ -751,7 +751,7 @@ SWTP6800MP_A2_LIB = $(LIB_DIR)SWTP6800MP-A2-$(ARCH).OLB SWTP6800MP_A2_SOURCE = $(SWTP6800MP_A2_COMMON)mp-a2.c,$(SWTP6800MP_A2_COMMON)m6800.c,\ $(SWTP6800MP_A2_COMMON)m6810.c,$(SWTP6800MP_A2_COMMON)bootrom.c,$(SWTP6800MP_A2_COMMON)dc-4.c,\ $(SWTP6800MP_A2_COMMON)mp-s.c,$(SWTP6800MP_A2_DIR)mp-a2_sys.c,$(SWTP6800MP_A2_COMMON)mp-b2.c,\ - $(SWTP6800MP_A2_COMMON)mp-8m.c,$(SWTP6800MP_A2_COMMON)i2716.c + $(SWTP6800MP_A2_COMMON)mp-8m.c,$(SWTP6800MP_A2_COMMON)i2716.c,,$(SWTP6800MP_A_COMMON)fd400.c SWTP6800MP_A2_OPTIONS = /INCL=($(SIMH_DIR),$(SWTP6800MP_A2_DIR))/DEF=($(CC_DEFS)) # diff --git a/doc/swtp6800_doc.doc b/doc/swtp6800_doc.doc index 315e3e02901d317133a58213fdd2b7c0a1a4679d..2660ed1898e070e063b83fbefd54e009e5cb70c2 100644 GIT binary patch literal 105984 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/GII2mv>ZFC1riEa(DyP2z! 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 @ZFXT<>}~GgAukn;AqMy~ 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 N8Dx>veRWv^{}0J~rZWHl literal 77824 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 i++) { + dptr->units[i].u3 = NOTRDY; /* current flags = NOTRDY*/ + 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 = calloc(SECT_SIZE, sizeof(uint8)); /* allocate buffer */ + if (dptr->units[i].filebuf == NULL) { + printf("dc-4_reset: Calloc error\n"); return SCPE_MEM; } } @@ -371,11 +390,31 @@ t_stat dsk_reset (DEVICE *dptr) heds = 0; cpd = 0; dsksiz = 0; + //RSV - for hansling multiple disk formats and OSs + sectsize = SECT_SIZE; + multiple_sector=0; + index_countdown=0; + sector_base=1; + return SCPE_OK; +} + +/* dsk attach - attach an .IMG file to an FDD */ + +t_stat dsk_attach (UNIT *uptr, CONST char *cptr) +{ + t_stat r; + + if ((r = attach_unit (uptr, cptr)) != SCPE_OK) { + sim_printf("dsk_attach: Attach error %d\n", r); + return r; + } + uptr->u3 &= ~NOTRDY; //reset FDD to ready + uptr->capac = sim_fsize(uptr->fileref); //file size return SCPE_OK; } /* I/O instruction handlers, called from the MP-B2 module when a - read or write occur to addresses 0x8004-0x8007. */ + read or write occur to addresses 0x8014-0x801B. */ /* DC-4 drive select register routine - this register is not part of the 1797 */ @@ -384,47 +423,59 @@ int32 fdcdrv(int32 io, int32 data) { static long pos; static int32 err; + uint8 *SIR; + int32 disk_image_size; - if (io) { /* write to DC-4 drive register */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcdrv: Drive selected %d cur_dsk=%d", - data & 0x03, cur_dsk); - if (cur_dsk == (data & 0x03)) - return 0; /* already selected */ - cur_dsk = data & 0x03; /* only 2 drive select bits */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcdrv: Drive set to %d", cur_dsk); - dsk_unit[cur_dsk].flags &= ~LOST; - if ((dsk_unit[cur_dsk].flags & UNIT_ENABLE) == 0) { - dsk_unit[cur_dsk].u3 |= WRPROT; /* set 1797 WPROT */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcdrv: Drive write protected"); - } else { - dsk_unit[cur_dsk].u3 &= ~WRPROT; /* set 1797 not WPROT */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcdrv: Drive NOT write protected"); - } - pos = 0x200; /* Read in SIR */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcdrv: Read pos = %ld ($%04X)", - pos, (unsigned int) pos); - err = sim_fseek(dsk_unit[cur_dsk].fileref, pos, SEEK_SET); /* seek to offset */ - if (err) { - sim_printf("\nfdccmd: Seek error read in SIR\n"); - return SCPE_IOERR; - } - err = sim_fread(dsk_unit[cur_dsk].filebuf, SECT_SIZE, 1, dsk_unit[cur_dsk].fileref); /* read in buffer */ - if (err != 1) { - sim_printf("\nfdccmd: File error read in SIR\n"); - return SCPE_IOERR; - } + if (io) { // write to DC-4 drive register + if (cur_dsk == (data & 0x03)) // already selected? + return 0; //yes + cur_dsk = data & 0x03; // only 2 drive select bits/ + dsk_unit[cur_dsk].u3 &= ~LOST; //RSV - reset LOST flag + if ((dsk_unit[cur_dsk].flags & UNIT_ENABLE) == 0) //RO? + dsk_unit[cur_dsk].u3 |= WRPROT; /* Set WPROT */ + else + dsk_unit[cur_dsk].u3 &= ~WRPROT; /* SET not WPROT */ + if (dsk_unit[cur_dsk].fileref == 0) // no file attached + return 0; + /* RSV - Read in SIR */ + pos = 0x200; + sim_fseek(dsk_unit[cur_dsk].fileref, pos, SEEK_SET); /* seek to SIR */ + sim_fread(dsk_unit[cur_dsk].filebuf, SECT_SIZE, 1, dsk_unit[cur_dsk].fileref); /* read in SIR */ dsk_unit[cur_dsk].u3 |= BUSY | DRQ; /* set DRQ & BUSY */ dsk_unit[cur_dsk].pos = 0; /* clear counter */ - spt = *((uint8 *)(dsk_unit[cur_dsk].filebuf) + MAXSEC) & 0xFF; - heds = 0; - cpd = *((uint8 *)(dsk_unit[cur_dsk].filebuf) + MAXCYL) & 0xFF; - trksiz = spt * SECT_SIZE; + SIR = (uint8 * )(dsk_unit[cur_dsk].filebuf); + // detect disk type based on image geometry or SIR record + disk_image_size = sim_fsize(dsk_unit[cur_dsk].fileref); //get actual file size + if (disk_image_size == 35 * 10 * 256) { // 89600 bytes -> FDOS image + // FDOS disc has no SIR record. + spt = 10; // 10 sectors + cpd = 35; // 35 tracks + sectsize = 256; + sector_base = 0; // first sector in track is number ZERO + } else if (disk_image_size == 35 * 18 * 128) { // 80640 bytes -> FLEX 1.0 image + spt = 18; // 18 sectors + cpd = 35; // 35 tracks + sectsize = 128; + sector_base = 1; // first sector in track is number ONE + } else if ((SIR[0] == 0) && (SIR[1] == 0)) { + // FLEX disc has SIR record. on disk image offset $200 + spt = SIR[MAXSEC]; // Highest number of tracks. As in FLEX sectors are numbered as + // 1,2,..Hi this is also the number of sectors per track + cpd = SIR[MAXCYL] + 1; // highest track number . On FLEX, first track is track zero + sectsize = 256; + sector_base = 1; // first sector in track is number ONE + } else { + spt = 18; + sectsize = 128; + cpd = disk_image_size / (spt * sectsize); + sector_base = 1; // first sector in track is number ONE + } + heds = 0; //RSV - always SS + trksiz = spt * sectsize; dsksiz = trksiz * cpd; - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcdrv: spt=%d heds=%d cpd=%d trksiz=%d dsksiz=%d flags=%08X u3=%08X", - spt, heds, cpd, trksiz, dsksiz, dsk_unit[cur_dsk].flags, dsk_unit[cur_dsk].u3); + return 0; } else { /* read from DC-4 drive register */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcdrv: Drive read as %02X", intrq); return intrq; } } @@ -438,83 +489,88 @@ int32 fdccmd(int32 io, int32 data) static int32 err; if ((dsk_unit[cur_dsk].flags & UNIT_ATT) == 0) { /* not attached */ - dsk_unit[cur_dsk].u3 |= NOTRDY; /* set not ready flag */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdccmd: Drive %d is not attached", cur_dsk); - return 0; + val = dsk_unit[cur_dsk].u3 |= NOTRDY; /* set not ready flag */ + return SEEKERR; // RSV - return SEEK ERROR STATUS bit } else { dsk_unit[cur_dsk].u3 &= ~(NOTRDY); /* clear not ready flag */ } if (io) { /* write command to fdc */ + // RSV - on commands type I ... + if ((data & 0x80) == 0) { + // ... set bits h V r1r0 to h=1 (home drive), V=0 (verify off), r1r0=11 (40msec track stepping) + data = ((data & 0xF0) | 0x0B); + // and starts countdown for index status bit + index_countdown = 10; + } else { + index_countdown = 0; + } + // process command switch(data) { case 0x8C: //read sector command type II case 0x9C: //read multiple sectors command type II - sim_debug (DEBUG_flow, &dsk_dev, "\nfdccmd: Read of disk %d, track %d, sector %d", - cur_dsk, dsk_unit[cur_dsk].u4, dsk_unit[cur_dsk].u5); + if ((dsk_unit[cur_dsk].u5 - sector_base >= spt) || (dsk_unit[cur_dsk].u5 < sector_base)) { + dsk_unit[cur_dsk].u3 |= RECNF; /* RSV - set RECORD NOT FOUND */ + break; + } dsk_unit[cur_dsk].u3 |= BUSY; /* set BUSY */ pos = trksiz * dsk_unit[cur_dsk].u4; /* calculate file offset */ - pos += SECT_SIZE * (dsk_unit[cur_dsk].u5 - 1); - sim_debug (DEBUG_flow, &dsk_dev, "\nfdccmd: Read pos = %ld ($%08X)", - pos, (unsigned int) pos); + pos += sectsize * (dsk_unit[cur_dsk].u5 - sector_base); err = sim_fseek(dsk_unit[cur_dsk].fileref, pos, SEEK_SET); /* seek to offset */ if (err) { - sim_printf("\nfdccmd: Seek error in read command\n"); + sim_printf("fdccmd: Seek error in read command\n"); return SCPE_IOERR; - } - err = sim_fread(dsk_unit[cur_dsk].filebuf, SECT_SIZE, 1, dsk_unit[cur_dsk].fileref); /* read in buffer */ + } + /* read in buffer */ + err = sim_fread(dsk_unit[cur_dsk].filebuf, sectsize, 1, dsk_unit[cur_dsk].fileref); if (err != 1) { - sim_printf("\nfdccmd: File error in read command\n"); + sim_printf("fdccmd: File error in read command\n"); return SCPE_IOERR; } dsk_unit[cur_dsk].u3 |= DRQ; /* set DRQ */ dsk_unit[cur_dsk].pos = 0; /* clear counter */ + multiple_sector = (data == 0x9C) ? 1:0; // RSV = set multiple sector TYPE II cmds break; case 0xAC: //write command type II case 0xBC: //write multiple sectors command type II - sim_debug (DEBUG_flow, &dsk_dev, "\nfdccmd: Write of disk %d, track %d, sector %d", - cur_dsk, dsk_unit[cur_dsk].u4, dsk_unit[cur_dsk].u5); if (dsk_unit[cur_dsk].u3 & WRPROT) { - printf("\nfdccmd: Drive %d is write-protected", cur_dsk); } else { dsk_unit[cur_dsk].u3 |= BUSY;/* set BUSY */ pos = trksiz * dsk_unit[cur_dsk].u4; /* calculate file offset */ - pos += SECT_SIZE * (dsk_unit[cur_dsk].u5 - 1); - sim_debug (DEBUG_flow, &dsk_dev, "\nfdccmd: Write pos = %ld ($%08X)", - pos, (unsigned int) pos); + pos += sectsize * (dsk_unit[cur_dsk].u5 - sector_base); err = sim_fseek(dsk_unit[cur_dsk].fileref, pos, SEEK_SET); /* seek to offset */ if (err) { - sim_printf("\nfdccmd: Seek error in write command\n"); + sim_printf("fdccmd: Seek error in write command\n"); return SCPE_IOERR; } dsk_unit[cur_dsk].u3 |= DRQ;/* set DRQ */ - wrt_flag = 1; /* set write flag */ + wrt_flag = 1; /* RSV - set write flag */ dsk_unit[cur_dsk].pos = 0; /* clear counter */ } break; - case 0x18: //seek command type I case 0x1B: //seek command type I - dsk_unit[cur_dsk].u4 = fdcbyte; /* set track */ + dsk_unit[cur_dsk].u4 = fdcbyte; /* set track */ dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* clear flags */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdccmd: Seek of disk %d, track %d", - cur_dsk, fdcbyte); break; - case 0x0B: //restore command type I - dsk_unit[cur_dsk].u4 = 0; /* home the drive */ - dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* clear flags */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdccmd: Drive %d homed", cur_dsk); + case 0x0B: //restore command type I + dsk_unit[cur_dsk].u4 = 0; /* home the drive */ + dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ | RECNF); /* clear flags */ break; case 0xF0: //write track command type III case 0xF4: //write track command type III - sim_debug (DEBUG_flow, &dsk_dev, "\nfdccmd: Write track command for drive %d", - cur_dsk); + break; + case 0xD0: //Force Interrupt - terminate current command + dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* clear flags */ break; default: - printf("Unknown FDC command %02XH\n\r", data); + sim_printf("Unknown FDC command %02X\n\r", data); } } else { /* read status from fdc */ val = dsk_unit[cur_dsk].u3; /* set return value */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdccmd: Exit Drive %d status=%02X", - cur_dsk, val); - sim_debug (DEBUG_flow, &dsk_dev, "\n%02X", val); //even this short fails it! + if (index_countdown) { // RSV - Handle INDEX flag + index_countdown--; + // if index countdoen expires, set index flag in status returned to cpu + if (index_countdown==0) val |= INDEX; + } } return val; } @@ -524,12 +580,9 @@ int32 fdccmd(int32 io, int32 data) int32 fdctrk(int32 io, int32 data) { if (io) { - dsk_unit[cur_dsk].u4 = data & 0xFF; - sim_debug (DEBUG_flow, &dsk_dev, "\nfdctrk: Drive %d track set to %d", - cur_dsk, dsk_unit[cur_dsk].u4); + dsk_unit[cur_dsk].u3 &= ~(RECNF); /* reset RECNF flag */ + dsk_unit[cur_dsk].u4 = data & BYTEMASK; } - sim_debug (DEBUG_flow, &dsk_dev, "\nfdctrk: Drive %d track read as %d", - cur_dsk, dsk_unit[cur_dsk].u4); return dsk_unit[cur_dsk].u4; } @@ -538,14 +591,12 @@ int32 fdctrk(int32 io, int32 data) int32 fdcsec(int32 io, int32 data) { if (io) { - dsk_unit[cur_dsk].u5 = data & 0xFF; - if (dsk_unit[cur_dsk].u5 == 0) /* fix for swtp boot! */ - dsk_unit[cur_dsk].u5 = 1; - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcsec: Drive %d sector set to %d", - cur_dsk, dsk_unit[cur_dsk].u5); + dsk_unit[cur_dsk].u3 &= ~(RECNF); /* reset RECNF flag */ + dsk_unit[cur_dsk].u5 = data & BYTEMASK; + if (dsk_unit[cur_dsk].u5 < sector_base) //RSV - force to sector 1 + dsk_unit[cur_dsk].u5 = sector_base; + return 0; } - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcsec: Drive %d sector read as %d", - cur_dsk, dsk_unit[cur_dsk].u5); return dsk_unit[cur_dsk].u5; } @@ -553,38 +604,48 @@ int32 fdcsec(int32 io, int32 data) int32 fdcdata(int32 io, int32 data) { - int32 val; + int32 val, err; + if (cur_dsk >= NUM_DISK) // RSV - illegal disk + return 0; if (io) { /* write byte to fdc */ fdcbyte = data; /* save for seek */ - if (dsk_unit[cur_dsk].pos < SECT_SIZE) { /* copy bytes to buffer */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcdata: Writing byte %d of %02X", - dsk_unit[cur_dsk].pos, data); + if (dsk_unit[cur_dsk].pos < (t_addr) sectsize) { /* copy bytes to buffer */ *((uint8 *)(dsk_unit[cur_dsk].filebuf) + dsk_unit[cur_dsk].pos) = data; /* byte into buffer */ dsk_unit[cur_dsk].pos++; /* step counter */ - if (dsk_unit[cur_dsk].pos == SECT_SIZE) { + if (dsk_unit[cur_dsk].pos == sectsize) { dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); if (wrt_flag) { /* if initiated by FDC write command */ - sim_fwrite(dsk_unit[cur_dsk].filebuf, SECT_SIZE, 1, dsk_unit[cur_dsk].fileref); /* write it */ + sim_fwrite(dsk_unit[cur_dsk].filebuf, sectsize, 1, dsk_unit[cur_dsk].fileref); /* write it */ wrt_flag = 0; /* clear write flag */ } - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcdata: Sector write complete"); } } return 0; } else { /* read byte from fdc */ - if (dsk_unit[cur_dsk].pos < SECT_SIZE) { /* copy bytes from buffer */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcdata: Reading byte %d u3=%02X", - dsk_unit[cur_dsk].pos, dsk_unit[cur_dsk].u3); - val = *((uint8 *)(dsk_unit[cur_dsk].filebuf) + dsk_unit[cur_dsk].pos) & 0xFF; - dsk_unit[cur_dsk].pos++; /* step counter */ - if (dsk_unit[cur_dsk].pos == SECT_SIZE) { /* done? */ - dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* clear flags */ - sim_debug (DEBUG_flow, &dsk_dev, "\nfdcdata: Sector read complete"); + if (dsk_unit[cur_dsk].pos < (t_addr) sectsize) { /* copy bytes from buffer */ + val = *((uint8 *)(dsk_unit[cur_dsk].filebuf) + dsk_unit[cur_dsk].pos) & BYTEMASK; + dsk_unit[cur_dsk].pos++; /* step counter */ + if (dsk_unit[cur_dsk].pos == sectsize) { // sector finished + if ((multiple_sector) && (dsk_unit[cur_dsk].u5-sector_base < spt-1)) { // read multiple in progress + dsk_unit[cur_dsk].u5++; + err = sim_fread(dsk_unit[cur_dsk].filebuf, sectsize, 1, dsk_unit[cur_dsk].fileref); /* read in buffer */ + if (err != 1) { + sim_printf("fdccmd: File error in read command\n"); + return SCPE_IOERR; + } + dsk_unit[cur_dsk].pos = 0; + } else { // RSV - handle multiple sector disk read + dsk_unit[cur_dsk].u5++; + dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* clear flags */ + if (multiple_sector) { + multiple_sector=0; + } + } } return val; } else - return 0; + return 0; } } diff --git a/swtp6800/common/fd400.c b/swtp6800/common/fd400.c new file mode 100644 index 00000000..31323f41 --- /dev/null +++ b/swtp6800/common/fd400.c @@ -0,0 +1,519 @@ +/* fd400.c: Percom LFD-400 FDC Simulator + + Copyright (c) 2022, Roberto Sancho + + 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 Roberto Sancho shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Roberto Sancho . + + MODIFICATIONS: + + NOTES: + + The FDC-400 is a 5-1/4"-inch floppy controller which can control up + to four 5-1/4inch floppy drives. + This file only emulates the minimum functionality to interface with + the virtual disk file. + + The floppy controller is interfaced to the CPU by use of 7 memory + addreses (0xCC00-0xCC06). + + Address Mode Function + ------- ---- -------- + + 0xCC00 Read CONTROLLER STATUS + 0xCC00 Write SYNC WORD PORT + 0xCC01 Read RECEIVED DATA + 0xCC01 Write WRITE DATA PORT + 0xCC02 Read SECTOR COUNTER + 0xCC02 Write FILL WORD PORT + 0xCC03 Read DRIVE STATUS + 0xCC03 Write DRIVE AND TRACK SELECT + 0xCC04 Read RECEIVER RESTART PULSE + 0xCC04 Write WRITE PULSE + 0xCC05 Read MOTOR ON PULSE + 0xCC06 Read MOTOR OFF PULSE + + + CONTROLLER STATUS (Read 0xCC00): + + +---+---+---+---+---+---+---+---+ + | B | x | x | x | x | x | x | R | + +---+---+---+---+---+---+---+---+ + + B = Controller Ready (0=Busy, 1=Ready) + R = Read byte ready (1=can retrieve read byte) + + + RECEIVED DATA (Read 0xCC01): + WRITE DATA PORT (Write 0xCC01): + + +---+---+---+---+---+---+---+---+ + | byte | + +---+---+---+---+---+---+---+---+ + + Data byte from retrieved sector being read + Data byte to store in sector being write + + + CURRENT SECTOR (Read 0xCC02): + WRITE FILL CHAR (Write 0xCC02): + + +---+---+---+---+---+---+---+---+ + | x | Sector | + +---+---+---+---+---+---+---+---+ + + Return current Sector + Set the fill char for write sector + + + DRIVE STATUS (Read 0xCC03): + + +---+---+---+---+---+---+---+---+ + | DD | I | S | W | M | T | P | + +---+---+---+---+---+---+---+---+ + + P = Write allowed Bit (0=disk is write protected) + T = Track Zero Bit (1=head is NOT positioned in track zero) + M = Motor Test Bit (1=motor stopped) + W = Write Gate Bit (1=drive gate door is closed) + S = Sector Pulse Bit (1=head at start of sector) + I = Index Pulse bit (???) + DD = Current selected drive (0..3) + + + DRIVE AND TRACK SELECT (Write 0xCC03): + + +---+---+---+---+---+---+---+---+ + | DD | S | D | x | x | x | x | + +---+---+---+---+---+---+---+---+ + + D = Direction bit (1=Track In=increment track number) + S = Step Bit (1=Move disk head one track using direction D) + DD = Select drive (0..3) + + LFD-400 Disck supports these operating systems (1977) + + - MINIDOS: Just Load/Save ram starting at given sector in disk. + No files. No sector allocation management. Rom based + - MPX (also know as MiniDOS Plus or MiniDOS/MPX or MiniDOS-PlusX): + Based on MiniDOS, add named files, contiguos allocation management. Transient disk command + - MiniDisk+ DOS: + Based on MiniDOS, add named files, contiguos allocation management. More disk commands + + + MiniDOS files have 40 track (0..39) with 10 sectors (0..9) each with 256 bytes of data + + The following unit registers are used by this controller emulation: + + fd400_dsk_unit[cur_drv].u4 unit current track + fd400_dsk_unit[cur_drv].u5 unit current sector + fd400_dsk_unit[cur_drv].pos unit current sector byte index into buffer + fd400_dsk_unit[cur_drv].filebuf unit current sector buffer + fd400_dsk_unit[cur_drv].fileref unit current attached file reference + + At start, units discs from controller are dissabled + To use it, befor attaching the disk image, it is mecessary to do "set lfd-4000 enabled" + (for unit 0), and optionally "set lfd-4001 enabled" (for unit 1) and so on. +*/ + +#include +#include "swtp_defs.h" + +#define UNIT_V_ENABLE (UNIT_V_UF + 0) /* Write Enable */ +#define UNIT_ENABLE (1 << UNIT_V_ENABLE) + +/* emulate a Disk disk with 10 sectors and 40 tracks */ + +#define NUM_DISK 4 +#define SECT_SIZE (8+4+256) /* sector size=header (10 bytes) + data (256 bytes) + CRC (2 bytes) */ +#define NUM_SECT 10 /* sectors/track */ +#define TRAK_SIZE (SECT_SIZE * NUM_SECT) /* trk size (bytes) */ +#define HEADS 1 /* handle as SS with twice the sectors */ +#define NUM_CYL 40 /* maximum tracks */ +#define DSK_SIZE (NUM_SECT * HEADS * NUM_CYL * SECT_SIZE) /* dsk size (bytes) */ + +#define TRK fd400_dsk_unit[fd400.cur_dsk].u4 // current disk track and sector +#define SECT fd400_dsk_unit[fd400.cur_dsk].u5 + +#define BUF_SIZE (SECT_SIZE+16) // sector buffer in memory + +/* function prototypes */ + +t_stat fd400_dsk_reset (DEVICE *dptr); +t_stat fd400_attach (UNIT *, CONST char *); + +/* SS-50 I/O address space functions */ + +int32 fd400_fdcstatus(int32 io, int32 data); +int32 fd400_cstatus(int32 io, int32 data); +int32 fd400_data(int32 io, int32 data); +int32 fd400_cursect(int32 io, int32 data); +int32 fd400_startrw(int32 io, int32 data); + +/* Local Variables */ + +struct { + int32 cur_dsk; /* Currently selected drive */ + int32 SectorPulse; // Head positioned at beginning of sector + int32 StepBit; + uint8 FillChar; +} fd400 = {0}; + +/* Floppy Disk Controller data structures + + fd400_dsk_dev Disk Controller device descriptor + fd400_dsk_unit Disk Controller unit descriptor + fd400_dsk_reg Disk Controller register list + fd400_dsk_mod Disk Controller modifiers list +*/ + +UNIT fd400_dsk_unit[] = { + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (NULL, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+UNIT_DIS, 0) } +}; + +REG fd400_dsk_reg[] = { + { HRDATA (DISK, fd400.cur_dsk, 4) }, + { NULL } +}; + +DEBTAB fd400_dsk_debug[] = { + { "ALL", DEBUG_all, "All debug bits" }, + { "FLOW", DEBUG_flow, "Flow control" }, + { "READ", DEBUG_read, "Read Command" }, + { "WRITE", DEBUG_write, "Write Command"}, + { NULL } +}; + +DEVICE fd400_dsk_dev = { + "LFD-400", //name + fd400_dsk_unit, //units + fd400_dsk_reg, //registers + NULL, //modifiers + NUM_DISK, //numunits + 16, //aradix + 16, //awidth + 1, //aincr + 16, //dradix + 8, //dwidth + NULL, //examine + NULL, //deposit + &fd400_dsk_reset, //reset + NULL, //boot + &fd400_attach, //attach + NULL, //detach + NULL, //ctxt + DEV_DISABLE|DEV_DIS|DEV_DEBUG, //flags + 0, //dctrl + fd400_dsk_debug, //debflags + NULL, //msize + NULL //lname +}; + +/* Reset routine */ + +t_stat fd400_dsk_reset (DEVICE *dptr) +{ + int i; + + for (i=0; iflags & UNIT_ATT) == 0) { + sim_debug (DEBUG_flow, &fd400_dsk_dev, "Current Drive %d has no file attached \n", fd400.cur_dsk); + } else { + // file attached = disk inserted into unit + if ((uptr->flags & UNIT_RO) == 0) val |= 1; // unit is read/write + if (TRK!=0) val |= 2; // head is NOT in track zero + if (fd400.SectorPulse) { + val |= 16; + fd400.SectorPulse--; + } else { + // set sector pulse and incr current sector + // Simulates somewhat disk rotation whitout having to set up _svr and sim_activate + fd400.SectorPulse=2; + SECT++; if (SECT >= NUM_SECT) SECT = 0; + uptr->pos=0; // init sector read + } + if (SECT==0) val |= 32; // index pulse: head is positioned in sector zero + } + sim_debug (DEBUG_flow, &fd400_dsk_dev, "Status Returned %02X, Current Drive %d TRK %d SECT %d \n", + val, fd400.cur_dsk, TRK, SECT); + return val; + } + // io=1 -> writing data to i/o register, + fd400.cur_dsk = data >> 6; // select current disk + fd400.SectorPulse = 0; // init sector pulse + if (data & 32) { + fd400.StepBit=1; // Step bit set to one + } else if ((data & 32)==0) { // Step bit set to zero + if (fd400.StepBit==0) { + // but was already zero -> no action + } else { + // StepBit changing from 1 to 0 -> step track motot + fd400.StepBit=0; + // step track depending on direction bit + if (data & 16) TRK++; else TRK--; + if (TRK < 0) TRK=0; + if (TRK >= NUM_CYL) TRK = NUM_CYL-1; + // on changing track also incr sect num, but not issue sector pulse (landed on middle of sector) + SECT++; if (SECT >= NUM_SECT) SECT = 0; + uptr->pos=0; // init sector read + } + } + sim_debug (DEBUG_flow, &fd400_dsk_dev, "Set Drive and Track %02X, Current Drive %d TRK %d SECT %d \n", + data, fd400.cur_dsk, TRK, SECT); + return 0; +} + +/* CONTROLLER STATUS register (read $CC00)*/ + +int32 fd400_cstatus(int32 io, int32 data) +{ + // controller allways ready, byte read from sector allways ready + // writing to is set the sync byte. This is not implemented + return 128+1; +} + +/* DATA register */ + +int32 fd400_data(int32 io, int32 data) +{ + uint32 loc; + UNIT * uptr = &fd400_dsk_unit[fd400.cur_dsk]; + uint8 dsk_sect[SECT_SIZE]; // image of sector read/saved in disk image + uint8 * p = (uint8 *)(uptr->filebuf); // sector byte stream as seen by program + int i, n; + + if ((uptr->flags & UNIT_ATT) == 0) return 0; // not attached + if (io==0) { + // io=0 when reading from io register (return data read from i/o device register) + // read data from sector + if (uptr->pos==0) { + // read new sector buffer + // init buffer to zero + memset(uptr->filebuf, 0, SECT_SIZE); + // calculate location of current sector in disk image file + loc=(TRK * NUM_SECT + SECT) * SECT_SIZE; + if (loc >= uptr->capac) { + // reading past image file current size -> read as zeroes + } else { + // read sector + sim_fseek(uptr->fileref, loc, SEEK_SET); + sim_fread(dsk_sect, 1, SECT_SIZE, uptr->fileref); + // reorganize buffer to match the byte order expected by MiniDOS + // + // Data in MiniDOS MPX disk image: + // BT BS FT FS NN AH AL TY CH CL PH PL [256 data bytes] = 268 bytes + // where BT=Backward link track, DS=Backward link sector, + // FT=Forward link track, FS=Forward link sector. = 00 00 if this is last sector of file + // NN=Number of data bytes (00=256 bytes) + // AH AL=Addr in RAM where to load sector data bytes (H=High byte, L=Low byte) + // TY=file type + // CH CL=CheckSum Hi/Low byte + // PH PL=Postamble Hi/Low byte. Holds program start addr on last sector + // + // Data as expected by MiniDOS ROM when reading a sector + // SY TR SE BT BS FT FS NN AH AL TY [NN data bytes] CH CL PH PL + // where SY=Sync Byte=$FD + // TR SE=This track and sector + // BT BS FT FS NN AH AL TY=same as above + // CH CL=same as above + // + // so we create the filebuf (p pointer) reordering data read from disk image file (dsk_sect) + p[0]=0xFB; // sync byte + p[1]=TRK; p[2]=SECT; // this sector track and sector number + for (i=0; i<8; i++) p[3+i]=dsk_sect[i]; // 8 byte header with bytes BT ... TY + n=dsk_sect[4]; if (n==0) n=256; // number of data bytes + for (i=0; ipos=0; + } + // retrieve read byte from sector buffer + if (uptr->pos>=BUF_SIZE) { + sim_debug (DEBUG_write, &fd400_dsk_dev, "Sector overrun - do not read data\n"); + return 0; + } + data=p[uptr->pos]; + sim_debug (DEBUG_read, &fd400_dsk_dev, "Read byte %02X (dec=%d char='%c'), Current Drive %d TRK %d SECT %d POS %d\n", + data, data, (data < 32) ? '?':data, fd400.cur_dsk, TRK, SECT, uptr->pos); + uptr->pos++; + + return data; + } + // io=1 -> writing data to i/o register, + // write data to sector + if (uptr->flags & UNIT_RO) { + sim_debug (DEBUG_write, &fd400_dsk_dev, "Write data %02X, but Current Drive %d is Read Only\n", + data, fd400.cur_dsk); + return 0; + } + sim_debug (DEBUG_write, &fd400_dsk_dev, "Write data %02X, Current Drive %d TRK %d SECT %d POS %d\n", + data, fd400.cur_dsk, TRK, SECT, uptr->pos); + // store byte into sector buffer + if (uptr->pos==0) { + if (data==0) return 0; // ignore zero bytes before sync byte + } + if (uptr->pos >= BUF_SIZE) { + sim_debug (DEBUG_write, &fd400_dsk_dev, "Sector overrun - do not write data\n"); + return 0; + } + // save byte to buffer + p[uptr->pos]=data; + uptr->pos++; + // calculate location of current sector in disk image file + loc=(TRK * NUM_SECT + SECT) * SECT_SIZE; + if (loc >= uptr->capac) { + // writing past image file current size -> extend disk image size + uint8 buf[SECT_SIZE]; + memset(buf, 0, sizeof(buf)); + sim_fseek(uptr->fileref, uptr->capac, SEEK_SET); + while (uptr->capac <= loc) { + sim_fwrite(buf, 1, SECT_SIZE, uptr->fileref); + uptr->capac += SECT_SIZE; + } + sim_debug (DEBUG_write, &fd400_dsk_dev, "Disk image extended up to %d bytes \n", uptr->capac); + } + // convert byte stream into sector format to save to disk. + // reorganize buffer to match the byte order expected by MiniDOS + // + // Data as sent to controller by MiniDOS ROM when writing a sector + // SY TR SE BT BS FT FS NN AH AL TY [NN data bytes] CH CL PH PL + // where SY=Sync Byte=$FD + // TR SE=This track and sector + // BT BS FT FS NN AH AL TY=same as below + // CH CL=same as below + // + // Data in MiniDOS MPX disk image: + // BT BS FT FS NN AH AL TY CH CL PH PL [256 data bytes] = 268 bytes + // where BT=Backward link track, DS=Backward link sector, + // FT=Forward link track, FS=Forward link sector. = 00 00 if this is last sector of file + // NN=Number of data bytes (00=256 bytes) + // AH AL=Addr in RAM where to load sector data bytes (H=High byte, L=Low byte) + // TY=file type + // CH CL=CheckSum Hi/Low byte + // PH PL=Postamble Hi/Low byte. Holds program start addr on last sector + // + // so we create the sector to write in disk image file (dsk_sect) reordering data from filebuf (p pointer) + + memset(dsk_sect, 255, sizeof(dsk_sect)); + for (i=0; i<8; i++) dsk_sect[i]=p[3+i]; // disk sector start with 8 byte header with bytes BT BS FT FS NN AH AL TY + n=uptr->pos-11; // number of data bytes + if (n>256+4) n=256+4; + if (n>4) { + for (i=0; i<4; i++) dsk_sect[i+8]=p[3+8+n+i-4]; // copy checksum and postamble + for (i=0; ifileref, loc, SEEK_SET); + sim_fwrite(dsk_sect, 1, SECT_SIZE, uptr->fileref); + return 0; +} + +/* CURRENT SECTOR / FILL CHAR REGISTER */ + +int32 fd400_cursect(int32 io, int32 data) +{ + UNIT * uptr; + + uptr = &fd400_dsk_unit[fd400.cur_dsk]; + if ((uptr->flags & UNIT_ATT) == 0) return 0; // not attached + if (io==0) { + // io=0 when reading from io register (return data read from i/o device register) + // return current sector + sim_debug (DEBUG_flow, &fd400_dsk_dev, "Current Drive %d TRK %d SECT %d \n", + fd400.cur_dsk, TRK, SECT); + return SECT; + } + // io=1 -> writing data to i/o register, + // set fill char + fd400.FillChar=data; + return 0; +} + +/* RECEIVER RESTART / WRITE PULSE $CC00 */ + +int32 fd400_startrw(int32 io, int32 data) +{ + UNIT * uptr; + + uptr = &fd400_dsk_unit[fd400.cur_dsk]; + if ((uptr->flags & UNIT_ATT) == 0) return 0; // not attached + if (io==0) { + // io=0 when reading from io register (return data read from i/o device register) + // start read from sector -> init received so it will return sync char and tracks + uptr->pos=0; + return 0; + } + // io=1 -> writing data to i/o register, + // start write to sector + uptr->pos=0; + return 0; +} + +t_stat fd400_attach (UNIT * uptr, CONST char * file) +{ + t_stat r; + + if ((r = attach_unit(uptr, file)) != SCPE_OK) return r; + uptr->u4 = uptr->u5 = 0; + uptr->capac = sim_fsize(uptr->fileref); + uptr->pos = 0; + return SCPE_OK; +} + +/* end of fd400.c */ diff --git a/swtp6800/common/i2716.c b/swtp6800/common/i2716.c index dd5c1365..c2ac92f3 100644 --- a/swtp6800/common/i2716.c +++ b/swtp6800/common/i2716.c @@ -25,8 +25,6 @@ MODIFICATIONS: - 24 Apr 15 -- Modified to use simh_debug - NOTES: These functions support a simulated 2704 to 2764 EPROMs device on an 8-bit @@ -114,19 +112,15 @@ t_stat i2716_attach (UNIT *uptr, CONST char *cptr) t_stat r; FILE *fp; - sim_debug (DEBUG_flow, &i2716_dev, "i2716_attach: cptr=%s\n", cptr); if ((r = attach_unit (uptr, cptr)) != SCPE_OK) { - sim_debug (DEBUG_flow, &i2716_dev, "i2716_attach: Error\n"); return r; } - sim_debug (DEBUG_read, &i2716_dev, "\tOpen file\n"); fp = fopen(uptr->filename, "rb"); /* open EPROM file */ if (fp == NULL) { printf("i2716%d: Unable to open ROM file %s\n", (int)(uptr - i2716_dev.units), uptr->filename); printf("\tNo ROM image loaded!!!\n"); return SCPE_OK; } - sim_debug (DEBUG_read, &i2716_dev, "\tRead file\n"); j = 0; /* load EPROM file */ c = fgetc(fp); while (c != EOF) { @@ -137,10 +131,7 @@ t_stat i2716_attach (UNIT *uptr, CONST char *cptr) break; } } - sim_debug (DEBUG_read, &i2716_dev, "\tClose file\n"); fclose(fp); -// printf("i2716%d: %d bytes of ROM image %s loaded\n",uptr - i2716_dev.units, j, uptr->filename); - sim_debug (DEBUG_flow, &i2716_dev, "i2716_attach: Done\n"); return SCPE_OK; } @@ -151,32 +142,21 @@ t_stat i2716_reset (DEVICE *dptr) int32 i, base; UNIT *uptr; - sim_debug (DEBUG_flow, &i2716_dev, "i2716_reset: \n"); for (i = 0; i < I2716_NUM; i++) { /* init all units */ uptr = i2716_dev.units + i; - sim_debug (DEBUG_flow, &i2716_dev, "i2716 %d unit.flags=%08X\n", - i, uptr->flags); uptr->capac = 2048; uptr->u3 = 2048 * i; base = get_base(); if (uptr->filebuf == NULL) { /* no buffer allocated */ - uptr->filebuf = malloc(2048); /* allocate EPROM buffer */ + uptr->filebuf = calloc(2048, sizeof(uint8)); /* allocate EPROM buffer */ if (uptr->filebuf == NULL) { - sim_debug (DEBUG_flow, &i2716_dev, "i2716_reset: Malloc error\n"); return SCPE_MEM; } } if (base == 0) { -// printf("i2716%d: Not enabled on MP-A2\n", i); continue; } -// printf("i2716%d: Initializing [%04X-%04XH]\n", -// i, base+uptr->u3, base+uptr->u3 + uptr->capac); -// if ((uptr->flags & UNIT_ATT) == 0) { -// printf("i2716%d: No file attached\n", i); -// } } - sim_debug (DEBUG_flow, &i2716_dev, "i2716_reset: Done\n"); return SCPE_OK; } @@ -197,16 +177,13 @@ int32 i2716_get_mbyte(int32 offset) len = uptr->capac - 1; if ((offset >= org) && (offset < (org + len))) { if (uptr->filebuf == NULL) { - sim_debug (DEBUG_read, &i2716_dev, "i2716_get_mbyte: EPROM not configured\n"); return 0xFF; } else { val = *((uint8 *)(uptr->filebuf) + (offset - org)); - sim_debug (DEBUG_read, &i2716_dev, " val=%04X\n", val); return (val & 0xFF); } } } - sim_debug (DEBUG_read, &i2716_dev, "i2716_get_mbyte: Out of range\n"); return 0xFF; } diff --git a/swtp6800/common/m6800.c b/swtp6800/common/m6800.c index a63c8635..df755638 100644 --- a/swtp6800/common/m6800.c +++ b/swtp6800/common/m6800.c @@ -25,8 +25,8 @@ MODIFICATIONS: - 23 Apr 15 -- Modified to use simh_debug - 21 Apr 20 -- Richard Brinegar numerous fixes for flag errors + 21 Apr 20 -- Richard Brinegar numerous fixes for condition code errors + 28 May 22 -- Roberto Sancho Villa (RSV)some more fixes for condition code errors NOTES: cpu Motorola M6800 CPU @@ -36,7 +36,7 @@ A<0:7> Accumulator A B<0:7> Accumulator B IX<0:15> Index Register - CC<0:7> Condition Code Register + CC<0:7> Condition Code Register HF half-carry flag IF interrupt flag NF negative flag @@ -111,23 +111,47 @@ #define COND_SET_FLAG_V(COND) \ if (COND) SET_FLAG(VF); else CLR_FLAG(VF) -/* local global variables */ +#define m6800_NAME "Motorola M6800 Processor Chip" +#define HIST_MIN 64 +#define HIST_MAX (1u << 18) +#define HIST_ILNT 3 /* max inst length */ + +typedef struct { + uint16 pc; + uint16 sp; + uint8 cc; + uint8 a; + uint8 b; + uint16 ix; + t_value inst[HIST_ILNT]; + } InstHistory; + +/* local global variables */ int32 A = 0; /* Accumulator A */ int32 B = 0; /* Accumulator B */ int32 IX = 0; /* Index register */ int32 SP = 0; /* Stack pointer */ -int32 CC = CC_ALWAYS_ON | IF; /* Condition Code Register */ -int32 saved_PC = 0; /* Program counter */ -int32 PC; /* global for the helper routines */ - -int32 mem_fault = 0; /* memory fault flag */ -int32 NMI = 0, IRQ = 0; +int32 CC = CC_ALWAYS_ON | IF; /* Condition Code Register */ +int32 saved_PC = 0xffff; /* Program counter */ +int32 PC; /* global for the helper routines */ +int32 NMI = 0, IRQ = 0; //interrupt flags +int32 hst_p = 0; /* history pointer */ +int32 hst_lnt = 0; /* history length */ +InstHistory *hst = NULL; /* instruction history */ +int32 reason; //reason for halting processor +static const char* m6800_desc(DEVICE *dptr) { + return m6800_NAME; +} /* function prototypes */ +t_stat cpu_set_hist (UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, CONST void *desc); t_stat m6800_reset (DEVICE *dptr); -t_stat m6800_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); +t_stat m6800_ex(t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +t_stat m6800_dep(t_value val, t_addr addr, UNIT *uptr, int32 sw); + void dump_regs(void); int32 fetch_byte(void); int32 fetch_word(void); @@ -154,70 +178,70 @@ extern int32 CPU_BD_get_mbyte(int32 addr); extern int32 CPU_BD_get_mword(int32 addr); static const char *opcode[] = { -"???", "NOP", "???", "???", //0x00 -"???", "???", "TAP", "TPA", -"INX", "DEX", "CLV", "SEV", -"CLC", "SEC", "CLI", "SEI", -"SBA", "CBA", "???", "???", //0x10 -"???", "???", "TAB", "TBA", -"???", "DAA", "???", "ABA", -"???", "???", "???", "???", -"BRA", "???", "BHI", "BLS", //0x20 -"BCC", "BCS", "BNE", "BEQ", -"BVC", "BVS", "BPL", "BMI", -"BGE", "BLT", "BGT", "BLE", -"TSX", "INS", "PULA", "PULB", //0x30 -"DES", "TXS", "PSHA", "PSHB", -"???", "RTS", "???", "RTI", -"???", "???", "WAI", "SWI", -"NEGA", "???", "???", "COMA", //0x40 -"LSRA", "???", "RORA", "ASRA", -"ASLA", "ROLA", "DECA", "???", -"INCA", "TSTA", "???", "CLRA", -"NEGB", "???", "???", "COMB", //0x50 -"LSRB", "???", "RORB", "ASRB", -"ASLB", "ROLB", "DECB", "???", -"INCB", "TSTB", "???", "CLRB", -"NEG", "???", "???", "COM", //0x60 -"LSR", "???", "ROR", "ASR", -"ASL", "ROL", "DEC", "???", -"INC", "TST", "JMP", "CLR", -"NEG", "???", "???", "COM", //0x70 -"LSR", "???", "ROR", "ASR", -"ASL", "ROL", "DEC", "???", -"INC", "TST", "JMP", "CLR", -"SUBA", "CMPA", "SBCA", "???", //0x80 -"ANDA", "BITA", "LDAA", "???", -"EORA", "ADCA", "ORAA", "ADDA", -"CPX", "BSR", "LDS", "???", -"SUBA", "CMPA", "SBCA", "???", //0x90 -"ANDA", "BITA", "LDAA", "STAA", -"EORA", "ADCA", "ORAA", "ADDA", -"CPX", "???", "LDS", "STS", -"SUBA", "CMPA", "SBCA", "???", //0xA0 -"ANDA", "BITA", "LDAA", "STAA", -"EORA", "ADCA", "ORAA", "ADDA", +"??? ", "NOP ", "??? ", "??? ", //0x00 +"??? ", "??? ", "TAP ", "TPA ", +"INX ", "DEX ", "CLV ", "SEV ", +"CLC ", "SEC ", "CLI ", "SEI ", +"SBA ", "CBA ", "??? ", "??? ", //0x10 +"??? ", "??? ", "TAB ", "TBA ", +"??? ", "DAA ", "??? ", "ABA ", +"??? ", "??? ", "??? ", "??? ", +"BRA ", "??? ", "BHI ", "BLS ", //0x20 +"BCC ", "BCS ", "BNE ", "BEQ ", +"BVC ", "BVS ", "BPL ", "BMI ", +"BGE ", "BLT ", "BGT ", "BLE ", +"TSX ", "INS ", "PUL A", "PUL B", //0x30 +"DES ", "TXS ", "PSH A", "PSH B", +"??? ", "RTS ", "??? ", "RTI ", +"??? ", "??? ", "WAI ", "SWI ", +"NEG A", "??? ", "??? ", "COM A", //0x40 +"LSR A", "??? ", "ROR A", "ASR A", +"ASL A", "ROL A", "DEC A", "??? ", +"INC A", "TST A", "??? ", "CLR A", +"NEG B", "??? ", "??? ", "COM B", //0x50 +"LSR B", "??? ", "ROR B", "ASR B", +"ASL B", "ROL B", "DEC B", "??? ", +"INC B", "TST B", "??? ", "CLR B", +"NEG ", "??? ", "??? ", "COM ", //0x60 +"LSR ", "??? ", "ROR ", "ASR ", +"ASL ", "ROL ", "DEC ", "??? ", +"INC ", "TST ", "JMP ", "CLR ", +"NEG ", "??? ", "??? ", "COM ", //0x70 +"LSR ", "??? ", "ROR ", "ASR ", +"ASL ", "ROL ", "DEC ", "??? ", +"INC ", "TST ", "JMP ", "CLR ", +"SUB A", "CMP A", "SBC A", "??? ", //0x80 +"AND A", "BIT A", "LDA A", "??? ", +"EOR A", "ADC A", "ORA A", "ADD A", +"CPX ", "BSR ", "LDS ", "??? ", +"SUB A", "CMP A", "SBC A", "??? ", //0x90 +"AND A", "BIT A", "LDA A", "STA A", +"EOR A", "ADC A", "ORA A", "ADD A", +"CPX ", "??? ", "LDS ", "STS ", +"SUB A", "CMP A", "SBC A", "??? ", //0xA0 +"AND A", "BIT A", "LDA A", "STA A", +"EOR A", "ADC A", "ORA A", "ADD A", "CPX X", "JSR X", "LDS X", "STS X", -"SUBA", "CMPA", "SBCA", "???", //0xB0 -"ANDA", "BITA", "LDAA", "STAA", -"EORA", "ADCA", "ORAA", "ADDA", -"CPX", "JSR", "LDS", "STS", -"SUBB", "CMPB", "SBCB", "???", //0xC0 -"ANDB", "BITB", "LDAB", "???", -"EORB", "ADCB", "ORAB", "ADDB", -"???", "???", "LDX", "???", -"SUBB", "CMPB", "SBCB", "???", //0xD0 -"ANDB", "BITB", "LDAB", "STAB", -"EORB", "ADCB", "ORAB", "ADDB", -"???", "???", "LDX", "STX", -"SUBB", "CMPB", "SBCB", "???", //0xE0 -"ANDB", "BITB", "LDAB", "STAB", -"EORB", "ADCB", "ORAB", "ADDB", -"???", "???", "LDX", "STX", -"SUBB", "CMPB", "SBCB", "???", //0xF0 -"ANDB", "BITB", "LDAB", "STAB", -"EORB", "ADCB", "ORAB", "ADDB", -"???", "???", "LDX", "STX", +"SUB A", "CMP A", "SBC A", "??? ", //0xB0 +"AND A", "BIT A", "LDA A", "STA A", +"EOR A", "ADC A", "ORA A", "ADD A", +"CPX ", "JSR ", "LDS ", "STS ", +"SUB B", "CMP B", "SBC B", "??? ", //0xC0 +"AND B", "BIT B", "LDA B", "??? ", +"EOR B", "ADC B", "ORA B", "ADD B", +"??? ", "??? ", "LDX ", "??? ", +"SUB B", "CMP B", "SBC B", "??? ", //0xD0 +"AND B", "BIT B", "LDA B", "STA B", +"EOR B", "AD CB", "ORA B", "ADD B", +"??? ", "??? ", "LDX ", "STX ", +"SUB B", "CMP B", "SBC B", "??? ", //0xE0 +"AND B", "BIT B", "LDA B", "STA B", +"EOR B", "ADC B", "ORA B", "ADD B", +"??? ", "??? ", "LDX ", "STX ", +"SUB B", "CMP B", "SBC B", "??? ", //0xF0 +"AND B", "BIT B", "LDA B", "STA B", +"EOR B", "ADC B", "ORA B", "ADD B", +"??? ", "??? ", "LDX ", "STX ", }; int32 oplen[256] = { @@ -256,14 +280,18 @@ REG m6800_reg[] = { { HRDATA (SP, SP, 16) }, { HRDATA (CC, CC, 8) }, { ORDATA (WRU, sim_int_char, 8) }, - { NULL } }; + { NULL } +}; MTAB m6800_mod[] = { { UNIT_OPSTOP, UNIT_OPSTOP, "ITRAP", "ITRAP", NULL }, { UNIT_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL }, { UNIT_MSTOP, UNIT_MSTOP, "MTRAP", "MTRAP", NULL }, { UNIT_MSTOP, 0, "NOMTRAP", "NOMTRAP", NULL }, - { 0 } }; + { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP|MTAB_NC, 0, "HISTORY", "HISTORY=n", + &cpu_set_hist, &cpu_show_hist, NULL, "Enable/Display instruction history" }, + { 0 } +}; DEBTAB m6800_debug[] = { { "ALL", DEBUG_all, "All debug bits" }, @@ -284,8 +312,8 @@ DEVICE m6800_dev = { 1, //aincr 16, //dradix 8, //dwidth - &m6800_examine, //examine - NULL, //deposit + &m6800_ex, //examine + &m6800_dep, //deposit &m6800_reset, //reset NULL, //boot NULL, //attach @@ -295,12 +323,17 @@ DEVICE m6800_dev = { 0, //dctrl m6800_debug, //debflags NULL, //msize - NULL //lname + NULL, //lname + NULL, //help routine + NULL, //attach help routine + NULL, //help context + &m6800_desc //device description }; t_stat sim_instr (void) { - int32 IR, EA, reason, hi, lo, op1; + int32 IR, EA, hi, lo, op1, i, sw = 0; + InstHistory *hst_ent = NULL; PC = saved_PC & ADDRMASK; /* load local PC */ reason = 0; @@ -311,11 +344,6 @@ t_stat sim_instr (void) if (sim_interval <= 0) /* check clock queue */ if ((reason = sim_process_event ())) break; - //if (mem_fault) { /* memory fault? */ - //mem_fault = 0; /* reset fault flag */ - //reason = STOP_MEMORY; - //break; - //} if (NMI > 0) { //* NMI? */ push_word(PC); push_word(IX); @@ -331,6 +359,7 @@ t_stat sim_instr (void) push_byte(A); push_byte(B); push_byte(CC); + SET_FLAG(IF); //rsv fix PC = get_vec_val(0xFFF8); } } /* end IRQ */ @@ -340,13 +369,27 @@ t_stat sim_instr (void) break; } + if (hst_lnt) { /* record history? */ + hst_ent = &hst[hst_p]; + hst_ent->pc = PC; + hst_ent->sp = SP; + hst_ent->cc = CC; + hst_ent->a = A; + hst_ent->b = B; + hst_ent->ix = IX; + for (i = 0; i < HIST_ILNT; i++) + hst_ent->inst[i] = (t_value)CPU_BD_get_mbyte (PC + i); + hst_p = (hst_p + 1); + if (hst_p >= hst_lnt) + hst_p = 0; + } + sim_interval--; IR = fetch_byte(); /* fetch instruction */ /* The Big Instruction Decode Switch */ switch (IR) { - case 0x01: /* NOP */ break; case 0x06: /* TAP */ @@ -385,7 +428,7 @@ t_stat sim_instr (void) op1 = A; A = A - B; COND_SET_FLAG_C(A); - A &= 0xFF; + A &= BYTEMASK; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); condevalVs(op1, B); @@ -393,7 +436,7 @@ t_stat sim_instr (void) case 0x11: /* CBA */ lo = A - B; COND_SET_FLAG_C(lo); - lo &= 0xFF ; + lo &= BYTEMASK; COND_SET_FLAG_N(lo); COND_SET_FLAG_Z(lo); condevalVs(A, B); @@ -423,7 +466,7 @@ t_stat sim_instr (void) A = (A & 0x0F) | (EA << 4) | 0x100; } COND_SET_FLAG_C(A); - A &= 0xFF; + A &= BYTEMASK; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); break; @@ -431,7 +474,7 @@ t_stat sim_instr (void) op1 = A ; A += B; COND_SET_FLAG_C(A); - A &= 0xFF; + A &= BYTEMASK; condevalHa(op1, B); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); @@ -540,15 +583,15 @@ t_stat sim_instr (void) PC = get_vec_val(0xFFFA); break; case 0x40: /* NEG A */ - COND_SET_FLAG_V(A == 0x80); - A = (0 - A); - COND_SET_FLAG_C(A); - A &= 0xFF; + op1 = A; + A = (0 - A) & BYTEMASK; + condevalVs(A, op1); //RSV - fixed boundry condition + COND_SET_FLAG(A,CF); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); break; case 0x43: /* COM A */ - A = ~A & 0xFF; + A = ~A & BYTEMASK; CLR_FLAG(VF); SET_FLAG(CF); COND_SET_FLAG_N(A); @@ -556,7 +599,7 @@ t_stat sim_instr (void) break; case 0x44: /* LSR A */ COND_SET_FLAG(A & 0x01,CF); - A = (A >> 1) & 0xFF; + A = (A >> 1) & BYTEMASK; CLR_FLAG(NF); COND_SET_FLAG_Z(A); COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); @@ -564,7 +607,7 @@ t_stat sim_instr (void) case 0x46: /* ROR A */ hi = get_flag(CF); COND_SET_FLAG(A & 0x01,CF); - A = (A >> 1) & 0xFF; + A = (A >> 1) & BYTEMASK; if (hi) A |= 0x80; COND_SET_FLAG_N(A); @@ -574,7 +617,7 @@ t_stat sim_instr (void) case 0x47: /* ASR A */ COND_SET_FLAG(A & 0x01,CF); lo = A & 0x80; - A = (A >> 1) & 0xFF; + A = (A >> 1) & BYTEMASK; A |= lo; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); @@ -582,7 +625,7 @@ t_stat sim_instr (void) break; case 0x48: /* ASL A */ COND_SET_FLAG(A & 0x80,CF); - A = (A << 1) & 0xFF; + A = (A << 1) & BYTEMASK; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); @@ -590,7 +633,7 @@ t_stat sim_instr (void) case 0x49: /* ROL A */ hi = get_flag(CF); COND_SET_FLAG(A & 0x80,CF); - A = (A << 1) & 0xFF; + A = (A << 1) & BYTEMASK; if (hi) A |= 0x01; COND_SET_FLAG_N(A); @@ -599,18 +642,18 @@ t_stat sim_instr (void) break; case 0x4A: /* DEC A */ COND_SET_FLAG_V(A == 0x80); - A = (A - 1) & 0xFF; + A = (A - 1) & BYTEMASK; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); break; case 0x4C: /* INC A */ COND_SET_FLAG_V(A == 0x7F); - A = (A + 1) & 0xFF; + A = (A + 1) & BYTEMASK; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); break; case 0x4D: /* TST A */ - lo = (A - 0) & 0xFF; + lo = (A - 0) & BYTEMASK; CLR_FLAG(VF); CLR_FLAG(CF); COND_SET_FLAG_N(lo); @@ -624,16 +667,16 @@ t_stat sim_instr (void) SET_FLAG(ZF); break; case 0x50: /* NEG B */ - COND_SET_FLAG_V(B == 0x80); - B = (0 - B); - COND_SET_FLAG_C(B); - B &= 0xFF; + op1 = B; + B = (0 - B) & BYTEMASK; + condevalVs(B, op1); //RSV - fixed boundry condition + COND_SET_FLAG(B,CF); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); break; case 0x53: /* COM B */ B = ~B; - B &= 0xFF; + B &= BYTEMASK; CLR_FLAG(VF); SET_FLAG(CF); COND_SET_FLAG_N(B); @@ -641,7 +684,7 @@ t_stat sim_instr (void) break; case 0x54: /* LSR B */ COND_SET_FLAG(B & 0x01,CF); - B = (B >> 1) & 0xFF; + B = (B >> 1) & BYTEMASK; CLR_FLAG(NF); COND_SET_FLAG_Z(B); COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); @@ -649,7 +692,7 @@ t_stat sim_instr (void) case 0x56: /* ROR B */ hi = get_flag(CF); COND_SET_FLAG(B & 0x01,CF); - B = (B >> 1) & 0xFF; + B = (B >> 1) & BYTEMASK; if (hi) B |= 0x80; COND_SET_FLAG_N(B); @@ -659,7 +702,7 @@ t_stat sim_instr (void) case 0x57: /* ASR B */ COND_SET_FLAG(B & 0x01,CF); lo = B & 0x80; - B = (B >> 1) & 0xFF; + B = (B >> 1) & BYTEMASK; B |= lo; COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); @@ -667,7 +710,7 @@ t_stat sim_instr (void) break; case 0x58: /* ASL B */ COND_SET_FLAG(B & 0x80,CF); - B = (B << 1) & 0xFF; + B = (B << 1) & BYTEMASK; COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); COND_SET_FLAG_V(get_flag(NF) ^ get_flag(CF)); @@ -675,7 +718,7 @@ t_stat sim_instr (void) case 0x59: /* ROL B */ hi = get_flag(CF); COND_SET_FLAG(B & 0x80,CF); - B = (B << 1) & 0xFF; + B = (B << 1) & BYTEMASK; if (hi) B |= 0x01; COND_SET_FLAG_N(B); @@ -684,18 +727,18 @@ t_stat sim_instr (void) break; case 0x5A: /* DEC B */ COND_SET_FLAG_V(B == 0x80); - B = (B - 1) & 0xFF; + B = (B - 1) & BYTEMASK; COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); break; case 0x5C: /* INC B */ COND_SET_FLAG_V(B == 0x7F); - B = (B + 1) & 0xFF; + B = (B + 1) & BYTEMASK; COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); break; case 0x5D: /* TST B */ - lo = (B - 0) & 0xFF; + lo = (B - 0) & BYTEMASK; CLR_FLAG(VF); CLR_FLAG(CF); COND_SET_FLAG_N(lo); @@ -711,18 +754,17 @@ t_stat sim_instr (void) case 0x60: /* NEG ind */ EA = (fetch_byte() + IX) & ADDRMASK; op1 = CPU_BD_get_mbyte(EA); - COND_SET_FLAG_V(op1 == 0x80); - lo = (0 - op1); - COND_SET_FLAG_C(lo); - lo &= 0xFF; + lo = (0 - op1) & BYTEMASK; CPU_BD_put_mbyte(EA, lo); + condevalVs(lo, op1); //RSV - fixed boundry condition + COND_SET_FLAG(lo,CF); COND_SET_FLAG_N(lo); COND_SET_FLAG_Z(lo); break; case 0x63: /* COM ind */ EA = (fetch_byte() + IX) & ADDRMASK; lo = ~CPU_BD_get_mbyte(EA); - lo &= 0xFF; + lo &= BYTEMASK; CPU_BD_put_mbyte(EA, lo); CLR_FLAG(VF); SET_FLAG(CF); @@ -766,7 +808,7 @@ t_stat sim_instr (void) EA = (fetch_byte() + IX) & ADDRMASK; lo = CPU_BD_get_mbyte(EA); COND_SET_FLAG(lo & 0x80,CF); - lo = (lo << 1) & 0xFF; + lo = (lo << 1) & BYTEMASK; CPU_BD_put_mbyte(EA, lo); COND_SET_FLAG_N(lo); COND_SET_FLAG_Z(lo); @@ -777,7 +819,7 @@ t_stat sim_instr (void) lo = CPU_BD_get_mbyte(EA); hi = get_flag(CF); COND_SET_FLAG(lo & 0x80,CF); - lo = (lo << 1) &0xFF; + lo = (lo << 1) &BYTEMASK; if (hi) lo |= 0x01; CPU_BD_put_mbyte(EA, lo); COND_SET_FLAG_N(lo); @@ -788,7 +830,7 @@ t_stat sim_instr (void) EA = (fetch_byte() + IX) & ADDRMASK; lo = CPU_BD_get_mbyte(EA); COND_SET_FLAG_V(lo == 0x80); - lo = (lo - 1) & 0xFF; + lo = (lo - 1) & BYTEMASK; CPU_BD_put_mbyte(EA, lo); COND_SET_FLAG_N(lo); COND_SET_FLAG_Z(lo); @@ -797,13 +839,13 @@ t_stat sim_instr (void) EA= (fetch_byte() + IX) & ADDRMASK; lo = CPU_BD_get_mbyte(EA); COND_SET_FLAG_V(lo == 0x7F); - lo = (lo + 1) & 0xFF; + lo = (lo + 1) & BYTEMASK; CPU_BD_put_mbyte(EA, lo); COND_SET_FLAG_N(lo); COND_SET_FLAG_Z(lo); break; case 0x6D: /* TST ind */ - lo = (get_indir_val() - 0) & 0xFF; + lo = (get_indir_val() - 0) & BYTEMASK; CLR_FLAG(VF); CLR_FLAG(CF); COND_SET_FLAG_N(lo); @@ -822,17 +864,19 @@ t_stat sim_instr (void) case 0x70: /* NEG ext */ EA = fetch_word(); op1 = CPU_BD_get_mbyte(EA); - COND_SET_FLAG_V(op1 == 0x80) ; - COND_SET_FLAG(op1 != 0, CF); - lo = (0 - op1) & 0xFF; + lo = (0 - op1) & BYTEMASK; CPU_BD_put_mbyte(EA, lo); + condevalVs(lo, op1); //RSV - fixed boundry condition + CLR_FLAG(CF); + if (lo) + SET_FLAG(CF); COND_SET_FLAG_N(lo); COND_SET_FLAG_Z(lo); break; case 0x73: /* COM ext */ EA = fetch_word(); lo = ~CPU_BD_get_mbyte(EA); - lo &= 0xFF; + lo &= BYTEMASK; CPU_BD_put_mbyte(EA, lo); CLR_FLAG(VF); SET_FLAG(CF); @@ -878,7 +922,7 @@ t_stat sim_instr (void) EA = fetch_word(); lo = CPU_BD_get_mbyte(EA); COND_SET_FLAG(lo & 0x80,CF); - lo = (lo << 1) & 0xFF; + lo = (lo << 1) & BYTEMASK; CPU_BD_put_mbyte(EA, lo); COND_SET_FLAG_N(lo); COND_SET_FLAG_Z(lo); @@ -889,7 +933,7 @@ t_stat sim_instr (void) lo = CPU_BD_get_mbyte(EA); hi = get_flag(CF); COND_SET_FLAG(lo & 0x80,CF); - lo = (lo << 1) & 0xFF; + lo = (lo << 1) & BYTEMASK; if (hi) lo |= 0x01; CPU_BD_put_mbyte(EA, lo); COND_SET_FLAG_N(lo); @@ -900,7 +944,7 @@ t_stat sim_instr (void) EA = fetch_word(); lo = CPU_BD_get_mbyte(EA); COND_SET_FLAG_V(lo == 0x80); - lo = (lo - 1) & 0xFF; + lo = (lo - 1) & BYTEMASK; CPU_BD_put_mbyte(EA, lo); COND_SET_FLAG_N(lo); COND_SET_FLAG_Z(lo); @@ -909,7 +953,7 @@ t_stat sim_instr (void) EA = fetch_word(); lo = CPU_BD_get_mbyte(EA); COND_SET_FLAG_V(lo == 0x7F); - lo = (lo + 1) & 0xFF; + lo = (lo + 1) & BYTEMASK; CPU_BD_put_mbyte(EA, lo); COND_SET_FLAG_N(lo); COND_SET_FLAG_Z(lo); @@ -919,7 +963,7 @@ t_stat sim_instr (void) CLR_FLAG(VF); CLR_FLAG(CF); COND_SET_FLAG_N(lo); - lo &= 0xFF; + lo &= BYTEMASK; COND_SET_FLAG_Z(lo); break; case 0x7E: /* JMP ext */ @@ -933,81 +977,81 @@ t_stat sim_instr (void) SET_FLAG(ZF); break; case 0x80: /* SUB A imm */ - lo = fetch_byte() & 0xFF; + lo = fetch_byte(); op1 = A; A = A - lo; COND_SET_FLAG_C(A); - A &= 0xFF; + A &= BYTEMASK; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); condevalVs(op1, lo); break; case 0x81: /* CMP A imm */ - op1 = fetch_byte() & 0xFF; + op1 = fetch_byte(); lo = A - op1; COND_SET_FLAG_C(lo); - lo &= 0xFF; + lo &= BYTEMASK; COND_SET_FLAG_N(lo); COND_SET_FLAG_Z(lo); condevalVs(A, op1); break; case 0x82: /* SBC A imm */ - lo = fetch_byte() & 0xFF + get_flag(CF); + lo = (fetch_byte() + get_flag(CF)) & BYTEMASK; //RSV - fixed ordering problem op1 = A; A = A - lo; COND_SET_FLAG_C(A); - A &= 0xFF; + A &= BYTEMASK; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); condevalVs(op1, lo); break; case 0x84: /* AND A imm */ - A = (A & fetch_byte() & 0xFF) & 0xFF; + A = (A & fetch_byte()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); break; case 0x85: /* BIT A imm */ - lo = (A & fetch_byte() & 0xFF) & 0xFF; + lo = (A & fetch_byte()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(lo); COND_SET_FLAG_Z(lo); break; case 0x86: /* LDA A imm */ - A = fetch_byte() & 0xFF; + A = fetch_byte(); CLR_FLAG(VF); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); break; case 0x88: /* EOR A imm */ - A = (A ^ fetch_byte() & 0xFF) & 0xFF; + A = (A ^ fetch_byte()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); break; case 0x89: /* ADC A imm */ - lo = fetch_byte() & 0xFF + get_flag(CF); + lo = (fetch_byte() + get_flag(CF)) & BYTEMASK; op1 = A; A = A + lo; COND_SET_FLAG_C(A); - A &= 0xFF; + A &= BYTEMASK; condevalHa(op1, lo); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); condevalVa(op1, lo); break; case 0x8A: /* ORA A imm */ - A = (A | fetch_byte() & 0xFF) & 0xFF; + A = (A | fetch_byte()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); break; case 0x8B: /* ADD A imm */ - lo = fetch_byte() & 0xFF; + lo = fetch_byte(); op1 = A; A = A + lo; COND_SET_FLAG_C(A); - A &= 0xFF; + A &= BYTEMASK; condevalHa(op1, lo); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); @@ -1039,7 +1083,7 @@ t_stat sim_instr (void) op1 = A; A = A - lo; COND_SET_FLAG_C(A); - A &= 0xFF; + A &= BYTEMASK; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); condevalVs(op1, lo); @@ -1050,27 +1094,26 @@ t_stat sim_instr (void) COND_SET_FLAG_N(lo); COND_SET_FLAG_C(lo); condevalVs(A, op1); - lo &= 0xFF; + lo &= BYTEMASK; COND_SET_FLAG_Z(lo); break; case 0x92: /* SBC A dir */ - lo = get_dir_val() + get_flag(CF); - op1 = A; + lo = (get_dir_val() + get_flag(CF)) & BYTEMASK; //RSV - fixed ordering problem A = A - lo; COND_SET_FLAG_C(A); - A &= 0xFF; + A &= BYTEMASK; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); condevalVs(op1, lo); break; case 0x94: /* AND A dir */ - A = (A & get_dir_val()) & 0xFF; + A = (A & get_dir_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); break; case 0x95: /* BIT A dir */ - lo = (A & get_dir_val()) & 0xFF; + lo = (A & get_dir_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(lo); COND_SET_FLAG_Z(lo); @@ -1082,30 +1125,30 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(A); break; case 0x97: /* STA A dir */ - CPU_BD_put_mbyte(fetch_byte() & 0xFF, A); + CPU_BD_put_mbyte(fetch_byte(), A); CLR_FLAG(VF); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); break; case 0x98: /* EOR A dir */ - A = (A ^ get_dir_val()) & 0xFF; + A = (A ^ get_dir_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); break; case 0x99: /* ADC A dir */ - lo = get_dir_val() + get_flag(CF); + lo = (get_dir_val() + get_flag(CF)) & BYTEMASK; op1 = A; A = A + lo; COND_SET_FLAG_C(A); - A &= 0xFF; + A &= BYTEMASK; condevalHa(op1, lo); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); condevalVa(op1, lo); break; case 0x9A: /* ORA A dir */ - A = (A | get_dir_val()) & 0xFF; + A = (A | get_dir_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); @@ -1115,26 +1158,26 @@ t_stat sim_instr (void) op1 = A; A = A + lo; COND_SET_FLAG_C(A); - A &= 0xFF; + A &= BYTEMASK; condevalHa(op1, lo); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); condevalVa(op1, lo); break; case 0x9C: /* CPX dir */ - op1 = IX - CPU_BD_get_mword(fetch_byte() & 0xFF); + op1 = IX - CPU_BD_get_mword(fetch_byte()); COND_SET_FLAG_Z(op1); COND_SET_FLAG_N(op1 >> 8); COND_SET_FLAG_V(op1 & 0x10000); break; case 0x9E: /* LDS dir */ - SP = CPU_BD_get_mword(fetch_byte() & 0xFF); + SP = CPU_BD_get_mword(fetch_byte()); COND_SET_FLAG_N(SP >> 8); COND_SET_FLAG_Z(SP); CLR_FLAG(VF); break; case 0x9F: /* STS dir */ - CPU_BD_put_mword(fetch_byte() & 0xFF, SP); + CPU_BD_put_mword(fetch_byte(), SP); COND_SET_FLAG_N(SP >> 8); COND_SET_FLAG_Z(SP); CLR_FLAG(VF); @@ -1144,7 +1187,7 @@ t_stat sim_instr (void) op1 = A; A = A - lo; COND_SET_FLAG_C(A); - A &= 0xFF; + A &= BYTEMASK; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); condevalVs(op1, lo); @@ -1155,27 +1198,26 @@ t_stat sim_instr (void) COND_SET_FLAG_N(lo); COND_SET_FLAG_C(lo); condevalVs(A, op1); - lo &= 0xFF; + lo &= BYTEMASK; COND_SET_FLAG_Z(lo); break; case 0xA2: /* SBC A ind */ - lo = get_indir_val() + get_flag(CF); - op1 = A; + lo = (get_indir_val() + get_flag(CF)) & BYTEMASK; //RSV - fixed ordering problem A = A - lo; COND_SET_FLAG_C(A); - A &= 0xFF; + A &= BYTEMASK; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); condevalVs(op1, lo); break; case 0xA4: /* AND A ind */ - A = (A & get_indir_val()) & 0xFF; + A = (A & get_indir_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); break; case 0xA5: /* BIT A ind */ - lo = (A & get_indir_val()) & 0xFF; + lo = (A & get_indir_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(lo); COND_SET_FLAG_Z(lo); @@ -1193,24 +1235,24 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(A); break; case 0xA8: /* EOR A ind */ - A = (A ^ get_indir_val()) & 0xFF; + A = (A ^ get_indir_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); break; case 0xA9: /* ADC A ind */ - lo = get_indir_val() + get_flag(CF); + lo = (get_indir_val() + get_flag(CF)) & BYTEMASK; op1 = A; A = A + lo; COND_SET_FLAG_C(A); - A &= 0xFF; + A &= BYTEMASK; condevalHa(op1, lo); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); condevalVa(op1, lo); break; case 0xAA: /* ORA A ind */ - A = (A | get_indir_val()) & 0xFF; + A = (A | get_indir_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); @@ -1220,7 +1262,7 @@ t_stat sim_instr (void) op1 = A; A = A + lo; COND_SET_FLAG_C(A); - A &= 0xFF; + A &= BYTEMASK; condevalHa(op1, lo); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); @@ -1254,7 +1296,7 @@ t_stat sim_instr (void) op1 = A; A = A - lo; COND_SET_FLAG_C(A); - A &= 0xFF; + A &= BYTEMASK; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); condevalVs(op1, lo); @@ -1265,27 +1307,27 @@ t_stat sim_instr (void) COND_SET_FLAG_N(lo); COND_SET_FLAG_C(lo); condevalVs(A, op1); - lo &= 0xFF; + lo &= BYTEMASK; COND_SET_FLAG_Z(lo); break; case 0xB2: /* SBC A ext */ - lo = get_ext_val() + get_flag(CF); + lo = (get_ext_val() + get_flag(CF)) & BYTEMASK; //RSV - fixed ordering problem op1 = A; A = A - lo; COND_SET_FLAG_C(A); - A &= 0xFF; + A &= BYTEMASK; COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); condevalVs(op1, lo); break; case 0xB4: /* AND A ext */ - A = (A & get_ext_val()) & 0xFF; + A = (A & get_ext_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); break; case 0xB5: /* BIT A ext */ - lo = (A & get_ext_val()) & 0xFF; + lo = (A & get_ext_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(lo); COND_SET_FLAG_Z(lo); @@ -1303,24 +1345,24 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(A); break; case 0xB8: /* EOR A ext */ - A = (A ^ get_ext_val()) & 0xFF; + A = (A ^ get_ext_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); break; case 0xB9: /* ADC A ext */ - lo = get_ext_val() + get_flag(CF); + lo = (get_ext_val() + get_flag(CF)) & BYTEMASK; op1 = A; A = A + lo; COND_SET_FLAG_C(A); - A &= 0xFF; + A &= BYTEMASK; condevalHa(op1, lo); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); condevalVa(op1, lo); break; case 0xBA: /* ORA A ext */ - A = (A | get_ext_val()) & 0xFF; + A = (A | get_ext_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); @@ -1330,7 +1372,7 @@ t_stat sim_instr (void) op1 = A; A = A + lo; COND_SET_FLAG_C(A); - A &= 0xFF; + A &= BYTEMASK; condevalHa(op1, lo); COND_SET_FLAG_N(A); COND_SET_FLAG_Z(A); @@ -1360,81 +1402,81 @@ t_stat sim_instr (void) CLR_FLAG(VF); break; case 0xC0: /* SUB B imm */ - lo = fetch_byte() & 0xFF; + lo = fetch_byte(); op1 = B; B = B - lo; COND_SET_FLAG_C(B); - B &= 0xFF; + B &= BYTEMASK; COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); condevalVs(op1, lo); break; case 0xC1: /* CMP B imm */ - op1 = fetch_byte() & 0xFF; + op1 = fetch_byte(); lo = B - op1; COND_SET_FLAG_N(lo); COND_SET_FLAG_C(lo); condevalVs(B, op1); - lo &= 0xFF; + lo &= BYTEMASK; COND_SET_FLAG_Z(lo); break; case 0xC2: /* SBC B imm */ - lo = fetch_byte() & 0xFF + get_flag(CF); + lo = (fetch_byte() + get_flag(CF)) & BYTEMASK; //RSV - fixed ordering problem op1 = B; B = B - lo; COND_SET_FLAG_C(B); - B &= 0xFF; + B &= BYTEMASK; COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); condevalVs(op1, lo); break; case 0xC4: /* AND B imm */ - B = (B & fetch_byte() & 0xFF) & 0xFF; + B = (B & fetch_byte()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); break; case 0xC5: /* BIT B imm */ - lo = (B & fetch_byte() & 0xFF) & 0xFF; + lo = (B & fetch_byte()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(lo); COND_SET_FLAG_Z(lo); break; case 0xC6: /* LDA B imm */ - B = fetch_byte() & 0xFF; + B = fetch_byte(); CLR_FLAG(VF); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); break; case 0xC8: /* EOR B imm */ - B = (B ^ fetch_byte() & 0xFF) & 0xFF; + B = (B ^ fetch_byte()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); break; case 0xC9: /* ADC B imm */ - lo = fetch_byte() & 0xFF + get_flag(CF); + lo = (fetch_byte() + get_flag(CF)) & BYTEMASK; op1 = B; B = B + lo; COND_SET_FLAG_C(B); - B &= 0xFF; + B &= BYTEMASK; condevalHa(op1, lo); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); condevalVa(op1, lo); break; case 0xCA: /* ORA B imm */ - B = (B | fetch_byte() & 0xFF) & 0xFF; + B = (B | fetch_byte()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); break; case 0xCB: /* ADD B imm */ - lo = fetch_byte() & 0xFF; + lo = fetch_byte(); op1 = B; B = B + lo; COND_SET_FLAG_C(B); - B &= 0xFF; + B &= BYTEMASK; condevalHa(op1, lo); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); @@ -1451,7 +1493,7 @@ t_stat sim_instr (void) op1 = B; B = B - lo; COND_SET_FLAG_C(B); - B &= 0xFF; + B &= BYTEMASK; COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); condevalVs(op1, lo); @@ -1460,29 +1502,29 @@ t_stat sim_instr (void) lo = get_dir_val(); op1 = B - lo; COND_SET_FLAG_C(op1); - op1 &= 0xFF; + op1 &= BYTEMASK; COND_SET_FLAG_N(op1); COND_SET_FLAG_Z(op1); condevalVs(B, lo); break; case 0xD2: /* SBC B dir */ - lo = get_dir_val() + get_flag(CF); + lo = (get_dir_val() + get_flag(CF)) & BYTEMASK; //RSV - fixed ordering problem op1 = B; B = B - lo; COND_SET_FLAG_C(B); - B &= 0xFF; + B &= BYTEMASK; COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); condevalVs(op1, lo); break; case 0xD4: /* AND B dir */ - B = (B & get_dir_val()) & 0xFF; + B = (B & get_dir_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); break; case 0xD5: /* BIT B dir */ - lo = (B & get_dir_val()) & 0xFF; + lo = (B & get_dir_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(lo); COND_SET_FLAG_Z(lo); @@ -1494,30 +1536,30 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(B); break; case 0xD7: /* STA B dir */ - CPU_BD_put_mbyte(fetch_byte() & 0xFF, B); + CPU_BD_put_mbyte(fetch_byte(), B); CLR_FLAG(VF); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); break; case 0xD8: /* EOR B dir */ - B = (B ^ get_dir_val()) & 0xFF; + B = (B ^ get_dir_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); break; case 0xD9: /* ADC B dir */ - lo = get_dir_val() + get_flag(CF); + lo = (get_dir_val() + get_flag(CF)) & BYTEMASK; op1 = B; B = B + lo; COND_SET_FLAG_C(B); - B &= 0xFF; + B &= BYTEMASK; condevalHa(op1, lo); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); condevalVa(op1, lo); break; case 0xDA: /* ORA B dir */ - B = (B | get_dir_val()) & 0xFF; + B = (B | get_dir_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); @@ -1527,20 +1569,20 @@ t_stat sim_instr (void) op1 = B; B = B + lo; COND_SET_FLAG_C(B); - B &= 0xFF; + B &= BYTEMASK; condevalHa(op1, lo); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); condevalVa(op1, lo); break; case 0xDE: /* LDX dir */ - IX = CPU_BD_get_mword(fetch_byte() & 0xFF); + IX = CPU_BD_get_mword(fetch_byte()); COND_SET_FLAG_N(IX >> 8); COND_SET_FLAG_Z(IX); CLR_FLAG(VF); break; case 0xDF: /* STX dir */ - CPU_BD_put_mword(fetch_byte() & 0xFF, IX); + CPU_BD_put_mword(fetch_byte(), IX); COND_SET_FLAG_N(IX >> 8); COND_SET_FLAG_Z(IX); CLR_FLAG(VF); @@ -1550,7 +1592,7 @@ t_stat sim_instr (void) op1 = B; B = B - lo; COND_SET_FLAG_C(B); - B &= 0xFF; + B &= BYTEMASK; COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); condevalVs(op1, lo); @@ -1561,27 +1603,27 @@ t_stat sim_instr (void) COND_SET_FLAG_N(lo); COND_SET_FLAG_C(lo); condevalVs(B, op1); - lo &= 0xFF; + lo &= BYTEMASK; COND_SET_FLAG_Z(lo); break; case 0xE2: /* SBC B ind */ - lo = get_indir_val() + get_flag(CF); + lo = (get_indir_val() + get_flag(CF)) & BYTEMASK; //RSV - fixed ordering problem op1 = B; B = B - lo; COND_SET_FLAG_C(B); - B &= 0xFF; + B &= BYTEMASK; COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); condevalVs(op1, lo); break; case 0xE4: /* AND B ind */ - B = (B & get_indir_val()) & 0xFF; + B = (B & get_indir_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); break; case 0xE5: /* BIT B ind */ - lo = (B & get_indir_val()) & 0xFF; + lo = (B & get_indir_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(lo); COND_SET_FLAG_Z(lo); @@ -1599,24 +1641,24 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(B); break; case 0xE8: /* EOR B ind */ - B = (B ^ get_indir_val()) & 0xFF; + B = (B ^ get_indir_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); break; case 0xE9: /* ADC B ind */ - lo = get_indir_val() + get_flag(CF); + lo = (get_indir_val() + get_flag(CF)) & BYTEMASK; op1 = B; B = B + lo; COND_SET_FLAG_C(B); - B &= 0xFF; + B &= BYTEMASK; condevalHa(op1, lo); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); condevalVa(op1, lo); break; case 0xEA: /* ORA B ind */ - B = (B | get_indir_val()) & 0xFF; + B = (B | get_indir_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); @@ -1626,7 +1668,7 @@ t_stat sim_instr (void) op1 = B; B = B + lo; COND_SET_FLAG_C(B); - B &= 0xFF; + B &= BYTEMASK; condevalHa(op1, lo); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); @@ -1649,7 +1691,7 @@ t_stat sim_instr (void) op1 = B; B = B - lo; COND_SET_FLAG_C(B); - B &= 0xFF; + B &= BYTEMASK; COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); condevalVs(op1, lo); @@ -1660,27 +1702,27 @@ t_stat sim_instr (void) COND_SET_FLAG_N(lo); COND_SET_FLAG_C(lo); condevalVs(B, op1); - lo &= 0xFF; + lo &= BYTEMASK; COND_SET_FLAG_Z(lo); break; case 0xF2: /* SBC B ext */ - lo = get_ext_val() + get_flag(CF); + lo = (get_ext_val() + get_flag(CF)) & BYTEMASK; //RSV - fixed ordering problem op1 = B; B = B - lo; COND_SET_FLAG_C(B); - B &= 0xFF; + B &= BYTEMASK; COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); condevalVs(op1, lo); break; case 0xF4: /* AND B ext */ - B = (B & get_ext_val()) & 0xFF; + B = (B & get_ext_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); break; case 0xF5: /* BIT B ext */ - lo = (B & get_ext_val()) & 0xFF; + lo = (B & get_ext_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(lo); COND_SET_FLAG_Z(lo); @@ -1698,24 +1740,24 @@ t_stat sim_instr (void) COND_SET_FLAG_Z(B); break; case 0xF8: /* EOR B ext */ - B = (B ^ get_ext_val()) & 0xFF; + B = (B ^ get_ext_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); break; case 0xF9: /* ADC B ext */ - lo = get_ext_val() + get_flag(CF); + lo = (get_ext_val() + get_flag(CF)) & BYTEMASK; op1 = B; B = B + lo; COND_SET_FLAG_C(B); - B &= 0xFF; + B &= BYTEMASK; condevalHa(op1, lo); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); condevalVa(op1, lo); break; case 0xFA: /* ORA B ext */ - B = (B | get_ext_val()) & 0xFF; + B = (B | get_ext_val()) & BYTEMASK; CLR_FLAG(VF); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); @@ -1725,7 +1767,7 @@ t_stat sim_instr (void) op1 = B; B = B + lo; COND_SET_FLAG_C(B); - B &= 0xFF; + B &= BYTEMASK; condevalHa(op1, lo); COND_SET_FLAG_N(B); COND_SET_FLAG_Z(B); @@ -1754,7 +1796,6 @@ t_stat sim_instr (void) } } /* Simulation halted - lets dump all the registers! */ - dump_regs(); saved_PC = PC; return reason; } @@ -1772,7 +1813,8 @@ int32 fetch_byte(void) { uint8 val; - val = CPU_BD_get_mbyte(PC) & 0xFF; /* fetch byte */ + val = CPU_BD_get_mbyte(PC) & BYTEMASK; /* fetch byte */ + //rsv fix on opernd order but moved the "& BYTEMASK" here PC = (PC + 1) & ADDRMASK; /* increment PC */ return val; } @@ -1783,7 +1825,7 @@ int32 fetch_word(void) uint16 val; val = CPU_BD_get_mbyte(PC) << 8; /* fetch high byte */ - val |= CPU_BD_get_mbyte(PC + 1) & 0xFF; /* fetch low byte */ + val |= CPU_BD_get_mbyte(PC + 1) & BYTEMASK; /* fetch low byte */ PC = (PC + 2) & ADDRMASK; /* increment PC */ return val; } @@ -1791,14 +1833,15 @@ int32 fetch_word(void) /* push a byte to the stack */ void push_byte(uint8 val) { - CPU_BD_put_mbyte(SP, val & 0xFF); + CPU_BD_put_mbyte(SP, val & BYTEMASK); + //rsv fix on opernd order but moved the "& BYTEMASK" here SP = (SP - 1) & ADDRMASK; } /* push a word to the stack */ void push_word(uint16 val) { - push_byte(val & 0xFF); + push_byte(val & BYTEMASK); push_byte(val >> 8); } @@ -1848,14 +1891,14 @@ int32 get_vec_val(int32 vec) int32 get_imm_val(void) { - return (fetch_byte() & 0xFF); + return fetch_byte(); } /* returns the value at the direct address pointed to by PC */ int32 get_dir_val(void) { - return CPU_BD_get_mbyte(fetch_byte() & 0xFF); + return CPU_BD_get_mbyte(fetch_byte()); } /* returns the value at the indirect address pointed to by PC */ @@ -1918,16 +1961,16 @@ void condevalHa(int32 op1, int32 op2) /* Reset routine */ -t_stat m6800_reset (DEVICE *dptr) +t_stat m6800_reset(DEVICE *dptr) { CC = CC_ALWAYS_ON | IF; NMI = 0, IRQ = 0; sim_brk_types = sim_brk_dflt = SWMASK ('E'); saved_PC = CPU_BD_get_mword(0xFFFE); -// if (saved_PC == 0xFFFF) -// printf("No EPROM image found - M6800 reset incomplete!\n"); -// else -// printf("EPROM vector=%04X\n", saved_PC); + if ((saved_PC == 0xFFFF) && ((sim_switches & SWMASK ('P')) == 0)) { + printf("No EPROM image found\n"); + reason = STOP_MEMORY; /* stop simulation - no ROM*/ + } return SCPE_OK; } @@ -1936,19 +1979,113 @@ t_stat m6800_reset (DEVICE *dptr) 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; +#define HLEN 16 - 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); +int32 sim_load(FILE *fileref, CONST char *cptr, CONST char *fnam, int flag) +{ + int32 i, addr = 0, addr0 = 0, cnt = 0, cnt0 = 0, start = 0x10000; + int32 addr1 = 0, end = 0, byte, chk, rtype, flag0 = 1; + char buf[128], data[128], *p; + + cnt = sscanf(cptr, " %04X %04X", &start, &end); + addr=start; + if (flag == 0) { //load + if (sim_switches & SWMASK ('H')) { //hex + if (cnt > 1) //2 arguments - error + return SCPE_ARG; + cnt = 0; + while (fgets(buf, sizeof(buf)-1, fileref)) { + sscanf(buf, " S%1d%02x%04x%s", &rtype, &cnt0, &addr, data); + if (flag0) { + addr1 = addr; + flag0 = 0; + } + if (rtype == 1) { + chk = 0; + chk += cnt0; + cnt0 -= 3; + chk += addr & BYTEMASK; + chk += addr >> 8; + p = (char *) data; + for (i=0; i 1) //2 arguments - error + return SCPE_ARG; + cnt = 0; + addr1 = addr; + while ((i = getc (fileref)) != EOF) { + CPU_BD_put_mbyte(addr, i); + addr++; cnt++; + } + } + printf ("%d Bytes loaded at %04X\n", cnt, addr1); + return (SCPE_OK); + } else { //dump + if (cnt != 2) //must be 2 arguments + return SCPE_ARG; + cnt = 0; + addr0 = addr; + if (sim_switches & SWMASK ('H')) { //hex + while((addr + HLEN) <= end) { //full records + fprintf(fileref,"S1%02X%04X", HLEN + 3, addr); + chk = 0; + chk += HLEN + 3; + chk += addr & BYTEMASK; + chk += addr >> 8; + for (i=0; i> 8; + for (i=0; i<=(end - addr); i++) { + byte = CPU_BD_get_mbyte(addr + i); + fprintf(fileref, "%02X", byte); + chk += byte; chk &= BYTEMASK; + cnt++; + } + chk = (~chk) & BYTEMASK; + fprintf(fileref, "%02X\n", chk); + addr = end; + } + fprintf(fileref,"S9\n"); //EOF record + } else { //binary + while (addr <= end) { + i = CPU_BD_get_mbyte(addr); + putc(i, fileref); + addr++; cnt++; + } + } + printf ("%d Bytes dumped from %04X\n", cnt, addr0); + } + return SCPE_OK; } /* Symbolic output @@ -1963,9 +2100,9 @@ t_stat sim_load (FILE *fileref, CONST char *cptr, CONST char *fnam, int flag) status = error code for M6800 */ -t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) +t_stat fprint_sym(FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) { - int32 i, inst, inst1; + int i, inst, inst1; if (sw & SWMASK ('D')) { // dump memory for (i=0; i<16; i++) @@ -2018,14 +2155,94 @@ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) status = error status */ -t_stat parse_sym (CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) +t_stat parse_sym(CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) { - return (-2); + return (1); } -t_stat m6800_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) +/* Set history */ + +t_stat cpu_set_hist (UNIT *uptr, int32 val, CONST char *cptr, void *desc) { - return SCPE_OK; + int i, lnt; + t_stat r; + + if (cptr == NULL) { + for (i = 0; i < hst_lnt; i++) + hst[i].pc = 0; + hst_p = 0; + return SCPE_OK; + } + lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r); + if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) + return SCPE_ARG; + hst_p = 0; + if (hst_lnt) { + free (hst); + hst_lnt = 0; + hst = NULL; + } + if (lnt) { + hst = (InstHistory *) calloc (lnt, sizeof (InstHistory)); + if (hst == NULL) + return SCPE_MEM; + hst_lnt = lnt; + } + return SCPE_OK; +} + +/* Show history */ + +t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, CONST void *desc) +{ + int k, di, lnt, ir; + const char *cptr = (const char *) desc; + t_stat r; + InstHistory *h; + + if (hst_lnt == 0) /* enabled? */ + return SCPE_NOFNC; + if (cptr) { + lnt = (int32) get_uint (cptr, 10, hst_lnt, &r); + if ((r != SCPE_OK) || (lnt == 0)) + return SCPE_ARG; + } + else lnt = hst_lnt; + di = hst_p - lnt; /* work forward */ + if (di < 0) + di = di + hst_lnt; + fprintf (st, "PC SP CC A B IX Instruction\n\n"); + for (k = 0; k < lnt; k++) { /* print specified */ + h = &hst[(di++) % hst_lnt]; /* entry pointer */ + ir = h->inst[0]; + fprintf (st, "%04X %04X %02X ", h->pc , h->sp, h->cc); + fprintf (st, "%02X %02X %04X ", h->a, h->b, h->ix); + if ((fprint_sym (st, h->pc, h->inst, &m6800_unit, SWMASK ('M'))) > 0) + fprintf (st, "(undefined) %02X", h->inst[0]); + fputc ('\n', st); /* end line */ + } + return SCPE_OK; +} + +/* Memory examine */ + +t_stat m6800_ex(t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ + if (addr >= MAXMEMSIZE) + return SCPE_NXM; + if (vptr != NULL) + *vptr = CPU_BD_get_mbyte(addr); + return SCPE_OK; +} + +/* Memory deposit */ + +t_stat m6800_dep(t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ + if (addr >= MAXMEMSIZE) + return SCPE_NXM; + CPU_BD_put_mbyte(addr, val); + return SCPE_OK; } /* end of m6800.c */ diff --git a/swtp6800/common/m6810.c b/swtp6800/common/m6810.c index cb50a3cc..a1af1c9b 100644 --- a/swtp6800/common/m6810.c +++ b/swtp6800/common/m6810.c @@ -25,8 +25,6 @@ MODIFICATIONS: - 24 Apr 15 -- Modified to use simh_debug - NOTES: These functions support a simulated m6810 RAM device on a CPU board. The @@ -43,13 +41,12 @@ t_stat m6810_reset (DEVICE *dptr); int32 m6810_get_mbyte(int32 offset); void m6810_put_mbyte(int32 offset, int32 val); -t_stat m6810_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); -t_stat m6810_deposit(t_value value, t_addr addr, UNIT *uptr, int32 switches); /* SIMH RAM Standard I/O Data Structures */ -UNIT m6810_unit = { UDATA (NULL, UNIT_BINK, 128), - 0 }; +UNIT m6810_unit = { + UDATA (NULL, UNIT_BINK, 128), + 0 }; MTAB m6810_mod[] = { { 0 } @@ -74,8 +71,8 @@ DEVICE m6810_dev = { 1, //aincr 16, //dradix 8, //dwidth - &m6810_examine, //examine - &m6810_deposit, //deposit + NULL, //examine + NULL, //deposit &m6810_reset, //reset NULL, //boot NULL, //attach @@ -94,16 +91,14 @@ DEVICE m6810_dev = { t_stat m6810_reset (DEVICE *dptr) { - sim_debug (DEBUG_flow, &m6810_dev, "m6810_reset: \n"); if (m6810_unit.filebuf == NULL) { - m6810_unit.filebuf = malloc(128); + m6810_unit.filebuf = calloc(128, sizeof(uint8)); if (m6810_unit.filebuf == NULL) { - printf("m6810_reset: Malloc error\n"); + printf("m6810_reset: Calloc error\n"); return SCPE_MEM; } m6810_unit.capac = 128; } - sim_debug (DEBUG_flow, &m6810_dev, "m6810_reset: Done\n"); return SCPE_OK; } @@ -117,13 +112,10 @@ int32 m6810_get_mbyte(int32 offset) { int32 val; - sim_debug (DEBUG_read, &m6810_dev, "m6810_get_mbyte: offset=%04X\n", offset); if (((t_addr)offset) < m6810_unit.capac) { val = *((uint8 *)(m6810_unit.filebuf) + offset) & 0xFF; - sim_debug (DEBUG_read, &m6810_dev, "val=%04X\n", val); return val; } else { - sim_debug (DEBUG_read, &m6810_dev, "m6810_get_mbyte: out of range\n"); return 0xFF; } } @@ -132,30 +124,12 @@ int32 m6810_get_mbyte(int32 offset) void m6810_put_mbyte(int32 offset, int32 val) { - sim_debug (DEBUG_write, &m6810_dev, "m6810_put_mbyte: offset=%04X, val=%02X\n", - offset, val); if ((t_addr)offset < m6810_unit.capac) { *((uint8 *)(m6810_unit.filebuf) + offset) = val & 0xFF; return; - } else { - sim_debug (DEBUG_write, &m6810_dev, "m6810_put_mbyte: out of range\n"); - return; } + return; } /* end of m6810.c */ -t_stat m6810_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) -{ - int32 i; - - for (i=0; i #include "swtp_defs.h" -#define MP_8M_NUM 6 /* number of MP-*m boards */ +#define MP_8M_NUM 6 /* number of MP-8M boards */ /* prototypes */ @@ -105,11 +103,8 @@ t_stat mp_8m_reset (DEVICE *dptr) int32 i; UNIT *uptr; - sim_debug (DEBUG_flow, &mp_8m_dev, "mp_8m_reset: \n"); for (i = 0; i < MP_8M_NUM; i++) { /* init all units */ uptr = mp_8m_dev.units + i; - sim_debug (DEBUG_flow, &mp_8m_dev, "MP-8M %d unit.flags=%08X\n", - i, uptr->flags); uptr->capac = 0x2000; if (i < 4) uptr->u3 = 0x2000 * i; @@ -121,15 +116,8 @@ t_stat mp_8m_reset (DEVICE *dptr) printf("mp_8m_reset: Calloc error\n"); return SCPE_MEM; } -// for (j=0; j<8192; j++) { /* fill pattern for testing */ -// val = (0xA0 | i); -// *((uint8 *)(uptr->filebuf) + j) = val & 0xFF; -// } } - sim_debug (DEBUG_flow, &mp_8m_dev, "MP-8M %d initialized at [%04X-%04XH]\n", - i, uptr->u3, uptr->u3 + uptr->capac - 1); } - sim_debug (DEBUG_flow, &mp_8m_dev, "mp_8m_reset: Done\n"); return SCPE_OK; } @@ -145,19 +133,16 @@ int32 mp_8m_get_mbyte(int32 addr) int32 i; UNIT *uptr; - sim_debug (DEBUG_read, &mp_8m_dev, "mp_8m_get_mbyte: addr=%04X", addr); for (i = 0; i < MP_8M_NUM; i++) { /* find addressed unit */ uptr = mp_8m_dev.units + i; org = uptr->u3; len = uptr->capac - 1; if ((addr >= org) && (addr <= org + len)) { val = *((uint8 *)(uptr->filebuf) + (addr - org)); - sim_debug (DEBUG_read, &mp_8m_dev, " val=%04X\n", val); - return (val & 0xFF); + return (val & BYTEMASK); } } - sim_debug (DEBUG_read, &mp_8m_dev, "mp_8m_get_mbyte: Out of range\n"); - return 0xFF; /* multibus has active high pullups */ + return 0xFF; } /* get a word from memory */ @@ -179,19 +164,15 @@ void mp_8m_put_mbyte(int32 addr, int32 val) int32 i; UNIT *uptr; - sim_debug (DEBUG_write, &mp_8m_dev, "mp_8m_put_mbyte: addr=%04X, val=%02X", - addr, val); for (i = 0; i < MP_8M_NUM; i++) { /* find addressed unit */ uptr = mp_8m_dev.units + i; org = uptr->u3; len = uptr->capac - 1; if ((addr >= org) && (addr <= org + len)) { - *((uint8 *)(uptr->filebuf) + (addr - org)) = val & 0xFF; - sim_debug (DEBUG_write, &mp_8m_dev, "\n"); + *((uint8 *)(uptr->filebuf) + (addr - org)) = val & BYTEMASK; return; } } - sim_debug (DEBUG_write, &mp_8m_dev, "mp_8m_put_mbyte: Out of range\n"); } /* put a word into memory */ diff --git a/swtp6800/common/mp-a.c b/swtp6800/common/mp-a.c index 36a3678f..d9200259 100644 --- a/swtp6800/common/mp-a.c +++ b/swtp6800/common/mp-a.c @@ -55,12 +55,10 @@ 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); -t_stat mpa_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches); -t_stat mpa_deposit(t_value value, t_addr addr, UNIT *uptr, int32 switches); /* external routines */ -/* MP-B2 bus routines */ +/* MP-B2 MB routines */ extern int32 MB_get_mbyte(int32 addr); extern int32 MB_get_mword(int32 addr); extern void MB_put_mbyte(int32 addr, int32 val); @@ -114,8 +112,8 @@ DEVICE CPU_BD_dev = { 1, //aincr 16, //dradix 8, //dwidth - mpa_examine, //examine - mpa_deposit, //deposit + NULL, //examine + NULL, //deposit NULL, //reset NULL, //boot NULL, //attach @@ -132,30 +130,27 @@ DEVICE CPU_BD_dev = { int32 CPU_BD_get_mbyte(int32 addr) { - int32 val; + int32 val = 0, EA = 0, EA1 = 0; sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mbyte: addr=%04X\n", addr); switch(addr & 0xF000) { case 0xA000: if (CPU_BD_unit.flags & UNIT_RAM) { - val = m6810_get_mbyte(addr - 0xA000) & 0xFF; - sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mbyte: m6810 val=%02X\n", val); + val = m6810_get_mbyte(addr - 0xA000) & BYTEMASK; } else { - val = MB_get_mbyte(addr) & 0xFF; - sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mbyte: m6810 val=%02X\n", val); + val = MB_get_mbyte(addr) & BYTEMASK; } break; case 0xE000: - val = BOOTROM_get_mbyte(addr - 0xE000) & 0xFF; - sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mbyte: EPROM=%02X\n", val); + val = BOOTROM_get_mbyte(addr - 0xE000) & BYTEMASK; break; case 0xF000: - val = BOOTROM_get_mbyte(addr - (0x10000 - BOOTROM_unit.capac)) & 0xFF; - sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mbyte: EPROM=%02X\n", val); + EA1 = 0x10000 - BOOTROM_unit.capac; + EA = addr - EA1; + val = BOOTROM_get_mbyte(EA) & BYTEMASK; break; default: - val = MB_get_mbyte(addr) & 0xFF; - sim_debug (DEBUG_read, &CPU_BD_dev, "CPU_BD_get_mbyte: mp_b2 val=%02X\n", val); + val = MB_get_mbyte(addr) & BYTEMASK; } return val; } @@ -166,11 +161,9 @@ 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; } @@ -178,8 +171,6 @@ int32 CPU_BD_get_mword(int32 addr) void CPU_BD_put_mbyte(int32 addr, int32 val) { - sim_debug (DEBUG_write, &CPU_BD_dev, "CPU_BD_put_mbyte: addr=%04X, val=%02X\n", - addr, val); switch(addr & 0xF000) { case 0xA000: if (CPU_BD_unit.flags & UNIT_RAM) @@ -196,25 +187,8 @@ void CPU_BD_put_mbyte(int32 addr, int32 val) 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); } -t_stat mpa_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) -{ - int32 i; - - for (i=0; i> 8); CPU_BD_put_mbyte(addr+1, val); } -t_stat mpa2_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) -{ - int32 i; - - for (i=0; i> 8); MB_put_mbyte(addr+1, val); } -t_stat mpb2_examine(t_value *eval_array, t_addr addr, UNIT *uptr, int32 switches) -{ - int32 i; - - for (i=0; i