diff --git a/0readme_38.txt b/0readme_38.txt index ffa2798b..befc49c0 100644 --- a/0readme_38.txt +++ b/0readme_38.txt @@ -1,7 +1,7 @@ Notes For V3.8 -The makefile now works for Linux and most Unix's. Howevr, for Solaris +The makefile now works for Linux and most Unix's. However, for Solaris and MacOS, you must first export the OSTYPE environment variable: > export OSTYPE @@ -49,6 +49,21 @@ Otherwise, you will get build errors. - Added support for 12620A/12936A privileged interrupt fence. - Added support for 12792C eight-channel asynchronous multiplexer. +1.3 3.8-2 + +1.3.1 1401 + +- Added "no rewind" option to magtape boot. + +1.3.2 PDP-11 + +- Added RD32 support to RQ +- Added debug support to RL + +1.3.3 PDP-8 + +- Added FPP support (many thanks to Rick Murphy for debugging the code) + 2. Bugs Fixed diff --git a/ALTAIR/altair_dsk.c b/ALTAIR/altair_dsk.c index 4218f1d7..64ef739c 100644 --- a/ALTAIR/altair_dsk.c +++ b/ALTAIR/altair_dsk.c @@ -1,6 +1,6 @@ /* altair_dsk.c: MITS Altair 88-DISK Simulator - Copyright (c) 1997-2005, Charles E. Owen + Copyright (c) 1997-2010, Charles E. Owen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -325,6 +325,8 @@ int32 dsk12(int32 io, int32 data) cur_sect[cur_disk]);*/ pos = DSK_TRACSIZE * cur_track[cur_disk]; pos += DSK_SECTSIZE * cur_sect[cur_disk]; + if ((uptr == NULL) || (uptr->fileref == NULL)) + return 0; rtn = fseek(uptr -> fileref, pos, 0); rtn = fread(dskbuf, 137, 1, uptr -> fileref); cur_byte[cur_disk] = 1; diff --git a/AltairZ80/altairZ80_cpu.c b/AltairZ80/altairZ80_cpu.c index 26c54e2c..5c19ed64 100644 --- a/AltairZ80/altairZ80_cpu.c +++ b/AltairZ80/altairZ80_cpu.c @@ -1,6 +1,6 @@ /* altairz80_cpu.c: MITS Altair CPU (8080 and Z80) - Copyright (c) 2002-2008, Peter Schorn + Copyright (c) 2002-2010, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -144,6 +144,8 @@ extern int32 simh_dev (const int32 port, const int32 io, const int32 data); extern int32 sr_dev (const int32 port, const int32 io, const int32 data); extern void install_ALTAIRbootROM(void); extern void do_SIMH_sleep(void); +extern void prepareMemoryAccessMessage(const t_addr loc); +extern void prepareInstructionMessage(const t_addr loc, const uint32 op); extern FILE *sim_deb; @@ -1279,10 +1281,9 @@ static const uint8 cpTable[256] = { 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, }; -/* remove comments to generate table contents and define globally NEED_SIM_VM_INIT -static void altairz80_init(void); -void (*sim_vm_init) (void) = &altairz80_init; -static void altairz80_init(void) { +/* remove comments to generate table contents and add a call to + altairz80_print_tables in the altairz80_init +static void altairz80_print_tables(void) { */ /* parityTable */ /* @@ -1591,7 +1592,7 @@ uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, printf("%s memory 0x%05x, handler=%p\n", unmap ? "Unmapping" : " Mapping", addr, routine); if (unmap) { - if (mmu_table[page].routine == routine) /* unmap only if it was mapped */ + if (mmu_table[page].routine == routine) { /* unmap only if it was mapped */ if (MEMORYSIZE < MAXBANKSIZE) if (addr < MEMORYSIZE) mmu_table[page] = RAM_PAGE; @@ -1599,6 +1600,7 @@ uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, mmu_table[page] = EMPTY_PAGE; else mmu_table[page] = RAM_PAGE; + } } else { mmu_table[page] = ROM_PAGE; @@ -1785,44 +1787,32 @@ static int32 sim_brk_lookup (const t_addr loc, const int32 btyp) { return (sim_brk_pend[0] && (loc == sim_brk_ploc[0])) ? MASK_BRK : FALSE; } -static void prepareMemoryAccessMessage(t_addr loc) { - extern char memoryAccessMessage[]; - sprintf(memoryAccessMessage, "Memory access breakpoint [%05xh]", loc); -} - #define PUSH(x) { \ MM_PUT_BYTE(SP, (x) >> 8); \ MM_PUT_BYTE(SP, x); \ } #define CHECK_BREAK_BYTE(a) \ - if (sim_brk_summ && sim_brk_test((a) & 0xffff, SWMASK('M'))) { \ - reason = STOP_MEM; \ - prepareMemoryAccessMessage((a) & 0xffff); \ - goto end_decode; \ + if (sim_brk_summ) { \ + if (sim_brk_test((a) & 0xffff, SWMASK('M'))) { \ + reason = STOP_MEM; \ + prepareMemoryAccessMessage((a) & 0xffff); \ + goto end_decode; \ + } \ + sim_brk_pend[0] = FALSE; \ } #define CHECK_BREAK_TWO_BYTES_EXTENDED(a1, a2, iCode) \ if (sim_brk_summ) { \ - br1 = sim_brk_lookup((a1) & 0xffff, SWMASK('M')); \ - br2 = br1 ? FALSE : sim_brk_lookup((a2) & 0xffff, SWMASK('M'));\ - if ((br1 == MASK_BRK) || (br2 == MASK_BRK)) { \ - sim_brk_pend[0] = FALSE; \ - } \ - else if (br1 || br2) { \ + int32 brl = sim_brk_lookup((a1) & 0xffff, SWMASK('M')); \ + if ((brl == TRUE) || (brl == FALSE) && (sim_brk_lookup((a2) \ + & 0xffff, SWMASK('M')) == TRUE)) { \ reason = STOP_MEM; \ - if (br1) { \ - prepareMemoryAccessMessage((a1) & 0xffff); \ - } \ - else { \ - prepareMemoryAccessMessage((a2) & 0xffff); \ - } \ + prepareMemoryAccessMessage((brl ? (a1):(a2)) & 0xffff); \ iCode; \ goto end_decode; \ } \ - else { \ - sim_brk_pend[0] = FALSE; \ - } \ + sim_brk_pend[0] = FALSE; \ } #define CHECK_BREAK_TWO_BYTES(a1, a2) CHECK_BREAK_TWO_BYTES_EXTENDED(a1, a2,;) @@ -1908,7 +1898,7 @@ static t_stat sim_instr_mmu (void) { register uint32 tStates; uint32 tStatesInSlice; /* number of t-states in 10 mSec time-slice */ uint32 startTime, now; - int32 br1, br2, tStateModifier = FALSE; + int32 tStateModifier = FALSE; switch_cpu_now = TRUE; /* hharte */ @@ -1991,12 +1981,13 @@ static t_stat sim_instr_mmu (void) { } if (sim_brk_summ) { - if (sim_brk_lookup(PC, SWMASK('E')) == TRUE) { /* breakpoint? */ + if (sim_brk_test(PC, (2u << SIM_BKPT_V_SPC) | SWMASK('E'))) { /* breakpoint? */ reason = STOP_IBKPT; /* stop simulation */ break; } if (sim_brk_test(GetBYTE(PC), (1u << SIM_BKPT_V_SPC) | SWMASK('I'))) { /* instruction breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ + reason = STOP_INSTR; /* stop simulation */ + prepareInstructionMessage(PC, GetBYTE(PC)); break; } } @@ -3826,7 +3817,7 @@ static t_stat sim_instr_mmu (void) { case 0xdd: /* DD prefix */ CHECK_CPU_8080; - switch (op = RAM_PP(PC)) { + switch (RAM_PP(PC)) { case 0x09: /* ADD IX,BC */ tStates += 15; @@ -4712,7 +4703,7 @@ static t_stat sim_instr_mmu (void) { case 0xed: /* ED prefix */ CHECK_CPU_8080; - switch (op = RAM_PP(PC)) { + switch (RAM_PP(PC)) { case 0x40: /* IN B,(C) */ tStates += 12; @@ -5205,7 +5196,6 @@ static t_stat sim_instr_mmu (void) { case 0xb0: /* LDIR */ tStates -= 5; - acu = HIGH_REGISTER(AF); BC &= ADDRMASK; if (BC == 0) BC = 0x10000; @@ -5456,7 +5446,7 @@ static t_stat sim_instr_mmu (void) { case 0xfd: /* FD prefix */ CHECK_CPU_8080; - switch (op = RAM_PP(PC)) { + switch (RAM_PP(PC)) { case 0x09: /* ADD IY,BC */ tStates += 15; @@ -6388,10 +6378,10 @@ static char *ramTypeToString[] = { "AZ80", "HRAM", "VRAM", "CRAM" }; static t_stat chip_show(FILE *st, UNIT *uptr, int32 val, void *desc) { fprintf(st, cpu_unit.flags & UNIT_CPU_OPSTOP ? "ITRAP, " : "NOITRAP, "); if (chiptype <= MAX_CHIP_TYPE) - fprintf(st, chipTypeToString[chiptype]); + fprintf(st, "%s", chipTypeToString[chiptype]); fprintf(st, ", "); if (ramtype <= MAX_RAM_TYPE) - fprintf(st, ramTypeToString[ramtype]); + fprintf(st, "%s", ramTypeToString[ramtype]); return SCPE_OK; } @@ -6603,8 +6593,8 @@ static void cpu_set_chiptype_short(int32 value, uint32 need_cpu_clear) { extern REG *sim_PC; if ((chiptype == value) || (chiptype > MAX_CHIP_TYPE)) return; /* nothing to do */ - if ((chiptype == CHIP_TYPE_8080) && (value == CHIP_TYPE_Z80) || - (chiptype == CHIP_TYPE_Z80) && (value == CHIP_TYPE_8080)) { + if (((chiptype == CHIP_TYPE_8080) && (value == CHIP_TYPE_Z80)) || + ((chiptype == CHIP_TYPE_Z80) && (value == CHIP_TYPE_8080))) { chiptype = value; return; } @@ -6783,7 +6773,7 @@ static t_stat cpu_set_memory(UNIT *uptr, int32 value, char *cptr, void *desc) { return SCPE_ARG; result = sscanf(cptr, "%i%n", &size, &i); if ((result == 1) && (cptr[i] == 'K') && ((cptr[i + 1] == 0) || - (cptr[i + 1] == 'B') && (cptr[i + 2] == 0))) + ((cptr[i + 1] == 'B') && (cptr[i + 2] == 0)))) return set_size(size); return SCPE_ARG; } @@ -6791,6 +6781,7 @@ static t_stat cpu_set_memory(UNIT *uptr, int32 value, char *cptr, void *desc) { /* AltairZ80 Simulator initialization */ void altairz80_init(void) { cpu_clear(); +/* altairz80_print_tables(); */ } void (*sim_vm_init) (void) = &altairz80_init; diff --git a/AltairZ80/altairZ80_defs.h b/AltairZ80/altairZ80_defs.h index 2059407d..c16f7121 100644 --- a/AltairZ80/altairZ80_defs.h +++ b/AltairZ80/altairZ80_defs.h @@ -1,6 +1,6 @@ /* altairz80_defs.h: MITS Altair simulator definitions - Copyright (c) 2002-2008, Peter Schorn + Copyright (c) 2002-2010, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -57,7 +57,8 @@ #define STOP_HALT 0 /* HALT */ #define STOP_IBKPT 1 /* breakpoint (program counter) */ #define STOP_MEM 2 /* breakpoint (memory access) */ -#define STOP_OPCODE 3 /* invalid operation encountered (8080, Z80, 8086) */ +#define STOP_INSTR 3 /* breakpoint (instruction access) */ +#define STOP_OPCODE 4 /* invalid operation encountered (8080, Z80, 8086) */ #define UNIT_CPU_V_OPSTOP (UNIT_V_UF+0) /* stop on invalid operation */ #define UNIT_CPU_OPSTOP (1 << UNIT_CPU_V_OPSTOP) @@ -74,8 +75,11 @@ #define UNIT_CPU_V_SWITCHER (UNIT_V_UF+6) /* switcher 8086 <--> 8080/Z80 enabled */ #define UNIT_CPU_SWITCHER (1 << UNIT_CPU_V_SWITCHER) -#define UNIX_PLATFORM (defined (__linux) || defined(__NetBSD__) \ - || defined (__OpenBSD__) || defined (__FreeBSD__) || defined (__APPLE__)) +#if defined (__linux) || defined(__NetBSD__) || defined (__OpenBSD__) || defined (__FreeBSD__) || defined (__APPLE__) +#define UNIX_PLATFORM 1 +#else +#define UNIX_PLATFORM 0 +#endif #define ADDRESS_FORMAT "[0x%05x]" @@ -86,7 +90,7 @@ #define NLP "\n" #endif -#if defined (__MWERKS__) && defined (macintosh) +#if (defined (__MWERKS__) && defined (macintosh)) || defined(__DECC) #define __FUNCTION__ __FILE__ #endif diff --git a/AltairZ80/altairZ80_dsk.c b/AltairZ80/altairZ80_dsk.c index 6944fd96..070b8b6f 100644 --- a/AltairZ80/altairZ80_dsk.c +++ b/AltairZ80/altairZ80_dsk.c @@ -1,6 +1,6 @@ /* altairz80_dsk.c: MITS Altair 88-DISK Simulator - Copyright (c) 2002-2008, Peter Schorn + Copyright (c) 2002-2010, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -319,7 +319,7 @@ static t_stat dsk_boot(int32 unitno, DEVICE *dptr) { } static int32 dskseek(const UNIT *xptr) { - return fseek(xptr -> fileref, DSK_TRACSIZE * current_track[current_disk] + + return sim_fseek(xptr -> fileref, DSK_TRACSIZE * current_track[current_disk] + DSK_SECTSIZE * current_sector[current_disk], SEEK_SET); } @@ -338,9 +338,9 @@ static void writebuf(void) { printf("DSK%i: " ADDRESS_FORMAT " fseek failed D%d T%d S%d" NLP, current_disk, PCX, current_disk, current_track[current_disk], current_sector[current_disk]); } - rtn = fwrite(dskbuf, DSK_SECTSIZE, 1, uptr -> fileref); - if (rtn != 1) { - printf("DSK%i: " ADDRESS_FORMAT " fwrite failed T%d S%d Return=%d" NLP, current_disk, + rtn = sim_fwrite(dskbuf, 1, DSK_SECTSIZE, uptr -> fileref); + if (rtn != DSK_SECTSIZE) { + printf("DSK%i: " ADDRESS_FORMAT " sim_fwrite failed T%d S%d Return=%d" NLP, current_disk, PCX, current_track[current_disk], current_sector[current_disk], rtn); } } @@ -507,7 +507,7 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) { /* Disk Data In/Out */ int32 dsk12(const int32 port, const int32 io, const int32 data) { - int32 i; + int32 i, rtn; UNIT *uptr; if (current_disk >= NUM_OF_DSK) { @@ -530,8 +530,21 @@ int32 dsk12(const int32 port, const int32 io, const int32 data) { PCX, current_disk, current_track[current_disk], current_sector[current_disk])); for (i = 0; i < DSK_SECTSIZE; i++) dskbuf[i] = 0; - dskseek(uptr); - fread(dskbuf, DSK_SECTSIZE, 1, uptr -> fileref); + if (dskseek(uptr)) { + if ((dsk_dev.dctrl & VERBOSE_MSG) && (warnDSK12 < warnLevelDSK)) { + warnDSK12++; + printf("DSK%i: " ADDRESS_FORMAT " fseek error D%d T%d S%d" NLP, current_disk, + PCX, current_disk, current_track[current_disk], current_sector[current_disk]); + } + } + rtn = sim_fread(dskbuf, 1, DSK_SECTSIZE, uptr -> fileref); + if (rtn != DSK_SECTSIZE) { + if ((dsk_dev.dctrl & VERBOSE_MSG) && (warnDSK12 < warnLevelDSK)) { + warnDSK12++; + printf("DSK%i: " ADDRESS_FORMAT " sim_fread error D%d T%d S%d" NLP, current_disk, + PCX, current_disk, current_track[current_disk], current_sector[current_disk]); + } + } current_byte[current_disk] = 0; } return dskbuf[current_byte[current_disk]++] & 0xff; diff --git a/AltairZ80/altairZ80_sio.c b/AltairZ80/altairZ80_sio.c index 20c956fe..1ae1b935 100644 --- a/AltairZ80/altairZ80_sio.c +++ b/AltairZ80/altairZ80_sio.c @@ -1,6 +1,6 @@ /* altairz80_sio.c: MITS Altair serial I/O card - Copyright (c) 2002-2008, Peter Schorn + Copyright (c) 2002-2010, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -105,8 +105,8 @@ #define PORT_TABLE_SIZE 256 /* size of port mapping table */ #define SLEEP_ALLOWED_START_DEFAULT 100 /* default initial value for sleepAllowedCounter*/ +#define DEFAULT_TIMER_DELTA 100 /* default value for timer delta in ms */ -static t_stat sio_set_verbose (UNIT *uptr, int32 value, char *cptr, void *desc); static t_stat simh_dev_set_timeron (UNIT *uptr, int32 value, char *cptr, void *desc); static t_stat simh_dev_set_timeroff (UNIT *uptr, int32 value, char *cptr, void *desc); static t_stat sio_reset(DEVICE *dptr); @@ -154,6 +154,19 @@ extern UNIT cpu_unit; extern volatile int32 stop_cpu; extern int32 sim_interval; +#define TRACE_PRINT(device, level, args) if (device.dctrl & level) { \ + printf args; \ + } + +/* Debug Flags */ +static DEBTAB generic_dt[] = { + { "IN", IN_MSG }, + { "OUT", OUT_MSG }, + { "CMD", CMD_MSG }, + { "VERBOSE", VERBOSE_MSG }, + { NULL, 0 } +}; + /* SIMH pseudo device status registers */ /* ZSDOS clock definitions */ static time_t ClockZSDOSDelta = 0; /* delta between real clock and Altair clock */ @@ -168,12 +181,12 @@ static int32 setClockCPM3Adr = 0; /* address in M of 5 byte parame static int32 getClockCPM3Pos = 0; /* determines state for sending clock information */ static int32 daysCPM3SinceOrg = 0; /* days since 1 Jan 1978 */ -/* interrupt related */ +/* timer interrupt related */ static uint32 timeOfNextInterrupt; /* time when next interrupt is scheduled */ int32 timerInterrupt = FALSE; /* timer interrupt pending */ int32 timerInterruptHandler = 0x0fc00; /* default address of interrupt handling routine */ static int32 setTimerInterruptAdrPos= 0; /* determines state for receiving timerInterruptHandler */ -static int32 timerDelta = 100; /* interrupt every 100 ms */ +static int32 timerDelta = DEFAULT_TIMER_DELTA; /* interrupt every 100 ms */ static int32 setTimerDeltaPos = 0; /* determines state for receiving timerDelta */ /* stop watch and timer related */ @@ -270,7 +283,7 @@ static MTAB sio_mod[] = { { UNIT_SIO_BS, 0, "BS", "BS", NULL }, /* map delete to backspace */ { UNIT_SIO_BS, UNIT_SIO_BS, "DEL", "DEL", NULL }, /* map backspace to delete */ { UNIT_SIO_VERBOSE, 0, "QUIET", "QUIET", NULL }, /* quiet, no error messages */ - { UNIT_SIO_VERBOSE, UNIT_SIO_VERBOSE, "VERBOSE", "VERBOSE", &sio_set_verbose }, + { UNIT_SIO_VERBOSE, UNIT_SIO_VERBOSE, "VERBOSE", "VERBOSE", NULL }, /* verbose, display warning messages */ { UNIT_SIO_MAP, 0, "NOMAP", "NOMAP", NULL }, /* disable character mapping */ { UNIT_SIO_MAP, UNIT_SIO_MAP, "MAP", "MAP", NULL }, /* enable all character mapping */ @@ -291,12 +304,16 @@ DEVICE sio_dev = { 1, 10, 31, 1, 8, 8, NULL, NULL, &sio_reset, NULL, &sio_attach, &sio_detach, - NULL, 0, 0, - NULL, NULL, "Serial Input Output SIO" + NULL, DEV_DEBUG, 0, + generic_dt, NULL, "Serial Input Output SIO" +}; + +static MTAB ptpptr_mod[] = { + { 0 } }; static UNIT ptr_unit = { - UDATA (NULL, UNIT_SEQ | UNIT_ATTABLE | UNIT_ROABLE, 0) + UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE, 0) }; static REG ptr_reg[] = { @@ -305,25 +322,25 @@ static REG ptr_reg[] = { }; DEVICE ptr_dev = { - "PTR", &ptr_unit, ptr_reg, NULL, + "PTR", &ptr_unit, ptr_reg, ptpptr_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptr_reset, NULL, NULL, NULL, - NULL, DEV_DISABLE, 0, - NULL, NULL, "Paper Tape Reader PTR" + NULL, (DEV_DISABLE | DEV_DEBUG), 0, + generic_dt, NULL, "Paper Tape Reader PTR" }; static UNIT ptp_unit = { - UDATA (NULL, UNIT_SEQ + UNIT_ATTABLE, 0) + UDATA (NULL, UNIT_ATTABLE, 0) }; DEVICE ptp_dev = { - "PTP", &ptp_unit, NULL, NULL, + "PTP", &ptp_unit, NULL, ptpptr_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptp_reset, NULL, NULL, NULL, - NULL, DEV_DISABLE, 0, - NULL, NULL, "Paper Tape Puncher PTP" + NULL, (DEV_DISABLE | DEV_DEBUG), 0, + generic_dt, NULL, "Paper Tape Puncher PTP" }; /* Synthetic device SIMH for communication @@ -373,37 +390,19 @@ static MTAB simh_mod[] = { { 0 } }; -#define TRACE_PRINT(level, args) if (simh_device.dctrl & level) { \ - printf args; \ - } - -/* Debug Flags */ -static DEBTAB simh_dt[] = { - { "IN", IN_MSG }, - { "OUT", OUT_MSG }, - { "CMD", CMD_MSG }, - { "VERBOSE", VERBOSE_MSG }, - { NULL, 0 } -}; - DEVICE simh_device = { "SIMH", &simh_unit, simh_reg, simh_mod, 1, 10, 31, 1, 16, 4, NULL, NULL, &simh_dev_reset, NULL, NULL, NULL, NULL, (DEV_DISABLE | DEV_DEBUG), 0, - simh_dt, NULL, "Pseudo Device SIMH" + generic_dt, NULL, "Pseudo Device SIMH" }; static void resetSIOWarningFlags(void) { warnUnattachedPTP = warnUnattachedPTR = warnPTREOF = warnUnassignedPort = 0; } -static t_stat sio_set_verbose(UNIT *uptr, int32 value, char *cptr, void *desc) { - resetSIOWarningFlags(); - return SCPE_OK; -} - static t_stat sio_attach(UNIT *uptr, char *cptr) { t_stat r = SCPE_IERR; sio_unit.u3 = FALSE; /* no character in terminal input buffer */ @@ -439,6 +438,7 @@ static void pollConnection(void) { /* reset routines */ static t_stat sio_reset(DEVICE *dptr) { int32 i; + TRACE_PRINT(sio_dev, VERBOSE_MSG, ("SIO: " ADDRESS_FORMAT " Reset" NLP, PCX)); sio_unit.u3 = FALSE; /* no character in terminal input buffer */ resetSIOWarningFlags(); if (sio_unit.u4) { /* is terminal input attached to a file? */ @@ -454,6 +454,7 @@ static t_stat sio_reset(DEVICE *dptr) { } static t_stat ptr_reset(DEVICE *dptr) { + TRACE_PRINT(ptr_dev, VERBOSE_MSG, ("PTR: " ADDRESS_FORMAT " Reset" NLP, PCX)); resetSIOWarningFlags(); ptr_unit.u3 = FALSE; /* End Of File not yet reached */ if (ptr_unit.flags & UNIT_ATT) /* attached? */ @@ -464,6 +465,7 @@ static t_stat ptr_reset(DEVICE *dptr) { } static t_stat ptp_reset(DEVICE *dptr) { + TRACE_PRINT(ptp_dev, VERBOSE_MSG, ("PTP: " ADDRESS_FORMAT " Reset" NLP, PCX)); resetSIOWarningFlags(); sim_map_resource(0x12, 1, RESOURCE_TYPE_IO, &sio1s, dptr->flags & DEV_DIS); sim_map_resource(0x13, 1, RESOURCE_TYPE_IO, &sio1d, dptr->flags & DEV_DIS); @@ -625,17 +627,18 @@ static void voidSleep(void) { } /* generic status port for keyboard input / terminal output */ -int32 sio0s(const int32 port, const int32 io, const int32 data) { +static int32 sio0sCore(const int32 port, const int32 io, const int32 data) { int32 ch, result; SIO_PORT_INFO spi = lookupPortInfo(port, &ch); assert(spi.port == port); pollConnection(); if (io == 0) { /* IN */ - if (sio_unit.u4) /* attached to a file? */ + if (sio_unit.u4) { /* attached to a file? */ if (sio_unit.u5) /* EOF reached? */ sio_detach(&sio_unit); /* detach file and switch to keyboard input */ else return spi.sio_can_read | spi.sio_can_write; + } if (sio_unit.flags & UNIT_ATT) { /* attached to a port? */ if (tmxr_rqln(&TerminalLines[spi.terminalLine])) result = spi.sio_can_read; @@ -664,13 +667,25 @@ int32 sio0s(const int32 port, const int32 io, const int32 data) { checkSleep(); return spi.sio_can_write | spi.sio_cannot_read; } /* OUT follows, no fall-through from IN */ - if (spi.hasReset && (data == spi.sio_reset)) /* reset command */ + if (spi.hasReset && (data == spi.sio_reset)) { /* reset command */ sio_unit.u3 = FALSE; /* indicate that no character is available */ + TRACE_PRINT(sio_dev, CMD_MSG, + ("SIO: " ADDRESS_FORMAT " Command OUT(0x%03x) = 0x%02x" NLP, PCX, port, data)); + } return 0x00; /* ignored since OUT */ } +int32 sio0s(const int32 port, const int32 io, const int32 data) { + const int32 result = sio0sCore(port, io, data); + if ((io == 0) && (sio_dev.dctrl & IN_MSG)) + printf("SIO_S: " ADDRESS_FORMAT " IN(0x%03x) = 0x%02x" NLP, PCX, port, result); + else if ((io) && (sio_dev.dctrl & OUT_MSG)) + printf("SIO_S: " ADDRESS_FORMAT " OUT(0x%03x) = 0x%02x" NLP, PCX, port, data); + return result; +} + /* generic data port for keyboard input / terminal output */ -int32 sio0d(const int32 port, const int32 io, const int32 data) { +static int32 sio0dCore(const int32 port, const int32 io, const int32 data) { int32 ch; SIO_PORT_INFO spi = lookupPortInfo(port, &ch); assert(spi.port == port); @@ -705,14 +720,23 @@ int32 sio0d(const int32 port, const int32 io, const int32 data) { return 0x00; /* ignored since OUT */ } +int32 sio0d(const int32 port, const int32 io, const int32 data) { + const int32 result = sio0dCore(port, io, data); + if ((io == 0) && (sio_dev.dctrl & IN_MSG)) + printf("SIO_D: " ADDRESS_FORMAT " IN(0x%03x) = 0x%02x" NLP, PCX, port, result); + else if ((io) && (sio_dev.dctrl & OUT_MSG)) + printf("SIO_D: " ADDRESS_FORMAT " OUT(0x%03x) = 0x%02x" NLP, PCX, port, data); + return result; +} + /* PTR/PTP status port */ -int32 sio1s(const int32 port, const int32 io, const int32 data) { +static int32 sio1sCore(const int32 port, const int32 io, const int32 data) { if (io == 0) { /* IN */ /* reset I bit iff PTR unit not attached or no more data available. O bit is always set since write always possible. */ if ((ptr_unit.flags & UNIT_ATT) == 0) { /* PTR is not attached */ - if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnattachedPTR < warnLevelSIO)) { + if ((ptr_dev.dctrl & VERBOSE_MSG) && (warnUnattachedPTR < warnLevelSIO)) { warnUnattachedPTR++; /*06*/ printf("PTR: " ADDRESS_FORMAT " Attempt to test status of unattached PTR[0x%02x]. 0x02 returned." NLP, PCX, port); } @@ -722,24 +746,36 @@ int32 sio1s(const int32 port, const int32 io, const int32 data) { (SIO_CAN_WRITE and SIO_CAN_READ) */ return ptr_unit.u3 ? SIO_CAN_WRITE : (SIO_CAN_READ | SIO_CAN_WRITE); } /* OUT follows */ - if (data == SIO_RESET) + if (data == SIO_RESET) { ptr_unit.u3 = FALSE; /* reset EOF indicator */ + TRACE_PRINT(ptr_dev, CMD_MSG, + ("PTR: " ADDRESS_FORMAT " Command OUT(0x%03x) = 0x%02x" NLP, PCX, port, data)); + } return 0x00; /* ignored since OUT */ } +int32 sio1s(const int32 port, const int32 io, const int32 data) { + const int32 result = sio1sCore(port, io, data); + if ((io == 0) && ((ptr_dev.dctrl & IN_MSG) || (ptp_dev.dctrl & IN_MSG))) + printf("PTP/PTR_S: " ADDRESS_FORMAT " IN(0x%02x) = 0x%02x" NLP, PCX, port, result); + else if ((io) && ((ptr_dev.dctrl & OUT_MSG) || (ptp_dev.dctrl & OUT_MSG))) + printf("PTP/PTR_S: " ADDRESS_FORMAT " OUT(0x%02x) = 0x%02x" NLP, PCX, port, data); + return result; +} + /* PTR/PTP data port */ -int32 sio1d(const int32 port, const int32 io, const int32 data) { +static int32 sio1dCore(const int32 port, const int32 io, const int32 data) { int32 ch; if (io == 0) { /* IN */ if (ptr_unit.u3) { /* EOF reached, no more data available */ - if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnPTREOF < warnLevelSIO)) { + if ((ptr_dev.dctrl & VERBOSE_MSG) && (warnPTREOF < warnLevelSIO)) { warnPTREOF++; /*07*/ printf("PTR: " ADDRESS_FORMAT " PTR[0x%02x] attempted to read past EOF. 0x00 returned." NLP, PCX, port); } return 0x00; } if ((ptr_unit.flags & UNIT_ATT) == 0) { /* not attached */ - if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnattachedPTR < warnLevelSIO)) { + if ((ptr_dev.dctrl & VERBOSE_MSG) && (warnUnattachedPTR < warnLevelSIO)) { warnUnattachedPTR++; /*08*/ printf("PTR: " ADDRESS_FORMAT " Attempt to read from unattached PTR[0x%02x]. 0x00 returned." NLP, PCX, port); } @@ -754,13 +790,22 @@ int32 sio1d(const int32 port, const int32 io, const int32 data) { if (ptp_unit.flags & UNIT_ATT) /* unit must be attached */ putc(data, ptp_unit.fileref); /* else ignore data */ - else if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnattachedPTP < warnLevelSIO)) { + else if ((ptp_dev.dctrl & VERBOSE_MSG) && (warnUnattachedPTP < warnLevelSIO)) { warnUnattachedPTP++; /*09*/ printf("PTP: " ADDRESS_FORMAT " Attempt to output '0x%02x' to unattached PTP[0x%02x] - ignored." NLP, PCX, data, port); } return 0x00; /* ignored since OUT */ } +int32 sio1d(const int32 port, const int32 io, const int32 data) { + const int32 result = sio1dCore(port, io, data); + if ((io == 0) && ((ptr_dev.dctrl & IN_MSG) || (ptp_dev.dctrl & IN_MSG))) + printf("PTP/PTR_D: " ADDRESS_FORMAT " IN(0x%02x) = 0x%02x" NLP, PCX, port, result); + else if ((io) && ((ptr_dev.dctrl & OUT_MSG) || (ptp_dev.dctrl & OUT_MSG))) + printf("PTP/PTR_D: " ADDRESS_FORMAT " OUT(0x%02x) = 0x%02x" NLP, PCX, port, data); + return result; +} + static t_stat toBool(char tf, int *result) { if (tf == 'T') { *result = TRUE; @@ -856,8 +901,8 @@ static t_stat sio_dev_set_port(UNIT *uptr, int32 value, char *cptr, void *desc) printf("\n"); port_table[position] = sip; sim_map_resource(sip.port, 1, RESOURCE_TYPE_IO, (sip.hasOUT || - (sip.sio_can_read == 0) && (sip.sio_cannot_read == 0) && - (sip.sio_can_write == 0)) ? &sio0d : &sio0s, FALSE); + ((sip.sio_can_read == 0) && (sip.sio_cannot_read == 0) && + (sip.sio_can_write == 0))) ? &sio0d : &sio0s, FALSE); return SCPE_OK; } @@ -888,9 +933,8 @@ static t_stat sio_dev_set_interruptoff(UNIT *uptr, int32 value, char *cptr, void } static t_stat sio_svc(UNIT *uptr) { - if (sio0s(0, 0, 0) & KBD_HAS_CHAR) { + if (sio0s(0, 0, 0) & KBD_HAS_CHAR) keyboardInterrupt = TRUE; - } if (sio_unit.flags & UNIT_SIO_INTERRUPT) sim_activate(&sio_unit, sio_unit.wait); /* activate unit */ return SCPE_OK; @@ -909,12 +953,10 @@ static void mapAltairPorts(void) { int32 nulldev(const int32 port, const int32 io, const int32 data) { if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnassignedPort < warnLevelSIO)) { warnUnassignedPort++; - if (io == 0) { + if (io == 0) printf("SIO: " ADDRESS_FORMAT " Attempt to input from unassigned port 0x%04x - ignored." NLP, PCX, port); - } - else { + else printf("SIO: " ADDRESS_FORMAT " Attempt to output 0x%02x to unassigned port 0x%04x - ignored." NLP, PCX, data, port); - } } return io == 0 ? 0xff : 0; } @@ -1063,7 +1105,7 @@ static t_stat simh_dev_reset(DEVICE *dptr) { } static void warnNoRealTimeClock(void) { - TRACE_PRINT(VERBOSE_MSG, + TRACE_PRINT(simh_device, VERBOSE_MSG, ("SIMH: " ADDRESS_FORMAT " Sorry - no real time clock available." NLP, PCX)); } @@ -1078,20 +1120,32 @@ static t_stat simh_dev_set_timeron(UNIT *uptr, int32 value, char *cptr, void *de static t_stat simh_dev_set_timeroff(UNIT *uptr, int32 value, char *cptr, void *desc) { timerInterrupt = FALSE; - sim_cancel(&simh_unit); + if (rtc_avail) + sim_cancel(&simh_unit); return SCPE_OK; } static t_stat simh_svc(UNIT *uptr) { - uint32 n = sim_os_msec(); - if (n >= timeOfNextInterrupt) { + uint32 now = sim_os_msec(); + if (now >= timeOfNextInterrupt) { timerInterrupt = TRUE; - timeOfNextInterrupt += timerDelta; - if (n >= timeOfNextInterrupt) /* time of next interrupt is not in the future */ - timeOfNextInterrupt = n + timerDelta; /* make sure it is in the future! */ + if (timerDelta == 0) + timeOfNextInterrupt = now + DEFAULT_TIMER_DELTA; + else { + uint32 newTimeOfNextInterrupt = now + timerDelta - (now - timeOfNextInterrupt) % timerDelta; + if (newTimeOfNextInterrupt != timeOfNextInterrupt + timerDelta) { + TRACE_PRINT(simh_device, VERBOSE_MSG, + ("SIMH: " ADDRESS_FORMAT " Timer interrupts skipped %i. Delta %i. Expect %i. Got %i." NLP, PCX, + (newTimeOfNextInterrupt - timeOfNextInterrupt) / timerDelta - 1, + timerDelta, + timeOfNextInterrupt + timerDelta - now, newTimeOfNextInterrupt - now)); + } + timeOfNextInterrupt = newTimeOfNextInterrupt; + } } + /* post condition: now < timeOfNextInterrupt */ if (simh_unit.flags & UNIT_SIMH_TIMERON) - sim_activate(&simh_unit, simh_unit.wait); /* activate unit */ + sim_activate(&simh_unit, simh_unit.wait); /* activate unit */ return SCPE_OK; } @@ -1175,7 +1229,7 @@ static int32 simh_in(const int32 port) { case getHostFilenamesCmd: #if UNIX_PLATFORM - if (globValid) + if (globValid) { if (globPosNameList < globS.gl_pathc) { if (!(result = globS.gl_pathv[globPosNameList][globPosName++])) { globPosNameList++; @@ -1187,13 +1241,13 @@ static int32 simh_in(const int32 port) { lastCommand = 0; globfree(&globS); } + } #elif defined (_WIN32) if (globValid) if (globFinished) globValid = FALSE; - else if (firstPathCharacter <= lastPathSeparator) { + else if (firstPathCharacter <= lastPathSeparator) result = cpmCommandLine[firstPathCharacter++]; - } else if (!(result = FindFileData.cFileName[globPosName++])) { globPosName = firstPathCharacter = 0; if (!FindNextFile(hFind, &FindFileData)) { @@ -1296,7 +1350,7 @@ static int32 simh_in(const int32 port) { result = getBankSelect(); else { result = 0; - TRACE_PRINT(VERBOSE_MSG, + TRACE_PRINT(simh_device, VERBOSE_MSG, ("SIMH: " ADDRESS_FORMAT " Get selected bank ignored for non-banked memory." NLP, PCX)); } lastCommand = 0; @@ -1340,7 +1394,7 @@ static int32 simh_in(const int32 port) { break; default: - TRACE_PRINT(VERBOSE_MSG, + TRACE_PRINT(simh_device, VERBOSE_MSG, ("SIMH: " ADDRESS_FORMAT " Undefined IN from SIMH pseudo device on port %03xh ignored." NLP, PCX, port)); result = lastCommand = 0; @@ -1349,6 +1403,10 @@ static int32 simh_in(const int32 port) { } void do_SIMH_sleep(void) { + /* Do not sleep when timer interrupts are pending or are about to be created. + Otherwise there is the possibility that such interrupts are skipped. */ + if ((simh_unit.flags & UNIT_SIMH_TIMERON) && rtc_avail && (sim_os_msec() + 1 >= timeOfNextInterrupt)) + return; #if defined (_WIN32) if ((SIMHSleep / 1000) && !sio_unit.u4) /* time to sleep and SIO not attached to a file */ Sleep(SIMHSleep / 1000); @@ -1390,7 +1448,7 @@ static int32 simh_out(const int32 port, const int32 data) { if (cpu_unit.flags & UNIT_CPU_BANKED) setBankSelect(data & BANKMASK); else { - TRACE_PRINT(VERBOSE_MSG, + TRACE_PRINT(simh_device, VERBOSE_MSG, ("SIMH: " ADDRESS_FORMAT " Set selected bank to %i ignored for non-banked memory." NLP, PCX, data & 3)); } @@ -1405,6 +1463,12 @@ static int32 simh_out(const int32 port, const int32 data) { else { timerDelta |= (data << 8); setTimerDeltaPos = lastCommand = 0; + if (timerDelta == 0) { + timerDelta = DEFAULT_TIMER_DELTA; + TRACE_PRINT(simh_device, VERBOSE_MSG, + ("SIMH: " ADDRESS_FORMAT " Timer delta set to 0 ms ignored. Using %i ms instead." + NLP, PCX, DEFAULT_TIMER_DELTA)); + } } break; @@ -1420,7 +1484,7 @@ static int32 simh_out(const int32 port, const int32 data) { break; default: - TRACE_PRINT(CMD_MSG, + TRACE_PRINT(simh_device, CMD_MSG, ("SIMH: " ADDRESS_FORMAT " CMD(0x%02x) <- %i (0x%02x, '%s')" NLP, PCX, port, data, data, (0 <= data) && (data <= lastSIMHCommand) ? cmdNames[data] : "Unknown command")); @@ -1435,7 +1499,7 @@ static int32 simh_out(const int32 port, const int32 data) { createCPMCommandLine(); globError = glob(cpmCommandLine, GLOB_ERR, NULL, &globS); if (globError) { - TRACE_PRINT(VERBOSE_MSG, + TRACE_PRINT(simh_device, VERBOSE_MSG, ("SIMH: " ADDRESS_FORMAT " Cannot expand '%s'. Error is %i." NLP, PCX, cpmCommandLine, globError)); globfree(&globS); @@ -1451,7 +1515,7 @@ static int32 simh_out(const int32 port, const int32 data) { setLastPathSeparator(); hFind = FindFirstFile(cpmCommandLine, &FindFileData); if (hFind == INVALID_HANDLE_VALUE) { - TRACE_PRINT(VERBOSE_MSG, + TRACE_PRINT(simh_device, VERBOSE_MSG, ("SIMH: " ADDRESS_FORMAT " Cannot expand '%s'. Error is %lu." NLP, PCX, cpmCommandLine, GetLastError())); globValid = FALSE; @@ -1465,21 +1529,18 @@ static int32 simh_out(const int32 port, const int32 data) { break; case printTimeCmd: /* print time */ - if (rtc_avail) { + if (rtc_avail) printf("SIMH: " ADDRESS_FORMAT " Current time in milliseconds = %d." NLP, PCX, sim_os_msec()); - } - else { + else warnNoRealTimeClock(); - } break; case startTimerCmd: /* create a new timer on top of stack */ if (rtc_avail) if (markTimeSP < TIMER_STACK_LIMIT) markTime[markTimeSP++] = sim_os_msec(); - else { + else printf("SIMH: " ADDRESS_FORMAT " Timer stack overflow." NLP, PCX); - } else warnNoRealTimeClock(); break; @@ -1490,15 +1551,14 @@ static int32 simh_out(const int32 port, const int32 data) { uint32 delta = sim_os_msec() - markTime[--markTimeSP]; printf("SIMH: " ADDRESS_FORMAT " Timer stopped. Elapsed time in milliseconds = %d." NLP, PCX, delta); } - else { + else printf("SIMH: " ADDRESS_FORMAT " No timer active." NLP, PCX); - } else warnNoRealTimeClock(); break; case resetPTRCmd: /* reset ptr device */ - ptr_reset(NULL); + ptr_reset(&ptr_dev); break; case attachPTRCmd: /* attach ptr to the file with name at beginning of CP/M command line */ @@ -1569,9 +1629,8 @@ static int32 simh_out(const int32 port, const int32 data) { uint32 delta = sim_os_msec() - markTime[markTimeSP - 1]; printf("SIMH: " ADDRESS_FORMAT " Timer running. Elapsed in milliseconds = %d." NLP, PCX, delta); } - else { + else printf("SIMH: " ADDRESS_FORMAT " No timer active." NLP, PCX); - } else warnNoRealTimeClock(); break; @@ -1622,7 +1681,7 @@ static int32 simh_out(const int32 port, const int32 data) { break; default: - TRACE_PRINT(CMD_MSG, + TRACE_PRINT(simh_device, CMD_MSG, ("SIMH: " ADDRESS_FORMAT " Unknown command (%i) to SIMH pseudo device on port %03xh ignored." NLP, PCX, data, port)); } @@ -1635,13 +1694,13 @@ int32 simh_dev(const int32 port, const int32 io, const int32 data) { int32 result = 0; if (io == 0) { result = simh_in(port); - TRACE_PRINT(IN_MSG, + TRACE_PRINT(simh_device, IN_MSG, ("SIMH: " ADDRESS_FORMAT " IN(0x%02x) -> %i (0x%02x, '%c')" NLP, PCX, port, result, result, (32 <= (result & 0xff)) && ((result & 0xff) <= 127) ? (result & 0xff) : '?')); } else { - TRACE_PRINT(OUT_MSG, + TRACE_PRINT(simh_device, OUT_MSG, ("SIMH: " ADDRESS_FORMAT " OUT(0x%02x) <- %i (0x%02x, '%c')" NLP, PCX, port, data, data, (32 <= (data & 0xff)) && ((data & 0xff) <= 127) ? (data & 0xff) : '?')); simh_out(port, data); diff --git a/AltairZ80/altairZ80_sys.c b/AltairZ80/altairZ80_sys.c index 66534a9c..f02b826f 100644 --- a/AltairZ80/altairZ80_sys.c +++ b/AltairZ80/altairZ80_sys.c @@ -1,6 +1,6 @@ /* altairz80_sys.c: MITS Altair system interface - Copyright (c) 2002-2008, Peter Schorn + Copyright (c) 2002-2010, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -76,6 +76,8 @@ extern DEVICE fpc_dev; extern int32 chiptype; extern long disasm (unsigned char *data, char *output, int segsize, long offset); +void prepareMemoryAccessMessage(const t_addr loc); +void prepareInstructionMessage(const t_addr loc, const uint32 op); t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw); t_stat parse_sym(char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw); @@ -123,11 +125,13 @@ DEVICE *sim_devices[] = { NULL }; -char memoryAccessMessage[80]; +static char memoryAccessMessage[256]; +static char instructionMessage[256]; const char *sim_stop_messages[] = { "HALT instruction", "Breakpoint", memoryAccessMessage, + instructionMessage, "Invalid Opcode" }; @@ -347,6 +351,15 @@ static char *const MnemonicsXCB[256] = { "SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(I%@h)", "SET 7,A" /* f8-ff */ }; +void prepareMemoryAccessMessage(const t_addr loc) { + sprintf(memoryAccessMessage, "Memory access breakpoint [%05xh]", loc); +} + +void prepareInstructionMessage(const t_addr loc, const uint32 op) { + sprintf(instructionMessage, "Instruction \"%s\" breakpoint [%05xh]", chiptype == CHIP_TYPE_8080 ? Mnemonics8080[op & 0xff] : + (chiptype == CHIP_TYPE_Z80 ? MnemonicsZ80[op & 0xff] : "???"), loc); +} + /* Symbolic disassembler Inputs: @@ -504,7 +517,7 @@ static int32 checkbase(char ch, const char *numString) { static int32 numok(char ch, const char **numString, const int32 minvalue, const int32 maxvalue, const int32 requireSign, int32 *result) { int32 sign = 1, value = 0, base; - if (requireSign) + if (requireSign) { if (ch == '+') ch = *(*numString)++; else if (ch == '-') { @@ -513,6 +526,7 @@ static int32 numok(char ch, const char **numString, const int32 minvalue, } else return FALSE; + } if (!(base = checkbase(ch, *numString))) return FALSE; while (isxdigit(ch)) { diff --git a/AltairZ80/altairz80_cpu_nommu.c b/AltairZ80/altairz80_cpu_nommu.c index c952539c..fa1a9221 100644 --- a/AltairZ80/altairz80_cpu_nommu.c +++ b/AltairZ80/altairz80_cpu_nommu.c @@ -1,6 +1,6 @@ /* altairz80_cpu_opt.c: MITS Altair CPU (8080 and Z80) - Copyright (c) 2002-2008, Peter Schorn + Copyright (c) 2002-2010, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -2353,7 +2353,7 @@ t_stat sim_instr_nommu(void) { case 0xdd: /* DD prefix */ CHECK_CPU_8080; - switch (op = RAM_PP(PC)) { + switch (RAM_PP(PC)) { case 0x09: /* ADD IX,BC */ IX &= ADDRMASK; @@ -3019,7 +3019,7 @@ t_stat sim_instr_nommu(void) { case 0xed: /* ED prefix */ CHECK_CPU_8080; - switch (op = RAM_PP(PC)) { + switch (RAM_PP(PC)) { case 0x40: /* IN B,(C) */ temp = in(LOW_REGISTER(BC)); @@ -3405,7 +3405,6 @@ t_stat sim_instr_nommu(void) { break; case 0xb0: /* LDIR */ - acu = HIGH_REGISTER(AF); BC &= ADDRMASK; if (BC == 0) BC = 0x10000; @@ -3594,7 +3593,7 @@ t_stat sim_instr_nommu(void) { case 0xfd: /* FD prefix */ CHECK_CPU_8080; - switch (op = RAM_PP(PC)) { + switch (RAM_PP(PC)) { case 0x09: /* ADD IY,BC */ IY &= ADDRMASK; diff --git a/AltairZ80/altairz80_doc.pdf b/AltairZ80/altairz80_doc.pdf new file mode 100644 index 00000000..1d9f22d9 Binary files /dev/null and b/AltairZ80/altairz80_doc.pdf differ diff --git a/AltairZ80/altairz80_hdsk.c b/AltairZ80/altairz80_hdsk.c index 21327dbf..009fb0e5 100644 --- a/AltairZ80/altairz80_hdsk.c +++ b/AltairZ80/altairz80_hdsk.c @@ -1,6 +1,6 @@ /* altairz80_hdsk.c: simulated hard disk device to increase capacity - Copyright (c) 2002-2008, Peter Schorn + Copyright (c) 2002-2010, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -42,6 +42,7 @@ static t_stat show_format(FILE *st, UNIT *uptr, int32 val, void *desc); static t_stat hdsk_reset(DEVICE *dptr); static t_stat hdsk_attach(UNIT *uptr, char *cptr); +static t_stat hdsk_detach(UNIT *uptr); #define UNIT_V_HDSK_WLK (UNIT_V_UF + 0) /* write locked */ #define UNIT_HDSK_WLK (1 << UNIT_V_HDSK_WLK) @@ -77,60 +78,143 @@ extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc); extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc); extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, int32 (*routine)(const int32, const int32, const int32), uint8 unmap); +extern int32 find_unit_index(UNIT *uptr); static t_stat hdsk_boot(int32 unitno, DEVICE *dptr); int32 hdsk_io(const int32 port, const int32 io, const int32 data); static int32 hdskLastCommand = HDSK_NONE; static int32 hdskCommandPosition = 0; -static int32 paramcount = 0; +static int32 parameterCount = 0; static int32 selectedDisk; static int32 selectedSector; static int32 selectedTrack; static int32 selectedDMA; typedef struct { - char name[DPB_NAME_LENGTH + 1]; /* name of CP/M disk parameter block */ - t_addr capac; /* capacity */ - uint16 spt; /* sectors per track */ - uint8 bsh; /* data allocation block shift factor */ - uint8 blm; /* data allocation block mask */ - uint8 exm; /* extent mask */ - uint16 dsm; /* maximum data block number */ - uint16 drm; /* total number of directory entries */ - uint8 al0; /* determine reserved directory blocks */ - uint8 al1; /* determine reserved directory blocks */ - uint16 cks; /* size of directory check vector */ - uint16 off; /* number of reserved tracks */ - uint8 psh; /* physical record shift factor, CP/M 3 */ - uint8 phm; /* physical record mask, CP/M 3 */ + char name[DPB_NAME_LENGTH + 1]; /* name of CP/M disk parameter block */ + t_addr capac; /* capacity */ + uint16 spt; /* sectors per track */ + uint8 bsh; /* data allocation block shift factor */ + uint8 blm; /* data allocation block mask */ + uint8 exm; /* extent mask */ + uint16 dsm; /* maximum data block number */ + uint16 drm; /* total number of directory entries */ + uint8 al0; /* determine reserved directory blocks */ + uint8 al1; /* determine reserved directory blocks */ + uint16 cks; /* size of directory check vector */ + uint16 off; /* number of reserved tracks */ + uint8 psh; /* physical record shift factor, CP/M 3 */ + uint8 phm; /* physical record mask, CP/M 3 */ + int32 physicalSectorSize; /* 0 for 128 << psh, > 0 for special */ + int32 offset; /* offset in physical sector where logical sector starts */ + int32 *skew; /* pointer to skew table or NULL */ } DPB; typedef struct { PNP_INFO pnp; /* Plug and Play */ } HDSK_INFO; -static HDSK_INFO hdsk_info_data = { { 0x0000, 0, 0xFD, 1 } }; -/* static HDSK_INFO *hdsk_info = &hdsk_info_data; */ +#define SPT16 16 +#define SPT32 32 +#define SPT26 26 -/* Note in the following CKS = 0 for fixed media which are not supposed to be changed while CP/M is executing */ +static HDSK_INFO hdsk_info_data = { { 0x0000, 0, 0xFD, 1 } }; + +static int32 standard8[SPT26] = { 0, 6, 12, 18, 24, 4, 10, 16, + 22, 2, 8, 14, 20, 1, 7, 13, + 19, 25, 5, 11, 17, 23, 3, 9, + 15, 21 }; + +static int32 appple_ii_DOS[SPT16] = { 0, 6, 12, 3, 9, 15, 14, 5, + 11, 2, 8, 7, 13, 4, 10, 1 }; + +static int32 appple_ii_DOS2[SPT32] = { 0, 1, 12, 13, 24, 25, 6, 7, + 18, 19, 30, 31, 28, 29, 10, 11, + 22, 23, 4, 5, 16, 17, 14, 15, + 26, 27, 8, 9, 20, 21, 2, 3 }; + +static int32 appple_ii_PRODOS[SPT16] = { 0, 9, 3, 12, 6, 15, 1, 10, + 4, 13, 7, 8, 2, 11, 5, 14 }; + +static int32 appple_ii_PRODOS2[SPT32] = { 0, 1, 18, 19, 6, 7, 24, 25, + 12, 13, 30, 31, 2, 3, 20, 21, + 8, 9, 26, 27, 14, 15, 16, 17, + 4, 5, 22, 23, 10, 11, 28, 29 }; + +static int32 mits[SPT32] = { 0, 17, 2, 19, 4, 21, 6, 23, + 8, 25, 10, 27, 12, 29, 14, 31, + 16, 1, 18, 3, 20, 5, 22, 7, + 24, 9, 26, 11, 28, 13, 30, 15 }; + +/* Note in the following CKS = 0 for fixed media which are not supposed to be + changed while CP/M is executing. Also note that spt (sectors per track) is + measured in CP/M sectors of size 128 bytes. Standard format "HDSK" must be + first as index 0 is used as default in some cases. + */ static DPB dpb[] = { -/* name capac spt bsh blm exm dsm drm al0 al1 cks off psh phm */ - { "HDSK", HDSK_CAPACITY, 32, 0x05, 0x1F, 0x01, 0x07f9, 0x03FF, 0xFF, 0x00, 0x0000, 0x0006, 0x00, 0x00 }, /* AZ80 HDSK */ - { "EZ80FL", 131072, 32, 0x03, 0x07, 0x00, 127, 0x003E, 0xC0, 0x00, 0x0000, 0x0000, 0x02, 0x03 }, /* 128K FLASH */ - { "P112", 1474560, 72, 0x04, 0x0F, 0x00, 710, 0x00FE, 0xF0, 0x00, 0x0000, 0x0002, 0x02, 0x03 }, /* 1.44M P112 */ - { "SU720", 737280, 36, 0x04, 0x0F, 0x00, 354, 0x007E, 0xC0, 0x00, 0x0020, 0x0002, 0x02, 0x03 }, /* 720K Super I/O */ - { "OSB1", 102400, 20, 0x04, 0x0F, 0x01, 45, 0x003F, 0x80, 0x00, 0x0000, 0x0003, 0x02, 0x03 }, /* Osborne1 5.25" SS SD */ - { "OSB2", 204800, 40, 0x03, 0x07, 0x00, 184, 0x003F, 0xC0, 0x00, 0x0000, 0x0003, 0x02, 0x03 }, /* Osborne1 5.25" SS DD */ - { "NSSS1", 179200, 40, 0x03, 0x07, 0x00, 0xA4, 0x003F, 0xC0, 0x00, 0x0010, 0x0002, 0x02, 0x03 }, /* Northstar SSDD Format 1 */ - { "NSSS2", 179200, 40, 0x04, 0x0F, 0x01, 0x51, 0x003F, 0x80, 0x00, 0x0010, 0x0002, 0x02, 0x03 }, /* Northstar SSDD Format 2 */ - { "NSDS2", 358400, 40, 0x04, 0x0F, 0x01, 0xA9, 0x003F, 0x80, 0x00, 0x0010, 0x0002, 0x02, 0x03 }, /* Northstar DSDD Format 2 */ - { "VGSS", 315392, 32, 0x04, 0x0F, 0x00, 149, 0x007F, 0xC0, 0x00, 0x0020, 0x0002, 0x02, 0x03 }, /* Vector SS SD */ - { "VGDS", 632784, 32, 0x04, 0x0F, 0x00, 299, 0x007F, 0xC0, 0x00, 0x0020, 0x0004, 0x02, 0x03 }, /* Vector DS SD */ - /* Note on DISK1A Images: this is a bit of a mess. The first track on the disk is 128x26 bytes (SD) and to make this work - I had to "move" the data from 0x2d00 in the DSK image file down to 0x4000 (2-tracks in). I used WinHex to do it. */ - { "DISK1A", 630784, 64, 0x04, 0x0F, 0x00, 299, 0x007F, 0xC0, 0x00, 0x0020, 0x0002, 0x02, 0x03 }, /* CompuPro Disk1A 8" SS SD */ - { "SSSD8", 256256, 26, 0x03, 0x07, 0x00, 242, 0x003F, 0xC0, 0x00, 0x0000, 0x0002, 0x00, 0x00 }, /* Standard 8" SS SD */ +/* name capac spt bsh blm exm dsm drm + al0 al1 cks off psh phm ss off skew */ + { "HDSK", HDSK_CAPACITY, 32, 0x05, 0x1F, 0x01, 0x07f9, 0x03FF, + 0xFF, 0x00, 0x0000, 0x0006, 0x00, 0x00, 0, 0, NULL }, /* AZ80 HDSK */ + + { "EZ80FL", 131072, 32, 0x03, 0x07, 0x00, 127, 0x003E, + 0xC0, 0x00, 0x0000, 0x0000, 0x02, 0x03, 0, 0, NULL }, /* 128K FLASH */ + + { "P112", 1474560, 72, 0x04, 0x0F, 0x00, 710, 0x00FE, + 0xF0, 0x00, 0x0000, 0x0002, 0x02, 0x03, 0, 0, NULL }, /* 1.44M P112 */ + + { "SU720", 737280, 36, 0x04, 0x0F, 0x00, 354, 0x007E, + 0xC0, 0x00, 0x0020, 0x0002, 0x02, 0x03, 0, 0, NULL }, /* 720K Super I/O */ + + { "OSB1", 102400, 20, 0x04, 0x0F, 0x01, 45, 0x003F, + 0x80, 0x00, 0x0000, 0x0003, 0x02, 0x03, 0, 0, NULL }, /* Osborne1 5.25" SS SD */ + + { "OSB2", 204800, 40, 0x03, 0x07, 0x00, 184, 0x003F, + 0xC0, 0x00, 0x0000, 0x0003, 0x02, 0x03, 0, 0, NULL }, /* Osborne1 5.25" SS DD */ + + { "NSSS1", 179200, 40, 0x03, 0x07, 0x00, 0xA4, 0x003F, + 0xC0, 0x00, 0x0010, 0x0002, 0x02, 0x03, 0, 0, NULL }, /* Northstar SSDD Format 1 */ + + { "NSSS2", 179200, 40, 0x04, 0x0F, 0x01, 0x51, 0x003F, + 0x80, 0x00, 0x0010, 0x0002, 0x02, 0x03, 0, 0, NULL }, /* Northstar SSDD Format 2 */ + + { "NSDS2", 358400, 40, 0x04, 0x0F, 0x01, 0xA9, 0x003F, + 0x80, 0x00, 0x0010, 0x0002, 0x02, 0x03, 0, 0, NULL }, /* Northstar DSDD Format 2 */ + + { "VGSS", 315392, 32, 0x04, 0x0F, 0x00, 149, 0x007F, + 0xC0, 0x00, 0x0020, 0x0002, 0x02, 0x03, 0, 0, NULL }, /* Vector SS SD */ + + { "VGDS", 630784, 32, 0x04, 0x0F, 0x00, 299, 0x007F, + 0xC0, 0x00, 0x0020, 0x0004, 0x02, 0x03, 0, 0, NULL }, /* Vector DS SD */ + + { "DISK1A", 630784, 64, 0x04, 0x0F, 0x00, 299, 0x007F, + 0xC0, 0x00, 0x0020, 0x0002, 0x02, 0x03, 0, 0, NULL }, /* CompuPro Disk1A 8" SS SD */ + + { "SSSD8", 256256, SPT26, 0x03, 0x07, 0x00, 242, 0x003F, + 0xC0, 0x00, 0x0000, 0x0002, 0x00, 0x00, 0, 0, NULL }, /* Standard 8" SS SD */ + + { "SSSD8S", 256256, SPT26, 0x03, 0x07, 0x00, 242, 0x003F, + 0xC0, 0x00, 0x0000, 0x0002, 0x00, 0x00, 0, 0, standard8 }, /* Standard 8" SS SD with skew */ + + { "APPLE-DO",143360, SPT32, 0x03, 0x07, 0x00, 127, 0x003F, + 0xC0, 0x00, 0x0000, 0x0003, 0x01, 0x01, 0, 0, appple_ii_DOS }, /* Apple II DOS 3.3 */ + + { "APPLE-PO",143360, SPT32, 0x03, 0x07, 0x00, 127, 0x003F, + 0xC0, 0x00, 0x0000, 0x0003, 0x01, 0x01, 0, 0, appple_ii_PRODOS }, /* Apple II PRODOS */ + + { "APPLE-D2",143360, SPT32, 0x03, 0x07, 0x00, 127, 0x003F, + 0xC0, 0x00, 0x0000, 0x0003, 0x00, 0x00, 0, 0, appple_ii_DOS2 }, /* Apple II DOS 3.3, deblocked */ + + { "APPLE-P2",143360, SPT32, 0x03, 0x07, 0x00, 127, 0x003F, + 0xC0, 0x00, 0x0000, 0x0003, 0x00, 0x00, 0, 0, appple_ii_PRODOS2 }, /* Apple II PRODOS, deblocked */ + + { "MITS", 337568, SPT32, 0x03, 0x07, 0x00, 254, 0x00FF, + 0xFF, 0x00, 0x0000, 0x0006, 0x00, 0x00, 137, 3, mits }, /* MITS Altair original */ + + { "MITS2", 1113536, SPT32, 0x04, 0x0F, 0x00, 0x1EF, 0x00FF, + 0xF0, 0x00, 0x0000, 0x0006, 0x00, 0x00, 137, 3, mits }, /* MITS Altair original, extra */ + { "", 0 } }; @@ -180,7 +264,7 @@ DEVICE hdsk_dev = { "HDSK", hdsk_unit, hdsk_reg, hdsk_mod, 8, 10, 31, 1, 8, 8, NULL, NULL, &hdsk_reset, - &hdsk_boot, &hdsk_attach, NULL, + &hdsk_boot, &hdsk_attach, &hdsk_detach, &hdsk_info_data, (DEV_DISABLE | DEV_DEBUG), 0, hdsk_dt, NULL, "Hard Disk HDSK" }; @@ -212,7 +296,7 @@ static t_stat hdsk_attach(UNIT *uptr, char *cptr) { return r; /* Step 1: Determine capacity of this disk */ - uptr -> capac = sim_fsize(uptr -> fileref); /* the file length is a good candidate */ + uptr -> capac = sim_fsize(uptr -> fileref); /* the file length is a good indication */ if (uptr -> capac == 0) { /* file does not exist or has length 0 */ uptr -> capac = uptr -> HDSK_NUMBER_OF_TRACKS * uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE; @@ -252,10 +336,10 @@ static t_stat hdsk_attach(UNIT *uptr, char *cptr) { } } else { /* Case 2: disk parameter block found */ - uptr -> HDSK_SECTORS_PER_TRACK = dpb[uptr -> HDSK_FORMAT_TYPE].spt >> dpb[uptr -> HDSK_FORMAT_TYPE].psh; - uptr -> HDSK_SECTOR_SIZE = (128 << dpb[uptr -> HDSK_FORMAT_TYPE].psh); + uptr -> HDSK_SECTORS_PER_TRACK = dpb[uptr -> HDSK_FORMAT_TYPE].spt >> dpb[uptr -> HDSK_FORMAT_TYPE].psh; + uptr -> HDSK_SECTOR_SIZE = (128 << dpb[uptr -> HDSK_FORMAT_TYPE].psh); } - assert(uptr -> HDSK_SECTORS_PER_TRACK && uptr -> HDSK_SECTOR_SIZE); + assert((uptr -> HDSK_SECTORS_PER_TRACK) && (uptr -> HDSK_SECTOR_SIZE) && (uptr -> HDSK_FORMAT_TYPE >= 0)); /* Step 4: Number of tracks is smallest number to accomodate capacity */ uptr -> HDSK_NUMBER_OF_TRACKS = (uptr -> capac + uptr -> HDSK_SECTORS_PER_TRACK * @@ -264,9 +348,23 @@ static t_stat hdsk_attach(UNIT *uptr, char *cptr) { uptr -> HDSK_SECTOR_SIZE) < uptr -> capac) && (uptr -> capac <= (t_addr) (uptr -> HDSK_NUMBER_OF_TRACKS * uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE) ) ); + return SCPE_OK; } +static t_stat hdsk_detach(UNIT *uptr) { + t_stat result; + if (uptr == NULL) + return SCPE_IERR; + result = detach_unit(uptr); + uptr -> capac = HDSK_CAPACITY; + uptr -> HDSK_FORMAT_TYPE = 0; + uptr -> HDSK_SECTOR_SIZE = 0; + uptr -> HDSK_SECTORS_PER_TRACK = 0; + uptr -> HDSK_NUMBER_OF_TRACKS = 0; + return result; +} + /* Set disk geometry routine */ static t_stat set_geom(UNIT *uptr, int32 val, char *cptr, void *desc) { uint32 numberOfTracks, numberOfSectors, sectorSize; @@ -276,6 +374,10 @@ static t_stat set_geom(UNIT *uptr, int32 val, char *cptr, void *desc) { return SCPE_ARG; if (uptr == NULL) return SCPE_IERR; + if (((uptr -> flags) & UNIT_ATT) == 0) { + printf("Cannot set geometry for not attached unit %i.\n", find_unit_index(uptr)); + return SCPE_ARG; + } result = sscanf(cptr, "%d/%d/%d%n", &numberOfTracks, &numberOfSectors, §orSize, &n); if ((result != 3) || (result == EOF) || (cptr[n] != 0)) { result = sscanf(cptr, "T:%d/N:%d/S:%d%n", &numberOfTracks, &numberOfSectors, §orSize, &n); @@ -311,6 +413,10 @@ static t_stat set_format(UNIT *uptr, int32 val, char *cptr, void *desc) { return SCPE_IERR; if (sscanf(cptr, "%" QUOTE2(DPB_NAME_LENGTH) "s", fmtname) == 0) return SCPE_ARG; + if (((uptr -> flags) & UNIT_ATT) == 0) { + printf("Cannot set format for not attached unit %i.\n", find_unit_index(uptr)); + return SCPE_ARG; + } for (i = 0; dpb[i].capac != 0; i++) { if (strncmp(fmtname, dpb[i].name, strlen(fmtname)) == 0) { uptr -> HDSK_FORMAT_TYPE = i; @@ -405,8 +511,8 @@ static t_stat hdsk_boot(int32 unitno, DEVICE *dptr) { ; parameter block cmd: db HDSK_READ or HDSK_WRITE hd: db 0 ; 0 .. 7, defines hard disk to be used - sector: db 0 ; 0 .. 31, defines sector - track: dw 0 ; 0 .. 2047, defines track + sector: db 0 ; 0 .. 31, defines sector + track: dw 0 ; 0 .. 2047, defines track dma: dw 0 ; defines where result is placed in memory ; routine to execute @@ -444,12 +550,13 @@ static t_stat hdsk_boot(int32 unitno, DEVICE *dptr) { /* check the parameters and return TRUE iff parameters are correct or have been repaired */ static int32 checkParameters(void) { - UNIT *uptr = &hdsk_dev.units[selectedDisk]; + UNIT *uptr; if ((selectedDisk < 0) || (selectedDisk >= HDSK_NUMBER)) { TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Disk %i does not exist, will use HDSK0 instead." NLP, selectedDisk, PCX, selectedDisk)); selectedDisk = 0; } + uptr = &hdsk_dev.units[selectedDisk]; if ((hdsk_dev.units[selectedDisk].flags & UNIT_ATT) == 0) { TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Disk %i is not attached." NLP, selectedDisk, PCX, selectedDisk)); @@ -475,28 +582,33 @@ static int32 checkParameters(void) { return TRUE; } +/* pre-condition: checkParameters has been executed to repair any faulty parameters */ static int32 doSeek(void) { UNIT *uptr = &hdsk_dev.units[selectedDisk]; - if (fseek(uptr -> fileref, - (uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE) * selectedTrack + - (uptr -> HDSK_SECTOR_SIZE * selectedSector), SEEK_SET)) { - TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Could not access Sector=%02d Track=%04d." NLP, - selectedDisk, PCX, selectedSector, selectedTrack)); + int32 hostSector = (dpb[uptr -> HDSK_FORMAT_TYPE].skew == NULL) ? + selectedSector : dpb[uptr -> HDSK_FORMAT_TYPE].skew[selectedSector]; + int32 sectorSize = (dpb[uptr -> HDSK_FORMAT_TYPE].physicalSectorSize == 0) ? + uptr -> HDSK_SECTOR_SIZE : dpb[uptr -> HDSK_FORMAT_TYPE].physicalSectorSize; + if (sim_fseek(uptr -> fileref, + sectorSize * (uptr -> HDSK_SECTORS_PER_TRACK * selectedTrack + hostSector) + + dpb[uptr -> HDSK_FORMAT_TYPE].offset, SEEK_SET)) { + TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Could not access Sector=%02d[=%02d] Track=%04d." NLP, + selectedDisk, PCX, selectedSector, hostSector, selectedTrack)); return CPM_ERROR; } - else - return CPM_OK; + return CPM_OK; } uint8 hdskbuf[HDSK_MAX_SECTOR_SIZE] = { 0 }; /* data buffer */ +/* pre-condition: checkParameters has been executed to repair any faulty parameters */ static int32 doRead(void) { int32 i; UNIT *uptr = &hdsk_dev.units[selectedDisk]; if (doSeek()) return CPM_ERROR; - if (fread(hdskbuf, uptr -> HDSK_SECTOR_SIZE, 1, uptr -> fileref) != 1) { + if (sim_fread(hdskbuf, 1, uptr -> HDSK_SECTOR_SIZE, uptr -> fileref) != (size_t)(uptr -> HDSK_SECTOR_SIZE)) { for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++) hdskbuf[i] = CPM_EMPTY; TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Could not read Sector=%02d Track=%04d." NLP, @@ -508,18 +620,20 @@ static int32 doRead(void) { return CPM_OK; } +/* pre-condition: checkParameters has been executed to repair any faulty parameters */ static int32 doWrite(void) { int32 i; - + size_t rtn; UNIT *uptr = &hdsk_dev.units[selectedDisk]; if (((uptr -> flags) & UNIT_HDSK_WLK) == 0) { /* write enabled */ if (doSeek()) return CPM_ERROR; for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++) hdskbuf[i] = GetBYTEWrapper(selectedDMA + i); - if (fwrite(hdskbuf, uptr -> HDSK_SECTOR_SIZE, 1, uptr -> fileref) != 1) { - TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Could not write Sector=%02d Track=%04d." NLP, - selectedDisk, PCX, selectedSector, selectedTrack)); + rtn = sim_fwrite(hdskbuf, 1, uptr -> HDSK_SECTOR_SIZE, uptr -> fileref); + if (rtn != (size_t)(uptr -> HDSK_SECTOR_SIZE)) { + TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Could not write Sector=%02d Track=%04d Result=%zd." NLP, + selectedDisk, PCX, selectedSector, selectedTrack, rtn)); return CPM_ERROR; } } @@ -531,57 +645,59 @@ static int32 doWrite(void) { return CPM_OK; } -static int32 hdsk_in(const int32 port) { - UNIT *uptr = &hdsk_dev.units[selectedDisk]; +#define PARAMETER_BLOCK_SIZE 19 +static uint8 parameterBlock[PARAMETER_BLOCK_SIZE]; - int32 result; +static int32 hdsk_in(const int32 port) { if ((hdskCommandPosition == 6) && ((hdskLastCommand == HDSK_READ) || (hdskLastCommand == HDSK_WRITE))) { - result = checkParameters() ? ((hdskLastCommand == HDSK_READ) ? doRead() : doWrite()) : CPM_ERROR; + int32 result = checkParameters() ? ((hdskLastCommand == HDSK_READ) ? doRead() : doWrite()) : CPM_ERROR; hdskLastCommand = HDSK_NONE; hdskCommandPosition = 0; return result; - } else if (hdskLastCommand == HDSK_PARAM) { - DPB current = dpb[uptr -> HDSK_FORMAT_TYPE]; - uint8 params[17]; - params[ 0] = current.spt & 0xff; params[ 1] = (current.spt >> 8) & 0xff; - params[ 2] = current.bsh; - params[ 3] = current.blm; - params[ 4] = current.exm; - params[ 5] = current.dsm & 0xff; params[ 6] = (current.dsm >> 8) & 0xff; - params[ 7] = current.drm & 0xff; params[ 8] = (current.drm >> 8) & 0xff; - params[ 9] = current.al0; - params[10] = current.al1; - params[11] = current.cks & 0xff; params[12] = (current.cks >> 8) & 0xff; - params[13] = current.off & 0xff; params[14] = (current.off >> 8) & 0xff; - params[15] = current.psh; - params[16] = current.phm; - if (++paramcount >= 19) + } + if (hdskLastCommand == HDSK_PARAM) { + if (++parameterCount >= PARAMETER_BLOCK_SIZE) hdskLastCommand = HDSK_NONE; - if (paramcount <= 17) - return params[paramcount - 1]; - else if (paramcount == 18) - return (uptr -> HDSK_SECTOR_SIZE & 0xff); - else if (paramcount == 19) - return (uptr -> HDSK_SECTOR_SIZE >> 8); - else { - printf("HDSK%d: " ADDRESS_FORMAT " Get parameter error." NLP, - selectedDisk, PCX); - } - - } - else { - TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Illegal IN command detected (port=%03xh, cmd=%d, pos=%d)." NLP, - selectedDisk, PCX, port, hdskLastCommand, hdskCommandPosition)); + return parameterBlock[parameterCount - 1]; } + TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Illegal IN command detected (port=%03xh, cmd=%d, pos=%d)." NLP, + selectedDisk, PCX, port, hdskLastCommand, hdskCommandPosition)); return CPM_OK; } static int32 hdsk_out(const int32 port, const int32 data) { + int32 thisDisk; + UNIT *uptr; + DPB current; + switch(hdskLastCommand) { case HDSK_PARAM: - paramcount = 0; - selectedDisk = data; + parameterCount = 0; + thisDisk = (0 <= data) && (data < HDSK_NUMBER) ? data : 0; + uptr = &hdsk_dev.units[thisDisk]; + if ((uptr -> flags) & UNIT_ATT) { + current = dpb[uptr -> HDSK_FORMAT_TYPE]; + parameterBlock[17] = uptr -> HDSK_SECTOR_SIZE & 0xff; + parameterBlock[18] = (uptr -> HDSK_SECTOR_SIZE >> 8) & 0xff; + } + else { + current = dpb[0]; + parameterBlock[17] = 128; + parameterBlock[18] = 0; + } + parameterBlock[ 0] = current.spt & 0xff; parameterBlock[ 1] = (current.spt >> 8) & 0xff; + parameterBlock[ 2] = current.bsh; + parameterBlock[ 3] = current.blm; + parameterBlock[ 4] = current.exm; + parameterBlock[ 5] = current.dsm & 0xff; parameterBlock[ 6] = (current.dsm >> 8) & 0xff; + parameterBlock[ 7] = current.drm & 0xff; parameterBlock[ 8] = (current.drm >> 8) & 0xff; + parameterBlock[ 9] = current.al0; + parameterBlock[10] = current.al1; + parameterBlock[11] = current.cks & 0xff; parameterBlock[12] = (current.cks >> 8) & 0xff; + parameterBlock[13] = current.off & 0xff; parameterBlock[14] = (current.off >> 8) & 0xff; + parameterBlock[15] = current.psh; + parameterBlock[16] = current.phm; break; case HDSK_READ: diff --git a/AltairZ80/altairz80_net.c b/AltairZ80/altairz80_net.c index 4c67b206..c4fa016c 100644 --- a/AltairZ80/altairz80_net.c +++ b/AltairZ80/altairz80_net.c @@ -1,6 +1,6 @@ /* altairz80_net.c: networking capability - Copyright (c) 2002-2008, Peter Schorn + Copyright (c) 2002-2010, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -67,7 +67,7 @@ static struct { int32 outputPosRead; /* position of next character to write to ioSocket */ int32 outputPosWrite; /* position of next character to append to output buffer */ int32 outputSize; /* number of characters in circular output buffer */ -} serviceDescriptor[MAX_CONNECTIONS+1] = { /* serviceDescriptor[0] holds the information for a client */ +} serviceDescriptor[MAX_CONNECTIONS + 1] = { /* serviceDescriptor[0] holds the information for a client */ /* stat dat ms ios in inPR inPW inS out outPR outPW outS */ {0x32, 0x33, 0, 0, {0}, 0, 0, 0, {0}, 0, 0, 0}, /* client Z80 port 50 and 51 */ {0x28, 0x29, 0, 0, {0}, 0, 0, 0, {0}, 0, 0, 0}, /* server Z80 port 40 and 41 */ @@ -290,7 +290,7 @@ int32 netData(const int32 port, const int32 io, const int32 data) { return 0; net_svc(&net_unit); for (i = 0; i <= MAX_CONNECTIONS; i++) - if (serviceDescriptor[i].Z80DataPort == port) + if (serviceDescriptor[i].Z80DataPort == port) { if (io == 0) { /* IN */ if (serviceDescriptor[i].inputSize == 0) { printf("re-read from %i" NLP, port); @@ -323,5 +323,6 @@ int32 netData(const int32 port, const int32 io, const int32 data) { (32 <= data) && (data <= 127) ? data : '?')); return 0; } + } return 0; } diff --git a/AltairZ80/flashwriter2.c b/AltairZ80/flashwriter2.c index d4511ce6..ba11478f 100644 --- a/AltairZ80/flashwriter2.c +++ b/AltairZ80/flashwriter2.c @@ -3,7 +3,7 @@ * $Id: flashwriter2.c 1941 2008-06-13 05:31:03Z hharte $ * * * * Copyright (c) 2007-2008 Howard M. Harte. * - * http:/*www.hartetec.com * + * http://www.hartetec.com * * * * Permission is hereby granted, free of charge, to any person obtaining * * a copy of this software and associated documentation files (the * diff --git a/AltairZ80/i8272.c b/AltairZ80/i8272.c index af828bab..5a11ad4a 100644 --- a/AltairZ80/i8272.c +++ b/AltairZ80/i8272.c @@ -149,9 +149,6 @@ extern uint8 GetByteDMA(const uint32 Addr); #define UNIT_I8272_VERBOSE (1 << UNIT_V_I8272_VERBOSE) #define I8272_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */ #define I8272_CAPACITY_SSSD (77*1*26*128) /* Single-sided Single Density IBM Diskette1 */ -#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */ -#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */ -#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */ /* Intel 8272 Commands */ #define I8272_READ_TRACK 0x02 @@ -307,8 +304,8 @@ t_stat i8272_attach(UNIT *uptr, char *cptr) i8272_info->drive[i].ready = 0; if(uptr->capac > 0) { - fgets(header, 4, uptr->fileref); - if(strncmp(header, "IMD", 3)) { + char *rtn = fgets(header, 4, uptr->fileref); + if((rtn != NULL) && strncmp(header, "IMD", 3)) { printf("I8272: Only IMD disk images are supported\n"); i8272_info->drive[i].uptr = NULL; return SCPE_OPENERR; @@ -414,8 +411,7 @@ uint8 I8272_Read(const uint32 Addr) return 0xFF; } - cData = 0x00; - + /* the switch statement ensures that cData is set in all cases! */ switch(Addr & 0x3) { case I8272_FDC_MSR: cData = i8272_info->fdc_msr | I8272_MSR_RQM; diff --git a/AltairZ80/i86_decode.c b/AltairZ80/i86_decode.c index b83979ad..2b15e27f 100644 --- a/AltairZ80/i86_decode.c +++ b/AltairZ80/i86_decode.c @@ -86,7 +86,6 @@ static void i86_intr_handle(PC_ENV *m) if (intr & INTR_SYNCH) /* raised by something */ { intno = m->intno; - tmp = (uint16) mem_access_word(m, intno * 4); { tmp = m->R_FLG; push_word(m, tmp); diff --git a/AltairZ80/i86_ops.c b/AltairZ80/i86_ops.c index d289a5be..cb60407e 100644 --- a/AltairZ80/i86_ops.c +++ b/AltairZ80/i86_ops.c @@ -108,7 +108,7 @@ extern uint32 in(const uint32 Port); So, without further ado, ... */ -extern char parity_tab[]; +extern uint8 parity_tab[]; static void i86op_illegal_op(PC_ENV *m) { @@ -3823,7 +3823,6 @@ static void i86op_ret_far(PC_ENV *m) static void i86op_int3(PC_ENV *m) { uint16 tmp; - tmp = (uint16) mem_access_word(m, 3 * 4); /* access the segment register */ { tmp = m->R_FLG; @@ -3855,7 +3854,6 @@ static void i86op_int_IMM(PC_ENV *m) uint16 tmp; uint8 intnum; intnum = fetch_byte_imm(m); - tmp = mem_access_word(m, intnum * 4); { tmp = m->R_FLG; push_word(m, tmp); @@ -3886,7 +3884,6 @@ static void i86op_into(PC_ENV *m) uint16 tmp; if (ACCESS_FLAG(m,F_OF)) { - tmp = mem_access_word(m, 4 * 4); { tmp = m->R_FLG; push_word(m, tmp); @@ -4150,8 +4147,7 @@ static void i86op_aam(PC_ENV *m) /* opcode=0xd5*/ static void i86op_aad(PC_ENV *m) -{ uint8 a; - a = fetch_byte_imm(m); +{ m->R_AX = aad_word(m,m->R_AX); DECODE_CLEAR_SEGOVR(m); } @@ -5050,22 +5046,19 @@ static void i86op_esc_coprocess_d8(PC_ENV *m) static void i86op_esc_coprocess_d9(PC_ENV *m) { uint16 mod,rl,rh; - uint16 destoffset; - uint8 stkelem; FETCH_DECODE_MODRM(m,mod,rh,rl); switch (mod) { case 0: - destoffset=decode_rm00_address(m,rl); + decode_rm00_address(m,rl); break; case 1: - destoffset=decode_rm01_address(m,rl); + decode_rm01_address(m,rl); break; case 2: - destoffset=decode_rm10_address(m,rl); + decode_rm10_address(m,rl); break; case 3: /* register to register */ - stkelem = (uint8) rl; break; } DECODE_CLEAR_SEGOVR(m); @@ -5075,22 +5068,19 @@ static void i86op_esc_coprocess_d9(PC_ENV *m) static void i86op_esc_coprocess_da(PC_ENV *m) { uint16 mod,rl,rh; - uint16 destoffset; - uint8 stkelem; FETCH_DECODE_MODRM(m,mod,rh,rl); switch (mod) { case 0: - destoffset=decode_rm00_address(m,rl); + decode_rm00_address(m,rl); break; case 1: - destoffset=decode_rm01_address(m,rl); + decode_rm01_address(m,rl); break; case 2: - destoffset=decode_rm10_address(m,rl); + decode_rm10_address(m,rl); break; case 3: /* register to register */ - stkelem = (uint8) rl; break; } DECODE_CLEAR_SEGOVR(m); @@ -5100,19 +5090,17 @@ static void i86op_esc_coprocess_da(PC_ENV *m) static void i86op_esc_coprocess_db(PC_ENV *m) { uint16 mod,rl,rh; - uint16 destoffset; -/* uint8 stkelem;*/ FETCH_DECODE_MODRM(m,mod,rh,rl); switch (mod) { case 0: - destoffset=decode_rm00_address(m,rl); + decode_rm00_address(m,rl); break; case 1: - destoffset=decode_rm01_address(m,rl); + decode_rm01_address(m,rl); break; case 2: - destoffset=decode_rm10_address(m,rl); + decode_rm10_address(m,rl); break; case 3: /* register to register */ break; @@ -5124,22 +5112,19 @@ static void i86op_esc_coprocess_db(PC_ENV *m) static void i86op_esc_coprocess_dc(PC_ENV *m) { uint16 mod,rl,rh; - uint16 destoffset; - uint8 stkelem; FETCH_DECODE_MODRM(m,mod,rh,rl); switch (mod) { case 0: - destoffset=decode_rm00_address(m,rl); + decode_rm00_address(m,rl); break; case 1: - destoffset=decode_rm01_address(m,rl); + decode_rm01_address(m,rl); break; case 2: - destoffset=decode_rm10_address(m,rl); + decode_rm10_address(m,rl); break; case 3: /* register to register */ - stkelem = (uint8) rl; break; } DECODE_CLEAR_SEGOVR(m); @@ -5149,22 +5134,19 @@ static void i86op_esc_coprocess_dc(PC_ENV *m) static void i86op_esc_coprocess_dd(PC_ENV *m) { uint16 mod,rl,rh; - uint16 destoffset; - uint8 stkelem; FETCH_DECODE_MODRM(m,mod,rh,rl); switch (mod) { case 0: - destoffset=decode_rm00_address(m,rl); + decode_rm00_address(m,rl); break; case 1: - destoffset=decode_rm01_address(m,rl); + decode_rm01_address(m,rl); break; case 2: - destoffset=decode_rm10_address(m,rl); + decode_rm10_address(m,rl); break; case 3: /* register to register */ - stkelem = (uint8) rl; break; } DECODE_CLEAR_SEGOVR(m); @@ -5174,22 +5156,19 @@ static void i86op_esc_coprocess_dd(PC_ENV *m) static void i86op_esc_coprocess_de(PC_ENV *m) { uint16 mod,rl,rh; - uint16 destoffset; - uint8 stkelem; FETCH_DECODE_MODRM(m,mod,rh,rl); switch (mod) { case 0: - destoffset=decode_rm00_address(m,rl); + decode_rm00_address(m,rl); break; case 1: - destoffset=decode_rm01_address(m,rl); + decode_rm01_address(m,rl); break; case 2: - destoffset=decode_rm10_address(m,rl); + decode_rm10_address(m,rl); break; case 3: /* register to register */ - stkelem = (uint8) rl; break; } DECODE_CLEAR_SEGOVR(m); @@ -5199,22 +5178,19 @@ static void i86op_esc_coprocess_de(PC_ENV *m) static void i86op_esc_coprocess_df(PC_ENV *m) { uint16 mod,rl,rh; - uint16 destoffset; - uint8 stkelem; FETCH_DECODE_MODRM(m,mod,rh,rl); switch (mod) { case 0: - destoffset=decode_rm00_address(m,rl); + decode_rm00_address(m,rl); break; case 1: - destoffset=decode_rm01_address(m,rl); + decode_rm01_address(m,rl); break; case 2: - destoffset=decode_rm10_address(m,rl); + decode_rm10_address(m,rl); break; case 3: /* register to register */ - stkelem = (uint8) rl; break; } DECODE_CLEAR_SEGOVR(m); diff --git a/AltairZ80/i86_prim_ops.c b/AltairZ80/i86_prim_ops.c index 109f31f4..44355110 100644 --- a/AltairZ80/i86_prim_ops.c +++ b/AltairZ80/i86_prim_ops.c @@ -1106,7 +1106,6 @@ uint8 shr_byte(PC_ENV *m, uint8 d, uint8 s) uint16 shr_word(PC_ENV *m, uint16 d, uint16 s) { uint32 cnt,res,cf,mask; - res = d; if (s < 16) { cnt = s % 16; diff --git a/AltairZ80/mfdc.c b/AltairZ80/mfdc.c index 503230e9..bc6f3531 100644 --- a/AltairZ80/mfdc.c +++ b/AltairZ80/mfdc.c @@ -130,9 +130,6 @@ static SECTOR_FORMAT sdata; #define UNIT_V_MFDC_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ #define UNIT_MFDC_VERBOSE (1 << UNIT_V_MFDC_VERBOSE) #define MFDC_CAPACITY (77*16*MFDC_SECTOR_LEN) /* Default Micropolis Disk Capacity */ -#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */ -#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */ -#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */ static t_stat mfdc_reset(DEVICE *mfdc_dev); static t_stat mfdc_attach(UNIT *uptr, char *cptr); @@ -237,7 +234,6 @@ t_stat mfdc_reset(DEVICE *dptr) /* Attach routine */ t_stat mfdc_attach(UNIT *uptr, char *cptr) { - char header[4]; t_stat r; unsigned int i = 0; @@ -258,16 +254,10 @@ t_stat mfdc_attach(UNIT *uptr, char *cptr) uptr->u3 = IMAGE_TYPE_DSK; if(uptr->capac > 0) { - fgets(header, 4, uptr->fileref); - if(!strcmp(header, "IMD")) { - uptr->u3 = IMAGE_TYPE_IMD; - } else if(!strcmp(header, "CPT")) { - printf("CPT images not yet supported\n"); - uptr->u3 = IMAGE_TYPE_CPT; + r = assignDiskType(uptr); + if (r != SCPE_OK) { mfdc_detach(uptr); - return SCPE_OPENERR; - } else { - uptr->u3 = IMAGE_TYPE_DSK; + return r; } } @@ -386,6 +376,7 @@ static uint8 MFDC_Read(const uint32 Addr) { uint8 cData; MFDC_DRIVE_INFO *pDrive; + int32 rtn; cData = 0x00; @@ -482,10 +473,13 @@ static uint8 MFDC_Read(const uint32 Addr) } else { sim_fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET); #ifdef USE_VGI - fread(sdata.raw, MFDC_SECTOR_LEN, 1, (pDrive->uptr)->fileref); + rtn = sim_fread(sdata.raw, 1, MFDC_SECTOR_LEN, (pDrive->uptr)->fileref); + if (rtn != MFDC_SECTOR_LEN) #else - fread(sdata.u.data, 256, 1, (pDrive->uptr)->fileref); + rtn = sim_fread(sdata.u.data, 1, 256, (pDrive->uptr)->fileref); + if (rtn != 256) #endif /* USE_VGI */ + printf("%s: sim_fread error. Result = %d." NLP, __FUNCTION__, rtn); } break; case IMAGE_TYPE_CPT: @@ -603,9 +597,9 @@ static uint8 MFDC_Write(const uint32 Addr, uint8 cData) } else { sim_fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET); #ifdef USE_VGI - fwrite(sdata.raw, MFDC_SECTOR_LEN, 1, (pDrive->uptr)->fileref); + sim_fwrite(sdata.raw, 1, MFDC_SECTOR_LEN, (pDrive->uptr)->fileref); #else - fwrite(sdata.u.data, 256, 1, (pDrive->uptr)->fileref); + sim_fwrite(sdata.u.data, 1, 256, (pDrive->uptr)->fileref); #endif /* USE_VGI */ } break; diff --git a/AltairZ80/n8vem.c b/AltairZ80/n8vem.c index 7f34c383..c1dbdbe2 100644 --- a/AltairZ80/n8vem.c +++ b/AltairZ80/n8vem.c @@ -165,7 +165,7 @@ static t_stat n8vem_reset(DEVICE *dptr) { PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Reset." NLP)); + TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Reset.\n")); if(dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */ sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &n8vemdev, TRUE); @@ -196,7 +196,7 @@ static t_stat n8vem_reset(DEVICE *dptr) static t_stat n8vem_boot(int32 unitno, DEVICE *dptr) { - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Boot." NLP)); + TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Boot.\n")); /* Clear the RAM and ROM mapping registers */ n8vem_info->mpcl_ram = 0; @@ -211,7 +211,7 @@ static t_stat n8vem_boot(int32 unitno, DEVICE *dptr) static t_stat n8vem_attach(UNIT *uptr, char *cptr) { t_stat r; - int32 i = 0; + int32 i = 0, rtn; i = find_unit_index(uptr); @@ -226,7 +226,7 @@ static t_stat n8vem_attach(UNIT *uptr, char *cptr) /* Determine length of this disk */ uptr->capac = sim_fsize(uptr->fileref); - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Attach %s." NLP, i == 0 ? "ROM" : "RAM")); + TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Attach %s.\n", i == 0 ? "ROM" : "RAM")); if(i == 0) { /* Attaching ROM */ n8vem_info->rom_attached = TRUE; @@ -239,8 +239,10 @@ static t_stat n8vem_attach(UNIT *uptr, char *cptr) if (uptr->capac > N8VEM_ROM_SIZE) uptr->capac = N8VEM_ROM_SIZE; - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Reading %d bytes into ROM.\n", uptr->capac)); - fread((void *)(n8vem_info->rom), uptr->capac, 1, uptr->fileref); + rtn = fread((void *)(n8vem_info->rom), uptr->capac, 1, uptr->fileref); + TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Reading %d bytes into ROM." + " Result = %ssuccessful.\n", + uptr->capac, rtn == 1 ? "" : "not ")); } } else { /* attaching RAM */ /* Erase RAM */ @@ -251,8 +253,10 @@ static t_stat n8vem_attach(UNIT *uptr, char *cptr) if(uptr->capac > N8VEM_RAM_SIZE) uptr->capac = N8VEM_RAM_SIZE; - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Reading %d bytes into RAM.\n", uptr->capac)); - fread((void *)(n8vem_info->ram), uptr->capac, 1, uptr->fileref); + rtn = fread((void *)(n8vem_info->ram), uptr->capac, 1, uptr->fileref); + TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Reading %d bytes into RAM." + " Result = %ssuccessful.\n", + uptr->capac, rtn == 1 ? "" : "not ")); } } return r; @@ -270,7 +274,7 @@ static t_stat n8vem_detach(UNIT *uptr) return (SCPE_IERR); } - TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Detach %s." NLP, i == 0 ? "ROM" : "RAM")); + TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Detach %s.\n", i == 0 ? "ROM" : "RAM")); /* rewind to the beginning of the file. */ sim_fseek(uptr->fileref, 0, SEEK_SET); diff --git a/AltairZ80/s100_disk2.c b/AltairZ80/s100_disk2.c index a0cdc5fb..1af9a918 100644 --- a/AltairZ80/s100_disk2.c +++ b/AltairZ80/s100_disk2.c @@ -132,9 +132,6 @@ extern void raise_ss1_interrupt(uint8 intnum); #define UNIT_V_DISK2_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ #define UNIT_DISK2_VERBOSE (1 << UNIT_V_DISK2_VERBOSE) #define DISK2_CAPACITY (C20MB_NTRACKS*C20MB_NHEADS*C20MB_NSECTORS*C20MB_SECTSIZE) /* Default Disk Capacity */ -#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */ -#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */ -#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */ static t_stat disk2_reset(DEVICE *disk2_dev); static t_stat disk2_attach(UNIT *uptr, char *cptr); @@ -226,7 +223,6 @@ static t_stat disk2_attach(UNIT *uptr, char *cptr) { t_stat r = SCPE_OK; DISK2_DRIVE_INFO *pDrive; - char header[4]; int i = 0; i = find_unit_index(uptr); @@ -260,16 +256,10 @@ static t_stat disk2_attach(UNIT *uptr, char *cptr) uptr->u3 = IMAGE_TYPE_DSK; if(uptr->capac > 0) { - fgets(header, 4, uptr->fileref); - if(!strcmp(header, "IMD")) { - uptr->u3 = IMAGE_TYPE_IMD; - } else if(!strcmp(header, "CPT")) { - printf("CPT images not yet supported\n"); - uptr->u3 = IMAGE_TYPE_CPT; + r = assignDiskType(uptr); + if (r != SCPE_OK) { disk2_detach(uptr); - return SCPE_OPENERR; - } else { - uptr->u3 = IMAGE_TYPE_DSK; + return r; } } @@ -395,6 +385,7 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) uint8 i; long file_offset; DISK2_DRIVE_INFO *pDrive; + size_t rtn; pDrive = &disk2_info->drive[disk2_info->sel_drive]; @@ -457,7 +448,10 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) sim_fseek((pDrive->uptr)->fileref, track_offset + (disk2_info->head_sel * pDrive->nsectors * (pDrive->sectsize + 3)), SEEK_SET); for(i=0;insectors;i++) { /* Read sector */ - fread(sdata.raw, (pDrive->sectsize + 3), 1, (pDrive->uptr)->fileref); + rtn = sim_fread(sdata.raw, 1, (pDrive->sectsize + 3), (pDrive->uptr)->fileref); + if (rtn != (size_t)(pDrive->sectsize + 3)) { + TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " READ_DATA: sim_fread error." NLP, PCX)); + } if(sdata.u.header[2] == disk2_info->sector) { if(sdata.u.header[0] != disk2_info->cyl) { /*pDrive->track) { */ printf("DISK2: " ADDRESS_FORMAT " READ_DATA Incorrect header: track" NLP, PCX); @@ -497,7 +491,10 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) for(i=0;insectors;i++) { /* Read sector */ file_offset = ftell((pDrive->uptr)->fileref); - fread(sdata.raw, 3, 1, (pDrive->uptr)->fileref); + rtn = sim_fread(sdata.raw, 1, 3, (pDrive->uptr)->fileref); + if (rtn != 3) { + TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " WRITE_DATA: sim_fread error." NLP, PCX)); + } if(sdata.u.header[2] == disk2_info->sector) { if(sdata.u.header[0] != disk2_info->cyl) { printf("DISK2: " ADDRESS_FORMAT " WRITE_DATA Incorrect header: track" NLP, PCX); @@ -510,10 +507,13 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) selchan_dma(sdata.u.data, pDrive->sectsize); sim_fseek((pDrive->uptr)->fileref, file_offset+3, SEEK_SET); - fwrite(sdata.u.data, (pDrive->sectsize), 1, (pDrive->uptr)->fileref); + sim_fwrite(sdata.u.data, 1, (pDrive->sectsize), (pDrive->uptr)->fileref); break; } - fread(sdata.raw, pDrive->sectsize, 1, (pDrive->uptr)->fileref); + rtn = sim_fread(sdata.raw, 1, pDrive->sectsize, (pDrive->uptr)->fileref); + if (rtn != (size_t)(pDrive->sectsize)) { + TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " WRITE_DATA: sim_fread error." NLP, PCX)); + } if(i == pDrive->nsectors) { printf("DISK2: " ADDRESS_FORMAT " Sector not found" NLP, PCX); disk2_info->timeout = 1; @@ -532,7 +532,7 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) i = disk2_info->hdr_sector; selchan_dma(sdata.raw, 3); sim_fseek((pDrive->uptr)->fileref, track_offset + (disk2_info->head_sel * (pDrive->sectsize + 3) * pDrive->nsectors) + (i * (pDrive->sectsize + 3)), SEEK_SET); - fwrite(sdata.raw, 3, 1, (pDrive->uptr)->fileref); + sim_fwrite(sdata.raw, 1, 3, (pDrive->uptr)->fileref); disk2_info->hdr_sector++; if(disk2_info->hdr_sector >= pDrive->nsectors) { @@ -544,7 +544,10 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData) track_offset = pDrive->track * pDrive->nheads * pDrive->nsectors * (pDrive->sectsize + 3); TRACE_PRINT(CMD_MSG, ("DISK2: " ADDRESS_FORMAT " READ_HEADER Command" NLP, PCX)); sim_fseek((pDrive->uptr)->fileref, track_offset + (disk2_info->head_sel * pDrive->nsectors * (pDrive->sectsize + 3)), SEEK_SET); - fread(sdata.raw, 3, 1, (pDrive->uptr)->fileref); + rtn = sim_fread(sdata.raw, 1, 3, (pDrive->uptr)->fileref); + if (rtn != 3) { + TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " READ_HEADER: sim_fread error." NLP, PCX)); + } selchan_dma(sdata.raw, 3); break; diff --git a/AltairZ80/s100_disk3.c b/AltairZ80/s100_disk3.c index 6602f9cb..9d578a83 100644 --- a/AltairZ80/s100_disk3.c +++ b/AltairZ80/s100_disk3.c @@ -193,9 +193,6 @@ extern uint8 GetByteDMA(const uint32 Addr); #define UNIT_V_DISK3_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ #define UNIT_DISK3_VERBOSE (1 << UNIT_V_DISK3_VERBOSE) #define DISK3_CAPACITY (C20MB_NTRACKS*C20MB_NHEADS*C20MB_NSECTORS*C20MB_SECTSIZE) /* Default Disk Capacity */ -#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */ -#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */ -#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */ static t_stat disk3_reset(DEVICE *disk3_dev); static t_stat disk3_attach(UNIT *uptr, char *cptr); @@ -293,8 +290,7 @@ static t_stat disk3_attach(UNIT *uptr, char *cptr) { t_stat r = SCPE_OK; DISK3_DRIVE_INFO *pDrive; - char header[4]; - unsigned int i = 0; + int i = 0; i = find_unit_index(uptr); if (i == -1) { @@ -326,16 +322,10 @@ static t_stat disk3_attach(UNIT *uptr, char *cptr) uptr->u3 = IMAGE_TYPE_DSK; if(uptr->capac > 0) { - fgets(header, 4, uptr->fileref); - if(!strcmp(header, "IMD")) { - uptr->u3 = IMAGE_TYPE_IMD; - } else if(!strcmp(header, "CPT")) { - printf("CPT images not yet supported\n"); - uptr->u3 = IMAGE_TYPE_CPT; + r = assignDiskType(uptr); + if (r != SCPE_OK) { disk3_detach(uptr); - return SCPE_OPENERR; - } else { - uptr->u3 = IMAGE_TYPE_DSK; + return r; } } @@ -517,6 +507,7 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData) uint32 file_offset; uint32 xfr_count = 0; uint8 *dataBuffer; + size_t rtn; if(disk3_info->mode == DISK3_MODE_ABS) { TRACE_PRINT(ERROR_MSG, ("DISK3: Absolute addressing not supported." NLP)); @@ -539,16 +530,19 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData) sim_fseek((pDrive->uptr)->fileref, file_offset, SEEK_SET); if(disk3_info->iopb[DISK3_IOPB_ARG1] == 1) { /* Read */ - TRACE_PRINT(RD_DATA_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " READ @0x%05x T:%04d/S:%04d/#:%d" NLP, - disk3_info->sel_drive, - PCX, - disk3_info->dma_addr, - pDrive->cur_track, - pDrive->cur_sect, - pDrive->xfr_nsects - )); + rtn = sim_fread(dataBuffer, 1, xfr_len, (pDrive->uptr)->fileref); + + TRACE_PRINT(RD_DATA_MSG, + ("DISK3[%d]: " ADDRESS_FORMAT " READ @0x%05x T:%04d/S:%04d/#:%d %s" NLP, + disk3_info->sel_drive, + PCX, + disk3_info->dma_addr, + pDrive->cur_track, + pDrive->cur_sect, + pDrive->xfr_nsects, + rtn == (size_t)xfr_len ? "OK" : "NOK" + )); - fread(dataBuffer, xfr_len, 1, (pDrive->uptr)->fileref); /* Perform DMA Transfer */ for(xfr_count = 0;xfr_count < xfr_len; xfr_count++) { @@ -569,7 +563,7 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData) dataBuffer[xfr_count] = GetByteDMA(disk3_info->dma_addr + xfr_count); } - fwrite(dataBuffer, xfr_len, 1, (pDrive->uptr)->fileref); + sim_fwrite(dataBuffer, 1, xfr_len, (pDrive->uptr)->fileref); } free(dataBuffer); @@ -618,7 +612,7 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData) memset(fmtBuffer, disk3_info->iopb[DISK3_IOPB_ARG2], data_len); sim_fseek((pDrive->uptr)->fileref, file_offset, SEEK_SET); - fwrite(fmtBuffer, data_len, 1, (pDrive->uptr)->fileref); + sim_fwrite(fmtBuffer, 1, data_len, (pDrive->uptr)->fileref); free(fmtBuffer); diff --git a/AltairZ80/s100_fif.c b/AltairZ80/s100_fif.c index 0b7e8b1c..913de8e0 100644 --- a/AltairZ80/s100_fif.c +++ b/AltairZ80/s100_fif.c @@ -2,7 +2,7 @@ IMSAI FIF Disk Controller by Ernie Price - Based on altairz80_dsk.c, Copyright (c) 2002-2008, Peter Schorn + Based on altairz80_dsk.c, Copyright (c) 2002-2010, Peter Schorn Plug-n-Play added by Howard M. Harte @@ -197,6 +197,7 @@ static int DoDiskOperation(desc_t *dsc, uint8 val) addr; FILE *cpx; UNIT *uptr; + int32 rtn; #if 0 printf("%02x %02x %02x %02x %02x %02x %02x %02x \n", @@ -242,14 +243,19 @@ static int DoDiskOperation(desc_t *dsc, uint8 val) /* write a track worth of sectors */ for (kt=0; kt < SPT; kt++) { - fwrite(blanksec, 1, sizeof(blanksec), cpx); + sim_fwrite(blanksec, 1, sizeof(blanksec), cpx); } break; case READ_SEC: addr = (dsc->track * SPT) + dsc->sector - 1; sim_fseek(cpx, addr * SEC_SZ, SEEK_SET); - fread(blanksec, 1, SEC_SZ, cpx); + rtn = sim_fread(blanksec, 1, SEC_SZ, cpx); + if ( (rtn != SEC_SZ) && (current_disk_flags & UNIT_DSK_VERBOSE) && + (warnAttached[current_disk] < warnLevelDSK) ) { + warnAttached[current_disk]++; + printf("FIF%i: " ADDRESS_FORMAT " sim_fread error." NLP, current_disk, PCX); + } addr = dsc->addr_l + (dsc->addr_h << 8); /* no assumption on endianness */ for (kt = 0; kt < SEC_SZ; kt++) { PutBYTEWrapper(addr++, blanksec[kt]); @@ -263,7 +269,7 @@ static int DoDiskOperation(desc_t *dsc, uint8 val) for (kt = 0; kt < SEC_SZ; kt++) { blanksec[kt] = GetBYTEWrapper(addr++); } - fwrite(blanksec, 1, SEC_SZ, cpx); + sim_fwrite(blanksec, 1, SEC_SZ, cpx); break; default: @@ -447,7 +453,7 @@ uint8 FTP(int32 BC, int32 DE) case 20: memset(temp, 0x1a, SEC_SZ); - retval = fread(temp, 1, SEC_SZ, myfile) ? 0 : 1; + retval = sim_fread(temp, 1, SEC_SZ, myfile) ? 0 : 1; xfero( DE, temp, SEC_SZ); if (retval) { diff --git a/AltairZ80/s100_hdc1001.c b/AltairZ80/s100_hdc1001.c index 75cf1fd3..a5afa7fb 100644 --- a/AltairZ80/s100_hdc1001.c +++ b/AltairZ80/s100_hdc1001.c @@ -112,9 +112,6 @@ extern uint8 GetBYTEWrapper(const uint32 Addr); #define UNIT_V_HDC1001_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ #define UNIT_HDC1001_VERBOSE (1 << UNIT_V_HDC1001_VERBOSE) #define HDC1001_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */ -#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */ -#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */ -#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */ static t_stat hdc1001_reset(DEVICE *hdc1001_dev); static t_stat hdc1001_attach(UNIT *uptr, char *cptr); @@ -137,13 +134,13 @@ static REG hdc1001_reg[] = { }; static MTAB hdc1001_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL }, - { UNIT_HDC1001_WLK, 0, "WRTENB", "WRTENB", NULL }, - { UNIT_HDC1001_WLK, UNIT_HDC1001_WLK, "WRTLCK", "WRTLCK", NULL }, + { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL }, + { UNIT_HDC1001_WLK, 0, "WRTENB", "WRTENB", NULL }, + { UNIT_HDC1001_WLK, UNIT_HDC1001_WLK, "WRTLCK", "WRTLCK", NULL }, /* quiet, no warning messages */ - { UNIT_HDC1001_VERBOSE, 0, "QUIET", "QUIET", NULL }, + { UNIT_HDC1001_VERBOSE, 0, "QUIET", "QUIET", NULL }, /* verbose, show warning messages */ - { UNIT_HDC1001_VERBOSE, UNIT_HDC1001_VERBOSE, "VERBOSE", "VERBOSE", NULL }, + { UNIT_HDC1001_VERBOSE, UNIT_HDC1001_VERBOSE, "VERBOSE", "VERBOSE", NULL }, { 0 } }; @@ -198,8 +195,7 @@ static t_stat hdc1001_attach(UNIT *uptr, char *cptr) { t_stat r = SCPE_OK; HDC1001_DRIVE_INFO *pDrive; - char header[4]; - unsigned int i = 0; + int i = 0; i = find_unit_index(uptr); if (i == -1) { @@ -231,16 +227,10 @@ static t_stat hdc1001_attach(UNIT *uptr, char *cptr) uptr->u3 = IMAGE_TYPE_DSK; if(uptr->capac > 0) { - fgets(header, 4, uptr->fileref); - if(!strcmp(header, "IMD")) { - uptr->u3 = IMAGE_TYPE_IMD; - } else if(!strcmp(header, "CPT")) { - printf("CPT images not yet supported\n"); - uptr->u3 = IMAGE_TYPE_CPT; + r = assignDiskType(uptr); + if (r != SCPE_OK) { hdc1001_detach(uptr); - return SCPE_OPENERR; - } else { - uptr->u3 = IMAGE_TYPE_DSK; + return r; } } @@ -372,7 +362,6 @@ static uint8 HDC1001_Write(const uint32 Addr, uint8 cData) switch(Addr & 0x07) { case TF_SDH: hdc1001_info->sel_drive = (cData >> 3) & 0x03; - pDrive = &hdc1001_info->drive[hdc1001_info->sel_drive]; case TF_DATA: case TF_ERROR: case TF_SECNT: @@ -393,14 +382,10 @@ static uint8 HDC1001_Write(const uint32 Addr, uint8 cData) hdc1001_info->taskfile[TF_SDH] & 0x07, hdc1001_info->taskfile[TF_SECNO], pDrive->xfr_nsects)); - break; default: break; } - - - return 0; } @@ -541,7 +526,7 @@ static uint8 HDC1001_Read(const uint32 Addr) pDrive->xfr_nsects )); - fread(dataBuffer, xfr_len, 1, (pDrive->uptr)->fileref); + sim_fread(dataBuffer, 1, xfr_len, (pDrive->uptr)->fileref); /* Perform DMA Transfer */ for(xfr_count = 0;xfr_count < xfr_len; xfr_count++) { @@ -562,7 +547,7 @@ static uint8 HDC1001_Read(const uint32 Addr) dataBuffer[xfr_count] = GetBYTEWrapper(hdc1001_info->dma_addr + xfr_count); } - fwrite(dataBuffer, xfr_len, 1, (pDrive->uptr)->fileref); + sim_fwrite(dataBuffer, 1, xfr_len, (pDrive->uptr)->fileref); } free(dataBuffer); @@ -593,7 +578,7 @@ static uint8 HDC1001_Read(const uint32 Addr) memset(fmtBuffer, hdc1001_info->iopb[4], data_len); sim_fseek((pDrive->uptr)->fileref, file_offset, SEEK_SET); - fwrite(fmtBuffer, data_len, 1, (pDrive->uptr)->fileref); + sim_fwrite(fmtBuffer, 1, data_len, (pDrive->uptr)->fileref); free(fmtBuffer); diff --git a/AltairZ80/s100_mdsad.c b/AltairZ80/s100_mdsad.c index 7e29d069..639df98c 100644 --- a/AltairZ80/s100_mdsad.c +++ b/AltairZ80/s100_mdsad.c @@ -42,6 +42,7 @@ /*#define DBG_MSG*/ #include "altairz80_defs.h" +#include "sim_imd.h" #if defined (_WIN32) #include @@ -160,8 +161,6 @@ static SECTOR_FORMAT sdata; #define UNIT_V_MDSAD_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ #define UNIT_MDSAD_VERBOSE (1 << UNIT_V_MDSAD_VERBOSE) #define MDSAD_CAPACITY (70*10*MDSAD_SECTOR_LEN) /* Default North Star Disk Capacity */ -#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */ -#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */ /* MDS-AD Controller Subcases */ #define MDSAD_READ_ROM 0 @@ -325,8 +324,8 @@ t_stat mdsad_attach(UNIT *uptr, char *cptr) uptr->u3 = IMAGE_TYPE_DSK; if(uptr->capac > 0) { - fgets(header, 4, uptr->fileref); - if(!strcmp(header, "CPT")) { + char *rtn = fgets(header, 4, uptr->fileref); + if((rtn != NULL) && (strncmp(header, "CPT", 3) == 0)) { printf("CPT images not yet supported\n"); uptr->u3 = IMAGE_TYPE_CPT; mdsad_detach(uptr); @@ -338,7 +337,7 @@ t_stat mdsad_attach(UNIT *uptr, char *cptr) if (uptr->flags & UNIT_MDSAD_VERBOSE) printf("MDSAD%d, attached to '%s', type=%s, len=%d\n", i, cptr, - uptr->u3 == uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK", + uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK", uptr->capac); return SCPE_OK; @@ -450,6 +449,7 @@ static uint8 MDSAD_Read(const uint32 Addr) uint8 cData; uint8 ds; MDSAD_DRIVE_INFO *pDrive; + int32 rtn; cData = 0x00; @@ -502,7 +502,7 @@ static uint8 MDSAD_Read(const uint32 Addr) printf(".fileref is NULL!" NLP); } else { sim_fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET); - fwrite(sdata.u.data, MDSAD_SECTOR_LEN, 1, + sim_fwrite(sdata.u.data, 1, MDSAD_SECTOR_LEN, (pDrive->uptr)->fileref); } break; @@ -735,8 +735,11 @@ static uint8 MDSAD_Read(const uint32 Addr) } else { sim_fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET); - fread(&sdata.u.data[0], MDSAD_SECTOR_LEN, - 1, (pDrive->uptr)->fileref); + rtn = sim_fread(&sdata.u.data[0], 1, MDSAD_SECTOR_LEN, + (pDrive->uptr)->fileref); + if (rtn != MDSAD_SECTOR_LEN) { + TRACE_PRINT(ERROR_MSG, ("MDSAD: " ADDRESS_FORMAT " READ: sim_fread error." NLP, PCX)); + } } break; case IMAGE_TYPE_CPT: diff --git a/AltairZ80/sim_imd.c b/AltairZ80/sim_imd.c index c487fa76..3d746d93 100644 --- a/AltairZ80/sim_imd.c +++ b/AltairZ80/sim_imd.c @@ -63,8 +63,11 @@ #endif /* use NLP for new line printing while the simulation is running */ -#define UNIX_PLATFORM (defined (__linux) || defined(__NetBSD__) \ -|| defined (__OpenBSD__) || defined (__FreeBSD__) || defined (__APPLE__)) +#if defined (__linux) || defined(__NetBSD__) || defined (__OpenBSD__) || defined (__FreeBSD__) || defined (__APPLE__) +#define UNIX_PLATFORM 1 +#else +#define UNIX_PLATFORM 0 +#endif #if UNIX_PLATFORM #define NLP "\r\n" @@ -72,7 +75,7 @@ #define NLP "\n" #endif -#if defined (__MWERKS__) && defined (macintosh) +#if (defined (__MWERKS__) && defined (macintosh)) || defined(__DECC) #define __FUNCTION__ __FILE__ #endif @@ -174,7 +177,7 @@ static t_stat diskParse(DISK_INFO *myDisk, uint32 isVerbose) do { DBG_PRINT(("start of track %d at file offset %ld" NLP, myDisk->ntracks, ftell(myDisk->file))); - fread(&imd, 1, 5, myDisk->file); + sim_fread(&imd, 1, 5, myDisk->file); if (feof(myDisk->file)) break; sectorSize = 128 << imd.sectsize; @@ -197,7 +200,10 @@ static t_stat diskParse(DISK_INFO *myDisk, uint32 isVerbose) myDisk->track[imd.cyl][imd.head].nsects = imd.nsects; myDisk->track[imd.cyl][imd.head].sectsize = sectorSize; - fread(sectorMap, 1, imd.nsects, myDisk->file); + if (sim_fread(sectorMap, 1, imd.nsects, myDisk->file) != imd.nsects) { + printf("SIM_IMD: Corrupt file [Sector Map]." NLP); + return (SCPE_OPENERR); + } myDisk->track[imd.cyl][imd.head].start_sector = imd.nsects; DBG_PRINT(("\tSector Map: ")); for(i=0;itrack[imd.cyl][imd.head].start_sector)); if(sectorHeadwithFlags & IMD_FLAG_SECT_HEAD_MAP) { - fread(sectorHeadMap, 1, imd.nsects, myDisk->file); + if (sim_fread(sectorHeadMap, 1, imd.nsects, myDisk->file) != imd.nsects) { + printf("SIM_IMD: Corrupt file [Sector Head Map]." NLP); + return (SCPE_OPENERR); + } DBG_PRINT(("\tSector Head Map: ")); for(i=0;ifile); + if (sim_fread(sectorCylMap, 1, imd.nsects, myDisk->file) != imd.nsects) { + printf("SIM_IMD: Corrupt file [Sector Cyl Map]." NLP); + return (SCPE_OPENERR); + } DBG_PRINT(("\tSector Cyl Map: ")); for(i=0;itrack[Cyl][Head].sectsize, myDisk->file); + if (sim_fread(buf, 1, myDisk->track[Cyl][Head].sectsize, myDisk->file) != myDisk->track[Cyl][Head].sectsize) { + printf("SIM_IMD[%s]: sim_fread error for SECT_RECORD_NORM_DAM." NLP, __FUNCTION__); + } *readlen = myDisk->track[Cyl][Head].sectsize; break; case SECT_RECORD_NORM_COMP_ERR: /* Compressed Normal Data */ @@ -641,7 +655,7 @@ t_stat sectWrite(DISK_INFO *myDisk, } fputc(sectRecordType, myDisk->file); - fwrite(buf, 1, myDisk->track[Cyl][Head].sectsize, myDisk->file); + sim_fwrite(buf, 1, myDisk->track[Cyl][Head].sectsize, myDisk->file); *writelen = myDisk->track[Cyl][Head].sectsize; return(SCPE_OK); @@ -729,9 +743,9 @@ t_stat trackWrite(DISK_INFO *myDisk, track_header.sectsize = sectorLen; /* Forward to end of the file, write track header and sector map. */ - fseek(myDisk->file, 0, SEEK_END); - fwrite(&track_header, sizeof(IMD_HEADER), 1, fileref); - fwrite(sectorMap, 1, numSectors, fileref); + sim_fseek(myDisk->file, 0, SEEK_END); + sim_fwrite(&track_header, 1, sizeof(IMD_HEADER), fileref); + sim_fwrite(sectorMap, 1, numSectors, fileref); /* Compute data length, and fill a sector buffer with the * sector record type as the first byte, and fill the sector @@ -744,7 +758,7 @@ t_stat trackWrite(DISK_INFO *myDisk, /* For each sector on the track, write the record type and sector data. */ for(i=0;ifileref) == NULL) + uptr->u3 = IMAGE_TYPE_DSK; + else if (strncmp(header, "IMD", 3) == 0) + uptr->u3 = IMAGE_TYPE_IMD; + else if(strncmp(header, "CPT", 3) == 0) { + printf("CPT images not yet supported.\n"); + uptr->u3 = IMAGE_TYPE_CPT; + result = SCPE_OPENERR; + } + else + uptr->u3 = IMAGE_TYPE_DSK; + return result; +} + diff --git a/AltairZ80/sim_imd.h b/AltairZ80/sim_imd.h index e90dc394..b6989111 100644 --- a/AltairZ80/sim_imd.h +++ b/AltairZ80/sim_imd.h @@ -85,6 +85,10 @@ typedef struct { #define IMD_MODE_FM(x) (x <= IMD_MODE_250K_FM) #define IMD_MODE_MFM(x) (x >= IMD_MODE_500K_MFM) +#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */ +#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */ +#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */ + typedef struct { uint8 mode; uint8 nsects; @@ -121,3 +125,4 @@ extern t_stat trackWrite(DISK_INFO *myDisk, uint8 mode, uint8 fillbyte, uint32 *flags); +extern t_stat assignDiskType(UNIT *uptr); diff --git a/AltairZ80/vfdhd.c b/AltairZ80/vfdhd.c index c0173e10..df021b87 100644 --- a/AltairZ80/vfdhd.c +++ b/AltairZ80/vfdhd.c @@ -146,9 +146,6 @@ extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_typ #define UNIT_V_VFDHD_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ #define UNIT_VFDHD_VERBOSE (1 << UNIT_V_VFDHD_VERBOSE) #define VFDHD_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */ -#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */ -#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */ -#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */ static t_stat vfdhd_reset(DEVICE *vfdhd_dev); static t_stat vfdhd_attach(UNIT *uptr, char *cptr); @@ -230,7 +227,6 @@ static t_stat vfdhd_reset(DEVICE *dptr) /* Attach routine */ static t_stat vfdhd_attach(UNIT *uptr, char *cptr) { - char header[4]; t_stat r; unsigned int i = 0; @@ -252,16 +248,10 @@ static t_stat vfdhd_attach(UNIT *uptr, char *cptr) } if(uptr->capac > 0) { - fgets(header, 4, uptr->fileref); - if(!strcmp(header, "IMD")) { - uptr->u3 = IMAGE_TYPE_IMD; - } else if(!strcmp(header, "CPT")) { - printf("CPT images not yet supported\n"); - uptr->u3 = IMAGE_TYPE_CPT; + r = assignDiskType(uptr); + if (r != SCPE_OK) { vfdhd_detach(uptr); - return SCPE_OPENERR; - } else { - uptr->u3 = IMAGE_TYPE_DSK; + return r; } } else { /* creating file, must be DSK format. */ @@ -542,6 +532,7 @@ static void VFDHD_Command(void) uint32 sec_offset; uint32 flags; + int32 rtn; pDrive = &(vfdhd_info->drive[vfdhd_info->sel_drive]); @@ -604,7 +595,10 @@ static void VFDHD_Command(void) printf(".fileref is NULL!" NLP); } else { sim_fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET); - fread(&sdata.u.sync, 274, /*VFDHD_SECTOR_LEN,*/ 1, (pDrive->uptr)->fileref); + rtn = sim_fread(&sdata.u.sync, 1, 274, /*VFDHD_SECTOR_LEN,*/ (pDrive->uptr)->fileref); + if (rtn != 274) { + TRACE_PRINT(ERROR_MSG, ("VFDHD: " ADDRESS_FORMAT " READ: sim_fread error." NLP, PCX)); + } memset(&sdata.u.preamble, 0, 40); memset(&sdata.u.ecc, 0, 5); /* Clear out the ECC and ECC Valid bytes */ @@ -670,9 +664,9 @@ static void VFDHD_Command(void) vfdhd_info->sector)); sim_fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET); #ifdef USE_VGI - fwrite(&sdata.u.sync, VFDHD_SECTOR_LEN, 1, (pDrive->uptr)->fileref); + sim_fwrite(&sdata.u.sync, 1, VFDHD_SECTOR_LEN, (pDrive->uptr)->fileref); #else - fwrite(sdata.u.data, 256, 1, (pDrive->uptr)->fileref); + sim_fwrite(sdata.u.data, 1, 256, (pDrive->uptr)->fileref); #endif /* USE_VGI */ } break; diff --git a/AltairZ80/wd179x.c b/AltairZ80/wd179x.c index dc1621fb..e0f77454 100644 --- a/AltairZ80/wd179x.c +++ b/AltairZ80/wd179x.c @@ -152,6 +152,7 @@ extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc); extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc); extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, int32 (*routine)(const int32, const int32, const int32), uint8 unmap); +extern int32 find_unit_index (UNIT *uptr); t_stat wd179x_svc (UNIT *uptr); @@ -165,9 +166,6 @@ extern uint8 GetBYTEWrapper(const uint32 Addr); #define UNIT_WD179X_VERBOSE (1 << UNIT_V_WD179X_VERBOSE) #define WD179X_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */ #define WD179X_CAPACITY_SSSD (77*1*26*128) /* Single-sided Single Density IBM Diskette1 */ -#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */ -#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */ -#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */ /* Write Track (format) Statemachine states */ #define FMT_GAP1 1 @@ -197,7 +195,6 @@ extern uint8 GetBYTEWrapper(const uint32 Addr); static int32 wd179xdev(const int32 port, const int32 io, const int32 data); static t_stat wd179x_reset(DEVICE *dptr); -int32 find_unit_index (UNIT *uptr); uint8 floorlog2(unsigned int n); WD179X_INFO wd179x_info_data = { { 0x0, 0, 0x30, 4 } }; @@ -278,8 +275,6 @@ static t_stat wd179x_reset(DEVICE *dptr) return SCPE_OK; } -extern int32 find_unit_index (UNIT *uptr); - void wd179x_external_restore(void) { WD179X_DRIVE_INFO *pDrive; @@ -330,8 +325,8 @@ t_stat wd179x_attach(UNIT *uptr, char *cptr) wd179x_info->drive[i].ready = 0; if(uptr->capac > 0) { - fgets(header, 4, uptr->fileref); - if(strncmp(header, "IMD", 3)) { + char *rtn = fgets(header, 4, uptr->fileref); + if ((rtn != NULL) && strncmp(header, "IMD", 3)) { printf("WD179X: Only IMD disk images are supported\n"); wd179x_info->drive[i].uptr = NULL; return SCPE_OPENERR; diff --git a/H316/h316_cpu.c b/H316/h316_cpu.c index d336ee4a..4f3d64ed 100644 --- a/H316/h316_cpu.c +++ b/H316/h316_cpu.c @@ -1,6 +1,6 @@ /* h316_cpu.c: Honeywell 316/516 CPU simulator - Copyright (c) 1999-2008, Robert M. Supnik + Copyright (c) 1999-2010, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ cpu H316/H516 CPU + 10-Jan-10 RMS Fixed bugs in LDX, STX introduced in 3.8-1 (from Theo Engel) 28-Apr-07 RMS Removed clock initialization 03-Apr-06 RMS Fixed bugs in LLL, LRL (from Theo Engel) 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) @@ -614,13 +615,13 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ break; case 015: case 055: /* STX */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if (reason = Ea (MB & ~IDX, &Y)) /* eff addr */ break; Write (Y, XR); /* store XR */ break; case 035: case 075: /* LDX */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if (reason = Ea (MB & ~IDX, &Y)) /* eff addr */ break; XR = Read (Y); /* load XR */ break; diff --git a/HP2100/hp2100_cpu.h b/HP2100/hp2100_cpu.h index 707c4af0..4b1f8e94 100644 --- a/HP2100/hp2100_cpu.h +++ b/HP2100/hp2100_cpu.h @@ -1,6 +1,6 @@ /* hp2100_cpu.h: HP 2100 CPU definitions - Copyright (c) 2005-2008, Robert M. Supnik + Copyright (c) 2005-2010, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 03-Jan-10 RMS Changed declarations of mp_control, mp_mefvv, for VMS compiler 15-Jul-08 JDB Rearranged declarations with hp2100_cpu.c and hp2100_defs.h 26-Jun-08 JDB Added mp_control to CPU state externals 24-Apr-08 JDB Added calc_defer() prototype @@ -285,10 +286,10 @@ extern uint32 dms_enb; extern uint32 dms_ump; extern uint32 dms_sr; extern uint32 dms_vr; -extern uint32 mp_control; +extern FLIP_FLOP mp_control; extern uint32 mp_fence; extern uint32 mp_viol; -extern uint32 mp_mevff; +extern FLIP_FLOP mp_mevff; extern uint32 iop_sp; extern t_bool ion_defer; extern uint32 intaddr; diff --git a/I1401/i1401_cd.c b/I1401/i1401_cd.c index eea3b5b2..f1912cf7 100644 --- a/I1401/i1401_cd.c +++ b/I1401/i1401_cd.c @@ -1,6 +1,6 @@ /* i1401_cd.c: IBM 1402 card reader/punch - Copyright (c) 1993-2008, Robert M. Supnik + Copyright (c) 1993-2010, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -35,6 +35,8 @@ Cards are represented as ASCII text streams terminated by newlines. This allows cards to be created and edited as normal files. + 24-Mar-09 RMS Fixed read stacker operation in column binary mode + Fixed punch stacker operation (from Van Snyder) 28-Jun-07 RMS Added support for SS overlap modifiers 19-Jan-07 RMS Added UNIT_TEXT flag 20-Sep-05 RMS Revised for new code tables, compatible colbinary treatment @@ -59,10 +61,16 @@ extern int32 ind[64], ssa, iochk; extern int32 conv_old; int32 s1sel, s2sel, s4sel, s8sel; -char rbuf[2 * CBUFSIZE]; /* > CDR_WIDTH */ +char cdr_buf[(2 * CBUFSIZE) + 1]; /* > CDR_WIDTH */ +char cdp_buf[(2 * CDP_WIDTH) + 1]; /* + null */ +int32 cdp_buf_full = 0; /* punch buf full? */ + t_stat cdr_svc (UNIT *uptr); t_stat cdr_boot (int32 unitno, DEVICE *dptr); t_stat cdr_attach (UNIT *uptr, char *cptr); +t_stat cdp_attach (UNIT *uptr, char *cptr); +t_stat cdp_detach (UNIT *uptr); +t_stat cdp_npr (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cd_reset (DEVICE *dptr); int32 bcd2asc (int32 c, UNIT *uptr); char colbin_to_bcd (uint32 cb); @@ -85,7 +93,7 @@ REG cdr_reg[] = { { FLDATA (S2, s2sel, 0) }, { DRDATA (POS, cdr_unit.pos, T_ADDR_W), PV_LEFT }, { DRDATA (TIME, cdr_unit.wait, 24), PV_LEFT }, - { BRDATA (BUF, rbuf, 8, 8, CDR_WIDTH) }, + { BRDATA (BUF, cdr_buf, 8, 8, CDR_WIDTH * 2) }, { NULL } }; @@ -112,12 +120,17 @@ REG cdp_reg[] = { { FLDATA (S4, s4sel, 0) }, { FLDATA (S8, s8sel, 0) }, { DRDATA (POS, cdp_unit.pos, T_ADDR_W), PV_LEFT }, + { BRDATA (BUF, cdp_buf, 8, 8, CDP_WIDTH * 2) }, + { FLDATA (FULL, cdp_buf_full, 0) }, { NULL } }; MTAB cdp_mod[] = { { UNIT_PCH, 0, "business set", "BUSINESS" }, { UNIT_PCH, UNIT_PCH, "Fortran set", "FORTRAN" }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "NPR", + &cdp_npr, NULL }, + { 0 } }; @@ -125,7 +138,7 @@ DEVICE cdp_dev = { "CDP", &cdp_unit, cdp_reg, cdp_mod, 1, 10, 31, 1, 8, 7, NULL, NULL, &cd_reset, - NULL, NULL, NULL + NULL, &cdp_attach, &cdp_detach }; /* Stacker data structures @@ -152,7 +165,7 @@ REG stack_reg[] = { }; DEVICE stack_dev = { - "STKR", stack_unit, stack_reg, cdp_mod, + "STKR", stack_unit, stack_reg, NULL, 5, 10, 31, 1, 8, 7, NULL, NULL, &cd_reset, NULL, NULL, NULL @@ -178,9 +191,9 @@ if ((cdr_unit.flags & UNIT_ATT) == 0) /* attached? */ return SCPE_UNATT; ind[IN_READ] = ind[IN_LST] = s1sel = s2sel = 0; /* default stacker */ cbn = ((ilnt == 2) || (ilnt == 5)) && (mod == BCD_C); /* col binary? */ -for (i = 0; i < 2 * CBUFSIZE; i++) /* clear extended buf */ - rbuf[i] = 0; -fgets (rbuf, (cbn)? 2 * CBUFSIZE: CBUFSIZE, /* rd bin/char card */ +for (i = 0; i < (2 * CBUFSIZE) + 1; i++) /* clear extended buf */ + cdr_buf[i] = 0; +fgets (cdr_buf, (cbn)? 2 * CBUFSIZE: CBUFSIZE, /* rd bin/char card */ cdr_unit.fileref); if (feof (cdr_unit.fileref)) /* eof? */ return STOP_NOCD; @@ -202,12 +215,12 @@ if (ssa) { /* if last cd on */ if (cbn) { /* column binary */ for (i = 0; i < CDR_WIDTH; i++) { if (conv_old) { - c1 = ascii2bcd (rbuf[i]); - c2 = ascii2bcd (rbuf[CDR_WIDTH + i]); + c1 = ascii2bcd (cdr_buf[i]); + c2 = ascii2bcd (cdr_buf[CDR_WIDTH + i]); } else { - c1 = ascii2bcd (rbuf[2 * i]); - c2 = ascii2bcd (rbuf[(2 * i) + 1]); + c1 = ascii2bcd (cdr_buf[2 * i]); + c2 = ascii2bcd (cdr_buf[(2 * i) + 1]); } M[CD_CBUF1 + i] = (M[CD_CBUF1 + i] & WM) | c1; M[CD_CBUF2 + i] = (M[CD_CBUF2 + i] & WM) | c2; @@ -216,8 +229,8 @@ if (cbn) { /* column binary */ } /* end if col bin */ else { /* normal read */ for (i = 0; i < CDR_WIDTH; i++) { /* cvt to BCD */ - rbuf[i] = ascii2bcd (rbuf[i]); - M[CDR_BUF + i] = (M[CDR_BUF + i] & WM) | rbuf[i]; + c1 = ascii2bcd (cdr_buf[i]); + M[CDR_BUF + i] = (M[CDR_BUF + i] & WM) | c1; } } M[CDR_BUF - 1] = 060; /* mem mark */ @@ -228,12 +241,15 @@ return SCPE_OK; /* Card reader service. If a stacker select is active, copy to the selected stacker. Otherwise, copy to the normal stacker. If the unit is unattached, simply exit. + + The original card buffer (cdr_buf) has not been changed from its input + format (ASCII text), with its newline attached. There is a guaranteed + null at the end, because the buffer was zeroed prior to the read, and + is one character longer than the maximum string length. */ t_stat cdr_svc (UNIT *uptr) { -int32 i; - if (s1sel) /* stacker 1? */ uptr = &stack_unit[1]; else if (s2sel) /* stacker 2? */ @@ -241,13 +257,7 @@ else if (s2sel) /* stacker 2? */ else uptr = &stack_unit[0]; /* then default */ if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ return SCPE_OK; -for (i = 0; i < CDR_WIDTH; i++) - rbuf[i] = bcd2ascii (rbuf[i], uptr->flags & UNIT_PCH); -for (i = CDR_WIDTH - 1; (i >= 0) && (rbuf[i] == ' '); i--) - rbuf[i] = 0; -rbuf[CDR_WIDTH] = 0; /* null at end */ -fputs (rbuf, uptr->fileref); /* write card */ -fputc ('\n', uptr->fileref); /* plus new line */ +fputs (cdr_buf, uptr->fileref); /* write card */ uptr->pos = ftell (uptr->fileref); /* update position */ if (ferror (uptr->fileref)) { /* error? */ perror ("Card stacker I/O error"); @@ -262,23 +272,22 @@ return SCPE_OK; Modifiers have been checked by the caller C modifier is recognized (column binary is implemented) + + - Run out any previously buffered card + - Clear stacker select + - Copy card from memory buffer to punch buffer */ t_stat punch_card (int32 ilnt, int32 mod) { int32 i, cbn, c1, c2; -static char pbuf[(2 * CDP_WIDTH) + 1]; /* + null */ t_bool use_h; -UNIT *uptr; +t_stat r; -if (s8sel) /* stack 8? */ - uptr = &stack_unit[2]; -else if (s4sel) /* stack 4? */ - uptr = &stack_unit[4]; -else uptr = &cdp_unit; /* normal output */ -if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ - return SCPE_UNATT; -use_h = uptr->flags & UNIT_PCH; +r = cdp_npr (NULL, 0, NULL, NULL); /* write card */ +if (r != SCPE_OK) + return r; +use_h = cdp_unit.flags & UNIT_PCH; ind[IN_PNCH] = s4sel = s8sel = 0; /* clear flags */ cbn = ((ilnt == 2) || (ilnt == 5)) && (mod == BCD_C); /* col binary? */ @@ -288,26 +297,46 @@ if (cbn) { /* column binary */ c1 = bcd2ascii (M[CD_CBUF1 + i] & CHAR, use_h); c2 = bcd2ascii (M[CD_CBUF2 + i] & CHAR, use_h); if (conv_old) { - pbuf[i] = c1; - pbuf[i + CDP_WIDTH] = c2; + cdp_buf[i] = c1; + cdp_buf[i + CDP_WIDTH] = c2; } else { - pbuf[2 * i] = c1; - pbuf[(2 * i) + 1] = c2; + cdp_buf[2 * i] = c1; + cdp_buf[(2 * i) + 1] = c2; } } - for (i = 2 * CDP_WIDTH - 1; (i >= 0) && (pbuf[i] == ' '); i--) - pbuf[i] = 0; - pbuf[2 * CDP_WIDTH] = 0; /* trailing null */ + for (i = (2 * CDP_WIDTH) - 1; (i >= 0) && (cdp_buf[i] == ' '); i--) + cdp_buf[i] = 0; + cdp_buf[2 * CDP_WIDTH] = 0; /* trailing null */ } else { /* normal */ for (i = 0; i < CDP_WIDTH; i++) - pbuf[i] = bcd2ascii (M[CDP_BUF + i] & CHAR, use_h); - for (i = CDP_WIDTH - 1; (i >= 0) && (pbuf[i] == ' '); i--) - pbuf[i] = 0; - pbuf[CDP_WIDTH] = 0; /* trailing null */ + cdp_buf[i] = bcd2ascii (M[CDP_BUF + i] & CHAR, use_h); + for (i = CDP_WIDTH - 1; (i >= 0) && (cdp_buf[i] == ' '); i--) + cdp_buf[i] = 0; + cdp_buf[CDP_WIDTH] = 0; /* trailing null */ } -fputs (pbuf, uptr->fileref); /* output card */ +cdp_buf_full = 1; /* card buffer full */ +return SCPE_OK; +} + +/* Punch buffered card (also handles non-process runout button) */ + +t_stat cdp_npr (UNIT *notused, int32 val, char *cptr, void *desc) +{ +UNIT *uptr; + +if (cdp_buf_full == 0) /* any card? */ + return SCPE_OK; /* no, done */ +cdp_buf_full = 0; /* buf empty */ +if (s8sel) /* stack 8? */ + uptr = &stack_unit[2]; +else if (s4sel) /* stack 4? */ + uptr = &stack_unit[4]; +else uptr = &cdp_unit; /* normal output */ +if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ + return SCPE_UNATT; +fputs (cdp_buf, uptr->fileref); /* output card */ fputc ('\n', uptr->fileref); /* plus new line */ uptr->pos = ftell (uptr->fileref); /* update position */ if (ferror (uptr->fileref)) { /* error? */ @@ -380,6 +409,26 @@ saved_IS = BOOT_START; return SCPE_OK; } +/* Card punch attach */ + +t_stat cdp_attach (UNIT *uptr, char *cptr) +{ +cdp_buf_full = 0; +return attach_unit (uptr, cptr); +} + +/* Card punch detach */ + +t_stat cdp_detach (UNIT *uptr) +{ +t_stat r; + +r = cdp_npr (NULL, 0, NULL, NULL); +if (r != SCPE_OK) + return r; +return detach_unit (uptr); +} + /* Column binary to BCD This is based on documentation in the IBM 1620 manual and may not be diff --git a/I1401/i1401_cpu.c b/I1401/i1401_cpu.c index 851f0c2a..3a1196a0 100644 --- a/I1401/i1401_cpu.c +++ b/I1401/i1401_cpu.c @@ -1,6 +1,6 @@ /* i1401_cpu.c: IBM 1401 CPU simulator - Copyright (c) 1993-2008, Robert M. Supnik + Copyright (c) 1993-2010, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 24-Apr-10 RMS Revised divide algorithm (from Van Snyder) 11-Jul-08 RMS Added missing A magtape modifier (from Van Snyder) Fixed tape indicator implementation (from Bob Abeles) Fixed bug in ZA and ZS (from Bob Abeles) @@ -210,8 +211,8 @@ t_stat cpu_show_conv (FILE *st, UNIT *uptr, int32 val, void *desc); int32 store_addr_h (int32 addr); int32 store_addr_t (int32 addr); int32 store_addr_u (int32 addr); -int32 div_add (int32 ap, int32 bp, int32 aend); -int32 div_sub (int32 ap, int32 bp, int32 aend); +int32 div_add (int32 ap, int32 bp); +int32 div_sub (int32 ap, int32 bp); void div_sign (int32 dvrc, int32 dvdc, int32 qp, int32 rp); t_stat iomod (int32 ilnt, int32 mod, const int32 *tptr); t_stat iodisp (int32 dev, int32 unit, int32 flag, int32 mod); @@ -518,7 +519,7 @@ int32 IS, ilnt, flags; int32 op, xa, t, wm, ioind, dev, unit; int32 a, b, i, k, asave, bsave; int32 carry, lowprd, sign, ps; -int32 quo, ahigh, qs; +int32 quo, qs; int32 qzero, qawm, qbody, qsign, qdollar, qaster, qdecimal; t_stat reason, r1, r2; @@ -1432,19 +1433,16 @@ CHECK_LENGTH: - AS points to the low order divisor digit. - BS points to the high order dividend digit. - The low order dividend digit is identified by sign (zone) bits. - - To the left of the dividend is a zero field of length LS + 1. - The low quotient is at low dividend - LS - 1. As BS points to the - high dividend, the low dividend is at BS + LD - 1, so the low - quotient is at BS + LD - LS - 2. The longest possible quotient is - LD - LS + 1, so the first possible non-zero quotient bit will be - found as BS - 2. + - To the left of the dividend is a (zero) field of length LS + 1. + So the quotient starts as BS - LS - 1. + The divide process starts with a subdividend that begins at BS - LS + and ends at BS. (Note that the subdividend is one digit wider than + the divisor, to allow for borrows during the divide process.) This + means that non-zero digits in the "zero" field to the left of the + dividend CAN affect the divide. - This pointer calculation assumes that the divisor has no leading zeroes. - For each leading zero, the start of the quotient will be one position - further left. - - Start by locating the high order non-zero digit of the divisor. This - also tests for a divide by zero. + Start by computing the length of the divisor and testing for divide + by zero. Instruction lengths: @@ -1458,17 +1456,17 @@ CHECK_LENGTH: case OP_DIV: asave = AS; - ahigh = -1; - do { + t = 0; /* assume all 0's */ + do { /* scan divisor */ a = M[AS]; /* get dvr char */ - if ((a & CHAR) != BCD_ZERO) /* mark non-zero */ - ahigh = AS; + if ((bcd_to_bin[a & DIGIT]) != 0) /* mark non-zero */ + t = 1; MM (AS); } while ((a & WM) == 0); if (reason) /* address err? */ break; - if (ahigh < 0) { /* div by zero? */ + if (t == 0) { /* div by zero? */ ind[IN_OVF] = 1; /* set ovf indic */ qs = bsave = BS; /* quo, dividend */ do { @@ -1485,15 +1483,15 @@ CHECK_LENGTH: BS = (BS - 2) - (asave - (AS + 1)); /* final bs */ break; } - bsave = BS + (asave - ahigh); /* end subdivd */ - qs = (BS - 2) - (ahigh - (AS + 1)); /* quo start */ + bsave = BS; /* end subdivd */ + qs = BS - (asave - AS) - 1; /* quo start */ /* Divide loop - done with subroutines to keep the code clean. In the loop, - asave = low order divisor - bsave = low order subdividend - qs = current quotient digit + asave = low order divisor (constant) + bsave = low order subdividend (increments) + qs = current quotient digit (increments) */ do { @@ -1504,11 +1502,13 @@ CHECK_LENGTH: } b = M[bsave]; /* save low divd */ do { - t = div_sub (asave, bsave, ahigh); /* subtract */ + t = div_sub (asave, bsave); /* subtract */ quo++; /* incr quo digit */ } while (t == 0); /* until borrow */ - div_add (asave, bsave, ahigh); /* restore */ + div_add (asave, bsave); /* restore */ quo--; + if (quo > 9) /* overflow? */ + ind[IN_OVF] = 1; /* set ovf indic */ M[qs] = (M[qs] & WM) | sum_table[quo]; /* store quo digit */ bsave++; /* adv divd, quo */ qs++; @@ -1695,7 +1695,7 @@ return bin_to_bcd[addr % 10] | (thous << (V_ZONE - 2)); /* div_add - add string for divide */ -int32 div_add (int32 ap, int32 bp, int32 aend) +int32 div_add (int32 ap, int32 bp) { int32 a, b, c, r; @@ -1709,13 +1709,13 @@ do { M[bp] = sum_table[r]; /* store result */ ap--; bp--; - } while (ap >= aend); + } while ((a & WM) == 0); return c; } /* div_sub - substract string for divide */ -int32 div_sub (int32 ap, int32 bp, int32 aend) +int32 div_sub (int32 ap, int32 bp) { int32 a, b, c, r; @@ -1729,9 +1729,9 @@ do { M[bp] = sum_table[r + 10]; /* store result */ ap--; bp--; - } while (ap >= aend); -b = M[bp] & CHAR; /* borrow position */ -if (b && (b != BCD_ZERO)) { /* non-zero? */ + } while ((a & WM) == 0); +b = M[bp]; /* borrow position */ +if (bcd_to_bin[b & DIGIT] != 0) { /* non-zero? */ r = bcd_to_bin[b & DIGIT] - c; /* subtract borrow */ M[bp] = sum_table[r]; /* store result */ return 0; /* subtract worked */ diff --git a/I1401/i1401_mt.c b/I1401/i1401_mt.c index 2da50d84..54c97ef1 100644 --- a/I1401/i1401_mt.c +++ b/I1401/i1401_mt.c @@ -1,6 +1,6 @@ /* i1401_mt.c: IBM 1401 magnetic tape simulator - Copyright (c) 1993-2008, Robert M. Supnik + Copyright (c) 1993-2010, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/Ibm1130/ibm1130_sca.c b/Ibm1130/ibm1130_sca.c index 3571166c..1e41d3c8 100644 --- a/Ibm1130/ibm1130_sca.c +++ b/Ibm1130/ibm1130_sca.c @@ -7,7 +7,7 @@ 2005.03.08 - Started - * (C) Copyright 2005, Brian Knittel. + * (C) Copyright 2005-2010, Brian Knittel. * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN * RISK basis, there is no warranty of fitness for any purpose, and the rest of the * usual yada-yada. Please keep this notice and the copyright in any distributions @@ -343,7 +343,7 @@ static void sca_flush (void) #endif if (sca_sock != INVALID_SOCKET) { - nbytes = sim_write_sock(sca_sock, sca_sendbuf, sca_n2send); + nbytes = sim_write_sock(sca_sock, (char *) sca_sendbuf, sca_n2send); if (nbytes == SOCKET_ERROR) sca_socket_error(); @@ -655,7 +655,7 @@ static void sca_check_indata (void) #else /* read socket; 0 is returned if no data is available */ - nbytes = sim_read_sock(sca_sock, sca_rcvbuf, SCA_RCVBUF_SIZE); + nbytes = sim_read_sock(sca_sock, (char *) sca_rcvbuf, SCA_RCVBUF_SIZE); #endif diff --git a/PDP11/pdp11_cr.c b/PDP11/pdp11_cr.c index 55e6b71a..d8ee8258 100644 --- a/PDP11/pdp11_cr.c +++ b/PDP11/pdp11_cr.c @@ -1,6 +1,6 @@ /* pdp11_cr.c: CR/CM/CD-11 card reader simulator - Copyright (c) 2005-2007, John A. Dundas III + Copyright (c) 2005-2010, John A. Dundas III Portions derived from work by Douglas W. Jones, jones@cs.uiowa.edu Portions derived from work by Robert M Supnik @@ -87,6 +87,7 @@ Revision History: + 03-Jan-10 JAD Eliminate gcc warnings 01-Feb-07 RMS Added PDP-10 support 12-May-06 JAD Modify the DEBUG code to use the SIMH DEBUG_x macros. Modify the UNIT structure to include diff --git a/PDP11/pdp11_kg.c b/PDP11/pdp11_kg.c index 3e643531..6597250f 100644 --- a/PDP11/pdp11_kg.c +++ b/PDP11/pdp11_kg.c @@ -1,6 +1,6 @@ /* pdp11_kg.c - Communications Arithmetic Option KG11-A - Copyright (c) 2007-2008, John A. Dundas III + Copyright (c) 2007-2010, John A. Dundas III Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ kg KG11-A Communications Arithmetic Option (M7251) + 03-Jan-10 JAD Eliminate gcc warnings 08-Jan-08 JAD First public release integrated with SIMH V3.7-3. 09-Dec-07 JAD SIMH-style debugging. Finished validating against real hardware. @@ -178,7 +179,7 @@ static t_stat set_units (UNIT *, int32, char *, void *); /* 16-bit rotate right */ -#define ROR(n,v) (((v >> n) & DMASK) | (v << (16 - n)) & DMASK) +#define ROR(n,v) (((v >> n) & DMASK) | ((v << (16 - n)) & DMASK)) /* 8-bit rotate right */ diff --git a/PDP11/pdp11_rk.c b/PDP11/pdp11_rk.c index ccee5026..2b7c089c 100644 --- a/PDP11/pdp11_rk.c +++ b/PDP11/pdp11_rk.c @@ -1,6 +1,6 @@ /* pdp11_rk.c: RK11/RKV11 cartridge disk simulator - Copyright (c) 1993-2008, Robert M Supnik + Copyright (c) 1993-2009, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ rk RK11/RKV11/RK05 cartridge disk + 20-Mar-09 RMS Fixed bug in read header (from Walter F Mueller) 16-Aug-05 RMS Fixed C++ declaration and cast problems 07-Jul-05 RMS Removed extraneous externs 30-Sep-04 RMS Revised Unibus interface @@ -533,7 +534,7 @@ if (wc && (err == 0)) { /* seek ok? */ wc = i; /* trim transfer */ break; } - rkxb[i] = (cda / RK_NUMWD) / (RK_NUMSF * RK_NUMSC); + rkxb[i] = ((cda / RK_NUMWD) / (RK_NUMSF * RK_NUMSC)) << RKDA_V_CYL; cda = cda + RK_NUMWD; /* next sector */ } /* end for wc */ } /* end if format */ diff --git a/PDP11/pdp11_rl.c b/PDP11/pdp11_rl.c index 46fc1657..19944926 100644 --- a/PDP11/pdp11_rl.c +++ b/PDP11/pdp11_rl.c @@ -1,6 +1,6 @@ /* pdp11_rl.c: RL11 (RLV12) cartridge disk simulator - Copyright (c) 1993-2008, Robert M Supnik + Copyright (c) 1993-2009, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ rl RL11(RLV12)/RL01/RL02 cartridge disk + 10-Oct-09 RMS Added debug support 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) 16-Aug-05 RMS Fixed C++ declaration and cast problems 07-Jul-05 RMS Removed extraneous externs @@ -192,6 +193,7 @@ extern uint32 cpu_opt; #define RLBAE_IMP 0000077 /* implemented */ extern int32 int_req[IPL_HLVL]; +extern FILE *sim_deb; uint16 *rlxb = NULL; /* xfer buffer */ int32 rlcs = 0; /* control/status */ @@ -283,7 +285,7 @@ DEVICE rl_dev = { RL_NUMDR, DEV_RDX, 24, 1, DEV_RDX, 16, NULL, NULL, &rl_reset, &rl_boot, &rl_attach, NULL, - &rl_dib, DEV_DISABLE | DEV_UBUS | DEV_QBUS + &rl_dib, DEV_DEBUG | DEV_DISABLE | DEV_UBUS | DEV_QBUS }; /* I/O dispatch routines, I/O addresses 17774400 - 17774407 @@ -333,6 +335,9 @@ switch ((PA >> 1) & 07) { /* decode PA<2:1> */ break; } /* end switch */ +if (DEBUG_PRS (rl_dev)) + fprintf (sim_deb, ">>RL read: reg%d=%o\n", (PA >> 1) & 07, *data); + return SCPE_OK; } @@ -341,6 +346,9 @@ t_stat rl_wr (int32 data, int32 PA, int32 access) int32 curr, offs, newc, maxc; UNIT *uptr; +if (DEBUG_PRS (rl_dev)) + fprintf (sim_deb, ">>RL write: reg%d=%o\n", (PA >> 1) & 07, data); + switch ((PA >> 1) & 07) { /* decode PA<2:1> */ case 0: /* RLCS */ diff --git a/PDP11/pdp11_rq.c b/PDP11/pdp11_rq.c index 3def339a..89da0cb5 100644 --- a/PDP11/pdp11_rq.c +++ b/PDP11/pdp11_rq.c @@ -1,6 +1,6 @@ /* pdp11_rq.c: MSCP disk controller simulator - Copyright (c) 2002-2008, Robert M Supnik + Copyright (c) 2002-2010, Robert M Supnik Derived from work by Stephen F. Shirron Permission is hereby granted, free of charge, to any person obtaining a @@ -26,6 +26,7 @@ rq RQDX3 disk controller + 14-Jan-09 JH Added support for RD32 disc drive 18-Jun-07 RMS Added UNIT_IDLE flag to timer thread 31-Oct-05 RMS Fixed address width for large files 16-Aug-05 RMS Fixed C++ declaration and cast problems @@ -127,7 +128,7 @@ extern int32 cpu_opt; #define UNIT_V_WLK (UNIT_V_UF + 1) /* hwre write lock */ #define UNIT_V_ATP (UNIT_V_UF + 2) /* attn pending */ #define UNIT_V_DTYPE (UNIT_V_UF + 3) /* drive type */ -#define UNIT_M_DTYPE 0xF +#define UNIT_M_DTYPE 0x1F #define UNIT_ONL (1 << UNIT_V_ONL) #define UNIT_WLK (1 << UNIT_V_WLK) #define UNIT_ATP (1 << UNIT_V_ATP) @@ -219,7 +220,7 @@ struct rqpkt { RD51 18 4 306 4 1 36*4 21600 RD31 17 4 615 4 1 3*8 41560 RD52 17 8 512 8 1 4*8 60480 -x RD32 17 6 820 ? ? ? 83236 + RD32 17 6 820 6 1 4*8 83204 x RD33 17 7 1170 ? ? ? 138565 RD53 17 7 1024 7 1 5*8 138672 RD54 17 15 1225 15 1 7*8 311200 @@ -505,6 +506,22 @@ x RA73 70(+1) 21 2667+ 21 1 ? 3920490 #define RA71_MED 0x25641047 #define RA71_FLGS RQDF_SDI +#define RD32_DTYPE 16 +#define RD32_SECT 17 +#define RD32_SURF 6 +#define RD32_CYL 820 +#define RD32_TPG RD32_SURF +#define RD32_GPC 1 +#define RD32_XBN 54 +#define RD32_DBN 48 +#define RD32_LBN 83204 +#define RD32_RCTS 4 +#define RD32_RCTC 8 +#define RD32_RBN 200 +#define RD32_MOD 15 +#define RD32_MED 0x25644020 +#define RD32_FLGS 0 + struct drvtyp { int32 sect; /* sectors */ int32 surf; /* surfaces */ @@ -539,6 +556,7 @@ static struct drvtyp drv_tab[] = { { RQ_DRV (RA90), "RA90" }, { RQ_DRV (RA92), "RA92" }, { RQ_DRV (RA8U), "RAUSER" }, { RQ_DRV (RA60), "RA60" }, { RQ_DRV (RA81), "RA81" }, { RQ_DRV (RA71), "RA71" }, + { RQ_DRV (RD32), "RD32" }, { 0 } }; @@ -724,6 +742,8 @@ MTAB rq_mod[] = { &rq_set_type, NULL, NULL }, { MTAB_XTD | MTAB_VUN, RD31_DTYPE, NULL, "RD31", &rq_set_type, NULL, NULL }, + { MTAB_XTD | MTAB_VUN, RD32_DTYPE, NULL, "RD32", + &rq_set_type, NULL, NULL }, { MTAB_XTD | MTAB_VUN, RD51_DTYPE, NULL, "RD51", &rq_set_type, NULL, NULL }, { MTAB_XTD | MTAB_VUN, RD52_DTYPE, NULL, "RD52", diff --git a/PDP11/pdp11_vh.c b/PDP11/pdp11_vh.c index 2fdde2a7..72f09280 100644 --- a/PDP11/pdp11_vh.c +++ b/PDP11/pdp11_vh.c @@ -1,6 +1,6 @@ /* pdp11_vh.c: DHQ11 asynchronous terminal multiplexor simulator - Copyright (c) 2004-2008, John A. Dundas III + Copyright (c) 2004-2010, John A. Dundas III Portions derived from work by Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a @@ -26,6 +26,7 @@ vh DHQ11 asynch multiplexor for SIMH + 03-Jan-10 JAD Eliminate gcc warnings 19-Nov-08 RMS Revised for common TMXR show routines 18-Jun-07 RMS Added UNIT_IDLE flag 29-Oct-06 RMS Synced poll and clock @@ -258,13 +259,13 @@ static const int32 bitmask[4] = { 037, 077, 0177, 0377 }; /* RX FIFO state */ static int32 rbuf_idx[VH_MUXES] = { 0 };/* index into vh_rbuf */ -static uint32 vh_rbuf[VH_MUXES][FIFO_SIZE] = { 0 }; +static uint32 vh_rbuf[VH_MUXES][FIFO_SIZE] = { { 0 } }; /* TXQ state */ #define TXQ_SIZE (16) static int32 txq_idx[VH_MUXES] = { 0 }; -static uint32 vh_txq[VH_MUXES][TXQ_SIZE] = { 0 }; +static uint32 vh_txq[VH_MUXES][TXQ_SIZE] = { { 0 } }; /* Need to extend the TMLN structure */ @@ -279,9 +280,9 @@ typedef struct { uint16 txchar; /* single character I/O */ } TMLX; -static TMLN vh_ldsc[VH_MUXES * VH_LINES] = { 0 }; +static TMLN vh_ldsc[VH_MUXES * VH_LINES] = { { 0 } }; static TMXR vh_desc = { VH_MUXES * VH_LINES, 0, 0, vh_ldsc }; -static TMLX vh_parm[VH_MUXES * VH_LINES] = { 0 }; +static TMLX vh_parm[VH_MUXES * VH_LINES] = { { 0 } }; /* Forward references */ static t_stat vh_rd (int32 *data, int32 PA, int32 access); @@ -675,7 +676,7 @@ static void vh_getc ( int32 vh ) for (i = 0; i < VH_LINES; i++) { lp = &vh_parm[(vh * VH_LINES) + i]; - while (c = tmxr_getc_ln (lp->tmln)) { + while ((c = tmxr_getc_ln (lp->tmln)) != 0) { if (c & SCPE_BREAK) { fifo_put (vh, lp, RBUF_FRAME_ERR | RBUF_PUTLINE (i)); @@ -786,7 +787,7 @@ static t_stat vh_wr ( int32 data, if (access == WRITEB) data = (PA & 1) ? (vh_csr[vh] & 0377) | (data << 8) : - (vh_csr[vh] & ~0377) | data & 0377; + (vh_csr[vh] & ~0377) | (data & 0377); if (data & CSR_MASTER_RESET) { if ((vh_unit[vh].flags & UNIT_MODEDHU) && (data & CSR_SKIP)) data &= ~CSR_MASTER_RESET; @@ -877,7 +878,7 @@ static t_stat vh_wr ( int32 data, if (access == WRITEB) data = (PA & 1) ? (lp->lpr & 0377) | (data << 8) : - (lp->lpr & ~0377) | data & 0377; + (lp->lpr & ~0377) | (data & 0377); /* Modify only if CSR<3:0> == 0 */ if (CSR_GETCHAN (vh_csr[vh]) != 0) data &= ~LPR_DISAB_XRPT; @@ -926,7 +927,7 @@ static t_stat vh_wr ( int32 data, if (access == WRITEB) data = (PA & 1) ? (lp->lnctrl & 0377) | (data << 8) : - (lp->lnctrl & ~0377) | data & 0377; + (lp->lnctrl & ~0377) | (data & 0377); /* catch the abort TX transition */ if (!(lp->lnctrl & LNCTRL_TX_ABORT) && (data & LNCTRL_TX_ABORT)) { @@ -993,7 +994,7 @@ static t_stat vh_wr ( int32 data, if (access == WRITEB) data = (PA & 1) ? (lp->tbuf1 & 0377) | (data << 8) : - (lp->tbuf1 & ~0377) | data & 0377; + (lp->tbuf1 & ~0377) | (data & 0377); lp->tbuf1 = data; break; case 6: /* TBUFFAD2 */ @@ -1008,7 +1009,7 @@ static t_stat vh_wr ( int32 data, if (access == WRITEB) data = (PA & 1) ? (lp->tbuf2 & 0377) | (data << 8) : - (lp->tbuf2 & ~0377) | data & 0377; + (lp->tbuf2 & ~0377) | (data & 0377); lp->tbuf2 = data; /* if starting a DMA, clear DMA_ERR */ if (vh_unit[vh].flags & UNIT_FASTDMA) { @@ -1028,7 +1029,7 @@ static t_stat vh_wr ( int32 data, if (access == WRITEB) data = (PA & 1) ? (lp->tbuffct & 0377) | (data << 8) : - (lp->tbuffct & ~0377) | data & 0377; + (lp->tbuffct & ~0377) | (data & 0377); lp->tbuffct = data; break; default: diff --git a/PDP8/pdp8_fpp.c b/PDP8/pdp8_fpp.c index 3937127e..4fb04c01 100644 --- a/PDP8/pdp8_fpp.c +++ b/PDP8/pdp8_fpp.c @@ -1,6 +1,6 @@ /* pdp8_fpp.c: PDP-8 floating point processor (FPP8A) - Copyright (c) 2007-2008, Robert M Supnik + Copyright (c) 2007-2010, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,27 @@ fpp FPP8A floating point processor + 03-Jan-10 RMS Initialized variables statically, for VMS compiler + 19-Apr-09 RHM FPICL does not clear all command and status reg bits + modify fpp_reset to conform with FPP + 27-Mar-09 RHM Fixed handling of Underflow fix (zero FAC on underflow) + Implemented FPP division and multiplication algorithms + FPP behavior on traps - FEXIT does not update APT + Follow FPP settings for OPADD + Correct detection of DP add/sub overflow + Detect and handle add/sub overshift + Single-step mode made consistent with FPP + Write calculation results prior to traps + 24-Mar-09 RMS Many fixes from Rick Murphy: + Fix calculation of ATX shift amount + Added missing () to read, write XR macros + Fixed indirect address calculation + Fixed == written as = in normalization + Fixed off-by-one count bug in multiplication + Removed extraneous ; in divide + Fixed direction of compare in divide + Fixed count direction bug in alignment + Floating point formats: 00 01 02 03 04 05 06 07 08 09 10 11 @@ -85,8 +106,8 @@ extern UNIT cpu_unit; /* Index registers are in memory */ -#define fpp_read_xr(xr) fpp_read (fpp_xra + xr) -#define fpp_write_xr(xr,d) fpp_write (fpp_xra +xr, d) +#define fpp_read_xr(xr) fpp_read (fpp_xra + (xr)) +#define fpp_write_xr(xr,d) fpp_write (fpp_xra + (xr), d) /* Command register */ @@ -112,8 +133,7 @@ extern UNIT cpu_unit; #define FPS_IOVX 00200 /* int ovf exit */ #define FPS_FOVX 00100 /* flt ovf exit */ #define FPS_UNF 00040 /* underflow */ -#define FPS_UNFX 00020 /* undf exit */ -#define FPS_XXXM 00010 /* FADDM/FMULM */ +#define FPS_XXXM 00020 /* FADDM/FMULM */ #define FPS_LOCK (FPC_LOCK) /* lockout */ #define FPS_EP 00004 /* ext prec */ #define FPS_PAUSE 00002 /* paused */ @@ -124,24 +144,28 @@ extern UNIT cpu_unit; #define FPN_FRSIGN 04000 #define FPN_NFR_FP 2 /* std precision */ #define FPN_NFR_EP 5 /* ext precision */ +#define FPN_NFR_MDS 6 /* mul/div precision */ #define EXACT (uint32)((fpp_sta & FPS_EP)? FPN_NFR_EP: FPN_NFR_FP) #define EXTEND ((uint32) FPN_NFR_EP) typedef struct { - int32 exp; - uint32 fr[FPN_NFR_EP]; + int32 exp; + uint32 fr[FPN_NFR_MDS+1]; } FPN; -uint32 fpp_apta; /* APT pointer */ -uint32 fpp_aptsvf; /* APT saved field */ -uint32 fpp_opa; /* operand pointer */ -uint32 fpp_fpc; /* FP PC */ -uint32 fpp_bra; /* base reg pointer */ -uint32 fpp_xra; /* indx reg pointer */ -uint32 fpp_cmd; /* command */ -uint32 fpp_sta; /* status */ -uint32 fpp_flag; /* flag */ +uint32 fpp_apta = 0; /* APT pointer */ +uint32 fpp_aptsvf = 0; /* APT saved field */ +uint32 fpp_opa = 0; /* operand pointer */ +uint32 fpp_fpc = 0; /* FP PC */ +uint32 fpp_bra = 0; /* base reg pointer */ +uint32 fpp_xra = 0; /* indx reg pointer */ +uint32 fpp_cmd = 0; /* command */ +uint32 fpp_sta = 0; /* status */ +uint32 fpp_flag = 0; /* flag */ FPN fpp_ac; /* FAC */ +uint32 fpp_ssf = 0; /* single-step flag */ +uint32 fpp_last_lockbit = 0; /* last lockbit */ + static FPN fpp_zero = { 0, { 0, 0, 0, 0, 0 } }; static FPN fpp_one = { 1, { 02000, 0, 0, 0, 0 } }; @@ -155,13 +179,13 @@ uint32 fpp_2wd_dir (uint32 ir); uint32 fpp_indir (uint32 ir); uint32 fpp_ad15 (uint32 hi); uint32 fpp_adxr (uint32 ir, uint32 base_ad); -t_bool fpp_add (FPN *a, FPN *b, uint32 sub); -t_bool fpp_mul (FPN *a, FPN *b); -t_bool fpp_div (FPN *a, FPN *b); +void fpp_add (FPN *a, FPN *b, uint32 sub); +void fpp_mul (FPN *a, FPN *b); +void fpp_div (FPN *a, FPN *b); t_bool fpp_imul (FPN *a, FPN *b); -uint32 fpp_fr_add (uint32 *c, uint32 *a, uint32 *b); -void fpp_fr_sub (uint32 *c, uint32 *a, uint32 *b); -void fpp_fr_mul (uint32 *c, uint32 *a, uint32 *b); +uint32 fpp_fr_add (uint32 *c, uint32 *a, uint32 *b, uint32 cnt); +void fpp_fr_sub (uint32 *c, uint32 *a, uint32 *b, uint32 cnt); +void fpp_fr_mul (uint32 *c, uint32 *a, uint32 *b, t_bool fix); t_bool fpp_fr_div (uint32 *c, uint32 *a, uint32 *b); uint32 fpp_fr_neg (uint32 *a, uint32 cnt); int32 fpp_fr_cmp (uint32 *a, uint32 *b, uint32 cnt); @@ -214,6 +238,8 @@ REG fpp_reg[] = { { ORDATA (BRA, fpp_bra, 15) }, { ORDATA (XRA, fpp_xra, 15) }, { ORDATA (OPA, fpp_opa, 15) }, + { ORDATA (SSF, fpp_ssf, 12) }, + { ORDATA (LASTLOCK, fpp_last_lockbit, 12) }, { FLDATA (FLAG, fpp_flag, 0) }, { NULL } }; @@ -242,6 +268,7 @@ switch (IR & 07) { /* decode IR<9:11> */ case 3: /* FPCOM */ if (!fpp_flag && !(fpp_sta & FPS_RUN)) { /* flag clr, !run? */ fpp_cmd = AC; /* load cmd */ + fpp_last_lockbit = fpp_cmd & FPS_LOCK; /* remember lock state */ fpp_sta = (fpp_sta & ~FPC_STA) | /* copy flags */ (fpp_cmd & FPC_STA); /* to status */ } @@ -251,16 +278,25 @@ switch (IR & 07) { /* decode IR<9:11> */ if (fpp_sta & FPS_RUN) { /* running? */ if (fpp_sta & FPS_PAUSE) /* paused? */ fpp_fpc = (fpp_fpc - 1) & ADDRMASK; /* decr FPC */ + fpp_sta &= ~FPS_PAUSE; /* no longer paused */ sim_cancel (&fpp_unit); /* stop execution */ fpp_dump_apt (fpp_apta, FPS_HLTX); /* dump APT */ + fpp_ssf = 1; /* assume sstep */ } - else sim_activate (&fpp_unit, 0); /* single step */ + else if (!fpp_flag) + fpp_ssf = 1; /* FPST sing steps */ + if (fpp_sta & FPS_DVZX) /* fix diag timing */ + fpp_sta |= FPS_HLTX; break; case 5: /* FPST */ if (!fpp_flag && !(fpp_sta & FPS_RUN)) { /* flag clr, !run? */ + if (fpp_ssf) + fpp_sta |= fpp_last_lockbit; + fpp_sta &= ~FPS_HLTX; /* Clear halted */ fpp_apta = (FPC_GETAPTF (fpp_cmd) << 12) | AC; fpp_load_apt (fpp_apta); /* load APT */ + fpp_opa = fpp_fpc; sim_activate (&fpp_unit, 0); /* start unit */ return IOT_SKP | AC; } @@ -278,7 +314,7 @@ switch (IR & 07) { /* decode IR<9:11> */ if (fpp_flag) { /* if flag set */ uint32 old_sta = fpp_sta; fpp_flag = 0; /* clr flag, status */ - fpp_sta = 0; + fpp_sta &= ~(FPS_DP|FPS_EP|FPS_TRPX|FPS_DVZX|FPS_IOVX|FPS_FOVX|FPS_UNF); int_req &= ~INT_FPP; /* clr int req */ return IOT_SKP | old_sta; /* ret old status */ } @@ -296,8 +332,10 @@ int32 fpp56 (int32 IR, int32 AC) switch (IR & 07) { /* decode IR<9:11> */ case 7: /* FPEP */ - if ((AC & 04000) && !(fpp_sta & FPS_RUN)) /* if AC0, not run, */ + if ((AC & 04000) && !(fpp_sta & FPS_RUN)) { /* if AC0, not run, */ fpp_sta = (fpp_sta | FPS_EP) & ~FPS_DP; /* set ep */ + AC = 0; + } break; default: @@ -314,6 +352,7 @@ t_stat fpp_svc (UNIT *uptr) FPN x; uint32 ir, op, op2, op3, ad, ea, wd; uint32 i; +int32 sc; fpp_ac.exp = SEXT12 (fpp_ac.exp); /* sext AC exp */ do { /* repeat */ @@ -332,7 +371,11 @@ do { /* repeat */ switch (op3) { /* case on subsubop */ case 0: /* FEXIT */ - fpp_dump_apt (fpp_apta, 0); + /* if already trapped, don't update APT, just update status */ + if (fpp_sta & (FPS_DVZX|FPS_IOVX|FPS_FOVX|FPS_UNF)) + fpp_sta |= FPS_HLTX; + else + fpp_dump_apt (fpp_apta, 0); break; case 1: /* FPAUSE */ @@ -351,8 +394,7 @@ do { /* repeat */ if (!(fpp_sta & FPS_DP)) { /* fp or ep only */ fpp_copy (&x, &fpp_ac); /* copy AC */ fpp_norm (&x, EXACT); /* do exact length */ - if (!fpp_test_xp (&x)) /* no trap? */ - fpp_copy (&fpp_ac, &x); /* copy back */ + fpp_copy (&fpp_ac, &x); /* copy back */ } break; @@ -360,8 +402,7 @@ do { /* repeat */ if (fpp_sta & FPS_EP) { /* if ep, */ fpp_copy (&x, &fpp_ac); /* copy AC */ fpp_round (&x); /* round */ - if (!fpp_test_xp (&x)) /* no trap? */ - fpp_copy (&fpp_ac, &x); /* copy back */ + fpp_copy (&fpp_ac, &x); /* copy back */ } fpp_sta &= ~(FPS_DP|FPS_EP); break; @@ -377,17 +418,22 @@ do { /* repeat */ break; case 001: /* ALN */ - if (op3 != 0) /* if xr, */ + if (op3 != 0) { /* if xr, */ wd = fpp_read_xr (op3); /* use val */ + fpp_opa = fpp_xra + op3; + } else wd = 027; /* else 23 */ if (!(fpp_sta & FPS_DP)) { /* fp or ep? */ - int32 t = wd - fpp_ac.exp; /* alignment */ - fpp_ac.exp = SEXT12 (wd); /* new exp */ - wd = t & 07777; + sc = (SEXT12(wd) - fpp_ac.exp) & 07777; /* alignment */ + sc = SEXT12 (sc); + fpp_ac.exp = SEXT12(wd); /* new exp */ } - if (wd & 04000) /* left? */ - fpp_fr_lshn (fpp_ac.fr, 04000 - wd, EXACT); - else fpp_fr_algn (fpp_ac.fr, wd, EXACT); + else sc = SEXT12 (wd); /* dp - simple cnt */ + if (sc < 0) /* left? */ + fpp_fr_lshn (fpp_ac.fr, -sc, EXACT); + else fpp_fr_algn (fpp_ac.fr, sc, EXACT); + if (fpp_fr_test (fpp_ac.fr, 0, EXACT) == 0) /* zero? */ + fpp_ac.exp = 0; /* clean exp */ break; case 002: /* ATX */ @@ -395,10 +441,10 @@ do { /* repeat */ fpp_write_xr (op3, fpp_ac.fr[1]); /* xr<-FAC<12:23> */ else { fpp_copy (&x, &fpp_ac); /* copy AC */ - wd = (fpp_ac.exp - 027) & 07777; /* shift amt */ - if (wd & 04000) /* left? */ - fpp_fr_lshn (x.fr, 04000 - wd, EXACT); - else fpp_fr_algn (x.fr, wd, EXACT); + sc = 027 - x.exp; /* shift amt */ + if (sc < 0) /* left? */ + fpp_fr_lshn (x.fr, -sc, EXACT); + else fpp_fr_algn (x.fr, sc, EXACT); fpp_write_xr (op3, x.fr[1]); /* xr<-val<12:23> */ } break; @@ -411,10 +457,11 @@ do { /* repeat */ x.exp = 027; /* standard exp */ if (!(fpp_sta & FPS_DP)) { /* fp or ep? */ fpp_norm (&x, EXACT); /* normalize */ - if (fpp_test_xp (&x)) /* exception? */ - break; } fpp_copy (&fpp_ac, &x); /* result to AC */ + if (fpp_sta & FPS_DP) /* dp skips exp */ + fpp_ac.exp = x.exp; /* so force copy */ + fpp_opa = fpp_xra + op3; break; case 004: /* NOP */ @@ -431,12 +478,14 @@ do { /* repeat */ case 010: /* LDX */ wd = fpp_ad15 (0); /* load XR immed */ fpp_write_xr (op3, wd); + fpp_opa = fpp_xra + op3; break; case 011: /* ADDX */ wd = fpp_ad15 (0); wd = wd + fpp_read_xr (op3); /* add to XR immed */ fpp_write_xr (op3, wd); /* trims to 12b */ + fpp_opa = fpp_xra + op3; break; default: @@ -452,6 +501,9 @@ do { /* repeat */ case 002: ea = fpp_2wd_dir (ir); fpp_read_op (ea, &fpp_ac); + if (fpp_sta & FPS_DP) + fpp_opa = ea + 1; + else fpp_opa = ea + 2; break; case 003: @@ -480,13 +532,14 @@ do { /* repeat */ case 012: /* JSA */ fpp_write (ad, 01030 + (fpp_fpc >> 12)); /* save return */ fpp_write (ad + 1, fpp_fpc); /* trims to 12b */ - fpp_fpc = (ad + 2) & ADDRMASK; + fpp_fpc = (ad + 2) & ADDRMASK; + fpp_opa = fpp_fpc - 1; break; case 013: /* JSR */ fpp_write (fpp_bra + 1, 01030 + (fpp_fpc >> 12)); fpp_write (fpp_bra + 2, fpp_fpc); /* trims to 12b */ - fpp_fpc = ad; + fpp_opa = fpp_fpc = ad; break; default: @@ -512,17 +565,18 @@ do { /* repeat */ fpp_add (&fpp_ac, &x, 0); break; - case 010: /* JNX */ + case 010: { /* JNX */ + uint32 xrn = op2 & 07; ad = fpp_ad15 (op3); /* get 15b addr */ - wd = fpp_read_xr (op2 & 07); /* read xr */ - if (ir & 00100) { /* inc? */ + wd = fpp_read_xr (xrn); /* read xr */ + if (op2 & 010) { /* inc? */ wd = (wd + 1) & 07777; - fpp_write_xr (op2 & 07, wd); /* ++xr */ + fpp_write_xr (xrn, wd); /* ++xr */ } if (wd != 0) /* xr != 0? */ fpp_fpc = ad; /* jump */ break; - + } case 011: /* FSUB */ ea = fpp_1wd_dir (ir); fpp_read_op (ea, &x); @@ -591,24 +645,24 @@ do { /* repeat */ fpp_sta |= FPS_XXXM; ea = fpp_1wd_dir (ir); fpp_read_op (ea, &x); - if (!fpp_add (&x, &fpp_ac, 0)) /* no trap? */ - fpp_write_op (ea, &x); /* store result */ + fpp_add (&x, &fpp_ac, 0); + fpp_write_op (ea, &x); /* store result */ break; case 026: fpp_sta |= FPS_XXXM; ea = fpp_2wd_dir (ir); fpp_read_op (ea, &x); - if (!fpp_add (&x, &fpp_ac, 0)) /* no trap? */ - fpp_write_op (ea, &x); /* store result */ + fpp_add (&x, &fpp_ac, 0); + fpp_write_op (ea, &x); /* store result */ break; case 027: fpp_sta |= FPS_XXXM; ea = fpp_indir (ir); fpp_read_op (ea, &x); - if (!fpp_add (&x, &fpp_ac, 0)) /* no trap? */ - fpp_write_op (ea, &x); /* store result */ + fpp_add (&x, &fpp_ac, 0); + fpp_write_op (ea, &x); /* store result */ break; case 030: /* IMUL/LEA */ @@ -649,6 +703,7 @@ do { /* repeat */ fpp_sta = (fpp_sta | FPS_DP) & ~FPS_EP; /* set dp */ fpp_ac.fr[0] = (ea >> 12) & 07; fpp_ac.fr[1] = ea & 07777; + fpp_opa = ea; } break; @@ -656,30 +711,35 @@ do { /* repeat */ fpp_sta |= FPS_XXXM; ea = fpp_1wd_dir (ir); fpp_read_op (ea, &x); - if (!fpp_mul (&x, &fpp_ac)) /* no trap? */ - fpp_write_op (ea, &x); /* store result */ + fpp_mul (&x, &fpp_ac); + fpp_write_op (ea, &x); /* store result */ break; case 036: fpp_sta |= FPS_XXXM; ea = fpp_2wd_dir (ir); fpp_read_op (ea, &x); - if (!fpp_mul (&x, &fpp_ac)) /* no trap? */ - fpp_write_op (ea, &x); /* store result */ + fpp_mul (&x, &fpp_ac); + fpp_write_op (ea, &x); /* store result */ break; case 037: fpp_sta |= FPS_XXXM; ea = fpp_indir (ir); fpp_read_op (ea, &x); - if (!fpp_mul (&x, &fpp_ac)) /* no trap? */ - fpp_write_op (ea, &x); /* store result */ + fpp_mul (&x, &fpp_ac); + fpp_write_op (ea, &x); /* store result */ break; } /* end sw op+mode */ + if (fpp_ssf) { + fpp_dump_apt (fpp_apta, FPS_HLTX); /* dump APT */ + fpp_ssf = 0; + } + if (sim_interval) sim_interval = sim_interval - 1; - } while ((sim_interval > 0) && + } while ((sim_interval > 0) && ((fpp_sta & (FPS_RUN|FPS_PAUSE|FPS_LOCK)) == (FPS_RUN|FPS_LOCK))); if ((fpp_sta & (FPS_RUN|FPS_PAUSE)) == FPS_RUN) sim_activate (uptr, 1); @@ -696,7 +756,11 @@ uint32 ad; ad = fpp_bra + ((ir & 0177) * 3); /* base + 3*7b off */ if (fpp_sta & FPS_DP) /* dp? skip exp */ ad = ad + 1; -return ad & ADDRMASK; +ad = ad & ADDRMASK; +if (fpp_sta & FPS_DP) + fpp_opa = ad + 1; +else fpp_opa = ad + 2; +return ad; } uint32 fpp_2wd_dir (uint32 ir) @@ -709,13 +773,18 @@ return fpp_adxr (ir, ad); /* do indexing */ uint32 fpp_indir (uint32 ir) { -uint32 ad, iad, wd1, wd2; +uint32 ad, wd1, wd2; ad = fpp_bra + ((ir & 07) * 3); /* base + 3*3b off */ -iad = fpp_adxr (ir, ad); /* do indexing */ -wd1 = fpp_read (iad + 1); /* read wds 2,3 */ -wd2 = fpp_read (iad + 2); -return ((wd1 & 07) << 12) | wd2; /* return addr */ +wd1 = fpp_read (ad + 1); /* bp+off points to */ +wd2 = fpp_read (ad + 2); +ad = ((wd1 & 07) << 12) | wd2; /* indirect ptr */ + +ad = fpp_adxr (ir, ad); /* do indexing */ +if (fpp_sta & FPS_DP) + fpp_opa = ad + 1; +else fpp_opa = ad + 2; +return ad; } uint32 fpp_ad15 (uint32 hi) @@ -738,8 +807,10 @@ if (ir & 0100) { /* increment? */ fpp_write_xr (xr, wd); } if (xr != 0) { /* indexed? */ - if (fpp_sta & FPS_EP) wd = wd * 6; /* scale by len */ - else if (fpp_sta & FPS_DP) wd = wd * 2; + if (fpp_sta & FPS_EP) + wd = wd * 6; /* scale by len */ + else if (fpp_sta & FPS_DP) + wd = wd * 2; else wd = wd * 3; return (base_ad + wd) & ADDRMASK; /* return index */ } @@ -748,22 +819,28 @@ else return base_ad & ADDRMASK; /* return addr */ /* Computation routines */ -/* Fraction/floating add - return true if overflow */ +/* Fraction/floating add */ -t_bool fpp_add (FPN *a, FPN *b, uint32 sub) +void fpp_add (FPN *a, FPN *b, uint32 sub) { FPN x, y, z; -uint32 ediff, c; +uint32 c, ediff; fpp_zcopy (&x, a); /* copy opnds */ fpp_zcopy (&y, b); if (sub) /* subtract? */ fpp_fr_neg (y.fr, EXACT); /* neg B, exact */ if (fpp_sta & FPS_DP) { /* dp? */ - fpp_fr_add (z.fr, x.fr, y.fr); /* z = a + b */ - if ((~x.fr[0] ^ y.fr[0]) & (x.fr[0] ^ z.fr[0]) & FPN_FRSIGN) { + uint32 cout = fpp_fr_add (z.fr, x.fr, y.fr, EXTEND);/* z = a + b */ + uint32 zsign = z.fr[0] & FPN_FRSIGN; + cout = (cout? 04000: 0); /* make sign bit */ + /* overflow is indicated when signs are equal and overflow does not + match the result sign bit */ + fpp_copy (a, &z); /* result is z */ + if (!((x.fr[0] ^ y.fr[0]) & FPN_FRSIGN) && (cout != zsign)) { + fpp_copy (a, &z); /* copy out result */ fpp_dump_apt (fpp_apta, FPS_IOVX); /* int ovf? */ - return TRUE; + return; } } else { /* fp or ep */ @@ -778,11 +855,11 @@ else { /* fp or ep */ y = z; } ediff = x.exp - y.exp; /* exp diff */ - z.exp = x.exp; /* result exp */ - if (ediff <= (fpp_sta & FPS_EP)? 59: 24) { /* any add? */ + if (ediff <= (uint32) ((fpp_sta & FPS_EP)? 59: 24)) { /* any add? */ + z.exp = x.exp; /* result exp */ if (ediff != 0) /* any align? */ fpp_fr_algn (y.fr, ediff, EXTEND); /* align, 60b */ - c = fpp_fr_add (z.fr, x.fr, y.fr); /* add fractions */ + c = fpp_fr_add (z.fr, x.fr, y.fr, EXTEND); /* add fractions */ if ((((x.fr[0] ^ y.fr[0]) & FPN_FRSIGN) == 0) && /* same signs? */ (c || /* carry out? */ ((~x.fr[0] & z.fr[0] & FPN_FRSIGN)))) { /* + to - change? */ @@ -790,57 +867,66 @@ else { /* fp or ep */ z.exp = z.exp + 1; /* incr exp */ } /* end same signs */ } /* end in range */ + else z = x; /* ovrshift */ } /* end ops != 0 */ if (fpp_norm (&z, EXTEND)) /* norm, !exact? */ fpp_round (&z); /* round */ - if (fpp_test_xp (&z)) /* ovf, unf? */ - return TRUE; + fpp_copy (a, &z); /* copy out */ + fpp_test_xp (&z); /* ovf, unf? */ } /* end else */ -fpp_copy (a, &z); /* result is z */ -return FALSE; +return; } -/* Fraction/floating multiply - return true if overflow */ +/* Fraction/floating multiply */ -t_bool fpp_mul (FPN *a, FPN *b) +void fpp_mul (FPN *a, FPN *b) { FPN x, y, z; fpp_zcopy (&x, a); /* copy opnds */ fpp_zcopy (&y, b); +if ((fpp_fr_test(y.fr, 0, EXACT-1) == 0) && (y.fr[EXACT-1] < 2)) { + y.exp = 0; + y.fr[EXACT-1] = 0; +} if (fpp_sta & FPS_DP) /* dp? */ - fpp_fr_mul (z.fr, x.fr, y.fr); /* mult frac */ + fpp_fr_mul (z.fr, x.fr, y.fr, TRUE); /* mult frac */ else { /* fp or ep */ + fpp_norm (&x, EXACT); + fpp_norm (&y, EXACT); z.exp = x.exp + y.exp; /* add exp */ - fpp_fr_mul (z.fr, x.fr, y.fr); /* mult frac */ + fpp_fr_mul (z.fr, x.fr, y.fr, TRUE); /* mult frac */ if (fpp_norm (&z, EXTEND)) /* norm, !exact? */ fpp_round (&z); /* round */ - if (fpp_test_xp (&z)) /* ovf, unf? */ - return TRUE; + fpp_copy (a, &z); + if (z.exp > 2047) + fpp_dump_apt (fpp_apta, FPS_FOVX); /* trap */ + return; } fpp_copy (a, &z); /* result is z */ -return FALSE; +return; } -/* Fraction/floating divide - return true if div by zero or overflow */ +/* Fraction/floating divide */ -t_bool fpp_div (FPN *a, FPN *b) +void fpp_div (FPN *a, FPN *b) { FPN x, y, z; if (fpp_fr_test (b->fr, 0, EXACT) == 0) { /* divisor 0? */ fpp_dump_apt (fpp_apta, FPS_DVZX); /* error */ - return TRUE; + return; } if (fpp_fr_test (a->fr, 0, EXACT) == 0) /* dividend 0? */ - return FALSE; /* quotient is 0 */ + return; /* quotient is 0 */ fpp_zcopy (&x, a); /* copy opnds */ fpp_zcopy (&y, b); if (fpp_sta & FPS_DP) { /* dp? */ if (fpp_fr_div (z.fr, x.fr, y.fr)) { /* fr div, ovflo? */ fpp_dump_apt (fpp_apta, FPS_IOVX); /* error */ - return TRUE; + return; } + fpp_copy (a, &z); /* result is z */ } else { /* fp or ep */ fpp_norm (&y, EXACT); /* norm divisor */ @@ -856,11 +942,15 @@ else { /* fp or ep */ } if (fpp_norm (&z, EXTEND)) /* norm, !exact? */ fpp_round (&z); /* round */ - if (fpp_test_xp (&z)) /* ovf, unf? */ - return TRUE; + fpp_copy (a, &z); + if (z.exp > 2048) { /* underflow? */ + if (fpp_cmd & FPC_UNFX) { /* trap? */ + fpp_dump_apt (fpp_apta, FPS_UNF); + return; + } + } } -fpp_copy (a, &z); /* result is z */ -return FALSE; +return; } /* Integer multiply - returns true if overflow */ @@ -872,15 +962,17 @@ FPN x, y, z; fpp_zcopy (&x, a); /* copy args */ fpp_zcopy (&y, b); -fpp_fr_mul (z.fr, x.fr, y.fr); /* mult fracs */ +fpp_fr_mul (z.fr, x.fr, y.fr, FALSE); /* mult fracs */ +a->fr[0] = z.fr[1]; /* low 24b */ +a->fr[1] = z.fr[2]; +if ((a->fr[0] == 0) && (a->fr[1] == 0)) /* fpp zeroes exp */ + a->exp = 0; /* even in dp mode */ sext = (z.fr[2] & FPN_FRSIGN)? 07777: 0; if (((z.fr[0] | z.fr[1] | sext) != 0) && /* hi 25b == 0 */ ((z.fr[0] & z.fr[1] & sext) != 07777)) { /* or 777777774? */ fpp_dump_apt (fpp_apta, FPS_IOVX); return TRUE; } -a->fr[0] = z.fr[2]; /* low 24b */ -a->fr[1] = z.fr[3]; return FALSE; } @@ -926,7 +1018,7 @@ if (fpp_fr_test (a->fr, 0, cnt) == 0) { /* zero? */ return FALSE; /* don't round */ } while (((a->fr[0] == 0) && !(a->fr[1] & 04000)) || /* lead 13b same? */ - ((a->fr[0] = 07777) && (a->fr[1] & 04000))) { + ((a->fr[0] == 07777) && (a->fr[1] & 04000))) { fpp_fr_lsh12 (a->fr, cnt); /* move word */ a->exp = a->exp - 12; } @@ -967,6 +1059,8 @@ for (i = 0; i < FPN_NFR_EP; i++) { a->fr[i] = b->fr[i]; else a->fr[i] = 0; } +a->fr[i++] = 0; +a->fr[i] = 0; return; } @@ -979,9 +1073,8 @@ if (a->exp > 2047) { /* overflow? */ return TRUE; } if (a->exp < -2048) { /* underflow? */ - fpp_sta |= FPS_UNF; /* set flag */ - if (fpp_sta & FPS_UNFX) { /* trap? */ - fpp_dump_apt (fpp_apta, FPS_UNFX); + if (fpp_cmd & FPC_UNFX) { /* trap? */ + fpp_dump_apt (fpp_apta, FPS_UNF); return TRUE; } fpp_copy (a, &fpp_zero); /* flush to 0 */ @@ -1015,13 +1108,14 @@ return; /* N-precision integer routines */ -/* Fraction add/sub - always carried out to 60b */ +/* Fraction add/sub */ + +uint32 fpp_fr_add (uint32 *c, uint32 *a, uint32 *b, uint32 cnt) -uint32 fpp_fr_add (uint32 *c, uint32 *a, uint32 *b) { uint32 i, cin; -for (i = FPN_NFR_EP, cin = 0; i > 0; i--) { +for (i = cnt, cin = 0; i > 0; i--) { c[i - 1] = a[i - 1] + b[i - 1] + cin; cin = (c[i - 1] >> 12) & 1; c[i - 1] = c[i - 1] & 07777; @@ -1029,11 +1123,11 @@ for (i = FPN_NFR_EP, cin = 0; i > 0; i--) { return cin; } -void fpp_fr_sub (uint32 *c, uint32 *a, uint32 *b) +void fpp_fr_sub (uint32 *c, uint32 *a, uint32 *b, uint32 cnt) { uint32 i, cin; -for (i = FPN_NFR_EP, cin = 0; i > 0; i--) { +for (i = cnt, cin = 0; i > 0; i--) { c[i - 1] = a[i - 1] - b[i - 1] - cin; cin = (c[i - 1] >> 12) & 1; c[i - 1] = c[i - 1] & 07777; @@ -1062,25 +1156,48 @@ return; If a-sign != c-sign, shift-in = result-sign */ -void fpp_fr_mul (uint32 *c, uint32 *a, uint32 *b) +void fpp_fr_mul (uint32 *c, uint32 *a, uint32 *b, t_bool fix) { -uint32 i, cnt, lo, c_old, cin; +uint32 i, cnt, lo, wc, fill, b_sign; -fpp_fr_fill (c, 0, EXTEND); /* clr answer */ +b_sign = b[0] & FPN_FRSIGN; /* remember b's sign */ + +fpp_fr_fill (c, 0, FPN_NFR_MDS); /* clr answer */ if (fpp_sta & FPS_EP) /* ep? */ - lo = FPN_NFR_EP - 1; /* test <59> */ -else lo = FPN_NFR_FP - 1; /* sp, test <23> */ -cnt = (lo + 1) * 12; /* # iterations */ -for (i = 0; i < cnt; i++) { /* loop thru mpcd */ - c_old = c[0]; - if (b[lo] & 1) /* mpcd bit set? */ - fpp_fr_add (c, a, c); /* add mpyr */ - cin = (((a[0] ^ c_old) & FPN_FRSIGN)? c[0]: a[0]) & FPN_FRSIGN; - fpp_fr_rsh1 (c, cin, EXTEND); /* shift answer */ - fpp_fr_rsh1 (b, 0, EXACT); /* shift mpcd */ + lo = FPN_NFR_EP; /* low order mpyr word */ +else + lo = FPN_NFR_FP; /* low order mpyr word */ + +if (fix) + fpp_fr_algn (a, 12, FPN_NFR_MDS + 1); /* fill left with sign */ +wc = 2; /* 3 words at start */ +fill = 0; +cnt = lo * 12; /* total steps */ +for (i = 0; i < cnt; i++) { + if ((i % 12) == 0) { + wc++; /* do another word */ + lo--; /* and next mpyr word */ + fpp_fr_algn (c, 24, wc + 1); + c[wc] = 0; + c[0] = c[1] = fill; /* propagate sign */ + } + if (b[lo] & FPN_FRSIGN) /* mpyr bit set? */ + fpp_fr_add(c, a, c, wc); + fill = ((c[0] & FPN_FRSIGN) ? 07777 : 0); /* remember sign */ + fpp_fr_lsh1 (c, wc); /* shift the result */ + fpp_fr_lsh1 (b + lo, 1); /* shift mpcd */ + } -if (a[0] & FPN_FRSIGN) /* mpyr negative? */ - fpp_fr_sub (c, c, a); /* adjust result */ + +if (!fix) /* imul shifts result */ + fpp_fr_rsh1 (c, c[0] & FPN_FRSIGN, EXACT + 1); /* result is 1 wd right */ +if (b_sign) { /* if mpyr was negative */ + if (fix) + fpp_fr_lsh12 (a, FPN_NFR_MDS+1); /* restore a */ + fpp_fr_sub (c, c, a, EXACT); /* adjust result */ + fpp_fr_sub (c, c, a, EXACT); + } + return; } @@ -1088,29 +1205,35 @@ return; t_bool fpp_fr_div (uint32 *c, uint32 *a, uint32 *b) { -uint32 i, old_c, lo, cnt, sign; +uint32 i, old_c, lo, cnt, sign, b_sign, addsub, limit; +/* Number of words processed by each divide step */ +static uint32 limits[7] = {6, 6, 5, 4, 3, 3, 2}; -fpp_fr_fill (c, 0, EXTEND); /* clr answer */ +fpp_fr_fill (c, 0, FPN_NFR_MDS); /* clr answer */ sign = (a[0] ^ b[0]) & FPN_FRSIGN; /* sign of result */ +b_sign = (b[0] & FPN_FRSIGN); if (a[0] & FPN_FRSIGN) /* |a| */ fpp_fr_neg (a, EXACT); -if (b[0] & FPN_FRSIGN); /* |b| */ - fpp_fr_neg (b, EXACT); -if (fpp_sta & FPS_EP) /* ep? 5 words */ - lo = FPN_NFR_EP - 1; -else lo = FPN_NFR_FP; /* fp, dp? 3 words */ +if (fpp_sta & FPS_EP) /* ep? 6 words */ + lo = FPN_NFR_EP-1; +else lo = FPN_NFR_FP-1; /* fp, dp? 3 words */ cnt = (lo + 1) * 12; +addsub = 04000; /* setup first op */ for (i = 0; i < cnt; i++) { /* loop */ - fpp_fr_lsh1 (c, EXTEND); /* shift quotient */ - if (fpp_fr_cmp (a, b, EXTEND) >= 0) { /* sub work? */ - fpp_fr_sub (a, a, b); /* divd - divr */ - if (a[0] & FPN_FRSIGN) /* sign flip? */ - return TRUE; /* no, overflow */ + limit = limits[i / 12]; /* how many wds this time */ + fpp_fr_lsh1 (c, FPN_NFR_MDS); /* shift quotient */ + if (addsub ^ b_sign) /* diff signs, subtr */ + fpp_fr_sub (a, a, b, limit); /* divd - divr */ + else + fpp_fr_add (a, a, b, limit); /* restore */ + if (!(a[0] & FPN_FRSIGN)) { c[lo] |= 1; /* set quo bit */ + addsub = 04000; /* sign for nxt loop */ } - fpp_fr_lsh1 (a, EXTEND); /* shift dividend */ + else addsub = 0; + fpp_fr_lsh1 (a, limit); /* shift dividend */ } -old_c = c[0]; /* save hi quo */ +old_c = c[0]; /* save ho quo */ if (sign) /* expect neg ans? */ fpp_fr_neg (c, EXTEND); /* -quo */ if (old_c & FPN_FRSIGN) /* sign set before */ @@ -1126,7 +1249,7 @@ uint32 i, cin; for (i = cnt, cin = 1; i > 0; i--) { a[i - 1] = (~a[i - 1] + cin) & 07777; - cin = (a[i - 1] == 0); + cin = (cin != 0 && a[i - 1] == 0); } return cin; } @@ -1244,7 +1367,7 @@ if (sc >= (cnt * 12)) { /* out of range? */ return; } while (sc >= 12) { - for (i = cnt - 1; i > 0; i++) + for (i = cnt - 1; i > 0; i--) a[i] = a[i - 1]; a[0] = sign; sc = sc - 12; @@ -1263,7 +1386,6 @@ void fpp_read_op (uint32 ea, FPN *a) { uint32 i; -fpp_opa = ea; if (!(fpp_sta & FPS_DP)) { a->exp = fpp_read (ea++); a->exp = SEXT12 (a->exp); @@ -1277,7 +1399,7 @@ void fpp_write_op (uint32 ea, FPN *a) { uint32 i; -fpp_opa = ea; +fpp_opa = ea + 2; if (!(fpp_sta & FPS_DP)) fpp_write (ea++, a->exp); for (i = 0; i < EXACT; i++) @@ -1328,7 +1450,7 @@ fpp_fpc = ((wd0 & 07) << 12) | apt_read (ad++); if (FPC_GETFAST (fpp_cmd) != 017) { fpp_xra = ((wd0 & 00070) << 9) | apt_read (ad++); fpp_bra = ((wd0 & 00700) << 6) | apt_read (ad++); - ad++; + fpp_opa = ((wd0 & 07000) << 3) | apt_read (ad++); fpp_ac.exp = apt_read (ad++); for (i = 0; i < EXACT; i++) fpp_ac.fr[i] = apt_read (ad++); @@ -1370,9 +1492,8 @@ return; t_stat fpp_reset (DEVICE *dptr) { sim_cancel (&fpp_unit); -fpp_sta = 0; -fpp_cmd = 0; fpp_flag = 0; +fpp_last_lockbit = 0; int_req &= ~INT_FPP; if (sim_switches & SWMASK ('P')) { fpp_apta = 0; @@ -1382,6 +1503,14 @@ if (sim_switches & SWMASK ('P')) { fpp_xra = 0; fpp_opa = 0; fpp_ac = fpp_zero; + fpp_ssf = 0; + fpp_sta = 0; + fpp_cmd = 0; } +else { + fpp_sta &= ~(FPS_DP|FPS_EP|FPS_TRPX|FPS_DVZX|FPS_IOVX|FPS_FOVX|FPS_UNF); + fpp_cmd &= (FPC_DP|FPC_UNFX|FPC_IE); + } + return SCPE_OK; } diff --git a/PDP8/pdp8_sys.c b/PDP8/pdp8_sys.c index db3a095c..3b550941 100644 --- a/PDP8/pdp8_sys.c +++ b/PDP8/pdp8_sys.c @@ -1,6 +1,6 @@ /* pdp8_sys.c: PDP-8 simulator interface - Copyright (c) 1993-2008, Robert M Supnik + Copyright (c) 1993-2009, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 24-Mar-09 RMS Added link to FPP 24-Jun-08 RMS Fixed bug in new rim loader (found by Don North) 24-May-08 RMS Fixed signed/unsigned declaration inconsistency 03-Sep-07 RMS Added FPP8 support @@ -52,6 +53,7 @@ extern DEVICE cpu_dev; extern UNIT cpu_unit; extern DEVICE tsc_dev; +extern DEVICE fpp_dev; extern DEVICE ptr_dev, ptp_dev; extern DEVICE tti_dev, tto_dev; extern DEVICE clk_dev, lpt_dev; @@ -91,6 +93,7 @@ int32 sim_emax = 4; DEVICE *sim_devices[] = { &cpu_dev, &tsc_dev, + &fpp_dev, &clk_dev, &ptr_dev, &ptp_dev, diff --git a/VAX/vax_cpu.c b/VAX/vax_cpu.c index aad5a5f0..933040f3 100644 --- a/VAX/vax_cpu.c +++ b/VAX/vax_cpu.c @@ -1,6 +1,6 @@ /* vax_cpu.c: VAX CPU - Copyright (c) 1998-2008, Robert M Supnik + Copyright (c) 1998-2010, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,8 @@ cpu VAX central processor + 24-Apr-10 RMS Added OLDVMS idle timer option + Fixed bug in SET CPU IDLE 21-May-08 RMS Removed inline support 28-May-08 RMS Inlined instruction prefetch, physical memory routines 13-Aug-07 RMS Fixed bug in read access g-format indexed specifiers @@ -173,6 +175,8 @@ #define UNIT_CONH (1u << UNIT_V_CONH) #define UNIT_MSIZE (1u << UNIT_V_MSIZE) #define GET_CUR acc = ACC_MASK (PSL_GETCUR (PSL)) +#define VAX_IDLE_DFLT 1000 +#define OLD_IDLE_DFLT 200 #define OPND_SIZE 16 #define INST_SIZE 52 @@ -259,7 +263,7 @@ int32 ibufl, ibufh; /* prefetch buf */ int32 ibcnt, ppc; /* prefetch ctl */ uint32 cpu_idle_ipl_mask = 0x8; /* idle if on IPL 3 */ uint32 cpu_idle_type = 1; /* default to VMS */ -int32 cpu_idle_wait = 1000; /* for these cycles */ +int32 cpu_idle_wait = VAX_IDLE_DFLT; /* for these cycles */ jmp_buf save_env; REG *pcq_r = NULL; /* PC queue reg ptr */ int32 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ @@ -3377,15 +3381,17 @@ return more; struct os_idle { char *name; uint32 mask; + int32 value; }; static struct os_idle os_tab[] = { - { "VMS", 0x8 }, - { "NETBSD", 0x2 }, - { "ULTRIX", 0x2 }, - { "OPENBSD", 0x1 }, - { "32V", 0x1 }, - { NULL, 0 } + { "VMS", 0x8, VAX_IDLE_DFLT }, + { "NETBSD", 0x2, VAX_IDLE_DFLT }, + { "ULTRIX", 0x2, VAX_IDLE_DFLT }, + { "OPENBSD", 0x1, VAX_IDLE_DFLT }, + { "32V", 0x1, VAX_IDLE_DFLT }, + { "OLDVMS", 0xB, OLD_IDLE_DFLT }, + { NULL, 0, 0 } }; /* Set and show idle */ @@ -3399,7 +3405,8 @@ if (cptr != NULL) { if (strcmp (os_tab[i].name, cptr) == 0) { cpu_idle_type = i + 1; cpu_idle_ipl_mask = os_tab[i].mask; - return sim_set_idle (uptr, val, cptr, desc); + cpu_idle_wait = os_tab[i].value; + return sim_set_idle (uptr, val, NULL, desc); } } return SCPE_ARG; diff --git a/descrip.mms b/descrip.mms index f6530a56..1dd77ed7 100644 --- a/descrip.mms +++ b/descrip.mms @@ -2,6 +2,7 @@ # Written By: Robert Alan Byer / byer@mail.ourservers.net # Modified By: Mark Pizzolato / mark@infocomm.com # Norman Lastovica / norman.lastovica@oracle.com +# Camiel Vanderhoeven / camiel@camicom.com # # This MMS/MMK build script is used to compile the various simulators in # the SIMH package for OpenVMS using DEC C v6.0-001(AXP), v6.5-001(AXP), @@ -182,21 +183,24 @@ ALTAIR_OPTIONS = /INCL=($(SIMH_DIR),$(ALTAIR_DIR))/DEF=($(CC_DEFS)) # MITS Altair Z80 Simulator Definitions. # ALTAIRZ80_DIR = SYS$DISK:[.ALTAIRZ80] -ALTAIRZ80_LIB = $(LIB_DIR)ALTAIRZ80-$(ARCH).OLB -ALTAIRZ80_SOURCE = $(ALTAIRZ80_DIR)/ALTAIRZ80_CPU.C,$(ALTAIRZ80_DIR)/ALTAIRZ80_CPU_NOMMU.C,\ - $(ALTAIRZ80_DIR)/ALTAIRZ80_DSK.C,$(ALTAIRZ80_DIR)/DISASM.C,\ - $(ALTAIRZ80_DIR)/ALTAIRZ80_SIO.C,$(ALTAIRZ80_DIR)/ALTAIRZ80_SYS.C,\ - $(ALTAIRZ80_DIR)/ALTAIRZ80_HDSK.C,$(ALTAIRZ80_DIR)/ALTAIRZ80_NET.C,\ - $(ALTAIRZ80_DIR)/FLASHWRITER2.C,$(ALTAIRZ80_DIR)/I86_DECODE.C,\ - $(ALTAIRZ80_DIR)/I86_OPS.C,$(ALTAIRZ80_DIR)/I86_PRIM_OPS.C,\ - $(ALTAIRZ80_DIR)/I8272.C,$(ALTAIRZ80_DIR)/INSNSA.C,$(ALTAIRZ80_DIR)/INSNSD.C,\ - $(ALTAIRZ80_DIR)/MFDC.C,$(ALTAIRZ80_DIR)/N8VEM.C,$(ALTAIRZ80_DIR)/VFDHD.C,\ - $(ALTAIRZ80_DIR)/S100_DISK1A.C,$(ALTAIRZ80_DIR)/S100_DISK2.C,\ - $(ALTAIRZ80_DIR)/S100_FIF.C,$(ALTAIRZ80_DIR)/S100_MDRIVEH.C,\ - $(ALTAIRZ80_DIR)/S100_MDSAD.C,$(ALTAIRZ80_DIR)/S100_SELCHAN.C,\ - $(ALTAIRZ80_DIR)/S100_SS1.C,$(ALTAIRZ80_DIR)/S100_64FDC.C,\ - $(ALTAIRZ80_DIR)/S100_SCP300F.C,$(ALTAIRZ80_DIR)/SIM_IMD.C,\ - $(ALTAIRZ80_DIR)/WD179X.C +ALTAIRZ80_LIB1 = $(LIB_DIR)ALTAIRZ80L1-$(ARCH).OLB +ALTAIRZ80_SOURCE1 = $(ALTAIRZ80_DIR)ALTAIRZ80_CPU.C,$(ALTAIRZ80_DIR)ALTAIRZ80_CPU_NOMMU.C,\ + $(ALTAIRZ80_DIR)ALTAIRZ80_DSK.C,$(ALTAIRZ80_DIR)DISASM.C,\ + $(ALTAIRZ80_DIR)ALTAIRZ80_SIO.C,$(ALTAIRZ80_DIR)ALTAIRZ80_SYS.C,\ + $(ALTAIRZ80_DIR)ALTAIRZ80_HDSK.C,$(ALTAIRZ80_DIR)ALTAIRZ80_NET.C,\ + $(ALTAIRZ80_DIR)FLASHWRITER2.C,$(ALTAIRZ80_DIR)I86_DECODE.C,\ + $(ALTAIRZ80_DIR)I86_OPS.C,$(ALTAIRZ80_DIR)I86_PRIM_OPS.C,\ + $(ALTAIRZ80_DIR)I8272.C,$(ALTAIRZ80_DIR)INSNSA.C,$(ALTAIRZ80_DIR)INSNSD.C,\ + $(ALTAIRZ80_DIR)MFDC.C,$(ALTAIRZ80_DIR)N8VEM.C,$(ALTAIRZ80_DIR)VFDHD.C +ALTAIRZ80_LIB2 = $(LIB_DIR)ALTAIRZ80L2-$(ARCH).OLB +ALTAIRZ80_SOURCE2 = $(ALTAIRZ80_DIR)S100_DISK1A.C,$(ALTAIRZ80_DIR)S100_DISK2.C,\ + $(ALTAIRZ80_DIR)S100_FIF.C,$(ALTAIRZ80_DIR)S100_MDRIVEH.C,\ + $(ALTAIRZ80_DIR)S100_MDSAD.C,$(ALTAIRZ80_DIR)S100_SELCHAN.C,\ + $(ALTAIRZ80_DIR)S100_SS1.C,$(ALTAIRZ80_DIR)S100_64FDC.C,\ + $(ALTAIRZ80_DIR)S100_SCP300F.C,$(ALTAIRZ80_DIR)SIM_IMD.C,\ + $(ALTAIRZ80_DIR)WD179X.C,$(ALTAIRZ80_DIR)S100_DISK3.C,\ + $(ALTAIRZ80_DIR)S100_ADCS6.C,$(ALTAIRZ80_DIR)S100_HDC1001.C,\ + $(ALTAIRZ80_DIR)S100_IF3.C ALTAIRZ80_OPTIONS = /INCL=($(SIMH_DIR),$(ALTAIRZ80_DIR))/DEF=($(CC_DEFS)) # @@ -256,20 +260,21 @@ H316_OPTIONS = /INCL=($(SIMH_DIR),$(H316_DIR))/DEF=($(CC_DEFS)) # Hewlett-Packard HP-2100 Simulator Definitions. # HP2100_DIR = SYS$DISK:[.HP2100] -HP2100_LIB = $(LIB_DIR)HP2100-$(ARCH).OLB -HP2100_SOURCE = $(HP2100_DIR)HP2100_STDDEV.C,$(HP2100_DIR)HP2100_DP.C,\ - $(HP2100_DIR)HP2100_DQ.C,$(HP2100_DIR)HP2100_DR.C,\ - $(HP2100_DIR)HP2100_LPS.C,$(HP2100_DIR)HP2100_MS.C,\ - $(HP2100_DIR)HP2100_MT.C,$(HP2100_DIR)HP2100_MUX.C,\ - $(HP2100_DIR)HP2100_CPU.C,$(HP2100_DIR)HP2100_FP.C,\ - $(HP2100_DIR)HP2100_SYS.C,$(HP2100_DIR)HP2100_LPT.C,\ - $(HP2100_DIR)HP2100_IPL.C,$(HP2100_DIR)HP2100_DS.C,\ - $(HP2100_DIR)HP2100_CPU0.C,$(HP2100_DIR)HP2100_CPU1.C,\ - $(HP2100_DIR)HP2100_CPU2.C,$(HP2100_DIR)HP2100_CPU3.C,\ - $(HP2100_DIR)HP2100_CPU4.C,$(HP2100_DIR)HP2100_CPU5.C,\ - $(HP2100_DIR)HP2100_CPU6.C,$(HP2100_DIR)HP2100_CPU7.C,\ - $(HP2100_DIR)HP2100_FP1.C,$(HP2100_DIR)HP2100_BACI.C,\ - $(HP2100_DIR)HP2100_MPX.C,$(HP2100_DIR)HP2100_PIF.C +HP2100_LIB1 = $(LIB_DIR)HP2100L1-$(ARCH).OLB +HP2100_SOURCE1 = $(HP2100_DIR)HP2100_STDDEV.C,$(HP2100_DIR)HP2100_DP.C,\ + $(HP2100_DIR)HP2100_DQ.C,$(HP2100_DIR)HP2100_DR.C,\ + $(HP2100_DIR)HP2100_LPS.C,$(HP2100_DIR)HP2100_MS.C,\ + $(HP2100_DIR)HP2100_MT.C,$(HP2100_DIR)HP2100_MUX.C,\ + $(HP2100_DIR)HP2100_CPU.C,$(HP2100_DIR)HP2100_FP.C,\ + $(HP2100_DIR)HP2100_SYS.C,$(HP2100_DIR)HP2100_LPT.C,\ + $(HP2100_DIR)HP2100_IPL.C,$(HP2100_DIR)HP2100_DS.C,\ + $(HP2100_DIR)HP2100_CPU0.C,$(HP2100_DIR)HP2100_CPU1.C,\ + $(HP2100_DIR)HP2100_CPU2.C,$(HP2100_DIR)HP2100_CPU3.C,\ + $(HP2100_DIR)HP2100_CPU4.C,$(HP2100_DIR)HP2100_CPU5.C,\ + $(HP2100_DIR)HP2100_CPU6.C,$(HP2100_DIR)HP2100_CPU7.C +HP2100_LIB2 = $(LIB_DIR)HP2100L2-$(ARCH).OLB +HP2100_SOURCE2 = $(HP2100_DIR)HP2100_FP1.C,$(HP2100_DIR)HP2100_BACI.C,\ + $(HP2100_DIR)HP2100_MPX.C,$(HP2100_DIR)HP2100_PIF.C .IF ALPHA_OR_IA64 HP2100_OPTIONS = /INCL=($(SIMH_DIR),$(HP2100_DIR))\ /DEF=($(CC_DEFS),"HAVE_INT64=1") @@ -362,7 +367,7 @@ PDP8_SOURCE = $(PDP8_DIR)PDP8_CPU.C,$(PDP8_DIR)PDP8_CLK.C,\ $(PDP8_DIR)PDP8_SYS.C,$(PDP8_DIR)PDP8_TT.C,\ $(PDP8_DIR)PDP8_TTX.C,$(PDP8_DIR)PDP8_RL.C,\ $(PDP8_DIR)PDP8_TSC.C,$(PDP8_DIR)PDP8_TD.C,\ - $(PDP8_DIR)PDP8_CT.C + $(PDP8_DIR)PDP8_CT.C,$(PDP8_DIR)PDP8_FPP.C PDP8_OPTIONS = /INCL=($(SIMH_DIR),$(PDP8_DIR))/DEF=($(CC_DEFS)) # @@ -509,14 +514,14 @@ I7094_OPTIONS = /INCL=($(SIMH_DIR),$(I7094_DIR))/DEF=($(CC_DEFS)) ALL : ALTAIR ALTAIRZ80 ECLIPSE GRI LGP H316 HP2100 I1401 I1620 IBM1130 ID16 \ ID32 NOVA PDP1 PDP4 PDP7 PDP8 PDP9 PDP10 PDP11 PDP15 S3 VAX VAX780 SDS \ I7094 - @CONTINUE + $! No further actions necessary .ELSE # # Else We Are On VAX And Build Everything EXCEPT the 64b simulators # ALL : ALTAIR ALTAIRZ80 GRI H316 HP2100 I1401 I1620 IBM1130 ID16 ID32 \ NOVA PDP1 PDP4 PDP7 PDP8 PDP9 PDP11 PDP15 S3 VAX VAX780 SDS - @CONTINUE + $! No further actions necessary .ENDIF CLEAN : @@ -559,9 +564,20 @@ $(ALTAIR_LIB) : $(ALTAIR_SOURCE) $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -$(ALTAIRZ80_LIB) : $(ALTAIRZ80_SOURCE) +$(ALTAIRZ80_LIB1) : $(ALTAIRZ80_SOURCE1) $! - $! Building The $(ALTAIRZ80_LIB) Library. + $! Building The $(ALTAIRZ80_LIB1) Library. + $! + $ $(CC)$(ALTAIRZ80_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(ALTAIRZ80_LIB2) : $(ALTAIRZ80_SOURCE2) + $! + $! Building The $(ALTAIRZ80_LIB2) Library. $! $ $(CC)$(ALTAIRZ80_OPTIONS) - /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) @@ -628,9 +644,20 @@ $(H316_LIB) : $(H316_SOURCE) $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -$(HP2100_LIB) : $(HP2100_SOURCE) +$(HP2100_LIB1) : $(HP2100_SOURCE1) $! - $! Building The $(HP2100_LIB) Library. + $! Building The $(HP2100_LIB1) Library. + $! + $ $(CC)$(HP2100_OPTIONS) - + /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) + $ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN - + LIBRARY/CREATE $(MMS$TARGET) + $ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ + $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* + +$(HP2100_LIB2) : $(HP2100_SOURCE2) + $! + $! Building The $(HP2100_LIB2) Library. $! $ $(CC)$(HP2100_OPTIONS) - /OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST) @@ -918,13 +945,14 @@ ALTAIR : $(SIMH_LIB) $(ALTAIR_LIB) $(BLD_DIR)SCP.OBJ,$(ALTAIR_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -ALTAIRZ80 : $(SIMH_LIB) $(ALTAIRZ80_LIB) +ALTAIRZ80 : $(SIMH_LIB) $(ALTAIRZ80_LIB1) $(ALTAIRZ80_LIB2) $! $! Building The $(BIN_DIR)ALTAIRZ80-$(ARCH).EXE Simulator. $! $ $(CC)$(ALTAIRZ80_OPTIONS)/OBJ=$(BLD_DIR) SCP.C $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)ALTAIRZ80-$(ARCH).EXE - - $(BLD_DIR)SCP.OBJ,$(ALTAIRZ80_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $(BLD_DIR)SCP.OBJ,$(ALTAIRZ80_LIB1)/LIBRARY, - + $(ALTAIRZ80_LIB2)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* # @@ -976,13 +1004,14 @@ H316 : $(SIMH_LIB) $(H316_LIB) $(BLD_DIR)SCP.OBJ,$(H316_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* -HP2100 : $(SIMH_LIB) $(HP2100_LIB) +HP2100 : $(SIMH_LIB) $(HP2100_LIB1) $(HP2100_LIB2) $! $! Building The $(BIN_DIR)HP2100-$(ARCH).EXE Simulator. $! $ $(CC)$(HP2100_OPTIONS)/OBJ=$(BLD_DIR) SCP.C $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)HP2100-$(ARCH).EXE - - $(BLD_DIR)SCP.OBJ,$(HP2100_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $(BLD_DIR)SCP.OBJ,$(HP2100_LIB1)/LIBRARY, - + $(HP2100_LIB2)/LIBRARY,$(SIMH_LIB)/LIBRARY $ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;* I1401 : $(SIMH_LIB) $(I1401_LIB) diff --git a/makefile b/makefile index 2b65533f..57cde601 100644 --- a/makefile +++ b/makefile @@ -251,13 +251,19 @@ SDS = ${SDSD}/sds_cpu.c ${SDSD}/sds_drm.c ${SDSD}/sds_dsk.c ${SDSD}/sds_io.c \ ${SDSD}/sds_stddev.c ${SDSD}/sds_sys.c SDS_OPT = -I ${SDSD} +SWTPD = SWTP +SWTP = ${SWTPD}/swtp_cpu.c ${SWTPD}/swtp_dsk.c ${SWTPD}/swtp_sio.c \ + ${SWTPD}/swtp_sys.c +SWTP_OPT = -I ${SWTPD} + + # # Build everything # ALL = pdp1 pdp4 pdp7 pdp8 pdp9 pdp15 pdp11 pdp10 \ vax vax780 nova eclipse hp2100 i1401 i1620 s3 \ altair altairz80 gri i1620 i7094 ibm1130 id16 \ - id32 sds lgp h316 + id32 sds lgp h316 swtp all : ${ALL} @@ -400,3 +406,8 @@ sds : ${BIN}sds${EXE} ${BIN}sds${EXE} : ${SDS} ${SIM} ${CC} ${SDS} ${SIM} ${SDS_OPT} -o $@ ${LDFLAGS} + +swtp : ${BIN}swtp${EXE} + +${BIN}swtp${EXE} : ${SWTP} ${SIM} + ${CC} ${SWTP} ${SIM} ${SWTP_OPT} -o $@ ${LDFLAGS} \ No newline at end of file diff --git a/sim_rev.h b/sim_rev.h index 4ba41b2d..eeaf513e 100644 --- a/sim_rev.h +++ b/sim_rev.h @@ -1,6 +1,6 @@ /* sim_rev.h: simulator revisions and current rev level - Copyright (c) 1993-2008, Robert M Supnik + Copyright (c) 1993-2010, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -29,13 +29,45 @@ #define SIM_MAJOR 3 #define SIM_MINOR 8 -#define SIM_PATCH 1 +#define SIM_PATCH 2 #define SIM_DELTA 0 /* V3.8 revision history patch date module(s) and fix(es) + 2 tbd h316_cpu.c: + - fixed bugs in MPY, DIV introduced in 3.8-1 + + i1401_cd.c: + - fixed read stacker operation in column binary mode + - fixed punch stacker operation (from Van Snyder) + + 1401_cpu.c: + - revised divide algorithm (from Van Snyder) + + i1401_mt.c: + - added no rewind option (from Van Snyder) + + pdp11_rk.c: + - fixed bug in read header (from Walter F Mueller) + + pdp11_rl.c: + - added debug support + + pdp11_rq.c: + - added RD32 support + + pdp8_fpp.c: + - many bug fixes (all from Rick Murphy); now functional + + pdp8_sys.c: + - added link to FPP + + vax_cpu.c: + - added OLDVMS idle timer option + - fixed bug in SET CPU IDLE + 1 08-Feb-09 scp.c: - revised RESTORE unit logic for consistency - "detach_all" ignores error status returns if shutting down (from Dave Bryan) diff --git a/swtp/6800boot.dsk b/swtp/6800boot.dsk new file mode 100644 index 00000000..132cd569 Binary files /dev/null and b/swtp/6800boot.dsk differ diff --git a/swtp/6800work.dsk b/swtp/6800work.dsk new file mode 100644 index 00000000..34a1da5e Binary files /dev/null and b/swtp/6800work.dsk differ diff --git a/swtp/swtp b/swtp/swtp new file mode 100644 index 00000000..67ffe076 Binary files /dev/null and b/swtp/swtp differ diff --git a/swtp/swtp.txt b/swtp/swtp.txt new file mode 100644 index 00000000..4d16f9fb --- /dev/null +++ b/swtp/swtp.txt @@ -0,0 +1,100 @@ +SWTP 6800 Emulator +===================== + +1. Background. + + The Southwest Technical Products (SWTP) SWTP 6800 was announced 1n the 1976 SWTP Catalog, which boasted you could buy and build this powerful computer kit for only $395. The kit consisted at that time of only the parts to build a case, power supply, mother board, CPU card, serial card with RS-232 or 20 ma loop interface, and memory card with 2048 *bytes* of static memory. + +2. Hardware + + We are simulating a fairly "loaded" SWTP 6800 from about 1978, with the following configuration: + + device simulates + name(s) + + CPU SWTP MP-A with Motorola 6080 CPU board, 62KB of RAM, 2K of EPROM with start boot ROM. + SIO SWTP MP-S Dual Serial Interface Board. Port 1 is assumed to be connected to a serial "glass TTY" that is your terminal running the Simulator. + PTR Second serial port of SIO is assumed to be connected to the paper tap reader/punch. + PTP Second serial port of SIO is assumed to be connected to the paper tap reader/punch. + DSK SWTP DC-4 Floppy Disk controller with up to four drives. + +2.1 The CPU Card (MP-A) + + We allow you to select memory sizes, but be aware that some sample software requires the full 32K (i.e. FLEX). We emulate the SWTP SWTBUG boot rom. + + SET CPU ITRAP Causes the simulator to halt if an invalid 8080 Opcode is detected. + SET CPU NOITRAP Does not stop on an invalid Opcode. This is how the real 6800 operates. + SET CPU MTRAP Causes the simulator to halt if an invalid address is accessed. + SET CPU NOMTRAP Does not stop on invalid address access. This is how a real 6800 operates. + SET CPU 4K + SET CPU 8K + SET CPU 12K + SET CPU 16K + ...... + SET CPU 32K All these set various CPU memory configurations. + The 2K EPROM at the high end of memory is always present and will always boot. + SET CPU MA000 Enable 8 K bytes of memory at $A000-$BFFF. Otherwise, only 128 bytes re available at $A000. + SET CPU NOMA000 Enable only 128 bytes of memory at $A000. + +The SWTBUG EPROM maps to both addresses $E000-E3FF and $FC00-FFFF. + +The real 6800, on receiving a HLT (Halt) instruction, freezes the processor and only an interrupt or CPU hardware reset will restore it. The simulator is a lot nicer, it will halt but send you back to the simulator command line. + +CPU Registers include the following: + + name size comments + + PC 16 Program Counter + A 8 Accumulator A + B 8 Accumulator B + IX 16 Index Register + C 1 Carry flag + Z 1 Zero Flag + H 1 Half-Carry flag + I 1 Interrupt flag + N 1 Negative flag + V 1 Overflao Flag + + +2.2 The Serial I/O Card (MP-S) + + This simple programmed I/O device provides 2 serial ports to the outside world, which could be hardware jumpered to support RS-232 plugs or a TTY current loop interface. The standard I/O addresses assigned by SWTP was $8004-8005 for the first port, and $8006-8007 for the second. We follow this standard in the Simulator. + + The simulator directs I/O to/from the first port to the screen. The second port reads from an attachable "tape reader" file on input, and writes to an attachable "punch file" on output. These files are considered a simple stream of 8-bit bytes. + +2.3 The Floppy Disk controller (DC4) + + The SWTP DC4 is a simple programmed I/O interface to the SWTP MF-68 5-inch dual floppy drive, which was basically a pair of Shugart SA-400s with a power supply and buffer board builtin. The controller supports neither interrupts nor DMA, so floppy access required the sustained attention of the CPU. The standard I/O addresses were $8018-801B, and we follow the standard. Details on controlling this hardware are in the swtp_dsk.c source file. + + +3. Sample Software + + Running an SWTP 6800 in 1978 you would be running the FLEX Version 2.0 Operating System from Technical Systems Consultants, Inc. + +3.1 CP/M Version 2.2 + + This version is a port of the standard FLEX Version 2.0 to the SWTP 6800. + + To boot FLEX: + + sim> set cpu hex + sim> set cpu itrap + sim> set cpu mtrap + sim> att dsk 6800boot.dsk + sim> att dsk1 6800work.dsk + sim> set cpu MA000 + sim> set dsk1 rw + sim> go + + $D ; Capital D causes SWTBUG to boot Flex + FLEX 2.0 + + DATE (MM,DD,YY)? 03,09,99 ; Must enter a date from last century! + + +++ ;Flex prompt! + + + + + + diff --git a/swtp/swtp6800 b/swtp/swtp6800 new file mode 100644 index 00000000..0c8c2d1d --- /dev/null +++ b/swtp/swtp6800 @@ -0,0 +1,9 @@ +reset +set cpu hex +set cpu itrap +set cpu mtrap +att dsk 6800boot.dsk +att dsk1 6800work.dsk +set cpu MA000 +set dsk1 rw +g diff --git a/swtp/swtp_cpu.c b/swtp/swtp_cpu.c new file mode 100644 index 00000000..09cdaa83 --- /dev/null +++ b/swtp/swtp_cpu.c @@ -0,0 +1,2293 @@ +/* swtp_6800_cpu.c: SWTP 6800 Motorola 6800 CPU simulator + + Copyright (c) 2005, 2007, William Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + Based on work by Charles E Owen (c) 1997 and Peter Schorn (c) 2002-2005 + + cpu 6800 CPU + + The register state for the 6800 CPU is: + + A<0:7> Accumulator A + B<0:7> Accumulator B + IX<0:15> Index Register + H half-carry flag + I interrupt flag + N negative flag + Z zero flag + V overflow flag + C carry flag + PC<0:15> program counter + SP<0:15> Stack Pointer + + The 6800 is an 8-bit CPU, which uses 16-bit registers to address + up to 64KB of memory. + + The 72 basic instructions come in 1, 2, and 3-byte flavors. + + This routine is the instruction decode routine for the 6800. + It is called from the simulator control program to execute + instructions in simulated memory, starting at the simulated PC. + It runs until 'reason' is set non-zero. + + General notes: + + 1. Reasons to stop. The simulator can be stopped by: + + WAI instruction + I/O error in I/O simulator + Invalid OP code (if ITRAP is set on CPU) + Invalid mamory address (if MTRAP is set on CPU) + + 2. Interrupts. + There are 4 types of interrupt, and in effect they do a + hardware CALL instruction to one of 4 possible high memory addresses. + + 3. Non-existent memory. On the SWTP 6800, reads to non-existent memory + return 0FFH, and writes are ignored. In the simulator, the + largest possible memory is instantiated and initialized to zero. + Thus, only writes need be checked against actual memory size. + + 4. Adding I/O devices. These modules must be modified: + + swtp_6800_cpu.c add I/O service routines to dev_table + swtp_sys.c add pointer to data structures in sim_devices +*/ + +#include + +#include "swtp_defs.h" + +//#include +//#include + +#define UNIT_V_OPSTOP (UNIT_V_UF) /* Stop on Invalid OP? */ +#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP) +#define UNIT_V_MSTOP (UNIT_V_UF+1) /* Stop on Invalid memory? */ +#define UNIT_MSTOP (1 << UNIT_V_MSTOP) +#define UNIT_V_MSIZE (UNIT_V_UF+2) /* Memory Size */ +#define UNIT_MSIZE (1 << UNIT_V_MSIZE) +#define UNIT_V_MA000 (UNIT_V_UF+2) /* 128B or 8kB at 0xA000 */ +#define UNIT_MA000 (1 << UNIT_V_MA000) + +uint8 M[MAXMEMSIZE]; /* Memory */ +int32 A = 0; /* Accumulator A */ +int32 B = 0; /* Accumulator B */ +int32 IX = 0; /* Index register */ +int32 SP = 0; /* Stack pointer */ +int32 H = 0; /* Half-carry flag */ +int32 I = 1; /* Interrupt flag */ +int32 N = 0; /* Negative flag */ +int32 Z = 0; /* Zero flag */ +int32 V = 0; /* Overflow flag */ +int32 C = 0; /* Carry flag */ +int32 saved_PC = 0; /* Program counter */ +int32 INTE = 0; /* Interrupt Enable */ +int32 int_req = 0; /* Interrupt request */ + +int32 mem_fault = 0; /* memory fault flag */ + +extern int32 sim_int_char; +extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ + +/* function prototypes */ + +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_reset (DEVICE *dptr); +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +void dump_regs(); +void go_rel(int32 cond); +int32 get_rel_addr(); +int32 get_dir_val(); +int32 get_dir_addr(); +int32 get_indir_val(); +int32 get_indir_addr(); +int32 get_ext_val(); +int32 get_ext_addr(); +int32 get_psw(); +void set_psw(int32 psw); +void condevalH(int32 res); +void condevalN(int32 res); +void condevalZ(int32 res); +void condevalC(int32 res); +void condevalVa(int32 op1, int32 op2); +void condevalVs(int32 op1, int32 op2); +void mem_put_byte(int32 addr, int32 val); +void mem_put_word(int32 addr, int32 val); +int32 mem_get_byte(int32 addr); +int32 mem_get_word(int32 addr); +int32 nulldev(int32 io, int32 data); + +/* external routines */ + +extern int32 sio0s(int32 io, int32 data); +extern int32 sio0d(int32 io, int32 data); +extern int32 sio1s(int32 io, int32 data); +extern int32 sio1d(int32 io, int32 data); +extern int32 fdcdrv(int32 io, int32 data); +extern int32 fdccmd(int32 io, int32 data); +extern int32 fdctrk(int32 io, int32 data); +extern int32 fdcsec(int32 io, int32 data); +extern int32 fdcdata(int32 io, int32 data); +extern int32 fprint_sym (FILE *of, int32 addr, uint32 *val, + UNIT *uptr, int32 sw); + + +/* This is the I/O configuration table. There are 32 possible +device addresses, if a device is plugged into a port it's routine +address is here, 'nulldev' means no device is available +*/ + +struct idev { + int32 (*routine)(); +}; + +struct idev dev_table[32] = { + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 0 8000-8003*/ + {&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /*Port 1 8004-8007*/ +/* sio1x routines just return the last value read on the matching + sio0x routine. SWTBUG tests for the MP-C with most port reads! */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 2 8008-800B*/ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 3 800C-800F*/ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 4 8010-8013*/ + {&fdcdrv}, {&nulldev}, {&nulldev}, {&nulldev}, /*Port 5 8014-8017*/ + {&fdccmd}, {&fdctrk}, {&fdcsec}, {&fdcdata}, /*Port 6 8018-801B*/ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev} /*Port 7 801C-801F*/ +}; + +/* SWTP 6800 SWTBUG BOOT EPROM, fits at 0E000-0E3FFH and replicated + at 0FC000-0FFFF for the interrupt vectors */ + +#define BOOTLEN 1024 + +int32 bootrom[BOOTLEN] = { +0xFE,0xA0,0x00,0x6E,0x00,0x8D,0x40,0x6E, +0x00,0x10,0x16,0x04,0xBD,0xE3,0x34,0x8D, +0x67,0x81,0x53,0x26,0xFA,0x8D,0x61,0x81, +0x39,0x27,0x29,0x81,0x31,0x26,0xF0,0x7F, +0xA0,0x0F,0x8D,0x31,0x80,0x02,0xB7,0xA0, +0x47,0x8D,0x1C,0x8D,0x28,0x7A,0xA0,0x47, +0x27,0x09,0xA7,0x00,0xA1,0x00,0x26,0x08, +0x08,0x20,0xF0,0x7C,0xA0,0x0F,0x27,0xCF, +0x86,0x3F,0x8D,0x31,0x7E,0xE2,0xD4,0x8D, +0x0C,0xB7,0xA0,0x0D,0x8D,0x07,0xB7,0xA0, +0x0E,0xFE,0xA0,0x0D,0x39,0x8D,0x53,0x48, +0x48,0x48,0x48,0x16,0x8D,0x4C,0x1B,0x16, +0xFB,0xA0,0x0F,0xF7,0xA0,0x0F,0x39,0x44, +0x44,0x44,0x44,0x84,0x0F,0x8B,0x30,0x81, +0x39,0x23,0x02,0x8B,0x07,0x7E,0xE1,0xD1, +0x7E,0xE1,0xAC,0x8D,0xF8,0x08,0xA6,0x00, +0x81,0x04,0x26,0xF7,0x39,0x7E,0xE1,0x4A, +0x8D,0xBD,0xCE,0xE1,0x9D,0x8D,0xEF,0xCE, +0xA0,0x0D,0x8D,0x34,0xFE,0xA0,0x0D,0x8D, +0x31,0x8D,0x31,0x8D,0xDB,0x81,0x20,0x27, +0xFA,0x81,0x0D,0x27,0xE0,0x81,0x5E,0x20, +0x2C,0x01,0x8D,0xCC,0x80,0x30,0x2B,0x4C, +0x81,0x09,0x2F,0x0A,0x81,0x11,0x2B,0x44, +0x81,0x16,0x2E,0x40,0x80,0x07,0x39,0xA6, +0x00,0x8D,0xA4,0xA6,0x00,0x08,0x20,0xA3, +0x8D,0xF5,0x8D,0xF3,0x86,0x20,0x20,0xA5, +0x8E,0xA0,0x42,0x20,0x2C,0x26,0x07,0x09, +0x09,0xFF,0xA0,0x0D,0x20,0xAC,0xFF,0xA0, +0x0D,0x20,0x02,0x20,0x6D,0x81,0x30,0x25, +0xA1,0x81,0x46,0x22,0x9D,0x8D,0xBD,0xBD, +0xE0,0x57,0x09,0xA7,0x00,0xA1,0x00,0x27, +0x91,0x7E,0xE0,0x40,0xBE,0xA0,0x08,0x20, +0x49,0xBF,0xA0,0x08,0x86,0xFF,0xBD,0xE3, +0x08,0xCE,0x80,0x04,0xBD,0xE2,0x84,0xA6, +0x00,0xA1,0x02,0x20,0x02,0x20,0x19,0x26, +0x39,0x86,0x03,0xA7,0x00,0x86,0x11,0xA7, +0x00,0x20,0x2F,0x01,0xBF,0xA0,0x08,0x30, +0x6D,0x06,0x26,0x02,0x6A,0x05,0x6A,0x06, +0xCE,0xE1,0x9D,0xBD,0xE0,0x7E,0xFE,0xA0, +0x08,0x08,0x8D,0x8E,0x8D,0x8C,0x8D,0x8A, +0x8D,0x86,0x8D,0x84,0xCE,0xA0,0x08,0xBD, +0xE0,0xC8,0xFE,0xA0,0x12,0x8C,0xE1,0x23, +0x27,0x19,0x8E,0xA0,0x42,0xCE,0x80,0x04, +0xFF,0xA0,0x0A,0x7F,0xA0,0x0C,0x8D,0x73, +0x27,0x03,0xBD,0xE2,0x7D,0xBD,0xE3,0x53, +0xBD,0xE3,0x47,0xCE,0xE1,0x9C,0xBD,0xE0, +0x7E,0x8D,0x39,0xCE,0xE3,0xD1,0xA1,0x00, +0x26,0x07,0xBD,0xE0,0xCC,0xEE,0x01,0x6E, +0x00,0x08,0x08,0x08,0x8C,0xE3,0xF8,0x26, +0xED,0x20,0xBF,0xFE,0xA0,0x12,0x6E,0x00, +0x53,0x39,0x04,0x0D,0x0A,0x15,0x00,0x00, +0x00,0x53,0x31,0x04,0x13,0x0D,0x0A,0x15, +0x00,0x00,0x00,0x24,0x04,0x20,0x4C,0xFE, +0xA0,0x06,0x6E,0x00,0x20,0x40,0xBD,0xE0, +0x47,0xFF,0xA0,0x04,0xBD,0xE0,0x47,0xBD, +0xE0,0x55,0x16,0xA6,0x00,0xFF,0xA0,0x0D, +0x11,0x27,0x02,0x20,0x21,0xCE,0xE1,0x9D, +0xBD,0xE0,0x7E,0xCE,0xA0,0x0D,0x20,0x10, +0x3B,0x20,0x3A,0xFF,0xA0,0x10,0xFE,0xA0, +0x0A,0x37,0xE6,0x01,0xE1,0x03,0x33,0x39, +0xBD,0xE0,0xC8,0xFE,0xA0,0x0D,0xBC,0xA0, +0x04,0x27,0x9E,0x08,0x20,0xCD,0x8D,0x06, +0x84,0x7F,0x39,0x31,0x31,0x31,0x37,0x8D, +0xDA,0x26,0x28,0x86,0x15,0xA7,0x00,0xA6, +0x00,0x47,0x24,0xFB,0xA6,0x01,0xF6,0xA0, +0x0C,0x27,0x07,0x20,0x11,0x37,0x8D,0xC3, +0x26,0x2E,0xC6,0x11,0xE7,0x00,0xE6,0x00, +0x57,0x57,0x24,0xFA,0xA7,0x01,0x33,0xFE, +0xA0,0x10,0x39,0xA6,0x00,0x2B,0xFC,0x8D, +0x3A,0xC6,0x04,0xE7,0x02,0x58,0x8D,0x2A, +0x0D,0x69,0x00,0x46,0x5A,0x26,0xF7,0x8D, +0x21,0xF6,0xA0,0x0C,0x27,0x13,0x20,0xDE, +0x8D,0x23,0xC6,0x0A,0x6A,0x00,0x8D,0x16, +0x8D,0x10,0xA7,0x00,0x0D,0x46,0x5A,0x26, +0xF7,0xE6,0x02,0x58,0x2A,0xC8,0x8D,0x02, +0x20,0xC4,0x6D,0x02,0x2A,0xFC,0x6C,0x02, +0x6A,0x02,0x39,0x6F,0x02,0x8D,0xF7,0x20, +0xF1,0x8D,0x83,0x16,0x7F,0xA0,0x0B,0xFE, +0xA0,0x0A,0x8D,0x10,0x8D,0x07,0xCE,0xE3, +0xEF,0x17,0x7E,0xE1,0x76,0x86,0x34,0xA7, +0x03,0xA7,0x02,0x39,0x6C,0x00,0x86,0x07, +0xA7,0x01,0x6C,0x00,0xA7,0x02,0x39,0x7F, +0x80,0x14,0x8D,0x2E,0xC6,0x0B,0x8D,0x25, +0xE6,0x04,0xC5,0x01,0x26,0xFA,0x6F,0x06, +0x8D,0x1D,0xC6,0x9C,0x8D,0x17,0xCE,0x24, +0x00,0xC5,0x02,0x27,0x06,0xB6,0x80,0x1B, +0xA7,0x00,0x08,0xF6,0x80,0x18,0xC5,0x01, +0x26,0xEF,0x7E,0x24,0x00,0xE7,0x04,0x8D, +0x00,0x39,0xCE,0xFF,0xFF,0x09,0x8C,0x80, +0x14,0x26,0xFA,0x39,0xCE,0xE0,0x09,0xBD, +0xE0,0x7E,0x8D,0xF1,0xBD,0xE3,0x47,0x20, +0x58,0xCE,0xE1,0x23,0xBC,0xA0,0x12,0x27, +0x1A,0x08,0x8D,0x32,0xBD,0xE0,0x47,0xFF, +0xA0,0x14,0xA6,0x00,0xB7,0xA0,0x16,0x86, +0x3F,0xA7,0x00,0xCE,0xE1,0x23,0x8D,0x1E, +0x7E,0xE1,0x6B,0xFE,0xA0,0x14,0xB6,0xA0, +0x16,0xA7,0x00,0xCE,0xE1,0x24,0x20,0xDA, +0xB7,0xA0,0x43,0xFE,0xA0,0x12,0x8C,0xE1, +0x23,0x27,0x06,0xCE,0xE1,0x24,0xFF,0xA0, +0x12,0x39,0x8D,0x5A,0x20,0x0F,0xCE,0xA0, +0x49,0xFF,0xA0,0x04,0x09,0x8D,0x52,0xCE, +0xE1,0x90,0xBD,0xE0,0x7E,0x8D,0x24,0x8D, +0x91,0x7E,0xE1,0x52,0x73,0xA0,0x0C,0x86, +0x11,0xC6,0x20,0x8D,0x1A,0xBD,0xE1,0xD9, +0x27,0x04,0x86,0x3C,0xA7,0x03,0x39,0x86, +0x13,0xC6,0x10,0x20,0x0A,0x86,0x12,0xC6, +0x04,0x20,0x04,0x86,0x14,0xC6,0x08,0xBD, +0xE0,0x75,0xBD,0xE1,0xD6,0x27,0x16,0x86, +0x02,0xCA,0x01,0x8D,0x0C,0x8D,0x08,0x86, +0x02,0xC6,0x01,0xE7,0x00,0x8D,0x02,0x86, +0x06,0xA7,0x01,0xE7,0x00,0x39,0xFE,0xA0, +0x02,0xFF,0xA0,0x44,0x8D,0xCF,0xB6,0xA0, +0x05,0xB0,0xA0,0x45,0xF6,0xA0,0x04,0xF2, +0xA0,0x44,0x26,0x04,0x81,0x10,0x25,0x02, +0x86,0x0F,0x8B,0x04,0xB7,0xA0,0x47,0x80, +0x03,0xB7,0xA0,0x46,0xCE,0xE1,0x93,0xBD, +0xE0,0x7E,0x5F,0xCE,0xA0,0x47,0x8D,0x24, +0xCE,0xA0,0x44,0x8D,0x1F,0x8D,0x1D,0xFE, +0xA0,0x44,0x8D,0x18,0x7A,0xA0,0x46,0x26, +0xF9,0xFF,0xA0,0x44,0x53,0x37,0x30,0x8D, +0x0B,0x33,0xFE,0xA0,0x44,0x09,0xBC,0xA0, +0x04,0x26,0xB3,0x39,0xEB,0x00,0x7E,0xE0, +0xBF,0x47,0xE1,0xD0,0x5A,0xC0,0x00,0x4D, +0xE0,0x88,0x46,0xE1,0xAE,0x52,0xE1,0x30, +0x4A,0xE0,0x05,0x43,0xE2,0xCC,0x44,0xE2, +0x8F,0x42,0xE2,0xD9,0x4F,0xE2,0x69,0x50, +0xE3,0x1A,0x4C,0xE0,0x0C,0x45,0xE3,0x1E, +0xE0,0x00,0xE1,0x8B,0xE1,0xA7,0xE0,0xD0 +}; + +/* CPU data structures + + cpu_dev CPU device descriptor + cpu_unit CPU unit descriptor + cpu_reg CPU register list + cpu_mod CPU modifiers list */ + +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, + 32768) }; + +REG cpu_reg[] = { + { HRDATA (PC, saved_PC, 16) }, + { HRDATA (A, A, 8) }, + { HRDATA (B, B, 8) }, + { HRDATA (IX, IX, 16) }, + { HRDATA (SP, SP, 16) }, + { FLDATA (H, H, 16) }, + { FLDATA (I, I, 16) }, + { FLDATA (N, N, 16) }, + { FLDATA (Z, Z, 16) }, + { FLDATA (V, V, 16) }, + { FLDATA (C, C, 16) }, + { FLDATA (INTE, INTE, 16) }, + { ORDATA (WRU, sim_int_char, 8) }, + { NULL } }; + +MTAB cpu_mod[] = { + { UNIT_OPSTOP, UNIT_OPSTOP, "ITRAP", "ITRAP", NULL }, + { UNIT_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL }, + { UNIT_MSTOP, UNIT_MSTOP, "MTRAP", "MTRAP", NULL }, + { UNIT_MSTOP, 0, "NOMTRAP", "NOMTRAP", NULL }, + { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size }, + { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size }, + { UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size }, + { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size }, + { UNIT_MSIZE, 20480, NULL, "20K", &cpu_set_size }, + { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size }, + { UNIT_MSIZE, 28672, NULL, "28K", &cpu_set_size }, + { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size }, + { UNIT_MA000, UNIT_MA000, "MA000", "MA000", NULL }, + { UNIT_MA000, 0, "NOMA000", "NOMA000", NULL }, + { 0 } }; + +DEVICE cpu_dev = { + "CPU", &cpu_unit, cpu_reg, cpu_mod, + 1, 16, 16, 1, 16, 8, + &cpu_ex, &cpu_dep, &cpu_reset, + NULL, NULL, NULL }; + +int32 PC; /* global for the helper routines */ + +int32 sim_instr (void) +{ + extern int32 sim_interval; + int32 IR, OP, DAR, reason, hi, lo, op1; +// uint32 val1[3]; + + PC = saved_PC & ADDRMASK; /* load local PC */ + reason = 0; + + /* Main instruction fetch/decode loop */ + + while (reason == 0) { /* loop until halted */ + if (sim_interval <= 0) /* check clock queue */ + if (reason = sim_process_event ()) + break; + if (mem_fault) { /* memory fault? */ + mem_fault = 0; /* reset fault flag */ + reason = STOP_MEMORY; + break; + } + if (int_req > 0) { /* interrupt? */ + /* 6800 interrupts not implemented yet. None were used, + on a standard SWTP 6800. All I/O is programmed. */ + } /* end interrupt */ + if (sim_brk_summ && + sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; + } + /* transient routine area - trace */ + /* + if (PC >= 0xa100 && PC < 0xa400) { + dump_regs(); + printf("\n\r%04X: ", PC); + val1[0] = M[PC]; + val1[1] = M[PC+1]; + val1[2] = M[PC+2]; + fprint_sym(stdout, PC, val1, NULL, SWMASK ('M')); + } +*/ + IR = OP = mem_get_byte(PC); /* fetch instruction */ + PC = ++PC & ADDRMASK; /* increment PC */ + sim_interval--; + + /* The Big Instruction Decode Switch */ + + switch (IR) { + + case 0x01: /* NOP */ + break; + case 0x06: /* TAP */ + set_psw(A); + break; + case 0x07: /* TPA */ + A = get_psw(); + break; + case 0x08: /* INX */ + IX = ++IX & ADDRMASK; + condevalZ(IX); + break; + case 0x09: /* DEX */ + IX = --IX & ADDRMASK; + condevalZ(IX); + break; + case 0x0A: /* CLV */ + V = 0; + break; + case 0x0B: /* SEV */ + V = 0x10000; + break; + case 0x0C: /* CLC */ + C = 0; + break; + case 0x0D: /* SEC */ + C = 0x10000; + break; + case 0x0E: /* CLI */ + I = 0; + break; + case 0x0F: /* SEI */ + I = 0x10000; + break; + case 0x10: /* SBA */ + op1 = A; + A = A - B; + condevalN(A); + condevalZ(A); + condevalC(A); + condevalVs(B, op1); + A &= 0xFF; + break; + case 0x11: /* CBA */ + lo = A - B; + condevalN(lo); + condevalZ(lo); + condevalC(lo); + condevalVs(B, A); + break; + case 0x16: /* TAB */ + B = A; + condevalN(B); + condevalZ(B); + V = 0; + break; + case 0x17: /* TBA */ + A = B; + condevalN(B); + condevalZ(B); + V = 0; + break; + case 0x19: /* DAA */ + DAR = A & 0x0F; + op1 = C; + if (DAR > 9 || C) { + DAR += 6; + A &= 0xF0; + A |= DAR & 0x0F; + C = 0; + if (DAR & 0x10) + C = 0x10000; + } + DAR = (A >> 4) & 0x0F; + if (DAR > 9 || C) { + DAR += 6; + if (C) + DAR++; + A &= 0x0F; + A |= (DAR << 4); + } + C = op1; + if ((DAR << 4) & 0x100) + C = 0x10000; + condevalN(A); + condevalZ(A); + A &= 0xFF; + break; + case 0x1B: /* ABA */ + A += B; + condevalH(A); + condevalN(A); + condevalZ(A); + condevalC(A); + condevalVa(A, B); + A &= 0xFF; + break; + case 0x20: /* BRA rel */ + go_rel(1); + break; + case 0x22: /* BHI rel */ + go_rel(!(C | Z)); + break; + case 0x23: /* BLS rel */ + go_rel(C | Z); + break; + case 0x24: /* BCC rel */ + go_rel(!C); + break; + case 0x25: /* BCS rel */ + go_rel(C); + break; + case 0x26: /* BNE rel */ + go_rel(!Z); + break; + case 0x27: /* BEQ rel */ + go_rel(Z); + break; + case 0x28: /* BVC rel */ + go_rel(!V); + break; + case 0x29: /* BVS rel */ + go_rel(V); + break; + case 0x2A: /* BPL rel */ + go_rel(!N); + break; + case 0x2B: /* BMI rel */ + go_rel(N); + break; + case 0x2C: /* BGE rel */ + go_rel(!(N ^ V)); + break; + case 0x2D: /* BLT rel */ + go_rel(N ^ V); + break; + case 0x2E: /* BGT rel */ + go_rel(!(Z | (N ^ V))); + break; + case 0x2F: /* BLE rel */ + go_rel(Z | (N ^ V)); + break; + case 0x30: /* TSX */ + IX = (SP + 1) & ADDRMASK; + break; + case 0x31: /* INS */ + SP = ++SP & ADDRMASK; + break; + case 0x32: /* PUL A */ + SP = ++SP & ADDRMASK; + A = mem_get_byte(SP); + break; + case 0x33: /* PUL B */ + SP = ++SP & ADDRMASK; + B = mem_get_byte(SP); + break; + case 0x34: /* DES */ + SP = --SP & ADDRMASK; + break; + case 0x35: /* TXS */ + SP = (IX - 1) & ADDRMASK; + break; + case 0x36: /* PSH A */ + mem_put_byte(SP, A); + SP = --SP & ADDRMASK; + break; + case 0x37: /* PSH B */ + mem_put_byte(SP, B); + SP = --SP & ADDRMASK; + break; + case 0x39: /* RTS */ + SP = ++SP & ADDRMASK; + PC = mem_get_word(SP) & ADDRMASK; + SP = ++SP & ADDRMASK; + break; + case 0x3B: /* RTI */ + SP = ++SP & ADDRMASK; + set_psw(mem_get_byte(SP)); + SP = ++SP & ADDRMASK; + B = mem_get_byte(SP); + SP = ++SP & ADDRMASK; + A = mem_get_byte(SP); + SP = ++SP & ADDRMASK; + IX = mem_get_word(SP); + SP = (SP += 2) & ADDRMASK; + PC = mem_get_word(SP) & ADDRMASK; + SP = ++SP & ADDRMASK; + break; + case 0x3E: /* WAI */ + SP = --SP & ADDRMASK; + mem_put_word(SP, PC); + SP = (SP -= 2) & ADDRMASK; + mem_put_word(SP, IX); + SP = --SP & ADDRMASK; + mem_put_byte(SP, A); + SP = --SP & ADDRMASK; + mem_put_byte(SP, B); + SP = --SP & ADDRMASK; + mem_put_byte(SP, get_psw()); + SP = --SP & ADDRMASK; + if (I) { + reason = STOP_HALT; + continue; + } else { + I = 0x10000; + PC = mem_get_word(0xFFFE) & ADDRMASK; + } + break; + case 0x3F: /* SWI */ + SP = --SP & ADDRMASK; + mem_put_word(SP, PC); + SP = (SP -= 2) & ADDRMASK; + mem_put_word(SP, IX); + SP = --SP & ADDRMASK; + mem_put_byte(SP, A); + SP = --SP & ADDRMASK; + mem_put_byte(SP, B); + SP = --SP & ADDRMASK; + mem_put_byte(SP, get_psw()); + SP = --SP & ADDRMASK; + I = 0x10000; + PC = mem_get_word(0xFFFB) & ADDRMASK; + break; + case 0x40: /* NEG A */ + A = (0 - A) & 0xFF; + V = 0; + if (A & 0x80) + V = 0x10000; + C = 0; + if (A) + C = 0x10000; + condevalN(A); + condevalZ(A); + break; + case 0x43: /* COM A */ + A = ~A & 0xFF; + V = 0; + C = 0x10000; + condevalN(A); + condevalZ(A); + break; + case 0x44: /* LSR A */ + C = 0; + if (A & 0x01) + C = 0x10000; + A = (A >> 1) & 0xFF; + N = 0; + condevalZ(A); + V = 0; + if (N ^ C) + V = 0x10000; + break; + case 0x46: /* ROR A */ + hi = C; + C = 0; + if (A & 0x01) + C = 0x10000; + A = (A >> 1) & 0xFF; + if (hi) + A |= 0x80; + condevalN(A); + condevalZ(A); + V = 0; + if (N ^ C) + V = 0x10000; + break; + case 0x47: /* ASR A */ + C = 0; + if (A & 0x01) + C = 0x10000; + lo = A & 0x8000; + A = (A >> 1) & 0xFF; + A |= lo; + condevalN(A); + condevalZ(A); + V = 0; + if (N ^ C) + V = 0x10000; + break; + case 0x48: /* ASL A */ + C = 0; + if (A & 0x80) + C = 0x10000; + A = (A << 1) & 0xFF; + condevalN(A); + condevalZ(A); + V = 0; + if (N ^ C) + V = 0x10000; + break; + case 0x49: /* ROL A */ + hi = C; + C = 0; + if (A & 0x80) + C = 0x10000; + A = (A << 1) & 0xFF; + if (hi) + A |= 0x01; + condevalN(A); + condevalZ(A); + V = 0; + if (N ^ C) + V = 0x10000; + break; + case 0x4A: /* DEC A */ + V = 0; + if (A == 0x80) + V = 0x10000; + A = --A & 0xFF; + condevalN(A); + condevalZ(A); + break; + case 0x4C: /* INC A */ + V = 0; + if (A == 0x7F) + V = 0x10000; + A = ++A & 0xFF; + condevalN(A); + condevalZ(A); + break; + case 0x4D: /* TST A */ + lo = (A - 0) & 0xFF; + V = 0; + C = 0; + condevalN(lo); + condevalZ(lo); + break; + case 0x4F: /* CLR A */ + A = 0; + N = V = C = 0; + Z = 0x10000; + break; + case 0x50: /* NEG B */ + B = (0 - V) & 0xFF; + V = 0; + if (B & 0x8000) + V = 0x10000; + C = 0; + if (B) + C = 0x10000; + condevalN(B); + condevalZ(B); + break; + case 0x53: /* COM B */ + B = ~B & 0xFF; + V = 0; + C = 0x10000; + condevalN(B); + condevalZ(B); + break; + case 0x54: /* LSR B */ + C = 0; + if (B & 0x01) + C = 0x10000; + B = (B >> 1) & 0xFF; + N = 0; + condevalZ(B); + V = 0; + if (N ^ C) + V = 0x10000; + break; + case 0x56: /* ROR B */ + hi = C; + C = 0; + if (B & 0x01) + C = 0x10000; + B = (B >> 1) & 0xFF; + if (hi) + B |= 0x80; + condevalN(B); + condevalZ(B); + V = 0; + if (N ^ C) + V = 0x10000; + break; + case 0x57: /* ASR B */ + C = 0; + if (B & 0x01) + C = 0x10000; + lo = B & 0x8000; + B = (B >> 1) & 0xFF; + B |= lo; + condevalN(B); + condevalZ(B); + V = 0; + if (N ^ C) + V = 0x10000; + break; + case 0x58: /* ASL B */ + C = 0; + if (B & 0x80) + C = 0x10000; + B = (B << 1) & 0xFF; + condevalN(B); + condevalZ(B); + V = 0; + if (N ^ C) + V = 0x10000; + break; + case 0x59: /* ROL B */ + hi = C; + C = 0; + if (B & 0x80) + C = 0x10000; + B = (B << 1) & 0xFF; + if (hi) + B |= 0x01; + condevalN(B); + condevalZ(B); + V = 0; + if (N ^ C) + V = 0x10000; + break; + case 0x5A: /* DEC B */ + V = 0; + if (B == 0x80) + V = 0x10000; + B = --B & 0xFF; + condevalN(B); + condevalZ(B); + break; + case 0x5C: /* INC B */ + V = 0; + if (B == 0x7F) + V = 0x10000; + B = ++B & 0xFF; + condevalN(B); + condevalZ(B); + break; + case 0x5D: /* TST B */ + lo = (B - 0) & 0xFF; + V = 0; + C = 0; + condevalN(lo); + condevalZ(lo); + break; + case 0x5F: /* CLR B */ + B = 0; + N = V = C = 0; + Z = 0x10000; + break; + case 0x60: /* NEG ind */ + DAR = get_indir_addr(); + lo = (0 - mem_get_byte(DAR)) & 0xFF; + mem_put_byte(DAR, lo); + V = 0; + if (lo & 0x80) + V = 0x10000; + C = 0; + if (lo) + C = 0x10000; + condevalN(lo); + condevalZ(lo); + break; + case 0x63: /* COM ind */ + DAR = get_indir_addr(); + lo = ~mem_get_byte(DAR) & 0xFF; + mem_put_byte(DAR, lo); + V = 0; + C = 0x10000; + condevalN(lo); + condevalZ(lo); + break; + case 0x64: /* LSR ind */ + DAR = get_indir_addr(); + lo = mem_get_byte(DAR); + C = 0; + if (lo & 0x01) + C = 0x10000; + lo >>= 1; + mem_put_byte(DAR, lo); + N = 0; + condevalZ(lo); + V = 0; + if (N ^ C) + V = 0x10000; + break; + case 0x66: /* ROR ind */ + DAR = get_indir_addr(); + lo = mem_get_byte(DAR); + hi = C; + C = 0; + if (lo & 0x01) + C = 0x10000; + lo >>= 1; + if (hi) + lo |= 0x80; + mem_put_byte(DAR, lo); + condevalN(lo); + condevalZ(lo); + V = 0; + if (N ^ C) + V = 0x10000; + break; + case 0x67: /* ASR ind */ + DAR = get_indir_addr(); + lo = mem_get_byte(DAR); + C = 0; + if (lo & 0x01) + C = 0x10000; + lo = (lo & 0x80) | (lo >> 1); + mem_put_byte(DAR, lo); + condevalN(lo); + condevalZ(lo); + V = 0; + if (N ^ C) + V = 0x10000; + break; + case 0x68: /* ASL ind */ + DAR = get_indir_addr(); + lo = mem_get_byte(DAR); + C = 0; + if (lo & 0x80) + C = 0x10000; + lo <<= 1; + mem_put_byte(DAR, lo); + condevalN(lo); + condevalZ(lo); + V = 0; + if (N ^ C) + V = 0x10000; + break; + case 0x69: /* ROL ind */ + DAR = get_indir_addr(); + lo = mem_get_byte(DAR); + hi = C; + C = 0; + if (lo & 0x80) + C = 0x10000; + lo <<= 1; + if (hi) + lo |= 0x01; + mem_put_byte(DAR, lo); + condevalN(lo); + condevalZ(lo); + V = 0; + if (N ^ C) + V = 0x10000; + break; + case 0x6A: /* DEC ind */ + DAR = get_indir_addr(); + lo = mem_get_byte(DAR); + V = 0; + if (lo == 0x80) + V = 0x10000; + lo = --lo & 0xFF; + mem_put_byte(DAR, lo); + condevalN(lo); + condevalZ(lo); + break; + case 0x6C: /* INC ind */ + DAR= get_indir_addr(); + lo = mem_get_byte(DAR); + V = 0; + if (lo == 0x7F) + V = 0x10000; + lo = ++lo & 0xFF; + mem_put_byte(DAR, lo); + condevalN(lo); + condevalZ(lo); + break; + case 0x6D: /* TST ind */ + lo = (get_indir_val() - 0) & 0xFF; + V = 0; + C = 0; + condevalN(lo); + condevalZ(lo); + break; + case 0x6E: /* JMP ind */ + PC = get_indir_addr(); + break; + case 0x6F: /* CLR ind */ + mem_put_byte(get_indir_addr(), 0); + N = V = C = 0; + Z = 0x10000; + break; + case 0x70: /* NEG ext */ + DAR = get_ext_addr(PC); + lo = (0 - mem_get_byte(DAR)) & 0xFF; + mem_put_byte(DAR, lo); + V = 0; + if (lo & 0x80) + V = 0x10000; + C = 0; + if (lo) + C = 0x10000; + condevalN(lo); + condevalZ(lo); + break; + case 0x73: /* COM ext */ + DAR = get_ext_addr(); + lo = ~mem_get_byte(DAR) & 0xFF; + mem_put_byte(DAR, lo); + V = 0; + C = 0x10000; + condevalN(lo); + condevalZ(lo); + break; + case 0x74: /* LSR ext */ + DAR = get_ext_addr(); + lo = mem_get_byte(DAR); + C = 0; + if (lo & 0x01) + C = 0x10000; + lo >>= 1; + mem_put_byte(DAR, lo); + N = 0; + condevalZ(lo); + V = 0; + if (N ^ C) + V = 0x10000; + break; + case 0x76: /* ROR ext */ + DAR = get_ext_addr(); + hi = C; + lo = mem_get_byte(DAR); + C = 0; + if (lo & 0x01) + C = 0x10000; + lo >>= 1; + if (hi) + lo |= 0x80; + mem_put_byte(DAR, lo); + condevalN(lo); + condevalZ(lo); + V = 0; + if (N ^ C) + V = 0x10000; + break; + case 0x77: /* ASR ext */ + DAR = get_ext_addr(); + lo = mem_get_byte(DAR); + C = 0; + if (lo & 0x01) + C = 0x10000; + hi = lo & 0x80; + lo >>= 1; + lo |= hi; + mem_put_byte(DAR, lo); + condevalN(lo); + condevalZ(lo); + V = 0; + if (N ^ C) + V = 0x10000; + break; + case 0x78: /* ASL ext */ + DAR = get_ext_addr(); + lo = mem_get_byte(DAR); + C = 0; + if (lo & 0x80) + C = 0x10000; + lo <<= 1; + mem_put_byte(DAR, lo); + condevalN(lo); + condevalZ(lo); + V = 0; + if (N ^ C) + V = 0x10000; + break; + case 0x79: /* ROL ext */ + DAR = get_ext_addr(); + lo = mem_get_byte(DAR); + hi = C; + C = 0; + if (lo & 0x80) + C = 0x10000; + lo <<= 1; + if (hi) + lo |= 0x01; + mem_put_byte(DAR, lo); + condevalN(lo); + condevalZ(lo); + V = 0; + if (N ^ C) + V = 0x10000; + break; + case 0x7A: /* DEC ext */ + DAR = get_ext_addr(); + lo = mem_get_byte(DAR); + V = 0; + if (lo == 0x80) + V = 0x10000; + lo = --lo & 0xFF; + mem_put_byte(DAR, lo); + condevalN(lo); + condevalZ(lo); + break; + case 0x7C: /* INC ext */ + DAR = get_ext_addr(); + lo = mem_get_byte(DAR); + V = 0; + if (lo == 0x7F) + V = 0x10000; + lo = ++lo & 0xFF; + mem_put_byte(DAR, lo); + condevalN(lo); + condevalZ(lo); + break; + case 0x7D: /* TST ext */ + lo = mem_get_byte(get_ext_addr()) - 0; + V = 0; + C = 0; + condevalN(lo); + condevalZ(lo & 0xFF); + break; + case 0x7E: /* JMP ext */ + PC = get_ext_addr() & ADDRMASK; + break; + case 0x7F: /* CLR ext */ + mem_put_byte(get_ext_addr(), 0); + N = V = C = 0; + Z = 0x10000; + break; + case 0x80: /* SUB A imm */ + op1 = get_dir_addr(); + A = A - op1; + condevalN(A); + condevalC(A); + condevalVs(A, op1); + A &= 0xFF; + condevalZ(A); + break; + case 0x81: /* CMP A imm */ + op1 = get_dir_addr(); + lo = A - op1; + condevalN(lo); + condevalZ(lo & 0xFF); + condevalC(lo); + condevalVs(lo, op1); + break; + case 0x82: /* SBC A imm */ + op1 = get_dir_addr(); + if (C) + A = A - op1 - 1; + else + A = A - op1; + condevalN(A); + condevalC(A); + condevalVs(A, op1); + A &= 0xFF; + condevalZ(A); + break; + case 0x84: /* AND A imm */ + A = (A & get_dir_addr()) & 0xFF; + V = 0; + condevalN(A); + condevalZ(A); + break; + case 0x85: /* BIT A imm */ + lo = (A & get_dir_addr()) & 0xFF; + V = 0; + condevalN(lo); + condevalZ(lo); + break; + case 0x86: /* LDA A imm */ + A = get_dir_addr(); + V = 0; + condevalN(A); + condevalZ(A); + break; + case 0x88: /* EOR A imm */ + A = (A ^ get_dir_addr()) & 0xFF; + V = 0; + condevalN(A); + condevalZ(A); + break; + case 0x89: /* ADC A imm */ + op1 = get_dir_addr(); + if (C) + A = A + op1 + 1; + else + A = A + op1; + condevalH(A); + condevalN(A); + condevalC(A); + condevalVa(A, op1); + A &= 0xFF; + condevalZ(A); + break; + case 0x8A: /* ORA A imm */ + A = (A | get_dir_addr()) & 0xFF; + V = 0; + condevalN(A); + condevalZ(A); + break; + case 0x8B: /* ADD A imm */ + op1 = get_dir_addr(); + A = A + op1; + condevalH(A); + condevalN(A); + condevalC(A); + condevalVa(A, op1); + A &= 0xFF; + condevalZ(A); + break; + case 0x8C: /* CPX imm */ + op1 = IX - get_ext_addr(); + condevalZ(op1); + condevalN(op1 >> 8); + V = op1 & 0x10000; + break; + case 0x8D: /* BSR rel */ + lo = get_rel_addr(); + SP = --SP & ADDRMASK; + mem_put_word(SP, PC); + SP = --SP & ADDRMASK; + PC = PC + lo; + PC &= ADDRMASK; + break; + case 0x8E: /* LDS imm */ + SP = get_ext_addr(); + condevalN(SP >> 8); + condevalZ(SP); + V = 0; + break; + case 0x90: /* SUB A dir */ + op1 = get_dir_val(); + A = A - op1; + condevalN(A); + condevalC(A); + condevalVs(A, op1); + A &= 0xFF; + condevalZ(A); + break; + case 0x91: /* CMP A dir */ + op1 = get_dir_val(); + lo = A - op1; + condevalN(lo); + condevalZ(lo & 0xff); + condevalC(lo); + condevalVs(A, op1); + break; + case 0x92: /* SBC A dir */ + op1 = get_dir_val(); + if (C) + A = A - op1 - 1; + else + A = A - op1; + condevalN(A); + condevalC(A); + condevalVs(A, op1); + A &= 0xFF; + condevalZ(A); + break; + case 0x94: /* AND A dir */ + A = (A & get_dir_val()) & 0xFF; + V = 0; + condevalN(A); + condevalZ(A); + break; + case 0x95: /* BIT A dir */ + lo = (A & get_dir_val()) & 0xFF; + V = 0; + condevalN(lo); + condevalZ(lo); + break; + case 0x96: /* LDA A dir */ + A = get_dir_val(); + V = 0; + condevalN(A); + condevalZ(A); + break; + case 0x97: /* STA A dir */ + mem_put_byte(get_dir_addr(), A); + V = 0; + condevalN(A); + condevalZ(A); + break; + case 0x98: /* EOR A dir */ + A = (A ^ get_dir_val()) & 0xFF; + V = 0; + condevalN(A); + condevalZ(A); + break; + case 0x99: /* ADC A dir */ + op1 = get_dir_val(); + if (C) + A = A + op1 + 1; + else + A = A + op1; + condevalH(A); + condevalN(A); + condevalC(A); + condevalVa(A, op1); + A &= 0xFF; + condevalZ(A); + break; + case 0x9A: /* ORA A dir */ + A = (A | get_dir_val()) & 0xFF; + V = 0; + condevalN(A); + condevalZ(A); + break; + case 0x9B: /* ADD A dir */ + op1 = get_dir_val(); + A = A + op1; + condevalH(A); + condevalN(A); + condevalC(A); + condevalVa(A, op1); + A &= 0xFF; + condevalZ(A); + break; + case 0x9C: /* CPX dir */ + op1 = IX - mem_get_word(get_dir_addr()); + condevalZ(op1); + condevalN(op1 >> 8); + V = op1 & 0x10000; + break; + case 0x9E: /* LDS dir */ + SP = mem_get_word(get_dir_addr()); + condevalN(SP >> 8); + condevalZ(SP); + V = 0; + break; + case 0x9F: /* STS dir */ + mem_put_word(get_dir_addr(), SP); + condevalN(SP >> 8); + condevalZ(SP); + V = 0; + break; + case 0xA0: /* SUB A ind */ + op1 = get_indir_val(); + A = A - op1; + condevalN(A); + condevalC(A); + condevalVs(A, op1); + A &= 0xFF; + condevalZ(A); + break; + case 0xA1: /* CMP A ind */ + op1 = get_indir_val(); + lo = A - op1; + condevalN(lo); + condevalZ(lo & 0xFF); + condevalC(lo); + condevalVs(A, op1); + break; + case 0xA2: /* SBC A ind */ + op1 = get_indir_val(); + if (C) + A = A - op1 - 1; + else + A = A - op1; + condevalN(A); + condevalC(A); + condevalVs(A, op1); + A &= 0xFF; + condevalZ(A); + break; + case 0xA4: /* AND A ind */ + A = (A & get_indir_val()) & 0xFF; + V = 0; + condevalN(A); + condevalZ(A); + break; + case 0xA5: /* BIT A ind */ + lo = (A & get_indir_val()) & 0xFF; + V = 0; + condevalN(lo); + condevalZ(lo); + break; + case 0xA6: /* LDA A ind */ + A = get_indir_val(); + V = 0; + condevalN(A); + condevalZ(A); + break; + case 0xA7: /* STA A ind */ + mem_put_byte(get_indir_addr(), A); + V = 0; + condevalN(A); + condevalZ(A); + break; + case 0xA8: /* EOR A ind */ + A = (A ^ get_indir_val()) & 0xFF; + V = 0; + condevalN(A); + condevalZ(A); + break; + case 0xA9: /* ADC A ind */ + op1 = get_indir_val(); + if (C) + A = A + op1 + 1; + else + A = A + op1; + condevalH(A); + condevalN(A); + condevalC(A); + condevalVa(A, op1); + A &= 0xFF; + condevalZ(A); + break; + case 0xAA: /* ORA A ind */ + A = (A | get_indir_val()) & 0xFF; + V = 0; + condevalN(A); + condevalZ(A); + break; + case 0xAB: /* ADD A ind */ + op1 = get_indir_val(); + A = A + op1; + condevalH(A); + condevalN(A); + condevalC(A); + condevalVa(A, op1); + A &= 0xFF; + condevalZ(A); + break; + case 0xAC: /* CPX ind */ + op1 = (IX - get_indir_addr()) & ADDRMASK; + condevalZ(op1); + condevalN(op1 >> 8); + V = op1 & 0x10000; + break; + case 0xAD: /* JSR ind */ + DAR = get_indir_addr(); + SP = --SP & ADDRMASK; + mem_put_word(SP, PC); + SP = --SP & ADDRMASK; + PC = DAR; + break; + case 0xAE: /* LDS ind */ + SP = mem_get_word(get_indir_addr()); + condevalN(SP >> 8); + condevalZ(SP); + V = 0; + break; + case 0xAF: /* STS ind */ + mem_put_word(get_indir_addr(), SP); + condevalN(SP >> 8); + condevalZ(SP); + V = 0; + break; + case 0xB0: /* SUB A ext */ + op1 = get_ext_val(); + A = A - op1; + condevalN(A); + condevalC(A); + condevalVs(A, op1); + A &= 0xFF; + condevalZ(A); + break; + case 0xB1: /* CMP A ext */ + op1 = get_ext_val(); + lo = A - op1; + condevalN(lo); + condevalZ(lo & 0xFF); + condevalC(lo); + condevalVs(A, op1); + break; + case 0xB2: /* SBC A ext */ + op1 = get_ext_val(); + if (C) + A = A - op1 - 1; + else + A = A - op1; + condevalN(A); + condevalC(A); + condevalVs(A, op1); + A &= 0xFF; + condevalZ(A); + break; + case 0xB4: /* AND A ext */ + A = (A & get_ext_val()) & 0xFF; + V = 0; + condevalN(A); + condevalZ(A); + break; + case 0xB5: /* BIT A ext */ + lo = (A & get_ext_val()) & 0xFF; + V = 0; + condevalN(lo); + condevalZ(lo); + break; + case 0xB6: /* LDA A ext */ + A = get_ext_val(); + V = 0; + condevalN(A); + condevalZ(A); + break; + case 0xB7: /* STA A ext */ + mem_put_byte(get_ext_addr(), A); + V = 0; + condevalN(A); + condevalZ(A); + break; + case 0xB8: /* EOR A ext */ + A = (A ^ get_ext_val()) & 0xFF; + V = 0; + condevalN(A); + condevalZ(A); + break; + case 0xB9: /* ADC A ext */ + op1 = get_ext_val(); + if (C) + A = A + op1 + 1; + else + A = A + op1; + condevalH(A); + condevalN(A); + condevalC(A); + condevalVa(A, op1); + A &= 0xFF; + condevalZ(A); + break; + case 0xBA: /* ORA A ext */ + A = (A | get_ext_val()) & 0xFF; + V = 0; + condevalN(A); + condevalZ(A); + break; + case 0xBB: /* ADD A ext */ + op1 = get_ext_val(); + A = A + op1; + condevalH(A); + condevalN(A); + condevalC(A); + condevalVa(A, op1); + A &= 0xFF; + condevalZ(A); + break; + case 0xBC: /* CPX ext */ + op1 = (IX - mem_get_word(get_ext_addr())) & ADDRMASK; + condevalZ(op1); + condevalN(op1 >> 8); + V = op1 & 0x10000; + break; + case 0xBD: /* JSR ext */ + DAR = get_ext_addr(); + SP = --SP & ADDRMASK; + mem_put_word(SP, PC); + SP = --SP & ADDRMASK; + PC = DAR; + break; + case 0xBE: /* LDS ext */ + SP = mem_get_word(get_ext_addr()); + condevalN(SP >> 8); + condevalZ(SP); + V = 0; + break; + case 0xBF: /* STS ext */ + mem_put_word(get_ext_addr(), SP); + condevalN(SP >> 8); + condevalZ(SP); + V = 0; + break; + case 0xC0: /* SUB B imm */ + op1 = get_dir_addr(); + B = B - op1; + condevalN(B); + condevalC(B); + condevalVs(B, op1); + B &= 0xFF; + condevalZ(B); + break; + case 0xC1: /* CMP B imm */ + op1 = get_dir_addr(); + lo = B - op1; + condevalN(lo); + condevalZ(lo & 0xFF); + condevalC(lo); + condevalVs(B, op1); + break; + case 0xC2: /* SBC B imm */ + op1 = get_dir_addr(); + if (C) + B = B - op1 - 1; + else + B = B - op1; + condevalN(B); + condevalC(B); + condevalVs(B, op1); + B &= 0xFF; + condevalZ(B); + break; + case 0xC4: /* AND B imm */ + B = (B & get_dir_addr()) & 0xFF; + V = 0; + condevalN(B); + condevalZ(B); + break; + case 0xC5: /* BIT B imm */ + lo = (B & get_dir_addr()) & 0xFF; + V = 0; + condevalN(lo); + condevalZ(lo); + break; + case 0xC6: /* LDA B imm */ + B = get_dir_addr(); + V = 0; + condevalN(B); + condevalZ(B); + break; + case 0xC8: /* EOR B imm */ + B = (B ^ get_dir_addr()) & 0xFF; + V = 0; + condevalN(B); + condevalZ(B); + break; + case 0xC9: /* ADC B imm */ + op1 = get_dir_addr(); + if (C) + B = B + op1 + 1; + else + B = B + op1; + condevalH(B); + condevalN(B); + condevalC(B); + condevalVa(B, op1); + B &= 0xFF; + condevalZ(B); + break; + case 0xCA: /* ORA B imm */ + B = (B | get_dir_addr()) & 0xFF; + V = 0; + condevalN(B); + condevalZ(B); + break; + case 0xCB: /* ADD B imm */ + op1 = get_dir_addr(); + B = B + op1; + condevalH(B); + condevalN(B); + condevalC(B); + condevalVa(B, op1); + B &= 0xFF; + condevalZ(B); + break; + case 0xCE: /* LDX imm */ + IX = get_ext_addr(); + condevalN(IX >> 8); + condevalZ(IX); + V = 0; + break; + case 0xD0: /* SUB B dir */ + op1 = get_dir_val(); + B = B - op1; + condevalN(B); + condevalC(B); + condevalVs(B, op1); + B &= 0xFF; + condevalZ(B); + break; + case 0xD1: /* CMP B dir */ + op1 = get_dir_val(); + lo = B - op1; + condevalN(lo); + condevalZ(lo); + condevalC(lo); + condevalVs(B, op1); + break; + case 0xD2: /* SBC B dir */ + op1 = get_dir_val(); + if (C) + B = B - op1 - 1; + else + B = B - op1; + condevalN(B); + condevalC(B); + condevalVs(B, op1); + B &= 0xFF; + condevalZ(B); + break; + case 0xD4: /* AND B dir */ + B = (B & get_dir_val()) & 0xFF; + V = 0; + condevalN(B); + condevalZ(B); + break; + case 0xD5: /* BIT B dir */ + lo = (B & get_dir_val()) & 0xFF; + V = 0; + condevalN(lo); + condevalZ(lo); + break; + case 0xD6: /* LDA B dir */ + B = get_dir_val(); + V = 0; + condevalN(B); + condevalZ(B); + break; + case 0xD7: /* STA B dir */ + mem_put_byte(get_dir_addr(), B); + V = 0; + condevalN(B); + condevalZ(B); + break; + case 0xD8: /* EOR B dir */ + B = (B ^ get_dir_val()) & 0xFF; + V = 0; + condevalN(B); + condevalZ(B); + break; + case 0xD9: /* ADC B dir */ + op1 = get_dir_val(); + if (C) + B = B + op1 + 1; + else + B = B + op1; + condevalH(B); + condevalN(B); + condevalC(B); + condevalVa(B, op1); + B &= 0xFF; + condevalZ(B); + break; + case 0xDA: /* ORA B dir */ + B = (B | get_dir_val()) & 0xFF; + V = 0; + condevalN(B); + condevalZ(B); + break; + case 0xDB: /* ADD B dir */ + op1 = get_dir_val(); + B = B + op1; + condevalH(B); + condevalN(B); + condevalC(B); + condevalVa(B, op1); + B &= 0xFF; + condevalZ(B); + break; + case 0xDE: /* LDX dir */ + IX = mem_get_word(get_dir_addr()); + condevalN(IX >> 8); + condevalZ(IX); + V = 0; + break; + case 0xDF: /* STX dir */ + mem_put_word(get_dir_addr(), IX); + condevalN(IX >> 8); + condevalZ(IX); + V = 0; + break; + case 0xE0: /* SUB B ind */ + op1 = get_indir_val(); + B = B - op1; + condevalN(B); + condevalC(B); + condevalVs(B, op1); + B &= 0xFF; + condevalZ(B); + break; + case 0xE1: /* CMP B ind */ + op1 = get_indir_val(); + lo = B - op1; + condevalN(lo); + condevalZ(lo & 0xFF); + condevalC(lo); + condevalVs(B, op1); + break; + case 0xE2: /* SBC B ind */ + op1 = get_indir_val(); + if (C) + B = B - op1 - 1; + else + B = B - op1; + condevalN(B); + condevalC(B); + condevalVs(B, op1); + B &= 0xFF; + condevalZ(B); + break; + case 0xE4: /* AND B ind */ + B = (B & get_indir_val()) & 0xFF; + V = 0; + condevalN(B); + condevalZ(B); + break; + case 0xE5: /* BIT B ind */ + lo = (B & get_indir_val()) & 0xFF; + V = 0; + condevalN(lo); + condevalZ(lo); + break; + case 0xE6: /* LDA B ind */ + B = get_indir_val(); + V = 0; + condevalN(B); + condevalZ(B); + break; + case 0xE7: /* STA B ind */ + mem_put_byte(get_indir_addr(), B); + V = 0; + condevalN(B); + condevalZ(B); + break; + case 0xE8: /* EOR B ind */ + B = (B ^ get_indir_val()) & 0xFF; + V = 0; + condevalN(B); + condevalZ(B); + break; + case 0xE9: /* ADC B ind */ + op1 = get_indir_val(); + if (C) + B = B + op1 + 1; + else + B = B + op1; + condevalH(B); + condevalN(B); + condevalC(B); + condevalVa(B, op1); + B &= 0xFF; + condevalZ(B); + break; + case 0xEA: /* ORA B ind */ + B = (B | get_indir_val()) & 0xFF; + V = 0; + condevalN(B); + condevalZ(B); + break; + case 0xEB: /* ADD B ind */ + op1 = get_indir_val(); + B = B + op1; + condevalH(B); + condevalN(B); + condevalC(B); + condevalVa(B, op1); + B &= 0xFF; + condevalZ(B); + break; + case 0xEE: /* LDX ind */ + IX = mem_get_word(get_indir_addr()); + condevalN(IX >> 8); + condevalZ(IX); + V = 0; + break; + case 0xEF: /* STX ind */ + mem_put_word(get_indir_addr(), IX); + condevalN(IX >> 8); + condevalZ(IX); + V = 0; + break; + case 0xF0: /* SUB B ext */ + op1 = get_ext_val(); + B = B - op1; + condevalN(B); + condevalC(B); + condevalVs(B, op1); + B &= 0xFF; + condevalZ(B); + break; + case 0xF1: /* CMP B ext */ + op1 = get_ext_val(); + lo = B - op1; + condevalN(lo); + condevalZ(lo & 0xFF); + condevalC(lo); + condevalVs(B, op1); + break; + case 0xF2: /* SBC B ext */ + op1 = get_ext_val(); + if (C) + B = B - op1 - 1; + else + B = B - op1; + condevalN(B); + condevalC(B); + condevalVs(B, op1); + B &= 0xFF; + condevalZ(B); + break; + case 0xF4: /* AND B ext */ + B = (B & get_ext_val()) & 0xFF; + V = 0; + condevalN(B); + condevalZ(B); + break; + case 0xF5: /* BIT B ext */ + lo = (B & get_ext_val()) & 0xFF; + V = 0; + condevalN(lo); + condevalZ(lo); + break; + case 0xF6: /* LDA B ext */ + B = get_ext_val(); + V = 0; + condevalN(B); + condevalZ(B); + break; + case 0xF7: /* STA B ext */ + mem_put_byte(get_ext_addr(), B); + V = 0; + condevalN(B); + condevalZ(B); + break; + case 0xF8: /* EOR B ext */ + B = (B ^ get_ext_val()) & 0xFF; + V = 0; + condevalN(B); + condevalZ(B); + break; + case 0xF9: /* ADC B ext */ + op1 = get_ext_val(); + if (C) + B = B + op1 + 1; + else + B = B + op1; + condevalH(B); + condevalN(B); + condevalC(B); + condevalVa(B, op1); + B &= 0xFF; + condevalZ(B); + break; + case 0xFA: /* ORA B ext */ + B = (B | get_ext_val()) & 0xFF; + V = 0; + condevalN(B); + condevalZ(B); + break; + case 0xFB: /* ADD B ext */ + op1 = get_ext_val(); + B = B + op1; + condevalH(B); + condevalN(B); + condevalC(B); + condevalVa(B, op1); + B &= 0xFF; + condevalZ(B); + break; + case 0xFE: /* LDX ext */ + IX = mem_get_word(get_ext_addr()); + condevalN(IX >> 8); + condevalZ(IX); + V = 0; + break; + case 0xFF: /* STX ext */ + mem_put_word(get_ext_addr(), IX); + condevalN(IX >> 8); + condevalZ(IX); + V = 0; + break; + + default: { /* Unassigned */ + if (cpu_unit.flags & UNIT_OPSTOP) { + reason = STOP_OPCODE; + PC--; + } + break; + } + } + } + /* Simulation halted - lets dump all the registers! */ + dump_regs(); + saved_PC = PC; + return reason; +} + +/* dump the working registers */ + +void dump_regs() +{ + printf("\r\nPC=%04X SP=%04X IX=%04X ", PC, SP, IX); + printf("A=%02X B=%02X PSW=%02X", A, B, get_psw()); +} + +/* this routine does the jump to relative offset if the condition is + met. Otherwise, execution continues at the current PC. */ + +void go_rel(int32 cond) +{ + int32 temp; + + temp = get_rel_addr(); + if (cond) + PC += temp; + PC &= ADDRMASK; +} + +/* returns the relative offset sign-extended */ + +int32 get_rel_addr() +{ + int32 temp; + + temp = mem_get_byte(PC++); + if (temp & 0x80) + temp |= 0xFF00; + return temp & ADDRMASK; +} + +/* returns the value at the direct address pointed to by PC */ + +int32 get_dir_val() +{ + return mem_get_byte(get_dir_addr()); +} + +/* returns the direct address pointed to by PC */ + +int32 get_dir_addr() +{ + int32 temp; + + temp = mem_get_byte(PC); + PC = ++PC & ADDRMASK; + return temp & 0xFF; +} + +/* returns the value at the indirect address pointed to by PC */ + +int32 get_indir_val() +{ + return mem_get_byte(get_indir_addr()); +} + +/* returns the indirect address pointed to by PC or immediate byte */ + +int32 get_indir_addr() +{ + int32 temp; + + temp = (mem_get_byte(PC++) + IX) & ADDRMASK; + PC &= ADDRMASK; + return temp; +} + +/* returns the value at the extended address pointed to by PC */ + +int32 get_ext_val() +{ + return mem_get_byte(get_ext_addr()); +} + +/* returns the extended address pointed to by PC or immediate word */ + +int32 get_ext_addr() +{ + int32 temp; + + temp = (mem_get_byte(PC) << 8) | mem_get_byte(PC+1); + PC = (PC +2) & ADDRMASK; + return temp; +} + +/* return a PSW from the current flags */ + +int32 get_psw() +{ + int32 psw; + + psw = 0xC0; + if (H) + psw |= 0x20; + if (I) + psw |= 0x10; + if (N) + psw |= 0x08; + if (Z) + psw |= 0x04; + if (V) + psw |= 0x02; + if (C) + psw |= 0x01; + return psw; +} + +/* set the current flags from a PSW */ + +void set_psw(int32 psw) +{ + H = 0; + if (psw & 0x20) + H = 0x10000; + I = 0; + if (psw & 0x10) + I = 0x10000; + N = 0; + if (psw & 0x08) + N = 0x10000; + Z = 0; + if (psw & 0x04) + Z = 0x10000; + V = 0; + if (psw & 0x02) + V = 0x10000; + C = 0; + if (psw & 0x01) + C = 0x10000; +} + +/* test and set H */ + +void condevalH(int32 res) +{ + H = (res & 0x10) << 12; +} + +/* test and set N */ + +void condevalN(int32 res) +{ + N = 0; + if (res & 0x80) + N = 0x10000; +} + +/* test and set Z */ + +void condevalZ(int32 res) +{ + Z = 0; + if (res == 0) + Z = 0x10000; +} + +/* test and set V for addition */ + +void condevalVa(int32 op1, int32 op2) +{ + if (C) { + V = 0; + if (((op1 & 0x80) && (op2 & 0x80)) || + (((op1 & 0x80) == 0) && ((op2 & 0x80) == 0))) + V = 0x10000; + } +} + +/* test and set V for subtraction */ + +void condevalVs(int32 op1, int32 op2) +{ + if (C) { + V = 0; + if (((op1 & 0x80) && ((op2 & 0x80) == 0)) || + (((op1 & 0x80) == 0) && (op2 & 0x80))) + V = 0x10000; + } +} + +/* test and set C */ + +void condevalC(int32 res) +{ + C = (res & 0x100) << 8; +} + +/* memory write operations */ + +/* put word */ + +void mem_put_word(int32 addr, int32 val) +{ + mem_put_byte(addr,val >> 8); + mem_put_byte(addr + 1, val); +} + +/* put byte */ + +void mem_put_byte(int32 addr, int32 val) +{ + if (addr >= 0x0000 && addr < (int32) MEMSIZE) /* memory cards */ + M[addr] = val & 0xFF; + else if (addr >= 0x8000 && addr < 0x8020) /* memory mapped I/O */ + dev_table[addr - 0x8000].routine(1, val); + else if (addr >= 0xA000 && addr < 0xA080) /* CPU memory */ + M[addr] = val & 0xFF; + else if ((addr >= 0xA080 && addr < 0xC000) && /* extended CPU memory */ + cpu_unit.flags & UNIT_MA000) + M[addr] = val & 0xFF; + else { + if (cpu_unit.flags & UNIT_MSTOP) + mem_fault = 1; + printf("Invalid write to %04X\n\r", addr); + } +} + +/* memory read operations */ + +/* get word */ + +int32 mem_get_word(int32 addr) +{ + int32 temp; + + temp = (mem_get_byte(addr) << 8) | mem_get_byte(addr+1); + return temp; +} + +/* get byte */ + +int32 mem_get_byte(int32 addr) +{ + int32 val; + + if (addr >= 0x0000 && addr < (int32) MEMSIZE) /* memory cards */ + val = M[addr]; + else if (addr >= 0x8000 && addr < 0x8020) /* memory mapped I/O */ + val = dev_table[addr - 0x8000].routine(0, 0); + else if (addr >= 0xA000 && addr < 0xA080) /* CPU memory */ + val = M[addr]; + else if ((addr >= 0xA080 && addr < 0xC000) && /* extended CPU memory */ + cpu_unit.flags & UNIT_MA000) + val = M[addr]; + else if (addr >= 0xE000 && addr < 0x10000) /* ROM memory */ + val = M[addr]; + else { + if (cpu_unit.flags & UNIT_MSTOP) + mem_fault = 1; + val = 0xFF; /* default for no memory at address */ + printf("Invalid read of %04X\n\r", addr); + } + return val & 0xFF; +} + +/* calls from the simulator */ + +/* Reset routine */ + +t_stat cpu_reset (DEVICE *dptr) +{ + int i; + + I = 0x10000; + saved_PC = (M[0xFFFE] << 8) | M[0xFFFF]; + int_req = 0; + sim_brk_types = sim_brk_dflt = SWMASK ('E'); + /* copy in rom image at E000 */ + for (i = 0; i < BOOTLEN; i++) { + M[i + 0xE000] = bootrom[i] & 0xFF; + } + /* copy in rom image at FC00 for vectors! */ + for (i = 0; i < BOOTLEN; i++) { + M[i + 0xFC00] = bootrom[i] & 0xFF; + } + return SCPE_OK; +} + +/* Memory examine */ + +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ + if (addr >= MAXMEMSIZE) + return SCPE_NXM; + if (vptr != NULL) + *vptr = mem_get_byte(addr); + return SCPE_OK; +} + +/* Memory deposit */ + +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ + if (addr >= MAXMEMSIZE) + return SCPE_NXM; + mem_put_byte(addr, val); +// printf("Deposit to %04X of %02X\n\r", addr, val); + return SCPE_OK; +} + +/* adjust the memory size for the emulator 4k to 32k in 4k steps */ + +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ + int32 mc = 0; + uint32 i; + + if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 0x0FFF) != 0)) + return SCPE_ARG; + for (i = val; i < MEMSIZE; i++) + mc = mc | M[i]; + if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) + return SCPE_OK; + MEMSIZE = val; + return SCPE_OK; +} + +/* dummy i/o device */ + +int32 nulldev(int32 io, int32 data) +{ + if (io == 0) + return (0xFF); + return 0; +} + diff --git a/swtp/swtp_defs.h b/swtp/swtp_defs.h new file mode 100644 index 00000000..9e946c18 --- /dev/null +++ b/swtp/swtp_defs.h @@ -0,0 +1,46 @@ +/* swtp_defs.h: SWTP 6800 simulator definitions + +Copyright (c) 2005, 2007, William Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + WILLIAM A BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A Beech shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A Beech. + + Based on work by Charles E Owen (c) 1997 and Peter Schorn (c) 2002-2005 + +*/ + +#include "../sim_defs.h" // simulator defs + +/* Memory */ + +#define MAXMEMSIZE 65536 // max memory size +#define MEMSIZE (cpu_unit.capac)// actual memory size +#define ADDRMASK (MAXMEMSIZE - 1)// address mask +#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) + +/* Simulator stop codes */ + +#define STOP_RSRV 1 // must be 1 +#define STOP_HALT 2 // HALT-really WAI +#define STOP_IBKPT 3 // breakpoint +#define STOP_OPCODE 4 // invalid opcode +#define STOP_MEMORY 5 // invalid memory address + diff --git a/swtp/swtp_dsk.c b/swtp/swtp_dsk.c new file mode 100644 index 00000000..3a636279 --- /dev/null +++ b/swtp/swtp_dsk.c @@ -0,0 +1,506 @@ +/* swtp_dc4_dsk.c: SWTP DC-4 DISK Simulator + + Copyright (c) 2005, 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 + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + Based on work by Charles E Owen (c) 1997 and Peter Schorn (c) 2002-2005 + + + 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 device numbers 5 and 6 (0x8014-0x801B). + + Address Mode Function + ------- ---- -------- + + 0x8014 Read Returns FDC interrupt status + 0x8014 Write Selects the drive/head/motor control + 0x8018 Read Returns status of FDC + 0x8018 Write FDC command register + 0x8019 Read Returns FDC track register + 0x8019 Write Set FDC track register + 0x801A Read Returns FDC sector register + 0x801A Write Set FDC sector register + 0x801B Read Read data + 0x801B Write Write data + + Drive Select Read (0x8014): + + +---+---+---+---+---+---+---+---+ + | I | D | X | X | X | X | X | X | + +---+---+---+---+---+---+---+---+ + + I = Set indicates an interrupt request from the FDC pending. + D = DRQ pending - same as bit 1 of FDC status register. + + Drive Select Write (0x8014): + + +---+---+---+---+---+---+---+---+ + | 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 (0x8018): + + +---+---+---+---+---+---+---+---+ + | 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 (0x8018) 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 (0x8018) 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 (0x8018) 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 (0x8019): + + +---+---+---+---+---+---+---+---+ + | Track Number | + +---+---+---+---+---+---+---+---+ + + Reads the current 8-bit value from the track position. + + Track Register Write (0x8019): + + +---+---+---+---+---+---+---+---+ + | 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 (0x801A): + + +---+---+---+---+---+---+---+---+ + | Sector Number | + +---+---+---+---+---+---+---+---+ + + Reads the current 8-bit value from the sector position. + + Sector Register Write (0x801A): + + +---+---+---+---+---+---+---+---+ + | Sector Number | + +---+---+---+---+---+---+---+---+ + + Writes the 8-bit value to the sector register. + + Data Register Read (0x801B): + + +---+---+---+---+---+---+---+---+ + | Data | + +---+---+---+---+---+---+---+---+ + + Reads the current 8-bit value from the data register. + + Data Register Write (0x801B): + + +---+---+---+---+---+---+---+---+ + | 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 + 0 4 System Identity Record (explained below) + 0 5 Unused + 0 6-last Directory - 10 entries/sector (explained below) + 1 1 First available data sector + last-1 last Last available data sector + + System Identity Record + + Byte Use + 0x10 Volume ID (8 bytes) + 0x18 ??? + 0x19 ??? + 0x1A ??? + 0x1B Volume number (2 bytes) + 0x1D First free sector (2 bytes) + 0x1F Last track minus one (byte) + 0x20 Last sector (byte) + 0x21 Total sectors on disk (2 bytes) + 0x23 Month (byte + 0x24 Day (byte) + 0x25 Year (byte) + 0x26 Last track minus one (byte) + 0x27 Last sector (byte) + +*/ + +#include + +#include "swtp_defs.h" + +#define UNIT_V_ENABLE (UNIT_V_UF + 0) /* Write Enable */ +#define UNIT_ENABLE (1 << UNIT_V_ENABLE) + +/* emulate a SS FLEX disk with 72 sectors and 80 tracks */ + +#define NUM_DISK 4 /* standard 1797 maximum */ +#define SECT_SIZE 256 /* standard FLEX sector */ +#define NUM_SECT 72 /* sectors/track */ +#define TRAK_SIZE (SECT_SIZE * NUM_SECT) +#define HEADS 1 /* handle as SS with twice the sectors */ +#define NUM_CYL 80 /* maximum tracks */ +#define DSK_SIZE (NUM_SECT * HEADS * NUM_CYL * SECT_SIZE) + +/* 1797 status bits */ + +#define BUSY 0x01 +#define DRQ 0x02 +#define WRPROT 0x40 +#define NOTRDY 0x80 + +/* debug prints */ + +#define DEBUG 0 + + +/* prototypes */ + +t_stat dsk_svc (UNIT *uptr); +t_stat dsk_reset (DEVICE *dptr); +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); + +/* Global data on status */ + +int32 cur_dsk = NUM_DISK; /* Currently selected drive */ +int32 cur_trk[NUM_DISK] = {0, 0, 0, 0}; +int32 cur_sec[NUM_DISK] = {0, 0, 0, 0}; +int32 cur_byt[NUM_DISK] = {0, 0, 0, 0}; +int32 cur_flg[NUM_DISK] = {NOTRDY, NOTRDY, NOTRDY, NOTRDY}; + +/* Variables */ + +uint8 dskbuf[SECT_SIZE]; /* Data Buffer */ +UNIT *dptr = NULL; /* fileref to write dirty buffer to */ +int32 fdcbyte; +int32 intrq = 0; /* interrupt request flag */ + +/* DC-4 Simh Device Data Structures */ + +UNIT dsk_unit[] = { + { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) }, + { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) }, + { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) }, + { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) } }; + +REG dsk_reg[] = { + { HRDATA (DISK, cur_dsk, 4) }, + { NULL } }; + +MTAB dsk_mod[] = { + { UNIT_ENABLE, UNIT_ENABLE, "RW", "RW", NULL }, + { UNIT_ENABLE, 0, "RO", "RO", NULL }, + { 0 } }; + +DEVICE dsk_dev = { + "DSK", dsk_unit, dsk_reg, dsk_mod, + NUM_DISK, 16, 16, 1, 16, 8, + NULL, NULL, &dsk_reset, + NULL, NULL, NULL }; + +/* service routines to handle simlulator functions */ + +/* service routine - actually gets char & places in buffer */ + +t_stat dsk_svc (UNIT *uptr) +{ +return SCPE_OK; +} + +/* Reset routine */ + +t_stat dsk_reset (DEVICE *dptr) +{ +cur_dsk = 0; +return SCPE_OK; +} + +/* I/O instruction handlers, called from the CPU module when an + memory read or write to the proper addresses is issued. + + Each function is passed an 'io' flag, where 0 means a read from + the port, and 1 means a write to the port. On input, the actual + input is passed as the return value, on output, 'data' is written + to the device. +*/ + +/* DC-4 drive select register routine - this register is not part of the 1797 +*/ + +int32 fdcdrv(int32 io, int32 data) +{ +/* **** probably need to grab the parameters from the SIR and set the limits */ + if (io) { /* write to DC-4 drive register */ + cur_dsk = data & 0x03; /* only 2 drive select bits */ +#if DEBUG > 0 + printf("Drive set to %d\n\r", cur_dsk); +#endif + if ((dsk_unit[cur_dsk].flags & UNIT_ENABLE) == 0) + cur_flg[cur_dsk] |= WRPROT; /* set WPROT */ + return 0; + } else { /* read from DC-4 drive register */ +#if DEBUG > 0 + printf("Drive read as %02X\n\r", intrq); +#endif + return intrq; + } +} + +/* WD 1797 FDC command register routine */ + +int32 fdccmd(int32 io, int32 data) +{ + static int32 val = 0, val1 = NOTRDY, i; + static long pos; + UNIT *uptr; + + if ((dsk_unit[cur_dsk].flags & UNIT_ATT) == 0) { /* not attached */ + cur_flg[cur_dsk] |= NOTRDY; /* set not ready flag */ + printf("Drive %d is not attached\n\r", cur_dsk); + return 0; + } else { + cur_flg[cur_dsk] &= ~NOTRDY; /* clear not ready flag */ + } + uptr = dsk_dev.units + cur_dsk; /* get virtual drive address */ + if (io) { /* write command to fdc */ + switch(data) { + case 0x8C: /* read command */ + case 0x9C: +#if DEBUG > 0 + printf("Read of disk %d, track %d, sector %d\n\r", + cur_dsk, cur_trk[cur_dsk], cur_sec[cur_dsk]); +#endif + pos = TRAK_SIZE * cur_trk[cur_dsk]; /* calculate file offset */ + pos += SECT_SIZE * (cur_sec[cur_dsk] - 1); +#if DEBUG > 0 + printf("Read pos = %ld ($%04X)\n\r", pos, pos); +#endif + sim_fseek(uptr -> fileref, pos, 0); /* seek to offset */ + sim_fread(dskbuf, 256, 1, uptr -> fileref); /* read in buffer */ + cur_flg[cur_dsk] |= BUSY | DRQ; /* set DRQ & BUSY */ + i = cur_byt[cur_dsk] = 0; /* clear counter */ + break; + case 0xAC: /* write command */ +#if DEBUG > 0 + printf("Write of disk %d, track %d, sector %d\n\r", + cur_dsk, cur_trk[cur_dsk], cur_sec[cur_dsk]); +#endif + if (cur_flg[cur_dsk] & WRPROT) { + printf("Drive %d is write-protected\n\r", cur_dsk); + } else { + pos = TRAK_SIZE * cur_trk[cur_dsk]; /* calculate file offset */ + pos += SECT_SIZE * (cur_sec[cur_dsk] - 1); +#if DEBUG > 1 + printf("Write pos = %ld ($%04X)\n\r", pos, pos); +#endif + sim_fseek(uptr -> fileref, pos, 0); /* seek to offset */ + dptr = uptr; /* save pointer for actual write */ + cur_flg[cur_dsk] |= BUSY | DRQ;/* set DRQ & BUSY */ + i = cur_byt[cur_dsk] = 0; /* clear counter */ + } + break; + case 0x18: /* seek command */ + case 0x1B: + cur_trk[cur_dsk] = fdcbyte; /* set track */ + cur_flg[cur_dsk] &= ~(BUSY | DRQ); /* clear flags */ +#if DEBUG > 0 + printf("Seek of disk %d, track %d\n\r", cur_dsk, fdcbyte); +#endif + break; + case 0x0B: /* restore command */ + cur_trk[cur_dsk] = 0; /* home the drive */ + cur_flg[cur_dsk] &= ~(BUSY | DRQ); /* clear flags */ +#if DEBUG > 0 + printf("Drive %d homed\n\r", cur_dsk); +#endif + break; + default: + printf("Unknown FDC command %02H\n\r", data); + } + } else { /* read status from fdc */ + val = cur_flg[cur_dsk]; /* set return value */ + if (val1 == 0 && val == 0x03) /* delay BUSY going high */ + val = 0x02; /* set DRQ first */ + if (val != val1) { /* now allow BUSY after on read */ + val1 = val; +#if DEBUG > 0 + printf("Drive %d status=%02X\n\r", cur_dsk, cur_flg[cur_dsk]); +#endif + } + } + return val; +} + +/* WD 1797 FDC track register routine */ + +int32 fdctrk(int32 io, int32 data) +{ + if (io) { + cur_trk[cur_dsk] = data & 0xFF; +#if DEBUG > 1 + printf("Drive %d track set to %d\n\r", cur_dsk, data); +#endif + } else + ; +#if DEBUG > 1 + printf("Drive %d track read as %d\n\r", cur_dsk, cur_trk[cur_dsk]); +#endif + return cur_trk[cur_dsk]; +} + +/* WD 1797 FDC sector register routine */ + +int32 fdcsec(int32 io, int32 data) +{ + if (io) { + cur_sec[cur_dsk] = data & 0xFF; + if (cur_sec[cur_dsk] == 0) /* fix for swtp boot! */ + cur_sec[cur_dsk] = 1; +#if DEBUG > 1 + printf("Drive %d sector set to %d\n\r", cur_dsk, data); +#endif + } else + ; +#if DEBUG > 1 + printf("Drive %d sector read as %d\n\r", cur_dsk, cur_sec[cur_dsk]); +#endif + return cur_sec[cur_dsk]; +} + +/* WD 1797 FDC data register routine */ + +int32 fdcdata(int32 io, int32 data) +{ + int32 i; + + if (io) { /* write byte to fdc */ + fdcbyte = data; /* save for seek */ + if ((i = cur_byt[cur_dsk]) < SECT_SIZE) { /* copy bytes to buffer */ +#if DEBUG > 3 + printf("Writing byte %d of %02X\n\r", cur_byt[cur_dsk], data); +#endif + cur_byt[cur_dsk]++; /* step counter */ + dskbuf[i] = data; /* byte into buffer */ + if (cur_byt[cur_dsk] == SECT_SIZE) { + cur_flg[cur_dsk] &= ~(BUSY | DRQ); + if (dptr) { /* if initiated by FDC write command */ + sim_fwrite(dskbuf, 256, 1, dptr -> fileref); /* write it */ + dptr = NULL; + } +#if DEBUG > 0 + printf("Sector write complete\n\r"); +#endif + } + } + return 0; + } else { /* read byte from fdc */ + if ((i = cur_byt[cur_dsk]) < SECT_SIZE) { /* copy bytes from buffer */ +#if DEBUG > 1 + printf("Reading byte %d\n\r", cur_byt[cur_dsk]); +#endif + cur_byt[cur_dsk]++; /* step counter */ + if (cur_byt[cur_dsk] == SECT_SIZE) { /* done? */ + cur_flg[cur_dsk] &= ~(BUSY | DRQ); /* clear flags */ +#if DEBUG > 0 + printf("Sector read complete\n\r"); +#endif + } + return (dskbuf[i] & 0xFF); + } else + return 0; + } +} + diff --git a/swtp/swtp_sio.c b/swtp/swtp_sio.c new file mode 100644 index 00000000..859074c4 --- /dev/null +++ b/swtp/swtp_sio.c @@ -0,0 +1,312 @@ +/* swtp_sio: SWTP serial I/O card + +Copyright (c) 2005, 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. + + Based on work by Charles E Owen (c) 1997 and Peter Schorn (c) 2002-2005 + + These functions support a simulated SWTP MP-S interface card. + The card had two physical I/O ports which could be connected + to any serial I/O device that would connect to a current loop + or RS232 interface. Available baud rates were jumper selectable + for each port from 110 to 9600. The 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. + + 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_ANSI (UNIT_V_UF + 0) // ANSI mode +#define UNIT_ANSI (1 << UNIT_V_ANSI) + +t_stat sio_svc (UNIT *uptr); +t_stat sio_reset (DEVICE *dptr); +t_stat ptr_svc (UNIT *uptr); +t_stat ptr_reset (DEVICE *dptr); +t_stat ptp_svc (UNIT *uptr); +t_stat ptp_reset (DEVICE *dptr); + +int32 ptr_stopioe = 0, ptp_stopioe = 0; // stop on error + +// MP-S Standard I/O Data Structures + +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_ANSI, 0, "TTY", "TTY", NULL }, + { 0 } }; + +DEVICE sio_dev = { + "MP-S", &sio_unit, sio_reg, sio_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &sio_reset, + NULL, NULL, NULL }; + +UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ + UNIT_ATTABLE, 0), + KBD_POLL_WAIT }; +DEVICE ptr_dev = { + "PTR", &ptr_unit, NULL, NULL, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &ptr_reset, + NULL, NULL, NULL }; + +UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ + UNIT_ATTABLE, 0), + KBD_POLL_WAIT }; +DEVICE ptp_dev = { + "PTP", &ptp_unit, NULL, NULL, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &ptp_reset, + NULL, NULL, NULL }; + +/* Service routines to handle simulator functions */ + +/* service routine - actually gets char & places in buffer */ + +int32 ptp_rdr(int32 io, int32 data); + +int32 ptp_flag = 0, ptr_flag = 0; + +/* console input service routine */ + +int32 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 & 0xFF; // Save char + sio_unit.u3 |= 0x01; // Set RXF flag + + /* Do any special character handling here */ + + sio_unit.pos++; // step character count + return SCPE_OK; +} + +/* paper tape reader input service routine */ + +int32 ptr_svc (UNIT *uptr) +{ + return SCPE_OK; +} + +/* paper tape punch output service routine */ + +int32 ptp_svc (UNIT *uptr) +{ + return SCPE_OK; +} + +/* Reset console */ + +int32 sio_reset (DEVICE *dptr) +{ + sio_unit.buf = 0; // Data buffer + sio_unit.u3 = 0x02; // Status buffer + sim_activate (&sio_unit, sio_unit.wait); // activate unit + return SCPE_OK; +} + +/* Reset paper tape reader */ + +int32 ptr_reset (DEVICE *dptr) +{ + ptr_unit.buf = 0; + ptr_unit.u3 = 0x02; + sim_cancel (&ptr_unit); // deactivate unit + return SCPE_OK; +} + +/* Reset paper tape punch */ + +int32 ptp_reset (DEVICE *dptr) +{ + ptp_unit.buf = 0; + ptp_unit.u3 = 0x02; + sim_cancel (&ptp_unit); // deactivate unit + return SCPE_OK; +} + +/* I/O instruction handlers, called from the CPU module when a + read or write occur to addresses 0x8000-0x801F. + + Each function is passed an 'io' flag, where 0 means a read from + the port, and 1 means a write to the port. On input, the actual + input is passed as the return value, on output, 'data' is written + to the device. + + This code emulates a SWTP MP-S Serial Card with a Model 33 Teletype + attached. The Model 33 uses DC1-DC4 codes to enable or disable the + paper tape reader and punch. Those devices are defined in this module, + and the code built to emulate those functions if the PTP and/or PTR + are attached in the simulator. +*/ + +/* Port 1 (0x8004-0x8007) controls the Model 33 Teletype */ + +int32 ptr_flg1 = 0; +int32 odata, status; + + +int32 sio0s(int32 io, int32 data) +{ + UNIT *uptr; + + if (io == 0) { // control register read + if (ptr_flag) { // reader enabled? + if ((ptr_unit.flags & UNIT_ATT) == 0) // attached? + ptr_unit.u3 &= 0xFE; // no, clear RXF flag + else { + uptr = ptr_dev.units;// not EOF? + if (feof(uptr -> fileref)) + ptr_unit.u3 &= 0xFE; + else + ptr_unit.u3 |= 0x01; + } + return (status = ptr_unit.u3); // no - done + } else { + return (status = sio_unit.u3); // return console status + } + } else { // control register write + if (data == 0x03) { // reset port! + sio_unit.u3 = 0x02; // reset console + sio_unit.buf = 0; + sio_unit.pos = 0; + ptr_unit.u3 = 0x02; // reset reader + ptr_unit.buf = 0; + ptr_unit.pos = 0; + ptp_unit.u3 = 0x02; // reset punch + ptp_unit.buf = 0; + ptp_unit.pos = 0; + } + return (status = 0); // invalid io + } +} + +int32 sio0d(int32 io, int32 data) +{ + UNIT *uptr; + + if (io == 0) { // data register read + if (ptr_flag) { // RDR enabled? + if ((ptr_unit.flags & UNIT_ATT) == 0) // attached? + return 0; // no, done +// printf("ptr_unit.u3=%02X\n", ptr_unit.u3); + if ((ptr_unit.u3 & 0x01) == 0) { // yes, more data? +// printf("Returning old %02X\n", odata); // no, return previous byte + return (odata & 0xFF); + } + uptr = ptr_dev.units; // get data byte + if ((odata = getc(uptr -> fileref)) == EOF) { // end of file? +// printf("Got EOF\n"); + ptr_unit.u3 &= 0xFE; // clear RXF flag + return (odata = 0); // no data + } +// printf("Returning new %02X\n", odata); + ptr_unit.pos++; // step character count + ptr_unit.u3 &= 0xFE; // clear RXF flag + return (odata & 0xFF); // return character + } else { + sio_unit.u3 &= 0xFE; // 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? + uptr = ptp_dev.units; // punch character to file + putc(data, uptr -> fileref); + ptp_unit.pos++; // step character counter + } + } else { // DC1-DC4 control Reader/Punch + switch (data) { + case 0x11: // RDR on + ptr_flag = 1; + ptr_flg1 = 0; + ptr_unit.u3 |= 0x01; +// printf("Reader on\r\n"); + break; + case 0x12: // PTP on + ptp_flag = 1; + ptp_unit.u3 |= 0x02; +// printf("Punch on\r\n"); + break; + case 0x13: // RDR off + ptr_flag = 0; +// printf("Reader off-%d bytes read\r\n", ptr_unit.pos); + break; + case 0x14: // PTP off + ptp_flag = 0; +// printf("Punch off-%d bytes written\r\n", ptp_unit.pos); + 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; +} + diff --git a/swtp/swtp_sys.c b/swtp/swtp_sys.c new file mode 100644 index 00000000..391065cd --- /dev/null +++ b/swtp/swtp_sys.c @@ -0,0 +1,425 @@ +/* swtp_sys.c: SWTP 6800 system interface + + Copyright (c) 2005, William Beech + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + WILLIAM A BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of William A. Beech shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from William A. Beech. + + Based on work by Charles E Owen (c) 1997 and Peter Schorn (c) 2002-2005 + +*/ + +#include +#include +#include "swtp_defs.h" + +/* externals */ + +extern DEVICE cpu_dev; +extern DEVICE dsk_dev; +extern UNIT cpu_unit; +extern REG cpu_reg[]; +extern DEVICE sio_dev; +extern DEVICE ptr_dev; +extern DEVICE ptp_dev; +extern DEVICE lpt_dev; +extern unsigned char M[]; +extern int32 saved_PC; +extern int32 sim_switches; +//extern int32 (*sim_vm_fprint_addr)(FILE*, DEVICE*,t_addr); + +/* prototypes */ + +int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag); +int32 fprint_sym (FILE *of, int32 addr, uint32 *val, + UNIT *uptr, int32 sw); +t_addr fprint_addr(FILE *stream, DEVICE *dptr, t_addr addr); +int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw); +void sim_special_init (void); + +/* links into scp */ + +void (*sim_vm_init)(void) = &sim_special_init; + +/* 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 6800"; + +REG *sim_PC = &cpu_reg[0]; + +int32 sim_emax = 16; + +DEVICE *sim_devices[] = { &cpu_dev, &sio_dev, &ptp_dev, &ptr_dev, &dsk_dev, NULL }; + +const char *sim_stop_messages[] = { + "Unknown error", + "Unknown I/O Instruction", + "HALT instruction", + "Breakpoint", + "Invalid Opcode", + "Invalid Memory" }; + +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", +"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", + }; + +int32 oplen[256] = { +0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1, //0x00 +1,1,0,0,0,0,1,1,0,1,0,1,0,0,0,0, +2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +1,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1, +1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, //0x40 +1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, +2,0,0,2,2,0,2,2,2,2,2,0,2,2,2,2, +3,0,0,3,3,0,3,3,3,3,3,0,3,3,3,3, +2,2,2,0,2,2,2,0,2,2,2,2,3,2,3,0, //0x80 +2,2,2,0,2,2,2,2,2,2,2,2,2,0,2,2, +2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2, +3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3, +2,2,2,0,2,2,2,0,2,2,2,2,0,0,3,0, //0xC0 +2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, +2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, +3,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3 }; + +/* 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. +*/ + +int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag) +{ + int32 i, cnt = 0, addr = 0, start = 0x10000, end = 0, bytecnt, + cksum1, cksum, bytes[250]; + char buffer[256]; + + sscanf(cptr," %x-%x", &start, &end); + if (flag) { // dump + if (start == 0x10000) // no address parameter + return SCPE_2FARG; + if (sim_switches & 0x80) { // hex dump + addr = start; + while (addr <= end) { // more records to write + if ((addr + 16) <= end) // how many bytes this record + bytecnt = 16 + 3; + else + bytecnt = end - addr + 4; + cksum = -1 - (bytecnt) - (addr >> 8) - (addr & 0xFF); //init cksum + fprintf(fileref, "S1%02X%02X%02X", bytecnt, addr>>8, addr&0xFF); //header + for (i=0; i> 8) - (addr & 0xFF); //init cksum + for (i=0; i < bytecnt-3; i++) + cksum -= bytes[i]; + cksum &= 0xFF; + if (cksum != cksum1) + printf("Checksum error\n"); + else { + for (i=0; i < bytecnt-3; i++) { + M[addr++] = bytes[i]; + cnt++; + } + } + } else if (buffer[1] == '9') // end of file + printf("End of file\n"); + } + } + } else { // binary load + if (start == 0x10000) // no starting address + addr = saved_PC; + else + addr = start; + start = addr; + while ((i = getc (fileref)) != EOF) { + M[addr] = i; + addr++; + cnt++; + } + } + printf ("%d Bytes loaded starting at %04X\n", cnt, start); + } + 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 +*/ + +int32 fprint_sym (FILE *of, int32 addr, uint32 *val, + UNIT *uptr, int32 sw) +{ + int32 i, inst, inst1; + + if (sw & SWMASK ('D')) { // dump memory + for (i=0; i<16; i++) + fprintf(of, "%02X ", val[i]); + fprintf(of, " "); + for (i=0; i<16; i++) + if (isprint(val[i])) + fprintf(of, "%c", val[i]); + else + fprintf(of, "."); + return -15; + } else if (sw & SWMASK ('M')) { // dump instruction mnemonic + inst = val[0]; + if (!oplen[inst]) { // invalid opcode + fprintf(of, "%02X", inst); + return 0; + } + inst1 = inst & 0xF0; + fprintf (of, "%s", opcode[inst]); // mnemonic + if (strlen(opcode[inst]) == 3) + fprintf(of, " "); + if (inst1 == 0x20 || inst == 0x8D) { // rel operand + inst1 = val[1]; + if (val[1] & 0x80) + inst1 |= 0xFF00; + fprintf(of, " $%04X", (addr + inst1 + 2) & ADDRMASK); + } else if (inst1 == 0x80 || inst1 == 0xC0) { // imm operand + if ((inst & 0x0F) < 0x0C) + fprintf(of, " #$%02X", val[1]); + else + fprintf(of, " #$%02X%02X", val[1], val[2]); + } else if (inst1 == 0x60 || inst1 == 0xA0 || inst1 == 0xE0) // ind operand + fprintf(of, " %d,X", val[1]); + else if (inst1 == 0x70 || inst1 == 0xb0 || inst1 == 0xF0) // ext operand + fprintf(of, " $%02X%02X", val[1], val[2]); + return (-(oplen[inst] - 1)); + } else + return SCPE_ARG; +} + +/* address output routine */ + +t_addr fprint_addr(FILE *of, DEVICE *dptr, t_addr addr) +{ + fprintf(of, "%04X", addr); + return 0; +} + +/* 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 +*/ + +int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw) +{ + int32 cflag, i = 0, j, r; + char gbuf[CBUFSIZE]; + + cflag = (uptr == NULL) || (uptr == &cpu_unit); + while (isspace (*cptr)) cptr++; /* absorb spaces */ + if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ + if (cptr[0] == 0) + return SCPE_ARG; /* must have 1 char */ + val[0] = (uint32) cptr[0]; + return SCPE_OK; + } + if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */ + if (cptr[0] == 0) + return SCPE_ARG; /* must have 1 char */ + val[0] = ((uint32) cptr[0] << 8) + (uint32) cptr[1]; + return SCPE_OK; + } + +/* An instruction: get opcode (all characters until null, comma, + or numeric (including spaces). +*/ + + while (1) { + if (*cptr == ',' || *cptr == '\0' || + isdigit(*cptr)) + break; + gbuf[i] = toupper(*cptr); + cptr++; + i++; + } + +/* Allow for RST which has numeric as part of opcode */ + + if (toupper(gbuf[0]) == 'R' && + toupper(gbuf[1]) == 'S' && + toupper(gbuf[2]) == 'T') { + gbuf[i] = toupper(*cptr); + cptr++; + i++; + } + +/* Allow for 'MOV' which is only opcode that has comma in it. */ + + if (toupper(gbuf[0]) == 'M' && + toupper(gbuf[1]) == 'O' && + toupper(gbuf[2]) == 'V') { + gbuf[i] = toupper(*cptr); + cptr++; + i++; + gbuf[i] = toupper(*cptr); + cptr++; + i++; + } + +/* kill trailing spaces if any */ + gbuf[i] = '\0'; + for (j = i - 1; gbuf[j] == ' '; j--) { + gbuf[j] = '\0'; + } + +/* find opcode in table */ + for (j = 0; j < 256; j++) { + if (strcmp(gbuf, opcode[j]) == 0) + break; + } + if (j > 255) /* not found */ + return SCPE_ARG; + + val[0] = j; /* store opcode */ + if (oplen[j] < 2) /* if 1-byter we are done */ + return SCPE_OK; + if (*cptr == ',') cptr++; + cptr = get_glyph(cptr, gbuf, 0); /* get address */ + sscanf(gbuf, "%o", &r); + if (oplen[j] == 2) { + val[1] = r & 0xFF; + return (-1); + } + val[1] = r & 0xFF; + val[2] = (r >> 8) & 0xFF; + return (-2); +} + +/* initialize optional interfaces */ + +void sim_special_init (void) +{ +// *sim_vm_fprint_addr = &fprint_addr; +} +