diff --git a/0readme_36.txt b/0readme_36.txt deleted file mode 100644 index ece7be4f..00000000 --- a/0readme_36.txt +++ /dev/null @@ -1,51 +0,0 @@ -Notes For V3.6-0 - -The save/restore format has been updated to improve its reliability. -As a result, save files prior to release 3.0 are no longer supported. - -The text documentation files are obsolete and are no longer included -with the distribution. Up-to-date PDF documentation files are -available on the SimH web site. - - -1. New Features - -1.1 3.6-0 - -1.1.1 Most magnetic tapes - -- Added support for limiting tape capacity to a particular size in MB - -1.1.2 IBM 7090/7094 - -- First release - -1.1.3 VAX-11/780 - -- Added FLOAD command, loads system file from console floppy disk - -1.1.4 VAX, VAX-11/780, and PDP-11 - -- Added card reader support (from John Dundas) - -1.1.5 PDP-11 - -- Added instruction history - -1.2 3.6-1 - -1.2.1 PDP-11 - -- Added RF11 support -- Added multiple KL11/DL11 support -- Added upper-case only mode to TTI, TTO - -1.2.2 - -- Added binary loader (courtesy of Dave Pitt) - - -2. Bugs Fixed - -Please see the revision history on http://simh.trailing-edge.com or -in the source module sim_rev.h. diff --git a/0readme_37.txt b/0readme_37.txt new file mode 100644 index 00000000..5c571c79 --- /dev/null +++ b/0readme_37.txt @@ -0,0 +1,66 @@ +Notes For V3.7-0 + + +1. New Features + +1.1 3.7-0 + +1.1.1 SCP + +- Added SET THROTTLE and SET NOTHROTTLE commands to regulate simulator + execution rate and host resource utilization. +- Added idle support (based on work by Mark Pizzolato). +- Added -e to control error processing in nested DO commands (from + Dave Bryan). + +1.1.2 HP2100 + +- Added Double Integer instructions, 1000-F CPU, and Floating Point + Processor (from Dave Bryan). +- Added 2114 and 2115 CPUs, 12607B and 12578A DMA controllers, and + 21xx binary loader protection (from Dave Bryan). + +1.1.3 Interdata + +- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait + state. + +1.1.4 PDP-11 + +- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait + state (WAIT instruction executed). +- Added TA11/TU60 cassette support. + +1.1.5 PDP-8 + +- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait + state (keyboard poll loop or jump-to-self). +- Added TA8E/TU60 cassette support. + +1.1.6 PDP-1 + +- Added support for 16-channel sequence break system. +- Added support for PDP-1D extended features and timesharing clock. +- Added support for Type 630 data communications subsystem. + +1.1.6 PDP-4/7/9/15 + +- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait + state (keyboard poll loop or jump-to-self). + +1.1.7 VAX, VAX780 + +- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait + state (more than 200 cycles at IPL's 0, 1, or 3 in kernel mode). + +1.1.8 PDP-10 + +- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait + state (operating system dependent). +- Added CD20 (CD11) support. + + +2. Bugs Fixed + +Please see the revision history on http://simh.trailing-edge.com or +in the source module sim_rev.h. diff --git a/AltairZ80/altairZ80_cpu.c b/AltairZ80/altairZ80_cpu.c index 0254dcae..b1a79969 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-2006, Peter Schorn + Copyright (c) 2002-2007, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -29,7 +29,9 @@ #include "altairz80_defs.h" -#if !defined (_WIN32) +#if defined (_WIN32) +#include +#else #include #endif @@ -54,28 +56,28 @@ #define SETFLAG(f,c) AF = (c) ? AF | FLAG_ ## f : AF & ~FLAG_ ## f #define TSTFLAG(f) ((AF & FLAG_ ## f) != 0) -#define ldig(x) ((x) & 0xf) -#define hdig(x) (((x) >> 4) & 0xf) -#define lreg(x) ((x) & 0xff) -#define hreg(x) (((x) >> 8) & 0xff) +#define LOW_DIGIT(x) ((x) & 0xf) +#define HIGH_DIGIT(x) (((x) >> 4) & 0xf) +#define LOW_REGISTER(x) ((x) & 0xff) +#define HIGH_REGISTER(x) (((x) >> 8) & 0xff) -#define Setlreg(x, v) x = (((x) & 0xff00) | ((v) & 0xff)) -#define Sethreg(x, v) x = (((x) & 0xff) | (((v) & 0xff) << 8)) +#define SET_LOW_REGISTER(x, v) x = (((x) & 0xff00) | ((v) & 0xff)) +#define SET_HIGH_REGISTER(x, v) x = (((x) & 0xff) | (((v) & 0xff) << 8)) -#define parity(x) parityTable[(x) & 0xff] -/* SetPV and SetPV2 are used to provide correct parity flag semantics for the 8080 in cases +#define PARITY(x) parityTable[(x) & 0xff] +/* SET_PV and SET_PV2 are used to provide correct PARITY flag semantics for the 8080 in cases where the Z80 uses the overflow flag */ -#define SetPVS(s) ((cpu_unit.flags & UNIT_CHIP) ? (((cbits >> 6) ^ (cbits >> 5)) & 4) : (parity(s))) -#define SetPV (SetPVS(sum)) -#define SetPV2(x) ((cpu_unit.flags & UNIT_CHIP) ? (((temp == (x)) << 2)) : (parity(temp))) +#define SET_PVS(s) ((cpu_unit.flags & UNIT_CHIP) ? (((cbits >> 6) ^ (cbits >> 5)) & 4) : (PARITY(s))) +#define SET_PV (SET_PVS(sum)) +#define SET_PV2(x) ((cpu_unit.flags & UNIT_CHIP) ? (((temp == (x)) << 2)) : (PARITY(temp))) -/* checkCPU8080 must be invoked whenever a Z80 only instruction is executed +/* CHECK_CPU_8080 must be invoked whenever a Z80 only instruction is executed In case a Z80 instruction is executed on an 8080 the following two cases exist: 1) Trapping is enabled: execution stops 2) Trapping is not enabled: decoding continues with the next byte */ -#define checkCPU8080 \ +#define CHECK_CPU_8080 \ if ((cpu_unit.flags & UNIT_CHIP) == 0) { \ if (cpu_unit.flags & UNIT_OPSTOP) { \ reason = STOP_OPCODE; \ @@ -87,23 +89,23 @@ } \ } -/* checkCPUZ80 must be invoked whenever a non Z80 instruction is executed */ -#define checkCPUZ80 \ +/* CHECK_CPU_Z80 must be invoked whenever a non Z80 instruction is executed */ +#define CHECK_CPU_Z80 \ if (cpu_unit.flags & UNIT_OPSTOP) { \ reason = STOP_OPCODE; \ goto end_decode; \ } #define POP(x) { \ - register uint32 y = RAM_pp(SP); \ - x = y + (RAM_pp(SP) << 8); \ + register uint32 y = RAM_PP(SP); \ + x = y + (RAM_PP(SP) << 8); \ } #define JPC(cond) { \ tStates += 10; \ if (cond) { \ PCQ_ENTRY(PC - 1); \ - PC = GetWORD(PC); \ + PC = GET_WORD(PC); \ } \ else { \ PC += 2; \ @@ -112,8 +114,8 @@ #define CALLC(cond) { \ if (cond) { \ - register uint32 adrr = GetWORD(PC); \ - CheckBreakWord(SP - 2); \ + register uint32 adrr = GET_WORD(PC); \ + CHECK_BREAK_WORD(SP - 2); \ PUSH(PC + 2); \ PCQ_ENTRY(PC - 1); \ PC = adrr; \ @@ -134,6 +136,8 @@ extern int32 sio1d (const int32 port, const int32 io, const int32 data); extern int32 dsk10 (const int32 port, const int32 io, const int32 data); extern int32 dsk11 (const int32 port, const int32 io, const int32 data); extern int32 dsk12 (const int32 port, const int32 io, const int32 data); +extern int32 netStatus (const int32 port, const int32 io, const int32 data); +extern int32 netData (const int32 port, const int32 io, const int32 data); extern int32 nulldev (const int32 port, const int32 io, const int32 data); extern int32 hdsk_io (const int32 port, const int32 io, const int32 data); extern int32 simh_dev (const int32 port, const int32 io, const int32 data); @@ -174,8 +178,8 @@ static void checkROMBoundaries(void); static void reset_memory(void); static uint32 in(const uint32 Port); static void out(const uint32 Port, const uint32 Value); -static void PutBYTE(register uint32 Addr, register uint32 Value); -static void PutWORD(register uint32 a, register uint32 v); +static void PutBYTE(register uint32 Addr, const register uint32 Value); +static void PutWORD(register uint32 Addr, const register uint32 Value); static t_bool sim_brk_lookup (const t_addr bloc, const int32 btyp); static void resetCell(const int32 address, const int32 bank); @@ -208,8 +212,8 @@ static int32 IR_S; /* interrupt (upper)/refresh int32 SR = 0; /* switch register */ static int32 bankSelect = 0; /* determines selected memory bank */ static uint32 common = 0xc000; /* addresses >= 'common' are in common memory */ -static uint32 ROMLow = defaultROMLow; /* lowest address of ROM */ -static uint32 ROMHigh = defaultROMHigh; /* highest address of ROM */ +static uint32 ROMLow = DEFAULT_ROM_LOW; /* lowest address of ROM */ +static uint32 ROMHigh = DEFAULT_ROM_HIGH; /* highest address of ROM */ static uint32 previousCapacity = 0; /* safe for previous memory capacity */ static uint32 clockFrequency = 0; /* in kHz, 0 means as fast as possible */ static uint32 sliceLength = 10; /* length of time-slice for CPU speed */ @@ -315,9 +319,9 @@ static const struct idev dev_table[256] = { {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1C */ {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 20 */ {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 24 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 28 */ + {&netStatus},{&netData},{&netStatus},{&netData}, /* 28 */ {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2C */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 30 */ + {&nulldev}, {&nulldev}, {&netStatus},{&netData}, /* 30 */ {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 34 */ {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 38 */ {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3C */ @@ -1334,7 +1338,7 @@ static void altairz80_init(void) { /* uint32 temp, v; for (temp = 0; temp < 256; temp++) { - v = (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | parity(temp); + v = (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | PARITY(temp); printf("%3d,", v); if ( ((temp+1) & 0xf) == 0) { printf("\n"); @@ -1466,17 +1470,17 @@ static uint8 M[MAXMEMSIZE][MAXBANKS]; /* RAM which is present */ static void warnUnsuccessfulWriteAttempt(const uint32 Addr) { if (cpu_unit.flags & UNIT_WARNROM) { if (addressIsInROM(Addr)) { - message2("Attempt to write to ROM " AddressFormat ".", Addr); + MESSAGE_2("Attempt to write to ROM " ADDRESS_FORMAT ".", Addr); } else { - message2("Attempt to write to non existing memory " AddressFormat ".", Addr); + MESSAGE_2("Attempt to write to non existing memory " ADDRESS_FORMAT ".", Addr); } } } static uint8 warnUnsuccessfulReadAttempt(const uint32 Addr) { if (cpu_unit.flags & UNIT_WARNROM) { - message2("Attempt to read from non existing memory " AddressFormat ".", Addr); + MESSAGE_2("Attempt to read from non existing memory " ADDRESS_FORMAT ".", Addr); } return 0xff; } @@ -1486,7 +1490,7 @@ int32 addressIsInROM(const uint32 Addr) { uint32 addr = Addr & ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ return (cpu_unit.flags & UNIT_ROM) && ( /* must have ROM enabled */ /* in banked case we have standard Altair ROM */ - ((cpu_unit.flags & UNIT_BANKED) && (defaultROMLow <= addr)) || + ((cpu_unit.flags & UNIT_BANKED) && (DEFAULT_ROM_LOW <= addr)) || /* in non-banked case we check the bounds of the ROM */ (((cpu_unit.flags & UNIT_BANKED) == 0) && (ROMLow <= addr) && (addr <= ROMHigh))); } @@ -1505,7 +1509,7 @@ static void PutBYTE(register uint32 Addr, const register uint32 Value) { if (Addr < common) { M[Addr][bankSelect] = Value; } - else if ((Addr < defaultROMLow) || ((cpu_unit.flags & UNIT_ROM) == 0)) { + else if ((Addr < DEFAULT_ROM_LOW) || ((cpu_unit.flags & UNIT_ROM) == 0)) { M[Addr][0] = Value; } else { @@ -1528,7 +1532,7 @@ static void PutWORD(register uint32 Addr, const register uint32 Value) { if (Addr < common) { M[Addr][bankSelect] = Value; } - else if ((Addr < defaultROMLow) || ((cpu_unit.flags & UNIT_ROM) == 0)) { + else if ((Addr < DEFAULT_ROM_LOW) || ((cpu_unit.flags & UNIT_ROM) == 0)) { M[Addr][0] = Value; } else { @@ -1538,7 +1542,7 @@ static void PutWORD(register uint32 Addr, const register uint32 Value) { if (Addr < common) { M[Addr][bankSelect] = Value >> 8; } - else if ((Addr < defaultROMLow) || ((cpu_unit.flags & UNIT_ROM) == 0)) { + else if ((Addr < DEFAULT_ROM_LOW) || ((cpu_unit.flags & UNIT_ROM) == 0)) { M[Addr][0] = Value >> 8; } else { @@ -1577,12 +1581,12 @@ void PutBYTEBasic(const uint32 Addr, const uint32 Bank, const uint32 Value) { } int32 install_bootrom(void) { - extern int32 bootrom[bootrom_size]; + extern int32 bootrom[BOOTROM_SIZE]; int32 i, cnt = 0; - for (i = 0; i < bootrom_size; i++) { - if (M[i + defaultROMLow][0] != (bootrom[i] & 0xff)) { + for (i = 0; i < BOOTROM_SIZE; i++) { + if (M[i + DEFAULT_ROM_LOW][0] != (bootrom[i] & 0xff)) { cnt++; - M[i + defaultROMLow][0] = bootrom[i] & 0xff; + M[i + DEFAULT_ROM_LOW][0] = bootrom[i] & 0xff; } } return cnt; @@ -1618,57 +1622,57 @@ uint32 getCommon(void) { return common; } -#define Reduce(Addr) ((Addr) & ADDRMASK) +#define REDUCE(Addr) ((Addr) & ADDRMASK) -#define GetBYTE(Addr) \ +#define GET_BYTE(Addr) \ ((cpu_unit.flags & UNIT_BANKED) ? \ - (Reduce(Addr) < common ? \ - M[Reduce(Addr)][bankSelect] \ + (REDUCE(Addr) < common ? \ + M[REDUCE(Addr)][bankSelect] \ : \ - M[Reduce(Addr)][0]) \ + M[REDUCE(Addr)][0]) \ : \ - (((Reduce(Addr) < MEMSIZE) || ( (cpu_unit.flags & UNIT_ROM) && (ROMLow <= Reduce(Addr)) && (Reduce(Addr) <= ROMHigh) )) ? \ - M[Reduce(Addr)][0] \ + (((REDUCE(Addr) < MEMSIZE) || ( (cpu_unit.flags & UNIT_ROM) && (ROMLow <= REDUCE(Addr)) && (REDUCE(Addr) <= ROMHigh) )) ? \ + M[REDUCE(Addr)][0] \ : \ - warnUnsuccessfulReadAttempt(Reduce(Addr)))) + warnUnsuccessfulReadAttempt(REDUCE(Addr)))) -#define RAM_pp(Addr) \ +#define RAM_PP(Addr) \ ((cpu_unit.flags & UNIT_BANKED) ? \ - (Reduce(Addr) < common ? \ - M[Reduce(Addr++)][bankSelect] \ + (REDUCE(Addr) < common ? \ + M[REDUCE(Addr++)][bankSelect] \ : \ - M[Reduce(Addr++)][0]) \ + M[REDUCE(Addr++)][0]) \ : \ - (((Reduce(Addr) < MEMSIZE) || ( (cpu_unit.flags & UNIT_ROM) && (ROMLow <= Reduce(Addr)) && (Reduce(Addr) <= ROMHigh) )) ? \ - M[Reduce(Addr++)][0] \ + (((REDUCE(Addr) < MEMSIZE) || ( (cpu_unit.flags & UNIT_ROM) && (ROMLow <= REDUCE(Addr)) && (REDUCE(Addr) <= ROMHigh) )) ? \ + M[REDUCE(Addr++)][0] \ : \ - warnUnsuccessfulReadAttempt(Reduce(Addr++)))) + warnUnsuccessfulReadAttempt(REDUCE(Addr++)))) -#define RAM_mm(Addr) \ +#define RAM_MM(Addr) \ ((cpu_unit.flags & UNIT_BANKED) ? \ - (Reduce(Addr) < common ? \ - M[Reduce(Addr--)][bankSelect] \ + (REDUCE(Addr) < common ? \ + M[REDUCE(Addr--)][bankSelect] \ : \ - M[Reduce(Addr--)][0]) \ + M[REDUCE(Addr--)][0]) \ : \ - (((Reduce(Addr) < MEMSIZE) || ( (cpu_unit.flags & UNIT_ROM) && (ROMLow <= Reduce(Addr)) && (Reduce(Addr) <= ROMHigh) )) ? \ - M[Reduce(Addr--)][0] \ + (((REDUCE(Addr) < MEMSIZE) || ( (cpu_unit.flags & UNIT_ROM) && (ROMLow <= REDUCE(Addr)) && (REDUCE(Addr) <= ROMHigh) )) ? \ + M[REDUCE(Addr--)][0] \ : \ - warnUnsuccessfulReadAttempt(Reduce(Addr--)))) + warnUnsuccessfulReadAttempt(REDUCE(Addr--)))) -#define GetWORD(Addr) (GetBYTE(Addr) | (GetBYTE(Addr + 1) << 8)) +#define GET_WORD(Addr) (GET_BYTE(Addr) | (GET_BYTE(Addr + 1) << 8)) uint8 GetBYTEWrapper(const uint32 Addr) { - return GetBYTE(Addr); + return GET_BYTE(Addr); } void PutBYTEWrapper(const uint32 Addr, const uint32 Value) { PutBYTE(Addr, Value); } -#define PutBYTE_pp(a,v) PutBYTE(a++, v) -#define PutBYTE_mm(a,v) PutBYTE(a--, v) -#define mm_PutBYTE(a,v) PutBYTE(--a, v) +#define PUT_BYTE_PP(a,v) PutBYTE(a++, v) +#define PUT_BYTE_MM(a,v) PutBYTE(a--, v) +#define MM_PUT_BYTE(a,v) PutBYTE(--a, v) #define MASK_BRK (TRUE + 1) @@ -1700,31 +1704,31 @@ static void prepareMemoryAccessMessage(t_addr loc) { } #define PUSH(x) { \ - mm_PutBYTE(SP, (x) >> 8); \ - mm_PutBYTE(SP, x); \ + MM_PUT_BYTE(SP, (x) >> 8); \ + MM_PUT_BYTE(SP, x); \ } -#define CheckBreakByte(a) \ - if (sim_brk_summ && sim_brk_test(a, SWMASK('M'))) { \ +#define CHECK_BREAK_BYTE(a) \ + if (sim_brk_summ && sim_brk_test(a & 0xffff, SWMASK('M'))) {\ reason = STOP_MEM; \ - prepareMemoryAccessMessage(a); \ + prepareMemoryAccessMessage(a & 0xffff); \ goto end_decode; \ } -#define CheckBreakTwoBytesExtended(a1, a2, iCode) \ +#define CHECK_BREAK_TWO_BYTES_EXTENDED(a1, a2, iCode) \ if (sim_brk_summ) { \ - br1 = sim_brk_lookup(a1, SWMASK('M')); \ - br2 = br1 ? FALSE : sim_brk_lookup(a2, SWMASK('M')); \ + 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) { \ reason = STOP_MEM; \ if (br1) { \ - prepareMemoryAccessMessage(a1); \ + prepareMemoryAccessMessage(a1 & 0xffff); \ } \ else { \ - prepareMemoryAccessMessage(a2); \ + prepareMemoryAccessMessage(a2 & 0xffff); \ } \ iCode; \ goto end_decode; \ @@ -1734,9 +1738,9 @@ static void prepareMemoryAccessMessage(t_addr loc) { } \ } -#define CheckBreakTwoBytes(a1, a2) CheckBreakTwoBytesExtended(a1, a2,;) +#define CHECK_BREAK_TWO_BYTES(a1, a2) CHECK_BREAK_TWO_BYTES_EXTENDED(a1, a2,;) -#define CheckBreakWord(a) CheckBreakTwoBytes(a, (a + 1)) +#define CHECK_BREAK_WORD(a) CHECK_BREAK_TWO_BYTES(a, (a + 1)) t_stat sim_instr (void) { extern int32 sim_interval; @@ -1766,7 +1770,7 @@ t_stat sim_instr (void) { in one microsecond on a 1MHz CPU. tStates is used for real-time simulations. */ register uint32 tStates; uint32 tStatesInSlice; /* number of t-states in 10 mSec time-slice */ - uint32 startTime; + uint32 startTime, now; int32 br1, br2, tStateModifier = FALSE; AF = AF_S; @@ -1789,7 +1793,12 @@ t_stat sim_instr (void) { /* main instruction fetch/decode loop */ while (TRUE) { /* loop until halted */ - if (sim_interval <= 0) { /* check clock queue */ + if (sim_interval <= 0) { /* check clock queue */ +#if !UNIX_PLATFORM + if ((reason = sim_poll_kbd()) == SCPE_STOP) { /* poll on platforms without reliable signalling */ + break; + } +#endif if ( (reason = sim_process_event()) ) { break; } @@ -1803,23 +1812,20 @@ t_stat sim_instr (void) { /* clockFrequency != 0 implies that real time clock is available */ startTime += sliceLength; tStates -= tStatesInSlice; + if (startTime > (now = sim_os_msec())) { #if defined (_WIN32) - while (sim_os_msec() <= startTime) {} /* poor man's sleep */ + Sleep(startTime - now); #else - { - uint32 now; - if (startTime > (now = sim_os_msec())) { - usleep(1000 * (startTime - now)); - } - } + usleep(1000 * (startTime - now)); #endif + } } if (timerInterrupt && (IFF_S & 1)) { timerInterrupt = FALSE; specialProcessing = clockFrequency | sim_brk_summ; IFF_S = 0; /* disable interrupts */ - CheckBreakTwoBytesExtended(SP - 2, SP - 1, (timerInterrupt = TRUE, IFF_S |= 1)); + CHECK_BREAK_TWO_BYTES_EXTENDED(SP - 2, SP - 1, (timerInterrupt = TRUE, IFF_S |= 1)); PUSH(PC); PCQ_ENTRY(PC - 1); PC = timerInterruptHandler & ADDRMASK; @@ -1838,7 +1844,7 @@ t_stat sim_instr (void) { 1) Either directly to FALSE if no memory access takes place or 2) through a call to a Check... routine */ - switch(RAM_pp(PC)) { + switch(RAM_PP(PC)) { case 0x00: /* NOP */ tStates += 4; @@ -1848,14 +1854,14 @@ t_stat sim_instr (void) { case 0x01: /* LD BC,nnnn */ tStates += 10; sim_brk_pend[0] = FALSE; - BC = GetWORD(PC); + BC = GET_WORD(PC); PC += 2; break; case 0x02: /* LD (BC),A */ tStates += 7; - CheckBreakByte(BC) - PutBYTE(BC, hreg(AF)); + CHECK_BREAK_BYTE(BC) + PutBYTE(BC, HIGH_REGISTER(AF)); break; case 0x03: /* INC BC */ @@ -1868,22 +1874,22 @@ t_stat sim_instr (void) { tStates += 4; sim_brk_pend[0] = FALSE; BC += 0x100; - temp = hreg(BC); - AF = (AF & ~0xfe) | incTable[temp] | SetPV2(0x80); /* SetPV2 uses temp */ + temp = HIGH_REGISTER(BC); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); /* SET_PV2 uses temp */ break; case 0x05: /* DEC B */ tStates += 4; sim_brk_pend[0] = FALSE; BC -= 0x100; - temp = hreg(BC); - AF = (AF & ~0xfe) | decTable[temp] | SetPV2(0x7f); /* SetPV2 uses temp */ + temp = HIGH_REGISTER(BC); + AF = (AF & ~0xfe) | decTable[temp] | SET_PV2(0x7f); /* SET_PV2 uses temp */ break; case 0x06: /* LD B,nn */ tStates += 7; sim_brk_pend[0] = FALSE; - Sethreg(BC, RAM_pp(PC)); + SET_HIGH_REGISTER(BC, RAM_PP(PC)); break; case 0x07: /* RLCA */ @@ -1896,7 +1902,7 @@ t_stat sim_instr (void) { case 0x08: /* EX AF,AF' */ tStates += 4; sim_brk_pend[0] = FALSE; - checkCPU8080; + CHECK_CPU_8080; temp = AF; AF = AF1_S; AF1_S = temp; @@ -1914,8 +1920,8 @@ t_stat sim_instr (void) { case 0x0a: /* LD A,(BC) */ tStates += 7; - CheckBreakByte(BC) - Sethreg(AF, GetBYTE(BC)); + CHECK_BREAK_BYTE(BC) + SET_HIGH_REGISTER(AF, GET_BYTE(BC)); break; case 0x0b: /* DEC BC */ @@ -1927,37 +1933,37 @@ t_stat sim_instr (void) { case 0x0c: /* INC C */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = lreg(BC) + 1; - Setlreg(BC, temp); - AF = (AF & ~0xfe) | incTable[temp] | SetPV2(0x80); + temp = LOW_REGISTER(BC) + 1; + SET_LOW_REGISTER(BC, temp); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); break; case 0x0d: /* DEC C */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = lreg(BC) - 1; - Setlreg(BC, temp); - AF = (AF & ~0xfe) | decTable[temp & 0xff] | SetPV2(0x7f); + temp = LOW_REGISTER(BC) - 1; + SET_LOW_REGISTER(BC, temp); + AF = (AF & ~0xfe) | decTable[temp & 0xff] | SET_PV2(0x7f); break; case 0x0e: /* LD C,nn */ tStates += 7; sim_brk_pend[0] = FALSE; - Setlreg(BC, RAM_pp(PC)); + SET_LOW_REGISTER(BC, RAM_PP(PC)); break; case 0x0f: /* RRCA */ tStates += 4; sim_brk_pend[0] = FALSE; - AF = (AF & 0xc4) | rrcaTable[hreg(AF)]; + AF = (AF & 0xc4) | rrcaTable[HIGH_REGISTER(AF)]; break; case 0x10: /* DJNZ dd */ sim_brk_pend[0] = FALSE; - checkCPU8080; + CHECK_CPU_8080; if ((BC -= 0x100) & 0xff00) { PCQ_ENTRY(PC - 1); - PC += (int8) GetBYTE(PC) + 1; + PC += (int8) GET_BYTE(PC) + 1; tStates += 13; } else { @@ -1969,14 +1975,14 @@ t_stat sim_instr (void) { case 0x11: /* LD DE,nnnn */ tStates += 10; sim_brk_pend[0] = FALSE; - DE = GetWORD(PC); + DE = GET_WORD(PC); PC += 2; break; case 0x12: /* LD (DE),A */ tStates += 7; - CheckBreakByte(DE) - PutBYTE(DE, hreg(AF)); + CHECK_BREAK_BYTE(DE) + PutBYTE(DE, HIGH_REGISTER(AF)); break; case 0x13: /* INC DE */ @@ -1989,22 +1995,22 @@ t_stat sim_instr (void) { tStates += 4; sim_brk_pend[0] = FALSE; DE += 0x100; - temp = hreg(DE); - AF = (AF & ~0xfe) | incTable[temp] | SetPV2(0x80); /* SetPV2 uses temp */ + temp = HIGH_REGISTER(DE); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); /* SET_PV2 uses temp */ break; case 0x15: /* DEC D */ tStates += 4; sim_brk_pend[0] = FALSE; DE -= 0x100; - temp = hreg(DE); - AF = (AF & ~0xfe) | decTable[temp] | SetPV2(0x7f); /* SetPV2 uses temp */ + temp = HIGH_REGISTER(DE); + AF = (AF & ~0xfe) | decTable[temp] | SET_PV2(0x7f); /* SET_PV2 uses temp */ break; case 0x16: /* LD D,nn */ tStates += 7; sim_brk_pend[0] = FALSE; - Sethreg(DE, RAM_pp(PC)); + SET_HIGH_REGISTER(DE, RAM_PP(PC)); break; case 0x17: /* RLA */ @@ -2017,9 +2023,9 @@ t_stat sim_instr (void) { case 0x18: /* JR dd */ tStates += 12; sim_brk_pend[0] = FALSE; - checkCPU8080; + CHECK_CPU_8080; PCQ_ENTRY(PC - 1); - PC += (int8) GetBYTE(PC) + 1; + PC += (int8) GET_BYTE(PC) + 1; break; case 0x19: /* ADD HL,DE */ @@ -2034,8 +2040,8 @@ t_stat sim_instr (void) { case 0x1a: /* LD A,(DE) */ tStates += 7; - CheckBreakByte(DE) - Sethreg(AF, GetBYTE(DE)); + CHECK_BREAK_BYTE(DE) + SET_HIGH_REGISTER(AF, GET_BYTE(DE)); break; case 0x1b: /* DEC DE */ @@ -2047,41 +2053,41 @@ t_stat sim_instr (void) { case 0x1c: /* INC E */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = lreg(DE) + 1; - Setlreg(DE, temp); - AF = (AF & ~0xfe) | incTable[temp] | SetPV2(0x80); + temp = LOW_REGISTER(DE) + 1; + SET_LOW_REGISTER(DE, temp); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); break; case 0x1d: /* DEC E */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = lreg(DE) - 1; - Setlreg(DE, temp); - AF = (AF & ~0xfe) | decTable[temp & 0xff] | SetPV2(0x7f); + temp = LOW_REGISTER(DE) - 1; + SET_LOW_REGISTER(DE, temp); + AF = (AF & ~0xfe) | decTable[temp & 0xff] | SET_PV2(0x7f); break; case 0x1e: /* LD E,nn */ tStates += 7; sim_brk_pend[0] = FALSE; - Setlreg(DE, RAM_pp(PC)); + SET_LOW_REGISTER(DE, RAM_PP(PC)); break; case 0x1f: /* RRA */ tStates += 4; sim_brk_pend[0] = FALSE; - AF = ((AF & 1) << 15) | (AF & 0xc4) | rraTable[hreg(AF)]; + AF = ((AF & 1) << 15) | (AF & 0xc4) | rraTable[HIGH_REGISTER(AF)]; break; case 0x20: /* JR NZ,dd */ sim_brk_pend[0] = FALSE; - checkCPU8080; + CHECK_CPU_8080; if (TSTFLAG(Z)) { PC++; tStates += 7; } else { PCQ_ENTRY(PC - 1); - PC += (int8) GetBYTE(PC) + 1; + PC += (int8) GET_BYTE(PC) + 1; tStates += 12; } break; @@ -2089,14 +2095,14 @@ t_stat sim_instr (void) { case 0x21: /* LD HL,nnnn */ tStates += 10; sim_brk_pend[0] = FALSE; - HL = GetWORD(PC); + HL = GET_WORD(PC); PC += 2; break; case 0x22: /* LD (nnnn),HL */ tStates += 16; - temp = GetWORD(PC); - CheckBreakWord(temp); + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); PutWORD(temp, HL); PC += 2; break; @@ -2111,29 +2117,29 @@ t_stat sim_instr (void) { tStates += 4; sim_brk_pend[0] = FALSE; HL += 0x100; - temp = hreg(HL); - AF = (AF & ~0xfe) | incTable[temp] | SetPV2(0x80); /* SetPV2 uses temp */ + temp = HIGH_REGISTER(HL); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); /* SET_PV2 uses temp */ break; case 0x25: /* DEC H */ tStates += 4; sim_brk_pend[0] = FALSE; HL -= 0x100; - temp = hreg(HL); - AF = (AF & ~0xfe) | decTable[temp] | SetPV2(0x7f); /* SetPV2 uses temp */ + temp = HIGH_REGISTER(HL); + AF = (AF & ~0xfe) | decTable[temp] | SET_PV2(0x7f); /* SET_PV2 uses temp */ break; case 0x26: /* LD H,nn */ tStates += 7; sim_brk_pend[0] = FALSE; - Sethreg(HL, RAM_pp(PC)); + SET_HIGH_REGISTER(HL, RAM_PP(PC)); break; case 0x27: /* DAA */ tStates += 4; sim_brk_pend[0] = FALSE; - acu = hreg(AF); - temp = ldig(acu); + acu = HIGH_REGISTER(AF); + temp = LOW_DIGIT(acu); cbits = TSTFLAG(C); if (TSTFLAG(N)) { /* last operation was a subtract */ int hd = cbits || acu > 0x99; @@ -2162,10 +2168,10 @@ t_stat sim_instr (void) { case 0x28: /* JR Z,dd */ sim_brk_pend[0] = FALSE; - checkCPU8080; + CHECK_CPU_8080; if (TSTFLAG(Z)) { PCQ_ENTRY(PC - 1); - PC += (int8) GetBYTE(PC) + 1; + PC += (int8) GET_BYTE(PC) + 1; tStates += 12; } else { @@ -2185,9 +2191,9 @@ t_stat sim_instr (void) { case 0x2a: /* LD HL,(nnnn) */ tStates += 16; - temp = GetWORD(PC); - CheckBreakWord(temp); - HL = GetWORD(temp); + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); + HL = GET_WORD(temp); PC += 2; break; @@ -2200,23 +2206,23 @@ t_stat sim_instr (void) { case 0x2c: /* INC L */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = lreg(HL) + 1; - Setlreg(HL, temp); - AF = (AF & ~0xfe) | incTable[temp] | SetPV2(0x80); + temp = LOW_REGISTER(HL) + 1; + SET_LOW_REGISTER(HL, temp); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); break; case 0x2d: /* DEC L */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = lreg(HL) - 1; - Setlreg(HL, temp); - AF = (AF & ~0xfe) | decTable[temp & 0xff] | SetPV2(0x7f); + temp = LOW_REGISTER(HL) - 1; + SET_LOW_REGISTER(HL, temp); + AF = (AF & ~0xfe) | decTable[temp & 0xff] | SET_PV2(0x7f); break; case 0x2e: /* LD L,nn */ tStates += 7; sim_brk_pend[0] = FALSE; - Setlreg(HL, RAM_pp(PC)); + SET_LOW_REGISTER(HL, RAM_PP(PC)); break; case 0x2f: /* CPL */ @@ -2227,14 +2233,14 @@ t_stat sim_instr (void) { case 0x30: /* JR NC,dd */ sim_brk_pend[0] = FALSE; - checkCPU8080; + CHECK_CPU_8080; if (TSTFLAG(C)) { PC++; tStates += 7; } else { PCQ_ENTRY(PC - 1); - PC += (int8) GetBYTE(PC) + 1; + PC += (int8) GET_BYTE(PC) + 1; tStates += 12; } break; @@ -2242,15 +2248,15 @@ t_stat sim_instr (void) { case 0x31: /* LD SP,nnnn */ tStates += 10; sim_brk_pend[0] = FALSE; - SP = GetWORD(PC); + SP = GET_WORD(PC); PC += 2; break; case 0x32: /* LD (nnnn),A */ tStates += 13; - temp = GetWORD(PC); - CheckBreakByte(temp); - PutBYTE(temp, hreg(AF)); + temp = GET_WORD(PC); + CHECK_BREAK_BYTE(temp); + PutBYTE(temp, HIGH_REGISTER(AF)); PC += 2; break; @@ -2262,24 +2268,24 @@ t_stat sim_instr (void) { case 0x34: /* INC (HL) */ tStates += 11; - CheckBreakByte(HL); - temp = GetBYTE(HL) + 1; + CHECK_BREAK_BYTE(HL); + temp = GET_BYTE(HL) + 1; PutBYTE(HL, temp); - AF = (AF & ~0xfe) | incTable[temp] | SetPV2(0x80); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); break; case 0x35: /* DEC (HL) */ tStates += 11; - CheckBreakByte(HL); - temp = GetBYTE(HL) - 1; + CHECK_BREAK_BYTE(HL); + temp = GET_BYTE(HL) - 1; PutBYTE(HL, temp); - AF = (AF & ~0xfe) | decTable[temp & 0xff] | SetPV2(0x7f); + AF = (AF & ~0xfe) | decTable[temp & 0xff] | SET_PV2(0x7f); break; case 0x36: /* LD (HL),nn */ tStates += 10; - CheckBreakByte(HL); - PutBYTE(HL, RAM_pp(PC)); + CHECK_BREAK_BYTE(HL); + PutBYTE(HL, RAM_PP(PC)); break; case 0x37: /* SCF */ @@ -2290,10 +2296,10 @@ t_stat sim_instr (void) { case 0x38: /* JR C,dd */ sim_brk_pend[0] = FALSE; - checkCPU8080; + CHECK_CPU_8080; if (TSTFLAG(C)) { PCQ_ENTRY(PC - 1); - PC += (int8) GetBYTE(PC) + 1; + PC += (int8) GET_BYTE(PC) + 1; tStates += 12; } else { @@ -2314,9 +2320,9 @@ t_stat sim_instr (void) { case 0x3a: /* LD A,(nnnn) */ tStates += 13; - temp = GetWORD(PC); - CheckBreakByte(temp); - Sethreg(AF, GetBYTE(temp)); + temp = GET_WORD(PC); + CHECK_BREAK_BYTE(temp); + SET_HIGH_REGISTER(AF, GET_BYTE(temp)); PC += 2; break; @@ -2330,22 +2336,22 @@ t_stat sim_instr (void) { tStates += 4; sim_brk_pend[0] = FALSE; AF += 0x100; - temp = hreg(AF); - AF = (AF & ~0xfe) | incTable[temp] | SetPV2(0x80); /* SetPV2 uses temp */ + temp = HIGH_REGISTER(AF); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); /* SET_PV2 uses temp */ break; case 0x3d: /* DEC A */ tStates += 4; sim_brk_pend[0] = FALSE; AF -= 0x100; - temp = hreg(AF); - AF = (AF & ~0xfe) | decTable[temp] | SetPV2(0x7f); /* SetPV2 uses temp */ + temp = HIGH_REGISTER(AF); + AF = (AF & ~0xfe) | decTable[temp] | SET_PV2(0x7f); /* SET_PV2 uses temp */ break; case 0x3e: /* LD A,nn */ tStates += 7; sim_brk_pend[0] = FALSE; - Sethreg(AF, RAM_pp(PC)); + SET_HIGH_REGISTER(AF, RAM_PP(PC)); break; case 0x3f: /* CCF */ @@ -2391,8 +2397,8 @@ t_stat sim_instr (void) { case 0x46: /* LD B,(HL) */ tStates += 7; - CheckBreakByte(HL); - Sethreg(BC, GetBYTE(HL)); + CHECK_BREAK_BYTE(HL); + SET_HIGH_REGISTER(BC, GET_BYTE(HL)); break; case 0x47: /* LD B,A */ @@ -2438,8 +2444,8 @@ t_stat sim_instr (void) { case 0x4e: /* LD C,(HL) */ tStates += 7; - CheckBreakByte(HL); - Setlreg(BC, GetBYTE(HL)); + CHECK_BREAK_BYTE(HL); + SET_LOW_REGISTER(BC, GET_BYTE(HL)); break; case 0x4f: /* LD C,A */ @@ -2485,8 +2491,8 @@ t_stat sim_instr (void) { case 0x56: /* LD D,(HL) */ tStates += 7; - CheckBreakByte(HL); - Sethreg(DE, GetBYTE(HL)); + CHECK_BREAK_BYTE(HL); + SET_HIGH_REGISTER(DE, GET_BYTE(HL)); break; case 0x57: /* LD D,A */ @@ -2532,8 +2538,8 @@ t_stat sim_instr (void) { case 0x5e: /* LD E,(HL) */ tStates += 7; - CheckBreakByte(HL); - Setlreg(DE, GetBYTE(HL)); + CHECK_BREAK_BYTE(HL); + SET_LOW_REGISTER(DE, GET_BYTE(HL)); break; case 0x5f: /* LD E,A */ @@ -2579,8 +2585,8 @@ t_stat sim_instr (void) { case 0x66: /* LD H,(HL) */ tStates += 7; - CheckBreakByte(HL); - Sethreg(HL, GetBYTE(HL)); + CHECK_BREAK_BYTE(HL); + SET_HIGH_REGISTER(HL, GET_BYTE(HL)); break; case 0x67: /* LD H,A */ @@ -2626,8 +2632,8 @@ t_stat sim_instr (void) { case 0x6e: /* LD L,(HL) */ tStates += 7; - CheckBreakByte(HL); - Setlreg(HL, GetBYTE(HL)); + CHECK_BREAK_BYTE(HL); + SET_LOW_REGISTER(HL, GET_BYTE(HL)); break; case 0x6f: /* LD L,A */ @@ -2638,38 +2644,38 @@ t_stat sim_instr (void) { case 0x70: /* LD (HL),B */ tStates += 7; - CheckBreakByte(HL); - PutBYTE(HL, hreg(BC)); + CHECK_BREAK_BYTE(HL); + PutBYTE(HL, HIGH_REGISTER(BC)); break; case 0x71: /* LD (HL),C */ tStates += 7; - CheckBreakByte(HL); - PutBYTE(HL, lreg(BC)); + CHECK_BREAK_BYTE(HL); + PutBYTE(HL, LOW_REGISTER(BC)); break; case 0x72: /* LD (HL),D */ tStates += 7; - CheckBreakByte(HL); - PutBYTE(HL, hreg(DE)); + CHECK_BREAK_BYTE(HL); + PutBYTE(HL, HIGH_REGISTER(DE)); break; case 0x73: /* LD (HL),E */ tStates += 7; - CheckBreakByte(HL); - PutBYTE(HL, lreg(DE)); + CHECK_BREAK_BYTE(HL); + PutBYTE(HL, LOW_REGISTER(DE)); break; case 0x74: /* LD (HL),H */ tStates += 7; - CheckBreakByte(HL); - PutBYTE(HL, hreg(HL)); + CHECK_BREAK_BYTE(HL); + PutBYTE(HL, HIGH_REGISTER(HL)); break; case 0x75: /* LD (HL),L */ tStates += 7; - CheckBreakByte(HL); - PutBYTE(HL, lreg(HL)); + CHECK_BREAK_BYTE(HL); + PutBYTE(HL, LOW_REGISTER(HL)); break; case 0x76: /* HALT */ @@ -2681,8 +2687,8 @@ t_stat sim_instr (void) { case 0x77: /* LD (HL),A */ tStates += 7; - CheckBreakByte(HL); - PutBYTE(HL, hreg(AF)); + CHECK_BREAK_BYTE(HL); + PutBYTE(HL, HIGH_REGISTER(AF)); break; case 0x78: /* LD A,B */ @@ -2723,8 +2729,8 @@ t_stat sim_instr (void) { case 0x7e: /* LD A,(HL) */ tStates += 7; - CheckBreakByte(HL); - Sethreg(AF, GetBYTE(HL)); + CHECK_BREAK_BYTE(HL); + SET_HIGH_REGISTER(AF, GET_BYTE(HL)); break; case 0x7f: /* LD A,A */ @@ -2735,225 +2741,225 @@ t_stat sim_instr (void) { case 0x80: /* ADD A,B */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = hreg(BC); - acu = hreg(AF); + temp = HIGH_REGISTER(BC); + acu = HIGH_REGISTER(AF); sum = acu + temp; cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); break; case 0x81: /* ADD A,C */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = lreg(BC); - acu = hreg(AF); + temp = LOW_REGISTER(BC); + acu = HIGH_REGISTER(AF); sum = acu + temp; cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); break; case 0x82: /* ADD A,D */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = hreg(DE); - acu = hreg(AF); + temp = HIGH_REGISTER(DE); + acu = HIGH_REGISTER(AF); sum = acu + temp; cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); break; case 0x83: /* ADD A,E */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = lreg(DE); - acu = hreg(AF); + temp = LOW_REGISTER(DE); + acu = HIGH_REGISTER(AF); sum = acu + temp; cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); break; case 0x84: /* ADD A,H */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = hreg(HL); - acu = hreg(AF); + temp = HIGH_REGISTER(HL); + acu = HIGH_REGISTER(AF); sum = acu + temp; cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); break; case 0x85: /* ADD A,L */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = lreg(HL); - acu = hreg(AF); + temp = LOW_REGISTER(HL); + acu = HIGH_REGISTER(AF); sum = acu + temp; cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); break; case 0x86: /* ADD A,(HL) */ tStates += 7; - CheckBreakByte(HL); - temp = GetBYTE(HL); - acu = hreg(AF); + CHECK_BREAK_BYTE(HL); + temp = GET_BYTE(HL); + acu = HIGH_REGISTER(AF); sum = acu + temp; cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); break; case 0x87: /* ADD A,A */ tStates += 4; sim_brk_pend[0] = FALSE; - cbits = 2 * hreg(AF); - AF = cbitsDup8Table[cbits] | (SetPVS(cbits)); + cbits = 2 * HIGH_REGISTER(AF); + AF = cbitsDup8Table[cbits] | (SET_PVS(cbits)); break; case 0x88: /* ADC A,B */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = hreg(BC); - acu = hreg(AF); + temp = HIGH_REGISTER(BC); + acu = HIGH_REGISTER(AF); sum = acu + temp + TSTFLAG(C); cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); break; case 0x89: /* ADC A,C */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = lreg(BC); - acu = hreg(AF); + temp = LOW_REGISTER(BC); + acu = HIGH_REGISTER(AF); sum = acu + temp + TSTFLAG(C); cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); break; case 0x8a: /* ADC A,D */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = hreg(DE); - acu = hreg(AF); + temp = HIGH_REGISTER(DE); + acu = HIGH_REGISTER(AF); sum = acu + temp + TSTFLAG(C); cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); break; case 0x8b: /* ADC A,E */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = lreg(DE); - acu = hreg(AF); + temp = LOW_REGISTER(DE); + acu = HIGH_REGISTER(AF); sum = acu + temp + TSTFLAG(C); cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); break; case 0x8c: /* ADC A,H */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = hreg(HL); - acu = hreg(AF); + temp = HIGH_REGISTER(HL); + acu = HIGH_REGISTER(AF); sum = acu + temp + TSTFLAG(C); cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); break; case 0x8d: /* ADC A,L */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = lreg(HL); - acu = hreg(AF); + temp = LOW_REGISTER(HL); + acu = HIGH_REGISTER(AF); sum = acu + temp + TSTFLAG(C); cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); break; case 0x8e: /* ADC A,(HL) */ tStates += 7; - CheckBreakByte(HL); - temp = GetBYTE(HL); - acu = hreg(AF); + CHECK_BREAK_BYTE(HL); + temp = GET_BYTE(HL); + acu = HIGH_REGISTER(AF); sum = acu + temp + TSTFLAG(C); cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); break; case 0x8f: /* ADC A,A */ tStates += 4; sim_brk_pend[0] = FALSE; - cbits = 2 * hreg(AF) + TSTFLAG(C); - AF = cbitsDup8Table[cbits] | (SetPVS(cbits)); + cbits = 2 * HIGH_REGISTER(AF) + TSTFLAG(C); + AF = cbitsDup8Table[cbits] | (SET_PVS(cbits)); break; case 0x90: /* SUB B */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = hreg(BC); - acu = hreg(AF); + temp = HIGH_REGISTER(BC); + acu = HIGH_REGISTER(AF); sum = acu - temp; cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); break; case 0x91: /* SUB C */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = lreg(BC); - acu = hreg(AF); + temp = LOW_REGISTER(BC); + acu = HIGH_REGISTER(AF); sum = acu - temp; cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); break; case 0x92: /* SUB D */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = hreg(DE); - acu = hreg(AF); + temp = HIGH_REGISTER(DE); + acu = HIGH_REGISTER(AF); sum = acu - temp; cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); break; case 0x93: /* SUB E */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = lreg(DE); - acu = hreg(AF); + temp = LOW_REGISTER(DE); + acu = HIGH_REGISTER(AF); sum = acu - temp; cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); break; case 0x94: /* SUB H */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = hreg(HL); - acu = hreg(AF); + temp = HIGH_REGISTER(HL); + acu = HIGH_REGISTER(AF); sum = acu - temp; cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); break; case 0x95: /* SUB L */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = lreg(HL); - acu = hreg(AF); + temp = LOW_REGISTER(HL); + acu = HIGH_REGISTER(AF); sum = acu - temp; cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); break; case 0x96: /* SUB (HL) */ tStates += 7; - CheckBreakByte(HL); - temp = GetBYTE(HL); - acu = hreg(AF); + CHECK_BREAK_BYTE(HL); + temp = GET_BYTE(HL); + acu = HIGH_REGISTER(AF); sum = acu - temp; cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); break; case 0x97: /* SUB A */ @@ -2965,78 +2971,78 @@ t_stat sim_instr (void) { case 0x98: /* SBC A,B */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = hreg(BC); - acu = hreg(AF); + temp = HIGH_REGISTER(BC); + acu = HIGH_REGISTER(AF); sum = acu - temp - TSTFLAG(C); cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); break; case 0x99: /* SBC A,C */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = lreg(BC); - acu = hreg(AF); + temp = LOW_REGISTER(BC); + acu = HIGH_REGISTER(AF); sum = acu - temp - TSTFLAG(C); cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); break; case 0x9a: /* SBC A,D */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = hreg(DE); - acu = hreg(AF); + temp = HIGH_REGISTER(DE); + acu = HIGH_REGISTER(AF); sum = acu - temp - TSTFLAG(C); cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); break; case 0x9b: /* SBC A,E */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = lreg(DE); - acu = hreg(AF); + temp = LOW_REGISTER(DE); + acu = HIGH_REGISTER(AF); sum = acu - temp - TSTFLAG(C); cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); break; case 0x9c: /* SBC A,H */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = hreg(HL); - acu = hreg(AF); + temp = HIGH_REGISTER(HL); + acu = HIGH_REGISTER(AF); sum = acu - temp - TSTFLAG(C); cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); break; case 0x9d: /* SBC A,L */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = lreg(HL); - acu = hreg(AF); + temp = LOW_REGISTER(HL); + acu = HIGH_REGISTER(AF); sum = acu - temp - TSTFLAG(C); cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); break; case 0x9e: /* SBC A,(HL) */ tStates += 7; - CheckBreakByte(HL); - temp = GetBYTE(HL); - acu = hreg(AF); + CHECK_BREAK_BYTE(HL); + temp = GET_BYTE(HL); + acu = HIGH_REGISTER(AF); sum = acu - temp - TSTFLAG(C); cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); break; case 0x9f: /* SBC A,A */ tStates += 4; sim_brk_pend[0] = FALSE; cbits = -TSTFLAG(C); - AF = subTable[cbits & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPVS(cbits)); + AF = subTable[cbits & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PVS(cbits)); break; case 0xa0: /* AND B */ @@ -3077,8 +3083,8 @@ t_stat sim_instr (void) { case 0xa6: /* AND (HL) */ tStates += 7; - CheckBreakByte(HL); - AF = andTable[((AF >> 8) & GetBYTE(HL)) & 0xff]; + CHECK_BREAK_BYTE(HL); + AF = andTable[((AF >> 8) & GET_BYTE(HL)) & 0xff]; break; case 0xa7: /* AND A */ @@ -3125,8 +3131,8 @@ t_stat sim_instr (void) { case 0xae: /* XOR (HL) */ tStates += 7; - CheckBreakByte(HL); - AF = xororTable[((AF >> 8) ^ GetBYTE(HL)) & 0xff]; + CHECK_BREAK_BYTE(HL); + AF = xororTable[((AF >> 8) ^ GET_BYTE(HL)) & 0xff]; break; case 0xaf: /* XOR A */ @@ -3173,8 +3179,8 @@ t_stat sim_instr (void) { case 0xb6: /* OR (HL) */ tStates += 7; - CheckBreakByte(HL); - AF = xororTable[((AF >> 8) | GetBYTE(HL)) & 0xff]; + CHECK_BREAK_BYTE(HL); + AF = xororTable[((AF >> 8) | GET_BYTE(HL)) & 0xff]; break; case 0xb7: /* OR A */ @@ -3186,91 +3192,91 @@ t_stat sim_instr (void) { case 0xb8: /* CP B */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = hreg(BC); + temp = HIGH_REGISTER(BC); AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); + acu = HIGH_REGISTER(AF); sum = acu - temp; cbits = acu ^ temp ^ sum; AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - (SetPV) | cbits2Table[cbits & 0x1ff]; + (SET_PV) | cbits2Table[cbits & 0x1ff]; break; case 0xb9: /* CP C */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = lreg(BC); + temp = LOW_REGISTER(BC); AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); + acu = HIGH_REGISTER(AF); sum = acu - temp; cbits = acu ^ temp ^ sum; AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - (SetPV) | cbits2Table[cbits & 0x1ff]; + (SET_PV) | cbits2Table[cbits & 0x1ff]; break; case 0xba: /* CP D */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = hreg(DE); + temp = HIGH_REGISTER(DE); AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); + acu = HIGH_REGISTER(AF); sum = acu - temp; cbits = acu ^ temp ^ sum; AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - (SetPV) | cbits2Table[cbits & 0x1ff]; + (SET_PV) | cbits2Table[cbits & 0x1ff]; break; case 0xbb: /* CP E */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = lreg(DE); + temp = LOW_REGISTER(DE); AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); + acu = HIGH_REGISTER(AF); sum = acu - temp; cbits = acu ^ temp ^ sum; AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - (SetPV) | cbits2Table[cbits & 0x1ff]; + (SET_PV) | cbits2Table[cbits & 0x1ff]; break; case 0xbc: /* CP H */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = hreg(HL); + temp = HIGH_REGISTER(HL); AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); + acu = HIGH_REGISTER(AF); sum = acu - temp; cbits = acu ^ temp ^ sum; AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - (SetPV) | cbits2Table[cbits & 0x1ff]; + (SET_PV) | cbits2Table[cbits & 0x1ff]; break; case 0xbd: /* CP L */ tStates += 4; sim_brk_pend[0] = FALSE; - temp = lreg(HL); + temp = LOW_REGISTER(HL); AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); + acu = HIGH_REGISTER(AF); sum = acu - temp; cbits = acu ^ temp ^ sum; AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - (SetPV) | cbits2Table[cbits & 0x1ff]; + (SET_PV) | cbits2Table[cbits & 0x1ff]; break; case 0xbe: /* CP (HL) */ tStates += 7; - CheckBreakByte(HL); - temp = GetBYTE(HL); + CHECK_BREAK_BYTE(HL); + temp = GET_BYTE(HL); AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); + acu = HIGH_REGISTER(AF); sum = acu - temp; cbits = acu ^ temp ^ sum; AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - (SetPV) | cbits2Table[cbits & 0x1ff]; + (SET_PV) | cbits2Table[cbits & 0x1ff]; break; case 0xbf: /* CP A */ tStates += 4; sim_brk_pend[0] = FALSE; - Setlreg(AF, (hreg(AF) & 0x28) | (cpu_unit.flags & UNIT_CHIP ? 0x42 : 0x46)); + SET_LOW_REGISTER(AF, (HIGH_REGISTER(AF) & 0x28) | (cpu_unit.flags & UNIT_CHIP ? 0x42 : 0x46)); break; case 0xc0: /* RET NZ */ @@ -3279,7 +3285,7 @@ t_stat sim_instr (void) { tStates += 5; } else { - CheckBreakWord(SP); + CHECK_BREAK_WORD(SP); PCQ_ENTRY(PC - 1); POP(PC); tStates += 11; @@ -3288,7 +3294,7 @@ t_stat sim_instr (void) { case 0xc1: /* POP BC */ tStates += 10; - CheckBreakWord(SP); + CHECK_BREAK_WORD(SP); POP(BC); break; @@ -3308,23 +3314,23 @@ t_stat sim_instr (void) { case 0xc5: /* PUSH BC */ tStates += 11; - CheckBreakWord(SP - 2); + CHECK_BREAK_WORD(SP - 2); PUSH(BC); break; case 0xc6: /* ADD A,nn */ tStates += 7; sim_brk_pend[0] = FALSE; - temp = RAM_pp(PC); - acu = hreg(AF); + temp = RAM_PP(PC); + acu = HIGH_REGISTER(AF); sum = acu + temp; cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); break; case 0xc7: /* RST 0 */ tStates += 11; - CheckBreakWord(SP - 2); + CHECK_BREAK_WORD(SP - 2); PUSH(PC); PCQ_ENTRY(PC - 1); PC = 0; @@ -3332,7 +3338,7 @@ t_stat sim_instr (void) { case 0xc8: /* RET Z */ if (TSTFLAG(Z)) { - CheckBreakWord(SP); + CHECK_BREAK_WORD(SP); PCQ_ENTRY(PC - 1); POP(PC); tStates += 11; @@ -3345,7 +3351,7 @@ t_stat sim_instr (void) { case 0xc9: /* RET */ tStates += 10; - CheckBreakWord(SP); + CHECK_BREAK_WORD(SP); PCQ_ENTRY(PC - 1); POP(PC); break; @@ -3356,56 +3362,56 @@ t_stat sim_instr (void) { break; case 0xcb: /* CB prefix */ - checkCPU8080; + CHECK_CPU_8080; adr = HL; - switch ((op = GetBYTE(PC)) & 7) { + switch ((op = GET_BYTE(PC)) & 7) { case 0: sim_brk_pend[0] = tStateModifier = FALSE; ++PC; - acu = hreg(BC); + acu = HIGH_REGISTER(BC); tStates += 8; break; case 1: sim_brk_pend[0] = tStateModifier = FALSE; ++PC; - acu = lreg(BC); + acu = LOW_REGISTER(BC); tStates += 8; break; case 2: sim_brk_pend[0] = tStateModifier = FALSE; ++PC; - acu = hreg(DE); + acu = HIGH_REGISTER(DE); tStates += 8; break; case 3: sim_brk_pend[0] = tStateModifier = FALSE; ++PC; - acu = lreg(DE); + acu = LOW_REGISTER(DE); tStates += 8; break; case 4: sim_brk_pend[0] = tStateModifier = FALSE; ++PC; - acu = hreg(HL); + acu = HIGH_REGISTER(HL); tStates += 8; break; case 5: sim_brk_pend[0] = tStateModifier = FALSE; ++PC; - acu = lreg(HL); + acu = LOW_REGISTER(HL); tStates += 8; break; case 6: - CheckBreakByte(adr); + CHECK_BREAK_BYTE(adr); ++PC; - acu = GetBYTE(adr); + acu = GET_BYTE(adr); tStateModifier = TRUE; tStates += 15; break; @@ -3413,7 +3419,7 @@ t_stat sim_instr (void) { case 7: sim_brk_pend[0] = tStateModifier = FALSE; ++PC; - acu = hreg(AF); + acu = HIGH_REGISTER(AF); tStates += 8; break; } @@ -3493,27 +3499,27 @@ t_stat sim_instr (void) { switch (op & 7) { case 0: - Sethreg(BC, temp); + SET_HIGH_REGISTER(BC, temp); break; case 1: - Setlreg(BC, temp); + SET_LOW_REGISTER(BC, temp); break; case 2: - Sethreg(DE, temp); + SET_HIGH_REGISTER(DE, temp); break; case 3: - Setlreg(DE, temp); + SET_LOW_REGISTER(DE, temp); break; case 4: - Sethreg(HL, temp); + SET_HIGH_REGISTER(HL, temp); break; case 5: - Setlreg(HL, temp); + SET_LOW_REGISTER(HL, temp); break; case 6: @@ -3521,7 +3527,7 @@ t_stat sim_instr (void) { break; case 7: - Sethreg(AF, temp); + SET_HIGH_REGISTER(AF, temp); break; } break; @@ -3537,16 +3543,16 @@ t_stat sim_instr (void) { case 0xce: /* ADC A,nn */ tStates += 7; sim_brk_pend[0] = FALSE; - temp = RAM_pp(PC); - acu = hreg(AF); + temp = RAM_PP(PC); + acu = HIGH_REGISTER(AF); sum = acu + temp + TSTFLAG(C); cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SetPV); + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); break; case 0xcf: /* RST 8 */ tStates += 11; - CheckBreakWord(SP - 2); + CHECK_BREAK_WORD(SP - 2); PUSH(PC); PCQ_ENTRY(PC - 1); PC = 8; @@ -3558,7 +3564,7 @@ t_stat sim_instr (void) { tStates += 5; } else { - CheckBreakWord(SP); + CHECK_BREAK_WORD(SP); PCQ_ENTRY(PC - 1); POP(PC); tStates += 11; @@ -3567,7 +3573,7 @@ t_stat sim_instr (void) { case 0xd1: /* POP DE */ tStates += 10; - CheckBreakWord(SP); + CHECK_BREAK_WORD(SP); POP(DE); break; @@ -3579,7 +3585,7 @@ t_stat sim_instr (void) { case 0xd3: /* OUT (nn),A */ tStates += 11; sim_brk_pend[0] = FALSE; - out(RAM_pp(PC), hreg(AF)); + out(RAM_PP(PC), HIGH_REGISTER(AF)); break; case 0xd4: /* CALL NC,nnnn */ @@ -3588,23 +3594,23 @@ t_stat sim_instr (void) { case 0xd5: /* PUSH DE */ tStates += 11; - CheckBreakWord(SP - 2); + CHECK_BREAK_WORD(SP - 2); PUSH(DE); break; case 0xd6: /* SUB nn */ tStates += 7; sim_brk_pend[0] = FALSE; - temp = RAM_pp(PC); - acu = hreg(AF); + temp = RAM_PP(PC); + acu = HIGH_REGISTER(AF); sum = acu - temp; cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); break; case 0xd7: /* RST 10H */ tStates += 11; - CheckBreakWord(SP - 2); + CHECK_BREAK_WORD(SP - 2); PUSH(PC); PCQ_ENTRY(PC - 1); PC = 0x10; @@ -3612,7 +3618,7 @@ t_stat sim_instr (void) { case 0xd8: /* RET C */ if (TSTFLAG(C)) { - CheckBreakWord(SP); + CHECK_BREAK_WORD(SP); PCQ_ENTRY(PC - 1); POP(PC); tStates += 11; @@ -3626,7 +3632,7 @@ t_stat sim_instr (void) { case 0xd9: /* EXX */ tStates += 4; sim_brk_pend[0] = FALSE; - checkCPU8080; + CHECK_CPU_8080; temp = BC; BC = BC1_S; BC1_S = temp; @@ -3646,7 +3652,7 @@ t_stat sim_instr (void) { case 0xdb: /* IN A,(nn) */ tStates += 11; sim_brk_pend[0] = FALSE; - Sethreg(AF, in(RAM_pp(PC))); + SET_HIGH_REGISTER(AF, in(RAM_PP(PC))); break; case 0xdc: /* CALL C,nnnn */ @@ -3654,8 +3660,8 @@ t_stat sim_instr (void) { break; case 0xdd: /* DD prefix */ - checkCPU8080; - switch (op = RAM_pp(PC)) { + CHECK_CPU_8080; + switch (op = RAM_PP(PC)) { case 0x09: /* ADD IX,BC */ tStates += 15; @@ -3680,14 +3686,14 @@ t_stat sim_instr (void) { case 0x21: /* LD IX,nnnn */ tStates += 14; sim_brk_pend[0] = FALSE; - IX = GetWORD(PC); + IX = GET_WORD(PC); PC += 2; break; case 0x22: /* LD (nnnn),IX */ tStates += 20; - temp = GetWORD(PC); - CheckBreakWord(temp); + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); PutWORD(temp, IX); PC += 2; break; @@ -3702,20 +3708,20 @@ t_stat sim_instr (void) { tStates += 9; sim_brk_pend[0] = FALSE; IX += 0x100; - AF = (AF & ~0xfe) | incZ80Table[hreg(IX)]; + AF = (AF & ~0xfe) | incZ80Table[HIGH_REGISTER(IX)]; break; case 0x25: /* DEC IXH */ tStates += 9; sim_brk_pend[0] = FALSE; IX -= 0x100; - AF = (AF & ~0xfe) | decZ80Table[hreg(IX)]; + AF = (AF & ~0xfe) | decZ80Table[HIGH_REGISTER(IX)]; break; case 0x26: /* LD IXH,nn */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(IX, RAM_pp(PC)); + SET_HIGH_REGISTER(IX, RAM_PP(PC)); break; case 0x29: /* ADD IX,IX */ @@ -3729,9 +3735,9 @@ t_stat sim_instr (void) { case 0x2a: /* LD IX,(nnnn) */ tStates += 20; - temp = GetWORD(PC); - CheckBreakWord(temp); - IX = GetWORD(temp); + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); + IX = GET_WORD(temp); PC += 2; break; @@ -3744,48 +3750,48 @@ t_stat sim_instr (void) { case 0x2c: /* INC IXL */ tStates += 9; sim_brk_pend[0] = FALSE; - temp = lreg(IX) + 1; - Setlreg(IX, temp); + temp = LOW_REGISTER(IX) + 1; + SET_LOW_REGISTER(IX, temp); AF = (AF & ~0xfe) | incZ80Table[temp]; break; case 0x2d: /* DEC IXL */ tStates += 9; sim_brk_pend[0] = FALSE; - temp = lreg(IX) - 1; - Setlreg(IX, temp); + temp = LOW_REGISTER(IX) - 1; + SET_LOW_REGISTER(IX, temp); AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; break; case 0x2e: /* LD IXL,nn */ tStates += 9; sim_brk_pend[0] = FALSE; - Setlreg(IX, RAM_pp(PC)); + SET_LOW_REGISTER(IX, RAM_PP(PC)); break; case 0x34: /* INC (IX+dd) */ tStates += 23; - adr = IX + (int8) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr) + 1; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GET_BYTE(adr) + 1; PutBYTE(adr, temp); AF = (AF & ~0xfe) | incZ80Table[temp]; break; case 0x35: /* DEC (IX+dd) */ tStates += 23; - adr = IX + (int8) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr) - 1; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GET_BYTE(adr) - 1; PutBYTE(adr, temp); AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; break; case 0x36: /* LD (IX+dd),nn */ tStates += 19; - adr = IX + (int8) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, RAM_pp(PC)); + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, RAM_PP(PC)); break; case 0x39: /* ADD IX,SP */ @@ -3801,101 +3807,101 @@ t_stat sim_instr (void) { case 0x44: /* LD B,IXH */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(BC, hreg(IX)); + SET_HIGH_REGISTER(BC, HIGH_REGISTER(IX)); break; case 0x45: /* LD B,IXL */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(BC, lreg(IX)); + SET_HIGH_REGISTER(BC, LOW_REGISTER(IX)); break; case 0x46: /* LD B,(IX+dd) */ tStates += 19; - adr = IX + (int8) RAM_pp(PC); - CheckBreakByte(adr); - Sethreg(BC, GetBYTE(adr)); + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_HIGH_REGISTER(BC, GET_BYTE(adr)); break; case 0x4c: /* LD C,IXH */ tStates += 9; sim_brk_pend[0] = FALSE; - Setlreg(BC, hreg(IX)); + SET_LOW_REGISTER(BC, HIGH_REGISTER(IX)); break; case 0x4d: /* LD C,IXL */ tStates += 9; sim_brk_pend[0] = FALSE; - Setlreg(BC, lreg(IX)); + SET_LOW_REGISTER(BC, LOW_REGISTER(IX)); break; case 0x4e: /* LD C,(IX+dd) */ tStates += 19; - adr = IX + (int8) RAM_pp(PC); - CheckBreakByte(adr); - Setlreg(BC, GetBYTE(adr)); + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_LOW_REGISTER(BC, GET_BYTE(adr)); break; case 0x54: /* LD D,IXH */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(DE, hreg(IX)); + SET_HIGH_REGISTER(DE, HIGH_REGISTER(IX)); break; case 0x55: /* LD D,IXL */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(DE, lreg(IX)); + SET_HIGH_REGISTER(DE, LOW_REGISTER(IX)); break; case 0x56: /* LD D,(IX+dd) */ tStates += 19; - adr = IX + (int8) RAM_pp(PC); - CheckBreakByte(adr); - Sethreg(DE, GetBYTE(adr)); + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_HIGH_REGISTER(DE, GET_BYTE(adr)); break; case 0x5c: /* LD E,IXH */ tStates += 9; sim_brk_pend[0] = FALSE; - Setlreg(DE, hreg(IX)); + SET_LOW_REGISTER(DE, HIGH_REGISTER(IX)); break; case 0x5d: /* LD E,IXL */ tStates += 9; sim_brk_pend[0] = FALSE; - Setlreg(DE, lreg(IX)); + SET_LOW_REGISTER(DE, LOW_REGISTER(IX)); break; case 0x5e: /* LD E,(IX+dd) */ tStates += 19; - adr = IX + (int8) RAM_pp(PC); - CheckBreakByte(adr); - Setlreg(DE, GetBYTE(adr)); + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_LOW_REGISTER(DE, GET_BYTE(adr)); break; case 0x60: /* LD IXH,B */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(IX, hreg(BC)); + SET_HIGH_REGISTER(IX, HIGH_REGISTER(BC)); break; case 0x61: /* LD IXH,C */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(IX, lreg(BC)); + SET_HIGH_REGISTER(IX, LOW_REGISTER(BC)); break; case 0x62: /* LD IXH,D */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(IX, hreg(DE)); + SET_HIGH_REGISTER(IX, HIGH_REGISTER(DE)); break; case 0x63: /* LD IXH,E */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(IX, lreg(DE)); + SET_HIGH_REGISTER(IX, LOW_REGISTER(DE)); break; case 0x64: /* LD IXH,IXH */ @@ -3906,50 +3912,50 @@ t_stat sim_instr (void) { case 0x65: /* LD IXH,IXL */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(IX, lreg(IX)); + SET_HIGH_REGISTER(IX, LOW_REGISTER(IX)); break; case 0x66: /* LD H,(IX+dd) */ tStates += 19; - adr = IX + (int8) RAM_pp(PC); - CheckBreakByte(adr); - Sethreg(HL, GetBYTE(adr)); + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_HIGH_REGISTER(HL, GET_BYTE(adr)); break; case 0x67: /* LD IXH,A */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(IX, hreg(AF)); + SET_HIGH_REGISTER(IX, HIGH_REGISTER(AF)); break; case 0x68: /* LD IXL,B */ tStates += 9; sim_brk_pend[0] = FALSE; - Setlreg(IX, hreg(BC)); + SET_LOW_REGISTER(IX, HIGH_REGISTER(BC)); break; case 0x69: /* LD IXL,C */ tStates += 9; sim_brk_pend[0] = FALSE; - Setlreg(IX, lreg(BC)); + SET_LOW_REGISTER(IX, LOW_REGISTER(BC)); break; case 0x6a: /* LD IXL,D */ tStates += 9; sim_brk_pend[0] = FALSE; - Setlreg(IX, hreg(DE)); + SET_LOW_REGISTER(IX, HIGH_REGISTER(DE)); break; case 0x6b: /* LD IXL,E */ tStates += 9; sim_brk_pend[0] = FALSE; - Setlreg(IX, lreg(DE)); + SET_LOW_REGISTER(IX, LOW_REGISTER(DE)); break; case 0x6c: /* LD IXL,IXH */ tStates += 9; sim_brk_pend[0] = FALSE; - Setlreg(IX, hreg(IX)); + SET_LOW_REGISTER(IX, HIGH_REGISTER(IX)); break; case 0x6d: /* LD IXL,IXL */ @@ -3959,90 +3965,90 @@ t_stat sim_instr (void) { case 0x6e: /* LD L,(IX+dd) */ tStates += 19; - adr = IX + (int8) RAM_pp(PC); - CheckBreakByte(adr); - Setlreg(HL, GetBYTE(adr)); + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_LOW_REGISTER(HL, GET_BYTE(adr)); break; case 0x6f: /* LD IXL,A */ tStates += 9; sim_brk_pend[0] = FALSE; - Setlreg(IX, hreg(AF)); + SET_LOW_REGISTER(IX, HIGH_REGISTER(AF)); break; case 0x70: /* LD (IX+dd),B */ tStates += 19; - adr = IX + (int8) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, hreg(BC)); + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, HIGH_REGISTER(BC)); break; case 0x71: /* LD (IX+dd),C */ tStates += 19; - adr = IX + (int8) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, lreg(BC)); + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, LOW_REGISTER(BC)); break; case 0x72: /* LD (IX+dd),D */ tStates += 19; - adr = IX + (int8) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, hreg(DE)); + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, HIGH_REGISTER(DE)); break; case 0x73: /* LD (IX+dd),E */ tStates += 19; - adr = IX + (int8) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, lreg(DE)); + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, LOW_REGISTER(DE)); break; case 0x74: /* LD (IX+dd),H */ tStates += 19; - adr = IX + (int8) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, hreg(HL)); + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, HIGH_REGISTER(HL)); break; case 0x75: /* LD (IX+dd),L */ tStates += 19; - adr = IX + (int8) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, lreg(HL)); + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, LOW_REGISTER(HL)); break; case 0x77: /* LD (IX+dd),A */ tStates += 19; - adr = IX + (int8) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, hreg(AF)); + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, HIGH_REGISTER(AF)); break; case 0x7c: /* LD A,IXH */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(AF, hreg(IX)); + SET_HIGH_REGISTER(AF, HIGH_REGISTER(IX)); break; case 0x7d: /* LD A,IXL */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(AF, lreg(IX)); + SET_HIGH_REGISTER(AF, LOW_REGISTER(IX)); break; case 0x7e: /* LD A,(IX+dd) */ tStates += 19; - adr = IX + (int8) RAM_pp(PC); - CheckBreakByte(adr); - Sethreg(AF, GetBYTE(adr)); + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_HIGH_REGISTER(AF, GET_BYTE(adr)); break; case 0x84: /* ADD A,IXH */ tStates += 9; sim_brk_pend[0] = FALSE; - temp = hreg(IX); - acu = hreg(AF); + temp = HIGH_REGISTER(IX); + acu = HIGH_REGISTER(AF); sum = acu + temp; AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; break; @@ -4050,18 +4056,18 @@ t_stat sim_instr (void) { case 0x85: /* ADD A,IXL */ tStates += 9; sim_brk_pend[0] = FALSE; - temp = lreg(IX); - acu = hreg(AF); + temp = LOW_REGISTER(IX); + acu = HIGH_REGISTER(AF); sum = acu + temp; AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; break; case 0x86: /* ADD A,(IX+dd) */ tStates += 19; - adr = IX + (int8) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr); - acu = hreg(AF); + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GET_BYTE(adr); + acu = HIGH_REGISTER(AF); sum = acu + temp; AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; break; @@ -4069,8 +4075,8 @@ t_stat sim_instr (void) { case 0x8c: /* ADC A,IXH */ tStates += 9; sim_brk_pend[0] = FALSE; - temp = hreg(IX); - acu = hreg(AF); + temp = HIGH_REGISTER(IX); + acu = HIGH_REGISTER(AF); sum = acu + temp + TSTFLAG(C); AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; break; @@ -4078,28 +4084,28 @@ t_stat sim_instr (void) { case 0x8d: /* ADC A,IXL */ tStates += 9; sim_brk_pend[0] = FALSE; - temp = lreg(IX); - acu = hreg(AF); + temp = LOW_REGISTER(IX); + acu = HIGH_REGISTER(AF); sum = acu + temp + TSTFLAG(C); AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; break; case 0x8e: /* ADC A,(IX+dd) */ tStates += 19; - adr = IX + (int8) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr); - acu = hreg(AF); + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GET_BYTE(adr); + acu = HIGH_REGISTER(AF); sum = acu + temp + TSTFLAG(C); AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; break; case 0x96: /* SUB (IX+dd) */ tStates += 19; - adr = IX + (int8) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr); - acu = hreg(AF); + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GET_BYTE(adr); + acu = HIGH_REGISTER(AF); sum = acu - temp; AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; break; @@ -4110,8 +4116,8 @@ t_stat sim_instr (void) { case 0x9c: /* SBC A,IXH */ tStates += 9; sim_brk_pend[0] = FALSE; - temp = hreg(IX); - acu = hreg(AF); + temp = HIGH_REGISTER(IX); + acu = HIGH_REGISTER(AF); sum = acu - temp - TSTFLAG(C); AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; break; @@ -4122,18 +4128,18 @@ t_stat sim_instr (void) { case 0x9d: /* SBC A,IXL */ tStates += 9; sim_brk_pend[0] = FALSE; - temp = lreg(IX); - acu = hreg(AF); + temp = LOW_REGISTER(IX); + acu = HIGH_REGISTER(AF); sum = acu - temp - TSTFLAG(C); AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; break; case 0x9e: /* SBC A,(IX+dd) */ tStates += 19; - adr = IX + (int8) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr); - acu = hreg(AF); + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GET_BYTE(adr); + acu = HIGH_REGISTER(AF); sum = acu - temp - TSTFLAG(C); AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; break; @@ -4152,9 +4158,9 @@ t_stat sim_instr (void) { case 0xa6: /* AND (IX+dd) */ tStates += 19; - adr = IX + (int8) RAM_pp(PC); - CheckBreakByte(adr); - AF = andTable[((AF >> 8) & GetBYTE(adr)) & 0xff]; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + AF = andTable[((AF >> 8) & GET_BYTE(adr)) & 0xff]; break; case 0xac: /* XOR IXH */ @@ -4171,9 +4177,9 @@ t_stat sim_instr (void) { case 0xae: /* XOR (IX+dd) */ tStates += 19; - adr = IX + (int8) RAM_pp(PC); - CheckBreakByte(adr); - AF = xororTable[((AF >> 8) ^ GetBYTE(adr)) & 0xff]; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + AF = xororTable[((AF >> 8) ^ GET_BYTE(adr)) & 0xff]; break; case 0xb4: /* OR IXH */ @@ -4190,17 +4196,17 @@ t_stat sim_instr (void) { case 0xb6: /* OR (IX+dd) */ tStates += 19; - adr = IX + (int8) RAM_pp(PC); - CheckBreakByte(adr); - AF = xororTable[((AF >> 8) | GetBYTE(adr)) & 0xff]; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + AF = xororTable[((AF >> 8) | GET_BYTE(adr)) & 0xff]; break; case 0xbc: /* CP IXH */ tStates += 9; sim_brk_pend[0] = FALSE; - temp = hreg(IX); + temp = HIGH_REGISTER(IX); AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); + acu = HIGH_REGISTER(AF); sum = acu - temp; AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; @@ -4209,9 +4215,9 @@ t_stat sim_instr (void) { case 0xbd: /* CP IXL */ tStates += 9; sim_brk_pend[0] = FALSE; - temp = lreg(IX); + temp = LOW_REGISTER(IX); AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); + acu = HIGH_REGISTER(AF); sum = acu - temp; AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; @@ -4219,66 +4225,66 @@ t_stat sim_instr (void) { case 0xbe: /* CP (IX+dd) */ tStates += 19; - adr = IX + (int8) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr); + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GET_BYTE(adr); AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); + acu = HIGH_REGISTER(AF); sum = acu - temp; AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; break; case 0xcb: /* CB prefix */ - adr = IX + (int8) RAM_pp(PC); - switch ((op = GetBYTE(PC)) & 7) { + adr = IX + (int8) RAM_PP(PC); + switch ((op = GET_BYTE(PC)) & 7) { case 0: sim_brk_pend[0] = FALSE; ++PC; - acu = hreg(BC); + acu = HIGH_REGISTER(BC); break; case 1: sim_brk_pend[0] = FALSE; ++PC; - acu = lreg(BC); + acu = LOW_REGISTER(BC); break; case 2: sim_brk_pend[0] = FALSE; ++PC; - acu = hreg(DE); + acu = HIGH_REGISTER(DE); break; case 3: sim_brk_pend[0] = FALSE; ++PC; - acu = lreg(DE); + acu = LOW_REGISTER(DE); break; case 4: sim_brk_pend[0] = FALSE; ++PC; - acu = hreg(HL); + acu = HIGH_REGISTER(HL); break; case 5: sim_brk_pend[0] = FALSE; ++PC; - acu = lreg(HL); + acu = LOW_REGISTER(HL); break; case 6: - CheckBreakByte(adr); + CHECK_BREAK_BYTE(adr); ++PC; - acu = GetBYTE(adr); + acu = GET_BYTE(adr); break; case 7: sim_brk_pend[0] = FALSE; ++PC; - acu = hreg(AF); + acu = HIGH_REGISTER(AF); break; } switch (op & 0xc0) { @@ -4357,27 +4363,27 @@ t_stat sim_instr (void) { switch (op & 7) { case 0: - Sethreg(BC, temp); + SET_HIGH_REGISTER(BC, temp); break; case 1: - Setlreg(BC, temp); + SET_LOW_REGISTER(BC, temp); break; case 2: - Sethreg(DE, temp); + SET_HIGH_REGISTER(DE, temp); break; case 3: - Setlreg(DE, temp); + SET_LOW_REGISTER(DE, temp); break; case 4: - Sethreg(HL, temp); + SET_HIGH_REGISTER(HL, temp); break; case 5: - Setlreg(HL, temp); + SET_LOW_REGISTER(HL, temp); break; case 6: @@ -4385,20 +4391,20 @@ t_stat sim_instr (void) { break; case 7: - Sethreg(AF, temp); + SET_HIGH_REGISTER(AF, temp); break; } break; case 0xe1: /* POP IX */ tStates += 14; - CheckBreakWord(SP); + CHECK_BREAK_WORD(SP); POP(IX); break; case 0xe3: /* EX (SP),IX */ tStates += 23; - CheckBreakWord(SP); + CHECK_BREAK_WORD(SP); temp = IX; POP(IX); PUSH(temp); @@ -4406,7 +4412,7 @@ t_stat sim_instr (void) { case 0xe5: /* PUSH IX */ tStates += 15; - CheckBreakWord(SP - 2); + CHECK_BREAK_WORD(SP - 2); PUSH(IX); break; @@ -4425,7 +4431,7 @@ t_stat sim_instr (void) { default: /* ignore DD */ sim_brk_pend[0] = FALSE; - checkCPUZ80; + CHECK_CPU_Z80; PC--; } break; @@ -4433,16 +4439,16 @@ t_stat sim_instr (void) { case 0xde: /* SBC A,nn */ tStates += 7; sim_brk_pend[0] = FALSE; - temp = RAM_pp(PC); - acu = hreg(AF); + temp = RAM_PP(PC); + acu = HIGH_REGISTER(AF); sum = acu - temp - TSTFLAG(C); cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SetPV); + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); break; case 0xdf: /* RST 18H */ tStates += 11; - CheckBreakWord(SP - 2); + CHECK_BREAK_WORD(SP - 2); PUSH(PC); PCQ_ENTRY(PC - 1); PC = 0x18; @@ -4454,7 +4460,7 @@ t_stat sim_instr (void) { tStates += 5; } else { - CheckBreakWord(SP); + CHECK_BREAK_WORD(SP); PCQ_ENTRY(PC - 1); POP(PC); tStates += 11; @@ -4463,7 +4469,7 @@ t_stat sim_instr (void) { case 0xe1: /* POP HL */ tStates += 10; - CheckBreakWord(SP); + CHECK_BREAK_WORD(SP); POP(HL); break; @@ -4474,7 +4480,7 @@ t_stat sim_instr (void) { case 0xe3: /* EX (SP),HL */ tStates += 19; - CheckBreakWord(SP); + CHECK_BREAK_WORD(SP); temp = HL; POP(HL); PUSH(temp); @@ -4486,19 +4492,19 @@ t_stat sim_instr (void) { case 0xe5: /* PUSH HL */ tStates += 11; - CheckBreakWord(SP - 2); + CHECK_BREAK_WORD(SP - 2); PUSH(HL); break; case 0xe6: /* AND nn */ tStates += 7; sim_brk_pend[0] = FALSE; - AF = andTable[((AF >> 8) & RAM_pp(PC)) & 0xff]; + AF = andTable[((AF >> 8) & RAM_PP(PC)) & 0xff]; break; case 0xe7: /* RST 20H */ tStates += 11; - CheckBreakWord(SP - 2); + CHECK_BREAK_WORD(SP - 2); PUSH(PC); PCQ_ENTRY(PC - 1); PC = 0x20; @@ -4506,7 +4512,7 @@ t_stat sim_instr (void) { case 0xe8: /* RET PE */ if (TSTFLAG(P)) { - CheckBreakWord(SP); + CHECK_BREAK_WORD(SP); PCQ_ENTRY(PC - 1); POP(PC); tStates += 11; @@ -4542,21 +4548,21 @@ t_stat sim_instr (void) { break; case 0xed: /* ED prefix */ - checkCPU8080; - switch (op = RAM_pp(PC)) { + CHECK_CPU_8080; + switch (op = RAM_PP(PC)) { case 0x40: /* IN B,(C) */ tStates += 12; sim_brk_pend[0] = FALSE; - temp = in(lreg(BC)); - Sethreg(BC, temp); + temp = in(LOW_REGISTER(BC)); + SET_HIGH_REGISTER(BC, temp); AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; break; case 0x41: /* OUT (C),B */ tStates += 12; sim_brk_pend[0] = FALSE; - out(lreg(BC), hreg(BC)); + out(LOW_REGISTER(BC), HIGH_REGISTER(BC)); break; case 0x42: /* SBC HL,BC */ @@ -4572,8 +4578,8 @@ t_stat sim_instr (void) { case 0x43: /* LD (nnnn),BC */ tStates += 20; - temp = GetWORD(PC); - CheckBreakWord(temp); + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); PutWORD(temp, BC); PC += 2; break; @@ -4595,7 +4601,7 @@ t_stat sim_instr (void) { case 0x7C: /* NEG, unofficial */ tStates += 8; sim_brk_pend[0] = FALSE; - temp = hreg(AF); + temp = HIGH_REGISTER(AF); AF = ((~(AF & 0xff00) + 1) & 0xff00); /* AF = (-(AF & 0xff00) & 0xff00); */ AF |= ((AF >> 8) & 0xa8) | (((AF & 0xff00) == 0) << 6) | negTable[temp]; break; @@ -4615,7 +4621,7 @@ t_stat sim_instr (void) { case 0x7D: /* RETN, unofficial */ tStates += 14; IFF_S |= IFF_S >> 1; - CheckBreakWord(SP); + CHECK_BREAK_WORD(SP); PCQ_ENTRY(PC - 2); POP(PC); break; @@ -4635,15 +4641,15 @@ t_stat sim_instr (void) { case 0x48: /* IN C,(C) */ tStates += 12; sim_brk_pend[0] = FALSE; - temp = in(lreg(BC)); - Setlreg(BC, temp); + temp = in(LOW_REGISTER(BC)); + SET_LOW_REGISTER(BC, temp); AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; break; case 0x49: /* OUT (C),C */ tStates += 12; sim_brk_pend[0] = FALSE; - out(lreg(BC), lreg(BC)); + out(LOW_REGISTER(BC), LOW_REGISTER(BC)); break; case 0x4a: /* ADC HL,BC */ @@ -4659,16 +4665,16 @@ t_stat sim_instr (void) { case 0x4b: /* LD BC,(nnnn) */ tStates += 20; - temp = GetWORD(PC); - CheckBreakWord(temp); - BC = GetWORD(temp); + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); + BC = GET_WORD(temp); PC += 2; break; case 0x4d: /* RETI */ tStates += 14; IFF_S |= IFF_S >> 1; - CheckBreakWord(SP); + CHECK_BREAK_WORD(SP); PCQ_ENTRY(PC - 2); POP(PC); break; @@ -4682,15 +4688,15 @@ t_stat sim_instr (void) { case 0x50: /* IN D,(C) */ tStates += 12; sim_brk_pend[0] = FALSE; - temp = in(lreg(BC)); - Sethreg(DE, temp); + temp = in(LOW_REGISTER(BC)); + SET_HIGH_REGISTER(DE, temp); AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; break; case 0x51: /* OUT (C),D */ tStates += 12; sim_brk_pend[0] = FALSE; - out(lreg(BC), hreg(DE)); + out(LOW_REGISTER(BC), HIGH_REGISTER(DE)); break; case 0x52: /* SBC HL,DE */ @@ -4706,8 +4712,8 @@ t_stat sim_instr (void) { case 0x53: /* LD (nnnn),DE */ tStates += 20; - temp = GetWORD(PC); - CheckBreakWord(temp); + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); PutWORD(temp, DE); PC += 2; break; @@ -4727,15 +4733,15 @@ t_stat sim_instr (void) { case 0x58: /* IN E,(C) */ tStates += 12; sim_brk_pend[0] = FALSE; - temp = in(lreg(BC)); - Setlreg(DE, temp); + temp = in(LOW_REGISTER(BC)); + SET_LOW_REGISTER(DE, temp); AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; break; case 0x59: /* OUT (C),E */ tStates += 12; sim_brk_pend[0] = FALSE; - out(lreg(BC), lreg(DE)); + out(LOW_REGISTER(BC), LOW_REGISTER(DE)); break; case 0x5a: /* ADC HL,DE */ @@ -4751,9 +4757,9 @@ t_stat sim_instr (void) { case 0x5b: /* LD DE,(nnnn) */ tStates += 20; - temp = GetWORD(PC); - CheckBreakWord(temp); - DE = GetWORD(temp); + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); + DE = GET_WORD(temp); PC += 2; break; @@ -4773,15 +4779,15 @@ t_stat sim_instr (void) { case 0x60: /* IN H,(C) */ tStates += 12; sim_brk_pend[0] = FALSE; - temp = in(lreg(BC)); - Sethreg(HL, temp); + temp = in(LOW_REGISTER(BC)); + SET_HIGH_REGISTER(HL, temp); AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; break; case 0x61: /* OUT (C),H */ tStates += 12; sim_brk_pend[0] = FALSE; - out(lreg(BC), hreg(HL)); + out(LOW_REGISTER(BC), HIGH_REGISTER(HL)); break; case 0x62: /* SBC HL,HL */ @@ -4796,8 +4802,8 @@ t_stat sim_instr (void) { case 0x63: /* LD (nnnn),HL */ tStates += 20; - temp = GetWORD(PC); - CheckBreakWord(temp); + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); PutWORD(temp, HL); PC += 2; break; @@ -4805,24 +4811,24 @@ t_stat sim_instr (void) { case 0x67: /* RRD */ tStates += 18; sim_brk_pend[0] = FALSE; - temp = GetBYTE(HL); - acu = hreg(AF); - PutBYTE(HL, hdig(temp) | (ldig(acu) << 4)); - AF = rrdrldTable[(acu & 0xf0) | ldig(temp)] | (AF & 1); + temp = GET_BYTE(HL); + acu = HIGH_REGISTER(AF); + PutBYTE(HL, HIGH_DIGIT(temp) | (LOW_DIGIT(acu) << 4)); + AF = rrdrldTable[(acu & 0xf0) | LOW_DIGIT(temp)] | (AF & 1); break; case 0x68: /* IN L,(C) */ tStates += 12; sim_brk_pend[0] = FALSE; - temp = in(lreg(BC)); - Setlreg(HL, temp); + temp = in(LOW_REGISTER(BC)); + SET_LOW_REGISTER(HL, temp); AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; break; case 0x69: /* OUT (C),L */ tStates += 12; sim_brk_pend[0] = FALSE; - out(lreg(BC), lreg(HL)); + out(LOW_REGISTER(BC), LOW_REGISTER(HL)); break; case 0x6a: /* ADC HL,HL */ @@ -4837,33 +4843,33 @@ t_stat sim_instr (void) { case 0x6b: /* LD HL,(nnnn) */ tStates += 20; - temp = GetWORD(PC); - CheckBreakWord(temp); - HL = GetWORD(temp); + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); + HL = GET_WORD(temp); PC += 2; break; case 0x6f: /* RLD */ tStates += 18; sim_brk_pend[0] = FALSE; - temp = GetBYTE(HL); - acu = hreg(AF); - PutBYTE(HL, (ldig(temp) << 4) | ldig(acu)); - AF = rrdrldTable[(acu & 0xf0) | hdig(temp)] | (AF & 1); + temp = GET_BYTE(HL); + acu = HIGH_REGISTER(AF); + PutBYTE(HL, (LOW_DIGIT(temp) << 4) | LOW_DIGIT(acu)); + AF = rrdrldTable[(acu & 0xf0) | HIGH_DIGIT(temp)] | (AF & 1); break; case 0x70: /* IN (C) */ tStates += 12; sim_brk_pend[0] = FALSE; - temp = in(lreg(BC)); - Setlreg(temp, temp); + temp = in(LOW_REGISTER(BC)); + SET_LOW_REGISTER(temp, temp); AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; break; case 0x71: /* OUT (C),0 */ tStates += 12; sim_brk_pend[0] = FALSE; - out(lreg(BC), 0); + out(LOW_REGISTER(BC), 0); break; case 0x72: /* SBC HL,SP */ @@ -4879,8 +4885,8 @@ t_stat sim_instr (void) { case 0x73: /* LD (nnnn),SP */ tStates += 20; - temp = GetWORD(PC); - CheckBreakWord(temp); + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); PutWORD(temp, SP); PC += 2; break; @@ -4888,15 +4894,15 @@ t_stat sim_instr (void) { case 0x78: /* IN A,(C) */ tStates += 12; sim_brk_pend[0] = FALSE; - temp = in(lreg(BC)); - Sethreg(AF, temp); + temp = in(LOW_REGISTER(BC)); + SET_HIGH_REGISTER(AF, temp); AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; break; case 0x79: /* OUT (C),A */ tStates += 12; sim_brk_pend[0] = FALSE; - out(lreg(BC), hreg(AF)); + out(LOW_REGISTER(BC), HIGH_REGISTER(AF)); break; case 0x7a: /* ADC HL,SP */ @@ -4912,27 +4918,27 @@ t_stat sim_instr (void) { case 0x7b: /* LD SP,(nnnn) */ tStates += 20; - temp = GetWORD(PC); - CheckBreakWord(temp); - SP = GetWORD(temp); + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); + SP = GET_WORD(temp); PC += 2; break; case 0xa0: /* LDI */ tStates += 16; - CheckBreakTwoBytes(HL, DE); - acu = RAM_pp(HL); - PutBYTE_pp(DE, acu); - acu += hreg(AF); + CHECK_BREAK_TWO_BYTES(HL, DE); + acu = RAM_PP(HL); + PUT_BYTE_PP(DE, acu); + acu += HIGH_REGISTER(AF); AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4) | (((--BC & ADDRMASK) != 0) << 2); break; case 0xa1: /* CPI */ tStates += 16; - CheckBreakByte(HL); - acu = hreg(AF); - temp = RAM_pp(HL); + CHECK_BREAK_BYTE(HL); + acu = HIGH_REGISTER(AF); + temp = RAM_PP(HL); sum = acu - temp; cbits = acu ^ temp ^ sum; AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | @@ -4946,8 +4952,8 @@ t_stat sim_instr (void) { case 0xa2: /* INI */ tStates += 16; - CheckBreakByte(HL); - PutBYTE(HL, in(lreg(BC))); + CHECK_BREAK_BYTE(HL); + PutBYTE(HL, in(LOW_REGISTER(BC))); ++HL; SETFLAG(N, 1); SETFLAG(P, (--BC & ADDRMASK) != 0); @@ -4955,29 +4961,29 @@ t_stat sim_instr (void) { case 0xa3: /* OUTI */ tStates += 16; - CheckBreakByte(HL); - out(lreg(BC), GetBYTE(HL)); + CHECK_BREAK_BYTE(HL); + out(LOW_REGISTER(BC), GET_BYTE(HL)); ++HL; SETFLAG(N, 1); - Sethreg(BC, lreg(BC) - 1); - SETFLAG(Z, lreg(BC) == 0); + SET_HIGH_REGISTER(BC, LOW_REGISTER(BC) - 1); + SETFLAG(Z, LOW_REGISTER(BC) == 0); break; case 0xa8: /* LDD */ tStates += 16; - CheckBreakTwoBytes(HL, DE); - acu = RAM_mm(HL); - PutBYTE_mm(DE, acu); - acu += hreg(AF); + CHECK_BREAK_TWO_BYTES(HL, DE); + acu = RAM_MM(HL); + PUT_BYTE_MM(DE, acu); + acu += HIGH_REGISTER(AF); AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4) | (((--BC & ADDRMASK) != 0) << 2); break; case 0xa9: /* CPD */ tStates += 16; - CheckBreakByte(HL); - acu = hreg(AF); - temp = RAM_mm(HL); + CHECK_BREAK_BYTE(HL); + acu = HIGH_REGISTER(AF); + temp = RAM_MM(HL); sum = acu - temp; cbits = acu ^ temp ^ sum; AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | @@ -4991,46 +4997,46 @@ t_stat sim_instr (void) { case 0xaa: /* IND */ tStates += 16; - CheckBreakByte(HL); - PutBYTE(HL, in(lreg(BC))); + CHECK_BREAK_BYTE(HL); + PutBYTE(HL, in(LOW_REGISTER(BC))); --HL; SETFLAG(N, 1); - Sethreg(BC, lreg(BC) - 1); - SETFLAG(Z, lreg(BC) == 0); + SET_HIGH_REGISTER(BC, LOW_REGISTER(BC) - 1); + SETFLAG(Z, LOW_REGISTER(BC) == 0); break; case 0xab: /* OUTD */ tStates += 16; - CheckBreakByte(HL); - out(lreg(BC), GetBYTE(HL)); + CHECK_BREAK_BYTE(HL); + out(LOW_REGISTER(BC), GET_BYTE(HL)); --HL; SETFLAG(N, 1); - Sethreg(BC, lreg(BC) - 1); - SETFLAG(Z, lreg(BC) == 0); + SET_HIGH_REGISTER(BC, LOW_REGISTER(BC) - 1); + SETFLAG(Z, LOW_REGISTER(BC) == 0); break; case 0xb0: /* LDIR */ tStates -= 5; - acu = hreg(AF); + acu = HIGH_REGISTER(AF); BC &= ADDRMASK; do { tStates += 21; - CheckBreakTwoBytes(HL, DE); - acu = RAM_pp(HL); - PutBYTE_pp(DE, acu); + CHECK_BREAK_TWO_BYTES(HL, DE); + acu = RAM_PP(HL); + PUT_BYTE_PP(DE, acu); } while (--BC); - acu += hreg(AF); + acu += HIGH_REGISTER(AF); AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4); break; case 0xb1: /* CPIR */ tStates -= 5; - acu = hreg(AF); + acu = HIGH_REGISTER(AF); BC &= ADDRMASK; do { tStates += 21; - CheckBreakByte(HL); - temp = RAM_pp(HL); + CHECK_BREAK_BYTE(HL); + temp = RAM_PP(HL); op = --BC != 0; sum = acu - temp; } while (op && sum != 0); @@ -5046,28 +5052,28 @@ t_stat sim_instr (void) { case 0xb2: /* INIR */ tStates -= 5; - temp = hreg(BC); + temp = HIGH_REGISTER(BC); do { tStates += 21; - CheckBreakByte(HL); - PutBYTE(HL, in(lreg(BC))); + CHECK_BREAK_BYTE(HL); + PutBYTE(HL, in(LOW_REGISTER(BC))); ++HL; } while (--temp); - Sethreg(BC, 0); + SET_HIGH_REGISTER(BC, 0); SETFLAG(N, 1); SETFLAG(Z, 1); break; case 0xb3: /* OTIR */ tStates -= 5; - temp = hreg(BC); + temp = HIGH_REGISTER(BC); do { tStates += 21; - CheckBreakByte(HL); - out(lreg(BC), GetBYTE(HL)); + CHECK_BREAK_BYTE(HL); + out(LOW_REGISTER(BC), GET_BYTE(HL)); ++HL; } while (--temp); - Sethreg(BC, 0); + SET_HIGH_REGISTER(BC, 0); SETFLAG(N, 1); SETFLAG(Z, 1); break; @@ -5077,22 +5083,22 @@ t_stat sim_instr (void) { BC &= ADDRMASK; do { tStates += 21; - CheckBreakTwoBytes(HL, DE); - acu = RAM_mm(HL); - PutBYTE_mm(DE, acu); + CHECK_BREAK_TWO_BYTES(HL, DE); + acu = RAM_MM(HL); + PUT_BYTE_MM(DE, acu); } while (--BC); - acu += hreg(AF); + acu += HIGH_REGISTER(AF); AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4); break; case 0xb9: /* CPDR */ tStates -= 5; - acu = hreg(AF); + acu = HIGH_REGISTER(AF); BC &= ADDRMASK; do { tStates += 21; - CheckBreakByte(HL); - temp = RAM_mm(HL); + CHECK_BREAK_BYTE(HL); + temp = RAM_MM(HL); op = --BC != 0; sum = acu - temp; } while (op && sum != 0); @@ -5108,47 +5114,47 @@ t_stat sim_instr (void) { case 0xba: /* INDR */ tStates -= 5; - temp = hreg(BC); + temp = HIGH_REGISTER(BC); do { tStates += 21; - CheckBreakByte(HL); - PutBYTE(HL, in(lreg(BC))); + CHECK_BREAK_BYTE(HL); + PutBYTE(HL, in(LOW_REGISTER(BC))); --HL; } while (--temp); - Sethreg(BC, 0); + SET_HIGH_REGISTER(BC, 0); SETFLAG(N, 1); SETFLAG(Z, 1); break; case 0xbb: /* OTDR */ tStates -= 5; - temp = hreg(BC); + temp = HIGH_REGISTER(BC); do { tStates += 21; - CheckBreakByte(HL); - out(lreg(BC), GetBYTE(HL)); + CHECK_BREAK_BYTE(HL); + out(LOW_REGISTER(BC), GET_BYTE(HL)); --HL; } while (--temp); - Sethreg(BC, 0); + SET_HIGH_REGISTER(BC, 0); SETFLAG(N, 1); SETFLAG(Z, 1); break; default: /* ignore ED and following byte */ sim_brk_pend[0] = FALSE; - checkCPUZ80; + CHECK_CPU_Z80; } break; case 0xee: /* XOR nn */ tStates += 7; sim_brk_pend[0] = FALSE; - AF = xororTable[((AF >> 8) ^ RAM_pp(PC)) & 0xff]; + AF = xororTable[((AF >> 8) ^ RAM_PP(PC)) & 0xff]; break; case 0xef: /* RST 28H */ tStates += 11; - CheckBreakWord(SP - 2); + CHECK_BREAK_WORD(SP - 2); PUSH(PC); PCQ_ENTRY(PC - 1); PC = 0x28; @@ -5160,7 +5166,7 @@ t_stat sim_instr (void) { tStates += 5; } else { - CheckBreakWord(SP); + CHECK_BREAK_WORD(SP); PCQ_ENTRY(PC - 1); POP(PC); tStates += 11; @@ -5169,7 +5175,7 @@ t_stat sim_instr (void) { case 0xf1: /* POP AF */ tStates += 10; - CheckBreakWord(SP); + CHECK_BREAK_WORD(SP); POP(AF); break; @@ -5190,19 +5196,19 @@ t_stat sim_instr (void) { case 0xf5: /* PUSH AF */ tStates += 11; - CheckBreakWord(SP - 2); + CHECK_BREAK_WORD(SP - 2); PUSH(AF); break; case 0xf6: /* OR nn */ tStates += 7; sim_brk_pend[0] = FALSE; - AF = xororTable[((AF >> 8) | RAM_pp(PC)) & 0xff]; + AF = xororTable[((AF >> 8) | RAM_PP(PC)) & 0xff]; break; case 0xf7: /* RST 30H */ tStates += 11; - CheckBreakWord(SP - 2); + CHECK_BREAK_WORD(SP - 2); PUSH(PC); PCQ_ENTRY(PC - 1); PC = 0x30; @@ -5210,7 +5216,7 @@ t_stat sim_instr (void) { case 0xf8: /* RET M */ if (TSTFLAG(S)) { - CheckBreakWord(SP); + CHECK_BREAK_WORD(SP); PCQ_ENTRY(PC - 1); POP(PC); tStates += 11; @@ -5243,8 +5249,8 @@ t_stat sim_instr (void) { break; case 0xfd: /* FD prefix */ - checkCPU8080; - switch (op = RAM_pp(PC)) { + CHECK_CPU_8080; + switch (op = RAM_PP(PC)) { case 0x09: /* ADD IY,BC */ tStates += 15; @@ -5269,14 +5275,14 @@ t_stat sim_instr (void) { case 0x21: /* LD IY,nnnn */ tStates += 14; sim_brk_pend[0] = FALSE; - IY = GetWORD(PC); + IY = GET_WORD(PC); PC += 2; break; case 0x22: /* LD (nnnn),IY */ tStates += 20; - temp = GetWORD(PC); - CheckBreakWord(temp); + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); PutWORD(temp, IY); PC += 2; break; @@ -5291,20 +5297,20 @@ t_stat sim_instr (void) { tStates += 9; sim_brk_pend[0] = FALSE; IY += 0x100; - AF = (AF & ~0xfe) | incZ80Table[hreg(IY)]; + AF = (AF & ~0xfe) | incZ80Table[HIGH_REGISTER(IY)]; break; case 0x25: /* DEC IYH */ tStates += 9; sim_brk_pend[0] = FALSE; IY -= 0x100; - AF = (AF & ~0xfe) | decZ80Table[hreg(IY)]; + AF = (AF & ~0xfe) | decZ80Table[HIGH_REGISTER(IY)]; break; case 0x26: /* LD IYH,nn */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(IY, RAM_pp(PC)); + SET_HIGH_REGISTER(IY, RAM_PP(PC)); break; case 0x29: /* ADD IY,IY */ @@ -5318,9 +5324,9 @@ t_stat sim_instr (void) { case 0x2a: /* LD IY,(nnnn) */ tStates += 20; - temp = GetWORD(PC); - CheckBreakWord(temp); - IY = GetWORD(temp); + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); + IY = GET_WORD(temp); PC += 2; break; @@ -5333,48 +5339,48 @@ t_stat sim_instr (void) { case 0x2c: /* INC IYL */ tStates += 9; sim_brk_pend[0] = FALSE; - temp = lreg(IY) + 1; - Setlreg(IY, temp); + temp = LOW_REGISTER(IY) + 1; + SET_LOW_REGISTER(IY, temp); AF = (AF & ~0xfe) | incZ80Table[temp]; break; case 0x2d: /* DEC IYL */ tStates += 9; sim_brk_pend[0] = FALSE; - temp = lreg(IY) - 1; - Setlreg(IY, temp); + temp = LOW_REGISTER(IY) - 1; + SET_LOW_REGISTER(IY, temp); AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; break; case 0x2e: /* LD IYL,nn */ tStates += 9; sim_brk_pend[0] = FALSE; - Setlreg(IY, RAM_pp(PC)); + SET_LOW_REGISTER(IY, RAM_PP(PC)); break; case 0x34: /* INC (IY+dd) */ tStates += 23; - adr = IY + (int8) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr) + 1; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GET_BYTE(adr) + 1; PutBYTE(adr, temp); AF = (AF & ~0xfe) | incZ80Table[temp]; break; case 0x35: /* DEC (IY+dd) */ tStates += 23; - adr = IY + (int8) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr) - 1; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GET_BYTE(adr) - 1; PutBYTE(adr, temp); AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; break; case 0x36: /* LD (IY+dd),nn */ tStates += 19; - adr = IY + (int8) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, RAM_pp(PC)); + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, RAM_PP(PC)); break; case 0x39: /* ADD IY,SP */ @@ -5390,101 +5396,101 @@ t_stat sim_instr (void) { case 0x44: /* LD B,IYH */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(BC, hreg(IY)); + SET_HIGH_REGISTER(BC, HIGH_REGISTER(IY)); break; case 0x45: /* LD B,IYL */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(BC, lreg(IY)); + SET_HIGH_REGISTER(BC, LOW_REGISTER(IY)); break; case 0x46: /* LD B,(IY+dd) */ tStates += 19; - adr = IY + (int8) RAM_pp(PC); - CheckBreakByte(adr); - Sethreg(BC, GetBYTE(adr)); + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_HIGH_REGISTER(BC, GET_BYTE(adr)); break; case 0x4c: /* LD C,IYH */ tStates += 9; sim_brk_pend[0] = FALSE; - Setlreg(BC, hreg(IY)); + SET_LOW_REGISTER(BC, HIGH_REGISTER(IY)); break; case 0x4d: /* LD C,IYL */ tStates += 9; sim_brk_pend[0] = FALSE; - Setlreg(BC, lreg(IY)); + SET_LOW_REGISTER(BC, LOW_REGISTER(IY)); break; case 0x4e: /* LD C,(IY+dd) */ tStates += 19; - adr = IY + (int8) RAM_pp(PC); - CheckBreakByte(adr); - Setlreg(BC, GetBYTE(adr)); + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_LOW_REGISTER(BC, GET_BYTE(adr)); break; case 0x54: /* LD D,IYH */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(DE, hreg(IY)); + SET_HIGH_REGISTER(DE, HIGH_REGISTER(IY)); break; case 0x55: /* LD D,IYL */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(DE, lreg(IY)); + SET_HIGH_REGISTER(DE, LOW_REGISTER(IY)); break; case 0x56: /* LD D,(IY+dd) */ tStates += 19; - adr = IY + (int8) RAM_pp(PC); - CheckBreakByte(adr); - Sethreg(DE, GetBYTE(adr)); + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_HIGH_REGISTER(DE, GET_BYTE(adr)); break; case 0x5c: /* LD E,IYH */ tStates += 9; sim_brk_pend[0] = FALSE; - Setlreg(DE, hreg(IY)); + SET_LOW_REGISTER(DE, HIGH_REGISTER(IY)); break; case 0x5d: /* LD E,IYL */ tStates += 9; sim_brk_pend[0] = FALSE; - Setlreg(DE, lreg(IY)); + SET_LOW_REGISTER(DE, LOW_REGISTER(IY)); break; case 0x5e: /* LD E,(IY+dd) */ tStates += 19; - adr = IY + (int8) RAM_pp(PC); - CheckBreakByte(adr); - Setlreg(DE, GetBYTE(adr)); + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_LOW_REGISTER(DE, GET_BYTE(adr)); break; case 0x60: /* LD IYH,B */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(IY, hreg(BC)); + SET_HIGH_REGISTER(IY, HIGH_REGISTER(BC)); break; case 0x61: /* LD IYH,C */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(IY, lreg(BC)); + SET_HIGH_REGISTER(IY, LOW_REGISTER(BC)); break; case 0x62: /* LD IYH,D */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(IY, hreg(DE)); + SET_HIGH_REGISTER(IY, HIGH_REGISTER(DE)); break; case 0x63: /* LD IYH,E */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(IY, lreg(DE)); + SET_HIGH_REGISTER(IY, LOW_REGISTER(DE)); break; case 0x64: /* LD IYH,IYH */ @@ -5495,50 +5501,50 @@ t_stat sim_instr (void) { case 0x65: /* LD IYH,IYL */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(IY, lreg(IY)); + SET_HIGH_REGISTER(IY, LOW_REGISTER(IY)); break; case 0x66: /* LD H,(IY+dd) */ tStates += 19; - adr = IY + (int8) RAM_pp(PC); - CheckBreakByte(adr); - Sethreg(HL, GetBYTE(adr)); + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_HIGH_REGISTER(HL, GET_BYTE(adr)); break; case 0x67: /* LD IYH,A */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(IY, hreg(AF)); + SET_HIGH_REGISTER(IY, HIGH_REGISTER(AF)); break; case 0x68: /* LD IYL,B */ tStates += 9; sim_brk_pend[0] = FALSE; - Setlreg(IY, hreg(BC)); + SET_LOW_REGISTER(IY, HIGH_REGISTER(BC)); break; case 0x69: /* LD IYL,C */ tStates += 9; sim_brk_pend[0] = FALSE; - Setlreg(IY, lreg(BC)); + SET_LOW_REGISTER(IY, LOW_REGISTER(BC)); break; case 0x6a: /* LD IYL,D */ tStates += 9; sim_brk_pend[0] = FALSE; - Setlreg(IY, hreg(DE)); + SET_LOW_REGISTER(IY, HIGH_REGISTER(DE)); break; case 0x6b: /* LD IYL,E */ tStates += 9; sim_brk_pend[0] = FALSE; - Setlreg(IY, lreg(DE)); + SET_LOW_REGISTER(IY, LOW_REGISTER(DE)); break; case 0x6c: /* LD IYL,IYH */ tStates += 9; sim_brk_pend[0] = FALSE; - Setlreg(IY, hreg(IY)); + SET_LOW_REGISTER(IY, HIGH_REGISTER(IY)); break; case 0x6d: /* LD IYL,IYL */ @@ -5548,90 +5554,90 @@ t_stat sim_instr (void) { case 0x6e: /* LD L,(IY+dd) */ tStates += 19; - adr = IY + (int8) RAM_pp(PC); - CheckBreakByte(adr); - Setlreg(HL, GetBYTE(adr)); + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_LOW_REGISTER(HL, GET_BYTE(adr)); break; case 0x6f: /* LD IYL,A */ tStates += 9; sim_brk_pend[0] = FALSE; - Setlreg(IY, hreg(AF)); + SET_LOW_REGISTER(IY, HIGH_REGISTER(AF)); break; case 0x70: /* LD (IY+dd),B */ tStates += 19; - adr = IY + (int8) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, hreg(BC)); + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, HIGH_REGISTER(BC)); break; case 0x71: /* LD (IY+dd),C */ tStates += 19; - adr = IY + (int8) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, lreg(BC)); + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, LOW_REGISTER(BC)); break; case 0x72: /* LD (IY+dd),D */ tStates += 19; - adr = IY + (int8) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, hreg(DE)); + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, HIGH_REGISTER(DE)); break; case 0x73: /* LD (IY+dd),E */ tStates += 19; - adr = IY + (int8) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, lreg(DE)); + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, LOW_REGISTER(DE)); break; case 0x74: /* LD (IY+dd),H */ tStates += 19; - adr = IY + (int8) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, hreg(HL)); + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, HIGH_REGISTER(HL)); break; case 0x75: /* LD (IY+dd),L */ tStates += 19; - adr = IY + (int8) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, lreg(HL)); + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, LOW_REGISTER(HL)); break; case 0x77: /* LD (IY+dd),A */ tStates += 19; - adr = IY + (int8) RAM_pp(PC); - CheckBreakByte(adr); - PutBYTE(adr, hreg(AF)); + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, HIGH_REGISTER(AF)); break; case 0x7c: /* LD A,IYH */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(AF, hreg(IY)); + SET_HIGH_REGISTER(AF, HIGH_REGISTER(IY)); break; case 0x7d: /* LD A,IYL */ tStates += 9; sim_brk_pend[0] = FALSE; - Sethreg(AF, lreg(IY)); + SET_HIGH_REGISTER(AF, LOW_REGISTER(IY)); break; case 0x7e: /* LD A,(IY+dd) */ tStates += 19; - adr = IY + (int8) RAM_pp(PC); - CheckBreakByte(adr); - Sethreg(AF, GetBYTE(adr)); + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_HIGH_REGISTER(AF, GET_BYTE(adr)); break; case 0x84: /* ADD A,IYH */ tStates += 9; sim_brk_pend[0] = FALSE; - temp = hreg(IY); - acu = hreg(AF); + temp = HIGH_REGISTER(IY); + acu = HIGH_REGISTER(AF); sum = acu + temp; AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; break; @@ -5639,18 +5645,18 @@ t_stat sim_instr (void) { case 0x85: /* ADD A,IYL */ tStates += 9; sim_brk_pend[0] = FALSE; - temp = lreg(IY); - acu = hreg(AF); + temp = LOW_REGISTER(IY); + acu = HIGH_REGISTER(AF); sum = acu + temp; AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; break; case 0x86: /* ADD A,(IY+dd) */ tStates += 19; - adr = IY + (int8) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr); - acu = hreg(AF); + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GET_BYTE(adr); + acu = HIGH_REGISTER(AF); sum = acu + temp; AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; break; @@ -5658,8 +5664,8 @@ t_stat sim_instr (void) { case 0x8c: /* ADC A,IYH */ tStates += 9; sim_brk_pend[0] = FALSE; - temp = hreg(IY); - acu = hreg(AF); + temp = HIGH_REGISTER(IY); + acu = HIGH_REGISTER(AF); sum = acu + temp + TSTFLAG(C); AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; break; @@ -5667,28 +5673,28 @@ t_stat sim_instr (void) { case 0x8d: /* ADC A,IYL */ tStates += 9; sim_brk_pend[0] = FALSE; - temp = lreg(IY); - acu = hreg(AF); + temp = LOW_REGISTER(IY); + acu = HIGH_REGISTER(AF); sum = acu + temp + TSTFLAG(C); AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; break; case 0x8e: /* ADC A,(IY+dd) */ tStates += 19; - adr = IY + (int8) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr); - acu = hreg(AF); + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GET_BYTE(adr); + acu = HIGH_REGISTER(AF); sum = acu + temp + TSTFLAG(C); AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; break; case 0x96: /* SUB (IY+dd) */ tStates += 19; - adr = IY + (int8) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr); - acu = hreg(AF); + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GET_BYTE(adr); + acu = HIGH_REGISTER(AF); sum = acu - temp; AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; break; @@ -5699,8 +5705,8 @@ t_stat sim_instr (void) { case 0x9c: /* SBC A,IYH */ tStates += 9; sim_brk_pend[0] = FALSE; - temp = hreg(IY); - acu = hreg(AF); + temp = HIGH_REGISTER(IY); + acu = HIGH_REGISTER(AF); sum = acu - temp - TSTFLAG(C); AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; break; @@ -5711,18 +5717,18 @@ t_stat sim_instr (void) { case 0x9d: /* SBC A,IYL */ tStates += 9; sim_brk_pend[0] = FALSE; - temp = lreg(IY); - acu = hreg(AF); + temp = LOW_REGISTER(IY); + acu = HIGH_REGISTER(AF); sum = acu - temp - TSTFLAG(C); AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; break; case 0x9e: /* SBC A,(IY+dd) */ tStates += 19; - adr = IY + (int8) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr); - acu = hreg(AF); + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GET_BYTE(adr); + acu = HIGH_REGISTER(AF); sum = acu - temp - TSTFLAG(C); AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; break; @@ -5741,9 +5747,9 @@ t_stat sim_instr (void) { case 0xa6: /* AND (IY+dd) */ tStates += 19; - adr = IY + (int8) RAM_pp(PC); - CheckBreakByte(adr); - AF = andTable[((AF >> 8) & GetBYTE(adr)) & 0xff]; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + AF = andTable[((AF >> 8) & GET_BYTE(adr)) & 0xff]; break; case 0xac: /* XOR IYH */ @@ -5760,9 +5766,9 @@ t_stat sim_instr (void) { case 0xae: /* XOR (IY+dd) */ tStates += 19; - adr = IY + (int8) RAM_pp(PC); - CheckBreakByte(adr); - AF = xororTable[((AF >> 8) ^ GetBYTE(adr)) & 0xff]; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + AF = xororTable[((AF >> 8) ^ GET_BYTE(adr)) & 0xff]; break; case 0xb4: /* OR IYH */ @@ -5779,17 +5785,17 @@ t_stat sim_instr (void) { case 0xb6: /* OR (IY+dd) */ tStates += 19; - adr = IY + (int8) RAM_pp(PC); - CheckBreakByte(adr); - AF = xororTable[((AF >> 8) | GetBYTE(adr)) & 0xff]; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + AF = xororTable[((AF >> 8) | GET_BYTE(adr)) & 0xff]; break; case 0xbc: /* CP IYH */ tStates += 9; sim_brk_pend[0] = FALSE; - temp = hreg(IY); + temp = HIGH_REGISTER(IY); AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); + acu = HIGH_REGISTER(AF); sum = acu - temp; AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; @@ -5798,9 +5804,9 @@ t_stat sim_instr (void) { case 0xbd: /* CP IYL */ tStates += 9; sim_brk_pend[0] = FALSE; - temp = lreg(IY); + temp = LOW_REGISTER(IY); AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); + acu = HIGH_REGISTER(AF); sum = acu - temp; AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; @@ -5808,66 +5814,66 @@ t_stat sim_instr (void) { case 0xbe: /* CP (IY+dd) */ tStates += 19; - adr = IY + (int8) RAM_pp(PC); - CheckBreakByte(adr); - temp = GetBYTE(adr); + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GET_BYTE(adr); AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); + acu = HIGH_REGISTER(AF); sum = acu - temp; AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; break; case 0xcb: /* CB prefix */ - adr = IY + (int8) RAM_pp(PC); - switch ((op = GetBYTE(PC)) & 7) { + adr = IY + (int8) RAM_PP(PC); + switch ((op = GET_BYTE(PC)) & 7) { case 0: sim_brk_pend[0] = FALSE; ++PC; - acu = hreg(BC); + acu = HIGH_REGISTER(BC); break; case 1: sim_brk_pend[0] = FALSE; ++PC; - acu = lreg(BC); + acu = LOW_REGISTER(BC); break; case 2: sim_brk_pend[0] = FALSE; ++PC; - acu = hreg(DE); + acu = HIGH_REGISTER(DE); break; case 3: sim_brk_pend[0] = FALSE; ++PC; - acu = lreg(DE); + acu = LOW_REGISTER(DE); break; case 4: sim_brk_pend[0] = FALSE; ++PC; - acu = hreg(HL); + acu = HIGH_REGISTER(HL); break; case 5: sim_brk_pend[0] = FALSE; ++PC; - acu = lreg(HL); + acu = LOW_REGISTER(HL); break; case 6: - CheckBreakByte(adr); + CHECK_BREAK_BYTE(adr); ++PC; - acu = GetBYTE(adr); + acu = GET_BYTE(adr); break; case 7: sim_brk_pend[0] = FALSE; ++PC; - acu = hreg(AF); + acu = HIGH_REGISTER(AF); break; } switch (op & 0xc0) { @@ -5946,27 +5952,27 @@ t_stat sim_instr (void) { switch (op & 7) { case 0: - Sethreg(BC, temp); + SET_HIGH_REGISTER(BC, temp); break; case 1: - Setlreg(BC, temp); + SET_LOW_REGISTER(BC, temp); break; case 2: - Sethreg(DE, temp); + SET_HIGH_REGISTER(DE, temp); break; case 3: - Setlreg(DE, temp); + SET_LOW_REGISTER(DE, temp); break; case 4: - Sethreg(HL, temp); + SET_HIGH_REGISTER(HL, temp); break; case 5: - Setlreg(HL, temp); + SET_LOW_REGISTER(HL, temp); break; case 6: @@ -5974,20 +5980,20 @@ t_stat sim_instr (void) { break; case 7: - Sethreg(AF, temp); + SET_HIGH_REGISTER(AF, temp); break; } break; case 0xe1: /* POP IY */ tStates += 14; - CheckBreakWord(SP); + CHECK_BREAK_WORD(SP); POP(IY); break; case 0xe3: /* EX (SP),IY */ tStates += 23; - CheckBreakWord(SP); + CHECK_BREAK_WORD(SP); temp = IY; POP(IY); PUSH(temp); @@ -5995,7 +6001,7 @@ t_stat sim_instr (void) { case 0xe5: /* PUSH IY */ tStates += 15; - CheckBreakWord(SP - 2); + CHECK_BREAK_WORD(SP - 2); PUSH(IY); break; @@ -6014,7 +6020,7 @@ t_stat sim_instr (void) { default: /* ignore FD */ sim_brk_pend[0] = FALSE; - checkCPUZ80; + CHECK_CPU_Z80; PC--; } break; @@ -6022,18 +6028,18 @@ t_stat sim_instr (void) { case 0xfe: /* CP nn */ tStates += 7; sim_brk_pend[0] = FALSE; - temp = RAM_pp(PC); + temp = RAM_PP(PC); AF = (AF & ~0x28) | (temp & 0x28); - acu = hreg(AF); + acu = HIGH_REGISTER(AF); sum = acu - temp; cbits = acu ^ temp ^ sum; AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - (SetPV) | cbits2Table[cbits & 0x1ff]; + (SET_PV) | cbits2Table[cbits & 0x1ff]; break; case 0xff: /* RST 38H */ tStates += 11; - CheckBreakWord(SP - 2); + CHECK_BREAK_WORD(SP - 2); PUSH(PC); PCQ_ENTRY(PC - 1); PC = 0x38; @@ -6128,13 +6134,13 @@ static void checkROMBoundaries(void) { ROMHigh = temp; } if (cpu_unit.flags & UNIT_ALTAIRROM) { - if (defaultROMLow < ROMLow) { - printf("ROMLOW [%04X] reset to %04X since Altair ROM was desired.\n", ROMLow, defaultROMLow); - ROMLow = defaultROMLow; + if (DEFAULT_ROM_LOW < ROMLow) { + printf("ROMLOW [%04X] reset to %04X since Altair ROM was desired.\n", ROMLow, DEFAULT_ROM_LOW); + ROMLow = DEFAULT_ROM_LOW; } - if (ROMHigh < defaultROMHigh) { - printf("ROMHIGH [%04X] reset to %04X since Altair ROM was desired.\n", ROMHigh, defaultROMHigh); - ROMHigh = defaultROMHigh; + if (ROMHigh < DEFAULT_ROM_HIGH) { + printf("ROMHIGH [%04X] reset to %04X since Altair ROM was desired.\n", ROMHigh, DEFAULT_ROM_HIGH); + ROMHigh = DEFAULT_ROM_HIGH; } } } @@ -6154,13 +6160,13 @@ static t_stat cpu_set_norom(UNIT *uptr, int32 value, char *cptr, void *desc) { static t_stat cpu_set_altairrom(UNIT *uptr, int32 value, char *cptr, void *desc) { install_bootrom(); - if (ROMLow != defaultROMLow) { - printf("\"D ROMLOW %04X\" also executed.\n", defaultROMLow); - ROMLow = defaultROMLow; + if (ROMLow != DEFAULT_ROM_LOW) { + printf("\"D ROMLOW %04X\" also executed.\n", DEFAULT_ROM_LOW); + ROMLow = DEFAULT_ROM_LOW; } - if (ROMHigh != defaultROMHigh) { - printf("\"D ROMHIGH %04X\" also executed.\n", defaultROMHigh); - ROMHigh = defaultROMHigh; + if (ROMHigh != DEFAULT_ROM_HIGH) { + printf("\"D ROMHIGH %04X\" also executed.\n", DEFAULT_ROM_HIGH); + ROMHigh = DEFAULT_ROM_HIGH; } if (!(cpu_unit.flags & UNIT_ROM)) { printf("\"SET CPU ROM\" also executed.\n"); @@ -6177,10 +6183,10 @@ static t_stat cpu_set_warnrom(UNIT *uptr, int32 value, char *cptr, void *desc) { } static t_stat cpu_set_banked(UNIT *uptr, int32 value, char *cptr, void *desc) { - if (common > defaultROMLow) { + if (common > DEFAULT_ROM_LOW) { printf("Warning: COMMON [%04X] must not be greater than %04X. Reset to %04X.\n", - common, defaultROMLow, defaultROMLow); - common = defaultROMLow; + common, DEFAULT_ROM_LOW, DEFAULT_ROM_LOW); + common = DEFAULT_ROM_LOW; } if (MEMSIZE != (MAXBANKS * MAXMEMSIZE)) { previousCapacity = MEMSIZE; @@ -6226,7 +6232,7 @@ t_stat sim_load(FILE *fileref, char *cptr, char *fnam, int32 flag) { return SCPE_ARG; } for (j = lo; j <= hi; j++) { - if (putc(GetBYTE(j), fileref) == EOF) { + if (putc(GET_BYTE(j), fileref) == EOF) { return SCPE_IOERR; } } diff --git a/AltairZ80/altairZ80_defs.h b/AltairZ80/altairZ80_defs.h index 6b9f3814..00153c84 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-2006, Peter Schorn + Copyright (c) 2002-2007, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -30,19 +30,19 @@ #define MAXMEMSIZE 65536 /* maximum memory size */ #define ADDRMASK (MAXMEMSIZE - 1) /* address mask */ -#define bootrom_size 256 /* size of boot rom */ +#define BOOTROM_SIZE 256 /* size of boot rom */ #define MAXBANKS 8 /* max number of memory banks */ #define MAXBANKSLOG2 3 /* log2 of MAXBANKS */ #define BANKMASK (MAXBANKS-1) /* bank mask */ #define MEMSIZE (cpu_unit.capac) /* actual memory size */ #define KB 1024 /* kilo byte */ -#define defaultROMLow 0xff00 /* default for lowest address of ROM */ -#define defaultROMHigh 0xffff /* default for highest address of ROM */ +#define DEFAULT_ROM_LOW 0xff00 /* default for lowest address of ROM */ +#define DEFAULT_ROM_HIGH 0xffff /* default for highest address of ROM */ #define NUM_OF_DSK 8 /* NUM_OF_DSK must be power of two */ -#define LDAInstruction 0x3e /* op-code for LD A,<8-bit value> instruction */ -#define unitNoOffset1 0x37 /* LD A, */ -#define unitNoOffset2 0xb4 /* LD a,80h | */ +#define LDA_INSTRUCTION 0x3e /* op-code for LD A,<8-bit value> instruction */ +#define UNIT_NO_OFFSET_1 0x37 /* LD A, */ +#define UNIT_NO_OFFSET_2 0xb4 /* LD a,80h | */ #define UNIT_V_OPSTOP (UNIT_V_UF+0) /* stop on invalid operation */ #define UNIT_OPSTOP (1 << UNIT_V_OPSTOP) @@ -59,17 +59,22 @@ #define UNIT_V_WARNROM (UNIT_V_UF+6) /* warn if ROM is written to */ #define UNIT_WARNROM (1 << UNIT_V_WARNROM) -#define AddressFormat "[%04xh]" -#define PCformat "\n" AddressFormat " " -#define message1(p1) \ - sprintf(messageBuffer,PCformat p1,PCX); printMessage() -#define message2(p1,p2) \ - sprintf(messageBuffer,PCformat p1,PCX,p2); printMessage() -#define message3(p1,p2,p3) \ - sprintf(messageBuffer,PCformat p1,PCX,p2,p3); printMessage() -#define message4(p1,p2,p3,p4) \ - sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4); printMessage() -#define message5(p1,p2,p3,p4,p5) \ - sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4,p5); printMessage() -#define message6(p1,p2,p3,p4,p5,p6) \ - sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4,p5,p6); printMessage() +#define UNIX_PLATFORM (defined (__linux) || defined(__NetBSD__) || defined (__OpenBSD__) || \ + defined (__FreeBSD__) || defined (__APPLE__)) + +#define ADDRESS_FORMAT "[%04xh]" +#define PC_FORMAT "\n" ADDRESS_FORMAT " " +#define MESSAGE_1(p1) \ + sprintf(messageBuffer,PC_FORMAT p1,PCX); printMessage() +#define MESSAGE_2(p1,p2) \ + sprintf(messageBuffer,PC_FORMAT p1,PCX,p2); printMessage() +#define MESSAGE_3(p1,p2,p3) \ + sprintf(messageBuffer,PC_FORMAT p1,PCX,p2,p3); printMessage() +#define MESSAGE_4(p1,p2,p3,p4) \ + sprintf(messageBuffer,PC_FORMAT p1,PCX,p2,p3,p4); printMessage() +#define MESSAGE_5(p1,p2,p3,p4,p5) \ + sprintf(messageBuffer,PC_FORMAT p1,PCX,p2,p3,p4,p5); printMessage() +#define MESSAGE_6(p1,p2,p3,p4,p5,p6) \ + sprintf(messageBuffer,PC_FORMAT p1,PCX,p2,p3,p4,p5,p6); printMessage() +#define MESSAGE_7(p1,p2,p3,p4,p5,p6,p7) \ + sprintf(messageBuffer,PC_FORMAT p1,PCX,p2,p3,p4,p5,p6,p7); printMessage() diff --git a/AltairZ80/altairZ80_dsk.c b/AltairZ80/altairZ80_dsk.c index f3613c1a..0a9c2898 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-2006, Peter Schorn + Copyright (c) 2002-2007, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -132,7 +132,6 @@ int32 dsk12(const int32 port, const int32 io, const int32 data); static int32 dskseek(const UNIT *xptr); static t_stat dsk_boot(int32 unitno, DEVICE *dptr); static t_stat dsk_reset(DEVICE *dptr); -static t_stat dsk_svc(UNIT *uptr); static void writebuf(void); static t_stat dsk_set_verbose(UNIT *uptr, int32 value, char *cptr, void *desc); static void resetDSKWarningFlags(void); @@ -142,11 +141,12 @@ static char* selectInOut(const int32 io); extern int32 PCX; extern int32 saved_PC; extern FILE *sim_log; -extern void printMessage(void); extern char messageBuffer[]; -extern int32 install_bootrom(void); extern UNIT cpu_unit; +extern void printMessage(void); +extern int32 install_bootrom(void); + /* global data on status */ static int32 current_disk = NUM_OF_DSK; /* currently selected drive (values are 0 .. NUM_OF_DSK) @@ -170,7 +170,7 @@ static int32 warnDSK12 = 0; static int8 dskbuf[DSK_SECTSIZE]; /* data Buffer */ /* Altair MITS modified BOOT EPROM, fits in upper 256 byte of memory */ -int32 bootrom[bootrom_size] = { +int32 bootrom[BOOTROM_SIZE] = { 0xf3, 0x06, 0x80, 0x3e, 0x0e, 0xd3, 0xfe, 0x05, /* ff00-ff07 */ 0xc2, 0x05, 0xff, 0x3e, 0x16, 0xd3, 0xfe, 0x3e, /* ff08-ff0f */ 0x12, 0xd3, 0xfe, 0xdb, 0xfe, 0xb7, 0xca, 0x20, /* ff10-ff17 */ @@ -208,14 +208,14 @@ int32 bootrom[bootrom_size] = { /* 88DSK Standard I/O Data Structures */ static UNIT dsk_unit[] = { - { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) } + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) } }; static REG dsk_reg[] = { @@ -290,13 +290,6 @@ static char* selectInOut(const int32 io) { } /* service routines to handle simulator functions */ - -/* service routine - actually gets char & places in buffer */ - -static t_stat dsk_svc(UNIT *uptr) { - return SCPE_OK; -} - /* reset routine */ static t_stat dsk_reset(DEVICE *dptr) { @@ -317,16 +310,16 @@ static t_stat dsk_boot(int32 unitno, DEVICE *dptr) { printf("ALTAIR boot ROM installed.\n"); } /* check whether we are really modifying an LD A,<> instruction */ - if ((bootrom[unitNoOffset1 - 1] == LDAInstruction) && (bootrom[unitNoOffset2 - 1] == LDAInstruction)) { - bootrom[unitNoOffset1] = unitno & 0xff; /* LD A, */ - bootrom[unitNoOffset2] = 0x80 | (unitno & 0xff); /* LD a,80h | */ + if ((bootrom[UNIT_NO_OFFSET_1 - 1] == LDA_INSTRUCTION) && (bootrom[UNIT_NO_OFFSET_2 - 1] == LDA_INSTRUCTION)) { + bootrom[UNIT_NO_OFFSET_1] = unitno & 0xff; /* LD A, */ + bootrom[UNIT_NO_OFFSET_2] = 0x80 | (unitno & 0xff); /* LD a,80h | */ } else { /* Attempt to modify non LD A,<> instructions is refused. */ printf("Incorrect boot ROM offsets detected.\n"); return SCPE_IERR; } } - saved_PC = defaultROMLow; + saved_PC = DEFAULT_ROM_LOW; return SCPE_OK; } @@ -356,7 +349,7 @@ int32 dsk10(const int32 port, const int32 io, const int32 data) { if (current_disk >= NUM_OF_DSK) { if (hasVerbose() && (warnDSK10 < warnLevelDSK)) { warnDSK10++; -/*01*/ message1("Attempt of IN 0x08 on unattached disk - ignored."); +/*01*/ MESSAGE_1("Attempt of IN 0x08 on unattached disk - ignored."); } return 0xff; /* no drive selected - can do nothing */ } @@ -368,14 +361,14 @@ int32 dsk10(const int32 port, const int32 io, const int32 data) { writebuf(); } if (trace_flag & TRACE_IN_OUT) { - message2("OUT 0x08: %x", data); + MESSAGE_2("OUT 0x08: %x", data); } current_disk = data & NUM_OF_DSK_MASK; /* 0 <= current_disk < NUM_OF_DSK */ current_disk_flags = (dsk_dev.units + current_disk) -> flags; if ((current_disk_flags & UNIT_ATT) == 0) { /* nothing attached? */ if ( (current_disk_flags & UNIT_DSK_VERBOSE) && (warnAttached[current_disk] < warnLevelDSK) ) { warnAttached[current_disk]++; -/*02*/message2("Attempt to select unattached DSK%d - ignored.", current_disk); +/*02*/MESSAGE_2("Attempt to select unattached DSK%d - ignored.", current_disk); } current_disk = NUM_OF_DSK; } @@ -395,7 +388,7 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) { if (current_disk >= NUM_OF_DSK) { if (hasVerbose() && (warnDSK11 < warnLevelDSK)) { warnDSK11++; -/*03*/ message2("Attempt of %s 0x09 on unattached disk - ignored.", selectInOut(io)); +/*03*/ MESSAGE_2("Attempt of %s 0x09 on unattached disk - ignored.", selectInOut(io)); } return 0; /* no drive selected - can do nothing */ } @@ -405,10 +398,10 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) { in9_count++; if ((trace_flag & TRACE_SECTOR_STUCK) && (in9_count > 2 * DSK_SECT) && (!in9_message)) { in9_message = TRUE; - message2("Looping on sector find %d.", current_disk); + MESSAGE_2("Looping on sector find %d.", current_disk); } if (trace_flag & TRACE_IN_OUT) { - message1("IN 0x09"); + MESSAGE_1("IN 0x09"); } if (dirty) {/* implies that current_disk < NUM_OF_DSK */ writebuf(); @@ -430,12 +423,12 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) { /* drive functions */ if (trace_flag & TRACE_IN_OUT) { - message2("OUT 0x09: %x", data); + MESSAGE_2("OUT 0x09: %x", data); } if (data & 0x01) { /* step head in */ if (trace_flag & TRACE_TRACK_STUCK) { if (current_track[current_disk] == (tracks[current_disk] - 1)) { - message2("Unnecessary step in for disk %d", current_disk); + MESSAGE_2("Unnecessary step in for disk %d", current_disk); } } current_track[current_disk]++; @@ -452,7 +445,7 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) { if (data & 0x02) { /* step head out */ if (trace_flag & TRACE_TRACK_STUCK) { if (current_track[current_disk] == 0) { - message2("Unnecessary step out for disk %d", current_disk); + MESSAGE_2("Unnecessary step out for disk %d", current_disk); } } current_track[current_disk]--; @@ -506,7 +499,7 @@ int32 dsk12(const int32 port, const int32 io, const int32 data) { if (current_disk >= NUM_OF_DSK) { if (hasVerbose() && (warnDSK12 < warnLevelDSK)) { warnDSK12++; -/*04*/ message2("Attempt of %s 0x0a on unattached disk - ignored.", selectInOut(io)); +/*04*/ MESSAGE_2("Attempt of %s 0x0a on unattached disk - ignored.", selectInOut(io)); } return 0; } @@ -518,7 +511,7 @@ int32 dsk12(const int32 port, const int32 io, const int32 data) { if (current_byte[current_disk] >= DSK_SECTSIZE) { /* physically read the sector */ if (trace_flag & TRACE_READ_WRITE) { - message4("IN 0x0a (READ) D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]); + MESSAGE_4("IN 0x0a (READ) D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]); } for (i = 0; i < DSK_SECTSIZE; i++) { dskbuf[i] = 0; @@ -552,20 +545,20 @@ static void writebuf(void) { uptr = dsk_dev.units + current_disk; if (((uptr -> flags) & UNIT_DSKWLK) == 0) { /* write enabled */ if (trace_flag & TRACE_READ_WRITE) { - message4("OUT 0x0a (WRITE) D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]); + MESSAGE_4("OUT 0x0a (WRITE) D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]); } if (dskseek(uptr)) { - message4("fseek failed D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]); + MESSAGE_4("fseek failed D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]); } rtn = fwrite(dskbuf, DSK_SECTSIZE, 1, uptr -> fileref); if (rtn != 1) { - message4("fwrite failed T%d S%d Return=%d", current_track[current_disk], current_sector[current_disk], rtn); + MESSAGE_4("fwrite failed T%d S%d Return=%d", current_track[current_disk], current_sector[current_disk], rtn); } } else if ( ((uptr -> flags) & UNIT_DSK_VERBOSE) && (warnLock[current_disk] < warnLevelDSK) ) { /* write locked - print warning message if required */ warnLock[current_disk]++; -/*05*/ message2("Attempt to write to locked DSK%d - ignored.", current_disk); +/*05*/ MESSAGE_2("Attempt to write to locked DSK%d - ignored.", current_disk); } current_flag[current_disk] &= 0xfe; /* ENWD off */ current_byte[current_disk] = 0xff; diff --git a/AltairZ80/altairZ80_sio.c b/AltairZ80/altairZ80_sio.c index 474646b8..eaba1c69 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-2006, Peter Schorn + Copyright (c) 2002-2007, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -55,6 +55,12 @@ #include "sim_sock.h" #include "sim_tmxr.h" #include +#include +#if UNIX_PLATFORM +#include +#elif defined (_WIN32) +#include +#endif #define UNIT_V_ANSI (UNIT_V_UF + 0) /* ANSI mode, strip bit 8 on output */ #define UNIT_ANSI (1 << UNIT_V_ANSI) @@ -66,23 +72,29 @@ #define UNIT_SIO_VERBOSE (1 << UNIT_V_SIO_VERBOSE) #define UNIT_V_MAP (UNIT_V_UF + 4) /* mapping mode on */ #define UNIT_MAP (1 << UNIT_V_MAP) +#define UNIT_V_BELL (UNIT_V_UF + 5) /* ^G (bell character) rings bell */ +#define UNIT_BELL (1 << UNIT_V_BELL) #define UNIT_V_SIMH_VERBOSE (UNIT_V_UF + 0) /* verbose mode for SIMH pseudo device */ #define UNIT_SIMH_VERBOSE (1 << UNIT_V_SIMH_VERBOSE) #define UNIT_V_SIMH_TIMERON (UNIT_V_UF + 1) /* SIMH pseudo device timer generate interrupts */ #define UNIT_SIMH_TIMERON (1 << UNIT_V_SIMH_VERBOSE) -#define Terminals 4 /* lines per mux */ +#define TERMINALS 4 /* lines per mux */ +#define SIO_CAN_READ 0x01 /* bit 0 is set iff character available */ +#define SIO_CAN_WRITE 0x02 /* bit 1 is set iff character can be sent */ +#define SIO_RESET 0x03 /* Command to reset SIO */ -#define BACKSPACE_CHAR 0x08 /* backspace character */ -#define DELETE_CHAR 0x7f /* delete character */ -#define CONTROLZ_CHAR 0x1a /* control Z character */ +#define BACKSPACE_CHAR 0x08 /* backspace character */ +#define DELETE_CHAR 0x7f /* delete character */ +#define CONTROLC_CHAR 0x03 /* control C character */ +#define CONTROLG_CHAR 0x07 /* control G char., rings bell when displayed */ +#define CONTROLZ_CHAR 0x1a /* control Z character */ static void resetSIOWarningFlags(void); 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_svc(UNIT *uptr); static t_stat sio_reset(DEVICE *dptr); static t_stat sio_attach(UNIT *uptr, char *cptr); static t_stat sio_detach(UNIT *uptr); @@ -95,11 +107,13 @@ int32 sio0d (const int32 port, const int32 io, const int32 data); int32 sio0s (const int32 port, const int32 io, const int32 data); int32 sio1d (const int32 port, const int32 io, const int32 data); int32 sio1s (const int32 port, const int32 io, const int32 data); -static void reset_sio_terminals(const int32 useDefault); +static int32 mapCharacter(int32 ch); +static void pollConnection(void); static t_stat simh_dev_reset(DEVICE *dptr); static t_stat simh_svc(UNIT *uptr); static int32 simh_in(const int32 port); static int32 simh_out(const int32 port, const int32 data); +static void createCPMCommandLine(void); static void attachCPM(UNIT *uptr); static void setClockZSDOS(void); static void setClockCPM3(void); @@ -109,23 +123,20 @@ static int32 fromBCD(const int32 x); void printMessage(void); static void warnNoRealTimeClock(void); -extern t_stat sim_activate(UNIT *uptr, int32 interval); -extern t_stat sim_cancel(UNIT *uptr); -extern t_stat sim_poll_kbd(void); -extern t_stat sim_putchar(int32 out); -extern t_stat attach_unit(UNIT *uptr, char *cptr); extern int32 getBankSelect(void); extern void setBankSelect(const int32 b); extern uint32 getCommon(void); +extern uint8 GetBYTEWrapper(const uint32 Addr); + extern t_bool rtc_avail; extern FILE *sim_log; extern int32 PCX; extern int32 sim_switches; -extern uint32 sim_os_msec(void); extern const char *scp_error_messages[]; extern int32 SR; -extern uint8 GetBYTEWrapper(const uint32 Addr); extern UNIT cpu_unit; +extern volatile int32 stop_cpu; +extern int32 sim_interval; /* SIMH pseudo device status registers */ /* ZSDOS clock definitions */ @@ -155,12 +166,36 @@ static int32 getStopWatchDeltaPos = 0; /* determines the state for rece static uint32 stopWatchNow = 0; /* stores starting time of stop watch */ static int32 markTimeSP = 0; /* stack pointer for timer stack */ + /* default time in microseconds to sleep for SIMHSleepCmd */ +#if defined (_WIN32) +static uint32 SIMHSleep = 1000; /* Sleep uses milliseconds */ +#elif defined (__MWERKS__) && defined (macintosh) +static uint32 SIMHSleep = 0; /* No sleep on Macintosh OS9 */ +#else +static uint32 SIMHSleep = 100; /* on other platforms 100 micro seconds is good enough */ +#endif + /* miscellaneous */ static int32 versionPos = 0; /* determines state for sending device identifier */ static int32 lastCPMStatus = 0; /* result of last attachCPM command */ static int32 lastCommand = 0; /* most recent command processed on port 0xfeh */ static int32 getCommonPos = 0; /* determines state for sending the 'common' register */ +/* Support for wild card expansion */ +#if UNIX_PLATFORM +static glob_t globS; +static int32 globPosNameList = 0; +static int32 globPosName = 0; +static int32 globValid = FALSE; +static int32 globError = 0; +#elif defined (_WIN32) +static WIN32_FIND_DATA FindFileData; +static HANDLE hFind = INVALID_HANDLE_VALUE; +static int32 globFinished = FALSE; +static int32 globValid = FALSE; +static int32 globPosName = 0; +#endif + /* SIO status registers */ static int32 warnLevelSIO = 3; /* display at most 'warnLevelSIO' times the same warning */ static int32 warnUnattachedPTP = 0; /* display a warning message if < warnLevel and SIO set to @@ -171,45 +206,34 @@ static int32 warnPTREOF = 0; /* display a warning message if VERBOSE and attempt to read from PTR past EOF */ static int32 warnUnassignedPort = 0; /* display a warning message if < warnLevel and SIO set to VERBOSE and attempt to perform IN or OUT on an unassigned PORT */ -struct sio_terminal { - int32 data; /* data for this terminal */ - int32 status; /* status information for this terminal */ - int32 statusPort; /* status port of this terminal */ - int32 dataPort; /* data port of this terminal */ - int32 defaultStatus; /* default status value for this terminal */ + +static TMLN TerminalLines[TERMINALS] = { /* four terminals */ + { 0 } }; -typedef struct sio_terminal SIO_TERMINAL; - -static SIO_TERMINAL sio_terminals[Terminals] = { - {0, 0, 0x10, 0x11, 0x02}, - {0, 0, 0x14, 0x15, 0x00}, - {0, 0, 0x16, 0x17, 0x00}, - {0, 0, 0x18, 0x19, 0x00} -}; -static TMLN TerminalLines[Terminals] = { /* four terminals */ - {0} -}; -static TMXR altairTMXR = { /* mux descriptor */ - Terminals, 0, 0, TerminalLines +static TMXR altairTMXR = { /* mux descriptor */ + TERMINALS, 0, 0, TerminalLines }; -static UNIT sio_unit = { UDATA (&sio_svc, UNIT_ATTABLE + UNIT_MAP, 0), KBD_POLL_WAIT }; +static UNIT sio_unit = { + UDATA (NULL, UNIT_ATTABLE + UNIT_MAP, 0), + 0, /* wait = 0 */ + FALSE, /* u3 = FALSE, no character available in buffer */ + FALSE, /* u4 = FALSE, terminal input is not attached to a file */ + FALSE, /* u5 = FALSE, terminal input has not yet reached EOF */ + 0 /* u6 = 0, not used */ +}; static REG sio_reg[] = { - { HRDATA (DATA0, sio_terminals[0].data, 8) }, - { HRDATA (STAT0, sio_terminals[0].status, 8) }, - { HRDATA (DATA1, sio_terminals[1].data, 8) }, - { HRDATA (STAT1, sio_terminals[1].status, 8) }, - { HRDATA (DATA2, sio_terminals[2].data, 8) }, - { HRDATA (STAT2, sio_terminals[2].status, 8) }, - { HRDATA (DATA3, sio_terminals[3].data, 8) }, - { HRDATA (STAT3, sio_terminals[3].status, 8) }, - { DRDATA (SIOWL, warnLevelSIO, 32) }, - { DRDATA (WUPTP, warnUnattachedPTP, 32) }, - { DRDATA (WUPTR, warnUnattachedPTR, 32) }, - { DRDATA (WPTREOF, warnPTREOF, 32) }, - { DRDATA (WUPORT, warnUnassignedPort, 32) }, + { DRDATA (SIOWLEV, warnLevelSIO, 32) }, + { DRDATA (WRNUPTP, warnUnattachedPTP, 32) }, + { DRDATA (WRNUPTR, warnUnattachedPTR, 32) }, + { DRDATA (WRNPTRE, warnPTREOF, 32) }, + { DRDATA (WRUPORT, warnUnassignedPort, 32) }, + { HRDATA (FILEATT, sio_unit.u4, 8), REG_RO }, /* TRUE iff terminal input is attached to a file */ + { HRDATA (FILEEOF, sio_unit.u5, 8), REG_RO }, /* TRUE iff terminal input file has reached EOF */ + { HRDATA (TSTATUS, sio_unit.u3, 8) }, /* TRUE iff a character available in sio_unit.buf */ + { DRDATA (TBUFFER, sio_unit.buf, 8) }, /* input buffer for one character */ { NULL } }; @@ -225,6 +249,8 @@ static MTAB sio_mod[] = { /* verbose, display warning messages */ { UNIT_MAP, 0, "NOMAP", "NOMAP", NULL }, /* disable character mapping */ { UNIT_MAP, UNIT_MAP, "MAP", "MAP", NULL }, /* enable all character mapping */ + { UNIT_BELL, 0, "BELL", "BELL", NULL }, /* enable bell character */ + { UNIT_BELL, UNIT_BELL, "NOBELL", "NOBELL", NULL }, /* suppress ringing the bell */ { 0 } }; @@ -237,13 +263,11 @@ DEVICE sio_dev = { NULL, NULL, NULL }; static UNIT ptr_unit = { - UDATA (NULL, UNIT_SEQ + UNIT_ATTABLE + UNIT_ROABLE, 0), KBD_POLL_WAIT + UDATA (NULL, UNIT_SEQ + UNIT_ATTABLE + UNIT_ROABLE, 0) }; static REG ptr_reg[] = { - { HRDATA (DATA, ptr_unit.buf, 8) }, - { HRDATA (STAT, ptr_unit.u3, 8) }, - { DRDATA (POS, ptr_unit.pos, 32) }, + { HRDATA (STAT, ptr_unit.u3, 8) }, { NULL } }; @@ -257,18 +281,11 @@ DEVICE ptr_dev = { }; static UNIT ptp_unit = { - UDATA (NULL, UNIT_SEQ + UNIT_ATTABLE, 0), KBD_POLL_WAIT -}; - -static REG ptp_reg[] = { - { HRDATA (DATA, ptp_unit.buf, 8) }, - { HRDATA (STAT, ptp_unit.u3, 8) }, - { DRDATA (POS, ptp_unit.pos, 32) }, - { NULL } + UDATA (NULL, UNIT_SEQ + UNIT_ATTABLE, 0) }; DEVICE ptp_dev = { - "PTP", &ptp_unit, ptp_reg, NULL, + "PTP", &ptp_unit, NULL, NULL, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptp_reset, NULL, NULL, NULL, @@ -300,6 +317,7 @@ static REG simh_reg[] = { { DRDATA (STIAP, setTimerInterruptAdrPos,8), REG_RO }, { DRDATA (TIMD, timerDelta, 32) }, { DRDATA (STDP, setTimerDeltaPos, 8), REG_RO }, + { DRDATA (SLEEP, SIMHSleep, 32) }, { DRDATA (STPDT, stopWatchDelta, 32), REG_RO }, { DRDATA (STPOS, getStopWatchDeltaPos, 8), REG_RO }, @@ -338,7 +356,7 @@ char messageBuffer[256]; void printMessage(void) { printf(messageBuffer); -#if defined(__NetBSD__) || defined (__OpenBSD__) || defined (__FreeBSD__) || defined (__APPLE__) +#if UNIX_PLATFORM /* need to make sure that carriage return is executed - ttrunstate() of scp_tty.c has disabled \n translation */ printf("\r\n"); @@ -352,10 +370,7 @@ void printMessage(void) { } static void resetSIOWarningFlags(void) { - warnUnattachedPTP = 0; - warnUnattachedPTR = 0; - warnPTREOF = 0; - warnUnassignedPort = 0; + warnUnattachedPTP = warnUnattachedPTR = warnPTREOF = warnUnassignedPort = 0; } static t_stat sio_set_verbose(UNIT *uptr, int32 value, char *cptr, void *desc) { @@ -364,92 +379,63 @@ static t_stat sio_set_verbose(UNIT *uptr, int32 value, char *cptr, void *desc) { } static t_stat sio_attach(UNIT *uptr, char *cptr) { - reset_sio_terminals(FALSE); - return tmxr_attach(&altairTMXR, uptr, cptr); /* attach mux */ -} - -static void reset_sio_terminals(const int32 useDefault) { - int32 i; - for (i = 0; i < Terminals; i++) { - sio_terminals[i].status = useDefault ? sio_terminals[i].defaultStatus : 0; /* status */ - sio_terminals[i].data = 0x00; /* data */ + t_stat r = SCPE_IERR; + sio_unit.u3 = FALSE; /* no character in terminal input buffer */ + get_uint(cptr, 10, 65535, &r); /* attempt to get port, discard result */ + if (r == SCPE_OK) { /* string can be interpreted as port number */ + sio_unit.u4 = FALSE; /* terminal input is not attached to a file */ + return tmxr_attach(&altairTMXR, uptr, cptr); /* attach mux */ } + sio_unit.u4 = TRUE; /* terminal input is attached to a file */ + sio_unit.u5 = FALSE; /* EOF not yet reached */ + return attach_unit(uptr, cptr); } -/* detach */ static t_stat sio_detach(UNIT *uptr) { - reset_sio_terminals(TRUE); + sio_unit.u3 = FALSE; /* no character in terminal input buffer */ + if (sio_unit.u4) { /* is terminal input attached to a file? */ + sio_unit.u4 = FALSE; /* not anymore, detach */ + return detach_unit(uptr); + } return tmxr_detach(&altairTMXR, uptr); } -/* service routines to handle simulator functions */ - -/* service routine - actually gets char & places in buffer */ - -static t_stat sio_svc(UNIT *uptr) { - int32 temp; - - sim_activate(&sio_unit, sio_unit.wait); /* continue poll */ - +static void pollConnection(void) { if (sio_unit.flags & UNIT_ATT) { - if (sim_poll_kbd() == SCPE_STOP) { /* listen for ^E */ - return SCPE_STOP; - } - temp = tmxr_poll_conn(&altairTMXR); /* poll connection */ - if (temp >= 0) { - TerminalLines[temp].rcve = 1; /* enable receive */ - } - tmxr_poll_rx(&altairTMXR); /* poll input */ - tmxr_poll_tx(&altairTMXR); /* poll output */ + int32 temp = tmxr_poll_conn(&altairTMXR); /* poll connection */ + if (temp >= 0) + TerminalLines[temp].rcve = 1; /* enable receive */ + tmxr_poll_rx(&altairTMXR); /* poll input */ + tmxr_poll_tx(&altairTMXR); /* poll output */ } - else { - if ((temp = sim_poll_kbd()) < SCPE_KFLAG) { - return temp; /* no char or error? */ - } - sio_terminals[0].data = temp & 0xff; /* save character */ - sio_terminals[0].status |= 0x01; /* set status */ - } - return SCPE_OK; } - /* reset routines */ - static t_stat sio_reset(DEVICE *dptr) { int32 i; + sio_unit.u3 = FALSE; /* no character in terminal input buffer */ resetSIOWarningFlags(); - if (sio_unit.flags & UNIT_ATT) { - for (i = 0; i < Terminals; i++) { - if (TerminalLines[i].conn > 0) { + if (sio_unit.u4) { /* is terminal input attached to a file? */ + rewind(sio_unit.fileref); /* yes, rewind input */ + sio_unit.u5 = FALSE; /* EOF not yet reached */ + } + else if (sio_unit.flags & UNIT_ATT) + for (i = 0; i < TERMINALS; i++) + if (TerminalLines[i].conn) tmxr_reset_ln(&TerminalLines[i]); - } - } - reset_sio_terminals(FALSE); - } - else { - reset_sio_terminals(TRUE); - } - sim_activate(&sio_unit, sio_unit.wait); /* activate unit */ return SCPE_OK; } static t_stat ptr_reset(DEVICE *dptr) { resetSIOWarningFlags(); - ptr_unit.buf = 0; - ptr_unit.u3 = 0; - ptr_unit.pos = 0; - if (ptr_unit.flags & UNIT_ATT) { /* attached? */ - rewind(ptr_dev.units -> fileref); - } - sim_cancel(&ptp_unit); /* deactivate unit */ + ptr_unit.u3 = FALSE; /* End Of File not yet reached */ + if (ptr_unit.flags & UNIT_ATT) /* attached? */ + rewind(ptr_unit.fileref); return SCPE_OK; } static t_stat ptp_reset(DEVICE *dptr) { resetSIOWarningFlags(); - ptp_unit.buf = 0; - ptp_unit.u3 = 0x02; - sim_cancel(&ptp_unit); /* deactivate unit */ return SCPE_OK; } @@ -462,157 +448,168 @@ static t_stat ptp_reset(DEVICE *dptr) { input is passed as the return value, on output, 'data' is written to the device. - Port 1 controls console I/O. We distinguish two cases: - 1) SIO attached to a port (i.e. Telnet console I/O) - 2) SIO not attached to a port (i.e. "regular" console I/O) + Port 1 controls console I/O. We distinguish three cases: + 1) SIO attached to a file (i.e. input taken from a file ) + 2) SIO attached to a port (i.e. Telnet console I/O ) + 3) SIO not attached to a port (i.e. "regular" console I/O ) */ int32 sio0s(const int32 port, const int32 io, const int32 data) { - int32 ti; - for (ti = 0; ti < Terminals; ti++) { - if (sio_terminals[ti].statusPort == port) { - break; - } + int32 ti = 0, ch; + pollConnection(); + if (port != 0x10) { /* 0x10 is default port with ti == 0 */ + if (port == 0x14) ti = 1; + else if (port == 0x16) ti = 2; + else if (port == 0x18) ti = 3; + else assert(FALSE); } if (io == 0) { /* IN */ - if (sio_unit.flags & UNIT_ATT) { - sio_terminals[ti].status = - (((tmxr_rqln(&TerminalLines[ti]) > 0 ? 0x01 : 0) | - /* read possible if character available */ - ((TerminalLines[ti].conn) && (TerminalLines[ti].xmte) ? 0x02 : 0x00))); - /* write possible if connected and transmit enabled */ + 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 SIO_CAN_READ | SIO_CAN_WRITE; } - return sio_terminals[ti].status; - } - else { /* OUT */ - if (sio_unit.flags & UNIT_ATT) { - if (data == 0x03) { /* reset port! */ - sio_terminals[ti].status = 0x00; - sio_terminals[ti].data = 0; + if (sio_unit.flags & UNIT_ATT) { /* attached to a port? */ + return (tmxr_rqln(&TerminalLines[ti]) ? SIO_CAN_READ : 0x00) | + /* read possible if character available */ + (TerminalLines[ti].conn && TerminalLines[ti].xmte ? SIO_CAN_WRITE : 0x00); + /* write possible if connected and transmit + enabled */ + } + if (sio_unit.u3) /* character available? */ + return SIO_CAN_READ | SIO_CAN_WRITE; + ch = sim_poll_kbd(); /* no, try to get a character */ + if (ch) { /* character available? */ + if (ch == SCPE_STOP) { /* stop CPU in case ^E (default) was typed */ + stop_cpu = TRUE; + sim_interval = 0; /* detect stop condition as soon as possible*/ + return SIO_CAN_WRITE; /* do not consume stop character */ } + sio_unit.u3 = TRUE; /* indicate character available */ + sio_unit.buf = ch; /* store character in buffer */ + return SIO_CAN_READ | SIO_CAN_WRITE; } - else { - if (data == 0x03) { /* reset port! */ - sio_terminals[ti].status = sio_terminals[ti].defaultStatus; - sio_terminals[ti].data = 0; - } + return SIO_CAN_WRITE; + } /* OUT follows */ + if (data == SIO_RESET) /* reset command */ + sio_unit.u3 = FALSE; /* indicate that no character is available */ + return 0x00; /* ignored since OUT */ +} + +static int32 mapCharacter(int32 ch) { + ch &= 0xff; + if (sio_unit.flags & UNIT_MAP) { + if (sio_unit.flags & UNIT_BS) { + if (ch == BACKSPACE_CHAR) + return DELETE_CHAR; } - return 0; /* ignored since OUT */ + else if (ch == DELETE_CHAR) + return BACKSPACE_CHAR; + if (sio_unit.flags & UNIT_UPPER) + return toupper(ch); } + return ch; } int32 sio0d(const int32 port, const int32 io, const int32 data) { - int32 ti; - for (ti = 0; ti < Terminals; ti++) { - if (sio_terminals[ti].dataPort == port) { - break; - } + int32 ti = 0, ch; + pollConnection(); + if (port != 0x11) { /* 0x11 is default port with ti == 0 */ + if (port == 0x15) ti = 1; + else if (port == 0x17) ti = 2; + else if (port == 0x19) ti = 3; + else assert(FALSE); } if (io == 0) { /* IN */ - if (sio_unit.flags & UNIT_ATT) { - sio_terminals[ti].data = tmxr_getc_ln(&TerminalLines[ti]) & 0xff; - } - sio_terminals[ti].status &= 0xfe; - if (sio_unit.flags & UNIT_MAP) { - if (sio_unit.flags & UNIT_BS) { - if (sio_terminals[ti].data == BACKSPACE_CHAR) { - sio_terminals[ti].data = DELETE_CHAR; - } + 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 */ + return CONTROLC_CHAR; /* this time return ^C after all */ } - else { - if (sio_terminals[ti].data == DELETE_CHAR) { - sio_terminals[ti].data = BACKSPACE_CHAR; - } + if ((ch = getc(sio_unit.fileref)) == EOF) { /* end of file? */ + sio_unit.u5 = TRUE; /* terminal input file has reached EOF */ + return CONTROLC_CHAR; /* result is ^C (= CP/M interrupt) */ } + return mapCharacter(ch); /* return mapped character */ } - return ((sio_unit.flags & UNIT_UPPER) && (sio_unit.flags & UNIT_MAP)) ? - toupper(sio_terminals[ti].data) : sio_terminals[ti].data; - } - else { /* OUT */ - int32 d = sio_unit.flags & UNIT_ANSI ? data & 0x7f : data; - if (sio_unit.flags & UNIT_ATT) { - tmxr_putc_ln(&TerminalLines[ti], d); /* status ignored */ - } - else { - sim_putchar(d); - } - return 0; /* ignored since OUT */ - } + if (sio_unit.flags & UNIT_ATT) + return mapCharacter(tmxr_getc_ln(&TerminalLines[ti])); + sio_unit.u3 = FALSE; /* no character is available any more */ + return mapCharacter(sio_unit.buf); /* return previous character */ + } /* OUT follows */ + ch = sio_unit.flags & UNIT_ANSI ? data & 0x7f : data; /* clear highest bit in ANSI mode */ + if ((ch != CONTROLG_CHAR) || !(sio_unit.flags & UNIT_BELL)) + if ((sio_unit.flags & UNIT_ATT) && (!sio_unit.u4)) /* attached to a port and not to a file */ + tmxr_putc_ln(&TerminalLines[ti], ch); /* status ignored */ + else + sim_putchar(ch); + return 0x00; /* ignored since OUT */ } -/* port 2 controls the PTR/PTP devices */ - +/* PTR/PTP status port */ int32 sio1s(const int32 port, const int32 io, const int32 data) { - if (io == 0) { - /* 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) { + 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)) { warnUnattachedPTR++; -/*06*/ message1("Attempt to test status of unattached PTR. 0x02 returned."); +/*06*/ MESSAGE_1("Attempt to test status of unattached PTR. 0x02 returned."); } - return 0x02; + return SIO_CAN_WRITE; } - return ptr_unit.u3 ? 0x02 : 0x03; - } - else { /* OUT */ - if (data == 0x03) { - ptr_unit.u3 = 0; - ptr_unit.buf = 0; - ptr_unit.pos = 0; - ptp_unit.u3 = 0; - ptp_unit.buf = 0; - ptp_unit.pos = 0; - } - return 0; /* ignored since OUT */ - } + /* if EOF then SIO_CAN_WRITE else + (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) + ptr_unit.u3 = FALSE; /* reset EOF indicator */ + return 0x00; /* ignored since OUT */ } +/* PTR/PTP data port */ int32 sio1d(const int32 port, const int32 io, const int32 data) { - int32 temp; - if (io == 0) { /* IN */ - if (ptr_unit.u3) { /* no more data available */ + 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)) { warnPTREOF++; -/*07*/ message1("PTR attempted to read past EOF. 0x00 returned."); +/*07*/ MESSAGE_1("PTR attempted to read past EOF. 0x00 returned."); } - return 0; + return 0x00; } - if ((ptr_unit.flags & UNIT_ATT) == 0) { /* not attached */ + if ((ptr_unit.flags & UNIT_ATT) == 0) { /* not attached */ if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnattachedPTR < warnLevelSIO)) { warnUnattachedPTR++; -/*08*/ message1("Attempt to read from unattached PTR. 0x00 returned."); +/*08*/ MESSAGE_1("Attempt to read from unattached PTR. 0x00 returned."); } - return 0; + return 0x00; } - if ((temp = getc(ptr_dev.units -> fileref)) == EOF) { /* end of file? */ - ptr_unit.u3 = 0x01; - return CONTROLZ_CHAR; /* control Z denotes end of text file in CP/M */ + if ((ch = getc(ptr_unit.fileref)) == EOF) { /* end of file? */ + ptr_unit.u3 = TRUE; /* remember EOF reached */ + return CONTROLZ_CHAR; /* ^Z denotes end of text file in CP/M */ } - ptr_unit.pos++; - return temp & 0xff; - } - else { /* OUT */ - if (ptp_unit.flags & UNIT_ATT) { /* unit must be attached */ - putc(data, ptp_dev.units -> fileref); - } /* else ignore data */ - else if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnattachedPTP < warnLevelSIO)) { - warnUnattachedPTP++; -/*09*/ message2("Attempt to output '0x%02x' to unattached PTP - ignored.", data); - } - ptp_unit.pos++; - return 0; /* ignored since OUT */ + return ch & 0xff; + } /* OUT follows */ + 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)) { + warnUnattachedPTP++; +/*09*/ MESSAGE_2("Attempt to output '0x%02x' to unattached PTP - ignored.", data); } + return 0x00; /* ignored since OUT */ } int32 nulldev(const int32 port, const int32 io, const int32 data) { if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnassignedPort < warnLevelSIO)) { warnUnassignedPort++; if (io == 0) { - message2("Unassigned IN(%2xh) - ignored.", port); + MESSAGE_2("Unassigned IN(%2xh) - ignored.", port); } else { - message3("Unassigned OUT(%2xh) -> %2xh - ignored.", port, data); + MESSAGE_3("Unassigned OUT(%2xh) -> %2xh - ignored.", port, data); } } return io == 0 ? 0xff : 0; @@ -648,7 +645,7 @@ static int32 fromBCD(const int32 x) { out (0feh),a ... Note: The calling program must send all parameter bytes. Otherwise - the pseudo device is left in an unexpected state. + the pseudo device is left in an undefined state. 3) For commands that do not require parameters and return results ld a, @@ -657,7 +654,7 @@ static int32 fromBCD(const int32 x) { in a,(0feh) ; contains second byte of result ... Note: The calling program must request all bytes of the result. Otherwise - the pseudo device is left in an unexpected state. + the pseudo device is left in an undefined state. 4) Commands requiring parameters and returning results do not exist currently. @@ -687,18 +684,21 @@ enum simhPseudoDeviceCommands { /* do not change order or remove commands, add o set8080CPUCmd, /* 20 set the CPU to an 8080 */ startTimerInterruptsCmd, /* 21 start timer interrupts */ stopTimerInterruptsCmd, /* 22 stop timer interrupts */ - setTimerDeltaCmd, /* 23 set the timer interval in which interrupts occur */ + setTimerDeltaCmd, /* 23 set the timer interval in which interrupts occur */ setTimerInterruptAdrCmd, /* 24 set the address to call by timer interrupts */ resetStopWatchCmd, /* 25 reset the millisecond stop watch */ - readStopWatchCmd /* 26 read the millisecond stop watch */ + readStopWatchCmd, /* 26 read the millisecond stop watch */ + SIMHSleepCmd, /* 27 let SIMH sleep for SIMHSleep microseconds */ + getHostOSPathSeparator, /* 28 obtain the file path separator of the OS under which SIMH runs */ + getHostFilenames /* 29 perform wildcard expansion and obtain list of file names */ }; -#define cpmCommandLineLength 128 -#define splimit 10 /* stack depth of timer stack */ -static uint32 markTime[splimit];/* timer stack */ +#define CPM_COMMAND_LINE_LENGTH 128 +#define TIMER_STACK_LIMIT 10 /* stack depth of timer stack */ +static uint32 markTime[TIMER_STACK_LIMIT]; /* timer stack */ static struct tm currentTime; static int32 currentTimeValid = FALSE; -static char version[] = "SIMH002"; +static char version[] = "SIMH003"; static t_stat simh_dev_reset(DEVICE *dptr) { currentTimeValid = FALSE; @@ -717,16 +717,14 @@ static t_stat simh_dev_reset(DEVICE *dptr) { lastCommand = 0; lastCPMStatus = SCPE_OK; timerInterrupt = FALSE; - if (simh_unit.flags & UNIT_SIMH_TIMERON) { + if (simh_unit.flags & UNIT_SIMH_TIMERON) simh_dev_set_timeron(NULL, 0, NULL, NULL); - } return SCPE_OK; } static void warnNoRealTimeClock(void) { - if (simh_unit.flags & UNIT_SIMH_VERBOSE) { + if (simh_unit.flags & UNIT_SIMH_VERBOSE) printf("Sorry - no real time clock available.\n"); - } } static t_stat simh_dev_set_timeron(UNIT *uptr, int32 value, char *cptr, void *desc) { @@ -734,10 +732,8 @@ static t_stat simh_dev_set_timeron(UNIT *uptr, int32 value, char *cptr, void *de timeOfNextInterrupt = sim_os_msec() + timerDelta; return sim_activate(&simh_unit, simh_unit.wait); /* activate unit */ } - else { - warnNoRealTimeClock(); - return SCPE_ARG; - } + warnNoRealTimeClock(); + return SCPE_ARG; } static t_stat simh_dev_set_timeroff(UNIT *uptr, int32 value, char *cptr, void *desc) { @@ -751,33 +747,34 @@ static t_stat simh_svc(UNIT *uptr) { if (n >= 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 (simh_unit.flags & UNIT_SIMH_TIMERON) { - sim_activate(&simh_unit, simh_unit.wait); /* activate unit */ + if (n >= timeOfNextInterrupt) /* time of next interrupt is not in the future */ + timeOfNextInterrupt = n + timerDelta; /* make sure it is in the future! */ } + if (simh_unit.flags & UNIT_SIMH_TIMERON) + sim_activate(&simh_unit, simh_unit.wait); /* activate unit */ return SCPE_OK; } +static char cpmCommandLine[CPM_COMMAND_LINE_LENGTH]; +static void createCPMCommandLine(void) { + int32 i, len = (GetBYTEWrapper(0x80) & 0x7f); /* 0x80 contains length of command line, discard first char */ + for (i = 0; i < len - 1; i++) + cpmCommandLine[i] = (char)GetBYTEWrapper(0x82 + i); /* the first char, typically ' ', is discarded */ + cpmCommandLine[i] = 0; /* make C string */ +} + /* The CP/M command line is used as the name of a file and UNIT* uptr is attached to it. */ static void attachCPM(UNIT *uptr) { - char cpmCommandLine[cpmCommandLineLength]; - uint32 i, len = (GetBYTEWrapper(0x80) & 0x7f) - 1; /* 0x80 contains length of command line, discard first char */ - for (i = 0; i < len; i++) { - cpmCommandLine[i] = (char)GetBYTEWrapper(0x82 + i); /* the first char, typically ' ', is discarded */ - } - cpmCommandLine[i] = 0; /* make C string */ - if (uptr == &ptr_unit) { + createCPMCommandLine(); + if (uptr == &ptr_unit) sim_switches = SWMASK('R'); - } - else if (uptr == &ptp_unit) { - sim_switches = SWMASK('W'); - } + else if (uptr == &ptp_unit) + sim_switches = SWMASK('W') | SWMASK('C'); /* 'C' option makes sure that file is properly truncated + if it had existed before */ lastCPMStatus = attach_unit(uptr, cpmCommandLine); if ((lastCPMStatus != SCPE_OK) && (simh_unit.flags & UNIT_SIMH_VERBOSE)) { - message3("Cannot open '%s' (%s).", cpmCommandLine, scp_error_messages[lastCPMStatus - SCPE_BASE]); + MESSAGE_3("Cannot open '%s' (%s).", cpmCommandLine, scp_error_messages[lastCPMStatus - SCPE_BASE]); + /* must keep curly braces as messageX is a macro with two statements */ } } @@ -794,9 +791,9 @@ static void setClockZSDOS(void) { ClockZSDOSDelta = mktime(&newTime) - time(NULL); } -#define secondsPerMinute 60 -#define secondsPerHour (60 * secondsPerMinute) -#define secondsPerDay (24 * secondsPerHour) +#define SECONDS_PER_MINUTE 60 +#define SECONDS_PER_HOUR (60 * SECONDS_PER_MINUTE) +#define SECONDS_PER_DAY (24 * SECONDS_PER_HOUR) static time_t mkCPM3Origin(void) { struct tm date; date.tm_year = 77; @@ -815,9 +812,9 @@ static time_t mkCPM3Origin(void) { 4 BCD byte: SS */ static void setClockCPM3(void) { ClockCPM3Delta = mkCPM3Origin() + - (GetBYTEWrapper(setClockCPM3Adr) + GetBYTEWrapper(setClockCPM3Adr + 1) * 256) * secondsPerDay + - fromBCD(GetBYTEWrapper(setClockCPM3Adr + 2)) * secondsPerHour + - fromBCD(GetBYTEWrapper(setClockCPM3Adr + 3)) * secondsPerMinute + + (GetBYTEWrapper(setClockCPM3Adr) + GetBYTEWrapper(setClockCPM3Adr + 1) * 256) * SECONDS_PER_DAY + + fromBCD(GetBYTEWrapper(setClockCPM3Adr + 2)) * SECONDS_PER_HOUR + + fromBCD(GetBYTEWrapper(setClockCPM3Adr + 3)) * SECONDS_PER_MINUTE + fromBCD(GetBYTEWrapper(setClockCPM3Adr + 4)) - time(NULL); } @@ -825,6 +822,39 @@ static int32 simh_in(const int32 port) { int32 result = 0; switch(lastCommand) { + case getHostFilenames: +#if UNIX_PLATFORM + if (globValid) + if (globPosNameList < globS.gl_pathc) { + if (!(result = globS.gl_pathv[globPosNameList][globPosName++])) { + globPosNameList++; + globPosName = 0; + } + } + else { + globValid = FALSE; + lastCommand = 0; + globfree(&globS); + } +#elif defined (_WIN32) + if (globValid) { + if (globFinished) { + globValid = FALSE; + } + else if (!(result = FindFileData.cFileName[globPosName++])) { + globPosName = 0; + if (!FindNextFile(hFind, &FindFileData)) { + globFinished = TRUE; + FindClose(hFind); + hFind = INVALID_HANDLE_VALUE; + } + } + } +#else + lastCommand = 0; +#endif + break; + case attachPTRCmd: case attachPTPCmd: @@ -921,7 +951,7 @@ static int32 simh_in(const int32 port) { else { result = 0; if (simh_unit.flags & UNIT_SIMH_VERBOSE) { - message1("Get selected bank ignored for non-banked memory."); + MESSAGE_1("Get selected bank ignored for non-banked memory."); } } lastCommand = 0; @@ -954,9 +984,19 @@ static int32 simh_in(const int32 port) { } break; + case getHostOSPathSeparator: +#if defined (__MWERKS__) && defined (macintosh) + result = ':'; /* colon on Macintosh OS 9 */ +#elif defined (_WIN32) + result = '\\'; /* back slash in Windows */ +#else + result = '/'; /* slash in UNIX */ +#endif + break; + default: if (simh_unit.flags & UNIT_SIMH_VERBOSE) { - message2("Unnecessary IN from SIMH pseudo device on port %03xh ignored.", + MESSAGE_2("Undefined IN from SIMH pseudo device on port %03xh ignored.", port); } result = lastCommand = 0; @@ -997,7 +1037,7 @@ static int32 simh_out(const int32 port, const int32 data) { setBankSelect(data & BANKMASK); } else if (simh_unit.flags & UNIT_SIMH_VERBOSE) { - message2("Set selected bank to %i ignored for non-banked memory.", data & 3); + MESSAGE_2("Set selected bank to %i ignored for non-banked memory.", data & 3); } lastCommand = 0; break; @@ -1028,9 +1068,51 @@ static int32 simh_out(const int32 port, const int32 data) { lastCommand = data; switch(data) { + case getHostFilenames: +#if UNIX_PLATFORM + if (!globValid) { + globValid = TRUE; + globPosNameList = globPosName = 0; + createCPMCommandLine(); + globError = glob(cpmCommandLine, GLOB_ERR, NULL, &globS); + if (globError) { + if (simh_unit.flags & UNIT_SIMH_VERBOSE) { + MESSAGE_3("Cannot expand '%s'. Error is %i.", cpmCommandLine, globError); + } + globfree(&globS); + globValid = FALSE; + } + } +#elif defined (_WIN32) + if (!globValid) { + globValid = TRUE; + globPosName = 0; + globFinished = FALSE; + createCPMCommandLine(); + hFind = FindFirstFile(cpmCommandLine, &FindFileData); + if (hFind == INVALID_HANDLE_VALUE) { + if (simh_unit.flags & UNIT_SIMH_VERBOSE) { + MESSAGE_3("Cannot expand '%s'. Error is %u.", cpmCommandLine, GetLastError()); + } + globValid = FALSE; + } + } +#endif + break; + + case SIMHSleepCmd: +#if defined (_WIN32) + if ((SIMHSleep / 1000) && !sio_unit.u4) /* time to sleep and SIO not attached to a file */ + Sleep(SIMHSleep / 1000); +#else + if (SIMHSleep && !sio_unit.u4) /* time to sleep and SIO not attached to a file */ + usleep(SIMHSleep); +#endif + break; + case printTimeCmd: /* print time */ if (rtc_avail) { - message2("Current time in milliseconds = %d.", sim_os_msec()); + MESSAGE_2("Current time in milliseconds = %d.", sim_os_msec()); } else { warnNoRealTimeClock(); @@ -1039,11 +1121,11 @@ static int32 simh_out(const int32 port, const int32 data) { case startTimerCmd: /* create a new timer on top of stack */ if (rtc_avail) { - if (markTimeSP < splimit) { + if (markTimeSP < TIMER_STACK_LIMIT) { markTime[markTimeSP++] = sim_os_msec(); } else { - message1("Timer stack overflow."); + MESSAGE_1("Timer stack overflow."); } } else { @@ -1055,10 +1137,10 @@ static int32 simh_out(const int32 port, const int32 data) { if (rtc_avail) { if (markTimeSP > 0) { uint32 delta = sim_os_msec() - markTime[--markTimeSP]; - message2("Timer stopped. Elapsed time in milliseconds = %d.", delta); + MESSAGE_2("Timer stopped. Elapsed time in milliseconds = %d.", delta); } else { - message1("No timer active."); + MESSAGE_1("No timer active."); } } else { @@ -1099,7 +1181,7 @@ static int32 simh_out(const int32 port, const int32 data) { now += ClockCPM3Delta; currentTime = *localtime(&now); currentTimeValid = TRUE; - daysCPM3SinceOrg = (now - mkCPM3Origin()) / secondsPerDay; + daysCPM3SinceOrg = (int32) ((now - mkCPM3Origin()) / SECONDS_PER_DAY); getClockCPM3Pos = 0; break; @@ -1108,27 +1190,38 @@ static int32 simh_out(const int32 port, const int32 data) { break; case getBankSelectCmd: - case setBankSelectCmd: - case getCommonCmd: - case hasBankedMemoryCmd: + case getHostOSPathSeparator: break; case resetSIMHInterfaceCmd: markTimeSP = 0; lastCommand = 0; +#if UNIX_PLATFORM + if (globValid) { + globValid = FALSE; + globfree(&globS); + } +#elif defined (_WIN32) + if (globValid) { + globValid = FALSE; + if (hFind != INVALID_HANDLE_VALUE) { + FindClose(hFind); + } + } +#endif break; case showTimerCmd: /* show time difference to timer on top of stack */ if (rtc_avail) { if (markTimeSP > 0) { uint32 delta = sim_os_msec() - markTime[markTimeSP - 1]; - message2("Timer running. Elapsed in milliseconds = %d.", delta); + MESSAGE_2("Timer running. Elapsed in milliseconds = %d.", delta); } else { - message1("No timer active."); + MESSAGE_1("No timer active."); } } else { @@ -1183,12 +1276,12 @@ static int32 simh_out(const int32 port, const int32 data) { default: if (simh_unit.flags & UNIT_SIMH_VERBOSE) { - message3("Unknown command (%i) to SIMH pseudo device on port %03xh ignored.", + MESSAGE_3("Unknown command (%i) to SIMH pseudo device on port %03xh ignored.", data, port); } } } - return 0; /* ignored, since OUT */ + return 0x00; /* ignored, since OUT */ } /* port 0xfe is a device for communication SIMH <--> Altair machine */ diff --git a/AltairZ80/altairZ80_sys.c b/AltairZ80/altairZ80_sys.c index 84a3837a..d7e1ca7e 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-2006, Peter Schorn + Copyright (c) 2002-2007, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -39,6 +39,7 @@ extern DEVICE sio_dev; extern DEVICE simh_device; extern DEVICE ptr_dev; extern DEVICE ptp_dev; +extern DEVICE net_dev; extern int32 saved_PC; int32 fprint_sym(FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw); @@ -65,7 +66,7 @@ char sim_name[] = "Altair 8800 (Z80)"; REG *sim_PC = &cpu_reg[0]; int32 sim_emax = 4; DEVICE *sim_devices[] = { - &cpu_dev, &sio_dev, &simh_device, &ptr_dev, &ptp_dev, &dsk_dev, &hdsk_dev, NULL + &cpu_dev, &sio_dev, &simh_device, &ptr_dev, &ptp_dev, &dsk_dev, &hdsk_dev, &net_dev, NULL }; char memoryAccessMessage[80]; diff --git a/AltairZ80/altairz80_hdsk.c b/AltairZ80/altairz80_hdsk.c index 61a9be46..6724dbef 100644 --- a/AltairZ80/altairz80_hdsk.c +++ b/AltairZ80/altairz80_hdsk.c @@ -1,402 +1,610 @@ -/* altairz80_hdsk.c: simulated hard disk device to increase capacity - - Copyright (c) 2002-2006, Peter Schorn - - 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 - PETER SCHORN 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 Peter Schorn shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Peter Schorn. -*/ - -#include "altairz80_defs.h" - -#define UNIT_V_HDSKWLK (UNIT_V_UF + 0) /* write locked */ -#define UNIT_HDSKWLK (1 << UNIT_V_HDSKWLK) -#define UNIT_V_HDSK_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ -#define UNIT_HDSK_VERBOSE (1 << UNIT_V_HDSK_VERBOSE) -#define HDSK_SECTOR_SIZE 128 /* size of sector */ -#define HDSK_SECTORS_PER_TRACK 32 /* sectors per track */ -#define HDS_MAX_TRACKS 2048 /* number of tracks */ -#define HDSK_TRACK_SIZE (HDSK_SECTOR_SIZE * HDSK_SECTORS_PER_TRACK) -#define HDSK_CAPACITY (HDSK_TRACK_SIZE * HDS_MAX_TRACKS) -#define HDSK_NUMBER 8 /* number of hard disks */ -#define CPM_OK 0 /* indicates to CP/M everything ok */ -#define CPM_ERROR 1 /* indicates to CP/M an error condition */ -#define CPM_EMPTY 0xe5 /* default value for non-existing bytes */ -#define hdsk_none 0 -#define hdsk_reset 1 -#define hdsk_read 2 -#define hdsk_write 3 -#define hdsk_boot_address 0x5c00 - -extern char messageBuffer[]; -extern int32 PCX; -extern UNIT cpu_unit; -extern uint8 M[MAXMEMSIZE][MAXBANKS]; -extern int32 saved_PC; - -extern int32 install_bootrom(void); -extern void printMessage(void); -extern void PutBYTEBasic(const uint32 Addr, const uint32 Bank, const uint32 Value); -extern void PutBYTEWrapper(const uint32 Addr, const uint32 Value); -extern void protect(const int32 l, const int32 h); -extern uint8 GetBYTEWrapper(const uint32 Addr); -extern int32 bootrom[bootrom_size]; - -static t_stat hdsk_svc(UNIT *uptr); -static t_stat hdsk_boot(int32 unitno, DEVICE *dptr); -static int32 hdsk_hasVerbose(void); -int32 hdsk_io(const int32 port, const int32 io, const int32 data); -static int32 hdsk_in(const int32 port); -static int32 hdsk_out(const int32 data); -static int32 checkParameters(void); -static int32 doSeek(void); -static int32 doRead(void); -static int32 doWrite(void); - -static int32 hdskLastCommand = hdsk_none; -static int32 hdskCommandPosition = 0; -static int32 selectedDisk; -static int32 selectedSector; -static int32 selectedTrack; -static int32 selectedDMA; -static int32 hdskTrace; - -static UNIT hdsk_unit[] = { - { UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, - { UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, - { UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, - { UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, - { UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, - { UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, - { UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, - { UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) } -}; - -static REG hdsk_reg[] = { - { DRDATA (HDCMD, hdskLastCommand, 32), REG_RO }, - { DRDATA (HDPOS, hdskCommandPosition, 32), REG_RO }, - { DRDATA (HDDSK, selectedDisk, 32), REG_RO }, - { DRDATA (HDSEC, selectedSector, 32), REG_RO }, - { DRDATA (HDTRK, selectedTrack, 32), REG_RO }, - { DRDATA (HDDMA, selectedDMA, 32), REG_RO }, - { DRDATA (HDTRACE, hdskTrace, 8), }, - { NULL } -}; - -static MTAB hdsk_mod[] = { - { UNIT_HDSKWLK, 0, "write enabled", "WRITEENABLED", NULL }, - { UNIT_HDSKWLK, UNIT_HDSKWLK, "write locked", "LOCKED", NULL }, - /* quiet, no warning messages */ - { UNIT_HDSK_VERBOSE, 0, "QUIET", "QUIET", NULL }, - /* verbose, show warning messages */ - { UNIT_HDSK_VERBOSE, UNIT_HDSK_VERBOSE, "VERBOSE", "VERBOSE", NULL }, - { 0 } -}; - -DEVICE hdsk_dev = { - "HDSK", hdsk_unit, hdsk_reg, hdsk_mod, - 8, 10, 31, 1, 8, 8, - NULL, NULL, NULL, - &hdsk_boot, NULL, NULL, - NULL, 0, 0, - NULL, NULL, NULL -}; - -static t_stat hdsk_svc(UNIT *uptr) { - return SCPE_OK; -} - -static const int32 hdskBoot[bootrom_size] = { - 0xf3, 0x06, 0x80, 0x3e, 0x0e, 0xd3, 0xfe, 0x05, /* 5c00-5c07 */ - 0xc2, 0x05, 0x5c, 0x3e, 0x16, 0xd3, 0xfe, 0x3e, /* 5c08-5c0f */ - 0x12, 0xd3, 0xfe, 0xdb, 0xfe, 0xb7, 0xca, 0x20, /* 5c10-5c17 */ - 0x5c, 0x3e, 0x0c, 0xd3, 0xfe, 0xaf, 0xd3, 0xfe, /* 5c18-5c1f */ - 0x06, 0x20, 0x3e, 0x01, 0xd3, 0xfd, 0x05, 0xc2, /* 5c20-5c27 */ - 0x24, 0x5c, 0x11, 0x08, 0x00, 0x21, 0x00, 0x00, /* 5c28-5c2f */ - 0x0e, 0xb8, 0x3e, 0x02, 0xd3, 0xfd, 0x3a, 0x37, /* 5c30-5c37 */ - 0xff, 0xd6, 0x08, 0xd3, 0xfd, 0x7b, 0xd3, 0xfd, /* 5c38-5c3f */ - 0x7a, 0xd3, 0xfd, 0xaf, 0xd3, 0xfd, 0x7d, 0xd3, /* 5c40-5c47 */ - 0xfd, 0x7c, 0xd3, 0xfd, 0xdb, 0xfd, 0xb7, 0xca, /* 5c48-5c4f */ - 0x53, 0x5c, 0x76, 0x79, 0x0e, 0x80, 0x09, 0x4f, /* 5c50-5c57 */ - 0x0d, 0xc2, 0x60, 0x5c, 0xfb, 0xc3, 0x00, 0x00, /* 5c58-5c5f */ - 0x1c, 0x1c, 0x7b, 0xfe, 0x20, 0xca, 0x73, 0x5c, /* 5c60-5c67 */ - 0xfe, 0x21, 0xc2, 0x32, 0x5c, 0x1e, 0x00, 0x14, /* 5c68-5c6f */ - 0xc3, 0x32, 0x5c, 0x1e, 0x01, 0xc3, 0x32, 0x5c, /* 5c70-5c77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c78-5c7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c80-5c87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c88-5c8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c90-5c97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c98-5c9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5ca0-5ca7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5ca8-5caf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cb0-5cb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cb8-5cbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cc0-5cc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cc8-5ccf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cd0-5cd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cd8-5cdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5ce0-5ce7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5ce8-5cef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cf0-5cf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cf8-5cff */ -}; - -static t_stat hdsk_boot(int32 unitno, DEVICE *dptr) { - int32 i; - if (MEMSIZE < 24*KB) { - printf("Need at least 24KB RAM to boot from hard disk.\n"); - return SCPE_ARG; - } - if (cpu_unit.flags & (UNIT_ALTAIRROM | UNIT_BANKED)) { - if (install_bootrom()) { - printf("ALTAIR boot ROM installed.\n"); - } - /* check whether we are really modifying an LD A,<> instruction */ - if (bootrom[unitNoOffset1 - 1] == LDAInstruction) { - bootrom[unitNoOffset1] = (unitno + NUM_OF_DSK) & 0xff; /* LD A, */ - } - else { /* Attempt to modify non LD A,<> instructions is refused. */ - printf("Incorrect boot ROM offset detected.\n"); - return SCPE_IERR; - } - } - for (i = 0; i < bootrom_size; i++) { - PutBYTEBasic(i + hdsk_boot_address, 0, hdskBoot[i] & 0xff); - } - saved_PC = hdsk_boot_address; - protect(hdsk_boot_address, hdsk_boot_address + bootrom_size - 1); - return SCPE_OK; -} - -/* returns TRUE iff there exists a disk with VERBOSE */ -static int32 hdsk_hasVerbose(void) { - int32 i; - for (i = 0; i < HDSK_NUMBER; i++) { - if (((hdsk_dev.units + i) -> flags) & UNIT_HDSK_VERBOSE) { - return TRUE; - } - } - return FALSE; -} - -/* The hard disk port is 0xfd. It understands the following commands. - - 1. Reset - ld b,32 - ld a,hdsk_reset - l: out (0fdh),a - dec b - jp nz,l - - 2. Read / write - ; 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 - dma: dw 0 ; defines where result is placed in memory - - ; routine to execute - ld b,7 ; size of parameter block - ld hl,cmd ; start address of parameter block - l: ld a,(hl) ; get byte of parameter block - out (0fdh),a ; send it to port - inc hl ; point to next byte - dec b ; decrement counter - jp nz,l ; again, if not done - in a,(0fdh) ; get result code - -*/ - -/* check the parameters and return TRUE iff parameters are correct or have been repaired */ -static int32 checkParameters(void) { - int32 currentFlag; - if ((selectedDisk < 0) || (selectedDisk >= HDSK_NUMBER)) { - if (hdsk_hasVerbose()) { - message2("HDSK%d does not exist, will use HDSK0 instead.", selectedDisk); - } - selectedDisk = 0; - } - currentFlag = (hdsk_dev.units + selectedDisk) -> flags; - if ((currentFlag & UNIT_ATT) == 0) { - if (currentFlag & UNIT_HDSK_VERBOSE) { - message2("HDSK%d is not attached.", selectedDisk); - } - return FALSE; /* cannot read or write */ - } - if ((selectedSector < 0) || (selectedSector >= HDSK_SECTORS_PER_TRACK)) { - if (currentFlag & UNIT_HDSK_VERBOSE) { - message4("HDSK%d: 0 <= Sector=%02d < %d violated, will use 0 instead.", - selectedDisk, selectedSector, HDSK_SECTORS_PER_TRACK); - } - selectedSector = 0; - } - if ((selectedTrack < 0) || (selectedTrack >= HDS_MAX_TRACKS)) { - if (currentFlag & UNIT_HDSK_VERBOSE) { - message4("HDSK%d: 0 <= Track=%04d < %04d violated, will use 0 instead.", - selectedDisk, selectedTrack, HDS_MAX_TRACKS); - } - selectedTrack = 0; - } - selectedDMA &= ADDRMASK; - if (hdskTrace) { - message6("%s HDSK%d Sector=%02d Track=%04d DMA=%04x", - (hdskLastCommand == hdsk_read) ? "Read" : "Write", - selectedDisk, selectedSector, selectedTrack, selectedDMA); - } - return TRUE; -} - -static int32 doSeek(void) { - UNIT *uptr = hdsk_dev.units + selectedDisk; - if (fseek(uptr -> fileref, - HDSK_TRACK_SIZE * selectedTrack + HDSK_SECTOR_SIZE * selectedSector, SEEK_SET)) { - if ((uptr -> flags) & UNIT_HDSK_VERBOSE) { - message4("Could not access HDSK%d Sector=%02d Track=%04d.", - selectedDisk, selectedSector, selectedTrack); - } - return CPM_ERROR; - } - else { - return CPM_OK; - } -} - -static int32 doRead(void) { - int32 i; - uint8 hdskbuf[HDSK_SECTOR_SIZE]; /* data buffer */ - UNIT *uptr = hdsk_dev.units + selectedDisk; - if (doSeek()) { - return CPM_ERROR; - } - if (fread(hdskbuf, HDSK_SECTOR_SIZE, 1, uptr -> fileref) != 1) { - for (i = 0; i < HDSK_SECTOR_SIZE; i++) { - hdskbuf[i] = CPM_EMPTY; - } - if ((uptr -> flags) & UNIT_HDSK_VERBOSE) { - message4("Could not read HDSK%d Sector=%02d Track=%04d.", - selectedDisk, selectedSector, selectedTrack); - } - return CPM_OK; /* allows the creation of empty hard disks */ - } - for (i = 0; i < HDSK_SECTOR_SIZE; i++) { - PutBYTEWrapper(selectedDMA + i, hdskbuf[i]); - } - return CPM_OK; -} - -static int32 doWrite(void) { - int32 i; - uint8 hdskbuf[HDSK_SECTOR_SIZE]; /* data buffer */ - UNIT *uptr = hdsk_dev.units + selectedDisk; - if (((uptr -> flags) & UNIT_HDSKWLK) == 0) { /* write enabled */ - if (doSeek()) { - return CPM_ERROR; - } - for (i = 0; i < HDSK_SECTOR_SIZE; i++) { - hdskbuf[i] = GetBYTEWrapper(selectedDMA + i); - } - if (fwrite(hdskbuf, HDSK_SECTOR_SIZE, 1, uptr -> fileref) != 1) { - if ((uptr -> flags) & UNIT_HDSK_VERBOSE) { - message4("Could not write HDSK%d Sector=%02d Track=%04d.", - selectedDisk, selectedSector, selectedTrack); - } - return CPM_ERROR; - } - } - else { - if ((uptr -> flags) & UNIT_HDSK_VERBOSE) { - message4("Could not write to locked HDSK%d Sector=%02d Track=%04d.", - selectedDisk, selectedSector, selectedTrack); - } - return CPM_ERROR; - } - return CPM_OK; -} - -static int32 hdsk_in(const int32 port) { - int32 result; - if ((hdskCommandPosition == 6) && ((hdskLastCommand == hdsk_read) || (hdskLastCommand == hdsk_write))) { - result = checkParameters() ? ((hdskLastCommand == hdsk_read) ? doRead() : doWrite()) : CPM_ERROR; - hdskLastCommand = hdsk_none; - hdskCommandPosition = 0; - return result; - } - else if (hdsk_hasVerbose()) { - message4("Illegal IN command detected (port=%03xh, cmd=%d, pos=%d).", - port, hdskLastCommand, hdskCommandPosition); - } - return CPM_OK; -} - -static int32 hdsk_out(const int32 data) { - switch(hdskLastCommand) { - - case hdsk_read: - - case hdsk_write: - switch(hdskCommandPosition) { - - case 0: - selectedDisk = data; - hdskCommandPosition++; - break; - - case 1: - selectedSector = data; - hdskCommandPosition++; - break; - - case 2: - selectedTrack = data; - hdskCommandPosition++; - break; - - case 3: - selectedTrack += (data << 8); - hdskCommandPosition++; - break; - - case 4: - selectedDMA = data; - hdskCommandPosition++; - break; - - case 5: - selectedDMA += (data << 8); - hdskCommandPosition++; - break; - - default: - hdskLastCommand = hdsk_none; - hdskCommandPosition = 0; - } - break; - - default: - hdskLastCommand = data; - hdskCommandPosition = 0; - } - return 0; /* ignored, since OUT */ -} - -int32 hdsk_io(const int32 port, const int32 io, const int32 data) { - return io == 0 ? hdsk_in(port) : hdsk_out(data); -} +/* altairz80_hdsk.c: simulated hard disk device to increase capacity + + Copyright (c) 2002-2007, Peter Schorn + + 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 + PETER SCHORN 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 Peter Schorn shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Peter Schorn. + + Contains code from Howard M. Harte for defining and changing disk geometry. +*/ + +#include "altairz80_defs.h" + +/* the following routines provided courtesy of Howard M. Harte */ +t_stat set_geom (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat show_geom (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat set_format (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat show_format (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat hdsk_attach (UNIT *uptr, char *cptr); + +#define UNIT_V_HDSKWLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_HDSKWLK (1 << UNIT_V_HDSKWLK) +#define UNIT_V_HDSK_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ +#define UNIT_HDSK_VERBOSE (1 << UNIT_V_HDSK_VERBOSE) +#define HDSK_MAX_SECTOR_SIZE 1024 /* size of sector */ +#define HDSK_SECTOR_SIZE u5 /* size of sector */ +#define HDSK_SECTORS_PER_TRACK u4 /* sectors per track */ +#define HDSK_MAX_TRACKS u3 /* number of tracks */ +#define HDSK_FORMAT_TYPE u6 /* Disk Format Type */ +#define HDSK_CAPACITY (2048*32*128) /* Default Altair HDSK Capacity */ +#define HDSK_NUMBER 8 /* number of hard disks */ +#define CPM_OK 0 /* indicates to CP/M everything ok */ +#define CPM_ERROR 1 /* indicates to CP/M an error condition */ +#define CPM_EMPTY 0xe5 /* default value for non-existing bytes */ +#define HDSK_NONE 0 +#define HDSK_RESET 1 +#define HDSK_READ 2 +#define HDSK_WRITE 3 +#define HDSK_PARAM 4 +#define HDSK_BOOT_ADDRESS 0x5c00 + +extern char messageBuffer[]; +extern int32 PCX; +extern UNIT cpu_unit; +extern uint8 M[MAXMEMSIZE][MAXBANKS]; +extern int32 saved_PC; + +extern int32 install_bootrom(void); +extern void printMessage(void); +extern void PutBYTEBasic(const uint32 Addr, const uint32 Bank, const uint32 Value); +extern void PutBYTEWrapper(const uint32 Addr, const uint32 Value); +extern void protect(const int32 l, const int32 h); +extern uint8 GetBYTEWrapper(const uint32 Addr); +extern int32 bootrom[BOOTROM_SIZE]; + +static t_stat hdsk_boot(int32 unitno, DEVICE *dptr); +static int32 hdsk_hasVerbose(void); +int32 hdsk_io(const int32 port, const int32 io, const int32 data); +static int32 hdsk_in(const int32 port); +static int32 hdsk_out(const int32 data); +static int32 checkParameters(void); +static int32 doSeek(void); +static int32 doRead(void); +static int32 doWrite(void); + +static int32 hdskLastCommand = HDSK_NONE; +static int32 hdskCommandPosition = 0; +static int32 paramcount = 0; +static int32 selectedDisk; +static int32 selectedSector; +static int32 selectedTrack; +static int32 selectedDMA; +static int32 hdskTrace; + +typedef struct { + char name[16]; + t_addr capac; + uint16 spt; + uint8 bsh; + uint8 blm; + uint8 exm; + uint16 dsm; + uint16 drm; + uint8 al0; + uint8 al1; + uint16 cks; + uint16 off; + uint8 psh; + uint8 phm; +} DPB; + +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, 0x8000, 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 */ + { "", 0 } +}; + +static UNIT hdsk_unit[] = { + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) } +}; + +static REG hdsk_reg[] = { + { DRDATA (HDCMD, hdskLastCommand, 32), REG_RO }, + { DRDATA (HDPOS, hdskCommandPosition, 32), REG_RO }, + { DRDATA (HDDSK, selectedDisk, 32), REG_RO }, + { DRDATA (HDSEC, selectedSector, 32), REG_RO }, + { DRDATA (HDTRK, selectedTrack, 32), REG_RO }, + { DRDATA (HDDMA, selectedDMA, 32), REG_RO }, + { DRDATA (HDTRACE, hdskTrace, 8), }, + { NULL } +}; + +static MTAB hdsk_mod[] = { + { MTAB_XTD|MTAB_VUN|MTAB_VAL, 0, "FORMAT", "FORMAT", &set_format, &show_format, NULL }, + { UNIT_HDSKWLK, 0, "WRTENB", "WRTENB", NULL }, + { UNIT_HDSKWLK, UNIT_HDSKWLK, "WRTLCK", "WRTLCK", NULL }, + /* quiet, no warning messages */ + { UNIT_HDSK_VERBOSE, 0, "QUIET", "QUIET", NULL }, + /* verbose, show warning messages */ + { UNIT_HDSK_VERBOSE, UNIT_HDSK_VERBOSE, "VERBOSE", "VERBOSE", NULL }, + { MTAB_XTD|MTAB_VUN|MTAB_VAL, 0, "GEOM", "GEOM", &set_geom, &show_geom, NULL }, + { 0 } +}; + +DEVICE hdsk_dev = { + "HDSK", hdsk_unit, hdsk_reg, hdsk_mod, + 8, 10, 31, 1, 8, 8, + NULL, NULL, NULL, + &hdsk_boot, &hdsk_attach, NULL, + NULL, 0, 0, + NULL, NULL, NULL +}; + +/* Attach routine */ +t_stat hdsk_attach (UNIT *uptr, char *cptr) { + uint32 flen; + t_stat r; + int32 i; + + r = attach_unit (uptr, cptr); /* attach unit */ + if (r != SCPE_OK) return r; /* error? */ + if ((flen = sim_fsize (uptr->fileref)) == 0) { /* new disk image? */ + if (uptr->flags & UNIT_RO) return SCPE_OK; /* if ro, done */ + return SCPE_OK; + } + + if(flen>0) { + uptr->capac = flen; + + uptr->HDSK_FORMAT_TYPE = -1; /* Default to unknown format type */ + + for(i=0; dpb[i].spt != 0; i++) { + if(dpb[i].capac == uptr->capac) { + uptr->HDSK_FORMAT_TYPE = i; + break; + } + } + } + + if(uptr->HDSK_FORMAT_TYPE == -1) { + uptr->HDSK_FORMAT_TYPE = 0; + uptr->capac = dpb[uptr->HDSK_FORMAT_TYPE].capac; + printf("HDSK: WARNING: Unsupported disk capacity, assuming HDSK type.\n"); + uptr->flags |= UNIT_HDSKWLK; + printf("HDSK: WARNING: Forcing WRTLCK.\n"); + if(uptr->capac != (uptr->HDSK_MAX_TRACKS * uptr->HDSK_SECTORS_PER_TRACK * uptr->HDSK_SECTOR_SIZE)) { + printf("HDSK: WARNING: Geometry may be incorrect.\n"); + } + } + + 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_MAX_TRACKS = uptr->capac / (uptr->HDSK_SECTORS_PER_TRACK * uptr->HDSK_SECTOR_SIZE); + + return SCPE_OK; +} + +/* Set disk geometry routine */ +t_stat set_geom (UNIT *uptr, int32 val, char *cptr, void *desc) { + DEVICE *dptr; + + uint32 ncyl, nsect, ssize; + + if (cptr == NULL) return SCPE_ARG; + if (uptr == NULL) return SCPE_IERR; + dptr = find_dev_from_unit (uptr); + if (dptr == NULL) return SCPE_IERR; + + sscanf(cptr, "%d/%d/%d", &ncyl, &nsect, &ssize); + uptr->HDSK_MAX_TRACKS = ncyl; + uptr->HDSK_SECTORS_PER_TRACK = nsect; + uptr->HDSK_SECTOR_SIZE = ssize; + + return SCPE_OK; +} + +/* Show disk geometry routine */ +t_stat show_geom (FILE *st, UNIT *uptr, int32 val, void *desc) { + DEVICE *dptr; + if (uptr == NULL) return SCPE_IERR; + dptr = find_dev_from_unit (uptr); + if (dptr == NULL) return SCPE_IERR; + fprintf (st, "T:%d/N:%d/S:%d", uptr->HDSK_MAX_TRACKS, uptr->HDSK_SECTORS_PER_TRACK, uptr->u5); + + return SCPE_OK; +} + +/* Set disk format routine */ +t_stat set_format (UNIT *uptr, int32 val, char *cptr, void *desc) { + DEVICE *dptr; + + char fmtname[16]; + int32 i; + + if (cptr == NULL) return SCPE_ARG; + if (uptr == NULL) return SCPE_IERR; + dptr = find_dev_from_unit (uptr); + if (dptr == NULL) return SCPE_IERR; + + sscanf(cptr, "%s", fmtname); + + for(i=0;dpb[i].spt != 0;i++) { + if(!strncmp(fmtname, dpb[i].name, strlen(fmtname))) { + uptr->HDSK_FORMAT_TYPE = i; + uptr->capac = dpb[i].capac; /* Set capacity */ + + /* Configure physical disk geometry */ + 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_MAX_TRACKS = uptr->capac / (uptr->HDSK_SECTORS_PER_TRACK * uptr->HDSK_SECTOR_SIZE); + + return SCPE_OK; + } + } + return SCPE_ARG; +} + +/* Show disk format routine */ +t_stat show_format (FILE *st, UNIT *uptr, int32 val, void *desc) { + DEVICE *dptr; + if (uptr == NULL) return SCPE_IERR; + dptr = find_dev_from_unit (uptr); + if (dptr == NULL) return SCPE_IERR; + fprintf (st, "%s", dpb[uptr->HDSK_FORMAT_TYPE].name); + + return SCPE_OK; +} + +static const int32 hdskBoot[BOOTROM_SIZE] = { + 0xf3, 0x06, 0x80, 0x3e, 0x0e, 0xd3, 0xfe, 0x05, /* 5c00-5c07 */ + 0xc2, 0x05, 0x5c, 0x3e, 0x16, 0xd3, 0xfe, 0x3e, /* 5c08-5c0f */ + 0x12, 0xd3, 0xfe, 0xdb, 0xfe, 0xb7, 0xca, 0x20, /* 5c10-5c17 */ + 0x5c, 0x3e, 0x0c, 0xd3, 0xfe, 0xaf, 0xd3, 0xfe, /* 5c18-5c1f */ + 0x06, 0x20, 0x3e, 0x01, 0xd3, 0xfd, 0x05, 0xc2, /* 5c20-5c27 */ + 0x24, 0x5c, 0x11, 0x08, 0x00, 0x21, 0x00, 0x00, /* 5c28-5c2f */ + 0x0e, 0xb8, 0x3e, 0x02, 0xd3, 0xfd, 0x3a, 0x37, /* 5c30-5c37 */ + 0xff, 0xd6, 0x08, 0xd3, 0xfd, 0x7b, 0xd3, 0xfd, /* 5c38-5c3f */ + 0x7a, 0xd3, 0xfd, 0xaf, 0xd3, 0xfd, 0x7d, 0xd3, /* 5c40-5c47 */ + 0xfd, 0x7c, 0xd3, 0xfd, 0xdb, 0xfd, 0xb7, 0xca, /* 5c48-5c4f */ + 0x53, 0x5c, 0x76, 0x79, 0x0e, 0x80, 0x09, 0x4f, /* 5c50-5c57 */ + 0x0d, 0xc2, 0x60, 0x5c, 0xfb, 0xc3, 0x00, 0x00, /* 5c58-5c5f */ + 0x1c, 0x1c, 0x7b, 0xfe, 0x20, 0xca, 0x73, 0x5c, /* 5c60-5c67 */ + 0xfe, 0x21, 0xc2, 0x32, 0x5c, 0x1e, 0x00, 0x14, /* 5c68-5c6f */ + 0xc3, 0x32, 0x5c, 0x1e, 0x01, 0xc3, 0x32, 0x5c, /* 5c70-5c77 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c78-5c7f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c80-5c87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c88-5c8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c90-5c97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c98-5c9f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5ca0-5ca7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5ca8-5caf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cb0-5cb7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cb8-5cbf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cc0-5cc7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cc8-5ccf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cd0-5cd7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cd8-5cdf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5ce0-5ce7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5ce8-5cef */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cf0-5cf7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cf8-5cff */ +}; + +static t_stat hdsk_boot(int32 unitno, DEVICE *dptr) { + int32 i; + if (MEMSIZE < 24*KB) { + printf("Need at least 24KB RAM to boot from hard disk.\n"); + return SCPE_ARG; + } + if (cpu_unit.flags & (UNIT_ALTAIRROM | UNIT_BANKED)) { + if (install_bootrom()) { + printf("ALTAIR boot ROM installed.\n"); + } + /* check whether we are really modifying an LD A,<> instruction */ + if (bootrom[UNIT_NO_OFFSET_1 - 1] == LDA_INSTRUCTION) { + bootrom[UNIT_NO_OFFSET_1] = (unitno + NUM_OF_DSK) & 0xff; /* LD A, */ + } + else { /* Attempt to modify non LD A,<> instructions is refused. */ + printf("Incorrect boot ROM offset detected.\n"); + return SCPE_IERR; + } + } + for (i = 0; i < BOOTROM_SIZE; i++) { + PutBYTEBasic(i + HDSK_BOOT_ADDRESS, 0, hdskBoot[i] & 0xff); + } + saved_PC = HDSK_BOOT_ADDRESS; + protect(HDSK_BOOT_ADDRESS, HDSK_BOOT_ADDRESS + BOOTROM_SIZE - 1); + return SCPE_OK; +} + +/* returns TRUE iff there exists a disk with VERBOSE */ +static int32 hdsk_hasVerbose(void) { + int32 i; + for (i = 0; i < HDSK_NUMBER; i++) { + if (((hdsk_dev.units + i) -> flags) & UNIT_HDSK_VERBOSE) { + return TRUE; + } + } + return FALSE; +} + +/* The hard disk port is 0xfd. It understands the following commands. + + 1. Reset + ld b,32 + ld a,HDSK_RESET + l: out (0fdh),a + dec b + jp nz,l + + 2. Read / write + ; 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 + dma: dw 0 ; defines where result is placed in memory + + ; routine to execute + ld b,7 ; size of parameter block + ld hl,cmd ; start address of parameter block + l: ld a,(hl) ; get byte of parameter block + out (0fdh),a ; send it to port + inc hl ; point to next byte + dec b ; decrement counter + jp nz,l ; again, if not done + in a,(0fdh) ; get result code + + 3. Retrieve Disk Parameters from controller (Howard M. Harte) + Reads a 19-byte parameter block from the disk controller. + This parameter block is in CP/M DPB format for the first 17 bytes, + and the last two bytes are the lsb/msb of the disk's physical + sector size. + + ; routine to execute + ld a,hdskParam ; hdskParam = 4 + out (hdskPort),a ; Send 'get parameters' command, hdskPort = 0fdh + ld a,(diskno) + out (hdskPort),a ; Send selected HDSK number + ld b,17 + 1: in a,(hdskPort) ; Read 17-bytes of DPB + ld (hl), a + inc hl + djnz 1 + in a,(hdskPort) ; Read LSB of disk's physical sector size. + ld (hsecsiz), a + in a,(hdskPort) ; Read MSB of disk's physical sector size. + ld (hsecsiz+1), a + +*/ + +/* check the parameters and return TRUE iff parameters are correct or have been repaired */ +static int32 checkParameters(void) { + UNIT *uptr = hdsk_dev.units + selectedDisk; + int32 currentFlag; + if ((selectedDisk < 0) || (selectedDisk >= HDSK_NUMBER)) { + if (hdsk_hasVerbose()) { + MESSAGE_2("HDSK%d does not exist, will use HDSK0 instead.", selectedDisk); + } + selectedDisk = 0; + } + currentFlag = (hdsk_dev.units + selectedDisk) -> flags; + if ((currentFlag & UNIT_ATT) == 0) { + if (currentFlag & UNIT_HDSK_VERBOSE) { + MESSAGE_2("HDSK%d is not attached.", selectedDisk); + } + return FALSE; /* cannot read or write */ + } + if ((selectedSector < 0) || (selectedSector >= uptr->HDSK_SECTORS_PER_TRACK)) { + if (currentFlag & UNIT_HDSK_VERBOSE) { + MESSAGE_4("HDSK%d: 0 <= Sector=%02d < %d violated, will use 0 instead.", + selectedDisk, selectedSector, uptr->HDSK_SECTORS_PER_TRACK); + } + selectedSector = 0; + } + if ((selectedTrack < 0) || (selectedTrack >= uptr->HDSK_MAX_TRACKS)) { + if (currentFlag & UNIT_HDSK_VERBOSE) { + MESSAGE_4("HDSK%d: 0 <= Track=%04d < %04d violated, will use 0 instead.", + selectedDisk, selectedTrack, uptr->HDSK_MAX_TRACKS); + } + selectedTrack = 0; + } + selectedDMA &= ADDRMASK; + if (hdskTrace) { + MESSAGE_7("%s HDSK%d Track=%04d Sector=%02d Len=%04d DMA=%04x\n", + (hdskLastCommand == HDSK_READ) ? "Read" : "Write", + selectedDisk, selectedTrack, selectedSector, uptr->HDSK_SECTOR_SIZE, selectedDMA); + } + return TRUE; +} + +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)) { + if ((uptr -> flags) & UNIT_HDSK_VERBOSE) { + MESSAGE_4("Could not access HDSK%d Sector=%02d Track=%04d.", + selectedDisk, selectedSector, selectedTrack); + } + return CPM_ERROR; + } + else { + return CPM_OK; + } +} + +uint8 hdskbuf[HDSK_MAX_SECTOR_SIZE]; /* data buffer */ + +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) { + for (i = 0; i < uptr->HDSK_SECTOR_SIZE; i++) { + hdskbuf[i] = CPM_EMPTY; + } + if ((uptr -> flags) & UNIT_HDSK_VERBOSE) { + MESSAGE_4("Could not read HDSK%d Sector=%02d Track=%04d.", + selectedDisk, selectedSector, selectedTrack); + } + return CPM_OK; /* allows the creation of empty hard disks */ + } + for (i = 0; i < uptr->HDSK_SECTOR_SIZE; i++) { + PutBYTEWrapper(selectedDMA + i, hdskbuf[i]); + } + return CPM_OK; +} + +static int32 doWrite(void) { + int32 i; + + UNIT *uptr = hdsk_dev.units + selectedDisk; + if (((uptr -> flags) & UNIT_HDSKWLK) == 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) { + if ((uptr -> flags) & UNIT_HDSK_VERBOSE) { + MESSAGE_4("Could not write HDSK%d Sector=%02d Track=%04d.", + selectedDisk, selectedSector, selectedTrack); + } + return CPM_ERROR; + } + } + else { + if ((uptr -> flags) & UNIT_HDSK_VERBOSE) { + MESSAGE_4("Could not write to locked HDSK%d Sector=%02d Track=%04d.", + selectedDisk, selectedSector, selectedTrack); + } + return CPM_ERROR; + } + return CPM_OK; +} + +static int32 hdsk_in(const int32 port) { + UNIT *uptr = hdsk_dev.units + selectedDisk; + + int32 result; + if ((hdskCommandPosition == 6) && ((hdskLastCommand == HDSK_READ) || (hdskLastCommand == HDSK_WRITE))) { + 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) { + 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 + MESSAGE_2("HDSK%d Get parameter error.", selectedDisk); + + } + else if (hdsk_hasVerbose()) { + MESSAGE_4("Illegal IN command detected (port=%03xh, cmd=%d, pos=%d).", + port, hdskLastCommand, hdskCommandPosition); + } + return CPM_OK; +} + +static int32 hdsk_out(const int32 data) { + switch(hdskLastCommand) { + + case HDSK_PARAM: + paramcount = 0; + selectedDisk = data; + break; + + case HDSK_READ: + + case HDSK_WRITE: + switch(hdskCommandPosition) { + + case 0: + selectedDisk = data; + hdskCommandPosition++; + break; + + case 1: + selectedSector = data; + hdskCommandPosition++; + break; + + case 2: + selectedTrack = data; + hdskCommandPosition++; + break; + + case 3: + selectedTrack += (data << 8); + hdskCommandPosition++; + break; + + case 4: + selectedDMA = data; + hdskCommandPosition++; + break; + + case 5: + selectedDMA += (data << 8); + hdskCommandPosition++; + break; + + default: + hdskLastCommand = HDSK_NONE; + hdskCommandPosition = 0; + } + break; + + default: + hdskLastCommand = data; + hdskCommandPosition = 0; + } + return 0; /* ignored, since OUT */ +} + +int32 hdsk_io(const int32 port, const int32 io, const int32 data) { + return io == 0 ? hdsk_in(port) : hdsk_out(data); +} diff --git a/AltairZ80/altairz80_net.c b/AltairZ80/altairz80_net.c new file mode 100644 index 00000000..1354cff2 --- /dev/null +++ b/AltairZ80/altairz80_net.c @@ -0,0 +1,292 @@ +/* altairz80_net.c: networking capability + + Copyright (c) 2002-2007, Peter Schorn + + 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 + PETER SCHORN 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 Peter Schorn shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Peter Schorn. +*/ + +#include "altairz80_defs.h" +#include "sim_sock.h" + +#define UNIT_V_SERVER (UNIT_V_UF + 0) /* define machine as a server */ +#define UNIT_SERVER (1 << UNIT_V_SERVER) +#define NET_INIT_POLL_SERVER 16000 +#define NET_INIT_POLL_CLIENT 15000 + +/*#define DEBUG_NETWORK TRUE*/ + +static t_stat net_attach (UNIT *uptr, char *cptr); +static t_stat net_detach (UNIT *uptr); +static t_stat net_reset (DEVICE *dptr); +static t_stat net_svc (UNIT *uptr); +static t_stat set_net (UNIT *uptr, int32 value, char *cptr, void *desc); +int32 netStatus (const int32 port, const int32 io, const int32 data); +int32 netData (const int32 port, const int32 io, const int32 data); + +#define MAX_CONNECTIONS 2 /* maximal number of server connections */ +#define BUFFER_LENGTH 512 /* length of input and output buffer */ + +static struct { + int32 Z80StatusPort; /* Z80 status port associated with this ioSocket, read only */ + int32 Z80DataPort; /* Z80 data port associated with this ioSocket, read only */ + SOCKET masterSocket; /* server master socket, only defined at [1] */ + SOCKET ioSocket; /* accepted server socket or connected client socket, 0 iff free */ + char inputBuffer[BUFFER_LENGTH]; /* buffer for input characters read from ioSocket */ + int32 inputPosRead; /* position of next character to read from buffer */ + int32 inputPosWrite; /* position of next character to append to input buffer from ioSocket */ + int32 inputSize; /* number of characters in circular input buffer */ + char outputBuffer[BUFFER_LENGTH];/* buffer for output characters to be written to ioSocket */ + 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 */ +/* stat dat ms ios in inPR inPW inS out outPR outPW outS */ + {50, 51, 0, 0, {0}, 0, 0, 0, {0}, 0, 0, 0}, /* client Z80 port 50 and 51 */ + {40, 41, 0, 0, {0}, 0, 0, 0, {0}, 0, 0, 0}, /* server Z80 port 40 and 41 */ + {42, 43, 0, 0, {0}, 0, 0, 0, {0}, 0, 0, 0} /* server Z80 port 42 and 43 */ +}; + +static UNIT net_unit = { + UDATA (&net_svc, UNIT_ATTABLE, 0), + 0, /* wait, set in attach */ + 0, /* u3 = Port */ + 0, /* u4 = IP of host */ + 0, /* u5, unused */ + 0, /* u6, unused */ +}; + +static REG net_reg[] = { + { DRDATA (POLL, net_unit.wait, 32) }, + { HRDATA (IPHOST, net_unit.u4, 32), REG_RO }, + { DRDATA (PORT, net_unit.u3, 32), REG_RO }, + { NULL } +}; + +static MTAB net_mod[] = { + { UNIT_SERVER, 0, "CLIENT", "CLIENT", &set_net}, /* machine is a client */ + { UNIT_SERVER, UNIT_SERVER, "SERVER", "SERVER", &set_net}, /* machine is a server */ + { 0 } +}; + +DEVICE net_dev = { + "NET", &net_unit, net_reg, net_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &net_reset, + NULL, &net_attach, &net_detach, + NULL, 0, 0, + NULL, NULL, NULL +}; + +static t_stat set_net(UNIT *uptr, int32 value, char *cptr, void *desc) { + char temp[CBUFSIZE]; + if ((net_unit.flags & UNIT_ATT) && ((net_unit.flags & UNIT_SERVER) != value)) { + strncpy(temp, net_unit.filename, CBUFSIZE); /* save name for later attach */ + net_detach(&net_unit); + net_unit.flags ^= UNIT_SERVER; /* now switch from client to server and vice versa */ + net_attach(uptr, temp); + return SCPE_OK; + } + return SCPE_OK; +} + +static void serviceDescriptor_reset(const uint32 i) { + serviceDescriptor[i].inputPosRead = 0; + serviceDescriptor[i].inputPosWrite = 0; + serviceDescriptor[i].inputSize = 0; + serviceDescriptor[i].outputPosRead = 0; + serviceDescriptor[i].outputPosWrite = 0; + serviceDescriptor[i].outputSize = 0; +} + +static t_stat net_reset(DEVICE *dptr) { + uint32 i; + if (net_unit.flags & UNIT_ATT) + sim_activate(&net_unit, net_unit.wait); /* start poll */ + for (i = 0; i <= MAX_CONNECTIONS; i++) + serviceDescriptor_reset(i); + return SCPE_OK; +} + +static t_stat net_attach(UNIT *uptr, char *cptr) { + uint32 i, ipa, ipp; + t_stat r = get_ipaddr(cptr, &ipa, &ipp); + if (r != SCPE_OK) return SCPE_ARG; + if (ipa == 0) ipa = 0x7F000001; /* localhost = 127.0.0.1 */ + if (ipp == 0) ipp = 3000; + net_unit.u3 = ipp; + net_unit.u4 = ipa; + net_reset(&net_dev); + for (i = 0; i <= MAX_CONNECTIONS; i++) serviceDescriptor[i].ioSocket = 0; + if (net_unit.flags & UNIT_SERVER) { + net_unit.wait = NET_INIT_POLL_SERVER; + serviceDescriptor[1].masterSocket = sim_master_sock(ipp); + if (serviceDescriptor[1].masterSocket == INVALID_SOCKET) return SCPE_IOERR; + } + else { + net_unit.wait = NET_INIT_POLL_CLIENT; + serviceDescriptor[0].ioSocket = sim_connect_sock(ipa, ipp); + if (serviceDescriptor[0].ioSocket == INVALID_SOCKET) return SCPE_IOERR; + } + net_unit.flags |= UNIT_ATT; + net_unit.filename = (char *) calloc(CBUFSIZE, sizeof (char)); /* alloc name buf */ + if (net_unit.filename == NULL) return SCPE_MEM; + strncpy(net_unit.filename, cptr, CBUFSIZE); /* save name */ + return SCPE_OK; +} + +static t_stat net_detach(UNIT *uptr) { + uint32 i; + if (!(net_unit.flags & UNIT_ATT)) return SCPE_OK; /* if not attached simply return */ + if (net_unit.flags & UNIT_SERVER) + sim_close_sock(serviceDescriptor[1].masterSocket, TRUE); + for (i = 0; i <= MAX_CONNECTIONS; i++) + if (serviceDescriptor[i].ioSocket) + sim_close_sock(serviceDescriptor[i].ioSocket, FALSE); + free(net_unit.filename); /* free port string */ + net_unit.filename = NULL; + net_unit.flags &= ~UNIT_ATT; /* not attached */ + return SCPE_OK; +} + +/* cannot use sim_check_conn to check whether read will return an error */ +static t_stat net_svc(UNIT *uptr) { + int32 i, j, k, r; + SOCKET s; + static char svcBuffer[BUFFER_LENGTH]; + if (net_unit.flags & UNIT_ATT) { + sim_activate(&net_unit, net_unit.wait); /* continue poll */ + if (net_unit.flags & UNIT_SERVER) { + for (i = 1; i <= MAX_CONNECTIONS; i++) + if (serviceDescriptor[i].ioSocket == 0) { + s = sim_accept_conn(serviceDescriptor[1].masterSocket, NULL); + if (s != INVALID_SOCKET) { + serviceDescriptor[i].ioSocket = s; +#ifdef DEBUG_NETWORK + printf("Accepted connection %i with socket %i.\n\r", i, s); +#endif + } + } + } + else if (serviceDescriptor[0].ioSocket == 0) { + serviceDescriptor[0].ioSocket = sim_connect_sock(net_unit.u4, net_unit.u3); + if (serviceDescriptor[0].ioSocket == INVALID_SOCKET) return SCPE_IOERR; + printf("\rWaiting for server ... Type g (possibly twice) when ready\n\r"); + return SCPE_STOP; + } + for (i = 0; i <= MAX_CONNECTIONS; i++) + if (serviceDescriptor[i].ioSocket) { + if (serviceDescriptor[i].inputSize < BUFFER_LENGTH) { /* there is space left in inputBuffer */ + r = sim_read_sock(serviceDescriptor[i].ioSocket, svcBuffer, + BUFFER_LENGTH - serviceDescriptor[i].inputSize); + if (r == -1) { +#ifdef DEBUG_NETWORK + printf("Drop connection %i with socket %i.\n\r", i, serviceDescriptor[i].ioSocket); +#endif + sim_close_sock(serviceDescriptor[i].ioSocket, FALSE); + serviceDescriptor[i].ioSocket = 0; + serviceDescriptor_reset(i); + continue; + } + else { + for (j = 0; j < r; j++) { + serviceDescriptor[i].inputBuffer[serviceDescriptor[i].inputPosWrite++] = svcBuffer[j]; + if (serviceDescriptor[i].inputPosWrite == BUFFER_LENGTH) + serviceDescriptor[i].inputPosWrite = 0; + } + serviceDescriptor[i].inputSize += r; + } + } + if (serviceDescriptor[i].outputSize > 0) { /* there is something to write in outputBuffer */ + k = serviceDescriptor[i].outputPosRead; + for (j = 0; j < serviceDescriptor[i].outputSize; j++) { + svcBuffer[j] = serviceDescriptor[i].outputBuffer[k++]; + if (k == BUFFER_LENGTH) k = 0; + } + r = sim_write_sock(serviceDescriptor[i].ioSocket, svcBuffer, serviceDescriptor[i].outputSize); + if (r >= 0) { + serviceDescriptor[i].outputSize -= r; + serviceDescriptor[i].outputPosRead += r; + if (serviceDescriptor[i].outputPosRead >= BUFFER_LENGTH) + serviceDescriptor[i].outputPosRead -= BUFFER_LENGTH; + } + else printf("write %i\r\n", r); + } + } + } + return SCPE_OK; +} + +int32 netStatus(const int32 port, const int32 io, const int32 data) { + uint32 i; + net_svc(&net_unit); + if (io == 0) { /* IN */ + for (i = 0; i <= MAX_CONNECTIONS; i++) + if (serviceDescriptor[i].Z80StatusPort == port) + return (serviceDescriptor[i].inputSize > 0 ? 1 : 0) | + (serviceDescriptor[i].outputSize < BUFFER_LENGTH ? 2 : 0); + } + return 0; +} + +int32 netData(const int32 port, const int32 io, const int32 data) { + uint32 i; + char result; + net_svc(&net_unit); + for (i = 0; i <= MAX_CONNECTIONS; i++) + if (serviceDescriptor[i].Z80DataPort == port) + if (io == 0) { /* IN */ + if (serviceDescriptor[i].inputSize == 0) { + printf("re-read from %i\r\n", port); + result = serviceDescriptor[i].inputBuffer[serviceDescriptor[i].inputPosRead > 0 ? + serviceDescriptor[i].inputPosRead - 1 : BUFFER_LENGTH - 1]; + } + else { + result = serviceDescriptor[i].inputBuffer[serviceDescriptor[i].inputPosRead++]; + if (serviceDescriptor[i].inputPosRead == BUFFER_LENGTH) + serviceDescriptor[i].inputPosRead = 0; + serviceDescriptor[i].inputSize--; + } +#ifdef DEBUG_NETWORK + printf(" IN(%i)=%03xh (%c)\r\n", port, (result & 0xff), + (32 <= (result & 0xff)) && ((result & 0xff) <= 127) ? (result & 0xff) : '?'); +#endif + return result; + } + else { /* OUT */ + if (serviceDescriptor[i].outputSize == BUFFER_LENGTH) { + printf("over-write %i to %i\r\n", data, port); + serviceDescriptor[i].outputBuffer[serviceDescriptor[i].outputPosWrite > 0 ? + serviceDescriptor[i].outputPosWrite - 1 : BUFFER_LENGTH - 1] = data; + } + else { + serviceDescriptor[i].outputBuffer[serviceDescriptor[i].outputPosWrite++] = data; + if (serviceDescriptor[i].outputPosWrite== BUFFER_LENGTH) + serviceDescriptor[i].outputPosWrite = 0; + serviceDescriptor[i].outputSize++; + } +#ifdef DEBUG_NETWORK + printf("OUT(%i)=%03xh (%c)\r\n", port, data, (32 <= data) && (data <= 127) ? data : '?'); +#endif + return 0; + } + return 0; +} diff --git a/GRI/gri_stddev.c b/GRI/gri_stddev.c index a6c07474..493a1713 100644 --- a/GRI/gri_stddev.c +++ b/GRI/gri_stddev.c @@ -1,6 +1,6 @@ /* gri_stddev.c: GRI-909 standard devices - Copyright (c) 2001-2005, Robert M Supnik + Copyright (c) 2001-2006, 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,6 +29,7 @@ hsp S42-006 high speed punch rtc real time clock + 30-Sep-06 RMS Fixed handling of non-printable characters in KSR mode 22-Nov-05 RMS Revised for new terminal processing routines 29-Dec-03 RMS Added support for console backpressure 25-Apr-03 RMS Revised for extended file support @@ -254,7 +255,7 @@ t_stat tto_svc (UNIT *uptr) int32 c; t_stat r; -c = sim_tt_outcvt (uptr->buf, TT_GET_MODE (uptr->flags)); +c = sim_tt_outcvt (uptr->buf, TT_GET_MODE (uptr->flags) | TTUF_KSR); if (c >= 0) { if ((r = sim_putchar_s (c)) != SCPE_OK) { /* output; error? */ sim_activate (uptr, uptr->wait); /* try again */ diff --git a/H316/h316_dp.c b/H316/h316_dp.c index a00950df..f90ceeb8 100644 --- a/H316/h316_dp.c +++ b/H316/h316_dp.c @@ -952,7 +952,7 @@ inp = (int32) get_uint (cptr, 10, 2048, &r); if (r != SCPE_OK) return r; if (inp == 0) return SCPE_ARG; finp = (float) inp; -if (sim_switches & SWMASK ('R')) { /* format records? */ +if (sim_switches & SWMASK ('R')) { /* format records? */ nr = inp; nw = (int32) ((dp_tab[dp_ctype].wrds / (finp + ((finp - 1.0) / 20.0))) - REC_OVHD_WRDS); if (nw <= 0) return SCPE_ARG; diff --git a/H316/h316_stddev.c b/H316/h316_stddev.c index 89985214..8d1644b4 100644 --- a/H316/h316_stddev.c +++ b/H316/h316_stddev.c @@ -28,6 +28,7 @@ tty 316/516-33 teleprinter clk/options 316/516-12 real time clocks/internal options + 30-Sep-06 RMS Fixed handling of non-printable characters in KSR mode 03-Apr-06 RMS Fixed bugs in punch state handling (from Theo Engel) 22-Nov-05 RMS Revised for new terminal processing routines 05-Feb-05 RMS Fixed bug in OCP '0001 (found by Philipp Hachtmann) @@ -688,7 +689,7 @@ t_stat tto_write (int32 c) { UNIT *tuptr = &tty_unit[TTO]; -c = sim_tt_outcvt (c, TT_GET_MODE (tuptr->flags)); +c = sim_tt_outcvt (c, TT_GET_MODE (tuptr->flags) | TTUF_KSR); tuptr->pos = tuptr->pos + 1; if (c >= 0) return sim_putchar_s (c); else return SCPE_OK; diff --git a/HP2100/hp2100_cpu.c b/HP2100/hp2100_cpu.c index 5695b5d6..50a9d122 100644 --- a/HP2100/hp2100_cpu.c +++ b/HP2100/hp2100_cpu.c @@ -1,6 +1,6 @@ -/* hp2100_cpu.c: HP 2100 CPU simulator +/* hp2100_cpu.c: HP 21xx CPU simulator - Copyright (c) 1993-2005, Robert M. Supnik + Copyright (c) 1993-2007, 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,10 +23,29 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - CPU 2116A/2100A/21MX-M/21MX-E central processing unit - MP 12892B memory protect - DMA0,DMA1 12895A/12897B direct memory access/dual channel port controller + CPU 2114C/2115A/2116C/2100A/1000-M/E/F central processing unit + MP 12581A/12892B memory protect + DMA0,DMA1 12607B/12578A/12895A direct memory access controller + DCPC0,DCPC1 12897B dual channel port controller + 11-Jan-07 JDB Added 12578A DMA byte packing + 28-Dec-06 JDB CLC 0 now sends CRS instead of CLC to devices + 26-Dec-06 JDB Fixed improper IRQ deferral for 21xx CPUs + Fixed improper interrupt servicing in resolve + 21-Dec-06 JDB Added 21xx loader enable/disable support + 16-Dec-06 JDB Added 2114 and 2115 CPU options. + Added support for 12607B (2114) and 12578A (2115/6) DMA + 01-Dec-06 JDB Added 1000-F CPU option (requires HAVE_INT64) + SHOW CPU displays 1000-M/E instead of 21MX-M/E + 16-Oct-06 JDB Moved ReadF to hp2100_cpu1.c + 12-Oct-06 JDB Fixed INDMAX off-by-one error in resolve + 26-Sep-06 JDB Added iotrap parameter to UIG dispatchers for RTE microcode + 12-Sep-06 JDB iogrp returns NOTE_IOG to recalc interrupts + resolve returns NOTE_INDINT to service held-off interrupt + 16-Aug-06 JDB Added support for future microcode options, future F-Series + 09-Aug-06 JDB Added double integer microcode, 1000-M/E synonyms + Enhanced CPU option validity checking + Added DCPC as a synonym for DMA for 21MX simulations 26-Dec-05 JDB Improved reporting in dev_conflict 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) 21-Jan-05 JDB Reorganized CPU option flags @@ -98,10 +117,15 @@ 15-Oct-00 RMS Added dynamic device number support References: - - 21MX M-Series Computer, HP 2108B and HP 2112B, Operating and Reference Manual - (02108-90037, Apr-1979) + - 2100A Computer Reference Manual (02100-90001, Dec-1971) + - HP 1000 M/E/F-Series Computers Technical Reference Handbook + (5955-0282, Mar-1980) - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation (92851-90001, Mar-1981) + - 12607A Direct Memory Access Operating and Service Manual + (12607-90002, Jan-1970) + - 12578A/12578A-01 Direct Memory Access Operating and Service Manual + (12578-9001, Mar-1972) The register state for the HP 2116 CPU is: @@ -125,7 +149,7 @@ YR<15:0> Y register dms_sr<15:0> dynamic memory system status register dms_vr<15:0> dynamic memory system violation register - + The original HP 2116 has four instruction formats: memory reference, shift, alter/skip, and I/O. The HP 2100 added extended memory reference and extended arithmetic. The HP21MX added extended byte, bit, and word @@ -293,7 +317,7 @@ device controls as bit array dev_ctl[2][31..0] device service requests as bit array dev_srq[3][31..0] - The HP 2100 interrupt structure is based on flag, flag buffer,. + The HP 2100 interrupt structure is based on flag, flag buffer, and control. If a device flag is set, the flag buffer is set, the control bit is set, and the device is the highest priority on the interrupt chain, it requests an interrupt. When the @@ -307,11 +331,14 @@ devices don't need to track command separately from control. Service requests are used to trigger the DMA service logic. - + 3. Non-existent memory. On the HP 2100, reads to non-existent memory return zero, 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. + Thus, only writes need be checked against memory size. + + On the 21xx machines, doing SET CPU LOADERDISABLE decreases available + memory size by 64 words. 4. Adding I/O devices. These modules must be modified: @@ -327,12 +354,23 @@ instruction, the interrupt is taken at the appropriate point; but there is no testing for new interrupts during execution (that is, the event timer is not called). + + 6. Interrupt deferral. At instruction fetch time, a pending interrupt + request may be deferred if the previous instruction was a JMP indirect, + JSB indirect, STC, CLC, STF, CLF, SFS (1000 only), or SFC (1000 only), or + was executing from an interrupt trap cell. If the CPU is a 1000, then the + request is always deferred until after the current instruction completes. + If the CPU is a 21xx, then the request is deferred unless the current + instruction is an MRG instruction other than JMP or JMP,I or JSB,I. Note + that for the 21xx, SFS and SFC are not included in the deferral criteria. */ #include "hp2100_defs.h" #include #include "hp2100_cpu.h" +/* Memory protect constants */ + #define UNIT_V_MP_JSB (UNIT_V_UF + 0) /* MP jumper W5 out */ #define UNIT_V_MP_INT (UNIT_V_UF + 1) /* MP jumper W6 out */ #define UNIT_V_MP_SEL1 (UNIT_V_UF + 2) /* MP jumper W7 out */ @@ -340,16 +378,6 @@ #define UNIT_MP_INT (1 << UNIT_V_MP_INT) #define UNIT_MP_SEL1 (1 << UNIT_V_MP_SEL1) -#define MOD_211X (1 << TYPE_211X) -#define MOD_2100 (1 << TYPE_2100) -#define MOD_21MX (1 << TYPE_21MX) -#define MOD_CURRENT (1 << CPU_TYPE) - -#define UNIT_SYSTEM (UNIT_CPU_MASK | UNIT_OPTS) -#define UNIT_SYS_2116 (UNIT_2116) -#define UNIT_SYS_2100 (UNIT_2100 | UNIT_EAU) -#define UNIT_SYS_21MX_M (UNIT_21MX_M | UNIT_EAU | UNIT_FP | UNIT_DMS) -#define UNIT_SYS_21MX_E (UNIT_21MX_E | UNIT_EAU | UNIT_FP | UNIT_DMS) #define ABORT(val) longjmp (save_env, (val)) @@ -365,6 +393,7 @@ uint16 ABREG[2]; /* during execution */ uint32 PC = 0; /* P register */ uint32 SR = 0; /* S register */ uint32 MR = 0; /* M register */ +uint32 saved_MR = 0; /* between executions */ uint32 TR = 0; /* T register */ uint32 XR = 0; /* X register */ uint32 YR = 0; /* Y register */ @@ -393,27 +422,63 @@ uint32 iop_sp = 0; /* iop stack */ uint32 ind_max = 16; /* iadr nest limit */ uint32 stop_inst = 1; /* stop on ill inst */ uint32 stop_dev = 0; /* stop on ill dev */ +uint32 fwanxm = 0; /* first word addr of nx mem */ uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ uint32 pcq_p = 0; /* PC queue ptr */ REG *pcq_r = NULL; /* PC queue reg ptr */ jmp_buf save_env; /* abort handler */ -struct opt_table { /* options table */ - int32 optf; - int32 cpuf; +/* Table of CPU features by model. + + Fields: + - typ: standard features plus typically configured options. + - opt: complete list of optional features. + - maxmem: maximum configurable memory in 16-bit words. + + Features in the "typical" list are enabled when the CPU model is selected. + If a feature appears in the "typical" list but NOT in the "optional" list, + then it is standard equipment and cannot be disabled. If a feature appears + in the "optional" list, then it may be enabled or disabled as desired by the + user. +*/ + +struct FEATURE_TABLE { /* CPU model feature table: */ + uint32 typ; /* - typical features */ + uint32 opt; /* - optional features */ + uint32 maxmem; /* - maximum memory */ }; -static struct opt_table opt_val[] = { - { UNIT_EAU, MOD_211X }, - { UNIT_FP, MOD_2100 }, - { UNIT_DMS, MOD_21MX }, - { UNIT_IOP, MOD_2100 | MOD_21MX }, - { UNIT_FFP, MOD_2100 | MOD_21MX }, - { TYPE_211X, MOD_211X | MOD_2100 | MOD_21MX }, - { TYPE_2100, MOD_211X | MOD_2100 | MOD_21MX }, - { TYPE_21MX, MOD_211X | MOD_2100 | MOD_21MX }, - { 0, 0 } - }; +static struct FEATURE_TABLE cpu_features[] = { /* features in UNIT_xxxx order*/ + { UNIT_DMA | UNIT_MP, /* UNIT_2116 */ + UNIT_PFAIL | UNIT_DMA | UNIT_MP | UNIT_EAU, + 32768 }, + { UNIT_DMA, /* UNIT_2115 */ + UNIT_PFAIL | UNIT_DMA | UNIT_EAU, + 8192 }, + { UNIT_DMA, /* UNIT_2114 */ + UNIT_PFAIL | UNIT_DMA, + 16384 }, + { 0, 0, 0 }, + { UNIT_PFAIL | UNIT_MP | UNIT_DMA | UNIT_EAU, /* UNIT_2100 */ + UNIT_DMA | UNIT_FP | UNIT_IOP | UNIT_FFP, + 32768 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { UNIT_MP | UNIT_DMA | UNIT_EAU | UNIT_FP | UNIT_DMS, /* UNIT_1000_M */ + UNIT_PFAIL | UNIT_DMA | UNIT_MP | UNIT_DMS | + UNIT_IOP | UNIT_FFP | UNIT_DBI | UNIT_DS, + 1048576 }, + { UNIT_MP | UNIT_DMA | UNIT_EAU | UNIT_FP | UNIT_DMS, /* UNIT_1000_E */ + UNIT_PFAIL | UNIT_DMA | UNIT_MP | UNIT_DMS | + UNIT_IOP | UNIT_FFP | UNIT_DBI | UNIT_DS | UNIT_EMA_VMA, + 1048576 }, + { UNIT_MP | UNIT_DMA | UNIT_EAU | UNIT_FP | /* UNIT_1000_F */ + UNIT_FFP | UNIT_DBI | UNIT_DMS, + UNIT_PFAIL | UNIT_DMA | UNIT_MP | + UNIT_IOP | UNIT_DS | UNIT_SIGNAL | UNIT_EMA_VMA, + 1048576 } + }; extern int32 sim_interval; extern int32 sim_int_char; @@ -444,14 +509,19 @@ t_stat cpu_boot (int32 unitno, DEVICE *dptr); t_stat mp_reset (DEVICE *dptr); t_stat dma0_reset (DEVICE *dptr); t_stat dma1_reset (DEVICE *dptr); -t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_set_opt (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_set_size (UNIT *uptr, int32 new_size, char *cptr, void *desc); +t_stat cpu_set_model (UNIT *uptr, int32 new_model, char *cptr, void *desc); +t_stat cpu_show_model (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat cpu_set_opt (UNIT *uptr, int32 option, char *cptr, void *desc); +t_stat cpu_clr_opt (UNIT *uptr, int32 option, char *cptr, void *desc); +t_stat cpu_set_ldr (UNIT *uptr, int32 enable, char *cptr, void *desc); t_bool dev_conflict (void); void hp_post_cmd (t_bool from_scp); extern t_stat cpu_eau (uint32 IR, uint32 intrq); -extern t_stat cpu_uig_0 (uint32 IR, uint32 intrq); -extern t_stat cpu_uig_1 (uint32 IR, uint32 intrq); +extern t_stat cpu_uig_0 (uint32 IR, uint32 intrq, uint32 iotrap); +extern t_stat cpu_uig_1 (uint32 IR, uint32 intrq, uint32 iotrap); + extern int32 clk_delay (int32 flg); extern void (*sim_vm_post) (t_bool from_scp); @@ -463,7 +533,7 @@ extern void (*sim_vm_post) (t_bool from_scp); cpu_mod CPU modifiers list */ -UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, VASIZE) }; +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, 0) }; REG cpu_reg[] = { { ORDATA (P, PC, 15) }, @@ -488,6 +558,7 @@ REG cpu_reg[] = { { FLDATA (STOP_INST, stop_inst, 0) }, { FLDATA (STOP_DEV, stop_dev, 1) }, { DRDATA (INDMAX, ind_max, 16), REG_NZ + PV_LEFT }, + { ORDATA (FWANXM, fwanxm, 32), REG_HRO }, { BRDATA (PCQ, pcq, 8, 15, PCQ_SIZE), REG_RO+REG_CIRC }, { ORDATA (PCQP, pcq_p, 6), REG_HRO }, { ORDATA (WRU, sim_int_char, 8), REG_HRO }, @@ -506,50 +577,86 @@ REG cpu_reg[] = { { NULL } }; +/* CPU modifier table. + + The 21MX monikers are deprecated in favor of the 1000 designations. See the + "HP 1000 Series Naming History" on the back inside cover of the Technical + Reference Handbook. */ + MTAB cpu_mod[] = { - { UNIT_SYSTEM, UNIT_SYS_2116, NULL, "2116", &cpu_set_opt, NULL, - (void *) TYPE_211X }, - { UNIT_SYSTEM, UNIT_SYS_2100, NULL, "2100", &cpu_set_opt, NULL, - (void *) TYPE_2100 }, - { UNIT_SYSTEM, UNIT_SYS_21MX_E, NULL, "21MX-E", &cpu_set_opt, NULL, - (void *) TYPE_21MX }, - { UNIT_SYSTEM, UNIT_SYS_21MX_M, NULL, "21MX-M", &cpu_set_opt, NULL, - (void *) TYPE_21MX }, + { UNIT_MODEL_MASK, UNIT_2116, "", "2116", &cpu_set_model, &cpu_show_model, "2116" }, + { UNIT_MODEL_MASK, UNIT_2115, "", "2115", &cpu_set_model, &cpu_show_model, "2115" }, + { UNIT_MODEL_MASK, UNIT_2114, "", "2114", &cpu_set_model, &cpu_show_model, "2114" }, + { UNIT_MODEL_MASK, UNIT_2100, "", "2100", &cpu_set_model, &cpu_show_model, "2100" }, + { UNIT_MODEL_MASK, UNIT_1000_E, "", "1000-E", &cpu_set_model, &cpu_show_model, "1000-E" }, + { UNIT_MODEL_MASK, UNIT_1000_E, NULL, "21MX-E", &cpu_set_model, &cpu_show_model, "1000-E" }, + { UNIT_MODEL_MASK, UNIT_1000_M, "", "1000-M", &cpu_set_model, &cpu_show_model, "1000-M" }, + { UNIT_MODEL_MASK, UNIT_1000_M, NULL, "21MX-M", &cpu_set_model, &cpu_show_model, "1000-M" }, - { UNIT_CPU_MASK, UNIT_2116, "2116", NULL, NULL }, - { UNIT_CPU_MASK, UNIT_2100, "2100", NULL, NULL }, - { UNIT_CPU_MASK, UNIT_21MX_E, "21MX-E", NULL, NULL }, - { UNIT_CPU_MASK, UNIT_21MX_M, "21MX-M", NULL, NULL }, +#if defined (HAVE_INT64) + { UNIT_MODEL_MASK, UNIT_1000_F, "", "1000-F", &cpu_set_model, &cpu_show_model, "1000-F" }, +#endif - { UNIT_EAU, UNIT_EAU, "EAU", "EAU", &cpu_set_opt, NULL, - (void *) UNIT_EAU }, - { UNIT_EAU, 0, "no EAU", "NOEAU", &cpu_set_opt, NULL, - (void *) UNIT_EAU }, - { UNIT_FP, UNIT_FP, "FP", "FP", &cpu_set_opt, NULL, - (void *) UNIT_FP }, - { UNIT_FP, 0, "no FP", "NOFP", &cpu_set_opt, NULL, - (void *) UNIT_FP }, - { UNIT_IOP, UNIT_IOP, "IOP", "IOP", &cpu_set_opt, NULL, - (void *) UNIT_IOP }, - { UNIT_IOP, 0, "no IOP", "NOIOP", &cpu_set_opt, NULL, - (void *) UNIT_IOP }, - { UNIT_DMS, UNIT_DMS, "DMS", "DMS", &cpu_set_opt, NULL, - (void *) UNIT_DMS }, - { UNIT_DMS, 0, "no DMS", "NODMS", &cpu_set_opt, NULL, - (void *) UNIT_DMS }, - { UNIT_FFP, UNIT_FFP, "FFP", "FFP", &cpu_set_opt, NULL, - (void *) UNIT_FFP }, - { UNIT_FFP, 0, "no FFP", "NOFFP", &cpu_set_opt, NULL, - (void *) UNIT_FFP }, - { MTAB_XTD | MTAB_VDV, 4096, NULL, "4K", &cpu_set_size }, - { MTAB_XTD | MTAB_VDV, 8192, NULL, "8K", &cpu_set_size }, - { MTAB_XTD | MTAB_VDV, 16384, NULL, "16K", &cpu_set_size }, - { MTAB_XTD | MTAB_VDV, 32768, NULL, "32K", &cpu_set_size }, - { MTAB_XTD | MTAB_VDV, 65536, NULL, "64K", &cpu_set_size }, - { MTAB_XTD | MTAB_VDV, 131072, NULL, "128K", &cpu_set_size }, - { MTAB_XTD | MTAB_VDV, 262144, NULL, "256K", &cpu_set_size }, - { MTAB_XTD | MTAB_VDV, 524288, NULL, "512K", &cpu_set_size }, - { MTAB_XTD | MTAB_VDV, 1048576, NULL, "1024K", &cpu_set_size }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "LOADERENABLE", &cpu_set_ldr, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "LOADERDISABLE", &cpu_set_ldr, NULL, NULL }, + + { UNIT_EAU, UNIT_EAU, "EAU", "EAU", &cpu_set_opt, NULL, NULL }, + { UNIT_EAU, 0, "no EAU", NULL, NULL, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, UNIT_EAU, NULL, "NOEAU", &cpu_clr_opt, NULL, NULL }, + + { UNIT_FP, UNIT_FP, "FP", "FP", &cpu_set_opt, NULL, NULL }, + { UNIT_FP, 0, "no FP", NULL, NULL, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, UNIT_FP, NULL, "NOFP", &cpu_clr_opt, NULL, NULL }, + + { UNIT_IOP, UNIT_IOP, "IOP", "IOP", &cpu_set_opt, NULL, NULL }, + { UNIT_IOP, 0, "no IOP", NULL, NULL, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, UNIT_IOP, NULL, "NOIOP", &cpu_clr_opt, NULL, NULL }, + + { UNIT_DMS, UNIT_DMS, "DMS", "DMS", &cpu_set_opt, NULL, NULL }, + { UNIT_DMS, 0, "no DMS", NULL, NULL, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, UNIT_DMS, NULL, "NODMS", &cpu_clr_opt, NULL, NULL }, + + { UNIT_FFP, UNIT_FFP, "FFP", "FFP", &cpu_set_opt, NULL, NULL }, + { UNIT_FFP, 0, "no FFP", NULL, NULL, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, UNIT_FFP, NULL, "NOFFP", &cpu_clr_opt, NULL, NULL }, + + { UNIT_DBI, UNIT_DBI, "DBI", "DBI", &cpu_set_opt, NULL, NULL }, + { UNIT_DBI, 0, "no DBI", NULL, NULL, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, UNIT_DBI, NULL, "NODBI", &cpu_clr_opt, NULL, NULL }, + +/* Future microcode support. + { UNIT_EMA_VMA, UNIT_EMA, "EMA", "EMA", &cpu_set_opt, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, UNIT_EMA, NULL, "NOEMA", &cpu_clr_opt, NULL, NULL }, + + { UNIT_EMA_VMA, UNIT_VMAOS, "VMA", "VMA", &cpu_set_opt, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, UNIT_VMAOS, NULL, "NOVMA", &cpu_clr_opt, NULL, NULL }, + + { UNIT_EMA_VMA, 0, "no EMA/VMA", NULL, &cpu_set_opt, NULL, NULL }, + + { UNIT_VIS, UNIT_VIS, "VIS", "VIS", &cpu_set_opt, NULL, NULL }, + { UNIT_VIS, 0, "no VIS", NULL, NULL, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, UNIT_VIS, NULL, "NOVIS", &cpu_clr_opt, NULL, NULL }, + + { UNIT_DS, UNIT_DS, "DS", "DS", &cpu_set_opt, NULL, NULL }, + { UNIT_DS, 0, "no DS", NULL, NULL, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, UNIT_DS, NULL, "NODS", &cpu_clr_opt, NULL, NULL }, + + { UNIT_SIGNAL, UNIT_SIGNAL,"SIGNAL", "SIGNAL", &cpu_set_opt, NULL, NULL }, + { UNIT_SIGNAL, 0, "no SIGNAL", NULL, NULL, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, UNIT_SIGNAL, NULL, "NOSIGNAL", &cpu_clr_opt, NULL, NULL }, +*/ + + { MTAB_XTD | MTAB_VDV, 4096, NULL, "4K", &cpu_set_size, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 8192, NULL, "8K", &cpu_set_size, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 12288, NULL, "12K", &cpu_set_size, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 16384, NULL, "16K", &cpu_set_size, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 24576, NULL, "24K", &cpu_set_size, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 32768, NULL, "32K", &cpu_set_size, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 65536, NULL, "64K", &cpu_set_size, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 131072, NULL, "128K", &cpu_set_size, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 262144, NULL, "256K", &cpu_set_size, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 524288, NULL, "512K", &cpu_set_size, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 1048576, NULL, "1024K", &cpu_set_size, NULL, NULL }, { 0 } }; @@ -616,6 +723,9 @@ REG dma0_reg[] = { { ORDATA (CW1, dmac[0].cw1, 16) }, { ORDATA (CW2, dmac[0].cw2, 16) }, { ORDATA (CW3, dmac[0].cw3, 16) }, + { DRDATA (LATENCY, dmac[0].latency, 8) }, + { FLDATA (BYTE, dmac[0].packer, 31) }, + { ORDATA (PACKER, dmac[0].packer, 8) }, { NULL } }; @@ -638,6 +748,9 @@ REG dma1_reg[] = { { ORDATA (CW1, dmac[1].cw1, 16) }, { ORDATA (CW2, dmac[1].cw2, 16) }, { ORDATA (CW3, dmac[1].cw3, 16) }, + { DRDATA (LATENCY, dmac[1].latency, 8) }, + { FLDATA (BYTE, dmac[1].packer, 31) }, + { ORDATA (PACKER, dmac[1].packer, 8) }, { NULL } }; @@ -649,9 +762,9 @@ DEVICE dma1_dev = { NULL, DEV_DISABLE }; -/* Interrupt defer table */ +/* Interrupt defer table (1000 version) */ -static const int32 defer_tab[] = { 0, 1, 1, 1, 0, 0, 0, 1 }; +static int32 defer_tab[] = { 0, 1, 1, 1, 0, 0, 0, 1 }; /* Device dispatch table */ @@ -730,6 +843,13 @@ for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru dev */ } sim_rtc_init (clk_delay (0)); /* recalibrate clock */ +/* Configure interrupt deferral table */ + +if (UNIT_CPU_FAMILY == UNIT_FAMILY_21XX) /* 21xx series? */ + defer_tab[ioSFC] = defer_tab[ioSFS] = 0; /* SFC/S doesn't defer */ +else /* 1000 series */ + defer_tab[ioSFC] = defer_tab[ioSFS] = 1; /* SFC/S does defer */ + /* Abort handling If an abort occurs in memory protection, the relocation routine @@ -765,6 +885,23 @@ while (reason == 0) { /* loop until halted */ intrq = calc_int (); /* recalc interrupts */ } +/* Interrupt deferral rules differ on the 21xx vs. the 1000. The 1000 always + defers until the completion of the instruction following a deferring + instruction. The 21xx defers unless the current instruction is an MRG + instruction other than JMP or JMP,I or JSB,I. See the "Set Phase Logic + Flowchart" in the 2100A Computer Reference Manual for details. +*/ + + if (intrq && /* interrupt pending? */ + ion_defer && /* deferring instruction? */ + (UNIT_CPU_FAMILY == UNIT_FAMILY_21XX)) { /* 21xx series? */ + IR = ReadW (PC); /* prefetch next instr */ + if (((IR & 0070000) != 0000000) && /* MRG instruction? */ + ((IR & 0174000) != 0114000) && /* JSB,I? */ + ((IR & 0074000) != 0024000)) /* JMP or JMP,I? */ + ion_defer = 0; /* no, so clear deferral */ + } + /* (From Dave Bryan) Unlike most other I/O devices, the MP flag flip-flop is cleared automatically when the interrupt is acknowledged and not by a programmed @@ -774,7 +911,8 @@ while (reason == 0) { /* loop until halted */ 92851-90001) says: "When IAK occurs and IRQ5 is asserted, the FLAGBFF is cleared, FLAGFF - clocked off at next T2, and IRQ5 will no longer occur." */ + clocked off at next T2, and IRQ5 will no longer occur." +*/ if (intrq && ((intrq <= PRO) || !ion_defer)) { /* interrupt request? */ iotrap = 1; /* I/O trap cell instr */ @@ -827,7 +965,7 @@ while (reason == 0) { /* loop until halted */ 1 0 0 0 1 0 0 1 double store (decoded as 104400) 1 0 0 0 1 0 1 0 extended instr group 0 (A/B must be set) 1 0 0 0 x 0 1 1 extended instr group 1 (A/B ignored) */ - + absel = (IR & I_AB)? 1: 0; /* get A/B select */ switch ((IR >> 8) & 0377) { /* decode IR<15:8> */ @@ -841,10 +979,12 @@ while (reason == 0) { /* loop until halted */ AR = AR & ReadW (MA); break; - case 0030:case 0031:case 0032:case 0033: - case 0034:case 0035:case 0036:case 0037: case 0230:case 0231:case 0232:case 0233: case 0234:case 0235:case 0236:case 0237: + ion_defer = 1; /* defer if JSB,I */ + + case 0030:case 0031:case 0032:case 0033: + case 0034:case 0035:case 0036:case 0037: if (reason = Ea (IR, &MA, intrq)) break; /* JSB */ if ((mp_unit.flags & UNIT_MP_JSB) && /* MP if W7 (JSB) out */ CTL (PRO) && (MA < mp_fence)) @@ -852,7 +992,6 @@ while (reason == 0) { /* loop until halted */ WriteW (MA, PC); /* store PC */ PCQ_ENTRY; PC = (MA + 1) & VAMASK; /* jump */ - if (IR & I_IA) ion_defer = 1; /* ind? defer intr */ break; case 0040:case 0041:case 0042:case 0043: @@ -863,15 +1002,16 @@ while (reason == 0) { /* loop until halted */ AR = AR ^ ReadW (MA); break; - case 0050:case 0051:case 0052:case 0053: - case 0054:case 0055:case 0056:case 0057: case 0250:case 0251:case 0252:case 0253: case 0254:case 0255:case 0256:case 0257: + ion_defer = 1; /* defer if JMP,I */ + + case 0050:case 0051:case 0052:case 0053: + case 0054:case 0055:case 0056:case 0057: if (reason = Ea (IR, &MA, intrq)) break; /* JMP */ mp_dms_jmp (MA); /* validate jump addr */ PCQ_ENTRY; PC = MA; /* jump */ - if (IR & I_IA) ion_defer = 1; /* ind? defer int */ break; case 0060:case 0061:case 0062:case 0063: @@ -1025,8 +1165,6 @@ while (reason == 0) { /* loop until halted */ case 0204:case 0205:case 0206:case 0207: case 0214:case 0215:case 0216:case 0217: reason = iogrp (IR, iotrap); /* execute instr */ - dmarq = calc_dma (); /* recalc DMA */ - intrq = calc_int (); /* recalc interrupts */ break; /* end if I/O */ /* Extended arithmetic */ @@ -1042,22 +1180,23 @@ while (reason == 0) { /* loop until halted */ /* Extended instructions */ case 0212: /* UIG 0 extension */ - reason = cpu_uig_0 (IR, intrq); /* extended opcode */ - dmarq = calc_dma (); /* recalc DMA masks */ - intrq = calc_int (); /* recalc interrupts */ + reason = cpu_uig_0 (IR, intrq, iotrap); /* extended opcode */ break; case 0203: /* UIG 1 extension */ case 0213: - reason = cpu_uig_1 (IR, intrq); /* extended opcode */ - dmarq = calc_dma (); /* recalc DMA masks */ - intrq = calc_int (); /* recalc interrupts */ + reason = cpu_uig_1 (IR, intrq, iotrap); /* extended opcode */ break; } /* end case IR */ - if (reason == STOP_INDINT) { /* indirect intr? */ + if (reason == NOTE_IOG) { /* I/O instr exec? */ + dmarq = calc_dma (); /* recalc DMA masks */ + intrq = calc_int (); /* recalc interrupts */ + reason = 0; /* continue */ + } + + else if (reason == NOTE_INDINT) { /* intr pend during indir? */ PC = err_PC; /* back out of inst */ - ion_defer = 0; /* clear defer */ reason = 0; /* continue */ } } /* end while */ @@ -1069,9 +1208,12 @@ saved_BR = BR & DMASK; if (iotrap && (reason == STOP_HALT)) MR = intaddr; /* HLT in trap cell? */ else MR = (PC - 1) & VAMASK; /* no, M = P - 1 */ TR = ReadTAB (MR); /* last word fetched */ +saved_MR = MR; /* save for T cmd update */ if ((reason == STOP_RSRV) || (reason == STOP_IODV) || /* instr error? */ (reason == STOP_IND)) PC = err_PC; /* back up PC */ dms_upd_sr (); /* update dms_sr */ +if (reason == STOP_HALT) /* programmed halt? */ + cpu_set_ldr (NULL, FALSE, NULL, NULL); /* disable loader (ignore errors) */ for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru dev */ dibp = (DIB *) dptr->ctxt; /* get DIB */ if (dibp) { /* exist? */ @@ -1087,20 +1229,36 @@ pcq_r->qptr = pcq_p; /* update pc q ptr */ return reason; } -/* Resolve indirect addresses */ +/* Resolve indirect addresses. + + An indirect chain is followed until a direct address is obtained. Under + simulation, a maximum number of indirect levels are allowed (typically 16), + after which the instruction will be aborted. + + If the memory protect feature is present, an indirect counter is used that + allows a pending interrupt to be serviced if more than three levels of + indirection are encountered. If MP jumper W6 ("INT") is out and MP is + enabled, then pending interrupts are serviced immediately. When employing + the indirect counter, the hardware clears a pending interrupt deferral after + the third indirection and aborts the instruction after the fourth. +*/ t_stat resolve (uint32 MA, uint32 *addr, uint32 irq) { uint32 i; +t_bool pending = (irq && !(mp_unit.flags & DEV_DIS)); +t_bool int_enable = ((mp_unit.flags & UNIT_MP_INT) && CTL(PRO)); for (i = 0; (i < ind_max) && (MA & I_IA); i++) { /* resolve multilevel */ - if (irq && /* int req? */ - ((i >= 2) || (mp_unit.flags & UNIT_MP_INT)) && /* ind > 3 or W6 out? */ - !(mp_unit.flags & DEV_DIS)) /* MP installed? */ - return STOP_INDINT; /* break out */ - MA = ReadW (MA & VAMASK); + if (pending) { /* interrupt pending and MP enabled? */ + if ((i == 2) || int_enable) /* 3rd level indirect or INT out? */ + ion_defer = 0; /* reenable interrrupts */ + if ((i > 2) || int_enable) /* 4th or higher or INT out? */ + return NOTE_INDINT; /* break out now */ + } + MA = ReadW (MA & VAMASK); /* follow address chain */ } -if (i >= ind_max) return STOP_IND; /* indirect loop? */ +if (MA & I_IA) return STOP_IND; /* indirect loop? */ *addr = MA; return SCPE_OK; } @@ -1164,7 +1322,7 @@ return t; /* input unchanged */ t_stat iogrp (uint32 ir, uint32 iotrap) { -uint32 dev, sop, iodata, ab; +uint32 dev, sop, iodata, iostat, ab; ab = (ir & I_AB)? 1: 0; /* get A/B select */ dev = ir & I_DEVMASK; /* get device */ @@ -1184,7 +1342,9 @@ if (sop == ioHLT) { /* halt? */ sprintf (&halt_msg[len - 6], "%06o", ir); /* add the halt */ return STOP_HALT; } -return (iodata >> IOT_V_REASON); /* return status */ +iostat = iodata >> IOT_V_REASON; +if (iostat == SCPE_OK) return NOTE_IOG; /* normal status */ +else return iostat; /* abnormal status */ } /* Device dispatch */ @@ -1304,13 +1464,6 @@ else pa = va; return ReadPW (pa); } -uint32 ReadF (uint32 va) -{ -uint32 t = ReadW (va); -uint32 t1 = ReadW ((va + 1) & VAMASK); -return (t << 16) | t1; -} - uint16 ReadIO (uint32 va, uint32 map) { uint32 pa; @@ -1340,7 +1493,8 @@ else return ReadIO (addr, dms_ump); writable, then whether the target is below the MP fence is not checked. [The simulator must] do MP check on all writes after DMS translation and violation checks are done (so, to pass, the page must be writable AND the target must - be above the MP fence). */ + be above the MP fence). +*/ #define MP_TEST(x) (CTL (PRO) && ((x) > 1) && ((x) < mp_fence)) @@ -1519,7 +1673,7 @@ return; void dms_viol (uint32 va, uint32 st) { dms_vr = st | VA_GETPAG (va) | - ((st & (MVI_RPR | MVI_WPR))? MVI_MEB: 0) | /* set MEB */ + ((st & (MVI_RPR | MVI_WPR))? MVI_MEB: 0) | /* set MEB */ (dms_enb? MVI_MEM: 0) | /* set MEM */ (dms_ump? MVI_UMP: 0); /* set UMAP */ if (CTL (PRO)) { /* protected? */ @@ -1544,6 +1698,10 @@ return dms_sr; NOTE: LIx/MIx reads floating I/O bus (0 on all machines). + NOTE: CLC 0 issues CRS to all devices, not CLC. While most cards react + identically to CRS and CLC, some do not, e.g., the 12566B when used as an + I/O diagnostic target. PRESET also issues CRS (with POPIO). + From Dave Bryan: RTE uses the undocumented instruction "SFS 0,C" to both test and turn off the interrupt system. This is confirmed in the "RTE-6/VM Technical Specifications" manual (HP 92084-90015), section 2.3.1 "Process @@ -1559,7 +1717,8 @@ return dms_sr; The major hole in being able to save the complete state is in saving the interrupt system state. In order to do this in both the 21MX and the 21XE the instruction 103300 was used to both test the interrupt system and - turn it off." */ + turn it off." +*/ int32 cpuio (int32 inst, int32 IR, int32 dat) { @@ -1584,12 +1743,9 @@ switch (inst) { /* case on opcode */ break; case ioCTL: /* control */ - if (IR & I_CTL) { /* =CLC 02,03,06..77 */ - devdisp (DMALT0, inst, I_CTL + DMALT0, 0); - devdisp (DMALT1, inst, I_CTL + DMALT1, 0); - for (i = 6; i <= I_DEVMASK; i++) - devdisp (i, inst, I_CTL + i, 0); - } + if (IR & I_CTL) /* CLC 0 sends CRS */ + for (i = 0; i <= I_DEVMASK; i++) /* to all devices */ + devdisp (i, ioCRS, I_CTL + i, 0); /* IR -> "CLC i" for convenience */ break; default: @@ -1600,9 +1756,11 @@ if (IR & I_HC) ion = 0; /* HC option */ return dat; } -/* Device 1 (overflow) I/O routine +/* Device 1 (overflow/S-register) I/O routine - NOTE: The S register is read-only on the 2115/2116. */ + NOTE: The S register is read-only on the 2115/2116. It is read/write on + the 2114, 2100, and 1000. +*/ int32 ovfio (int32 inst, int32 IR, int32 dat) { @@ -1629,7 +1787,9 @@ switch (inst) { /* case on opcode */ break; case ioOTX: /* output */ - if (UNIT_CPU_TYPE != UNIT_TYPE_211X) SR = dat; + if ((UNIT_CPU_MODEL != UNIT_2116) && + (UNIT_CPU_MODEL != UNIT_2115)) + SR = dat; break; default: @@ -1665,7 +1825,8 @@ return dat; From Dave Bryan: Examination of the schematics for the MP card in the engineering documentation shows that the SFS and SFC I/O backplane signals - gate the output of the MEVFF onto the SKF line unconditionally. */ + gate the output of the MEVFF onto the SKF line unconditionally. +*/ int32 proio (int32 inst, int32 IR, int32 dat) { @@ -1692,6 +1853,7 @@ switch (inst) { /* case on opcode */ if (cpu_unit.flags & UNIT_2100) iop_sp = mp_fence; break; + case ioCRS: /* control reset */ case ioCTL: /* control clear/set */ if ((IR & I_CTL) == 0) { /* STC */ setCTL (PRO); @@ -1709,7 +1871,19 @@ if (IR & I_HC) { clrFLG (PRO); } /* HC option */ return dat; } -/* Devices 2,3 (secondary DMA) I/O routine */ +/* Devices 2,3 (secondary DMA) I/O routine. + + Implements control word 2 (memory address) and control word 3 (word count). + + The 12607B (2114) supports 14-bit addresses and 13-bit word counts. + The 12578A (2115/6) supports 15-bit addresses and 14-bit word counts. + The 12895A (2100) and 12897B (1000) support 15-bit addresses and 16-bit word + counts. + + Note: because the I/O bus floats to zero on 211x computers, LIA/MIA (word + count) returns zeros in the unused bit locations, even though the word count + is a negative value. +*/ int32 dmsio (int32 inst, int32 IR, int32 dat) { @@ -1718,19 +1892,29 @@ int32 ch; ch = IR & 1; /* get channel num */ switch (inst) { /* case on opcode */ - case ioMIX: /* merge */ - dat = dat | dmac[ch].cw3; - break; + case ioLIX: /* load remaining word count */ + dat = 0; - case ioLIX: /* load */ - dat = dmac[ch].cw3; + case ioMIX: /* merge */ + if (UNIT_CPU_MODEL == UNIT_2114) /* 2114? */ + dat = dat | (dmac[ch].cw3 & 0017777); /* only 13-bit count */ + else if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* 2115/2116? */ + dat = dat | (dmac[ch].cw3 & 0037777); /* only 14-bit count */ + else + dat = dat | dmac[ch].cw3; /* rest use full value */ break; case ioOTX: /* output */ - if (CTL (DMALT0 + ch)) dmac[ch].cw3 = dat; - else dmac[ch].cw2 = dat; + if (CTL (DMALT0 + ch)) /* word count selected? */ + dmac[ch].cw3 = dat; /* save count */ + else /* memory address selected */ + if (UNIT_CPU_MODEL == UNIT_2114) /* 2114? */ + dmac[ch].cw2 = dat & 0137777; /* 14-bit address */ + else + dmac[ch].cw2 = dat; /* full address stored */ break; + case ioCRS: /* control reset */ case ioCTL: /* control clear/set */ if (IR & I_CTL) { clrCTL (DMALT0 + ch); } /* CLC */ else { setCTL (DMALT0 + ch); } /* STC */ @@ -1745,7 +1929,20 @@ return dat; /* Devices 6,7 (primary DMA) I/O routine - NOTE: LIx/MIx reads floating S-bus (1 on 21MX, 0 on 2116/2100). */ + Implements control word 1 (device address) and DMA control. + + The 12607B (2114) stores only bits 2-0 of the select code and interprets them + as select codes 10-16 (SRQ17 is not decoded). The 12578A (2115/6), 12895A + (2100), and 12897B (1000) support the full 10-77 range of select codes. + + The 12578A supports byte-sized transfers by setting bit 14. Bit 14 is + ignored by all other DMA cards, which support word transfers only. + + NOTE: LIx/MIx reads floating S-bus (1 on 21MX, 0 on 211x/2100). + + NOTE: CRS clears control and command flip-flops, whereas CLC clears only + control. +*/ int32 dmpio (int32 inst, int32 IR, int32 dat) { @@ -1772,17 +1969,33 @@ switch (inst) { /* case on opcode */ case ioLIX: /* load */ dat = 0; + case ioMIX: /* merge */ - if (UNIT_CPU_TYPE == UNIT_TYPE_21MX) dat = DMASK; + if (UNIT_CPU_TYPE == UNIT_TYPE_1000) + dat = DMASK; break; case ioOTX: /* output */ - dmac[ch].cw1 = dat; + if (UNIT_CPU_MODEL == UNIT_2114) /* 12607? */ + dmac[ch].cw1 = (dat & 0137707) | 010; /* mask SC, convert to 10-17 */ + else if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* 12578? */ + dmac[ch].cw1 = dat; /* store full select code, flags */ + else /* 12895, 12897 */ + dmac[ch].cw1 = dat & ~DMA1_PB; /* clip byte-packing flag */ break; + case ioCRS: /* control reset */ + clrCMD (DMA0 + ch); /* clear command flip-flop */ + case ioCTL: /* control */ if (IR & I_CTL) { clrCTL (DMA0 + ch); } /* CLC: cmd unchgd */ else { /* STC */ + if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* slow DMA card? */ + dmac[ch].latency = 1; /* needs startup latency */ + else + dmac[ch].latency = 0; /* DCPC starts immediately */ + + dmac[ch].packer = 0; /* clear packing register */ setCTL (DMA0 + ch); /* set ctl, cmd */ setCMD (DMA0 + ch); } @@ -1798,6 +2011,10 @@ return dat; /* DMA cycle routine + The 12578A card supports byte-packing. If bit 14 in control word 1 is set, + each transfer will involve one read/write from memory and two output/input + operations in order to transfer sequential bytes to/from the device. + The last cycle (word count reaches 0) logic is quite tricky. Input cases: - CLC requested: issue CLC @@ -1813,19 +2030,57 @@ void dma_cycle (uint32 ch, uint32 map) { int32 temp, dev, MA; int32 inp = dmac[ch].cw2 & DMA2_OI; /* input flag */ +int32 byt = dmac[ch].cw1 & DMA1_PB; /* pack bytes flag */ + +if (dmac[ch].latency) { /* start-up latency? */ + dmac[ch].latency = dmac[ch].latency - 1; /* decrease it */ + return; /* that's all this cycle */ + } dev = dmac[ch].cw1 & I_DEVMASK; /* get device */ MA = dmac[ch].cw2 & VAMASK; /* get mem addr */ -if (inp) { /* input? */ + +if (inp) { /* input cycle? */ temp = devdisp (dev, ioLIX, dev, 0); /* do LIA dev */ - WriteIO (MA, temp, map); /* store data */ + + if (byt) { /* byte packing? */ + if (dmac[ch].packer & DMA_OE) { /* second byte? */ + temp = (dmac[ch].packer << 8) | /* merge stored byte */ + (temp & DMASK8); + WriteIO (MA, temp, map); /* store word data */ + } + else /* first byte */ + dmac[ch].packer = (temp & DMASK8); /* save it */ + + dmac[ch].packer = dmac[ch].packer ^ DMA_OE; /* flip odd/even bit */ + } + else /* no byte packing */ + WriteIO (MA, temp, map); /* store word data */ } -else { - temp = ReadIO (MA, map); /* read data */ +else { /* output cycle */ + if (byt) { /* byte packing? */ + if (dmac[ch].packer & DMA_OE) /* second byte? */ + temp = dmac[ch].packer & DMASK8; /* retrieve it */ + + else { /* first byte */ + dmac[ch].packer = ReadIO (MA, map); /* read word data */ + temp = (dmac[ch].packer >> 8) & DMASK8; /* get high byte */ + } + + dmac[ch].packer = dmac[ch].packer ^ DMA_OE; /* flip odd/even bit */ + } + else /* no byte packing */ + temp = ReadIO (MA, map); /* read word data */ + devdisp (dev, ioOTX, dev, temp); /* do OTA dev */ } -dmac[ch].cw2 = (dmac[ch].cw2 & DMA2_OI) | ((dmac[ch].cw2 + 1) & VAMASK); -dmac[ch].cw3 = (dmac[ch].cw3 + 1) & DMASK; /* incr wcount */ + +if ((dmac[ch].packer & DMA_OE) == 0) { /* new byte or no packing? */ + dmac[ch].cw2 = (dmac[ch].cw2 & DMA2_OI) | /* increment address */ + ((dmac[ch].cw2 + 1) & VAMASK); + dmac[ch].cw3 = (dmac[ch].cw3 + 1) & DMASK; /* increment word count */ + } + if (dmac[ch].cw3) { /* more to do? */ if (dmac[ch].cw1 & DMA1_STC) /* if STC flag, */ devdisp (dev, ioCTL, I_HC + dev, 0); /* do STC,C dev */ @@ -1853,8 +2108,9 @@ return; /* Unimplemented device routine - NOTE: For SC < 10, LIx/MIx reads floating S-bus (-1 on 21MX, 0 on 2116/2100). - For SC >= 10, LIx/MIx reads floating I/O bus (0 on all machines). */ + NOTE: For SC < 10, LIx/MIx reads floating S-bus (-1 on 21MX, 0 on 211x/2100). + For SC >= 10, LIx/MIx reads floating I/O bus (0 on all machines). +*/ int32 nulio (int32 inst, int32 IR, int32 dat) { @@ -1871,7 +2127,7 @@ switch (inst) { /* case on opcode */ dat = 0; case ioMIX: /* merge */ - if ((devd < VARDEV) && (UNIT_CPU_TYPE == UNIT_TYPE_21MX)) + if ((devd < VARDEV) && (UNIT_CPU_TYPE == UNIT_TYPE_1000)) dat = DMASK; break; @@ -1900,11 +2156,25 @@ dms_vr = 0; pcq_r = find_reg ("PCQ", NULL, dptr); sim_brk_types = ALL_BKPTS; sim_brk_dflt = SWMASK ('E'); -if (M == NULL) M = calloc (PASIZE, sizeof (uint16)); -if (M == NULL) return SCPE_MEM; + +if (M == NULL) { /* initial call? */ + M = calloc (PASIZE, sizeof (uint16)); /* alloc mem */ + + if (M == NULL) /* alloc fail? */ + return SCPE_MEM; + else { /* do one-time init */ + MEMSIZE = 32768; /* set initial memory size */ + cpu_set_model (NULL, UNIT_2116, NULL, NULL); /* set initial CPU model */ + SR = 001000; /* select PTR boot ROM at SC 10 */ + cpu_boot (0, NULL); /* install loader for 2116 */ + cpu_set_ldr (NULL, FALSE, NULL, NULL); /* disable loader (was enabled) */ + SR = 0; /* clear S */ + sim_vm_post = &hp_post_cmd; /* set cmd post proc */ + } +} + if (pcq_r) pcq_r->qptr = 0; else return SCPE_IERR; -sim_vm_post = &hp_post_cmd; /* set cmd post proc */ return SCPE_OK; } @@ -1922,12 +2192,14 @@ return SCPE_OK; t_stat dma0_reset (DEVICE *tptr) { -hp_enbdis_pair (&dma0_dev, &dma1_dev); /* make pair cons */ +if (UNIT_CPU_MODEL != UNIT_2114) /* 2114 has only one channel */ + hp_enbdis_pair (&dma0_dev, &dma1_dev); /* make pair cons */ clrCMD (DMA0); clrCTL (DMA0); setFLG (DMA0); clrSRQ (DMA0); clrCTL (DMALT0); +dmac[0].latency = dmac[0].packer = 0; if (sim_switches & SWMASK ('P')) /* power up? */ dmac[0].cw1 = dmac[0].cw2 = dmac[0].cw3 = 0; return SCPE_OK; @@ -1935,12 +2207,14 @@ return SCPE_OK; t_stat dma1_reset (DEVICE *tptr) { -hp_enbdis_pair (&dma1_dev, &dma0_dev); /* make pair cons */ +if (UNIT_CPU_MODEL != UNIT_2114) /* 2114 has only one channel */ + hp_enbdis_pair (&dma1_dev, &dma0_dev); /* make pair cons */ clrCMD (DMA1); clrCTL (DMA1); setFLG (DMA1); clrSRQ (DMA1); clrCTL (DMALT1); +dmac[1].latency = dmac[1].packer = 0; if (sim_switches & SWMASK ('P')) /* power up? */ dmac[1].cw1 = dmac[1].cw2 = dmac[1].cw3 = 0; return SCPE_OK; @@ -1973,26 +2247,6 @@ else M[addr] = val & DMASK; return SCPE_OK; } -/* Memory size validation */ - -t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 mc = 0; -uint32 i; - -if ((val <= 0) || (val > PASIZE) || ((val & 07777) != 0) || - ((UNIT_CPU_TYPE != UNIT_TYPE_21MX) && (val > VASIZE))) - return SCPE_ARG; -if (!(sim_switches & SWMASK ('F'))) { /* force truncation? */ - for (i = val; i < MEMSIZE; i++) mc = mc | M[i]; - if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) - return SCPE_INCOMP; - } -MEMSIZE = val; -for (i = MEMSIZE; i < PASIZE; i++) M[i] = 0; -return SCPE_OK; -} - /* Set device number */ t_stat hp_setdev (UNIT *uptr, int32 num, char *cptr, void *desc) @@ -2038,13 +2292,17 @@ else dcp->flags = dcp->flags & ~DEV_DIS; return; } -/* Command post-processor +/* VM command post-processor - Update T register to contents of memory addressed by M register. */ + Update T register to contents of memory addressed by M register + if M register has changed. */ void hp_post_cmd (t_bool from_scp) { -TR = ReadTAB (MR); /* sync T with M */ +if (MR != saved_MR) { /* M changed since last update? */ + saved_MR = MR; + TR = ReadTAB (MR); /* sync T with new M */ + } return; } @@ -2095,43 +2353,264 @@ if (is_conflict) { return is_conflict; } -/* Configuration validation +/* Change CPU memory size. - - Checks that the current CPU type supports the option selected. - - Ensures that FP/FFP and IOP are mutually exclusive if CPU is 2100. - - Disables memory protect if 2116 is selected. - - Enables memory protect if 2100 or 21MX or DMS is selected. - - Enables DMA if 2116 or 2100 or 21MX is selected. - - Memory is trimmed to 32K if 2116 or 2100 is selected. */ + On a 21xx, move the current loader to the top of the new memory size. Then + clear "non-existent memory" so that reads return zero, per spec. -t_bool cpu_set_opt (UNIT *uptr, int32 val, char *cptr, void *desc) + Validation: + - New size <= maximum size for current CPU. + - New size a positive multiple of 4K (progamming error if not). + - If new size < old size, truncation accepted. +*/ + +t_stat cpu_set_size (UNIT *uptr, int32 new_size, char *cptr, void *desc) { -int32 opt = (int32) desc; -int32 i; -uint32 mod; +int32 mc = 0; +uint32 i; +uint32 model = CPU_MODEL_INDEX; /* current CPU model index */ +uint32 old_size = MEMSIZE; /* current memory size */ -mod = MOD_CURRENT; -for (i = 0; opt_val[i].cpuf != 0; i++) { - if ((opt == opt_val[i].optf) && (mod & opt_val[i].cpuf)) { - if (mod == MOD_2100) - if ((opt == UNIT_FP) || (opt == UNIT_FFP)) - uptr->flags = uptr->flags & ~UNIT_IOP; - else if (opt == UNIT_IOP) - uptr->flags = uptr->flags & ~(UNIT_FP | UNIT_FFP); - if (opt == TYPE_211X) - mp_dev.flags = mp_dev.flags | DEV_DIS; - else if ((opt == UNIT_DMS) || (opt == TYPE_2100) || (opt == TYPE_21MX)) - mp_dev.flags = mp_dev.flags & ~DEV_DIS; - if ((opt == TYPE_211X) || (opt == TYPE_2100) || (opt == TYPE_21MX)) { - dma0_dev.flags = dma0_dev.flags & ~DEV_DIS; - dma1_dev.flags = dma1_dev.flags & ~DEV_DIS; - } - if (((opt == TYPE_211X) || (opt == TYPE_2100)) && (MEMSIZE > VASIZE)) - return cpu_set_size (uptr, VASIZE, cptr, desc); - return SCPE_OK; +if ((uint32) new_size > cpu_features[model].maxmem) + return SCPE_NOFNC; /* mem size unsupported */ + +if ((new_size <= 0) || (new_size > PASIZE) || ((new_size & 07777) != 0)) + return SCPE_NXM; /* invalid size (prog err) */ + +if (!(sim_switches & SWMASK ('F'))) { /* force truncation? */ + for (i = new_size; i < MEMSIZE; i++) mc = mc | M[i]; + if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) + return SCPE_INCOMP; + } + +if (UNIT_CPU_FAMILY == UNIT_FAMILY_21XX) { /* 21xx CPU? */ + cpu_set_ldr (uptr, FALSE, NULL, NULL); /* save loader to shadow RAM */ + MEMSIZE = new_size; /* set new memory size */ + fwanxm = MEMSIZE - IBL_LNT; /* reserve memory for loader */ + } +else /* loader unsupported */ + fwanxm = MEMSIZE = new_size; /* set new memory size */ + +for (i = fwanxm; i < old_size; i++) M[i] = 0; /* zero non-existent memory */ +return SCPE_OK; +} + +/* Change CPU models. + + For convenience, MP and DMA are typically enabled if available; they may be + disabled subsequently if desired. Note that the 2114 supports only one DMA + channel (channel 0). All other models support two channels. + + Validation: + - Sets standard equipment and convenience features. + - Changes DMA device name to DCPC if 1000 is selected. + - Enforces maximum memory allowed (doesn't change otherwise). + - Disables loader on 21xx machines. +*/ + +t_stat cpu_set_model (UNIT *uptr, int32 new_model, char *cptr, void *desc) +{ +uint32 old_family = UNIT_CPU_FAMILY; /* current CPU type */ +uint32 new_family = new_model & UNIT_FAMILY_MASK; /* new CPU family */ +uint32 new_index = new_model >> UNIT_V_CPU; /* new CPU model index */ +uint32 new_memsize; +t_stat result; + +cpu_unit.flags = cpu_unit.flags & ~UNIT_OPTS | /* set typical features */ + cpu_features[new_index].typ & UNIT_OPTS; /* mask pseudo-opts */ + + +if (cpu_features[new_index].typ & UNIT_MP) /* MP in typ config? */ + mp_dev.flags = mp_dev.flags & ~DEV_DIS; /* enable it */ +else + mp_dev.flags = mp_dev.flags | DEV_DIS; /* disable it */ + +if (cpu_features[new_index].opt & UNIT_MP) /* MP an option? */ + mp_dev.flags = mp_dev.flags | DEV_DISABLE; /* make it alterable */ +else + mp_dev.flags = mp_dev.flags & ~DEV_DISABLE; /* make it unalterable */ + + +if (cpu_features[new_index].typ & UNIT_DMA) { /* DMA in typ config? */ + dma0_dev.flags = dma0_dev.flags & ~DEV_DIS; /* enable DMA channel 0 */ + + if (new_model == UNIT_2114) /* 2114 has only one channel */ + dma1_dev.flags = dma1_dev.flags | DEV_DIS; /* disable channel 1 */ + else /* all others have two channels */ + dma1_dev.flags = dma1_dev.flags & ~DEV_DIS; /* enable it */ + } +else { + dma0_dev.flags = dma0_dev.flags | DEV_DIS; /* disable channel 0 */ + dma1_dev.flags = dma1_dev.flags | DEV_DIS; /* disable channel 1 */ + } + +if (cpu_features[new_index].opt & UNIT_DMA) { /* DMA an option? */ + dma0_dev.flags = dma0_dev.flags | DEV_DISABLE; /* make it alterable */ + + if (new_model == UNIT_2114) /* 2114 has only one channel */ + dma1_dev.flags = dma1_dev.flags & ~DEV_DISABLE; /* make it unalterable */ + else /* all others have two channels */ + dma1_dev.flags = dma1_dev.flags | DEV_DISABLE; /* make it alterable */ + } +else { + dma0_dev.flags = dma0_dev.flags & ~DEV_DISABLE; /* make it unalterable */ + dma1_dev.flags = dma1_dev.flags & ~DEV_DISABLE; /* make it unalterable */ + } + + +if ((old_family == UNIT_FAMILY_1000) && /* if current family is 1000 */ + (new_family == UNIT_FAMILY_21XX)) { /* and new family is 21xx */ + deassign_device (&dma0_dev); /* delete DCPC names */ + deassign_device (&dma1_dev); + } +else if ((old_family == UNIT_FAMILY_21XX) && /* if current family is 21xx */ + (new_family == UNIT_FAMILY_1000)) { /* and new family is 1000 */ + assign_device (&dma0_dev, "DCPC0"); /* change DMA device name */ + assign_device (&dma1_dev, "DCPC1"); /* to DCPC for familiarity */ + } + +if ((MEMSIZE == 0) || /* current mem size not set? */ + (MEMSIZE > cpu_features[new_index].maxmem)) /* current mem size too large? */ + new_memsize = cpu_features[new_index].maxmem; /* set it to max supported */ +else + new_memsize = MEMSIZE; /* or leave it unchanged */ + +result = cpu_set_size (uptr, new_memsize, NULL, NULL); /* set memory size */ + +if (result == SCPE_OK) /* memory change OK? */ + if (new_family == UNIT_FAMILY_21XX) /* 21xx CPU? */ + fwanxm = MEMSIZE - IBL_LNT; /* reserve memory for loader */ + else + fwanxm = MEMSIZE; /* loader reserved only for 21xx */ + +return result; +} + +/* Display the CPU model and optional loader status. + + Loader status is displayed for 21xx models and suppressed for 1000 models. +*/ + +t_stat cpu_show_model (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fputs ((char *) desc, st); /* write model name */ + +if (UNIT_CPU_FAMILY == UNIT_FAMILY_21XX) /* valid only for 21xx */ + if (fwanxm < MEMSIZE) /* loader area non-existent? */ + fputs (", loader disabled", st); /* yes, so access disabled */ + else + fputs (", loader enabled", st); /* no, so access enabled */ +return SCPE_OK; +} + +/* Set a CPU option. + + Validation: + - Checks that the current CPU model supports the option selected. + - If CPU is 2100, ensures that FP/FFP and IOP are mutually exclusive. + - If CPU is 2100, ensures that FP is enabled if FFP enabled + (FP is required for FFP installation). +*/ + +t_stat cpu_set_opt (UNIT *uptr, int32 option, char *cptr, void *desc) +{ +uint32 model = CPU_MODEL_INDEX; /* current CPU model index */ + +if ((cpu_features[model].opt & option) == 0) /* option supported? */ + return SCPE_NOFNC; /* no */ + +if (UNIT_CPU_TYPE == UNIT_TYPE_2100) { + if ((option == UNIT_FP) || (option == UNIT_FFP)) /* 2100 IOP and FP/FFP options */ + uptr->flags = uptr->flags & ~UNIT_IOP; /* are mutually exclusive */ + else if (option == UNIT_IOP) + uptr->flags = uptr->flags & ~(UNIT_FP | UNIT_FFP); + + if (option == UNIT_FFP) /* 2100 FFP option requires FP */ + uptr->flags = uptr->flags | UNIT_FP; + } + +return SCPE_OK; +} + +/* Clear a CPU option. + + Validation: + - Checks that the current CPU model supports the option selected. + - Clears flag from unit structure (we are processing MTAB_XTD entries). + - If CPU is 2100, ensures that FFP is disabled if FP disabled + (FP is required for FFP installation). +*/ + +t_bool cpu_clr_opt (UNIT *uptr, int32 option, char *cptr, void *desc) +{ +uint32 model = CPU_MODEL_INDEX; /* current CPU model index */ + +if ((cpu_features[model].opt & option) == 0) /* option supported? */ + return SCPE_NOFNC; /* no */ + +uptr->flags = uptr->flags & ~option; /* disable option */ + +if ((UNIT_CPU_TYPE == UNIT_TYPE_2100) && /* disabling 2100 FP? */ + (option == UNIT_FP)) + uptr->flags = uptr->flags & ~UNIT_FFP; /* yes, so disable FFP too */ + +return SCPE_OK; +} + +/* 21xx loader enable/disable function. + + The 21xx CPUs store their initial binary loaders in the last 64 words of + available memory. This memory is protected by a LOADER ENABLE switch on the + front panel. When the switch is off (disabled), main memory effectively ends + 64 locations earlier, i.e., the loader area is treated as non-existent. + Because these are core machines, the loader is retained when system power is + off. + + 1000 CPUs do not have a protected loader feature. Instead, loaders are + stored in PROMs and are copied into main memory for execution by the IBL + switch. + + Under simulation, we keep both a total configured memory size (MEMSIZE) and a + current configured memory size (fwanxm = "first word address of non-existent + memory). When the two are equal, the loader is enabled. When the current + size is less than the total size, the loader is disabled. + + Disabling the loader copies the last 64 words to a shadow array, zeros the + corresponding memory, and decreases the last word of addressable memory by + 64. Enabling the loader reverses this process. + + Disabling may be done manually by user command or automatically when a halt + instruction is executed. Enabling occurs only by user command. This differs + slightly from actual machine operation, which additionally disables the + loader when a manual halt is performed. We do not do this to allow + breakpoints within and single-stepping through the loaders. +*/ + +t_stat cpu_set_ldr (UNIT *uptr, int32 enable, char *cptr, void *desc) +{ +static uint16 loader[IBL_LNT]; +int32 i; +t_bool is_enabled = (fwanxm == MEMSIZE); + +if ((UNIT_CPU_FAMILY != UNIT_FAMILY_21XX) || /* valid only for 21xx */ + (MEMSIZE == 0)) /* and for initialized memory */ + return SCPE_NOFNC; + +if (is_enabled && (enable == 0)) { /* disable loader? */ + fwanxm = MEMSIZE - IBL_LNT; /* decrease available memory */ + for (i = 0; i < IBL_LNT; i++) { /* copy loader */ + loader[i] = M[fwanxm + i]; /* from memory */ + M[fwanxm + i] = 0; /* and zero location */ } } -return SCPE_NOFNC; + +else if ((!is_enabled) && (enable == 1)) { /* enable loader? */ + for (i = 0; i < IBL_LNT; i++) /* copy loader */ + M[fwanxm + i] = loader[i]; /* to memory */ + fwanxm = MEMSIZE; /* increase available memory */ + } + +return SCPE_OK; } /* IBL routine (CPU boot) */ @@ -2183,6 +2662,8 @@ t_stat ibl_copy (const uint16 pboot[IBL_LNT], int32 dev) int32 i; uint16 wd; +cpu_set_ldr (NULL, TRUE, NULL, NULL); /* enable loader (ignore errors) */ + if (dev < 010) return SCPE_ARG; /* valid device? */ PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */ for (i = 0; i < IBL_LNT; i++) { /* copy bootstrap */ @@ -2197,4 +2678,3 @@ M[PC + IBL_DPC] = (M[PC + IBL_DPC] + (dev - 010)) & DMASK; /* patch DMA ctr M[PC + IBL_END] = (~PC + 1) & DMASK; /* fill in start of boot */ return SCPE_OK; } - diff --git a/HP2100/hp2100_cpu.h b/HP2100/hp2100_cpu.h index 7a034be1..40012a48 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, Robert M. Supnik + Copyright (c) 2005-2006, 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,72 +23,175 @@ 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. + 16-Dec-06 JDB Added UNIT_2115 and UNIT_2114 + 16-Oct-06 JDB Moved ReadF to hp2100_cpu1.c + 26-Sep-06 JDB Added CPU externs for microcode simulators + 16-Aug-06 JDB Added UNIT_EMA for future RTE-4 EMA microcode + Added UNIT_VMA for future RTE-6 VMA and OS microcode + Added UNIT_1000_F for future F-Series support + 09-Aug-06 JDB Added UNIT_DBI for double integer microcode 21-Jan-05 JDB Reorganized CPU option flags 14-Jan-05 RMS Cloned from hp2100_cpu.c - CPU models are broken down into type and series to facilitate option - validation. Bits 3:2 encode the type, and bits 1:0 encode the series - within the type. + CPU models are broken down into family, type, and series to facilitate option + validation. Bit 3 encodes the family, bit 2 encodes the type, and bits 1:0 + encode the series within the type. */ #ifndef _HP2100_CPU_H_ #define _HP2100_CPU_H_ 0 +/* CPU model definition flags */ + #define CPU_V_SERIES 0 #define CPU_V_TYPE 2 +#define CPU_V_FAMILY 3 -#define TYPE_211X 0 /* 2114, 2115, 2116 */ -#define TYPE_2100 1 /* 2100A, 2100S */ -#define TYPE_21MX 2 /* 21MX-M, 21MX-E, 21MX-F */ -#define TYPE_1000A 3 /* A600, A700, A900, A990 */ +#define FAMILY_21XX (0 << CPU_V_FAMILY) +#define FAMILY_1000 (1 << CPU_V_FAMILY) -#define CPU_2116 (TYPE_211X << CPU_V_TYPE | 0) -#define CPU_2100 (TYPE_2100 << CPU_V_TYPE | 0) -#define CPU_21MX_M (TYPE_21MX << CPU_V_TYPE | 0) -#define CPU_21MX_E (TYPE_21MX << CPU_V_TYPE | 1) +#define TYPE_211X (0 << CPU_V_TYPE) /* 2114, 2115, 2116 */ +#define TYPE_2100 (1 << CPU_V_TYPE) /* 2100A, 2100S */ +#define TYPE_1000MEF (0 << CPU_V_TYPE) /* 1000-M, 1000-E, 1000-F */ +#define TYPE_1000AL (1 << CPU_V_TYPE) /* 1000-L, A600, A700, A900, A990 */ + +#define SERIES_16 (0 << CPU_V_SERIES) /* 211X */ +#define SERIES_15 (1 << CPU_V_SERIES) /* 211X */ +#define SERIES_14 (2 << CPU_V_SERIES) /* 211X */ +#define SERIES_00 (0 << CPU_V_SERIES) /* 2100 */ +#define SERIES_M (0 << CPU_V_SERIES) /* 1000 */ +#define SERIES_E (1 << CPU_V_SERIES) /* 1000 */ +#define SERIES_F (2 << CPU_V_SERIES) /* 1000 */ + +/* CPU unit flags */ + +#define UNIT_M_CPU 017 /* CPU model mask [3:0] */ +#define UNIT_M_TYPE 014 /* CPU type mask [3:2] */ +#define UNIT_M_FAMILY 010 /* CPU family mask [3:3] */ #define UNIT_V_CPU (UNIT_V_UF + 0) /* CPU model bits 0-3 */ -#define UNIT_M_CPU 017 /* CPU model mask */ -#define UNIT_M_TYPE 014 /* CPU type mask */ #define UNIT_V_EAU (UNIT_V_UF + 4) /* EAU installed */ #define UNIT_V_FP (UNIT_V_UF + 5) /* FP installed */ #define UNIT_V_IOP (UNIT_V_UF + 6) /* IOP installed */ #define UNIT_V_DMS (UNIT_V_UF + 7) /* DMS installed */ #define UNIT_V_FFP (UNIT_V_UF + 8) /* FFP installed */ +#define UNIT_V_DBI (UNIT_V_UF + 9) /* DBI installed */ +#define UNIT_V_EMA (UNIT_V_UF + 10) /* RTE-4 EMA installed */ +#define UNIT_V_VMAOS (UNIT_V_UF + 11) /* RTE-6 VMA/OS installed */ +/* Future microcode expansion; reuse flags bottom-up if needed */ +#define UNIT_V_VIS (UNIT_V_UF + 12) /* VIS installed */ +#define UNIT_V_DS (UNIT_V_UF + 13) /* DS installed */ +#define UNIT_V_SIGNAL (UNIT_V_UF + 14) /* SIGNAL/1000 installed */ -#define UNIT_CPU_MASK (UNIT_M_CPU << UNIT_V_CPU) -#define UNIT_2116 (CPU_2116 << UNIT_V_CPU) -#define UNIT_2100 (CPU_2100 << UNIT_V_CPU) -#define UNIT_21MX_M (CPU_21MX_M << UNIT_V_CPU) -#define UNIT_21MX_E (CPU_21MX_E << UNIT_V_CPU) +/* Unit models */ + +#define UNIT_MODEL_MASK (UNIT_M_CPU << UNIT_V_CPU) + +#define UNIT_2116 ((FAMILY_21XX | TYPE_211X | SERIES_16) << UNIT_V_CPU) +#define UNIT_2115 ((FAMILY_21XX | TYPE_211X | SERIES_15) << UNIT_V_CPU) +#define UNIT_2114 ((FAMILY_21XX | TYPE_211X | SERIES_14) << UNIT_V_CPU) +#define UNIT_2100 ((FAMILY_21XX | TYPE_2100 | SERIES_00) << UNIT_V_CPU) +#define UNIT_1000_M ((FAMILY_1000 | TYPE_1000MEF | SERIES_M) << UNIT_V_CPU) +#define UNIT_1000_E ((FAMILY_1000 | TYPE_1000MEF | SERIES_E) << UNIT_V_CPU) +#define UNIT_1000_F ((FAMILY_1000 | TYPE_1000MEF | SERIES_F) << UNIT_V_CPU) + +/* Unit types */ #define UNIT_TYPE_MASK (UNIT_M_TYPE << UNIT_V_CPU) -#define UNIT_TYPE_211X ((TYPE_211X << CPU_V_TYPE) << UNIT_V_CPU) -#define UNIT_TYPE_2100 ((TYPE_2100 << CPU_V_TYPE) << UNIT_V_CPU) -#define UNIT_TYPE_21MX ((TYPE_21MX << CPU_V_TYPE) << UNIT_V_CPU) -#define UNIT_CPU_MODEL (cpu_unit.flags & UNIT_CPU_MASK) +#define UNIT_TYPE_211X ((FAMILY_21XX | TYPE_211X) << UNIT_V_CPU) +#define UNIT_TYPE_2100 ((FAMILY_21XX | TYPE_2100) << UNIT_V_CPU) +#define UNIT_TYPE_1000 ((FAMILY_1000 | TYPE_1000MEF) << UNIT_V_CPU) + +/* Unit families */ + +#define UNIT_FAMILY_MASK (UNIT_M_FAMILY << UNIT_V_CPU) + +#define UNIT_FAMILY_21XX (FAMILY_21XX << UNIT_V_CPU) +#define UNIT_FAMILY_1000 (FAMILY_1000 << UNIT_V_CPU) + +/* Unit accessors */ + +#define UNIT_CPU_MODEL (cpu_unit.flags & UNIT_MODEL_MASK) #define UNIT_CPU_TYPE (cpu_unit.flags & UNIT_TYPE_MASK) -#define CPU_TYPE (UNIT_CPU_TYPE >> (UNIT_V_CPU + CPU_V_TYPE)) +#define UNIT_CPU_FAMILY (cpu_unit.flags & UNIT_FAMILY_MASK) + +#define CPU_MODEL_INDEX (UNIT_CPU_MODEL >> UNIT_V_CPU) + +/* Unit features */ #define UNIT_EAU (1 << UNIT_V_EAU) #define UNIT_FP (1 << UNIT_V_FP) #define UNIT_IOP (1 << UNIT_V_IOP) #define UNIT_DMS (1 << UNIT_V_DMS) #define UNIT_FFP (1 << UNIT_V_FFP) +#define UNIT_DBI (1 << UNIT_V_DBI) +#define UNIT_EMA (1 << UNIT_V_EMA) +#define UNIT_VMAOS (1 << UNIT_V_VMAOS) +#define UNIT_VIS (1 << UNIT_V_VIS) +#define UNIT_DS (1 << UNIT_V_DS) +#define UNIT_SIGNAL (1 << UNIT_V_SIGNAL) -#define UNIT_OPTS (UNIT_EAU | UNIT_FP | UNIT_IOP | UNIT_DMS | UNIT_FFP) +#define UNIT_EMA_VMA (UNIT_EMA | UNIT_VMAOS) + +#define UNIT_OPTS (UNIT_EAU | UNIT_FP | UNIT_IOP | \ + UNIT_DMS | UNIT_FFP | UNIT_DBI | \ + UNIT_EMA | UNIT_VMAOS | \ + UNIT_VIS | UNIT_DS | UNIT_SIGNAL) + +/* "Pseudo-option" flags used only for option testing; never set into UNIT structure. */ + +#define UNIT_V_PFAIL (UNIT_V_UF - 1) /* Power fail installed */ +#define UNIT_V_DMA (UNIT_V_UF - 2) /* DMA installed */ +#define UNIT_V_MP (UNIT_V_UF - 3) /* Memory protect installed */ + +#define UNIT_PFAIL (1 << UNIT_V_PFAIL) +#define UNIT_DMA (1 << UNIT_V_DMA) +#define UNIT_MP (1 << UNIT_V_MP) + +#define UNIT_NONE 0 /* no options */ + + +/* PC queue. */ #define PCQ_SIZE 64 /* must be 2**n */ #define PCQ_MASK (PCQ_SIZE - 1) #define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = err_PC +/* CPU registers */ + +extern uint16 ABREG[2]; /* A/B regs (use AR/BR) */ +extern uint32 PC; /* P register */ +extern uint32 SR; /* S register */ +extern uint32 MR; /* M register */ +extern uint32 TR; /* T register */ +extern uint32 XR; /* X register */ +extern uint32 YR; /* Y register */ +extern uint32 E; /* E register */ +extern uint32 O; /* O register */ + +/* CPU state */ + +extern uint32 err_PC; +extern uint32 dms_enb; +extern uint32 dms_ump; +extern uint32 dms_sr; +extern uint32 dms_vr; +extern uint32 mp_fence; +extern uint32 iop_sp; +extern uint32 ion_defer; +extern uint16 pcq[PCQ_SIZE]; +extern uint32 pcq_p; +extern uint32 stop_inst; +extern UNIT cpu_unit; + +/* CPU functions */ + t_stat resolve (uint32 MA, uint32 *addr, uint32 irq); uint8 ReadB (uint32 addr); uint8 ReadBA (uint32 addr); uint16 ReadW (uint32 addr); uint16 ReadWA (uint32 addr); -uint32 ReadF (uint32 addr); void WriteB (uint32 addr, uint32 dat); void WriteBA (uint32 addr, uint32 dat); void WriteW (uint32 addr, uint32 dat); diff --git a/HP2100/hp2100_cpu0.c b/HP2100/hp2100_cpu0.c new file mode 100644 index 00000000..f537f4da --- /dev/null +++ b/HP2100/hp2100_cpu0.c @@ -0,0 +1,557 @@ +/* hp2100_cpu0.c: HP 1000 unimplemented instruction set stubs + + Copyright (c) 2006, J. David Bryan + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHOR 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 the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + CPU0 Unimplemented firmware option instructions + + 01-Dec-06 JDB Removed and implemented "cpu_sis". + 26-Sep-06 JDB Created + + This file contains template simulations for the firmware options that have + not yet been implemented. When a given firmware option is implemented, it + should be moved out of this file and into another (or its own, depending on + complexity). + + Primary references: + - HP 1000 M/E/F-Series Computers Technical Reference Handbook + (5955-0282, Mar-1980) + - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation + (92851-90001, Mar-1981) + - Macro/1000 Reference Manual (92059-90001, Dec-1992) + + Additional references are listed with the associated firmware + implementations, as are the HP option model numbers pertaining to the + applicable CPUs. +*/ + +#include "hp2100_defs.h" +#include "hp2100_cpu.h" +#include "hp2100_cpu1.h" + + +t_stat cpu_rte_ema (uint32 IR, uint32 intrq); /* RTE-4 EMA */ +t_stat cpu_rte_vma (uint32 IR, uint32 intrq); /* RTE-6 VMA */ +t_stat cpu_rte_os (uint32 IR, uint32 intrq, uint32 iotrap); /* RTE-6 OS */ +t_stat cpu_ds (uint32 IR, uint32 intrq); /* Distributed System */ +t_stat cpu_vis (uint32 IR, uint32 intrq); /* Vector Instruction Set */ +t_stat cpu_signal (uint32 IR, uint32 intrq); /* SIGNAL/1000 Instructions */ + + +/* RTE-IV Extended Memory Area Instructions + + The RTE-IV operating system (HP product number 92067A) introduced the + Extended Memory Area (EMA) instructions. EMA provided a mappable data area + up to one megaword in size. These three instructions accelerated data + accesses to variables stored in EMA partitions. Support was limited to + E/F-Series machines; M-Series machines used software equivalents. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A N/A 92067A 92067A + + The routines are mapped to instruction codes as follows: + + Instr. 1000-E/F Description + ------ -------- ---------------------------------------------- + .EMIO 105240 EMA I/O + MMAP 105241 Map physical to logical memory + [test] 105242 [self test] + .EMAP 105257 Resolve array element address + + Notes: + + 1. RTE-IV EMA and RTE-6 VMA instructions share the same address space, so a + given machine can run one or the other, but not both. + + Additional references: + - RTE-IVB Programmer's Reference Manual (92068-90004, Dec-1983). + - RTE-IVB Technical Specifications (92068-90013, Jan-1980). +*/ + +static const OP_PAT op_ema[16] = { + OP_A, OP_AKK, OP_N, OP_N, /* .EMIO MMAP [test] --- */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_A /* --- --- --- .EMAP */ + }; + +t_stat cpu_rte_ema (uint32 IR, uint32 intrq) +{ +t_stat reason = SCPE_OK; +OPS op; +uint32 entry; + +if ((cpu_unit.flags & UNIT_EMA) == 0) /* EMA option installed? */ + return stop_inst; + +entry = IR & 017; /* mask to entry point */ + +if (op_ema[entry] != OP_N) + if (reason = cpu_ops (op_ema[entry], op, intrq)) /* get instruction operands */ + return reason; + +switch (entry) { /* decode IR<3:0> */ + + default: /* others undefined */ + reason = stop_inst; + } + +return reason; +} + + +/* RTE-6/VM Virtual Memory Area Instructions + + RTE-6/VM (product number 92084A) introduced Virtual Memory Area (VMA) + instructions -- a superset of the RTE-IV EMA instructions. Different + microcode was supplied with the operating system that replaced the microcode + used with RTE-IV. Microcode was limited to the E/F-Series, and the M-Series + used software equivalents. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A N/A 92084A 92084A + + The routines are mapped to instruction codes as follows: + + Instr. 1000-E/F Description + ------ -------- ---------------------------------------------- + .PMAP 105240 Map VMA page into map register + $LOC 105241 Load on call + [test] 105242 [self test] + .SWP 105243 [Swap A and B registers] + .STAS 105244 [STA B; LDA SP] + .LDAS 105245 [LDA SP] + .MYAD 105246 [NOP in microcode] + .UMPY 105247 [Unsigned multiply and add] + + .IMAP 105250 Integer element resolve address and map + .IMAR 105251 Integer element resolve address + .JMAP 105252 Double integer element resolve address and map + .JMAR 105253 Double integer element resolve address + .LPXR 105254 Map pointer in P+1 plus offset in P+2 + .LPX 105255 Map pointer in A/B plus offset in P+1 + .LBPR 105256 Map pointer in P+1 + .LBP 105257 Map pointer in A/B registers + + Notes: + + 1. The opcodes 105243-247 are undocumented and do not appear to be used in + any HP software. + + 2. The opcode list in the CE Handbook incorrectly shows 105246 as ".MYAD - + multiply 2 signed integers." The microcode listing shows that this + instruction was deleted, and the opcode is now a NOP. + + 3. RTE-IV EMA and RTE-6 VMA instructions shared the same address space, so + a given machine could run one or the other, but not both. + + Additional references: + - RTE-6/VM VMA/EMA Microcode Source (92084-18828, revision 3). + - RTE-6/VM Technical Specifications (92084-90015, Apr-1983). + - M/E/F-Series Computer Systems CE Handbook (5950-3767, Jul-1984). +*/ + +static const OP_PAT op_vma[16] = { + OP_N, OP_KKKAKK, OP_N, OP_N, /* .PMAP $LOC [test] .SWAP */ + OP_N, OP_N, OP_N, OP_K, /* .STAS .LDAS .MYAD .UMPY */ + OP_A, OP_A, OP_A, OP_A, /* .IMAP .IMAR .JMAP .JMAR */ + OP_FF, OP_F, OP_F, OP_N /* .LPXR .LPX .LBPR .LBP */ + }; + +t_stat cpu_rte_vma (uint32 IR, uint32 intrq) +{ +t_stat reason = SCPE_OK; +OPS op; +uint32 entry; + +if ((cpu_unit.flags & UNIT_VMAOS) == 0) /* VMA/OS option installed? */ + return cpu_rte_ema (IR, intrq); /* try EMA */ + +entry = IR & 017; /* mask to entry point */ + +if (op_vma[entry] != OP_N) + if (reason = cpu_ops (op_vma[entry], op, intrq)) /* get instruction operands */ + return reason; + +switch (entry) { /* decode IR<3:0> */ + + default: /* others undefined */ + reason = stop_inst; + } + +return reason; +} + + +/* RTE-6/VM Operating System Instructions + + The OS instructions were added to acccelerate certain time-consuming + operations of the RTE-6/VM operating system, HP product number 92084A. + Microcode was available for the E- and F-Series; the M-Series used software + equivalents. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A N/A 92084A 92084A + + The routines are mapped to instruction codes as follows: + + Instr. 1000-E/F Description + ------ -------- ---------------------------------------------- + $LIBR 105340 Enter privileged/reentrant library routine + $LIBX 105341 Exit privileged/reentrant library routine + .TICK 105342 TBG tick interrupt handler + .TNAM 105343 Find ID segment that matches name + .STIO 105344 Configure I/O instructions + .FNW 105345 Find word with user increment + .IRT 105346 Interrupt return processing + .LLS 105347 Linked list search + + .SIP 105350 Skip if interrupt pending + .YLD 105351 .SIP completion return point + .CPM 105352 Compare words LT/EQ/GT + .ETEQ 105353 Set up EQT pointers in base page + .ENTN 105354 Transfer parameter addresses (utility) + [test] 105355 [self test] + .ENTC 105356 Transfer parameter addresses (priv/reent) + .DSPI 105357 Set display indicator + + Opcodes 105354-105357 are "dual use" instructions that take different + actions, depending on whether they are executed from a trap cell during an + interrupt. When executed from a trap cell, they have these actions: + + Instr. 1000-E/F Description + ------ -------- ---------------------------------------------- + [dma] 105354 DCPC channel interrupt processing + [dms] 105355 DMS/MP/PE interrupt processing + [dev] 105356 Standard device interrupt processing + [tbg] 105357 TBG interrupt processing + + Notes: + + 1. The microcode differentiates between interrupt processing and normal + execution of the "dual use" instructions by testing the CPU flag. + Interrupt vectoring sets the flag; a normal instruction fetch clears it. + Under simulation, interrupt vectoring is indicated by the value of the + "iotrap" parameter. + + 2. The operand patterns for .ENTN and .ENTC normally would be coded as + "OP_A", as each takes a single address as a parameter. However, because + they might also be executed from a trap cell, we cannot assume that P+1 + is an address, or we might cause a DM abort when trying to access + memory. Therefore, "OP_A" handling is done within each routine, once + the type of use is determined. + + Additional references: + - RTE-6/VM O/S Microcode Source (92084-18831, revision 6). + - RTE-6/VM Technical Specifications (92084-90015, Apr-1983). +*/ + +static const OP_PAT op_os[16] = { + OP_A, OP_A, OP_N, OP_N, /* $LIBR $LIBX .TICK .TNAM */ + OP_A, OP_K, OP_A, OP_KK, /* .STIO .FNW .IRT .LLS */ + OP_N, OP_CC, OP_KK, OP_N, /* .SIP .YLD .CPM .ETEQ */ + OP_N, OP_N, OP_N, OP_N /* .ENTN [test] .ENTC .DSPI */ + }; + +t_stat cpu_rte_os (uint32 IR, uint32 intrq, uint32 iotrap) +{ +t_stat reason = SCPE_OK; +OPS op; +uint32 entry; + +if ((cpu_unit.flags & UNIT_VMAOS) == 0) /* VMA/OS option installed? */ + return stop_inst; + +entry = IR & 017; /* mask to entry point */ + +if (op_os[entry] != OP_N) + if (reason = cpu_ops (op_os[entry], op, intrq)) /* get instruction operands */ + return reason; + +switch (entry) { /* decode IR<3:0> */ + + default: /* others undefined */ + reason = stop_inst; + } + +return reason; +} + + +/* Distributed System + + Distributed System firmware was provided with the HP 91740A DS/1000 product + for use with the HP 12771A (12665A) Serial Interface and 12773A Modem + Interface system interconnection kits. Firmware permitted high-speed + transfers with minimum impact to the processor. The advent of the + "intelligent" 12794A and 12825A HDLC cards, the 12793A and 12834A Bisync + cards, and the 91750A DS-1000/IV software obviated the need for CPU firmware, + as essentially the firmware was moved onto the I/O cards. + + Primary documentation for the DS instructions has not been located. However, + examination of the DS/1000 sources reveals that two instruction were used by + the DVA65 Serial Interface driver (91740-18071) and placed in the trap cells + of the communications interfaces. Presumably they handled interrupts from + the cards. + + Implementation of the DS instructions will also require simulation of the + 12665A Hardwired Serial Data Interface Card and the 12620A RTE Privileged + Interrupt Fence. These are required for DS/1000. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A 91740A 91740B 91740B + + The routines are mapped to instruction codes as follows: + + Instr. 1000-M 1000-E/F Description + ------ ------ -------- ---------------------------------------------- + 105520 105300 "Open loop" (trap cell handler) + 105521 105301 "Closed loop" (trap cell handler) + 105522 105302 [unknown] + [test] 105524 105304 [self test] + + Notes: + + 1. The E/F-Series opcodes were moved from 105340-357 to 105300-317 at + revision 1813. + + 2. DS/1000 ROM data are available from Bitsavers. + + Additional references (documents unavailable): + - HP 91740A M-Series Distributed System (DS/1000) Firmware Installation + Manual (91740-90007). + - HP 91740B Distributed System (DS/1000) Firmware Installation Manual + (91740-90009). +*/ + +static const OP_PAT op_ds[16] = { + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N /* --- --- --- --- */ + }; + +t_stat cpu_ds (uint32 IR, uint32 intrq) +{ +t_stat reason = SCPE_OK; +OPS op; +uint32 entry; + +if ((cpu_unit.flags & UNIT_DS) == 0) /* DS option installed? */ + return stop_inst; + +entry = IR & 017; /* mask to entry point */ + +if (op_ds[entry] != OP_N) + if (reason = cpu_ops (op_ds[entry], op, intrq)) /* get instruction operands */ + return reason; + +switch (entry) { /* decode IR<3:0> */ + + default: /* others undefined */ + reason = stop_inst; + } + +return reason; +} + + +/* Vector Instruction Set + + The VIS provides instructions that operate on one-dimensional arrays of + floating-point values. Both single- and double-precision operations are + supported. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A N/A N/A 12824A + + The routines are mapped to instruction codes as follows: + + Single-Precision Double-Precision + Instr. Opcode Subcod Instr. Opcode Subcod Description + ------ ------ ------ ------ ------ ------ ----------------------------- + VADD 101460 000000 DVADD 105460 004002 Vector add + VSUB 101460 000020 DVSUB 105460 004022 Vector subtract + VMPY 101460 000040 DVMPY 105460 004042 Vector multiply + VDIV 101460 000060 DVDIV 105460 004062 Vector divide + VSAD 101460 000400 DVSAD 105460 004402 Scalar-vector add + VSSB 101460 000420 DVSSB 105460 004422 Scalar-vector subtract + VSMY 101460 000440 DVSMY 105460 004442 Scalar-vector multiply + VSDV 101460 000460 DVSDV 105460 004462 Scalar-vector divide + VPIV 101461 0xxxxx DVPIV 105461 0xxxxx Vector pivot + VABS 101462 0xxxxx DVABS 105462 0xxxxx Vector absolute value + VSUM 101463 0xxxxx DVSUM 105463 0xxxxx Vector sum + VNRM 101464 0xxxxx DVNRM 105464 0xxxxx Vector norm + VDOT 101465 0xxxxx DVDOT 105465 0xxxxx Vector dot product + VMAX 101466 0xxxxx DVMAX 105466 0xxxxx Vector maximum value + VMAB 101467 0xxxxx DVMAB 105467 0xxxxx Vector maximum absolute value + VMIN 101470 0xxxxx DVMIN 105470 0xxxxx Vector minimum value + VMIB 101471 0xxxxx DVMIB 105471 0xxxxx Vector minimum absolute value + VMOV 101472 0xxxxx DVMOV 105472 0xxxxx Vector move + VSWP 101473 0xxxxx DVSWP 105473 0xxxxx Vector swap + .ERES 101474 -- -- -- -- Resolve array element address + .ESEG 101475 -- -- -- -- Load MSEG maps + .VSET 101476 -- -- -- -- Vector setup + [test] -- -- -- 105477 -- [self test] + + Instructions use IR bit 11 to select single- or double-precision format. The + double-precision instruction names begin with "D" (e.g., DVADD vs. VADD). + Most VIS instructions are two words in length, with a sub-opcode immediately + following the primary opcode. + + Notes: + + 1. The .VECT (101460) and .DVCT (105460) opcodes preface a single- or + double-precision arithmetic operation that is determined by the + sub-opcode value. The remainder of the dual-precision sub-opcode values + are "don't care," except for requiring a zero in bit 15. + + 2. The VIS uses the hardware FPP of the F-Series. FPP malfunctions are + detected by the VIS firmware and are indicated by a memory-protect + violation and setting the overflow flag. Under simulation, + malfunctions cannot occur. + + 3. VIS ROM data are available from Bitsavers. + + Additional references: + - 12824A Vector Instruction Set User's Manual (12824-90001, Jun-1979). +*/ + +static const OP_PAT op_vis[16] = { + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N /* --- --- --- --- */ + }; + +t_stat cpu_vis (uint32 IR, uint32 intrq) +{ +t_stat reason = SCPE_OK; +OPS op; +uint32 entry; + +if ((cpu_unit.flags & UNIT_VIS) == 0) /* VIS option installed? */ + return stop_inst; + +entry = IR & 017; /* mask to entry point */ + +if (op_vis[entry] != OP_N) + if (reason = cpu_ops (op_vis[entry], op, intrq)) /* get instruction operands */ + return reason; + +switch (entry) { /* decode IR<3:0> */ + + default: /* others undefined */ + reason = stop_inst; + } + +return reason; +} + + +/* SIGNAL/1000 Instructions + + The SIGNAL/1000 instructions provide fast Fourier transforms and complex + arithmetic. They utilize the F-Series floating-point processor and the + Vector Instruction Set. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A N/A N/A 92835A + + The routines are mapped to instruction codes as follows: + + Instr. 1000-F Description + ------ ------ ---------------------------------------------- + BITRV 105600 Bit reversal + BTRFY 105601 Butterfly algorithm + UNSCR 105602 Unscramble for phasor MPY + PRSCR 105603 Unscramble for phasor MPY + BITR1 105604 Swap two elements in array (alternate format) + BTRF1 105605 Butterfly algorithm (alternate format) + .CADD 105606 Complex number addition + .CSUB 105607 Complex number subtraction + .CMPY 105610 Complex number multiplication + .CDIV 105611 Complex number division + CONJG 105612 Complex conjugate + ..CCM 105613 Complex complement + AIMAG 105614 Return imaginary part + CMPLX 105615 Form complex number + [nop] 105616 [no operation] + [test] 105617 [self test] + + Notes: + + 1. SIGNAL/1000 ROM data are available from Bitsavers. + + Additional references (documents unavailable): + - HP Signal/1000 User Reference and Installation Manual (92835-90002). +*/ + +static const OP_PAT op_signal[16] = { + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N /* --- --- --- --- */ + }; + +t_stat cpu_signal (uint32 IR, uint32 intrq) +{ +t_stat reason = SCPE_OK; +OPS op; +uint32 entry; + +if ((cpu_unit.flags & UNIT_SIGNAL) == 0) /* SIGNAL option installed? */ + return stop_inst; + +entry = IR & 017; /* mask to entry point */ + +if (op_signal[entry] != OP_N) + if (reason = cpu_ops (op_signal[entry], op, intrq)) /* get instruction operands */ + return reason; + +switch (entry) { /* decode IR<3:0> */ + + default: /* others undefined */ + reason = stop_inst; + } + +return reason; +} diff --git a/HP2100/hp2100_cpu1.c b/HP2100/hp2100_cpu1.c index fe15ae8f..091e18c0 100644 --- a/HP2100/hp2100_cpu1.c +++ b/HP2100/hp2100_cpu1.c @@ -1,6 +1,6 @@ -/* hp2100_cpu1.c: HP 2100 EAU and UIG simulator +/* hp2100_cpu1.c: HP 2100/1000 EAU simulator and UIG dispatcher - Copyright (c) 2005, Robert M. Supnik + Copyright (c) 2005-2007, 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,11 +23,15 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - CPU1 Extended arithmetic and optional microcode instructions + CPU1 Extended arithmetic and optional microcode dispatchers - 22-Feb-05 JDB Fixed missing MPCK on JRS target - Removed EXECUTE instruction (is NOP in actual microcode) - 18-Feb-05 JDB Add 2100/21MX Fast FORTRAN Processor instructions + 04-Jan-07 JDB Added special DBI dispatcher for non-INT64 diagnostic + 29-Dec-06 JDB Allows RRR as NOP if 2114 (diag config test) + 01-Dec-06 JDB Substitutes FPP for firmware FP if HAVE_INT64 + 16-Oct-06 JDB Generalized operands for F-Series FP types + 26-Sep-06 JDB Split hp2100_cpu1.c into multiple modules to simplify extensions + Added iotrap parameter to UIG dispatchers for RTE microcode + 22-Feb-05 JDB Removed EXECUTE instruction (is NOP in actual microcode) 21-Jan-05 JDB Reorganized CPU option and operand processing flags Split code along microcode modules 15-Jan-05 RMS Cloned from hp2100_cpu.c @@ -37,28 +41,33 @@ (5955-0282, Mar-1980) - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation (92851-90001, Mar-1981) + - Macro/1000 Reference Manual (92059-90001, Dec-1992) Additional references are listed with the associated firmware implementations, as are the HP option model numbers pertaining to the applicable CPUs. - This source file contains the Extended Arithmetic Unit and various optional - User Instruction Group (a.k.a. "Macro") instruction sets for the 2100 and - 21MX CPUs. Unit flags indicate which options are present in the current - system. + This source file contains the Extended Arithmetic Unit simulator and the User + Instruction Group (a.k.a. "Macro") dispatcher for the 2100 and 1000 (21MX) + CPUs. The UIG simulators reside in separate source files, due to the large + number of firmware options available for the 1000 machines. Unit flags + indicate which options are present in the current system. + + This module also provides generalized instruction operand processing. The microcode address space of the 2100 encompassed four modules of 256 words - each. The 21MX M-series expanded that to sixteen modules, and the 21MX - E-series expanded that still further to sixty-four modules. Each CPU had its - own microinstruction set, although the micromachines of the various 21MX + each. The 1000 M-series expanded that to sixteen modules, and the 1000 + E/F-series expanded that still further to sixty-four modules. Each CPU had + its own microinstruction set, although the micromachines of the various 1000 models were similar internally. Regarding option instruction sets, there was some commonality across CPU types. EAU instructions were identical across all models, and the floating - point set was the same on the 2100 and 21MX. Other options implemented + point set was the same on the 2100 and 1000. Other options implemented proper instruction supersets (e.g., the Fast FORTRAN Processor from 2100 to - 21MX-M to 21MX-E to 21MX-F) or functional equivalence with differing code - points (the 2000 I/O Processor from 2100 to 21MX). + 1000-M to 1000-E to 1000-F) or functional equivalence with differing code + points (the 2000 I/O Processor from 2100 to 1000 and extended-precision + floating-point instructions from 1000-E to 1000-F). The 2100 decoded the EAU and UIG sets separately in hardware and supported only the UIG 0 code points. Bits 7-4 of a UIG instruction decoded one of @@ -66,7 +75,7 @@ entry points could be used directly (as for the floating-point instructions), or additional decoding based on bits 3-0 could be implemented. - The 21MX generalized the instruction decoding to a series of microcoded + The 1000 generalized the instruction decoding to a series of microcoded jumps, based on the bits in the instruction. Bits 15-8 indicated the group of the current instruction: EAU (200, 201, 202, 210, and 211), UIG 0 (212), or UIG 1 (203 and 213). UIG 0, UIG 1, and some EAU instructions were decoded @@ -76,112 +85,37 @@ set, so modules needed only to be concerned with decoding their individual entry points within the module. - While the 2100 and 21MX hardware decoded these instruction sets differently, - the decoding mechanism of the simulation follows that of the 21MX E-series. + While the 2100 and 1000 hardware decoded these instruction sets differently, + the decoding mechanism of the simulation follows that of the 1000 E/F-series. Where needed, CPU type- or model-specific behavior is simulated. - The design of the 21MX microinstruction set was such that executing an + The design of the 1000 microinstruction set was such that executing an instruction for which no microcode was present (e.g., executing a FFP instruction when the FFP firmware was not installed) resulted in a NOP. Under simulation, such execution causes an undefined instruction stop. */ -#include #include "hp2100_defs.h" #include "hp2100_cpu.h" -#include "hp2100_fp1.h" +#include "hp2100_cpu1.h" -/* Operand processing encoding */ +#if defined (HAVE_INT64) /* int64 support available */ +extern t_stat cpu_fpp (uint32 IR, uint32 intrq); /* Floating Point Processor */ +extern t_stat cpu_sis (uint32 IR, uint32 intrq); /* Scientific Instruction */ +#else /* int64 support unavailable */ +extern t_stat cpu_fp (uint32 IR, uint32 intrq); /* Firmware Floating Point */ +#endif /* end of int64 support */ -#define OP_NUL 0 /* no operand */ -#define OP_CON 1 /* operand is a constant */ -#define OP_VAR 2 /* operand is a variable */ -#define OP_ADR 3 /* operand is an address */ -#define OP_ADK 4 /* op is addr of 1-word const */ -#define OP_ADF 5 /* op is addr of 2-word const */ -#define OP_ADX 6 /* op is addr of 3-word const */ -#define OP_ADT 7 /* op is addr of 4-word const */ - -#define OP_N_FLAGS 3 /* number of flag bits */ -#define OP_M_FLAGS ((1 << OP_N_FLAGS) - 1) /* mask for flag bits */ - -#define OP_N_F 4 /* number of op fields */ - -#define OP_V_F1 (0 * OP_N_FLAGS) /* 1st operand field */ -#define OP_V_F2 (1 * OP_N_FLAGS) /* 2nd operand field */ -#define OP_V_F3 (2 * OP_N_FLAGS) /* 3rd operand field */ -#define OP_V_F4 (3 * OP_N_FLAGS) /* 4th operand field */ - -/* Operand patterns */ - -#define OP_N (OP_NUL) -#define OP_C (OP_CON << OP_V_F1) -#define OP_V (OP_VAR << OP_V_F1) -#define OP_A (OP_ADR << OP_V_F1) -#define OP_K (OP_ADK << OP_V_F1) -#define OP_F (OP_ADF << OP_V_F1) -#define OP_CV ((OP_CON << OP_V_F1) | (OP_VAR << OP_V_F2)) -#define OP_AC ((OP_ADR << OP_V_F1) | (OP_CON << OP_V_F2)) -#define OP_AA ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2)) -#define OP_AK ((OP_ADR << OP_V_F1) | (OP_ADK << OP_V_F2)) -#define OP_AX ((OP_ADR << OP_V_F1) | (OP_ADX << OP_V_F2)) -#define OP_KV ((OP_ADK << OP_V_F1) | (OP_VAR << OP_V_F2)) -#define OP_KA ((OP_ADK << OP_V_F1) | (OP_ADR << OP_V_F2)) -#define OP_KK ((OP_ADK << OP_V_F1) | (OP_ADK << OP_V_F2)) -#define OP_CVA ((OP_CON << OP_V_F1) | (OP_VAR << OP_V_F2) | \ - (OP_ADR << OP_V_F3)) -#define OP_AAF ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ - (OP_ADF << OP_V_F3)) -#define OP_AAX ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ - (OP_ADX << OP_V_F3)) -#define OP_AXX ((OP_ADR << OP_V_F1) | (OP_ADX << OP_V_F2) | \ - (OP_ADX << OP_V_F3)) -#define OP_AAXX ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ - (OP_ADX << OP_V_F3) | (OP_ADX << OP_V_F4)) -#define OP_KKKK ((OP_ADK << OP_V_F1) | (OP_ADK << OP_V_F2) | \ - (OP_ADK << OP_V_F3) | (OP_ADK << OP_V_F4)) - -typedef uint32 OP_PAT; /* operand pattern */ -typedef uint32 OPS[OP_N_F * 2]; /* operand array */ - -extern uint16 ABREG[2]; -extern uint32 PC; -extern uint32 err_PC; -extern uint32 XR; -extern uint32 YR; -extern uint32 E; -extern uint32 O; -extern uint32 dms_enb; -extern uint32 dms_ump; -extern uint32 dms_sr; -extern uint32 dms_vr; -extern uint32 mp_fence; -extern uint32 iop_sp; -extern uint32 ion_defer; -extern uint16 pcq[PCQ_SIZE]; -extern uint32 pcq_p; -extern uint32 stop_inst; -extern UNIT cpu_unit; - -t_stat cpu_eau (uint32 IR, uint32 intrq); /* EAU group handler */ -t_stat cpu_uig_0 (uint32 IR, uint32 intrq); /* UIG group 0 handler */ -t_stat cpu_uig_1 (uint32 IR, uint32 intrq); /* UIG group 1 handler */ - -static t_stat cpu_fp (uint32 IR, uint32 intrq); /* Floating-point */ -static t_stat cpu_ffp (uint32 IR, uint32 intrq); /* Fast FORTRAN Processor */ -static t_stat cpu_iop (uint32 IR, uint32 intrq); /* 2000 I/O Processor */ -static t_stat cpu_dms (uint32 IR, uint32 intrq); /* Dynamic mapping system */ -static t_stat cpu_eig (uint32 IR, uint32 intrq); /* Extended instruction group */ -static t_stat get_ops (OP_PAT pattern, OPS op, uint32 irq); /* operand processor */ - -extern uint32 f_as (uint32 op, t_bool sub); /* FAD/FSB */ -extern uint32 f_mul (uint32 op); /* FMP */ -extern uint32 f_div (uint32 op); /* FDV */ -extern uint32 f_fix (void); /* FIX */ -extern uint32 f_flt (void); /* FLT */ -extern uint32 f_pack (int32 expon); /* .PACK helper */ -extern void f_unpack (void); /* .FLUN helper */ -extern void f_pwr2 (int32 n); /* .PWR2 helper */ +extern t_stat cpu_ffp (uint32 IR, uint32 intrq); /* Fast FORTRAN Processor */ +extern t_stat cpu_ds (uint32 IR, uint32 intrq); /* Distributed Systems */ +extern t_stat cpu_vis (uint32 IR, uint32 intrq); /* Vector Instruction */ +extern t_stat cpu_dbi (uint32 IR, uint32 intrq); /* Double integer */ +extern t_stat cpu_rte_vma (uint32 IR, uint32 intrq); /* RTE-4/6 EMA/VMA */ +extern t_stat cpu_rte_os (uint32 IR, uint32 intrq, uint32 iotrap); /* RTE-6 OS */ +extern t_stat cpu_iop (uint32 IR, uint32 intrq); /* 2000 I/O Processor */ +extern t_stat cpu_signal (uint32 IR, uint32 intrq); /* SIGNAL/1000 Instructions */ +extern t_stat cpu_dms (uint32 IR, uint32 intrq); /* Dynamic mapping system */ +extern t_stat cpu_eig (uint32 IR, uint32 intrq); /* Extended instruction group */ /* EAU @@ -189,19 +123,19 @@ extern void f_pwr2 (int32 n); /* .PWR2 helper */ operands, including multiply, divide, shifts, and rotates. Option implementation by CPU was as follows: - 2116 2100 21MX-M 21MX-E 21MX-F - ------ ------ ------ ------ ------ - 12579A std std std std + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A 12579A 12579A std std std std The instruction codes are mapped to routines as follows: Instr. Bits - Code 15-8 7-4 2116 2100 21MX-M 21MX-E 21MX-F Note + Code 15-8 7-4 2116 2100 1000-M 1000-E 1000-F Note ------ ---- --- ------ ------ ------ ------ ------ --------------------- - 100000 200 00 DIAG DIAG Unsupported + 100000 200 00 [diag] [diag] [self test] 100020 200 01 ASL ASL ASL ASL ASL Bits 3-0 encode shift 100040 200 02 LSL LSL LSL LSL LSL Bits 3-0 encode shift - 100060 200 03 TIMER TIMER Unsupported + 100060 200 03 TIMER TIMER [deterministic delay] 100100 200 04 RRL RRL RRL RRL RRL Bits 3-0 encode shift 100200 200 10 MPY MPY MPY MPY MPY 100400 201 xx DIV DIV DIV DIV DIV @@ -212,25 +146,37 @@ extern void f_pwr2 (int32 n); /* .PWR2 helper */ 104400 211 xx DST DST DST DST DST The remaining codes for bits 7-4 are undefined and will cause a simulator - stop if enabled. On a real 21MX-M, all undefined instructions in the 200 + stop if enabled. On a real 1000-M, all undefined instructions in the 200 group decode as MPY, and all in the 202 group decode as NOP. On a real - 21MX-E, instruction patterns 200/05 through 200/07 and 202/03 decode as NOP; + 1000-E, instruction patterns 200/05 through 200/07 and 202/03 decode as NOP; all others cause erroneous execution. - EAU instruction decoding on the 21MX M-series is convoluted. The JEAU + EAU instruction decoding on the 1000 M-series is convoluted. The JEAU microorder maps IR bits 11, 9-7 and 5-4 to bits 2-0 of the microcode jump address. The map is detailed on page IC-84 of the ERD. - - The 21MX E/F-series add two undocumented instructions to the 200 group: - TIMER and DIAG. These are described in the ERD on page IA 5-5, paragraph - 5-7. The M-series executes these as MPY and RRL, respectively. A third - instruction, EXECUTE (100120), is also described but was never implemented, - and the E/F-series microcode execute a NOP for this instruction code. - Under simulation, TIMER, DIAG, and EXECUTE cause undefined instruction stops - if the CPU is set to 2100 or 2116. DIAG and EXECUTE also cause stops on the - 21MX-M. TIMER does not, because it is used by several HP programs to - differentiate between M- and E/F-series machines. + The 1000 E/F-series add two undocumented instructions to the 200 group: TIMER + and DIAG. These are described in the ERD on page IA 5-5, paragraph 5-7. The + M-series executes these as MPY and RRL, respectively. A third instruction, + EXECUTE (100120), is also described but was never implemented, and the + E/F-series microcode execute a NOP for this instruction code. + + Notes: + + 1. Under simulation, TIMER, DIAG, and EXECUTE cause undefined instruction + stops if the CPU is set to 21xx. DIAG and EXECUTE also cause stops on + the 1000-M. TIMER does not, because it is used by several HP programs + to differentiate between M- and E/F-series machines. + + 2. DIAG is not implemented under simulation. On the E/F, it performs a + destructive test of all installed memory. Because of this, it is only + functional if the machine is halted, i.e., if the instruction is + executed with the INSTR STEP button. If it is executed in a program, + the result is NOP. + + 3. RRR is permitted and executed as NOP if the CPU is a 2114, as the + presence of the EAU is tested by the diagnostic configurator to + differentiate between 2114 and 2100/1000 CPUs. */ t_stat cpu_eau (uint32 IR, uint32 intrq) @@ -240,7 +186,11 @@ OPS op; uint32 rs, qs, sc, v1, v2, t; int32 sop1, sop2; -if ((cpu_unit.flags & UNIT_EAU) == 0) return stop_inst; /* implemented? */ +if ((cpu_unit.flags & UNIT_EAU) == 0) /* option installed? */ + if ((UNIT_CPU_MODEL == UNIT_2114) && (IR == 0101100)) /* 2114 and RRR 16? */ + return SCPE_OK; /* allowed as NOP */ + else + return stop_inst; /* fail */ switch ((IR >> 8) & 0377) { /* decode IR<15:8> */ @@ -248,7 +198,7 @@ switch ((IR >> 8) & 0377) { /* decode IR<15:8> */ switch ((IR >> 4) & 017) { /* decode IR<7:4> */ case 000: /* DIAG 100000 */ - if (UNIT_CPU_MODEL != UNIT_21MX_E) /* must be 21MX-E */ + if (UNIT_CPU_MODEL != UNIT_1000_E) /* must be 1000-E */ return stop_inst; /* trap if not */ break; /* DIAG is NOP unless halted */ @@ -270,9 +220,9 @@ switch ((IR >> 8) & 0377) { /* decode IR<15:8> */ break; case 003: /* TIMER 100060 */ - if (UNIT_CPU_TYPE != UNIT_TYPE_21MX) /* must be 21MX */ + if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */ return stop_inst; /* trap if not */ - if (UNIT_CPU_MODEL == UNIT_21MX_M) /* 21MX M-series? */ + if (UNIT_CPU_MODEL == UNIT_1000_M) /* 1000 M-series? */ goto MPY; /* decode as MPY */ BR = (BR + 1) & DMASK; /* increment B */ if (BR) PC = err_PC; /* if !=0, repeat */ @@ -285,12 +235,12 @@ switch ((IR >> 8) & 0377) { /* decode IR<15:8> */ AR = ((AR << sc) | (t >> (16 - sc))) & DMASK; break; - case 010: /* MPY 100200 */ + case 010: /* MPY 100200 (OP_K) */ MPY: - if (reason = get_ops (OP_K, op, intrq)) /* get operand */ + if (reason = cpu_ops (OP_K, op, intrq)) /* get operand */ break; sop1 = SEXT (AR); /* sext AR */ - sop2 = SEXT (op[0]); /* sext mem */ + sop2 = SEXT (op[0].word); /* sext mem */ sop1 = sop1 * sop2; /* signed mpy */ BR = (sop1 >> 16) & DMASK; /* to BR'AR */ AR = sop1 & DMASK; @@ -300,17 +250,17 @@ switch ((IR >> 8) & 0377) { /* decode IR<15:8> */ default: /* others undefined */ return stop_inst; } - + break; - case 0201: /* DIV 100400 */ - if (reason = get_ops (OP_K, op, intrq)) /* get operand */ + case 0201: /* DIV 100400 (OP_K) */ + if (reason = cpu_ops (OP_K, op, intrq)) /* get operand */ break; if (rs = qs = BR & SIGN) { /* save divd sign, neg? */ AR = (~AR + 1) & DMASK; /* make B'A pos */ BR = (~BR + (AR == 0)) & DMASK; /* make divd pos */ } - v2 = op[0]; /* divr = mem */ + v2 = op[0].word; /* divr = mem */ if (v2 & SIGN) { /* neg? */ v2 = (~v2 + 1) & DMASK; /* make divr pos */ qs = qs ^ SIGN; /* sign of quotient */ @@ -338,44 +288,43 @@ switch ((IR >> 8) & 0377) { /* decode IR<15:8> */ BR = (SEXT (BR) >> sc) & DMASK; /* BR'AR ash right */ O = 0; break; - + case 002: /* LSR 101040-101057 */ sc = (IR & 017)? (IR & 017): 16; /* get sc */ AR = ((BR << (16 - sc)) | (AR >> sc)) & DMASK; BR = BR >> sc; /* BR'AR log right */ break; - + case 004: /* RRR 101100-101117 */ sc = (IR & 017)? (IR & 017): 16; /* get sc */ t = AR; /* BR'AR rot right */ AR = ((AR >> sc) | (BR << (16 - sc))) & DMASK; BR = ((BR >> sc) | (t << (16 - sc))) & DMASK; break; - + default: /* others undefined */ return stop_inst; } - + break; - case 0210: /* DLD 104200 */ - if (reason = get_ops (OP_F, op, intrq)) /* get operand */ + case 0210: /* DLD 104200 (OP_D) */ + if (reason = cpu_ops (OP_D, op, intrq)) /* get operand */ break; - AR = (op[0] >> 16) & DMASK; /* load AR */ - BR = op[0] & DMASK; /* load BR */ + AR = (op[0].dword >> 16) & DMASK; /* load AR */ + BR = op[0].dword & DMASK; /* load BR */ break; - case 0211: /* DST 104400 */ - if (reason = get_ops (OP_A, op, intrq)) /* get operand */ + case 0211: /* DST 104400 (OP_A) */ + if (reason = cpu_ops (OP_A, op, intrq)) /* get operand */ break; - WriteW (op[0], AR); /* store AR */ - op[0] = (op[0] + 1) & VAMASK; - WriteW (op[0], BR); /* store BR */ + WriteW (op[0].word, AR); /* store AR */ + WriteW ((op[0].word + 1) & VAMASK, BR); /* store BR */ break; default: /* should never get here */ - return SCPE_IERR; - } + return SCPE_IERR; /* bad call from cpu_instr */ + } return reason; } @@ -383,61 +332,112 @@ return reason; /* UIG 0 The first User Instruction Group (UIG) encodes firmware options for the 2100 - and 21MX. Instruction codes 105000-105377 are assigned to microcode options + and 1000. Instruction codes 105000-105377 are assigned to microcode options as follows: - Instructions Option Name 2100 21MX-M 21MX-E 21MX-F - ------------- ------------------------- ------ ------ ------ ------ - 105000-105362 2000 I/O Processor opt - - - - 105000-105120 Floating Point opt std std std - 105200-105237 Fast FORTRAN Processor opt opt opt std - 105240-105257 RTE-IVA/B EMA - - opt opt - 105240-105257 RTE-6/VMA - - opt opt - 105300-105317 Distributed System - - opt opt - 105340-105357 RTE-6/VM Operating System - - opt opt + Instructions Option Name 2100 1000-M 1000-E 1000-F + ------------- -------------------------- ------ ------ ------ ------ + 105000-105362 2000 I/O Processor opt - - - + 105000-105137 Floating Point opt std std std + 105200-105237 Fast FORTRAN Processor opt opt opt std + 105240-105257 RTE-IVA/B Extended Memory - - opt opt + 105240-105257 RTE-6/VM Virtual Memory - - opt opt + 105300-105317 Distributed System - - opt opt + 105320-105337 Double Integer - - opt - + 105320-105337 Scientific Instruction Set - - - std + 105340-105357 RTE-6/VM Operating System - - opt opt Because the 2100 IOP microcode uses the same instruction range as the 2100 FP and FFP options, it cannot coexist with them. To simplify simulation, the - 2100 IOP instructions are remapped to the equivalent 21MX instructions and + 2100 IOP instructions are remapped to the equivalent 1000 instructions and dispatched to the UIG 1 module. Note that if the 2100 IOP is installed, the only valid UIG instructions are IOP instructions, as the IOP used the full 2100 microcode addressing space. + + The F-Series moved the three-word extended real instructions from the FFP + range to the base floating-point range and added four-word double real and + two-word double integer instructions. The double integer instructions + occupied some of the vacated extended real instruction codes in the FFP, with + the rest assigned to the floating-point range. Consequently, many + instruction codes for the F-Series are different from the E-Series. + + Notes: + + 1. Product 93585A, available from the "Specials" group, added double + integer microcode to the E-Series. The instruction codes were different + from those in the F-Series to avoid conflicting with the E-Series FFP. + HP manual number 93585-90007 documents the double integer instructions, + but no copy of this manual has been found. The Macro/1000 manual + (92059-090001) lists E-Series double integer instructions as occupying + the code points of the F-Series Scientific Instruction Set. + + 2. To run the double-integer instructions diagnostic in the absence of + 64-bit integer support (and therefore of F-Series simulation), a special + DBI dispatcher may be enabled by defining ENABLE_DIAG during + compilation. This dispatcher will remap the F-Series DBI instructions + to the E-Series codes, so that the F-Series diagnostic may be run. + Because several of the F-Series DBI instruction codes replace M/E-Series + FFP codes, this dispatcher will only operate if FFP is disabled. + + Note that enabling the dispatcher will produce non-standard FP behavior. + For example, any code in the range 105000-105017 normally would execute + a FAD instruction. With the dispatcher enabled, 105014 would execute a + .DAD, while the other codes would execute a FAD. Therefore, ENABLE_DIAG + should only be used to run the diagnostic and is not intended for + general use. */ -t_stat cpu_uig_0 (uint32 IR, uint32 intrq) +t_stat cpu_uig_0 (uint32 IR, uint32 intrq, uint32 iotrap) { -if ((cpu_unit.flags & UNIT_IOP) && (UNIT_CPU_TYPE == UNIT_TYPE_2100)) { - if ((IR >= 0105020) && (IR <= 0105057)) /* remap LAI */ - IR = 0105400 | (IR - 0105020); - else if ((IR >= 0105060) && (IR <= 0105117)) /* remap SAI */ - IR = 0101400 | (IR - 0105060); - else { - switch (IR) { /* remap others */ - case 0105000: IR = 0105470; break; /* ILIST */ - case 0105120: IR = 0105765; break; /* MBYTE (maps to MBT) */ - case 0105150: IR = 0105460; break; /* CRC */ - case 0105160: IR = 0105467; break; /* TRSLT */ - case 0105200: IR = 0105777; break; /* MWORD (maps to MVW) */ - case 0105220: IR = 0105462; break; /* READF */ - case 0105221: IR = 0105473; break; /* PRFIO */ - case 0105222: IR = 0105471; break; /* PRFEI */ - case 0105223: IR = 0105472; break; /* PRFEX */ - case 0105240: IR = 0105464; break; /* ENQ */ - case 0105257: IR = 0105465; break; /* PENQ */ - case 0105260: IR = 0105466; break; /* DEQ */ - case 0105300: IR = 0105764; break; /* SBYTE (maps to SBT) */ - case 0105320: IR = 0105763; break; /* LBYTE (maps to LBT) */ - case 0105340: IR = 0105461; break; /* REST */ - case 0105362: IR = 0105474; break; /* SAVE */ +if ((cpu_unit.flags & UNIT_IOP) && /* I/O Processor? */ + (UNIT_CPU_TYPE == UNIT_TYPE_2100)) /* 2100 CPU? */ + return cpu_iop (IR, intrq); /* dispatch to IOP */ + + +#if !defined (HAVE_INT64) && defined (ENABLE_DIAG) /* DBI diagnostic dispatcher wanted */ + +if ((cpu_unit.flags & UNIT_FFP) == 0) + switch (IR & 0377) { + case 0014: /* .DAD 105014 */ + return cpu_dbi (0105321, intrq); + + case 0034: /* .DSB 105034 */ + return cpu_dbi (0105327, intrq); + + case 0054: /* .DMP 105054 */ + return cpu_dbi (0105322, intrq); + + case 0074: /* .DDI 105074 */ + return cpu_dbi (0105325, intrq); + + case 0114: /* .DSBR 105114 */ + return cpu_dbi (0105334, intrq); + + case 0134: /* .DDIR 105134 */ + return cpu_dbi (0105326, intrq); + + case 0203: /* .DNG 105203 */ + return cpu_dbi (0105323, intrq); + + case 0204: /* .DCO 105204 */ + return cpu_dbi (0105324, intrq); + + case 0210: /* .DIN 105210 */ + return cpu_dbi (0105330, intrq); + + case 0211: /* .DDE 105211 */ + return cpu_dbi (0105331, intrq); + + case 0212: /* .DIS 105212 */ + return cpu_dbi (0105332, intrq); + + case 0213: /* .DDS 105213 */ + return cpu_dbi (0105333, intrq); + } /* otherwise, continue */ + +#endif /* end of DBI dispatcher */ - default: /* all others invalid */ - return stop_inst; - } - } - if (IR >= 0105700) return cpu_eig (IR, intrq); /* dispatch to 21MX EIG */ - else return cpu_iop (IR, intrq); /* or to 21MX IOP */ - } switch ((IR >> 4) & 017) { /* decode IR<7:4> */ @@ -447,12 +447,33 @@ switch ((IR >> 4) & 017) { /* decode IR<7:4> */ case 003: /* 105060-105077 */ case 004: /* 105100-105117 */ case 005: /* 105120-105137 */ - return cpu_fp (IR, intrq); /* Floating Point */ +#if defined (HAVE_INT64) /* int64 support available */ + return cpu_fpp (IR, intrq); /* Floating Point Processor */ +#else /* int64 support unavailable */ + return cpu_fp (IR, intrq); /* Firmware Floating Point */ +#endif /* end of int64 support */ case 010: /* 105200-105217 */ case 011: /* 105220-105237 */ return cpu_ffp (IR, intrq); /* Fast FORTRAN Processor */ - } + + case 012: /* 105240-105257 */ + return cpu_rte_vma (IR, intrq); /* RTE-4/6 EMA/VMA */ + + case 014: /* 105300-105317 */ + return cpu_ds (IR, intrq); /* Distributed System */ + + case 015: /* 105320-105337 */ +#if defined (HAVE_INT64) /* int64 support available */ + if (UNIT_CPU_MODEL == UNIT_1000_F) /* F-series? */ + return cpu_sis (IR, intrq); /* Scientific Instruction */ + else /* M/E-series */ +#endif /* end of int64 support */ + return cpu_dbi (IR, intrq); /* Double integer */ + + case 016: /* 105340-105357 */ + return cpu_rte_os (IR, intrq, iotrap); /* RTE-6 OS */ + } return stop_inst; /* others undefined */ } @@ -460,31 +481,46 @@ return stop_inst; /* others undefined */ /* UIG 1 The second User Instruction Group (UIG) encodes firmware options for the - 21MX. Instruction codes 101400-101777 and 105400-105777 are assigned to + 1000. Instruction codes 101400-101777 and 105400-105777 are assigned to microcode options as follows ("x" is "1" or "5" below): - Instructions Option Name 21MX-M 21MX-E 21MX-F - ------------- -------------------------- ------ ------ ------ - 10x400-10x437 2000 IOP opt opt - - 10x460-10x477 2000 IOP opt opt - - 10x700-10x737 Dynamic Mapping System opt opt std - 10x740-10x777 Extended Instruction Group std std std + Instructions Option Name 1000-M 1000-E 1000-F + ------------- ---------------------------- ------ ------ ------ + 10x400-10x437 2000 IOP opt opt - + 10x460-10x477 2000 IOP opt opt - + 10x460-10x477 Vector Instruction Set - - opt + 105520-105537 Distributed System opt - - + 105600-105617 SIGNAL/1000 Instruction Set - - opt + 10x700-10x737 Dynamic Mapping System opt opt std + 10x740-10x777 Extended Instruction Group std std std - Only 21MX systems execute these instructions. + Only 1000 systems execute these instructions. */ -t_stat cpu_uig_1 (uint32 IR, uint32 intrq) +t_stat cpu_uig_1 (uint32 IR, uint32 intrq, uint32 iotrap) { -if (UNIT_CPU_TYPE != UNIT_TYPE_21MX) /* 21MX execution? */ +if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* 1000 execution? */ return stop_inst; /* no, so trap */ switch ((IR >> 4) & 017) { /* decode IR<7:4> */ case 000: /* 105400-105417 */ case 001: /* 105420-105437 */ - case 003: /* 105460-105477 */ return cpu_iop (IR, intrq); /* 2000 I/O Processor */ + case 003: /* 105460-105477 */ + if (UNIT_CPU_MODEL == UNIT_1000_F) /* F-series? */ + return cpu_vis (IR, intrq); /* Vector Instruction Set */ + else /* M/E-series */ + return cpu_iop (IR, intrq); /* 2000 I/O Processor */ + + case 005: /* 105520-105537 */ + IR = IR ^ 0000620; /* remap to 105300-105317 */ + return cpu_ds (IR, intrq); /* Distributed System */ + + case 010: /* 105600-105617 */ + return cpu_signal (IR, intrq); /* SIGNAL/1000 Instructions */ + case 014: /* 105700-105717 */ case 015: /* 105720-105737 */ return cpu_dms (IR, intrq); /* Dynamic Mapping System */ @@ -492,1405 +528,134 @@ switch ((IR >> 4) & 017) { /* decode IR<7:4> */ case 016: /* 105740-105737 */ case 017: /* 105760-105777 */ return cpu_eig (IR, intrq); /* Extended Instruction Group */ - } + } return stop_inst; /* others undefined */ } -/* Floating Point - The 2100 and 21MX CPUs share the single-precision (two word) floating point - instruction codes. Option implementation by CPU was as follows: +/* Read a multiple-precision operand value. */ - 2116 2100 21MX-M 21MX-E 21MX-F - ------ ------ ------ ------ ------ - N/A 12901A std std std - - The instruction codes are mapped to routines as follows: - - Instr. 2100/21MX-M/E/F - ------ --------------- - 105000 FAD - 105020 FSB - 105040 FMP - 105060 FDV - 105100 FIX - 105120 FLT - - Bits 3-0 are not decoded by these instructions, so FAD (e.g.) would be - executed by any instruction in the range 105000-105017. -*/ - -static const OP_PAT op_fp[6] = { - OP_F, OP_F, OP_F, OP_F, /* FAD FSB FMP FDV */ - OP_N, OP_N /* FIX FLT --- --- */ - }; - -static t_stat cpu_fp (uint32 IR, uint32 intrq) +OP ReadOp (uint32 va, OPSIZE precision) { -t_stat reason = SCPE_OK; -OPS op; -uint32 entry; +OP operand; +uint32 i; -if ((cpu_unit.flags & UNIT_FP) == 0) /* FP option installed? */ - return stop_inst; +if (precision == in_s) + operand.word = ReadW (va); /* read single integer */ -entry = (IR >> 4) & 017; /* mask to entry point */ +else if (precision == in_d) + operand.dword = ReadW (va) << 16 | /* read double integer */ + ReadW ((va + 1) & VAMASK); /* merge high and low words */ -if (op_fp[entry] != OP_N) { - if (reason = get_ops (op_fp[entry], op, intrq)) /* get instruction operands */ - return reason; - } - -switch (entry) { /* decode IR<7:4> */ - - case 000: /* FMP 105000 */ - O = f_as (op[0], 0); /* add, upd ovflo */ - break; - - case 001: /* FMP 105020 */ - O = f_as (op[0], 1); /* sub, upd ovflo */ - break; - - case 002: /* FMP 105040 */ - O = f_mul (op[0]); /* mul, upd ovflo */ - break; - - case 003: /* FDV 105060 */ - O = f_div (op[0]); /* div, upd ovflo */ - break; - - case 004: /* FIX 105100 */ - O = f_fix (); /* fix, upd ovflo */ - break; - - case 005: /* FLT 105120 */ - O = f_flt (); /* float, upd ovflo */ - break; - - default: /* should be impossible */ - return SCPE_IERR; +else + for (i = 0; i < (uint32) precision; i++) { /* read fp 2 to 5 words */ + operand.fpk[i] = ReadW (va); + va = (va + 1) & VAMASK; } - -return reason; +return operand; } -/* Fast FORTRAN Processor +/* Write a multiple-precision operand value. */ - The Fast FORTRAN Processor (FFP) is a set of FORTRAN language accelerators - and extended-precision (three-word) floating point routines. Although the - FFP is an option for the 2100 and later CPUs, each implements the FFP in a - slightly different form. - - Option implementation by CPU was as follows: - - 2116 2100 21MX-M 21MX-E 21MX-F - ------ ------ ------ ------ ------ - N/A 12907A 12977B 13306B std - - The instruction codes are mapped to routines as follows: - - Instr. 2100 21MX-M 21MX-E 21MX-F Instr. 2100 21MX-M 21MX-E 21MX-F - ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ - 105200 -- -- -- [test] 105220 .XFER .XFER .XFER .XFER - 105201 DBLE DBLE DBLE DBLE 105221 .GOTO .GOTO .GOTO .GOTO - 105202 SNGL SNGL SNGL SNGL 105222 ..MAP ..MAP ..MAP ..MAP - 105203 .XMPY .XMPY .XMPY -- 105223 .ENTR .ENTR .ENTR .ENTR - 105204 .XDIV .XDIV .XDIV -- 105224 .ENTP .ENTP .ENTP .ENTP - 105205 .DFER .DFER .DFER .DFER 105225 -- .PWR2 .PWR2 .PWR2 - 105206 -- .XPAK .XPAK .XPAK 105226 -- .FLUN .FLUN .FLUN - 105207 -- XADD XADD .BLE 105227 $SETP $SETP $SETP $SETP - - 105210 -- XSUB XSUB -- 105230 -- .PACK .PACK .PACK - 105211 -- XMPY XMPY -- 105231 -- -- .CFER .CFER - 105212 -- XDIV XDIV -- 105232 -- -- -- ..FCM - 105213 .XADD .XADD .XADD -- 105233 -- -- -- ..TCM - 105214 .XSUB .XSUB .XSUB .NGL 105234 -- -- -- -- - 105215 -- .XCOM .XCOM .XCOM 105235 -- -- -- -- - 105216 -- ..DCM ..DCM ..DCM 105236 -- -- -- -- - 105217 -- DDINT DDINT DDINT 105237 -- -- -- -- - - Notes: - - 1. The "$SETP" instruction is sometimes listed as ".SETP" in the - documentation. - - 2. Extended-precision arithmetic routines (e.g., .XMPY) exist on the - 21MX-F, but they are assigned instruction codes in the single-precision - floating-point module. - - 3. The software implementation of ..MAP supports 1-, 2-, or 3-dimensional - arrays, designated by setting A = -1, 0, and +1, respectively. The - firmware implementation supports only 2- and 3-dimensional access. - - 4. The documentation for ..MAP for the 2100 FFP shows A = 0 or -1 for two - or three dimensions, respectively, but the 21MX FFP shows A = 0 or +1. - The firmware actually only checks the LSB of A. - - 5. The .DFER and .XFER implementations for the 2100 FFP return X+4 and Y+4 - in the A and B registers, whereas the 21MX FFP returns X+3 and Y+3. - - 6. The .XFER implementation for the 2100 FFP returns to P+2, whereas the - 21MX implementation returns to P+1. - - Additional references: - - DOS/RTE Relocatable Library Reference Manual (24998-90001, Oct-1981) - - Implementing the HP 2100 Fast FORTRAN Processor (12907-90010, Nov-1974) -*/ - -static const OP_PAT op_ffp[32] = { - OP_N, OP_AAF, OP_AX, OP_AXX, /* --- DBLE SNGL .XMPY */ - OP_AXX, OP_AA, OP_A, OP_AAXX, /* .XDIV .DFER .XPAK XADD */ - OP_AAXX, OP_AAXX, OP_AAXX, OP_AXX, /* XSUB XMPY XDIV .XADD */ - OP_AXX, OP_A, OP_A, OP_AAX, /* .XSUB .XCOM ..DCM DDINT */ - OP_N, OP_AK, OP_KKKK, OP_A, /* .XFER .GOTO ..MAP .ENTR */ - OP_A, OP_K, OP_N, OP_K, /* .ENTP .PWR2 .FLUN $SETP */ - OP_C, OP_AA, OP_N, OP_N, /* .PACK .CFER --- --- */ - OP_N, OP_N, OP_N, OP_N /* --- --- --- --- */ - }; - -static t_stat cpu_ffp (uint32 IR, uint32 intrq) +void WriteOp (uint32 va, OP operand, OPSIZE precision) { -t_stat reason = SCPE_OK; -OPS op, op2; -uint32 entry; -uint32 j, sa, sb, sc, da, dc, ra, MA; -int32 i; -XPN xop; +uint32 i; -if ((cpu_unit.flags & UNIT_FFP) == 0) /* FFP option installed? */ - return stop_inst; +if (precision == in_s) + WriteW (va, operand.word); /* write single integer */ -entry = IR & 037; /* mask to entry point */ - -if (op_ffp[entry] != OP_N) { - if (reason = get_ops (op_ffp[entry], op, intrq)) /* get instruction operands */ - return reason; +else if (precision == in_d) { + WriteW (va, (operand.dword >> 16) & DMASK); /* write double integer */ + WriteW ((va + 1) & VAMASK, operand.dword & DMASK); /* high word, then low word */ } -switch (entry) { /* decode IR<3:0> */ - -/* FFP module 1 */ - - case 001: /* DBLE 105201 (OP_AAF) */ - WriteW (op[1]++, (op[2] >> 16) & DMASK); /* transfer high mantissa */ - WriteW (op[1]++, op[2] & 0177400); /* convert low mantissa */ - WriteW (op[1], op[2] & 0377); /* convert exponent */ - break; - - case 002: /* SNGL 105202 (OP_AX) */ - BR = op[2] >> 16; /* move LSB and expon to B */ - f_unpack (); /* unpack B into A/B */ - sa = AR; /* save exponent */ - AR = (op[1] >> 16) & DMASK; /* move MSB to A */ - BR = (op[1] & DMASK) | (BR != 0); /* move mid to B with carry */ - O = f_pack (SEXT (sa)); /* pack into A/B */ - break; - -#if defined (HAVE_INT64) - - case 003: /* .XMPY 105203 (OP_AXX) */ - i = 0; /* params start at op[0] */ - goto XMPY; /* process as XMPY */ - - case 004: /* .XDIV 105204 (OP_AXX) */ - i = 0; /* params start at op[0] */ - goto XDIV; /* process as XDIV */ - -#endif - - case 005: /* .DFER 105205 (OP_AA) */ - BR = op[0]; /* get destination address */ - AR = op[1]; /* get source address */ - goto XFER; /* do transfer */ - -#if defined (HAVE_INT64) - - case 006: /* .XPAK 105206 (OP_A) */ - if (UNIT_CPU_TYPE != UNIT_TYPE_21MX) /* must be 21MX */ - return stop_inst; /* trap if not */ - if (intrq) { /* interrupt pending? */ - PC = err_PC; /* restart instruction */ - break; - } - xop = ReadX (op[0]); /* read unpacked */ - O = x_pak (&xop, xop, SEXT (AR)); /* pack mantissa, exponent */ - WriteX (op[0], xop); /* write back */ - break; - - case 007: /* XADD 105207 (OP_AAXX) */ - i = 1; /* params start at op[1] */ - XADD: /* enter here from .XADD */ - if (intrq) { /* interrupt pending? */ - PC = err_PC; /* restart instruction */ - break; - } - O = x_add (&xop, AS_XPN (op [i + 1]), AS_XPN (op [i + 3])); /* add ops */ - WriteX (op[i], xop); /* write sum */ - break; - - case 010: /* XSUB 105210 (OP_AAXX) */ - i = 1; /* params start at op[1] */ - XSUB: /* enter here from .XSUB */ - if (intrq) { /* interrupt pending? */ - PC = err_PC; /* restart instruction */ - break; - } - O = x_sub (&xop, AS_XPN (op [i + 1]), AS_XPN (op [i + 3])); /* subtract */ - WriteX (op[i], xop); /* write difference */ - break; - - case 011: /* XMPY 105211 (OP_AAXX) */ - i = 1; /* params start at op[1] */ - XMPY: /* enter here from .XMPY */ - if (intrq) { /* interrupt pending? */ - PC = err_PC; /* restart instruction */ - break; - } - O = x_mpy (&xop, AS_XPN (op [i + 1]), AS_XPN (op [i + 3])); /* multiply */ - WriteX (op[i], xop); /* write product */ - break; - - case 012: /* XDIV 105212 (OP_AAXX) */ - i = 1; /* params start at op[1] */ - XDIV: /* enter here from .XDIV */ - if (intrq) { /* interrupt pending? */ - PC = err_PC; /* restart instruction */ - break; - } - O = x_div (&xop, AS_XPN (op [i + 1]), AS_XPN (op [i + 3])); /* divide */ - WriteX (op[i], xop); /* write quotient */ - break; - - case 013: /* .XADD 105213 (OP_AXX) */ - i = 0; /* params start at op[0] */ - goto XADD; /* process as XADD */ - - case 014: /* .XSUB 105214 (OP_AXX) */ - i = 0; /* params start at op[0] */ - goto XSUB; /* process as XSUB */ - - case 015: /* .XCOM 105215 (OP_A) */ - if (UNIT_CPU_TYPE != UNIT_TYPE_21MX) /* must be 21MX */ - return stop_inst; /* trap if not */ - xop = ReadX (op[0]); /* read operand */ - AR = x_com (&xop); /* neg and rtn exp adj */ - WriteX (op[0], xop); /* write result */ - break; - - case 016: /* ..DCM 105216 (OP_A) */ - if (UNIT_CPU_TYPE != UNIT_TYPE_21MX) /* must be 21MX */ - return stop_inst; /* trap if not */ - if (intrq) { /* interrupt pending? */ - PC = err_PC; /* restart instruction */ - break; - } - xop = ReadX (op[0]); /* read operand */ - O = x_dcm (&xop); /* negate */ - WriteX (op[0], xop); /* write result */ - break; - - case 017: /* DDINT 105217 (OP_AAX) */ - if (UNIT_CPU_TYPE != UNIT_TYPE_21MX) /* must be 21MX */ - return stop_inst; /* trap if not */ - if (intrq) { /* interrupt pending? */ - PC = err_PC; /* restart instruction */ - break; - } - x_trun (&xop, AS_XPN (op [2])); /* truncate operand */ - WriteX (op[1], xop); /* write result */ - break; - -#endif - -/* FFP module 2 */ - - case 020: /* .XFER 105220 (OP_N) */ - if (UNIT_CPU_TYPE == UNIT_TYPE_2100) - PC = (PC + 1) & VAMASK; /* 2100 .XFER returns to P+2 */ - XFER: /* enter here from .DFER */ - sc = 3; /* set count for 3-wd xfer */ - goto CFER; /* do transfer */ - - case 021: /* .GOTO 105221 (OP_AK) */ - if ((op[1] == 0) || (op[1] & SIGN)) /* index < 1? */ - op[1] = 1; /* reset min */ - sa = PC + op[1] - 1; /* point to jump target */ - if (sa >= op[0]) /* must be <= last target */ - sa = op[0] - 1; - da = ReadW (sa); /* get jump target */ - if (reason = resolve (da, &MA, intrq)) { /* resolve indirects */ - PC = err_PC; /* irq restarts instruction */ - break; - } - mp_dms_jmp (MA); /* validate jump addr */ - PCQ_ENTRY; /* record last PC */ - PC = MA; /* jump */ - BR = op[0]; /* (for 2100 FFP compat) */ - break; - - case 022: /* ..MAP 105222 (OP_KKKK) */ - op[1] = op[1] - 1; /* decrement 1st subscr */ - if ((AR & 1) == 0) /* 2-dim access? */ - op[1] = op[1] + (op[2] - 1) * op[3]; /* compute element offset */ - else { /* 3-dim access */ - if (reason = get_ops (OP_KK, op2, intrq)) { /* get 1st, 2nd ranges */ - PC = err_PC; /* irq restarts instruction */ - break; - } - op[1] = op[1] + ((op[3] - 1) * op2[1] + op[2] - 1) * op2[0]; /* offset */ - } - AR = (op[0] + op[1] * BR) & DMASK; /* return element address */ - break; - - case 023: /* .ENTR 105223 (OP_A) */ - MA = PC - 3; /* get addr of entry point */ - ENTR: /* enter here from .ENTP */ - da = op[0]; /* get addr of 1st formal */ - dc = MA - da; /* get count of formals */ - sa = ReadW (MA); /* get addr of return point */ - ra = ReadW (sa++); /* get rtn, ptr to 1st actual */ - WriteW (MA, ra); /* stuff rtn into caller's ent */ - sc = ra - sa; /* get count of actuals */ - if (sc > dc) sc = dc; /* use min (actuals, formals) */ - for (j = 0; j < sc; j++) { - MA = ReadW (sa++); /* get addr of actual */ - if (reason = resolve (MA, &MA, intrq)) { /* resolve indirect */ - PC = err_PC; /* irq restarts instruction */ - break; - } - WriteW (da++, MA); /* put addr into formal */ - } - AR = ra; /* return address */ - BR = da; /* addr of 1st unused formal */ - break; - - case 024: /* .ENTP 105224 (OP_A) */ - MA = PC - 5; /* get addr of entry point */ - goto ENTR; - - case 025: /* .PWR2 105225 (OP_K) */ - if (UNIT_CPU_TYPE != UNIT_TYPE_21MX) /* must be 21MX */ - return stop_inst; /* trap if not */ - f_pwr2 (SEXT (op[0])); /* calc result into A/B */ - break; - - case 026: /* .FLUN 105226 (OP_N) */ - if (UNIT_CPU_TYPE != UNIT_TYPE_21MX) /* must be 21MX */ - return stop_inst; /* trap if not */ - f_unpack (); /* unpack into A/B */ - break; - - case 027: /* $SETP 105227 (OP_K) */ - j = sa = AR; /* save initial value */ - sb = BR; /* save initial address */ - AR = 0; /* AR will return = 0 */ - BR = BR & VAMASK; /* addr must be direct */ - do { - WriteW (BR, j); /* write value to address */ - j = (j + 1) & DMASK; /* incr value */ - BR = (BR + 1) & VAMASK; /* incr address */ - op[0] = op[0] - 1; /* decr count */ - if (op[0] && intrq) { /* more and intr? */ - AR = sa; /* restore A */ - BR = sb; /* restore B */ - PC = err_PC; /* restart instruction */ - break; - } - } - while (op[0] != 0); /* loop until count exhausted */ - break; - - case 030: /* .PACK 105230 (OP_C) */ - if (UNIT_CPU_TYPE != UNIT_TYPE_21MX) /* must be 21MX */ - return stop_inst; /* trap if not */ - O = f_pack (SEXT (op[0])); /* calc A/B and overflow */ - break; - - case 031: /* .CFER 105231 (OP_AA) */ - if (UNIT_CPU_MODEL != UNIT_21MX_E) /* must be 21MX E-series */ - return stop_inst; /* trap if not */ - BR = op[0]; /* get destination address */ - AR = op[1]; /* get source address */ - sc = 4; /* set for 4-wd xfer */ - CFER: /* enter here from .XFER */ - for (j = 0; j < sc; j++) { /* xfer loop */ - WriteW (BR, ReadW (AR)); /* transfer word */ - AR = (AR + 1) & VAMASK; /* bump source addr */ - BR = (BR + 1) & VAMASK; /* bump destination addr */ - } - E = 0; /* routine clears E */ - if (UNIT_CPU_TYPE == UNIT_TYPE_2100) { /* 2100 (and .DFER/.XFER)? */ - AR = (AR + 1) & VAMASK; /* 2100 FFP returns X+4, Y+4 */ - BR = (BR + 1) & VAMASK; - } - break; - - default: /* others undefined */ - reason = stop_inst; +else + for (i = 0; i < (uint32) precision; i++) { /* write fp 2 to 5 words */ + WriteW (va, operand.fpk[i]); + va = (va + 1) & VAMASK; } - -return reason; +return; } -/* 2000 I/O Processor - The IOP accelerates certain operations of the HP 2000 Time-Share BASIC system - I/O processor. Most 2000 systems were delivered with 2100 CPUs, although IOP - microcode was developed for the 21MX-M and 21MX-E. As the I/O processors - were specific to the 2000 system, general compatibility with other CPU - microcode options was unnecessary, and indeed no other options were possible - for the 2100. - - Option implementation by CPU was as follows: - - 2116 2100 21MX-M 21MX-E 21MX-F - ------ ------ ------ ------ ------ - N/A 13206A 13207A 22702A N/A - - The routines are mapped to instruction codes as follows: - - Instr. 2100 21MX-M/E Description - ------ ---------- ---------- -------------------------------------------- - SAI 105060-117 101400-037 Store A indexed by B (+/- offset in IR<4:0>) - LAI 105020-057 105400-037 Load A indexed by B (+/- offset in IR<4:0>) - CRC 105150 105460 Generate CRC - REST 105340 105461 Restore registers from stack - READF 105220 105462 Read F register (stack pointer) - INS -- 105463 Initialize F register (stack pointer) - ENQ 105240 105464 Enqueue - PENQ 105257 105465 Priority enqueue - DEQ 105260 105466 Dequeue - TRSLT 105160 105467 Translate character - ILIST 105000 105470 Indirect address list (similar to $SETP) - PRFEI 105222 105471 Power fail exit with I/O - PRFEX 105223 105472 Power fail exit - PRFIO 105221 105473 Power fail I/O - SAVE 105362 105474 Save registers to stack - - MBYTE 105120 105765 Move bytes (MBT) - MWORD 105200 105777 Move words (MVW) - SBYTE 105300 105764 Store byte (SBT) - LBYTE 105320 105763 Load byte (LBT) - - The INS instruction was not required in the 2100 implementation because the - stack pointer was actually the memory protect fence register and so could be - loaded directly with an OTA/B 05. Also, the 21MX implementation did not - offer the MBYTE, MWORD, SBYTE, and LBYTE instructions because the equivalent - instructions from the standard Extended Instruction Group were used instead. - - Additional reference: - - HP 2000 Computer System Sources and Listings Documentation - (22687-90020, undated), section 3, pages 2-74 through 2-91. -*/ - -static const OP_PAT op_iop[16] = { - OP_V, OP_N, OP_N, OP_N, /* CRC RESTR READF INS */ - OP_N, OP_N, OP_N, OP_V, /* ENQ PENQ DEQ TRSLT */ - OP_AC, OP_CVA, OP_A, OP_CV, /* ILIST PRFEI PRFEX PRFIO */ - OP_N, OP_N, OP_N, OP_N /* SAVE --- --- --- */ - }; - -static t_stat cpu_iop (uint32 IR, uint32 intrq) -{ -t_stat reason = SCPE_OK; -OPS op; -uint32 entry; -uint32 hp, tp, i, t, wc, MA; - -if ((cpu_unit.flags & UNIT_IOP) == 0) /* IOP option installed? */ - return stop_inst; - -entry = IR & 077; /* mask to entry point */ - -if (entry <= 037) { /* LAI/SAI 10x400-437 */ - MA = ((entry - 020) + BR) & VAMASK; /* +/- offset */ - if (IR & I_AB) AR = ReadW (MA); /* AB = 1 -> LAI */ - else WriteW (MA, AR); /* AB = 0 -> SAI */ - return reason; - } -else if (entry <= 057) /* IR = 10x440-457? */ - return stop_inst; /* not part of IOP */ - -entry = entry - 060; /* offset 10x460-477 */ - -if (op_iop[entry] != OP_N) { - if (reason = get_ops (op_iop[entry], op, intrq)) /* get instruction operands */ - return reason; - } - -switch (entry) { /* decode IR<5:0> */ - - case 000: /* CRC 105460 (OP_V) */ - t = ReadW (op[0]) ^ (AR & 0377); /* xor prev CRC and char */ - for (i = 0; i < 8; i++) { /* apply polynomial */ - t = (t >> 1) | ((t & 1) << 15); /* rotate right */ - if (t & SIGN) t = t ^ 020001; /* old t<0>? xor */ - } - WriteW (op[0], t); /* rewrite CRC */ - break; - - case 001: /* RESTR 105461 (OP_N) */ - iop_sp = (iop_sp - 1) & VAMASK; /* decr stack ptr */ - t = ReadW (iop_sp); /* get E and O */ - O = ((t >> 1) ^ 1) & 1; /* restore O */ - E = t & 1; /* restore E */ - iop_sp = (iop_sp - 1) & VAMASK; /* decr sp */ - BR = ReadW (iop_sp); /* restore B */ - iop_sp = (iop_sp - 1) & VAMASK; /* decr sp */ - AR = ReadW (iop_sp); /* restore A */ - if (UNIT_CPU_MODEL == UNIT_2100) - mp_fence = iop_sp; /* 2100 keeps sp in MP FR */ - break; - - case 002: /* READF 105462 (OP_N) */ - AR = iop_sp; /* copy stk ptr */ - break; - - case 003: /* INS 105463 (OP_N) */ - iop_sp = AR; /* init stk ptr */ - break; - - case 004: /* ENQ 105464 (OP_N) */ - hp = ReadW (AR & VAMASK); /* addr of head */ - tp = ReadW ((AR + 1) & VAMASK); /* addr of tail */ - WriteW ((BR - 1) & VAMASK, 0); /* entry link */ - WriteW ((tp - 1) & VAMASK, BR); /* tail link */ - WriteW ((AR + 1) & VAMASK, BR); /* queue tail */ - if (hp != 0) PC = (PC + 1) & VAMASK; /* q not empty? skip */ - break; - - case 005: /* PENQ 105465 (OP_N) */ - hp = ReadW (AR & VAMASK); /* addr of head */ - WriteW ((BR - 1) & VAMASK, hp); /* becomes entry link */ - WriteW (AR & VAMASK, BR); /* queue head */ - if (hp == 0) /* q empty? */ - WriteW ((AR + 1) & VAMASK, BR); /* queue tail */ - else PC = (PC + 1) & VAMASK; /* skip */ - break; - - case 006: /* DEQ 105466 (OP_N) */ - BR = ReadW (AR & VAMASK); /* addr of head */ - if (BR) { /* queue not empty? */ - hp = ReadW ((BR - 1) & VAMASK); /* read hd entry link */ - WriteW (AR & VAMASK, hp); /* becomes queue head */ - if (hp == 0) /* q now empty? */ - WriteW ((AR + 1) & VAMASK, (AR + 1) & DMASK); - PC = (PC + 1) & VAMASK; /* skip */ - } - break; - - case 007: /* TRSLT 105467 (OP_V) */ - wc = ReadW (op[0]); /* get count */ - if (wc & SIGN) break; /* cnt < 0? */ - while (wc != 0) { /* loop */ - MA = (AR + AR + ReadB (BR)) & VAMASK; - t = ReadB (MA); /* xlate */ - WriteB (BR, t); /* store char */ - BR = (BR + 1) & DMASK; /* incr ptr */ - wc = (wc - 1) & DMASK; /* decr cnt */ - if (wc && intrq) { /* more and intr? */ - WriteW (op[0], wc); /* save count */ - PC = err_PC; /* stop for now */ - break; - } - } - break; - - case 010: /* ILIST 105470 (OP_AC) */ - do { /* for count */ - WriteW (op[0], AR); /* write AR to mem */ - AR = (AR + 1) & DMASK; /* incr AR */ - op[0] = (op[0] + 1) & VAMASK; /* incr MA */ - op[1] = (op[1] - 1) & DMASK; /* decr count */ - } - while (op[1] != 0); - break; - - case 011: /* PRFEI 105471 (OP_CVA) */ - WriteW (op[1], 1); /* set flag */ - reason = iogrp (op[0], 0); /* execute I/O instr */ - op[0] = op[2]; /* set rtn and fall through */ - - case 012: /* PRFEX 105472 (OP_A) */ - PCQ_ENTRY; - PC = ReadW (op[0]) & VAMASK; /* jump indirect */ - WriteW (op[0], 0); /* clear exit */ - break; - - case 013: /* PRFIO 105473 (OP_CV) */ - WriteW (op[1], 1); /* set flag */ - reason = iogrp (op[0], 0); /* execute instr */ - break; - - case 014: /* SAVE 105474 (OP_N) */ - WriteW (iop_sp, AR); /* save A */ - iop_sp = (iop_sp + 1) & VAMASK; /* incr stack ptr */ - WriteW (iop_sp, BR); /* save B */ - iop_sp = (iop_sp + 1) & VAMASK; /* incr stack ptr */ - t = ((O ^ 1) << 1) | E; /* merge E and O */ - WriteW (iop_sp, t); /* save E and O */ - iop_sp = (iop_sp + 1) & VAMASK; /* incr stack ptr */ - if (UNIT_CPU_TYPE == UNIT_TYPE_2100) - mp_fence = iop_sp; /* 2100 keeps sp in MP FR */ - break; - - default: /* instruction undefined */ - return stop_inst; - } - -return reason; -} - -/* Dynamic Mapping System - - The 21MX Dynamic Mapping System (DMS) consisted of the 12731A Memory - Expansion Module (MEM) card and 38 instructions to expand the basic 32K - logical address space to a 1024K physical space. The MEM provided four maps - of 32 mapping registers each: a system map, a user map, and two DCPC maps. - DMS worked in conjunction with memory protect to provide a "protected mode" - in which memory read and write violations could be trapped, and that - inhibited "privileged" instruction execution that attempted to alter the - memory mapping. - - Option implementation by CPU was as follows: - - 2116 2100 21MX-M 21MX-E 21MX-F - ------ ------ ------ ------ ------ - N/A N/A 12976B 13307B std - - The instruction codes are mapped to routines as follows: - - Instr. 21MX-M 21MX-E/F Instr. 21MX-M 21MX-E/F - ------ ------ -------- ------ ------ -------- - 10x700 [xmm] [xmm] 10x720 XMM XMM - 10x701 [nop] [test] 10x721 XMS XMS - 10x702 MBI MBI 10x722 XM* XM* - 10x703 MBF MBF 10x723 [nop] [nop] - 10x704 MBW MBW 10x724 XL* XL* - 10x705 MWI MWI 10x725 XS* XS* - 10x706 MWF MWF 10x726 XC* XC* - 10x707 MWW MWW 10x727 LF* LF* - 10x710 SY* SY* 10x730 RS* RS* - - 10x711 US* US* 10x731 RV* RV* - 10x712 PA* PA* 10x732 DJP DJP - 10x713 PB* PB* 10x733 DJS DJS - 10x714 SSM SSM 10x734 SJP SJP - 10x715 JRS JRS 10x735 SJS SJS - 10x716 [nop] [nop] 10x736 UJP UJP - 10x717 [nop] [nop] 10x737 UJS UJS - - Instructions that use IR bit 9 to select the A or B register are designated - with a * above (e.g., 101710 is SYA, and 105710 is SYB). For those that do - not use this feature, either the 101xxx or 105xxx code will execute the - corresponding instruction, although the 105xxx form is the documented - instruction code. - - Notes: - - 1. Instruction code 10x700 will execute the XMM instruction, although - 10x720 is the documented instruction value. - - 2. The DMS privilege violation rules are: - - load map and CTL5 set (XMM, XMS, XM*, SY*, US*, PA*, PB*) - - load state or fence and UMAP set (JRS, DJP, DJS, SJP, SJS, UJP, UJS, LF*) - - 3. The 21MX manual is incorrect in stating that M*I, M*W, XS* are - privileged. -*/ - -static const OP_PAT op_dms[32] = { - OP_N, OP_N, OP_N, OP_N, /* xmm test MBI MBF */ - OP_N, OP_N, OP_N, OP_N, /* MBW MWI MWF MWW */ - OP_N, OP_N, OP_N, OP_N, /* SYA/B USA/B PAA/B PBA/B */ - OP_A, OP_KA, OP_N, OP_N, /* SSM JRS nop nop */ - OP_N, OP_N, OP_N, OP_N, /* XMM XMS XMA/B nop */ - OP_A, OP_A, OP_A, OP_N, /* XLA/B XSA/B XCA/B LFA/B */ - OP_N, OP_N, OP_A, OP_A, /* RSA/B RVA/B DJP DJS */ - OP_A, OP_A, OP_A, OP_A /* SJP SJS UJP UJS */ - }; - -static t_stat cpu_dms (uint32 IR, uint32 intrq) -{ -t_stat reason = SCPE_OK; -OPS op; -uint32 entry, absel; -uint32 i, t, mapi, mapj; - -if ((cpu_unit.flags & UNIT_DMS) == 0) /* DMS option installed? */ - return stop_inst; - -absel = (IR & I_AB)? 1: 0; /* get A/B select */ -entry = IR & 037; /* mask to entry point */ - -if (op_dms[entry] != OP_N) { - if (reason = get_ops (op_dms[entry], op, intrq)) /* get instruction operands */ - return reason; - } - -switch (entry) { /* decode IR<3:0> */ - -/* DMS module 1 */ - - case 000: /* [undefined] 105700 (OP_N) */ - goto XMM; /* decodes as XMM */ - - case 001: /* [self test] 105701 (OP_N) */ - ABREG[absel] = ABREG[absel] ^ DMASK; /* CMA or CMB */ - break; - - case 002: /* MBI 105702 (OP_N) */ - AR = AR & ~1; /* force A, B even */ - BR = BR & ~1; - while (XR != 0) { /* loop */ - t = ReadB (AR); /* read curr */ - WriteBA (BR, t); /* write alt */ - AR = (AR + 1) & DMASK; /* incr ptrs */ - BR = (BR + 1) & DMASK; - XR = (XR - 1) & DMASK; - if (XR && intrq && !(AR & 1)) { /* more, int, even? */ - PC = err_PC; /* stop for now */ - break; - } - } - break; - - case 003: /* MBF 105703 (OP_N) */ - AR = AR & ~1; /* force A, B even */ - BR = BR & ~1; - while (XR != 0) { /* loop */ - t = ReadBA (AR); /* read alt */ - WriteB (BR, t); /* write curr */ - AR = (AR + 1) & DMASK; /* incr ptrs */ - BR = (BR + 1) & DMASK; - XR = (XR - 1) & DMASK; - if (XR && intrq && !(AR & 1)) { /* more, int, even? */ - PC = err_PC; /* stop for now */ - break; - } - } - break; - - case 004: /* MBW 105704 (OP_N) */ - AR = AR & ~1; /* force A, B even */ - BR = BR & ~1; - while (XR != 0) { /* loop */ - t = ReadBA (AR); /* read alt */ - WriteBA (BR, t); /* write alt */ - AR = (AR + 1) & DMASK; /* incr ptrs */ - BR = (BR + 1) & DMASK; - XR = (XR - 1) & DMASK; - if (XR && intrq && !(AR & 1)) { /* more, int, even? */ - PC = err_PC; /* stop for now */ - break; - } - } - break; - - case 005: /* MWI 105705 (OP_N) */ - while (XR != 0) { /* loop */ - t = ReadW (AR & VAMASK); /* read curr */ - WriteWA (BR & VAMASK, t); /* write alt */ - AR = (AR + 1) & DMASK; /* incr ptrs */ - BR = (BR + 1) & DMASK; - XR = (XR - 1) & DMASK; - if (XR && intrq) { /* more and intr? */ - PC = err_PC; /* stop for now */ - break; - } - } - break; - - case 006: /* MWF 105706 (OP_N) */ - while (XR != 0) { /* loop */ - t = ReadWA (AR & VAMASK); /* read alt */ - WriteW (BR & VAMASK, t); /* write curr */ - AR = (AR + 1) & DMASK; /* incr ptrs */ - BR = (BR + 1) & DMASK; - XR = (XR - 1) & DMASK; - if (XR && intrq) { /* more and intr? */ - PC = err_PC; /* stop for now */ - break; - } - } - break; - - case 007: /* MWW 105707 (OP_N) */ - while (XR != 0) { /* loop */ - t = ReadWA (AR & VAMASK); /* read alt */ - WriteWA (BR & VAMASK, t); /* write alt */ - AR = (AR + 1) & DMASK; /* incr ptrs */ - BR = (BR + 1) & DMASK; - XR = (XR - 1) & DMASK; - if (XR && intrq) { /* more and intr? */ - PC = err_PC; /* stop for now */ - break; - } - } - break; - - case 010: /* SYA, SYB 10x710 (OP_N) */ - case 011: /* USA, USB 10x711 (OP_N) */ - case 012: /* PAA, PAB 10x712 (OP_N) */ - case 013: /* PBA, PBB 10x713 (OP_N) */ - mapi = (IR & 03) << VA_N_PAG; /* map base */ - if (ABREG[absel] & SIGN) { /* store? */ - for (i = 0; i < MAP_LNT; i++) { - t = dms_rmap (mapi + i); /* map to memory */ - WriteW ((ABREG[absel] + i) & VAMASK, t); - } - } - else { /* load */ - dms_viol (err_PC, MVI_PRV); /* priv if PRO */ - for (i = 0; i < MAP_LNT; i++) { - t = ReadW ((ABREG[absel] + i) & VAMASK); - dms_wmap (mapi + i, t); /* mem to map */ - } - } - ABREG[absel] = (ABREG[absel] + MAP_LNT) & DMASK; - break; - - case 014: /* SSM 105714 (OP_A) */ - WriteW (op[0], dms_upd_sr ()); /* store stat */ - break; - - case 015: /* JRS 105715 (OP_KA) */ - if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ - dms_enb = 0; /* assume off */ - dms_ump = SMAP; - if (op[0] & 0100000) { /* set enable? */ - dms_enb = 1; - if (op[0] & 0040000) dms_ump = UMAP; /* set/clr usr */ - } - mp_dms_jmp (op[1]); /* mpck jmp target */ - PCQ_ENTRY; /* save old PC */ - PC = op[1]; /* jump */ - ion_defer = 1; /* defer intr */ - break; - -/* DMS module 2 */ - - case 020: /* XMM 105720 (OP_N) */ - XMM: - if (XR == 0) break; /* nop? */ - while (XR != 0) { /* loop */ - if (XR & SIGN) { /* store? */ - t = dms_rmap (AR); /* map to mem */ - WriteW (BR & VAMASK, t); - XR = (XR + 1) & DMASK; - } - else { /* load */ - dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ - t = ReadW (BR & VAMASK); /* mem to map */ - dms_wmap (AR, t); - XR = (XR - 1) & DMASK; - } - AR = (AR + 1) & DMASK; - BR = (BR + 1) & DMASK; - if (intrq && ((XR & 017) == 017)) { /* intr, grp of 16? */ - PC = err_PC; /* stop for now */ - break; - } - } - break; - - case 021: /* XMS 105721 (OP_N) */ - if ((XR & SIGN) || (XR == 0)) break; /* nop? */ - dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ - while (XR != 0) { - dms_wmap (AR, BR); /* AR to map */ - XR = (XR - 1) & DMASK; - AR = (AR + 1) & DMASK; - BR = (BR + 1) & DMASK; - if (intrq && ((XR & 017) == 017)) { /* intr, grp of 16? */ - PC = err_PC; - break; - } - } - break; - - case 022: /* XMA, XMB 10x722 (OP_N) */ - dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ - if (ABREG[absel] & 0100000) mapi = UMAP; - else mapi = SMAP; - if (ABREG[absel] & 0000001) mapj = PBMAP; - else mapj = PAMAP; - for (i = 0; i < MAP_LNT; i++) { - t = dms_rmap (mapi + i); /* read map */ - dms_wmap (mapj + i, t); /* write map */ - } - break; - - case 024: /* XLA, XLB 10x724 (OP_A) */ - ABREG[absel] = ReadWA (op[0]); /* load alt */ - break; - - case 025: /* XSA, XSB 10x725 (OP_A) */ - WriteWA (op[0], ABREG[absel]); /* store alt */ - break; - - case 026: /* XCA, XCB 10x726 (OP_A) */ - if (ABREG[absel] != ReadWA (op[0])) /* compare alt */ - PC = (PC + 1) & VAMASK; - break; - - case 027: /* LFA, LFB 10x727 (OP_N) */ - if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ - dms_sr = (dms_sr & ~(MST_FLT | MST_FENCE)) | - (ABREG[absel] & (MST_FLT | MST_FENCE)); - break; - - case 030: /* RSA, RSB 10x730 (OP_N) */ - ABREG[absel] = dms_upd_sr (); /* save stat */ - break; - - case 031: /* RVA, RVB 10x731 (OP_N) */ - ABREG[absel] = dms_vr; /* save viol */ - break; - - case 032: /* DJP 105732 (OP_A) */ - if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ - mp_dms_jmp (op[0]); /* validate jump addr */ - PCQ_ENTRY; /* save curr PC */ - PC = op[0]; /* new PC */ - dms_enb = 0; /* disable map */ - dms_ump = SMAP; - ion_defer = 1; - break; - - case 033: /* DJS 105733 (OP_A) */ - if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ - WriteW (op[0], PC); /* store ret addr */ - PCQ_ENTRY; /* save curr PC */ - PC = (op[0] + 1) & VAMASK; /* new PC */ - dms_enb = 0; /* disable map */ - dms_ump = SMAP; - ion_defer = 1; /* defer intr */ - break; - - case 034: /* SJP 105734 (OP_A) */ - if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ - mp_dms_jmp (op[0]); /* validate jump addr */ - PCQ_ENTRY; /* save curr PC */ - PC = op[0]; /* jump */ - dms_enb = 1; /* enable system */ - dms_ump = SMAP; - ion_defer = 1; /* defer intr */ - break; - - case 035: /* SJS 105735 (OP_A) */ - if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ - t = PC; /* save retn addr */ - PCQ_ENTRY; /* save curr PC */ - PC = (op[0] + 1) & VAMASK; /* new PC */ - dms_enb = 1; /* enable system */ - dms_ump = SMAP; - WriteW (op[0], t); /* store ret addr */ - ion_defer = 1; /* defer intr */ - break; - - case 036: /* UJP 105736 (OP_A) */ - if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ - mp_dms_jmp (op[0]); /* validate jump addr */ - PCQ_ENTRY; /* save curr PC */ - PC = op[0]; /* jump */ - dms_enb = 1; /* enable user */ - dms_ump = UMAP; - ion_defer = 1; /* defer intr */ - break; - - case 037: /* UJS 105737 (OP_A) */ - if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ - t = PC; /* save retn addr */ - PCQ_ENTRY; /* save curr PC */ - PC = (op[0] + 1) & VAMASK; /* new PC */ - dms_enb = 1; /* enable user */ - dms_ump = UMAP; - WriteW (op[0], t); /* store ret addr */ - ion_defer = 1; /* defer intr */ - break; - - default: /* others NOP */ - break; - } - -return reason; -} - -/* Extended Instruction Group - - The Extended Instruction Group (EIG) adds 32 index and 10 bit/byte/word - manipulation instructions to the 21MX base set. These instructions - use the new X and Y index registers that were added to the 21MX. - - Option implementation by CPU was as follows: - - 2116 2100 21MX-M 21MX-E 21MX-F - ------ ------ ------ ------ ------ - N/A N/A std std std - - The instruction codes are mapped to routines as follows: - - Instr. 21MX-M/E/F Instr. 21MX-M/E/F - ------ ---------- ------ ---------- - 10x740 S*X 10x760 ISX - 10x741 C*X 10x761 DSX - 10x742 L*X 10x762 JLY - 10x743 STX 10x763 LBT - 10x744 CX* 10x764 SBT - 10x745 LDX 10x765 MBT - 10x746 ADX 10x766 CBT - 10x747 X*X 10x767 SFB - - 10x750 S*Y 10x770 ISY - 10x751 C*Y 10x771 DSY - 10x752 L*Y 10x772 JPY - 10x753 STY 10x773 SBS - 10x754 CY* 10x774 CBS - 10x755 LDY 10x775 TBS - 10x756 ADY 10x776 CMW - 10x757 X*Y 10x777 MVW - - Instructions that use IR bit 9 to select the A or B register are designated - with a * above (e.g., 101740 is SAX, and 105740 is SBX). For those that do - not use this feature, either the 101xxx or 105xxx code will execute the - corresponding instruction, although the 105xxx form is the documented - instruction code. - - Notes: - - 1. The LBT, SBT, MBT, and MVW instructions are used as part of the 2100 IOP - implementation. When so called, the MBT and MVW instructions have the - additional restriction that the count must be positive. -*/ - -static const OP_PAT op_eig[32] = { - OP_A, OP_N, OP_A, OP_A, /* S*X C*X L*X STX */ - OP_N, OP_K, OP_K, OP_N, /* CX* LDX ADX X*X */ - OP_A, OP_N, OP_A, OP_A, /* S*Y C*Y L*Y STY */ - OP_N, OP_K, OP_K, OP_N, /* CY* LDY ADY X*Y */ - OP_N, OP_N, OP_A, OP_N, /* ISX DSX JLY LBT */ - OP_N, OP_KV, OP_KV, OP_N, /* SBT MBT CBT SFB */ - OP_N, OP_N, OP_C, OP_KA, /* ISY DSY JPY SBS */ - OP_KA, OP_KK, OP_KV, OP_KV /* CBS TBS CMW MVW */ - }; - -static t_stat cpu_eig (uint32 IR, uint32 intrq) -{ -t_stat reason = SCPE_OK; -OPS op; -uint32 entry, absel; -uint32 t, v1, v2, wc; -int32 sop1, sop2; - -absel = (IR & I_AB)? 1: 0; /* get A/B select */ -entry = IR & 037; /* mask to entry point */ - -if (op_eig[entry] != OP_N) { - if (reason = get_ops (op_eig[entry], op, intrq)) /* get instruction operands */ - return reason; - } - -switch (entry) { /* decode IR<4:0> */ - -/* EIG module 1 */ - - case 000: /* SAX, SBX 10x740 (OP_A) */ - op[0] = (op[0] + XR) & VAMASK; /* indexed addr */ - WriteW (op[0], ABREG[absel]); /* store */ - break; - - case 001: /* CAX, CBX 10x741 (OP_N) */ - XR = ABREG[absel]; /* copy to XR */ - break; - - case 002: /* LAX, LBX 10x742 (OP_A) */ - op[0] = (op[0] + XR) & VAMASK; /* indexed addr */ - ABREG[absel] = ReadW (op[0]); /* load */ - break; - - case 003: /* STX 105743 (OP_A) */ - WriteW (op[0], XR); /* store XR */ - break; - - case 004: /* CXA, CXB 10x744 (OP_N) */ - ABREG[absel] = XR; /* copy from XR */ - break; - - case 005: /* LDX 105745 (OP_K)*/ - XR = op[0]; /* load XR */ - break; - - case 006: /* ADX 105746 (OP_K) */ - t = XR + op[0]; /* add to XR */ - if (t > DMASK) E = 1; /* set E, O */ - if (((~XR ^ op[0]) & (XR ^ t)) & SIGN) O = 1; - XR = t & DMASK; - break; - - case 007: /* XAX, XBX 10x747 (OP_N) */ - t = XR; /* exchange XR */ - XR = ABREG[absel]; - ABREG[absel] = t; - break; - - case 010: /* SAY, SBY 10x750 (OP_A) */ - op[0] = (op[0] + YR) & VAMASK; /* indexed addr */ - WriteW (op[0], ABREG[absel]); /* store */ - break; - - case 011: /* CAY, CBY 10x751 (OP_N) */ - YR = ABREG[absel]; /* copy to YR */ - break; - - case 012: /* LAY, LBY 10x752 (OP_A) */ - op[0] = (op[0] + YR) & VAMASK; /* indexed addr */ - ABREG[absel] = ReadW (op[0]); /* load */ - break; - - case 013: /* STY 105753 (OP_A) */ - WriteW (op[0], YR); /* store YR */ - break; - - case 014: /* CYA, CYB 10x754 (OP_N) */ - ABREG[absel] = YR; /* copy from YR */ - break; - - case 015: /* LDY 105755 (OP_K) */ - YR = op[0]; /* load YR */ - break; - - case 016: /* ADY 105756 (OP_K) */ - t = YR + op[0]; /* add to YR */ - if (t > DMASK) E = 1; /* set E, O */ - if (((~YR ^ op[0]) & (YR ^ t)) & SIGN) O = 1; - YR = t & DMASK; - break; - - case 017: /* XAY, XBY 10x757 (OP_N) */ - t = YR; /* exchange YR */ - YR = ABREG[absel]; - ABREG[absel] = t; - break; - -/* EIG module 2 */ - - case 020: /* ISX 105760 (OP_N) */ - XR = (XR + 1) & DMASK; /* incr XR */ - if (XR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */ - break; - - case 021: /* DSX 105761 (OP_N) */ - XR = (XR - 1) & DMASK; /* decr XR */ - if (XR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */ - break; - - case 022: /* JLY 105762 (OP_A) */ - mp_dms_jmp (op[0]); /* validate jump addr */ - PCQ_ENTRY; - YR = PC; /* ret addr to YR */ - PC = op[0]; /* jump */ - break; - - case 023: /* LBT 105763 (OP_N) */ - AR = ReadB (BR); /* load byte */ - BR = (BR + 1) & DMASK; /* incr ptr */ - break; - - case 024: /* SBT 105764 (OP_N) */ - WriteB (BR, AR); /* store byte */ - BR = (BR + 1) & DMASK; /* incr ptr */ - break; - - case 025: /* MBT 105765 (OP_KV) */ - wc = ReadW (op[1]); /* get continuation count */ - if (wc == 0) wc = op[0]; /* none? get initiation count */ - if ((wc & SIGN) && (UNIT_CPU_TYPE == UNIT_TYPE_2100)) - break; /* < 0 is NOP for 2100 IOP */ - while (wc != 0) { /* while count */ - WriteW (op[1], wc); /* for MP abort */ - t = ReadB (AR); /* move byte */ - WriteB (BR, t); - AR = (AR + 1) & DMASK; /* incr src */ - BR = (BR + 1) & DMASK; /* incr dst */ - wc = (wc - 1) & DMASK; /* decr cnt */ - if (intrq && wc) { /* intr, more to do? */ - PC = err_PC; /* back up PC */ - break; - } - } - WriteW (op[1], wc); /* clean up inline */ - break; - - case 026: /* CBT 105766 (OP_KV) */ - wc = ReadW (op[1]); /* get continuation count */ - if (wc == 0) wc = op[0]; /* none? get initiation count */ - while (wc != 0) { /* while count */ - WriteW (op[1], wc); /* for MP abort */ - v1 = ReadB (AR); /* get src1 */ - v2 = ReadB (BR); /* get src2 */ - if (v1 != v2) { /* compare */ - PC = (PC + 1 + (v1 > v2)) & VAMASK; - BR = (BR + wc) & DMASK; /* update BR */ - wc = 0; /* clr interim */ - break; - } - AR = (AR + 1) & DMASK; /* incr src1 */ - BR = (BR + 1) & DMASK; /* incr src2 */ - wc = (wc - 1) & DMASK; /* decr cnt */ - if (intrq && wc) { /* intr, more to do? */ - PC = err_PC; /* back up PC */ - break; - } - } - WriteW (op[1], wc); /* clean up inline */ - break; - - case 027: /* SFB 105767 (OP_N) */ - v1 = AR & 0377; /* test byte */ - v2 = (AR >> 8) & 0377; /* term byte */ - for (;;) { /* scan */ - t = ReadB (BR); /* read byte */ - if (t == v1) break; /* test match? */ - BR = (BR + 1) & DMASK; - if (t == v2) { /* term match? */ - PC = (PC + 1) & VAMASK; - break; - } - if (intrq) { /* int pending? */ - PC = err_PC; /* back up PC */ - break; - } - } - break; - - case 030: /* ISY 105770 (OP_N) */ - YR = (YR + 1) & DMASK; /* incr YR */ - if (YR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */ - break; - - case 031: /* DSY 105771 (OP_N) */ - YR = (YR - 1) & DMASK; /* decr YR */ - if (YR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */ - break; - - case 032: /* JPY 105772 (OP_C) */ - op[0] = (op[0] + YR) & VAMASK; /* index, no indir */ - mp_dms_jmp (op[0]); /* validate jump addr */ - PCQ_ENTRY; - PC = op[0]; /* jump */ - break; - - case 033: /* SBS 105773 (OP_KA) */ - WriteW (op[1], ReadW (op[1]) | op[0]); /* set bits */ - break; - - case 034: /* CBS 105774 (OP_KA) */ - WriteW (op[1], ReadW (op[1]) & ~op[0]); /* clear bits */ - break; - - case 035: /* TBS 105775 (OP_KK) */ - if ((op[1] & op[0]) != op[0]) /* test bits */ - PC = (PC + 1) & VAMASK; - break; - - case 036: /* CMW 105776 (OP_KV) */ - wc = ReadW (op[1]); /* get continuation count */ - if (wc == 0) wc = op[0]; /* none? get initiation count */ - while (wc != 0) { /* while count */ - WriteW (op[1], wc); /* for abort */ - v1 = ReadW (AR & VAMASK); /* first op */ - v2 = ReadW (BR & VAMASK); /* second op */ - sop1 = (int32) SEXT (v1); /* signed */ - sop2 = (int32) SEXT (v2); - if (sop1 != sop2) { /* compare */ - PC = (PC + 1 + (sop1 > sop2)) & VAMASK; - BR = (BR + wc) & DMASK; /* update BR */ - wc = 0; /* clr interim */ - break; - } - AR = (AR + 1) & DMASK; /* incr src1 */ - BR = (BR + 1) & DMASK; /* incr src2 */ - wc = (wc - 1) & DMASK; /* decr cnt */ - if (intrq && wc) { /* intr, more to do? */ - PC = err_PC; /* back up PC */ - break; - } - } - WriteW (op[1], wc); /* clean up inline */ - break; - - case 037: /* MVW 105777 (OP_KV) */ - wc = ReadW (op[1]); /* get continuation count */ - if (wc == 0) wc = op[0]; /* none? get initiation count */ - if ((wc & SIGN) && (UNIT_CPU_TYPE == UNIT_TYPE_2100)) - break; /* < 0 is NOP for 2100 IOP */ - while (wc != 0) { /* while count */ - WriteW (op[1], wc); /* for abort */ - t = ReadW (AR & VAMASK); /* move word */ - WriteW (BR & VAMASK, t); - AR = (AR + 1) & DMASK; /* incr src */ - BR = (BR + 1) & DMASK; /* incr dst */ - wc = (wc - 1) & DMASK; /* decr cnt */ - if (intrq && wc) { /* intr, more to do? */ - PC = err_PC; /* back up PC */ - break; - } - } - WriteW (op[1], wc); /* clean up inline */ - break; - - default: /* all others NOP */ - break; - } - -return reason; -} - -/* Get instruction operands +/* Get instruction operands. Operands for a given instruction are specifed by an "operand pattern" consisting of flags indicating the types and storage methods. The pattern directs how each operand is to be retrieved and whether the operand value or address is returned in the operand array. - Eight operand encodings are defined: + Typically, a microcode simulation handler will define an OP_PAT array, with + each element containing an operand pattern corresponding to the simulated + instruction. Operand patterns are defined in the header file accompanying + this source file. After calling this function with the appropriate operand + pattern and a pointer to an array of OPs, operands are decoded and stored + sequentially in the array. - Code Operand Description Example Return - ------ ----------------------------- ----------- ------------ - OP_NUL No operand present [inst] None + The following operand encodings are defined: - OP_CON Inline constant [inst] Value of C - C DEC 0 + Code Operand Description Example Return + ------ ---------------------------------------- ----------- ------------ + OP_NUL No operand present [inst] None - OP_VAR Inline variable [inst] Address of V - V BSS 1 + OP_IAR Integer constant in A register LDA I Value of I + [inst] + ... + I DEC 0 - OP_ADR Address [inst] Address of A - DEF A - ... - A EQU * - - OP_ADK Address of a 1-word constant [instr] Value of K - DEF K - ... - K DEC 0 + OP_DAB Double integer constant in A/B registers DLD J Value of J + [inst] + ... + J DEC 0,0 - OP_ADF Address of a 2-word constant [inst] Value of F - DEF F - ... - F DEC 0.0 + OP_FAB 2-word FP constant in A/B registers DLD F Value of F + [inst] + ... + F DEC 0.0 - OP_ADX Address of a 3-word constant [inst] Value of X - DEF X - ... - X DEX 0.0 + OP_CON Inline 1-word constant [inst] Value of C + C DEC 0 + ... - OP_ADT Address of a 4-word constant [inst] Value of T - DEF T - ... - T DEY 0.0 + OP_VAR Inline 1-word variable [inst] Address of V + V BSS 1 + ... + + OP_ADR Inline address [inst] Address of A + DEF A + ... + A EQU * + + OP_ADK Address of integer constant [inst] Value of K + DEF K + ... + K DEC 0 + + OP_ADD Address of double integer constant [inst] Value of D + DEF D + ... + D DEC 0,0 + + OP_ADF Address of 2-word FP constant [inst] Value of F + DEF F + ... + F DEC 0.0 + + OP_ADX Address of 3-word FP constant [inst] Value of X + DEF X + ... + X DEX 0.0 + + OP_ADT Address of 4-word FP constant [inst] Value of T + DEF T + ... + T DEY 0.0 + + OP_ADE Address of 5-word FP constant [inst] Value of E + DEF E + ... + E DEC 0,0,0,0,0 Address operands, i.e., those having a DEF to the operand, will be resolved to direct addresses. If an interrupt is pending and more than three levels @@ -1900,21 +665,14 @@ return reason; An operand pattern consists of one or more operand encodings, corresponding to the operands required by a given instruction. Values are returned in - sequence to the operand array. Addresses and one-word values are returned in - the lower half of the 32-bit array element. Two-word values are packed into - one array element, with the first word in the upper 16 bits. Three- and - four-word values are packed into two consecutive elements, with the last word - of a three-word value in the upper 16 bits of of the second element. - - IMPLEMENTATION NOTE: OP_ADT is not currently supported. + sequence to the operand array. */ -static t_stat get_ops (OP_PAT pattern, OPS op, uint32 irq) +t_stat cpu_ops (OP_PAT pattern, OPS op, uint32 irq) { t_stat reason = SCPE_OK; OP_PAT flags; uint32 i, MA; -XPN xop; for (i = 0; i < OP_N_F; i++) { flags = pattern & OP_M_FLAGS; /* get operand pattern */ @@ -1927,39 +685,61 @@ for (i = 0; i < OP_N_F; i++) { case OP_NUL: /* null operand */ return reason; /* no more, so quit */ - case OP_CON: /* constant operand */ - *op++ = ReadW (PC); /* get value */ + case OP_IAR: /* int in A */ + (*op++).word = AR; /* get one-word value */ break; - case OP_VAR: /* variable operand */ - *op++ = PC; /* get pointer to variable */ + case OP_JAB: /* dbl-int in A/B */ + (*op++).dword = (AR << 16) | BR; /* get two-word value */ break; - case OP_ADR: /* address operand */ - *op++ = MA; /* get address */ + case OP_FAB: /* 2-word FP in A/B */ + (*op).fpk[0] = AR; /* get high FP word */ + (*op++).fpk[1] = BR; /* get low FP word */ break; - case OP_ADK: /* address of 1-word constant */ - *op++ = ReadW (MA); /* get value */ + case OP_CON: /* inline constant operand */ + *op++ = ReadOp (PC, in_s); /* get value */ break; - case OP_ADF: /* address of 2-word constant */ - *op++ = ReadF (MA); /* get value */ + case OP_VAR: /* inline variable operand */ + (*op++).word = PC; /* get pointer to variable */ break; - case OP_ADX: /* address of 3-word constant */ - xop = ReadX (MA); - *op++ = xop.high; /* get first two words of value */ - *op++ = xop.low; /* get third word of value */ + case OP_ADR: /* inline address operand */ + (*op++).word = MA; /* get address */ break; - case OP_ADT: /* address of 4-word constant */ + case OP_ADK: /* address of int constant */ + *op++ = ReadOp (MA, in_s); /* get value */ + break; + + case OP_ADD: /* address of dbl-int constant */ + *op++ = ReadOp (MA, in_d); /* get value */ + break; + + case OP_ADF: /* address of 2-word FP const */ + *op++ = ReadOp (MA, fp_f); /* get value */ + break; + + case OP_ADX: /* address of 3-word FP const */ + *op++ = ReadOp (MA, fp_x); /* get value */ + break; + + case OP_ADT: /* address of 4-word FP const */ + *op++ = ReadOp (MA, fp_t); /* get value */ + break; + + case OP_ADE: /* address of 5-word FP const */ + *op++ = ReadOp (MA, fp_e); /* get value */ + break; default: return SCPE_IERR; /* not implemented */ } - PC = (PC + 1) & VAMASK; + if (flags >= OP_CON) /* operand after instruction? */ + PC = (PC + 1) & VAMASK; /* yes, so bump to next */ pattern = pattern >> OP_N_FLAGS; /* move next pattern into place */ } return reason; diff --git a/HP2100/hp2100_cpu1.h b/HP2100/hp2100_cpu1.h new file mode 100644 index 00000000..e61d1d2a --- /dev/null +++ b/HP2100/hp2100_cpu1.h @@ -0,0 +1,215 @@ +/* hp2100_cpu1.h: HP 2100/1000 firmware dispatcher definitions + + Copyright (c) 2006, J. David Bryan + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHOR 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 the author shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + 16-Oct-06 JDB Generalized operands for F-Series FP types + 26-Sep-06 JDB Split from hp2100_cpu1.c +*/ + +#ifndef _HP2100_CPU1_H_ +#define _HP2100_CPU1_H_ + + +/* Operand processing encoding. */ + +/* Base operand types. Note that all address encodings must be grouped together + after OP_ADR. */ + +#define OP_NUL 0 /* no operand */ +#define OP_IAR 1 /* 1-word int in A reg */ +#define OP_JAB 2 /* 2-word int in A/B regs */ +#define OP_FAB 3 /* 2-word FP const in A/B regs */ +#define OP_CON 4 /* inline 1-word constant */ +#define OP_VAR 5 /* inline 1-word variable */ + +#define OP_ADR 6 /* inline address */ +#define OP_ADK 7 /* addr of 1-word int const */ +#define OP_ADD 8 /* addr of 2-word int const */ +#define OP_ADF 9 /* addr of 2-word FP const */ +#define OP_ADX 10 /* addr of 3-word FP const */ +#define OP_ADT 11 /* addr of 4-word FP const */ +#define OP_ADE 12 /* addr of 5-word FP const */ + +#define OP_N_FLAGS 4 /* number of bits needed for flags */ +#define OP_M_FLAGS ((1 << OP_N_FLAGS) - 1) /* mask for flag bits */ + +#define OP_N_F (8 * sizeof (uint32) / OP_N_FLAGS) /* max number of op fields */ + +#define OP_V_F1 (0 * OP_N_FLAGS) /* 1st operand field */ +#define OP_V_F2 (1 * OP_N_FLAGS) /* 2nd operand field */ +#define OP_V_F3 (2 * OP_N_FLAGS) /* 3rd operand field */ +#define OP_V_F4 (3 * OP_N_FLAGS) /* 4th operand field */ +#define OP_V_F5 (4 * OP_N_FLAGS) /* 5th operand field */ +#define OP_V_F6 (5 * OP_N_FLAGS) /* 6th operand field */ +#define OP_V_F7 (6 * OP_N_FLAGS) /* 7th operand field */ +#define OP_V_F8 (7 * OP_N_FLAGS) /* 8th operand field */ + +/* Operand processing patterns. */ + +#define OP_N (OP_NUL << OP_V_F1) +#define OP_I (OP_IAR << OP_V_F1) +#define OP_J (OP_JAB << OP_V_F1) +#define OP_R (OP_FAB << OP_V_F1) +#define OP_C (OP_CON << OP_V_F1) +#define OP_V (OP_VAR << OP_V_F1) +#define OP_A (OP_ADR << OP_V_F1) +#define OP_K (OP_ADK << OP_V_F1) +#define OP_D (OP_ADD << OP_V_F1) +#define OP_F (OP_ADF << OP_V_F1) +#define OP_X (OP_ADX << OP_V_F1) +#define OP_T (OP_ADT << OP_V_F1) +#define OP_E (OP_ADE << OP_V_F1) + +#define OP_IA ((OP_IAR << OP_V_F1) | (OP_ADR << OP_V_F2)) +#define OP_JA ((OP_JAB << OP_V_F1) | (OP_ADR << OP_V_F2)) +#define OP_JD ((OP_JAB << OP_V_F1) | (OP_ADD << OP_V_F2)) +#define OP_RC ((OP_FAB << OP_V_F1) | (OP_CON << OP_V_F2)) +#define OP_RK ((OP_FAB << OP_V_F1) | (OP_ADK << OP_V_F2)) +#define OP_RF ((OP_FAB << OP_V_F1) | (OP_ADF << OP_V_F2)) +#define OP_CC ((OP_CON << OP_V_F1) | (OP_CON << OP_V_F2)) +#define OP_CV ((OP_CON << OP_V_F1) | (OP_VAR << OP_V_F2)) +#define OP_AC ((OP_ADR << OP_V_F1) | (OP_CON << OP_V_F2)) +#define OP_AA ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2)) +#define OP_AK ((OP_ADR << OP_V_F1) | (OP_ADK << OP_V_F2)) +#define OP_AX ((OP_ADR << OP_V_F1) | (OP_ADX << OP_V_F2)) +#define OP_AT ((OP_ADR << OP_V_F1) | (OP_ADT << OP_V_F2)) +#define OP_KV ((OP_ADK << OP_V_F1) | (OP_VAR << OP_V_F2)) +#define OP_KA ((OP_ADK << OP_V_F1) | (OP_ADR << OP_V_F2)) +#define OP_KK ((OP_ADK << OP_V_F1) | (OP_ADK << OP_V_F2)) +#define OP_FF ((OP_ADF << OP_V_F1) | (OP_ADF << OP_V_F2)) + +#define OP_IIF ((OP_IAR << OP_V_F1) | (OP_IAR << OP_V_F2) | \ + (OP_ADF << OP_V_F3)) + +#define OP_IAT ((OP_IAR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADT << OP_V_F3)) + +#define OP_CVA ((OP_CON << OP_V_F1) | (OP_VAR << OP_V_F2) | \ + (OP_ADR << OP_V_F3)) + +#define OP_AAF ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADF << OP_V_F3)) + +#define OP_AAX ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADX << OP_V_F3)) + +#define OP_AAT ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADT << OP_V_F3)) + +#define OP_AKK ((OP_ADR << OP_V_F1) | (OP_ADK << OP_V_F2) | \ + (OP_ADK << OP_V_F3)) + +#define OP_AXX ((OP_ADR << OP_V_F1) | (OP_ADX << OP_V_F2) | \ + (OP_ADX << OP_V_F3)) + +#define OP_ATT ((OP_ADR << OP_V_F1) | (OP_ADT << OP_V_F2) | \ + (OP_ADT << OP_V_F3)) + +#define OP_AEE ((OP_ADR << OP_V_F1) | (OP_ADE << OP_V_F2) | \ + (OP_ADE << OP_V_F3)) + +#define OP_AAXX ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADX << OP_V_F3) | (OP_ADX << OP_V_F4)) + +#define OP_KKKK ((OP_ADK << OP_V_F1) | (OP_ADK << OP_V_F2) | \ + (OP_ADK << OP_V_F3) | (OP_ADK << OP_V_F4)) + +#define OP_CATAKK ((OP_CON << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADT << OP_V_F3) | (OP_ADR << OP_V_F4) | \ + (OP_ADK << OP_V_F5) | (OP_ADK << OP_V_F6)) + +#define OP_KKKAKK ((OP_ADK << OP_V_F1) | (OP_ADK << OP_V_F2) | \ + (OP_ADK << OP_V_F3) | (OP_ADR << OP_V_F4) | \ + (OP_ADK << OP_V_F5) | (OP_ADK << OP_V_F6)) + +#define OP_CCACACCA ((OP_CON << OP_V_F1) | (OP_CON << OP_V_F2) | \ + (OP_ADR << OP_V_F3) | (OP_CON << OP_V_F4) | \ + (OP_ADR << OP_V_F5) | (OP_CON << OP_V_F6) | \ + (OP_CON << OP_V_F7) | (OP_ADR << OP_V_F8)) + + +/* Operand precisions (compatible with F-Series FPP): + + - S = 1-word integer + - D = 2-word integer + - F = 2-word single-precision floating-point + - X = 3-word extended-precision floating-point + - T = 4-word double-precision floating-point + - E = 5-word expanded-exponent floating-point + - A = null operand (operand is in FPP accumulator) + + 5-word floating-point numbers are supported by the F-Series Floating-Point + Processor hardware, but the instruction codes are not documented. + + Note that ordering is important, as we depend on the "fp" type codes to + reflect the number of words needed. +*/ + +typedef enum { in_s, in_d, fp_f, fp_x, fp_t, fp_e, fp_a } OPSIZE; + + +/* Conversion from operand size to word count. */ + +#define TO_COUNT(s) ((s == fp_a) ? 0 : s + (s < fp_f)) + + +/* HP in-memory representation of a packed floating-point number. + Actual value will use two, three, four, or five words, as needed. */ + +typedef uint16 FPK[5]; + + +/* Operand processing types. + + NOTE: Microsoft VC++ 6.0 does not support the C99 standard, so we cannot + initialize unions by arbitrary variant ("designated initializers"). + Therefore, we follow the C90 form of initializing via the first named + variant. The FPK variant must appear first in the OP structure, as we define + a number of FPK constants in other modules. +*/ + +typedef union { /* general operand */ + FPK fpk; /* floating-point value */ + uint16 word; /* 16-bit integer */ + uint32 dword; /* 32-bit integer */ + } OP; + +typedef OP OPS[OP_N_F]; /* operand array */ + +typedef uint32 OP_PAT; /* operand pattern */ + + +/* Microcode dispatcher functions. */ + +t_stat cpu_eau (uint32 IR, uint32 intrq); /* EAU group simulator */ +t_stat cpu_uig_0 (uint32 IR, uint32 intrq, uint32 iotrap); /* UIG group 0 dispatcher */ +t_stat cpu_uig_1 (uint32 IR, uint32 intrq, uint32 iotrap); /* UIG group 1 dispatcher */ + +/* Microcode helper functions. */ + +OP ReadOp (uint32 va, OPSIZE precision); /* generalized operand read */ +void WriteOp (uint32 va, OP operand, OPSIZE precision); /* generalized operand write */ +t_stat cpu_ops (OP_PAT pattern, OPS op, uint32 irq); /* operand processor */ + +#endif diff --git a/HP2100/hp2100_cpu2.c b/HP2100/hp2100_cpu2.c new file mode 100644 index 00000000..014c88bf --- /dev/null +++ b/HP2100/hp2100_cpu2.c @@ -0,0 +1,1125 @@ +/* hp2100_cpu2.c: HP 2100/1000 FP/DMS/EIG/IOP instructions + + Copyright (c) 2005-2006, 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"), + 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 Robert M Supnik shall not 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. + + CPU2 Floating-point, dynamic mapping, extended, and I/O processor + instructions + + 19-Dec-06 JDB DMS self-test now executes as NOP on 1000-M + 01-Dec-06 JDB Substitutes FPP for firmware FP if HAVE_INT64 + 26-Sep-06 JDB Moved from hp2100_cpu1.c to simplify extensions + 22-Feb-05 JDB Fixed missing MPCK on JRS target + 21-Jan-05 JDB Reorganized CPU option and operand processing flags + Split code along microcode modules + 15-Jan-05 RMS Cloned from hp2100_cpu.c + + Primary references: + - HP 1000 M/E/F-Series Computers Technical Reference Handbook + (5955-0282, Mar-1980) + - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation + (92851-90001, Mar-1981) + - Macro/1000 Reference Manual (92059-90001, Dec-1992) + + Additional references are listed with the associated firmware + implementations, as are the HP option model numbers pertaining to the + applicable CPUs. +*/ + +#include "hp2100_defs.h" +#include "hp2100_cpu.h" +#include "hp2100_cpu1.h" + +#if !defined (HAVE_INT64) /* int64 support unavailable */ + +#include "hp2100_fp.h" + +t_stat cpu_fp (uint32 IR, uint32 intrq); /* Firmware Floating Point */ + +#endif /* int64 support unavailable */ + +t_stat cpu_dms (uint32 IR, uint32 intrq); /* Dynamic mapping system */ +t_stat cpu_eig (uint32 IR, uint32 intrq); /* Extended instruction group */ +t_stat cpu_iop (uint32 IR, uint32 intrq); /* 2000 I/O Processor */ + + +#if !defined (HAVE_INT64) /* int64 support unavailable */ + +/* Single-Precision Floating Point Instructions + + The 2100 and 1000 CPUs share the single-precision (two word) floating-point + instruction codes. Floating-point firmware was an option on the 2100 and was + standard on the 1000-M and E. The 1000-F had a standard hardware Floating + Point Processor that executed these six instructions and added extended- and + double-precision floating- point instructions, as well as double-integer + instructions (the FPP is simulated separately). + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A 12901A std std N/A + + The instruction codes for the 2100 and 1000-M/E systems are mapped to + routines as follows: + + Instr. 2100/1000-M/E Description + ------ ------------- ----------------------------------- + 105000 FAD Single real add + 105020 FSB Single real subtract + 105040 FMP Single real multiply + 105060 FDV Single real divide + 105100 FIX Single integer to single real fix + 105120 FLT Single real to single integer float + + Bits 3-0 are not decoded by these instructions, so FAD (e.g.) would be + executed by any instruction in the range 105000-105017. + + Implementation note: rather than have two simulators that each executes the + single-precision FP instruction set, we compile conditionally, based on the + availability of 64-bit integer support in the host compiler. 64-bit integers + are required for the FPP, so if they are available, then the FPP is used to + handle the six single-precision instructions for the 2100 and M/E-Series, and + this function is omitted. If support is unavailable, this function is used + instead. + + Implementation note: the operands to FAD, etc. are floating-point values, so + OP_F would normally be used. However, the firmware FP support routines want + floating-point operands as 32-bit integer values, so OP_D is used to achieve + this. +*/ + +static const OP_PAT op_fp[8] = { + OP_D, OP_D, OP_D, OP_D, /* FAD FSB FMP FDV */ + OP_N, OP_N, OP_N, OP_N /* FIX FLT --- --- */ + }; + +t_stat cpu_fp (uint32 IR, uint32 intrq) +{ +t_stat reason = SCPE_OK; +OPS op; +uint32 entry; + +if ((cpu_unit.flags & UNIT_FP) == 0) /* FP option installed? */ + return stop_inst; + +entry = (IR >> 4) & 017; /* mask to entry point */ + +if (op_fp[entry] != OP_N) + if (reason = cpu_ops (op_fp[entry], op, intrq)) /* get instruction operands */ + return reason; + +switch (entry) { /* decode IR<7:4> */ + + case 000: /* FAD 105000 (OP_D) */ + O = f_as (op[0].dword, 0); /* add, upd ovflo */ + break; + + case 001: /* FSB 105020 (OP_D) */ + O = f_as (op[0].dword, 1); /* sub, upd ovflo */ + break; + + case 002: /* FMP 105040 (OP_D) */ + O = f_mul (op[0].dword); /* mul, upd ovflo */ + break; + + case 003: /* FDV 105060 (OP_D) */ + O = f_div (op[0].dword); /* div, upd ovflo */ + break; + + case 004: /* FIX 105100 (OP_N) */ + O = f_fix (); /* fix, upd ovflo */ + break; + + case 005: /* FLT 105120 (OP_N) */ + O = f_flt (); /* float, upd ovflo */ + break; + + default: /* should be impossible */ + return SCPE_IERR; + } + +return reason; +} + +#endif /* int64 support unavailable */ + + +/* Dynamic Mapping System + + The 1000 Dynamic Mapping System (DMS) consisted of the 12731A Memory + Expansion Module (MEM) card and 38 instructions to expand the basic 32K + logical address space to a 1024K physical space. The MEM provided four maps + of 32 mapping registers each: a system map, a user map, and two DCPC maps. + DMS worked in conjunction with memory protect to provide a "protected mode" + in which memory read and write violations could be trapped, and that + inhibited "privileged" instruction execution that attempted to alter the + memory mapping. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A 12976B 13307B std + + The instruction codes are mapped to routines as follows: + + Instr. 1000-M 1000-E/F Instr. 1000-M 1000-E/F + ------ ------ -------- ------ ------ -------- + 10x700 [xmm] [xmm] 10x720 XMM XMM + 10x701 [nop] [test] 10x721 XMS XMS + 10x702 MBI MBI 10x722 XM* XM* + 10x703 MBF MBF 10x723 [nop] [nop] + 10x704 MBW MBW 10x724 XL* XL* + 10x705 MWI MWI 10x725 XS* XS* + 10x706 MWF MWF 10x726 XC* XC* + 10x707 MWW MWW 10x727 LF* LF* + 10x710 SY* SY* 10x730 RS* RS* + + 10x711 US* US* 10x731 RV* RV* + 10x712 PA* PA* 10x732 DJP DJP + 10x713 PB* PB* 10x733 DJS DJS + 10x714 SSM SSM 10x734 SJP SJP + 10x715 JRS JRS 10x735 SJS SJS + 10x716 [nop] [nop] 10x736 UJP UJP + 10x717 [nop] [nop] 10x737 UJS UJS + + Instructions that use IR bit 9 to select the A or B register are designated + with a * above (e.g., 101710 is SYA, and 105710 is SYB). For those that do + not use this feature, either the 101xxx or 105xxx code will execute the + corresponding instruction, although the 105xxx form is the documented + instruction code. + + Notes: + + 1. Instruction code 10x700 will execute the XMM instruction, although + 10x720 is the documented instruction value. + + 2. Instruction code 10x701 will complement the A or B register, as + indicated, on 1000-E and F-Series machines. This instruction is a NOP + on M-Series machines. + + 3. The DMS privilege violation rules are: + - load map and CTL5 set (XMM, XMS, XM*, SY*, US*, PA*, PB*) + - load state or fence and UMAP set (JRS, DJP, DJS, SJP, SJS, UJP, UJS, LF*) + + 4. The 1000 manual is incorrect in stating that M*I, M*W, XS* are + privileged. +*/ + +static const OP_PAT op_dms[32] = { + OP_N, OP_N, OP_N, OP_N, /* [xmm] [test] MBI MBF */ + OP_N, OP_N, OP_N, OP_N, /* MBW MWI MWF MWW */ + OP_N, OP_N, OP_N, OP_N, /* SYA/B USA/B PAA/B PBA/B */ + OP_A, OP_KA, OP_N, OP_N, /* SSM JRS nop nop */ + OP_N, OP_N, OP_N, OP_N, /* XMM XMS XMA/B nop */ + OP_A, OP_A, OP_A, OP_N, /* XLA/B XSA/B XCA/B LFA/B */ + OP_N, OP_N, OP_A, OP_A, /* RSA/B RVA/B DJP DJS */ + OP_A, OP_A, OP_A, OP_A /* SJP SJS UJP UJS */ + }; + +t_stat cpu_dms (uint32 IR, uint32 intrq) +{ +t_stat reason = SCPE_OK; +OPS op; +uint32 entry, absel; +uint32 i, t, mapi, mapj; + +if ((cpu_unit.flags & UNIT_DMS) == 0) /* DMS option installed? */ + return stop_inst; + +absel = (IR & I_AB)? 1: 0; /* get A/B select */ +entry = IR & 037; /* mask to entry point */ + +if (op_dms[entry] != OP_N) + if (reason = cpu_ops (op_dms[entry], op, intrq)) /* get instruction operands */ + return reason; + +switch (entry) { /* decode IR<3:0> */ + +/* DMS module 1 */ + + case 000: /* [undefined] 105700 (OP_N) */ + goto XMM; /* decodes as XMM */ + + case 001: /* [self test] 105701 (OP_N) */ + if (UNIT_CPU_MODEL != UNIT_1000_M) /* executes as NOP on 1000-M */ + ABREG[absel] = ~ABREG[absel]; /* CMA or CMB */ + break; + + case 002: /* MBI 105702 (OP_N) */ + AR = AR & ~1; /* force A, B even */ + BR = BR & ~1; + while (XR != 0) { /* loop */ + t = ReadB (AR); /* read curr */ + WriteBA (BR, t); /* write alt */ + AR = (AR + 1) & DMASK; /* incr ptrs */ + BR = (BR + 1) & DMASK; + XR = (XR - 1) & DMASK; + if (XR && intrq && !(AR & 1)) { /* more, int, even? */ + PC = err_PC; /* stop for now */ + break; + } + } + break; + + case 003: /* MBF 105703 (OP_N) */ + AR = AR & ~1; /* force A, B even */ + BR = BR & ~1; + while (XR != 0) { /* loop */ + t = ReadBA (AR); /* read alt */ + WriteB (BR, t); /* write curr */ + AR = (AR + 1) & DMASK; /* incr ptrs */ + BR = (BR + 1) & DMASK; + XR = (XR - 1) & DMASK; + if (XR && intrq && !(AR & 1)) { /* more, int, even? */ + PC = err_PC; /* stop for now */ + break; + } + } + break; + + case 004: /* MBW 105704 (OP_N) */ + AR = AR & ~1; /* force A, B even */ + BR = BR & ~1; + while (XR != 0) { /* loop */ + t = ReadBA (AR); /* read alt */ + WriteBA (BR, t); /* write alt */ + AR = (AR + 1) & DMASK; /* incr ptrs */ + BR = (BR + 1) & DMASK; + XR = (XR - 1) & DMASK; + if (XR && intrq && !(AR & 1)) { /* more, int, even? */ + PC = err_PC; /* stop for now */ + break; + } + } + break; + + case 005: /* MWI 105705 (OP_N) */ + while (XR != 0) { /* loop */ + t = ReadW (AR & VAMASK); /* read curr */ + WriteWA (BR & VAMASK, t); /* write alt */ + AR = (AR + 1) & DMASK; /* incr ptrs */ + BR = (BR + 1) & DMASK; + XR = (XR - 1) & DMASK; + if (XR && intrq) { /* more and intr? */ + PC = err_PC; /* stop for now */ + break; + } + } + break; + + case 006: /* MWF 105706 (OP_N) */ + while (XR != 0) { /* loop */ + t = ReadWA (AR & VAMASK); /* read alt */ + WriteW (BR & VAMASK, t); /* write curr */ + AR = (AR + 1) & DMASK; /* incr ptrs */ + BR = (BR + 1) & DMASK; + XR = (XR - 1) & DMASK; + if (XR && intrq) { /* more and intr? */ + PC = err_PC; /* stop for now */ + break; + } + } + break; + + case 007: /* MWW 105707 (OP_N) */ + while (XR != 0) { /* loop */ + t = ReadWA (AR & VAMASK); /* read alt */ + WriteWA (BR & VAMASK, t); /* write alt */ + AR = (AR + 1) & DMASK; /* incr ptrs */ + BR = (BR + 1) & DMASK; + XR = (XR - 1) & DMASK; + if (XR && intrq) { /* more and intr? */ + PC = err_PC; /* stop for now */ + break; + } + } + break; + + case 010: /* SYA, SYB 10x710 (OP_N) */ + case 011: /* USA, USB 10x711 (OP_N) */ + case 012: /* PAA, PAB 10x712 (OP_N) */ + case 013: /* PBA, PBB 10x713 (OP_N) */ + mapi = (IR & 03) << VA_N_PAG; /* map base */ + if (ABREG[absel] & SIGN) { /* store? */ + for (i = 0; i < MAP_LNT; i++) { + t = dms_rmap (mapi + i); /* map to memory */ + WriteW ((ABREG[absel] + i) & VAMASK, t); + } + } + else { /* load */ + dms_viol (err_PC, MVI_PRV); /* priv if PRO */ + for (i = 0; i < MAP_LNT; i++) { + t = ReadW ((ABREG[absel] + i) & VAMASK); + dms_wmap (mapi + i, t); /* mem to map */ + } + } + ABREG[absel] = (ABREG[absel] + MAP_LNT) & DMASK; + break; + + case 014: /* SSM 105714 (OP_A) */ + WriteW (op[0].word, dms_upd_sr ()); /* store stat */ + break; + + case 015: /* JRS 105715 (OP_KA) */ + if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ + dms_enb = 0; /* assume off */ + dms_ump = SMAP; + if (op[0].word & 0100000) { /* set enable? */ + dms_enb = 1; + if (op[0].word & 0040000) dms_ump = UMAP; /* set/clr usr */ + } + mp_dms_jmp (op[1].word); /* mpck jmp target */ + PCQ_ENTRY; /* save old PC */ + PC = op[1].word; /* jump */ + ion_defer = 1; /* defer intr */ + break; + +/* DMS module 2 */ + + case 020: /* XMM 105720 (OP_N) */ + XMM: + if (XR == 0) break; /* nop? */ + while (XR != 0) { /* loop */ + if (XR & SIGN) { /* store? */ + t = dms_rmap (AR); /* map to mem */ + WriteW (BR & VAMASK, t); + XR = (XR + 1) & DMASK; + } + else { /* load */ + dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ + t = ReadW (BR & VAMASK); /* mem to map */ + dms_wmap (AR, t); + XR = (XR - 1) & DMASK; + } + AR = (AR + 1) & DMASK; + BR = (BR + 1) & DMASK; + if (intrq && ((XR & 017) == 017)) { /* intr, grp of 16? */ + PC = err_PC; /* stop for now */ + break; + } + } + break; + + case 021: /* XMS 105721 (OP_N) */ + if ((XR & SIGN) || (XR == 0)) break; /* nop? */ + dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ + while (XR != 0) { + dms_wmap (AR, BR); /* AR to map */ + XR = (XR - 1) & DMASK; + AR = (AR + 1) & DMASK; + BR = (BR + 1) & DMASK; + if (intrq && ((XR & 017) == 017)) { /* intr, grp of 16? */ + PC = err_PC; + break; + } + } + break; + + case 022: /* XMA, XMB 10x722 (OP_N) */ + dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ + if (ABREG[absel] & 0100000) mapi = UMAP; + else mapi = SMAP; + if (ABREG[absel] & 0000001) mapj = PBMAP; + else mapj = PAMAP; + for (i = 0; i < MAP_LNT; i++) { + t = dms_rmap (mapi + i); /* read map */ + dms_wmap (mapj + i, t); /* write map */ + } + break; + + case 024: /* XLA, XLB 10x724 (OP_A) */ + ABREG[absel] = ReadWA (op[0].word); /* load alt */ + break; + + case 025: /* XSA, XSB 10x725 (OP_A) */ + WriteWA (op[0].word, ABREG[absel]); /* store alt */ + break; + + case 026: /* XCA, XCB 10x726 (OP_A) */ + if (ABREG[absel] != ReadWA (op[0].word)) /* compare alt */ + PC = (PC + 1) & VAMASK; + break; + + case 027: /* LFA, LFB 10x727 (OP_N) */ + if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ + dms_sr = (dms_sr & ~(MST_FLT | MST_FENCE)) | + (ABREG[absel] & (MST_FLT | MST_FENCE)); + break; + + case 030: /* RSA, RSB 10x730 (OP_N) */ + ABREG[absel] = dms_upd_sr (); /* save stat */ + break; + + case 031: /* RVA, RVB 10x731 (OP_N) */ + ABREG[absel] = dms_vr; /* save viol */ + break; + + case 032: /* DJP 105732 (OP_A) */ + if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ + mp_dms_jmp (op[0].word); /* validate jump addr */ + PCQ_ENTRY; /* save curr PC */ + PC = op[0].word; /* new PC */ + dms_enb = 0; /* disable map */ + dms_ump = SMAP; + ion_defer = 1; + break; + + case 033: /* DJS 105733 (OP_A) */ + if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ + WriteW (op[0].word, PC); /* store ret addr */ + PCQ_ENTRY; /* save curr PC */ + PC = (op[0].word + 1) & VAMASK; /* new PC */ + dms_enb = 0; /* disable map */ + dms_ump = SMAP; + ion_defer = 1; /* defer intr */ + break; + + case 034: /* SJP 105734 (OP_A) */ + if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ + mp_dms_jmp (op[0].word); /* validate jump addr */ + PCQ_ENTRY; /* save curr PC */ + PC = op[0].word; /* jump */ + dms_enb = 1; /* enable system */ + dms_ump = SMAP; + ion_defer = 1; /* defer intr */ + break; + + case 035: /* SJS 105735 (OP_A) */ + if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ + t = PC; /* save retn addr */ + PCQ_ENTRY; /* save curr PC */ + PC = (op[0].word + 1) & VAMASK; /* new PC */ + dms_enb = 1; /* enable system */ + dms_ump = SMAP; + WriteW (op[0].word, t); /* store ret addr */ + ion_defer = 1; /* defer intr */ + break; + + case 036: /* UJP 105736 (OP_A) */ + if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ + mp_dms_jmp (op[0].word); /* validate jump addr */ + PCQ_ENTRY; /* save curr PC */ + PC = op[0].word; /* jump */ + dms_enb = 1; /* enable user */ + dms_ump = UMAP; + ion_defer = 1; /* defer intr */ + break; + + case 037: /* UJS 105737 (OP_A) */ + if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ + t = PC; /* save retn addr */ + PCQ_ENTRY; /* save curr PC */ + PC = (op[0].word + 1) & VAMASK; /* new PC */ + dms_enb = 1; /* enable user */ + dms_ump = UMAP; + WriteW (op[0].word, t); /* store ret addr */ + ion_defer = 1; /* defer intr */ + break; + + default: /* others NOP */ + break; + } + +return reason; +} + + +/* Extended Instruction Group + + The Extended Instruction Group (EIG) adds 32 index and 10 bit/byte/word + manipulation instructions to the 1000 base set. These instructions + use the new X and Y index registers that were added to the 1000. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A std std std + + The instruction codes are mapped to routines as follows: + + Instr. 1000-M/E/F Instr. 1000-M/E/F + ------ ---------- ------ ---------- + 10x740 S*X 10x760 ISX + 10x741 C*X 10x761 DSX + 10x742 L*X 10x762 JLY + 10x743 STX 10x763 LBT + 10x744 CX* 10x764 SBT + 10x745 LDX 10x765 MBT + 10x746 ADX 10x766 CBT + 10x747 X*X 10x767 SFB + + 10x750 S*Y 10x770 ISY + 10x751 C*Y 10x771 DSY + 10x752 L*Y 10x772 JPY + 10x753 STY 10x773 SBS + 10x754 CY* 10x774 CBS + 10x755 LDY 10x775 TBS + 10x756 ADY 10x776 CMW + 10x757 X*Y 10x777 MVW + + Instructions that use IR bit 9 to select the A or B register are designated + with a * above (e.g., 101740 is SAX, and 105740 is SBX). For those that do + not use this feature, either the 101xxx or 105xxx code will execute the + corresponding instruction, although the 105xxx form is the documented + instruction code. + + Notes: + + 1. The LBT, SBT, MBT, and MVW instructions are used as part of the 2100 IOP + implementation. When so called, the MBT and MVW instructions have the + additional restriction that the count must be positive. +*/ + +static const OP_PAT op_eig[32] = { + OP_A, OP_N, OP_A, OP_A, /* S*X C*X L*X STX */ + OP_N, OP_K, OP_K, OP_N, /* CX* LDX ADX X*X */ + OP_A, OP_N, OP_A, OP_A, /* S*Y C*Y L*Y STY */ + OP_N, OP_K, OP_K, OP_N, /* CY* LDY ADY X*Y */ + OP_N, OP_N, OP_A, OP_N, /* ISX DSX JLY LBT */ + OP_N, OP_KV, OP_KV, OP_N, /* SBT MBT CBT SFB */ + OP_N, OP_N, OP_C, OP_KA, /* ISY DSY JPY SBS */ + OP_KA, OP_KK, OP_KV, OP_KV /* CBS TBS CMW MVW */ + }; + +t_stat cpu_eig (uint32 IR, uint32 intrq) +{ +t_stat reason = SCPE_OK; +OPS op; +uint32 entry, absel; +uint32 t, v1, v2, wc; +int32 sop1, sop2; + +absel = (IR & I_AB)? 1: 0; /* get A/B select */ +entry = IR & 037; /* mask to entry point */ + +if (op_eig[entry] != OP_N) + if (reason = cpu_ops (op_eig[entry], op, intrq)) /* get instruction operands */ + return reason; + +switch (entry) { /* decode IR<4:0> */ + +/* EIG module 1 */ + + case 000: /* SAX, SBX 10x740 (OP_A) */ + op[0].word = (op[0].word + XR) & VAMASK; /* indexed addr */ + WriteW (op[0].word, ABREG[absel]); /* store */ + break; + + case 001: /* CAX, CBX 10x741 (OP_N) */ + XR = ABREG[absel]; /* copy to XR */ + break; + + case 002: /* LAX, LBX 10x742 (OP_A) */ + op[0].word = (op[0].word + XR) & VAMASK; /* indexed addr */ + ABREG[absel] = ReadW (op[0].word); /* load */ + break; + + case 003: /* STX 105743 (OP_A) */ + WriteW (op[0].word, XR); /* store XR */ + break; + + case 004: /* CXA, CXB 10x744 (OP_N) */ + ABREG[absel] = XR; /* copy from XR */ + break; + + case 005: /* LDX 105745 (OP_K)*/ + XR = op[0].word; /* load XR */ + break; + + case 006: /* ADX 105746 (OP_K) */ + t = XR + op[0].word; /* add to XR */ + if (t > DMASK) E = 1; /* set E, O */ + if (((~XR ^ op[0].word) & (XR ^ t)) & SIGN) O = 1; + XR = t & DMASK; + break; + + case 007: /* XAX, XBX 10x747 (OP_N) */ + t = XR; /* exchange XR */ + XR = ABREG[absel]; + ABREG[absel] = t; + break; + + case 010: /* SAY, SBY 10x750 (OP_A) */ + op[0].word = (op[0].word + YR) & VAMASK; /* indexed addr */ + WriteW (op[0].word, ABREG[absel]); /* store */ + break; + + case 011: /* CAY, CBY 10x751 (OP_N) */ + YR = ABREG[absel]; /* copy to YR */ + break; + + case 012: /* LAY, LBY 10x752 (OP_A) */ + op[0].word = (op[0].word + YR) & VAMASK; /* indexed addr */ + ABREG[absel] = ReadW (op[0].word); /* load */ + break; + + case 013: /* STY 105753 (OP_A) */ + WriteW (op[0].word, YR); /* store YR */ + break; + + case 014: /* CYA, CYB 10x754 (OP_N) */ + ABREG[absel] = YR; /* copy from YR */ + break; + + case 015: /* LDY 105755 (OP_K) */ + YR = op[0].word; /* load YR */ + break; + + case 016: /* ADY 105756 (OP_K) */ + t = YR + op[0].word; /* add to YR */ + if (t > DMASK) E = 1; /* set E, O */ + if (((~YR ^ op[0].word) & (YR ^ t)) & SIGN) O = 1; + YR = t & DMASK; + break; + + case 017: /* XAY, XBY 10x757 (OP_N) */ + t = YR; /* exchange YR */ + YR = ABREG[absel]; + ABREG[absel] = t; + break; + +/* EIG module 2 */ + + case 020: /* ISX 105760 (OP_N) */ + XR = (XR + 1) & DMASK; /* incr XR */ + if (XR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */ + break; + + case 021: /* DSX 105761 (OP_N) */ + XR = (XR - 1) & DMASK; /* decr XR */ + if (XR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */ + break; + + case 022: /* JLY 105762 (OP_A) */ + mp_dms_jmp (op[0].word); /* validate jump addr */ + PCQ_ENTRY; + YR = PC; /* ret addr to YR */ + PC = op[0].word; /* jump */ + break; + + case 023: /* LBT 105763 (OP_N) */ + AR = ReadB (BR); /* load byte */ + BR = (BR + 1) & DMASK; /* incr ptr */ + break; + + case 024: /* SBT 105764 (OP_N) */ + WriteB (BR, AR); /* store byte */ + BR = (BR + 1) & DMASK; /* incr ptr */ + break; + + case 025: /* MBT 105765 (OP_KV) */ + wc = ReadW (op[1].word); /* get continuation count */ + if (wc == 0) wc = op[0].word; /* none? get initiation count */ + if ((wc & SIGN) && + (UNIT_CPU_TYPE == UNIT_TYPE_2100)) + break; /* < 0 is NOP for 2100 IOP */ + while (wc != 0) { /* while count */ + WriteW (op[1].word, wc); /* for MP abort */ + t = ReadB (AR); /* move byte */ + WriteB (BR, t); + AR = (AR + 1) & DMASK; /* incr src */ + BR = (BR + 1) & DMASK; /* incr dst */ + wc = (wc - 1) & DMASK; /* decr cnt */ + if (intrq && wc) { /* intr, more to do? */ + PC = err_PC; /* back up PC */ + break; + } + } + WriteW (op[1].word, wc); /* clean up inline */ + break; + + case 026: /* CBT 105766 (OP_KV) */ + wc = ReadW (op[1].word); /* get continuation count */ + if (wc == 0) wc = op[0].word; /* none? get initiation count */ + while (wc != 0) { /* while count */ + WriteW (op[1].word, wc); /* for MP abort */ + v1 = ReadB (AR); /* get src1 */ + v2 = ReadB (BR); /* get src2 */ + if (v1 != v2) { /* compare */ + PC = (PC + 1 + (v1 > v2)) & VAMASK; + BR = (BR + wc) & DMASK; /* update BR */ + wc = 0; /* clr interim */ + break; + } + AR = (AR + 1) & DMASK; /* incr src1 */ + BR = (BR + 1) & DMASK; /* incr src2 */ + wc = (wc - 1) & DMASK; /* decr cnt */ + if (intrq && wc) { /* intr, more to do? */ + PC = err_PC; /* back up PC */ + break; + } + } + WriteW (op[1].word, wc); /* clean up inline */ + break; + + case 027: /* SFB 105767 (OP_N) */ + v1 = AR & 0377; /* test byte */ + v2 = (AR >> 8) & 0377; /* term byte */ + for (;;) { /* scan */ + t = ReadB (BR); /* read byte */ + if (t == v1) break; /* test match? */ + BR = (BR + 1) & DMASK; + if (t == v2) { /* term match? */ + PC = (PC + 1) & VAMASK; + break; + } + if (intrq) { /* int pending? */ + PC = err_PC; /* back up PC */ + break; + } + } + break; + + case 030: /* ISY 105770 (OP_N) */ + YR = (YR + 1) & DMASK; /* incr YR */ + if (YR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */ + break; + + case 031: /* DSY 105771 (OP_N) */ + YR = (YR - 1) & DMASK; /* decr YR */ + if (YR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */ + break; + + case 032: /* JPY 105772 (OP_C) */ + op[0].word = (op[0].word + YR) & VAMASK; /* index, no indir */ + mp_dms_jmp (op[0].word); /* validate jump addr */ + PCQ_ENTRY; + PC = op[0].word; /* jump */ + break; + + case 033: /* SBS 105773 (OP_KA) */ + WriteW (op[1].word, /* set bits */ + ReadW (op[1].word) | op[0].word); + break; + + case 034: /* CBS 105774 (OP_KA) */ + WriteW (op[1].word, /* clear bits */ + ReadW (op[1].word) & ~op[0].word); + break; + + case 035: /* TBS 105775 (OP_KK) */ + if ((op[1].word & op[0].word) != op[0].word) /* test bits */ + PC = (PC + 1) & VAMASK; + break; + + case 036: /* CMW 105776 (OP_KV) */ + wc = ReadW (op[1].word); /* get continuation count */ + if (wc == 0) wc = op[0].word; /* none? get initiation count */ + while (wc != 0) { /* while count */ + WriteW (op[1].word, wc); /* for abort */ + v1 = ReadW (AR & VAMASK); /* first op */ + v2 = ReadW (BR & VAMASK); /* second op */ + sop1 = (int32) SEXT (v1); /* signed */ + sop2 = (int32) SEXT (v2); + if (sop1 != sop2) { /* compare */ + PC = (PC + 1 + (sop1 > sop2)) & VAMASK; + BR = (BR + wc) & DMASK; /* update BR */ + wc = 0; /* clr interim */ + break; + } + AR = (AR + 1) & DMASK; /* incr src1 */ + BR = (BR + 1) & DMASK; /* incr src2 */ + wc = (wc - 1) & DMASK; /* decr cnt */ + if (intrq && wc) { /* intr, more to do? */ + PC = err_PC; /* back up PC */ + break; + } + } + WriteW (op[1].word, wc); /* clean up inline */ + break; + + case 037: /* MVW 105777 (OP_KV) */ + wc = ReadW (op[1].word); /* get continuation count */ + if (wc == 0) wc = op[0].word; /* none? get initiation count */ + if ((wc & SIGN) && + (UNIT_CPU_TYPE == UNIT_TYPE_2100)) + break; /* < 0 is NOP for 2100 IOP */ + while (wc != 0) { /* while count */ + WriteW (op[1].word, wc); /* for abort */ + t = ReadW (AR & VAMASK); /* move word */ + WriteW (BR & VAMASK, t); + AR = (AR + 1) & DMASK; /* incr src */ + BR = (BR + 1) & DMASK; /* incr dst */ + wc = (wc - 1) & DMASK; /* decr cnt */ + if (intrq && wc) { /* intr, more to do? */ + PC = err_PC; /* back up PC */ + break; + } + } + WriteW (op[1].word, wc); /* clean up inline */ + break; + + } + +return reason; +} + + +/* 2000 I/O Processor + + The IOP accelerates certain operations of the HP 2000 Time-Share BASIC system + I/O processor. Most 2000 systems were delivered with 2100 CPUs, although IOP + microcode was developed for the 1000-M and 1000-E. As the I/O processors + were specific to the 2000 system, general compatibility with other CPU + microcode options was unnecessary, and indeed no other options were possible + for the 2100. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A 13206A 13207A 22702A N/A + + The routines are mapped to instruction codes as follows: + + Instr. 2100 1000-M/E Description + ------ ---------- ---------- -------------------------------------------- + SAI 105060-117 101400-037 Store A indexed by B (+/- offset in IR<4:0>) + LAI 105020-057 105400-037 Load A indexed by B (+/- offset in IR<4:0>) + CRC 105150 105460 Generate CRC + REST 105340 105461 Restore registers from stack + READF 105220 105462 Read F register (stack pointer) + INS -- 105463 Initialize F register (stack pointer) + ENQ 105240 105464 Enqueue + PENQ 105257 105465 Priority enqueue + DEQ 105260 105466 Dequeue + TRSLT 105160 105467 Translate character + ILIST 105000 105470 Indirect address list (similar to $SETP) + PRFEI 105222 105471 Power fail exit with I/O + PRFEX 105223 105472 Power fail exit + PRFIO 105221 105473 Power fail I/O + SAVE 105362 105474 Save registers to stack + + MBYTE 105120 105765 Move bytes (MBT) + MWORD 105200 105777 Move words (MVW) + SBYTE 105300 105764 Store byte (SBT) + LBYTE 105320 105763 Load byte (LBT) + + The INS instruction was not required in the 2100 implementation because the + stack pointer was actually the memory protect fence register and so could be + loaded directly with an OTA/B 05. Also, the 1000 implementation did not + offer the MBYTE, MWORD, SBYTE, and LBYTE instructions because the equivalent + instructions from the standard Extended Instruction Group were used instead. + Note that the 2100 MBYTE and MWORD instructions operate slightly differently + from the 1000 MBT and MVW instructions. Specifically, the move count is + signed on the 2100 and unsigned on the 1000. A negative count on the 2100 + results in a NOP. + + The simulator remaps the 2100 instructions to the 1000 codes. The four EIG equivalents + are dispatched to the EIG simulator. The rest are handled here. Note that the MBT and + MVW instructions operate slightly differently on the 2100; they are + + Additional reference: + - HP 2000 Computer System Sources and Listings Documentation + (22687-90020, undated), section 3, pages 2-74 through 2-91. +*/ + +static const OP_PAT op_iop[16] = { + OP_V, OP_N, OP_N, OP_N, /* CRC RESTR READF INS */ + OP_N, OP_N, OP_N, OP_V, /* ENQ PENQ DEQ TRSLT */ + OP_AC, OP_CVA, OP_A, OP_CV, /* ILIST PRFEI PRFEX PRFIO */ + OP_N, OP_N, OP_N, OP_N /* SAVE --- --- --- */ + }; + +t_stat cpu_iop (uint32 IR, uint32 intrq) +{ +t_stat reason = SCPE_OK; +OPS op; +uint32 entry; +uint32 hp, tp, i, t, wc, MA; + +if ((cpu_unit.flags & UNIT_IOP) == 0) /* IOP option installed? */ + return stop_inst; + +if (UNIT_CPU_TYPE == UNIT_TYPE_2100) { /* 2100 IOP? */ + if ((IR >= 0105020) && (IR <= 0105057)) /* remap LAI */ + IR = 0105400 | (IR - 0105020); + else if ((IR >= 0105060) && (IR <= 0105117)) /* remap SAI */ + IR = 0101400 | (IR - 0105060); + else { + switch (IR) { /* remap others */ + case 0105000: IR = 0105470; break; /* ILIST */ + case 0105120: return cpu_eig (0105765, intrq); /* MBYTE (maps to MBT) */ + case 0105150: IR = 0105460; break; /* CRC */ + case 0105160: IR = 0105467; break; /* TRSLT */ + case 0105200: return cpu_eig (0105777, intrq); /* MWORD (maps to MVW) */ + case 0105220: IR = 0105462; break; /* READF */ + case 0105221: IR = 0105473; break; /* PRFIO */ + case 0105222: IR = 0105471; break; /* PRFEI */ + case 0105223: IR = 0105472; break; /* PRFEX */ + case 0105240: IR = 0105464; break; /* ENQ */ + case 0105257: IR = 0105465; break; /* PENQ */ + case 0105260: IR = 0105466; break; /* DEQ */ + case 0105300: return cpu_eig (0105764, intrq); /* SBYTE (maps to SBT) */ + case 0105320: return cpu_eig (0105763, intrq); /* LBYTE (maps to LBT) */ + case 0105340: IR = 0105461; break; /* REST */ + case 0105362: IR = 0105474; break; /* SAVE */ + + default: /* all others invalid */ + return stop_inst; + } + } + } + +entry = IR & 077; /* mask to entry point */ + +if (entry <= 037) { /* LAI/SAI 10x400-437 */ + MA = ((entry - 020) + BR) & VAMASK; /* +/- offset */ + if (IR & I_AB) AR = ReadW (MA); /* AB = 1 -> LAI */ + else WriteW (MA, AR); /* AB = 0 -> SAI */ + return reason; + } +else if (entry <= 057) /* IR = 10x440-457? */ + return stop_inst; /* not part of IOP */ + +entry = entry - 060; /* offset 10x460-477 */ + +if (op_iop[entry] != OP_N) + if (reason = cpu_ops (op_iop[entry], op, intrq)) /* get instruction operands */ + return reason; + +switch (entry) { /* decode IR<5:0> */ + + case 000: /* CRC 105460 (OP_V) */ + t = ReadW (op[0].word) ^ (AR & 0377); /* xor prev CRC and char */ + for (i = 0; i < 8; i++) { /* apply polynomial */ + t = (t >> 1) | ((t & 1) << 15); /* rotate right */ + if (t & SIGN) t = t ^ 020001; /* old t<0>? xor */ + } + WriteW (op[0].word, t); /* rewrite CRC */ + break; + + case 001: /* RESTR 105461 (OP_N) */ + iop_sp = (iop_sp - 1) & VAMASK; /* decr stack ptr */ + t = ReadW (iop_sp); /* get E and O */ + O = ((t >> 1) ^ 1) & 1; /* restore O */ + E = t & 1; /* restore E */ + iop_sp = (iop_sp - 1) & VAMASK; /* decr sp */ + BR = ReadW (iop_sp); /* restore B */ + iop_sp = (iop_sp - 1) & VAMASK; /* decr sp */ + AR = ReadW (iop_sp); /* restore A */ + if (UNIT_CPU_MODEL == UNIT_2100) + mp_fence = iop_sp; /* 2100 keeps sp in MP FR */ + break; + + case 002: /* READF 105462 (OP_N) */ + AR = iop_sp; /* copy stk ptr */ + break; + + case 003: /* INS 105463 (OP_N) */ + iop_sp = AR; /* init stk ptr */ + break; + + case 004: /* ENQ 105464 (OP_N) */ + hp = ReadW (AR & VAMASK); /* addr of head */ + tp = ReadW ((AR + 1) & VAMASK); /* addr of tail */ + WriteW ((BR - 1) & VAMASK, 0); /* entry link */ + WriteW ((tp - 1) & VAMASK, BR); /* tail link */ + WriteW ((AR + 1) & VAMASK, BR); /* queue tail */ + if (hp != 0) PC = (PC + 1) & VAMASK; /* q not empty? skip */ + break; + + case 005: /* PENQ 105465 (OP_N) */ + hp = ReadW (AR & VAMASK); /* addr of head */ + WriteW ((BR - 1) & VAMASK, hp); /* becomes entry link */ + WriteW (AR & VAMASK, BR); /* queue head */ + if (hp == 0) /* q empty? */ + WriteW ((AR + 1) & VAMASK, BR); /* queue tail */ + else PC = (PC + 1) & VAMASK; /* skip */ + break; + + case 006: /* DEQ 105466 (OP_N) */ + BR = ReadW (AR & VAMASK); /* addr of head */ + if (BR) { /* queue not empty? */ + hp = ReadW ((BR - 1) & VAMASK); /* read hd entry link */ + WriteW (AR & VAMASK, hp); /* becomes queue head */ + if (hp == 0) /* q now empty? */ + WriteW ((AR + 1) & VAMASK, (AR + 1) & DMASK); + PC = (PC + 1) & VAMASK; /* skip */ + } + break; + + case 007: /* TRSLT 105467 (OP_V) */ + wc = ReadW (op[0].word); /* get count */ + if (wc & SIGN) break; /* cnt < 0? */ + while (wc != 0) { /* loop */ + MA = (AR + AR + ReadB (BR)) & VAMASK; + t = ReadB (MA); /* xlate */ + WriteB (BR, t); /* store char */ + BR = (BR + 1) & DMASK; /* incr ptr */ + wc = (wc - 1) & DMASK; /* decr cnt */ + if (wc && intrq) { /* more and intr? */ + WriteW (op[0].word, wc); /* save count */ + PC = err_PC; /* stop for now */ + break; + } + } + break; + + case 010: /* ILIST 105470 (OP_AC) */ + do { /* for count */ + WriteW (op[0].word, AR); /* write AR to mem */ + AR = (AR + 1) & DMASK; /* incr AR */ + op[0].word = (op[0].word + 1) & VAMASK; /* incr MA */ + op[1].word = (op[1].word - 1) & DMASK; /* decr count */ + } + while (op[1].word != 0); + break; + + case 011: /* PRFEI 105471 (OP_CVA) */ + WriteW (op[1].word, 1); /* set flag */ + reason = iogrp (op[0].word, 0); /* execute I/O instr */ + op[0].word = op[2].word; /* set rtn and fall through */ + + case 012: /* PRFEX 105472 (OP_A) */ + PCQ_ENTRY; + PC = ReadW (op[0].word) & VAMASK; /* jump indirect */ + WriteW (op[0].word, 0); /* clear exit */ + break; + + case 013: /* PRFIO 105473 (OP_CV) */ + WriteW (op[1].word, 1); /* set flag */ + reason = iogrp (op[0].word, 0); /* execute instr */ + break; + + case 014: /* SAVE 105474 (OP_N) */ + WriteW (iop_sp, AR); /* save A */ + iop_sp = (iop_sp + 1) & VAMASK; /* incr stack ptr */ + WriteW (iop_sp, BR); /* save B */ + iop_sp = (iop_sp + 1) & VAMASK; /* incr stack ptr */ + t = ((O ^ 1) << 1) | E; /* merge E and O */ + WriteW (iop_sp, t); /* save E and O */ + iop_sp = (iop_sp + 1) & VAMASK; /* incr stack ptr */ + if (UNIT_CPU_TYPE == UNIT_TYPE_2100) + mp_fence = iop_sp; /* 2100 keeps sp in MP FR */ + break; + + default: /* instruction undefined */ + return stop_inst; + } + +return reason; +} diff --git a/HP2100/hp2100_cpu3.c b/HP2100/hp2100_cpu3.c new file mode 100644 index 00000000..c49b615b --- /dev/null +++ b/HP2100/hp2100_cpu3.c @@ -0,0 +1,819 @@ +/* hp2100_cpu3.c: HP 2100/1000 FFP/DBI instructions + + Copyright (c) 2005-2006, J. David Bryan + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHOR 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 the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + CPU3 Fast FORTRAN and Double Integer instructions + + 16-Oct-06 JDB Calls FPP for extended-precision math + 12-Oct-06 JDB Altered DBLE, DDINT for F-Series FFP compatibility + 26-Sep-06 JDB Moved from hp2100_cpu1.c to simplify extensions + 09-Aug-06 JDB Added double-integer instruction set + 18-Feb-05 JDB Add 2100/21MX Fast FORTRAN Processor instructions + + Primary references: + - HP 1000 M/E/F-Series Computers Technical Reference Handbook + (5955-0282, Mar-1980) + - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation + (92851-90001, Mar-1981) + - Macro/1000 Reference Manual (92059-90001, Dec-1992) + + Additional references are listed with the associated firmware + implementations, as are the HP option model numbers pertaining to the + applicable CPUs. +*/ + +#include "hp2100_defs.h" +#include "hp2100_cpu.h" +#include "hp2100_cpu1.h" + +#if defined (HAVE_INT64) /* int64 support available */ +#include "hp2100_fp1.h" +#else /* int64 support unavailable */ +#include "hp2100_fp.h" +#endif /* end of int64 support */ + + +t_stat cpu_ffp (uint32 IR, uint32 intrq); /* Fast FORTRAN Processor */ +t_stat cpu_dbi (uint32 IR, uint32 intrq); /* Double-Integer instructions */ + + +/* Fast FORTRAN Processor. + + The Fast FORTRAN Processor (FFP) is a set of FORTRAN language accelerators + and extended-precision (three-word) floating point routines. Although the + FFP is an option for the 2100 and later CPUs, each implements the FFP in a + slightly different form. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A 12907A 12977B 13306B std + + The instruction codes are mapped to routines as follows: + + Instr. 2100 1000-M 1000-E 1000-F Instr. 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ + 105200 -- [nop] [nop] [test] 105220 .XFER .XFER .XFER .XFER + 105201 DBLE DBLE DBLE DBLE 105221 .GOTO .GOTO .GOTO .GOTO + 105202 SNGL SNGL SNGL SNGL 105222 ..MAP ..MAP ..MAP ..MAP + 105203 .XMPY .XMPY .XMPY .DNG 105223 .ENTR .ENTR .ENTR .ENTR + 105204 .XDIV .XDIV .XDIV .DCO 105224 .ENTP .ENTP .ENTP .ENTP + 105205 .DFER .DFER .DFER .DFER 105225 -- .PWR2 .PWR2 .PWR2 + 105206 -- .XPAK .XPAK .XPAK 105226 -- .FLUN .FLUN .FLUN + 105207 -- XADD XADD .BLE 105227 $SETP $SETP $SETP $SETP + + 105210 -- XSUB XSUB .DIN 105230 -- .PACK .PACK .PACK + 105211 -- XMPY XMPY .DDE 105231 -- -- .CFER .CFER + 105212 -- XDIV XDIV .DIS 105232 -- -- -- ..FCM + 105213 .XADD .XADD .XADD .DDS 105233 -- -- -- ..TCM + 105214 .XSUB .XSUB .XSUB .NGL 105234 -- -- -- -- + 105215 -- .XCOM .XCOM .XCOM 105235 -- -- -- -- + 105216 -- ..DCM ..DCM ..DCM 105236 -- -- -- -- + 105217 -- DDINT DDINT DDINT 105237 -- -- -- -- + + The F-Series maps different instructions to several of the standard FFP + opcodes. We first look for these and dispatch them appropriately before + falling into the handler for the common instructions. + + The math functions use the F-Series FPP for implementation. The FPP requires + that the host compiler support 64-bit integers. Therefore, if 64-bit + integers are not available, the math instructions of the FFP are disabled. + We allow this partial implementation as an aid in running systems generated + for the FFP. Most system programs did not use the math instructions, but + almost all use .ENTR. Supporting the latter even on systems that do not + support the former still allows such systems to boot. + + Notes: + + 1. The "$SETP" instruction is sometimes listed as ".SETP" in the + documentation. + + 2. Extended-precision arithmetic routines (e.g., .XMPY) exist on the + 1000-F, but they are assigned instruction codes in the single-precision + floating-point module range. They are replaced by several double + integer instructions, which we dispatch to the double integer handler. + + 3. The software implementation of ..MAP supports 1-, 2-, or 3-dimensional + arrays, designated by setting A = -1, 0, and +1, respectively. The + firmware implementation supports only 2- and 3-dimensional access. + + 4. The documentation for ..MAP for the 2100 FFP shows A = 0 or -1 for two + or three dimensions, respectively, but the 1000 FFP shows A = 0 or +1. + The firmware actually only checks the LSB of A. + + 5. The .DFER and .XFER implementations for the 2100 FFP return X+4 and Y+4 + in the A and B registers, whereas the 1000 FFP returns X+3 and Y+3. + + 6. The .XFER implementation for the 2100 FFP returns to P+2, whereas the + 1000 implementation returns to P+1. + + 7. The firmware implementations of DBLE, .BLE, and DDINT clear the overflow + flag. The software implementations do not change overflow. + + 8. The M/E-Series FFP arithmetic instructions (.XADD, etc.) return negative + infinity on negative overflow and positive infinity on positive + overflow. The equivalent F-Series instructions return positive infinity + on both. + + Additional references: + - DOS/RTE Relocatable Library Reference Manual (24998-90001, Oct-1981) + - Implementing the HP 2100 Fast FORTRAN Processor (12907-90010, Nov-1974) +*/ + +static const OP_PAT op_ffp_f[32] = { /* patterns for F-Series only */ + OP_N, OP_AAF, OP_AX, OP_N, /* [tst] DBLE SNGL .DNG */ + OP_N, OP_AA, OP_A, OP_AAF, /* .DCO .DFER .XPAK .BLE */ + OP_N, OP_N, OP_N, OP_N, /* .DIN .DDE .DIS .DDS */ + OP_AT, OP_A, OP_A, OP_AAX, /* .NGL .XCOM ..DCM DDINT */ + OP_N, OP_AK, OP_KKKK, OP_A, /* .XFER .GOTO ..MAP .ENTR */ + OP_A, OP_RK, OP_R, OP_K, /* .ENTP .PWR2 .FLUN $SETP */ + OP_RC, OP_AA, OP_R, OP_A, /* .PACK .CFER ..FCM ..TCM */ + OP_N, OP_N, OP_N, OP_N /* --- --- --- --- */ + }; + +static const OP_PAT op_ffp_e[32] = { /* patterns for 2100/M/E-Series */ + OP_N, OP_AAF, OP_AX, OP_AXX, /* [nop] DBLE SNGL .XMPY */ + OP_AXX, OP_AA, OP_A, OP_AAXX, /* .XDIV .DFER .XPAK XADD */ + OP_AAXX, OP_AAXX, OP_AAXX, OP_AXX, /* XSUB XMPY XDIV .XADD */ + OP_AXX, OP_A, OP_A, OP_AAX, /* .XSUB .XCOM ..DCM DDINT */ + OP_N, OP_AK, OP_KKKK, OP_A, /* .XFER .GOTO ..MAP .ENTR */ + OP_A, OP_RK, OP_R, OP_K, /* .ENTP .PWR2 .FLUN $SETP */ + OP_RC, OP_AA, OP_N, OP_N, /* .PACK .CFER --- --- */ + OP_N, OP_N, OP_N, OP_N /* --- --- --- --- */ + }; + +t_stat cpu_ffp (uint32 IR, uint32 intrq) +{ +OP fpop; +OPS op, op2; +uint32 entry; +uint32 j, sa, sb, sc, da, dc, ra, MA; +int32 expon; +t_stat reason = SCPE_OK; + +#if defined (HAVE_INT64) /* int64 support available */ + +int32 i; + +#endif /* end of int64 support */ + +if ((cpu_unit.flags & UNIT_FFP) == 0) /* FFP option installed? */ + return stop_inst; + +entry = IR & 037; /* mask to entry point */ + +if (UNIT_CPU_MODEL != UNIT_1000_F) { /* 2100/M/E-Series? */ + if (op_ffp_e[entry] != OP_N) + if (reason = cpu_ops (op_ffp_e[entry], op, intrq)) /* get instruction operands */ + return reason; + } + +#if defined (HAVE_INT64) /* int64 support available */ + +else { /* F-Series */ + if (op_ffp_f[entry] != OP_N) + if (reason = cpu_ops (op_ffp_f[entry], op, intrq)) /* get instruction operands */ + return reason; + + switch (entry) { /* decode IR<4:0> */ + + case 000: /* [tst] 105200 (OP_N) */ + XR = 4; /* firmware revision */ + SR = 0102077; /* test passed code */ + AR = 0; /* test clears A/B */ + BR = 0; + PC = (PC + 1) & VAMASK; /* P+2 return for firmware w/DBI */ + return reason; + + case 003: /* .DNG 105203 (OP_N) */ + return cpu_dbi (0105323, intrq); /* remap to double int handler */ + + case 004: /* .DCO 105204 (OP_N) */ + return cpu_dbi (0105324, intrq); /* remap to double int handler */ + + case 007: /* .BLE 105207 (OP_AAF) */ + O = fp_cvt (&op[2], fp_f, fp_t); /* convert value and clear overflow */ + WriteOp (op[1].word, op[2], fp_t); /* write double-precision value */ + return reason; + + case 010: /* .DIN 105210 (OP_N) */ + return cpu_dbi (0105330, intrq); /* remap to double int handler */ + + case 011: /* .DDE 105211 (OP_N) */ + return cpu_dbi (0105331, intrq); /* remap to double int handler */ + + case 012: /* .DIS 105212 (OP_N) */ + return cpu_dbi (0105332, intrq); /* remap to double int handler */ + + case 013: /* .DDS 105213 (OP_N) */ + return cpu_dbi (0105333, intrq); /* remap to double int handler */ + + case 014: /* .NGL 105214 (OP_AT) */ + O = fp_cvt (&op[1], fp_t, fp_f); /* convert value */ + AR = op[1].fpk[0]; /* move MSB to A */ + BR = op[1].fpk[1]; /* move LSB to B */ + return reason; + + case 032: /* ..FCM 105232 (OP_R) */ + O = fp_pcom (&op[0], fp_f); /* complement value */ + AR = op[0].fpk[0]; /* return result */ + BR = op[0].fpk[1]; /* to A/B registers */ + return reason; + + case 033: /* ..TCM 105233 (OP_A) */ + fpop = ReadOp (op[0].word, fp_t); /* read 4-word value */ + O = fp_pcom (&fpop, fp_t); /* complement it */ + WriteOp (op[0].word, fpop, fp_t); /* write 4-word value */ + return reason; + } /* fall thru if not special to F */ + } + +#endif /* end of int64 support */ + +switch (entry) { /* decode IR<4:0> */ + +/* FFP module 1 */ + + case 000: /* [nop] 105200 (OP_N) */ + if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 M/E-series */ + return stop_inst; /* trap if not */ + break; + +#if defined (HAVE_INT64) /* int64 support available */ + + case 001: /* DBLE 105201 (OP_AAF) */ + O = fp_cvt (&op[2], fp_f, fp_x); /* convert value and clear overflow */ + WriteOp (op[1].word, op[2], fp_x); /* write extended-precision value */ + break; + + case 002: /* SNGL 105202 (OP_AX) */ + O = fp_cvt (&op[1], fp_x, fp_f); /* convert value */ + AR = op[1].fpk[0]; /* move MSB to A */ + BR = op[1].fpk[1]; /* move LSB to B */ + break; + + case 003: /* .XMPY 105203 (OP_AXX) */ + i = 0; /* params start at op[0] */ + goto XMPY; /* process as XMPY */ + + case 004: /* .XDIV 105204 (OP_AXX) */ + i = 0; /* params start at op[0] */ + goto XDIV; /* process as XDIV */ + +#endif /* end of int64 support */ + + case 005: /* .DFER 105205 (OP_AA) */ + BR = op[0].word; /* get destination address */ + AR = op[1].word; /* get source address */ + goto XFER; /* do transfer */ + +#if defined (HAVE_INT64) /* int64 support available */ + + case 006: /* .XPAK 105206 (OP_A) */ + if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */ + return stop_inst; /* trap if not */ + + if (intrq) { /* interrupt pending? */ + PC = err_PC; /* restart instruction */ + break; + } + + fpop = ReadOp (op[0].word, fp_x); /* read unpacked */ + O = fp_nrpack (&fpop, fpop, (int16) AR, fp_x); /* nrm/rnd/pack mantissa, exponent */ + WriteOp (op[0].word, fpop, fp_x); /* write result */ + break; + + case 007: /* XADD 105207 (OP_AAXX) */ + i = 1; /* params start at op[1] */ + XADD: /* enter here from .XADD */ + if (intrq) { /* interrupt pending? */ + PC = err_PC; /* restart instruction */ + break; + } + + O = fp_exec (001, &fpop, op[i + 1], op[i + 2]); /* three-word add */ + WriteOp (op[i].word, fpop, fp_x); /* write sum */ + break; + + case 010: /* XSUB 105210 (OP_AAXX) */ + i = 1; /* params start at op[1] */ + XSUB: /* enter here from .XSUB */ + if (intrq) { /* interrupt pending? */ + PC = err_PC; /* restart instruction */ + break; + } + + O = fp_exec (021, &fpop, op[i + 1], op[i + 2]); /* three-word subtract */ + WriteOp (op[i].word, fpop, fp_x); /* write difference */ + break; + + case 011: /* XMPY 105211 (OP_AAXX) */ + i = 1; /* params start at op[1] */ + XMPY: /* enter here from .XMPY */ + if (intrq) { /* interrupt pending? */ + PC = err_PC; /* restart instruction */ + break; + } + + O = fp_exec (041, &fpop, op[i + 1], op[i + 2]); /* three-word multiply */ + WriteOp (op[i].word, fpop, fp_x); /* write product */ + break; + + case 012: /* XDIV 105212 (OP_AAXX) */ + i = 1; /* params start at op[1] */ + XDIV: /* enter here from .XDIV */ + if (intrq) { /* interrupt pending? */ + PC = err_PC; /* restart instruction */ + break; + } + + O = fp_exec (061, &fpop, op[i + 1], op[i + 2]); /* three-word divide */ + WriteOp (op[i].word, fpop, fp_x); /* write quotient */ + break; + + case 013: /* .XADD 105213 (OP_AXX) */ + i = 0; /* params start at op[0] */ + goto XADD; /* process as XADD */ + + case 014: /* .XSUB 105214 (OP_AXX) */ + i = 0; /* params start at op[0] */ + goto XSUB; /* process as XSUB */ + + case 015: /* .XCOM 105215 (OP_A) */ + if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */ + return stop_inst; /* trap if not */ + + fpop = ReadOp (op[0].word, fp_x); /* read unpacked */ + AR = fp_ucom (&fpop, fp_x); /* complement and rtn exp adj */ + WriteOp (op[0].word, fpop, fp_x); /* write result */ + break; + + case 016: /* ..DCM 105216 (OP_A) */ + if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */ + return stop_inst; /* trap if not */ + + if (intrq) { /* interrupt pending? */ + PC = err_PC; /* restart instruction */ + break; + } + + fpop = ReadOp (op[0].word, fp_x); /* read operand */ + O = fp_pcom (&fpop, fp_x); /* complement (can't ovf neg) */ + WriteOp (op[0].word, fpop, fp_x); /* write result */ + break; + + case 017: /* DDINT 105217 (OP_AAX) */ + if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */ + return stop_inst; /* trap if not */ + + if (intrq) { /* interrupt pending? */ + PC = err_PC; /* restart instruction */ + break; + } + + O = fp_trun (&fpop, op[2], fp_x); /* truncate operand (can't ovf) */ + WriteOp (op[1].word, fpop, fp_x); /* write result */ + break; + +#endif /* end of int64 support */ + +/* FFP module 2 */ + + case 020: /* .XFER 105220 (OP_N) */ + if (UNIT_CPU_TYPE == UNIT_TYPE_2100) + PC = (PC + 1) & VAMASK; /* 2100 .XFER returns to P+2 */ + XFER: /* enter here from .DFER */ + sc = 3; /* set count for 3-wd xfer */ + goto CFER; /* do transfer */ + + case 021: /* .GOTO 105221 (OP_AK) */ + if ((int16) op[1].word < 1) /* index < 1? */ + op[1].word = 1; /* reset min */ + + sa = PC + op[1].word - 1; /* point to jump target */ + if (sa >= op[0].word) /* must be <= last target */ + sa = op[0].word - 1; + + da = ReadW (sa); /* get jump target */ + if (reason = resolve (da, &MA, intrq)) { /* resolve indirects */ + PC = err_PC; /* irq restarts instruction */ + break; + } + + mp_dms_jmp (MA); /* validate jump addr */ + PCQ_ENTRY; /* record last PC */ + PC = MA; /* jump */ + BR = op[0].word; /* (for 2100 FFP compat) */ + break; + + case 022: /* ..MAP 105222 (OP_KKKK) */ + op[1].word = op[1].word - 1; /* decrement 1st subscr */ + + if ((AR & 1) == 0) /* 2-dim access? */ + op[1].word = op[1].word + /* compute element offset */ + (op[2].word - 1) * op[3].word; + else { /* 3-dim access */ + if (reason = cpu_ops (OP_KK, op2, intrq)) { /* get 1st, 2nd ranges */ + PC = err_PC; /* irq restarts instruction */ + break; + } + op[1].word = op[1].word + /* offset */ + ((op[3].word - 1) * op2[1].word + + op[2].word - 1) * op2[0].word; + } + + AR = (op[0].word + op[1].word * BR) & DMASK; /* return element address */ + break; + + case 023: /* .ENTR 105223 (OP_A) */ + MA = PC - 3; /* get addr of entry point */ + ENTR: /* enter here from .ENTP */ + da = op[0].word; /* get addr of 1st formal */ + dc = MA - da; /* get count of formals */ + sa = ReadW (MA); /* get addr of return point */ + ra = ReadW (sa++); /* get rtn, ptr to 1st actual */ + WriteW (MA, ra); /* stuff rtn into caller's ent */ + sc = ra - sa; /* get count of actuals */ + if (sc > dc) /* use min (actuals, formals) */ + sc = dc; + + for (j = 0; j < sc; j++) { + MA = ReadW (sa++); /* get addr of actual */ + if (reason = resolve (MA, &MA, intrq)) { /* resolve indirect */ + PC = err_PC; /* irq restarts instruction */ + break; + } + WriteW (da++, MA); /* put addr into formal */ + } + + AR = ra; /* return address */ + BR = da; /* addr of 1st unused formal */ + break; + + case 024: /* .ENTP 105224 (OP_A) */ + MA = PC - 5; /* get addr of entry point */ + goto ENTR; + + case 025: /* .PWR2 105225 (OP_RK) */ + if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */ + return stop_inst; /* trap if not */ + + fp_unpack (&fpop, &expon, op[0], fp_f); /* unpack value */ + expon = expon + (int16) (op[1].word); /* multiply by 2**n */ + fp_pack (&fpop, fpop, expon, fp_f); /* repack value */ + AR = fpop.fpk[0]; /* return result */ + BR = fpop.fpk[1]; /* to A/B registers */ + break; + + case 026: /* .FLUN 105226 (OP_R) */ + if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */ + return stop_inst; /* trap if not */ + + fp_unpack (&fpop, &expon, op[0], fp_f); /* unpack value */ + AR = (int16) expon; /* return expon to A */ + BR = fpop.fpk[1]; /* and low mant to B */ + break; + + case 027: /* $SETP 105227 (OP_K) */ + j = sa = AR; /* save initial value */ + sb = BR; /* save initial address */ + AR = 0; /* AR will return = 0 */ + BR = BR & VAMASK; /* addr must be direct */ + + do { + WriteW (BR, j); /* write value to address */ + j = (j + 1) & DMASK; /* incr value */ + BR = (BR + 1) & VAMASK; /* incr address */ + op[0].word = op[0].word - 1; /* decr count */ + if (op[0].word && intrq) { /* more and intr? */ + AR = sa; /* restore A */ + BR = sb; /* restore B */ + PC = err_PC; /* restart instruction */ + break; + } + } + while (op[0].word != 0); /* loop until count exhausted */ + break; + + case 030: /* .PACK 105230 (OP_RC) */ + if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */ + return stop_inst; /* trap if not */ + + O = fp_nrpack (&fpop, op[0], /* nrm/rnd/pack value */ + (int16) (op[1].word), fp_f); + AR = fpop.fpk[0]; /* return result */ + BR = fpop.fpk[1]; /* to A/B registers */ + break; + + case 031: /* .CFER 105231 (OP_AA) */ + if ((UNIT_CPU_MODEL != UNIT_1000_E) && /* must be 1000 E-series */ + (UNIT_CPU_MODEL != UNIT_1000_F)) /* or 1000 F-series */ + return stop_inst; /* trap if not */ + + BR = op[0].word; /* get destination address */ + AR = op[1].word; /* get source address */ + sc = 4; /* set for 4-wd xfer */ + CFER: /* enter here from .XFER */ + for (j = 0; j < sc; j++) { /* xfer loop */ + WriteW (BR, ReadW (AR)); /* transfer word */ + AR = (AR + 1) & VAMASK; /* bump source addr */ + BR = (BR + 1) & VAMASK; /* bump destination addr */ + } + + E = 0; /* routine clears E */ + + if (UNIT_CPU_TYPE == UNIT_TYPE_2100) { /* 2100 (and .DFER/.XFER)? */ + AR = (AR + 1) & VAMASK; /* 2100 FFP returns X+4, Y+4 */ + BR = (BR + 1) & VAMASK; + } + break; + + default: /* others undefined */ + reason = stop_inst; + } + +return reason; +} + + +/* Double-Integer Instructions. + + The double-integer instructions were added to the HP instruction set at + revision 1920 of the 1000-F. They were immediately adopted in a number of HP + software products, most notably the RTE file management package (FMP) + routines. As these routines are used in nearly every RTE program, F-Series + programs were almost always a few hundred bytes smaller than their M- and + E-Series counterparts. This became significant as RTE continued to grow in + size, and some customer programs ran out of address space on E-Series + machines. + + While HP never added double-integer instructions to the standard E-Series, a + product from the HP "specials group," HP 93585A, provided microcoded + replacements for the E-Series. This could provide just enough address-space + savings to allow programs to load in E-Series systems, in addition to + accelerating these common operations. + + M-Series microcode was never offered by HP. However, it costs us nothing to + enable double-integer instructions for M-Series simulations. This has the + concomitant advantage that it allows RTE-6/VM to run under SIMH (for + simulation, we must SET CPU 1000-M, because RTE-6/VM looks for the OS and VM + microcode -- which we do not implement yet -- if it detects an E- or F-Series + machine). + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A N/A 93575A std + + The routines are mapped to instruction codes as follows: + + Instr. 1000-E 1000-F Description + ------ ------ ------ ----------------------------------------- + [test] 105320 -- [self test] + .DAD 105321 105014 Double integer add + .DMP 105322 105054 Double integer multiply + .DNG 105323 105203 Double integer negate + .DCO 105324 105204 Double integer compare + .DDI 105325 105074 Double integer divide + .DDIR 105326 105134 Double integer divide (reversed) + .DSB 105327 105034 Double integer subtract + .DIN 105330 105210 Double integer increment + .DDE 105331 105211 Double integer decrement + .DIS 105332 105212 Double integer increment and skip if zero + .DDS 105333 105213 Double integer decrement and skip if zero + .DSBR 105334 105114 Double integer subtraction (reversed) + + On the F-Series, the double-integer instruction codes are split among the + floating-point processor and the Fast FORTRAN Processor ranges. They are + dispatched from those respective simulators for processing here. + + Notes: + + 1. The E-Series opcodes are listed in Appendix C of the Macro/1000 manual. + These should be the same opcodes as given in the 93585A manual listed + below, but no copy of the reference below has been located to confirm + the proper opcodes. This module should be corrected if needed when such + documentation is found. + + 2. The action of the self-test instruction (105320) is unknown. At the + moment, we take an unimplemented instruction trap for this. When + documentation explaining the action is located, it will be implemented. + + 3. The F-Series firmware executes .DMP and .DDI/.DDIR by floating the + 32-bit double integer to a 48-bit extended-precision number, calling the + FPP to execute the extended-precision multiply/divide, and then fixing + the product to a 32-bit double integer. We simulate these directly with + 64- or 32-bit integer arithmetic. + + Additional references: + - 93575A Double Integer Instructions Installation and Reference Manual + (93575-90007) +*/ + +static const OP_PAT op_dbi[16] = { + OP_N, OP_JD, OP_JD, OP_J, /* [test] .DAD .DMP .DNG */ + OP_JD, OP_JD, OP_JD, OP_JD, /* .DCO .DDI .DDIR .DSB */ + OP_J, OP_J, OP_A, OP_A, /* .DIN .DDE .DIS .DDS */ + OP_JD, OP_N, OP_N, OP_N /* .DSBR --- --- --- */ + }; + +t_stat cpu_dbi (uint32 IR, uint32 intrq) +{ +OP din; +OPS op; +uint32 entry, t; +t_stat reason = SCPE_OK; + +if ((cpu_unit.flags & UNIT_DBI) == 0) /* DBI option installed? */ + return stop_inst; + +entry = IR & 017; /* mask to entry point */ + +if (op_dbi[entry] != OP_N) + if (reason = cpu_ops (op_dbi[entry], op, intrq)) /* get instruction operands */ + return reason; + +switch (entry) { /* decode IR<3:0> */ + + case 000: /* [test] 105320 (OP_N) */ + t = (AR << 16) | BR; /* set t for nop */ + reason = stop_inst; /* function unknown; not impl. */ + break; + + case 001: /* .DAD 105321 (OP_JD) */ + t = op[0].dword + op[1].dword; /* add values */ + E = E | (t < op[0].dword); /* carry if result smaller */ + O = (((~op[0].dword ^ op[1].dword) & /* overflow if sign wrong */ + (op[0].dword ^ t) & SIGN32) != 0); + break; + + case 002: /* .DMP 105322 (OP_JD) */ + { + +#if defined (HAVE_INT64) /* int64 support available */ + + t_int64 t64; + + t64 = (t_int64) op[0].dword * /* multiply values */ + (t_int64) op[1].dword; + O = ((t64 < -(t_int64) 0x80000000) || /* overflow if out of range */ + (t64 > (t_int64) 0x7FFFFFFF)); + if (O) + t = ~SIGN32; /* if overflow, rtn max pos */ + else + t = (uint32) (t64 & DMASK32); /* else lower 32 bits of result */ + +#else /* int64 support unavailable */ + + uint32 sign, xu, yu, rh, rl; + + sign = ((int32) op[0].dword < 0) ^ /* save sign of result */ + ((int32) op[1].dword < 0); + + xu = (uint32) abs ((int32) op[0].dword); /* make operands pos */ + yu = (uint32) abs ((int32) op[1].dword); + + if ((xu & 0xFFFF0000) == 0 && /* 16 x 16 multiply? */ + (yu & 0xFFFF0000) == 0) { + t = xu * yu; /* do it */ + O = 0; /* can't overflow */ + } + + else if ((xu & 0xFFFF0000) != 0 && /* 32 x 32 multiply? */ + (yu & 0xFFFF0000) != 0) + O = 1; /* always overflows */ + + else { /* 16 x 32 or 32 x 16 */ + rl = (xu & 0xFFFF) * (yu & 0xFFFF); /* form 1st partial product */ + + if ((xu & 0xFFFF0000) == 0) + rh = xu * (yu >> 16) + (rl >> 16); /* 16 x 32 2nd partial */ + else + rh = (xu >> 16) * yu + (rl >> 16); /* 32 x 16 2nd partial */ + + O = (rh > 0x7FFF + sign); /* check for out of range */ + if (O == 0) + t = (rh << 16) | (rl & 0xFFFF); /* combine partials */ + } + + if (O) + t = ~SIGN32; /* if overflow, rtn max pos */ + else if (sign) + t = ~t + 1; /* if result neg, 2s compl */ + +#endif /* end of int64 support */ + + } + break; + + case 003: /* .DNG 105323 (OP_J) */ + t = ~op[0].dword + 1; /* negate value */ + O = (op[0].dword == SIGN32); /* overflow if max neg */ + if (op[0].dword == 0) /* borrow if result zero */ + E = 1; + break; + + case 004: /* .DCO 105324 (OP_JD) */ + t = op[0].dword; /* copy for later store */ + if ((int32) op[0].dword < (int32) op[1].dword) + PC = (PC + 1) & VAMASK; /* < rtns to P+2 */ + else if ((int32) op[0].dword > (int32) op[1].dword) + PC = (PC + 2) & VAMASK; /* > rtns to P+3 */ + break; /* = rtns to P+1 */ + + case 005: /* .DDI 105325 (OP_JD) */ + DDI: + O = ((op[1].dword == 0) || /* overflow if div 0 */ + ((op[0].dword == SIGN32) && /* or max neg div -1 */ + ((int32) op[1].dword == -1))); + if (O) + t = ~SIGN32; /* rtn max pos for ovf */ + else + t = op[0].dword / op[1].dword; /* else return quotient */ + break; + + case 006: /* .DDIR 105326 (OP_JD) */ + t = op[0].dword; /* swap operands */ + op[0].dword = op[1].dword; + op[1].dword = t; + goto DDI; /* continue at .DDI */ + + case 007: /* .DSB 105327 (OP_JD) */ + DSB: + t = op[0].dword - op[1].dword; /* subtract values */ + E = E | (op[0].dword < op[1].dword); /* borrow if minu < subtr */ + O = (((op[0].dword ^ op[1].dword) & /* overflow if sign wrong */ + (op[0].dword ^ t) & SIGN32) != 0); + break; + + case 010: /* .DIN 105330 (OP_J) */ + t = op[0].dword + 1; /* increment value */ + O = (t == SIGN32); /* overflow if sign flipped */ + if (t == 0) + E = 1; /* carry if result zero */ + break; + + case 011: /* .DDE 105331 (OP_J) */ + t = op[0].dword - 1; /* decrement value */ + O = (t == ~SIGN32); /* overflow if sign flipped */ + if ((int32) t == -1) + E = 1; /* borrow if result -1 */ + break; + + case 012: /* .DIS 105332 (OP_A) */ + din = ReadOp (op[0].word, in_d); /* get value */ + t = din.dword = din.dword + 1; /* increment value */ + WriteOp (op[0].word, din, in_d); /* store it back */ + if (t == 0) + PC = (PC + 1) & VAMASK; /* skip if result zero */ + break; + + case 013: /* .DDS 105333 (OP_A) */ + din = ReadOp (op[0].word, in_d); /* get value */ + t = din.dword = din.dword - 1; /* decrement value */ + WriteOp (op[0].word, din, in_d); /* write it back */ + if (t == 0) + PC = (PC + 1) & VAMASK; /* skip if result zero */ + break; + + case 014: /* .DSBR 105334 (OP_JD) */ + t = op[0].dword; /* swap operands */ + op[0].dword = op[1].dword; + op[1].dword = t; + goto DSB; /* continue at .DSB */ + + default: /* others undefined */ + t = (AR << 16) | BR; /* set t for nop */ + reason = stop_inst; + } + +if (reason == SCPE_OK) { /* if return OK */ + AR = (t >> 16) & DMASK; /* break result */ + BR = t & DMASK; /* into A and B */ + } + +return reason; +} diff --git a/HP2100/hp2100_cpu4.c b/HP2100/hp2100_cpu4.c new file mode 100644 index 00000000..3f253553 --- /dev/null +++ b/HP2100/hp2100_cpu4.c @@ -0,0 +1,1125 @@ +/* hp2100_cpu4.c: HP 1000 FPP/SIS + + Copyright (c) 2006, J. David Bryan + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHOR 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 the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + CPU4 Floating Point Processor and Scientific Instruction Set + + 01-Dec-06 JDB Substitutes FPP for firmware FP if HAVE_INT64 + + Primary references: + - HP 1000 M/E/F-Series Computers Technical Reference Handbook + (5955-0282, Mar-1980) + - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation + (92851-90001, Mar-1981) + - Macro/1000 Reference Manual (92059-90001, Dec-1992) + + Additional references are listed with the associated firmware + implementations, as are the HP option model numbers pertaining to the + applicable CPUs. +*/ + +#include "hp2100_defs.h" +#include "hp2100_cpu.h" +#include "hp2100_cpu1.h" + +#if defined (HAVE_INT64) /* int64 support available */ + +#include "hp2100_fp1.h" + + +t_stat cpu_fpp (uint32 IR, uint32 intrq); /* Floating Point Processor */ +t_stat cpu_sis (uint32 IR, uint32 intrq); /* Scientific Instruction Set */ + +extern t_stat cpu_dbi (uint32 IR, uint32 intrq); /* Double-Integer instructions */ + + +/* Floating-Point Processor. + + The 1000 F-Series replaces the six 2100/1000-M/E single-precision firmware + floating-point instructions with a hardware floating-point processor (FPP). + The FPP executes single-, extended-, and double-precision floating-point + instructions, as well as double-integer instructions. All of the + floating-point instructions, as well as the single- and double-integer fix + and float instructions, are handled here. Pure double-integer instructions + are dispatched to the double-integer handler for simulation. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A N/A N/A std + + For the F-Series, the instruction codes are mapped to routines as follows: + + Instr. 1000-F Description + ------ ------ ------------------------------------- + 105000 FAD Single real add + 105001 .XADD Extended real add + 105002 .TADD Double real add + 105003 [EAD] [5-word add] + 105004 [tst] [Floating Point Processor self test] + 105005 [xpd] [Expand exponent] + 105006 [rst] [Floating Point Processor reset] + 105007 [stk] [Process stack of operands] + 105010 [chk] [FPP addressing check] + 105014 .DAD Double integer add + 105020 FSB Single real subtract + 105021 .XSUB Extended real subtract + 105022 .TSUB Double real subtract + 105023 [ESB] [5-word subtract] + 105034 .DSB Double integer subtract + 105040 FMP Single real multiply + 105041 .XMPY Extended real multiply + 105042 .TMPY Double real multiply + 105043 [EMP] [5-word multiply] + 105054 .DMP Double integer multiply + 105060 FDV Single real divide + 105061 .XDIV Extended real divide + 105062 .TDIV Double real divide + 105063 [EDV] [5-word divide] + 105074 .DDI Double integer divide + 105100 FIX Single real to integer fix + 105101 .XFXS Extended real to integer fix (.DINT) + 105102 .TXFS Double real to integer fix (.TINT) + 105103 [EFS] [5-word FIXS] + 105104 .FIXD Real to double integer fix + 105105 .XFXD Extended real to double integer fix + 105106 .TFXD Double real to double integer fix + 105107 [EFD] [5-word FIXD] + 105114 .DSBR Double integer subtraction (reversed) + 105120 FLT Integer to single real float + 105121 .XFTS Integer to extended real float (.IDBL) + 105122 .TFTS Integer to double real float (.ITBL) + 105123 [ELS] [5-word FLTS] + 105124 .FLTD Double integer to real float + 105125 .XFTD Double integer to extended real float + 105126 .TFTD Double integer to double real float + 105127 [ELD] [5-word FLTD] + 105134 .DDIR Double integer divide (reversed) + + Implementation note: rather than have two simulators that each executes the + single-precision FP instruction set, we compile conditionally, based on the + availability of 64-bit integer support in the host compiler. 64-bit integers + are required for the FPP, so if they are available, then we handle the + single-precision instructions for the 2100 and M/E-Series here, and the + firmware simulation is omitted. If support is unavailable, then the firmware + function is used instead. + + Notes: + + 1. Single-precision arithmetic instructions (.FAD, etc.) and extended- and + double-precision F-Series FPP arithmetic instructions (.XADD, .TADD, + etc.) return positive infinity on both positive and negative overflow. + The equivalent extended-precision M/E-Series FFP instructions return + negative infinity on negative overflow and positive infinity on positive + overflow. + + 2. The items in brackets above are undocumented instructions that are used + by the 12740 FPP-SIS-FFP diagnostic only. + + 3. The five-word arithmetic instructions (e.g., 105003) use an expanded + operand format that dedicates a separate word to the exponent. See the + implementation notes in the hardware floating-point processor simulation + for details. + + 4. The "self test" instruction (105004) returned to P+1 for early F-Series + units without double-integer support. Units incorporating such support + returned to P+2. + + 5. The "expand exponent" instruction (105005) is used as a "prefix" + instruction to enable a 10-bit exponent range. It is placed immediately + before a 5-word arithmetic instruction sequence, e.g., immediately + preceding an EAD instruction sequence. The arithmetic instruction + executes normally, except that under/overflow is not indicated unless + the exponent exceeds the 10-bit range, instead of the normal 8-bit + range. If overflow is indicated, the exponent is still set to +128. + + Note that as 2-, 3-, and 4-word packed numbers only have room for 8-bit + exponents, the Expand Exponent instruction serves no useful purpose in + conjunction with instructions associated with these precisions. If + used, the resulting values may be in error, as overflow from the 8-bit + exponents will not be indicated. + + 6. The "FPP reset" instruction (105006) is provided to reset a hung box, + e.g., in cases where an improper number of parameters is supplied. The + hardware resets its internal state machine in response to this + instruction. Under simulation, the instruction has no effect, as the + simulated FPP cannot hang. + + 7. The "process stack" instruction (105007) executes a series of FPP + instruction sets in sequence. Each set consists of a single FPP + instruction and associated operands that specifies the operation, + followed by a "result" instruction and operand. The result instruction + is optional and is only used to specify the result precision; the + instruction itself is not executed. If the result instruction is NOP, + then the result precision is that of the executed FPP instruction. If + the result operand is null, then the result is kept in the internal FPP + accumulator for later use. + + The calling sequence is as follows: + + STK Process stack instruction + DEF ERRTN Address of error return + DEF SET1 Address of first instruction set + DEF SET2 Address of second instruction set + . + . + . + ERRTN EQU * Return here if execution in error + OKRTN EQU * Return here if execution OK + + Instruction sets are specified as follows (e.g.): + + SET1 .TADD Operation instruction (NOP to terminate series) + DEC 4 Number of words in first operand (or 0 if accum) + DEF OP1 Address of first operand + DEC 4 Number of words in second operand (or 0 if accum) + DEF OP2 Address of second operand + .XADD Result precision conversion instruction (or NOP) + DEC 3 Number of words to store (or 0 if no store) + DEF RSLT Address of buffer to hold value + + The primary use of the "process stack" instruction is to enable chained + operations employing the FPP accumulator for intermediate results and to + enable expanded exponent usage across multiple instructions. + + 8. The "addressing check" instruction sets bit 0 of the L register to 1, + copies the X register value to the FPP, and then reads the FPP and + stores the result in the Y register. Setting the L register bit 0 to 1 + normally deselects the FPP, so that the value in Y is 177777. However, + the FPP box has a strap that inverts the selection logic, even though + the box will not work with the base-set firmware if this is done. The + "addressing check" instruction is provided to test whether the strap is + in the alternate location. Under simulation, the return value is always + 177777, indicating that the strap is correctly set. + + Additional references: + - DOS/RTE Relocatable Library Reference Manual (24998-90001, Oct-1981) + - FPP-SIS-FFP Diagnostic Source (12740-18001, Rev. 1926) +*/ + +static const OP_PAT op_fpp[96] = { + OP_RF, OP_AXX, OP_ATT, OP_AEE, /* FAD .XADD .TADD .EADD */ + OP_N, OP_C, OP_N, OP_A, /* [tst] [xpd] [rst] [stk] */ + OP_N, OP_N, OP_N, OP_N, /* [chk] --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* .DAD --- --- --- */ + OP_RF, OP_AXX, OP_ATT, OP_AEE, /* FSB .XSUB .TSUB .ESUB */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* .DSB --- --- --- */ + OP_RF, OP_AXX, OP_ATT, OP_AEE, /* FMP .XMPY .TMPY .EMPY */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* .DMP --- --- --- */ + OP_RF, OP_AXX, OP_ATT, OP_AEE, /* FDV .XDIV .TDIV .EDIV */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* .DDI --- --- --- */ + OP_R, OP_X, OP_T, OP_E, /* FIX .XFXS .TFXS .EFXS */ + OP_R, OP_X, OP_T, OP_E, /* .FIXD .XFXD .TFXD .EFXD */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* .DSBR --- --- --- */ + OP_I, OP_IA, OP_IA, OP_IA, /* FLT .XFTS .TFTS .EFTS */ + OP_J, OP_JA, OP_JA, OP_JA, /* .FLTD .XFTD .TFTD .EFTD */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N /* .DDIR --- --- --- */ + }; + +t_stat cpu_fpp (uint32 IR, uint32 intrq) +{ +OP fpop; +OPS op; +OPSIZE op1_prec, op2_prec, rslt_prec, cvt_prec; +uint16 opcode, rtn_addr, stk_ptr; +uint32 entry; +t_stat reason = SCPE_OK; + +if ((cpu_unit.flags & UNIT_FP) == 0) /* FP option installed? */ + return stop_inst; + +if (UNIT_CPU_MODEL == UNIT_1000_F) /* F-Series? */ + opcode = (uint16) (IR & 0377); /* yes, use full opcode */ +else + opcode = (uint16) (IR & 0160); /* no, use 6 SP FP opcodes */ + +entry = opcode & 0177; /* map to <6:0> */ + +if (op_fpp[entry] != OP_N) + if (reason = cpu_ops (op_fpp[entry], op, intrq)) /* get instruction operands */ + return reason; + +switch (entry) { /* decode IR<6:0> */ + case 0000: /* FAD 105000 (OP_RF) */ + case 0020: /* FSB 105020 (OP_RF) */ + case 0040: /* FMP 105040 (OP_RF) */ + case 0060: /* FDV 105060 (OP_RF) */ + O = fp_exec (opcode, &fpop, op[0], op[1]); /* execute operation */ + AR = fpop.fpk[0]; /* return result to A/B */ + BR = fpop.fpk[1]; + break; + + case 0001: /* .XADD 105001 (OP_AXX) */ + case 0002: /* .TADD 105002 (OP_ATT) */ + case 0003: /* .EADD 105003 (OP_AEE) */ + + case 0021: /* .XSUB 105021 (OP_AXX) */ + case 0022: /* .TSUB 105022 (OP_ATT) */ + case 0023: /* .ESUB 105023 (OP_AEE) */ + + case 0041: /* .XMPY 105041 (OP_AXX) */ + case 0042: /* .TMPY 105042 (OP_ATT) */ + case 0043: /* .EMPY 105043 (OP_AEE) */ + + case 0061: /* .XDIV 105061 (OP_AXX) */ + case 0062: /* .TDIV 105062 (OP_ATT) */ + case 0063: /* .EDIV 105063 (OP_AEE) */ + O = fp_exec (opcode, &fpop, op[1], op[2]); /* execute operation */ + fp_prec (opcode, NULL, NULL, &rslt_prec); /* determine result precision */ + WriteOp (op[0].word, fpop, rslt_prec); /* write result */ + break; + + case 0004: /* [tst] 105004 (OP_N) */ + XR = 3; /* firmware revision */ + SR = 0102077; /* test passed code */ + PC = (PC + 1) & VAMASK; /* P+2 return for firmware w/DBI */ + break; + + case 0005: /* [xpd] 105005 (OP_C) */ + return cpu_fpp (op[0].word | 0200, intrq); /* set bit 7, execute instr */ + + case 0006: /* [rst] 105006 (OP_N) */ + break; /* do nothing for FPP reset */ + + case 0007: /* [stk] 105007 (OP_A) */ + O = 0; /* clear overflow */ + stk_ptr = PC; /* save ptr to next buf */ + rtn_addr = op[0].word; /* save return address */ + + while (TRUE) { + PC = ReadW (stk_ptr) & VAMASK; /* point at next instruction set */ + stk_ptr = (stk_ptr + 1) & VAMASK; + + reason = cpu_ops (OP_CCACACCA, op, intrq); /* get instruction set */ + + if (reason) { + PC = err_PC; /* irq restarts */ + break; + } + + if (op[0].word == 0) { /* opcode = NOP? */ + PC = (rtn_addr + 1) & VAMASK; /* bump to good return */ + break; /* done */ + } + + fp_prec ((uint16) (op[0].word & 0377), /* determine operand precisions */ + &op1_prec, &op2_prec, &rslt_prec); + + if (TO_COUNT(op1_prec) != op[1].word) { /* first operand precisions agree? */ + PC = rtn_addr; /* no, so take error return */ + break; + } + + else if (op1_prec != fp_a) /* operand in accumulator? */ + op[1] = ReadOp (op[2].word, op1_prec); /* no, so get operand 1 */ + + if (TO_COUNT(op2_prec) != op[3].word) { /* second operand precisions agree? */ + PC = rtn_addr; /* no, so take error return */ + break; + } + + else if (op2_prec != fp_a) /* operand in accumulator? */ + op[2] = ReadOp (op[4].word, op2_prec); /* no, so get operand 2 */ + + O = O | /* execute instruction */ + fp_exec ((uint16) (op[0].word & 0377), /* and accumulate overflow */ + &fpop, op[1], op[2]); + + if (op[5].word) { /* precision conversion? */ + fp_prec ((uint16) (op[5].word & 0377), /* determine conversion precision */ + NULL, NULL, &cvt_prec); + + fpop = fp_accum (NULL, cvt_prec); /* convert result */ + } + else /* no conversion specified */ + cvt_prec = rslt_prec; /* so use original precision */ + + if (op[6].word) /* store result? */ + WriteOp (op[7].word, fpop, cvt_prec); /* yes, so write it */ + } + + break; + + case 0010: /* [chk] 105010 (OP_N) */ + YR = 0177777; /* -1 if selection strap OK */ + break; + + case 0014: /* .DAD 105014 (OP_N) */ + return cpu_dbi (0105321, intrq); /* remap to double int handler */ + + case 0034: /* .DSB 105034 (OP_N) */ + return cpu_dbi (0105327, intrq); /* remap to double int handler */ + + case 0054: /* .DMP 105054 (OP_N) */ + return cpu_dbi (0105322, intrq); /* remap to double int handler */ + + case 0074: /* .DDI 105074 (OP_N) */ + return cpu_dbi (0105325, intrq); /* remap to double int handler */ + + case 0100: /* FIX 105100 (OP_R) */ + case 0101: /* .XFXS 105101 (OP_X) */ + case 0102: /* .TFXS 105102 (OP_T) */ + case 0103: /* .EFXS 105103 (OP_E) */ + O = fp_exec (opcode, &fpop, op[0], NOP); /* fix to integer */ + AR = fpop.fpk[0]; /* save result */ + break; + + case 0104: /* .FIXD 105104 (OP_R) */ + case 0105: /* .XFXD 105105 (OP_X) */ + case 0106: /* .TFXD 105106 (OP_T) */ + case 0107: /* .EFXD 105107 (OP_E) */ + O = fp_exec (opcode, &fpop, op[0], NOP); /* fix to integer */ + AR = (fpop.dword >> 16) & DMASK; /* save result */ + BR = fpop.dword & DMASK; /* in A and B */ + break; + + case 0114: /* .DSBR 105114 (OP_N) */ + return cpu_dbi (0105334, intrq); /* remap to double int handler */ + + case 0120: /* FLT 105120 (OP_I) */ + case 0124: /* .FLTD 105124 (OP_J) */ + O = fp_exec (opcode, &fpop, op[0], NOP); /* float to single */ + AR = fpop.fpk[0]; /* save result */ + BR = fpop.fpk[1]; /* into A/B */ + break; + + case 0121: /* .XFTS 105121 (OP_IA) */ + case 0122: /* .TFTS 105122 (OP_IA) */ + case 0123: /* .EFTS 105123 (OP_IA) */ + case 0125: /* .XFTD 105125 (OP_JA) */ + case 0126: /* .TFTD 105126 (OP_JA) */ + case 0127: /* .EFTD 105127 (OP_JA) */ + O = fp_exec (opcode, &fpop, op[0], NOP); /* float integer */ + fp_prec (opcode, NULL, NULL, &rslt_prec); /* determine result precision */ + WriteOp (op[1].word, fpop, rslt_prec); /* write result */ + break; + + case 0134: /* .DDIR 105134 (OP_N) */ + return cpu_dbi (0105326, intrq); /* remap to double int handler */ + + default: /* others undefined */ + reason = stop_inst; + } + +return reason; +} + + +/* Scientific Instruction Set. + + The SIS adds single-precision trigonometric and logarithmic, and + double-precision polynomial evaluation instructions to the 1000-F instruction + set. The SIS is standard on the 1000-F. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A N/A N/A std + + The routines are mapped to instruction codes as follows: + + Instr. 1000-F Description + ------ ------ ---------------------------------------------- + TAN 105320 Tangent + SQRT 105321 Square root + ALOG 105322 Natural logarithm + ATAN 105323 Arc tangent + COS 105324 Cosine + SIN 105325 Sine + EXP 105326 E to the power X + ALOGT 105327 Common logarithm + TANH 105330 Hyperbolic tangent + DPOLY 105331 Double-precision polynomial evaluation + /CMRT 105332 Double-precision common range reduction + /ATLG 105333 Compute (1-x)/(1+x) for .ATAN and .LOG + .FPWR 105334 Single-precision exponentiation + .TPWR 105335 Double-precision exponentiation + [tst] 105337 [self test] + + The SIS simulation follows the F-Series SIS microcode, which, in turn, + follows the algebraic approximations given in the Relocatable Library manual + descriptions of the equivalent software routines. + + Notes: + + 1. The word following the DPOLY instruction contains up to three flag bits + to indicate one of several polynomial forms to evaluate. The comments + in the DPOLY software library routine source interchange the actions of + the bit 14 and bit 0 flags. The DPOLY description in the Technical + Reference Handbook is correct. + + 2. Several instructions (e.g., DPOLY) are documented as leaving undefined + values in the A, B, X, Y, E, or O registers. Simulation does not + attempt to reproduce the same values as would be obtained with the + hardware. + + 3. The SIS uses the hardware FPP of the F-Series. FPP malfunctions are + detected by the SIS firmware and are indicated by a memory-protect + violation and setting the overflow flag. Under simulation, + malfunctions cannot occur. + + 4. We use OP_IIT for the .FPWR operand pattern. The "II" is redundant, but + it aligns the operands with the OP_IAT of .TPWR, so the code may be + shared. + + Additional references: + - DOS/RTE Relocatable Library Reference Manual (24998-90001, Oct-1981) + - HP 1000 E-Series and F-Series Computer Microprogramming Reference Manual + (02109-90004, Apr-1980). +*/ + + +/* Common single-precision range reduction for SIN, COS, TAN, and EXP. + + This routine is called by the SIN, COS, TAN, and EXP handlers to reduce the + range of the argument. Reduction is performed in extended-precision. We + calculate: + + multiple = (nearest even integer to argument * multiplier) + argument = argument * multiplier - multiple +*/ + +static uint32 reduce (OP *argument, int32 *multiple, OP multiplier) +{ +OP product, count; +uint32 overflow; + +fp_cvt (argument, fp_f, fp_x); /* convert to extended precision */ +fp_exec (0041, &product, *argument, multiplier); /* product = argument * multiplier */ +overflow = fp_exec (0111, &count, NOP, NOP); /* count = FIX (acc) */ + +if ((int16) count.word >= 0) /* nearest even integer */ + count.word = count.word + 1; +count.word = count.word & ~1; +*multiple = (int16) count.word; + +if (overflow == 0) { /* in range? */ + fp_exec (0121, ACCUM, count, NOP); /* acc = FLT (count) */ + overflow = fp_exec (0025, ACCUM, product, NOP); /* acc = product - acc */ + *argument = fp_accum (NULL, fp_f); /* trim to single-precision */ + } +return overflow; +} + + +/* SIS dispatcher. */ + +static const OP_PAT op_sis[16] = { + OP_R, OP_R, OP_R, OP_R, /* TAN SQRT ALOG ATAN */ + OP_R, OP_R, OP_R, OP_R, /* COS SIN EXP ALOGT */ + OP_R, OP_CATAKK, OP_AAT, OP_A, /* TANH DPOLY /CMRT /ATLG */ + OP_IIF, OP_IAT, OP_N, OP_N /* .FPWR .TPWR --- [tst] */ + }; + +t_stat cpu_sis (uint32 IR, uint32 intrq) +{ +OPS op; +OP arg, coeff, pwr, product, count, result; +int16 f, p; +int32 multiple, power, exponent, rsltexp; +uint32 entry, i; +t_bool flag, sign; +t_stat reason = SCPE_OK; + +static const OP tan_c4 = { { 0137763, 0051006 } }; /* DEC -4.0030956 */ +static const OP tan_c3 = { { 0130007, 0051026 } }; /* DEC -1279.5424 */ +static const OP tan_c2 = { { 0040564, 0012761 } }; /* DEC 0.0019974806 */ +static const OP tan_c1 = { { 0045472, 0001375 } }; /* DEC 0.14692695 */ + +static const OP alog_c3 = { { 0065010, 0063002 } }; /* DEC 1.6567626301 */ +static const OP alog_c2 = { { 0125606, 0044404 } }; /* DEC -2.6398577035 */ +static const OP alog_c1 = { { 0051260, 0037402 } }; /* DEC 1.2920070987 */ + +static const OP atan_c4 = { { 0040257, 0154404 } }; /* DEC 2.0214656 */ +static const OP atan_c3 = { { 0132062, 0133406 } }; /* DEC -4.7376165 */ +static const OP atan_c2 = { { 0047407, 0173775 } }; /* DEC 0.154357652 */ +static const OP atan_c1 = { { 0053447, 0014002 } }; /* DEC 1.3617611 */ + +static const OP sin_c4 = { { 0132233, 0040745 } }; /* DEC -0.000035950439 */ +static const OP sin_c3 = { { 0050627, 0122361 } }; /* DEC 0.002490001 */ +static const OP sin_c2 = { { 0126521, 0011373 } }; /* DEC -0.0807454325 */ +static const OP sin_c1 = { { 0062207, 0166400 } }; /* DEC 0.78539816 */ + +static const OP cos_c4 = { { 0126072, 0002753 } }; /* DEC -0.00031957 */ +static const OP cos_c3 = { { 0040355, 0007767 } }; /* DEC 0.015851077 */ +static const OP cos_c2 = { { 0130413, 0011377 } }; /* DEC -0.30842483 */ +static const OP cos_c1 = { { 0040000, 0000002 } }; /* DEC 1.0 */ + +static const OP sqrt_a2 = { { 0045612, 0067400 } }; /* DEC 0.5901621 */ +static const OP sqrt_b2 = { { 0065324, 0126377 } }; /* DEC 0.4173076 */ +static const OP sqrt_a1 = { { 0065324, 0126400 } }; /* DEC 0.8346152 */ +static const OP sqrt_b1 = { { 0045612, 0067400 } }; /* DEC 0.5901621 */ + +static const OP exp_c2 = { { 0073000, 0070771 } }; /* DEC 0.05761803 */ +static const OP exp_c1 = { { 0056125, 0041406 } }; /* DEC 5.7708162 */ + +static const OP tanh_c3 = { { 0050045, 0022004 } }; /* DEC 2.5045337 */ +static const OP tanh_c2 = { { 0041347, 0101404 } }; /* DEC 2.0907609 */ +static const OP tanh_c1 = { { 0052226, 0047375 } }; /* DEC 0.16520923 */ + +static const OP minus_1 = { { 0100000, 0000000 } }; /* DEC -1.0 */ +static const OP plus_1 = { { 0040000, 0000002 } }; /* DEC +1.0 */ +static const OP plus_half = { { 0040000, 0000000 } }; /* DEC +0.5 */ +static const OP ln_2 = { { 0054271, 0006000 } }; /* DEC 0.6931471806 (ln 2.0) */ +static const OP log_e = { { 0067455, 0166377 } }; /* DEC 0.43429228 (log e) */ +static const OP pi_over_4 = { { 0062207, 0166400 } }; /* Pi / 4.0 */ +static const OP pi_over_2 = { { 0062207, 0166402 } }; /* Pi / 2.0 */ + +static const OP four_over_pi = { { 0050574, 0140667, 0023402 } }; /* 4.0 / Pi */ +static const OP two_over_ln2 = { { 0056125, 0016624, 0127404 } }; /* 2.0 / ln(2.0) */ + +static const OP t_one = { { 0040000, 0000000, 0000000, 0000002 } }; /* DEY 1.0 */ + + +if (UNIT_CPU_MODEL != UNIT_1000_F) /* F-Series? */ + return stop_inst; + +entry = IR & 017; /* mask to entry point */ + +if (op_sis[entry] != OP_N) + if (reason = cpu_ops (op_sis[entry], op, intrq)) /* get instruction operands */ + return reason; + +switch (entry) { /* decode IR<3:0> */ + + case 000: /* TAN 105320 (OP_R) */ + O = reduce (&op[0], &multiple, four_over_pi); /* reduce range */ + + if (O) { /* out of range? */ + op[0].fpk[0] = '0' << 8 | '9'; /* return '09' */ + op[0].fpk[1] = 'O' << 8 | 'R'; /* return 'OR' */ + break; /* error return is P+1 */ + } + + fp_exec (0040, &op[1], op[0], op[0]); /* op1 = arg ^ 2 */ + fp_exec (0010, ACCUM, NOP, tan_c4); /* acc = acc + C4 */ + fp_exec (0064, ACCUM, tan_c3, NOP); /* acc = C3 / acc */ + fp_exec (0010, ACCUM, NOP, op[1]); /* acc = acc + op1 */ + fp_exec (0050, ACCUM, NOP, tan_c2); /* acc = acc * C2 */ + fp_exec (0010, ACCUM, NOP, tan_c1); /* acc = acc + C1 */ + fp_exec (0050, &op[0], NOP, op[0]); /* res = acc * arg */ + + if (multiple & 0002) /* multiple * 2 odd? */ + fp_exec (0064, &op[0], minus_1, NOP); /* res = -1.0 / acc */ + + PC = (PC + 1) & VAMASK; /* normal return is P+2 */ + break; + + + case 001: /* SQRT 105321 (OP_R) */ + O = 0; /* clear overflow */ + + if (op[0].fpk[0] == 0) { /* arg = 0? */ + PC = (PC + 1) & VAMASK; /* normal return is P+2 */ + break; + } + + else if ((int16) op[0].fpk[0] < 0) { /* sqrt of neg? */ + op[0].fpk[0] = '0' << 8 | '3'; /* return '03' */ + op[0].fpk[1] = 'U' << 8 | 'N'; /* return 'UN' */ + O = 1; /* set overflow */ + break; /* error return is P+1 */ + } + + fp_unpack (&op[1], &exponent, op[0], fp_f); /* unpack argument */ + + if (exponent & 1) { /* exponent odd? */ + fp_exec (0040, ACCUM, op[1], sqrt_a1); /* acc = op1 * A1 */ + fp_exec (0010, &op[2], NOP, sqrt_b1); /* op2 = acc + B1 */ + op[1].fpk[1] = op[1].fpk[1] + 2; /* op1 = op1 * 2.0 */ + } + else { /* exponent even */ + fp_exec (0040, ACCUM, op[1], sqrt_a2); /* acc = op1 * A2 */ + fp_exec (0010, &op[2], NOP, sqrt_b2); /* op2 = acc + B2 */ + } + + fp_exec (0064, ACCUM, op[1], NOP); /* acc = op1 / acc */ + fp_exec (0010, &op[2], NOP, op[2]); /* op2 = acc + op2 */ + + op[1].fpk[1] = op[1].fpk[1] + 4; /* op1 = op1 * 4.0 */ + + fp_exec (0064, ACCUM, op[1], NOP); /* acc = op1 / acc */ + fp_exec (0010, &op[0], NOP, op[2]); /* res = acc + op2 */ + + power = (exponent >> 1) - 2; + + if (op[0].fpk[0]) { /* calc x * 2**n */ + fp_unpack (&op[1], &exponent, op[0], fp_f); /* unpack argument */ + exponent = exponent + power; /* multiply by 2**n */ + + if ((exponent > 0177) || /* exponent overflow? */ + (exponent < -0200)) { /* or underflow? */ + O = 1; /* rtn unscaled val, set ovf */ + break; /* error return is P+1 */ + } + + else + fp_pack (&op[0], op[1], exponent, fp_f);/* repack result */ + } + + PC = (PC + 1) & VAMASK; /* normal return is P+2 */ + break; + + + case 002: /* ALOG 105322 (OP_R) */ + case 007: /* ALOGT 105327 (OP_R) */ + O = 0; /* clear overflow */ + + if ((int16) op[0].fpk[0] <= 0) { /* log of neg or zero? */ + op[0].fpk[0] = '0' << 8 | '2'; /* return '02' */ + op[0].fpk[1] = 'U' << 8 | 'N'; /* return 'UN' */ + O = 1; /* set overflow */ + break; /* error return is P+1 */ + } + + fp_unpack (&op[1], &exponent, op[0], fp_f); /* unpack argument */ + + if (op[0].fpk[0] < 0055000) { /* out of range? */ + exponent = exponent - 1; /* drop exponent */ + op[1].fpk[1] = op[1].fpk[1] | 2; /* set "exponent" to 1 */ + } + + op[2].fpk[0] = exponent; + fp_exec (0120, &op[3], op[2], NOP); /* op3 = FLT(exponent) */ + + fp_exec (0020, &op[4], op[1], plus_1); /* op4 = op1 - 1.0 */ + fp_exec (0000, ACCUM, op[1], plus_1); /* acc = op1 + 1.0 */ + fp_exec (0064, &op[5], op[4], NOP); /* op5 = op4 / acc */ + + fp_exec (0054, ACCUM, NOP, NOP); /* acc = acc * acc */ + fp_exec (0030, ACCUM, NOP, alog_c3); /* acc = acc - c3 */ + fp_exec (0064, ACCUM, alog_c2, NOP); /* acc = c2 / acc */ + fp_exec (0010, ACCUM, NOP, alog_c1); /* acc = acc + c1 */ + fp_exec (0050, ACCUM, NOP, op[5]); /* acc = acc * op5 */ + fp_exec (0010, ACCUM, NOP, op[3]); /* acc = acc + op3 */ + fp_exec (0050, &op[0], NOP, ln_2); /* res = acc * ln2 */ + + if (entry == 007) /* ALOGT? */ + fp_exec (0050, &op[0], NOP, log_e); /* res = acc * log(e) */ + + PC = (PC + 1) & VAMASK; /* normal return is P+2 */ + break; + + + case 003: /* ATAN 105323 (OP_R) */ + O = 0; /* clear overflow */ + + if (op[0].fpk[0] == 0) /* argument zero? */ + break; /* result zero */ + + flag = (op[0].fpk[1] & 1); /* get exponent sign */ + sign = ((int16) op[0].fpk[0] < 0); /* get argument sign */ + + if (flag == 0) { /* exp pos? (abs >= 0.5)? */ + if (sign) /* argument negative? */ + fp_pcom (&op[0], fp_f); /* make positive */ + + if (op[0].fpk[1] & 0374) { /* arg >= 2? */ + fp_exec(0060, &op[0], plus_1, op[0]); /* arg = 1.0 / arg */ + op[2] = pi_over_2; /* constant = pi / 2.0 */ + } + else { + fp_exec (0020, &op[1], plus_1, op[0]); /* op1 = 1.0 - arg */ + fp_exec (0000, ACCUM, plus_1, op[0]); /* acc = 1.0 + arg */ + fp_exec (0064, &op[0], op[1], NOP); /* arg = op1 / acc */ + op[2] = pi_over_4; /* constant = pi / 4.0 */ + } + } + + fp_exec (0040, &op[1], op[0], op[0]); /* op1 = arg * arg */ + fp_exec (0010, ACCUM, NOP, atan_c4); /* acc = acc + C4 */ + fp_exec (0064, ACCUM, atan_c3, NOP); /* acc = C3 / acc */ + fp_exec (0010, ACCUM, NOP, op[1]); /* acc = acc + op1 */ + fp_exec (0050, ACCUM, NOP, atan_c2); /* acc = acc * C2 */ + fp_exec (0010, ACCUM, NOP, atan_c1); /* acc = acc + C1 */ + fp_exec (0064, &op[0], op[0], NOP); /* res = arg / acc */ + + if (flag == 0) { /* exp pos? (abs >= 0.5)? */ + fp_exec (0030, &op[0], NOP, op[2]); /* res = acc - pi / n */ + + if (sign == 0) /* argument positive? */ + fp_pcom (&op[0], fp_f); /* make negative */ + } + + break; + + + case 004: /* COS 105324 (OP_R) */ + case 005: /* SIN 105325 (OP_R) */ + O = reduce (&op[0], &multiple, four_over_pi); /* reduce range */ + + if (O) { /* out of range? */ + op[0].fpk[0] = '0' << 8 | '5'; /* return '05' */ + op[0].fpk[1] = 'O' << 8 | 'R'; /* return 'OR' */ + break; /* error return is P+1 */ + } + + multiple = multiple / 2 + (entry == 004); /* add one for cosine */ + flag = (multiple & 1); /* decide on series */ + + fp_exec (0040, &op[1], op[0], op[0]); /* op1 = arg ^ 2 */ + + if (flag) { + fp_exec (0050, ACCUM, NOP, cos_c4); /* acc = acc * c4 */ + fp_exec (0010, ACCUM, NOP, cos_c3); /* acc = acc + c3 */ + fp_exec (0050, ACCUM, NOP, op[1]); /* acc = acc * op1 */ + fp_exec (0010, ACCUM, NOP, cos_c2); /* acc = acc + c2 */ + fp_exec (0050, ACCUM, NOP, op[1]); /* acc = acc * op1 */ + fp_exec (0010, &op[0], NOP, cos_c1); /* res = acc + c1 */ + } + + else { + fp_exec (0050, ACCUM, NOP, sin_c4); /* acc = acc * c4 */ + fp_exec (0010, ACCUM, NOP, sin_c3); /* acc = acc + c3 */ + fp_exec (0050, ACCUM, NOP, op[1]); /* acc = acc * op1 */ + fp_exec (0010, ACCUM, NOP, sin_c2); /* acc = acc + c2 */ + fp_exec (0050, ACCUM, NOP, op[1]); /* acc = acc * op1 */ + fp_exec (0010, ACCUM, NOP, sin_c1); /* acc = acc + c1 */ + fp_exec (0050, &op[0], NOP, op[0]); /* res = acc * arg */ + } + + if (multiple & 0002) /* multiple * 2 odd? */ + fp_pcom (&op[0], fp_f); /* make negative */ + + PC = (PC + 1) & VAMASK; /* normal return is P+2 */ + break; + + + case 006: /* EXP 105326 (OP_R) */ + sign = ((int16) op[0].fpk[0] < 0); /* get argument sign */ + + O = reduce (&op[0], &multiple, two_over_ln2); /* reduce range */ + multiple = multiple / 2; /* get true multiple */ + + if ((sign == 0) && (O | (multiple > 128))) { /* pos and ovf or out of range? */ + op[0].fpk[0] = '0' << 8 | '7'; /* return '07' */ + op[0].fpk[1] = 'O' << 8 | 'F'; /* return 'OF' */ + O = 1; /* set overflow */ + break; /* error return is P+1 */ + } + + else if (sign && (multiple < -128)) { /* neg and out of range? */ + op[0].fpk[0] = 0; /* result is zero */ + op[0].fpk[1] = 0; + O = 0; /* clear for underflow */ + PC = (PC + 1) & VAMASK; /* normal return is P+2 */ + break; + } + + fp_exec (0040, ACCUM, op[0], op[0]); /* acc = arg ^ 2 */ + fp_exec (0050, ACCUM, NOP, exp_c2); /* acc = acc * c2 */ + fp_exec (0030, ACCUM, NOP, op[0]); /* acc = acc - op0 */ + fp_exec (0010, ACCUM, NOP, exp_c1); /* acc = acc + c1 */ + fp_exec (0064, ACCUM, op[0], NOP); /* acc = op0 / acc */ + fp_exec (0010, &op[0], NOP, plus_half); /* res = acc + 0.5 */ + + power = multiple + 1; + + if (op[0].fpk[0]) { /* calc x * 2**n */ + fp_unpack (&op[1], &exponent, op[0], fp_f); /* unpack argument */ + exponent = exponent + power; /* multiply by 2**n */ + + if ((exponent > 0177) || /* exponent overflow? */ + (exponent < -0200)) { /* or underflow? */ + if (sign == 0) { /* arg positive? */ + op[0].fpk[0] = '0' << 8 | '7'; /* return '07' */ + op[0].fpk[1] = 'O' << 8 | 'F'; /* return 'OF' */ + O = 1; /* set overflow */ + } + else { + op[0].fpk[0] = 0; /* result is zero */ + op[0].fpk[1] = 0; + O = 0; /* clear for underflow */ + } + break; /* error return is P+1 */ + } + + else { + fp_pack (&op[0], op[1], exponent, fp_f);/* repack value */ + O = 0; + } + } + + PC = (PC + 1) & VAMASK; /* normal return is P+2 */ + break; + + + case 010: /* TANH 105330 (OP_R) */ + O = 0; + sign = ((int16) op[0].fpk[0] < 0); /* get argument sign */ + + if (op[0].fpk[1] & 1) { /* abs (arg) < 0.5? */ + fp_exec (0040, ACCUM, op[0], op[0]); /* acc = arg ^ 2 */ + fp_exec (0010, ACCUM, NOP, tanh_c3); /* acc = acc + c3 */ + fp_exec (0064, ACCUM, tanh_c2, NOP); /* acc = c2 / acc */ + fp_exec (0010, ACCUM, NOP, tanh_c1); /* acc = acc + c1 */ + fp_exec (0050, &op[0], NOP, op[0]); /* res = acc * arg */ + } + + else if (op[0].fpk[1] & 0370) /* abs (arg) >= 8.0? */ + if (sign) /* arg negative? */ + op[0] = minus_1; /* result = -1.0 */ + else /* arg positive */ + op[0] = plus_1; /* result = +1.0 */ + + else { /* 0.5 <= abs (arg) < 8.0 */ + BR = BR + 2; /* arg = arg * 2.0 */ + cpu_sis (0105326, intrq); /* calc exp (arg) */ + PC = (PC - 1) & VAMASK; /* correct P (always good rtn) */ + + op[0].fpk[0] = AR; /* save value */ + op[0].fpk[1] = BR; + + fp_exec (0020, &op[1], op[0], plus_1); /* op1 = op0 - 1.0 */ + fp_exec (0000, ACCUM, op[0], plus_1); /* acc = op0 + 1.0 */ + fp_exec (0064, &op[0], op[1], NOP); /* res = op1 / acc */ + } + + break; + + + case 011: /* DPOLY 105331 (OP_CATAKK) */ + O = 0; /* clear overflow */ + AR = op[0].word; /* get flag word */ + + if ((int16) AR >= 0) { /* flags present? */ + AR = 1; /* no, so set default */ + arg = op[2]; /* arg = X */ + } + + else /* bit 15 set */ + fp_exec (0042, &arg, op[2], op[2]); /* arg = X ^ 2 */ + + coeff = ReadOp (op[3].word, fp_t); /* get first coefficient */ + op[3].word = (op[3].word + 4) & VAMASK; /* point at next */ + fp_accum (&coeff, fp_t); /* acc = coeff */ + + for (i = 0; i < op[4].word; i++) { /* compute numerator */ + fp_exec (0052, ACCUM, NOP, arg); /* acc = P[m] * arg */ + coeff = ReadOp (op[3].word, fp_t); /* get next coefficient */ + op[3].word = (op[3].word + 4) & VAMASK; /* point at next */ + fp_exec (0012, ACCUM, NOP, coeff); /* acc = acc + P[m-1] */ + } + + if (AR & 1) /* bit 0 set? */ + op[6] = fp_accum (NULL, fp_t); /* save numerator */ + else + fp_exec (0046, &op[6], op[2], NOP); /* acc = X * acc */ + + + if (op[5].word) { /* n > 0 ? */ + fp_accum (&t_one, fp_t); /* acc = 1.0 */ + + for (i = 0; i < op[5].word; i++) { /* compute denominator */ + fp_exec (0052, ACCUM, NOP, arg); /* acc = P[m] * arg */ + coeff = ReadOp (op[3].word, fp_t); /* get next coefficient */ + op[3].word = (op[3].word + 4) & VAMASK; /* point at next */ + fp_exec (0012, ACCUM, NOP, coeff); /* acc = acc + P[m-1] */ + } + + if (AR & 0040000) /* bit 14 set? */ + fp_exec (0032, ACCUM, NOP, op[6]); /* acc = den - num */ + + fp_exec (0066, &op[6], op[6], NOP); /* op6 = num / den */ + } + + WriteOp (op[1].word, op[6], fp_t); /* write result */ + + if (O) /* overflow? */ + op[0].fpk[0] = 0; /* microcode rtns with A = 0 */ + break; + + + case 012: /* /CMRT 105332 (OP_AAT) */ + O = 0; + f = (int16) AR; /* save flags */ + + coeff = ReadOp (op[1].word, fp_t); /* get coefficient (C) */ + + fp_unpack (NULL, &exponent, op[2], fp_t); /* unpack exponent */ + + if ((f == -1) || (exponent < 4)) { /* TANH or abs (arg) < 16.0? */ + + /* result = x * c - n */ + + fp_exec (0042, &product, op[2], coeff); /* product = arg * C */ + O = fp_exec (0112, &count, NOP, NOP); /* count = FIX (acc) */ + + if ((int16) count.word >= 0) /* nearest even integer */ + count.word = count.word + 1; + BR = count.word = count.word & ~1; + + O = O | fp_exec (0122, ACCUM, count, NOP); /* acc = FLT (count) */ + + if (O) { /* out of range? */ + op[0].fpk[0] = 0; /* microcode rtns with A = 0 */ + break; /* error return is P+1 */ + } + + fp_exec (0026, &result, product, NOP); /* acc = product - acc */ + fp_unpack (NULL, &rsltexp, result, fp_t); /* unpack exponent */ + + /* determine if cancellation matters */ + + if ((f < 0) || (f == 2) || (f == 6) || /* EXP, TANH, or COS? */ + (exponent - rsltexp < 5)) { /* bits lost < 5? */ + WriteOp (op[0].word, result, fp_t); /* write result */ + PC = (PC + 1) & VAMASK; /* P+2 return for good result */ + break; /* all done! */ + } + } + + /* result = (xu * cu - n) + (x - xu) * c + xu * cl */ + + if (exponent >= (8 + 16 * (f >= 0))) { /* exp >= 8 (EXP,TANH)? */ + op[0].fpk[0] = 0; /* or 24 (SIN/COS/TAN)? */ + break; /* range error return is P+1 */ + } + + op[3].fpk[0] = coeff.fpk[0]; /* form upper bits of C (CU) */ + op[3].fpk[1] = coeff.fpk[1] & 0177770; + op[3].fpk[2] = 0; + op[3].fpk[3] = coeff.fpk[3] & 0000377; + + op[4].fpk[0] = op[2].fpk[0]; /* form upper bits of X (XU) */ + op[4].fpk[1] = op[2].fpk[1] & 0177770; + op[4].fpk[2] = 0; + op[4].fpk[3] = op[2].fpk[3] & 0000377; + + fp_exec (0042, &op[5], op[3], op[4]); /* op5 = cu * xu */ + + fp_exec (0116, &op[6], NOP, NOP); /* op6 = fix (acc) (2wd) */ + + if ((int32) op[6].dword >= 0) /* nearest even integer */ + op[6].dword = op[6].dword + 1; + op[6].dword = op[6].dword & ~1; + + O = fp_exec (0126, ACCUM, op[6], NOP); /* acc = flt (op6) */ + + if (O) { /* overflow? */ + op[0].fpk[0] = 0; /* microcode rtns with A = 0 */ + break; /* range error return is P+1 */ + } + + fp_exec (0026, &op[7], op[5], NOP); /* op7 = cu * xu - n */ + + fp_exec (0022, ACCUM, op[2], op[4]); /* acc = x - xu */ + fp_exec (0052, ACCUM, NOP, coeff); /* acc = (x - xu) * c */ + fp_exec (0012, &op[5], NOP, op[7]); /* op5 = acc + (cu * xu - n) */ + + op[1].word = (op[1].word + 4) & VAMASK; /* point at second coefficient */ + coeff = ReadOp (op[1].word, fp_t); /* get coefficient (CL) */ + + fp_exec (0042, ACCUM, op[4], coeff); /* acc = xu * cl */ + fp_exec (0012, &result, NOP, op[5]); /* result = acc + (x - xu) * c + (cu * xu - n) */ + + WriteOp (op[0].word, result, fp_t); /* write result */ + PC = (PC + 1) & VAMASK; /* P+2 return for good result */ + break; + + + case 013: /* /ATLG 105333 (OP_A) */ + arg = ReadOp (op[0].word, fp_t); /* get argument */ + + fp_exec (0022, &op[1], t_one, arg); /* op1 = 1.0 - arg */ + fp_exec (0002, ACCUM, t_one, arg); /* acc = 1.0 + arg */ + fp_exec (0066, &op[1], op[1], NOP); /* res = op1 / acc */ + + WriteOp (op[0].word, op[1], fp_t); /* write result */ + break; + + + case 014: /* .FPWR 105334 (OP_IIF) */ + p = 0; /* set to single-precision */ + goto NPWR; + + case 015: /* .TPWR 105335 (OP_IAT) */ + p = 2; /* set to double-precision */ + + NPWR: + if (op[2].fpk[0]) { /* non-zero base? */ + fp_exec (0120, &pwr, op[0], NOP); /* float power */ + + sign = ((int16) pwr.fpk[0] < 0); /* save sign of power */ + i = (pwr.fpk[0] << 2) & DMASK; /* clear it */ + + fp_unpack (NULL, &exponent, pwr, fp_f); /* unpack exponent */ + + if (sign == 0) + exponent = exponent - 1; + + O = 0; /* clear overflow */ + fp_accum (&op[2], (fp_f + p)); /* acc = arg */ + + while (exponent-- > 0) { + O = O | fp_exec ((uint16) (0054 | p), /* square acc */ + ACCUM, NOP, NOP); + + if (i & SIGN) + O = O | fp_exec ((uint16) (0050 | p), /* acc = acc * arg */ + ACCUM, NOP, op[2]); + i = i << 1; + } + + op[2] = fp_accum (NULL, (fp_f + p)); /* get accum */ + + if (op[2].fpk[0] == 0) /* result zero? */ + O = 1; /* underflow */ + } + + if (entry == 014) /* .FPWR ? */ + op[0] = op[2]; /* copy result */ + else /* .TPWR */ + WriteOp (op[1].word, op[2], fp_t); /* write result */ + + break; + + + case 017: /* [tst] 105337 (OP_N) */ + XR = 4; /* firmware revision */ + SR = 0102077; /* test passed code */ + PC = (PC + 1) & VAMASK; /* P+2 return for firmware w/DPOLY */ + return reason; + + + default: /* others undefined */ + return stop_inst; + } + +AR = op[0].fpk[0]; /* save result */ +BR = op[0].fpk[1]; /* into A/B */ +return reason; +} + +#endif /* end of int64 support */ diff --git a/HP2100/hp2100_defs.h b/HP2100/hp2100_defs.h index c56e5205..0d0d94d0 100644 --- a/HP2100/hp2100_defs.h +++ b/HP2100/hp2100_defs.h @@ -1,6 +1,6 @@ /* hp2100_defs.h: HP 2100 simulator definitions - Copyright (c) 1993-2004, Robert M. Supnik + Copyright (c) 1993-2007, 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,12 @@ 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. + 11-Jan-07 JDB Added 12578A DMA byte packing to DMA structure + 28-Dec-06 JDB Added CRS backplane signal as I/O pseudo-opcode + Added DMASK32 32-bit mask value + 21-Dec-06 JDB Changed MEM_ADDR_OK for 21xx loader support + 12-Sep-06 JDB Define NOTE_IOG to recalc interrupts after instr exec + Rename STOP_INDINT to NOTE_INDINT (not a stop condition) 30-Dec-04 JDB Added IBL_DS_HEAD head number mask 19-Nov-04 JDB Added STOP_OFFLINE, STOP_PWROFF stop codes 25-Apr-04 RMS Added additional IBL definitions @@ -45,24 +51,25 @@ #include "sim_defs.h" /* simulator defns */ -/* Simulator stop codes */ +/* Simulator stop and notification codes */ #define STOP_RSRV 1 /* must be 1 */ #define STOP_IODV 2 /* must be 2 */ #define STOP_HALT 3 /* HALT */ #define STOP_IBKPT 4 /* breakpoint */ #define STOP_IND 5 /* indirect loop */ -#define STOP_INDINT 6 /* indirect intr */ +#define NOTE_INDINT 6 /* indirect intr */ #define STOP_NOCONN 7 /* no connection */ #define STOP_OFFLINE 8 /* device offline */ #define STOP_PWROFF 9 /* device powered off */ +#define NOTE_IOG 10 /* I/O instr executed */ #define ABORT_PRO 1 /* protection abort */ /* Memory */ #define MEMSIZE (cpu_unit.capac) /* actual memory size */ -#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) +#define MEM_ADDR_OK(x) (((uint32) (x)) < fwanxm) #define VA_N_SIZE 15 /* virtual addr size */ #define VASIZE (1 << VA_N_SIZE) #define VAMASK 077777 /* virt addr mask */ @@ -73,8 +80,10 @@ /* Architectural constants */ #define SIGN32 020000000000 /* 32b sign */ +#define DMASK32 037777777777 /* 32b data mask */ #define SIGN 0100000 /* 16b sign */ #define DMASK 0177777 /* 16b data mask */ +#define DMASK8 0377 /* 8b data mask */ #define AR ABREG[0] /* A = reg 0 */ #define BR ABREG[1] /* B = reg 1 */ #define SEXT(x) ((int32) (((x) & SIGN)? ((x) | ~DMASK): ((x) & DMASK))) @@ -101,7 +110,9 @@ /* DMA channels */ +#define DMA_OE 020000000000 /* byte packing odd/even flag */ #define DMA1_STC 0100000 /* DMA - issue STC */ +#define DMA1_PB 0040000 /* DMA - pack bytes */ #define DMA1_CLC 0020000 /* DMA - issue CLC */ #define DMA2_OI 0100000 /* DMA - output/input */ @@ -109,6 +120,8 @@ struct DMA { /* DMA channel */ uint32 cw1; /* device select */ uint32 cw2; /* direction, address */ uint32 cw3; /* word count */ + uint32 latency; /* 1st cycle delay */ + uint32 packer; /* byte-packer holding reg */ }; /* Memory management */ @@ -182,6 +195,7 @@ struct DMA { /* DMA channel */ #define ioOTX 6 /* output from A/B */ #define ioCTL 7 /* set/clear control */ #define ioEDT 8 /* DMA: end data transfer */ +#define ioCRS 9 /* control reset ("CLC 0") */ /* I/O devices - fixed assignments */ diff --git a/HP2100/hp2100_diag.txt b/HP2100/hp2100_diag.txt index 256eef0d..236e7f45 100644 --- a/HP2100/hp2100_diag.txt +++ b/HP2100/hp2100_diag.txt @@ -1,18 +1,19 @@ SIMH/HP 21XX DIAGNOSTICS PERFORMANCE ==================================== - Last update: 2005-03-22 + Last update: 2007-01-12 The HP 24396 diagnostic suite has been run against the SIMH HP 21xx simulation. -Diagnostic programs were obtained from magnetic tape, HP 24396-13601 Rev. 2040. -For each diagnostic, the recommended standard tests were selected, plus any -available optional tests that broadened the test coverage. +Diagnostic programs were obtained from two magnetic tapes, HP 24396-13601 Rev. +1713 and Rev. 2326, plus a few standalone paper tapes. For each diagnostic, the +recommended standard tests were selected, plus any available optional tests that +broadened the test coverage. -The test system configuration is the default SIMH configuration with these -alterations (except where noted in the individual diagnostic reports): +Except where noted in the individual diagnostic reports, the test system +configuration is the default SIMH configuration with these alterations: * All I/O devices are enabled. - * The CPU is configured as a 21MX-E with 128KW of memory. + * The CPU is configured as a 1000-E with 128KW of memory. Detailed diagnostic configuration, operation, and results are given after the summary table. These may be used to duplicate the diagnostic results. @@ -33,19 +34,23 @@ The results of the diagnostic runs are summarized below: 101004 EAU Instruction Group 1431 3.2-3 Passed 101207 Floating Point Instruction Group 1551 3.2-3 Passed +102001 Memory Protect 1431 3.7-0 Passed +102002 Memory Parity Check 1431 - No simulation 102305 Memory Protect/Parity Error 1705 3.3-0 Partial 101206 Power Fail/Auto Restart 1635 - No simulation 141103 I/O Instruction Group 1810 3.2-3 Passed 143300 General Purpose Register 1813 3.2-3 Passed -101220 Direct Memory Access 1705 3.2-3 Passed +101105 Direct Memory Access (2114/15/16) 1502 3.7-0 Passed +101220 Direct Memory Access (2100/21MX) 1705 3.2-3 Passed 101011 Extended Instruction Group (Index) 1432 3.2-3 Passed 101112 Extended Instruction Group (Word, Byte) 1728 3.2-3 Passed 101110 2100 Fast FORTRAN Package 1632 3.4-0 Partial 101213 M/E-Series Fast FORTRAN Package 1 1822 3.4-0 Passed 101114 M/E-Series Fast FORTRAN Package 2 1632 3.4-0 Passed -101121 F-Series FPP/SIS/FFP 1926 - No simulation +101121 F-Series FPP/SIS/FFP 1926 3.7-0 Passed +101016 2000/Access Comm Processor for 2100 1526 3.2-3 Partial 102103 Memory Expansion Unit 1830 3.2-3 Passed 102103 Semiconductor Memory Microcoded 21MX 1644 - No simulation @@ -66,13 +71,26 @@ The results of the diagnostic runs are summarized below: 103121 12968 Asynchronous Comm. Interface 1602 - No simulation 103024 12821 ICD Disc Interface 1928 - No simulation +104000 2600 Keyboard Display Terminal 1615 - No simulation +104003 Teleprinter 1509 3.2-3 Partial +144105 2762A/B Terminal (Terminet) 1546 - No simulation +104007 2615 Video Terminal 1347 - No simulation +104011 2640 Interactive Terminal 1502 - No simulation +104012 2644 Mini Data Station (non CTU) 1542 - No simulation +104013 2644 Mini Data Station (CTU Only) 1542 - No simulation +104017 92900 Terminal Subsystem (3070, 40280) 1643 - No simulation + +105000 2610/14 Line Printer 1451 - No simulation +105101 2767 Line Printer 1611 3.3-0 Passed 105102 2607 Line Printer 1446 3.3-0 Passed 145103 2613/17/18 Line Printer 1633 - No simulation +105104 9866 Line Printer 1541 - No simulation 105106 2631 Printer 1913 - No simulation 105107 2635 Printing Terminal 1913 - No simulation 105105 2608 Line Printer 2026 - No simulation 105104 9866 Line Printer 1541 - No simulation +111001 Disc File (2883) 1451 3.3-0 Partial 111104 12732 Flexible Disc Subsystem 1708 - No simulation 151302 7900/01 Cartridge Disc 1805 3.2-3 Partial 151403 7905/06/20/25 Disc 1805 3.3-1 Partial @@ -86,8 +104,7 @@ The results of the diagnostic runs are summarized below: 107000 Digital Plotter Interface (CALCOMP) 1540 - No simulation 113100 2892 Card Reader 1537 - No simulation 113001 2894 Card Reader Punch 1728 - No simulation -104003 Teleprinter 1509 3.2-3 Partial -104007 2615 Video Terminal 1347 - No simulation +113003 7261 Card Reader 1546 - No simulation 103006 12909B PROM Writer 1420 - No simulation @@ -97,12 +114,9 @@ not supported by the 24396 suite: Paper Tape Date SIMH Part Number DSN Diagnostic Name Code Vers. Result ----------- ------ --------------------------------------- ---- ----- ---------- -12984-16001 105101 2767 Diagnostic 1611 3.3-0 Passed 24203-60001 -- HP2100A Cartridge Disc Memory (2871) A 3.3-0 Partial -12965-16001 111001 HP2100A Disc File (2883) 1451 3.3-0 Partial 22682-16017 177777 HP 2100 Fixed Head Disc/Drum (277x) 1612 3.3-0 Passed -13206-16001 101016 2100 2000/Access Comm. Proc. Firmware 1526 3.2-3 Partial -13207-16001 101217 21MX 2000/Access Comm. Proc. Firmware 1728 3.2-3 Passed +13207-16001 101217 2000/Access Comm Processor for 21MX 1728 3.2-3 Passed 20433-????? -- HP 3030 Magnetic Tape Subsystem -- - Not tested @@ -123,7 +137,7 @@ diagnostic: model were either excluded or failed as expected, due to known limitations in the simulation, e.g., the lack of "defective cylinder" flags in a disc simulation. - + Failed One or more of the standard tests relevant to the hardware model failed unexpectedly. @@ -144,7 +158,7 @@ For all runs other than the diagnostic configurator pretest, the configurator was used in automatic mode to load the target diagnostic via its Diagnostic Serial Number (DSN), as follows: - sim> attach -r MSC0 24396-13601-REV-2040.tape + sim> attach -r MSC0 24396-13601_Rev-2326.abin.tape sim> deposit S 000000 sim> boot MSC0 @@ -233,6 +247,7 @@ TESTED DEVICE: CPU (hp2100_cpu.c) CONFIGURATION: sim> set CPU 2100 sim> set CPU 32K + sim> deposit S 000000 sim> reset sim> go 100 @@ -273,7 +288,7 @@ TEST NOTES: The standard tests 00-10, plus optional tests 13, 14, and 16 are DSN 101004 - EAU Instruction Group ---------------------------------- -TESTED DEVICE: CPU (hp2100_cpu.c) +TESTED DEVICE: CPU (hp2100_cpu1.c) CONFIGURATION: sim> deposit S 000000 sim> reset @@ -292,7 +307,7 @@ TEST RESULT: Passed. DSN 101207 - Floating Point Instruction Group --------------------------------------------- -TESTED DEVICE: CPU (hp2100_fp.c) +TESTED DEVICE: CPU (hp2100_cpu2.c) CONFIGURATION: sim> deposit S 000000 sim> reset @@ -307,6 +322,44 @@ TEST RESULT: Passed. +--------------------------- +DSN 102001 - Memory Protect +--------------------------- + +TESTED DEVICE: MP (hp2100_cpu.c) + +CONFIGURATION: sim> set CPU 2100 + sim> set CPU 32K + + sim> deposit S 000000 + sim> reset + sim> go 100 + +TEST REPORT: HP 2100 SERIES MEMORY PROTECT DIAGNOSTIC + H07. PRESS PRESET (EXT/INT), RUN + + HALT instruction 102007 + + sim> reset + sim> go + + H13. PRESS HALT, PRESET(INT), RUN + IN LESS THAN 15 SEC. + + [CTRL+E] + Simulation stopped + + sim> reset + sim> go + + PASS 000001 + + HALT instruction 102077 + +TEST RESULT: Passed. + + + ---------------------------------------- DSN 102305 - Memory Protect/Parity Error ---------------------------------------- @@ -353,7 +406,7 @@ TEST REPORT: H061 POWER DOWN COMPUTER PASS 000001 H062 POWER DOWN COMPUTER - SET JUMPERS TO INITIAL SETTINGS + SET JUMPERS TO INITIAL SETTINGS PER TABLE 3-1 IN MOD POWER UP COMPUTER @@ -454,12 +507,47 @@ TEST RESULT: Passed. ---------------------------------- -DSN 101220 - Direct Memory Access ---------------------------------- +---------------------------------------------- +DSN 101105 - Direct Memory Access (2114/15/16) +---------------------------------------------- TESTED DEVICE: DMA0/DMA1 (hp2100_cpu.c) +CONFIGURATION: sim> set CPU 2116 + sim> set CPU 16K + sim> set LPS diag + + sim> deposit S 000014 + sim> reset + sim> go 100 + + HALT instruction 102074 + + sim> deposit S 040000 + sim> reset + sim> go + +TEST REPORT: H0. START DMA DIAGNOSTIC + + HALT instruction 102027 + + sim> reset + sim> go + + H77. END DIAGNOSTIC + + HALT instruction 102077 + +TEST RESULT: Passed. + + + +--------------------------------------------- +DSN 101220 - Direct Memory Access (2100/21MX) +--------------------------------------------- + +TESTED DEVICE: DCPC0/DCPC1 (hp2100_cpu.c) + CONFIGURATION: sim> set LPS diag sim> deposit S 000014 sim> reset @@ -492,7 +580,7 @@ TEST RESULT: Passed. DSN 101011 - Extended Instruction Group (Index) ----------------------------------------------- -TESTED DEVICE: CPU (hp2100_cpu1.c) +TESTED DEVICE: CPU (hp2100_cpu2.c) CONFIGURATION: sim> deposit S 000000 sim> reset @@ -511,7 +599,7 @@ TEST RESULT: Passed. DSN 101112 - Extended Instruction Group (Word, Byte, Bit) --------------------------------------------------------- -TESTED DEVICE: CPU (hp2100_cpu1.c) +TESTED DEVICE: CPU (hp2100_cpu2.c) CONFIGURATION: sim> set LPS diag sim> deposit S 000014 @@ -537,7 +625,7 @@ TEST RESULT: Passed. DSN 101110 - 2100 Fast FORTRAN Package -------------------------------------- -TESTED DEVICE: CPU (hp2100_cpu1.c) +TESTED DEVICE: CPU (hp2100_cpu3.c) CONFIGURATION: sim> set CPU 2100 sim> set CPU 32K @@ -598,7 +686,7 @@ TEST NOTES: Tests 07 and 11 test the interruptibility of the .XADD and .XMPY DSN 101213 - M/E-Series Fast FORTRAN Package 1 ---------------------------------------------- -TESTED DEVICE: CPU (hp2100_cpu1.c) +TESTED DEVICE: CPU (hp2100_cpu3.c) CONFIGURATION: sim> set CPU FFP sim> set LPS diag @@ -636,10 +724,10 @@ TEST RESULT: Passed. ---------------------------------------------- -DSN 101115 - M/E-Series Fast FORTRAN Package 2 +DSN 101114 - M/E-Series Fast FORTRAN Package 2 ---------------------------------------------- -TESTED DEVICE: CPU (hp2100_cpu1.c) +TESTED DEVICE: CPU (hp2100_cpu3.c) CONFIGURATION: sim> set CPU FFP sim> set LPS diag @@ -675,11 +763,127 @@ TEST RESULT: Passed. +--------------------------------- +DSN 101121 - F-Series FPP/SIS/FFP +--------------------------------- + +TESTED DEVICE: CPU (hp2100_cpu3.c) + +CONFIGURATION: sim> set CPU 1000-F + sim> set LPS diag + + sim> deposit S 000014 + sim> reset + sim> go 100 + + HALT instruction 102074 + + sim> deposit S 000000 + sim> reset + sim> go + +TEST REPORT: FPP-SIS-FFP DIAGNOSTIC DSN 101121 + BEGIN BASIC CONTROL TEST + OVFL TEST + CONF TEST + BASE RETN TEST + SIS1 RETN TEST + SIS2 RETN TEST + SIS3 RETN TEST + FPP1 RETN TEST + FFP2 RETN TEST + FFP3 RETN TEST + END BASIC CONTROL TEST + LONG PASSES + FIXS TEST + FIXD TEST + FLTS TEST + FLTD TEST + ADD TEST + SUB TEST + MPY TEST + DIV TEST + ACC TEST + SIS1 TEST + SIS2 TEST + SIS3 TEST + FFP1 TEST + FFP2 TEST + FFP3 TEST + PASS 00001 + + HALT instruction 102077 + +TEST RESULT: Passed. + + + +------------------------------------------------ +DSN 101016 - 2000/Access Comm Processor for 2100 +------------------------------------------------ + +TESTED DEVICE: CPU (hp2100_cpu2.c) + +BINARY TAPE: 13206-16001 Rev. 1526 + +CONFIGURATION: sim> set CPU 2100 + sim> set CPU 32K + sim> set CPU IOP + + sim> deposit S 000013 + sim> reset + sim> go 100 + + HALT instruction 102074 + + sim> deposit S 000000 + sim> reset + sim> go + +TEST REPORT: 2100 2000-ACCESS COMM. PROC. FIRMWARE DIAGNOSTIC + H030 CRC TEST + H040 ENQ, DEQ AND PENQ TESTS + H060 IAL TEST + H110 READF, SAVE AND RESTR TESTS + H120 LAI AND SAI TESTS + H130 PFREX TEST + H140 PFREI TEST + H150 PFRIO TEST + H160 STORE-LOAD BYTE, TRSLT + AND BYTE MOVE TEST + + TEST 10 + E165 TRSLT NOT INTERRUPTIBLE + + HALT instruction 106065 + + sim> go + + H230 WORD MOVE TEST + + TEST 11 + E234 WORD MOVE NOT INTERRUPTIBLE + + HALT instruction 103034 + + sim> go + + PASS 000001 + + HALT instruction 102077 + +TEST RESULT: Partially passed. + +TEST NOTES: Tests 10 and 11 test the interruptibility of the TRSLT and MWORD + instructions. These features are not simulated. + + + ---------------------------------- DSN 102103 - Memory Expansion Unit ---------------------------------- -TESTED DEVICE: CPU (hp2100_cpu.c) +TESTED DEVICE: CPU (hp2100_cpu2.c) CONFIGURATION: sim> set LPS diag sim> deposit S 000014 @@ -693,7 +897,7 @@ CONFIGURATION: sim> set LPS diag sim> go MEMORY EXPANSION MODULE DIAGNOSTIC, DSN = 102103 - + HALT instruction 102075 sim> deposit A 177777 @@ -728,7 +932,7 @@ TEST RESULT: Passed. TEST NOTES: The standard tests 00-22 plus optional tests 23 and 24 are executed. - + Test 25 (Register Crusher Test) is not executed. This test is designed specifically for the RAM chips present on the hardware and isn't relevant to simulation. @@ -812,6 +1016,109 @@ TEST RESULT: Not tested. +------------------------------ +DSN 105101 - 2767 Line Printer +------------------------------ + +TESTED DEVICE: LPS (hp2100_lps.c) + +BINARY TAPE: 12984-16001 Rev. 1611 + +CONFIGURATION: sim> set LPS realtime + sim> attach LPS scratch.2767.printer + sim> deposit S 000014 + sim> reset + sim> go 100 + + HALT instruction 102074 + + sim> deposit S 000000 + sim> reset + sim> go + +TEST REPORT: 2767 L.P. DIAGNOSTIC + H024 PRESS PRESET (EXT&INT),RUN + + HALT instruction 102024 + + sim> reset + sim> go + + H025 BI-O COMP + H035 TURN OFF L.P. POWER + + HALT instruction 102035 + + sim> set LPS poweroff + sim> go + + H036 TURN ON L.P. POWER + + HALT instruction 102036 + + sim> set LPS poweron + sim> go + + H033 PUT L.P. ON-LINE + + HALT instruction 102033 + + sim> set LPS online + sim> go + + H034 MASTER CLEAR L.P. + + HALT instruction 102034 + + sim> set LPS offline + sim> go + + H033 PUT L.P. ON-LINE + + HALT instruction 102033 + + sim> set LPS online + sim> go + + H040 PUT L.P. OFF-LINE. TOGGLE TOP-OF-FORM SWITCH + + HALT instruction 102040 + + sim> set LPS offline + sim> go + + H033 PUT L.P. ON-LINE + + HALT instruction 102033 + + sim> set LPS online + sim> go + + H041 PUT L.P. OFF-LINE. TOGGLE PAPER-STEP 5 TIMES + + HALT instruction 102041 + + sim> set LPS offline + sim> go + + H033 PUT L.P. ON-LINE + + HALT instruction 102033 + + sim> set LPS online + sim> go + + PASS 000001 + + HALT instruction 102077 + +TEST RESULT: Passed. + +TEST NOTES: The simulation provides no manual Master Clear, Top of Form, or + Paper Step functions, so these are merely presumed above. + + + ------------------------------ DSN 105102 - 2607 Line Printer ------------------------------ @@ -1160,49 +1467,49 @@ CONFIGURATION: sim> set DS0 7905 ENTER:(U)NIT,(?) ERRS,(H)EAD,(O)UTPUT,(P)ATT,(S)OFT,(C)YL,(M)CPU,(E)XIT H - H62 HEAD TABLE; UNIT 0 7905A , 02 HEAD(S) 0 1 - H62 HEAD TABLE; UNIT 1 7906A , 02 HEAD(S) 0 1 - H62 HEAD TABLE; UNIT 2 7920A , 05 HEAD(S) 0 1 2 3 4 - H62 HEAD TABLE; UNIT 3 7925A , 09 HEAD(S) 0 1 2 3 4 5 6 7 8 - H62 HEAD TABLE; UNIT 4 7905A , 02 HEAD(S) 0 1 - H62 HEAD TABLE; UNIT 5 7906A , 02 HEAD(S) 0 1 - H62 HEAD TABLE; UNIT 6 7920A , 05 HEAD(S) 0 1 2 3 4 - H62 HEAD TABLE; UNIT 7 7925A , 09 HEAD(S) 0 1 2 3 4 5 6 7 8 + H62 HEAD TABLE; UNIT 0 7905A , 02 HEAD(S) 0 1 + H62 HEAD TABLE; UNIT 1 7906A , 02 HEAD(S) 0 1 + H62 HEAD TABLE; UNIT 2 7920A , 05 HEAD(S) 0 1 2 3 4 + H62 HEAD TABLE; UNIT 3 7925A , 09 HEAD(S) 0 1 2 3 4 5 6 7 8 + H62 HEAD TABLE; UNIT 4 7905A , 02 HEAD(S) 0 1 + H62 HEAD TABLE; UNIT 5 7906A , 02 HEAD(S) 0 1 + H62 HEAD TABLE; UNIT 6 7920A , 05 HEAD(S) 0 1 2 3 4 + H62 HEAD TABLE; UNIT 7 7925A , 09 HEAD(S) 0 1 2 3 4 5 6 7 8 H25 WISH TO CHANGE? YES H132 TYPE UNITS YOU WISH TO CHANGE SEPERATED BY COMMAS 0,1,4,5 - H62 HEAD TABLE; UNIT 0 7905A , 02 HEAD(S) 0 1 + H62 HEAD TABLE; UNIT 0 7905A , 02 HEAD(S) 0 1 H106 ENTER HEADS SEPARATED BY COMMAS 0,1,2 - H62 HEAD TABLE; UNIT 0 7905A , 03 HEAD(S) 0 1 2 + H62 HEAD TABLE; UNIT 0 7905A , 03 HEAD(S) 0 1 2 H25 WISH TO CHANGE? NO - H62 HEAD TABLE; UNIT 1 7906A , 02 HEAD(S) 0 1 + H62 HEAD TABLE; UNIT 1 7906A , 02 HEAD(S) 0 1 H106 ENTER HEADS SEPARATED BY COMMAS 0,1,2,3 - H62 HEAD TABLE; UNIT 1 7906A , 04 HEAD(S) 0 1 2 3 + H62 HEAD TABLE; UNIT 1 7906A , 04 HEAD(S) 0 1 2 3 H25 WISH TO CHANGE? NO - H62 HEAD TABLE; UNIT 4 7905A , 02 HEAD(S) 0 1 + H62 HEAD TABLE; UNIT 4 7905A , 02 HEAD(S) 0 1 H106 ENTER HEADS SEPARATED BY COMMAS 0,1,2 - H62 HEAD TABLE; UNIT 4 7905A , 03 HEAD(S) 0 1 2 + H62 HEAD TABLE; UNIT 4 7905A , 03 HEAD(S) 0 1 2 H25 WISH TO CHANGE? NO - H62 HEAD TABLE; UNIT 5 7906A , 02 HEAD(S) 0 1 + H62 HEAD TABLE; UNIT 5 7906A , 02 HEAD(S) 0 1 H106 ENTER HEADS SEPARATED BY COMMAS 0,1,2,3 - H62 HEAD TABLE; UNIT 5 7906A , 04 HEAD(S) 0 1 2 3 + H62 HEAD TABLE; UNIT 5 7906A , 04 HEAD(S) 0 1 2 3 H25 WISH TO CHANGE? NO @@ -1262,9 +1569,9 @@ TEST REPORT: H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN H135 S P D TSTAT XXXX UNIT / E DRTYPE X A P F DF FS SC NR B E64 STATUS IS 0 0 0 00000 0000 0000 / 0 000010 0 0 0 1 0 0 0 0 0 SHOULD BE 0 1 0 00000 XXXX XXXX / 0 000010 0 0 0 1 0 0 0 0 0 - H137 TERMINATION STATUS IS "NORMAL COMPLET" + H137 TERMINATION STATUS IS "NORMAL COMPLET" START 0000/00/00-LAST 0000/00/01 WORD COUNT 00128,OLD CYL 0000,UNIT 00 - + HALT instruction 102001 sim> go @@ -1273,9 +1580,9 @@ TEST REPORT: H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN H135 S P D TSTAT XXXX UNIT / E DRTYPE X A P F DF FS SC NR B E64 STATUS IS 0 0 0 00000 0000 0000 / 0 000010 0 0 0 1 0 0 0 0 0 SHOULD BE 0 1 0 00000 XXXX XXXX / 0 000010 0 0 0 1 0 0 0 0 0 - H137 TERMINATION STATUS IS "NORMAL COMPLET" + H137 TERMINATION STATUS IS "NORMAL COMPLET" START 0000/00/00-LAST 0001/00/00 WORD COUNT 00048,OLD CYL 0000,UNIT 00 - + HALT instruction 102001 sim> go @@ -1293,7 +1600,7 @@ TEST REPORT: H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN SHOULD BE 0 0 1 10001 XXXX XXXX / 0 000010 0 0 0 0 0 0 0 0 0 H137 TERMINATION STATUS IS "NORMAL COMPLET" SHOULD BE "DEFECTIVE TRK " START 0001/00/00-LAST 0001/00/01 WORD COUNT 00128,OLD CYL 0000,UNIT 00 - + HALT instruction 102001 sim> go @@ -1304,7 +1611,7 @@ TEST REPORT: H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN SHOULD BE 0 1 0 10110 XXXX XXXX / 0 000010 0 0 0 0 0 0 0 0 0 H137 TERMINATION STATUS IS "NORMAL COMPLET" SHOULD BE "WRT PROTEC TRK" START 0000/00/00-LAST 0000/00/01 WORD COUNT 00128,OLD CYL 0001,UNIT 00 - + HALT instruction 102001 sim> go @@ -1320,9 +1627,9 @@ TEST REPORT: H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN H135 S P D TSTAT XXXX UNIT / E DRTYPE X A P F DF FS SC NR B E64 STATUS IS 0 0 0 00000 0000 0000 / 0 000010 0 0 0 1 0 0 0 0 0 SHOULD BE 0 1 0 00000 XXXX XXXX / 0 000010 0 0 0 1 0 0 0 0 0 - H137 TERMINATION STATUS IS "NORMAL COMPLET" + H137 TERMINATION STATUS IS "NORMAL COMPLET" START 0000/00/00-LAST 0000/00/08 WORD COUNT 01024,OLD CYL 0000,UNIT 00 - + HALT instruction 102001 sim> go @@ -1369,7 +1676,7 @@ TEST REPORT: H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN SHOULD BE 0 0 0 00111 0000 0000 / 0 000010 0 0 0 X 0 0 0 0 0 H137 TERMINATION STATUS IS "NORMAL COMPLET" SHOULD BE "CYL CMP ERROR " START 0000/00/01-LAST 0000/00/03 WORD COUNT 00138,OLD CYL 0000,UNIT 00 - + HALT instruction 102001 sim> go @@ -1380,7 +1687,7 @@ TEST REPORT: H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN SHOULD BE 0 0 0 01001 XXXX XXXX / 0 000010 0 0 0 X 0 0 0 0 0 H137 TERMINATION STATUS IS "NORMAL COMPLET" SHOULD BE "HD/SEC CMP ERR" START 0000/00/01-LAST 0000/00/03 WORD COUNT 00138,OLD CYL 0000,UNIT 00 - + HALT instruction 102001 sim> go @@ -1391,7 +1698,7 @@ TEST REPORT: H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN SHOULD BE 0 0 0 01001 XXXX XXXX / 0 000010 0 0 0 X 0 0 0 0 0 H137 TERMINATION STATUS IS "NORMAL COMPLET" SHOULD BE "HD/SEC CMP ERR" START 0000/00/01-LAST 0000/00/03 WORD COUNT 00138,OLD CYL 0000,UNIT 00 - + HALT instruction 102001 sim> go @@ -1404,7 +1711,7 @@ TEST REPORT: H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN SHOULD BE 0 0 0 01111 XXXX XXXX / 0 000010 0 0 0 X 0 0 0 0 0 H137 TERMINATION STATUS IS "NORMAL COMPLET" SHOULD BE "POSS CORR DATA" START 0000/00/00-LAST 0000/00/03 WORD COUNT 00128,OLD CYL 0000,UNIT 00 - + HALT instruction 102001 sim> go @@ -1415,7 +1722,7 @@ TEST REPORT: H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN SHOULD BE 0 0 0 01000 XXXX XXXX / 0 000010 0 0 0 X 0 0 0 0 0 H137 TERMINATION STATUS IS "NORMAL COMPLET" SHOULD BE "UNCOR DATA ERR" START 0000/00/00-LAST 0000/00/03 WORD COUNT 00276,OLD CYL 0000,UNIT 00 - + HALT instruction 102001 sim> go @@ -1426,7 +1733,7 @@ TEST REPORT: H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN SHOULD BE 0 0 1 10001 XXXX XXXX / 0 000010 0 0 0 X 0 0 0 0 0 H137 TERMINATION STATUS IS "NORMAL COMPLET" SHOULD BE "DEFECTIVE TRK " START 0016/00/00-LAST 0017/00/00 WORD COUNT 00048,OLD CYL 0128,UNIT 00 - + HALT instruction 102001 sim> go @@ -1437,7 +1744,7 @@ TEST REPORT: H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN SHOULD BE 1 0 0 10000 XXXX XXXX / 0 000010 0 0 0 X 0 0 0 0 0 H137 TERMINATION STATUS IS "NORMAL COMPLET" SHOULD BE "SPR TRK ACCESS" START 0128/01/00-LAST 0129/01/00 WORD COUNT 00048,OLD CYL 0016,UNIT 00 - + HALT instruction 102001 sim> go @@ -1446,9 +1753,9 @@ TEST REPORT: H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN H135 S P D TSTAT XXXX UNIT / E DRTYPE X A P F DF FS SC NR B E64 STATUS IS 0 0 0 00000 0000 0000 / 0 000010 0 0 0 1 0 0 0 0 0 SHOULD BE 1 0 0 00000 XXXX XXXX / 0 000010 0 0 0 X 0 0 0 0 0 - H137 TERMINATION STATUS IS "NORMAL COMPLET" + H137 TERMINATION STATUS IS "NORMAL COMPLET" START 0016/00/33-LAST 0016/00/34 WORD COUNT 00128,OLD CYL 0128,UNIT 00 - + HALT instruction 102001 sim> go @@ -1457,9 +1764,9 @@ TEST REPORT: H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN H135 S P D TSTAT XXXX UNIT / E DRTYPE X A P F DF FS SC NR B E64 STATUS IS 0 0 0 00000 0000 0000 / 0 000010 0 0 0 1 0 0 0 0 0 SHOULD BE 1 0 0 00000 XXXX XXXX / 0 000010 0 0 0 X 0 0 0 0 0 - H137 TERMINATION STATUS IS "NORMAL COMPLET" + H137 TERMINATION STATUS IS "NORMAL COMPLET" START 0016/00/33-LAST 0016/00/34 WORD COUNT 00128,OLD CYL 0016,UNIT 00 - + HALT instruction 102001 sim> go @@ -1471,7 +1778,7 @@ TEST REPORT: H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN H135 S P D TSTAT XXXX UNIT / E DRTYPE X A P F DF FS SC NR B E64 STATUS IS 0 0 0 00000 0000 0000 / 0 000010 0 0 0 1 0 0 0 0 0 SHOULD BE 1 0 0 00000 XXXX XXXX / 0 000010 0 0 0 X 0 0 0 0 0 - H137 TERMINATION STATUS IS "NORMAL COMPLET" + H137 TERMINATION STATUS IS "NORMAL COMPLET" START 0016/00/33-LAST 0016/00/34 WORD COUNT 00128,OLD CYL 0016,UNIT 00 HALT instruction 102001 @@ -1859,8 +2166,8 @@ TEST REPORT: H050 BI-O ON PUNCH sim> attach PTR scratch.2895.punch sim> go - H054 PLACE LOOP IN READER-PRESS RUN - TO START READ, SET BIT0 TO 1 + H054 PLACE LOOP IN READER-PRESS RUN + TO START READ, SET BIT0 TO 1 TO EXIT TEST, SET BIT0 TO 0 HALT instruction 102054 @@ -1876,8 +2183,8 @@ TEST REPORT: H050 BI-O ON PUNCH sim> deposit S 000000 sim> go - H054 PLACE LOOP IN READER-PRESS RUN - TO START READ, SET BIT0 TO 1 + H054 PLACE LOOP IN READER-PRESS RUN + TO START READ, SET BIT0 TO 1 TO EXIT TEST, SET BIT0 TO 0 HALT instruction 102054 @@ -1895,8 +2202,8 @@ TEST REPORT: H050 BI-O ON PUNCH H056 TURN PUNCH ON, PRESS RUN. PUNCH ROUTINE WILL START. LOAD THE TAPE BEING PUNCHED - INTO THE READER. - TO START READ, SET BIT0 TO 1 + INTO THE READER. + TO START READ, SET BIT0 TO 1 TO EXIT, SET BIT0 TO 0 HALT instruction 102056 @@ -2007,7 +2314,7 @@ TEST REPORT: H024 PRESS PRESET (EXT&INT),RUN sim> attach TTY2 scratch.2752.punch sim> go - H045 TURN TTY PUNCH OFF + H045 TURN TTY PUNCH OFF PRESS RUN HALT instruction 102045 @@ -2037,24 +2344,24 @@ TEST REPORT: H024 PRESS PRESET (EXT&INT),RUN sim> go INPUT THE FOLLOWING: - 1 2 3 4 5 6 7 8 9 0 : - + 1 2 3 4 5 6 7 8 9 0 : - - Q W E R T Y U I O P + Q W E R T Y U I O P - A S D F G H J K L ; + A S D F G H J K L ; - Z X C V B N M , . / + Z X C V B N M , . / SHIFT+ - ! " # $ % & ' ( ) * = + ! " # $ % & ' ( ) * = - _ @ + ^ < > ? + _ @ + ^ < > ? CNTRL+ - WRU TAPE NTAP XOFF EOT RU BELL TAB VT FORM + WRU TAPE NTAP XOFF EOT RU BELL TAB VT FORM - RBOT CR LF + RBOT CR LF HALT instruction 102076 @@ -2062,9 +2369,9 @@ TEST REPORT: H024 PRESS PRESET (EXT&INT),RUN sim> set console WRU=005 sim> go - INPUT ANY KEY - T H I S 040 I S 040 A 040 - T E S T + INPUT ANY KEY + T H I S 040 I S 040 A 040 + T E S T [CTRL+E] Simulation stopped @@ -2080,7 +2387,7 @@ TEST REPORT: H024 PRESS PRESET (EXT&INT),RUN H044 INPUT TERMINATED - ECHO MODE ANY INPUT IS ECHOED + ECHO MODE ANY INPUT IS ECHOED THIS IS A TEST [CTRL+E] @@ -2125,7 +2432,7 @@ Each execution note below presumes that the target diagnostic has been loaded. For all runs, the diagnostic configurator was used in automatic mode to load the target diagnostic from a paper tape image, as follows: - sim> attach -r MSC0 24396-13601-REV-2040.tape + sim> attach -r MSC0 24396-13601_Rev-2236.abin.tape sim> deposit S 000000 sim> boot MSC0 @@ -2138,109 +2445,6 @@ target diagnostic from a paper tape image, as follows: ------------------------------- -DSN 105101 - 2767 Line Printer ------------------------------- - -TESTED DEVICE: LPS (hp2100_lps.c) - -BINARY TAPE: 12984-16001 Rev. 1611 - -CONFIGURATION: sim> set LPS realtime - sim> attach LPS scratch.2767.printer - sim> deposit S 000014 - sim> reset - sim> go 100 - - HALT instruction 102074 - - sim> deposit S 000000 - sim> reset - sim> go - -TEST REPORT: 2767 L.P. DIAGNOSTIC - H024 PRESS PRESET (EXT&INT),RUN - - HALT instruction 102024 - - sim> reset - sim> go - - H025 BI-O COMP - H035 TURN OFF L.P. POWER - - HALT instruction 102035 - - sim> set LPS poweroff - sim> go - - H036 TURN ON L.P. POWER - - HALT instruction 102036 - - sim> set LPS poweron - sim> go - - H033 PUT L.P. ON-LINE - - HALT instruction 102033 - - sim> set LPS online - sim> go - - H034 MASTER CLEAR L.P. - - HALT instruction 102034 - - sim> set LPS offline - sim> go - - H033 PUT L.P. ON-LINE - - HALT instruction 102033 - - sim> set LPS online - sim> go - - H040 PUT L.P. OFF-LINE. TOGGLE TOP-OF-FORM SWITCH - - HALT instruction 102040 - - sim> set LPS offline - sim> go - - H033 PUT L.P. ON-LINE - - HALT instruction 102033 - - sim> set LPS online - sim> go - - H041 PUT L.P. OFF-LINE. TOGGLE PAPER-STEP 5 TIMES - - HALT instruction 102041 - - sim> set LPS offline - sim> go - - H033 PUT L.P. ON-LINE - - HALT instruction 102033 - - sim> set LPS online - sim> go - - PASS 000001 - - HALT instruction 102077 - -TEST RESULT: Passed. - -TEST NOTES: The simulation provides no manual Master Clear, Top of Form, or - Paper Step functions, so these are merely presumed above. - - - ----------------------------------------------------------------- DSN (none) - HP2100A Cartridge Disc Memory (2871) (multiple unit) ----------------------------------------------------------------- @@ -2264,7 +2468,7 @@ CONFIGURATION: sim> set DPC 12557A sim> reset sim> go 100 - H0 HP2100A CARTRIDGE DISC MEMORY DIAGNOSTIC + H0 HP2100A CARTRIDGE DISC MEMORY DIAGNOSTIC H34 ENTER UNIT NUMBERS(0-3)SEPARATED BY COMMAS 0,1,2,3 @@ -2276,17 +2480,17 @@ CONFIGURATION: sim> set DPC 12557A sim> go H24 CYLINDER TABLE - 000,001,002,004,008,016,032,064,128,202 + 000,001,002,004,008,016,032,064,128,202 H25 WISH TO ALTER TABLE? NO - H27 PATTERN TABLE - 000000 177777 125252 052525 007417 - 170360 162745 163346 155555 022222 + H27 PATTERN TABLE + 000000 177777 125252 052525 007417 + 170360 162745 163346 155555 022222 H25 WISH TO ALTER TABLE? NO - H62 TYPE A FOR HEADS 0,1;B FOR 2,3;C FOR ALTERNATELY 0,1 THEN 2,3 + H62 TYPE A FOR HEADS 0,1;B FOR 2,3;C FOR ALTERNATELY 0,1 THEN 2,3 C H32 RESET SWITCH 2 @@ -2297,7 +2501,7 @@ CONFIGURATION: sim> set DPC 12557A sim> reset sim> go 100 -TEST REPORT: H0 HP2100A CARTRIDGE DISC MEMORY DIAGNOSTIC +TEST REPORT: H0 HP2100A CARTRIDGE DISC MEMORY DIAGNOSTIC H65 PASS 0001 H65 PASS 0002 H65 PASS 0003 @@ -2332,7 +2536,7 @@ CONFIGURATION: sim> set DPC 12557A sim> reset sim> go 100 -TEST REPORT: H0 HP2100A CARTRIDGE DISC MEMORY DIAGNOSTIC +TEST REPORT: H0 HP2100A CARTRIDGE DISC MEMORY DIAGNOSTIC H66 SET OVERRIDE SWITCH,PUSH RUN HALT instruction 102002 @@ -2369,7 +2573,7 @@ TEST REPORT: H0 HP2100A CARTRIDGE DISC MEMORY DIAGNOSTIC sim> go - H42 WRITE PROTECTED TRACK IN S0 + H42 WRITE PROTECTED TRACK IN S0 E64 STATUS IS 000000 SHOULD BE 000011 H51 CYL 0000 HEAD 00 SECTOR 00 WORD COUNT 0128 UNIT 00 @@ -2397,7 +2601,7 @@ TEST REPORT: H0 HP2100A CARTRIDGE DISC MEMORY DIAGNOSTIC sim> go - H70 UNLOCK UNIT 0,PUSH RUN + H70 UNLOCK UNIT 0,PUSH RUN HALT instruction 102002 @@ -2412,7 +2616,7 @@ TEST REPORT: H0 HP2100A CARTRIDGE DISC MEMORY DIAGNOSTIC sim> set DPC0 loaded sim> go - H71 PRESS PRESET THEN PRESS RUN + H71 PRESS PRESET THEN PRESS RUN HALT instruction 102002 @@ -2444,14 +2648,14 @@ CONFIGURATION: sim> attach DQC0 scratch.U0.2883.disc H0 HP 2100 SERIES DISC FILE(2883) DIAGNOSTIC - H72 ENTER SELECT CODES,DMA CHANNEL IN SWITCH REGISTER,PRESS RUN + H72 ENTER SELECT CODES,DMA CHANNEL IN SWITCH REGISTER,PRESS RUN HALT instruction 107001 sim> deposit S 002411 sim> go - H1 ENTER PROGRAM OPTIONS IN SWITCH REGISTER,PRESS RUN + H1 ENTER PROGRAM OPTIONS IN SWITCH REGISTER,PRESS RUN HALT instruction 107077 @@ -2484,21 +2688,21 @@ CONFIGURATION: sim> attach DQC0 scratch.U0.2883.disc H0 HP 2100 SERIES DISC FILE(2883) DIAGNOSTIC - H72 ENTER SELECT CODES,DMA CHANNEL IN SWITCH REGISTER,PRESS RUN + H72 ENTER SELECT CODES,DMA CHANNEL IN SWITCH REGISTER,PRESS RUN HALT instruction 107001 sim> deposit S 002411 sim> go - H1 ENTER PROGRAM OPTIONS IN SWITCH REGISTER,PRESS RUN + H1 ENTER PROGRAM OPTIONS IN SWITCH REGISTER,PRESS RUN HALT instruction 107077 sim> deposit S 000142 sim> go -TEST REPORT: H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN +TEST REPORT: H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN HALT instruction 102002 @@ -2520,7 +2724,7 @@ TEST REPORT: H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN sim> go - H33 WRITE DEFECTIVE TRACK IN S0 + H33 WRITE DEFECTIVE TRACK IN S0 E64 STATUS IS 000000 SHOULD BE 000031 H51 CYL 0000 HEAD 01 SECTOR 00 WORD COUNT 0128 UNIT 00 @@ -2536,13 +2740,13 @@ TEST REPORT: H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN sim> go - H67 CLEAR FORMAT SWITCH ON UNIT 0,PUSH RUN + H67 CLEAR FORMAT SWITCH ON UNIT 0,PUSH RUN HALT instruction 102002 sim> go - H33 WRITE DEFECTIVE TRACK IN S0 + H33 WRITE DEFECTIVE TRACK IN S0 E64 STATUS IS 000000 SHOULD BE 000031 H51 CYL 0000 HEAD 01 SECTOR 00 WORD COUNT 0128 UNIT 00 @@ -2558,7 +2762,7 @@ TEST REPORT: H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN sim> go - H42 WRITE PROTECTED TRACK IN S0 + H42 WRITE PROTECTED TRACK IN S0 E64 STATUS IS 000000 SHOULD BE 000011 H51 CYL 0000 HEAD 00 SECTOR 00 WORD COUNT 0128 UNIT 00 @@ -2574,19 +2778,19 @@ TEST REPORT: H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN sim> go - H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN + H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN HALT instruction 102002 sim> go - H67 CLEAR FORMAT SWITCH ON UNIT 0,PUSH RUN + H67 CLEAR FORMAT SWITCH ON UNIT 0,PUSH RUN HALT instruction 102002 sim> go - H70 DISABLE UNIT 0,PUSH RUN + H70 DISABLE UNIT 0,PUSH RUN HALT instruction 102002 @@ -2601,7 +2805,7 @@ TEST REPORT: H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN sim> set DQC0 loaded sim> go - H71 PRESS PRESET THEN PRESS RUN + H71 PRESS PRESET THEN PRESS RUN HALT instruction 102002 @@ -2663,7 +2867,7 @@ TEST REPORT: H12 DEVICE HAS 90 SECTORS sim> set DRC unprotected sim> go - H10 SET TRACK PROTECT SWITCH TO PROTECTED,PRESS RUN + H10 SET TRACK PROTECT SWITCH TO PROTECTED,PRESS RUN HALT instruction 102002 @@ -2726,7 +2930,7 @@ TEST REPORT: H12 DEVICE HAS 90 SECTORS sim> set DRC unprotected sim> go - H10 SET TRACK PROTECT SWITCH TO PROTECTED,PRESS RUN + H10 SET TRACK PROTECT SWITCH TO PROTECTED,PRESS RUN HALT instruction 102002 @@ -2788,8 +2992,8 @@ TEST REPORT: H12 DEVICE HAS 32 SECTORS sim> set DRC unprotected sim> go - - H10 SET TRACK PROTECT SWITCH TO PROTECTED,PRESS RUN + + H10 SET TRACK PROTECT SWITCH TO PROTECTED,PRESS RUN HALT instruction 102002 @@ -2852,7 +3056,7 @@ TEST REPORT: H12 DEVICE HAS 32 SECTORS sim> set DRC unprotected sim> go - H10 SET TRACK PROTECT SWITCH TO PROTECTED,PRESS RUN + H10 SET TRACK PROTECT SWITCH TO PROTECTED,PRESS RUN HALT instruction 102002 @@ -2876,75 +3080,16 @@ TEST RESULT: Passed. -------------------------------------------------- -DSN 101016 - 2000/Access Comm. Processor Firmware -------------------------------------------------- - -TESTED DEVICE: CPU (hp2100_cpu.c) +------------------------------------------------ +DSN 101217 - 2000/Access Comm Processor for 21MX +------------------------------------------------ -BINARY TAPE: 13206-16001 Rev. 1526 - -CONFIGURATION: sim> set CPU 2100 - sim> set CPU 32K - sim> set CPU IOP - sim> deposit S 000013 - sim> reset - sim> go 100 - - HALT instruction 102074 - - sim> deposit S 000000 - sim> reset - sim> go - -TEST REPORT: 2100 2000-ACCESS COMM. PROC. FIRMWARE DIAGNOSTIC - H030 CRC TEST - H040 ENQ, DEQ AND PENQ TESTS - H060 IAL TEST - H110 READF, SAVE AND RESTR TESTS - H120 LAI AND SAI TESTS - H130 PFREX TEST - H140 PFREI TEST - H150 PFRIO TEST - H160 STORE-LOAD BYTE, TRSLT - AND BYTE MOVE TEST - - TEST 10 - E165 TRSLT NOT INTERRUPTIBLE - - HALT instruction 106065 - - sim> go - - H230 WORD MOVE TEST - - TEST 11 - E234 WORD MOVE NOT INTERRUPTIBLE - - HALT instruction 103034 - - sim> go - - PASS 000001 - - HALT instruction 102077 - -TEST RESULT: Partially passed. - -TEST NOTES: Tests 10 and 11 test the interruptibility of the TRSLT and MWORD - instructions. These features are not simulated. - - - -------------------------------------------------- -DSN 101217 - 2000/Access Comm. Processor Firmware -------------------------------------------------- - -TESTED DEVICE: CPU (hp2100_cpu.c) +TESTED DEVICE: CPU (hp2100_cpu2.c) BINARY TAPE: 13207-16001 Rev. 1728 CONFIGURATION: sim> set CPU IOP + sim> deposit S 000013 sim> reset sim> go 100 diff --git a/HP2100/hp2100_dp.c b/HP2100/hp2100_dp.c index 66384165..17c5c216 100644 --- a/HP2100/hp2100_dp.c +++ b/HP2100/hp2100_dp.c @@ -1,6 +1,6 @@ /* hp2100_dp.c: HP 2100 12557A/13210A disk simulator - Copyright (c) 1993-2005, Robert M. Supnik + Copyright (c) 1993-2006, 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"), @@ -26,6 +26,7 @@ dp 12557A 2871 disk subsystem 13210A 7900 disk subsystem + 28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified) 01-Mar-05 JDB Added SET UNLOAD/LOAD 07-Oct-04 JDB Fixed enable/disable from either device Fixed ANY ERROR status for 12557A interface @@ -395,6 +396,7 @@ switch (inst) { /* case on opcode */ dat = dpd_ibuf; break; + case ioCRS: /* control reset (action unverif) */ case ioCTL: /* control clear/set */ if (IR & I_CTL) { /* CLC */ clrCTL (devd); /* clr ctl, cmd */ @@ -449,6 +451,7 @@ switch (inst) { /* case on opcode */ if (!dp_ctype) break; IR = IR | I_CTL; /* 13210 OTx causes CLC */ + case ioCRS: /* control reset (action unverif) */ case ioCTL: /* control clear/set */ if (IR & I_CTL) { /* CLC? */ clrCTL (devc); /* clr cmd, ctl */ diff --git a/HP2100/hp2100_dq.c b/HP2100/hp2100_dq.c index dce7361a..6e3fcf6c 100644 --- a/HP2100/hp2100_dq.c +++ b/HP2100/hp2100_dq.c @@ -1,6 +1,6 @@ /* hp2100_dq.c: HP 2100 12565A disk simulator - Copyright (c) 1993-2005, Bill McDermith + Copyright (c) 1993-2006, Bill McDermith 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 @@ dq 12565A 2883 disk system + 28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified) 01-Mar-05 JDB Added SET UNLOAD/LOAD 07-Oct-04 JDB Fixed enable/disable from either device Shortened xtime from 5 to 3 (drive avg 156KW/second) @@ -313,6 +314,7 @@ switch (inst) { /* case on opcode */ dat = dqd_ibuf; break; + case ioCRS: /* control reset (action unverif) */ case ioCTL: /* control clear/set */ if (IR & I_CTL) { /* CLC */ clrCTL (devd); /* clr ctl, cmd */ @@ -363,6 +365,7 @@ switch (inst) { /* case on opcode */ case ioMIX: /* merge */ break; /* no data */ + case ioCRS: /* control reset (action unverif) */ case ioCTL: /* control clear/set */ if (IR & I_CTL) { /* CLC? */ clrCMD (devc); /* clr cmd, ctl */ diff --git a/HP2100/hp2100_dr.c b/HP2100/hp2100_dr.c index 8bf8baf5..2796e8cb 100644 --- a/HP2100/hp2100_dr.c +++ b/HP2100/hp2100_dr.c @@ -1,6 +1,6 @@ /* hp2100_dr.c: HP 2100 12606B/12610B fixed head disk/drum simulator - Copyright (c) 1993-2005, Robert M. Supnik + Copyright (c) 1993-2006, 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"), @@ -26,6 +26,7 @@ dr 12606B 2770/2771 fixed head disk 12610B 2773/2774/2775 drum + 28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified) 07-Oct-04 JDB Fixed enable/disable from either device Fixed sector return in status word Provided protected tracks and "Writing Enabled" status bit @@ -52,7 +53,7 @@ flip-flop is not wired into the interrupt chain; accordingly, the simulator uses command rather than control for the data channel. Its flag does not respond to SFS, SFC, or STF. - + The drum control channel does not have any of the traditional flip-flops. The 12606 interface implements two diagnostic tests. An SFS CC instruction @@ -331,6 +332,7 @@ switch (inst) { /* case on opcode */ dat = drd_ibuf; break; + case ioCRS: /* control reset (action unverif) */ case ioCTL: /* control clear/set */ if (IR & I_AB) { /* CLC */ clrCMD (devd); /* clr "ctl" */ @@ -639,6 +641,6 @@ for (i = BOOT_BASE; i < IBL_LNT; i++) { /* copy bootstrap */ M[ad + i] = (wd + (dev - 010)) & DMASK; else M[ad + i] = wd; } -PC = ad + BOOT_START; +PC = ad + BOOT_START; return SCPE_OK; } diff --git a/HP2100/hp2100_ds.c b/HP2100/hp2100_ds.c index 10dfabc3..10fbef9a 100644 --- a/HP2100/hp2100_ds.c +++ b/HP2100/hp2100_ds.c @@ -1,6 +1,6 @@ /* hp2100_ds.c: HP 2100 13037 disk controller simulator - Copyright (c) 2004-2005, Robert M. Supnik + Copyright (c) 2004-2006, 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,9 @@ ds 13037 disk controller + 28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified) + 03-Aug-06 JDB Fixed REQUEST STATUS command to clear status-1 + Removed redundant attached test in "ds_detach" 18-Mar-05 RMS Added attached test to detach routine 01-Mar-05 JDB Added SET UNLOAD/LOAD @@ -540,7 +543,7 @@ MTAB ds_mod[] = { { (UNIT_AUTO+UNIT_DTYPE), (D7905_DTYPE << UNIT_V_DTYPE), NULL, "7905", &ds_set_size }, { (UNIT_AUTO+UNIT_DTYPE), (D7906_DTYPE << UNIT_V_DTYPE), - NULL, "7906", &ds_set_size }, + NULL, "7906", &ds_set_size }, { (UNIT_AUTO+UNIT_DTYPE), (D7920_DTYPE << UNIT_V_DTYPE), NULL, "7920", &ds_set_size }, { (UNIT_AUTO+UNIT_DTYPE), (D7925_DTYPE << UNIT_V_DTYPE), @@ -595,6 +598,7 @@ switch (inst) { /* case on opcode */ dat = ds_fifo_read (); break; + case ioCRS: /* control reset (action unverif) */ case ioCTL: /* control clear/set */ if (IR & I_CTL) { /* CLC */ clrCTL (dev); /* clear control */ @@ -705,7 +709,8 @@ switch (op) { case DSC_RSTA: /* read status */ dsxb[1] = ds_sr1; /* return SR1 */ - if (unum < DS_NUMDR) { /* and SR2 */ + ds_sr1 = 0; /* clear SR1 */ + if (unum < DS_NUMDR) { /* return SR2 */ dsxb[0] = ds_updds2 (&ds_unit[unum]); ds_unit[unum].STA &= ~DS2_FS; /* clear 1st */ } @@ -817,7 +822,7 @@ switch (op) { ds_reset_cmn (&ds_dev); /* reset ctrl */ clrCTL (dev); /* clear CTL, SRQ */ clrSRQ (dev); - ds_cmd_done (1, DS1_OK); /* op done, set flag */ + ds_cmd_done (1, DS1_OK); /* op done, set flag */ break; case DSC_SFM: /* set file mask */ @@ -1031,7 +1036,7 @@ switch (op) { /* case on function */ ds_poll (); return SCPE_OK; -} +} /* Schedule timed wait for CPU response @@ -1171,7 +1176,7 @@ if (uptr->flags & UNIT_UNLOAD) { /* drive down? */ } if (ds_eoc) { /* at end of cylinder? */ ds_next_cyl (uptr); /* auto seek to next */ - return TRUE; /* or error */ + return TRUE; /* or error */ } if (vfy && ((uint32) uptr->CYL != ds_cyl)) { /* on wrong cylinder? */ if (ds_cyl >= drv_tab[dtyp].cyl) /* seeking to bad? */ @@ -1460,8 +1465,7 @@ return SCPE_OK; t_stat ds_detach (UNIT *uptr) { -if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* attached? */ -ds_load_unload (uptr, UNIT_UNLOAD, NULL, NULL); /* unload heads */ +ds_load_unload (uptr, UNIT_UNLOAD, NULL, NULL); /* unload heads if attached */ return detach_unit (uptr); } diff --git a/HP2100/hp2100_fp.c b/HP2100/hp2100_fp.c index 613aca63..1544696e 100644 --- a/HP2100/hp2100_fp.c +++ b/HP2100/hp2100_fp.c @@ -1,6 +1,6 @@ /* hp2100_fp.c: HP 2100 floating point instructions - Copyright (c) 2002-2005, Robert M. Supnik + Copyright (c) 2002-2006, 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. + 01-Dec-06 JDB Reworked FFP helpers for 1000-F support, deleted f_pwr2 22-Jul-05 RMS Fixed compiler warning in Solaris (from Doug Glyn) 25-Feb-05 JDB Added FFP helpers f_pack, f_unpack, f_pwr2 11-Feb-05 JDB Fixed missing negative overflow renorm in StoreFP @@ -30,6 +31,16 @@ 15-Jul-03 RMS Fixed signed/unsigned warning 21-Oct-02 RMS Recoded for compatibility with 21MX microcode algorithms + + Implementation note: The 2100/1000-M/E Fast FORTRAN Processor (FFP) and 1000 + F-Series Floating Point Processor (FPP) simulations require that the host + compiler support 64-bit integers and the HAVE_INT64 symbol be defined during + compilation. If this symbol is defined, two-word floating-point operations + are handled in the FPP code, and this module is not used. If it is not + defined, then FFP and FPP operations are not available, and this module + provides the floating-point support. + + The HP2100 uses a unique binary floating point format: 15 14 0 @@ -39,7 +50,7 @@ | fraction low | exponent |XS| : A + 1 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 15 8 7 1 0 - + where S = 0 for plus fraction, 1 for minus fraction fraction = s.bbbbb..., 24 binary digits exponent = 2**+/-n @@ -69,6 +80,10 @@ */ #include "hp2100_defs.h" +#include "hp2100_cpu1.h" +#include "hp2100_fp.h" + +#if !defined (HAVE_INT64) /* int64 support unavailable */ struct ufp { /* unpacked fp */ int32 exp; /* exp */ @@ -98,8 +113,6 @@ struct ufp { /* unpacked fp */ #define FPAB ((((uint32) AR) << 16) | ((uint32) BR)) -#define DMASK32 0xFFFFFFFF - /* Fraction shift; 0 < shift < 32 */ #define FR_ARS(v,s) (((v) >> (s)) | (((v) & FP_SIGN)? \ @@ -112,6 +125,7 @@ extern uint16 ABREG[2]; uint32 UnpackFP (struct ufp *fop, uint32 opnd); void NegFP (struct ufp *fop); void NormFP (struct ufp *fop); +uint32 PackFP (struct ufp *fop); uint32 StoreFP (struct ufp *fop); /* Floating to integer conversion */ @@ -275,47 +289,6 @@ if (fop1.fr) { /* dvd != 0? */ return StoreFP (&quo); /* store result */ } -/* Fast FORTRAN Processor helpers. */ - -/* Pack mantissa in A/B and exponent and return fp in A/B */ - -uint32 f_pack (int32 expon) -{ -struct ufp fop; - -fop.fr = FPAB; -fop.exp = expon; -return StoreFP (&fop); -} - -/* Unpack fp number in A/B into A (exponent) and B (lower mantissa) */ - -void f_unpack (void) -{ -AR = FP_GETEXP (BR); /* get exponent */ -if (FP_GETEXPS (BR)) AR = (AR | ~FP_M_EXP) & DMASK; /* < 0? sext */ -BR = BR & (uint16) ~(FP_EXP | FP_EXPS); /* clear exp */ -return; -} - -/* Multiply fp number in A/B by 2**n and return in A/B. - Exponent overflow or underflow wraps around. */ - -void f_pwr2 (int32 n) -{ -uint32 save_a; - -if (AR | BR) { /* microcode test */ - save_a = AR; - f_unpack (); /* unpack exponent */ - AR = AR + n; /* multiply */ - BR = BR | ((AR & FP_M_EXP) << FP_V_EXP) | /* merge exponent */ - ((AR & SIGN)? (1 << FP_V_EXPS): 0); /* and exponent sign */ - AR = save_a; - } -return; -} - /* Utility routines */ /* Unpack operand */ @@ -343,6 +316,15 @@ else fop->exp = 0; /* clean 0 */ return; } +/* Pack fp number */ + +uint32 PackFP (struct ufp *fop) +{ +return (fop->fr & FP_FR) | /* merge frac */ + ((fop->exp & FP_M_EXP) << FP_V_EXP) | /* and exp */ + ((fop->exp < 0)? (1 << FP_V_EXPS): 0); /* add exp sign */ +} + /* Round fp number, store, generate overflow */ uint32 StoreFP (struct ufp *fop) @@ -367,10 +349,58 @@ else if (fop->exp > FP_M_EXP) { /* overflow? */ hi = 0x7FFFFFFE; /* all 1's */ ov = 1; } -else hi = (fop->fr & FP_FR) | /* merge frac */ - ((fop->exp & FP_M_EXP) << FP_V_EXP) | /* and exp */ - ((fop->exp < 0)? (1 << FP_V_EXPS): 0); /* add exp sign */ +else hi = PackFP (fop); /* pack mant and exp */ AR = (hi >> 16) & DMASK; BR = hi & DMASK; return ov; } + + +/* Single-precision Fast FORTRAN Processor helpers. */ + +/* Pack mantissa and exponent and return fp value. */ + +uint32 fp_pack (OP *result, OP mantissa, int32 exponent, OPSIZE precision) +{ +struct ufp fop; +uint32 val; + +fop.fr = ((uint32) mantissa.fpk[0] << 16) | mantissa.fpk[1]; +fop.exp = exponent; +val = PackFP (&fop); +result->fpk[0] = (int16) (val >> 16); +result->fpk[1] = (int16) val; +return 0; +} + +/* Normalize, round, and pack mantissa and exponent and return fp value. */ + +uint32 fp_nrpack (OP *result, OP mantissa, int32 exponent, OPSIZE precision) +{ +struct ufp fop; +uint32 ovf; + +fop.fr = ((uint32) mantissa.fpk[0] << 16) | mantissa.fpk[1]; +fop.exp = exponent; +ovf = StoreFP (&fop); +result->fpk[0] = AR; +result->fpk[1] = BR; +return ovf; +} + +/* Unpack fp number in into mantissa and exponent. */ + +uint32 fp_unpack (OP *mantissa, int32 *exponent, OP packed, OPSIZE precision) +{ +struct ufp fop; +uint32 operand; + +operand = ((uint32) packed.fpk[0] << 16) | packed.fpk[1]; +UnpackFP (&fop, operand); +mantissa->fpk[0] = (uint16) fop.fr >> 16; +mantissa->fpk[1] = (uint16) fop.fr; +*exponent = fop.exp; +return 0; +} + +#endif /* int64 support unavailable */ diff --git a/HP2100/hp2100_fp.h b/HP2100/hp2100_fp.h new file mode 100644 index 00000000..4809da49 --- /dev/null +++ b/HP2100/hp2100_fp.h @@ -0,0 +1,47 @@ +/* hp2100_fp.h: HP 2100/21MX floating point definitions + + Copyright (c) 2002-2006, 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"), + 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 Robert M Supnik shall not 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. + + 01-Dec-06 JDB Reworked FFP helpers for 1000-F support, deleted f_pwr2 + 26-Sep-06 JDB Moved from hp2100_fp.c to simplify extensions +*/ + +#ifndef _HP2100_FP_H_ +#define _HP2100_FP_H_ + +/* Firmware floating-point routines */ + +uint32 f_as (uint32 op, t_bool sub); /* FAD/FSB */ +uint32 f_mul (uint32 op); /* FMP */ +uint32 f_div (uint32 op); /* FDV */ +uint32 f_fix (void); /* FIX */ +uint32 f_flt (void); /* FLT */ + +/* Firmware FFP helpers */ + +uint32 fp_pack (OP *result, OP mantissa, int32 exponent, OPSIZE precision); +uint32 fp_nrpack (OP *result, OP mantissa, int32 exponent, OPSIZE precision); +uint32 fp_unpack (OP *mantissa, int32 *exponent, OP packed, OPSIZE precision); + +#endif diff --git a/HP2100/hp2100_fp1.c b/HP2100/hp2100_fp1.c index 025c5818..9215363a 100644 --- a/HP2100/hp2100_fp1.c +++ b/HP2100/hp2100_fp1.c @@ -1,6 +1,6 @@ -/* hp2100_fp1.c: HP 2100/21MX extended-precision floating point routines +/* hp2100_fp1.c: HP 1000 multiple-precision floating point routines - Copyright (c) 2005, J. David Bryan + Copyright (c) 2005-2006, J. David Bryan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -15,29 +15,75 @@ 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 + THE AUTHOR 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 the author shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the author. + Except as contained in this notice, the name of the author shall not be used + in advertising or otherwise to promote the sale, use or other dealings in + this Software without prior written authorization from the author. + + 01-Dec-06 JDB Reworked into generalized multiple-precision ops for FPP + 12-Oct-06 JDB Altered x_trun for F-Series FFP compatibility + Added F-Series ..TCM FFP helpers Primary references: + - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation + (92851-90001, Mar-1981) - HP 1000 M/E/F-Series Computers Technical Reference Handbook (5955-0282, Mar-1980) - DOS/RTE Relocatable Library Reference Manual (24998-90001, Oct-1981) - The extended-precision floating-point format is a 48-bit extension of the - 32-bit format used for single precision. A packed "XP" number consists of a - 40-bit twos-complement mantissa and an 8-bit twos-complement exponent. The - exponent is rotated left so that the sign is in the LSB. Pictorially, an XP - number appears in memory as follows: + + This module implements multiple-precision floating-point operations to + support the 1000 F-Series hardware Floating Point Processor. It employs + 64-bit integer arithmetic for speed and simplicity of implementation. The + host compiler must support 64-bit integers, and the HAVE_INT64 symbol must be + defined during compilation. If this symbol is not defined, then FPP support + is not available. + + HP 2100/1000 computers used a proprietary floating-point format. The 2100 + had optional firmware that provided two-word floating-point add, subtract, + multiply, and divide, as well as single-integer fix and float. The 1000-M/E + provided the same two-word firmware operations as standard equipment. + Three-word extended-precision instructions for the 2100 and 1000-M/E were + provided by the optional Fast FORTRAN Processor firmware. + + The 1000-F substituted a hardware floating point processor for the firmware + in previous machines. In addition to the two- and three-word formats, the + F-Series introduced a four-word double-precision format. A five-word format + that provided extra range in the exponent by unpacking it from the mantissa + was also provided, although this capability was not documented in the user + manual. In addition, the FPP improved the accuracy of floating-point + calculations, as the firmware versions sacrificed a few bits of precision to + gain speed. Consequently, operations on the F-Series may return results that + differ slightly from the same operations on the M/E-Series or the 2100. + + F-Series units after date code 1920 also provided two-word double-integer + instructions in firmware, as well as double-integer fix and float operations. + + The original 32-bit floating-point format is as follows: 15 14 0 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - |S | mantissa high | : M + |MS| mantissa high | : M + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | mantissa low | exponent |XS| : M + 1 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + 15 8 7 1 0 + + Both 23-bit mantissa and 7-bit exponent are in twos-complement form. The + exponent sign bit has been rotated into the LSB of the second word. + + The extended-precision floating-point format is a 48-bit extension of the + 32-bit format used for single precision. A packed extended-precision value + consists of a 39-bit mantissa and a 7-bit exponent. The format is as + follows: + + 15 14 0 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + |MS| mantissa high | : M +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | mantissa middle | : M + 1 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ @@ -45,481 +91,1337 @@ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 15 8 7 1 0 - In a normalized value, the sign and MSB of the mantissa differ. Zero is - represented by all three words = 0. + The double-precision floating-point format is similar to the 48-bit + extended-precision format, although with a 55-bit mantissa: - Internally, an unpacked XP number is contained in a structure having a signed - 64-bit mantissa and a signed 32-bit exponent. The mantissa is masked to 48 - bits and left-justified, while the exponent is right-justified. + 15 14 0 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + |MS| mantissa high | : M + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | mantissa middle high | : M + 1 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | mantissa middle low | : M + 2 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | mantissa low | exponent |XS| : M + 3 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + 15 8 7 1 0 + + The FPP also supports a special five-word expanded-exponent format: + + 15 14 0 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + |MS| mantissa high | : M + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | mantissa middle high | : M + 1 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | mantissa middle low | : M + 2 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | mantissa low | : M + 3 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | exponent |XS| : M + 4 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + 15 8 7 1 0 + + The exponent is a full 16-bit twos-complement value, but the allowed range is + only 10 bits, i.e., -512 to +511. + + In a normalized value, the sign and MSB of the mantissa differ. Zero is + represented by all words = 0. + + Internally, unpacked floating-point values are contained in a structure + having a signed 64-bit mantissa and a signed 32-bit exponent. Mantissas are + left-justified with the unused bits masked to zero. Exponents are + right-justified. The precision is indicated by the value of a structure + field. + + HP terminology for the three-word floating-point format is confused. Some + documents refer to it as "double precision," while others use "extended + precision." The instruction mnemonics begin with "X" (e.g., .XADD), + suggesting the extended-precision term. + + HP apparently intended that the four-word double-precision format would be + called "triple-precision," as the instruction mnemonics begin with "T" (e.g., + ".TADD" for the four-word add instruction). The source files for the + software simulations of these instructions for the M/E-Series also explicitly + refer to "triple precision math." However, the engineering documentation and + the F-Series reference manual both use the double-precision term. + + This module adopts the single/extended/double terminology and uses the + initial letters of the instructions (F/X/T) to indicate the precision used. + + The FPP hardware consisted of two circuit boards that interfaced to the main + CPU via the Microprogammable Processor Port (MPP) that had been introduced + with the 1000 E-Series. One board contained argument registers and ALUs, + split into separate mantissa and exponent parts. The other contained a state + machine sequencer. FPP results were copied automatically to the argument + registers in addition to being available over the MPP, so that chained + operations could be executed from these "accumulators" without reloading. + + The FPP operated independently of the CPU. An opcode, specifying one of the + six operations (add, subtract, multiply, divide, fix, or float) was sent to + the FPP, and a start command was given. Operands of appropriate precision + were then supplied to the FPP. Once the operands were received, the FPP + would execute and set a flag when the operation was complete. The result + would then be retrieved from the FPP. The floating-point instruction + firmware in the CPU initiated the desired FPP operation and handled operand + reads from and result writes to main memory. + + Under simulation, "fp_exec" provides the six arithmetic operations analogous + to FPP execution. The remainder of the functions are helpers that were + provided by firmware in the 1000-F but that can reuse code needed to simulate + the FPP hardware. As with the hardware, "fp_exec" retains the last result + in an internal accumulator that may be referenced in subsequent operations. + + NOTE: this module also provides the floating-point support for the firmware + single-precision 1000-M/E base set and extended-precision FFP instructions. + Because the firmware and hardware implementations returned slightly different + results, particularly with respect to round-off, conditional checks are + implemented in the arithmetic routines. In some cases, entirely different + algorithms are used to ensure fidelity with the real machines. Functionally, + this means that the 2100/1000-M/E and 1000-F floating-point diagnostics are + not interchangeable, and failures are to be expected if a diagnostic is run + on the wrong machine. */ #include "hp2100_defs.h" #include "hp2100_cpu.h" +#include "hp2100_cpu1.h" #include "hp2100_fp1.h" + #if defined (HAVE_INT64) /* we need int64 support */ -/* packed starting bit numbers */ +/* Field widths. */ -#define XP_PAD 16 /* padding LSBs */ +#define IN_W_SIGN 1 +#define IN_W_SMAGN 15 +#define IN_W_DMAGN 31 -#define XP_V_MSIGN (47 + XP_PAD) /* mantissa sign */ -#define XP_V_MANT ( 8 + XP_PAD) /* mantissa */ -#define XP_V_EXP ( 1 + XP_PAD) /* exponent */ -#define XP_V_ESIGN ( 0 + XP_PAD) /* exponent sign */ +#define FP_W_MSIGN 1 +#define FP_W_FMANT 23 +#define FP_W_XMANT 39 +#define FP_W_TMANT 55 +#define FP_W_EMANT 55 +#define FP_W_EXPANDEXP 9 +#define FP_W_EXP 7 +#define FP_W_ESIGN 1 -/* packed bit widths */ +/* Starting bit numbers. */ -#define XP_W_MSIGN 1 /* mantissa sign */ -#define XP_W_MANT 39 /* mantissa */ -#define XP_W_EXP 7 /* exponent */ -#define XP_W_ESIGN 1 /* exponent sign */ +#define IN_V_SIGN (64 - IN_W_SIGN) +#define IN_V_SNUM (64 - IN_W_SIGN - IN_W_SMAGN) +#define IN_V_DNUM (64 - IN_W_SIGN - IN_W_DMAGN) -/* packed bit masks */ +#define FP_V_FNUM (64 - FP_W_MSIGN - FP_W_FMANT - FP_W_EXP - FP_W_ESIGN) +#define FP_V_XNUM (64 - FP_W_MSIGN - FP_W_XMANT - FP_W_EXP - FP_W_ESIGN) +#define FP_V_TNUM (64 - FP_W_MSIGN - FP_W_TMANT - FP_W_EXP - FP_W_ESIGN) +#define FP_V_ENUM (64 - FP_W_MSIGN - FP_W_EMANT - FP_W_EXP - FP_W_ESIGN) -#define XP_M_MSIGN (((t_uint64) 1 << XP_W_MSIGN) - 1) /* mantissa sign */ -#define XP_M_MANT (((t_uint64) 1 << XP_W_MANT) - 1) /* mantissa */ -#define XP_M_EXP (((t_uint64) 1 << XP_W_EXP) - 1) /* exponent */ -#define XP_M_ESIGN (((t_uint64) 1 << XP_W_ESIGN) - 1) /* exponent sign */ +#define FP_V_MSIGN (64 - FP_W_MSIGN) +#define FP_V_FMANT (64 - FP_W_MSIGN - FP_W_FMANT) +#define FP_V_XMANT (64 - FP_W_MSIGN - FP_W_XMANT) +#define FP_V_TMANT (64 - FP_W_MSIGN - FP_W_TMANT) +#define FP_V_EMANT (64 - FP_W_MSIGN - FP_W_EMANT) +#define FP_V_EXP 1 +#define FP_V_ESIGN 0 -/* packed field masks */ +/* Right-aligned field masks. */ -#define XP_MSIGN (XP_M_MSIGN << XP_V_MSIGN) /* mantissa sign */ -#define XP_MANT (XP_M_MANT << XP_V_MANT) /* mantissa */ -#define XP_SMANT (XP_MSIGN | XP_MANT) /* signed mantissa */ +#define IN_M_SIGN (((t_uint64) 1 << IN_W_SIGN) - 1) +#define IN_M_SMAGN (((t_uint64) 1 << IN_W_SMAGN) - 1) +#define IN_M_DMAGN (((t_uint64) 1 << IN_W_DMAGN) - 1) -/* unpacked starting bit numbers */ +#define FP_M_MSIGN (((t_uint64) 1 << FP_W_MSIGN) - 1) +#define FP_M_FMANT (((t_uint64) 1 << FP_W_FMANT) - 1) +#define FP_M_XMANT (((t_uint64) 1 << FP_W_XMANT) - 1) +#define FP_M_TMANT (((t_uint64) 1 << FP_W_TMANT) - 1) +#define FP_M_EMANT (((t_uint64) 1 << FP_W_EMANT) - 1) -#define XP_V_UMANT (0 + XP_PAD) /* signed mantissa */ +#define FP_M_EXPANDEXP ((1 << FP_W_EXPANDEXP) - 1) +#define FP_M_EXP ((1 << FP_W_EXP) - 1) +#define FP_M_ESIGN ((1 << FP_W_ESIGN) - 1) -/* unpacked bit widths */ +/* In-place field masks. */ -#define XP_W_USMANT 48 /* signed mantissa */ +#define IN_SIGN (IN_M_SIGN << IN_V_SIGN) +#define IN_SMAGN (IN_M_SMAGN << IN_V_SNUM) +#define IN_DMAGN (IN_M_DMAGN << IN_V_DNUM) -/* unpacked bit masks */ +#define FP_MSIGN (FP_M_MSIGN << FP_V_MSIGN) +#define FP_FMANT (FP_M_FMANT << FP_V_FMANT) +#define FP_XMANT (FP_M_XMANT << FP_V_XMANT) +#define FP_TMANT (FP_M_TMANT << FP_V_TMANT) +#define FP_EMANT (FP_M_EMANT << FP_V_EMANT) +#define FP_EXP (FP_M_EXP << FP_V_EXP) +#define FP_ESIGN (FP_M_ESIGN << FP_V_ESIGN) -#define XP_M_USMANT (((t_uint64) 1 << XP_W_USMANT) - 1) /* mantissa */ +/* In-place record masks. */ -/* unpacked field masks */ +#define IN_SSMAGN (IN_SIGN | IN_SMAGN) +#define IN_SDMAGN (IN_SIGN | IN_DMAGN) -#define XP_USMANT (XP_M_USMANT << XP_V_UMANT) /* signed mantissa */ +#define FP_SFMANT (FP_MSIGN | FP_FMANT) +#define FP_SXMANT (FP_MSIGN | FP_XMANT) +#define FP_STMANT (FP_MSIGN | FP_TMANT) +#define FP_SEMANT (FP_MSIGN | FP_EMANT) +#define FP_SEXP (FP_ESIGN | FP_EXP) -/* values */ +/* Minima and maxima. */ -#define XP_ONEHALF ((t_int64) 1 << (XP_V_MSIGN - 1)) /* mantissa = 0.5 */ -#define XP_HALSBPOS ((t_int64) 1 << (XP_V_MANT - 1)) /* + 1/2 LSB */ -#define XP_HALSBNEG ((t_int64) XP_HALSBPOS - 1) /* - 1/2 LSB */ -#define XP_MAXPOS ((t_int64) XP_MANT) /* maximum pos mantissa */ -#define XP_MAXNEG ((t_int64) XP_MSIGN) /* maximum neg mantissa */ -#define XP_MAXEXP ((t_int64) XP_M_EXP) /* maximum pos exponent */ +#define FP_ONEHALF ((t_int64) 1 << (FP_V_MSIGN - 1)) /* mantissa = 0.5 */ +#define FP_MAXPMANT ((t_int64) FP_EMANT) /* maximum pos mantissa */ +#define FP_MAXNMANT ((t_int64) FP_MSIGN) /* maximum neg mantissa */ +#define FP_MAXPEXP (FP_M_EXPANDEXP) /* maximum pos expanded exponent */ +#define FP_MAXNEXP (-(FP_MAXPEXP + 1)) /* maximum neg expanded exponent */ -/* helpers */ +/* Floating-point helpers. */ -#define DENORM(x) ((((x) ^ (x) << 1) & XP_MSIGN) == 0) +#define DENORM(x) ((((x) ^ (x) << 1) & FP_MSIGN) == 0) -#define TO_INT64(xpn) ((t_int64) ((t_uint64) (xpn).high << 32 | (xpn).low)) +#define TO_EXP(e) (int8) ((e >> FP_V_EXP & FP_M_EXP) | \ + (e & FP_M_ESIGN ? ~FP_M_EXP : 0)) -/* internal unpacked extended-precision representation */ +/* Property constants. */ + +static const t_int64 p_half_lsb[6] = { ((t_int64) 1 << IN_V_SNUM) - 1, /* different than FP! */ + ((t_int64) 1 << IN_V_DNUM) - 1, /* different than FP! */ + (t_int64) 1 << (FP_V_FMANT - 1), + (t_int64) 1 << (FP_V_XMANT - 1), + (t_int64) 1 << (FP_V_TMANT - 1), + (t_int64) 1 << (FP_V_EMANT - 1) }; + +static const t_int64 n_half_lsb[6] = { 0, + 0, + ((t_int64) 1 << (FP_V_FMANT - 1)) - 1, + ((t_int64) 1 << (FP_V_XMANT - 1)) - 1, + ((t_int64) 1 << (FP_V_TMANT - 1)) - 1, + ((t_int64) 1 << (FP_V_EMANT - 1)) - 1 }; + +static const uint32 op_start[6] = { IN_V_SNUM, + IN_V_DNUM, + FP_V_FMANT, + FP_V_XMANT, + FP_V_TMANT, + FP_V_EMANT }; + +static const t_int64 mant_mask[6] = { IN_SSMAGN, + IN_SDMAGN, + FP_SFMANT, + FP_SXMANT, + FP_STMANT, + FP_SEMANT }; + +static const uint32 op_bits[6] = { IN_W_SMAGN, + IN_W_DMAGN, + FP_W_FMANT + FP_W_MSIGN, + FP_W_XMANT + FP_W_MSIGN, + FP_W_TMANT + FP_W_MSIGN, + FP_W_EMANT + FP_W_MSIGN }; + +static const t_int64 op_mask[6] = { ~(t_int64) 0 << IN_V_SNUM, + ~(t_int64) 0 << IN_V_DNUM, + ~(t_int64) 0 << FP_V_FNUM, + ~(t_int64) 0 << FP_V_XNUM, + ~(t_int64) 0 << FP_V_TNUM, + ~(t_int64) 0 << FP_V_ENUM }; + +static const uint32 int_p_max[2] = { IN_M_SMAGN, + IN_M_DMAGN }; + + +/* Internal unpacked floating-point representation. */ typedef struct { - t_int64 mantissa; - int32 exponent; - } XPU; - -/* Private routines */ + t_int64 mantissa; + int32 exponent; + OPSIZE precision; + } FPU; -/* Pack an unpacked mantissa and exponent */ -static XPN to_xpn (t_uint64 m, int32 e) +/* Low-level helper routines. */ + + +/* Arithmetic shift right for mantissa only. + + Returns TRUE if any one-bits are shifted out (for F-series only). +*/ + +static t_bool asr (FPU *operand, int32 shift) { -XPN packed; +t_uint64 mask; +t_bool bits_lost; -packed.high = (uint32) (m >> 32); -packed.low = (uint32) (m | ((e & XP_M_EXP) << XP_V_EXP) | ((e < 0) << XP_V_ESIGN)); -return packed; +if (UNIT_CPU_MODEL == UNIT_1000_F) { /* F-series? */ + mask = ((t_uint64) 1 << shift) - 1; /* mask for lost bits */ + bits_lost = ((operand->mantissa & mask) != 0); /* flag if any lost */ + } +else + bits_lost = FALSE; + +operand->mantissa = operand->mantissa >> shift; /* mantissa is int, so ASR */ +return bits_lost; } -/* Unpack a packed number */ +/* Logical shift right for mantissa and exponent. -static XPU unpack (XPN packed) + Shifts mantissa and corrects exponent for mantissa overflow. + Returns TRUE if any one-bits are shifted out (for F-series only). +*/ + +static t_bool lsrx (FPU *operand, int32 shift) { -XPU unpacked; +t_uint64 mask; +t_bool bits_lost; -unpacked.mantissa = TO_INT64 (packed) & XP_SMANT; /* left-justify mantissa */ -unpacked.exponent = (int8) ((packed.low >> XP_V_EXP & XP_M_EXP) | /* sign-extend exponent */ - packed.low >> (XP_V_ESIGN - XP_W_EXP)); +if (UNIT_CPU_MODEL == UNIT_1000_F) { /* F-series? */ + mask = ((t_uint64) 1 << shift) - 1; /* mask for lost bits */ + bits_lost = ((operand->mantissa & mask) != 0); /* flag if any lost */ + } +else + bits_lost = FALSE; + +operand->mantissa = (t_uint64) operand->mantissa >> shift; /* uint, so LSR */ +operand->exponent = operand->exponent + shift; /* correct exponent */ +return bits_lost; +} + + +/* Unpack an operand into a long integer. + + Returns a left-aligned integer or mantissa. Does not mask to precision; this + should be done subsequently if desired. +*/ + +static t_int64 unpack_int (OP packed, OPSIZE precision) +{ +int32 i; +t_uint64 unpacked = 0; + +if (precision == in_s) + unpacked = (t_uint64) packed.word << 48; /* unpack single integer */ + +else if (precision == in_d) + unpacked = (t_uint64) packed.dword << 32; /* unpack double integer */ + +else { + if (precision == fp_e) /* five word operand? */ + precision = fp_t; /* only four mantissa words */ + + for (i = 0; i < 4; i++) /* unpack fp 2 to 4 words */ + if (i < TO_COUNT (precision)) + unpacked = unpacked << 16 | packed.fpk[i]; + else + unpacked = unpacked << 16; + } + +return (t_int64) unpacked; +} + + +/* Unpack a packed operand. + + The packed value is split into separate mantissa and exponent variables. The + multiple words of the mantissa are concatenated into a single 64-bit signed + value, and the exponent is shifted with recovery of the sign. +*/ + +static FPU unpack (OP packed, OPSIZE precision) +{ +FPU unpacked; + +unpacked.precision = precision; /* set value's precision */ + +unpacked.mantissa = /* unpack and mask mantissa */ + unpack_int (packed, precision) & mant_mask[precision]; + +switch (precision) { + + case in_s: + case in_d: + unpacked.exponent = 0; /* integers don't use exponent */ + break; + + case fp_f: + case fp_x: + case fp_t: + unpacked.exponent = /* unpack exponent from correct word */ + TO_EXP (packed.fpk[(uint32) precision - 1]); + break; + + case fp_e: + unpacked.exponent = /* unpack expanded exponent */ + (int16) (packed.fpk[4] >> FP_V_EXP | /* rotate sign into place */ + (packed.fpk[4] & 1 ? SIGN : 0)); + break; + + case fp_a: /* no action for value in accum */ + break; + } return unpacked; } -/* Normalize an unpacked number */ +/* Pack a long integer into an operand. */ -static void normalize (XPU *unpacked) +static OP pack_int (t_int64 unpacked, OPSIZE precision) { -if (unpacked->mantissa) { /* non-zero? */ - while (DENORM (unpacked->mantissa)) { /* normal form? */ - unpacked->exponent = unpacked->exponent - 1; /* no, so shift */ - unpacked->mantissa = unpacked->mantissa << 1; - } - } -else unpacked->exponent = 0; /* clean for zero */ -return; -} +int32 i; +OP packed; +if (precision == in_s) + packed.word = (uint16) (unpacked >> 48) & DMASK; /* pack single integer */ -/* Round and pack an unpacked number */ +else if (precision == in_d) + packed.dword = (uint32) (unpacked >> 32) & DMASK32; /* pack double integer */ -static uint32 pack (XPN *packed, XPU unpacked) -{ -int32 sign, overflow = 0; - -normalize (&unpacked); /* normalize */ -sign = (unpacked.mantissa < 0); /* save sign */ -unpacked.mantissa = (unpacked.mantissa + /* round the number */ - (sign? XP_HALSBNEG: XP_HALSBPOS)) & XP_SMANT; /* mask off rounding bits */ -if (sign != (unpacked.mantissa < 0)) { /* pos overflow? */ - unpacked.mantissa = /* renormalize */ - (t_uint64) unpacked.mantissa >> 1 & XP_SMANT; /* and remask */ - unpacked.exponent = unpacked.exponent + 1; - } -else normalize (&unpacked); /* neg overflow? renorm */ -unpacked.mantissa = unpacked.mantissa & XP_SMANT; -if (unpacked.mantissa == 0) /* result 0? */ - packed->high = packed->low = 0; /* return 0 */ -else if (unpacked.exponent < -(XP_MAXEXP + 1)) { /* underflow? */ - packed->high = packed->low = 0; /* return 0 */ - overflow = 1; /* and set overflow */ - } -else if (unpacked.exponent > XP_MAXEXP) { /* overflow? */ - if (sign) *packed = to_xpn (XP_MAXNEG, XP_MAXEXP); /* return neg infinity */ - else *packed = to_xpn (XP_MAXPOS, XP_MAXEXP); /* or pos infinity */ - overflow = 1; /* with overflow */ - } -else *packed = to_xpn (unpacked.mantissa, unpacked.exponent); -return overflow; -} - - -/* Complement an unpacked number */ - -static void complement (XPU *result) -{ -result->mantissa = -result->mantissa; /* negate mantissa */ -if (result->mantissa == XP_MAXNEG) { /* maximum negative? */ - result->mantissa = (t_uint64) result->mantissa >> 1; /* renormalize to pos */ - result->exponent = result->exponent + 1; /* correct exponent */ - } -return; -} - - -/* Add two unpacked numbers - - The mantissas are first aligned (if necessary) by scaling the smaller of the - two operands. If the magnitude of the difference between the exponents is - greater than the number of significant bits, then the smaller number has been - scaled to zero, and so the sum is simply the larger operand. Otherwise, the - sum is computed and checked for overflow, which has occured if the signs of - the operands are the same but differ from that of the result. Scaling and - renormalization is perfomed if overflow occurred. */ - -static void add (XPU *sum, XPU augend, XPU addend) -{ -int32 magn; - -if (augend.mantissa == 0) *sum = addend; /* x + 0 = x */ -else if (addend.mantissa == 0) *sum = augend; /* 0 + x = x */ else { - magn = augend.exponent - addend.exponent; /* difference exponents */ - if (magn > 0) { /* addend smaller? */ - *sum = augend; /* preset augend */ - addend.mantissa = addend.mantissa >> magn; /* align addend */ - } - else { /* augend smaller? */ - *sum = addend; /* preset addend */ - magn = -magn; /* make difference positive */ - augend.mantissa = augend.mantissa >> magn; /* align augend */ - } - if (magn <= XP_W_MANT + 1) { /* check mangitude */ - sum->mantissa = addend.mantissa + augend.mantissa; /* add mantissas */ - if (((addend.mantissa < 0) == (augend.mantissa < 0)) && /* chk overflow */ - ((addend.mantissa < 0) != (sum->mantissa < 0))) { - sum->mantissa = (addend.mantissa & XP_MSIGN) | /* restore sign */ - (t_uint64) sum->mantissa >> 1; /* renormalize */ - sum->exponent = sum->exponent + 1; /* adjust exponent */ - } + if (precision == fp_e) /* five word operand? */ + precision = fp_t; /* only four mantissa words */ + + for (i = 3; i >= 0; i--) { /* pack fp 2 to 4 words */ + packed.fpk[i] = (uint16) unpacked & DMASK; + unpacked = unpacked >> 16; } } -return; -} - -/* Multiply two unpacked numbers - - The firmware first negates the operands as necessary so that the values are - positive. Then it performs six of the nine 16-bit x 16-bit = 32-bit unsigned - multiplications required for a full 96-bit product. Given a 48-bit - multiplicand "a1a2a3" and a 48-bit multiplier "b1b2b3", the firmware performs - these calculations to develop a 48-bit product: - - a1 a2 a3 - +-------+-------+-------+ - b1 b2 b3 - +-------+-------+-------+ - _________________________ - - a1 * b3 [m1] - +-------+-------+ - a2 * b2 [m2] - +-------+-------+ - a1 * b2 [m3] - +-------+-------+ - a3 * b1 [m4] - +-------+-------+ - a2 * b1 [m5] - +-------+-------+ - a1 * b1 [m6] - +-------+-------+ - _________________________________ - - product - +-------+-------+-------+ - - The least-significant words of intermediate multiplications [m1], [m2], and - [m4] are used only to develop a carry bit into the 48-bit sum. The product - is complemented if necessary to restore the sign. - - Instead of implementing this algorithm directly, it is more efficient under - simulation to use 32 x 32 = 64-bit multiplications, thereby reducing the - number required from six to four. */ - -static void multiply (XPU *product, XPU multiplicand, XPU multiplier) -{ -uint32 ah, al, bh, bl, carry, sign = 0; -t_uint64 hi, m1, m2, m3; - -if ((multiplicand.mantissa == 0) || (multiplier.mantissa == 0)) /* x * 0 = 0 */ - product->mantissa = product->exponent = 0; -else { - if (multiplicand.mantissa < 0) { /* negative? */ - complement (&multiplicand); /* complement operand */ - sign = ~sign; /* track sign */ - } - if (multiplier.mantissa < 0) { /* negative? */ - complement (&multiplier); /* complement operand */ - sign = ~sign; /* track sign */ - } - product->exponent = multiplicand.exponent + /* compute exponent */ - multiplier.exponent + 1; - - ah = (uint32) (multiplicand.mantissa >> 32); /* split multiplicand */ - al = (uint32) multiplicand.mantissa; /* into high and low parts */ - bh = (uint32) (multiplier.mantissa >> 32); /* split multiplier */ - bl = (uint32) multiplier.mantissa; /* into high and low parts */ - - hi = ((t_uint64) ah * bh); /* form four cross products */ - m1 = ((t_uint64) ah * bl); /* using 32 x 32 = 64-bit */ - m2 = ((t_uint64) al * bh); /* hardware multiplies */ - m3 = ((t_uint64) al * bl); - - carry = ((uint32) m1 + (uint32) m2 + /* form a carry bit */ - (uint32) (m3 >> 32)) >> (31 - XP_V_UMANT); /* and align to LSB - 1 */ - - product->mantissa = (hi + (m1 >> 32) + /* align, sum, and mask */ - (m2 >> 32) + carry) & XP_USMANT; - if (sign) complement (product); /* negate if required */ - } -return; -} - - -/* Divide two unpacked numbers - - The firmware performs division by calculating (1.0 / divisor) and then - multiplying by the dividend. The simulator uses 64-bit division and uses a - "divide-and-correct" algorithm similar to the one employed by the base set - single-precision floating-point division routine. */ - -static void divide (XPU *quotient, XPU dividend, XPU divisor) -{ -t_int64 bh, bl, m1, m2, m3, m4; - -if (divisor.mantissa == 0) { /* division by zero? */ - if (dividend.mantissa < 0) - quotient->mantissa = XP_MSIGN; /* return minus infinity */ - else quotient->mantissa = XP_MANT; /* or plus infinity */ - quotient->exponent = XP_MAXEXP + 1; - } -else if (dividend.mantissa == 0) /* dividend zero? */ - quotient->mantissa = quotient->exponent = 0; /* yes; result is zero */ -else { - quotient->exponent = dividend.exponent - /* division subtracts exponents */ - divisor.exponent + 1; - - bh = divisor.mantissa >> 32; /* split divisor */ - bl = divisor.mantissa & 0xFFFFFFFF; - - m1 = (dividend.mantissa >> 2) / bh; /* form 1st partial quotient */ - m2 = (dividend.mantissa >> 2) % bh; /* obtain remainder */ - m3 = bl * m1; /* calculate correction */ - m4 = ((m2 - (m3 >> 32)) << 32) / bh; /* form 2nd partial quotient */ - - quotient->mantissa = (m1 << 32) + m4; /* merge quotients */ - } -return; -} - -#endif - -/* Global routines */ - -/* Extended-precision memory read */ - -XPN ReadX (uint32 va) -{ -XPN packed; - -packed.high = ReadW (va) << 16 | ReadW ((va + 1) & VAMASK); -packed.low = ReadW ((va + 2) & VAMASK) << 16; /* read and pack */ return packed; } -/* Extended-precision memory write */ +/* Pack an unpacked floating-point number. -void WriteX (uint32 va, XPN packed) -{ -WriteW (va, (packed.high >> 16) & DMASK); /* write high word */ -WriteW ((va + 1) & VAMASK, packed.high & DMASK); /* write middle word */ -WriteW ((va + 2) & VAMASK, (packed.low >> 16) & DMASK); /* write low word */ -} - - -#if defined (HAVE_INT64) - -/* Extended-precision add */ - -uint32 x_add (XPN *sum, XPN augend, XPN addend) -{ -XPU usum, uaddend, uaugend; - -uaugend = unpack (augend); /* unpack augend */ -uaddend = unpack (addend); /* unpack addend */ -add (&usum, uaugend, uaddend); /* calculate sum */ -return pack (sum, usum); /* pack sum */ -} - - -/* Extended-precision subtract */ - -uint32 x_sub (XPN *difference, XPN minuend, XPN subtrahend) -{ -XPU udifference, uminuend, usubtrahend; - -uminuend = unpack (minuend); /* unpack minuend */ -usubtrahend = unpack (subtrahend); /* unpack subtrahend */ -complement (&usubtrahend); /* calculate difference */ -add (&udifference, uminuend, usubtrahend); /* pack difference */ -return pack (difference, udifference); -} - - -/* Extended-precision multiply */ - -uint32 x_mpy (XPN *product, XPN multiplicand, XPN multiplier) -{ -XPU uproduct, umultiplicand, umultiplier; - -umultiplicand = unpack (multiplicand); /* unpack multiplicand */ -umultiplier = unpack (multiplier); /* unpack multiplier */ -multiply (&uproduct, umultiplicand, umultiplier); /* calculate product */ -return pack (product, uproduct); /* pack product */ -} - - -/* Extended-precision divide */ - -uint32 x_div (XPN *quotient, XPN dividend, XPN divisor) -{ -XPU uquotient, udividend, udivisor; - -udividend = unpack (dividend); /* unpack dividend */ -udivisor = unpack (divisor); /* unpack divisor */ -divide (&uquotient, udividend, udivisor); /* calculate quotient */ -return pack (quotient, uquotient); /* pack quotient */ -} - - -/* Pack an extended-precision number - - An unpacked mantissa is passed as a "packed" number with an unused exponent. + The 64-bit mantissa is split into the appropriate number of 16-bit words. + The exponent is rotated to incorporate the sign bit and merged into the + appropriate word. */ -uint32 x_pak (XPN *result, XPN mantissa, int32 exponent) -{ -XPU unpacked; -unpacked.mantissa = TO_INT64 (mantissa); /* retrieve mantissa */ -unpacked.exponent = exponent; /* and exponent */ -return pack (result, unpacked); /* pack them */ +static OP pack (FPU unpacked) +{ +OP packed; +uint8 exp; + +packed = pack_int (unpacked.mantissa, unpacked.precision); /* pack mantissa */ + +exp = ((uint8) unpacked.exponent << FP_V_EXP) | /* rotate exponent */ + ((unpacked.exponent < 0) << FP_V_ESIGN); + +switch (unpacked.precision) { /* merge exponent into correct word */ + + case in_s: /* no action for integers */ + case in_d: + break; + + case fp_f: /* merge into last word */ + case fp_x: + case fp_t: + packed.fpk[(uint32) unpacked.precision - 1] = + (packed.fpk[(uint32) unpacked.precision - 1] & ~FP_SEXP) | exp; + break; + + case fp_e: /* place in separate word */ + packed.fpk[4] = ((uint16) unpacked.exponent << FP_V_EXP) | + ((unpacked.exponent < 0) << FP_V_ESIGN); + break; + + case fp_a: /* no action for value in accum */ + break; + } + +return packed; } -/* Complement an extended-precision mantissa +/* Normalize an unpacked floating-point number. - An unpacked mantissa is passed as a "packed" number with an unused exponent. - We return the exponent increment, i.e., either zero or one, depending on - whether a renormalization was required. */ + Floating-point numbers are in normal form if the sign bit and the MSB of the + mantissa differ. Unnormalized numbers are shifted as needed with appropriate + exponent modification. +*/ -uint32 x_com (XPN *mantissa) +static void normalize (FPU *unpacked) { -XPU unpacked; -unpacked.mantissa = TO_INT64 (*mantissa); /* retrieve mantissa */ -unpacked.exponent = 0; /* exponent is irrelevant */ -complement (&unpacked); /* negate it */ -*mantissa = to_xpn (unpacked.mantissa, 0); /* replace mantissa */ -return (uint32) unpacked.exponent; /* return exponent increment */ +if (unpacked->mantissa) /* non-zero? */ + while (DENORM (unpacked->mantissa)) { /* normal form? */ + unpacked->exponent = unpacked->exponent - 1; /* no, so left shift */ + unpacked->mantissa = unpacked->mantissa << 1; + } +else + unpacked->exponent = 0; /* clean for zero */ +return; } -/* Complement an extended-precision number */ +/* Round an unpacked floating-point number and check for overflow. -uint32 x_dcm (XPN *packed) + An unpacked floating-point number is rounded by adding one-half of the LSB + value, maintaining symmetry around zero. If rounding resulted in a mantissa + overflow, the result logically is shifted to the right with an appropriate + exponent modification. Finally, the result is checked for exponent underflow + or overflow, and the appropriate approximation (zero or infinity) is + returned. + + Rounding in hardware involves a special mantissa extension register that + holds three "guard" bits and one "sticky" bit. These represent the value of + bits right-shifted out the mantissa register. Under simulation, we track + such right-shifts and utilize the lower eight bits of the 64-bit mantissa + value to simulate the extension register. + + Overflow depends on whether the FPP expanded-exponent form is being used + (this expands the exponent range by two bits). If overflow is detected, the + value representing infinity is dependent on whether the operation is on + behalf of the Fast FORTRAN Processor. The F-Series FPP returns positive + infinity on both positive and negative overflow for all precisions. The 2100 + and M/E-Series FFPs return negative infinity on negative overflow of + extended-precision values. Single-precision overflows on these machines + always return positive infinity. + + The number to be rounded must be normalized upon entry. +*/ + +static uint32 roundovf (FPU *unpacked, t_bool expand) { -XPU unpacked; +uint32 overflow; +t_bool sign; -unpacked = unpack (*packed); /* unpack the number */ -complement (&unpacked); /* negate it */ -return pack (packed, unpacked); /* and repack */ +sign = (unpacked->mantissa < 0); /* save mantissa sign */ + +if (sign) /* round and mask the number */ + unpacked->mantissa = + (unpacked->mantissa + n_half_lsb[unpacked->precision]) & + mant_mask[unpacked->precision]; +else + unpacked->mantissa = + (unpacked->mantissa + p_half_lsb[unpacked->precision]) & + mant_mask[unpacked->precision]; + +if (sign != (unpacked->mantissa < 0)) /* mantissa overflow? */ + lsrx (unpacked, 1); /* correct by shifting */ +else + normalize (unpacked); /* renorm may be needed */ + +if (unpacked->mantissa == 0) { /* result zero? */ + unpacked->mantissa = 0; /* return zero */ + unpacked->exponent = 0; + overflow = 0; /* with overflow clear */ + } +else if (unpacked->exponent < /* result underflow? */ + (FP_MAXNEXP >> (expand ? 0 : 2))) { + unpacked->mantissa = 0; /* return zero */ + unpacked->exponent = 0; + overflow = 1; /* and set overflow */ + } +else if (unpacked->exponent > /* result overflow? */ + (FP_MAXPEXP >> (expand ? 0 : 2))) { + if (sign && /* negative value? */ + (unpacked->precision == fp_x) && /* extended precision? */ + (UNIT_CPU_MODEL != UNIT_1000_F)) { /* not F-series? */ + unpacked->mantissa = FP_MAXNMANT; /* return negative infinity */ + unpacked->exponent = FP_MAXPEXP & FP_M_EXP; + } + else { + unpacked->mantissa = FP_MAXPMANT; /* return positive infinity */ + unpacked->exponent = FP_MAXPEXP & FP_M_EXP; + } + overflow = 1; /* and set overflow */ + } +else + overflow = 0; /* value is in range */ + +return overflow; } -/* Truncate an extended-precision number */ +/* Normalize, round, and pack an unpacked floating-point number. */ -void x_trun (XPN *result, XPN source) +static uint32 nrpack (OP *packed, FPU unpacked, t_bool expand) { -t_uint64 mask; -uint32 bitslost; -XPU unpacked; -const XPU one = { XP_ONEHALF, 1 }; /* 0.5 * 2 ** 1 = 1.0 */ +uint32 overflow; + +normalize (&unpacked); /* normalize for rounding */ +overflow = roundovf (&unpacked, expand); /* round and check for overflow */ +*packed = pack (unpacked); /* pack result */ + +return overflow; +} + + + +/* Low-level arithmetic routines. */ + + +/* Complement an unpacked number. */ + +static void complement (FPU *result) +{ +result->mantissa = -result->mantissa; /* negate mantissa */ +if (result->mantissa == FP_MAXNMANT) /* maximum negative? */ + lsrx (result, 1); /* correct it */ +return; +} + + +/* Add two unpacked numbers. + + The mantissas are first aligned if necessary by scaling the smaller of the + two operands. If the magnitude of the difference between the exponents is + greater than the number of significant bits, then the smaller number has been + scaled to zero (swamped), and so the sum is simply the larger operand. + Otherwise, the sum is computed and checked for overflow, which has occured if + the signs of the operands are the same but differ from that of the result. + Scaling and renormalization is perfomed if overflow occurred. +*/ + +static void add (FPU *sum, FPU augend, FPU addend) +{ +int32 magn; +t_bool bits_lost; + +if (augend.mantissa == 0) + *sum = addend; /* X + 0 = X */ + +else if (addend.mantissa == 0) + *sum = augend; /* 0 + X = X */ -unpacked = unpack (source); -if (unpacked.exponent < 0) /* number < 0.5? */ - result->high = result->low = 0; /* return 0 */ -else if (unpacked.exponent > XP_W_MANT) /* no fractional bits? */ - *result = source; /* already integer */ else { - mask = (XP_MANT >> unpacked.exponent) & XP_MANT; /* mask fractional bits */ - bitslost = (uint32) (unpacked.mantissa & mask); /* flag if bits lost */ - unpacked.mantissa = unpacked.mantissa & ~mask; /* mask off fraction */ - if ((unpacked.mantissa < 0) && bitslost) /* negative? */ - add (&unpacked, unpacked, one); /* truncate toward zero */ - pack (result, unpacked); /* (overflow cannot occur) */ + magn = augend.exponent - addend.exponent; /* difference exponents */ + + if (magn > 0) { /* addend smaller? */ + *sum = augend; /* preset augend */ + bits_lost = asr (&addend, magn); /* align addend */ + } + else { /* augend smaller? */ + *sum = addend; /* preset addend */ + magn = -magn; /* make difference positive */ + bits_lost = asr (&augend, magn); /* align augend */ + } + + if (magn <= (int32) op_bits[augend.precision]) { /* value swamped? */ + sum->mantissa = /* no, add mantissas */ + addend.mantissa + augend.mantissa; + + if (((addend.mantissa < 0) == (augend.mantissa < 0)) && /* mantissa overflow? */ + ((addend.mantissa < 0) != (sum->mantissa < 0))) { + bits_lost = bits_lost | lsrx (sum, 1); /* restore value */ + sum->mantissa = /* restore sign */ + sum-> mantissa | (addend.mantissa & FP_MSIGN); + } + + if (bits_lost) /* any bits lost? */ + sum->mantissa = sum->mantissa | 1; /* include one for rounding */ + } } return; } -#endif /* defined (HAVE_INT64) */ + +/* Multiply two unpacked numbers. + + The single-precision firmware (FMP) operates differently from the firmware + extended-precision (.XMPY) and the hardware multiplies of any precision. + Firmware implementations form 16-bit x 16-bit = 32-bit partial products and + sum them to form the result. The hardware uses a series of shifts and adds. + This means that firmware FMP and hardware FMP return slightly different + values, as may be seen by attempting to run the firmware FMP diagnostic on + the FPP. + + The FMP microcode calls a signed multiply routine to calculate three partial + products (all but LSB * LSB). Because the LSBs are unsigned, i.e., all bits + significant, the two MSB * LSB products are calculated using LSB/2. The + unsigned right-shift ensures a positive LSB with no significant bits lost, + because the lower eight bits are unused (they held the vacated exponent). In + order to sum the partial products, the LSB of the result of MSB * MSB is also + right-shifted before addition. Note, though, that this loses a significant + bit. After summation, the result is left-shifted to correct for the original + right shifts. + + The .XMPY microcode negates both operands as necessary to produce positive + values and then forms six of the nine 16-bit x 16-bit = 32-bit unsigned + multiplications required for a full 96-bit product. Given a 48-bit + multiplicand "a1a2a3" and a 48-bit multiplier "b1b2b3", the firmware performs + these calculations to develop a 48-bit product: + + a1 a2 a3 + +-------+-------+-------+ + b1 b2 b3 + +-------+-------+-------+ + _________________________ + + a1 * b3 [p1] + +-------+-------+ + a2 * b2 [p2] + +-------+-------+ + a1 * b2 [p3] + +-------+-------+ + a3 * b1 [p4] + +-------+-------+ + a2 * b1 [p5] + +-------+-------+ + a1 * b1 [p6] + +-------+-------+ + _________________________________ + + product + +-------+-------+-------+ + + The least-significant words of partial products [p1], [p2], and [p4] are used + only to develop a carry bit into the 48-bit sum. The product is complemented + as necessary to restore the sign. + + The basic FPP hardware algorithm scans the multiplier and adds a shifted copy + of the multiplicand whenever a one-bit is detected. To avoid successive adds + when a string of ones is encountered (because adds are more expensive than + shifts), the hardware instead adds the multiplicand shifted by N+1+P and + subtracts the multiplicand shifted by P to obtain the equivalent value with a + maximum of two operations. + + Instead of implementing either the .XMPY firmware algorithm or the hardware + shift-and-add algorithm directly, it is more efficient under simulation to + use 32 x 32 = 64-bit multiplications, thereby reducing the number required + from six to four (64-bit "c1c2" x 64-bit "d1d2"): + + ah al + +-------+-------+ + bh bl + +-------+-------+ + _________________ + + al * bl [ll] + +-------+-------+ + ah * bl [hl] + +-------+-------+ + al * bh [lh] + +-------+-------+ + ah * bh [hh] + +-------+-------+ + _________________________________ + + product + +-------+-------+ + + However, the FMP algorithm is implemented directly from the microcode to + preserve the fidelity of the simulation, i.e., to lose the same amount + of precision. +*/ + +static void multiply (FPU *product, FPU multiplicand, FPU multiplier) +{ +uint32 ah, al, bh, bl, sign = 0; +t_uint64 hh, hl, lh, ll, carry; +int16 ch, cl, dh, dl; +t_bool firmware; + +product->precision = multiplicand.precision; /* set precision */ + +if ((multiplicand.mantissa == 0) || /* 0 * X = 0 */ + (multiplier.mantissa == 0)) /* X * 0 = 0 */ + product->mantissa = product->exponent = 0; + +else { + firmware = (UNIT_CPU_MODEL != UNIT_1000_F); /* set firmware flag */ + + if (!firmware || (product->precision != fp_f)) { /* hardware? */ + if (multiplicand.mantissa < 0) { /* negative? */ + complement (&multiplicand); /* complement operand */ + sign = ~sign; /* track sign */ + } + if (multiplier.mantissa < 0) { /* negative? */ + complement (&multiplier); /* complement operand */ + sign = ~sign; /* track sign */ + } + } + + product->exponent = /* compute exponent */ + multiplicand.exponent + multiplier.exponent + 1; + + ah = (uint32) (multiplicand.mantissa >> 32); /* split multiplicand */ + al = (uint32) (multiplicand.mantissa & DMASK32); /* into high and low parts */ + bh = (uint32) (multiplier.mantissa >> 32); /* split multiplier */ + bl = (uint32) (multiplier.mantissa & DMASK32); /* into high and low parts */ + + if (firmware && (product->precision == fp_f)) { /* single-precision firmware? */ + ch = (int16) (ah >> 16) & DMASK; /* split 32-bit multiplicand */ + cl = (int16) (ah & 0xfffe); /* into high and low parts */ + dh = (int16) (bh >> 16) & DMASK; /* split 32-bit multiplier */ + dl = (int16) (bh & 0xfffe); /* into high and low parts */ + + hh = (t_uint64) (((int32) ch * dh) & ~1); /* form cross products */ + hl = (t_uint64) (((t_int64) ch * (t_int64) (uint16) dl + + (t_int64) dh * (t_int64) (uint16) cl) & + 0xfffffffffffe0000); + + product->mantissa = (t_uint64) (((t_int64) hh << 32) + /* sum partials */ + ((t_int64) hl << 16)); + } + + else { + hh = ((t_uint64) ah * bh); /* form four cross products */ + hl = ((t_uint64) ah * bl); /* using 32 x 32 = */ + lh = ((t_uint64) al * bh); /* 64-bit multiplies */ + ll = ((t_uint64) al * bl); + + carry = ((ll >> 32) + (uint32) hl + (uint32) lh) >> 32; /* form carry */ + + product->mantissa = hh + (hl >> 32) + (lh >> 32) + carry; /* sum partials */ + + if (sign) /* negate if required */ + complement (product); + } + } +return; +} + + +/* Divide two unpacked numbers. + + As with multiply, the single-precision firmware (FDV) operates differently + from the firmware extended-precision (.XDIV) and the hardware divisions of + any precision. Firmware implementations utilize a "divide and correct" + algorithm, wherein the quotient is estimated and then corrected by comparing + the dividend to the product of the quotient and the divisor. The hardware + uses a series of shifts and subtracts. This means that firmware FDV and + hardware FDV once again return slightly different values. + + Under simulation, the classic divide-and-correct method is employed, using + 64-bit / 32-bit = 32-bit divisions. This involves dividing the 64-bit + dividend "a1a2a3a4" by the first 32-bit digit "b1b2" of the 64-bit divisor + "b1b2b3b4". The resulting 32-bit quotient is ... + + The microcoded single-precision division avoids overflows by right-shifting + some values, which leads to a loss of precision in the LSBs. We duplicate + the firmware algorithm here to preserve the fidelity of the simulation. +*/ + +static void divide (FPU *quotient, FPU dividend, FPU divisor) +{ +uint32 sign = 0; +t_int64 bh, bl, r1, r0, p1, p0; +t_uint64 q, q1, q0; +t_bool firmware; +int32 ah, div, cp; +int16 dh, dl, pq1, pq2, cq; + +quotient->precision = dividend.precision; /* set precision */ + +if (divisor.mantissa == 0) { /* division by zero? */ + if (dividend.mantissa < 0) + quotient->mantissa = FP_MSIGN; /* return minus infinity */ + else + quotient->mantissa = ~FP_MSIGN; /* or plus infinity */ + quotient->exponent = FP_MAXPEXP + 1; + } + +else if (dividend.mantissa == 0) /* dividend zero? */ + quotient->mantissa = quotient->exponent = 0; /* yes; result is zero */ + +else { + firmware = (UNIT_CPU_MODEL != UNIT_1000_F); /* set firmware flag */ + + if (!firmware || (quotient->precision != fp_f)) { /* hardware or FFP? */ + if (dividend.mantissa < 0) { /* negative? */ + complement (÷nd); /* complement operand */ + sign = ~sign; /* track sign */ + } + if (divisor.mantissa < 0) { /* negative? */ + complement (&divisor); /* complement operand */ + sign = ~sign; /* track sign */ + } + } + + quotient->exponent = /* division subtracts exponents */ + dividend.exponent - divisor.exponent; + + bh = divisor.mantissa >> 32; /* split divisor */ + bl = divisor.mantissa & DMASK32; /* into high and low parts */ + + if (firmware && (quotient->precision == fp_f)) { /* single-precision firmware? */ + quotient->exponent = quotient->exponent + 1; /* fix exponent */ + + ah = (int32) (dividend.mantissa >> 32); /* split dividend */ + dh = (int16) (bh >> 16); /* split divisor again */ + dl = (int16) bh; + + div = ah >> 2; /* ASR 2 to prevent overflow */ + + pq1 = div / dh; /* form first partial quotient */ + div = ((div % dh) & ~1) << 15; /* ASR 1, move rem to upper */ + pq2 = div / dh; /* form second partial quotient */ + + div = (uint16) dl << 13; /* move divisor LSB to upper, LSR 3 */ + cq = div / dh; /* form correction quotient */ + cp = -cq * pq1; /* and correction product */ + + cp = (((cp >> 14) & ~3) + (int32) pq2) << 1; /* add corr prod and 2nd partial quo */ + quotient->mantissa = /* add 1st partial quo and align */ + (t_uint64) (((int32) pq1 << 16) + cp) << 32; + } + + else { /* hardware or FFP */ + q1 = (t_uint64) (dividend.mantissa / bh); /* form 1st trial quotient */ + r1 = dividend.mantissa % bh; /* and remainder */ + p1 = (r1 << 24) - (bl >> 8) * q1; /* calculate correction */ + + while (p1 < 0) { /* correction needed? */ + q1 = q1 - 1; /* trial quotient too large */ + p1 = p1 + (divisor.mantissa >> 8); /* increase remainder */ + } + + q0 = (t_uint64) ((p1 << 8) / bh); /* form 2nd trial quotient */ + r0 = (p1 << 8) % bh; /* and remainder */ + p0 = (r0 << 24) - (bl >> 8) * q0; /* calculate correction */ + + while (p0 < 0) { /* correction needed? */ + q0 = q0 - 1; /* trial quotient too large */ + p0 = p0 + (divisor.mantissa >> 8); /* increase remainder */ + } + + q = (q1 << 32) + q0; /* sum quotient digits */ + + if (q1 & 0xffffffff00000000) { /* did we lose MSB? */ + q = (q >> 1) | 0x8000000000000000; /* shift right and replace bit */ + quotient->exponent = quotient->exponent + 1;/* bump exponent for shift */ + } + + if (q & 0x8000000000000000) /* lose normalization? */ + q = q >> 1; /* correct */ + + quotient->mantissa = (t_int64) q; + } + + if (sign) + complement (quotient); /* negate if required */ + } +return; +} + + +/* Fix an unpacked number. + + A floating-point value is converted to an integer. The desired precision of + the result (single or double integer) must be set before calling. + + Values less than 0.5 (i.e., with negative exponents) underflow to zero. If + the value exceeds the specified integer range, the maximum integer value is + returned and overflow is set. Otherwise, the floating-point value is + right-shifted to zero the exponent. The result is then rounded. +*/ + +static uint32 fix (FPU *result, FPU operand) +{ +uint32 overflow; +t_bool bits_lost; + +if (operand.exponent < 0) { /* value < 0.5? */ + result->mantissa = 0; /* result rounds to zero */ + overflow = 0; /* clear for underflow */ + } + +else if (operand.exponent > /* value > integer size? */ + (int32) op_bits[result->precision]) { + result->mantissa = /* return max int value */ + (t_uint64) int_p_max[result->precision] << + op_start[result->precision]; + overflow = 1; /* and set overflow */ + } + +else { /* value in range */ + bits_lost = asr (&operand, /* shift to zero exponent */ + op_bits[result->precision] - operand.exponent); + + if (operand.mantissa < 0) { /* value negative? */ + if (bits_lost) /* bits lost? */ + operand.mantissa = operand.mantissa | 1; /* include one for rounding */ + + operand.mantissa = operand.mantissa + /* round result */ + p_half_lsb[result->precision]; + } + + result->mantissa = operand.mantissa & /* mask to precision */ + op_mask[result->precision]; + overflow = 0; + } + +result->exponent = 0; /* tidy up for integer value */ +return overflow; +} + + +/* Float an integer to an unpacked number. + + An integer is converted to a floating-point value. The desired precision of + the result must be set before calling. + + Conversion is simply a matter of copying the integer value, setting an + exponent that reflects the right-aligned position of the bits, and + normalizing. +*/ + +static void ffloat (FPU *result, FPU operand) +{ +result->mantissa = operand.mantissa; /* set value */ +result->exponent = op_bits[operand.precision]; /* set exponent */ +normalize (result); /* normalize */ +return; +} + + + +/* High-level floating-point routines. */ + + +/* Determine operand precisions. + + The precisions of the operands and result are determined by decoding an + operation opcode and returned to the caller. Pass NULL for both of the + operands if only the result precision is wanted. Pass NULL for the result if + only the operand precisions are wanted. +*/ + +void fp_prec (uint16 opcode, OPSIZE *operand_l, OPSIZE *operand_r, OPSIZE *result) +{ +OPSIZE fp_size, int_size; + +fp_size = (OPSIZE) ((opcode & 0003) + 2); /* fp_f, fp_x, fp_t, fp_e */ +int_size = (OPSIZE) ((opcode & 0004) >> 2); /* in_s, in_d */ + +if (operand_l && operand_r) { /* want operand precisions? */ + switch (opcode & 0120) { /* mask out opcode bit 5 */ + case 0000: /* add/mpy */ + case 0020: /* sub/div */ + *operand_l = fp_size; /* assume first op is fp */ + + if (opcode & 0004) /* operand internal? */ + *operand_r = fp_a; /* second op is accum */ + else + *operand_r = fp_size; /* second op is fp */ + break; + + case 0100: /* fix/accum as integer */ + *operand_l = fp_size; /* first op is fp */ + *operand_r = fp_a; /* second op is always null */ + break; + + case 0120: /* flt/accum as float */ + *operand_l = int_size; /* first op is integer */ + *operand_r = fp_a; /* second op is always null */ + break; + } + + if (opcode & 0010) /* operand internal? */ + *operand_l = fp_a; /* first op is accum */ + } + +if (result) /* want result precision? */ + if ((opcode & 0120) == 0100) /* fix? */ + *result = int_size; /* result is integer */ + else /* all others */ + *result = fp_size; /* result is fp */ + +return; +} + + +/* Floating Point Processor executor. + + The executor simulates the MPP interface between the CPU and the FPP. The + operation to be performed is specified by the supplied opcode, which conforms + to the FPP hardware interface, as follows: + + Bits Value Action + ---- ----- ---------------------------------------------- + 7 0 Exponent range is standard (+/-127) + 1 Exponent range is expanded (+/-511) + + 6-4 000 Add + 001 Subtract + 010 Multiply + 011 Divide + 100 Fix + 101 Float + 110 (diagnostic) + 111 (diagnostic) + + 3 0 Left operand is supplied + 1 Left operand in accumulator + + 2 0 Right operand is supplied (ADD/SUB/MPY/DIV) + Single integer operation (FIX/FLT) + 1 Right operand in accumulator (ADD/SUB/MPY/DIV) + Double integer operation (FIX/FLT) + + 1-0 00 2-word operation + 01 3-word operation + 10 4-word operation + 11 5-word operation + + If the opcode specifies that the left (or right) operand is in the + accumulator, then the value supplied for that parameter is not used. All + results are automatically left in the accumulator. If the result is not + needed externally, then NULL may be passed for the result parameter. + + To support accumulator set/get operations under simulation, the opcode is + expanded to include a special mode, indicated by bit 15 = 1. In this mode, + if the result parameter is NULL, then the accumulator is set from the value + passed as operand_l. If the result parameter is not null, then the + accumulator value is returned as the result, and operand_l is ignored. The + precision of the operation is performed as specified by the OPSIZE value + passed in bits 2-0 of the opcode. + + The function returns 1 if the operation overflows and 0 if not. +*/ + +uint32 fp_exec (uint16 opcode, OP *result, OP operand_l, OP operand_r) +{ +static FPU accumulator; +FPU uoperand_l, uoperand_r; +OPSIZE op_l_prec, op_r_prec, rslt_prec; +uint32 overflow; + +if (opcode & SIGN) { /* accumulator mode? */ + rslt_prec = (OPSIZE) (opcode & 0017); /* get operation precision */ + + if (result) { /* get accumulator? */ + op_l_prec = accumulator.precision; /* save accum prec temp */ + accumulator.precision = rslt_prec; /* set desired precision */ + *result = pack (accumulator); /* pack accumulator */ + accumulator.precision = op_l_prec; /* restore correct prec */ + } + else /* set accumulator */ + accumulator = unpack (operand_l, rslt_prec); /* unpack from operand */ + + return 0; /* no overflow from accum ops */ + } + +fp_prec (opcode, &op_l_prec, &op_r_prec, &rslt_prec); /* calc precs from opcode */ + +if (op_l_prec == fp_a) /* left operand in accum? */ + uoperand_l = accumulator; /* copy it */ +else /* operand supplied */ + uoperand_l = unpack (operand_l, op_l_prec); /* unpack from parameter */ + +if (op_r_prec == fp_a) /* right operand in accum? */ + uoperand_r = accumulator; /* copy it */ +else /* operand supplied */ + uoperand_r = unpack (operand_r, op_r_prec); /* unpack from parameter */ + + +switch (opcode & 0160) { /* dispatch operation */ + + case 0000: /* add */ + add (&accumulator, uoperand_l, uoperand_r); + break; + + case 0020: /* subtract */ + complement (&uoperand_r); + add (&accumulator, uoperand_l, uoperand_r); + break; + + case 0040: /* multiply */ + multiply (&accumulator, uoperand_l, uoperand_r); + break; + + case 0060: /* divide */ + divide (&accumulator, uoperand_l, uoperand_r); + break; + + case 0100: /* fix */ + accumulator.precision = rslt_prec; + overflow = fix (&accumulator, uoperand_l); + + if (result) /* result wanted? */ + *result = pack_int (accumulator.mantissa, /* pack integer */ + rslt_prec); + return overflow; + + case 0120: /* float */ + accumulator.precision = rslt_prec; + ffloat (&accumulator, uoperand_l); + + if (result) /* result wanted? */ + *result = pack (accumulator); /* pack FP (FLT does not round) */ + return 0; + + case 0140: /* (diagnostic) */ + case 0160: /* (diagnostic) */ + return 0; + } + +if (UNIT_CPU_MODEL != UNIT_1000_F) /* firmware implementation? */ + accumulator.mantissa = accumulator.mantissa & /* mask to precision */ + op_mask[accumulator.precision]; + +normalize (&accumulator); /* normalize */ +overflow = roundovf (&accumulator, opcode & 0200); /* round and check for overflow */ + +if (result) /* result wanted? */ + *result = pack (accumulator); /* pack result */ + +return overflow; +} + + +/* Set or get accumulator at desired precision. + + This function provides access to the FPP accumulator. In hardware, the + accumulator may be read at a given precision by sending the FPP an opcode + encoded with the desired precision and then reading words from the FPP + /without/ initiating the operation, i.e., without starting the processor. + + Under simulation, pass this function a NULL operand and the desired + precision to read the accumulator. Pass a pointer to an operand and the + desired precision to set the accumulator; the return value in this case is + not defined. +*/ + +OP fp_accum (const OP *operand, OPSIZE precision) +{ +OP result; +uint16 opcode = (uint16) precision | SIGN; /* add special mode bit */ + +if (operand) + fp_exec (opcode, NULL, *operand, NOP); /* set accum */ +else + fp_exec (opcode, &result, NOP, NOP); /* get accum */ +return result; +} + + +/* Pack an unpacked floating-point number. + + An unpacked mantissa is passed as a "packed" number with an unused exponent. + The mantissa and separately-passed exponent are packed into the in-memory + floating-point format. Note that all bits are significant in the mantissa + (no masking is done). +*/ + +uint32 fp_pack (OP *result, OP mantissa, int32 exponent, OPSIZE precision) +{ +FPU unpacked; + +unpacked.mantissa = unpack_int (mantissa, precision); /* unpack mantissa */ +unpacked.exponent = exponent; /* set exponent */ +unpacked.precision = precision; /* set precision */ +*result = pack (unpacked); /* pack them */ +return 0; +} + + +/* Normalize, round, and pack an unpacked floating-point number. + + An unpacked mantissa is passed as a "packed" number with an unused exponent. + The mantissa and separately-passed exponent are normalized, rounded, and + packed into the in-memory floating-point format. Note that all bits are + significant in the mantissa (no masking is done). +*/ + +uint32 fp_nrpack (OP *result, OP mantissa, int32 exponent, OPSIZE precision) +{ +FPU unpacked; + +unpacked.mantissa = unpack_int (mantissa, precision); /* unpack mantissa */ +unpacked.exponent = exponent; /* set exponent */ +unpacked.precision = precision; /* set precision */ +return nrpack (result, unpacked, FALSE); /* norm/rnd/pack them */ +} + + +/* Unpack a packed floating-point number. + + A floating-point number, packed into the in-memory format, is unpacked into + separate mantissa and exponent values. The unpacked mantissa is returned in + a "packed" structure with an exponent of zero. Mantissa or exponent may be + null if that part isn't wanted. +*/ + +uint32 fp_unpack (OP *mantissa, int32 *exponent, OP packed, OPSIZE precision) + +{ +FPU unpacked; + +unpacked = unpack (packed, precision); /* unpack mantissa and exponent */ + +if (exponent) /* exponent wanted? */ + *exponent = unpacked.exponent; /* return exponent */ + +if (mantissa) /* mantissa wanted? */ + *mantissa = pack_int (unpacked.mantissa, fp_t); /* return full-size mantissa */ +return 0; +} + + + /* Complement an unpacked mantissa. + + An unpacked mantissa is passed as a "packed" number with a zero exponent. + The exponent increment, i.e., either zero or one, depending on whether a + renormalization was required, is returned. Note that all bits are + significant in the mantissa. +*/ + +uint32 fp_ucom (OP *mantissa, OPSIZE precision) +{ +FPU unpacked; + +unpacked.mantissa = unpack_int (*mantissa, precision); /* unpack mantissa */ +unpacked.exponent = 0; /* clear undefined exponent */ +unpacked.precision = precision; /* set precision */ +complement (&unpacked); /* negate it */ +*mantissa = pack_int (unpacked.mantissa, precision); /* replace mantissa */ +return (uint32) unpacked.exponent; /* return exponent increment */ +} + + +/* Complement a floating-point number. */ + +uint32 fp_pcom (OP *packed, OPSIZE precision) +{ +FPU unpacked; + +unpacked = unpack (*packed, precision); /* unpack the number */ +complement (&unpacked); /* negate it */ +return nrpack (packed, unpacked, FALSE); /* and norm/rnd/pack */ +} + + +/* Truncate a floating-point number. */ + +uint32 fp_trun (OP *result, OP source, OPSIZE precision) +{ +t_bool bits_lost; +FPU unpacked; +FPU one = { FP_ONEHALF, 1, 0 }; /* 0.5 * 2 ** 1 = 1.0 */ +OP zero = { { 0, 0, 0, 0, 0 } }; /* 0.0 */ +t_uint64 mask = mant_mask[precision] & ~FP_MSIGN; + +unpacked = unpack (source, precision); +if (unpacked.exponent < 0) /* number < 0.5? */ + *result = zero; /* return 0 */ +else if (unpacked.exponent >= (int32) op_bits[precision]) /* no fractional bits? */ + *result = source; /* already integer */ +else { + mask = (mask >> unpacked.exponent) & mask; /* mask fractional bits */ + bits_lost = ((unpacked.mantissa & mask) != 0); /* flag if bits lost */ + unpacked.mantissa = unpacked.mantissa & ~mask; /* mask off fraction */ + if ((unpacked.mantissa < 0) && bits_lost) /* negative? */ + add (&unpacked, unpacked, one); /* truncate toward zero */ + nrpack (result, unpacked, FALSE); /* (overflow cannot occur) */ + } +return 0; /* clear overflow on return */ +} + + +/* Convert a floating-point number from one precision to another. */ + +uint32 fp_cvt (OP *result, OPSIZE source_precision, OPSIZE dest_precision) +{ +FPU unpacked; + +unpacked = unpack (*result, source_precision); +unpacked.precision = dest_precision; +return nrpack (result, unpacked, FALSE); /* norm/rnd/pack */ +} + + +#endif /* end of int64 support */ diff --git a/HP2100/hp2100_fp1.h b/HP2100/hp2100_fp1.h index 539eaf60..4649c09a 100644 --- a/HP2100/hp2100_fp1.h +++ b/HP2100/hp2100_fp1.h @@ -1,6 +1,6 @@ -/* hp2100_fp1.h: HP 2100/21MX extended-precision floating point definitions +/* hp2100_fp1.h: HP 2100/1000 multiple-precision floating point definitions - Copyright (c) 2005, J. David Bryan + Copyright (c) 2005-2006, J. David Bryan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -15,38 +15,39 @@ 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 + THE AUTHOR 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 the author shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the author. + Except as contained in this notice, the name of the author shall not be used + in advertising or otherwise to promote the sale, use or other dealings in + this Software without prior written authorization from the author. + + 16-Oct-06 JDB Generalized FP calling sequences for F-Series + 12-Oct-06 JDB Altered x_trun for F-Series FFP compatibility */ #ifndef _HP2100_FP1_H_ #define _HP2100_FP1_H_ 0 -/* HP memory representation of an extended-precision number */ -typedef struct { - uint32 high; - uint32 low; - } XPN; +/* Special operands. */ + +#define ACCUM NULL /* result not returned */ +static const OP NOP = { { 0, 0, 0, 0, 0 } }; /* unneeded operand */ -#define AS_XPN(x) (*(XPN *) &(x)) /* view as XPN */ +/* Generalized floating-point handlers. */ -XPN ReadX (uint32 va); -void WriteX (uint32 va, XPN packed); - -uint32 x_add (XPN *sum, XPN augend, XPN addend); -uint32 x_sub (XPN *difference, XPN minuend, XPN subtrahend); -uint32 x_mpy (XPN *product, XPN multiplicand, XPN multiplier); -uint32 x_div (XPN *quotient, XPN dividend, XPN divisor); -uint32 x_pak (XPN *result, XPN mantissa, int32 exponent); -uint32 x_com (XPN *mantissa); -uint32 x_dcm (XPN *packed); -void x_trun (XPN *result, XPN source); +void fp_prec (uint16 opcode, OPSIZE *operand_l, OPSIZE *operand_r, OPSIZE *result); +uint32 fp_exec (uint16 opcode, OP *result, OP operand_l, OP operand_r); +OP fp_accum (const OP *operand, OPSIZE precision); +uint32 fp_pack (OP *result, OP mantissa, int32 exponent, OPSIZE precision); +uint32 fp_nrpack (OP *result, OP mantissa, int32 exponent, OPSIZE precision); +uint32 fp_unpack (OP *mantissa, int32 *exponent, OP packed, OPSIZE precision); +uint32 fp_ucom (OP *mantissa, OPSIZE precision); +uint32 fp_pcom (OP *packed, OPSIZE precision); +uint32 fp_trun (OP *result, OP source, OPSIZE precision); +uint32 fp_cvt (OP *result, OPSIZE source_precision, OPSIZE dest_precision); #endif diff --git a/HP2100/hp2100_ipl.c b/HP2100/hp2100_ipl.c index 0a401b2c..95195010 100644 --- a/HP2100/hp2100_ipl.c +++ b/HP2100/hp2100_ipl.c @@ -1,6 +1,6 @@ /* hp2100_ipl.c: HP 2000 interprocessor link simulator - Copyright (c) 2002-2005, Robert M Supnik + Copyright (c) 2002-2006, 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 @@ ipli, iplo 12566B interprocessor link pair + 28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified) 16-Aug-05 RMS Fixed C++ declaration and cast problems 07-Oct-04 JDB Fixed enable/disable from either device 26-Apr-04 RMS Fixed SFS x,C and SFC x,C @@ -201,6 +202,7 @@ switch (inst) { /* case on opcode */ dat = dat | uptr->IBUF; /* get return data */ break; + case ioCRS: /* control reset (action unverif) */ case ioCTL: /* control clear/set */ if (IR & I_CTL) { /* CLC */ clrCMD (dev); /* clear ctl, cmd */ @@ -439,7 +441,7 @@ static const uint32 pboot[IBL_LNT] = { 0163774, /*BBL LDA ICK,I ; IPL sel code */ 0027751, /* JMP CFG ; go configure */ 0107700, /*ST CLC 0,C ; intr off */ - 0002702, /* CLA,CCE,SZA ; skip in */ + 0002702, /* CLA,CCE,SZA ; skip in */ 0063772, /*CN LDA M26 ; feed frame */ 0002307, /*EOC CCE,INA,SZA,RSS ; end of file? */ 0027760, /* JMP EOT ; yes */ diff --git a/HP2100/hp2100_lps.c b/HP2100/hp2100_lps.c index 38b8e593..9cf49cc6 100644 --- a/HP2100/hp2100_lps.c +++ b/HP2100/hp2100_lps.c @@ -1,6 +1,6 @@ -/* hp2100_lps.c: HP 2100 12653A line printer simulator +/* hp2100_lps.c: HP 2100 12653A/2767 line printer simulator - Copyright (c) 1993-2005, Robert M. Supnik + Copyright (c) 1993-2007, 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"), @@ -24,8 +24,10 @@ in this Software without prior written authorization from Robert M Supnik. lps 12653A 2767 line printer - (based on 12566B microcircuit interface) + 12566B microcircuit interface with loopback diagnostic connector + 11-Jan-07 JDB CLC cancels I/O event if DIAG (jumper W9 in "A" pos) + Added ioCRS state to I/O decoders 19-Nov-04 JDB Added restart when set online, etc. Fixed col count for non-printing chars 01-Oct-04 JDB Added SET OFFLINE/ONLINE, POWEROFF/POWERON @@ -47,6 +49,18 @@ Added command flop 15-Oct-00 RMS Added variable device number support + This module simulates two different devices. In "diagnostic mode," it + simulates a 12566B microcircuit interface card with a loopback connector and + the jumpers set as required for execution of the General Purpose Register + diagnostic. In non-diagnostic mode, it simulates a 12653A line printer + interface card and a 2767 line printer. + + The 12566B interface with the loopback connector ties the device command + output to the device flag input. Setting control therefore causes device + flag to set almost immediately. Device command is active only during that + interim. Under simulation, the loopback occurs within the STC handler, and + CMD is never set. + The 2767 impact printer has a rotating drum with 80 columns of 64 raised characters. ASCII codes 32 through 95 (SPACE through "_") form the print repertoire. The printer responds to the control characters FF, LF, and CR. @@ -64,7 +78,7 @@ the buffer memory. * LF -- same as CR, plus advances the paper one line. * FF -- same as CR, plus advances the paper to the top of the next form. - + The 2767 provides two status bits via the interface: bit 15 -- printer not ready @@ -103,6 +117,7 @@ */ #include "hp2100_defs.h" +#include "hp2100_cpu.h" #define LPS_ZONECNT 20 /* zone char count */ #define LPS_PAGECNT 80 /* page char count */ @@ -148,6 +163,13 @@ uint32 lps_power = LPS_ON; /* power state */ NOTE: the printer acknowledges before the print motion has stopped to allow for continuous slew, so the set times are a bit less than the calculated operation time from the manual. + + NOTE: the 2767 diagnostic checks completion times, so the realistic timing + must be used. Because simulator timing is in instructions, and because the + diagnostic uses the TIMER instruction (~1580 executions per millisecond) when + running on a 1000-E/F but a software timing loop (~400-600 executions per + millisecond) when running on anything else, realistic timings are decreased by + three-fourths when not executing on an E/F. */ int32 lps_ctime = 0; /* char xfer time */ @@ -280,16 +302,28 @@ switch (inst) { /* case on opcode */ fprintf (sim_deb, ">>LPS LIx: Status %06o returned\n", dat); break; + case ioCRS: /* control reset */ + clrCTL (dev); /* clear control */ + clrCMD (dev); /* clear command */ + sim_cancel (&lps_unit); /* deactivate unit */ + break; + case ioCTL: /* control clear/set */ if (IR & I_CTL) { /* CLC */ - clrCMD (dev); /* clear ctl, cmd */ - clrCTL (dev); + clrCTL (dev); /* clear control */ + if (lps_unit.flags & UNIT_DIAG) { /* diagnostic mode? */ + clrCMD (dev); /* clear command (jumper W9-A) */ + if (IR & I_HC) /* clear flag too? */ + sim_cancel (&lps_unit); /* prevent FLG/SRQ */ + } } else { /* STC */ - setCMD (dev); /* set ctl, cmd */ - setCTL (dev); - if (lps_unit.flags & UNIT_DIAG) /* diagnostic? */ - sim_activate (&lps_unit, 1); /* loop back */ + setCTL (dev); /* set ctl */ + setCMD (dev); /* set cmd */ + if (lps_unit.flags & UNIT_DIAG) { /* diagnostic? */ + lps_sta = lps_unit.buf; /* loop back data */ + sim_activate (&lps_unit, 2); /* schedule flag */ + } else { /* real lpt, sched */ if (DEBUG_PRS (lps_dev)) fprintf (sim_deb, ">>LPS STC: Character %06o scheduled for line %d, column %d, ", @@ -349,7 +383,6 @@ if (lps_power == LPS_TURNING_ON) { /* printer warmed up? */ } dev = lps_dib.devno; /* get dev no */ if (uptr->flags & UNIT_DIAG) { /* diagnostic? */ - lps_sta = uptr->buf; /* loop back */ clrCMD (dev); /* clear cmd */ setFSR (dev); /* set flag, fbf */ return SCPE_OK; /* done */ @@ -465,15 +498,22 @@ lps_restart (uptr, 0, NULL, NULL); /* restart I/O if hung * return attach_unit (uptr, cptr); } -/* Set printer timing */ +/* Set printer timing + + Realistic timing is factored, depending on CPU model, to account for the + timing method employed by the diagnostic. */ t_stat lps_set_timing (UNIT *uptr, int32 val, char *cptr, void *desc) { -int32 i; +uint32 i, factor = 1; lps_timing = (val != 0); /* determine choice */ +if ((lps_timing == 0) && /* calc speed factor */ + (UNIT_CPU_MODEL != UNIT_1000_E) && + (UNIT_CPU_MODEL != UNIT_1000_F)) + factor = 4; for (i = 0; i < (sizeof (lps_timers) / sizeof (lps_timers[0])); i++) - *lps_timers[i] = lps_times[lps_timing][i]; /* assign times */ + *lps_timers[i] = lps_times[lps_timing][i] / factor; /* assign times */ return SCPE_OK; } diff --git a/HP2100/hp2100_lpt.c b/HP2100/hp2100_lpt.c index 4d24226c..9c17c86a 100644 --- a/HP2100/hp2100_lpt.c +++ b/HP2100/hp2100_lpt.c @@ -1,6 +1,6 @@ /* hp2100_lpt.c: HP 2100 12845B line printer simulator - Copyright (c) 1993-2005, Robert M. Supnik + Copyright (c) 1993-2006, 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 @@ lpt 12845B 2607 line printer + 28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified) 19-Nov-04 JDB Added restart when set online, etc. 29-Sep-04 JDB Added SET OFFLINE/ONLINE, POWEROFF/POWERON Fixed status returns for error conditions @@ -190,6 +191,7 @@ switch (inst) { /* case on opcode */ } break; + case ioCRS: /* control reset (action unverif) */ case ioCTL: /* control clear/set */ if (IR & I_CTL) { /* CLC */ clrCMD (dev); /* clear ctl, cmd */ diff --git a/HP2100/hp2100_ms.c b/HP2100/hp2100_ms.c index cf15e20f..f94d9be2 100644 --- a/HP2100/hp2100_ms.c +++ b/HP2100/hp2100_ms.c @@ -26,6 +26,11 @@ ms 13181A 7970B 800bpi nine track magnetic tape 13183A 7970E 1600bpi nine track magnetic tape + 28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified) + 18-Sep-06 JDB Fixed 2nd CLR after WC causing another write + Improve debug reporting, add debug flags + 14-Sep-06 JDB Removed local BOT flag, now uses sim_tape_bot + 30-Aug-06 JDB Added erase gap support, improved tape lib err reporting 07-Jul-06 JDB Added CAPACITY as alternate for REEL Fixed EOT test for unlimited reel size 16-Feb-06 RMS Revised for new EOT test @@ -90,7 +95,17 @@ #define UST u4 /* unit status */ #define REEL u5 /* tape reel size */ -#define TCAP (300 * 12 * 800) /* 300 ft capacity at 800bpi */ +#define BPI_13181 800 /* 800 bpi for 13181 cntlr */ +#define BPI_13183 1600 /* 1600 bpi for 13183 cntlr */ +#define GAP_13181 48 /* gap is 4.8 inches for 13181 cntlr */ +#define GAP_13183 30 /* gap is 3.0 inches for 13183 cntlr */ +#define TCAP (300 * 12 * 800) /* 300 ft capacity at 800 bpi */ + +/* Debug flags */ + +#define DEB_CMDS (1 << 0) /* command init and compl */ +#define DEB_CPU (1 << 1) /* CPU I/O */ +#define DEB_RWS (1 << 2) /* tape reads, writes, status */ /* Command - msc_fnc */ @@ -106,7 +121,8 @@ #define FNC_REW 00101 /* rewind */ #define FNC_RWS 00105 /* rewind and offline */ #define FNC_WFM 00211 /* write file mark */ -#define FNC_RFF 00223 /* "read file fwd" */ +#define FNC_RFF 00223 /* read file fwd (diag) */ +#define FNC_RRR 00061 /* read record rev (diag) */ #define FNC_CMPL 00400 /* completion state */ #define FNC_V_SEL 9 /* select */ #define FNC_M_SEL 017 @@ -132,14 +148,15 @@ #define STA_TBSY 0001000 /* transport busy (d) */ #define STA_BUSY 0000400 /* ctrl busy */ #define STA_EOF 0000200 /* end of file */ -#define STA_BOT 0000100 /* beg of tape (u) */ +#define STA_BOT 0000100 /* beg of tape (d) */ #define STA_EOT 0000040 /* end of tape (d) */ #define STA_TIM 0000020 /* timing error */ #define STA_REJ 0000010 /* programming error */ #define STA_WLK 0000004 /* write locked (d) */ #define STA_PAR 0000002 /* parity error */ #define STA_LOCAL 0000001 /* local (d) */ -#define STA_DYN (STA_PE|STA_SEL|STA_TBSY|STA_WLK|STA_LOCAL) +#define STA_DYN (STA_PE | STA_SEL | STA_TBSY | STA_BOT | \ + STA_EOT | STA_WLK | STA_LOCAL) extern uint32 PC, SR; extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2]; @@ -151,13 +168,13 @@ int32 ms_timing = 1; /* timing type */ int32 msc_sta = 0; /* status */ int32 msc_buf = 0; /* buffer */ int32 msc_usl = 0; /* unit select */ -int32 msc_1st = 0; +int32 msc_1st = 0; /* first service */ int32 msc_stopioe = 1; /* stop on error */ int32 msd_buf = 0; /* data buffer */ uint8 msxb[DBSIZE] = { 0 }; /* data buffer */ t_mtrlnt ms_ptr = 0, ms_max = 0; /* buffer ptrs */ -/* Hardware timing at 45 IPS 13181 13183 +/* Hardware timing at 45 IPS 13181 13183 (based on 1580 instr/msec) instr msec SCP instr msec SCP -------------------- -------------------- - BOT start delay : btime = 161512 102.22 184 252800 160.00 288 @@ -165,7 +182,7 @@ t_mtrlnt ms_ptr = 0, ms_max = 0; /* buffer ptrs */ - GAP traversal time : gtime = 175553 111.11 200 105333 66.67 120 - IRG traversal time : itime = 24885 15.75 - 27387 17.33 - - rewind initiation time : rtime = 878 0.56 1 878 0.56 1 - - data xfer time / word : xtime = 88 55.56us - 44 27.78us - + - data xfer time / word : xtime = 88 55.56us - 44 27.78us - NOTE: The 13181-60001 Rev. 1629 tape diagnostic fails test 17B subtest 6 with "E116 BYTE TIME SHORT" if the correct data transfer time is used for @@ -201,6 +218,7 @@ t_stat msc_attach (UNIT *uptr, char *cptr); t_stat msc_detach (UNIT *uptr); t_stat msc_online (UNIT *uptr, int32 value, char *cptr, void *desc); t_stat msc_boot (int32 unitno, DEVICE *dptr); +t_stat ms_write_gap (UNIT *uptr); t_stat ms_map_err (UNIT *uptr, t_stat st); t_stat ms_settype (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat ms_showtype (FILE *st, UNIT *uptr, int32 val, void *desc); @@ -209,6 +227,7 @@ t_stat ms_show_timing (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat ms_set_reelsize (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat ms_show_reelsize (FILE *st, UNIT *uptr, int32 val, void *desc); void ms_config_timing (void); +char *ms_cmd_name (uint32 cmd); /* MSD data structures @@ -261,6 +280,7 @@ DEVICE msd_dev = { msc_unit MSC unit list msc_reg MSC register list msc_mod MSC modifier list + msc_deb MSC debug flags */ UNIT msc_unit[] = { @@ -305,7 +325,7 @@ MTAB msc_mod[] = { { UNIT_OFFLINE, UNIT_OFFLINE, "offline", "OFFLINE", NULL }, { UNIT_OFFLINE, 0, "online", "ONLINE", msc_online }, { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, + { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, { MTAB_XTD | MTAB_VUN, 0, "CAPACITY", "CAPACITY", &ms_set_reelsize, &ms_show_reelsize, NULL }, { MTAB_XTD | MTAB_VUN | MTAB_NMO, 1, "REEL", "REEL", @@ -329,12 +349,20 @@ MTAB msc_mod[] = { { 0 } }; +DEBTAB msc_deb[] = { + { "CMDS", DEB_CMDS }, + { "CPU", DEB_CPU }, + { "RWS", DEB_RWS }, + { NULL, 0 } + }; + DEVICE msc_dev = { "MSC", msc_unit, msc_reg, msc_mod, MS_NUMDR, 10, 31, 1, 8, 8, NULL, NULL, &msc_reset, &msc_boot, &msc_attach, &msc_detach, - &msc_dib, DEV_DISABLE | DEV_DEBUG + &msc_dib, DEV_DISABLE | DEV_DEBUG, + 0, msc_deb, NULL, NULL }; /* IO instructions */ @@ -370,6 +398,7 @@ switch (inst) { /* case on opcode */ dat = msd_buf; break; + case ioCRS: /* control reset (action unverif) */ case ioCTL: /* control clear/set */ if (IR & I_CTL) { /* CLC */ clrCTL (devd); /* clr ctl, cmd */ @@ -420,7 +449,7 @@ switch (inst) { /* case on opcode */ break; case ioOTX: /* output */ - if (DEBUG_PRS (msc_dev)) + if (DEBUG_PRI (msc_dev, DEB_CPU)) fprintf (sim_deb, ">>MSC OTx: Command = %06o\n", dat); msc_buf = dat; msc_sta = msc_sta & ~STA_REJ; /* clear reject */ @@ -432,9 +461,11 @@ switch (inst) { /* case on opcode */ if (dat & FNF_CHS) { /* select change */ msc_usl = map_sel[FNC_GETSEL (dat)]; /* is immediate */ uptr = msc_dev.units + msc_usl; + if (DEBUG_PRI (msc_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MSC OTx: Unit %d selected\n", msc_usl); } if (((dat & FNF_MOT) && sim_is_active (uptr)) || - ((dat & FNF_REV) && (uptr->UST & STA_BOT)) || + ((dat & FNF_REV) && sim_tape_bot (uptr)) || ((dat & FNF_WRT) && sim_tape_wrp (uptr))) msc_sta = msc_sta | STA_REJ; /* reject? */ break; @@ -445,30 +476,39 @@ switch (inst) { /* case on opcode */ dat = dat | (msc_sta & ~STA_DYN); /* get card status */ if ((uptr->flags & UNIT_OFFLINE) == 0) { /* online? */ dat = dat | uptr->UST; /* add unit status */ + if (sim_tape_bot (uptr)) /* BOT? */ + dat = dat | STA_BOT; if (sim_is_active (uptr) && /* TBSY unless RWD at BOT */ - !((uptr->FNC & FNF_RWD) && (uptr->UST & STA_BOT))) + !((uptr->FNC & FNF_RWD) && sim_tape_bot (uptr))) dat = dat | STA_TBSY; if (sim_tape_wrp (uptr)) /* write prot? */ dat = dat | STA_WLK; - if (sim_tape_eot (uptr)) + if (sim_tape_eot (uptr)) /* EOT? */ dat = dat | STA_EOT; } else dat = dat | STA_TBSY | STA_LOCAL; if (ms_ctype) dat = dat | STA_PE | /* 13183A? */ - (msc_usl << STA_V_SEL); - if (DEBUG_PRS (msc_dev)) + (msc_usl << STA_V_SEL); + if (DEBUG_PRI (msc_dev, DEB_CPU)) fprintf (sim_deb, ">>MSC LIx: Status = %06o\n", dat); break; + case ioCRS: /* control reset (action unverif) */ case ioCTL: /* control clear/set */ if (IR & I_CTL) { clrCTL (devc); } /* CLC */ else if (!(msc_sta & STA_REJ)) { /* STC, last cmd rejected? */ if ((msc_buf & 0377) == FNC_CLR) { /* clear? */ - for (i = 0; i < MS_NUMDR; i++) { /* loop thru units */ - if (sim_is_active (&msc_unit[i]) && /* write in prog? */ - (msc_unit[i].FNC == FNC_WC) && (ms_ptr > 0)) { + for (i = 0; i < MS_NUMDR; i++) { /* look for write in progr */ + if (sim_is_active (&msc_unit[i]) && /* unit active? */ + (msc_unit[i].FNC == FNC_WC) && /* last cmd write? */ + (ms_ptr > 0)) { /* partial buffer? */ + if (DEBUG_PRI (msc_dev, DEB_RWS)) + fprintf (sim_deb, + ">>MSC STC: Unit %d wrote %d word partial record\n", + i, ms_ptr / 2); if (st = sim_tape_wrrecf (uptr, msxb, ms_ptr | MTR_ERF)) - ms_map_err (uptr, st); + ms_map_err (uptr, st); /* discard any error */ + ms_ptr = 0; /* clear partial */ } if ((msc_unit[i].UST & STA_REW) == 0) sim_cancel (&msc_unit[i]); /* stop if not rew */ @@ -476,34 +516,35 @@ switch (inst) { /* case on opcode */ setCTL (devc); /* set CTL for STC */ setFSR (devc); /* set FLG for completion */ msc_sta = msc_1st = 0; /* clr ctlr status */ - if (DEBUG_PRS (msc_dev)) + if (DEBUG_PRI (msc_dev, DEB_CMDS)) fputs (">>MSC STC: Controller cleared\n", sim_deb); return SCPE_OK; } uptr->FNC = msc_buf & 0377; /* save function */ if (uptr->FNC & FNF_RWD) { /* rewind? */ - if (!(uptr->UST & STA_BOT)) /* not at BOT? */ + if (!sim_tape_bot (uptr)) /* not at BOT? */ uptr->UST = STA_REW; /* set rewinding */ sched_time = msc_rtime; /* set response time */ } else { - if (uptr-> UST & STA_BOT) /* at BOT? */ + if (sim_tape_bot (uptr)) /* at BOT? */ sched_time = msc_btime; /* use BOT start time */ else if ((uptr->FNC == FNC_GAP) || (uptr->FNC == FNC_GFM)) sched_time = msc_gtime; /* use gap traversal time */ else sched_time = 0; if (uptr->FNC != FNC_GAP) sched_time += msc_ctime; /* add base command time */ - if (uptr->FNC & FNF_MOT) /* motion command? */ - uptr->UST = 0; /* clear BOT status */ } if (msc_buf & ~FNC_SEL) { /* NOP for unit sel alone */ sim_activate (uptr, sched_time); /* else schedule op */ - if (DEBUG_PRS (msc_dev)) fprintf (sim_deb, - ">>MSC STC: Unit %d command %03o scheduled, time = %d\n", - msc_usl, uptr->FNC, sched_time); + if (DEBUG_PRI (msc_dev, DEB_CMDS)) + fprintf (sim_deb, + ">>MSC STC: Unit %d command %03o (%s) scheduled, " + "pos = %d, time = %d\n", + msc_usl, uptr->FNC, ms_cmd_name (uptr->FNC), + uptr->pos, sched_time); } - else if (DEBUG_PRS (msc_dev)) + else if (DEBUG_PRI (msc_dev, DEB_CMDS)) fputs (">>MSC STC: Unit select (NOP)\n", sim_deb); msc_sta = STA_BUSY; /* ctrl is busy */ msc_1st = 1; @@ -526,9 +567,17 @@ return dat; /* Unit service If rewind done, reposition to start of tape, set status - else, do operation, set done, interrupt + else, do operation, set done, interrupt. - Can't be write locked, can only write lock detached unit + In addition to decreasing the timing intervals, the FASTTIME option enables + two additional optimizations: WFM for GFM substitution, and BOT gap + elimination. If FASTTIME is selected, gap and file mark (GFM) commands are + processed as WFM (write file mark) commands. That is, the preceding GAP is + not performed. Also, the initial gap that normally precedes the first data + record or EOF mark at the beginning of the tape is omitted. These omissions + result in smaller tape image files. If REALTIME is selected, the gaps are + included. Note that the gaps (and realistic timing) are necessary to pass + the 7970 diagnostics. */ t_stat msc_svc (UNIT *uptr) @@ -552,7 +601,7 @@ switch (uptr->FNC) { /* case on function */ case FNC_RWS: /* rewind offline */ sim_tape_rewind (uptr); /* rewind tape */ uptr->flags = uptr->flags | UNIT_OFFLINE; /* set offline */ - uptr->UST = STA_BOT; /* BOT when online again */ + uptr->UST = 0; /* clear REW status */ break; /* we're done */ case FNC_REW: /* rewind */ @@ -564,19 +613,43 @@ switch (uptr->FNC) { /* case on function */ case FNC_REW | FNC_CMPL: /* complete rewind */ sim_tape_rewind (uptr); /* rewind tape */ - uptr->UST = STA_BOT; /* set BOT status */ + uptr->UST = 0; /* clear REW status */ return SCPE_OK; /* drive is free */ - case FNC_GFM: /* gap file mark */ + case FNC_GFM: /* gap + file mark */ + if (ms_timing == 1) /* fast timing? */ + goto DO_WFM; /* do plain file mark */ + /* else fall into GAP */ + case FNC_GAP: /* erase gap */ + if (DEBUG_PRI (msc_dev, DEB_RWS)) + fprintf (sim_deb, + ">>MSC svc: Unit %d wrote gap\n", + unum); + if ((r = ms_write_gap (uptr)) || /* write tape gap; error? */ + (uptr->FNC != FNC_GFM)) /* not GFM? */ + break; /* bail out now */ + /* else drop into WFM */ case FNC_WFM: /* write file mark */ + if ((ms_timing == 0) && sim_tape_bot (uptr)) { /* realistic timing + BOT? */ + if (DEBUG_PRI (msc_dev, DEB_RWS)) + fprintf (sim_deb, + ">>MSC svc: Unit %d wrote initial gap\n", + unum); + if (st = ms_write_gap (uptr)) { /* write initial gap; error? */ + r = ms_map_err (uptr, st); /* map error */ + break; /* terminate operation */ + } + } + DO_WFM: + if (DEBUG_PRI (msc_dev, DEB_RWS)) + fprintf (sim_deb, + ">>MSC svc: Unit %d wrote file mark\n", + unum); if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ r = ms_map_err (uptr, st); /* map error */ msc_sta = STA_EOF; /* set EOF status */ break; - case FNC_GAP: /* erase gap */ - break; - case FNC_FSR: /* space forward */ if (st = sim_tape_sprecf (uptr, &tbc)) /* space rec fwd, err? */ r = ms_map_err (uptr, st); /* map error */ @@ -606,8 +679,12 @@ switch (uptr->FNC) { /* case on function */ case FNC_RFF: /* diagnostic read */ case FNC_RC: /* read */ if (msc_1st) { /* first svc? */ - msc_1st = ms_ptr = 0; /* clr 1st flop */ + msc_1st = ms_ptr = ms_max = 0; /* clr 1st flop */ st = sim_tape_rdrecf (uptr, msxb, &ms_max, DBSIZE); /* read rec */ + if (DEBUG_PRI (msc_dev, DEB_RWS)) + fprintf (sim_deb, + ">>MSC svc: Unit %d read %d word record\n", + unum, ms_max / 2); if (st == MTSE_RECE) msc_sta = msc_sta | STA_PAR; /* rec in err? */ else if (st != MTSE_OK) { /* other error? */ r = ms_map_err (uptr, st); /* map error */ @@ -619,8 +696,6 @@ switch (uptr->FNC) { /* case on function */ break; /* err, done */ } if (ms_ctype) msc_sta = msc_sta | STA_ODD; /* set ODD for 13183A */ - if (DEBUG_PRS (msc_dev)) fprintf (sim_deb, - ">>MSC svc: Unit %d read %d word record\n", unum, ms_max / 2); } if (CTL (devd) && (ms_ptr < ms_max)) { /* DCH on, more data? */ if (FLG (devd)) msc_sta = msc_sta | STA_TIM | STA_PAR; @@ -638,14 +713,29 @@ switch (uptr->FNC) { /* case on function */ else uptr->FNC |= FNC_CMPL; /* set completion */ return SCPE_OK; + case FNC_RFF | FNC_CMPL: /* diagnostic read completion */ + case FNC_RC | FNC_CMPL: /* read completion */ + break; + case FNC_WC: /* write */ - if (msc_1st) msc_1st = ms_ptr = 0; /* no xfer on first */ + if (msc_1st) { /* first service? */ + msc_1st = ms_ptr = 0; /* no data xfer on first svc */ + if ((ms_timing == 0) && sim_tape_bot (uptr)) { /* realistic timing + BOT? */ + if (DEBUG_PRI (msc_dev, DEB_RWS)) + fprintf (sim_deb, + ">>MSC svc: Unit %d wrote initial gap\n", + unum); + if (st = ms_write_gap (uptr)) { /* write initial gap; error? */ + r = ms_map_err (uptr, st); /* map error */ + break; /* terminate operation */ + } + } + } else { /* not 1st, next char */ if (ms_ptr < DBSIZE) { /* room in buffer? */ msxb[ms_ptr] = msd_buf >> 8; /* store 2 char */ msxb[ms_ptr + 1] = msd_buf & 0377; ms_ptr = ms_ptr + 2; - uptr->UST = 0; } else msc_sta = msc_sta | STA_PAR; } @@ -655,8 +745,10 @@ switch (uptr->FNC) { /* case on function */ return SCPE_OK; } if (ms_ptr) { /* any data? write */ - if (DEBUG_PRS (msc_dev)) fprintf (sim_deb, - ">>MSC svc: Unit %d wrote %d word record\n", unum, ms_ptr / 2); + if (DEBUG_PRI (msc_dev, DEB_RWS)) + fprintf (sim_deb, + ">>MSC svc: Unit %d wrote %d word record\n", + unum, ms_ptr / 2); if (st = sim_tape_wrrecf (uptr, msxb, ms_ptr)) { /* write, err? */ r = ms_map_err (uptr, st); /* map error */ break; @@ -666,31 +758,63 @@ switch (uptr->FNC) { /* case on function */ uptr->FNC |= FNC_CMPL; /* set completion */ return SCPE_OK; - default: /* unknown */ + case FNC_WC | FNC_CMPL: /* write completion */ + break; + + case FNC_RRR: /* not supported */ + default: /* unknown command */ + if (DEBUG_PRI (msc_dev, DEB_CMDS)) + fprintf (sim_deb, + ">>MSC svc: Unit %d command %03o is unknown (NOP)\n", + unum, uptr->FNC); break; } setFSR (devc); /* set cch flg */ msc_sta = msc_sta & ~STA_BUSY; /* update status */ -if (DEBUG_PRS (msc_dev)) fprintf (sim_deb, - ">>MSC svc: Unit %d command %03o complete\n", unum, uptr->FNC & 0377); +if (DEBUG_PRI (msc_dev, DEB_CMDS)) + fprintf (sim_deb, + ">>MSC svc: Unit %d command %03o (%s) complete\n", + unum, uptr->FNC & 0377, ms_cmd_name (uptr->FNC)); return r; } +/* Write an erase gap */ + +t_stat ms_write_gap (UNIT *uptr) +{ +t_stat st; +uint32 gap_len = ms_ctype ? GAP_13183 : GAP_13181; /* establish gap length */ +uint32 tape_bpi = ms_ctype ? BPI_13183 : BPI_13181; /* establish nominal bpi */ + +if (st = sim_tape_wrgap (uptr, gap_len, tape_bpi)) /* write gap */ + return ms_map_err (uptr, st); /* map error if failure */ +else + return SCPE_OK; +} + /* Map tape error status */ t_stat ms_map_err (UNIT *uptr, t_stat st) { int32 unum = uptr - msc_dev.units; /* get unit number */ -if (DEBUG_PRS (msc_dev)) fprintf (sim_deb, - ">>MSC err: Unit %d tape library status = %d\n", unum, st); +if (DEBUG_PRI (msc_dev, DEB_RWS)) + fprintf (sim_deb, + ">>MSC err: Unit %d tape library status = %d\n", + unum, st); switch (st) { case MTSE_FMT: /* illegal fmt */ + msc_sta = msc_sta | STA_REJ; /* reject cmd */ + return SCPE_FMT; /* format error */ + case MTSE_UNATT: /* unattached */ - msc_sta = msc_sta | STA_REJ; /* reject */ + msc_detach (uptr); /* resync status (ignore rtn) */ + msc_sta = msc_sta | STA_REJ; /* reject cmd */ + return SCPE_UNATT; /* unit unattached */ + case MTSE_OK: /* no error */ return SCPE_IERR; /* never get here! */ @@ -712,10 +836,6 @@ switch (st) { msc_sta = msc_sta | STA_PAR; /* error */ break; - case MTSE_BOT: /* reverse into BOT */ - msc_sta = msc_sta | STA_BOT; /* set BOT status */ - break; - case MTSE_WRP: /* write protect */ msc_sta = msc_sta | STA_REJ; /* reject */ break; @@ -745,9 +865,7 @@ for (i = 0; i < MS_NUMDR; i++) { uptr = msc_dev.units + i; sim_tape_reset (uptr); sim_cancel (uptr); - if ((uptr->flags & UNIT_ATT) && sim_tape_bot (uptr)) - uptr->UST = STA_BOT; - else uptr->UST = 0; + uptr->UST = 0; } ms_config_timing (); return SCPE_OK; @@ -760,10 +878,8 @@ t_stat msc_attach (UNIT *uptr, char *cptr) t_stat r; r = sim_tape_attach (uptr, cptr); /* attach unit */ -if (r == SCPE_OK) { +if (r == SCPE_OK) uptr->flags = uptr->flags & ~UNIT_OFFLINE; /* set online */ - uptr->UST = STA_BOT; /* tape starts at BOT */ - } return r; } @@ -771,7 +887,7 @@ return r; t_stat msc_detach (UNIT* uptr) { -uptr->UST = 0; /* update status */ +uptr->UST = 0; /* clear status */ uptr->flags = uptr->flags | UNIT_OFFLINE; /* set offline */ return sim_tape_detach (uptr); /* detach unit */ } @@ -788,7 +904,7 @@ else return SCPE_UNATT; void ms_config_timing (void) { -int32 i, tset; +uint32 i, tset; tset = (ms_timing << 1) | (ms_timing? 0 : ms_ctype); /* select timing set */ for (i = 0; i < (sizeof (timers) / sizeof (timers[0])); i++) @@ -842,12 +958,12 @@ return SCPE_OK; val = 0 -> SET MSCn CAPACITY=n val = 1 -> SET MSCn REEL=n */ - + t_stat ms_set_reelsize (UNIT *uptr, int32 val, char *cptr, void *desc) { int32 reel; t_stat status; - + if (val == 0) { status = sim_tape_set_capac (uptr, val, cptr, desc); if (status == SCPE_OK) uptr->REEL = 0; @@ -858,7 +974,7 @@ if (cptr == NULL) return SCPE_ARG; reel = (int32) get_uint (cptr, 10, 2400, &status); if (status != SCPE_OK) return status; else switch (reel) { - + case 0: uptr->REEL = 0; /* type 0 = unlimited/custom */ break; @@ -887,7 +1003,7 @@ return SCPE_OK; val = 0 -> SHOW MSC or SHOW MSCn or SHOW MSCn CAPACITY val = 1 -> SHOW MSCn REEL */ - + t_stat ms_show_reelsize (FILE *st, UNIT *uptr, int32 val, void *desc) { t_stat status = SCPE_OK; @@ -898,6 +1014,34 @@ if (val == 1) fputc ('\n', st); /* MTAB_NMO omits \n */ return status; } +/* Translate command to mnemonic for debug logging + + The command names and descriptions are taken from the 13181 interface + manual. */ + +char *ms_cmd_name (uint32 cmd) +{ + +switch (cmd & 0377) { + case FNC_WC: return "WCC"; /* Write command */ + case FNC_WFM: return "WFM"; /* Write file mark */ + case FNC_RC: return "RRF"; /* Read record forward */ + case FNC_FSR: return "FSR"; /* Forward space record */ + case FNC_FSF: return "FSF"; /* Forward space file */ + case FNC_GAP: return "GAP"; /* Write gap */ + case FNC_BSR: return "BSR"; /* Backspace record */ + case FNC_BSF: return "BSF"; /* Backspace file */ + case FNC_REW: return "REW"; /* Rewind */ + case FNC_RWS: return "RWO"; /* Rewind off-line */ + case FNC_CLR: return "CLR"; /* Clear controller */ + case FNC_GFM: return "GFM"; /* Gap file mark */ + case FNC_RFF: return "RFF"; /* Read forward until file mark (diag) */ + case FNC_RRR: return "RRR"; /* Read record in reverse (diag) */ + + default: return "???"; /* Unknown command */ + } +} + /* 7970B/7970E bootstrap routine (HP 12992D ROM) */ const uint16 ms_rom[IBL_LNT] = { diff --git a/HP2100/hp2100_mt.c b/HP2100/hp2100_mt.c index de1d31fd..635a5844 100644 --- a/HP2100/hp2100_mt.c +++ b/HP2100/hp2100_mt.c @@ -1,6 +1,6 @@ /* hp2100_mt.c: HP 2100 12559A magnetic tape simulator - Copyright (c) 1993-2004, Robert M. Supnik + Copyright (c) 1993-2006, 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 @@ mt 12559A 3030 nine track magnetic tape + 28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified) 07-Oct-04 JDB Allow enable/disable from either device 14-Aug-04 RMS Modified handling of end of medium (suggested by Dave Bryan) 06-Jul-04 RMS Fixed spurious timing error after CLC (found by Dave Bryan) @@ -150,7 +151,7 @@ REG mtd_reg[] = { MTAB mtd_mod[] = { { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, + { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT", &sim_tape_set_fmt, &sim_tape_show_fmt, NULL }, { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", @@ -243,6 +244,7 @@ switch (inst) { /* case on opcode */ dat = mtc_unit.buf; break; + case ioCRS: /* control reset (action unverif) */ case ioCTL: /* control clear/set */ if (IR & I_CTL) mtc_dtf = 0; /* CLC: clr xfer flop */ break; @@ -257,7 +259,8 @@ return dat; int32 mtcio (int32 inst, int32 IR, int32 dat) { -int32 i, devc, devd, valid; +uint32 i; +int32 devc, devd, valid; t_stat st; devc = IR & I_DEVMASK; /* get device no */ @@ -299,7 +302,7 @@ switch (inst) { /* case on opcode */ if (dat == mtc_cmd[i]) valid = 1; if (!valid || sim_is_active (&mtc_unit) || /* is cmd valid? */ ((mtc_sta & STA_BOT) && (dat == FNC_BSR)) || - (sim_tape_wrp (&mtc_unit) && + (sim_tape_wrp (&mtc_unit) && ((dat == FNC_WC) || (dat == FNC_GAP) || (dat == FNC_WFM)))) mtc_sta = mtc_sta | STA_REJ; else { @@ -322,9 +325,10 @@ switch (inst) { /* case on opcode */ if (sim_is_active (&mtc_unit)) dat = dat | STA_BUSY; if (sim_tape_wrp (&mtc_unit)) dat = dat | STA_WLK; } - else dat = dat | STA_BUSY | STA_LOCAL; + else dat = dat | STA_BUSY | STA_LOCAL; break; + case ioCRS: /* control reset (action unverif) */ case ioCTL: /* control clear/set */ if (IR & I_CTL) { clrCTL (devc); } /* CLC */ else { setCTL (devc); } /* STC */ diff --git a/HP2100/hp2100_mux.c b/HP2100/hp2100_mux.c index 3573f910..9f15d1ea 100644 --- a/HP2100/hp2100_mux.c +++ b/HP2100/hp2100_mux.c @@ -1,6 +1,6 @@ /* hp2100_mux.c: HP 2100 12920A terminal multiplexor simulator - Copyright (c) 2002-2005, Robert M Supnik + Copyright (c) 2002-2006, 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 @@ mux,muxl,muxc 12920A terminal multiplexor + 28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified) + 02-Jun-06 JDB Fixed compiler warning for mux_ldsc init 22-Nov-05 RMS Revised for new terminal processing routines 29-Jun-05 RMS Added SET MUXLn DISCONNECT 07-Oct-04 JDB Allow enable/disable from any device @@ -157,7 +159,7 @@ uint32 muxu_obuf = 0; /* upr out: chan */ uint32 muxc_chan = 0; /* ctrl chan */ uint32 muxc_scan = 0; /* ctrl scan */ -TMLN mux_ldsc[MUX_LINES] = { 0 }; /* line descriptors */ +TMLN mux_ldsc[MUX_LINES] = { { 0 } }; /* line descriptors */ TMXR mux_desc = { MUX_LINES, 0, 0, mux_ldsc }; /* mux descriptor */ DEVICE muxl_dev, muxu_dev, muxc_dev; @@ -393,6 +395,7 @@ switch (inst) { /* case on opcode */ dat = muxl_ibuf; break; + case ioCRS: /* control reset (action unverif) */ case ioCTL: /* control clear/set */ if (IR & I_CTL) { clrCTL (dev); } /* CLC */ else { /* STC */ @@ -503,6 +506,7 @@ switch (inst) { /* case on opcode */ muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* incr channel */ break; + case ioCRS: /* control reset (action unverif) */ case ioCTL: /* ctrl clear/set */ if (IR & I_CTL) { clrCTL (dev); } /* CLC */ else { setCTL (dev); } /* STC */ @@ -538,7 +542,7 @@ if (ln >= 0) { /* got one? */ (muxc_ota[ln] & DTR)) /* DTR? */ muxc_lia[ln] = muxc_lia[ln] | CDET; /* set cdet */ muxc_lia[ln] = muxc_lia[ln] | DSR; /* set dsr */ - mux_ldsc[ln].rcve = 1; /* rcv enabled */ + mux_ldsc[ln].rcve = 1; /* rcv enabled */ } tmxr_poll_rx (&mux_desc); /* poll for input */ for (ln = 0; ln < MUX_LINES; ln++) { /* loop thru lines */ @@ -781,7 +785,7 @@ int32 i, t; for (i = t = 0; i < MUX_LINES; i++) t = t + (mux_ldsc[i].conn != 0); if (t) { for (i = 0; i < MUX_LINES; i++) { - if (mux_ldsc[i].conn) { + if (mux_ldsc[i].conn) { if (val) tmxr_fconns (st, &mux_ldsc[i], i); else tmxr_fstats (st, &mux_ldsc[i], i); } diff --git a/HP2100/hp2100_stddev.c b/HP2100/hp2100_stddev.c index a1e5fe90..5e03fac1 100644 --- a/HP2100/hp2100_stddev.c +++ b/HP2100/hp2100_stddev.c @@ -1,6 +1,6 @@ /* hp2100_stddev.c: HP2100 standard devices simulator - Copyright (c) 1993-2005, Robert M. Supnik + Copyright (c) 1993-2006, 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"), @@ -28,6 +28,7 @@ tty 12531C buffered teleprinter interface clk 12539C time base generator + 28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified) 22-Nov-05 RMS Revised for new terminal processing routines 13-Sep-04 JDB Added paper tape loop mode, DIAG/READER modifiers to PTR Added PV_LEFT to PTR TRLLIM register @@ -383,6 +384,7 @@ switch (inst) { /* case on opcode */ dat = ptr_unit.buf; break; + case ioCRS: /* control reset (action unverif) */ case ioCTL: /* control clear/set */ if (IR & I_CTL) { /* CLC */ clrCMD (dev); /* clear cmd, ctl */ @@ -420,7 +422,7 @@ while ((temp = getc (ptr_unit.fileref)) == EOF) { /* read byte, error? */ ptr_unit.pos = 0; } else { - if (ptr_trlcnt >= ptr_trllim) { /* added all trailer? */ + if (ptr_trlcnt >= ptr_trllim) { /* added all trailer? */ if (ptr_stopioe) { /* stop on error? */ printf ("PTR end of file\n"); return SCPE_IOERR; @@ -467,7 +469,7 @@ return SCPE_OK; const uint16 ptr_rom[IBL_LNT] = { 0107700, /*ST CLC 0,C ; intr off */ - 0002401, /* CLA,RSS ; skip in */ + 0002401, /* CLA,RSS ; skip in */ 0063756, /*CN LDA M11 ; feed frame */ 0006700, /* CLB,CCE ; set E to rd byte */ 0017742, /* JSB READ ; get #char */ @@ -560,6 +562,7 @@ switch (inst) { /* case on opcode */ ptp_unit.buf = dat; break; + case ioCRS: /* control reset (action unverif) */ case ioCTL: /* control clear/set */ if (IR & I_CTL) { /* CLC */ clrCMD (dev); /* clear cmd, ctl */ @@ -645,6 +648,7 @@ switch (inst) { /* case on opcode */ tty_buf = dat & 0377; break; + case ioCRS: /* control reset (action unverif) */ case ioCTL: /* control clear/set */ if (IR & I_CTL) { clrCTL (dev); } /* CLC */ else { /* STC */ @@ -664,27 +668,27 @@ return dat; /* Unit service routines. Note from Dave Bryan: - Referring to the 12531C schematic, the terminal input enters on pin X - ("DATA FROM EIA COMPATIBLE DEVICE"). The signal passes through four - transistor inversions (Q8, Q1, Q2, and Q3) to appear on pin 12 of NAND gate - U104C. If the flag flip-flop is not set, the terminal input passes to the - (inverted) output of U104C and thence to the D input of the first of the - flip-flops forming the data register. + Referring to the 12531C schematic, the terminal input enters on pin X + ("DATA FROM EIA COMPATIBLE DEVICE"). The signal passes through four + transistor inversions (Q8, Q1, Q2, and Q3) to appear on pin 12 of NAND gate + U104C. If the flag flip-flop is not set, the terminal input passes to the + (inverted) output of U104C and thence to the D input of the first of the + flip-flops forming the data register. - In the idle condition (no key pressed), the terminal input line is marking - (voltage negative), so in passing through a total of five inversions, a - logic one is presented at the serial input of the data register. During an - output operation, the register is parallel loaded and serially shifted, - sending the output data through the register to the device and -- this is - the crux -- filling the register with logic ones from U104C. + In the idle condition (no key pressed), the terminal input line is marking + (voltage negative), so in passing through a total of five inversions, a + logic one is presented at the serial input of the data register. During an + output operation, the register is parallel loaded and serially shifted, + sending the output data through the register to the device and -- this is + the crux -- filling the register with logic ones from U104C. - At the end of the output operation, the card flag is set, an interrupt - occurs, and the RTE driver is entered. The driver then does an LIA SC to - read the contents of the data register. If no key has been pressed during - the output operation, the register will read as all ones (octal 377). If, - however, any key was struck, at least one zero bit will be present. If the - register value doesn't equal 377, the driver sets the system "operator - attention" flag, which will cause RTE to output the asterisk and initiate a + At the end of the output operation, the card flag is set, an interrupt + occurs, and the RTE driver is entered. The driver then does an LIA SC to + read the contents of the data register. If no key has been pressed during + the output operation, the register will read as all ones (octal 377). If, + however, any key was struck, at least one zero bit will be present. If the + register value doesn't equal 377, the driver sets the system "operator + attention" flag, which will cause RTE to output the asterisk and initiate a terminal read when the current output line is completed. */ t_stat tti_svc (UNIT *uptr) @@ -783,9 +787,9 @@ t_stat tty_set_opt (UNIT *uptr, int32 val, char *cptr, void *desc) int32 u = uptr - tty_dev.units; if (u > TTO) return SCPE_NOFNC; -tty_unit[TTO].flags = (tty_unit[TTO].flags & ~TT_MODE) | val; -if (val == TT_MODE_7P) val = TT_MODE_7B; -tty_unit[TTI].flags = (tty_unit[TTI].flags & ~TT_MODE) | val; +if ((u == TTI) && (val == TT_MODE_7P)) + val = TT_MODE_7B; +tty_unit[u].flags = (tty_unit[u].flags & ~TT_MODE) | val; return SCPE_OK; } @@ -832,6 +836,7 @@ switch (inst) { /* case on opcode */ clrCTL (dev); /* clear control */ break; + case ioCRS: /* control reset (action unverif) */ case ioCTL: /* control clear/set */ if (IR & I_CTL) { /* CLC */ clrCTL (dev); /* turn off clock */ diff --git a/HP2100/hp2100_sys.c b/HP2100/hp2100_sys.c index 3f331659..7ea5fe51 100644 --- a/HP2100/hp2100_sys.c +++ b/HP2100/hp2100_sys.c @@ -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. + 21-Dec-06 JDB Added "fwanxm" external for sim_load check 19-Nov-04 JDB Added STOP_OFFLINE, STOP_PWROFF messages 25-Sep-04 JDB Added memory protect device Fixed display of CCA/CCB/CCE instructions @@ -61,6 +62,7 @@ extern DEVICE muxl_dev, muxu_dev, muxc_dev; extern DEVICE ipli_dev, iplo_dev; extern REG cpu_reg[]; extern uint16 *M; +extern uint32 fwanxm; /* SCP data structures and interface routines @@ -127,7 +129,7 @@ const char *sim_stop_messages[] = { word count-1 checksum - The checksum includes the origin but not the count. + The checksum includes the origin but not the count. */ int32 fgetw (FILE *fileref) @@ -325,7 +327,7 @@ static const int32 vtab[] = { *of = output stream addr = current PC *val = pointer to data - *uptr = pointer to unit + *uptr = pointer to unit sw = switches Outputs: return = status code @@ -386,7 +388,7 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ cm = TRUE; fprintf (of, "%s", stab[i]); } - } + } if (!cm) return SCPE_ARG; /* nothing decoded? */ break; @@ -618,7 +620,7 @@ for (cptr = get_glyph (iptr, gbuf, ','); gbuf[0] != 0; for (i = 0; stab[i] != NULL; i++) { /* find subopcode */ if ((strcmp (gbuf, stab[i]) == 0) && ((i >= 16) || (!clef && ((val[0] & 001710) == 0)))) break; - } + } if (stab[i] == NULL) return SCPE_ARG; if (tbits & mtab[i] & (I_AB | I_ASKP) & (vtab[i] ^ val[0])) return SCPE_ARG; diff --git a/I1401/i1401_cpu.c b/I1401/i1401_cpu.c index b67df249..69ba5721 100644 --- a/I1401/i1401_cpu.c +++ b/I1401/i1401_cpu.c @@ -1478,7 +1478,7 @@ CHECK_LENGTH: M[BS + 3] = (M[BS + 3] & WM) | store_addr_u (t); M[BS + 2] = (M[BS + 2] & (WM + ZONE)) | store_addr_t (t); M[BS + 1] = (M[BS + 1] & WM) | store_addr_h (t); - if (((a % 4000) + (b % 4000)) >= 4000) BS = BS + 2; /* carry? */ + if (((a % 4000) + (b % 4000)) >= 4000) BS = BS + 2; /* carry? */ break; /* Store address instructions A-check B-check @@ -1505,7 +1505,7 @@ CHECK_LENGTH: /* NOP - no validity checking, all instructions length ok */ - case OP_NOP: /* nop */ + case OP_NOP: /* nop */ break; /* HALT - unless length = 4 (branch), no validity checking; all lengths ok */ @@ -1569,7 +1569,8 @@ int32 a, b, c, r; c = 0; /* init carry */ do { - a = M[ap]; b = M[bp]; /* get operands */ + a = M[ap]; /* get operands */ + b = M[bp]; r = bcd_to_bin[b & DIGIT] + /* sum digits + c */ bcd_to_bin[a & DIGIT] + c; c = (r >= 10); /* set carry out */ @@ -1671,8 +1672,10 @@ for (i = 0; i < 64; i++) { /* clr indicators */ if ((i < IN_SSB) || (i > IN_SSG)) ind[i] = 0; /* except SSB-SSG */ } ind[IN_UNC] = 1; /* ind[0] always on */ -AS = 0; as_err = 1; /* clear AS */ -BS = 0; bs_err = 1; /* clear BS */ +AS = 0; /* clear AS */ +BS = 0; /* clear BS * +as_err = 1; +bs_err = 1;/ D = 0; /* clear D */ hb_pend = 0; /* no halt br */ pcq_r = find_reg ("ISQ", NULL, dptr); diff --git a/I1401/i1401_sys.c b/I1401/i1401_sys.c index f0389087..cd4c19da 100644 --- a/I1401/i1401_sys.c +++ b/I1401/i1401_sys.c @@ -134,7 +134,7 @@ char cbuf[CBUFSIZE], gbuf[CBUFSIZE]; if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; ptr = 0; -for ( ; (cptr = fgets (cbuf, CBUFSIZE, fileref)) != NULL; ) { /* until eof */ +for ( ; (cptr = fgets (cbuf, CBUFSIZE, fileref)) != NULL; ) { /* until eof */ mask = 0; if (*cptr == '(') { /* repeat count? */ cptr = get_glyph (cptr + 1, gbuf, ')'); /* get 1st field */ diff --git a/I1620/i1620_sys.c b/I1620/i1620_sys.c index 20a5d56b..3c62370e 100644 --- a/I1620/i1620_sys.c +++ b/I1620/i1620_sys.c @@ -129,7 +129,7 @@ char cbuf[CBUFSIZE], gbuf[CBUFSIZE]; if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; ptr = 0; -for ( ; (cptr = fgets (cbuf, CBUFSIZE, fileref)) != NULL; ) { /* until eof */ +for ( ; (cptr = fgets (cbuf, CBUFSIZE, fileref)) != NULL; ) { /* until eof */ mask = 0; if (*cptr == '(') { /* repeat count? */ cptr = get_glyph (cptr + 1, gbuf, ')'); /* get 1st field */ diff --git a/I7094/i7094_cpu.c b/I7094/i7094_cpu.c index 9797444a..790ace18 100644 --- a/I7094/i7094_cpu.c +++ b/I7094/i7094_cpu.c @@ -25,6 +25,8 @@ cpu 7094 central processor + 29-Oct-06 RMS Added additional expanded core instructions + 17-Oct-06 RMS Fixed the fix in halt IO wait loop 16-Jun-06 RMS Fixed bug in halt IO wait loop The register state for the 7094 is: @@ -1576,11 +1578,22 @@ while (reason == SCPE_OK) { /* loop until error */ reason = op_mse (ea); break; - case 01761: /* (CTSS) SEA, SEB */ + case 01761: /* (CTSS) ext core */ if (prot_trap (0)) break; /* user mode? */ - if (ea == 041) data_base = 0; - else if (ea == 042) data_base = BCORE_BASE; - else if (stop_illop) reason = STOP_ILLEG; + if (ea == 041) /* SEA? */ + data_base = 0; + else if (ea == 042) /* SEB? */ + data_base = BCORE_BASE; + else if (ea == 043) { /* IFT? */ + if (inst_base == 0) + PC = (PC + 1) & eamask; + } + else if (ea == 044) { /* EFT? */ + if (data_base == 0) + PC = (PC + 1) & eamask; + } + else if (stop_illop) + reason = STOP_ILLEG; break; case 01763: /* LGL */ @@ -1775,7 +1788,7 @@ while (reason == SCPE_OK) { /* loop until error */ if (r = sim_process_event ()) return r; /* process events */ chtr_pend = chtr_eval (NULL); /* eval chan traps */ while (ch_req) { /* until no ch req */ - for (j = 0; i < NUM_CHAN; j++) { /* loop thru channels */ + for (j = 0; j < NUM_CHAN; j++) { /* loop thru channels */ if (ch_req & REQ_CH (j)) { /* channel request? */ if (r = ch_proc (j)) return r; } diff --git a/I7094/i7094_sys.c b/I7094/i7094_sys.c index 652e15dc..ae473a49 100644 --- a/I7094/i7094_sys.c +++ b/I7094/i7094_sys.c @@ -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. + 29-Oct-06 RMS Added additional expanded core instructions 08-Jun-06 RMS Added Dave Pitts' binary loader */ @@ -362,6 +363,7 @@ static const char *opcode[] = { "TIA", "TIB", "LRI", "LPI", "SEA", "SEB", + "IFT", "EFT", "IOCD", "IOCDN", "TCH", "IORP", "IORPN", @@ -523,6 +525,7 @@ static const t_uint64 opc_v[] = { 0010100000000+I_MXN, 0410100000000+I_MXN, 0056200000000+I_MXN, 0456400000000+I_MXN, 0476100000041+I_SNS, 0476100000042+I_SNS, + 0476100000043+I_SNS, 0476100000044+I_SNS, 01000000000000+I_IOX, 01000000200000+I_IOX, 01100000000000+I_TCH, 01200000000000+I_IOX, 01200000200000+I_IOX, diff --git a/Ibm1130/dmsr2v12slet.h b/Ibm1130/dmsr2v12slet.h index 326baa06..7d00676b 100644 --- a/Ibm1130/dmsr2v12slet.h +++ b/Ibm1130/dmsr2v12slet.h @@ -1,4 +1,4 @@ -// DMS R2V12 SLET without RPG, for debugging only +/* DMS R2V12 SLET without RPG, for debugging only */ 0x0001, 0x7c50, 0x032f, 0x0008, 0x0002, 0x11de, 0x05a2, 0x000b, diff --git a/Ibm1130/ibm1130_conin.h b/Ibm1130/ibm1130_conin.h index 108e4917..a142e865 100644 --- a/Ibm1130/ibm1130_conin.h +++ b/Ibm1130/ibm1130_conin.h @@ -9,15 +9,17 @@ * Mail to sim@ibm1130.org */ -// 03 ctrl-C => Program stop (not handled here) -// 05 ctrl-E => Simulator stop (not handled here) -// 08 ctrl-H => Backspace -// 0D ctrl-M (Enter) => EOF -// 11 ctrl-Q => Interrupt request (not handled here) -// 12 ctrl-R => "cent" (R because that's where cent is on the 1130 keyboard) -// 15 ctrl-U => Erase Field -// 7E ~ => "not" -// FF Del => Backspace again +/* + * 03 ctrl-C => Program stop (not handled here) + * 05 ctrl-E => Simulator stop (not handled here) + * 08 ctrl-H => Backspace + * 0D ctrl-M (Enter) => EOF + * 11 ctrl-Q => Interrupt request (not handled here) + * 12 ctrl-R => "cent" (R because that's where cent is on the 1130 keyboard) + * 15 ctrl-U => Erase Field + * 7E ~ => "not" + * FF Del => Backspace again + */ static uint16 ascii_to_conin[] = /* ASCII to ((hollerith << 4) | special key flags) */ { diff --git a/Ibm1130/ibm1130_cpu.c b/Ibm1130/ibm1130_cpu.c index 13d7f11e..1db5600f 100644 --- a/Ibm1130/ibm1130_cpu.c +++ b/Ibm1130/ibm1130_cpu.c @@ -20,6 +20,21 @@ 24-Nov-03 BLK Fixed carry bit error in subtract and subtract double, found by Bob Flanders 20-Oct-04 BLK Changed "(unsigned int32)" to "(uint32)" to accomodate improved definitions of simh types Also commented out my echo command as it's now a standard simh command + 27-Nov-05 BLK Added Arithmetic Factor Register support per Carl Claunch (GUI only) + 06-Dec-06 BLK Moved CGI stuff out of ibm1130_cpu.c + +>> To do: verify actual operands stored in ARF, need to get this from state diagrams in the schematic set + Also: determine how many bits are actually stored in the IAR in a real 1130, by forcing wraparound + and storing the IAR. + + IBM 1800 support is just beginning. Mode set is done (SET CPU 1800 or SET CPU 1130). + Index registers are handled (1800 has real registers, 1130 uses core locations 1, 2 and 3 -- + but does the 1800 make its hardware index registers appear in the address space?) + Need to add: memory protect feature, more interrupt levels, GUI mods, IO device mods, timers, watchdog. + Memory protect was interesting -- they borrowed one of the two parity bits. XIO(0) on 1800 is used for + interval timers, console data switches, console sense/program select/CE switches, interrupt mask register, + programmed interrupt, console interrupt and operations monitor (watchdog) + very interesting stuff. The register state for the IBM 1130 CPU is: @@ -38,6 +53,7 @@ WRU simulator-break character IntRun Int Run flag (causes level 5 interrupt after every instruction) ILSW0..5 interrupt level status words + XR1, 2, 3 for IBM 1800 only, index registers 1, 2, and 3 The SAR (storage address register) and SBR (storage buffer register) are updated but not saved in the CPU state; they matter only to the GUI. @@ -113,7 +129,7 @@ ibm1130_defs.h add interrupt request definitions ibm1130_cpu.c add XIO command linkages - ibm1130_sys.c add to sim_devices + ibm1130_sys.c add to sim_devices array */ /* ------------------------------------------------------------------------ @@ -128,19 +144,20 @@ #define UPDATE_BY_TIMER #define ENABLE_BACKTRACE -#define CGI_SUPPORT -// #define USE_MY_ECHO_CMD /* simh now has echo command built in */ +/* #define USE_MY_ECHO_CMD */ /* simh now has echo command built in */ +#define ENABLE_1800_SUPPORT /* define to enable support for 1800 CPU simulation mode */ static void cgi_start(void); static void cgi_stop(t_stat reason); +static int simh_status_to_stopcode (int status); -// hook pointers from scp.c +/* hook pointers from scp.c */ void (*sim_vm_init) (void) = &sim_init; extern char* (*sim_vm_read) (char *ptr, int32 size, FILE *stream); extern void (*sim_vm_post) (t_bool from_scp); extern CTAB *sim_vm_cmd; -// space to store extra simulator-specific commands +/* space to store extra simulator-specific commands */ #define MAX_EXTRA_COMMANDS 10 CTAB x_cmds[MAX_EXTRA_COMMANDS]; @@ -159,12 +176,14 @@ CTAB x_cmds[MAX_EXTRA_COMMANDS]; uint16 M[MAXMEMSIZE]; /* core memory, up to 32Kwords (note: don't even think about trying 64K) */ uint16 ILSW[6] = {0,0,0,0,0,0}; /* interrupt level status words */ +uint16 XR[3] = {0,0,0}; /* IBM 1800 index registers */ int32 IAR; /* instruction address register */ int32 prev_IAR; /* instruction address register at start of current instruction */ int32 SAR, SBR; /* storage address/buffer registers */ int32 OP, TAG, CCC; /* instruction decoded pieces */ int32 CES; /* console entry switches */ int32 ACC, EXT; /* accumulator and extension */ +int32 ARF; /* arithmetic factor, a non-addressable internal CPU register */ int32 RUNMODE; /* processor run/step mode */ int32 ipl = -1; /* current interrupt level (-1 = not handling irq) */ int32 iplpending = 0; /* interrupted IPL's */ @@ -175,13 +194,15 @@ int32 wait_lamp = TRUE; /* alternate indicator to light the wait lamp on the int32 int_req = 0; /* sum of interrupt request levels active */ int32 int_lamps = 0; /* accumulated version of int_req - gives lamp persistence */ int32 int_mask; /* current active interrupt mask (ipl sensitive) */ -int32 mem_mask; +int32 mem_mask; /* mask for memory address bits based on current memory size */ int32 cpu_dsw = 0; /* CPU device status word */ int32 ibkpt_addr = -1; /* breakpoint addr */ int32 sim_gui = TRUE; /* enable gui */ t_bool running = FALSE; /* TRUE if CPU is running */ t_bool power = TRUE; /* TRUE if CPU power is on */ t_bool cgi = FALSE; /* TRUE if we are running as a CGI program */ +t_bool cgiwritable = FALSE; /* TRUE if we can write the disk images back to the image file in CGI mode */ +t_bool is_1800 = FALSE; /* TRUE if we are simulating an IBM 1800 processor */ t_stat reason; /* CPU execution loop control */ static int32 int_masks[6] = { @@ -197,6 +218,7 @@ t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_reset (DEVICE *dptr); t_stat cpu_svc (UNIT *uptr); t_stat cpu_set_size (UNIT *uptr, int32 value, char *cptr, void *desc); +t_stat cpu_set_type (UNIT *uptr, int32 value, char *cptr, void *desc); void calc_ints (void); extern t_stat ts_wr (int32 data, int32 addr, int32 access); @@ -215,10 +237,15 @@ extern int32 sim_switches; #define show_backtrace(ntrace) #endif +#ifdef GUI_SUPPORT +# define ARFSET(v) ARF = (v) & 0xFFFF /* set Arithmetic Factor Register (used for display purposes only) */ +#else +# define ARFSET(v) /* without GUI, no need for setting ARF */ +#endif + static void init_console_window (void); static void destroy_console_window (void); static t_stat view_cmd (int flag, char *cptr); -static t_stat cgi_cmd (int flag, char *cptr); static t_stat cpu_attach (UNIT *uptr, char *cptr); static t_bool bsctest (int32 DSPLC, t_bool reset_V); static void exit_irq (void); @@ -230,8 +257,14 @@ static void trace_instruction (void); * cpu_unit CPU unit descriptor * cpu_reg CPU register list * cpu_mod CPU modifier list + * + * The CPU is attachable; attaching a file to it write a log of instructions + * and registers * ------------------------------------------------------------------------ */ +#define UNIT_MSIZE (1 << (UNIT_V_UF + 7)) /* flag for memory size setting */ +#define UNIT_1800 (1 << (UNIT_V_UF + 0)) /* flag for 1800 mode */ + UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX | UNIT_BINK | UNIT_ATTABLE | UNIT_SEQ, INIMEMSIZE) }; REG cpu_reg[] = { @@ -257,24 +290,42 @@ REG cpu_reg[] = { { HRDATA (ILSW4, ILSW[4], 32), REG_RO }, { HRDATA (ILSW5, ILSW[5], 32), REG_RO }, +#ifdef ENABLE_1800_SUPPORT + { HRDATA (IS_1800, is_1800, 32), REG_RO|REG_HIDDEN}, /* is_1800 flag is part of state, but hidden */ + { HRDATA (XR1, XR[0], 16), REG_RO|REG_HIDDEN}, /* index registers are unhidden if CPU set to 1800 mode */ + { HRDATA (XR2, XR[1], 16), REG_RO|REG_HIDDEN}, + { HRDATA (XR3, XR[2], 16), REG_RO|REG_HIDDEN}, +#endif + + { HRDATA (ARF, ARF, 32) }, { NULL} }; MTAB cpu_mod[] = { - { UNIT_MSIZE, 4096, NULL, "4KW", &cpu_set_size}, - { UNIT_MSIZE, 8192, NULL, "8KW", &cpu_set_size}, - { UNIT_MSIZE, 16384, NULL, "16KW", &cpu_set_size}, - { UNIT_MSIZE, 32768, NULL, "32KW", &cpu_set_size}, + { UNIT_MSIZE, 4096, NULL, "4KW", &cpu_set_size}, + { UNIT_MSIZE, 8192, NULL, "8KW", &cpu_set_size}, + { UNIT_MSIZE, 16384, NULL, "16KW", &cpu_set_size}, + { UNIT_MSIZE, 32768, NULL, "32KW", &cpu_set_size}, +#ifdef ENABLE_1800_SUPPORT + { UNIT_1800, 0, "1130", "1130", &cpu_set_type}, + { UNIT_1800, UNIT_1800, "1800", "1800", &cpu_set_type}, +#endif { 0 } }; DEVICE cpu_dev = { "CPU", &cpu_unit, cpu_reg, cpu_mod, 1, 16, 16, 1, 16, 16, &cpu_ex, &cpu_dep, &cpu_reset, - NULL, cpu_attach, NULL}; // attaching to CPU creates cpu log file + NULL, cpu_attach, NULL}; /* attaching to CPU creates cpu log file */ /* ------------------------------------------------------------------------ - Memory read/write -- save SAR and SBR on the way in and out + * Memory read/write -- save SAR and SBR on the way in and out + * + * (It can be helpful to set breakpoints on a = 1, 2, or 3 in these routines + * to detect attempts to read/set index registers using normal memory addessing. + * APL\1130 does this in some places, I think these are why it had to be modified + * to run on the 1800. Of course not all read/write to 1, 2 or implies an attempt + * to read/set and index register -- they could using the address in the normal way). * ------------------------------------------------------------------------ */ int32 ReadW (int32 a) @@ -291,6 +342,37 @@ void WriteW (int32 a, int32 d) M[a & mem_mask] = (int16) d; } +/* ------------------------------------------------------------------------ + * read and write index registers. On the 1130, they're in core addresses 1, 2, 3. + * on the 1800, they're separate registers + * ------------------------------------------------------------------------ */ + +static uint16 ReadIndex (int32 tag) +{ +#ifdef ENABLE_1800_SUPPORT + if (is_1800) + return XR[tag-1]; /* 1800: fetch from register */ +#endif + + SAR = tag; /* 1130: ordinary read from memory (like ReadW) */ + SBR = (int32) M[(tag) & mem_mask]; + return SBR; +} + +static void WriteIndex (int32 tag, int32 d) +{ +#ifdef ENABLE_1800_SUPPORT + if (is_1800) { + XR[tag-1] = d; /* 1800: store in register */ + return; + } +#endif + + SAR = tag; /* 1130: ordinary write to memory (same as WriteW) */ + SBR = d; + M[tag & mem_mask] = (int16) d; +} + /* ------------------------------------------------------------------------ * upcase - force a string to uppercase (ASCII) * ------------------------------------------------------------------------ */ @@ -333,7 +415,7 @@ void calc_ints (void) register int i; register int32 newbits = 0; - GUI_BEGIN_CRITICAL_SECTION // using critical section here so we don't mislead the GUI thread + GUI_BEGIN_CRITICAL_SECTION /* using critical section here so we don't mislead the GUI thread */ for (i = 6; --i >= 0; ) { newbits >>= 1; @@ -373,7 +455,7 @@ static char *xio_devs[] = { "sys7", "d?", "e?", "f?", "10?", "dsk1", "dsk2", "dsk3", "dsk4", "dsk5", "dsk6", "dsk7+", - "18?", "2250disp", "1a?", "1b", + "18?", "2250disp", "2741attachment", "1b", "1c?", "1d?", "1e?", "1f?" }; @@ -393,10 +475,8 @@ t_stat sim_instr (void) static long ninstr = 0; static char *intlabel[] = {"INT0","INT1","INT2","INT3","INT4","INT5"}; -#ifdef CGI_SUPPORT - if (cgi) + if (cgi) /* give CGI hook function a chance to do something */ cgi_start(); -#endif if (running) /* this is definitely not reentrant */ return -1; @@ -431,14 +511,15 @@ t_stat sim_instr (void) } #else update_gui(FALSE); -#endif // ifdef UPDATE_INTERVAL -#endif // ifndef UPDATE_BY_TIMER -#endif // ifdef GUI_SUPPORT +#endif /* ifdef UPDATE_INTERVAL */ +#endif /* ifndef UPDATE_BY_TIMER */ +#endif /* ifdef GUI_SUPPORT */ if (sim_interval <= 0) { /* any events timed out? */ if (sim_clock_queue != NULL) { if ((status = sim_process_event()) != 0) - reason = status; + reason = simh_status_to_stopcode(status); + calc_ints(); continue; } @@ -477,8 +558,8 @@ t_stat sim_instr (void) if (sim_qcount() <= (cgi ? 0 : 1)) { /* one routine queued? we're waiting for keyboard only */ if (keyboard_is_busy()) { /* we are actually waiting for a keystroke */ - if ((status = sim_process_event()) != 0) /* get it with wait_state still set */ - reason = status; + if ((status = sim_process_event()) != SCPE_OK) /* get it with wait_state still set */ + reason = simh_status_to_stopcode(status); } else { /* CPU is not expecting a keystroke (keyboard interrupt) */ if (wait_state == WAIT_OP) @@ -519,7 +600,7 @@ t_stat sim_instr (void) if (TAG) TAG >>= 8; - // here I compute the usual effective address on the assumption that the instruction will need it. Some don't. + /* here I compute the usual effective address on the assumption that the instruction will need it. Some don't. */ if (F) { /* long instruction, ASSUME it's valid (have to decrement IAR if not) */ INDIR = IR & 0x0080; /* indirect bit */ @@ -532,7 +613,7 @@ t_stat sim_instr (void) eaddr = word2; /* assume standard addressing & compute effective address */ if (TAG) /* if indexed */ - eaddr += ReadW(TAG); /* add index register value (stored in core) */ + eaddr += ReadIndex(TAG); /* add index register value */ if (INDIR) /* if indirect addressing */ eaddr = ReadW(eaddr); /* pick up referenced address */ } @@ -543,15 +624,15 @@ t_stat sim_instr (void) DSPLC |= ~ 0xFF; if (TAG) /* if indexed */ - eaddr = ReadW(TAG) + DSPLC; /* add index register value (stored in core) */ + eaddr = ReadIndex(TAG) + DSPLC; /* add index register value */ else eaddr = IAR + DSPLC; /* otherwise relative to IAR after fetch */ } - switch (OP) { /* decode instruction */ + switch (OP) { /* decode instruction */ case 0x01: /* --- XIO --- */ - iocc_addr = ReadW(eaddr); /* get IOCC packet */ - iocc_op = ReadW(eaddr|1); /* note 'or' not plus, address must be even for proper operation */ + iocc_addr = ReadW(eaddr); /* get IOCC packet */ + iocc_op = ReadW(eaddr|1); /* note 'or' not plus, address must be even for proper operation */ iocc_dev = (iocc_op >> 11) & 0x001F; iocc_func = (iocc_op >> 8) & 0x0007; @@ -560,9 +641,9 @@ t_stat sim_instr (void) if (cpu_unit.flags & UNIT_ATT) trace_io("* XIO %s %s mod %02x addr %04x", xio_funcs[iocc_func], xio_devs[iocc_dev], iocc_mod, iocc_addr); -// fprintf(stderr, "* XIO %s %s mod %02x addr %04x\n", xio_funcs[iocc_func], xio_devs[iocc_dev], iocc_mod, iocc_addr); +/* fprintf(stderr, "* XIO %s %s mod %02x addr %04x\n", xio_funcs[iocc_func], xio_devs[iocc_dev], iocc_mod, iocc_addr); */ - ACC = 0; /* ACC is destroyed, and default XIO_SENSE_DEV result is 0 */ + ACC = 0; /* ACC is destroyed, and default XIO_SENSE_DEV result is 0 */ switch (iocc_func) { case XIO_UNUSED: @@ -604,7 +685,7 @@ t_stat sim_instr (void) xio_2501_card(iocc_addr, iocc_func, iocc_mod); break; case 0x0a: /* synchronous comm adapter */ - xio_1131_synch(iocc_addr, iocc_func, iocc_mod); + xio_sca(iocc_addr, iocc_func, iocc_mod); break; case 0x0c: /* IBM System/7 interprocessor link */ xio_system7(iocc_addr, iocc_func, iocc_mod); @@ -633,6 +714,9 @@ t_stat sim_instr (void) case 0x19: /* 2250 Display Unit */ xio_2250_display(iocc_addr, iocc_func, iocc_mod); break; + case 0x1a: /* 2741 Attachment (nonstandard serial interface used by APL\1130 */ + xio_t2741_terminal(iocc_addr, iocc_func, iocc_mod); + break; default: sprintf(msg, "unknown device %02x", iocc_dev); xio_error(msg); @@ -640,7 +724,7 @@ t_stat sim_instr (void) } } - calc_ints(); /* after every XIO, reset int_mask just in case */ + calc_ints(); /* after every XIO, reset int_mask just in case */ break; case 0x02: /* --- SLA,SLT,SLC,SLCA,NOP - Shift Left family --- */ @@ -649,24 +733,25 @@ t_stat sim_instr (void) DECREMENT_IAR; } - CCC = ((TAG == 0) ? DSPLC : ReadW(TAG)) & 0x003F; + CCC = ((TAG == 0) ? DSPLC : ReadIndex(TAG)) & 0x003F; + ARFSET(CCC); if (CCC == 0) - break; /* shift of zero is a NOP */ + break; /* shift of zero is a NOP */ switch (IR & 0x00C0) { - case 0x0040: /* SLCA */ + case 0x0040: /* SLCA */ if (TAG) { while (CCC > 0 && (ACC & 0x8000) == 0) { ACC <<= 1; CCC--; } C = (CCC != 0); - WriteW(TAG, ReadW(TAG) & 0xFF00 | CCC); /* put low 6 bits back into index register and zero bits 8 and 9 */ + WriteIndex(TAG, (ReadIndex(TAG) & 0xFF00) | CCC); /* put low 6 bits back into index register and zero bits 8 and 9 */ break; } /* if TAG == 0, fall through and treat like normal shift SLA */ - case 0x0000: /* SLA */ + case 0x0000: /* SLA */ while (CCC > 0) { C = (ACC & 0x8000); ACC = (ACC << 1) & 0xFFFF; @@ -674,7 +759,7 @@ t_stat sim_instr (void) } break; - case 0x00C0: /* SLC */ + case 0x00C0: /* SLC */ if (TAG) { while (CCC > 0 && (ACC & 0x8000) == 0) { abit = (EXT & 0x8000) >> 15; @@ -683,12 +768,12 @@ t_stat sim_instr (void) CCC--; } C = (CCC != 0); - WriteW(TAG, ReadW(TAG) & 0xFF00 | CCC); /* put 6 bits back into low byte of index register */ + WriteIndex(TAG, ReadIndex(TAG) & 0xFF00 | CCC); /* put 6 bits back into low byte of index register */ break; } /* if TAG == 0, fall through and treat like normal shift SLT */ - case 0x0080: /* SLT */ + case 0x0080: /* SLT */ while (CCC > 0) { C = (ACC & 0x8000); abit = (EXT & 0x8000) >> 15; @@ -710,21 +795,22 @@ t_stat sim_instr (void) DECREMENT_IAR; } - CCC = ((TAG == 0) ? DSPLC : ReadW(TAG)) & 0x3F; + CCC = ((TAG == 0) ? DSPLC : ReadIndex(TAG)) & 0x3F; + ARFSET(CCC); if (CCC == 0) - break; /* NOP */ + break; /* NOP */ switch (IR & 0x00C0) { - case 0x0000: /* SRA */ + case 0x0000: /* SRA */ ACC = (CCC < 16) ? ((ACC & 0xFFFF) >> CCC) : 0; CCC = 0; break; - case 0x0040: /* invalid */ + case 0x0040: /* invalid */ wait_state = WAIT_INVALID_OP; break; - case 0x0080: /* SRT */ + case 0x0080: /* SRT */ while (CCC > 0) { xbit = (ACC & 0x0001) << 15; abit = (ACC & 0x8000); @@ -734,7 +820,7 @@ t_stat sim_instr (void) } break; - case 0x00C0: /* RTE */ + case 0x00C0: /* RTE */ while (CCC > 0) { abit = (EXT & 0x0001) << 15; xbit = (ACC & 0x0001) << 15; @@ -751,7 +837,7 @@ t_stat sim_instr (void) break; case 0x04: /* --- LDS - Load Status --- */ - if (F) { /* never fetches second word */ + if (F) { /* never fetches second word? */ weirdop("Long LDS", -2); DECREMENT_IAR; } @@ -768,45 +854,45 @@ t_stat sim_instr (void) newval |= 1; WriteW(eaddr, newval); - C = V = 0; /* clear flags after storing */ + C = V = 0; /* clear flags after storing */ break; case 0x06: /* --- WAIT --- */ wait_state = WAIT_OP; - /* note: not valid in long mode, but what happens if we try? */ - if (F) { + if (F) { /* what happens if we use long format? */ weirdop("Long WAIT", -2); - DECREMENT_IAR; /* assume it wouldn't have fetched 2nd word */ + DECREMENT_IAR; /* assume it wouldn't have fetched 2nd word? */ } break; case 0x08: /* --- BSI - Branch and store IAR --- */ if (F) { - if (bsctest(IR, F)) /* do standard BSC long format testing */ - break; /* if any condition is true, do nothing */ + if (bsctest(IR, F)) /* do standard BSC long format testing */ + break; /* if any condition is true, do nothing */ } - WriteW(eaddr, IAR); /* do subroutine call */ - archive_backtrace("BSI"); /* save info in back-trace buffer */ + WriteW(eaddr, IAR); /* do subroutine call */ + archive_backtrace("BSI"); /* save info in back-trace buffer */ IAR = (eaddr + 1) & mem_mask; break; case 0x09: /* --- BSC - Branch and skip on Condition --- */ if (F) { - if (bsctest(IR, F)) /* long format; any indicator cancels branch */ + if (bsctest(IR, F)) /* long format; any indicator cancels branch */ break; archive_backtrace((DSPLC & 0x40) ? "BOSC" : "BSC"); /* save info in back-trace buffer */ - IAR = eaddr; /* no indicator means branch taken */ + IAR = eaddr; /* no indicator means branch taken */ } - else { /* short format: skip if any indicator hits */ + else { /* short format: skip if any indicator hits */ if (bsctest(IR, F)) { archive_backtrace((DSPLC & 0x40) ? "BOSC" : "BSC"); /* save info in back-trace buffer */ INCREMENT_IAR; } } -// 27Mar02: moved this test out of the (F) condition; BOSC works even in the -// short form. The displacement field in this instruction is always the set of -// condition bits, and the interrupt clear bit doesn't collide. +/* 27Mar02: moved this test out of the (F) condition; BOSC works even in the + * short form. The displacement field in this instruction is always the set of + * condition bits, and the interrupt clear bit doesn't collide. */ + if (DSPLC & 0x40) { /* BOSC = exit from interrupt handler */ exit_irq(); cwincount = 0; @@ -820,47 +906,47 @@ t_stat sim_instr (void) eaddr = DSPLC; if (TAG) - WriteW(TAG, eaddr); + WriteIndex(TAG, eaddr); else { - archive_backtrace("LDX"); /* save info in back-trace buffer */ - IAR = eaddr; /* what happens in short form? can onlyjump to low addresses? */ + archive_backtrace("LDX"); /* save info in back-trace buffer */ + IAR = eaddr; /* what happens in short form? can onlyjump to low addresses? */ } break; case 0x0d: /* --- STX - Store Index --- */ - if (F) { /* compute EA without any indexing */ + if (F) { /* compute EA without any indexing */ eaddr = (INDIR) ? ReadW(word2) : word2; } else { eaddr = IAR + DSPLC; } - WriteW(eaddr, TAG ? ReadW(TAG) : IAR); + WriteW(eaddr, TAG ? ReadIndex(TAG) : IAR); break; case 0x0e: /* --- MDX - Modify Index and Skip --- */ - if (F) { /* long mode: adjust memory location */ + if (F) { /* long format: adjust memory location */ if (TAG) { - oldval = ReadW(TAG); /* add word2 to index */ + oldval = ReadIndex(TAG); /* add word2 to index */ newval = oldval + (INDIR ? ReadW(word2) : word2); - WriteW(TAG, newval); + WriteIndex(TAG, newval); } else { oldval = ReadW(word2); - DSPLC = IR & 0x00FF; /* use extended displacement (includes INDIR bit) */ + DSPLC = IR & 0x00FF; /* use extended displacement (no INDIR bit, it's is part of displacement in this op) */ if (DSPLC & 0x0080) DSPLC |= ~ 0xFF; newval = oldval + DSPLC; /* add modifier to @word2 */ WriteW(word2, newval); } } - else { /* short mode: adust IAR or index */ + else { /* short format: adust IAR or index */ if (TAG) { - oldval = ReadW(TAG);/* add displacement to index */ + oldval = ReadIndex(TAG); /* add displacement to index */ newval = oldval + DSPLC; - WriteW(TAG, newval); + WriteIndex(TAG, newval); } else { - oldval = IAR; /* add displacement to IAR */ + oldval = IAR; /* add displacement to IAR */ newval = IAR + DSPLC; archive_backtrace("MDX"); IAR = newval & mem_mask; @@ -869,13 +955,14 @@ t_stat sim_instr (void) if ((F || TAG) && (((newval & 0xFFFF) == 0) || ((oldval & 0x8000) != (newval & 0x8000)))) { archive_backtrace("SKP"); - INCREMENT_IAR; /* skip if index sign change or zero */ + INCREMENT_IAR; /* skip if index sign change or zero */ } break; case 0x10: /* --- A - Add --- */ /* in adds and subtracts, carry is set or cleared, overflow is set only */ src = ReadW(eaddr); + ARFSET(src); src2 = ACC; ACC = (ACC + src) & 0xFFFF; @@ -886,6 +973,7 @@ t_stat sim_instr (void) case 0x11: /* --- AD - Add Double --- */ src = ((ACC << 16) | (EXT & 0xFFFF)); + ARFSET(EXT); src2 = (ReadW(eaddr) << 16) + ReadW(eaddr|1); dst = src + src2; ACC = (dst >> 16) & 0xFFFF; @@ -898,6 +986,7 @@ t_stat sim_instr (void) case 0x12: /* --- S - Subtract --- */ src = ACC; + ARFSET(src); src2 = ReadW(eaddr); ACC = (ACC-src2) & 0xFFFF; @@ -908,6 +997,7 @@ t_stat sim_instr (void) case 0x13: /* --- SD - Subtract Double --- */ src = ((ACC << 16) | (EXT & 0xFFFF)); + ARFSET(EXT); src2 = (ReadW(eaddr) << 16) + ReadW(eaddr|1); dst = src - src2; ACC = (dst >> 16) & 0xFFFF; @@ -919,23 +1009,26 @@ t_stat sim_instr (void) break; case 0x14: /* --- M - Multiply --- */ - if ((src = ACC & 0xFFFF) & 0x8000) /* sign extend the values */ + if ((src = ACC & 0xFFFF) & 0x8000) /* sign extend the values */ src |= ~0xFFFF; if ((src2 = ReadW(eaddr)) & 0x8000) src2 |= ~0xFFFF; + ARFSET(src2); dst = src * src2; - ACC = (dst >> 16) & 0xFFFF; /* split the results */ + ACC = (dst >> 16) & 0xFFFF; /* split the results */ EXT = dst & 0xFFFF; break; case 0x15: /* --- D - Divide --- */ src = ((ACC << 16) | (EXT & 0xFFFF)); if ((src2 = ReadW(eaddr)) & 0x8000) - src2 |= ~0xFFFF; /* oops: sign extend was missing, fixed 18Mar03 */ + src2 |= ~0xFFFF; /* oops: sign extend was missing, fixed 18Mar03 */ + + ARFSET(src2); if (src2 == 0) - V = 1; /* divide by zero just sets overflow, ACC & EXT are undefined */ + V = 1; /* divide by zero just sets overflow, ACC & EXT are undefined */ else { ACC = (src / src2) & 0xFFFF; EXT = (src % src2) & 0xFFFF; @@ -948,7 +1041,7 @@ t_stat sim_instr (void) case 0x19: /* --- LDD - Load Double --- */ ACC = ReadW(eaddr); - EXT = ReadW(eaddr|1); /* notice address is |1 not +1 */ + EXT = ReadW(eaddr|1); /* notice address is |1 not +1 */ break; case 0x1a: /* --- STO - Store ACC --- */ @@ -957,21 +1050,59 @@ t_stat sim_instr (void) case 0x1b: /* --- STD - Store Double --- */ WriteW(eaddr|1, EXT); - WriteW(eaddr, ACC); /* order is important: if odd addr, only ACC is stored */ + WriteW(eaddr, ACC); /* order is important: if odd addr, only ACC is stored */ break; case 0x1c: /* --- AND - Logical AND --- */ - ACC &= ReadW(eaddr); + src = ReadW(eaddr); + ARFSET(src); + ACC &= src; break; case 0x1d: /* --- OR - Logical OR --- */ - ACC |= ReadW(eaddr); + src = ReadW(eaddr); + ARFSET(src); + ACC |= src; break; case 0x1e: /* --- EOR - Logical Excl OR --- */ - ACC ^= ReadW(eaddr); + src = ReadW(eaddr); + ARFSET(src); + ACC ^= src; break; + case 0x16: + case 0x17: +#ifdef ENABLE_1800_SUPPORT + if (is_1800) { + if (OP == 0x16) { /* --- CMP - Compare --- */ + src = ACC; /* like subtract but result isn't stored */ + src2 = ReadW(eaddr); + dst = (ACC-src2) & 0xFFFF; + C = src < src2; + + if (dst & 0x8000) /* if ACC < operand, skip 1 instruction */ + IAR = IAR+1; + else if ((dst & 0xFFFF) == 0) /* if ACC == operand, skip 2 instructions */ + IAR = IAR+2; + } + else { /* --- DCMP - Compare Double --- */ + src = ((ACC << 16) | (EXT & 0xFFFF)); + src2 = (ReadW(eaddr) << 16) + ReadW(eaddr|1); + dst = src - src2; + C = (uint32) src < (uint32) src2; + + if (dst & 0x80000000) /* if ACC_EXT < operand, skip 1 instruction */ + IAR = IAR+1; + else if (dst == 0) /* if ACC_EXT == operand, skip 2 instructions */ + IAR = IAR+2; + } + + break; /* these are legal instructions on the 1800 */ + } +#endif + /* 1130: these are not legal instructions, fall through */ + default: /* all invalid instructions act like waits */ /* case 0x00: */ @@ -980,23 +1111,21 @@ t_stat sim_instr (void) /* case 0x0b: */ /* case 0x0e: */ /* case 0x0f: */ -/* case 0x16: */ -/* case 0x17: */ /* case 0x1f: */ wait_state = WAIT_INVALID_OP; if (F) - DECREMENT_IAR; /* assume it wouldn't have fetched 2nd word? */ + DECREMENT_IAR; /* assume it wouldn't have fetched 2nd word? */ break; - } /* end instruction decode switch */ + } /* end instruction decode switch */ if (RUNMODE != MODE_RUN && RUNMODE != MODE_INT_RUN) reason = STOP_WAIT; - if (tbit && (ipl < 0)) { /* if INT_RUN mode, set IRQ5 after this instr */ + if (tbit && (ipl < 0)) { /* if INT_RUN mode, set IRQ5 after this instr */ GUI_BEGIN_CRITICAL_SECTION SETBIT(cpu_dsw, CPU_DSW_INT_RUN); - SETBIT(ILSW[5], ILSW_5_INT_RUN); + SETBIT(ILSW[5], ILSW_5_INT_RUN_PROGRAM_STOP); int_req |= INT_REQ_5; GUI_END_CRITICAL_SECTION } @@ -1007,21 +1136,34 @@ t_stat sim_instr (void) #endif running = FALSE; - int_lamps = 0; /* display only currently active interrupts while halted */ + int_lamps = 0; /* display only currently active interrupts while halted */ if (reason == STOP_WAIT || reason == STOP_INVALID_INSTR) { - wait_state = 0; // on resume, don't wait - wait_lamp = TRUE; // but keep the lamp lit on the GUI + wait_state = 0; /* on resume, don't wait */ + wait_lamp = TRUE; /* but keep the lamp lit on the GUI */ + + CLRBIT(cpu_dsw, CPU_DSW_PROGRAM_STOP); /* and on resume, reset program start bit */ + if ((cpu_dsw & CPU_DSW_PROGRAM_STOP) == 0) + CLRBIT(ILSW[5], ILSW_5_INT_RUN_PROGRAM_STOP); } -#ifdef CGI_SUPPORT - if (cgi) + if (cgi) /* give CGI hook function a chance to do something */ cgi_stop(reason); -#endif return reason; } +/* + * simh_status_to_stopcode - convert a SCPE_xxx value from sim_process_event into a STOP_xxx code + */ + +static int simh_status_to_stopcode (int status) +{ + return (status == SCPE_BREAK) ? STOP_BREAK : + (status == SCPE_STOP) ? STOP_IMMEDIATE : + (status == SCPE_STEP) ? STOP_STEP : STOP_OTHER; +} + /* ------------------------------------------------------------------------ * bsctest - perform standard set of condition tests. We return TRUE if any * of the condition bits specified in DSPLC test positive, FALSE if none are true. @@ -1071,6 +1213,12 @@ static void exit_irq (void) GUI_BEGIN_CRITICAL_SECTION + if (ipl == 5 && tbit) { /* if we are exiting an INT_RUN interrupt, clear it for the next instruction */ + CLRBIT(cpu_dsw, CPU_DSW_INT_RUN); + if ((cpu_dsw & CPU_DSW_PROGRAM_STOP) == 0) + CLRBIT(ILSW[5], ILSW_5_INT_RUN_PROGRAM_STOP); + } + ipl = -1; /* default: return to main processor level */ int_mask = 0xFFFF; @@ -1116,6 +1264,9 @@ t_stat cpu_reset (DEVICE *dptr) GUI_BEGIN_CRITICAL_SECTION + CLRBIT(cpu_dsw, CPU_DSW_PROGRAM_STOP|CPU_DSW_INT_RUN); + CLRBIT(ILSW[5], ILSW_5_INT_RUN_PROGRAM_STOP); + reset_backtrace(); ipl = -1; @@ -1213,6 +1364,26 @@ t_stat cpu_set_size (UNIT *uptr, int32 value, char *cptr, void *desc) return SCPE_OK; } +/* processor type */ + +t_stat cpu_set_type (UNIT *uptr, int32 value, char *cptr, void *desc) +{ + REG *r; + + is_1800 = (value & UNIT_1800) != 0; /* set is_1800 mode flag */ + + for (r = cpu_reg; r->name != NULL; r++) { /* unhide or hide 1800-specific registers & state */ + if (strnicmp(r->name, "XR", 2) == 0) { + if (value & UNIT_1800) + CLRBIT(r->flags, REG_HIDDEN|REG_RO); + else + SETBIT(r->flags, REG_HIDDEN|REG_RO); + } + } + + return SCPE_OK; +} + /* ------------------------------------------------------------------------ * IO function for console switches * ------------------------------------------------------------------------ */ @@ -1228,10 +1399,6 @@ void xio_1131_switches (int32 addr, int32 func, int32 modify) case XIO_SENSE_DEV: ACC = cpu_dsw; - if (modify & 0x01) { /* reset interrupts */ - CLRBIT(cpu_dsw, CPU_DSW_PROGRAM_STOP|CPU_DSW_INT_RUN); - CLRBIT(ILSW[5], ILSW_5_INT_RUN); /* (these bits are set in the keyboard handler in 1130_stddev.c) */ - } break; default: @@ -1247,7 +1414,7 @@ void xio_1131_switches (int32 addr, int32 func, int32 modify) void xio_error (char *msg) { printf("*** XIO error at %04x: %s\n", prev_IAR, msg); - if (cgi) + if (cgi) /* if this happens in CGI mode, probably best to halt */ break_simulation(STOP_CRASH); } @@ -1259,25 +1426,25 @@ t_stat register_cmd (char *name, t_stat (*action)(int32 flag, char *ptr), int ar { int i; - for (i = 0; i < MAX_EXTRA_COMMANDS; i++) { // find end of command table + for (i = 0; i < MAX_EXTRA_COMMANDS; i++) { /* find end of command table */ if (x_cmds[i].action == action) - return SCPE_OK; // command is already there, just return + return SCPE_OK; /* command is already there, just return */ if (x_cmds[i].name == NULL) break; } - if (i >= (MAX_EXTRA_COMMANDS-1)) { // no more room (we need room for the NULL) + if (i >= (MAX_EXTRA_COMMANDS-1)) { /* no more room (we need room for the NULL) */ fprintf(stderr, "The command table is full - rebuild the simulator with more free slots\n"); return SCPE_ARG; } - x_cmds[i].action = action; // add new command + x_cmds[i].action = action; /* add new command */ x_cmds[i].name = name; x_cmds[i].arg = arg; x_cmds[i].help = help; i++; - x_cmds[i].action = NULL; // move the NULL terminator + x_cmds[i].action = NULL; /* move the NULL terminator */ x_cmds[i].name = NULL; return SCPE_OK; @@ -1306,7 +1473,7 @@ void sim_init (void) sim_vm_cmd = x_cmds; /* provide list of additional commands */ #ifdef GUI_SUPPORT - // set hook routines for GUI command processing + /* set hook routines for GUI command processing */ if (sim_gui) { sim_vm_read = &read_cmdline; sim_vm_post = &update_gui; @@ -1314,16 +1481,12 @@ void sim_init (void) #endif #ifdef ENABLE_BACKTRACE - // add the BACKTRACE command + /* add the BACKTRACE command */ register_cmd("BACKTRACE", &backtrace_cmd, 0, "ba{cktrace} {n} list last n branches/skips/interrupts\n"); #endif register_cmd("VIEW", &view_cmd, 0, "v{iew} filename view a text file with notepad\n"); -#ifdef CGI_SUPPORT - register_cmd("CGI", &cgi_cmd, 0, "cgi run simulator in CGI mode\n"); -#endif - #ifdef USE_MY_ECHO_CMD register_cmd("ECHO", &echo_cmd, 0, "echo args... echo arguments passed to command\n"); #endif @@ -1405,7 +1568,7 @@ static t_stat backtrace_cmd (int flag, char *cptr) } #else -// stub this for the disk routine +/* stub this for the disk routine */ void void_backtrace (int afrom, int ato) { @@ -1413,57 +1576,58 @@ void void_backtrace (int afrom, int ato) #endif -// CPU log routines -- attaching a file to the CPU creates a trace of instructions and register values -// -// Syntax is WEIRD: -// -// attach cpu logfile log instructions and registers to file "logfile" -// attach -f cpu cpu.log log instructions, registers and floating point acc -// attach -m cpu mapfile logfile read addresses from "mapfile", log instructions to "logfile" -// attach -f -m cpu mapfile logfile same and log floating point stuff too -// -// mapfile if specified is a list of symbols and addresses of the form: -// symbol hexval -// -// e.g. -// FSIN 082E -// FARC 09D4 -// FMPY 09A4 -// NORM 0976 -// XMDS 095A -// START 021A -// -// These values are easily obtained from a load map created by -// XEQ L -// -// The log output is of the form -// -// IAR ACC EXT (flt) XR1 XR2 XR3 CVI FAC OPERATION -// --------------- ---- ---- -------- ---- ---- ---- --- ------------- ----------------------- -// 002a 002a 1234 5381 0.14222 00b3 0236 3f7e CV 1.04720e+000 4c80 BSC I ,0028 -// 081d PAUSE+000d 1234 5381 0.14222 00b3 0236 3f7e CV 1.04720e+000 7400 MDM L 00f0,0 (0) -// 0820 PAUSE+0010 1234 5381 0.14222 00b3 0236 3f7e CV 1.04720e+000 7201 MDX 2 0001 -// 0821 PAUSE+0011 1234 5381 0.14222 00b3 0237 3f7e CV 1.04720e+000 6a03 STX 2 0003 -// 0822 PAUSE+0012 1234 5381 0.14222 00b3 0237 3f7e CV 1.04720e+000 6600 LDX L2 0231 -// 0824 PAUSE+0014 1234 5381 0.14222 00b3 0231 3f7e CV 1.04720e+000 4c00 BSC L ,0237 -// 0237 START+001d 1234 5381 0.14222 00b3 0231 3f7e CV 1.04720e+000 4480 BSI I ,3fff -// 082f FSIN +0001 1234 5381 0.14222 00b3 0231 3f7e CV 1.04720e+000 4356 BSI 3 0056 -// 3fd5 ILS01+35dd 1234 5381 0.14222 00b3 0231 3f7e CV 1.04720e+000 4c00 BSC L ,08de -// -// IAR - instruction address register value, optionally including symbol and offset -// ACC - accumulator -// EXT - extension -// flt - ACC+EXT interpreted as the mantissa of a floating pt number (value 0.5 -> 1) -// XR* - index registers -// CVI - carry, overflow and interrupt indicators -// FAC - floating point accumulator (exponent at 125+XR3, mantissa at 126+XR3 and 127+XR3) -// OP - opcode value and crude disassembly -// -// flt and FAC are displayed only when the -f flag is specified in the attach command -// The label and offset and displayed only when the -m flag is specified in the attach command -// -// The register values shown are the values BEFORE the instruction is executed. -// +/************************************************************************************* + * CPU log routines -- attaching a file to the CPU creates a trace of instructions and register values + * + * Syntax is WEIRD: + * + * attach cpu logfile log instructions and registers to file "logfile" + * attach -f cpu cpu.log log instructions, registers and floating point acc + * attach -m cpu mapfile logfile read addresses from "mapfile", log instructions to "logfile" + * attach -f -m cpu mapfile logfile same and log floating point stuff too + * + * mapfile if specified is a list of symbols and addresses of the form: + * symbol hexval + * + * e.g. + * FSIN 082E + * FARC 09D4 + * FMPY 09A4 + * NORM 0976 + * XMDS 095A + * START 021A + * + * These values are easily obtained from a load map created by + * XEQ L + * + * The log output is of the form + * + * IAR ACC EXT (flt) XR1 XR2 XR3 CVI FAC OPERATION + * --------------- ---- ---- -------- ---- ---- ---- --- ------------- ----------------------- + * 002a 002a 1234 5381 0.14222 00b3 0236 3f7e CV 1.04720e+000 4c80 BSC I ,0028 + * 081d PAUSE+000d 1234 5381 0.14222 00b3 0236 3f7e CV 1.04720e+000 7400 MDM L 00f0,0 (0) + * 0820 PAUSE+0010 1234 5381 0.14222 00b3 0236 3f7e CV 1.04720e+000 7201 MDX 2 0001 + * 0821 PAUSE+0011 1234 5381 0.14222 00b3 0237 3f7e CV 1.04720e+000 6a03 STX 2 0003 + * 0822 PAUSE+0012 1234 5381 0.14222 00b3 0237 3f7e CV 1.04720e+000 6600 LDX L2 0231 + * 0824 PAUSE+0014 1234 5381 0.14222 00b3 0231 3f7e CV 1.04720e+000 4c00 BSC L ,0237 + * 0237 START+001d 1234 5381 0.14222 00b3 0231 3f7e CV 1.04720e+000 4480 BSI I ,3fff + * 082f FSIN +0001 1234 5381 0.14222 00b3 0231 3f7e CV 1.04720e+000 4356 BSI 3 0056 + * 3fd5 ILS01+35dd 1234 5381 0.14222 00b3 0231 3f7e CV 1.04720e+000 4c00 BSC L ,08de + * + * IAR - instruction address register value, optionally including symbol and offset + * ACC - accumulator + * EXT - extension + * flt - ACC+EXT interpreted as the mantissa of a floating pt number (value 0.5 -> 1) + * XR* - index registers + * CVI - carry, overflow and interrupt indicators + * FAC - floating point accumulator (exponent at 125+XR3, mantissa at 126+XR3 and 127+XR3) + * OP - opcode value and crude disassembly + * + * flt and FAC are displayed only when the -f flag is specified in the attach command + * The label and offset and displayed only when the -m flag is specified in the attach command + * + * The register values shown are the values BEFORE the instruction is executed. + *************************************************************************************/ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw); @@ -1483,17 +1647,17 @@ static t_stat cpu_attach (UNIT *uptr, char *cptr) PSYMENTRY n, prv, s; FILE *fd; - remove(cptr); // delete old log file, if present + remove(cptr); /* delete old log file, if present */ new_log = TRUE; - log_fac = sim_switches & SWMASK ('F'); // display the FAC and the ACC/EXT as fixed point. + log_fac = sim_switches & SWMASK ('F'); /* display the FAC and the ACC/EXT as fixed point. */ - for (s = syms; s != NULL; s = n) { // free any old map entries + for (s = syms; s != NULL; s = n) { /* free any old map entries */ n = s->next; free(s); } syms = NULL; - if (sim_switches & SWMASK('M')) { // use a map file to display relative addresses + if (sim_switches & SWMASK('M')) { /* use a map file to display relative addresses */ cptr = get_glyph(cptr, mapfile, 0); if (! *mapfile) { printf("/m must be followed by a filename\n"); @@ -1504,7 +1668,7 @@ static t_stat cpu_attach (UNIT *uptr, char *cptr) return SCPE_OPENERR; } - while (fgets(buf, sizeof(buf), fd) != NULL) { // read symbols & addresses, link in descending address order + while (fgets(buf, sizeof(buf), fd) != NULL) { /* read symbols & addresses, link in descending address order */ if (sscanf(buf, "%s %x", sym, &addr) != 2) continue; if (*buf == ';') @@ -1641,13 +1805,30 @@ void trace_io (char *fmt, ...) if ((cpu_unit.flags & UNIT_ATT) == 0) return; - va_start(args, fmt); // get pointer to argument list - vfprintf(cpu_unit.fileref, fmt, args); // write errors to terminal (stderr) + va_start(args, fmt); /* get pointer to argument list */ + vfprintf(cpu_unit.fileref, fmt, args); /* write errors to cpu log file */ va_end(args); fputs(CRLF, cpu_unit.fileref); } +void trace_both (char *fmt, ...) +{ + va_list args; + + if (cpu_unit.flags & UNIT_ATT) { + va_start(args, fmt); /* get pointer to argument list */ + vfprintf(cpu_unit.fileref, fmt, args); + va_end(args); + fputs(CRLF, cpu_unit.fileref); + } + + va_start(args, fmt); /* get pointer to argument list */ + vfprintf(stdout, fmt, args); + va_end(args); + putchar('\n'); +} + /* debugging */ void debug_print (char *fmt, ...) @@ -1660,7 +1841,7 @@ void debug_print (char *fmt, ...) vfprintf(cpu_unit.fileref, fmt, args); va_end(args); - if (strchr(fmt, '\n') == NULL) { // be sure to emit a newline + if (strchr(fmt, '\n') == NULL) { /* be sure to emit a newline */ putchar('\n'); if (cpu_unit.flags & UNIT_ATT) putc('\n', cpu_unit.fileref); @@ -1671,7 +1852,7 @@ void debug_print (char *fmt, ...) #include #endif -// view_cmd - let user view and/or edit a file (e.g. a printer output file, script, or source deck) +/* view_cmd - let user view and/or edit a file (e.g. a printer output file, script, or source deck) */ static t_stat view_cmd (int flag, char *cptr) { @@ -1684,200 +1865,19 @@ static t_stat view_cmd (int flag, char *cptr) return SCPE_OK; } -#ifdef CGI_SUPPORT +/* web server version - hooks for CGI mode. These function pointer can be set by the CGI version's main() routine */ -int cgi_maxsec = 0; // default run time limit +void (*cgi_start_hook)(void) = NULL; /* these can be defined by a CGI wrapper to do things on start and stop of simulation */ +void (*cgi_end_hook)(void) = NULL; -// cgi_cmd - enable cgi mode. Specify time limit on command line if desired - -static t_stat cgi_cmd (int flag, char *cptr) +static void cgi_start (void) { - cgi = TRUE; // set CGI flag - - while (*cptr && *cptr <= ' ') - cptr++; - - if (*cptr) - cgi_maxsec = atoi(cptr); // set time limit, if specified - - return SCPE_OK; + if (cgi_start_hook != NULL) + (*cgi_start_hook)(); } -// cgi_timeout - called when timer runs out - -static void cgi_timeout (int dummy) +static void cgi_stop (t_stat reason) { - break_simulation(STOP_TIMED_OUT); // stop the simulator + if (cgi_end_hook != NULL) + (*cgi_end_hook)(); } - -// cgi_clockfail - report failure to set alarm - -static void cgi_clockfail (void) -{ - printf("Set CGI time limit failed!"); -} - -// cgi_start_timer - OS dependent routine to set things up so that -// cgi_timeout() will be called after cgi_maxsec seconds. - -#if defined(_WIN32) - static DWORD WINAPI cgi_timer_thread (LPVOID arg) - { - Sleep(cgi_maxsec*1000); // timer thread -- wait, then call timeout routine - cgi_timeout(0); - return 0; - } - - static void cgi_start_timer (void) - { - DWORD dwThreadID; - - if (CreateThread(NULL, 0, cgi_timer_thread, NULL, 0, &dwThreadID) == NULL) - cgi_clockfail(); - } -#else - #include - - #if defined(SIGVTALRM) && defined(ITMER_VIRTUAL) - - // setitimer counts actual runtime CPU seconds, so is insensitive to - // system load and is a better timer to use. Be sure to check, though, - // that it actually works on your OS. Note that time spent performing - // I/O does not count -- this counts user mode CPU time only, so - // the elapsed time it allows could be much larger, especially if - // the job is spewing output. - - #include - - static void cgi_start_timer (void) - { - struct itimerval rtime, otime; - - rtime.it_value.tv_sec = cgi_maxsec; - rtime.it_value.tv_usec = 0; - rtime.it_interval.tv_sec = cgi_maxsec; - rtime.it_interval.tv_usec = 0; - - if (signal(SIGVTALRM, cgi_timeout) == SIG_ERR) // set alarm handler - cgi_clockfail(); - else if (setitimer(ITIMER_VIRTUAL, &rtime, &otime)) // start timer - cgi_clockfail(); - } - - #elif defined(SIGALRM) - #include - - // if it's all we have, standard POSIX alarm will do the trick too - - static void cgi_start_timer (void) - { - if (signal(SIGALRM, cgi_timeout) == SIG_ERR) // set alarm handler - cgi_clockfail(); - else if (alarm(cgi_maxsec)) // start timer - cgi_clockfail(); - } - - #else - // don't seem to have a clock available. Better say so. - - static void cgi_start_timer (void) - { - printf("CGI time limit is not supported by this build\n"); - } - - #endif -#endif - -static void cgi_start(void) -{ - if (cgi_maxsec > 0) // if time limit was specified, set timer now - cgi_start_timer(); - -// printf("Content-type: text/html\n\n\n\n IBM 1130 Simulation Results\n\n\n
");
-}
-
-static void cgi_stop(t_stat reason)
-{
-	typedef enum {O_END, O_FORTRAN, O_MONITOR} ORIGIN;
-	char *errmsg = "";
-	static struct tag_pretstop {
-		int acc;
-		ORIGIN orig;
-		char *msg;
-	} pretstop[] = {
-		0x8000, O_FORTRAN, "I/O attempted on invalid unit # or uninstalled device (just a guess)",
-		0xF000, O_FORTRAN, "No *IOCS was specified but I/O was attempted",
-		0xF001, O_FORTRAN, "Local unit defined incorrectly, or no *IOCS for specified device",
-		0xF002, O_FORTRAN, "Requested record exceeds buffer size",
-		0xF003, O_FORTRAN, "Illegal character encountered in input record",
-		0xF004, O_FORTRAN, "Exponent too large or too small in input",
-		0xF005, O_FORTRAN, "More than one exponent encountered in input",
-		0xF006, O_FORTRAN, "More than one sign encountered in input",
-		0xF007, O_FORTRAN, "More than one decimal point encountered in input",
-		0xF008, O_FORTRAN, "Read of output-only device, or write to input-only device",
-		0xF009, O_FORTRAN, "Real variable transmitted with I format or integer transmitted with E or F",
-		0xF020, O_FORTRAN, "Illegal unit reference",
-		0xF021, O_FORTRAN, "Read list exceeds length of write list",
-		0xF022, O_FORTRAN, "Record does not exist in read list",
-		0xF023, O_FORTRAN, "Maximum length of $$$$$ area on disk has been exceeded",
-		0xF024, O_FORTRAN, "*IOCS (UDISK) was not specified",
-		0xF100, O_FORTRAN, "File not defined by DEFINE FILE statement",
-		0xF101, O_FORTRAN, "File record number too large, zero or negative",
-		0xF103, O_FORTRAN, "*IOCS(DISK) was not specified",
-		0xF105, O_FORTRAN, "Length of a list element exceeds record length in DEFINE FILE",
-		0xF107, O_FORTRAN, "Attempt to read or write an invalid sector address (may occur if a core image program is run with too little room in working storage)",
-		0xF10A, O_FORTRAN, "Define file table and/or core image header corrupted, probably by an out-of-bounds array subscript",
-		0x1000, O_MONITOR, "1442 card read/punch or 1442 punch: not ready or hopper empty. [emulator: attach a file to CR or CP and go]",
-		0x1001, O_MONITOR, "Illegal device, function or word count",
-		0x100F, O_MONITOR, "Occurs in a DUP operation after DUP error D112",
-		0x2000, O_MONITOR, "Keyboard/Console Printer not ready",
-		0x2001, O_MONITOR, "Illegal device, function or word count",
-		0x3000, O_MONITOR, "1134/1055 Paper Tape not ready",
-		0x3001, O_MONITOR, "Illegal device, function or word count, or invalid check digit",
-		0x4000, O_MONITOR, "2501 Card Reader not ready",
-		0x4001, O_MONITOR, "Illegal device, function or word count",
-		0x5000, O_MONITOR, "Disk not ready",
-		0x5001, O_MONITOR, "Illegal device, function or word count, or attempt to write in protected area",
-		0x5002, O_MONITOR, "Write select or power unsafe",
-		0x5003, O_MONITOR, "Read/write/seek failure after 16 attempts or disk overflow. Extension may display logical drive number in bits 0..3 and working storage address in bits 4..15. Program Start retries 16 more times.",
-		0x5004, O_MONITOR, "Same as above from routine DISK1 and DISKN, or, an uninitialized cartridge is online during a cold start.",
-		0x6000, O_MONITOR, "1132 Printer not ready or out of paper",
-		0x6001, O_MONITOR, "Illegal device, function or word count",
-		0x7000, O_MONITOR, "1627 Plotter not ready",
-		0x7001, O_MONITOR, "Illegal device, function or word count",
-		0x8001, O_MONITOR, "SCA error: Illegal function or word count",
-		0x8002, O_MONITOR, "SCA error: if STR mode, receive or transmit operation not completed;\n"
-						   "if BSC mode, invalid start characters in the I/O area for a transmit operation",
-		0x8003, O_MONITOR, "SCA error: if STR mode, failed to synchronize before attempt to read or write, or, attempted to receive before receiving INQ sequence;\n"
-						   "if BSC mode, invalid number of identification characters for an identification specification operation",
-		0x9000, O_MONITOR, "1403 printer no ready or out of paper",
-		0x9001, O_MONITOR, "Illegal device, function or word count",
-		0x9002, O_MONITOR, "Parity check, scan check or ring check",
-		0xA000, O_MONITOR, "1231 Optical Mark Reader not ready",
-		0xA001, O_MONITOR, "Illegal device, function or word count",
-		0xA002, O_MONITOR, "Feed check, last document was processed. Clear jam, do not refeed",
-		0xA003, O_MONITOR, "Feed check, last document not  processed. Clear jam and refeed",
-		0,      O_END, 	   NULL
-	};
-	int i;
-
-	detach_cmd(0, "prt");		/* flush last print line */
-
-	if (reason == STOP_TIMED_OUT)
-		printf("\n
Sorry, emulation run time exceeded %d second%s\n", cgi_maxsec, (cgi_maxsec == 1) ? "" : "s"); - else if (IAR != 0x2a || ACC != 0x1000) { - ACC &= 0xFFFF; - for (i = 0; pretstop[i].orig != O_END; i++) { - if (pretstop[i].acc == ACC) { - errmsg = pretstop[i].msg; - break; - } - } - printf("\n
Abnormal exit: %s\nIAR = %04x, ACC = %04x\n", errmsg, IAR, ACC); - } - -// printf("
\n\n\n"); - exit(0); /* save w/o writing disk image */ -} - -#endif // ifdef CGI_SUPPORT diff --git a/Ibm1130/ibm1130_cr.c b/Ibm1130/ibm1130_cr.c index 0b0e59d2..61014b71 100644 --- a/Ibm1130/ibm1130_cr.c +++ b/Ibm1130/ibm1130_cr.c @@ -2,7 +2,7 @@ #include "ibm1130_fmt.h" #ifdef _WIN32 -# include // Microsoft puts definition of mktemp into io.h rather than stdlib.h +# include /* Microsoft puts definition of mktemp into io.h rather than stdlib.h */ #endif /* ibm1130_cr.c: IBM 1130 1442 Card Reader simulator @@ -18,6 +18,20 @@ * This is not a supported product, but I welcome bug reports and fixes. * Mail to simh@ibm1130.org + * Update 2006-01-23 More fixes, in call to mktemp and in 2501 support, also thanks + to Carl Claunch. + + * Update 2006-01-03 Fixed bug found by Carl Claunch: feed function does not + cause an operation complete interrupt. Standard DMS routines were not + sensitive to this but DUP uses its own interrupt handler, and this + is why DUP would hang at end of deck. + + * Update 2005-05-19 Added support for 2501 reader + + * Update 2004-11-08 Merged in correct physical card reader code + + * Update 2004-11-02: Added -s to boot command: don't touch console switches. + * Update 2004-06-05: Removed "feedcycle" from cr_reset. Reset should not touch the card reader. * Update 2004-04-12: Changed ascii field of CPCODE to unsigned char, caught a couple @@ -264,6 +278,9 @@ way to solve the problem, the other is to keep DSW up-to-date all the time). the appropriate buffer, so you can punch w/o attaching a deck to the card reader. + (Note: Carl Claunch determined by examining DUP code that a feed cycle + does not cause an operation complete interrupt). + -- -- this may need changing depending on how things work in hardware. TBD. || A read cycle on an empty deck causes an error. || Hmmm -- what takes the place of the Start button on @@ -323,11 +340,12 @@ way to solve the problem, the other is to keep DSW up-to-date all the time). deck isn't allowed. */ -#define READ_DELAY 35 // see how small a number we can get away with +#define READ_DELAY 35 /* see how small a number we can get away with */ #define PUNCH_DELAY 35 #define FEED_DELAY 25 +#define READ_2501_DELAY 500 -// umm, this is a weird little future project of mine. +/* umm, this is a weird little future project of mine. */ #define ENABLE_PHYSICAL_CARD_READER_SUPPORT @@ -348,10 +366,13 @@ static t_stat cp_detach (UNIT *uptr); static int16 cr_dsw = 0; /* device status word */ static int32 cr_wait = READ_DELAY; /* read per-column wait */ +static int32 cr_wait2501 = READ_2501_DELAY; /* read card wait for 2501 reader */ static int32 cf_wait = PUNCH_DELAY; /* punch per-column wait */ static int32 cp_wait = FEED_DELAY; /* feed op wait */ static int32 cr_count= 0; /* read and punch card count */ static int32 cp_count= 0; +static int32 cr_addr = 0; /* 2501 reader transfer address */ +static int32 cr_cols = 0; /* 2501 reader column count */ #define UNIT_V_OPERATION (UNIT_V_UF + 0) /* operation in progress */ #define UNIT_V_CODE (UNIT_V_UF + 2) /* three bits */ @@ -363,6 +384,7 @@ static int32 cp_count= 0; #define UNIT_V_LASTPUNCH (UNIT_V_UF + 10) /* used in unit_cp only */ #define UNIT_V_LOWERCASE (UNIT_V_UF + 10) /* used in unit_cr only */ #define UNIT_V_ACTCODE (UNIT_V_UF + 11) /* used in unit_cr only, 3 bits */ +#define UNIT_V_2501 (UNIT_V_UF + 14) #define UNIT_OP (3u << UNIT_V_OPERATION) /* two bits */ #define UNIT_CODE (7u << UNIT_V_CODE) /* three bits */ @@ -374,14 +396,15 @@ static int32 cp_count= 0; #define UNIT_LASTPUNCH (1u << UNIT_V_LASTPUNCH) #define UNIT_LOWERCASE (1u << UNIT_V_LOWERCASE) /* permit lowercase input (needed for APL) */ #define UNIT_ACTCODE (7u << UNIT_V_ACTCODE) +#define UNIT_2501 (1u << UNIT_V_2501) #define OP_IDLE (0u << UNIT_V_OPERATION) #define OP_READING (1u << UNIT_V_OPERATION) #define OP_PUNCHING (2u << UNIT_V_OPERATION) #define OP_FEEDING (3u << UNIT_V_OPERATION) -#define SET_OP(op) {cr_unit.flags &= ~UNIT_OP; cr_unit.flags |= (op);} -#define CURRENT_OP (cr_unit.flags & UNIT_OP) +#define SET_OP(op) {cr_unit.flags &= ~UNIT_OP; cr_unit.flags |= (op);} +#define CURRENT_OP (cr_unit.flags & UNIT_OP) #define CODE_AUTO (0u << UNIT_V_CODE) #define CODE_029 (1u << UNIT_V_CODE) @@ -392,12 +415,12 @@ static int32 cp_count= 0; #define GET_CODE(un) (un.flags & UNIT_CODE) #define SET_CODE(un,cd) {un.flags &= ~UNIT_CODE; un.flags |= (cd);} -#define ACTCODE_029 (CODE_029 << (UNIT_V_ACTCODE-UNIT_V_CODE)) // these are used ONLY in MTAB. Elsewhere -#define ACTCODE_026F (CODE_026F << (UNIT_V_ACTCODE-UNIT_V_CODE)) // we use values CODE_xxx with macros -#define ACTCODE_026C (CODE_026C << (UNIT_V_ACTCODE-UNIT_V_CODE)) // GET_ACTCODE and SET_ACTCODE. +#define ACTCODE_029 (CODE_029 << (UNIT_V_ACTCODE-UNIT_V_CODE)) /* these are used ONLY in MTAB. Elsewhere */ +#define ACTCODE_026F (CODE_026F << (UNIT_V_ACTCODE-UNIT_V_CODE)) /* we use values CODE_xxx with macros */ +#define ACTCODE_026C (CODE_026C << (UNIT_V_ACTCODE-UNIT_V_CODE)) /* GET_ACTCODE and SET_ACTCODE. */ #define ACTCODE_BINARY (CODE_BINARY << (UNIT_V_ACTCODE-UNIT_V_CODE)) - // get/set macros for actual-code field, these use values like CODE_029 meant for the UNIT_CODE field + /* get/set macros for actual-code field, these use values like CODE_029 meant for the UNIT_CODE field */ #define GET_ACTCODE(un) ((un.flags & UNIT_ACTCODE) >> (UNIT_V_ACTCODE-UNIT_V_CODE)) #define SET_ACTCODE(un,cd) {un.flags &= ~UNIT_ACTCODE; un.flags |= (cd) << (UNIT_V_ACTCODE-UNIT_V_CODE);} @@ -416,6 +439,8 @@ MTAB cr_mod[] = { { UNIT_ACTCODE, ACTCODE_026F, "(026F)", NULL, NULL}, { UNIT_ACTCODE, ACTCODE_026C, "(026C)", NULL, NULL}, { UNIT_ACTCODE, ACTCODE_BINARY, "(BINARY)", NULL, NULL}, + { UNIT_2501, 0, "1442", "1442", NULL}, + { UNIT_2501, UNIT_2501, "2501", "2501", NULL}, { 0 } }; MTAB cp_mod[] = { @@ -426,10 +451,13 @@ MTAB cp_mod[] = { { 0 } }; REG cr_reg[] = { - { HRDATA (CRDSW, cr_dsw, 16) }, /* device status word */ - { DRDATA (CRTIME, cr_wait, 24), PV_LEFT }, /* operation wait */ - { DRDATA (CFTIME, cf_wait, 24), PV_LEFT }, /* operation wait */ - { DRDATA (CRCOUNT, cr_count, 32),PV_LEFT }, /* number of cards read since last attach cmd */ + { HRDATA (CRDSW, cr_dsw, 16) }, /* device status word */ + { DRDATA (CRTIME, cr_wait, 24), PV_LEFT }, /* operation wait for 1442 column read*/ + { DRDATA (2501TIME, cr_wait2501, 24), PV_LEFT }, /* operation wait for 2501 whole card read*/ + { DRDATA (CFTIME, cf_wait, 24), PV_LEFT }, /* operation wait */ + { DRDATA (CRCOUNT, cr_count, 32),PV_LEFT }, /* number of cards read since last attach cmd */ + { HRDATA (CRADDR, cr_addr, 32) }, /* 2501 reader transfer address */ + { HRDATA (CRCOLS, cr_cols, 32) }, /* 2501 reader column count */ { NULL } }; REG cp_reg[] = { @@ -449,14 +477,20 @@ DEVICE cp_dev = { NULL, NULL, cp_reset, NULL, cp_attach, cp_detach}; -#define CR_DSW_READ_RESPONSE 0x8000 /* device status word bits */ -#define CR_DSW_PUNCH_RESPONSE 0x4000 -#define CR_DSW_ERROR_CHECK 0x2000 -#define CR_DSW_LAST_CARD 0x1000 -#define CR_DSW_OP_COMPLETE 0x0800 -#define CR_DSW_FEED_CHECK 0x0100 -#define CR_DSW_BUSY 0x0002 -#define CR_DSW_NOT_READY 0x0001 +#define CR_DSW_1442_READ_RESPONSE 0x8000 /* device status word bits */ +#define CR_DSW_1442_PUNCH_RESPONSE 0x4000 +#define CR_DSW_1442_ERROR_CHECK 0x2000 +#define CR_DSW_1442_LAST_CARD 0x1000 +#define CR_DSW_1442_OP_COMPLETE 0x0800 +#define CR_DSW_1442_FEED_CHECK 0x0100 +#define CR_DSW_1442_BUSY 0x0002 +#define CR_DSW_1442_NOT_READY 0x0001 + +#define CR_DSW_2501_ERROR_CHECK 0x2000 /* DSW for 2501 reader */ +#define CR_DSW_2501_LAST_CARD 0x1000 +#define CR_DSW_2501_OP_COMPLETE 0x0800 +#define CR_DSW_2501_BUSY 0x0002 +#define CR_DSW_2501_NOT_READY 0x0001 typedef struct { uint16 hollerith; @@ -466,7 +500,7 @@ typedef struct { static CPCODE cardcode_029[] = { 0x0000, ' ', - 0x8000, '&', // + in 026 Fortran + 0x8000, '&', /* + in 026 Fortran */ 0x4000, '-', 0x2000, '0', 0x1000, '1', @@ -506,14 +540,14 @@ static CPCODE cardcode_029[] = 0x2020, 'Y', 0x2010, 'Z', 0x0820, ':', - 0x0420, '#', // = in 026 Fortran - 0x0220, '@', // ' in 026 Fortran + 0x0420, '#', /* = in 026 Fortran */ + 0x0220, '@', /* ' in 026 Fortran */ 0x0120, '\'', 0x00A0, '=', 0x0060, '"', - 0x8820, (unsigned char) '\xA2', // cent, in MS-DOS encoding (this is in guess_cr_code as well) + 0x8820, (unsigned char) '\xA2', /* cent, in MS-DOS encoding (this is in guess_cr_code as well) */ 0x8420, '.', - 0x8220, '<', // ) in 026 Fortran + 0x8220, '<', /* ) in 026 Fortran */ 0x8120, '(', 0x80A0, '+', 0x8060, '|', @@ -522,9 +556,9 @@ static CPCODE cardcode_029[] = 0x4220, '*', 0x4120, ')', 0x40A0, ';', - 0x4060, (unsigned char) '\xAC', // not, in MS-DOS encoding (this is in guess_cr_code as well) + 0x4060, (unsigned char) '\xAC', /* not, in MS-DOS encoding (this is in guess_cr_code as well) */ 0x2420, ',', - 0x2220, '%', // ( in 026 Fortran + 0x2220, '%', /* ( in 026 Fortran */ 0x2120, '_', 0x20A0, '>', 0xB000, 'a', @@ -552,21 +586,20 @@ static CPCODE cardcode_029[] = 0x6080, 'w', 0x6040, 'x', 0x6020, 'y', - 0x6010, 'z', // these odd punch codes are used by APL: - 0x1010, '\001', // no corresponding ASCII using ^A - 0x0810, '\002', // SYN using ^B - 0x0410, '\003', // no corresponding ASCII using ^C - 0x0210, '\004', // PUNCH ON using ^D - 0x0110, '\005', // READER STOP using ^E - 0x0090, '\006', // UPPER CASE using ^F - 0x0050, '\013', // EOT using ^K - 0x0030, '\016', // no corresponding ASCII using ^N - 0x1030, '\017', // no corresponding ASCII using ^O - 0x0830, '\020', // no corresponding ASCII using ^P - + 0x6010, 'z', /* these odd punch codes are used by APL: */ + 0x1010, '\001', /* no corresponding ASCII using ^A */ + 0x0810, '\002', /* SYN using ^B */ + 0x0410, '\003', /* no corresponding ASCII using ^C */ + 0x0210, '\004', /* PUNCH ON using ^D */ + 0x0110, '\005', /* READER STOP using ^E */ + 0x0090, '\006', /* UPPER CASE using ^F */ + 0x0050, '\013', /* EOT using ^K */ + 0x0030, '\016', /* no corresponding ASCII using ^N */ + 0x1030, '\017', /* no corresponding ASCII using ^O */ + 0x0830, '\020', /* no corresponding ASCII using ^P */ }; -static CPCODE cardcode_026F[] = // 026 fortran +static CPCODE cardcode_026F[] = /* 026 fortran */ { 0x0000, ' ', 0x8000, '+', @@ -618,7 +651,7 @@ static CPCODE cardcode_026F[] = // 026 fortran 0x2220, '(', }; -static CPCODE cardcode_026C[] = // 026 commercial +static CPCODE cardcode_026C[] = /* 026 commercial */ { 0x0000, ' ', 0x8000, '+', @@ -746,7 +779,7 @@ t_stat set_active_cr_code (int match) memset(ascii_to_card, 0, sizeof(ascii_to_card)); - for (i = 0; i < ncode; i++) // set ascii to card code table + for (i = 0; i < ncode; i++) /* set ascii to card code table */ ascii_to_card[code[i].ascii] = code[i].hollerith; return SCPE_OK; @@ -766,53 +799,54 @@ static int32 guess_cr_code (void) long filepos; int32 guess; union { - uint16 w[80]; // one card image, viewed as 80 short words - char c[160]; // same, viewed as 160 characters + uint16 w[80]; /* one card image, viewed as 80 short words */ + char c[160]; /* same, viewed as 160 characters */ } line; - // here, we can see if the attached file is binary or ascii and auto-set the - // mode. If we the file is a binary deck, we should be able to read a record of 80 short - // words, and the low 4 bits of each word must be zero. If the file was an ascii deck, - // then these low 4 bits are the low 4 bits of every other character in the first 160 - // chararacters of the file. They would all only be 0 if all of these characters were - // in the following set: {NUL ^P space 0 @ P ` p} . It seems very unlikely that - // this would happen, as even if the deck consisted of untrimmed card images and - // the first two lines were blank, the 81'st character would be a newline, and it would - // appear at one of the every-other characters seen on little-endian machines, anyway. - // So: if the code mode is AUTO, we can use this test and select either BINARY or 029. - // Might as well also check for the all-blanks and newlines case in case this is a - // big-endian machine. + /* here, we can see if the attached file is binary or ascii and auto-set the + * mode. If we the file is a binary deck, we should be able to read a record of 80 short + * words, and the low 4 bits of each word must be zero. If the file was an ascii deck, + * then these low 4 bits are the low 4 bits of every other character in the first 160 + * chararacters of the file. They would all only be 0 if all of these characters were + * in the following set: {NUL ^P space 0 @ P ` p} . It seems very unlikely that + * this would happen, as even if the deck consisted of untrimmed card images and + * the first two lines were blank, the 81'st character would be a newline, and it would + * appear at one of the every-other characters seen on little-endian machines, anyway. + * So: if the code mode is AUTO, we can use this test and select either BINARY or 029. + * Might as well also check for the all-blanks and newlines case in case this is a + * big-endian machine. + */ - guess = CODE_029; // assume ASCII, 029 + guess = CODE_029; /* assume ASCII, 029 */ if ((cr_unit.flags & UNIT_ATT) && (cr_unit.fileref != NULL)) { - filepos = ftell(cr_unit.fileref); // remember current position in file - fseek(cr_unit.fileref, 0, SEEK_SET); // go to first record of file - // read card image; if file too short, leave guess set to 029 + filepos = ftell(cr_unit.fileref); /* remember current position in file */ + fseek(cr_unit.fileref, 0, SEEK_SET); /* go to first record of file */ + /* read card image; if file too short, leave guess set to 029 */ if (fxread(line.w, sizeof(line.w[0]), 80, cr_unit.fileref) == 80) { - guess = CODE_BINARY; // we got a card image, assume binary + guess = CODE_BINARY; /* we got a card image, assume binary */ - for (i = 0; i < 80; i++) { // make sure low bits are zeroes, which our binary card format promises + for (i = 0; i < 80; i++) { /* make sure low bits are zeroes, which our binary card format promises */ if (line.w[i] & 0x000F) { - guess = CODE_029; // low bits set, must be ascii text + guess = CODE_029; /* low bits set, must be ascii text */ break; } } - if (guess == CODE_BINARY) { // if we saw no low bits, it could have been all spaces. - guess = CODE_029; // so now assume file is text - for (i = 0; i < 160; i++) { // ensure all 160 characters are 7-bit ASCII (or not or cent) - // 3.0-3, changed test for > 0x7f to & 0x80 + if (guess == CODE_BINARY) { /* if we saw no low bits, it could have been all spaces. */ + guess = CODE_029; /* so now assume file is text */ + for (i = 0; i < 160; i++) { /* ensure all 160 characters are 7-bit ASCII (or not or cent) */ + /* 3.0-3, changed test for > 0x7f to & 0x80 */ if ((strchr("\r\n\t\xA2\xAC", line.c[i]) == NULL) && ((line.c[i] < ' ') || (line.c[i] & 0x80))) { - guess = CODE_BINARY; // oops, null or weird character, it's binary after all + guess = CODE_BINARY; /* oops, null or weird character, it's binary after all */ break; } } } } - fseek(cr_unit.fileref, filepos, SEEK_SET); // return to original position + fseek(cr_unit.fileref, filepos, SEEK_SET); /* return to original position */ } return guess; @@ -826,7 +860,7 @@ static t_stat cp_set_code (UNIT *uptr, int32 match, char *cptr, void *desc) if (! lookup_codetable(match, &code, &ncode)) return SCPE_ARG; - cardcode = code; // save code table for punch output + cardcode = code; /* save code table for punch output */ ncardcode = ncode; return SCPE_OK; @@ -890,8 +924,9 @@ t_stat load_cr_boot (int drvno, int switches) expand = FALSE; } - if (drvno >= 0) /* if specified, set toggle switches to disk drive no */ + if (drvno >= 0 && ! (switches & SWMASK('S'))) /* if specified, set toggle switches to disk drive no */ CES = drvno; /* so BOOT DSK1 will work correctly (DMS boot uses this) */ + /* but do not touch switches if -S was specified */ IAR = 0; /* clear IAR */ @@ -903,7 +938,7 @@ t_stat load_cr_boot (int drvno, int switches) WriteW(i, word); } /* quiet switch or CGI mode inhibit the boot remark */ - if (((switches & SWMASK('Q')) == 0) && ! cgi) { // 3.0-3, parenthesized & operation, per lint check + if (((switches & SWMASK('Q')) == 0) && ! cgi) { /* 3.0-3, parenthesized & operation, per lint check */ sprintf(msg, "Loaded %s cold start card\n", name); #ifdef GUI_SUPPORT @@ -919,7 +954,6 @@ t_stat load_cr_boot (int drvno, int switches) t_stat cr_boot (int unitno, DEVICE *dptr) { t_stat rval; -// uint16 buf[80]; int i; if ((rval = reset_all(0)) != SCPE_OK) @@ -938,8 +972,8 @@ t_stat cr_boot (int unitno, DEVICE *dptr) feedcycle(TRUE, FALSE); -// if (fxread(buf, sizeof(buf[0]), 80, cr_unit.fileref) != 80) -// return SCPE_IOERR; +/* if (fxread(buf, sizeof(buf[0]), 80, cr_unit.fileref) != 80) */ +/* return SCPE_IOERR; */ IAR = 0; /* Program Load sets IAR = 0 */ @@ -960,7 +994,7 @@ char card_to_ascii (uint16 hol) return '?'; } -// hollerith_to_ascii - provide a generic conversion for simulator debugging +/* hollerith_to_ascii - provide a generic conversion for simulator debugging */ char hollerith_to_ascii (uint16 hol) { @@ -1011,14 +1045,15 @@ static void feedcycle (t_bool load, t_bool punching) cp_count++; } - if (! load) // all we wanted to do was flush the punch + if (! load) /* all we wanted to do was flush the punch */ return; /* slide cards from reader to punch. If we know we're punching, * generate a blank card in any case. Otherwise, it should take two feed - * cycles to get a read card from the hopper to punch station */ + * cycles to get a read card from the hopper to punch station. Also when + * the reader is a 2501, we assume the 1442 is a punch only */ - if (readstate == STATION_EMPTY) { + if (readstate == STATION_EMPTY || (cr_unit.flags & UNIT_2501)) { if (punching) { memset(punchstation, 0, sizeof(punchstation)); punchstate = STATION_LOADED; @@ -1048,7 +1083,7 @@ again: /* jump here if we've loaded a new deck after emptying the previous one else if (fgets(buf, sizeof(buf), cr_unit.fileref) == NULL) /* read up to 80 chars */ nread = 0; /* hmm, end of file */ - else { /* check for newline */ + else { /* check for CRLF or newline */ if ((x = strchr(buf, '\r')) == NULL) x = strchr(buf, '\n'); @@ -1065,7 +1100,8 @@ again: /* jump here if we've loaded a new deck after emptying the previous one break; } } - nread = 80; /* take just the first 80 characters */ + if ((nread = strlen(buf)) > 80) /* use the line as read, at most 80 characters */ + nread = 80; } else nread = x-buf; /* reduce length of string */ @@ -1107,8 +1143,8 @@ again: /* jump here if we've loaded a new deck after emptying the previous one cr_unit.pos++; } } -// else -// readstate = STATION_EMPTY; +/* else */ +/* readstate = STATION_EMPTY; */ cr_unit.COLUMN = -1; /* neither device is currently cycling */ cp_unit.COLUMN = -1; @@ -1150,6 +1186,19 @@ static char * skipbl (char *str) return str; } +static char * trim (char *str) +{ + char *s, *lastnb; + + for (lastnb = str-1, s = str; *s; s++) /* point to last nonblank characteter in string */ + if (*s > ' ') + lastnb = s; + + lastnb[1] = '\0'; /* clip just after it */ + + return str; +} + /* alltrim - remove all leading and trailing whitespace from a string */ static char * alltrim (char *str) @@ -1242,46 +1291,43 @@ static t_bool nextdeck (void) if (buf[0] == '!') { /* literal text line, make a temporary file */ -#if defined (__GNUC__) && !defined (_WIN32) // GCC complains about mktemp & always provides mkstemp +#if defined (__GNUC__) && !defined (_WIN32) /* GCC complains about mktemp & always provides mkstemp */ - if (*tempfile == '\0') { // first time, open guaranteed-unique file + if (*tempfile == '\0') { /* first time, open guaranteed-unique file */ int fh; - strcpy(tempfile, "tempXXXXXX"); // get modifiable copy of name template + strcpy(tempfile, "tempXXXXXX"); /* get modifiable copy of name template */ - if ((fh = mkstemp(tempfile)) == -1) { // open file. Actual name is set by side effect + if ((fh = mkstemp(tempfile)) == -1) { /* open file. Actual name is set by side effect */ printf("Cannot create temporary deck file\n"); break_simulation(STOP_DECK_BREAK); return 0; } - // get FILE * from the file handle + /* get FILE * from the file handle */ if ((cr_unit.fileref = fdopen(fh, "w+b")) == NULL) { printf("Cannot use temporary deck file %s\n", tempfile); break_simulation(STOP_DECK_BREAK); return 0; } } - else { // on later opens, just reuse the old name + else { /* on later opens, just reuse the old name */ if ((cr_unit.fileref = fopen(tempfile, "w+b")) == NULL) { printf("Cannot create temporary file %s\n", tempfile); break_simulation(STOP_DECK_BREAK); return 0; } } -#else // ANSI standard C always provides mktemp +#else /* ANSI standard C always provides mktemp */ - if (*tempfile == '\0') { // first time, construct unique name - char *tn; - - if ((tn = mktemp("crXXXXXX")) == NULL) { + if (*tempfile == '\0') { /* first time, construct unique name */ + strcpy(tempfile, "tempXXXXXX"); /* make a modifiable copy of the template */ + if (mktemp(tempfile) == NULL) { printf("Cannot create temporary card file name\n"); break_simulation(STOP_DECK_BREAK); return 0; } - strcpy(tempfile, tn); - strcat(tempfile, ".tmp"); } - // (re)create file + /* (re)create file */ if ((cr_unit.fileref = fopen(tempfile, "w+b")) == NULL) { printf("Cannot create temporary file %s\n", tempfile); break_simulation(STOP_DECK_BREAK); @@ -1291,7 +1337,7 @@ static t_bool nextdeck (void) SETBIT(cr_unit.flags, UNIT_SCRATCH); - for (;;) { /* store literal cards into temporary file */ + for (;;) { /* store literal cards into temporary file */ upcase(buf+1); fputs(buf+1, cr_unit.fileref); putc('\n', cr_unit.fileref); @@ -1381,10 +1427,6 @@ static t_bool nextdeck (void) } } -// don't complain about this -- There are comments after the mode character in loaddms.deck -// if (*skipbl(c)) /* there should be nothing left */ -// printf("* Bad mode specifier %s after filename %s in deck file", mode, fname); - if (code == CODE_AUTO) /* otherwise if mode is auto, guess it, otherwise use default */ code = guess_cr_code(); @@ -1427,20 +1469,6 @@ static t_stat cr_reset (DEVICE *dptr) return SCPE_OK; } -// SETBIT(cr_unit.flags, UNIT_CR_EMPTY); /* assume hopper empty */ -// -// if (cr_unit.flags & UNIT_ATT) { -// if (deckfile != NULL) { /* do NOT rewind the deck file */ -// fseek(deckfile, 0, SEEK_SET); -// nextdeck(); -// } -// else -// checkdeck(); -// -// if (cr_unit.fileref != NULL) -// feedcycle(FALSE, FALSE); -// } - return SCPE_OK; } @@ -1473,7 +1501,7 @@ t_stat cr_rewind (void) cr_unit.pos = 0; - // there is a read pending. Pull the card in to make it go + /* there is a read pending. Pull the card in to make it go */ if (CURRENT_OP == OP_READING || CURRENT_OP == OP_PUNCHING || CURRENT_OP == OP_FEEDING) feedcycle(TRUE, (cp_unit.flags & UNIT_ATT) != 0); @@ -1501,8 +1529,8 @@ static t_stat cr_attach (UNIT *uptr, char *cptr) if (sim_switches & SWMASK('A')) tab_proc = EditToAsm; if (sim_switches & SWMASK('T')) tab_proc = EditToWhitespace; - // user can specify multiple names on the CR attach command if using a deck file. The deck file - // can contain %n tokens to pickup the additional name(s). + /* user can specify multiple names on the CR attach command if using a deck file. The deck file + * can contain %n tokens to pickup the additional name(s). */ c = cptr; /* extract arguments */ for (list_nargs = 0; list_nargs < MAXARGS; list_nargs++) { @@ -1579,14 +1607,10 @@ static t_stat cr_attach (UNIT *uptr, char *cptr) cr_set_code(&cr_unit, GET_CODE(cr_unit), NULL, NULL); } - // there is a read pending. Pull the card in to make it go + /* there is a read pending. Pull the card in to make it go */ if (CURRENT_OP == OP_READING || CURRENT_OP == OP_PUNCHING || CURRENT_OP == OP_FEEDING) feedcycle(TRUE, (cp_unit.flags & UNIT_ATT) != 0); -// no - don't reset the reader -// cr_reset(&cr_dev); /* reset the whole thing */ -// cp_reset(&cp_dev); - return SCPE_OK; } @@ -1644,20 +1668,35 @@ static t_stat cp_detach (UNIT *uptr) return detach_unit(uptr); } -static void op_done (void) +static void op_done (UNIT *u, t_bool issue_intr) { - if (cr_unit.flags & UNIT_DEBUG) + if (u->flags & UNIT_DEBUG) DEBUG_PRINT("!CR Op Complete, card %d", cr_count); SET_OP(OP_IDLE); - SETBIT(cr_dsw, CR_DSW_OP_COMPLETE); - CLRBIT(cr_dsw, CR_DSW_BUSY); - SETBIT(ILSW[4], ILSW_4_1442_CARD); - calc_ints(); + + if (u->flags & UNIT_2501) /* we use u-> not cr_unit. because PUNCH is always a 1442 */ + CLRBIT(cr_dsw, CR_DSW_2501_BUSY); + else + CLRBIT(cr_dsw, CR_DSW_1442_BUSY); /* this is trickier. 1442 cr and cp share a dsw */ + + if (issue_intr) { /* issue op-complete interrupt for read and punch ops but not feed */ + if (u->flags & UNIT_2501) { + SETBIT(cr_dsw, CR_DSW_2501_OP_COMPLETE); + SETBIT(ILSW[4], ILSW_4_2501_CARD); + } + else { + SETBIT(cr_dsw, CR_DSW_1442_OP_COMPLETE); + SETBIT(ILSW[4], ILSW_4_1442_CARD); + } + calc_ints(); + } } static t_stat cr_svc (UNIT *uptr) { + int i; + if (uptr->flags & UNIT_PHYSICAL) return pcr_svc(uptr); @@ -1666,7 +1705,7 @@ static t_stat cr_svc (UNIT *uptr) break; case OP_FEEDING: - op_done(); + op_done(&cr_unit, FALSE); break; case OP_READING: @@ -1675,17 +1714,27 @@ static t_stat cr_svc (UNIT *uptr) break; } - if (++cr_unit.COLUMN < 80) { - SETBIT(cr_dsw, CR_DSW_READ_RESPONSE); + if (cr_unit.flags & UNIT_2501) { /* 2501 transfers entire card then interrupts */ + for (i = 0; i < cr_cols; i++) /* (we wait until end of delay time before transferring data) */ + M[(cr_addr + i) & mem_mask] = readstation[i]; + + readstate = STATION_READ; + if (cr_unit.flags & UNIT_DEBUG) + DEBUG_PRINT("!CR Op Complete, card %d", cr_count); + + op_done(&cr_unit, TRUE); + } + else if (++cr_unit.COLUMN < 80) { /* 1442 interrupts on each column... */ + SETBIT(cr_dsw, CR_DSW_1442_READ_RESPONSE); SETBIT(ILSW[0], ILSW_0_1442_CARD); calc_ints(); sim_activate(&cr_unit, cr_wait); if (cr_unit.flags & UNIT_DEBUG) DEBUG_PRINT("!CR Read Response %d : %d", cr_count, cr_unit.COLUMN+1); } - else { + else { /* ... then issues op-complete */ readstate = STATION_READ; - op_done(); + op_done(&cr_unit, TRUE); } break; @@ -1697,10 +1746,10 @@ static t_stat cr_svc (UNIT *uptr) if (cp_unit.flags & UNIT_LASTPUNCH) { punchstate = STATION_PUNCHED; - op_done(); + op_done(&cp_unit, TRUE); } else if (++cp_unit.COLUMN < 80) { - SETBIT(cr_dsw, CR_DSW_PUNCH_RESPONSE); + SETBIT(cr_dsw, CR_DSW_1442_PUNCH_RESPONSE); SETBIT(ILSW[0], ILSW_0_1442_CARD); calc_ints(); sim_activate(&cr_unit, cp_wait); @@ -1709,7 +1758,7 @@ static t_stat cr_svc (UNIT *uptr) } else { punchstate = STATION_PUNCHED; - op_done(); + op_done(&cp_unit, TRUE); } break; } @@ -1717,6 +1766,94 @@ static t_stat cr_svc (UNIT *uptr) return SCPE_OK; } +void xio_2501_card (int32 addr, int32 func, int32 modify) +{ + char msg[80]; + int ch; + t_bool lastcard; + +/* it would be nice for simulated reader to be able to use 2501 mode -- much more + * efficient. Using the 1403 printer and 2501 reader speeds things up quite considerably. */ + + switch (func) { + case XIO_SENSE_DEV: + if (cr_unit.flags & UNIT_PHYSICAL) { + pcr_xio_sense(modify); + break; + } + +// the following part is questionable -- the 2501 might need to be more picky about setting +// the LAST_CARD bit... + + if ((cr_unit.flags & UNIT_ATT) == 0) + lastcard = TRUE; /* if nothing to read, hopper's empty */ + else if (readstate == STATION_LOADED) + lastcard = FALSE; + else if (cr_unit.fileref == NULL) + lastcard = TRUE; + else if ((ch = getc(cr_unit.fileref)) != EOF) { + ungetc(ch, cr_unit.fileref); /* put character back; hopper's not empty */ + lastcard = FALSE; + } + else if (deckfile != NULL && nextdeck()) + lastcard = FALSE; + else + lastcard = TRUE; /* there is nothing left to read for a next card */ + + CLRBIT(cr_dsw, CR_DSW_2501_LAST_CARD|CR_DSW_2501_BUSY|CR_DSW_2501_NOT_READY); + + if (lastcard) + SETBIT(cr_dsw, CR_DSW_2501_LAST_CARD|CR_DSW_2501_NOT_READY); + // don't clear it here -- modify bit must be set before last card can be cleared + + if (CURRENT_OP != OP_IDLE) + SETBIT(cr_dsw, CR_DSW_2501_BUSY|CR_DSW_2501_NOT_READY); + + ACC = cr_dsw; /* return the DSW */ + + if (cr_unit.flags & UNIT_DEBUG) + DEBUG_PRINT("#CR Sense %04x%s", cr_dsw & 0xFFFF, (modify & 1) ? " RESET" : ""); + + if (modify & 0x01) { /* reset interrupts */ +// if (! lastcard) /* (lastcard is reset only when modify bit is set) */ + CLRBIT(cr_dsw, CR_DSW_2501_LAST_CARD); + CLRBIT(cr_dsw, CR_DSW_2501_OP_COMPLETE); + CLRBIT(ILSW[4], ILSW_4_2501_CARD); + } + break; + + case XIO_INITR: + if (cr_unit.flags & UNIT_DEBUG) + DEBUG_PRINT("#CR Start read"); + + cr_unit.COLUMN = -1; + + cr_cols = M[addr & mem_mask]; /* save column count and transfer address */ + cr_addr = addr+1; + + if ((cr_cols < 0) || (cr_cols > 80)) /* this is questionable -- what would hardware do? */ + cr_cols = 80; + + if (cr_unit.flags & UNIT_PHYSICAL) { + pcr_xio_startread(); + break; + } + + if (readstate != STATION_LOADED) + feedcycle(TRUE, (cp_unit.flags & UNIT_ATT) != 0); + + SET_OP(OP_READING); + sim_cancel(&cr_unit); + sim_activate(&cr_unit, cr_wait2501); + break; + + default: + sprintf(msg, "Invalid 2501 XIO function %x", func); + xio_error(msg); + break; + } +} + void xio_1142_card (int32 addr, int32 func, int32 modify) { char msg[80]; @@ -1731,6 +1868,9 @@ void xio_1142_card (int32 addr, int32 func, int32 modify) break; } +/* glunk + * have to separate out what status is 1442 is punch only and 2501 is the reader */ + if (cp_unit.flags & UNIT_ATT) lastcard = FALSE; /* if punch file is open, assume infinite blank cards in reader */ else if ((cr_unit.flags & UNIT_ATT) == 0) @@ -1748,15 +1888,15 @@ void xio_1142_card (int32 addr, int32 func, int32 modify) else lastcard = TRUE; /* there is nothing left to read for a next card */ - CLRBIT(cr_dsw, CR_DSW_LAST_CARD|CR_DSW_BUSY|CR_DSW_NOT_READY); + CLRBIT(cr_dsw, CR_DSW_1442_LAST_CARD | CR_DSW_1442_BUSY | CR_DSW_1442_NOT_READY); if (lastcard) - SETBIT(cr_dsw, CR_DSW_LAST_CARD); + SETBIT(cr_dsw, CR_DSW_1442_LAST_CARD); if (CURRENT_OP != OP_IDLE) - SETBIT(cr_dsw, CR_DSW_BUSY|CR_DSW_NOT_READY); + SETBIT(cr_dsw, CR_DSW_1442_BUSY | CR_DSW_1442_NOT_READY); else if (readstate == STATION_EMPTY && punchstate == STATION_EMPTY && lastcard) - SETBIT(cr_dsw, CR_DSW_NOT_READY); + SETBIT(cr_dsw, CR_DSW_1442_NOT_READY); ACC = cr_dsw; /* return the DSW */ @@ -1764,12 +1904,12 @@ void xio_1142_card (int32 addr, int32 func, int32 modify) DEBUG_PRINT("#CR Sense %04x%s%s", cr_dsw & 0xFFFF, (modify & 1) ? " RESET0" : "", (modify & 2) ? " RESET4" : ""); if (modify & 0x01) { /* reset interrupts */ - CLRBIT(cr_dsw, CR_DSW_READ_RESPONSE|CR_DSW_PUNCH_RESPONSE); + CLRBIT(cr_dsw, CR_DSW_1442_READ_RESPONSE | CR_DSW_1442_PUNCH_RESPONSE); CLRBIT(ILSW[0], ILSW_0_1442_CARD); } if (modify & 0x02) { - CLRBIT(cr_dsw, CR_DSW_OP_COMPLETE); + CLRBIT(cr_dsw, CR_DSW_1442_OP_COMPLETE); CLRBIT(ILSW[4], ILSW_4_1442_CARD); } break; @@ -1786,14 +1926,14 @@ void xio_1142_card (int32 addr, int32 func, int32 modify) } else if (cr_unit.COLUMN == 80) { xio_error("1442: Read past column 80!"); - cr_unit.COLUMN++; // don't report it again + cr_unit.COLUMN++; /* don't report it again */ } } else { -// don't complain: APL\1130 issues both reads and writes on every interrupt -// (probably to keep the code small). Apparently it's just ignored if corresponding -// control didn't initiate a read cycle. -// xio_error("1442: Read when not in a read cycle!"); +/* don't complain: APL\1130 issues both reads and writes on every interrupt + * (probably to keep the code small). Apparently it's just ignored if corresponding + * control didn't initiate a read cycle. + * xio_error("1442: Read when not in a read cycle!"); */ } break; @@ -1816,14 +1956,14 @@ void xio_1142_card (int32 addr, int32 func, int32 modify) } else if (cp_unit.COLUMN == 80) { xio_error("1442: Punch past column 80!"); - cp_unit.COLUMN++; // don't report it again + cp_unit.COLUMN++; /* don't report it again */ } } else { -// don't complain: APL\1130 issues both reads and writes on every interrupt -// (probably to keep the code small). Apparently it's just ignored if corresponding -// control didn't initiate a punch cycle. -// xio_error("1442: Write when not in a punch cycle!"); +/* don't complain: APL\1130 issues both reads and writes on every interrupt + * (probably to keep the code small). Apparently it's just ignored if corresponding + * control didn't initiate a punch cycle. + * xio_error("1442: Write when not in a punch cycle!"); */ } break; @@ -1916,60 +2056,104 @@ void xio_1142_card (int32 addr, int32 func, int32 modify) #else /* - * This code supports a physical card reader interface I built. Details - * available upon request, write to brian@ibm1130.org - - * NOTE: THIS IS NOT COMPLETE OR EVEN CLOSE, JUST SOME CODE SLAMMED INTO THE FILE + * This code supports a physical card reader interface I built. Interface schematic + * and documentation can be downloaded from http://ibm1130.org/sim/downloads/cardread.zip */ #include -#define PCR_STATUS_READY 1 // bits in interface reply byte +#define PCR_STATUS_READY 1 /* bits in interface reply byte */ #define PCR_STATUS_ERROR 2 #define PCR_STATUS_HEMPTY 4 #define PCR_STATUS_EOF 8 #define PCR_STATUS_PICKING 16 -#define PCR_STATUS_MSEC 150 // when idle, get status every 150 msec +#define PCR_STATUS_MSEC 150 /* when idle, get status every 150 msec */ typedef enum { - PCR_STATE_IDLE, // nothing expected from the interface - PCR_STATE_WAIT_CMD_RESPONSE, // waiting for response from any command other than P - PCR_STATE_WAIT_PICK_CMD_RESPONSE, // waiting for response from P command - PCR_STATE_WAIT_DATA_START, // waiting for introduction to data from P command - PCR_STATE_WAIT_DATA, // waiting for data from P command - PCR_STATE_WAIT_PICK_FINAL_RESPONSE, // waiting for status byte after last of the card data + PCR_STATE_IDLE, /* nothing expected from the interface */ + PCR_STATE_WAIT_CMD_RESPONSE, /* waiting for response from any command other than P */ + PCR_STATE_WAIT_PICK_CMD_RESPONSE, /* waiting for response from P command */ + PCR_STATE_WAIT_DATA_START, /* waiting for introduction to data from P command */ + PCR_STATE_WAIT_DATA, /* waiting for data from P command */ + PCR_STATE_WAIT_PICK_FINAL_RESPONSE, /* waiting for status byte after last of the card data */ PCR_STATE_CLOSED } PCR_STATE; static void pcr_cmd (char cmd); static DWORD CALLBACK pcr_thread (LPVOID arg); -static BOOL pcr_handle_status_byte (char byte); -static BOOL pcr_handle_byte (char byte); +static BOOL pcr_handle_status_byte (int nrcvd); static void pcr_trigger_interrupt_0(void); static void begin_pcr_critical_section (void); static void end_pcr_critical_section (void); static void pcr_set_dsw_from_status (BOOL post_pick); +static t_stat pcr_open_controller (char *devname); -static PCR_STATE pcr_state = PCR_STATE_CLOSED; // current state of connection to physical card reader interface -static char pcr_status = 0; // last status byte received from the interface -static int pcr_nleft; // number of bytes still expected from pick command -static int pcr_nready; // number of bytes waiting in the input buffer for simulator to read +static PCR_STATE pcr_state = PCR_STATE_CLOSED; /* current state of connection to physical card reader interface */ +static char pcr_status = 0; /* last status byte received from the interface */ +static int pcr_nleft; /* number of bytes still expected from pick command */ +static int pcr_nready; /* number of bytes waiting in the input buffer for simulator to read */ static BOOL pcr_done; -static HANDLE hpcr = INVALID_HANDLE_VALUE; +static HANDLE hpcr = INVALID_HANDLE_VALUE; static HANDLE hPickEvent = INVALID_HANDLE_VALUE; static HANDLE hResetEvent = INVALID_HANDLE_VALUE; +static OVERLAPPED ovRd, ovWr; /* overlapped IO structures for reading from, writing to device */ +static int nwaits; /* number of timeouts waiting for response from interface */ +static char response_byte; /* buffer to receive command/status response byte from overlapped read */ +static char lastcmd = '?'; + +/* pcr_attach - perform attach function to physical card reader */ static t_stat pcr_attach (UNIT *uptr, char *devname) { - DCB dcb; - COMMTIMEOUTS cto; - DWORD nerr, thread_id; + DWORD thread_id; + t_stat rval; pcr_state = PCR_STATE_CLOSED; sim_cancel(uptr); cr_unit.COLUMN = -1; /* device is not currently cycling */ + if ((rval = pcr_open_controller(devname)) != SCPE_OK) + return rval; + + if (hPickEvent == INVALID_HANDLE_VALUE) + hPickEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + + if (hResetEvent == INVALID_HANDLE_VALUE) + hResetEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + + pcr_status = PCR_STATUS_HEMPTY; /* set default status: offline, no cards */ + pcr_state = PCR_STATE_IDLE; + pcr_done = FALSE; + cr_dsw = CR_DSW_1442_LAST_CARD | CR_DSW_1442_NOT_READY; + + set_active_cr_code(CODE_BINARY); /* force binary mode */ + + if (CreateThread(NULL, 0, pcr_thread, NULL, 0, &thread_id) == NULL) { + pcr_state = PCR_STATE_CLOSED; + CloseHandle(hpcr); + hpcr = INVALID_HANDLE_VALUE; + printf("Error creating card reader thread\n"); + return SCPE_IERR; + } + + SETBIT(uptr->flags, UNIT_PHYSICAL|UNIT_ATT); /* mark device as attached */ + uptr->filename = malloc(strlen(devname)+1); + strcpy(uptr->filename, devname); + + return SCPE_OK; +} + +/* pcr_open_controller - open the USB device's virtual COM port and configure the interface */ + +static t_stat pcr_open_controller (char *devname) +{ + DCB dcb; + COMMTIMEOUTS cto; + DWORD nerr; + + if (hpcr != INVALID_HANDLE_VALUE) + return SCPE_OK; /* open the COM port */ hpcr = CreateFile(devname, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (hpcr == INVALID_HANDLE_VALUE) @@ -2003,12 +2187,6 @@ static t_stat pcr_attach (UNIT *uptr, char *devname) dcb.EofChar = 0; dcb.EvtChar = 0; - if (hPickEvent == INVALID_HANDLE_VALUE) - hPickEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - - if (hResetEvent == INVALID_HANDLE_VALUE) - hResetEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - if (! SetCommState(hpcr, &dcb)) { CloseHandle(hpcr); hpcr = INVALID_HANDLE_VALUE; @@ -2016,12 +2194,12 @@ static t_stat pcr_attach (UNIT *uptr, char *devname) return SCPE_OPENERR; } - cto.ReadIntervalTimeout = 100; // stop if 100 msec elapses between two received bytes - cto.ReadTotalTimeoutMultiplier = 0; // no length sensitivity - cto.ReadTotalTimeoutConstant = 400; // allow 400 msec for a read (reset command can take a while) + cto.ReadIntervalTimeout = 100; /* stop if 100 msec elapses between two received bytes */ + cto.ReadTotalTimeoutMultiplier = 0; /* no length sensitivity */ + cto.ReadTotalTimeoutConstant = 400; /* allow 400 msec for a read (reset command can take a while) */ cto.WriteTotalTimeoutMultiplier = 0; - cto.WriteTotalTimeoutConstant = 200; // allow 200 msec for a write + cto.WriteTotalTimeoutConstant = 200; /* allow 200 msec for a write */ if (! SetCommTimeouts(hpcr, &cto)) { CloseHandle(hpcr); @@ -2033,79 +2211,83 @@ static t_stat pcr_attach (UNIT *uptr, char *devname) PurgeComm(hpcr, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR); ClearCommError(hpcr, &nerr, NULL); - pcr_status = PCR_STATUS_HEMPTY; // set default status: offline, no cards - pcr_state = PCR_STATE_IDLE; - pcr_done = FALSE; - cr_dsw = CR_DSW_LAST_CARD | CR_DSW_NOT_READY; - - set_active_cr_code(CODE_BINARY); // force binary mode - - if (CreateThread(NULL, 0, pcr_thread, NULL, 0, &thread_id) == NULL) { - pcr_state = PCR_STATE_CLOSED; - CloseHandle(hpcr); - hpcr = INVALID_HANDLE_VALUE; - printf("Error creating card reader thread\n"); - return SCPE_IERR; - } - - SETBIT(uptr->flags, UNIT_PHYSICAL|UNIT_ATT); // mark device as attached - uptr->filename = malloc(strlen(devname)+1); - strcpy(uptr->filename, devname); - return SCPE_OK; } +/* pcr_detach - detach physical reader from CR device */ + static t_stat pcr_detach (UNIT *uptr) { if (cr_unit.flags & UNIT_ATT) { - CloseHandle(hpcr); // close the COM port (this will lead to the thread closing) + CloseHandle(hpcr); /* close the COM port (this will lead to the thread closing) */ hpcr = INVALID_HANDLE_VALUE; pcr_state = PCR_STATE_CLOSED; - free(uptr->filename); // release the name copy + free(uptr->filename); /* release the name copy */ uptr->filename = NULL; } - CLRBIT(cr_unit.flags, UNIT_PHYSICAL|UNIT_ATT); // drop the attach and physical bits + CLRBIT(cr_unit.flags, UNIT_PHYSICAL|UNIT_ATT); /* drop the attach and physical bits */ return SCPE_OK; } +/* pcr_xio_sense - perform XIO sense function on physical card reader */ + static void pcr_xio_sense (int modify) { - if (modify & 0x01) { // reset simulated interrupts - CLRBIT(cr_dsw, CR_DSW_READ_RESPONSE|CR_DSW_PUNCH_RESPONSE); + if (modify & 0x01) { /* reset simulated interrupts */ + CLRBIT(cr_dsw, CR_DSW_1442_READ_RESPONSE | CR_DSW_1442_PUNCH_RESPONSE); CLRBIT(ILSW[0], ILSW_0_1442_CARD); } if (modify & 0x02) { - CLRBIT(cr_dsw, CR_DSW_OP_COMPLETE); + CLRBIT(cr_dsw, CR_DSW_1442_OP_COMPLETE); CLRBIT(ILSW[4], ILSW_4_1442_CARD); } - ACC = cr_dsw; // DSW was set in real-time, just return the DSW + ACC = cr_dsw; /* DSW was set in real-time, just return the DSW */ if (cr_unit.flags & UNIT_DEBUG) DEBUG_PRINT("#CR Sense %04x%s%s", cr_dsw, (modify & 1) ? " RESET0" : "", (modify & 2) ? " RESET4" : ""); } -// pcr_thread - thread to handle receive side of card reader interface communications +/* report_error - issue detailed report of Windows IO error */ -static OVERLAPPED ovRd, ovWr; -int nwaits; -char response_byte; +static void report_error (char *msg, DWORD err) +{ + char *lpMessageBuffer = NULL; + + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* The user default language */ + (LPTSTR) &lpMessageBuffer, + 0, + NULL ); + + printf("GetOverlappedResult failed, %s, %s\n", + msg, lpMessageBuffer); + + LocalFree(lpMessageBuffer); +} + +/* pcr_thread - thread to handle card reader interface communications */ static DWORD CALLBACK pcr_thread (LPVOID arg) { - DWORD event, nrcvd, nread; + DWORD event; + long nrcvd, nread, nwritten; HANDLE objs[4]; BOOL pick_queued = FALSE, reset_queued = FALSE; - + nwaits = 0; ZeroMemory(&ovRd, sizeof(ovRd)); ZeroMemory(&ovWr, sizeof(ovWr)); - ovRd.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // create an event for async IO reads - ovWr.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // create an event for async IO writes + ovRd.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); /* create an event for async IO reads */ + ovWr.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); /* create an event for async IO writes */ objs[0] = ovRd.hEvent; objs[1] = ovWr.hEvent; @@ -2130,20 +2312,29 @@ static DWORD CALLBACK pcr_thread (LPVOID arg) event = WaitForMultipleObjects(4, objs, FALSE, PCR_STATUS_MSEC); switch (event) { - case WAIT_OBJECT_0+0: // read complete + case WAIT_OBJECT_0+0: /* read complete */ ResetEvent(ovRd.hEvent); + if (! GetOverlappedResult(hpcr, &ovRd, &nrcvd, TRUE)) + report_error("PCR_Read", GetLastError()); + else if (cr_unit.flags & UNIT_DEBUG) + printf("PCR_Read: event, %d rcvd\n", nrcvd); break; - case WAIT_OBJECT_0+1: // write complete + case WAIT_OBJECT_0+1: /* write complete */ + nwritten = 0; ResetEvent(ovWr.hEvent); + if (! GetOverlappedResult(hpcr, &ovWr, &nwritten, TRUE)) + report_error("PCR_Write", GetLastError()); + else if (cr_unit.flags & UNIT_DEBUG) + printf("PCR_Write: event, %d sent\n", nwritten); continue; - case WAIT_OBJECT_0+2: // reset request from simulator + case WAIT_OBJECT_0+2: /* reset request from simulator */ reset_queued = TRUE; pick_queued = FALSE; continue; - case WAIT_OBJECT_0+3: // pick request from simulator + case WAIT_OBJECT_0+3: /* pick request from simulator */ pick_queued = TRUE; continue; @@ -2165,60 +2356,65 @@ static DWORD CALLBACK pcr_thread (LPVOID arg) continue; } - // read data is ready + /* We only get here if read event occurred */ switch (pcr_state) { - case PCR_STATE_IDLE: // nothing expected from the interface + case PCR_STATE_IDLE: /* nothing expected from the interface */ PurgeComm(hpcr, PURGE_RXCLEAR|PURGE_RXABORT); break; - case PCR_STATE_WAIT_CMD_RESPONSE: // waiting for response from any command other than P - if (pcr_handle_status_byte(response_byte)) + case PCR_STATE_WAIT_CMD_RESPONSE: /* waiting for response from any command other than P */ + if (pcr_handle_status_byte(nrcvd)) pcr_state = PCR_STATE_IDLE; break; - case PCR_STATE_WAIT_PICK_CMD_RESPONSE: // waiting for response from P command - if (pcr_handle_status_byte(response_byte)) { + case PCR_STATE_WAIT_PICK_CMD_RESPONSE: /* waiting for response from P command */ + if (pcr_handle_status_byte(nrcvd)) { + pcr_cmd('\0'); /* queue a response read */ pcr_state = PCR_STATE_WAIT_DATA_START; - pcr_cmd('\0'); // queue a response read } break; - case PCR_STATE_WAIT_DATA_START: // waiting for leadin character from P command (= or !) - if (! pcr_handle_byte(response_byte)) - continue; // this could take a very long time + case PCR_STATE_WAIT_DATA_START: /* waiting for leadin character from P command (= or !) */ + if (nrcvd <= 0) { /* (this could take an indefinite amount of time) */ + if (cr_unit.flags & UNIT_DEBUG) + printf("PCR: NO RESP YET\n"); + + continue; /* reader is not ready */ + } + + if (cr_unit.flags & UNIT_DEBUG) /* (this could take an indefinite amount of time) */ + printf("PCR: GOT %c\n", response_byte); switch (response_byte) { - case '=': // = means pick in progress, 160 bytes of data will be coming + case '=': /* = means pick in progress, 160 bytes of data will be coming */ pcr_state = PCR_STATE_WAIT_DATA; ovRd.Offset = ovRd.OffsetHigh = 0; - nread = 20; // initiate a read + nread = 20; /* initiate a read */ ReadFile(hpcr, ((char *) readstation), nread, &nrcvd, &ovRd); break; - case '!': // ! means pick has been canceled, status will be coming next + case '!': /* ! means pick has been canceled, status will be coming next */ pcr_state = PCR_STATE_WAIT_CMD_RESPONSE; - pcr_cmd('\0'); // initiate read + pcr_cmd('\0'); /* initiate read */ break; - default: // anything else is a datacomm error, or something - // indicate read check or something -// pcr_state = PCR_STATE_IDLE; + default: /* anything else is a datacomm error, or something */ + /* indicate read check or something */ +/* pcr_state = PCR_STATE_IDLE; */ break; } - break; - case PCR_STATE_WAIT_DATA: // waiting for data from P command - GetOverlappedResult(hpcr, &ovRd, &nrcvd, TRUE); + case PCR_STATE_WAIT_DATA: /* waiting for data from P command */ if (cr_unit.flags & UNIT_DEBUG) printf((nrcvd <= 0) ? "PCR: NO RESP!\n" : "PCR: GOT %d BYTES\n", nrcvd); if (nrcvd > 0) { - pcr_nleft -= (int) nrcvd; + pcr_nleft -= nrcvd; begin_pcr_critical_section(); - pcr_nready += (int) nrcvd; + pcr_nready += nrcvd; end_pcr_critical_section(); } @@ -2229,12 +2425,12 @@ static DWORD CALLBACK pcr_thread (LPVOID arg) } else { pcr_state = PCR_STATE_WAIT_PICK_FINAL_RESPONSE; - pcr_cmd('\0'); // queue read + pcr_cmd('\0'); /* queue read */ } break; - case PCR_STATE_WAIT_PICK_FINAL_RESPONSE: // waiting for status byte after last of the card data - if (pcr_handle_status_byte(response_byte)) { + case PCR_STATE_WAIT_PICK_FINAL_RESPONSE: /* waiting for status byte after last of the card data */ + if (pcr_handle_status_byte(nrcvd)) { readstate = STATION_READ; pcr_state = PCR_STATE_IDLE; pcr_done = TRUE; @@ -2249,40 +2445,51 @@ static DWORD CALLBACK pcr_thread (LPVOID arg) return 0; } -static char lastcmd = '?'; +/* pcr_cmd - issue command byte to interface. Read of response byte is queued */ static void pcr_cmd (char cmd) { - DWORD nwrite, nrcvd; + long nwritten, nrcvd; + int status; if (cmd != '\0') { - if (cr_unit.flags & UNIT_DEBUG && (cmd != 'S' || cmd != lastcmd)) + if (cr_unit.flags & UNIT_DEBUG /* && (cmd != 'S' || cmd != lastcmd) */) printf("PCR: SENT %c\n", cmd); lastcmd = cmd; ResetEvent(ovWr.hEvent); ovWr.Offset = ovWr.OffsetHigh = 0; - WriteFile(hpcr, &cmd, 1, &nwrite, &ovWr); + status = WriteFile(hpcr, &cmd, 1, &nwritten, &ovWr); + if (status == 0 && GetLastError() != ERROR_IO_PENDING) + printf("Error initiating write in pcr_cmd\n"); } ovRd.Offset = ovRd.OffsetHigh = 0; - ReadFile(hpcr, &response_byte, 1, &nrcvd, &ovRd); // if no bytes ready, just return -- a later wait-event will catch it + status = ReadFile(hpcr, &response_byte, 1, &nrcvd, &ovRd); /* if no bytes ready, just return -- a later wait-event will catch it */ + if (status == 0 && GetLastError() != ERROR_IO_PENDING) + printf("Error initiating read in pcr_cmd\n"); + +/* if (cr_unit.flags & UNIT_DEBUG) + * if (nrcvd == 0) + * printf("PCR: NO RESPONSE\n"); + * else + * printf("PCR: RESPONSE %c\n", response_byte); */ nwaits = 0; } -static BOOL pcr_handle_status_byte (char byte) +/* pcr_handle_status_byte - handle completion of read of response byte */ + +static BOOL pcr_handle_status_byte (int nrcvd) { - DWORD nrcvd; static char prev_status = '?'; BOOL show; - GetOverlappedResult(hpcr, &ovRd, &nrcvd, TRUE); if (nrcvd <= 0) return FALSE; - pcr_status = byte; // save new status + pcr_status = response_byte; /* save new status */ show = lastcmd != 'S' || pcr_status != prev_status; @@ -2296,37 +2503,27 @@ static BOOL pcr_handle_status_byte (char byte) return TRUE; } +/* pcr_set_dsw_from_status - construct device status word from current physical reader status */ + static void pcr_set_dsw_from_status (BOOL post_pick) { - // set 1130 status word bits - CLRBIT(cr_dsw, CR_DSW_LAST_CARD|CR_DSW_BUSY|CR_DSW_NOT_READY|CR_DSW_ERROR_CHECK); + /* set 1130 status word bits */ + CLRBIT(cr_dsw, CR_DSW_1442_LAST_CARD | CR_DSW_1442_BUSY | CR_DSW_1442_NOT_READY | CR_DSW_1442_ERROR_CHECK); if (pcr_status & PCR_STATUS_HEMPTY) - SETBIT(cr_dsw, CR_DSW_LAST_CARD|CR_DSW_NOT_READY); + SETBIT(cr_dsw, CR_DSW_1442_LAST_CARD | CR_DSW_1442_NOT_READY); if (pcr_status & PCR_STATUS_ERROR) - SETBIT(cr_dsw, CR_DSW_ERROR_CHECK); + SETBIT(cr_dsw, CR_DSW_1442_ERROR_CHECK); - // we have a problem -- ready doesn't come back up right away after a pick. - // I think I'll fudge this and not set NOT_READY immediately after a pick + /* we have a problem -- ready doesn't come back up right away after a pick. */ + /* I think I'll fudge this and not set NOT_READY immediately after a pick */ if ((! post_pick) && ! (pcr_status & PCR_STATUS_READY)) - SETBIT(cr_dsw, CR_DSW_NOT_READY); + SETBIT(cr_dsw, CR_DSW_1442_NOT_READY); if (CURRENT_OP != OP_IDLE) - SETBIT(cr_dsw, CR_DSW_BUSY|CR_DSW_NOT_READY); -} - -static BOOL pcr_handle_byte (char byte) -{ - DWORD nrcvd; - - GetOverlappedResult(hpcr, &ovRd, &nrcvd, TRUE); - - if (cr_unit.flags & UNIT_DEBUG) - printf((nrcvd <= 0) ? "PCR: NO RESP!\n" : "PCR: GOT %c\n", byte); - - return nrcvd > 0; + SETBIT(cr_dsw, CR_DSW_1442_BUSY | CR_DSW_1442_NOT_READY); } static void pcr_xio_feedcycle (void) @@ -2334,7 +2531,7 @@ static void pcr_xio_feedcycle (void) SET_OP(OP_FEEDING); cr_unit.COLUMN = -1; SetEvent(hPickEvent); - sim_activate(&cr_unit, cr_wait); // keep checking frequently + sim_activate(&cr_unit, cr_wait); /* keep checking frequently */ } static void pcr_xio_startread (void) @@ -2344,26 +2541,26 @@ static void pcr_xio_startread (void) pcr_nleft = 160; pcr_nready = 0; SetEvent(hPickEvent); - sim_activate(&cr_unit, cr_wait); // keep checking frequently + sim_activate(&cr_unit, cr_wait); /* keep checking frequently */ } static void pcr_reset (void) { - pcr_status = PCR_STATUS_HEMPTY; // set default status: offline, no cards + pcr_status = PCR_STATUS_HEMPTY; /* set default status: offline, no cards */ pcr_state = PCR_STATE_IDLE; - cr_dsw = CR_DSW_LAST_CARD | CR_DSW_NOT_READY; + cr_dsw = CR_DSW_1442_LAST_CARD | CR_DSW_1442_NOT_READY; sim_cancel(&cr_unit); SetEvent(hResetEvent); } -// pcr_trigger_interrupt_0 - simulate a read response interrupt so OS will read queued column data +/* pcr_trigger_interrupt_0 - simulate a read response interrupt so OS will read queued column data */ static void pcr_trigger_interrupt_0 (void) { if (++cr_unit.COLUMN < 80) { - SETBIT(cr_dsw, CR_DSW_READ_RESPONSE); + SETBIT(cr_dsw, CR_DSW_1442_READ_RESPONSE); SETBIT(ILSW[0], ILSW_0_1442_CARD); calc_ints(); @@ -2383,28 +2580,29 @@ static t_stat pcr_svc (UNIT *uptr) break; case OP_READING: - if (pcr_nready >= 2) { // if there is a whole column buffered, simulate column interrupt + if (pcr_nready >= 2) { /* if there is a whole column buffered, simulate column interrupt/* pcr_trigger_interrupt_0 - simulate a read response interrupt so OS will read queued column data */ + pcr_trigger_interrupt_0(); - sim_activate(&cr_unit, cr_wait); // keep checking frequently + sim_activate(&cr_unit, cr_wait); /* keep checking frequently */ } else if (pcr_done) { pcr_done = FALSE; cr_count++; - op_done(); + op_done(&cr_unit, TRUE); pcr_set_dsw_from_status(TRUE); } else - sim_activate(&cr_unit, cr_wait); // keep checking frequently + sim_activate(&cr_unit, cr_wait); /* keep checking frequently */ break; case OP_FEEDING: if (pcr_done) { cr_count++; - op_done(); + op_done(&cr_unit, FALSE); pcr_set_dsw_from_status(TRUE); } else - sim_activate(&cr_unit, cr_wait); // keep checking frequently + sim_activate(&cr_unit, cr_wait); /* keep checking frequently */ break; @@ -2435,3 +2633,4 @@ static void end_pcr_critical_section (void) } #endif + diff --git a/Ibm1130/ibm1130_defs.h b/Ibm1130/ibm1130_defs.h index ef2a7a5b..36963a6a 100644 --- a/Ibm1130/ibm1130_defs.h +++ b/Ibm1130/ibm1130_defs.h @@ -27,11 +27,11 @@ #define MAX(a,b) (((a) >= (b)) ? (a) : (b)) #ifndef _WIN32 - int strnicmp (char *a, char *b, int n); - int strcmpi (char *a, char *b); + int strnicmp (const char *a, const char *b, int n); + int strcmpi (const char *a, const char *b); #endif -// #define GUI_SUPPORT // uncomment to compile the GUI extensions. It's defined in the windows ibm1130.mak makefile +/* #define GUI_SUPPORT uncomment to compile the GUI extensions. It's defined in the windows ibm1130.mak makefile */ /* ------------------------------------------------------------------------ */ /* Architectural constants */ @@ -40,14 +40,13 @@ #define INIMEMSIZE (16384) /* 16Kwords */ #define MEMSIZE (cpu_unit.capac) -#define UNIT_MSIZE (1 << (UNIT_V_UF + 7)) /* flag for memory size setting */ - #define ILL_ADR_FLAG 0x40000000 /* an impossible 1130 address */ /* ------------------------------------------------------------------------ */ /* Global state */ -extern int cgi; // TRUE if we are running as a CGI program +extern int cgi; /* TRUE if we are running as a CGI program */ +extern int cgiwritable; /* TRUE if we can write the disk images back to the image file in CGI mode */ extern int sim_gui; extern uint16 M[]; /* core memory, up to 32Kwords (note: don't even think about trying 64K) */ @@ -58,6 +57,7 @@ extern int32 SAR, SBR; /* storage address/buffer registers */ extern int32 OP, TAG, CCC; /* instruction decoded pieces */ extern int32 CES; /* console entry switches */ extern int32 ACC, EXT; /* accumulator and extension */ +extern int32 ARF; /* arithmetic factor register, a nonaddressable internal CPU register */ extern int32 RUNMODE; /* processor run/step mode */ extern int32 ipl; /* current interrupt level (-1 = not handling irq) */ extern int32 iplpending; /* interrupted IPL's */ @@ -71,9 +71,11 @@ extern int32 int_mask; /* current active interrupt mask (ipl sensitive) */ extern int32 mem_mask; extern int32 cpu_dsw; /* CPU device status word */ extern int32 sim_int_char; /* interrupt character */ +extern int32 con_dsw; /* has program stop and int run bits */ extern t_bool running; extern t_bool power; extern t_bool cgi; /* TRUE if we are running as a CGI program */ +extern t_bool cgiwritable; /* TRUE if we can write to the disk image file in CGI mode */ extern t_stat reason; /* CPU execution loop control */ #define WAIT_OP 1 /* wait state causes: wait instruction, invalid instruction*/ @@ -131,15 +133,19 @@ void WriteW (int32 a, int32 d); #define STOP_PHASE_BREAK 7 /* phase load break */ #define STOP_CRASH 8 /* program has crashed badly */ #define STOP_TIMED_OUT 9 /* simulation time limit exceeded */ +#define STOP_IMMEDIATE 10 /* simulator stop key pressed (immediate stop) */ +#define STOP_BREAK 11 /* simulator break key pressed */ +#define STOP_STEP 12 /* step count expired */ +#define STOP_OTHER 13 /* other reason, probably error returned by sim_process_event() */ #define IORETURN(f,v) ((f)? (v): SCPE_OK) /* cond error return */ -#define INT_REQ_0 0x01 /* bits for interrupt levels (ipl, iplpending, int_req, int_mask) */ -#define INT_REQ_1 0x02 -#define INT_REQ_2 0x04 -#define INT_REQ_3 0x08 -#define INT_REQ_4 0x10 -#define INT_REQ_5 0x20 +#define INT_REQ_5 0x01 /* bits for interrupt levels (ipl, iplpending, int_req, int_mask) */ +#define INT_REQ_4 0x02 +#define INT_REQ_3 0x04 +#define INT_REQ_2 0x08 +#define INT_REQ_1 0x10 +#define INT_REQ_0 0x20 #define XIO_UNUSED 0x00 /* XIO commands */ #define XIO_WRITE 0x01 @@ -156,7 +162,7 @@ void WriteW (int32 a, int32 d); #define ILSW_0_1442_CARD 0x8000 /* ILSW 0 is not really defined on the 1130 */ -#define ILSW_1_1132_PRINTER 0x8000 // had these backwards! +#define ILSW_1_1132_PRINTER 0x8000 /* had these backwards! */ #define ILSW_1_SCA 0x4000 #define ILSW_2_1131_DISK 0x8000 @@ -215,13 +221,13 @@ void WriteW (int32 a, int32 d); #define ILSW_4_SAC_BIT_09 0x0040 #define ILSW_4_SAC_BIT_10 0x0020 #define ILSW_4_SAC_BIT_11 0x0010 +#define ILSW_4_T2741_TERMINAL 0x0010 /* APL\1130 nonstandard serial interface uses this bit */ #define ILSW_4_SAC_BIT_12 0x0008 #define ILSW_4_SAC_BIT_13 0x0004 #define ILSW_4_SAC_BIT_14 0x0002 #define ILSW_4_SAC_BIT_15 0x0001 -#define ILSW_5_INT_RUN 0x8000 -#define ILSW_5_PROGRAM_STOP 0x8000 +#define ILSW_5_INT_RUN_PROGRAM_STOP 0x8000 /* this replaces both ILSW_5_INT_RUN and ILSW_5_PROGRAM_STOP */ #define ILSW_5_SAC_BIT_01 0x4000 #define ILSW_5_SAC_BIT_02 0x2000 #define ILSW_5_SAC_BIT_03 0x1000 @@ -238,26 +244,27 @@ void WriteW (int32 a, int32 d); #define ILSW_5_SAC_BIT_14 0x0002 #define ILSW_5_SAC_BIT_15 0x0001 -//* CPU DSW bits +/* CPU DSW bits */ #define CPU_DSW_PROGRAM_STOP 0x8000 #define CPU_DSW_INT_RUN 0x4000 /* prototypes: xio handlers */ -void xio_1131_console (int32 addr, int32 func, int32 modify); // console keyboard and printer -void xio_1142_card (int32 addr, int32 func, int32 modify); // standard card reader/punch -void xio_1134_papertape (int32 addr, int32 func, int32 modify); // paper tape reader/punch -void xio_disk (int32 addr, int32 func, int32 modify, int drv); // internal CPU disk -void xio_1627_plotter (int32 addr, int32 func, int32 modify); // XY plotter -void xio_1132_printer (int32 addr, int32 func, int32 modify); // standard line printer -void xio_1131_switches (int32 addr, int32 func, int32 modify); // console buttons & switches -void xio_1231_optical (int32 addr, int32 func, int32 modify); // optical mark page reader -void xio_2501_card (int32 addr, int32 func, int32 modify); // alternate high-speed card reader -void xio_1131_synch (int32 addr, int32 func, int32 modify); // synchronous communications adapter -void xio_system7 (int32 addr, int32 func, int32 modify); // system/7 interprocessor IO link -void xio_1403_printer (int32 addr, int32 func, int32 modify); // alternate high-speed printer -void xio_2250_display (int32 addr, int32 func, int32 modify); // vector display processor +void xio_1131_console (int32 addr, int32 func, int32 modify); /* console keyboard and printer */ +void xio_1142_card (int32 addr, int32 func, int32 modify); /* standard card reader/punch */ +void xio_1134_papertape (int32 addr, int32 func, int32 modify); /* paper tape reader/punch */ +void xio_disk (int32 addr, int32 func, int32 modify, int drv); /* internal CPU disk */ +void xio_1627_plotter (int32 addr, int32 func, int32 modify); /* XY plotter */ +void xio_1132_printer (int32 addr, int32 func, int32 modify); /* standard line printer */ +void xio_1131_switches (int32 addr, int32 func, int32 modify); /* console buttons & switches */ +void xio_1231_optical (int32 addr, int32 func, int32 modify); /* optical mark page reader */ +void xio_2501_card (int32 addr, int32 func, int32 modify); /* alternate high-speed card reader */ +void xio_sca (int32 addr, int32 func, int32 modify); /* synchronous communications adapter */ +void xio_system7 (int32 addr, int32 func, int32 modify); /* system/7 interprocessor IO link */ +void xio_1403_printer (int32 addr, int32 func, int32 modify); /* alternate high-speed printer */ +void xio_2250_display (int32 addr, int32 func, int32 modify); /* vector display processor */ +void xio_t2741_terminal (int32 addr, int32 func, int32 modify); /* IO selectric via nonstandard serial interface for APL */ void xio_error (char *msg); void bail (char *msg); @@ -267,6 +274,8 @@ t_stat cr_rewind (void); t_stat cr_detach (UNIT *uptr); void calc_ints (void); /* recalculate interrupt bitmask */ void trace_io (char *fmt, ...); /* debugging printout */ +void trace_both (char *fmt, ...); /* debugging printout */ +t_stat register_cmd (char *name, t_stat (*action)(int32 flag, char *ptr), int arg, char *help); void scp_panic (char *msg); /* bail out of simulator */ char *upcase(char *str); void break_simulation (t_stat reason); /* let a device halt the simulation */ diff --git a/Ibm1130/ibm1130_disk.c b/Ibm1130/ibm1130_disk.c index ad49a97c..52dc8525 100644 --- a/Ibm1130/ibm1130_disk.c +++ b/Ibm1130/ibm1130_disk.c @@ -14,6 +14,13 @@ commands may NOT be accurate. This should probably be fixed. * or modifications. * * Revision History + * 05-dec-06 Added cgiwritable mode + * + * 19-Dec-05 We no longer issue an operation complete interrupt if an INITR, INITW + * or CONTROL operation is attemped on a drive that is not online. DATA_ERROR + * is now only indicated in the DSW when + * + * 02-Nov-04 Addes -s option to boot to leave switches alone. * 15-jun-03 moved actual read on XIO read to end of time interval, * as the APL boot card required 2 instructions to run between the * time read was initiated and the time the data was read (a jump and a wait) @@ -29,7 +36,7 @@ commands may NOT be accurate. This should probably be fixed. #include "ibm1130_defs.h" #include "memory.h" -#define TRACE_DMS_IO // define to enable debug of DMS phase IO +#define TRACE_DMS_IO /* define to enable debug of DMS phase IO */ #ifdef TRACE_DMS_IO extern int32 sim_switches; @@ -86,7 +93,7 @@ static t_stat dsk_attach (UNIT *uptr, char *cptr); static t_stat dsk_detach (UNIT *uptr); static t_stat dsk_boot (int unitno, DEVICE *dptr); -static void diskfail (UNIT *uptr, int errflag); +static void diskfail (UNIT *uptr, int dswflag, int unitflag, t_bool do_interrupt); /* DSK data structures @@ -180,16 +187,17 @@ extern void void_backtrace (int afrom, int ato); void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv) { int i, rev, nsteps, newcyl, sec, nwords; - uint32 newpos; // changed from t_addr to uint32 in anticipation of simh 64-bit development + uint32 newpos; /* changed from t_addr to uint32 in anticipation of simh 64-bit development */ char msg[80]; UNIT *uptr = dsk_unit+drv; int16 buf[DSK_NUMWD]; - if (! BETWEEN(drv, 0, DSK_NUMDR-1)) { // hmmm, invalid drive */ - if (func != XIO_SENSE_DEV) { // tried to use it, too - // just do nothing, as if the controller isn't there. NAMCRA at N0116300 tests for drives by attempting reads -// sprintf(msg, "Op %x on invalid drive number %d", func, drv); -// xio_error(msg); + if (! BETWEEN(drv, 0, DSK_NUMDR-1)) { /* hmmm, invalid drive */ + if (func != XIO_SENSE_DEV) { /* tried to use it, too */ + /* just do nothing, as if the controller isn't there. NAMCRA at N0116300 tests for drives by attempting reads + sprintf(msg, "Op %x on invalid drive number %d", func, drv); + xio_error(msg); + */ } return; } @@ -199,7 +207,7 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv) switch (func) { case XIO_INITR: if (! IS_ONLINE(uptr)) { /* disk is offline */ - diskfail(uptr, UNIT_HARDERR); /* make error stick till reset or attach */ + diskfail(uptr, 0, 0, FALSE); break; } @@ -219,11 +227,12 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv) sec = modify & 0x07; /* get sector on cylinder */ if ((modify & 0x0080) == 0) { /* it's a real read if it's not a read check */ - // ah. We have a problem. The APL boot card counts on there being time for at least one - // more instruction to execute between the XIO read and the time the data starts loading - // into core. So, we have to defer the actual read operation a bit. Might as well wait - // until it's time to issue the operation complete interrupt. This means saving the - // IO information, then performing the actual read in dsk_svc. + /* ah. We have a problem. The APL boot card counts on there being time for at least one + * more instruction to execute between the XIO read and the time the data starts loading + * into core. So, we have to defer the actual read operation a bit. Might as well wait + * until it's time to issue the operation complete interrupt. This means saving the + * IO information, then performing the actual read in dsk_svc. + */ newpos = (uptr->CYL*DSK_NUMSC*DSK_NUMSF + sec)*2*DSK_NUMWD; @@ -248,12 +257,12 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv) case XIO_INITW: if (! IS_ONLINE(uptr)) { /* disk is offline */ - diskfail(uptr, UNIT_HARDERR); /* make error stick till reset or attach */ + diskfail(uptr, 0, 0, FALSE); break; } - if (uptr->flags & UNIT_RONLY) { /* oops, write to RO disk? permanent error */ - diskfail(uptr, UNIT_HARDERR); + if (uptr->flags & UNIT_RONLY) { /* oops, write to RO disk? permanent error until disk is powered off/on */ + diskfail(uptr, DSK_DSW_DATA_ERROR, UNIT_HARDERR, FALSE); break; } @@ -312,7 +321,7 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv) case XIO_CONTROL: /* step fwd/rev */ if (! IS_ONLINE(uptr)) { - diskfail(uptr, UNIT_HARDERR); + diskfail(uptr, 0, 0, FALSE); break; } @@ -364,19 +373,24 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv) /* diskfail - schedule an operation complete that sets the error bit */ -static void diskfail (UNIT *uptr, int errflag) +static void diskfail (UNIT *uptr, int dswflag, int unitflag, t_bool do_interrupt) { + int drv = uptr - dsk_unit; + sim_cancel(uptr); /* cancel any pending ops */ - SETBIT(uptr->flags, errflag); /* set the error flag */ + SETBIT(dsk_dsw[drv], dswflag); /* set any specified DSW bits */ + SETBIT(uptr->flags, unitflag); /* set any specified unit flag bits */ uptr->FUNC = DSK_FUNC_FAILED; /* tell svc routine why it failed */ - sim_activate(uptr, 1); /* schedule an immediate op complete interrupt */ + + if (do_interrupt) + sim_activate(uptr, 1); /* schedule an immediate op complete interrupt */ } t_stat dsk_svc (UNIT *uptr) { int drv = uptr - dsk_unit, i, nwords, sec; int16 buf[DSK_NUMWD]; - uint32 newpos; // changed from t_addr to uint32 in anticipation of simh 64-bit development + uint32 newpos; /* changed from t_addr to uint32 in anticipation of simh 64-bit development */ int32 iocc_addr; if (uptr->FUNC == DSK_FUNC_IDLE) /* service function called with no activity? not good, but ignore */ @@ -415,16 +429,16 @@ t_stat dsk_svc (UNIT *uptr) dsk_lastio[drv] = IO_READ; uptr->pos = newpos; } - fxread(buf, 2, DSK_NUMWD, uptr->fileref); // read whole sector so we're in position for next read + fxread(buf, 2, DSK_NUMWD, uptr->fileref); /* read whole sector so we're in position for next read */ uptr->pos = newpos + 2*DSK_NUMWD; } - void_backtrace(iocc_addr, iocc_addr + nwords - 1); // mark prev instruction as altered + void_backtrace(iocc_addr, iocc_addr + nwords - 1); /* mark prev instruction as altered */ trace_io("* DSK%d read %d words from %d.%d (%x, %x) to M[%04x-%04x]", drv, nwords, uptr->CYL, sec, uptr->CYL*8 + sec, newpos, iocc_addr & mem_mask, (iocc_addr + nwords - 1) & mem_mask); -// // this will help debug the monitor by letting me watch phase loading + /* this will help debug the monitor by letting me watch phase loading */ if (raw_disk_debug) printf("* DSK%d XIO @ %04x read %d words from %d.%d (%x, %x) to M[%04x-%04x]\n", drv, prev_IAR, nwords, uptr->CYL, sec, uptr->CYL*8 + sec, newpos, iocc_addr & mem_mask, (iocc_addr + nwords - 1) & mem_mask); @@ -448,7 +462,7 @@ t_stat dsk_svc (UNIT *uptr) } - uptr->FUNC = DSK_FUNC_IDLE; // we're done with this operation + uptr->FUNC = DSK_FUNC_IDLE; /* we're done with this operation */ return SCPE_OK; } @@ -459,8 +473,8 @@ t_stat dsk_reset (DEVICE *dptr) UNIT *uptr; #ifdef TRACE_DMS_IO - // add the WHERE command. It finds the phase that was loaded at given address and indicates - // the offset in the phase + /* add the WHERE command. It finds the phase that was loaded at given address and indicates */ + /* the offset in the phase */ register_cmd("WHERE", &where_cmd, 0, "w{here} address find phase and offset of an address\n"); register_cmd("PHDEBUG", &phdebug_cmd, 0, "ph{debug} off|phlo phhi break on phase load\n"); register_cmd("FDUMP", &fdump_cmd, 0, NULL); @@ -487,14 +501,14 @@ static t_stat dsk_attach (UNIT *uptr, char *cptr) int drv = uptr - dsk_unit; t_stat rval; - sim_cancel(uptr); // cancel current IO + sim_cancel(uptr); /* cancel current IO */ dsk_lastio[drv] = IO_NONE; - if (uptr->flags & UNIT_ATT) // dismount current disk + if (uptr->flags & UNIT_ATT) /* dismount current disk */ if ((rval = dsk_detach(uptr)) != SCPE_OK) return rval; - uptr->CYL = 0; // reset the device + uptr->CYL = 0; /* reset the device */ uptr->FUNC = DSK_FUNC_IDLE; dsk_dsw[drv] = DSK_DSW_CARRIAGE_HOME; @@ -502,18 +516,18 @@ static t_stat dsk_attach (UNIT *uptr, char *cptr) CLRBIT(ILSW[2], dsk_ilswbit[drv]); calc_ints(); - if (sim_switches & SWMASK('M')) // if memory mode (e.g. for CGI), buffer the file - SETBIT(uptr->flags, UNIT_BUFABLE); + if (sim_switches & SWMASK('M')) /* if memory mode (e.g. for CGI), buffer the file */ + SETBIT(uptr->flags, UNIT_BUFABLE|UNIT_MUSTBUF); - if (sim_switches & SWMASK('R')) // read lock mode + if (sim_switches & SWMASK('R')) /* read lock mode */ SETBIT(uptr->flags, UNIT_RO|UNIT_ROABLE|UNIT_RONLY); - if (cgi && (sim_switches & SWMASK('M'))) { // if cgi and memory mode, - sim_switches |= SWMASK('R'); // have attach_unit open file in readonly mode - SETBIT(uptr->flags, UNIT_ROABLE|UNIT_MUSTBUF); // but don't set the UNIT_RONLY flag so DMS can write to the buffered image + if (cgi && (sim_switches & SWMASK('M')) && ! cgiwritable) { /* if cgi and memory mode, but writable option not specified */ + sim_switches |= SWMASK('R'); /* have attach_unit open file in readonly mode */ + SETBIT(uptr->flags, UNIT_ROABLE); /* but don't set the UNIT_RONLY flag so DMS can write to the buffered image */ } - if ((rval = attach_unit(uptr, quotefix(cptr))) != SCPE_OK) { // mount new disk + if ((rval = attach_unit(uptr, quotefix(cptr))) != SCPE_OK) { /* mount new disk */ SETBIT(dsk_dsw[drv], DSK_DSW_NOT_READY); return rval; } @@ -536,7 +550,7 @@ static t_stat dsk_detach (UNIT *uptr) sim_cancel(uptr); - if ((rval = detach_unit (uptr)) != SCPE_OK) + if ((rval = detach_unit(uptr)) != SCPE_OK) return rval; CLRBIT(ILSW[2], dsk_ilswbit[drv]); @@ -555,7 +569,7 @@ static t_stat dsk_detach (UNIT *uptr) return SCPE_OK; } -// boot routine - if they type BOOT DSK, load the standard boot card. +/* boot routine - if they type BOOT DSK, load the standard boot card. */ static t_stat dsk_boot (int unitno, DEVICE *dptr) { @@ -585,7 +599,7 @@ struct tag_slet { int16 nwords; int16 sector; } slet[MAXSLET] = { -# include "dmsr2v12slet.h" // without RPG, use this info until overwritten by actual data from disk +# include "dmsr2v12slet.h" /* without RPG, use this info until overwritten by actual data from disk */ }; #pragma pack() @@ -599,7 +613,7 @@ int nseg = 0; static void enable_dms_tracing (int newsetting) { - nseg = 0; // clear the segment map + nseg = 0; /* clear the segment map */ if ((newsetting && trace_dms) || ! (newsetting || trace_dms)) return; @@ -678,7 +692,7 @@ static t_stat where_cmd (int flag, char *ptr) return SCPE_OK; } -// savesector - save info on a sector just read. THIS IS NOT YET TESTED +/* savesector - save info on a sector just read. THIS IS NOT YET TESTED */ static void addseg (int i) { @@ -713,14 +727,14 @@ static void savesector (int addr, int offset, int len, int phid, char *name) if (! trace_dms) return; - addr++; // first word is sector address, so account for that + addr++; /* first word is sector address, so account for that */ len--; for (i = 0; i < nseg; i++) { - if (addr >= (mseg[i].addr+mseg[i].len)) // entirely after this entry + if (addr >= (mseg[i].addr+mseg[i].len)) /* entirely after this entry */ continue; - if (mseg[i].addr < addr) { // old one starts before this. split it + if (mseg[i].addr < addr) { /* old one starts before this. split it */ addseg(i); mseg[i].len = addr-mseg[i].addr; i++; @@ -731,7 +745,7 @@ static void savesector (int addr, int offset, int len, int phid, char *name) break; } - addseg(i); // add new segment. Old one ends up after this + addseg(i); /* add new segment. Old one ends up after this */ if (i >= MAXMSEG) return; @@ -742,12 +756,12 @@ static void savesector (int addr, int offset, int len, int phid, char *name) mseg[i].len = len; mseg[i].name = name; - i++; // delete any segments completely covered + i++; /* delete any segments completely covered */ while (i < nseg && (mseg[i].addr+mseg[i].len) <= (addr+len)) delseg(i); - if (i < nseg && mseg[i].addr < (addr+len)) { // old one extends past this. Retain the end + if (i < nseg && mseg[i].addr < (addr+len)) { /* old one extends past this. Retain the end */ mseg[i].len = (mseg[i].addr+mseg[i].len) - (addr+len); mseg[i].addr = addr+len; } @@ -755,19 +769,19 @@ static void savesector (int addr, int offset, int len, int phid, char *name) static void tracesector (int iswrite, int nwords, int addr, int sector) { - int i, phid = 0, sletind = -1, offset = 0; + int i, phid = 0, offset = 0; char *name = NULL; if (nwords < 3 || ! trace_dms) return; - switch (sector) { // explicitly known sector name + switch (sector) { /* explicitly known sector name */ case 0: name = "ID/COLD START"; break; case 1: name = "DCOM"; break; case 2: name = "RESIDENT IMAGE"; break; case 3: case 4: - case 5: name = "SLET"; // save just-read or written SLET info + case 5: name = "SLET"; /* save just-read or written SLET info */ memmove(&slet[(320/4)*(sector-3)], &M[addr+1], nwords*2); break; case 6: name = "RELOAD TABLE"; break; @@ -777,9 +791,9 @@ static void tracesector (int iswrite, int nwords, int addr, int sector) printf("* %04x: %3d /%04x %c %3d.%d ", prev_IAR, nwords, addr, iswrite ? 'W' : 'R', sector/8, sector%8); - if (name == NULL) { // look up sector in SLET + if (name == NULL) { /* look up sector in SLET */ for (i = 0; i < MAXSLET; i++) { - if (slet[i].phid == 0) // not found + if (slet[i].phid == 0) /* not found */ goto done; else if (slet[i].sector > sector) { if (--i >= 0) { @@ -792,17 +806,17 @@ static void tracesector (int iswrite, int nwords, int addr, int sector) goto done; } if (slet[i].sector == sector) { - phid = slet[i].phid; // we found the starting sector + phid = slet[i].phid; /* we found the starting sector */ break; } } - if (i >= MAXSLET) // was not found + if (i >= MAXSLET) /* was not found */ goto done; name = "?"; for (i = sizeof(phase)/sizeof(phase[0]); --i >= 0; ) { - if (phase[i].phid == phid) { // look up name + if (phase[i].phid == phid) { /* look up name */ name = phase[i].name; break; } @@ -816,7 +830,7 @@ done: putchar('\n'); if (phid >= phdebug_lo && phid <= phdebug_hi && offset == 0) - break_simulation(STOP_PHASE_BREAK); // break on read of first sector of indicated phases + break_simulation(STOP_PHASE_BREAK); /* break on read of first sector of indicated phases */ if (name != NULL && *name != '?' && ! iswrite) savesector(addr, offset, nwords, phid, name); @@ -824,12 +838,12 @@ done: static t_stat fdump_cmd (int flags, char *cptr) { - int addr = 0x7a24; // address of next statement; + int addr = 0x7a24; /* address of next statement */ int sofst = 0x7a26, symaddr; int cword, nwords, stype, has_stnum, strel = 1, laststno = 0; - addr = M[addr & mem_mask] & mem_mask; // get address of first statement - sofst = M[sofst & mem_mask] & mem_mask; // get address of symbol table + addr = M[addr & mem_mask] & mem_mask; /* get address of first statement */ + sofst = M[sofst & mem_mask] & mem_mask ; /* get address of symbol table */ for (;;) { cword = M[addr]; @@ -851,7 +865,7 @@ static t_stat fdump_cmd (int flags, char *cptr) printf(" [%04x %04x %04x]", M[symaddr], M[symaddr+1], M[symaddr+2]); } - if (stype == 0x5000) { // error record + if (stype == 0x5000) { /* error record */ printf(" (err %d)", M[addr+1]); } @@ -872,4 +886,4 @@ static t_stat fdump_cmd (int flags, char *cptr) return SCPE_OK; } -#endif // TRACE_DMS_IO +#endif /* TRACE_DMS_IO */ diff --git a/Ibm1130/ibm1130_fmt.c b/Ibm1130/ibm1130_fmt.c index 1d501009..8178de89 100644 --- a/Ibm1130/ibm1130_fmt.c +++ b/Ibm1130/ibm1130_fmt.c @@ -1,60 +1,61 @@ -// ibm1130_fmt.c : interpret tabs in 1130 Assembler or Fortran source -// Bob Flanders -// ------------------------------------------------------------------------------------------- -// -// These routines are used by ibm1130_cr.c when the user has indicated -// that the input text is formatted with tabs. Input lines are edited -// into the appropriate column format. Three edit modes are recognized: -// -// Assembler mode: -// Input lines of the form -// -// [label][opcode][tag][L][argument] -// -// are rearranged so that the input fields are placed in the appropriate columns -// -// The label must start on the first character of the line. If there is no label, -// the first character(s) before the opcode must be whitespace. Following the opcode, there -// MUST be a tab character, followed by the format and tag. Following the format and tag -// may be exactly one whitespace character, and then starts the argument. -// -// Input lines with * in column 1 and blank lines are turned into Assembler comments, -// with the * in the Opcode field. -// -// Assembler directive lines at the beginning of the deck must be preceded by -// ! to indicate that they are not comments. For example, -// -// !*LIST -// * This is a comment -// -// Fortran mode: -// Input lines of the form -// -// [label]statement -// -// or -// -// [label]Xcontinuation -// -// where X is a non alphabetic contination character are rearranged in the -// appropriate manner: -// -// 1 2 -// 12345678901234567890... -// ------------------------ -// label statement -// labelXcontinuation -// -// However, you must take care that you don't end up with statement text after column 72. -// -// Input lines with * or C in column 1 are left alone (comments and directives) -// -// (The ! escape is not used before Fortran directives as before Assembler directives) -// -// Tab mode: -// Tabs are replaced with spaces. Tab settings are assumed to be eight characters wide, -// as is standard for vi, notepad, etc. -// ------------------------------------------------------------------------------------------- +/********************************************************************************************* + * ibm1130_fmt.c : interpret tabs in 1130 Assembler or Fortran source + * Bob Flanders + * ------------------------------------------------------------------------------------------- + * + * These routines are used by ibm1130_cr.c when the user has indicated + * that the input text is formatted with tabs. Input lines are edited + * into the appropriate column format. Three edit modes are recognized: + * + * Assembler mode: + * Input lines of the form + * + * [label][opcode][tag][L][argument] + * + * are rearranged so that the input fields are placed in the appropriate columns + * + * The label must start on the first character of the line. If there is no label, + * the first character(s) before the opcode must be whitespace. Following the opcode, there + * MUST be a tab character, followed by the format and tag. Following the format and tag + * may be exactly one whitespace character, and then starts the argument. + * + * Input lines with * in column 1 and blank lines are turned into Assembler comments, + * with the * in the Opcode field. + * + * Assembler directive lines at the beginning of the deck must be preceded by + * ! to indicate that they are not comments. For example, + * + * !*LIST + * * This is a comment + * + * Fortran mode: + * Input lines of the form + * + * [label]statement + * + * or + * + * [label]Xcontinuation + * + * where X is a non alphabetic contination character are rearranged in the + * appropriate manner: + * + * 1 2 + * 12345678901234567890... + * ------------------------ + * label statement + * labelXcontinuation + * + * However, you must take care that you don't end up with statement text after column 72. + * + * Input lines with * or C in column 1 are left alone (comments and directives) + * + * (The ! escape is not used before Fortran directives as before Assembler directives) + * + * Tab mode: + * Tabs are replaced with spaces. Tab settings are assumed to be eight characters wide, + * as is standard for vi, notepad, etc. + *********************************************************************************************/ #include #include @@ -63,10 +64,10 @@ #include #include "ibm1130_fmt.h" -#define MAXLINE 81 // maximum output line size -#define WORKSZ 256 // size for tab work area -#define TAGOFFSET 12 // offset for tag field -#define FMTOFFSET 11 // offset for format field +#define MAXLINE 81 /* maximum output line size */ +#define WORKSZ 256 /* size for tab work area */ +#define TAGOFFSET 12 /* offset for tag field */ +#define FMTOFFSET 11 /* offset for format field */ #define MIN(a,b) ((a < b) ? a : b) #define AMSG " with Assembler Reformat" @@ -77,227 +78,236 @@ #define FFORMAT "%-5.5s %-74.74s" #define FCONTFMT "%-5.5s%-75.75s" -char gszLabel[6]; // work area for label -char gszArg[MAXLINE]; // .. argument -char gszOutput[MAXLINE]; // .. output -short gaiAsmTabs[] = {7,12,15,20,25,30,35,40,45,52,0};// tab stops for assembler +char gszLabel[6]; /* work area for label */ +char gszArg[MAXLINE]; /* .. argument */ +char gszOutput[MAXLINE]; /* .. output */ +short gaiAsmTabs[] = {7,12,15,20,25,30,35,40,45,52,0};/* tab stops for assembler */ -short gaiPlainTabs[] = {9, 17, 25, 33, 41, 49, 57, 65, 73, 0};// tab stops for just plain tabs +short gaiPlainTabs[] = {9, 17, 25, 33, 41, 49, 57, 65, 73, 0};/* tab stops for just plain tabs */ -// /////////////// -// helper routines +/* + * helper routines + */ -/////////////////////////////////////////////////// -// ExpandTabs: Expand tabs to spaces +/************************************************* + * ExpandTabs: Expand tabs to spaces + */ -char* ExpandTabs(char* p_szInbuf, // expand tabs .. input buffer - char* p_szOutbuf, // .. output buffer - short* p_aiTabs) // .. array of tab stops (1 based) -- 0 end of array +char* ExpandTabs(char* p_szInbuf, /* expand tabs .. input buffer */ + char* p_szOutbuf, /* .. output buffer */ + short* p_aiTabs) /* .. array of tab stops (1 based) -- 0 end of array */ { -short iI, // input position - iO, // output position - iT; // next tab stop +short iI, /* input position */ + iO, /* output position */ + iT; /* next tab stop */ -char cX; // character to test +char cX; /* character to test */ - iI = 0; // init input position - iO = 0; // init output position - iT = 0; // init tab stop + iI = 0; /* init input position */ + iO = 0; /* init output position */ + iT = 0; /* init tab stop */ - while ((cX = *(p_szInbuf + iI)) != 0) // while there are characters + while ((cX = *(p_szInbuf + iI)) != 0) /* while there are characters */ { - if (cX == '\t') // q. tab character? - { // a. yes .. - while ((p_aiTabs[iT] <= iO + 1) // search for next valid stop .. - && (p_aiTabs[iT] != 0)) // .. or end of table - iT++; // .. go to next tab + if (cX == '\t') /* q. tab character? */ + { /* a. yes .. */ + while ((p_aiTabs[iT] <= iO + 1) /* search for next valid stop .. */ + && (p_aiTabs[iT] != 0)) /* .. or end of table */ + iT++; /* .. go to next tab */ - if (p_aiTabs[iT] != 0) // q. end of tab array? - { // a. no .. - while (iO < (p_aiTabs[iT] - 1)) // fill to tab with blanks - *(p_szOutbuf + iO++) = ' '; // .. put in a blank + if (p_aiTabs[iT] != 0) /* q. end of tab array? */ + { /* a. no .. */ + while (iO < (p_aiTabs[iT] - 1)) /* fill to tab with blanks */ + *(p_szOutbuf + iO++) = ' '; /* .. put in a blank */ } - else // Otherwise ... - *(p_szOutbuf + iO++) = ' '; // .. Translate to blank + else /* Otherwise ... */ + *(p_szOutbuf + iO++) = ' '; /* .. Translate to blank */ } - else // Otherwise .. not tab - *(p_szOutbuf + iO++) = cX; // .. save the input char + else /* Otherwise .. not tab */ + *(p_szOutbuf + iO++) = cX; /* .. save the input char */ - iI++; // next input character + iI++; /* next input character */ } - *(p_szOutbuf + iO) = 0; // end the string.. - return p_szOutbuf; // .. return output area addr + *(p_szOutbuf + iO) = 0; /* end the string.. */ + return p_szOutbuf; /* .. return output area addr */ } -///////////////////////////////////// -// extract next token, modify pointer +/************************************************* + * extract next token, modify pointer + */ -char* GetToken(char* p_szOut, // output location - int p_iLen, // max output length - char**p_pszToken) // pointer to input token +char* GetToken(char* p_szOut, /* output location */ + int p_iLen, /* max output length */ + char**p_pszToken) /* pointer to input token */ { -int iI; // work integer -char* pszX; // work pointer +int iI; /* work integer */ +char* pszX; /* work pointer */ - pszX = *p_pszToken; // get pointer to token + pszX = *p_pszToken; /* get pointer to token */ - for (iI = 0; *(pszX + iI) && (!isspace(*(pszX + iI)));) // while not whitespace & not end - iI++; // .. count token length + for (iI = 0; *(pszX + iI) && (!isspace(*(pszX + iI)));) /* while not whitespace & not end */ + iI++; /* .. count token length */ - memset(p_szOut, 0, p_iLen); // zero out output area + memset(p_szOut, 0, p_iLen); /* zero out output area */ - if (iI > 0) // q. any chars? - strncpy(p_szOut, *p_pszToken, MIN(iI, p_iLen-1)); // a. yes.. copy max of p_iLen-1 + if (iI > 0) /* q. any chars? */ + strncpy(p_szOut, *p_pszToken, MIN(iI, p_iLen-1)); /* a. yes.. copy max of p_iLen-1 */ - *p_pszToken += iI; // point beyond token - return p_szOut; // .. return token pointer + *p_pszToken += iI; /* point beyond token */ + return p_szOut; /* .. return token pointer */ } -///////////////////////////////////////////////////////// -// EditToAsm - convert tab-formatted text line to 1130 Assembler format +/************************************************* + * EditToAsm - convert tab-formatted text line to 1130 Assembler format + */ -char *EditToAsm (char* p_pszEdit) // convert line to 1130 assembler +char *EditToAsm (char* p_pszEdit) /* convert line to 1130 assembler */ { -char pszLine[MAXLINE]; // source line -char pszWork[WORKSZ]; // work buffer -char acTFWrk[2]; // tag/format work area -size_t iI; // work integer +char pszLine[MAXLINE]; /* source line */ +char pszWork[WORKSZ]; /* work buffer */ +char acTFWrk[2]; /* tag/format work area */ +size_t iI; /* work integer */ - if (p_pszEdit == NULL) // q. null request? - return AMSG; // a. yes .. return display message + if (p_pszEdit == NULL) /* q. null request? */ + return AMSG; /* a. yes .. return display message */ - if (*p_pszEdit == '!') // leave lines starting with ! alone + if (*p_pszEdit == '!') /* leave lines starting with ! alone */ return EditToWhitespace(p_pszEdit+1); - if (*p_pszEdit == '*') // q. comment line? - { // a. yes.. - strncpy(pszWork, EditToWhitespace(p_pszEdit), MAXLINE); // .. convert any tabs - sprintf(gszOutput, ACOMMENTFMT, pszWork); // .. put the comment out there in the opcode column - return gszOutput; // .. and return it + if (*p_pszEdit == '*') /* q. comment line? */ + { /* a. yes.. */ + strncpy(pszWork, EditToWhitespace(p_pszEdit), MAXLINE); /* .. convert any tabs */ + sprintf(gszOutput, ACOMMENTFMT, pszWork); /* .. put the comment out there in the opcode column */ + return gszOutput; /* .. and return it */ } - strncpy(pszLine, p_pszEdit, MAXLINE-1); // copy the line local + strncpy(pszLine, p_pszEdit, MAXLINE-1); /* copy the line local */ - ExpandTabs(pszLine, pszWork, gaiAsmTabs); // expand the tabs - strncpy(pszLine, pszWork, MAXLINE-1); // copy the line back + ExpandTabs(pszLine, pszWork, gaiAsmTabs); /* expand the tabs */ + strncpy(pszLine, pszWork, MAXLINE-1); /* copy the line back */ - for (iI = strlen(pszLine); iI--;) // trim trailing whitespace + for (iI = strlen(pszLine); iI--;) /* trim trailing whitespace */ { - if (*(pszLine + iI) <= ' ') // q. space or less? - *(pszLine + iI) = 0; // a. yes .. remove it - else // otherwise - break; // .. done. Leave loop. + if (*(pszLine + iI) <= ' ') /* q. space or less? */ + *(pszLine + iI) = 0; /* a. yes .. remove it */ + else /* otherwise */ + break; /* .. done. Leave loop. */ } - if (strlen(pszLine) == 0) // q. blank line? - { // a. yes .. Assembler abhors these so - sprintf(gszOutput, ABLANKLINE); // format as comment statement - return gszOutput; // .. and return it + if (strlen(pszLine) == 0) /* q. blank line? */ + { /* a. yes .. Assembler abhors these so */ + sprintf(gszOutput, ABLANKLINE); /* format as comment statement */ + return gszOutput; /* .. and return it */ } - // TODO: Add code to process a strip switch - // comment? + /* TODO: Add code to process a strip switch + * comment? + */ - if (strlen(pszLine) > (TAGOFFSET + 1)) // q. line long enough? - { // a. yes.. reorder tag/format - memcpy(acTFWrk, pszLine + FMTOFFSET, 2); // get tag/format - memset((pszLine + FMTOFFSET), ' ', 2); // .. blank 'em out + if (strlen(pszLine) > (TAGOFFSET + 1)) /* q. line long enough? */ + { /* a. yes.. reorder tag/format */ + memcpy(acTFWrk, pszLine + FMTOFFSET, 2); /* get tag/format */ + memset((pszLine + FMTOFFSET), ' ', 2); /* .. blank 'em out */ for (iI = 0; iI < 2; iI ++) - if (isalpha(acTFWrk[iI])) // q. alpha char? - *(pszLine + FMTOFFSET) = acTFWrk[iI]; // a. yes .. make it format - else if (isdigit(acTFWrk[iI])) // q. digit? - *(pszLine + TAGOFFSET) = acTFWrk[iI]; // a. yes .. make it the tag + if (isalpha(acTFWrk[iI])) /* q. alpha char? */ + *(pszLine + FMTOFFSET) = acTFWrk[iI]; /* a. yes .. make it format */ + else if (isdigit(acTFWrk[iI])) /* q. digit? */ + *(pszLine + TAGOFFSET) = acTFWrk[iI]; /* a. yes .. make it the tag */ } - sprintf(gszOutput, AFORMAT, pszLine); // format the line + sprintf(gszOutput, AFORMAT, pszLine); /* format the line */ - return gszOutput; // return formatted line + return gszOutput; /* return formatted line */ } -///////////////////////////////////////////////////////// -// EditToFortran - convert tab-formatted input text line to FORTRAN format -// (a la DEC Fortran) +/************************************************* + * EditToFortran - convert tab-formatted input text line to FORTRAN format + * (a la DEC Fortran) + */ -char *EditToFortran(char* p_pszEdit) // convert line to 1130 assembler +char *EditToFortran(char* p_pszEdit) /* convert line to 1130 assembler */ { -char pszLine[MAXLINE]; // source line -char* pszWork; // work pointer -size_t iI; // work integer -int bContinue; // true if continue +char pszLine[MAXLINE]; /* source line */ +char* pszWork; /* work pointer */ +size_t iI; /* work integer */ +int bContinue; /* true if continue */ - if (p_pszEdit == NULL) // q. null request? - return FMSG; // a. yes .. return display message + if (p_pszEdit == NULL) /* q. null request? */ + return FMSG; /* a. yes .. return display message */ - if (strchr(p_pszEdit, '\t') == NULL) // q. no tab in the line? - return p_pszEdit; // a. nope, return line as is, assume it's formatted correctly + if (strchr(p_pszEdit, '\t') == NULL) /* q. no tab in the line? */ + return p_pszEdit; /* a. nope, return line as is, assume it's formatted correctly */ - if (*p_pszEdit == 'C' || *p_pszEdit == '*' || *p_pszEdit == '\0') // q. comment or directive or blank line? - { // a. yes.. don't restructure + if (*p_pszEdit == 'C' || *p_pszEdit == '*' || *p_pszEdit == '\0') /* q. comment or directive or blank line? */ + { /* a. yes.. don't restructure */ return EditToWhitespace(p_pszEdit); } - strncpy(pszLine, p_pszEdit, MAXLINE-1); // copy the line local + strncpy(pszLine, p_pszEdit, MAXLINE-1); /* copy the line local */ - for (iI = strlen(pszLine); iI--;) // trim trailing whitespace + for (iI = strlen(pszLine); iI--;) /* trim trailing whitespace */ { - if (*(pszLine + iI) <= ' ') // q. space or less? - *(pszLine + iI) = 0; // a. yes .. remove it - else // otherwise - break; // .. done. Leave loop. + if (*(pszLine + iI) <= ' ') /* q. space or less? */ + *(pszLine + iI) = 0; /* a. yes .. remove it */ + else /* otherwise */ + break; /* .. done. Leave loop. */ } - // TODO: Add code to process a strip switch - // comment? + /* + * TODO: Add code to process a strip switch + * comment? + */ - pszWork = (char*) pszLine; // set pointer to line - GetToken(gszLabel, 6, &pszWork); // get the line, if any. + pszWork = (char*) pszLine; /* set pointer to line */ + GetToken(gszLabel, 6, &pszWork); /* get the line, if any. */ - pszWork++; // skip tab/whitespace + pszWork++; /* skip tab/whitespace */ - // continuation... - bContinue = ((isdigit(*pszWork) && (*pszWork != '0')) // if first char non-zero digit - || (!isspace(*pszWork) && !isalpha(*pszWork))); // .. or non-alpha non-blank + /* continuation... */ + bContinue = ((isdigit(*pszWork) && (*pszWork != '0')) /* if first char non-zero digit */ + || (!isspace(*pszWork) && !isalpha(*pszWork))); /* .. or non-alpha non-blank */ - memset(gszArg, 0, MAXLINE); // .. and arguments + memset(gszArg, 0, MAXLINE); /* .. and arguments */ - strncpy(gszArg, pszWork, 75); // copy rest to argument + strncpy(gszArg, pszWork, 75); /* copy rest to argument */ - sprintf(gszOutput, (bContinue) ? FCONTFMT : FFORMAT, // format the line - gszLabel, // .. statement # - gszArg); // .. code + sprintf(gszOutput, (bContinue) ? FCONTFMT : FFORMAT, /* format the line */ + gszLabel, /* .. statement # */ + gszArg); /* .. code */ - return gszOutput; // return formatted line + return gszOutput; /* return formatted line */ } -///////////////////////////////////////////////////////// -// EditToWhitespace - expand tabs at 8 space intervals. +/************************************************* + * EditToWhitespace - expand tabs at 8 space intervals. + */ char* EditToWhitespace(char *p_pszEdit) { -int iI; /* work integer */ -char pszLine[MAXLINE]; // source line -char pszWork[WORKSZ]; // work buffer +int iI; /* work integer */ +char pszLine[MAXLINE]; /* source line */ +char pszWork[WORKSZ]; /* work buffer */ - if (p_pszEdit == NULL) // q. null request? - return AMSG; // a. yes .. return display message + if (p_pszEdit == NULL) /* q. null request? */ + return AMSG; /* a. yes .. return display message */ - strncpy(pszLine, p_pszEdit, MAXLINE-1); // copy the line local + strncpy(pszLine, p_pszEdit, MAXLINE-1); /* copy the line local */ - ExpandTabs(pszLine, pszWork, gaiPlainTabs); // expand the tabs - strncpy(gszOutput, pszWork, MAXLINE-1); // copy the line back + ExpandTabs(pszLine, pszWork, gaiPlainTabs); /* expand the tabs */ + strncpy(gszOutput, pszWork, MAXLINE-1); /* copy the line back */ - for (iI = strlen(gszOutput); iI--;) // look at each character + for (iI = strlen(gszOutput); iI--;) /* look at each character */ { - if (*(gszOutput + iI) <= ' ') // q. space or less? - *(gszOutput + iI) = 0; // a. yes .. remove it - else // otherwise - break; // .. done. Leave loop. + if (*(gszOutput + iI) <= ' ') /* q. space or less? */ + *(gszOutput + iI) = 0; /* a. yes .. remove it */ + else /* otherwise */ + break; /* .. done. Leave loop. */ } - return gszOutput; /* ... return buffer */ + return gszOutput; /* ... return buffer */ } diff --git a/Ibm1130/ibm1130_fmt.h b/Ibm1130/ibm1130_fmt.h index 170d1c88..7232560b 100644 --- a/Ibm1130/ibm1130_fmt.h +++ b/Ibm1130/ibm1130_fmt.h @@ -12,6 +12,6 @@ /* ibm1130_asm.h: definition of routines in ibm1130_asm.c */ -char* EditToAsm(char*); // convert edit format to 1130 assembler format -char* EditToFortran(char*); // convert edit format to Fortran format -char* EditToWhitespace(char*); // clean white space, tabstops every 8 positions +char* EditToAsm(char*); /* convert edit format to 1130 assembler format */ +char* EditToFortran(char*); /* convert edit format to Fortran format */ +char* EditToWhitespace(char*); /* clean white space, tabstops every 8 positions */ diff --git a/Ibm1130/ibm1130_gdu.c b/Ibm1130/ibm1130_gdu.c index 293f5223..86d32c45 100644 --- a/Ibm1130/ibm1130_gdu.c +++ b/Ibm1130/ibm1130_gdu.c @@ -3,11 +3,11 @@ /* ibm1130_gdu.c: IBM 1130 2250 Graphical Display Unit (Under construction) -// stuff to fix: -// "store revert" might be backwards? -// alpha keyboard is not implemented -// pushbuttons are not implemented -// there is something about interrupts being deferred during a subroutine transition? + stuff to fix: + "store revert" might be backwards? + alpha keyboard is not implemented + pushbuttons are not implemented + there is something about interrupts being deferred during a subroutine transition? Based on the SIMH package written by Robert M Supnik @@ -21,13 +21,13 @@ * Mail to simh@ibm1130.org */ -#define BLIT_MODE // normally defined, undefine when debugging generate_image() -//#define DEBUG_LIGHTPEN // normally undefined, define to visualize light-pen sensing +#define BLIT_MODE /* define for better performance, undefine when debugging generate_image() */ +/* #define DEBUG_LIGHTPEN */ /* define to debug light-pen sensing */ -#define DEFAULT_GDU_RATE 20 // default frame rate -#define DEFAULT_PEN_THRESHOLD 3 // default looseness of light-pen hit -#define INDWIDTH 32 // width of an indicator (there are two columns of these) -#define INITSIZE 512 // initial window size +#define DEFAULT_GDU_RATE 20 /* default frame rate */ +#define DEFAULT_PEN_THRESHOLD 3 /* default looseness of light-pen hit */ +#define INDWIDTH 32 /* width of an indicator (there are two columns of these) */ +#define INITSIZE 512 /* initial window size */ #define GDU_DSW_ORDER_CONTROLLED_INTERRUPT 0x8000 #define GDU_DSW_KEYBOARD_INTERUPT 0x4000 @@ -109,7 +109,7 @@ static t_stat gdu_reset (DEVICE *dptr) void xio_2250_display (int32 addr, int32 func, int32 modify) { - // ignore commands to nonexistent device + /* ignore commands if device is nonexistent */ } t_bool gdu_active (void) @@ -118,7 +118,7 @@ t_bool gdu_active (void) } /* -------------------------------------------------------------------------------------- */ -#else // GUI_SUPPORT defined +#else /* GUI_SUPPORT defined */ /******* PLATFORM INDEPENDENT CODE ********************************************************/ @@ -127,7 +127,6 @@ static int xmouse, ymouse, lpen_dist, lpen_dist2; // current mouse pointer, scal static double sfactor; // current scaling factor static t_bool last_abs = TRUE; // last positioning instruction was absolute static t_bool mouse_present = FALSE; // mouse is/is not in the window - static void clear_interrupts (void); static void set_indicators (int32 new_inds); static void start_regeneration (void); @@ -239,23 +238,27 @@ static void start_regeneration (void) { SETBIT(gdu_dsw, GDU_DSW_BUSY); - if (gdu_unit.flags & UNIT_DISPLAYED) { - StartGDUUpdates(); - } - else { + if ((gdu_unit.flags & UNIT_DISPLAYED) == 0) { if (! CreateGDUWindow()) return; + SETBIT(gdu_unit.flags, UNIT_DISPLAYED); } + + StartGDUUpdates(); } static void halt_regeneration (void) { + // halt_regeneration gets called at end of every refresh interation, so it should NOT black out the + // screen -- this is why it was flickering so badly. The lower level code (called on a timer) + // should check to see if GDU_DSW_BUSY is clear, and if it it still zero after several msec, + // only then should it black out the screen and call StopGDUUpdates. if (gdu_dsw & GDU_DSW_BUSY) { - StopGDUUpdates(); +// StopGDUUpdates(); // let lower level code discover this during next refresh CLRBIT(gdu_dsw, GDU_DSW_BUSY); } - EraseGDUScreen(); +// EraseGDUScreen(); // let cessation of regeneration erase it (eventually) } static void notify_window_closed (void) @@ -264,7 +267,9 @@ static void notify_window_closed (void) StopGDUUpdates(); CLRBIT(gdu_dsw, GDU_DSW_BUSY); } + CLRBIT(gdu_unit.flags, UNIT_DISPLAYED); + gdu_reset(&gdu_dev); } @@ -671,7 +676,7 @@ static HPEN hRedPen = NULL; #endif static HBRUSH hGrayBrush, hDarkBrush; static HPEN hBlackPen; - +static int halted = 0; // number of time intervals that GDU has been halted w/o a regeneration static LRESULT APIENTRY GDUWndProc (HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam); static DWORD WINAPI GDUPump (LPVOID arg); @@ -719,11 +724,6 @@ static t_bool CreateGDUWindow (void) { static BOOL did_atexit = FALSE; - if (hwGDU != NULL) { // window already exists - StartGDUUpdates(); - return TRUE; - } - hInstance = GetModuleHandle(NULL); if (hGDUPump == INVALID_HANDLE_VALUE) @@ -878,7 +878,7 @@ static void gdu_WM_PAINT (HWND hWnd) static void gdu_WM_SIZE (HWND hWnd, UINT state, int cx, int cy) { - InvalidateRect(hWnd, NULL, FALSE); + InvalidateRect(hWnd, NULL, TRUE); } // tweak the sizing rectangle during a resize to guarantee a square window @@ -912,6 +912,16 @@ static void gdu_WM_TIMER (HWND hWnd, UINT id) HDC hDC; if (running) { // if CPU is running, update picture + if ((gdu_dsw & GDU_DSW_BUSY) == 0) { // regeneration is not to occur + if (++halted >= 4) { // stop the timer if four timer intervals go by with the display halted + EraseGDUScreen(); // screen goes black due to cessation of refreshing + StopGDUUpdates(); // might as well kill the timer + return; + } + } + else + halted = 0; + #ifdef BLIT_MODE hDC = GetDC(hWnd); // blit the new image right over the old PaintImage(hDC, FALSE); @@ -964,7 +974,7 @@ static void DrawPoint (int x, int y) static void UpdateGDUIndicators(void) { if (hwGDU != NULL) - InvalidateRect(hwGDU, NULL, TRUE); + InvalidateRect(hwGDU, NULL, FALSE); // no need to erase the background -- the draw routine fully paints the indicator } static void CheckGDUKeyboard (void) @@ -981,6 +991,7 @@ static void StartGDUUpdates (void) msec = (gdu_rate == 0) ? (1000 / DEFAULT_GDU_RATE) : 1000/gdu_rate; idTimer = SetTimer(hwGDU, 1, msec, NULL); } + halted = 0; } static void StopGDUUpdates (void) @@ -988,6 +999,7 @@ static void StopGDUUpdates (void) if (idTimer != 0) { KillTimer(hwGDU, 1); idTimer = 0; + halted = 10000; } } @@ -1086,8 +1098,6 @@ static DWORD WINAPI GDUPump (LPVOID arg) ShowWindow(hwGDU, SW_SHOWNOACTIVATE); /* display it */ UpdateWindow(hwGDU); - StartGDUUpdates(); - while (GetMessage(&msg, hwGDU, 0, 0)) { /* message pump - this basically loops forevermore */ TranslateMessage(&msg); DispatchMessage(&msg); diff --git a/Ibm1130/ibm1130_gui.c b/Ibm1130/ibm1130_gui.c index 990b43a2..765c2214 100644 --- a/Ibm1130/ibm1130_gui.c +++ b/Ibm1130/ibm1130_gui.c @@ -11,6 +11,9 @@ * This is not a supported product, but I welcome bug reports and fixes. * Mail to simh@ibm1130.org * + * 30-Dec-05 BLK Fixed mask for IAR and SAR register display and added display + * of Arithmetic Factor, per Carl Claunch. + * * 09-Apr-04 BLK Changed code to use stock windows cursor IDC_HAND if available * * 02-Dec-02 BLK Changed display, added printer and card reader icons @@ -33,9 +36,9 @@ #define UPDATE_BY_TIMER #ifdef UPDATE_BY_TIMER -# define UPDATE_INTERVAL 20 // set to desired number of updates/second +# define UPDATE_INTERVAL 20 /* set to desired number of updates/second */ #else -# define UPDATE_INTERVAL 5000 // GUI: set to 100000/f where f = desired updates/second of 1130 time +# define UPDATE_INTERVAL 5000 /* GUI: set to 100000/f where f = desired updates/second of 1130 time */ #endif #define UNIT_V_CR_EMPTY (UNIT_V_UF + 5) /* NOTE: THESE MUST MATCH THE DEFINITION IN ibm1130_cr.c */ @@ -46,8 +49,9 @@ #define UNIT_V_PHYSICAL_PTR (UNIT_V_UF + 10) /* NOTE: THESE MUST MATCH THE DEFINITION IN ibm1130_prt.c */ #define UNIT_PHYSICAL_PTR (1u << UNIT_V_PHYSICAL_PTR) -// I think I had it wrong; Program Load actually does start the processor after -// reading in the card? +/* I think I had it wrong; Program Load actually does start the processor after + * reading in the card? + */ #define PROGRAM_LOAD_STARTS_CPU @@ -86,7 +90,7 @@ DEVICE console_dev = { NULL, NULL, NULL }; -// reset for the "console" display device +/* reset for the "console" display device */ extern char *read_line (char *cptr, int size, FILE *stream); extern FILE *sim_log; @@ -117,8 +121,8 @@ extern UNIT prt_unit; t_stat console_reset (DEVICE *dptr) { if (! sim_gui) { - SETBIT(console_unit.flags, UNIT_DIS); // disable the GUI - CLRBIT(console_unit.flags, UNIT_DISPLAY); // turn the GUI off + SETBIT(console_unit.flags, UNIT_DIS); /* disable the GUI */ + CLRBIT(console_unit.flags, UNIT_DISPLAY); /* turn the GUI off */ } update_gui(FALSE); @@ -158,19 +162,19 @@ void scp_panic (char *msg) #define IDC_RESET 14 #define IDC_PROGRAM_LOAD 15 -#define IDC_TEAR 16 // standard button -#define IDC_1442 17 // device images +#define IDC_TEAR 16 /* standard button */ +#define IDC_1442 17 /* device images */ #define IDC_1132 18 -#define LAMPTIME 500 // 500 msec delay on updating +#define LAMPTIME 500 /* 500 msec delay on updating */ #define FLASH_TIMER_ID 1 #define UPDATE_TIMER_ID 2 -#define RUNSWITCH_X 689 // center of the run mode switch dial +#define RUNSWITCH_X 689 /* center of the run mode switch dial */ #define RUNSWITCH_Y 107 -#define TOGGLES_X 122 // left edge of series of toggle switches +#define TOGGLES_X 122 /* left edge of series of toggle switches */ -#define TXTBOX_X 200 // text labels showing attached devices +#define TXTBOX_X 200 /* text labels showing attached devices */ #define TXTBOX_Y 300 #define TXTBOX_WIDTH 195 #define TXTBOX_HEIGHT 12 @@ -238,19 +242,18 @@ static struct tag_btn { TXTBOX_X+40, TXTBOX_Y+25, 35, 12, "Tear", TRUE, FALSE, 0, NULL, NULL, NULL, FALSE, 635, 238, 110, 110, "EMPTY_1442", TRUE, FALSE, 0, NULL, NULL, NULL, FALSE, 635, 366, 110, 110, "EMPTY_1132", TRUE, FALSE, 0, NULL, NULL, NULL, FALSE, -// 635, 366, 110, 110, "EMPTY_1132", TRUE, FALSE, 0, NULL, NULL, NULL, FALSE, }; #define NBUTTONS (sizeof(btn) / sizeof(btn[0])) -#define STATE_1442_EMPTY 0 // no cards (no file attached) -#define STATE_1442_FULL 1 // cards in hopper (file attached at BOF) -#define STATE_1442_MIDDLE 2 // cards in hopper and stacker (file attached, neither EOF nor BOF) -#define STATE_1442_EOF 3 // cards in stacker (file attached, at EOF) -#define STATE_1442_HIDDEN 4 // simulator is attached to physical card reader +#define STATE_1442_EMPTY 0 /* no cards (no file attached) */ +#define STATE_1442_FULL 1 /* cards in hopper (file attached at BOF) */ +#define STATE_1442_MIDDLE 2 /* cards in hopper and stacker (file attached, neither EOF nor BOF) */ +#define STATE_1442_EOF 3 /* cards in stacker (file attached, at EOF) */ +#define STATE_1442_HIDDEN 4 /* simulator is attached to physical card reader */ -#define STATE_1132_EMPTY 0 // no paper hanging out of printer -#define STATE_1132_FULL 1 // paper hanging out of printer -#define STATE_1132_HIDDEN 2 // printer is attached to physical printer +#define STATE_1132_EMPTY 0 /* no paper hanging out of printer */ +#define STATE_1132_FULL 1 /* paper hanging out of printer */ +#define STATE_1132_HIDDEN 2 /* printer is attached to physical printer */ static struct tag_txtbox { int x, y; @@ -309,9 +312,9 @@ static void destroy_console_window (void) int i; if (hConsoleWnd != NULL) - SendMessage(hConsoleWnd, WM_CLOSE, 0, 0); // cross thread call is OK + SendMessage(hConsoleWnd, WM_CLOSE, 0, 0); /* cross thread call is OK */ - if (hPump != INVALID_HANDLE_VALUE) { // this is not the most graceful way to do it + if (hPump != INVALID_HANDLE_VALUE) { /* this is not the most graceful way to do it */ TerminateThread(hPump, 0); hPump = INVALID_HANDLE_VALUE; PumpID = 0; @@ -338,10 +341,11 @@ static void destroy_console_window (void) NIXOBJECT(btn[i].hbrDark); } -// if (class_defined) { -// UnregisterClass(hInstance, szConsoleClassName); -// class_defined = FALSE; -// } +/* if (class_defined) { + UnregisterClass(hInstance, szConsoleClassName); + class_defined = FALSE; + } +*/ } /* ------------------------------------------------------------------------ @@ -350,7 +354,7 @@ static void destroy_console_window (void) static int shown_iar = 0, shown_sar = 0, shown_sbr = 0, shown_afr = 0, shown_acc = 0, shown_ext = 0; static int shown_op = 0, shown_tag = 0, shown_irq = 0, shown_ccc = 0, shown_cnd = 0, shown_wait = 0; -static int shown_ces = 0, shown_runmode = MODE_RUN; +static int shown_ces = 0, shown_arf = 0, shown_runmode = MODE_RUN; static int CND; /* ------------------------------------------------------------------------ @@ -402,7 +406,7 @@ void update_gui (BOOL force) static int32 displayed = 0; RECT xin; - if ((int32)(console_unit.flags & UNIT_DISPLAY) != displayed) { // setting has changed + if ((int32)(console_unit.flags & UNIT_DISPLAY) != displayed) { /* setting has changed */ displayed = console_unit.flags & UNIT_DISPLAY; if (displayed) init_console_window(); @@ -438,6 +442,8 @@ void update_gui (BOOL force) {shown_iar = IAR; RedrawRegion(hConsoleWnd, 75, 8, 364, 32);} /* lamps: don't bother erasing bkgnd */ if (SAR != shown_sar) {shown_sar = SAR; RedrawRegion(hConsoleWnd, 75, 42, 364, 65);} + if (ARF != shown_arf) + {shown_arf = ARF; RedrawRegion(hConsoleWnd, 75, 114, 364, 136);} if (ACC != shown_acc) {shown_acc = ACC; RedrawRegion(hConsoleWnd, 75, 141, 364, 164);} if (EXT != shown_ext) @@ -465,7 +471,7 @@ void update_gui (BOOL force) int_lamps = 0; - // this loop works with lamp buttons that are calculated on-the-fly only + /* this loop works with lamp buttons that are calculated on-the-fly only */ for (i = 0; i < NBUTTONS; i++) { if (btn[i].pushable) continue; @@ -475,26 +481,28 @@ void update_gui (BOOL force) state = hFlashTimer || (running && ! wait_state); break; - // this button is always off -// case IDC_PARITY_CHECK: +/* this button is always off + case IDC_PARITY_CHECK +*/ - // these buttons are enabled/disabled directly -// case IDC_POWER_ON: -// case IDC_FILE_READY: -// case IDC_FORMS_CHECK: -// case IDC_KEYBOARD_SELECT: -// case IDC_DISK_UNLOCK: +/* these buttons are enabled/disabled directly + case IDC_POWER_ON: + case IDC_FILE_READY: + case IDC_FORMS_CHECK: + case IDC_KEYBOARD_SELECT: + case IDC_DISK_UNLOCK: +*/ default: continue; } - if (state != btn[i].state) { // state has changed + if (state != btn[i].state) { /* state has changed */ EnableWindow(btn[i].hBtn, state); btn[i].state = state; } } - if (force) { // if force flag is set, update text region + if (force) { /* if force flag is set, update text region */ SetRect(&xin, TXTBOX_X, TXTBOX_Y, TXTBOX_X+TXTBOX_WIDTH, TXTBOX_BOTTOM+2*TXTBOX_HEIGHT); InvalidateRect(hConsoleWnd, &xin, TRUE); } @@ -584,9 +592,9 @@ static int occurs (char *txt, char ch) } /* ------------------------------------------------------------------------ -// turns out to get properly colored buttons you have to paint them yourself. Sheesh. -// On the plus side, this lets do a better job of aligning the button text than -// the button would by itself. + * turns out to get properly colored buttons you have to paint them yourself. Sheesh. + * On the plus side, this lets do a better job of aligning the button text than + * the button would by itself. * ------------------------------------------------------------------------ */ void PaintButton (LPDRAWITEMSTRUCT dis) @@ -616,7 +624,7 @@ void PaintButton (LPDRAWITEMSTRUCT dis) LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.top); } else if (down) { - // do the three-D thing + /* do the three-D thing */ hOldPen = SelectObject(dis->hDC, hDkGreyPen); MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-2, NULL); LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.top); @@ -776,7 +784,7 @@ static DWORD WINAPI Pump (LPVOID arg) hcArrow = LoadCursor(NULL, IDC_ARROW); #ifdef IDC_HAND - hcHand = LoadCursor(NULL, IDC_HAND); // use stock object provided by Windows + hcHand = LoadCursor(NULL, IDC_HAND); /* use stock object provided by Windows */ if (hcHand == NULL) hcHand = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_MYHAND)); #else @@ -816,12 +824,13 @@ static DWORD WINAPI Pump (LPVOID arg) EnableWindow(btn[i].hBtn, btn[i].state); } -// This isn't needed anymore, now that we have the big printer icon -- it acts like a button now -// i = IDC_TEAR; -// btn[i].hBtn = CreateWindow("BUTTON", btn[i].txt, WS_CHILD|WS_VISIBLE|BS_CENTER, -// btn[i].x, btn[i].y, btn[i].wx, btn[i].wy, hConsoleWnd, (HMENU) i, hInstance, NULL); -// -// SendMessage(btn[i].hBtn, WM_SETFONT, (WPARAM) hTinyFont, TRUE); +/* This isn't needed anymore, now that we have the big printer icon -- it acts like a button now + * i = IDC_TEAR; + * btn[i].hBtn = CreateWindow("BUTTON", btn[i].txt, WS_CHILD|WS_VISIBLE|BS_CENTER, + * btn[i].x, btn[i].y, btn[i].wx, btn[i].wy, hConsoleWnd, (HMENU) i, hInstance, NULL); + * + * SendMessage(btn[i].hBtn, WM_SETFONT, (WPARAM) hTinyFont, TRUE); + */ hbm1442_full = LoadBitmap(hInstance, "FULL_1442"); hbm1442_empty = LoadBitmap(hInstance, "EMPTY_1442"); @@ -836,7 +845,6 @@ static DWORD WINAPI Pump (LPVOID arg) btn[i].x, btn[i].y, btn[i].wx, btn[i].wy, hConsoleWnd, (HMENU) i, hInstance, NULL); btn[i].state = STATE_1442_EMPTY; -// wx = SendMessage(btn[i].hBtn, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hbm1442_full); wx = SendMessage(btn[i].hBtn, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hbm1442_empty); i = IDC_1132; @@ -847,13 +855,6 @@ static DWORD WINAPI Pump (LPVOID arg) wx = SendMessage(btn[i].hBtn, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hbm1132_empty); -// for (i = 0; i < NTXTBOXES; i++) { -// txtbox[i].hBox = CreateWindow("EDIT", txtbox[i].txt, -// WS_CHILD|WS_VISIBLE|ES_LEFT|ES_READONLY, -// txtbox[i].x, txtbox[i].y, TXTBOX_WIDTH, TXTBOX_HEIGHT, hConsoleWnd, (HMENU) (i+100), hInstance, NULL); -// SendMessage(txtbox[i].hBox, WM_SETFONT, (WPARAM) hTinyFont, TRUE); -// } - GetWindowRect(hConsoleWnd, &r); /* get window size as created */ wx = r.right - r.left + 1; wy = r.bottom - r.top + 1; @@ -991,7 +992,7 @@ void DrawRunmode (HDC hDC, int mode) * than a mouse-region test. Return value TRUE means the cursor is over a hotspot. * ------------------------------------------------------------------------ */ -static BOOL HandleClick (HWND hWnd, int xh, int yh, BOOL actual) +static BOOL HandleClick (HWND hWnd, int xh, int yh, BOOL actual, BOOL rightclick) { int b, x, r, ang, i; @@ -1054,9 +1055,10 @@ static void DrawConsole (HDC hDC, PAINTSTRUCT *ps) SetBkMode(hDC, TRANSPARENT); /* overlay letters w/o changing background */ - DrawBits(hDC, 76, 15, shown_iar, 16, 0x3FFF, digits); - DrawBits(hDC, 76, 48, shown_sar, 16, 0x3FFF, digits); + DrawBits(hDC, 76, 15, shown_iar, 16, mem_mask, digits); /* register holds only 15 bits */ + DrawBits(hDC, 76, 48, shown_sar, 16, mem_mask, digits); /* but let's display only used bits */ DrawBits(hDC, 76, 81, shown_sbr, 16, 0xFFFF, digits); + DrawBits(hDC, 76, 114, shown_arf, 16, 0xFFFF, digits); DrawBits(hDC, 76, 147, shown_acc, 16, 0xFFFF, digits); DrawBits(hDC, 76, 180, shown_ext, 16, 0xFFFF, digits); @@ -1124,10 +1126,10 @@ static void DrawConsole (HDC hDC, PAINTSTRUCT *ps) void flash_run (void) { - EnableWindow(btn[IDC_RUN].hBtn, TRUE); // enable the run lamp + EnableWindow(btn[IDC_RUN].hBtn, TRUE); /* enable the run lamp */ if (hFlashTimer != 0) - KillTimer(hConsoleWnd, FLASH_TIMER_ID); // (re)schedule lamp update + KillTimer(hConsoleWnd, FLASH_TIMER_ID); /* (re)schedule lamp update */ hFlashTimer = SetTimer(hConsoleWnd, FLASH_TIMER_ID, LAMPTIME, NULL); } @@ -1154,10 +1156,12 @@ void HandleCommand (HWND hWnd, WORD wNotify, WORD idCtl, HWND hwCtl) reset_all(0); if (running && ! power) { /* turning off */ reason = STOP_POWER_OFF; -// this prevents message pump from running, which unfortunately locks up -// the emulator thread when it calls gui_run(FALSE) which calls EnableWindow on the Run lamp -// while (running) -// Sleep(10); /* wait for execution thread to exit */ + /* wait for execution thread to exit */ +/* this prevents message pump from running, which unfortunately locks up + * the emulator thread when it calls gui_run(FALSE) which calls EnableWindow on the Run lamp + * while (running) + * Sleep(10); + */ } btn[IDC_POWER_ON].state = power; @@ -1175,7 +1179,7 @@ void HandleCommand (HWND hWnd, WORD wNotify, WORD idCtl, HWND hwCtl) case MODE_INT_RUN: case MODE_RUN: case MODE_SI: - stuff_cmd("go"); + stuff_cmd("cont"); break; case MODE_DISP: /* display core and advance IAR */ @@ -1196,16 +1200,17 @@ void HandleCommand (HWND hWnd, WORD wNotify, WORD idCtl, HWND hwCtl) case IDC_PROGRAM_STOP: if (running) { /* potential race condition here */ GUI_BEGIN_CRITICAL_SECTION - SETBIT(cpu_dsw, CPU_DSW_PROGRAM_STOP); - SETBIT(ILSW[5], ILSW_5_PROGRAM_STOP); - int_req |= INT_REQ_5; + SETBIT(con_dsw, CPU_DSW_PROGRAM_STOP); + SETBIT(ILSW[5], ILSW_5_INT_RUN_PROGRAM_STOP); + int_req |= INT_REQ_5; /* note: calc_ints() is not needed in this case */ + int_lamps |= INT_REQ_5; GUI_END_CRITICAL_SECTION } break; case IDC_LOAD_IAR: if (! running) { - IAR = CES & 0x3FFF; /* set IAR from console entry switches */ + IAR = CES & mem_mask; /* set IAR from console entry switches */ } break; @@ -1214,12 +1219,13 @@ void HandleCommand (HWND hWnd, WORD wNotify, WORD idCtl, HWND hwCtl) case IDC_IMM_STOP: if (running) { - reason = STOP_WAIT; /* terminate execution without setting wait_mode */ - -// this prevents message pump from running, which unfortunately locks up -// the emulator thread when it calls gui_run(FALSE) which calls EnableWindow on the Run lamp -// while (running) -// Sleep(10); /* wait for execution thread to exit */ + reason = STOP_IMMEDIATE; /* terminate execution without setting wait_mode */ + /* wait for execution thread to exit */ +/* this prevents message pump from running, which unfortunately locks up + * the emulator thread when it calls gui_run(FALSE) which calls EnableWindow on the Run lamp + * while (running) + * Sleep(10); + */ } break; @@ -1290,10 +1296,6 @@ LRESULT CALLBACK ConsoleWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPa SetRect(&rbmp, 0, 0, bmwid, bmht); if (IntersectRect(&xsect, &clip, &rbmp)) BitBlt(hDC, xsect.left, xsect.top, xsect.right-xsect.left+1, xsect.bottom-xsect.top+1, hCDC, xsect.left, xsect.top, SRCCOPY); -// rbmp.top = rbmp.bottom; -// rbmp.bottom += 200; -// if (IntersectRect(&xsect, &clip, &rbmp)) -// FillRect(hDC, &xsect, hbBlack); return TRUE; /* let Paint do this so we know what the update region is (ps.rcPaint) */ case WM_PAINT: @@ -1318,11 +1320,15 @@ LRESULT CALLBACK ConsoleWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPa case WM_SETCURSOR: GetCursorPos(&p); ScreenToClient(hWnd, &p); - SetCursor(HandleClick(hWnd, p.x, p.y, FALSE) ? hcHand : hcArrow); + SetCursor(HandleClick(hWnd, p.x, p.y, FALSE, FALSE) ? hcHand : hcArrow); return TRUE; case WM_LBUTTONDOWN: - HandleClick(hWnd, LOWORD(lParam), HIWORD(lParam), TRUE); + HandleClick(hWnd, LOWORD(lParam), HIWORD(lParam), TRUE, FALSE); + break; + + case WM_RBUTTONDOWN: + HandleClick(hWnd, LOWORD(lParam), HIWORD(lParam), TRUE, TRUE); break; case WM_CTLCOLORBTN: @@ -1339,7 +1345,7 @@ LRESULT CALLBACK ConsoleWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPa break; case WM_DROPFILES: - accept_dropped_file((HANDLE) wParam); // console window - dragged file is a script or card deck + accept_dropped_file((HANDLE) wParam); /* console window - dragged file is a script or card deck */ break; default: @@ -1368,7 +1374,7 @@ void forms_check (int set) EnableWindow(btn[IDC_FORMS_CHECK].hBtn, printerstatus); if (btn[IDC_FORMS_CHECK].clr != oldcolor) - InvalidateRect(btn[IDC_FORMS_CHECK].hBtn, NULL, TRUE); // change color in any case + InvalidateRect(btn[IDC_FORMS_CHECK].hBtn, NULL, TRUE); /* change color in any case */ } } @@ -1389,7 +1395,7 @@ void print_check (int set) EnableWindow(btn[IDC_FORMS_CHECK].hBtn, printerstatus); if (btn[IDC_FORMS_CHECK].clr != oldcolor) - InvalidateRect(btn[IDC_FORMS_CHECK].hBtn, NULL, TRUE); // change color in any case + InvalidateRect(btn[IDC_FORMS_CHECK].hBtn, NULL, TRUE); /* change color in any case */ } } @@ -1425,34 +1431,34 @@ static void accept_dropped_file (HANDLE hDrop) POINT pt; HWND hWndDrop; - nfiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); // get file count, - DragQueryFile(hDrop, 0, fname, sizeof(fname)); // get first filename - DragQueryPoint(hDrop, &pt); // get location of drop + nfiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); /* get file count, */ + DragQueryFile(hDrop, 0, fname, sizeof(fname)); /* get first filename */ + DragQueryPoint(hDrop, &pt); /* get location of drop */ DragFinish(hDrop); - if (nfiles <= 0) // hmm, this seems unlikely to occur, but better check + if (nfiles <= 0) /* hmm, this seems unlikely to occur, but better check */ return; - if (running) { // can only accept a drop while processor is stopped + if (running) { /* can only accept a drop while processor is stopped */ MessageBeep(0); return; } if ((hWndDrop = ChildWindowFromPoint(hConsoleWnd, pt)) == btn[IDC_1442].hBtn) - cardreader = TRUE; // file was dropped onto 1442 card reader + cardreader = TRUE; /* file was dropped onto 1442 card reader */ else if (hWndDrop == NULL || hWndDrop == hConsoleWnd) - cardreader = FALSE; // file was dropped onto console window, not a button + cardreader = FALSE; /* file was dropped onto console window, not a button */ else { - MessageBeep(0); // file was dropped onto another button + MessageBeep(0); /* file was dropped onto another button */ return; } - if (nfiles > 1) { // oops, we wouldn't know what order to read them in + if (nfiles > 1) { /* oops, we wouldn't know what order to read them in */ MessageBox(hConsoleWnd, "You may only drop one file at a time", "", MB_OK); return; } - // if shift key is down, prepend @ to name (make it a deck file) + /* if shift key is down, prepend @ to name (make it a deck file) */ deckfile = ((GetKeyState(VK_SHIFT) & 0x8000) && cardreader) ? "@" : ""; sprintf(cmd, "%s \"%s%s\"", cardreader ? "attach cr" : "do", deckfile, fname); @@ -1466,22 +1472,18 @@ static void tear_printer (void) if ((prt_unit.flags & UNIT_ATT) == 0) return; - strcpy(filename, prt_unit.filename); // save current attached filename + strcpy(filename, prt_unit.filename); /* save current attached filename */ - if (! stuff_and_wait("detach prt", 1000, 0)) // detach it + if (! stuff_and_wait("detach prt", 1000, 0)) /* detach it */ return; - sprintf(cmd, "view \"%s\"", filename); // spawn notepad to view it + sprintf(cmd, "view \"%s\"", filename); /* spawn notepad to view it */ if (! stuff_and_wait(cmd, 3000, 500)) return; -// no, now we have them click the card reader icon twice to unload the deck. more flexible that way -// if (! stuff_and_wait("detach cr", 1000, 0)) // detach the card reader so they can edit the deck file -// return; + remove(filename); /* delete the file */ - remove(filename); // delete the file - - sprintf(cmd, "attach prt \"%s\"", filename); // reattach + sprintf(cmd, "attach prt \"%s\"", filename); /* reattach */ stuff_cmd(cmd); } @@ -1582,24 +1584,25 @@ void stuff_cmd (char *cmd) SetEvent(hCmdReadyEvent); /* notify main thread a line is ready */ } -// my_yield - process GUI messages. It's not apparent why stuff_and_wait would block, -// since it sleeps in the GUI thread while scp runs in the main thread. However, -// at the end of every command scp calls update_gui, which can result in messages -// being sent to the GUI thread. So, the GUI thread has to process messages while -// stuff_and_wait is waiting. - +/* my_yield - process GUI messages. It's not apparent why stuff_and_wait would block, + * since it sleeps in the GUI thread while scp runs in the main thread. However, + * at the end of every command scp calls update_gui, which can result in messages + * being sent to the GUI thread. So, the GUI thread has to process messages while + * stuff_and_wait is waiting. + */ static void my_yield (void) { MSG msg; - // multitask + /* multitask */ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } } -// stuff_and_wait -- stuff a command and wait for the emulator to process the command -// and come back to prompt for another +/* stuff_and_wait -- stuff a command and wait for the emulator to process the command + * and come back to prompt for another + */ t_bool stuff_and_wait (char *cmd, int timeout, int delay) { @@ -1650,5 +1653,5 @@ void remark_cmd (char *remark) } } -#endif // _WIN32 defined -#endif // GUI_SUPPORT defined +#endif /* _WIN32 defined */ +#endif /* GUI_SUPPORT defined */ diff --git a/Ibm1130/ibm1130_plot.c b/Ibm1130/ibm1130_plot.c new file mode 100644 index 00000000..02344a3c --- /dev/null +++ b/Ibm1130/ibm1130_plot.c @@ -0,0 +1,634 @@ +/* ibm1130_plot.c: IBM 1130 1627 plotter emulation + + Based on the SIMH simulator package written by Robert M Supnik + + Brian Knittel + Revision History + + 2004.10.22 - Written. + 2006.1.2 - Rewritten as plotter routine by Carl V Claunch + + * (C) Copyright 2004, 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 + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to simh@ibm1130.org + */ + +#include "ibm1130_defs.h" + +#ifndef ENABLE_PLOT_SUPPORT + + DEVICE plot_dev = { + "PLOT", NULL, NULL, NULL, + 0, 16, 16, 1, 16, 16, + NULL, NULL, NULL, + NULL, NULL, NULL}; + + void xio_1627_plotter (int32 addr, int32 func, int32 modify) + { + /* silently eat any plotter commands */ + } + +#else + +#include "gd.h" + +/*************************************************************************************** + * 1627 model 1 plotter (based on Calcomp 535 which was sold as IBM 1627) + * + * - 11" wide carriage, addressible in .01" steps + * - continous sheet paper up to 120' in length + * - sheet moveable in .01" steps, either direction + * - switchable pen, in various colors and line widths + * + * Simulator implementation will create a JPEG image corresponding to a + * landscape mode sheet of paper, the width of the carriage at 11". + * A diagram of more than 8" of paper travel will span printed pages + * in landscape mode. + * + * When an 'att plot' command is issued a file is created based on the + * default or currently set values of paper length, starting + * position of the pen in both X and Y axes, pen color and pen width. + * Based on the number of logical pages of paper, the command will create + * the proper size canvas internally and create the output JPEG file. + * + * When a 'det plot' command is issued, the plotter image will be converted + * into the file that was specified during the attach process. The + * image is not viewable until this point, unless an examine plot is + * issued which will dump the current state of the paper into the file. + * + * The 'set plot' command can set pen width, paper length, pen color, + * current carriage X and Y coordinates. Paper length can be set + * to alter the default of 800 (8"); changes are ignored until + * the next 'attach' command. The current carriage x and y positions + * can be set at any time and will go into effect immediately, just + * as the pen color and pen width can be altered on the fly. + * + * NOTE: requires gd library and definition of ENABLE_PLOT_SUPPORT in makefile or Visual C configuration + * gd is not included in the main simh and ibm1130.org distributions at the present time. + ***************************************************************************************/ + +#define PLOT1627_DSW_OP_COMPLETE 0x8000 +#define PLOT1627_DSW_BUSY 0x0200 +#define PLOT1627_DSW_NOT_READY 0x0100 + +#define IS_ONLINE(u) (((u)->flags & (UNIT_ATT|UNIT_DIS)) == UNIT_ATT) +#define IS_DEBUG ((plot_unit->flags & UNIT_DEBUG) == UNIT_DEBUG) +#define IS_PENDOWN ((plot_unit->flags & UNIT_PEN) == UNIT_PEN) + +static t_stat plot_svc (UNIT *uptr); /* activity routine */ +static t_stat plot_reset (DEVICE *dptr); /* reset of 1130 */ +static t_stat plot_attach (UNIT *uptr, char *cptr); /* attach, loads plotter */ +static t_stat plot_detach (UNIT *uptr); /* detach and save image */ +static t_stat plot_examine (UNIT *uptr); /* update file with current canvas */ +static t_stat plot_set_length (UNIT *uptr, int32 val, char * ptr, void *desc); /* set paper length */ +static t_stat plot_set_pos (UNIT *uptr, int32 val, char * ptr, void *desc); /* reset current X/Y position */ +static t_stat plot_show_vals(FILE *fp, UNIT *uptr, int32 val, void *descrip); /* print x, y and length */ +static t_stat plot_show_nl(FILE *fp, UNIT *uptr, int32 val, void *descrip); /* overcome wacky simh behavior */ +static void update_pen(void); /* will ensure pen action is correct when changes made */ +static t_stat plot_validate_change (UNIT *uptr, int32 val, char * ptr, void *desc); /* when set command issued */ +static void process_cmd(void); /* does actual drawing for plotter */ + +extern int32 sim_switches; /* switches set on simh command */ +static int16 plot_dsw = 0; /* device status word */ +static int16 plot_cmd = 0; /* the command to process */ +static int32 plot_wait = 1000; /* plotter movement wait */ +static int32 plot_xpos = 0; /* current X position */ +static int32 plot_xmax = 799; /* end of paper */ +static int32 plot_ypos = 0; /* current Y position */ +static int32 plot_ymax = 1099; /* right edge of carriage */ + +#define PEN_DOWN 0x80000000 +#define PEN_UP 0x00000000 +static int32 plot_pen = PEN_UP; /* current pen position */ + +static int black_pen; /* holds color black */ +static int blue_pen; /* holds color blue */ +static int red_pen; /* holds color red */ +static int green_pen; /* holds color green */ +static int yellow_pen; /* holds yellow color */ +static int purple_pen; /* holds color purple */ +static int ltgrey_pen; /* holds light grey */ +static int grey_pen; /* holds grey */ +static int white_background; /* holds white of paper roll */ +static int plot_pwidth; /* set and display variable */ +static int plot_pcolor; /* set and display variable */ +static int need_update = 0; /* flag to force and update_pen() */ +static gdImagePtr image; /* pointer to our canvas */ + +#define UNIT_V_COLOR (UNIT_V_UF + 0) /* color of selected pen - 3 bits */ +#define UNIT_V_WIDTH (UNIT_V_UF + 3) /* width of pen - two bits */ +#define UNIT_V_NOOP (UNIT_V_UF + 5) /* dummy for set/show commands */ +#define UNIT_V_DEBUG (UNIT_V_UF + 6) /* for -d switch on attach command */ +#define UNIT_V_PEN (UNIT_V_UF + 7) /* track pen state */ + +#define UNIT_WIDTH (3u << UNIT_V_WIDTH) /* two bits */ +#define UNIT_COLOR (7u << UNIT_V_COLOR) /* three bits */ +#define UNIT_NOOP (1u << UNIT_V_NOOP) /* dummy for set/show */ +#define UNIT_DEBUG (1u << UNIT_V_DEBUG) /* shows debug mode on */ +#define UNIT_PEN (1u << UNIT_V_PEN) /* the pen state bit */ + +#define PEN_BLACK (0u << UNIT_V_COLOR) +#define PEN_RED (1u << UNIT_V_COLOR) +#define PEN_BLUE (2u << UNIT_V_COLOR) +#define PEN_GREEN (3u << UNIT_V_COLOR) +#define PEN_YELLOW (4u << UNIT_V_COLOR) +#define PEN_PURPLE (5u << UNIT_V_COLOR) +#define PEN_LTGREY (6u << UNIT_V_COLOR) +#define PEN_GREY (7u << UNIT_V_COLOR) + +#define SET_COLOR(op) {plot_unit[0].flags &= ~UNIT_COLOR; plot_unit[0].flags |= (op);} +#define GET_COLOR (plot_unit[0].flags & UNIT_COLOR) + +#define BLACK 0,0,0 +#define BLUE 0,0,255 +#define RED 255,0,0 +#define GREEN 0,255,0 +#define YELLOW 200,200,0 +#define PURPLE 150,0,150 +#define LTGREY 200,200,200 +#define GREY 120,120,120 +#define WHITE 255,255,255 + +#define PEN_SINGLE (0u << UNIT_V_WIDTH) +#define PEN_DOUBLE (1u << UNIT_V_WIDTH) +#define PEN_TRIPLE (2u << UNIT_V_WIDTH) +#define PEN_QUAD (3u << UNIT_V_WIDTH) + +#define GET_WIDTH() (plot_unit[0].flags & UNIT_WIDTH) +#define SET_WIDTH(cd) {plot_unit[0].flags &= ~UNIT_WIDTH; un.flags |= (cd);} + +UNIT plot_unit[] = { + { UDATA (&plot_svc, UNIT_ATTABLE, 0) }, +}; + +REG plot_reg[] = { + { HRDATA (DSW, plot_dsw, 16) }, /* device status word */ + { DRDATA (WTIME, plot_wait, 24), PV_LEFT }, /* plotter movement wait */ + { DRDATA (Xpos, plot_xpos, 32), PV_LEFT }, /* Current X Position*/ + { DRDATA (Ypos, plot_ypos, 32), PV_LEFT }, /* Current Y Position*/ + { FLDATA (PenDown, plot_pen, 0)}, /* Current pen position - 1 = down */ + { DRDATA (PaperSize, plot_xmax, 32), PV_LEFT }, /* Length of paper in inches */ + { NULL } }; + +MTAB plot_mod[] = { + { UNIT_COLOR, PEN_BLACK, "black", "BLACK", &plot_validate_change}, + { UNIT_COLOR, PEN_RED, "red", "RED", &plot_validate_change}, + { UNIT_COLOR, PEN_BLUE, "blue", "BLUE", &plot_validate_change}, + { UNIT_COLOR, PEN_GREEN, "green", "GREEN", &plot_validate_change}, + { UNIT_COLOR, PEN_YELLOW, "yellow", "YELLOW", &plot_validate_change}, + { UNIT_COLOR, PEN_PURPLE, "purple", "PURPLE", &plot_validate_change}, + { UNIT_COLOR, PEN_LTGREY, "ltgrey", "LTGREY", &plot_validate_change}, + { UNIT_COLOR, PEN_GREY, "grey", "GREY", &plot_validate_change}, + { UNIT_WIDTH, PEN_SINGLE, "1.0", "1.0", &plot_validate_change}, + { UNIT_WIDTH, PEN_DOUBLE, "2.0", "2.0", &plot_validate_change}, + { UNIT_WIDTH, PEN_TRIPLE, "3.0", "3.0", &plot_validate_change}, + { UNIT_WIDTH, PEN_QUAD, "4.0", "4.0", &plot_validate_change}, + { UNIT_PEN, UNIT_PEN, "pendown", "PENDOWN", &plot_validate_change}, + { UNIT_PEN, 0, "penup", "PENUP", &plot_validate_change}, + /* below is dummy entry to trigger the show routine and print extended values */ + { UNIT_NOOP, 0, "", NULL, NULL, &plot_show_vals}, + /* extended entries must allow parm for both unit and dev, but + * then they will print the value twice for a 'show plot' command + * therefore they are set to not display unless explicity requested + * and the special dummy NOOP entry will cause the print of these values */ + { MTAB_XTD | MTAB_VAL | MTAB_VUN | MTAB_VDV | MTAB_NMO, 2, + "length", "LENGTH", &plot_set_length, &plot_show_nl, &plot_reg[5]}, + { MTAB_XTD | MTAB_VAL | MTAB_VDV | MTAB_VUN | MTAB_NMO, 0, + "Xpos", "XPOS", &plot_set_pos, &plot_show_nl, &plot_reg[2]}, + { MTAB_XTD | MTAB_VAL | MTAB_VDV | MTAB_VUN | MTAB_NMO, 1, + "Ypos", "YPOS", &plot_set_pos, &plot_show_nl, &plot_reg[3]}, + { 0 } }; + +DEVICE plot_dev = { + "PLOT", plot_unit, plot_reg, plot_mod, + 1, 16, 16, 1, 16, 16, + NULL, NULL, plot_reset, + NULL, plot_attach, plot_detach}; + +/* xio_1627_plotter - XIO command interpreter for the 1627 plotter model 1 */ + +void xio_1627_plotter (iocc_addr, iocc_func, iocc_mod) +{ + char msg[80]; + + if (! IS_ONLINE(plot_unit) ) { + SETBIT(plot_dsw, PLOT1627_DSW_NOT_READY); /* set not ready */ + if (IS_DEBUG) printf("Plotter has no paper, ignored\n"); + return; /* and ignore */ + } + + switch (iocc_func) { + case XIO_READ: /* read XIO */ + xio_error("Read XIO not supported by 1627 plotter"); + break; + + case XIO_WRITE: /* write: do one plotter operation */ + if ((plot_dsw & PLOT1627_DSW_NOT_READY)) { + if (IS_DEBUG) printf("Wrote to non-ready Plotter\n"); + break; + } + plot_cmd = (uint16) ( M[iocc_addr & mem_mask] >> 10 ); /* pick up command */ + process_cmd(); /* interpret command */ + sim_activate(plot_unit, plot_wait); /* schedule interrupt */ + SETBIT(plot_dsw, PLOT1627_DSW_BUSY); /* mark it busy */ + break; + + case XIO_SENSE_DEV: /* sense device status */ + ACC = plot_dsw; /* get current status */ + if (iocc_mod & 0x01) { /* reset interrupts */ + CLRBIT(plot_dsw, PLOT1627_DSW_OP_COMPLETE); + CLRBIT(ILSW[3], ILSW_3_1627_PLOTTER); + } + break; + + case XIO_CONTROL: /* control XIO */ + xio_error("Control XIO not supported by 1627 plotter"); + break; + + default: + sprintf(msg, "Invalid 1627 Plotter XIO function %x", iocc_func); + xio_error(msg); + } + return; +} + +// plot_svc - 1627 plotter operation complete + +static t_stat plot_svc (UNIT *uptr) +{ + CLRBIT(plot_dsw, PLOT1627_DSW_BUSY); /* clear reader busy flag */ + + SETBIT(plot_dsw, PLOT1627_DSW_OP_COMPLETE); /* indicate read complete */ + + SETBIT(ILSW[3], ILSW_3_1627_PLOTTER); /* initiate interrupt */ + calc_ints(); + + return SCPE_OK; +} + +/* plot_reset - reset emulated plotter */ + +static t_stat plot_reset (DEVICE *dptr) +{ + char * buf; + int32 size; + + sim_cancel(plot_unit); + + CLRBIT(plot_dsw, PLOT1627_DSW_BUSY | PLOT1627_DSW_OP_COMPLETE); + + if (IS_DEBUG) printf("reset routine for Plotter\n"); + + CLRBIT(ILSW[3], ILSW_3_1627_PLOTTER); + calc_ints(); + + return SCPE_OK; +} + + +/* plot_attach - attach file to simulated plotter */ + +static t_stat plot_attach (UNIT *uptr, char *cptr) +{ + t_stat result; + + CLRBIT(uptr->flags, UNIT_DEBUG); + if (sim_switches & SWMASK('D')) SETBIT(uptr->flags, UNIT_DEBUG); + + /* get the output file by using regular attach routine */ + result = attach_unit(uptr, cptr); + + if (result != SCPE_OK) { + if (IS_DEBUG) printf("problem attaching file\n"); + return result; + } + + SETBIT(plot_dsw, PLOT1627_DSW_NOT_READY); /* assume failure */ + + /* set up our canvas at the desired size */ + image = gdImageCreate(plot_ymax+1,plot_xmax+1); /* create our canvas */ + if (image == NULL) { + if (IS_DEBUG) printf("problem creating image canvas\n"); + return SCPE_MEM; + } + + /* set up the basic colors after image created */ + white_background = gdImageColorAllocate(image,WHITE); /* white is background */ + black_pen = gdImageColorAllocate(image,BLACK); /* load up black color */ + blue_pen = gdImageColorAllocate(image,BLUE); /* load up blue color */ + red_pen = gdImageColorAllocate(image,RED); /* load up red color */ + green_pen = gdImageColorAllocate(image,GREEN); /* load up green color */ + yellow_pen = gdImageColorAllocate(image,YELLOW); /* load up yellow color */ + purple_pen = gdImageColorAllocate(image,PURPLE); /* load up purple color */ + ltgrey_pen = gdImageColorAllocate(image,LTGREY); /* load up light grey color */ + grey_pen = gdImageColorAllocate(image,GREY); /* load up grey color */ + + if ( (white_background == -1) || (black_pen == -1) || + (red_pen == -1) || (blue_pen == -1) || (green_pen == -1) || + (purple_pen == -1) || (ltgrey_pen == -1) || (grey_pen == -1) ) { + if (IS_DEBUG) printf("problem allocating pen colors\n"); + return SCPE_MEM; + } + + CLRBIT(plot_dsw, PLOT1627_DSW_NOT_READY); /* we're in business */ + + update_pen(); /* routine to ensure pen is okay */ + + return SCPE_OK; +} + +/* pen updating routine, called at attach and whenever we reset the values */ + +void update_pen (void) +{ + int color; + int width; + + if (!IS_ONLINE(plot_unit)) return; /* only do this if attached */ + + /* pick up latest color as active pen */ + color = GET_COLOR; + switch (color) { + case PEN_BLACK: + plot_pcolor = black_pen; + break; + + case PEN_RED: + plot_pcolor = red_pen; + break; + + case PEN_BLUE: + plot_pcolor = blue_pen; + break; + + case PEN_GREEN: + plot_pcolor = green_pen; + break; + + case PEN_YELLOW: + plot_pcolor = yellow_pen; + break; + + case PEN_PURPLE: + plot_pcolor = purple_pen; + break; + + case PEN_LTGREY: + plot_pcolor = ltgrey_pen; + break; + + case PEN_GREY: + plot_pcolor = grey_pen; + break; + + default: + if (IS_DEBUG) printf("invalid pen color state\n"); + plot_pcolor = black_pen; + break; + } + + /* set up anti-aliasing for the line */ + gdImageSetAntiAliased(image, plot_pcolor); + + /* pick up latest width for pen */ + width = GET_WIDTH(); + switch (width) { + case PEN_SINGLE: + plot_pwidth = 1; + gdImageSetThickness(image, 1); + break; + + case PEN_TRIPLE: + plot_pwidth = 3; + gdImageSetThickness(image, 3); + break; + + case PEN_DOUBLE: + plot_pwidth = 2; + gdImageSetThickness(image, 2); + break; + + case PEN_QUAD: + plot_pwidth = 4; + gdImageSetThickness(image, 4); + break; + + default: + if (IS_DEBUG) printf("invalid pen width\n"); + plot_pwidth = 1; + gdImageSetThickness(image, 1); + break; + } + + /* now ensure the pen state is accurate */ + plot_pen = IS_PENDOWN ? PEN_DOWN : PEN_UP; + return; +} + +/* plot_detach - detach file from simulated plotter */ +static t_stat plot_detach (UNIT *uptr) +{ + char * buf; + int32 size; + FILE * fp; + int32 result; + + SETBIT(plot_dsw, PLOT1627_DSW_NOT_READY); + + /* copy images to files, close files, set device to detached, free gd memory */ + + buf = gdImageGifPtr(image,&size); + if (! buf) { + if (IS_DEBUG) printf("failure creating GIF in-memory\n"); + return SCPE_MEM; + } + + fp = uptr->fileref; /* get file attached to unit */ + + if (! fseek(fp,0,SEEK_SET)) { /* first we reset to begin of file */ + if (IS_DEBUG) printf("wrote out GIF to file\n"); + result = fwrite(buf,1,size,fp); /* write out our image to the file */ + } + + gdFree(buf); /* free up the memory of GIF format */ + gdImageDestroy(image); /* free up the canvas memory */ + + if (result != size) { /* some problem writing it */ + if (IS_DEBUG) printf("error in write of image file\n"); + return SCPE_IOERR; + } + + return detach_unit(uptr); /* have simh close the file */ +} + +/* process_cmd - implement the drawing actions of the plotter */ + +static void process_cmd (void) +{ + int32 oldx, oldy; + + /* first see if we set any changes to pen or position, do an update */ + if (need_update) { + update_pen(); + need_update = 0; + } + + /* will move pen one step or flip pen up or down */ + oldx = plot_xpos; + oldy = plot_ypos; + + switch (plot_cmd) { + case 1: /* raise pen command */ + plot_pen = PEN_UP; + plot_unit->flags = plot_unit->flags & (~UNIT_PEN); + return; + break; + + case 2: /* +Y command */ + plot_ypos = plot_ypos + 1; + break; + + case 4: /* -Y command */ + plot_ypos = plot_ypos - 1; + break; + + case 8: /* -X command */ + plot_xpos = plot_xpos - 1; + break; + + case 10: /* -X +Y command */ + plot_xpos = plot_xpos - 1; + plot_ypos = plot_ypos + 1; + break; + + case 12: /* -X -Y command */ + plot_xpos = plot_xpos - 1; + plot_ypos = plot_ypos - 1; + break; + + case 16: /* +X command */ + plot_xpos = plot_xpos + 1; + break; + + case 18: /* +X +Y command */ + plot_xpos = plot_xpos + 1; + plot_ypos = plot_ypos + 1; + break; + + case 20: /* +X -Y pen command */ + plot_xpos = plot_xpos + 1; + plot_ypos = plot_ypos - 1; + break; + + case 32: /* lower pen command */ + plot_pen = PEN_DOWN; + plot_unit->flags = plot_unit->flags | UNIT_PEN; + return; + break; + + default: + if (IS_DEBUG) printf("invalid plotter command\n"); + return; + break; + } + + /* check to see if carriage has moved off any edge */ + if ((plot_xpos > (plot_xmax+1)) || (plot_ypos > (plot_ymax+1)) || + (plot_xpos < 0) || (plot_ypos < 0)) { + /* if so, ignore as 1627 has no way of signalling error */ + if (IS_DEBUG) printf( + "attempted to move carriage off paper edge %d %d for command %d\n", + plot_xpos,plot_ypos,plot_cmd); + return; + } + + /* only draw a line if the pen was down during the movement command */ + if (plot_pen) { + gdImageLine(image, plot_ymax-plot_ypos, plot_xmax-plot_xpos, plot_ymax-oldy, plot_xmax-oldx, gdAntiAliased); + /* semantics are 0,0 point is lower right */ + } + + return; +} + +/* plot_set_length - validate and store the length of the paper */ + +static t_stat plot_set_length (UNIT *uptr, int32 set, char *ptr, void *desc) +{ + char *cptr; + int32 val; + +#define LONGEST_ROLL 1440000 /* longest is 120', 14400", 1,440,000 .01"s */ + + val = strtotv (ptr, &cptr, (uint32) 10); /* sim routine to get value */ + if ((val < 1) | (val >= LONGEST_ROLL)) { /* check valid range */ + if (IS_DEBUG) printf("setting paper more than 120' or less than 1 inch\n"); + return SCPE_ARG; + } + + /* origin zero drawing, reduce by 1 but show command will fudge by adding it back */ + *((int32 *)((REG *) desc)->loc) = val - 1; + + return SCPE_OK; +} + +/* plot_set_pos - validate and store the new position of the carriage */ + +static t_stat plot_set_pos (UNIT *uptr, int32 set, char *ptr, void *desc) +{ + char *cptr; + int32 val; + int32 max; + + max = (set == 1) ? plot_ymax : plot_xmax; + val = strtotv (ptr, &cptr, (uint32) 10); + if ((val < 0) | (val > max)) { + if (IS_DEBUG) printf("error moving carriage off paper edge\n"); + return SCPE_ARG; + } + + *((int32 *)((REG *) desc)->loc) = val; + + return SCPE_OK; +} + +/* routine to display the paper length and carriage position + * cannot use regular simh routine because it prints values twice, + * once for device and once for unit + */ + +static t_stat plot_show_vals (FILE *fp, UNIT *uptr, int32 val, void *descrip) +{ + fprintf(fp, "length=%d, Xpos=%d, Ypos=%d",plot_xmax+1, plot_xpos,plot_ypos); + return SCPE_OK; +} + +/* routine to add a terminating NL character when 'show plot length' + * or equivalent for xpos or ypos is issued, as simh will not append for us */ + +static t_stat plot_show_nl(FILE *fp, UNIT *uptr, int32 val, void *descrip) +{ + int32 disp; + char *label; + + disp = (val == 2) ? plot_xmax + 1 : ((val == 1) ? plot_ypos : plot_xpos); + label = (val == 2) ? "length=" : ((val == 1) ? "Ypos=" : "Xpos="); + + fprintf(fp, "%s%d\n", label, disp); + return SCPE_OK; +} + +/* plot_validate_change - force the update_pen routine to be called after user changes pen setting */ + +static t_stat plot_validate_change (UNIT *uptr, int32 set, char *ptr, void *desc) +{ + need_update = 1; + return SCPE_OK; +} + +#endif /* ENABLE_PLOT_SUPPORT */ diff --git a/Ibm1130/ibm1130_prt.c b/Ibm1130/ibm1130_prt.c index f5eabfa1..30fe258c 100644 --- a/Ibm1130/ibm1130_prt.c +++ b/Ibm1130/ibm1130_prt.c @@ -5,6 +5,17 @@ Brian Knittel Revision History + 2006.12.06 - Moved CGI stuff out of this routine into cgi1130 main() module. + + 2006.07.06 - Made 1403 printer 132 columns wide, was 120 previously + + 2006.01.03 - Fixed bug in prt_attach, found and fixed by Carl Claunch. Detach followed + by reattach of 1403-mode printer left device permanently not-ready. + + 2004.11.08 - HACK for demo mode: in physical (-p) mode, multiple consecutive formfeeds are suppressed. + This lets us do a formfeed at the end of a job to kick the last page out + without getting another blank page at the beginning of the next job. + 2003.12.02 - Added -p option for physical line printer output (flushes output buffer after each line). When using a physical printer on Windows, be sure to set printer to "send output directly to printer" @@ -36,6 +47,7 @@ */ #include "ibm1130_defs.h" +#include /* needed for atexit, for cgi mode */ /*************************************************************************************** * 1132 PRINTER @@ -87,6 +99,8 @@ static int32 prt_fwait = 100; /* fast wait, for 1403 operations */ static int32 prt_twait = 50; /* transfer wait, for 1403 operations */ #define SKIPTARGET (uptr->u4) /* target for skip operation */ +static t_bool formfed = FALSE; /* last line printed was a formfeed */ + #define UNIT_V_FORMCHECK (UNIT_V_UF + 0) /* out of paper error */ #define UNIT_V_DATACHECK (UNIT_V_UF + 1) /* printer overrun error */ #define UNIT_V_SKIPPING (UNIT_V_UF + 2) /* printer skipping */ @@ -145,12 +159,13 @@ DEVICE prt_dev = { NULL, NULL, &prt_reset, NULL, prt_attach, prt_detach}; -#define PRT_COLUMNS 120 -#define PRT_ROWLEN 120 -#define MAX_OVPRINT 20 +#define MAX_COLUMNS 120 +#define MAX_OVPRINT 20 +#define PRT1132_COLUMNS 120 +#define PRT1403_COLUMNS 120 /* the 1130's version of the 1403 printed in 120 columns only (see Functional Characteristics) */ -static char prtbuf[PRT_ROWLEN*MAX_OVPRINT]; -static int nprint[PRT_COLUMNS], ncol[MAX_OVPRINT], maxnp; +static char prtbuf[MAX_COLUMNS*MAX_OVPRINT]; +static int nprint[MAX_COLUMNS], ncol[MAX_OVPRINT], maxnp; static int prt_nchar, prt_row; /* current printwheel position, current page row */ static int prt_nnl; /* number of queued newlines */ @@ -178,18 +193,18 @@ static struct tag_ccpunches { /* list of rows and punches on tape */ int row, channels; } ccpunches[] = { - 2, CC_CHANNEL_1, // channel 1 = top of form - 62, CC_CHANNEL_12 // channel 12 = bottom of form + 2, CC_CHANNEL_1, /* channel 1 = top of form */ + 62, CC_CHANNEL_12 /* channel 12 = bottom of form */ }, cccgi[] = { - 2, CC_CHANNEL_1 // channel 1 = top of form; no bottom of form + 2, CC_CHANNEL_1 /* channel 1 = top of form; no bottom of form */ }; #include "ibm1130_prtwheel.h" extern int32 sim_switches; -// cc_format_1132 and cc_format_1403 - turn cctape bits into proper format for DSW or status read +/* cc_format_1132 and cc_format_1403 - turn cctape bits into proper format for DSW or status read */ static int cc_format_1132 (int bits) { @@ -200,7 +215,7 @@ static int cc_format_1132 (int bits) #define cc_format_1403(bits) (bits) -// reset_prt_line - clear the print line following paper advancement +/* reset_prt_line - clear the print line following paper advancement */ static void reset_prt_line (void) { @@ -209,116 +224,116 @@ static void reset_prt_line (void) maxnp = 0; } -// save_1132_prt_line - fire hammers for character 'ch' +/* save_1132_prt_line - fire hammers for character 'ch' */ static t_bool save_1132_prt_line (int ch) { int i, r, addr = 32; int32 mask = 0, wd = 0; - for (i = 0; i < PRT_COLUMNS; i++) { - if (mask == 0) { // fetch next word from memory + for (i = 0; i < PRT1132_COLUMNS; i++) { + if (mask == 0) { /* fetch next word from memory */ mask = 0x8000; wd = M[addr++]; } - if (wd & mask) { // hammer is to fire in this column + if (wd & mask) { /* hammer is to fire in this column */ if ((r = nprint[i]) < MAX_OVPRINT) { - if (ncol[r] <= i) { // we haven't moved this far yet - if (ncol[r] == 0) // first char in this row? - memset(prtbuf+r*PRT_ROWLEN, ' ', PRT_COLUMNS); // blank out the new row - ncol[r] = i+1; // remember new row length + if (ncol[r] <= i) { /* we haven't moved this far yet */ + if (ncol[r] == 0) /* first char in this row? */ + memset(prtbuf+r*MAX_COLUMNS, ' ', PRT1132_COLUMNS); /* blank out the new row */ + ncol[r] = i+1; /* remember new row length */ } - prtbuf[r*PRT_ROWLEN + i] = (char) ch; // save the character + prtbuf[r*MAX_COLUMNS + i] = (char) ch; /* save the character */ - nprint[i]++; // remember max overprintings for this column + nprint[i]++; /* remember max overprintings for this column */ maxnp = MAX(maxnp, nprint[i]); } } - mask >>= 1; // prepare to examine next bit + mask >>= 1; /* prepare to examine next bit */ } - return wd & 1; // return TRUE if the last word has lsb set, which means all bits had been set + return wd & 1; /* return TRUE if the last word has lsb set, which means all bits had been set */ } -// write_line - write collected line to output file. No need to trim spaces as the hammers -// are never fired for them, so ncol[r] is the last printed position on each line. +/* write_line - write collected line to output file. No need to trim spaces as the hammers + * are never fired for them, so ncol[r] is the last printed position on each line. + */ -static void newpage (FILE *fd) +static void newpage (FILE *fd, t_bool physical_printer) { if (cgi) fputs("
\n", fd); - else - putc('\f', fd); // formfeed + else if (! formfed) { + putc('\f', fd); + if (physical_printer) { + fflush(fd); /* send the ff out to the printer immediately */ + formfed = TRUE; /* hack: inhibit consecutive ff's */ + } + } } -static void flush_prt_line (FILE *fd, int spacemode, t_bool phys_flush) +static void flush_prt_line (FILE *fd, int spacemode, t_bool physical_printer) { int r; - if (! (spacemode || maxnp)) // nothing to do + if (! (spacemode || maxnp)) /* nothing to do */ return; - prt_row = (prt_row+1) % PRT_PAGELENGTH; // NEXT line + prt_row = (prt_row+1) % PRT_PAGELENGTH; /* NEXT line */ - if (spacemode && ! maxnp) { // spacing only + if (spacemode && ! maxnp) { /* spacing only */ if (prt_row == 0 && prt_nnl) { #ifdef _WIN32 if (! cgi) - putc('\r', fd); // DOS/Windows: end with cr/lf + putc('\r', fd); /* DOS/Windows: end with cr/lf */ #endif - putc('\n', fd); // otherwise end with lf - if (spacemode & UNIT_SKIPPING) // add formfeed if we crossed page boundary while skipping - newpage(fd); + putc('\n', fd); /* otherwise end with lf */ + if (spacemode & UNIT_SKIPPING) /* add formfeed if we crossed page boundary while skipping */ + newpage(fd, physical_printer); + prt_nnl = 0; } - else + else { prt_nnl++; + formfed = FALSE; + } - prt_unit->pos++; // note something written + prt_unit->pos++; /* note something written */ return; } - if (prt_nnl) { // there are queued newlines -// if we spaced to top of form, don't emit formfeed. We'd only ever emit the formfeed if we skipped via control tape channels -// if (prt_row == 0 && prt_nnl) { // we spaced to top of form -//#ifdef _WIN32 -// if (! cgi) -// putc('\r', fd); // DOS/Windows: end with cr/lf -//#endif -// putc('\n', fd); // otherwise end with lf -// newpage(fd); -// prt_nnl = 0; -// } -// else { - while (prt_nnl > 0) { // spit out queued newlines + if (prt_nnl) { /* there are queued newlines */ + while (prt_nnl > 0) { /* spit out queued newlines */ #ifdef _WIN32 - if (! cgi) - putc('\r', fd); // DOS/Windows: end with cr/lf + if (! cgi) + putc('\r', fd); /* DOS/Windows: end with cr/lf */ #endif - putc('\n', fd); // otherwise end with lf - prt_nnl--; - } -// } + putc('\n', fd); /* otherwise end with lf */ + prt_nnl--; + } } for (r = 0; r < maxnp; r++) { if (r > 0) - putc('\r', fd); // carriage return between overprinted lines - fxwrite(&prtbuf[r*PRT_ROWLEN], 1, ncol[r], fd); + putc('\r', fd); /* carriage return between overprinted lines */ + + fxwrite(&prtbuf[r*MAX_COLUMNS], 1, ncol[r], fd); } reset_prt_line(); - prt_unit->pos++; // note something written - prt_nnl++; // queue a newline + prt_unit->pos++; /* note something written */ + prt_nnl++; /* queue a newline */ - if (phys_flush) // if physical printer, send buffered output to device + if (physical_printer) /* if physical printer, send buffered output to device */ fflush(fd); + + formfed = FALSE; /* note that something is now on the page */ } -// 1132 printer commands +/* 1132 printer commands */ #define PRT_CMD_START_PRINTER 0x0080 #define PRT_CMD_STOP_PRINTER 0x0040 @@ -347,7 +362,7 @@ void xio_1132_printer (int32 iocc_addr, int32 func, int32 modify) switch (func) { case XIO_READ: - M[iocc_addr & mem_mask] = (uint16) (codewheel1132[prt_nchar].ebcdic << 8); + M[iocc_addr & mem_mask] = codewheel1132[prt_nchar].ebcdic << 8; if ((uptr->flags & UNIT_PRINTING) == 0) /* if we're not printing, advance this after every test */ prt_nchar = (prt_nchar + 1) % WHEELCHARS_1132; @@ -364,31 +379,31 @@ void xio_1132_printer (int32 iocc_addr, int32 func, int32 modify) case XIO_CONTROL: if (modify & PRT_CMD_START_PRINTER) { SETBIT(uptr->flags, UNIT_PRINTING); -// mytrace(1, "printing"); +/* mytrace(1, "printing"); */ } if (modify & PRT_CMD_STOP_PRINTER) { CLRBIT(uptr->flags, UNIT_PRINTING); -// mytrace(0, "printing"); +/* mytrace(0, "printing"); */ } if (modify & PRT_CMD_START_CARRIAGE) { SETBIT(uptr->flags, UNIT_SKIPPING); -// mytrace(1, "skipping"); +/* mytrace(1, "skipping"); */ } if (modify & PRT_CMD_STOP_CARRIAGE) { CLRBIT(uptr->flags, UNIT_SKIPPING); -// mytrace(0, "skipping"); +/* mytrace(0, "skipping"); */ } if (modify & PRT_CMD_SPACE) { SETBIT(uptr->flags, UNIT_SPACING); -// mytrace(1, "space"); +/* mytrace(1, "space"); */ } sim_cancel(uptr); - if (uptr->flags & (UNIT_SKIPPING|UNIT_SPACING|UNIT_PRINTING)) { // busy bits = doing something + if (uptr->flags & (UNIT_SKIPPING|UNIT_SPACING|UNIT_PRINTING)) { /* busy bits = doing something */ SETBIT(PRT_DSW, PRT1132_DSW_PRINTER_BUSY); sim_activate(uptr, prt_cwait); } @@ -419,14 +434,14 @@ static t_stat prt_svc (UNIT *uptr) return IS_1403(uptr) ? prt1403_svc(uptr) : prt1132_svc(uptr); } -// prt1132_svc - emulated timeout for 1132 operation +/* prt1132_svc - emulated timeout for 1132 operation */ static t_stat prt1132_svc (UNIT *uptr) { - if (PRT_DSW & PRT1132_DSW_NOT_READY) { // cancel operation if printer went offline + if (PRT_DSW & PRT1132_DSW_NOT_READY) { /* cancel operation if printer went offline */ SETBIT(uptr->flags, UNIT_FORMCHECK); SET_ACTION(uptr, 0); - forms_check(TRUE); // and turn on forms check lamp + forms_check(TRUE); /* and turn on forms check lamp */ return SCPE_OK; } @@ -436,7 +451,7 @@ static t_stat prt1132_svc (UNIT *uptr) CLRBIT(PRT_DSW, PRT1132_DSW_CHANNEL_MASK|PRT1132_DSW_PRINTER_BUSY|PRT1132_DSW_CARRIAGE_BUSY); SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row]) | PRT1132_DSW_SPACE_RESPONSE); SETBIT(ILSW[1], ILSW_1_1132_PRINTER); - CLRBIT(uptr->flags, UNIT_SPACING); // done with this + CLRBIT(uptr->flags, UNIT_SPACING); /* done with this */ calc_ints(); } @@ -445,7 +460,7 @@ static t_stat prt1132_svc (UNIT *uptr) flush_prt_line(uptr->fileref, UNIT_SKIPPING, IS_PHYSICAL(uptr)); CLRBIT(PRT_DSW, PRT1132_DSW_CHANNEL_MASK); SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row])); - } while ((cctape[prt_row] & CC_1132_BITS) == 0); // slew directly to a cc tape punch + } while ((cctape[prt_row] & CC_1132_BITS) == 0); /* slew directly to a cc tape punch */ SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row]) | PRT1132_DSW_SKIP_RESPONSE); SETBIT(ILSW[1], ILSW_1_1132_PRINTER); @@ -453,21 +468,21 @@ static t_stat prt1132_svc (UNIT *uptr) } if (uptr->flags & UNIT_PRINTING) { - if (! save_1132_prt_line(codewheel1132[prt_nchar].ascii)) { // save previous printed line - SETBIT(uptr->flags, UNIT_DATACHECK); // buffer wasn't set in time + if (! save_1132_prt_line(codewheel1132[prt_nchar].ascii)) { /* save previous printed line */ + SETBIT(uptr->flags, UNIT_DATACHECK); /* buffer wasn't set in time */ SET_ACTION(uptr, 0); - print_check(TRUE); // and turn on forms check lamp + print_check(TRUE); /* and turn on forms check lamp */ return SCPE_OK; } - prt_nchar = (prt_nchar + 1) % WHEELCHARS_1132; // advance print drum + prt_nchar = (prt_nchar + 1) % WHEELCHARS_1132; /* advance print drum */ - SETBIT(PRT_DSW, PRT1132_DSW_READ_EMITTER_RESPONSE); // issue interrupt to tell printer to set buffer - SETBIT(ILSW[1], ILSW_1_1132_PRINTER); // we'll save the printed stuff just before next emitter response (later than on real 1130) + SETBIT(PRT_DSW, PRT1132_DSW_READ_EMITTER_RESPONSE); /* issue interrupt to tell printer to set buffer */ + SETBIT(ILSW[1], ILSW_1_1132_PRINTER); /* we'll save the printed stuff just before next emitter response (later than on real 1130) */ calc_ints(); } - if (uptr->flags & (UNIT_SPACING|UNIT_SKIPPING|UNIT_PRINTING)) { // still doing something + if (uptr->flags & (UNIT_SPACING|UNIT_SKIPPING|UNIT_PRINTING)) { /* still doing something */ SETBIT(PRT_DSW, PRT1132_DSW_PRINTER_BUSY); sim_activate(uptr, prt_cwait); } @@ -483,18 +498,18 @@ void save_1403_prt_line (int32 addr) unsigned char ebcdic; int32 wd; - for (i = 0; i < PRT_COLUMNS; i++) { - if (even) { // fetch next word from memory + for (i = 0; i < PRT1403_COLUMNS; i++) { + if (even) { /* fetch next word from memory */ wd = M[addr++]; ebcdic = (unsigned char) ((wd >> 8) & 0x7F); even = FALSE; } else { - ebcdic = (unsigned char) (wd & 0x7F); // use low byte of previously fetched word + ebcdic = (unsigned char) (wd & 0x7F); /* use low byte of previously fetched word */ even = TRUE; } - ch = ' '; // translate ebcdic to ascii. Don't bother checking for parity errors + ch = ' '; /* translate ebcdic to ascii. Don't bother checking for parity errors */ for (j = 0; j < WHEELCHARS_1403; j++) { if (codewheel1403[j].ebcdic == ebcdic) { ch = codewheel1403[j].ascii; @@ -504,14 +519,14 @@ void save_1403_prt_line (int32 addr) if (ch > ' ') { if ((r = nprint[i]) < MAX_OVPRINT) { - if (ncol[r] <= i) { // we haven't moved this far yet - if (ncol[r] == 0) // first char in this row? - memset(prtbuf+r*PRT_ROWLEN, ' ', PRT_COLUMNS); // blank out the new row - ncol[r] = i+1; // remember new row length + if (ncol[r] <= i) { /* we haven't moved this far yet */ + if (ncol[r] == 0) /* first char in this row? */ + memset(prtbuf+r*MAX_COLUMNS, ' ', PRT1403_COLUMNS); /* blank out the new row */ + ncol[r] = i+1; /* remember new row length */ } - prtbuf[r*PRT_ROWLEN + i] = (char) ch; // save the character + prtbuf[r*MAX_COLUMNS + i] = (char) ch; /* save the character */ - nprint[i]++; // remember max overprintings for this column + nprint[i]++; /* remember max overprintings for this column */ maxnp = MAX(maxnp, nprint[i]); } } @@ -568,15 +583,15 @@ void xio_1403_printer (int32 iocc_addr, int32 func, int32 modify) static t_stat prt1403_svc(UNIT *uptr) { - if (PRT_DSW & PRT1403_DSW_NOT_READY) { // cancel operation if printer went offline + if (PRT_DSW & PRT1403_DSW_NOT_READY) { /* cancel operation if printer went offline */ SET_ACTION(uptr, 0); - forms_check(TRUE); // and turn on forms check lamp + forms_check(TRUE); /* and turn on forms check lamp */ } - else if (uptr->flags & UNIT_TRANSFERRING) { // end of transfer + else if (uptr->flags & UNIT_TRANSFERRING) { /* end of transfer */ CLRBIT(uptr->flags, UNIT_TRANSFERRING); - SETBIT(uptr->flags, UNIT_PRINTING); // schedule "print complete" + SETBIT(uptr->flags, UNIT_PRINTING); /* schedule "print complete" */ - SETBIT(PRT_DSW, PRT1403_DSW_TRANSFER_COMPLETE); // issue transfer complete interrupt + SETBIT(PRT_DSW, PRT1403_DSW_TRANSFER_COMPLETE); /* issue transfer complete interrupt */ SETBIT(ILSW[4], ILSW_4_1403_PRINTER); } else if (uptr->flags & UNIT_PRINTING) { @@ -584,14 +599,14 @@ static t_stat prt1403_svc(UNIT *uptr) CLRBIT(PRT_DSW, PRT1403_DSW_PRINTER_BUSY); SETBIT(PRT_DSW, PRT1403_DSW_PRINT_COMPLETE); - SETBIT(ILSW[4], ILSW_4_1403_PRINTER); // issue print complete interrupt + SETBIT(ILSW[4], ILSW_4_1403_PRINTER); /* issue print complete interrupt */ } else if (uptr->flags & UNIT_SKIPPING) { - do { // find line with exact match of tape punches + do { /* find line with exact match of tape punches */ flush_prt_line(uptr->fileref, UNIT_SKIPPING, IS_PHYSICAL(uptr)); - } while (cctape[prt_row] != SKIPTARGET); // slew directly to requested cc tape punch + } while (cctape[prt_row] != SKIPTARGET); /* slew directly to requested cc tape punch */ - CLRBIT(uptr->flags, UNIT_SKIPPING); // done with this + CLRBIT(uptr->flags, UNIT_SKIPPING); /* done with this */ CLRBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY); SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_COMPLETE); @@ -600,7 +615,7 @@ static t_stat prt1403_svc(UNIT *uptr) else if (uptr->flags & UNIT_SPACING) { flush_prt_line(uptr->fileref, UNIT_SPACING, IS_PHYSICAL(uptr)); - CLRBIT(uptr->flags, UNIT_SPACING); // done with this + CLRBIT(uptr->flags, UNIT_SPACING); /* done with this */ CLRBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY); SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_COMPLETE); @@ -610,7 +625,7 @@ static t_stat prt1403_svc(UNIT *uptr) if (uptr->flags & (UNIT_PRINTING|UNIT_SKIPPING|UNIT_SPACING|UNIT_TRANSFERRING)) sim_activate(uptr, prt_fwait); - CLRBIT(PRT_DSW, PRT1403_DSW_CH9|PRT1403_DSW_CH12); // set the two CC bits in the DSW + CLRBIT(PRT_DSW, PRT1403_DSW_CH9|PRT1403_DSW_CH12); /* set the two CC bits in the DSW */ if (cctape[prt_row] & CC_CHANNEL_9) SETBIT(PRT_DSW, PRT1403_DSW_CH9); if (cctape[prt_row] & CC_CHANNEL_12) @@ -646,16 +661,17 @@ static t_stat prt_reset (DEVICE *dptr) UNIT *uptr = &prt_unit[0]; int i; -// add a DELETE filename command so we can be sure to have clean listings +/* add a DELETE filename command so we can be sure to have clean listings */ register_cmd("DELETE", &delete_cmd, 0, "del{ete} filename remove file\n"); sim_cancel(uptr); - memset(cctape, 0, sizeof(cctape)); // copy punch list into carriage control tape image + memset(cctape, 0, sizeof(cctape)); /* copy punch list into carriage control tape image */ - if (cgi) + if (cgi) { for (i = 0; i < (sizeof(cccgi)/sizeof(cccgi[0])); i++) cctape[cccgi[i].row-1] |= cccgi[i].channels; + } else for (i = 0; i < (sizeof(ccpunches)/sizeof(ccpunches[0])); i++) cctape[ccpunches[i].row-1] |= ccpunches[i].channels; @@ -697,6 +713,7 @@ static t_stat prt_attach (UNIT *uptr, char *cptr) t_stat rval; /* assume failure */ SETBIT(PRT_DSW, IS_1132(uptr) ? PRT1132_DSW_NOT_READY : PRT1403_DSW_NOT_READY); + formfed = FALSE; if (uptr->flags & UNIT_ATT) { if ((rval = prt_detach(uptr)) != SCPE_OK) { @@ -745,7 +762,7 @@ static t_stat prt_attach (UNIT *uptr, char *cptr) reset_prt_line(); if (IS_1132(uptr)) { - PRT_DSW = (uint16) ((PRT_DSW & ~PRT1132_DSW_CHANNEL_MASK) | cc_format_1132(cctape[prt_row])); + PRT_DSW = (PRT_DSW & ~PRT1132_DSW_CHANNEL_MASK) | cc_format_1132(cctape[prt_row]); if (IS_ONLINE(uptr)) CLRBIT(PRT_DSW, PRT1132_DSW_NOT_READY); @@ -758,10 +775,11 @@ static t_stat prt_attach (UNIT *uptr, char *cptr) SETBIT(PRT_DSW, PRT1403_DSW_CH12); if (IS_ONLINE(uptr)) - CLRBIT(PRT_DSW, PRT1132_DSW_NOT_READY); + CLRBIT(PRT_DSW, PRT1403_DSW_NOT_READY); /* fixed by Carl Claunch */ } forms_check(FALSE); + return SCPE_OK; } @@ -769,7 +787,8 @@ static t_stat prt_detach (UNIT *uptr) { t_stat rval; - flush_prt_line(uptr->fileref, TRUE, TRUE); + if (uptr->flags & UNIT_ATT) + flush_prt_line(uptr->fileref, TRUE, TRUE); if (uptr->fileref == stdout) { CLRBIT(uptr->flags, UNIT_ATT); @@ -797,3 +816,4 @@ static t_stat prt_detach (UNIT *uptr) forms_check(FALSE); return SCPE_OK; } + diff --git a/Ibm1130/ibm1130_ptrp.c b/Ibm1130/ibm1130_ptrp.c index ea831a44..71498e3c 100644 --- a/Ibm1130/ibm1130_ptrp.c +++ b/Ibm1130/ibm1130_ptrp.c @@ -81,7 +81,7 @@ DEVICE ptp_dev = { /* xio_1134_papertape - XIO command interpreter for the 1134 paper tape reader and 1055 paper tape punch */ -void xio_1134_papertape (int iocc_addr, int iocc_func, int iocc_mod) +void xio_1134_papertape (int32 iocc_addr, int32 iocc_func, int32 iocc_mod) { char msg[80]; @@ -118,7 +118,7 @@ void xio_1134_papertape (int iocc_addr, int iocc_func, int iocc_mod) } } -// ptr_svc - emulated timeout - 1134 read operation complete +/* ptr_svc - emulated timeout - 1134 read operation complete */ static t_stat ptr_svc (UNIT *uptr) { @@ -141,7 +141,7 @@ static t_stat ptr_svc (UNIT *uptr) return SCPE_OK; } -// ptp_svc - emulated timeout -- 1055 punch operation complete +/* ptp_svc - emulated timeout -- 1055 punch operation complete */ static t_stat ptp_svc (UNIT *uptr) { @@ -245,37 +245,37 @@ static t_stat ptr_boot (int unitno, DEVICE *dptr) } if (leader) { - if ((ch & 0x7F) == 0x7F) // ignore leading rubouts or "delete" characters + if ((ch & 0x7F) == 0x7F) /* ignore leading rubouts or "delete" characters */ continue; - leader = FALSE; // after first nonrubout, any punch in channel 5 terminates load + leader = FALSE; /* after first nonrubout, any punch in channel 5 terminates load */ } - // this is untested -- not sure of actual byte ordering + /* this is untested -- not sure of actual byte ordering */ - val = (val << 4) | (ch & 0x0F); // get next nybble + val = (val << 4) | (ch & 0x0F); /* get next nybble */ - if (++nch == 4) { // if we now have four nybbles, store the word + if (++nch == 4) { /* if we now have four nybbles, store the word */ M[addr & mem_mask] = (uint16) val; - addr++; // prepare for next word + addr++; /* prepare for next word */ nch = 0; val = 0; } - if (ch & 0x10) { // channel 5 punch terminates load + if (ch & 0x10) { /* channel 5 punch terminates load */ start = TRUE; break; } } - if (! start) // if we didn't get a valid load, report EOF error + if (! start) /* if we didn't get a valid load, report EOF error */ return SCPE_EOF; - if ((rval = reset_all(0)) != SCPE_OK) // force a reset + if ((rval = reset_all(0)) != SCPE_OK) /* force a reset */ return rval; - IAR = 0; // start running at address 0 + IAR = 0; /* start running at address 0 */ return SCPE_OK; } diff --git a/Ibm1130/ibm1130_sca.c b/Ibm1130/ibm1130_sca.c new file mode 100644 index 00000000..37de87f4 --- /dev/null +++ b/Ibm1130/ibm1130_sca.c @@ -0,0 +1,1164 @@ +/* ibm1130_sca.c: IBM 1130 synchronous communications adapter emulation + + Based on the SIMH simulator package written by Robert M Supnik + + Brian Knittel + Revision History + + 2005.03.08 - Started + + * (C) Copyright 2005, 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 + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to simh@ibm1130.org + */ + +/****************************************************************************************************************** + * NOTES: + * This module sends raw bisync data over a standard TCP port. It's meant to be + * used with the emulated 2703 device in Hercules. + * + * Attach command: + * + * to establish an outgoing connection: + * + * attach sca host connect to named host on default port (initial default port is 2703); or + * attach sca host:### connect to named host on port ###. ### is also set as new default port number. + * >> The simulator waits until the connection is established + * + * or to set up for incoming connections: + * + * attach sca -l dummy listen for a connection on default port (initially 2703); Nonnumeric "dummy" argument is ignored; or + * attach sca -l ### listen for a connection on the port ###. ### is also set as the new default port + * >> The simulator proceeds. When another simulator connects, the READY bit is set in the DSW. + * + * If the SCA's autoanswer-enable bit has been set, an incoming connection causes an interrupt (untested) + * Configuration commands: + * + * set sca bsc set bisync mode (default) + * set sca str set synchronous transmit/recieve mode (NOT IMPLEMENTED) + * + * set sca ### set simulated baud rate to ###, where ### is 600, 1200, 2000, 2400 or 4800 (4800 is default) + * + * set sca half set simulated half-duplex mode + * set sca full set simulated full-duplex mode (note: 1130's SCA can't actually send and receive at the same time!) + * + * deposit sca keepalive ### send SYN packets every ### msec when suppressing SYN's, default is 0 (no keepalives) + * + * STR/BSC mode is selected by a toggle switch on the 1130, with the SET SCA BSC or SET SET STR command here. + * Testable with in_bsc_mode() or in_str_mode() in this module. If necessary, the SET command can be configured + * to call a routine when the mode is changed; or, we can just required the user to reboot the simulated 1130 + * when switching modes. + * + * STR MODE IS NOT IMPLEMENTED! + * + * The SCA adapter appears to know nothing of the protocols used by STR and BSC. It does handle the sync/idle + * character specially, and between BSC and STR mode the timers are used differently. Also in STR mode it + * can be set to a sychronization mode where it sends SYN's without program intervention. + * + * See definition of SCA_STATE for defintion of simulator states. + * + * Rather than trying to simulate the actual baud rates, we try to keep the character service interrupts + * coming at about the same number of instruction intervals -- thus existing 1130 code should work correctly + * but the effective data transfer rate will be much higher. The "timers" however are written to run on real wall clock + * time, This may or may not work. If necessary they could be set to time out based on the number of calls to sca_svc + * which occurs once per character send/receive time; For example, at 4800 baud and an 8 bit frame, we get + * 600 characters/second, so the 3 second timer would expire in 1800 sca_svc calls. Well, that's something to + * think about. + * + * To void blowing zillions of SYN characters across the network when the system is running but idle, we suppress + * them. If 100 consecutive SYN's are sent, we flush the output buffer and stop sending SYN's + * until some other character is sent, OR the line is turned around (e.g. INITR, INITW or an end-operation + * CONTROL is issued), or the number of msec set by DEPOSIT SCS KEEPALIVE has passed, if a value has + * been set. By default no keepalives are sent. + * + * Timer operations are not debugged. First, do timers automatically reset and re-interrupt if + * left alone after they timeout the first time? Does XIO_SENSE_DEV really restart all running timers? + * Does it touch the timer trigger (program timer?) How do 3 and 1.25 second timers really work + * in BSC mode? Hard to tell from the FC manual. + ******************************************************************************************************************/ + +#include "ibm1130_defs.h" +#include "sim_sock.h" /* include path must include main simh directory */ +#include + +extern SOCKET sim_create_sock (void); /* missing from sim_sock.h */ + +#define DEBUG_SCA_FLUSH 0x0001 /* debugging options */ +#define DEBUG_SCA_TRANSMIT 0x0002 +#define DEBUG_SCA_CHECK_INDATA 0x0004 +#define DEBUG_SCA_RECEIVE_SYNC 0x0008 +#define DEBUG_SCA_RECEIVE_DATA 0x0010 +#define DEBUG_SCA_XIO_READ 0x0020 +#define DEBUG_SCA_XIO_WRITE 0x0040 +#define DEBUG_SCA_XIO_CONTROL 0x0080 +#define DEBUG_SCA_XIO_INITW 0x0100 +#define DEBUG_SCA_XIO_INITR 0x0200 +#define DEBUG_SCA_XIO_SENSE_DEV 0x0400 +#define DEBUG_SCA_TIMERS 0x0800 +#define DEBUG_SCA_ALL 0xFFFF + +/* #define DEBUG_SCA (DEBUG_SCA_TIMERS|DEBUG_SCA_FLUSH|DEBUG_SCA_TRANSMIT|DEBUG_SCA_CHECK_INDATA|DEBUG_SCA_RECEIVE_SYNC|DEBUG_SCA_RECEIVE_DATA|DEBUG_SCA_XIO_INITR|DEBUG_SCA_XIO_INITW) */ +#define DEBUG_SCA (DEBUG_SCA_TIMERS|DEBUG_SCA_FLUSH|DEBUG_SCA_CHECK_INDATA|DEBUG_SCA_XIO_INITR|DEBUG_SCA_XIO_INITW) + +#define SCA_DEFAULT_PORT 2703 /* default socket, This is the number of the IBM 360's BSC device */ + +#define MAX_SYNS 100 /* number of consecutive syn's after which we stop buffering them */ + +/*************************************************************************************** + * SCA + ***************************************************************************************/ + +#define SCA_DSW_READ_RESPONSE 0x8000 /* receive buffer full interrupt */ +#define SCA_DSW_WRITE_RESPONSE 0x4000 /* transmitter buffer empty interrupt */ +#define SCA_DSW_CHECK 0x2000 /* data overrun or character gap error */ +#define SCA_DSW_TIMEOUT 0x1000 /* timer interrupt, mode specific */ +#define SCA_DSW_AUTOANSWER_REQUEST 0x0800 /* dataset is ringing and autoanswer is enabled */ +#define SCA_DSW_BUSY 0x0400 /* adapter is in either receive or transmit mode */ +#define SCA_DSW_AUTOANSWER_ENABLED 0x0200 /* 1 when autoanswer mode has been enabled */ +#define SCA_DSW_READY 0x0100 /* Carrier detect? Connected and ready to rcv, xmit or sync */ +#define SCA_DSW_RECEIVE_RUN 0x0080 /* used in two-wire half-duplex STR mode only. "Slave" mode (?) */ + +#define IS_ONLINE(u) (((u)->flags & (UNIT_ATT|UNIT_DIS)) == UNIT_ATT) + +typedef enum { /* ms m = mode (0 = idle, 1 = send, 2 = receive), s = substate */ + SCA_STATE_IDLE = 0x00, /* nothing happening */ + SCA_STATE_TURN_SEND = 0x10, /* line turning around to the send state */ + SCA_STATE_SEND_SYNC = 0x11, /* sca is sending syncs */ + SCA_STATE_SEND1 = 0x12, /* have issued write response, waiting for write command */ + SCA_STATE_SEND2 = 0x13, /* write command issued, "sending" byte */ + SCA_STATE_TURN_RECEIVE = 0x20, /* line turnaround to the receive state */ + SCA_STATE_RECEIVE_SYNC = 0x21, /* sca is receiving syncs */ + SCA_STATE_RECEIVE_SYNC2 = 0x22, /* bsc mode, waiting for 2nd SYN */ + SCA_STATE_RECEIVE_SYNC3 = 0x23, /* bsc mode, waiting for 1st non-SYN */ + SCA_STATE_RECEIVE1 = 0x24, /* "receiving" a byte */ + SCA_STATE_RECEIVE2 = 0x25, /* read response issued, "receiving" next byte */ +} SCA_STATE; + +#define in_send_state() (sca_state & 0x10) +#define in_receive_state() (sca_state & 0x20) + +static t_stat sca_svc (UNIT *uptr); /* prototypes */ +static t_stat sca_reset (DEVICE *dptr); +static t_stat sca_attach (UNIT *uptr, char *cptr); +static t_stat sca_detach (UNIT *uptr); +static void sca_start_timer (int n, int msec_now); +static void sca_halt_timer (int n); +static void sca_toggle_timer (int n, int msec_now); + /* timer states, chosen so any_timer_running can be calculated by oring states of all 3 timers */ +typedef enum {SCA_TIMER_INACTIVE = 0, SCA_TIMER_RUNNING = 1, SCA_TIMER_INHIBITED = 2, SCA_TIMER_TIMEDOUT = 4} SCA_TIMER_STATE; + +#define TIMER_3S 0 /* 3 second timer index into sca_timer_xxx arrays */ +#define TIMER_125S 1 /* 1.25 second timer */ +#define TIMER_035S 2 /* 0.35 second timer */ + +static uint16 sca_dsw = 0; /* device status word */ +static uint32 sca_cwait = 275; /* inter-character wait */ +static uint32 sca_iwait = 2750; /* idle wait */ +static uint32 sca_state = SCA_STATE_IDLE; +static uint8 sichar = 0; /* sync/idle character */ +static uint8 rcvd_char = 0; /* most recently received character */ +static uint8 sca_frame = 8; +static uint16 sca_port = SCA_DEFAULT_PORT; /* listening port number */ +static int32 sca_keepalive = 0; /* keepalive SYN packet period in msec, default = 0 (disabled) */ +static SCA_TIMER_STATE sca_timer_state[3]; /* current timer state */ +static int sca_timer_endtime[3]; /* clocktime when timeout is to occur if state is RUNNING */ +static int sca_timer_timeleft[3]; /* time left in msec if state is INHIBITED */ +static t_bool any_timer_running = FALSE; /* TRUE if at least one timer is running */ +static int sca_timer_msec[3] = {3000, 1250, 350}; /* timebase in msec for the three timers: 3 sec, 1.25 sec, 0.35 sec */ +static t_bool sca_timer_trigger; /* if TRUE, the "timer trigger" is set, the 0.35s timer is running and the 3 sec and 1.25 sec timers are inhibited */ +static int sca_nsyns = 0; /* number of consecutively sent SYN's */ +static int idles_since_last_write = 0; /* used to detect when software has ceased sending data */ +static SOCKET sca_lsock = INVALID_SOCKET; +static SOCKET sca_sock = INVALID_SOCKET; + +#define SCA_SENDBUF_SIZE 145 /* maximum number of bytes to buffer for transmission */ +#define SCA_RCVBUF_SIZE 256 /* max number of bytes to read from socket at a time */ +#define SCA_SEND_THRESHHOLD 140 /* number of bytes to buffer before initiating packet send */ +#define SCA_IDLE_THRESHHOLD 3 /* maximum number of unintentional idles to buffer before initiating send */ + +static uint8 sca_sendbuf[SCA_SENDBUF_SIZE]; /* bytes pending to write to socket */ +static uint8 sca_rcvbuf[SCA_RCVBUF_SIZE]; /* bytes received from socket, to be given to SCA */ +static int sca_n2send = 0; /* number of bytes queued for transmission */ +static int sca_nrcvd = 0; /* number of received bytes in buffer */ +static int sca_rcvptr = 0; /* index of next byte to take from rcvbuf */ + +#define UNIT_V_BISYNC (UNIT_V_UF + 0) /* BSC (bisync) mode */ +#define UNIT_V_BAUD (UNIT_V_UF + 1) /* 3 bits for baud rate encoding */ +#define UNIT_V_FULLDUPLEX (UNIT_V_UF + 4) +#define UNIT_V_AUTOANSWER (UNIT_V_UF + 5) +#define UNIT_V_LISTEN (UNIT_V_UF + 6) /* listen socket mode */ + +#define UNIT_BISYNC (1u << UNIT_V_BISYNC) +#define UNIT_BAUDMASK (7u << UNIT_V_BAUD) +#define UNIT_BAUD600 (0u << UNIT_V_BAUD) +#define UNIT_BAUD1200 (1u << UNIT_V_BAUD) +#define UNIT_BAUD2000 (2u << UNIT_V_BAUD) +#define UNIT_BAUD2400 (3u << UNIT_V_BAUD) +#define UNIT_BAUD4800 (4u << UNIT_V_BAUD) +#define UNIT_FULLDUPLEX (1u << UNIT_V_FULLDUPLEX) +#define UNIT_AUTOANSWER (1u << UNIT_V_AUTOANSWER) +#define UNIT_LISTEN (1u << UNIT_V_LISTEN) + +extern int sim_switches; /* variable that gets bits set for -x switches on command lines */ + +t_stat sca_set_baud (UNIT *uptr, int32 value, char *cptr, void *desc); + +UNIT sca_unit = { /* default settings */ + UDATA (sca_svc, UNIT_ATTABLE|UNIT_BISYNC|UNIT_BAUD4800|UNIT_FULLDUPLEX, 0), +}; + +REG sca_reg[] = { /* DEVICE STATE/SETTABLE PARAMETERS: */ + { HRDATA (SCADSW, sca_dsw, 16) }, /* device status word */ + { DRDATA (SICHAR, sichar, 8), PV_LEFT }, /* sync/idle character */ + { DRDATA (RCVDCHAR, rcvd_char, 8), PV_LEFT }, /* most recently received character */ + { DRDATA (FRAME, sca_frame, 8), PV_LEFT }, /* frame bits (6, 7 or 8) + { DRDATA (SCASTATE, sca_state, 32), PV_LEFT }, /* current state */ + { DRDATA (CTIME, sca_cwait, 32), PV_LEFT }, /* inter-character wait */ + { DRDATA (ITIME, sca_iwait, 32), PV_LEFT }, /* idle wait (polling interval for socket connects) */ + { DRDATA (SCASOCKET, sca_port, 16), PV_LEFT }, /* listening port number */ + { DRDATA (KEEPALIVE, sca_keepalive, 32), PV_LEFT }, /* keepalive packet period in msec */ + { NULL } }; + +MTAB sca_mod[] = { /* DEVICE OPTIONS */ + { UNIT_BISYNC, 0, "STR", "STR", NULL }, /* mode option */ + { UNIT_BISYNC, UNIT_BISYNC, "BSC", "BSC", NULL }, + { UNIT_BAUDMASK, UNIT_BAUD600, "600", "600", sca_set_baud }, /* data rate option */ + { UNIT_BAUDMASK, UNIT_BAUD1200, "1200", "1200", sca_set_baud }, + { UNIT_BAUDMASK, UNIT_BAUD2000, "2000", "2000", sca_set_baud }, + { UNIT_BAUDMASK, UNIT_BAUD2400, "2400", "2400", sca_set_baud }, + { UNIT_BAUDMASK, UNIT_BAUD4800, "4800", "4800", sca_set_baud }, + { UNIT_FULLDUPLEX, 0, "HALF", "HALF", NULL }, /* duplex option (does this matter?) */ + { UNIT_FULLDUPLEX, UNIT_FULLDUPLEX, "FULL", "FULL", NULL }, + { 0 } }; + +DEVICE sca_dev = { + "SCA", &sca_unit, sca_reg, sca_mod, + 1, 16, 16, 1, 16, 16, + NULL, NULL, sca_reset, + NULL, sca_attach, sca_detach +}; + +/********************************************************************************************* + * sca_set_baud - set baud rate handler (SET SCA.BAUD nnn) + *********************************************************************************************/ + +t_stat sca_set_baud (UNIT *uptr, int32 value, char *cptr, void *desc) +{ + uint32 newbits; + + switch (value) { + case 600: newbits = UNIT_BAUD600; break; + case 1200: newbits = UNIT_BAUD1200; break; + case 2000: newbits = UNIT_BAUD2000; break; + case 2400: newbits = UNIT_BAUD2400; break; + case 4800: newbits = UNIT_BAUD4800; break; + default: return SCPE_ARG; + } + + CLRBIT(sca_unit.flags, UNIT_BAUDMASK); + SETBIT(sca_unit.flags, newbits); + + sca_cwait = 1320000 / value; /* intercharacter wait time in instructions (roughly) */ + + return SCPE_OK; +} + +/********************************************************************************************* + * HANDY MACROS + *********************************************************************************************/ + +#define in_bsc_mode() (sca_unit.flags & UNIT_BISYNC) /* TRUE if user selected BSC mode */ +#define in_str_mode() ((sca_unit.flags & UNIT_BISYNC) == 0) /* TRUE if user selected STR mode */ + +/********************************************************************************************* + * mstring - allocate a copy of a string + *********************************************************************************************/ + +char *mstring (char *str) +{ + int len; + char *m; + + len = strlen(str)+1; + if ((m = malloc(len)) == NULL) { + printf("Out of memory!"); + return "?"; /* this will of course cause trouble if it's subsequently freed */ + } + strcpy(m, str); + return m; +} + +/********************************************************************************************* + * sca_socket_error - call when there is an error reading from or writing to socket + *********************************************************************************************/ + +static void sca_socket_error (void) +{ + char name[100]; + + /* print diagnostic? */ + printf("SCA socket error, closing connection\n"); + + /* tell 1130 that connection was lost */ + CLRBIT(sca_dsw, SCA_DSW_READY); + + if (sca_sock != INVALID_SOCKET) { + /* close socket, prepare to listen again if in listen mode. It's a "master" socket if it was an outgoing connection */ + sim_close_sock(sca_sock, (sca_unit.flags & UNIT_LISTEN) == 0); + sca_sock = INVALID_SOCKET; + + if (sca_unit.filename != NULL) /* reset filename string in unit record */ + free(sca_unit.filename); + + if (sca_unit.flags & UNIT_LISTEN) { + sprintf(name, "(Listening on port %d)", sca_port); + sca_unit.filename = mstring(name); + printf("%s\n", name); + } + else + sca_unit.filename = mstring("(connection failed)"); + } + + /* clear buffers */ + sca_nrcvd = sca_rcvptr = sca_n2send = sca_nsyns = 0; +} + +/********************************************************************************************* + * sca_transmit_byte, sca_flush - send data buffering mechanism + *********************************************************************************************/ + +static void sca_flush (void) +{ + int nbytes; + + if (sca_n2send > 0) { +#if (DEBUG_SCA & DEBUG_SCA_FLUSH) + printf("* SCA_FLUSH %d byte%s\n", sca_n2send, (sca_n2send == 1) ? "" : "s"); +#endif + + if (sca_sock != INVALID_SOCKET) { + nbytes = sim_write_sock(sca_sock, sca_sendbuf, sca_n2send); + + if (nbytes == SOCKET_ERROR) + sca_socket_error(); + else if (nbytes != sca_n2send) + printf("SOCKET BLOCKED -- NEED TO REWRITE IBM1130_SCA.C"); + + /* I'm going to assume that SCA communications on the 1130 will consist entirely */ + /* of back and forth exchanges of short records, and so we should never stuff the pipe so full that */ + /* it blocks. If it does ever block, we'll have to come up with an asychronous buffering mechanism. */ + } + + sca_n2send = 0; /* mark buffer cleared */ + } +} + +/********************************************************************************************* + * sca_transmit_byte - buffer a byte to be send to the socket + *********************************************************************************************/ + +static void sca_transmit_byte (uint8 b) +{ + uint32 curtime; + static uint32 last_syn_time, next_syn_time; + +#if (DEBUG_SCA & DEBUG_SCA_TRANSMIT) + printf("* SCA_TRANSMIT: %02x\n", b); +#endif + + /* write a byte to the socket. Let's assume an 8 bit frame in all cases. + * We buffer them up, then send the packet when (a) it fills up to a certain point + * and/or (b) some time has passed? We handle (b) by: + * checking in sva_svc if several sca_svc calls are made w/o any XIO_WRITES, and + * flushing send buffer on line turnaround, timeouts, or any other significant state change + */ + + /* on socket error, call sca_socket_error(); */ + + if (b == sichar) { + if (sca_nsyns >= MAX_SYNS) { /* we're suppressing SYN's */ + if (sca_keepalive > 0) { /* we're sending keepalives, though... check to see if it's time */ + curtime = sim_os_msec(); + if (curtime >= next_syn_time || curtime < last_syn_time) { /* check for < last_syn_time because sim_os_msec() can wrap when OS has been running a long time */ + sca_sendbuf[sca_n2send++] = b; + sca_sendbuf[sca_n2send++] = b; /* send 2 of them */ + sca_flush(); + last_syn_time = curtime; + next_syn_time = last_syn_time + sca_keepalive; + } + } + return; + } + + if (++sca_nsyns == MAX_SYNS) { /* we've sent a bunch of SYN's, time to stop sending them */ + sca_sendbuf[sca_n2send] = b; /* send last one */ + sca_flush(); + last_syn_time = sim_os_msec(); /* remember time, and note time to send next one */ + next_syn_time = last_syn_time + sca_keepalive; + return; + } + } + else + sca_nsyns = 0; + + sca_sendbuf[sca_n2send] = b; /* store character */ + + if (++sca_n2send >= SCA_SEND_THRESHHOLD) + sca_flush(); /* buffer is full, send it immediately */ +} + +/********************************************************************************************* + * sca_interrupt (utility routine) - set a bit in the device status word and initiate an interrupt + *********************************************************************************************/ + +static void sca_interrupt (int bit) +{ + sca_dsw |= bit; /* set device status word bit(s) */ + SETBIT(ILSW[1], ILSW_1_SCA); /* set interrupt level status word bit */ + + calc_ints(); /* udpate simulator interrupt status (not really needed if within xio handler, since ibm1130_cpu calls it after xio handler) */ +} + +/********************************************************************************************* + * sca_reset - reset the SCA device + *********************************************************************************************/ + +static t_stat sca_reset (DEVICE *dptr) +{ + /* flush any pending data */ + sca_flush(); + sca_nrcvd = sca_rcvptr = sca_n2send = sca_nsyns = 0; + + /* reset sca activity */ + sca_state = SCA_STATE_IDLE; + CLRBIT(sca_dsw, SCA_DSW_BUSY | SCA_DSW_AUTOANSWER_ENABLED | SCA_DSW_RECEIVE_RUN | SCA_DSW_READ_RESPONSE | SCA_DSW_WRITE_RESPONSE | SCA_DSW_CHECK | SCA_DSW_TIMEOUT | SCA_DSW_AUTOANSWER_REQUEST); + sca_timer_state[0] = sca_timer_state[1] = sca_timer_state[2] = SCA_TIMER_INACTIVE; + any_timer_running = FALSE; + sca_timer_trigger = FALSE; + + if (sca_unit.flags & UNIT_ATT) /* if unit is attached (or listening) */ + sim_activate(&sca_unit, sca_iwait); /* poll for service. Must do this here as BOOT clears activity queue before resetting all devices */ + + return SCPE_OK; +} + +/********************************************************************************************* + * sca_attach - attach the SCA device + *********************************************************************************************/ + +static t_stat sca_attach (UNIT *uptr, char *cptr) +{ + t_bool do_listen; + char *colon; + uint32 ipaddr; + int32 port; + struct hostent *he; + char name[256]; + static SOCKET sdummy = INVALID_SOCKET; + fd_set wr_set, err_set; + + do_listen = sim_switches & SWMASK('L'); /* -l means listen mode */ + + if (sca_unit.flags & UNIT_ATT) /* if already attached, detach */ + detach_unit(&sca_unit); + + if (do_listen) { /* if listen mode, string specifies socket number (only; otherwise it's a dummy argument) */ + if (isdigit(*cptr)) { /* if digits specified, extract port number */ + port = atoi(cptr); + if (port <= 0 || port > 65535) + return SCPE_ARG; + else + sca_port = port; + } + /* else if nondigits specified, ignore... but the command has to have something there otherwise the core scp */ + /* attach_cmd() routine complains "too few arguments". */ + + if ((sca_lsock = sim_master_sock(sca_port)) == INVALID_SOCKET) + return SCPE_OPENERR; + + SETBIT(sca_unit.flags, UNIT_LISTEN); /* note that we are listening, not yet connected */ + + sprintf(name, "(Listening on port %d)", sca_port); + sca_unit.filename = mstring(name); + printf("%s\n", name); + + } + else { + while (*cptr && *cptr <= ' ') + cptr++; + + if (! *cptr) + return SCPE_2FARG; + + if ((colon = strchr(cptr, ':')) != NULL) { + *colon++ = '\0'; /* clip hostname at colon */ + + port = atoi(colon); /* extract port number that follows it */ + if (port <= 0 || port > 65535) + return SCPE_ARG; + else + sca_port = port; + } + + if (sdummy == INVALID_SOCKET) + if ((sdummy = sim_create_sock()) == INVALID_SOCKET) /* create and keep a socket, to force initialization */ + return SCPE_IERR; /* of socket library (e.g on Win32 call WSAStartup), else gethostbyname fails */ + + if (get_ipaddr(cptr, &ipaddr, NULL) != SCPE_OK) { /* try to parse hostname as dotted decimal nnn.nnn.nnn.nnn */ + if ((he = gethostbyname(cptr)) == NULL) /* if not decimal, look up name through DNS */ + return SCPE_OPENERR; + + if ((ipaddr = * (unsigned long *) he->h_addr_list[0]) == INADDR_NONE) + return SCPE_OPENERR; + + ipaddr = ntohl(ipaddr); /* convert to host byte order; gethostbyname() gives us network order */ + } + + if ((sca_sock = sim_connect_sock(ipaddr, sca_port)) == INVALID_SOCKET) + return SCPE_OPENERR; + + /* sim_connect_sock() sets socket to nonblocking before initiating the connect, so + * the connect is pending when it returns. For outgoing connections, the attach command should wait + * until the connection succeeds or fails. We use "accept" to wait and find out which way it goes... + */ + + FD_ZERO(&wr_set); /* we are only interested in info for sca_sock */ + FD_ZERO(&err_set); + FD_SET(sca_sock, &wr_set); + FD_SET(sca_sock, &err_set); + + select(3, NULL, &wr_set, &err_set, NULL); /* wait for connection to complete or fail */ + + if (FD_ISSET(sca_sock, &wr_set)) { /* sca_sock appears in "writable" set -- connect completed */ + sprintf(name, "%s:%d", cptr, sca_port); + sca_unit.filename = mstring(name); + SETBIT(sca_dsw, SCA_DSW_READY); + } + else if (FD_ISSET(sca_sock, &err_set)) { /* sca_sock appears in "error" set -- connect failed */ + sim_close_sock(sca_sock, TRUE); + sca_sock = INVALID_SOCKET; + return SCPE_OPENERR; + } + else { /* if we get here my assumption about how select works is wrong */ + printf("SCA_SOCK NOT FOUND IN WR_SET -OR- ERR_SET, CODING IN IBM1130_SCA IS WRONG\n"); + sim_close_sock(sca_sock, TRUE); + sca_sock = INVALID_SOCKET; + return SCPE_OPENERR; + } + } + + /* set up socket connect or listen. on success, set UNIT_ATT. + * If listen mode, set UNIT_LISTEN. sca_svc will poll for connection + * If connect mode, set dsw SCA_DSW_READY to indicate connection is up + */ + + SETBIT(sca_unit.flags, UNIT_ATT); /* record successful socket binding */ + + sca_state = SCA_STATE_IDLE; + sim_activate(&sca_unit, sca_iwait); /* start polling for service */ + + sca_n2send = 0; /* clear buffers */ + sca_nrcvd = 0; + sca_rcvptr = 0; + sca_nsyns = 0; + + return SCPE_OK; +} + +/********************************************************************************************* + * sca_detach - detach the SCA device + *********************************************************************************************/ + +static t_stat sca_detach (UNIT *uptr) +{ + if ((sca_unit.flags & UNIT_ATT) == 0) + return SCPE_OK; + + sca_flush(); + + sca_state = SCA_STATE_IDLE; /* stop processing during service calls */ + sim_cancel(&sca_unit); /* stop polling for service */ + + CLRBIT(sca_dsw, SCA_DSW_READY); /* indicate offline */ + + if (sca_sock != INVALID_SOCKET) { /* close connected socket */ + sim_close_sock(sca_sock, (sca_unit.flags & UNIT_LISTEN) == 0); + sca_sock = INVALID_SOCKET; + } + if (sca_lsock != INVALID_SOCKET) { /* close listening socket */ + sim_close_sock(sca_lsock, TRUE); + sca_lsock = INVALID_SOCKET; + } + + free(sca_unit.filename); + sca_unit.filename = NULL; + + CLRBIT(sca_unit.flags, UNIT_ATT|UNIT_LISTEN); + + return SCPE_OK; +} + +/********************************************************************************************* + * sca_check_connect - see if an incoming socket connection has com + *********************************************************************************************/ + +static void sca_check_connect (void) +{ + uint32 ipaddr; + char name[100]; + + if ((sca_sock = sim_accept_conn(sca_lsock, &ipaddr)) == INVALID_SOCKET) + return; + + ipaddr = htonl(ipaddr); /* convert to network order so we can print it */ + + sprintf(name, "%d.%d.%d.%d", ipaddr & 0xFF, (ipaddr >> 8) & 0xFF, (ipaddr >> 16) & 0xFF, (ipaddr >> 24) & 0xFF); + + printf("(SCA connection from %s)\n", name); + + if (sca_unit.filename != NULL) + free(sca_unit.filename); + + sca_unit.filename = mstring(name); + + SETBIT(sca_dsw, SCA_DSW_READY); /* indicate active connection */ + + if (sca_dsw & SCA_DSW_AUTOANSWER_ENABLED) /* if autoanswer was enabled, I guess we should give them an interrupt. Untested. */ + sca_interrupt(SCA_DSW_AUTOANSWER_REQUEST); +} + +/********************************************************************************************* + * sca_check_indata - try to fill receive buffer from socket + *********************************************************************************************/ + +static void sca_check_indata (void) +{ + int nbytes; + + sca_rcvptr = 0; /* reset pointers and count */ + sca_nrcvd = 0; + +#ifdef FAKE_SCA + + nbytes = 5; /* FAKE: receive SYN SYN SYN SYN DLE ACK0 */ + sca_rcvbuf[0] = 0x32; + sca_rcvbuf[1] = 0x32; + sca_rcvbuf[2] = 0x32; + sca_rcvbuf[3] = 0x10; + sca_rcvbuf[4] = 0x70; + +#else + /* read socket; 0 is returned if no data is available */ + nbytes = sim_read_sock(sca_sock, sca_rcvbuf, SCA_RCVBUF_SIZE); + +#endif + + if (nbytes < 0) + sca_socket_error(); + else /* zero or more */ + sca_nrcvd = nbytes; + +#if (DEBUG_SCA & DEBUG_SCA_CHECK_INDATA) + if (sca_nrcvd > 0) + printf("* SCA_CHECK_INDATA %d byte%s\n", sca_nrcvd, (sca_nrcvd == 1) ? "" : "s"); +#endif +} + +/********************************************************************************************* + * sca_svc - handled scheduled event. This will presumably be scheduled frequently, and can check + * for incoming data, reasonableness of initiating a write interrupt, timeouts etc. + *********************************************************************************************/ + +static t_stat sca_svc (UNIT *uptr) +{ + t_bool timeout; + int msec_now; + int i; + + /* if not connected, and if in wait-for-connection mode, check for connection attempt */ + if ((sca_unit.flags & UNIT_LISTEN) && ! (sca_dsw & SCA_DSW_READY)) + sca_check_connect(); + + if (any_timer_running) { + msec_now = sim_os_msec(); + + timeout = FALSE; + for (i = 0; i < 3; i++) { + if (sca_timer_state[i] == SCA_TIMER_RUNNING && msec_now >= sca_timer_endtime[i]) { + timeout = TRUE; + sca_timer_state[i] = SCA_TIMER_TIMEDOUT; +#if (DEBUG_SCA & DEBUG_SCA_TIMERS) + printf("+ SCA_TIMER %d timed out\n", i); +#endif + + if (i == TIMER_035S && sca_timer_trigger) { + sca_timer_trigger = FALSE; /* uninhibit the other two timers */ + sca_toggle_timer(TIMER_3S, msec_now); + sca_toggle_timer(TIMER_125S, msec_now); + } + } + } + + if (timeout) + sca_interrupt(SCA_DSW_TIMEOUT); + + any_timer_running = (sca_timer_state[0]| sca_timer_state[1] | sca_timer_state[2]) & SCA_TIMER_RUNNING; + } + + if (sca_dsw & SCA_DSW_READY) { /* if connected */ + + /* if rcvd data buffer is empty, and if in one of the receive states, checÄk for arrival of received data */ + if (in_receive_state() && sca_rcvptr >= sca_nrcvd) + sca_check_indata(); + + switch (sca_state) { + case SCA_STATE_IDLE: + break; + + case SCA_STATE_TURN_SEND: + /* has enough time gone by yet? if so... */ + sca_state = SCA_STATE_SEND1; + sca_interrupt(SCA_DSW_WRITE_RESPONSE); + break; + + case SCA_STATE_SEND_SYNC: + sca_transmit_byte(sichar); + break; + + case SCA_STATE_SEND1: + sca_transmit_byte(sichar); /* character interval has passed with no character written? character gap check */ + sca_interrupt(SCA_DSW_CHECK); /* send an idle character (maybe? for socket IO maybe send nothing) and interrupt */ + + if (idles_since_last_write >= 0) { + if (++idles_since_last_write >= SCA_IDLE_THRESHHOLD) { + sca_flush(); + idles_since_last_write = -1; /* don't send a short packet again until real data gets written again */ + sca_nsyns = 0; /* resume sending syns if output starts up again */ + } + } + break; + + case SCA_STATE_SEND2: + sca_state = SCA_STATE_SEND1; /* character has been sent. Schedule another transmit */ + sca_interrupt(SCA_DSW_WRITE_RESPONSE); + break; + + case SCA_STATE_TURN_RECEIVE: + /* has enough time gone by yet? if so... */ + sca_state = SCA_STATE_RECEIVE_SYNC; /* assume a character is coming in */ + break; + + case SCA_STATE_RECEIVE_SYNC: + if (sca_rcvptr < sca_nrcvd) { + rcvd_char = sca_rcvbuf[sca_rcvptr++]; +#if (DEBUG_SCA & DEBUG_SCA_RECEIVE_SYNC) + printf("* SCA rcvd %02x %s\n", rcvd_char, (rcvd_char == sichar) ? "sync1" : "ignored"); +#endif + if (in_bsc_mode()) { + if (rcvd_char == sichar) /* count the SYN but don't interrupt */ + sca_state = SCA_STATE_RECEIVE_SYNC2; + } + } + break; + + case SCA_STATE_RECEIVE_SYNC2: + if (sca_rcvptr < sca_nrcvd) { + rcvd_char = sca_rcvbuf[sca_rcvptr++]; +#if (DEBUG_SCA & DEBUG_SCA_RECEIVE_SYNC) + printf("* SCA rcvd %02x %s\n", rcvd_char, (rcvd_char == sichar) ? "sync2" : "ignored"); +#endif + if (in_bsc_mode()) { + if (rcvd_char == sichar) /* count the SYN but don't interrupt */ + sca_state = SCA_STATE_RECEIVE_SYNC3; + } + } + break; + + case SCA_STATE_RECEIVE_SYNC3: + case SCA_STATE_RECEIVE1: + if (sca_rcvptr < sca_nrcvd) { + rcvd_char = sca_rcvbuf[sca_rcvptr++]; + + if (sca_state == SCA_STATE_RECEIVE_SYNC3 && rcvd_char == sichar) { + /* we're ready for data, but we're still seeing SYNs */ +#if (DEBUG_SCA & DEBUG_SCA_RECEIVE_SYNC) + printf("* SCA rcvd %02x extra sync\n", rcvd_char); +#endif + } + else { +#if (DEBUG_SCA & DEBUG_SCA_RECEIVE_DATA) + printf("* SCA rcvd %02x\n", rcvd_char); +#endif + sca_interrupt(SCA_DSW_READ_RESPONSE); + sca_state = SCA_STATE_RECEIVE2; + } + } + /* otherwise remain in state until data becomes available */ + break; + + case SCA_STATE_RECEIVE2: /* if we are still in this state when another service interval has passed */ + if (sca_rcvptr < sca_nrcvd) { + rcvd_char = sca_rcvbuf[sca_rcvptr++]; + + sca_interrupt(SCA_DSW_CHECK); /* overrun error */ + sca_state = SCA_STATE_RECEIVE1; /* another character will come soon */ + } + break; + + default: + printf("Simulator error: unknown state %d in sca_svc\n", sca_state); + sca_state = SCA_STATE_IDLE; + break; + } + } + /* schedule service again */ + sim_activate(&sca_unit, (sca_state == SCA_STATE_IDLE) ? sca_iwait : sca_cwait); + + return SCPE_OK; +} + +/********************************************************************************************* + * sca_toggle_timer - toggle a given timer's running/inhibited state for XIO_CONTROL + *********************************************************************************************/ + +static void sca_toggle_timer (int n, int msec_now) +{ + if (sca_timer_state[n] == SCA_TIMER_RUNNING && sca_timer_trigger) { + sca_timer_state[n] = SCA_TIMER_INHIBITED; + sca_timer_timeleft[n] = sca_timer_endtime[n] - msec_now; /* save time left */ +#if (DEBUG_SCA & DEBUG_SCA_TIMERS) + printf("+ SCA_TIMER %d inhibited\n", n); +#endif + } + else if (sca_timer_state[n] == SCA_TIMER_INHIBITED && ! sca_timer_trigger) { + sca_timer_state[n] = SCA_TIMER_RUNNING; + sca_timer_endtime[n] = sca_timer_timeleft[n] + msec_now; /* compute new endtime */ +#if (DEBUG_SCA & DEBUG_SCA_TIMERS) + printf("+ SCA_TIMER %d uninhibited\n", n); +#endif + } +} + +static void sca_start_timer (int n, int msec_now) +{ + sca_timer_state[n] = SCA_TIMER_RUNNING; + sca_timer_endtime[n] = sca_timer_msec[n] + msec_now; + any_timer_running = TRUE; +#if (DEBUG_SCA & DEBUG_SCA_TIMERS) + printf("+ SCA_TIMER %d started\n", n); +#endif +} + +static void sca_halt_timer (int n) +{ +#if (DEBUG_SCA & DEBUG_SCA_TIMERS) + if (sca_timer_state[n] != SCA_TIMER_INACTIVE) + printf("+ SCA_TIMER %d stopped\n", n); +#endif + + sca_timer_state[n] = SCA_TIMER_INACTIVE; +} + +/********************************************************************************************* + * sca_start_transmit - initiate transmit mode, from XIO_INITR or XIO_CONTROL (sync mode) + *********************************************************************************************/ + +void sca_start_transmit (int32 iocc_addr, int32 modify) +{ + sca_flush(); + sca_nsyns = 0; /* reset SYN suppression */ + + /* Address bits are used to reset DSW conditions. */ + + if (modify & 0x40) /* bit 9. If set, reset all conditions */ + iocc_addr = 0xD800; + + iocc_addr &= 0xD800; /* look at just bits 0, 1, 3 and 4 */ + if (iocc_addr) { /* if set, these bits clear DSW conditions */ + CLRBIT(sca_dsw, iocc_addr); + CLRBIT(ILSW[1], ILSW_1_SCA); /* and I assume clear the interrupt condition too? (Seems unlikely that INITW would */ + } /* be used in an interrupt service routine before SENSE, but who knows?) */ + + if (! in_send_state()) { + sca_state = SCA_STATE_TURN_SEND; /* begin line turnaround */ + } + else { + sca_state = SCA_STATE_SEND1; /* line is */ + sca_interrupt(SCA_DSW_WRITE_RESPONSE); + } + + SETBIT(sca_dsw, SCA_DSW_BUSY); /* SCA is now busy, in transmit mode */ + + sim_cancel(&sca_unit); + sim_activate(&sca_unit, sca_cwait); /* start polling frequently */ +} + +/********************************************************************************************* + * xio_sca - handle SCA XIO command + *********************************************************************************************/ + +void xio_sca (int32 iocc_addr, int32 func, int32 modify) +{ + char msg[80]; + int i, msec_now; + + switch (func) { + case XIO_READ: /* ***** XIO_READ - store last-received character to memory */ +#if (DEBUG_SCA & DEBUG_SCA_XIO_READ) + printf("SCA RD addr %04x mod %02x rcvd_char %02x\n", iocc_addr, modify, rcvd_char); +#endif + if (modify & 0x03) { /* bits 14 and 15 */ +#if (DEBUG_SCA & DEBUG_SCA_XIO_READ) + printf("(rd diag)\n"); +#endif + /* if either of low two modifier bits is set, reads diagnostic words. whatever that is */ + } + else { + WriteW(iocc_addr, rcvd_char << 8); /* always return last received character */ + + /* note: in read mode, read w/o interrupt (or two reads after an interrupt) causes a check + * so here we have to check the current state and possibly cause an interrupt + * Failure to have read before another arrives (overrun) also causes a check. + */ + + if (sca_state == SCA_STATE_RECEIVE2)/* XIO_READ should only be done (and only once) after a character interrupt */ + sca_state = SCA_STATE_RECEIVE1; /* assume another character is coming in -- wait for it */ + else + sca_interrupt(SCA_DSW_CHECK); + } + break; + + case XIO_WRITE: /* ***** XIO_WRITE - transfer character from memory to output shift register */ +#if (DEBUG_SCA & DEBUG_SCA_XIO_WRITE) + printf("SCA WRT addr %04x (%04x) mod %02x\n", iocc_addr, M[iocc_addr & mem_mask], modify); +#endif + if (modify & 0x01) { /* bit 15 */ + /* clear audible alarm trigger */ +#if (DEBUG_SCA & DEBUG_SCA_XIO_WRITE) + printf("(clr audible alarm trigger)\n"); +#endif + } + /* else? or can they all operate in parallel? */ + if (modify & 0x02) { /* bit 14 */ + /* set audible alarm trigger */ +#if (DEBUG_SCA & DEBUG_SCA_XIO_WRITE) + printf("(set audible alarm trigger)\n"); +#endif + } + /* else? */ + if (modify & 0x04) { /* bit 13 */ +#if (DEBUG_SCA & DEBUG_SCA_XIO_WRITE) + printf("(set SYN)\n"); +#endif + /* set sync/idle character */ + sichar = (uint8) (ReadW(iocc_addr) >> 8); + sca_nsyns = 0; /* reset SYN suppression */ + } + /* else? does presence of mod bit preclude sending a character? */ + if ((modify & 0x07) == 0) { /* no modifiers */ + /* transmit character -- + * note: in write mode, failure to write soon enough after a write response interrupt causes a check + * Also, writing w/o interrupt (or two writes after an interrupt) causes a check + * so again, here we have to check the state to be sure that a write is appropriate + * + * note that in this simulator, we transmit the character immediately on XIO_WRITE. Therefore, + * there is no need to delay an end-operation function (XIO_CONTROL bit 13) until after a character time + */ + + idles_since_last_write = 0; + + switch (sca_state) { + case SCA_STATE_SEND_SYNC: + case SCA_STATE_SEND1: + sca_transmit_byte((uint8) (M[iocc_addr & mem_mask] >> 8)); + sca_state = SCA_STATE_SEND2; + sim_cancel(&sca_unit); + sim_activate(&sca_unit, sca_cwait); /* schedule service after character write time */ + break; + + case SCA_STATE_SEND2: + sca_interrupt(SCA_DSW_CHECK); /* write issued while a character is in progress out? write overrun */ + break; + + case SCA_STATE_IDLE: /* wrong time to issue a write, incorrect sca state */ + default: + sca_flush(); + sca_interrupt(SCA_DSW_CHECK); /* ??? or does this just perform a line turnaround and start transmission? */ + break; + } + + } + break; + + case XIO_CONTROL: /* ***** XIO_CONTROL - manipulate interface state */ +#if (DEBUG_SCA & DEBUG_SCA_XIO_CONTROL) + printf("SCA CTL addr %04x mod %02x\n", iocc_addr, modify); +#endif + if (modify & 0x80) { /* bit 8 */ + /* enable auto answer */ +#if (DEBUG_SCA & DEBUG_SCA_XIO_CONTROL) + printf("(enable autoanswer)\n"); +#endif + SETBIT(sca_unit.flags, UNIT_AUTOANSWER); + SETBIT(sca_dsw, SCA_DSW_AUTOANSWER_ENABLED); + } + + if (modify & 0x40) { /* bit 9 */ + /* disable auto answer */ +#if (DEBUG_SCA & DEBUG_SCA_XIO_CONTROL) + printf("(disable autoanswer)\n"); +#endif + CLRBIT(sca_unit.flags, UNIT_AUTOANSWER); + CLRBIT(sca_dsw, SCA_DSW_AUTOANSWER_ENABLED); + } + + if (modify & 0x20) { /* bit 10 */ + /* toggle timers, inhibit->run or run->inhibit */ +#if (DEBUG_SCA & (DEBUG_SCA_XIO_CONTROL|DEBUG_SCA_TIMERS)) + printf("(toggle timers)\n"); +#endif + msec_now = sim_os_msec(); + + if (in_bsc_mode()) + sca_timer_trigger = ! sca_timer_trigger; /* toggle the timer trigger */ + if (sca_timer_trigger) /* if we've just set it, we're stopping the other timers and */ + sca_start_timer(TIMER_035S, msec_now); /* starting the 0.35 sec timer */ + else + sca_halt_timer(TIMER_035S); + + sca_toggle_timer(TIMER_3S, msec_now); /* toggle the 3 sec and 1.35 sec timers accordingly */ + sca_toggle_timer(TIMER_125S, msec_now); + + any_timer_running = (sca_timer_state[0]| sca_timer_state[1] | sca_timer_state[2]) & SCA_TIMER_RUNNING; + } + + if (modify & 0x10) { /* bit 11 */ + /* enable sync mode. See references to this in FC manual + * In STR mode only, sends a constant stream of SYN's without any CPU intervention + * In BSC mode, appears to start the 1.25 second timer and otherwise act like INITW? + */ +#if (DEBUG_SCA & DEBUG_SCA_XIO_CONTROL) + printf("(enable sync mode)\n"); +#endif + + if (in_bsc_mode()) { /* in bsc mode start the 1.25 second timer. not sure what resets it?!? */ + if (! in_send_state()) /* also may cause a line turnaround */ + sca_start_transmit(iocc_addr, 0); + + sca_start_timer(TIMER_125S, sim_os_msec()); + } + } + + if (modify & 0x08) { /* bit 12 */ + /* diagnostic mode. What does this do?!? */ +#if (DEBUG_SCA & DEBUG_SCA_XIO_CONTROL) + printf("(diag mode)\n"); +#endif + } + + if (modify & 0x04) { /* bit 13 */ + /* end operation (reset adapter. See references to this in FC manual). In transmit mode the real adapter delays this + * function until current character has been sent. We don't need to do that as the character got buffered for transmission + * immediately on XIO_WRITE. + */ + +#if (DEBUG_SCA & (DEBUG_SCA_XIO_CONTROL|DEBUG_SCA_XIO_INITR|DEBUG_SCA_XIO_INITW)) + printf("(end operation)\n"); +#endif + sca_state = SCA_STATE_IDLE; + sca_timer_state[0] = sca_timer_state[1] = sca_timer_state[2] = SCA_TIMER_INACTIVE; + any_timer_running = FALSE; + sca_timer_trigger = FALSE; + sca_nsyns = 0; /* reset SYN suppression */ + CLRBIT(sca_dsw, SCA_DSW_BUSY); + } + + if (modify & 0x02) { /* bit 14 */ +#if (DEBUG_SCA & DEBUG_SCA_XIO_CONTROL) + printf("(6 bit frame)\n"); +#endif + /* set six bit character frame. This is reset to 8 bits at every line turnaround */ + sca_frame = 6; + } + + if (modify & 0x01) { /* bit 15 */ +#if (DEBUG_SCA & DEBUG_SCA_XIO_CONTROL) + printf("(7 bit frame)\n"); +#endif + /* set seven bit character frame. This is reset to 8 bits at every line turnaround */ + sca_frame = 7; + } + + sca_flush(); + break; + + case XIO_INITW: /* ***** XIO_INITW - put SCA in transmit mode */ +#if (DEBUG_SCA & DEBUG_SCA_XIO_INITW) + printf("SCA INITW addr %04x mod %02x\n", iocc_addr, modify); +#endif + /* enter transmit mode. Causes line turnaround. Resets frame to 8 bits. */ + /* (may cause syncing, may involve a fixed timeout?) */ + sca_frame = 8; + sca_start_transmit(iocc_addr, modify); /* this code pulled out to a subroutine cuz transmit can be started from XIO_CONTROL too */ + break; + + case XIO_INITR: /* ***** XIO_INITR - put SCA in receive mode */ +#if (DEBUG_SCA & DEBUG_SCA_XIO_INITR) + printf("SCA INITR addr %04x mod %02x\n", iocc_addr, modify); +#endif + sca_flush(); + + sca_nrcvd = sca_rcvptr = 0; /* discard any data previously read! */ + sca_nsyns = 0; /* reset SYN suppression */ + + /* enter receive mode. Causes line turnaround (e.g. resets to 8 bit frame). Modifier bits are used here too */ + /* (may cause syncing, may involve a fixed timeout?) */ + + sca_frame = 8; + if (! in_receive_state()) + sca_state = SCA_STATE_TURN_RECEIVE; /* begin line turnaround */ + else + sca_state = SCA_STATE_RECEIVE_SYNC; + + SETBIT(sca_dsw, SCA_DSW_BUSY); /* SCA is now busy, in receive mode */ + + if (in_bsc_mode()) /* in BSC mode, start the 3 second timer when we enter receive mode */ + sca_start_timer(TIMER_3S, sim_os_msec()); + + break; + + case XIO_SENSE_DEV: /* ***** XIO_SENSE_DEV - read device status word */ +#if (DEBUG_SCA & DEBUG_SCA_XIO_SENSE_DEV) + printf("SCA SNS mod %02x dsw %04x\n", modify, sca_dsw); +#endif + ACC = sca_dsw; /* return DSW in accumulator */ + + if (modify & 0x01) { /* bit 15: reset interrupts */ +#if (DEBUG_SCA & DEBUG_SCA_XIO_SENSE_DEV) + printf("(reset interrupts)\n"); +#endif + CLRBIT(sca_dsw, SCA_DSW_READ_RESPONSE | SCA_DSW_WRITE_RESPONSE | SCA_DSW_CHECK | SCA_DSW_TIMEOUT | SCA_DSW_AUTOANSWER_REQUEST); + CLRBIT(ILSW[1], ILSW_1_SCA); + } + + if (modify & 0x02) { /* bit 14: restart running timers */ +#if (DEBUG_SCA & (DEBUG_SCA_XIO_SENSE_DEV|DEBUG_SCA_TIMERS)) + printf("(restart timers)\n"); +#endif + msec_now = sim_os_msec(); /* restart "any running timer?" All three, really? */ + for (i = 0; i < 3; i++) + if (sca_timer_state[i] == SCA_TIMER_RUNNING || sca_timer_state[i] == SCA_TIMER_TIMEDOUT) + sca_start_timer(i, msec_now); + } + break; + + default: + sprintf(msg, "Invalid SCA XIO function %x", func); + xio_error(msg); + } +} diff --git a/Ibm1130/ibm1130_stddev.c b/Ibm1130/ibm1130_stddev.c index 439f8b0d..d71d45b4 100644 --- a/Ibm1130/ibm1130_stddev.c +++ b/Ibm1130/ibm1130_stddev.c @@ -91,16 +91,13 @@ static void badio (char *dev) { -// the real 1130 just ignores attempts to use uninstalled devices. They get tested -// at times, so it's best to just be quiet about this -// printf("%s I/O is not yet supported", dev); +/* the real 1130 just ignores attempts to use uninstalled devices. They get tested + * at times, so it's best to just be quiet about this + * printf("%s I/O is not yet supported", dev); + */ } -// void xio_1134_papertape (int32 addr, int32 func, int32 modify) {badio("papertape");} -void xio_1627_plotter (int32 addr, int32 func, int32 modify) {badio("plotter");} void xio_1231_optical (int32 addr, int32 func, int32 modify) {badio("optical mark");} -void xio_2501_card (int32 addr, int32 func, int32 modify) {badio("2501 card");} -void xio_1131_synch (int32 addr, int32 func, int32 modify) {badio("SCA");} void xio_system7 (int32 addr, int32 func, int32 modify) {badio("System 7");} /* ---------------------------------------------------------------------------- */ @@ -120,7 +117,7 @@ extern int cgi; static int32 tti_dsw = 0; /* device status words */ static int32 tto_dsw = 0; -static int32 con_dsw = 0; + int32 con_dsw = 0; static unsigned char conout_map[256]; /* 1130 console code to ASCII translation. 0 = undefined, 0xFF = IGNR_ = no output */ static unsigned char conin_map[256]; /* input mapping */ @@ -211,9 +208,10 @@ DEVICE tti_dev = { tto_reg TTO register list */ - // 14-Nov-03 -- the wait time was SERIAL_OUT_WAIT, but recent versions of SIMH reduced - // this to 100, and wouldn't you know it, APL\1130 has about 120 instructions between the XIO WRITE - // to the console and the associated WAIT. + /* 14-Nov-03 -- the wait time was SERIAL_OUT_WAIT, but recent versions of SIMH reduced + * this to 100, and wouldn't you know it, APL\1130 has about 120 instructions between the XIO WRITE + * to the console and the associated WAIT. + */ UNIT tto_unit = { UDATA (&tto_svc, 0, 0), 200 }; @@ -279,7 +277,7 @@ void xio_1131_console (int32 iocc_addr, int32 func, int32 modify) ch = (ReadW(iocc_addr) >> 8) & 0xFF; /* get character to write */ tto_unit.buf = emit_conout_character(ch); /* output character and save write status */ -// fprintf(stderr, "[CONOUT] %02x\n", ch); +/* fprintf(stderr, "[CONOUT] %02x\n", ch); */ SETBIT(tto_dsw, TT_DSW_PRINTER_BUSY); sim_activate(&tto_unit, tto_unit.wait); /* schedule interrupt */ @@ -300,10 +298,10 @@ void xio_1131_console (int32 iocc_addr, int32 func, int32 modify) xio_error(msg); } -// fprintf(stderr, "After XIO %04x %04x\n", tti_dsw, tto_dsw); +/* fprintf(stderr, "After XIO %04x %04x\n", tti_dsw, tto_dsw); */ } -// emit_conout_character - write character with 1130 console code 'ch' +/* emit_conout_character - write character with 1130 console code 'ch' */ t_stat emit_conout_character (int ch) { @@ -342,12 +340,12 @@ t_stat emit_conout_character (int ch) return map_conout_character(ch); } -static void Beep (void) // notify user keyboard was locked or key was bad +static void Beep (void) /* notify user keyboard was locked or key was bad */ { sim_putchar(7); } -// tti_svc - keyboard polling (never stops) +/* tti_svc - keyboard polling (never stops) */ static t_stat tti_svc (UNIT *uptr) { @@ -386,7 +384,7 @@ static t_stat tti_svc (UNIT *uptr) if (temp == PROGRAM_STOP_KEY) { /* simulate the program stop button */ SETBIT(con_dsw, CPU_DSW_PROGRAM_STOP); - SETBIT(ILSW[5], ILSW_5_PROGRAM_STOP); + SETBIT(ILSW[5], ILSW_5_INT_RUN_PROGRAM_STOP); calc_ints(); #ifdef DEBUG_CONSOLE @@ -417,16 +415,13 @@ static t_stat tti_svc (UNIT *uptr) printf("[%04x]", tti_unit.buf & 0xFFFF); #endif -// CLRBIT(tti_dsw, TT_DSW_KEYBOARD_BUSY); /* clear busy flag (unselect keyboard) */ -// keyboard_selected(FALSE); - SETBIT(tti_unit.flags, KEYBOARD_LOCKED); /* prevent further keystrokes */ SETBIT(tti_dsw, TT_DSW_KEYBOARD_RESPONSE); /* queue interrupt */ SETBIT(ILSW[4], ILSW_4_CONSOLE); calc_ints(); -// fprintf(stderr, "TTI interrupt svc SET %04x %04x\n", tti_dsw, tto_dsw); +/* fprintf(stderr, "TTI interrupt svc SET %04x %04x\n", tti_dsw, tto_dsw); */ return SCPE_OK; } @@ -450,14 +445,14 @@ static t_stat tti_reset (DEVICE *dptr) return SCPE_OK; } -// basic_attach - fix quotes in filename, then call standard unit attach routine +/* basic_attach - fix quotes in filename, then call standard unit attach routine */ t_stat basic_attach (UNIT *uptr, char *cptr) { return attach_unit(uptr, quotefix(cptr)); /* fix quotes in filenames & attach */ } -// quotefix - strip off quotes around filename, if present +/* quotefix - strip off quotes around filename, if present */ char * quotefix (char * cptr) { @@ -492,7 +487,7 @@ static t_stat tto_svc (UNIT *uptr) SETBIT(ILSW[4], ILSW_4_CONSOLE); calc_ints(); -// fprintf(stderr, "TTO interrupt svc SET %04x %04x\n", tti_dsw, tto_dsw); +/* fprintf(stderr, "TTO interrupt svc SET %04x %04x\n", tti_dsw, tto_dsw); */ return (t_stat) tto_unit.buf; /* return status saved during output conversion */ } @@ -648,7 +643,7 @@ static struct { /* default output mapping for APLPLUS font */ #define NCONOUT_TO_APL (sizeof(conout_to_APL)/sizeof(conout_to_APL[0])) -static OS_MAP default_os_map[] = // overstrike mapping for APLPLUS font +static OS_MAP default_os_map[] = /* overstrike mapping for APLPLUS font */ { '\x8a', 2, "\x5e\x7e", '\x8b', 2, "\x9f\x7e", @@ -717,12 +712,12 @@ static void strsort (int n, unsigned char *s) unsigned char temp; int i, big; - while (--n > 0) { // repeatedly - big = 0; // find largest value of s[0]...s[n] + while (--n > 0) { /* repeatedly */ + big = 0; /* find largest value of s[0]...s[n] */ for (i = 1; i <= n; i++) if (s[i] > s[big]) big = i; - temp = s[n]; // put largest value at end of array + temp = s[n]; /* put largest value at end of array */ s[n] = s[big]; s[big] = temp; } @@ -730,10 +725,10 @@ static void strsort (int n, unsigned char *s) /* file format: -[font XXX] // font named XXX -OUT // failure character -OUT IN // single character mapping -OUT IN IN ... // overstrike mapping +[font XXX] font named XXX +OUT failure character +OUT IN single character mapping +OUT IN IN ... overstrike mapping */ @@ -742,35 +737,35 @@ static void set_conout_mapping (int32 flags) curcol = 0; maxcol = 0; - // set the default mappings. We may later override them with settings from an ini file + /* set the default mappings. We may later override them with settings from an ini file */ set_default_mapping(flags); } -// finish_conout_mapping - sort the finalized overstrike mapping +/* finish_conout_mapping - sort the finalized overstrike mapping */ static void finish_conout_mapping (int32 flags) { int i, n, big; OS_MAP temp; - for (i = 0; i < n_os_mappings; i++) // sort the inlist strings individually + for (i = 0; i < n_os_mappings; i++) /* sort the inlist strings individually */ strsort(os_map[i].nin, os_map[i].inlist); - for (n = n_os_mappings; --n > 0; ) { // then sort the os_map array itself with insertion sort - big = 0; // find largest value of s[0]...s[n] + for (n = n_os_mappings; --n > 0; ) { /* then sort the os_map array itself with insertion sort */ + big = 0; /* find largest value of s[0]...s[n] */ for (i = 1; i <= n; i++) if (os_map_comp(os_map+i, os_map+big) > 0) big = i; if (big != n) { - temp = os_map[n]; // put largest value at end of array + temp = os_map[n]; /* put largest value at end of array */ os_map[n] = os_map[big]; os_map[big] = temp; } } } -// validate_conout_mapping - called when set command gets a new value +/* validate_conout_mapping - called when set command gets a new value */ static t_stat validate_conout_mapping (UNIT *uptr, int32 match, char *cvptr, void *desc) { @@ -793,7 +788,7 @@ static void reset_mapping (void) conin_map[i] = (unsigned char) i; /* default conin_map is identity map */ } -// set_default_mapping - create standard font and overstrike map +/* set_default_mapping - create standard font and overstrike map */ static void set_default_mapping (int32 flags) { @@ -824,10 +819,10 @@ static void set_default_mapping (int32 flags) break; } - finish_conout_mapping(flags); // sort conout mapping if necessary + finish_conout_mapping(flags); /* sort conout mapping if necessary */ } -// sim_putstr - write a string to the console +/* sim_putstr - write a string to the console */ t_stat sim_putstr (char *s) { @@ -843,7 +838,7 @@ t_stat sim_putstr (char *s) return SCPE_OK; } -// map_conout_character - translate and write a single character +/* map_conout_character - translate and write a single character */ static t_stat map_conout_character (int ch) { @@ -857,54 +852,54 @@ static t_stat map_conout_character (int ch) return (tto_unit.flags & ENABLE_ANSI) ? sim_putstr((char *) red_ribbon) : SCPE_OK; if ((ch = conout_map[ch & 0xFF]) == 0) - ch = '?'; // unknown character? print ? + ch = '?'; /* unknown character? print ? */ - if (ch == '\n') { // newline: reset overstrike buffer + if (ch == '\n') { /* newline: reset overstrike buffer */ curcol = 0; maxcol = -1; } - else if (ch == '\r') { // carriage return: rewind to column 0 + else if (ch == '\r') { /* carriage return: rewind to column 0 */ curcol = 0; - maxcol = -1; // assume it advances paper too + maxcol = -1; /* assume it advances paper too */ } - else if (ch == '\b') { // backspace: back up one character + else if (ch == '\b') { /* backspace: back up one character */ if (curcol > 0) curcol--; } else if (n_os_mappings && ch != (unsigned char) IGNR_) { if (curcol >= MAX_OUTPUT_COLUMNS) - map_conout_character('\x81'); // precede with automatic carriage return/line feed, I guess + map_conout_character('\x81'); /* precede with automatic carriage return/line feed, I guess */ - if (curcol > maxcol) { // first time in this column, no overstrike possible yet + if (curcol > maxcol) { /* first time in this column, no overstrike possible yet */ os_buf[curcol].nin = 0; maxcol = curcol; } - if (ch != ' ' && ch != 0) { // (if it's not a blank or unknown) + if (ch != ' ' && ch != 0) { /* (if it's not a blank or unknown) */ os_buf[curcol].inlist[os_buf[curcol].nin] = (unsigned char) ch; strsort(++os_buf[curcol].nin, os_buf[curcol].inlist); } - if (os_buf[curcol].nin == 0) // if nothing but blanks seen, - ch = ' '; // output is a blank - else if (os_buf[curcol].nin == 1) { // if only one printing character seen, display it + if (os_buf[curcol].nin == 0) /* if nothing but blanks seen, */ + ch = ' '; /* output is a blank */ + else if (os_buf[curcol].nin == 1) { /* if only one printing character seen, display it */ ch = os_buf[curcol].inlist[0]; } - else { // otherwise look up mapping + else { /* otherwise look up mapping */ ch = '?'; for (i = 0; i < n_os_mappings; i++) { cmp = os_map_comp(&os_buf[curcol], &os_map[i]); - if (cmp == 0) { // a hit + if (cmp == 0) { /* a hit */ ch = os_map[i].ch; break; } - else if (cmp < 0) // not found + else if (cmp < 0) /* not found */ break; } } - if (curcol < MAX_OUTPUT_COLUMNS) // this should now never happen, as we automatically return + if (curcol < MAX_OUTPUT_COLUMNS) /* this should now never happen, as we automatically return */ curcol++; } diff --git a/Ibm1130/ibm1130_sys.c b/Ibm1130/ibm1130_sys.c index b439b12e..22cce803 100644 --- a/Ibm1130/ibm1130_sys.c +++ b/Ibm1130/ibm1130_sys.c @@ -3,6 +3,7 @@ Based on PDP-11 simulator written by Robert M Supnik Revision History + 0.27 2005Mar08 - Added sca device 0.26 2002Apr24 - Added !BREAK in card deck file to stop simulator 0.25 2002Apr18 - Fixed some card reader problems. It starts the reader properly if you attach a deck while it's waiting to a read. @@ -27,9 +28,9 @@ #include #include -extern DEVICE cpu_dev, console_dev, dsk_dev, cr_dev, cp_dev, ptr_dev, ptp_dev; -extern DEVICE tti_dev, tto_dev, prt_dev, log_dev; -extern DEVICE gdu_dev, console_dev; +extern DEVICE cpu_dev, console_dev, dsk_dev, cr_dev, cp_dev, ptr_dev, ptp_dev, t2741_dev; +extern DEVICE tti_dev, tto_dev, prt_dev, log_dev, sca_dev; +extern DEVICE gdu_dev, console_dev, plot_dev; extern UNIT cpu_unit; extern REG cpu_reg[]; @@ -61,8 +62,11 @@ DEVICE *sim_devices[] = { &prt_dev, /* 1132 printer */ &ptr_dev, /* 1134 paper tape reader */ &ptp_dev, /* 1055 paper tape punch */ + &sca_dev, /* Synchronous communications adapter option */ &console_dev, /* console display (windows GUI) */ &gdu_dev, /* 2250 display */ + &t2741_dev, /* nonstandard serial interface used by APL\1130 */ + &plot_dev, /* plotter device, in ibm1130_plot.c */ NULL }; @@ -76,7 +80,11 @@ const char *sim_stop_messages[] = { "!BREAK in card deck file", "Phase load break", "Program has run amok", - "Run time limit exceeded" + "Run time limit exceeded", + "Immediate Stop key requested", + "Simulator break key pressed", + "Simulator step count expired", + "Simulator IO error", }; /* Loader. IPL is normally performed by card reader (boot command). This function @@ -106,13 +114,13 @@ t_stat my_load (FILE *fileref, char *cptr, char *fnam) int iaddr = -1, runaddr = -1, val, nwords; while (fgets(line, sizeof(line), fileref) != NULL) { - for (c = line; *c && *c <= ' '; c++) // find first nonblank + for (c = line; *c && *c <= ' '; c++) /* find first nonblank */ ; if (*c == '\0' || *c == '#' || *c == '/' || *c == ';') - continue; // empty line or comment + continue; /* empty line or comment */ - if (*c == '@') { // set load address + if (*c == '@') { /* set load address */ if (sscanf(c+1, "%x", &iaddr) != 1) return SCPE_FMT; } @@ -124,7 +132,7 @@ t_stat my_load (FILE *fileref, char *cptr, char *fnam) if (sscanf(c+1, "%x", &val) != 1) return SCPE_FMT; - CES = val & 0xFFFF; // preload console entry switches + CES = val & 0xFFFF; /*preload console entry switches */ } else if (*c == 'z' || *c == 'Z') { if (sscanf(c+1, "%x", &nwords) != 1) @@ -145,11 +153,11 @@ t_stat my_load (FILE *fileref, char *cptr, char *fnam) if (iaddr == -1) return SCPE_FMT; - WriteW(iaddr, val); // store data + WriteW(iaddr, val); /*store data */ iaddr++; } else - return SCPE_FMT; // unexpected data + return SCPE_FMT; /*unexpected data */ } if (runaddr != -1) @@ -166,14 +174,14 @@ t_stat my_save (FILE *fileref, char *cptr, char *fnam) fprintf(fileref, "@0000\r\n"); for (iaddr = 0; iaddr < nwords; iaddr++) { val = ReadW(iaddr); - if (val == 0) // queue up zeroes + if (val == 0) /*queue up zeroes */ nzeroes++; else { - if (nzeroes >= 4) { // spit out a Z directive + if (nzeroes >= 4) { /*spit out a Z directive */ fprintf(fileref, "Z%04x\r\n", nzeroes); nzeroes = 0; } - else { // write queued zeroes literally + else { /*write queued zeroes literally */ while (nzeroes > 0) { fprintf(fileref, " 0000\r\n"); nzeroes--; @@ -182,7 +190,7 @@ t_stat my_save (FILE *fileref, char *cptr, char *fnam) fprintf(fileref, " %04x\r\n", val); } } - if (nzeroes >= 4) { // emit any queued zeroes + if (nzeroes >= 4) { /*emit any queued zeroes */ fprintf(fileref, "Z%04x\r\n", nzeroes); nzeroes = 0; } @@ -241,7 +249,7 @@ static char *opcode[] = { "AND ", "OR ", "EOR ", "?1F ", }; -static char relative[] = { // true if short mode displacements are IAR relative +static char relative[] = { /*true if short mode displacements are IAR relative */ FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, @@ -287,10 +295,11 @@ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) cflag = (uptr == NULL) || (uptr == &cpu_unit); -// if (sw & SWMASK ('A')) { /* ASCII? not useful */ -// fprintf (of, (c1 < 040)? "<%03o>": "%c", c1); -// return SCPE_OK; -// } +/* if (sw & SWMASK ('A')) { // ASCII? not useful + fprintf (of, (c1 < 040)? "<%03o>": "%c", c1); + return SCPE_OK; + } +*/ if (sw & SWMASK ('C')) /* character? not useful -- make it EBCDIC */ sw |= SWMASK('E'); @@ -349,7 +358,7 @@ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) DSPLC &= 0x003F; eaddr = DSPLC; } - else if ((OP == 0x08 && F)|| OP == 0x09) { // BSI L and BSC any + else if ((OP == 0x08 && F)|| OP == 0x09) { /* BSI L and BSC any */ if (OP == 0x09 && (IR & 0x40)) mnem = "BOSC"; @@ -368,7 +377,7 @@ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) fprintf(of, "%04x %s %c%c %s ", IR & 0xFFFF, mnem, F ? (INDIR ? 'I' : 'L') : ' ', tagc[TAG], tst); return SCPE_OK; } - else if (OP == 0x0e && TAG == 0) { // MDX with no tag => MDM or jump + else if (OP == 0x0e && TAG == 0) { /* MDX with no tag => MDM or jump */ if (F) { fprintf(of, "%04x %s %c%c %04x,%x (%d) ", IR & 0xFFFF, "MDM ", (INDIR ? 'I' : 'L'), tagc[TAG], eaddr & 0xFFFF, DSPLC & 0xFFFF, DSPLC); return -1; @@ -446,47 +455,47 @@ t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) #ifndef _WIN32 -int strnicmp (char *a, char *b, int n) +int strnicmp (const char *a, const char *b, int n) { int ca, cb; for (;;) { - if (--n < 0) // still equal after n characters? quit now + if (--n < 0) /* still equal after n characters? quit now */ return 0; - if ((ca = *a) == 0) // get character, stop on null terminator + if ((ca = *a) == 0) /* get character, stop on null terminator */ return *b ? -1 : 0; - if (ca >= 'a' && ca <= 'z') // fold lowercase to uppercase + if (ca >= 'a' && ca <= 'z') /* fold lowercase to uppercase */ ca -= 32; cb = *b; if (cb >= 'a' && cb <= 'z') cb -= 32; - if ((ca -= cb) != 0) // if different, return comparison + if ((ca -= cb) != 0) /* if different, return comparison */ return ca; a++, b++; } } -int strcmpi (char *a, char *b) +int strcmpi (const char *a, const char *b) { int ca, cb; for (;;) { - if ((ca = *a) == 0) // get character, stop on null terminator + if ((ca = *a) == 0) /* get character, stop on null terminator */ return *b ? -1 : 0; - if (ca >= 'a' && ca <= 'z') // fold lowercase to uppercase + if (ca >= 'a' && ca <= 'z') /* fold lowercase to uppercase */ ca -= 32; cb = *b; if (cb >= 'a' && cb <= 'z') cb -= 32; - if ((ca -= cb) != 0) // if different, return comparison + if ((ca -= cb) != 0) /* if different, return comparison */ return ca; a++, b++; diff --git a/Ibm1130/ibm1130_t2741.c b/Ibm1130/ibm1130_t2741.c new file mode 100644 index 00000000..7ef37c35 --- /dev/null +++ b/Ibm1130/ibm1130_t2741.c @@ -0,0 +1,388 @@ +/*************************************************************************************** + * Nonstandard serial attachment for remote 2741 terminal (IO selectric) used by APL\1130 + * This implementation may be incomplete and/or incorrect + ***************************************************************************************/ + +#include "ibm1130_defs.h" +#include "sim_sock.h" +#include "sim_tmxr.h" + +#define DEBUG_T2741 + +static TMLN t2741_ldsc = { 0 }; /* line descr for telnet attachment */ +static TMXR t2741_tmxr = { 1, 0, 0, &t2741_ldsc }; /* line mux for telnet attachment */ + +#define T2741_DSW_TRANSMIT_NOT_READY 0x4000 +#define T2741_DSW_READ_RESPONSE 0x1000 +#define T2741_DSW_READ_OVERRUN 0x0800 +#define T2741_DSW_ATTENTION 0x0010 + +#define IS_ONLINE(u) (((u)->flags & (UNIT_ATT|UNIT_DIS)) == UNIT_ATT) + +#define UNIT_V_PHYSICAL_TERM (UNIT_V_UF + 0) /* indicates not telnet but attachment to real terminal */ +#define UNIT_V_UPCASE (UNIT_V_UF + 1) /* indicates upshift performed */ +#define UNIT_V_SENDING (UNIT_V_UF + 2) /* indicates not telnet but attachment to real terminal */ +#define UNIT_V_RECEIVING (UNIT_V_UF + 3) /* indicates not telnet but attachment to real terminal */ + +#define UNIT_PHYSICAL_TERM (1u << UNIT_V_PHYSICAL_TERM) +#define UNIT_UPCASE (1u << UNIT_V_UPCASE) +#define UNIT_SENDING (1u << UNIT_V_SENDING) +#define UNIT_RECEIVING (1u << UNIT_V_RECEIVING) + +#define CODE_SHIFTUP 0x1C00 +#define CODE_SHIFTDOWN 0x7C00 +#define CODE_CIRCLEC 0x1F00 +#define CODE_CIRCLED 0x1600 +#define CODE_RETURN 0x5B00 +#define CODE_LINEFEED 0x3B00 +#define CODE_ATTENTION 0x0001 /* pseudocode, never really returned as a received character */ +#define CODE_UNKNOWN 0x0000 + +static t_stat t2741_svc (UNIT *uptr); +static t_stat t2741_reset (DEVICE *dptr); +static t_stat t2741_attach (UNIT *uptr, char *cptr); +static t_stat t2741_detach (UNIT *uptr); +static uint16 ascii_to_t2741 (int ascii); +static char * t2741_to_ascii (uint16 code); +static void set_transmit_notready (void); + +static uint16 t2741_dsw = T2741_DSW_TRANSMIT_NOT_READY; /* device status word */ +static uint32 t2741_swait = 200; /* character send wait */ +static uint32 t2741_rwait = 2000; /* character receive wait */ +static uint16 t2741_char = 0; /* last character received */ +static int overrun = FALSE; +static uint32 t2741_socket = 1130; + +UNIT t2741_unit[1] = { + { UDATA (&t2741_svc, UNIT_ATTABLE, 0) }, +}; + +REG t2741_reg[] = { + { HRDATA (DSW, t2741_dsw, 16) }, /* device status word */ + { DRDATA (RTIME, t2741_rwait, 24), PV_LEFT }, /* character receive wait */ + { DRDATA (STIME, t2741_swait, 24), PV_LEFT }, /* character send wait */ + { DRDATA (SOCKET, t2741_socket,16), PV_LEFT }, /* socket number */ + { HRDATA (LASTCHAR, t2741_char, 16), PV_LEFT }, /* last character read */ + { NULL } }; + +DEVICE t2741_dev = { + "T2741", t2741_unit, t2741_reg, NULL, + 1, 16, 16, 1, 16, 16, + NULL, NULL, t2741_reset, + NULL, t2741_attach, t2741_detach}; + +/* xio_t2741_terminal - XIO command interpreter for the terminal adapter */ + +void xio_t2741_terminal (int32 iocc_addr, int32 iocc_func, int32 iocc_mod) +{ + char msg[80]; + uint16 code; + + switch (iocc_func) { + case XIO_READ: /* read: return last character read */ + code = t2741_char & 0xFF00; + M[iocc_addr & mem_mask] = code; + overrun = FALSE; +#ifdef DEBUG_T2741 +/* trace_both("T2741 %04x READ %02x %s", prev_IAR, code >> 8, t2741_to_ascii(code)); */ +#endif + break; + + case XIO_WRITE: /* write: initiate character send */ + code = M[iocc_addr & mem_mask] & 0xFF00; +#ifdef DEBUG_T2741 + trace_both("T2741 %04x SEND %02x %s", prev_IAR, code >> 8, t2741_to_ascii(code)); +#endif + SETBIT(t2741_dsw, T2741_DSW_TRANSMIT_NOT_READY); + SETBIT(t2741_unit->flags, UNIT_SENDING); + + if (code == CODE_SHIFTUP) + SETBIT(t2741_unit->flags, UNIT_UPCASE); + else if (code == CODE_SHIFTDOWN) + CLRBIT(t2741_unit->flags, UNIT_UPCASE); + + sim_activate(t2741_unit, t2741_swait); /* schedule interrupt */ + break; + + case XIO_SENSE_DEV: /* sense device status */ + ACC = t2741_dsw; +#ifdef DEBUG_T2741 +/* trace_both("T2741 %04x SENS %04x%s", prev_IAR, t2741_dsw, (iocc_mod & 0x01) ? " reset" : ""); */ +#endif + if (iocc_mod & 0x01) { /* reset interrupts */ + CLRBIT(t2741_dsw, T2741_DSW_READ_RESPONSE); + CLRBIT(ILSW[4], ILSW_4_T2741_TERMINAL); + } + break; + + case XIO_CONTROL: /* control: do something to interface */ +#ifdef DEBUG_T2741 + trace_both("T2741 %04x CTRL %04x", prev_IAR, iocc_mod &0xFF); +#endif + SETBIT(t2741_unit->flags, UNIT_RECEIVING); /* set mode to receive mode */ + if (IS_ONLINE(t2741_unit) && (t2741_char != 0 || ! feof(t2741_unit->fileref))) { + sim_activate(t2741_unit, t2741_rwait); + t2741_char = (CODE_CIRCLED >> 8); /* first character received after turnaround is circled */ + } + break; + + default: + sprintf(msg, "Invalid T2741 XIO function %x", iocc_func); + xio_error(msg); + } +} + +static void set_transmit_notready (void) +{ + if (IS_ONLINE(t2741_unit) && ! (t2741_unit->flags & UNIT_SENDING)) + CLRBIT(t2741_dsw, T2741_DSW_TRANSMIT_NOT_READY); + else + SETBIT(t2741_dsw, T2741_DSW_TRANSMIT_NOT_READY); +} + +static t_stat t2741_svc (UNIT *uptr) +{ + int ch = EOF; + uint16 code; + + if (uptr->flags & UNIT_SENDING) { /* xmit: no interrupt, as far as I know. just clr busy bit */ + CLRBIT(uptr->flags, UNIT_SENDING); + set_transmit_notready(); + } + + if (uptr->flags & UNIT_RECEIVING) { /* rcv: fire interrupt */ + t2741_char <<= 8; + + if (t2741_char == 0) { /* there is no 2nd character from previous ascii input */ + if ((ch = getc(t2741_unit->fileref)) == EOF) + t2741_char = 0; + else { + if (ch == '\r') { /* if we get CR, jump to LF */ + if ((ch = getc(t2741_unit->fileref)) != '\n') { + ungetc(ch, t2741_unit->fileref); + ch = '\r'; + } + } + + if (ch == '\027') { + t2741_char = CODE_LINEFEED; /* attention key sends line feed character */ +#ifdef DEBUG_T2741 + trace_both("T2741 ---- ATTENTION"); +#endif + SETBIT(t2741_dsw, T2741_DSW_ATTENTION); /* no character returned ? */ + } + else { + t2741_char = ascii_to_t2741(ch); /* translate to 2741 code(s) */ + } + } + } + + code = t2741_char & 0xFF00; + + if (t2741_char != 0) { + if (overrun) /* previous character was not picked up! */ + SETBIT(t2741_dsw, T2741_DSW_READ_OVERRUN); + + SETBIT(t2741_dsw, T2741_DSW_READ_RESPONSE); + SETBIT(ILSW[4], ILSW_4_T2741_TERMINAL); /* issue interrupt */ + calc_ints(); + +#ifdef DEBUG_T2741 + trace_both("T2741 ---- RCVD %02x '%s' RDRESP%s%s", code >> 8, t2741_to_ascii(code), + (t2741_dsw & T2741_DSW_READ_OVERRUN) ? "|OVERRUN" : "", + (t2741_dsw & T2741_DSW_ATTENTION) ? "|ATTENTION" : ""); +#endif + + overrun = TRUE; /* arm overrun flag */ + } + + if (t2741_char == CODE_CIRCLEC) /* end of line (CIRCLEC after RETURN) auto downshifts */ + CLRBIT(t2741_unit->flags, UNIT_UPCASE); + + if (t2741_char == 0 || code == CODE_CIRCLEC) + CLRBIT(uptr->flags, UNIT_RECEIVING); /* on enter or EOF, stop typing */ + else + sim_activate(t2741_unit, t2741_rwait); /* schedule next character to arrive */ + } + + return SCPE_OK; +} + +static t_stat t2741_attach (UNIT *uptr, char *cptr) +{ + int rval; + + if ((rval = attach_unit(uptr, cptr)) == SCPE_OK) { /* use standard attach */ + t2741_char = 0; + overrun = FALSE; + + CLRBIT(t2741_unit->flags, UNIT_UPCASE); + + if ((t2741_unit->flags & UNIT_RECEIVING) && ! feof(t2741_unit->fileref)) + sim_activate(t2741_unit, t2741_rwait); /* schedule interrupt */ + } + + set_transmit_notready(); + + return rval; +} + +static t_stat t2741_detach (UNIT *uptr) +{ + t_stat rval; + + if (t2741_unit->flags & UNIT_RECEIVING) /* if receive was pending, cancel interrupt */ + sim_cancel(t2741_unit); + + t2741_char = 0; + overrun = FALSE; + + rval = detach_unit(uptr); /* use standard detach */ + + set_transmit_notready(); + + return rval; +} + +static t_stat t2741_reset (DEVICE *dptr) +{ + sim_cancel(t2741_unit); + + CLRBIT(t2741_unit->flags, UNIT_SENDING|UNIT_RECEIVING|UNIT_UPCASE); + + t2741_char = 0; + t2741_dsw = 0; + overrun = FALSE; + + set_transmit_notready(); + + CLRBIT(ILSW[4], ILSW_4_T2741_TERMINAL); + calc_ints(); + + return SCPE_OK; +} + +static struct tag_t2741_map { + int code; + int lcase, ucase; + t_bool shifts; +} t2741_map[] = { + {0x4F00, 'A', 'a', TRUE}, + {0x3700, 'B', 'b', TRUE}, + {0x2F00, 'C', 'c', TRUE}, + {0x2A00, 'D', 'd', TRUE}, + {0x2900, 'E', 'e', TRUE}, + {0x6700, 'F', '_', TRUE}, + {0x6200, 'G', 'g', TRUE}, + {0x3200, 'H', 'h', TRUE}, + {0x4C00, 'I', 'i', TRUE}, + {0x6100, 'J', 'j', TRUE}, + {0x2C00, 'K', '\'', TRUE}, + {0x3100, 'L', 'l', TRUE}, + {0x4300, 'M', '|', TRUE}, + {0x2500, 'N', 'n', TRUE}, + {0x5100, 'O', 'o', TRUE}, + {0x6800, 'P', '*', TRUE}, + {0x6D00, 'Q', '?', TRUE}, + {0x4A00, 'R', 'r', TRUE}, + {0x5200, 'S', 's', TRUE}, + {0x2000, 'T', '~', TRUE}, + {0x2600, 'U', 'u', TRUE}, + {0x4600, 'V', 'v', TRUE}, + {0x5700, 'W', 'w', TRUE}, + {0x2300, 'X', 'x', TRUE}, + {0x7300, 'Y', 'y', TRUE}, + {0x1500, 'Z', 'z', TRUE}, + {0x1300, '0', '&', TRUE}, + {0x0200, '1', '?', TRUE}, + {0x0400, '2', '?', TRUE}, + {0x0700, '3', '<', TRUE}, + {0x1000, '4', '?', TRUE}, + {0x0800, '5', '=', TRUE}, + {0x0D00, '6', '?', TRUE}, + {0x0B00, '7', '>', TRUE}, + {0x0E00, '8', '?', TRUE}, + {0x1600, '9', '|', TRUE}, + {0x7000, '/', '\\', TRUE}, + {0x7600, '+', '-', TRUE}, + {0x6400, '?', '?', TRUE}, + {0x4000, '<', '>', TRUE}, + {0x6B00, '[', '(', TRUE}, + {0x4900, ']', ')', TRUE}, + {0x6E00, ',', ';', TRUE}, + {0x4500, '.', ':', TRUE}, + {0x0100, ' ', 0, FALSE}, + {0x5B00, '\r', 0, FALSE}, + {0x3B00, '\n', 0, FALSE}, + {0x5D00, '\b', 0, FALSE}, + {0x5E00, '\t', 0, FALSE}, + {0x0001, '\027', 0, FALSE}, +}; + +static uint16 ascii_to_t2741 (int ascii) +{ + int i; + uint16 rval = 0; + + ascii &= 0xFF; + + if (ascii == '\n') /* turn newlines into returns + CIRCLED? */ + return CODE_RETURN | (CODE_CIRCLEC >> 8); + + for (i = sizeof(t2741_map)/sizeof(t2741_map[0]); --i >= 0; ) { + if (t2741_map[i].shifts) { + if (t2741_map[i].lcase == ascii) { + rval = t2741_map[i].code; + if (t2741_unit->flags & UNIT_UPCASE) { + CLRBIT(t2741_unit->flags, UNIT_UPCASE); + rval = CODE_SHIFTDOWN | (rval >> 8); + } + return rval; + } + if (t2741_map[i].ucase == ascii) { + rval = t2741_map[i].code; + if (! (t2741_unit->flags & UNIT_UPCASE)) { + SETBIT(t2741_unit->flags, UNIT_UPCASE); + rval = CODE_SHIFTUP | (rval >> 8); + } + return rval; + } + } + else if (t2741_map[i].lcase == ascii) + return t2741_map[i].code; + } + + return CODE_UNKNOWN; +} + +static char * t2741_to_ascii (uint16 code) +{ + int i; + static char string[2] = {'?', '\0'}; + + switch (code) { + case CODE_SHIFTUP: return "SHIFTUP"; + case CODE_SHIFTDOWN: return "SHIFTDN"; + case CODE_CIRCLEC: return "CIRCLEC"; + case CODE_CIRCLED: return "CIRCLED"; + } + + for (i = sizeof(t2741_map)/sizeof(t2741_map[0]); --i >= 0; ) { + if (t2741_map[i].code == code) { + if (t2741_map[i].shifts) { + string[0] = (t2741_unit->flags & UNIT_UPCASE) ? t2741_map[i].ucase : t2741_map[i].lcase; + return string; + } + switch (t2741_map[i].lcase) { + case ' ': return " "; + case '\r': return "RETURN"; + case '\n': return "LINEFEED"; + case '\b': return "BS"; + case '\t': return "IDLE"; + } + break; + } + } + + return "?"; +} diff --git a/Interdata/id16_cpu.c b/Interdata/id16_cpu.c index 932f7a71..36e033d4 100644 --- a/Interdata/id16_cpu.c +++ b/Interdata/id16_cpu.c @@ -25,6 +25,8 @@ cpu Interdata 16b CPU + 27-Oct-06 RMS Added idle support + Removed separate PASLA clock 06-Feb-06 RMS Fixed bug in DH (found by Mark Hittinger) 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) 25-Aug-05 RMS Fixed DH integer overflow cases @@ -219,7 +221,8 @@ uint32 (*dev_tab[DEVNO])(uint32 dev, uint32 op, uint32 datout) = { NULL }; extern int32 sim_interval; extern int32 sim_int_char; extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ -extern UNIT pic_unit, lfc_unit, pas_unit; /* timers */ +extern t_bool sim_idle_enab; +extern UNIT pic_unit, lfc_unit; /* timers */ uint32 ReadB (uint32 loc); uint32 ReadH (uint32 loc); @@ -445,7 +448,7 @@ static uint32 s1_rel_const[16] = { /* addr 8000-FFFF */ DIB cpu_dib = { d_DS, -1, v_DS, NULL, &display, NULL }; UNIT cpu_unit = { - UDATA (NULL, UNIT_FIX + UNIT_BINK + UNIT_716, MAXMEMSIZE16) + UDATA (NULL, UNIT_FIX | UNIT_BINK | UNIT_716, MAXMEMSIZE16) }; REG cpu_reg[] = { @@ -513,6 +516,13 @@ REG cpu_reg[] = { }; MTAB cpu_mod[] = { + { UNIT_TYPE, 0, "I3", "I3", &cpu_set_model }, + { UNIT_TYPE, UNIT_ID4, "I4", "I4", &cpu_set_model }, + { UNIT_TYPE, UNIT_716, "7/16", "716", &cpu_set_model }, + { UNIT_TYPE, UNIT_816, "8/16", "816", &cpu_set_model }, + { UNIT_TYPE, UNIT_816E, "8/16E", "816E", &cpu_set_model }, + { MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL }, { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size }, { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size }, { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size }, @@ -521,11 +531,6 @@ MTAB cpu_mod[] = { { UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size }, { UNIT_MSIZE, 131072, NULL, "128K", &cpu_set_size }, { UNIT_MSIZE, 262144, NULL, "256K", &cpu_set_size }, - { UNIT_TYPE, 0, "I3", "I3", &cpu_set_model }, - { UNIT_TYPE, UNIT_ID4, "I4", "I4", &cpu_set_model }, - { UNIT_TYPE, UNIT_716, "7/16", "716", &cpu_set_model }, - { UNIT_TYPE, UNIT_816, "8/16", "816", &cpu_set_model }, - { UNIT_TYPE, UNIT_816E, "8/16E", "816E", &cpu_set_model }, { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "CONSINT", &cpu_set_consint, NULL, NULL }, { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", @@ -584,7 +589,6 @@ int_eval (); /* eval interrupts */ cc = newPSW (PSW & psw_mask); /* split PSW, eval wait */ sim_rtcn_init (lfc_unit.wait, TMR_LFC); /* init clock */ sim_rtcn_init (pic_unit.wait, TMR_PIC); /* init timer */ -sim_rtcn_init (pas_unit.wait, TMR_PAS); /* init pas */ reason = 0; /* Process events */ @@ -641,10 +645,9 @@ while (reason == 0) { /* loop until halted */ } if (PSW & PSW_WAIT) { /* wait state? */ - t = sim_qcount (); /* events in queue */ - if ((t == 0) || ((t == 1) && stop_wait)) /* empty, or kbd only? */ - reason = STOP_WAIT; /* then stop */ - else sim_interval = 0; /* force check */ + if (sim_idle_enab) /* idling enabled? */ + sim_idle (TMR_LFC, TRUE); + else sim_interval = sim_interval - 1; /* no, count cycle */ continue; } diff --git a/Interdata/id16_sys.c b/Interdata/id16_sys.c index 292c7ec6..62b30dbe 100644 --- a/Interdata/id16_sys.c +++ b/Interdata/id16_sys.c @@ -1,6 +1,6 @@ /* id16_sys.c: Interdata 16b simulator interface - Copyright (c) 2000-2005, Robert M. Supnik + Copyright (c) 2000-2006, 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. + 18-Oct-06 RMS Re-ordered device list 26-Mar-04 RMS Fixed warning with -std=c99 27-Feb-03 RMS Added relative addressing support */ @@ -69,13 +70,13 @@ int32 sim_emax = 2; DEVICE *sim_devices[] = { &cpu_dev, &sch_dev, + &pic_dev, + &lfc_dev, &pt_dev, &tt_dev, &ttp_dev, &pas_dev, &pasl_dev, - &pic_dev, - &lfc_dev, &lpt_dev, &dp_dev, &idc_dev, diff --git a/Interdata/id32_cpu.c b/Interdata/id32_cpu.c index fcfa4268..93d4970a 100644 --- a/Interdata/id32_cpu.c +++ b/Interdata/id32_cpu.c @@ -25,7 +25,9 @@ cpu Interdata 32b CPU - 09-Mar-06 RMS Added 8 register bank support for 8/32 + 27-Oct-06 RMS Added idle support + Removed separate PASLA clock + 09-Mar-06 RMS Added 8 register bank support for 8/32 06-Feb-06 RMS Fixed bug in DH (found by Mark Hittinger) 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) 16-Aug-05 RMS Fixed C++ declaration and cast problems @@ -249,7 +251,8 @@ uint32 (*dev_tab[DEVNO])(uint32 dev, uint32 op, uint32 datout) = { NULL }; extern int32 sim_interval; extern int32 sim_int_char; extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ -extern UNIT pic_unit, lfc_unit, pas_unit; /* timers */ +extern t_bool sim_idle_enab; +extern UNIT pic_unit, lfc_unit; /* timers */ extern FILE *sim_deb; uint32 ReadB (uint32 loc, uint32 rel); @@ -566,11 +569,6 @@ REG cpu_reg[] = { }; MTAB cpu_mod[] = { - { UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size }, - { UNIT_MSIZE, 131072, NULL, "128K", &cpu_set_size }, - { UNIT_MSIZE, 262144, NULL, "256K", &cpu_set_size }, - { UNIT_MSIZE, 524288, NULL, "512K", &cpu_set_size }, - { UNIT_MSIZE, 1048756, NULL, "1M", &cpu_set_size }, { UNIT_8RS|UNIT_TYPE, 0, NULL, "732", NULL }, { UNIT_DPFP, UNIT_DPFP, NULL, "DPFP", NULL }, { UNIT_TYPE, 0, "7/32, single precision fp", "732", NULL }, @@ -579,6 +577,13 @@ MTAB cpu_mod[] = { { UNIT_8RS, 0, NULL, "2RS", NULL }, { UNIT_8RS|UNIT_TYPE, UNIT_8RS|UNIT_DPFP|UNIT_832, "832, 8 register sets", NULL, NULL }, { UNIT_8RS|UNIT_TYPE, UNIT_DPFP|UNIT_832, "832, 2 register sets", NULL, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL }, + { UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size }, + { UNIT_MSIZE, 131072, NULL, "128K", &cpu_set_size }, + { UNIT_MSIZE, 262144, NULL, "256K", &cpu_set_size }, + { UNIT_MSIZE, 524288, NULL, "512K", &cpu_set_size }, + { UNIT_MSIZE, 1048756, NULL, "1M", &cpu_set_size }, { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "CONSINT", &cpu_set_consint, NULL, NULL }, { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", @@ -624,7 +629,6 @@ int_eval (); /* eval interrupts */ cc = newPSW (PSW & PSW_MASK); /* split PSW, eval wait */ sim_rtcn_init (lfc_unit.wait, TMR_LFC); /* init clock */ sim_rtcn_init (pic_unit.wait, TMR_PIC); /* init timer */ -sim_rtcn_init (pas_unit.wait, TMR_PAS); /* init pas */ reason = 0; /* Abort handling @@ -703,10 +707,9 @@ while (reason == 0) { /* loop until halted */ } if (PSW & PSW_WAIT) { /* wait state? */ - t = sim_qcount (); /* events in queue */ - if ((t == 0) || ((t == 1) && stop_wait)) /* empty, or kbd only? */ - reason = STOP_WAIT; /* then stop */ - else sim_interval = 0; /* force check */ + if (sim_idle_enab) /* idling enabled? */ + sim_idle (TMR_LFC, TRUE); + else sim_interval = sim_interval - 1; /* no, count cycle */ continue; } diff --git a/Interdata/id32_sys.c b/Interdata/id32_sys.c index 01e3a5f6..e683f404 100644 --- a/Interdata/id32_sys.c +++ b/Interdata/id32_sys.c @@ -1,6 +1,6 @@ /* id32_sys.c: Interdata 32b simulator interface - Copyright (c) 2000-2005, Robert M. Supnik + Copyright (c) 2000-2007, 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,8 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 25-Jan-07 RMS Fixed conflict between -h (hex) and -h (halfword) + 18-Oct-06 RMS Re-ordered device list 02-Jul-04 RMS Fixed missing type in declaration 15-Jul-03 RMS Fixed signed/unsigned bug in get_imm 27-Feb-03 RMS Added relative addressing support @@ -72,13 +74,13 @@ int32 sim_emax = 6; DEVICE *sim_devices[] = { &cpu_dev, &sch_dev, + &pic_dev, + &lfc_dev, &pt_dev, &tt_dev, &ttp_dev, &pas_dev, &pasl_dev, - &pic_dev, - &lfc_dev, &lpt_dev, &dp_dev, &idc_dev, @@ -365,7 +367,7 @@ if (sw & SWMASK ('C')) { /* string? */ fprintf (of, (c2 < 0x20)? "<%02X>": "%c", c2); return -1; } -if (sw & SWMASK ('H')) { /* halfword? */ +if (sw & SWMASK ('W')) { /* halfword? */ fprint_val (of, val[0], rdx, 16, PV_RZRO); return -1; } @@ -584,7 +586,7 @@ if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII chars? */ val[0] = ((t_value) cptr[0] << 8) | (t_value) cptr[1]; return -1; } -if (sw & SWMASK ('H')) { /* halfword? */ +if (sw & SWMASK ('W')) { /* halfword? */ val[0] = (int32) get_uint (cptr, rdx, DMASK16, &r); /* get number */ if (r != SCPE_OK) return r; return -1; @@ -680,7 +682,7 @@ switch (j) { /* case on class */ val[2] = t & DMASK16; return -5; - case I_V_RI: /* 16b immediate */ + case I_V_RI: /* 16b immediate */ r = get_imm (gbuf, &t, &inst, DMASK16); /* process imm */ if (r != SCPE_OK) return r; val[0] = inst; diff --git a/Interdata/id_defs.h b/Interdata/id_defs.h index 0d20abcc..799b76ea 100644 --- a/Interdata/id_defs.h +++ b/Interdata/id_defs.h @@ -451,7 +451,6 @@ typedef struct { #define TMR_LFC 0 /* LFC = timer 0 */ #define TMR_PIC 1 /* PIC = timer 1 */ -#define TMR_PAS 2 /* PAS = timer 2 */ #define LPT_WIDTH 132 #define VFU_LNT 132 #define MIN(x,y) (((x) < (y))? (x): (y)) diff --git a/Interdata/id_idc.c b/Interdata/id_idc.c index 4a74b109..baf00dd6 100644 --- a/Interdata/id_idc.c +++ b/Interdata/id_idc.c @@ -128,8 +128,8 @@ #define HCYL_V_HD 10 /* head/cyl word */ #define HCYL_V_CYL 0 -#define GET_SA(cy,sf,sc,t) (((((cy)*drv_tab[t].surf)+(sf))* \ - IDC_NUMSC)+(sc)) +#define GET_SA(cy,sf,sc,t) \ + (((((cy)*drv_tab[t].surf)+(sf))*IDC_NUMSC)+(sc)) /* The MSM (IDC) controller supports (two) six different disk drive types: diff --git a/Interdata/id_lp.c b/Interdata/id_lp.c index 9a658ca0..8cf32045 100644 --- a/Interdata/id_lp.c +++ b/Interdata/id_lp.c @@ -167,8 +167,9 @@ if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ t = uptr->buf; /* get character */ if (lpt_spnd || ((t >= LF) && (t < CR))) { /* spc pend or spc op? */ lpt_spnd = 0; - if (lpt_bufout (uptr) != SCPE_OK) return SCPE_IOERR; /* print */ - if ((t == 1) || (t == LF)) lpt_spc (uptr, 1); /* single space */ + if (lpt_bufout (uptr) != SCPE_OK) /* print */ + return SCPE_IOERR; + if ((t == 1) || (t == LF)) lpt_spc (uptr, 1); /* single space */ else if (t == VT) r = lpt_vfu (uptr, VT_VFU - 1); /* VT->VFU */ else if (t == 0xC) r = lpt_vfu (uptr, FF_VFU - 1); /* FF->VFU */ else if ((t >= SPC_BASE) && (t < VFU_BASE)) @@ -287,7 +288,7 @@ char cbuf[CBUFSIZE], gbuf[CBUFSIZE]; if (*cptr != 0) return SCPE_ARG; ptr = 0; -for ( ; (cptr = fgets (cbuf, CBUFSIZE, fileref)) != NULL; ) { /* until eof */ +for ( ; (cptr = fgets (cbuf, CBUFSIZE, fileref)) != NULL; ) { /* until eof */ mask = 0; if (*cptr == '(') { /* repeat count? */ cptr = get_glyph (cptr + 1, gbuf, ')'); /* get 1st field */ diff --git a/Interdata/id_mt.c b/Interdata/id_mt.c index 9711de44..c91cfc54 100644 --- a/Interdata/id_mt.c +++ b/Interdata/id_mt.c @@ -312,8 +312,8 @@ switch (uptr->UCMD) { /* case on function */ case MTC_RD: /* read */ if (mt_blnt == 0) { /* first time? */ - st = sim_tape_rdrecf (uptr, mtxb, &tbc, MT_MAXFR); /* read rec */ - if (st == MTSE_RECE) mt_sta = mt_sta | STA_ERR; /* rec in err? */ + st = sim_tape_rdrecf (uptr, mtxb, &tbc, MT_MAXFR); /* read rec */ + if (st == MTSE_RECE) mt_sta = mt_sta | STA_ERR; /* rec in err? */ else if (st != SCPE_OK) { /* other error? */ r = mt_map_err (uptr, st); /* map error */ if (sch_actv (mt_dib.sch, dev)) /* if sch, stop */ @@ -343,7 +343,7 @@ switch (uptr->UCMD) { /* case on function */ case MTC_WR: /* write */ if (sch_actv (mt_dib.sch, dev)) { /* sch active? */ - mt_bptr = sch_rdmem (mt_dib.sch, mtxb, MT_MAXFR); /* get rec */ + mt_bptr = sch_rdmem (mt_dib.sch, mtxb, MT_MAXFR); /* get rec */ if (sch_actv (mt_dib.sch, dev)) /* not done? */ sch_stop (mt_dib.sch); /* stop chan */ } @@ -357,7 +357,7 @@ switch (uptr->UCMD) { /* case on function */ } if (mt_bptr) { /* any chars? */ - if (st = sim_tape_wrrecf (uptr, mtxb, mt_bptr)) /* write, err? */ + if (st = sim_tape_wrrecf (uptr, mtxb, mt_bptr)) /* write, err? */ r = mt_map_err (uptr, st); /* map error */ } break; /* record done */ diff --git a/Interdata/id_pas.c b/Interdata/id_pas.c index 6b73c33c..2a68bd4d 100644 --- a/Interdata/id_pas.c +++ b/Interdata/id_pas.c @@ -1,6 +1,6 @@ /* id_pas.c: Interdata programmable async line adapter simulator - Copyright (c) 2001-2005, Robert M Supnik + Copyright (c) 2001-2006, 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 @@ pas Programmable asynchronous line adapter(s) + 18-Oct-06 RMS Synced PASLA to clock 22-Nov-05 RMS Revised for new terminal processing routines 29-Jun-05 RMS Added SET PASLn DISCONNECT 21-Jun-05 RMS Fixed bug in SHOW CONN/STATS @@ -49,7 +50,6 @@ #define UNIT_V_MDM (TTUF_V_UF + 0) /* modem control */ #define UNIT_MDM (1 << UNIT_V_MDM) -#define PAS_INIT_POLL 8000 #define PASL_WAIT 500 /* Status byte */ @@ -88,6 +88,7 @@ #define CMD_TYP 0x01 /* command type */ extern uint32 int_req[INTSZ], int_enb[INTSZ]; +extern int32 lfc_poll; uint8 pas_sta[PAS_LINES]; /* status */ uint16 pas_cmd[PAS_LINES]; /* command */ @@ -96,7 +97,6 @@ uint8 pas_xbuf[PAS_LINES]; /* xmt buf */ uint8 pas_rarm[PAS_LINES]; /* rcvr int armed */ uint8 pas_xarm[PAS_LINES]; /* xmt int armed */ uint8 pas_rchp[PAS_LINES]; /* rcvr chr pend */ -uint32 pas_tps = 50; /* polls/second */ uint8 pas_tplte[PAS_LINES * 2 + 1]; /* template */ TMLN pas_ldsc[PAS_LINES] = { 0 }; /* line descriptors */ @@ -126,7 +126,7 @@ void pas_reset_ln (int32 i); DIB pas_dib = { d_PAS, -1, v_PAS, pas_tplte, &pas, &pas_ini }; -UNIT pas_unit = { UDATA (&pasi_svc, UNIT_ATTABLE, 0), PAS_INIT_POLL }; +UNIT pas_unit = { UDATA (&pasi_svc, UNIT_ATTABLE, 0), 0 }; REG pas_nlreg = { DRDATA (NLINES, PAS_ENAB, 6), PV_LEFT }; @@ -312,11 +312,10 @@ return 0; t_stat pasi_svc (UNIT *uptr) { -int32 ln, c, out, t; +int32 ln, c, out; if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */ -t = sim_rtcn_calb (pas_tps, TMR_PAS); /* calibrate */ -sim_activate (uptr, t); /* continue poll */ +sim_activate (uptr, lfc_poll); /* continue poll */ ln = tmxr_poll_conn (&pas_desc); /* look for connect */ if (ln >= 0) { /* got one? */ if ((pasl_unit[ln].flags & UNIT_MDM) && /* modem control */ @@ -448,7 +447,7 @@ return c & 0xFF; t_stat pas_reset (DEVICE *dptr) { -int32 i, t; +int32 i; if (dptr->flags & DEV_DIS) { /* disabled? */ pas_dev.flags = pas_dev.flags | DEV_DIS; /* disable lines */ @@ -458,12 +457,8 @@ else { pas_dev.flags = pas_dev.flags & ~DEV_DIS; /* enable lines */ pasl_dev.flags = pasl_dev.flags & ~DEV_DIS; } -if (pas_unit.flags & UNIT_ATT) { /* master att? */ - if (!sim_is_active (&pas_unit)) { - t = sim_rtcn_init (pas_unit.wait, TMR_PAS); - sim_activate (&pas_unit, t); /* activate */ - } - } +if (pas_unit.flags & UNIT_ATT) /* master att? */ + sim_activate_abs (&pas_unit, lfc_poll); /* cosched with clock */ else sim_cancel (&pas_unit); /* else stop */ for (i = 0; i < PAS_LINES; i++) pas_reset_ln (i); return SCPE_OK; @@ -477,8 +472,7 @@ t_stat r; r = tmxr_attach (&pas_desc, uptr, cptr); /* attach */ if (r != SCPE_OK) return r; /* error */ -sim_rtcn_init (pas_unit.wait, TMR_PAS); -sim_activate (uptr, 100); /* quick poll */ +sim_activate_abs (uptr, 100); /* quick poll */ return SCPE_OK; } diff --git a/Interdata/id_tt.c b/Interdata/id_tt.c index 08583542..993187c0 100644 --- a/Interdata/id_tt.c +++ b/Interdata/id_tt.c @@ -1,6 +1,6 @@ /* id_tt.c: Interdata teletype - Copyright (c) 2000-2005, Robert M. Supnik + Copyright (c) 2000-2006, 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 @@ tt console + 18-Oct-06 RMS Sync keyboard to LFC clock + 30-Sep-06 RMS Fixed handling of non-printable characters in KSR mode 22-Nov-05 RMS Revised for new terminal processing routines 29-Dec-03 RMS Added support for console backpressure 25-Apr-03 RMS Revised for extended file support @@ -49,6 +51,7 @@ #define CMD_V_RD 2 /* read/write */ extern uint32 int_req[INTSZ], int_enb[INTSZ]; +extern int32 lfc_poll; uint32 tt_sta = STA_BSY; /* status */ uint32 tt_fdpx = 1; /* tt mode */ @@ -74,7 +77,7 @@ t_stat tt_set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc); DIB tt_dib = { d_TT, -1, v_TT, NULL, &tt, NULL }; UNIT tt_unit[] = { - { UDATA (&tti_svc, TT_MODE_KSR, 0), KBD_POLL_WAIT }, + { UDATA (&tti_svc, TT_MODE_KSR, 0), 0 }, { UDATA (&tto_svc, TT_MODE_KSR, 0), SERIAL_OUT_WAIT } }; @@ -82,7 +85,7 @@ REG tt_reg[] = { { HRDATA (STA, tt_sta, 8) }, { HRDATA (KBUF, tt_unit[TTI].buf, 8) }, { DRDATA (KPOS, tt_unit[TTI].pos, T_ADDR_W), PV_LEFT }, - { DRDATA (KTIME, tt_unit[TTI].wait, 24), REG_NZ + PV_LEFT }, + { DRDATA (KTIME, tt_unit[TTI].wait, 24), PV_LEFT }, { HRDATA (TBUF, tt_unit[TTO].buf, 8) }, { DRDATA (TPOS, tt_unit[TTO].pos, T_ADDR_W), PV_LEFT }, { DRDATA (TTIME, tt_unit[TTO].wait, 24), REG_NZ + PV_LEFT }, @@ -175,7 +178,7 @@ t_stat tti_svc (UNIT *uptr) { int32 out, temp; -sim_activate (uptr, uptr->wait); /* continue poll */ +sim_activate (uptr, KBD_WAIT (uptr->wait, lfc_poll)); /* continue poll */ tt_sta = tt_sta & ~STA_BRK; /* clear break */ if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */ if (tt_rd) { /* read mode? */ @@ -192,7 +195,7 @@ if (temp & SCPE_BREAK) { /* break? */ else uptr->buf = sim_tt_inpcvt (temp, TT_GET_MODE (uptr->flags) | TTUF_KSR); uptr->pos = uptr->pos + 1; /* incr count */ if (!tt_fdpx) { /* half duplex? */ - out = sim_tt_outcvt (out, TT_GET_MODE (uptr->flags)); + out = sim_tt_outcvt (out, TT_GET_MODE (uptr->flags) | TTUF_KSR); if (out >= 0) { /* valid echo? */ sim_putchar (out); /* write char */ tt_unit[TTO].pos = tt_unit[TTO].pos + 1; @@ -206,7 +209,7 @@ t_stat tto_svc (UNIT *uptr) int32 ch; t_stat r; -ch = sim_tt_outcvt (uptr->buf, TT_GET_MODE (uptr->flags)); +ch = sim_tt_outcvt (uptr->buf, TT_GET_MODE (uptr->flags) | TTUF_KSR); if (ch >= 0) { if ((r = sim_putchar_s (ch)) != SCPE_OK) { /* output; error? */ sim_activate (uptr, uptr->wait); /* try again */ @@ -226,7 +229,7 @@ return SCPE_OK; t_stat tt_reset (DEVICE *dptr) { if (dptr->flags & DEV_DIS) sim_cancel (&tt_unit[TTI]); /* dis? cancel poll */ -else sim_activate (&tt_unit[TTI], tt_unit[TTI].wait); /* activate input */ +else sim_activate_abs (&tt_unit[TTI], KBD_WAIT (tt_unit[TTI].wait, lfc_poll)); sim_cancel (&tt_unit[TTO]); /* cancel output */ tt_rd = tt_fdpx = 1; /* read, full duplex */ tt_chp = 0; /* no char */ diff --git a/Interdata/id_ttp.c b/Interdata/id_ttp.c index ecd68130..43325073 100644 --- a/Interdata/id_ttp.c +++ b/Interdata/id_ttp.c @@ -1,6 +1,6 @@ /* id_ttp.c: Interdata PASLA console interface - Copyright (c) 2000-2005, Robert M. Supnik + Copyright (c) 2000-2006, 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 @@ ttp console (on PAS) + 18-Oct-06 RMS Sync keyboard to LFC clock 22-Nov-05 RMS Revised for new terminal processing routines 29-Dec-03 RMS Added support for console backpressure 25-Apr-03 RMS Revised for extended file support @@ -52,6 +53,8 @@ #define CMD_TYP 0x01 /* command type */ extern uint32 int_req[INTSZ], int_enb[INTSZ]; +extern int32 pas_par (int32 cmd, int32 c); +extern int32 lfc_poll; uint32 ttp_sta = 0; /* status */ uint32 ttp_cmd = 0; /* command */ @@ -68,14 +71,12 @@ t_stat ttp_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat ttp_set_break (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat ttp_set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc); -extern int32 pas_par (int32 cmd, int32 c); - /* TTP data structures */ DIB ttp_dib = { d_TTP, -1, v_TTP, ttp_tplte, &ttp, NULL }; UNIT ttp_unit[] = { - { UDATA (&ttpi_svc, 0, 0), KBD_POLL_WAIT }, + { UDATA (&ttpi_svc, 0, 0), 0 }, { UDATA (&ttpo_svc, 0, 0), SERIAL_OUT_WAIT } }; @@ -83,7 +84,7 @@ REG ttp_reg[] = { { HRDATA (CMD, ttp_cmd, 16) }, { HRDATA (KBUF, ttp_unit[TTI].buf, 8) }, { DRDATA (KPOS, ttp_unit[TTI].pos, T_ADDR_W), PV_LEFT }, - { DRDATA (KTIME, ttp_unit[TTI].wait, 24), REG_NZ + PV_LEFT }, + { DRDATA (KTIME, ttp_unit[TTI].wait, 24), REG_NZ + PV_LEFT + REG_HRO }, { FLDATA (KIREQ, int_req[l_TTP], i_TTP) }, { FLDATA (KIENB, int_enb[l_TTP], i_TTP) }, { FLDATA (KARM, ttp_karm, 0) }, @@ -175,7 +176,7 @@ t_stat ttpi_svc (UNIT *uptr) { int32 c, out; -sim_activate (uptr, uptr->wait); /* continue poll */ +sim_activate (uptr, KBD_WAIT (uptr->wait, lfc_poll)); /* continue poll */ ttp_sta = ttp_sta & ~STA_FR; /* clear break */ if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */ ttp_sta = ttp_sta & ~STA_PF; /* clear parity err */ @@ -227,7 +228,7 @@ return SCPE_OK; t_stat ttp_reset (DEVICE *dptr) { if (dptr->flags & DEV_DIS) sim_cancel (&ttp_unit[TTI]); -else sim_activate (&ttp_unit[TTI], ttp_unit[TTI].wait); +else sim_activate_abs (&ttp_unit[TTI], KBD_WAIT (ttp_unit[TTI].wait, lfc_poll)); sim_cancel (&ttp_unit[TTO]); CLR_INT (v_TTP); /* clear int */ CLR_ENB (v_TTP); diff --git a/Interdata/id_uvc.c b/Interdata/id_uvc.c index 5fce2d1e..0f4d8899 100644 --- a/Interdata/id_uvc.c +++ b/Interdata/id_uvc.c @@ -1,6 +1,6 @@ /* id_uvc.c: Interdata universal clock - Copyright (c) 2001-2005, Robert M. Supnik + Copyright (c) 2001-2006, 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"), @@ -26,6 +26,7 @@ pic precision incremental clock lfc line frequency clock + 18-Oct-06 RMS Changed LFC to be free running, export tmr_poll 23-Jul-05 RMS Fixed {} error in OC 01-Mar-03 RMS Added SET/SHOW LFC FREQ support Changed precision clock algorithm for V7 UNIX @@ -75,6 +76,7 @@ void pic_sched (t_bool strt); uint32 pic_rd_cic (void); int32 lfc_tps = 120; /* ticks per */ +int32 lfc_poll = 8000; uint32 lfc_arm = 0; /* int arm */ DEVICE lfc_dev; @@ -314,8 +316,6 @@ return SCPE_OK; uint32 lfc (uint32 dev, uint32 op, uint32 dat) { -int32 t; - switch (op) { /* case IO op */ case IO_ADR: /* select */ @@ -323,10 +323,6 @@ switch (op) { /* case IO op */ case IO_OC: /* command */ lfc_arm = int_chg (v_LFC, dat, lfc_arm); /* upd int ctrl */ - if (lfc_arm && !sim_is_active (&lfc_unit)) { /* starting? */ - t = sim_rtcn_init (lfc_unit.wait, TMR_LFC); - sim_activate (&lfc_unit, t); /* init clock */ - } break; } return 0; @@ -336,13 +332,10 @@ return 0; t_stat lfc_svc (UNIT *uptr) { -int32 t; - +lfc_poll = sim_rtcn_calb (lfc_tps, TMR_LFC); /* calibrate */ +sim_activate (uptr, lfc_poll); /* reactivate */ if (lfc_arm) { /* armed? */ SET_INT (v_LFC); /* req intr */ - if (pic_unit.flags & UNIT_DIAG) t = uptr->wait; /* diag? fixed delay */ - else t = sim_rtcn_calb (lfc_tps, TMR_LFC); /* else calibrate */ - sim_activate (uptr, t); /* reactivate */ } return SCPE_OK; } @@ -351,7 +344,8 @@ return SCPE_OK; t_stat lfc_reset (DEVICE *dptr) { -sim_cancel (&lfc_unit); /* cancel unit */ +lfc_poll = sim_rtcn_init (lfc_unit.wait, TMR_LFC); +sim_activate_abs (&lfc_unit, lfc_poll); /* init clock */ CLR_INT (v_LFC); /* clear int */ CLR_ENB (v_LFC); /* disable int */ lfc_arm = 0; /* disarm int */ diff --git a/NOVA/nova_dsk.c b/NOVA/nova_dsk.c index 7867b0bf..6d3f616f 100644 --- a/NOVA/nova_dsk.c +++ b/NOVA/nova_dsk.c @@ -59,7 +59,8 @@ #define DSK_NUMSC 8 /* sectors/track */ #define DSK_NUMTR 128 /* tracks/disk */ #define DSK_DKSIZE (DSK_NUMTR*DSK_NUMSC*DSK_NUMWD) /* words/disk */ -#define DSK_AMASK ((DSK_NUMDK*DSK_NUMTR*DSK_NUMSC) - 1) /* address mask */ +#define DSK_AMASK ((DSK_NUMDK*DSK_NUMTR*DSK_NUMSC) - 1) + /* address mask */ #define DSK_NUMDK 8 /* disks/controller */ #define GET_DISK(x) (((x) / (DSK_NUMSC * DSK_NUMTR)) & (DSK_NUMDK - 1)) diff --git a/PDP1/pdp1_clk.c b/PDP1/pdp1_clk.c new file mode 100644 index 00000000..db2b7ad1 --- /dev/null +++ b/PDP1/pdp1_clk.c @@ -0,0 +1,125 @@ +/* pdp1_clk.c: PDP-1D clock simulator + + Copyright (c) 2006, 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"), + 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 Robert M Supnik shall not be + bused in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + clk PDP-1D clock + + Note that the clock is run at 1/8 of real speed (125Hz instead of 1Khz), to + provide for eventual implementation of idling. +*/ + +#include "pdp1_defs.h" + +#define CLK_HWRE_TPS 1000 /* hardware freq */ +#define CLK_TPS 125 /* sim freq */ +#define CLK_CNTS (CLK_HWRE_TPS / CLK_TPS) /* counts per tick */ +#define CLK_C1MIN (1000 * 60) /* counts per min */ +#define CLK_C32MS 32 /* counts per 32ms */ + +int32 clk32ms_sbs = 0; /* 32ms SBS level */ +int32 clk1min_sbs = 0; /* 1min SBS level */ +int32 clk_cntr = 0; +int32 tmxr_poll = 5000; + +extern int32 stop_inst; + +t_stat clk_svc (UNIT *uptr); +t_stat clk_reset (DEVICE *dptr); + +/* CLK data structures + + clk_dev CLK device descriptor + clk_unit CLK unit + clk_reg CLK register list +*/ + +UNIT clk_unit = { + UDATA (&clk_svc, 0, 0), 5000 + }; + +REG clk_reg[] = { + { ORDATA (CNTR, clk_cntr, 16) }, + { DRDATA (SBS32LVL, clk32ms_sbs, 4), REG_HRO }, + { DRDATA (SBS1MLVL, clk1min_sbs, 4), REG_HRO }, + { NULL } + }; + +MTAB clk_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "SBS32MSLVL", "SBS32MSLVL", + &dev_set_sbs, &dev_show_sbs, (void *) &clk32ms_sbs }, + { MTAB_XTD|MTAB_VDV, 0, "SBS1MINLVL", "SBS1MINLVL", + &dev_set_sbs, &dev_show_sbs, (void *) &clk1min_sbs }, + { 0 } + }; + +DEVICE clk_dev = { + "CLK", &clk_unit, clk_reg, clk_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &clk_reset, + NULL, NULL, NULL, + NULL, DEV_DISABLE | DEV_DIS + }; + +/* Clock IOT routine */ + +int32 clk (int32 inst, int32 dev, int32 dat) +{ +int32 used, incr; + +if (clk_dev.flags & DEV_DIS) /* disabled? */ + return (stop_inst << IOT_V_REASON) | dat; /* illegal inst */ +used = tmxr_poll - (sim_is_active (&clk_unit) - 1); +incr = (used * CLK_CNTS) / tmxr_poll; +return clk_cntr + incr; +} + +/* Unit service, generate appropriate interrupts */ + +t_stat clk_svc (UNIT *uptr) +{ +if (clk_dev.flags & DEV_DIS) return SCPE_OK; /* disabled? */ +tmxr_poll = sim_rtcn_calb (CLK_TPS, TMR_CLK); /* calibrate clock */ +sim_activate (&clk_unit, tmxr_poll); /* reactivate unit */ +clk_cntr = clk_cntr + CLK_CNTS; /* incr counter */ +if ((clk_cntr % CLK_C32MS) == 0) /* 32ms interval? */ + dev_req_int (clk32ms_sbs); /* req intr */ +if (clk_cntr >= CLK_C1MIN) { /* 1min interval? */ + dev_req_int (clk1min_sbs); /* req intr */ + clk_cntr = 0; /* reset counter */ + } +return SCPE_OK; +} + +/* Reset routine */ + +t_stat clk_reset (DEVICE *dptr) +{ +if (clk_dev.flags & DEV_DIS) sim_cancel (&clk_unit); /* disabled? */ +else { + tmxr_poll = sim_rtcn_init (clk_unit.wait, TMR_CLK); + sim_activate_abs (&clk_unit, tmxr_poll); /* activate unit */ + } +clk_cntr = 0; /* clear counter */ +return SCPE_OK; +} diff --git a/PDP1/pdp1_cpu.c b/PDP1/pdp1_cpu.c index 63c71e37..f4c6a8d9 100644 --- a/PDP1/pdp1_cpu.c +++ b/PDP1/pdp1_cpu.c @@ -25,6 +25,7 @@ cpu PDP-1 central processor + 28-Dec-06 RMS Added 16-channel SBS support, PDP-1D support 28-Jun-06 RMS Fixed bugs in MUS and DIV 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) 16-Aug-05 RMS Fixed C++ declaration and cast problems @@ -55,23 +56,38 @@ IOSTA I/O status register SBS<0:2> sequence break flip flops IOH I/O halt flip flop - IOS I/O syncronizer (completion) flip flop + IOS I/O synchronizer (completion) flip flop EXTM extend mode PF<1:6> program flags SS<1:6> sense switches TW<0:17> test word (switch register) + The 16-channel sequence break system adds additional state: + + sbs_req<0:15> interrupt requests + sbs_enb<0:15> enabled levels + sbs_act<0:15> active levels + + The PDP-1D adds additional state: + + L link (SN 45 only) + RNG ring mode + RM restrict mode + RMASK restrict mode mask + RNAME rename table (SN 45 only) + RTB restict mode trap buffer (SN 45 only) + Questions: cks: which bits are line printer print done and space done? cks: is there a bit for sequence break enabled (yes, according - to the 1963 Handbook) + to the 1963 Handbook) sbs: do sequence breaks accumulate while the system is disabled - (yes, according to the Maintenance Manual) + (yes, according to the Maintenance Manual) - The PDP-1 has six instruction formats: memory reference, skips, - shifts, load immediate, I/O transfer, and operate. The memory - reference format is: + The PDP-1 has seven instruction formats: memory reference, skips, + shifts, load immediate, I/O transfer, operate, and (PDP-1D) special. + The memory reference format is: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ @@ -85,8 +101,8 @@ 04 IOR AC = AC | M[MA] 06 XOR AC = AC ^ M[MA] 10 XCT M[MA] is executed as an instruction - 12 - 14 + 12 LCH load character (PDP-1D) + 14 DCH store character (PDP-1D) 16 0 CAL M[100] = AC, AC = PC, PC = 101 16 1 JDA M[MA] = AC, AC = PC, PC = MA + 1 20 LAC AC = M[MA] @@ -96,7 +112,7 @@ 30 DIP M[MA]<0:5> = AC<0:5> 32 DIO M[MA] = IO 34 DZM M[MA] = 0 - 36 + 36 TAD L'AC = AC + M[MA] + L 40 ADD AC = AC + M[MA] 42 SUB AC = AC - M[MA] 44 IDX AC = M[MA] = M[MA] + 1 @@ -121,15 +137,16 @@ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | 1 1 0 1 0| | | | | | | | | | | | | | skip +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | | | | | | \______/ \______/ - | | | | | | | | - | | | | | | | +---- program flags - | | | | | | +------------- sense switches - | | | | | +------------------- AC == 0 - | | | | +---------------------- AC >= 0 - | | | +------------------------- AC < 0 - | | +---------------------------- OV == 0 - | +------------------------------- IO >= 0 + | | | | | | | \______/ \______/ + | | | | | | | | | + | | | | | | | | +---- program flags + | | | | | | | +------------- sense switches + | | | | | | +------------------- AC == 0 + | | | | | +---------------------- AC >= 0 + | | | | +------------------------- AC < 0 + | | | +---------------------------- OV == 0 + | | +------------------------------- IO >= 0 + | +---------------------------------- IO != 0 (PDP-1D) +------------------------------------- invert skip The shift format is: @@ -164,24 +181,48 @@ W bit specifies whether the CPU waits for completion, the C bit whether a completion pulse will be returned from the device. - The operate format is: + The special operate format (PDP-1D) is: + + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | 1 1 1 1 0| | | | | | | | | | | | | | special + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | | | | | | | | | | | + | | | | | | | | | | +------- CML (3) + | | | | | | | | | +---------- CLL (1) + | | | | | | | | +------------- SZL (1) + | | | | | | | +---------------- SCF (1) + | | | | | | +------------------- SCI (1) + | | | | | +---------------------- SCM (2) + | | | | +------------------------- IDA (3) + | | | +---------------------------- IDC (4) + | | +------------------------------- IFI (2) + | +---------------------------------- IIF (2) + +------------------------------------- reverse skip + + The special operate instruction can be microprogrammed. + + The standard operate format is: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | 1 1 1 1 1| | | | | | | | | | | | | | operate +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | | | | | | | \______/ - | | | | | | | | - | | | | | | | +---- PF select - | | | | | | +---------- clear/set PF - | | | | | +------------------- or PC - | | | | +---------------------- clear AC - | | | +------------------------- halt - | | +---------------------------- CMA - | +------------------------------- or TW - +---------------------------------- clear IO + | | | | | | | | | | \______/ + | | | | | | | | | | | + | | | | | | | | | | +---- PF select + | | | | | | | | | +---------- clear/set PF + | | | | | | | | +------------- LIA (PDP-1D) + | | | | | | | +---------------- LAI (PDP-1D) + | | | | | | +------------------- or PC + | | | | | +---------------------- CLA + | | | | +------------------------- halt + | | | +---------------------------- CMA + | | +------------------------------- or TW + | +---------------------------------- CLI + +------------------------------------- CMI (PDP-1D) - The operate instruction can be microprogrammed. + The standard operate instruction can be microprogrammed. This routine is the instruction decode routine for the PDP-1. It is called from the simulator control program to execute @@ -204,7 +245,10 @@ PDP-1 has a single break request (flop b2, here sbs). If sequence breaks are enabled (flop sbm, here sbs), and one is not already in progress (flop b4, here sbs), - a sequence break occurs. + a sequence break occurs. With a 16-channel sequence break + system, the PDP-1 has 16 request flops (sbs_req), 16 enable + flops (sbs_enb), and 16 active flops (sbs_act). It also has + 16 synchronizer flops, which are not needed in simulation. 3. Arithmetic. The PDP-1 is a 1's complement system. In 1's complement arithmetic, a negative number is represented by the @@ -225,8 +269,14 @@ #define PCQ_MASK (PCQ_SIZE - 1) #define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC #define UNIT_V_MDV (UNIT_V_UF + 0) /* mul/div */ -#define UNIT_V_MSIZE (UNIT_V_UF + 1) /* dummy mask */ +#define UNIT_V_SBS (UNIT_V_UF + 1) +#define UNIT_V_1D (UNIT_V_UF + 2) +#define UNIT_V_1D45 (UNIT_V_UF + 3) +#define UNIT_V_MSIZE (UNIT_V_UF + 4) /* dummy mask */ #define UNIT_MDV (1 << UNIT_V_MDV) +#define UNIT_SBS (1 << UNIT_V_SBS) +#define UNIT_1D (1 << UNIT_V_1D) +#define UNIT_1D45 (1 << UNIT_V_1D45) #define UNIT_MSIZE (1 << UNIT_V_MSIZE) #define HIST_PC 0x40000000 @@ -234,6 +284,10 @@ #define HIST_MIN 64 #define HIST_MAX 65536 +#define MA_GETBNK(x) ((cpu_unit.flags & UNIT_1D45)? \ + (((x) >> RM45_V_BNK) & RM45_M_BNK): \ + (((x) >> RM48_V_BNK) & RM48_M_BNK)) + typedef struct { uint32 pc; uint32 ir; @@ -247,6 +301,8 @@ int32 M[MAXMEMSIZE] = { 0 }; /* memory */ int32 AC = 0; /* AC */ int32 IO = 0; /* IO */ int32 PC = 0; /* PC */ +int32 MA = 0; /* MA */ +int32 MB = 0; /* MB */ int32 OV = 0; /* overflow */ int32 SS = 0; /* sense switches */ int32 PF = 0; /* program flags */ @@ -254,21 +310,28 @@ int32 TA = 0; /* address switches */ int32 TW = 0; /* test word */ int32 iosta = 0; /* status reg */ int32 sbs = 0; /* sequence break */ -int32 sbs_init = 0; /* seq break startup */ +int32 sbs_init = 0; /* seq break start */ int32 ioh = 0; /* I/O halt */ int32 ios = 0; /* I/O syncronizer */ -int32 cpls = 0; /* pending completions */ +int32 cpls = 0; /* pending compl */ +int32 sbs_req = 0; /* sbs requests */ +int32 sbs_enb = 0; /* sbs enabled */ +int32 sbs_act = 0; /* sbs active */ int32 extm = 0; /* ext mem mode */ +int32 rm = 0; /* restrict mode */ +int32 rmask = 0; /* restrict mask */ +int32 rname[RN45_SIZE]; /* rename table */ +int32 rtb = 0; /* restr trap buf */ int32 extm_init = 0; /* ext mem startup */ -int32 stop_inst = 0; /* stop on rsrv inst */ -int32 xct_max = 16; /* nested XCT limit */ -int32 ind_max = 16; /* nested ind limit */ +int32 stop_inst = 0; /* stop rsrv inst */ +int32 xct_max = 16; /* XCT limit */ +int32 ind_max = 16; /* ind limit */ uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ int32 pcq_p = 0; /* PC queue ptr */ REG *pcq_r = NULL; /* PC queue reg ptr */ int32 hst_p = 0; /* history pointer */ int32 hst_lnt = 0; /* history length */ -InstHistory *hst = NULL; /* instruction history */ +InstHistory *hst = NULL; /* inst history */ extern UNIT *sim_clock_queue; extern int32 sim_int_char; @@ -279,7 +342,16 @@ 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); t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_set_1d (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat Ea (int32 IR); +t_stat Ea_ch (int32 IR, int32 *byte_num); +int32 inc_bp (int32 bp); +t_stat set_rmv (int32 code); +int32 sbs_eval (void); +int32 sbs_ffo (int32 mask); +t_stat Read (void); +t_stat Write (void); extern int32 ptr (int32 inst, int32 dev, int32 dat); extern int32 ptp (int32 inst, int32 dev, int32 dat); @@ -288,8 +360,10 @@ extern int32 tto (int32 inst, int32 dev, int32 dat); extern int32 lpt (int32 inst, int32 dev, int32 dat); extern int32 dt (int32 inst, int32 dev, int32 dat); extern int32 drm (int32 inst, int32 dev, int32 dat); +extern int32 clk (int32 inst, int32 dev, int32 dat); +extern int32 dcs (int32 inst, int32 dev, int32 dat); -int32 sc_map[512] = { +const int32 sc_map[512] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, /* 00000xxxx */ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 00001xxxx */ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 00010xxxx */ @@ -324,6 +398,27 @@ int32 sc_map[512] = { 5, 6, 6, 7, 6, 7, 7, 8, 6, 7, 7, 8, 7, 8, 8, 9 /* 11111xxxx */ }; +const int32 ffo_map[256] = { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + +const int32 byt_shf[4] = { 0, 0, 6, 12 }; + /* CPU data structures cpu_dev CPU device descriptor @@ -338,19 +433,30 @@ REG cpu_reg[] = { { ORDATA (PC, PC, ASIZE) }, { ORDATA (AC, AC, 18) }, { ORDATA (IO, IO, 18) }, + { ORDATA (MA, MA, 16) }, + { ORDATA (MB, MB, 18) }, { FLDATA (OV, OV, 0) }, - { ORDATA (PF, PF, 6) }, + { ORDATA (PF, PF, 8) }, { ORDATA (SS, SS, 6) }, { ORDATA (TA, TA, ASIZE) }, { ORDATA (TW, TW, 18) }, { FLDATA (EXTM, extm, 0) }, - { ORDATA (IOSTA, iosta, 18), REG_RO }, + { FLDATA (RNGM, PF, PF_V_RNG) }, + { FLDATA (L, PF, PF_V_L) }, + { FLDATA (RM, rm, 0) }, + { ORDATA (RMASK, rmask, 18) }, + { ORDATA (RTB, rtb, 18) }, + { BRDATA (RNAME, rname, 8, 2, RN45_SIZE) }, { FLDATA (SBON, sbs, SB_V_ON) }, { FLDATA (SBRQ, sbs, SB_V_RQ) }, { FLDATA (SBIP, sbs, SB_V_IP) }, + { ORDATA (SBSREQ, sbs_req, 16) }, + { ORDATA (SBSENB, sbs_enb, 16) }, + { ORDATA (SBSACT, sbs_act, 16) }, + { ORDATA (IOSTA, iosta, 18), REG_RO }, + { ORDATA (CPLS, cpls, 6) }, { FLDATA (IOH, ioh, 0) }, { FLDATA (IOS, ios, 0) }, - { ORDATA (CPLS, cpls, 6) }, { BRDATA (PCQ, pcq, 8, ASIZE, PCQ_SIZE), REG_RO+REG_CIRC }, { ORDATA (PCQP, pcq_p, 6), REG_HRO }, { FLDATA (STOP_INST, stop_inst, 0) }, @@ -363,8 +469,13 @@ REG cpu_reg[] = { }; MTAB cpu_mod[] = { + { UNIT_1D+UNIT_1D45, 0, "standard CPU", "PDP1C" }, + { UNIT_1D+UNIT_1D45, UNIT_1D, "PDP-1D #48", "PDP1D48", &cpu_set_1d }, + { UNIT_1D+UNIT_1D45, UNIT_1D+UNIT_1D45, "PDP1D #45", "PDP1D45", &cpu_set_1d }, { UNIT_MDV, UNIT_MDV, "multiply/divide", "MDV", NULL }, { UNIT_MDV, 0, "no multiply/divide", "NOMDV", NULL }, + { UNIT_SBS, UNIT_SBS, "SBS", "SBS", NULL }, + { UNIT_SBS, 0, "no SBS", "NOSBS", 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 }, @@ -391,18 +502,39 @@ DEVICE cpu_dev = { t_stat sim_instr (void) { extern int32 sim_interval; -int32 IR, MA, op, i, t, xct_count; -int32 sign, signd, v; -int32 dev, io_data, sc, skip; +int32 IR, op, i, t, xct_count; +int32 sign, signd, v, sbs_lvl, byno; +int32 dev, pulse, io_data, sc, skip; t_stat reason; static int32 fs_test[8] = { - 0, 040, 020, 010, 04, 02, 01, 077 + 0, PF_SS_1, PF_SS_2, PF_SS_3, + PF_SS_4, PF_SS_5, PF_SS_6, PF_SS_ALL }; #define EPC_WORD ((OV << 17) | (extm << 16) | PC) #define INCR_ADDR(x) (((x) & EPCMASK) | (((x) + 1) & DAMASK)) #define DECR_ADDR(x) (((x) & EPCMASK) | (((x) - 1) & DAMASK)) -#define ABS(x) ((x) ^ (((x) & 0400000)? 0777777: 0)) +#define ABS(x) ((x) ^ (((x) & SIGN)? DMASK: 0)) + +if (cpu_unit.flags & UNIT_1D) { /* PDP-1D? */ + cpu_unit.flags |= UNIT_SBS|UNIT_MDV; /* 16-chan SBS, mdv */ + if (!(cpu_unit.flags & UNIT_1D45)) { /* SN 48? */ + PF &= ~PF_L; /* no link */ + rtb = 0; /* no RTB */ + for (i = 0; i < RN45_SIZE; i++) rname[i] = i; /* no rename */ + } + } +else { /* standard PDP-1 */ + PF &= ~(PF_L|PF_RNG); /* no link, ring */ + rm = 0; /* no restrict mode */ + rtb = 0; /* no RTB */ + for (i = 0; i < RN45_SIZE; i++) rname[i] = i; /* no rename */ + } +if (cpu_unit.flags & UNIT_SBS) { /* 16-chan SBS? */ + sbs = sbs & SB_ON; /* yes, only SB ON */ + sbs_lvl = sbs_eval (); /* eval SBS system */ + } +else sbs_lvl = sbs_req = sbs_enb = sbs_lvl = 0; /* no, clr SBS sys */ /* Main instruction fetch/decode loop: check events and interrupts */ @@ -411,15 +543,33 @@ while (reason == 0) { /* loop until halted */ if (sim_interval <= 0) { /* check clock queue */ if (reason = sim_process_event ()) break; + sbs_lvl = sbs_eval (); /* eval sbs system */ } - if (sbs == (SB_ON | SB_RQ)) { /* interrupt? */ - sbs = SB_ON | SB_IP; /* set in prog flag */ + if ((cpu_unit.flags & UNIT_SBS)? /* test interrupt */ + ((sbs & SB_ON) && sbs_lvl): /* 16-chan SBS? */ + (sbs == (SB_ON | SB_RQ))) { /* 1-chan SBS? */ + if (cpu_unit.flags & UNIT_SBS) { /* 16-chan intr */ + int32 lvl = sbs_lvl - 1; /* get level */ + MA = lvl << 2; /* status block */ + sbs_req &= ~SBS_MASK (lvl); /* clr lvl request */ + sbs_act |= SBS_MASK (lvl); /* set lvl active */ + sbs_lvl = sbs_eval (); /* re-eval SBS */ + } + else { /* 1-chan intr */ + MA = 0; /* always level 0 */ + sbs = SB_ON | SB_IP; /* set in prog flag */ + } PCQ_ENTRY; /* save old PC */ - M[0] = AC; /* save state */ - M[1] = EPC_WORD; - M[2] = IO; - PC = 3; /* fetch next from 3 */ + MB = AC; /* save AC */ + Write (); + MA = MA + 1; + MB = EPC_WORD; /* save OV'EXT'PC */ + Write (); + MA = MA + 1; + MB = IO; /* save IO */ + Write (); + PC = MA + 1; /* PC = block + 3 */ extm = 0; /* extend off */ OV = 0; /* clear overflow */ } @@ -431,67 +581,43 @@ while (reason == 0) { /* loop until halted */ /* Fetch, decode instruction */ - MA = PC; /* PC to MA */ - IR = M[MA]; /* fetch instruction */ + MA = PC; + if (Read ()) break; /* fetch inst */ + IR = MB; /* save in IR */ PC = INCR_ADDR (PC); /* increment PC */ - xct_count = 0; /* track nested XCT's */ + xct_count = 0; /* track XCT's */ sim_interval = sim_interval - 1; if (hst_lnt) { /* history enabled? */ hst_p = (hst_p + 1); /* next entry */ if (hst_p >= hst_lnt) hst_p = 0; - hst[hst_p].pc = MA | HIST_PC; /* save PC, IR, LAC, MQ */ + hst[hst_p].pc = MA | HIST_PC; /* save state */ hst[hst_p].ir = IR; hst[hst_p].ovac = (OV << HIST_V_SHF) | AC; hst[hst_p].pfio = (PF << HIST_V_SHF) | IO; } xct_instr: /* label for XCT */ - if ((IR == (OP_JMP+IA+1)) && ((MA & EPCMASK) == 0) && (sbs & SB_ON)) { - sbs = sbs & ~SB_IP; /* seq debreak */ - PCQ_ENTRY; /* save old PC */ - OV = (M[1] >> 17) & 1; /* restore OV */ - extm = (M[1] >> 16) & 1; /* restore ext mode */ - PC = M[1] & AMASK; /* JMP I 1 */ - continue; - } - op = ((IR >> 13) & 037); /* get opcode */ - if ((op < 032) && (op != 007)) { /* mem ref instr */ - MA = (MA & EPCMASK) | (IR & DAMASK); /* direct address */ - if (IR & IA) { /* indirect addr? */ - if (extm) MA = M[MA] & AMASK; /* if ext, one level */ - else { /* multi-level */ - for (i = 0; i < ind_max; i++) { /* count indirects */ - t = M[MA]; /* get indirect word */ - MA = (MA & EPCMASK) | (t & DAMASK); - if ((t & IA) == 0) break; - } - if (i >= ind_max) { /* indirect loop? */ - reason = STOP_IND; - break; - } - } /* end else !extm */ - } /* end if indirect */ - if (hst_p) { /* history enabled? */ - hst[hst_p].ea = MA; - hst[hst_p].opnd = M[MA]; - } - } - switch (op) { /* decode IR<0:4> */ /* Logical, load, store instructions */ case 001: /* AND */ - AC = AC & M[MA]; + if (reason = Ea (IR)) break; /* MA <- eff addr */ + if (reason = Read ()) break; /* MB <- data */ + AC = AC & MB; break; case 002: /* IOR */ - AC = AC | M[MA]; + if (reason = Ea (IR)) break; /* MA <- eff addr */ + if (reason = Read ()) break; /* MB <- data */ + AC = AC | MB; break; case 003: /* XOR */ - AC = AC ^ M[MA]; + if (reason = Ea (IR)) break; /* MA <- eff addr */ + if (reason = Read ()) break; /* MB <- data */ + AC = AC ^ MB; break; case 004: /* XCT */ @@ -499,44 +625,85 @@ while (reason == 0) { /* loop until halted */ reason = STOP_XCT; break; } + if (reason = Ea (IR)) break; /* MA <- eff addr */ + if (reason = Read ()) break; /* MB <- data */ xct_count = xct_count + 1; /* count XCT's */ - IR = M[MA]; /* get instruction */ + IR = MB; /* get instruction */ goto xct_instr; /* go execute */ + case 005: /* LCH */ + if (cpu_unit.flags & UNIT_1D) { /* PDP-1D? */ + if (reason = Ea_ch (IR, &byno)) break; /* MA <- eff addr */ + if (reason = Read ()) break; /* MB <- data */ + AC = (MB << byt_shf[byno]) & 0770000; /* extract byte */ + } + else reason = stop_inst; /* no, illegal */ + break; + + case 006: /* DCH */ + if (cpu_unit.flags & UNIT_1D) { /* PDP-1D? */ + if (reason = Ea_ch (IR, &byno)) break; /* MA <- eff addr */ + if (reason = Read ()) break; /* MB <- data */ + MB = (MB & ~(0770000 >> byt_shf[byno])) | /* insert byte */ + ((AC & 0770000) >> byt_shf[byno]); + Write (); /* rewrite */ + AC = ((AC << 6) | (AC >> 12)) & DMASK; /* rot AC left 6 */ + } + else reason = stop_inst; /* no, illegal */ + break; + case 007: /* CAL, JDA */ MA = (PC & EPCMASK) | ((IR & IA)? (IR & DAMASK): 0100); + if (hst_p) hst[hst_p].ea = MA; /* history enabled? */ PCQ_ENTRY; - M[MA] = AC; + MB = AC; /* save AC */ AC = EPC_WORD; PC = INCR_ADDR (MA); + reason = Write (); break; case 010: /* LAC */ - AC = M[MA]; + if (reason = Ea (IR)) break; /* MA <- eff addr */ + if (reason = Read ()) break; /* MB <- data */ + AC = MB; break; case 011: /* LIO */ - IO = M[MA]; + if (reason = Ea (IR)) break; /* MA <- eff addr */ + if (reason = Read ()) break; /* MB <- data */ + IO = MB; break; case 012: /* DAC */ - if (MEM_ADDR_OK (MA)) M[MA] = AC; + if (reason = Ea (IR)) break; /* MA <- eff addr */ + MB = AC; + reason = Write (); break; case 013: /* DAP */ - if (MEM_ADDR_OK (MA)) M[MA] = (AC & DAMASK) | (M[MA] & ~DAMASK); + if (reason = Ea (IR)) break; /* MA <- eff addr */ + if (reason = Read ()) break; /* MB <- data */ + MB = (AC & DAMASK) | (MB & ~DAMASK); + reason = Write (); break; case 014: /* DIP */ - if (MEM_ADDR_OK (MA)) M[MA] = (AC & ~DAMASK) | (M[MA] & DAMASK); + if (reason = Ea (IR)) break; /* MA <- eff addr */ + if (reason = Read ()) break; /* MB <- data */ + MB = (AC & ~DAMASK) | (MB & DAMASK); + reason = Write (); break; case 015: /* DIO */ - if (MEM_ADDR_OK (MA)) M[MA] = IO; + if (reason = Ea (IR)) break; /* MA <- eff addr */ + MB = IO; + reason = Write (); break; case 016: /* DZM */ - if (MEM_ADDR_OK (MA)) M[MA] = 0; + if (reason = Ea (IR)) break; /* MA <- eff addr */ + MB = 0; + reason = Write (); break; /* Add, subtract, control @@ -553,52 +720,100 @@ while (reason == 0) { /* loop until halted */ 3. end around carry propagate 4. overflow check 5. complement AC - Because no -0 check is done, (-0) - (+0) yields a result of -0 -*/ + Because no -0 check is done, (-0) - (+0) yields a result of -0 */ + + case 017: /* TAD */ + if (cpu_unit.flags & UNIT_1D) { /* PDP-1D? */ + if (reason = Ea (IR)) break; /* MA <- eff addr */ + if (reason = Read ()) break; /* MB <- data */ + AC = AC + MB + ((PF & PF_L)? 1: 0); /* AC + opnd + L */ + if (AC > DMASK) PF = PF | PF_L; /* carry? set L */ + else PF = PF & ~PF_L; /* no, clear L */ + AC = AC & DMASK; /* mask AC */ + } + else reason = stop_inst; /* no, illegal */ + break; case 020: /* ADD */ + if (reason = Ea (IR)) break; /* MA <- eff addr */ + if (reason = Read ()) break; /* MB <- data */ t = AC; - AC = AC + M[MA]; - if (AC > 0777777) AC = (AC + 1) & 0777777; /* end around carry */ - if (((~t ^ M[MA]) & (t ^ AC)) & 0400000) OV = 1; - if (AC == 0777777) AC = 0; /* minus 0 cleanup */ + AC = AC + MB; + if (AC > 0777777) AC = (AC + 1) & DMASK; /* end around carry */ + if (((~t ^ MB) & (t ^ AC)) & SIGN) OV = 1; + if (AC == DMASK) AC = 0; /* minus 0 cleanup */ break; case 021: /* SUB */ - t = AC ^ 0777777; /* complement AC */ - AC = t + M[MA]; /* -AC + MB */ - if (AC > 0777777) AC = (AC + 1) & 0777777; /* end around carry */ - if (((~t ^ M[MA]) & (t ^ AC)) & 0400000) OV = 1; - AC = AC ^ 0777777; /* recomplement AC */ + if (reason = Ea (IR)) break; /* MA <- eff addr */ + if (reason = Read ()) break; /* MB <- data */ + t = AC ^ DMASK; /* complement AC */ + AC = t + MB; /* -AC + MB */ + if (AC > DMASK) AC = (AC + 1) & DMASK; /* end around carry */ + if (((~t ^ MB) & (t ^ AC)) & SIGN) OV = 1; + AC = AC ^ DMASK; /* recomplement AC */ break; case 022: /* IDX */ - AC = M[MA] + 1; - if (AC >= 0777777) AC = (AC + 1) & 0777777; - if (MEM_ADDR_OK (MA)) M[MA] = AC; + if (reason = Ea (IR)) break; /* MA <- eff addr */ + if (reason = Read ()) break; /* MB <- data */ + AC = MB + 1; + if (AC >= DMASK) AC = (AC + 1) & DMASK; + MB = AC; + reason = Write (); break; case 023: /* ISP */ - AC = M[MA] + 1; - if (AC >= 0777777) AC = (AC + 1) & 0777777; - if (MEM_ADDR_OK (MA)) M[MA] = AC; - if (AC < 0400000) PC = INCR_ADDR (PC); + if (reason = Ea (IR)) break; /* MA <- eff addr */ + if (reason = Read ()) break; /* MB <- data */ + AC = MB + 1; + if (AC >= DMASK) AC = (AC + 1) & DMASK; + MB = AC; + if (!(AC & SIGN)) PC = INCR_ADDR (PC); + reason = Write (); break; case 024: /* SAD */ - if (AC != M[MA]) PC = INCR_ADDR (PC); + if (reason = Ea (IR)) break; /* MA <- eff addr */ + if (reason = Read ()) break; /* MB <- data */ + if (AC != MB) PC = INCR_ADDR (PC); break; case 025: /* SAS */ - if (AC == M[MA]) PC = INCR_ADDR (PC); + if (reason = Ea (IR)) break; /* MA <- eff addr */ + if (reason = Read ()) break; /* MB <- data */ + if (AC == MB) PC = INCR_ADDR (PC); break; case 030: /* JMP */ - PCQ_ENTRY; - PC = MA; + if (sbs && /* SBS enabled? */ + ((PC & EPCMASK) == 0) && /* in bank 0? */ + ((IR & (IA|07703)) == (IA|00001)) && /* jmp i 00x1/5? */ + ((cpu_unit.flags & UNIT_SBS) || /* 16-chan SBS or */ + ((IR & 00074) == 0))) { /* jmp i 0001? */ + if (cpu_unit.flags & UNIT_SBS) { /* 16-chan SBS dbk? */ + int32 lvl = (IR >> 2) & SBS_LVL_MASK; /* lvl = MA<14:15> */ + sbs_act &= ~SBS_MASK (lvl); /* clr level active */ + sbs_lvl = sbs_eval (); /* eval SBS system */ + } + else sbs = sbs & ~SB_IP; /* 1-chan dbk */ + PCQ_ENTRY; /* save old PC */ + MA = IR & DAMASK; /* ind addr */ + Read (); /* eff addr word */ + OV = (MB >> 17) & 1; /* restore OV */ + extm = (MB >> 16) & 1; /* restore ext mode */ + PC = MB & AMASK; /* jmp i 00x1/5 */ + if (hst_p) hst[hst_p].ea = PC; /* history enabled? */ + } + else { /* normal JMP */ + if (reason = Ea (IR)) break; /* MA <- eff addr */ + PCQ_ENTRY; + PC = MA; + } break; case 031: /* JSP */ + if (reason = Ea (IR)) break; /* MA <- eff addr */ AC = EPC_WORD; PCQ_ENTRY; PC = MA; @@ -615,75 +830,77 @@ while (reason == 0) { /* loop until halted */ */ case 026: /* MUL */ + if (reason = Ea (IR)) break; /* MA <- eff addr */ + if (reason = Read ()) break; /* MB <- data */ if (cpu_unit.flags & UNIT_MDV) { /* hardware? */ - sign = AC ^ M[MA]; /* result sign */ + sign = AC ^ MB; /* result sign */ IO = ABS (AC); /* IO = |AC| */ - v = ABS (M[MA]); /* v = |mpy| */ + v = ABS (MB); /* v = |mpy| */ for (i = AC = 0; i < 17; i++) { if (IO & 1) AC = AC + v; IO = (IO >> 1) | ((AC & 1) << 17); AC = AC >> 1; } - if ((sign & 0400000) && (AC | IO)) { /* negative, > 0? */ - AC = AC ^ 0777777; - IO = IO ^ 0777777; + if ((sign & SIGN) && (AC | IO)) { /* negative, > 0? */ + AC = AC ^ DMASK; + IO = IO ^ DMASK; } } else { /* multiply step */ - if (IO & 1) AC = AC + M[MA]; - if (AC > 0777777) AC = (AC + 1) & 0777777; -// if (AC == 0777777) AC = 0; + if (IO & 1) AC = AC + MB; + if (AC > DMASK) AC = (AC + 1) & DMASK; IO = (IO >> 1) | ((AC & 1) << 17); AC = AC >> 1; } break; case 027: /* DIV */ + if (reason = Ea (IR)) break; /* MA <- eff addr */ + if (reason = Read ()) break; /* MB <- data */ if (cpu_unit.flags & UNIT_MDV) { /* hardware */ - sign = AC ^ M[MA]; /* result sign */ + sign = AC ^ MB; /* result sign */ signd = AC; /* remainder sign */ - v = ABS (M[MA]); /* v = |divr| */ + v = ABS (MB); /* v = |divr| */ if (ABS (AC) >= v) break; /* overflow? */ - if (AC & 0400000) { - AC = AC ^ 0777777; /* AC'IO = |AC'IO| */ - IO = IO ^ 0777777; + if (AC & SIGN) { + AC = AC ^ DMASK; /* AC'IO = |AC'IO| */ + IO = IO ^ DMASK; } for (i = t = 0; i < 18; i++) { - if (t) AC = (AC + v) & 0777777; - else AC = (AC - v) & 0777777; + if (t) AC = (AC + v) & DMASK; + else AC = (AC - v) & DMASK; t = AC >> 17; - if (i != 17) AC = ((AC << 1) | (IO >> 17)) & 0777777; + if (i != 17) AC = ((AC << 1) | (IO >> 17)) & DMASK; IO = ((IO << 1) | (t ^ 1)) & 0777777; } - if (t) AC = (AC + v) & 0777777; /* correct remainder */ - t = ((signd & 0400000) && AC)? AC ^ 0777777: AC; - AC = ((sign & 0400000) && IO)? IO ^ 0777777: IO; + if (t) AC = (AC + v) & DMASK; /* fix remainder */ + t = ((signd & SIGN) && AC)? AC ^ DMASK: AC; + AC = ((sign & SIGN) && IO)? IO ^ DMASK: IO; IO = t; PC = INCR_ADDR (PC); /* skip */ } else { /* divide step */ t = AC >> 17; - AC = ((AC << 1) | (IO >> 17)) & 0777777; - IO = ((IO << 1) | (t ^ 1)) & 0777777; - if (IO & 1) AC = AC + (M[MA] ^ 0777777); - else AC = AC + M[MA] + 1; - if (AC > 0777777) AC = (AC + 1) & 0777777; - if (AC == 0777777) AC = 0; + AC = ((AC << 1) | (IO >> 17)) & DMASK; + IO = ((IO << 1) | (t ^ 1)) & DMASK; + if (IO & 1) AC = AC + (MB ^ DMASK); + else AC = AC + MB + 1; + if (AC > DMASK) AC = (AC + 1) & DMASK; + if (AC == DMASK) AC = 0; } break; -/* Skip and operate - - Operates execute in the order shown; there are no timing conflicts -*/ +/* Skips */ case 032: /* skip */ v = (IR >> 3) & 07; /* sense switches */ t = IR & 07; /* program flags */ - skip = (((IR & 02000) && (IO < 0400000)) || /* SPI */ + skip = (((cpu_unit.flags & UNIT_1D) && + (IR & 04000) && (IO != 0)) || /* SNI (PDP-1D) */ + ((IR & 02000) && !(IO & SIGN)) || /* SPI */ ((IR & 01000) && (OV == 0)) || /* SZO */ - ((IR & 00400) && (AC >= 0400000)) || /* SMA */ - ((IR & 00200) && (AC < 0400000)) || /* SPA */ + ((IR & 00400) && (AC & SIGN)) || /* SMA */ + ((IR & 00200) && !(AC & SIGN)) || /* SPA */ ((IR & 00100) && (AC == 0)) || /* SZA */ (v && ((SS & fs_test[v]) == 0)) || /* SZSn */ (t && ((PF & fs_test[t]) == 0))); /* SZFn */ @@ -692,18 +909,6 @@ while (reason == 0) { /* loop until halted */ if (IR & 01000) OV = 0; /* SOV clears OV */ break; - case 037: /* operate */ - if (IR & 04000) IO = 0; /* CLI */ - if (IR & 00200) AC = 0; /* CLA */ - if (IR & 02000) AC = AC | TW; /* LAT */ - if (IR & 00100) AC = AC | EPC_WORD; /* LAP */ - if (IR & 01000) AC = AC ^ 0777777; /* CMA */ - if (IR & 00400) reason = STOP_HALT; /* HALT */ - t = IR & 07; /* flag select */ - if (IR & 010) PF = PF | fs_test[t]; /* STFn */ - else PF = PF & ~fs_test[t]; /* CLFn */ - break; - /* Shifts */ case 033: @@ -711,72 +916,130 @@ while (reason == 0) { /* loop until halted */ switch ((IR >> 9) & 017) { /* case on IR<5:8> */ case 001: /* RAL */ - AC = ((AC << sc) | (AC >> (18 - sc))) & 0777777; + AC = ((AC << sc) | (AC >> (18 - sc))) & DMASK; break; case 002: /* RIL */ - IO = ((IO << sc) | (IO >> (18 - sc))) & 0777777; + IO = ((IO << sc) | (IO >> (18 - sc))) & DMASK; break; case 003: /* RCL */ t = AC; - AC = ((AC << sc) | (IO >> (18 - sc))) & 0777777; - IO = ((IO << sc) | (t >> (18 - sc))) & 0777777; + AC = ((AC << sc) | (IO >> (18 - sc))) & DMASK; + IO = ((IO << sc) | (t >> (18 - sc))) & DMASK; break; case 005: /* SAL */ - t = (AC & 0400000)? 0777777: 0; - AC = (AC & 0400000) | ((AC << sc) & 0377777) | + t = (AC & SIGN)? DMASK: 0; + AC = (AC & SIGN) | ((AC << sc) & 0377777) | (t >> (18 - sc)); break; case 006: /* SIL */ - t = (IO & 0400000)? 0777777: 0; - IO = (IO & 0400000) | ((IO << sc) & 0377777) | + t = (IO & SIGN)? DMASK: 0; + IO = (IO & SIGN) | ((IO << sc) & 0377777) | (t >> (18 - sc)); break; case 007: /* SCL */ - t = (AC & 0400000)? 0777777: 0; - AC = (AC & 0400000) | ((AC << sc) & 0377777) | + t = (AC & SIGN)? DMASK: 0; + AC = (AC & SIGN) | ((AC << sc) & 0377777) | (IO >> (18 - sc)); - IO = ((IO << sc) | (t >> (18 - sc))) & 0777777; + IO = ((IO << sc) | (t >> (18 - sc))) & DMASK; break; case 011: /* RAR */ - AC = ((AC >> sc) | (AC << (18 - sc))) & 0777777; + AC = ((AC >> sc) | (AC << (18 - sc))) & DMASK; break; case 012: /* RIR */ - IO = ((IO >> sc) | (IO << (18 - sc))) & 0777777; + IO = ((IO >> sc) | (IO << (18 - sc))) & DMASK; break; case 013: /* RCR */ t = IO; - IO = ((IO >> sc) | (AC << (18 - sc))) & 0777777; - AC = ((AC >> sc) | (t << (18 - sc))) & 0777777; + IO = ((IO >> sc) | (AC << (18 - sc))) & DMASK; + AC = ((AC >> sc) | (t << (18 - sc))) & DMASK; break; case 015: /* SAR */ - t = (AC & 0400000)? 0777777: 0; - AC = ((AC >> sc) | (t << (18 - sc))) & 0777777; + t = (AC & SIGN)? DMASK: 0; + AC = ((AC >> sc) | (t << (18 - sc))) & DMASK; break; case 016: /* SIR */ - t = (IO & 0400000)? 0777777: 0; - IO = ((IO >> sc) | (t << (18 - sc))) & 0777777; + t = (IO & SIGN)? DMASK: 0; + IO = ((IO >> sc) | (t << (18 - sc))) & DMASK; break; case 017: /* SCR */ - t = (AC & 0400000)? 0777777: 0; - IO = ((IO >> sc) | (AC << (18 - sc))) & 0777777; - AC = ((AC >> sc) | (t << (18 - sc))) & 0777777; + t = (AC & SIGN)? DMASK: 0; + IO = ((IO >> sc) | (AC << (18 - sc))) & DMASK; + AC = ((AC >> sc) | (t << (18 - sc))) & DMASK; break; default: /* undefined */ reason = stop_inst; break; - } /* end switch shifts */ + } /* end switch shf */ + break; + +/* Special operates (PDP-1D) - performed in order shown */ + + case 036: /* special */ + if (cpu_unit.flags & UNIT_1D) { /* PDP-1D? */ + if (IR & 000100) IO = 0; /* SCI */ + if (IR & 000040) PF = 0; /* SCF */ + if (cpu_unit.flags & UNIT_1D45) { /* SN 45? */ + if ((IR & 000020) && /* SZL/SNL? */ + (((PF & PF_L) == 0) == ((IR & IA) == 0))) + PC = INCR_ADDR (PC); + if (IR & 000010) PF = PF & ~PF_L; /* CLL */ + if (IR & 000200) { /* SCM */ + AC = (AC ^ DMASK) + ((PF & PF_L)? 1: 0); + if (AC > DMASK) PF = PF | PF_L; /* carry? set L */ + else PF = PF & ~PF_L; /* no, clear L */ + AC = AC & DMASK; /* mask AC */ + } + } + t = IO & PF_VR_ALL; + if (IR & 004000) IO = IO | PF; /* IIF */ + if (IR & 002000) PF = PF | t; /* IFI */ + if (cpu_unit.flags & UNIT_1D45) { /* SN 45? */ + if (IR & 000004) PF = PF ^ PF_L; /* CML */ + if (IR & 000400) /* IDA */ + AC = (PF & PF_RNG)? + (AC & 0777770) | ((AC + 1) & 07): + (AC + 1) & DMASK; + } + else PF = PF & ~PF_L; /* no link */ + if (IR & 01000) AC = inc_bp (AC); /* IDC */ + } + else reason = stop_inst; /* no, illegal */ + break; + +/* Operates - performed in the order shown */ + + case 037: /* operate */ + if (IR & 004000) IO = 0; /* CLI */ + if (IR & 000200) AC = 0; /* CLA */ + if (IR & 002000) AC = AC | TW; /* LAT */ + if (IR & 000100) AC = AC | EPC_WORD; /* LAP */ + if (IR & 001000) AC = AC ^ DMASK; /* CMA */ + if (cpu_unit.flags & UNIT_1D) { /* PDP-1D? */ + if (IR & 010000) IO = IO ^ DMASK; /* CMI */ + MB = IO; + if (IR & 000020) IO = AC; /* LIA */ + if (IR & 000040) AC = MB; /* LAI */ + } + t = IR & 07; /* flag select */ + if (IR & 010) PF = PF | fs_test[t]; /* STFn */ + else PF = PF & ~fs_test[t]; /* CLFn */ + if (IR & 000400) { /* HLT */ + if (rm && !sbs_act) /* restrict, ~brk? */ + reason = set_rmv (RTB_HLT); /* violation */ + else reason = STOP_HALT; /* no, halt */ + } break; /* IOT - The simulator behaves functionally like a real PDP-1 but does not @@ -795,18 +1058,22 @@ while (reason == 0) { /* loop until halted */ IOT is skipped. > If not set, I/O wait must start. IOH is set, the PC is backed up, and the IOT is executed. - On a real PDP-1, IOC is the I/O command enable and enables the IOT + - On a real PDP-1, IOC is the I/O command enable and enables the IOT pulses. In the simulator, the enabling of IOT pulses is done through code flow, and IOC is not explicitly simulated. */ case 035: + if (rm && !sbs_act) { /* restrict, ~brk? */ + reason = set_rmv (RTB_IOT); /* violation */ + break; + } if (IR & IO_WAIT) { /* wait? */ if (ioh) { /* I/O halt? */ if (ios) ioh = 0; /* comp pulse? done */ else { /* wait more */ PC = DECR_ADDR (PC); /* re-execute */ - if (cpls == 0) { /* any pending pulses? */ + if (cpls == 0) { /* pending pulses? */ reason = STOP_WAIT; /* no, CPU hangs */ break; } @@ -818,6 +1085,7 @@ while (reason == 0) { /* loop until halted */ PC = DECR_ADDR (PC); /* re-execute */ } dev = IR & 077; /* get dev addr */ + pulse = (IR >> 6) & 077; /* get pulse data */ io_data = IO; /* default data */ switch (dev) { /* case on dev */ @@ -845,14 +1113,63 @@ while (reason == 0) { /* loop until halted */ io_data = ptp (IR, dev, IO); break; + case 010: /* leave ring mode */ + if (cpu_unit.flags & UNIT_1D) PF = PF & ~PF_RNG; + else reason = stop_inst; + break; + + case 011: /* enter ring mode */ + if (cpu_unit.flags & UNIT_1D) PF = PF | PF_RNG; + else reason = stop_inst; + break; + + case 022: /* data comm sys */ + io_data = dcs (IR, dev, IO); + break; + + case 032: /* clock */ + io_data = clk (IR, dev, IO); + break; + case 033: /* check status */ io_data = iosta | ((sbs & SB_ON)? IOS_SQB: 0); break; + case 035: /* check trap buf */ + if (cpu_unit.flags & UNIT_1D45) { /* SN 45? */ + io_data = rtb; + rtb = 0; + } + else reason = stop_inst; + break; + case 045: /* line printer */ io_data = lpt (IR, dev, IO); break; + case 050: /* deact seq break */ + if (cpu_unit.flags & UNIT_SBS) + sbs_enb &= ~SBS_MASK (pulse & SBS_LVL_MASK); + else reason = stop_inst; + break; + + case 051: /* act seq break */ + if (cpu_unit.flags & UNIT_SBS) + sbs_enb |= SBS_MASK (pulse & SBS_LVL_MASK); + else reason = stop_inst; + break; + + case 052: /* start seq break */ + if (cpu_unit.flags & UNIT_SBS) + sbs_req |= SBS_MASK (pulse & SBS_LVL_MASK); + else reason = stop_inst; + break; + + case 053: /* clear all chan */ + if (cpu_unit.flags & UNIT_SBS) sbs_enb = 0; + else reason = stop_inst; + break; + case 054: /* seq brk off */ sbs = sbs & ~SB_ON; break; @@ -862,13 +1179,45 @@ while (reason == 0) { /* loop until halted */ break; case 056: /* clear seq brk */ - sbs = sbs & ~SB_IP; + sbs = 0; /* clear PI */ + sbs_req = 0; + sbs_enb = 0; + sbs_act = 0; break; - case 061: case 062: case 063: case 064: /* drum */ + case 061: case 062: case 063: /* drum */ io_data = drm (IR, dev, IO); break; + case 064: /* drum/leave rm */ + if (cpu_unit.flags & UNIT_1D) rm = 0; + else io_data = drm (IR, dev, IO); + break; + + case 065: /* enter rm */ + if (cpu_unit.flags & UNIT_1D) { + rm = 1; + rmask = IO; + } + else reason = stop_inst; + break; + + case 066: /* rename mem */ + if (cpu_unit.flags & UNIT_1D45) { /* SN45? */ + int32 from = (IR >> 9) & RM45_M_BNK; + int32 to = (IR >> 6) & RM45_M_BNK; + rname[from] = to; + } + else reason = stop_inst; + break; + + case 067: /* reset renaming */ + if (cpu_unit.flags & UNIT_1D45) { /* SN45 */ + for (i = 0; i < RN45_SIZE; i++) rname[i] = i; + } + else reason = stop_inst; + break; + case 074: /* extend mode */ extm = (IR >> 11) & 1; /* set from IR<6> */ break; @@ -878,29 +1227,214 @@ while (reason == 0) { /* loop until halted */ break; } /* end switch dev */ - IO = io_data & 0777777; + IO = io_data & DMASK; if (io_data & IOT_SKP) PC = INCR_ADDR (PC); /* skip? */ if (io_data >= IOT_REASON) reason = io_data >> IOT_V_REASON; + sbs_lvl = sbs_eval (); /* eval SBS system */ break; default: /* undefined */ - reason = STOP_RSRV; /* halt */ + if (rm && !sbs_act) /* restrict, ~brk? */ + reason = set_rmv (RTB_ILL); /* violation */ + else reason = STOP_RSRV; /* halt */ break; - } /* end switch opcode */ + } /* end switch op */ + + if (reason == ERR_RMV) { /* restrict viol? */ + sbs_req |= SBS_MASK (SBS_LVL_RMV); /* request break */ + sbs_lvl = sbs_eval (); /* re-eval SBS */ + reason = 0; /* continue */ + } } /* end while */ pcq_r->qptr = pcq_p; /* update pc q ptr */ return reason; } +/* Effective address routine for standard memory reference instructions */ + +t_stat Ea (int32 IR) +{ +int32 i; +t_stat r; + +MA = (PC & EPCMASK) | (IR & DAMASK); /* direct address */ +if (IR & IA) { /* indirect addr? */ + if (extm) { /* extend? */ + if (r = Read ()) return r; /* read; err? */ + MA = MB & AMASK; /* one level */ + } + else { /* multi-level */ + for (i = 0; i < ind_max; i++) { /* count indirects */ + if (r = Read ()) return r; /* get ind word */ + MA = (PC & EPCMASK) | (MB & DAMASK); + if ((MB & IA) == 0) break; + } + if (i >= ind_max) return STOP_IND; /* indirect loop? */ + } /* end else !extm */ + } /* end if indirect */ +if (hst_p) hst[hst_p].ea = MA; /* history enabled? */ +return SCPE_OK; +} + +/* Effective address routine for character instructions */ + +t_stat Ea_ch (int32 IR, int32 *bn) +{ +int32 i; +t_stat r; + +MA = (PC & EPCMASK) | (IR & DAMASK); /* direct address */ +if (extm) { /* extend? */ + if (r = Read ()) return r; /* read; err? */ + } +else { /* multi-level */ + for (i = 0; i < ind_max; i++) { /* count indirects */ + if (r = Read ()) return r; /* get ind word */ + if ((MB & IA) == 0) break; + MA = (PC & EPCMASK) | (MB & DAMASK); + } + if (i >= ind_max) return STOP_IND; /* indirect loop? */ + } /* end else !extm */ +if (IR & IA) { /* automatic mode? */ + if (rm & !sbs_act & ((MB & 0607777) == 0607777)) /* page cross? */ + return set_rmv (RTB_CHR); + MB = inc_bp (MB); /* incr byte ptr */ + Write (); /* rewrite */ + } +*bn = (MB >> 16) & 03; /* byte num */ +if (extm) MA = MB & AMASK; /* final ea */ +else MA = (PC & EPCMASK) | (MB & DAMASK); +if (hst_p) hst[hst_p].ea = MA; /* history enabled? */ +return SCPE_OK; +} + +/* Increment byte pointer, allowing for ring mode */ + +int32 inc_bp (int32 bp) +{ +bp = bp + (1 << 16); /* add to bit<1> */ +if (bp > DMASK) { /* carry out? */ + if (PF & PF_RNG) /* ring mode? */ + bp = (1 << 16) | (bp & 0177770) | ((bp + 1) & 07); + else bp = (1 << 16) | ((bp + 1) & AMASK); + } +return bp; +} + +/* Read and write memory */ + +t_stat Read (void) +{ +if (rm && !sbs_act) { /* restrict check? */ + int32 bnk = MA_GETBNK (MA); /* get bank */ + if ((rmask << bnk) & SIGN) return set_rmv (0); + } +MB = M[MA]; +if (hst_p) hst[hst_p].opnd = MB; /* history enabled? */ +return SCPE_OK; +} + +t_stat Write (void) +{ +if (hst_p) hst[hst_p].opnd = M[MA]; /* hist? old contents */ +if (rm && !sbs_act) { /* restrict check? */ + int32 bnk = MA_GETBNK (MA); /* get bank */ + if ((rmask << bnk) & SIGN) return set_rmv (0); + } +if (MEM_ADDR_OK (MA)) M[MA] = MB; +return SCPE_OK; +} + +/* Restrict mode trap */ + +t_stat set_rmv (int32 code) +{ +rtb = code | (MB & RTB_MB_MASK); +return ERR_RMV; +} + +/* Evaluate SBS system */ + +int32 sbs_eval (void) +{ +int32 hi; + +if (cpu_unit.flags & UNIT_SBS) { /* SBS enabled? */ + if (sbs_req == 0) return 0; /* any requests? */ + hi = sbs_ffo (sbs_req); /* find highest */ + if (hi < sbs_ffo (sbs_act)) return hi + 1; /* higher? */ + } +return 0; +} + +/* Find first one in a 16b field */ + +int32 sbs_ffo (int32 mask) +{ +if (mask & 0177400) + return ffo_map[(mask >> 8) & 0377]; +else return (ffo_map[mask & 0377] + 8); +} + +/* Device request interrupt */ + +t_stat dev_req_int (int32 lvl) +{ +if (cpu_unit.flags & UNIT_SBS) { /* SBS enabled? */ + if (lvl >= SBS_LVLS) return SCPE_IERR; /* invalid level? */ + if (sbs_enb & SBS_MASK (lvl)) /* level active? */ + sbs_req |= SBS_MASK (lvl); /* set SBS request */ + } +else sbs |= SB_RQ; /* PI request */ +return SCPE_OK; +} + +/* Device set/show SBS level */ + +t_stat dev_set_sbs (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 *lvl = (int32 *) desc; +int32 newlvl; +t_stat r; + +if ((cptr == NULL) || (*cptr == 0)) return SCPE_ARG; +newlvl = get_uint (cptr, 10, SBS_LVLS - 1, &r); +if (r != SCPE_OK) return SCPE_ARG; +*lvl = newlvl; +return SCPE_OK; +} + +t_stat dev_show_sbs (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +int32 *lvl = (int32 *) desc; + +if (lvl == NULL) return SCPE_IERR; +fprintf (st, "SBS level %d", *lvl); +return SCPE_OK; +} + /* Reset routine */ t_stat cpu_reset (DEVICE *dptr) { +int32 i; + sbs = sbs_init; extm = extm_init; -ioh = ios = cpls = 0; +ioh = 0; +ios = 0; +cpls = 0; +sbs_act = 0; +sbs_req = 0; +sbs_enb = 0; OV = 0; PF = 0; +MA = 0; +MB = 0; +rm = 0; +rtb = 0; +rmask = 0; +for (i = 0; i < RN45_SIZE; i++) rname[i] = i; pcq_r = find_reg ("PCQ", NULL, dptr); if (pcq_r) pcq_r->qptr = 0; else return SCPE_IERR; @@ -913,7 +1447,7 @@ return SCPE_OK; t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) { if (addr >= MEMSIZE) return SCPE_NXM; -if (vptr != NULL) *vptr = M[addr] & 0777777; +if (vptr != NULL) *vptr = M[addr] & DMASK; return SCPE_OK; } @@ -922,7 +1456,7 @@ return SCPE_OK; t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) { if (addr >= MEMSIZE) return SCPE_NXM; -M[addr] = val & 0777777; +M[addr] = val & DMASK; return SCPE_OK; } @@ -943,6 +1477,14 @@ for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0; return SCPE_OK; } +/* Set PDP-1D */ + +t_stat cpu_set_1d (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uptr->flags |= UNIT_SBS|UNIT_MDV; +return SCPE_OK; +} + /* Set history */ t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc) @@ -991,14 +1533,14 @@ if (cptr) { else lnt = hst_lnt; di = hst_p - lnt; /* work forward */ if (di < 0) di = di + hst_lnt; -fprintf (st, "PC OV AC IO PF EA IR\n\n"); +fprintf (st, "PC OV AC IO PF EA IR\n\n"); for (k = 0; k < lnt; k++) { /* print specified */ h = &hst[(++di) % hst_lnt]; /* entry pointer */ if (h->pc & HIST_PC) { /* instruction? */ ov = (h->ovac >> HIST_V_SHF) & 1; /* overflow */ - pf = (h->pfio >> HIST_V_SHF) & 077; /* prog flags */ + pf = (h->pfio >> HIST_V_SHF) & PF_VR_ALL; /* prog flags */ op = ((h->ir >> 13) & 037); /* get opcode */ - fprintf (st, "%06o %o %06o %06o %02o ", + fprintf (st, "%06o %o %06o %06o %03o ", h->pc & AMASK, ov, h->ovac & DMASK, h->pfio & DMASK, pf); if ((op < 032) && (op != 007)) /* mem ref instr */ fprintf (st, "%06o ", h->ea); @@ -1006,7 +1548,7 @@ for (k = 0; k < lnt; k++) { /* print specified */ sim_eval = h->ir; if ((fprint_sym (st, h->pc & AMASK, &sim_eval, &cpu_unit, SWMASK ('M'))) > 0) fprintf (st, "(undefined) %06o", h->ir); - else if ((op < 032) && (op != 007)) /* mem ref instr */ + else if (op < 030) /* mem ref instr */ fprintf (st, " [%06o]", h->opnd); fputc ('\n', st); /* end line */ } /* end else instruction */ diff --git a/PDP1/pdp1_dcs.c b/PDP1/pdp1_dcs.c new file mode 100644 index 00000000..deeef5c4 --- /dev/null +++ b/PDP1/pdp1_dcs.c @@ -0,0 +1,431 @@ +/* pdp1_dcs.c: PDP-1D terminal multiplexor simulator + + Copyright (c) 2006, 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"), + 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 Robert M Supnik shall not 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. + + dcs Type 630 data communications subsystem + + This module implements up to 32 individual serial interfaces. +*/ + +#include "pdp1_defs.h" +#include "sim_sock.h" +#include "sim_tmxr.h" + +#define DCS_LINES 32 /* lines */ +#define DCS_LINE_MASK (DCS_LINES - 1) +#define DCSL_WAIT 1000 /* output wait */ +#define DCS_NUMLIN dcs_desc.lines + +int32 dcs_sbs = 0; /* SBS level */ +uint32 dcs_send = 0; /* line for send */ +uint32 dcs_scan = 0; /* line for scanner */ +uint8 dcs_flg[DCS_LINES]; /* line flags */ +uint8 dcs_buf[DCS_LINES]; /* line bufffers */ + +extern int32 iosta, stop_inst; +extern int32 tmxr_poll; + +TMLN dcs_ldsc[DCS_LINES] = { 0 }; /* line descriptors */ +TMXR dcs_desc = { DCS_LINES, 0, 0, dcs_ldsc }; /* mux descriptor */ + +t_stat dcsi_svc (UNIT *uptr); +t_stat dcso_svc (UNIT *uptr); +t_stat dcs_reset (DEVICE *dptr); +t_stat dcs_attach (UNIT *uptr, char *cptr); +t_stat dcs_detach (UNIT *uptr); +t_stat dcs_summ (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat dcs_show (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat dcs_vlines (UNIT *uptr, int32 val, char *cptr, void *desc); +void dcs_reset_ln (int32 ln); +void dcs_scan_next (t_bool unlk); + +/* DCS data structures + + dcs_dev DCS device descriptor + dcs_unit DCS unit descriptor + dcs_reg DCS register list + dcs_mod DCS modifiers list +*/ + +REG dcs_nlreg = { DRDATA (NLINES, DCS_NUMLIN, 6), PV_LEFT }; + +UNIT dcs_unit = { UDATA (&dcsi_svc, UNIT_ATTABLE, 0) }; + +REG dcs_reg[] = { + { BRDATA (BUF, dcs_buf, 8, 8, DCS_LINES) }, + { BRDATA (FLAGS, dcs_flg, 8, 1, DCS_LINES) }, + { FLDATA (SCNF, iosta, IOS_V_DCS) }, + { ORDATA (SCAN, dcs_scan, 5) }, + { ORDATA (SEND, dcs_send, 5) }, + { DRDATA (SBSLVL, dcs_sbs, 4), REG_HRO }, + { NULL } + }; + +MTAB dcs_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL", + &dev_set_sbs, &dev_show_sbs, (void *) &dcs_sbs }, + { MTAB_XTD | MTAB_VDV | MTAB_VAL, 0, "lines", "LINES", + &dcs_vlines, NULL, &dcs_nlreg }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", + &tmxr_dscln, NULL, &dcs_desc }, + { UNIT_ATT, UNIT_ATT, "connections", NULL, NULL, &dcs_summ }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, + NULL, &dcs_show, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, + NULL, &dcs_show, NULL }, + { 0 } + }; + +DEVICE dcs_dev = { + "DCS", &dcs_unit, dcs_reg, dcs_mod, + 1, 10, 31, 1, 8, 8, + &tmxr_ex, &tmxr_dep, &dcs_reset, + NULL, &dcs_attach, &dcs_detach, + NULL, DEV_NET | DEV_DISABLE | DEV_DIS + }; + +/* DCSL data structures + + dcsl_dev DCSL device descriptor + dcsl_unit DCSL unit descriptor + dcsl_reg DCSL register list + dcsl_mod DCSL modifiers list +*/ + +UNIT dcsl_unit[] = { + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, + { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT } + }; + +MTAB dcsl_mod[] = { + { TT_MODE, TT_MODE_UC, "UC", "UC", NULL }, + { TT_MODE, TT_MODE_7B, "7b", "7B", NULL }, + { TT_MODE, TT_MODE_8B, "8b", "8B", NULL }, + { TT_MODE, TT_MODE_7P, "7p", "7P", NULL }, + { MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT", + &tmxr_dscln, NULL, &dcs_desc }, + { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG", + &tmxr_set_log, &tmxr_show_log, &dcs_desc }, + { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG", + &tmxr_set_nolog, NULL, &dcs_desc }, + { 0 } + }; + +REG dcsl_reg[] = { + { URDATA (TIME, dcsl_unit[0].wait, 10, 24, 0, + DCS_LINES, REG_NZ + PV_LEFT) }, + { NULL } + }; + +DEVICE dcsl_dev = { + "DCSL", dcsl_unit, dcsl_reg, dcsl_mod, + DCS_LINES, 10, 31, 1, 8, 8, + NULL, NULL, &dcs_reset, + NULL, NULL, NULL, + NULL, DEV_DIS + }; + +/* DCS IOT routine */ + +int32 dcs (int32 inst, int32 dev, int32 dat) +{ +int32 pls = (inst >> 6) & 077; + +if (dcs_dev.flags & DEV_DIS) /* disabled? */ + return (stop_inst << IOT_V_REASON) | dat; /* illegal inst */ +if (pls & 020) dat = 0; /* pulse 20? clr IO */ + +switch (pls & 057) { /* case IR<6,8:11> */ + + case 000: /* RCH */ + dat |= dcs_buf[dcs_scan]; /* return line buf */ + dcs_flg[dcs_scan] = 0; /* clr line flag */ + break; + + case 001: /* RRC */ + dat |= dcs_scan; /* return line num */ + break; + + case 010: /* RCC */ + dat |= dcs_buf[dcs_scan]; /* return line buf */ + dcs_flg[dcs_scan] = 0; /* clr line flag */ + /* fall through */ + case 011: /* RSC */ + dcs_scan_next (TRUE); /* unlock scanner */ + break; + + case 040: /* TCB */ + dcs_buf[dcs_send] = dat & 0377; /* load buffer */ + dcs_flg[dcs_send] = 0; /* clr line flag */ + sim_activate (&dcsl_unit[dcs_send], dcsl_unit[dcs_send].wait); + break; + + case 041: /* SSB */ + dcs_send = dat & DCS_LINE_MASK; /* load line num */ + break; + + case 050: /* TCC */ + dcs_buf[dcs_scan] = dat & 0377; /* load buffer */ + dcs_flg[dcs_scan] = 0; /* clr line flag */ + sim_activate (&dcsl_unit[dcs_scan], dcsl_unit[dcs_scan].wait); + dcs_scan_next (TRUE); /* unlock scanner */ + break; + + default: + return (stop_inst << IOT_V_REASON) | dat; /* illegal inst */ + } /* end case */ + +return dat; +} + +/* Unit service - receive side + + Poll all active lines for input + Poll for new connections +*/ + +t_stat dcsi_svc (UNIT *uptr) +{ +int32 ln, c, out; + +if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */ +if (dcs_dev.flags & DEV_DIS) return SCPE_OK; +sim_activate (uptr, tmxr_poll); /* continue poll */ +ln = tmxr_poll_conn (&dcs_desc); /* look for connect */ +if (ln >= 0) { /* got one? */ + dcs_ldsc[ln].rcve = 1; /* set rcv enable */ + } +tmxr_poll_rx (&dcs_desc); /* poll for input */ +for (ln = 0; ln < DCS_NUMLIN; ln++) { /* loop thru lines */ + if (dcs_ldsc[ln].conn) { /* connected? */ + if (c = tmxr_getc_ln (&dcs_ldsc[ln])) { /* get char */ + if (c & SCPE_BREAK) c = 0; /* break? */ + else c = sim_tt_inpcvt (c, TT_GET_MODE (dcsl_unit[ln].flags)|TTUF_KSR); + dcs_buf[ln] = c; /* save char */ + dcs_flg[ln] = 1; /* set line flag */ + dcs_scan_next (FALSE); /* kick scanner */ + out = sim_tt_outcvt (c & 0177, TT_GET_MODE (dcsl_unit[ln].flags)); + if (out >= 0) { + tmxr_putc_ln (&dcs_ldsc[ln], out); /* echo char */ + tmxr_poll_tx (&dcs_desc); /* poll xmt */ + } + } + } + else dcs_ldsc[ln].rcve = 0; /* disconnected */ + } /* end for */ +return SCPE_OK; +} + +/* Unit service - transmit side */ + +t_stat dcso_svc (UNIT *uptr) +{ +int32 c; +uint32 ln = uptr - dcsl_unit; /* line # */ + +if (dcs_dev.flags & DEV_DIS) return SCPE_OK; +if (dcs_ldsc[ln].conn) { /* connected? */ + if (dcs_ldsc[ln].xmte) { /* xmt enabled? */ + c = sim_tt_outcvt (dcs_buf[ln] & 0177, TT_GET_MODE (uptr->flags)); + if (c >= 0) tmxr_putc_ln (&dcs_ldsc[ln], c); /* output char */ + tmxr_poll_tx (&dcs_desc); /* poll xmt */ + } + else { /* buf full */ + tmxr_poll_tx (&dcs_desc); /* poll xmt */ + sim_activate (uptr, uptr->wait); /* reschedule */ + return SCPE_OK; + } + } +dcs_flg[ln] = 1; /* set line flag */ +dcs_scan_next (FALSE); /* kick scanner */ +return SCPE_OK; +} + +/* Kick scanner */ + +void dcs_scan_next (t_bool unlk) +{ +int32 i; + +if (unlk) iosta &= ~IOS_DCS; /* unlock? */ +else if (iosta & IOS_DCS) return; /* no, locked? */ +for (i = 0; i < DCS_LINES; i++) { /* scan flags */ + dcs_scan = (dcs_scan + 1) & DCS_LINE_MASK; /* next flag */ + if (dcs_flg[dcs_scan] != 0) { /* flag set? */ + iosta |= IOS_DCS; /* lock scanner */ + dev_req_int (dcs_sbs); /* request intr */ + return; + } + } +return; +} + +/* Reset routine */ + +t_stat dcs_reset (DEVICE *dptr) +{ +int32 i; + +if (dcs_dev.flags & DEV_DIS) /* master disabled? */ + dcsl_dev.flags = dcsl_dev.flags | DEV_DIS; /* disable lines */ +else dcsl_dev.flags = dcsl_dev.flags & ~DEV_DIS; +if (dcs_unit.flags & UNIT_ATT) /* master att? */ + sim_activate_abs (&dcs_unit, tmxr_poll); /* activate */ +else sim_cancel (&dcs_unit); /* else stop */ +for (i = 0; i < DCS_LINES; i++) dcs_reset_ln (i); /* reset lines */ +dcs_send = 0; +dcs_scan = 0; +iosta &= ~IOS_DCS; /* clr intr req */ +return SCPE_OK; +} + +/* Attach master unit */ + +t_stat dcs_attach (UNIT *uptr, char *cptr) +{ +t_stat r; + +r = tmxr_attach (&dcs_desc, uptr, cptr); /* attach */ +if (r != SCPE_OK) return r; /* error */ +sim_activate_abs (uptr, tmxr_poll); /* start poll */ +return SCPE_OK; +} + +/* Detach master unit */ + +t_stat dcs_detach (UNIT *uptr) +{ +int32 i; +t_stat r; + +r = tmxr_detach (&dcs_desc, uptr); /* detach */ +for (i = 0; i < DCS_LINES; i++) dcs_ldsc[i].rcve = 0; /* disable rcv */ +sim_cancel (uptr); /* stop poll */ +return r; +} + +/* Show summary processor */ + +t_stat dcs_summ (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +int32 i, t; + +for (i = t = 0; i < DCS_LINES; i++) t = t + (dcs_ldsc[i].conn != 0); +if (t == 1) fprintf (st, "1 connection"); +else fprintf (st, "%d connections", t); +return SCPE_OK; +} + +/* SHOW CONN/STAT processor */ + +t_stat dcs_show (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +int32 i, t; + +for (i = t = 0; i < DCS_LINES; i++) t = t + (dcs_ldsc[i].conn != 0); +if (t) { + for (i = 0; i < DCS_LINES; i++) { + if (dcs_ldsc[i].conn) { + if (val) tmxr_fconns (st, &dcs_ldsc[i], i); + else tmxr_fstats (st, &dcs_ldsc[i], i); + } + } + } +else fprintf (st, "all disconnected\n"); +return SCPE_OK; +} + +/* Change number of lines */ + +t_stat dcs_vlines (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 newln, i, t; +t_stat r; + +if (cptr == NULL) return SCPE_ARG; +newln = get_uint (cptr, 10, DCS_LINES, &r); +if ((r != SCPE_OK) || (newln == DCS_NUMLIN)) return r; +if (newln == 0) return SCPE_ARG; +if (newln < DCS_LINES) { + for (i = newln, t = 0; i < DCS_NUMLIN; i++) t = t | dcs_ldsc[i].conn; + if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE)) + return SCPE_OK; + for (i = newln; i < DCS_NUMLIN; i++) { + if (dcs_ldsc[i].conn) { + tmxr_linemsg (&dcs_ldsc[i], "\r\nOperator disconnected line\r\n"); + tmxr_reset_ln (&dcs_ldsc[i]); /* reset line */ + } + dcsl_unit[i].flags = dcsl_unit[i].flags | UNIT_DIS; + dcs_reset_ln (i); + } + } +else { + for (i = DCS_NUMLIN; i < newln; i++) { + dcsl_unit[i].flags = dcsl_unit[i].flags & ~UNIT_DIS; + dcs_reset_ln (i); + } + } +DCS_NUMLIN = newln; +return SCPE_OK; +} + +/* Reset an individual line */ + +void dcs_reset_ln (int32 ln) +{ +sim_cancel (&dcsl_unit[ln]); +dcs_buf[ln] = 0; +dcs_flg[ln] = 0; +return; +} diff --git a/PDP1/pdp1_defs.h b/PDP1/pdp1_defs.h index 3887d230..ef35bde9 100644 --- a/PDP1/pdp1_defs.h +++ b/PDP1/pdp1_defs.h @@ -1,6 +1,6 @@ /* pdp1_defs.h: 18b PDP simulator definitions - Copyright (c) 1993-2005, Robert M. Supnik + Copyright (c) 1993-2006, 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. + 21-Dec-06 RMS Added 16-channel sequence break support 22-Jul-05 RMS Fixed definition of CPLS_DPY 08-Feb-04 PLB Added support for display 08-Dec-03 RMS Added support for parallel drum @@ -61,6 +62,7 @@ #define STOP_IND 5 /* nested indirects */ #define STOP_WAIT 6 /* IO wait hang */ #define STOP_DTOFF 7 /* DECtape off reel */ +#define ERR_RMV 10 /* restrict mode viol */ /* Memory */ @@ -72,6 +74,7 @@ /* Architectural constants */ +#define SIGN 0400000 /* sign */ #define DMASK 0777777 /* data mask */ #define DAMASK 0007777 /* direct addr */ #define EPCMASK (AMASK & ~DAMASK) /* extended addr */ @@ -83,6 +86,37 @@ #define OP_JMP 0600000 /* JMP */ #define GEN_CPLS(x) (((x) ^ ((x) << 1)) & IO_WAIT) /* completion pulse? */ +/* Program flags/sense switches */ + +#define PF_V_L 7 +#define PF_V_RNG 6 +#define PF_L (1u << PF_V_L) +#define PF_RNG (1u << PF_V_RNG) +#define PF_SS_1 0040 +#define PF_SS_2 0020 +#define PF_SS_3 0010 +#define PF_SS_4 0004 +#define PF_SS_5 0002 +#define PF_SS_6 0001 +#define PF_VR_ALL 0377 +#define PF_SS_ALL 0077 + +/* Restict mode */ + +#define RTB_IOT 0400000 +#define RTB_ILL 0200000 +#define RTB_HLT 0100000 +#define RTB_DBK 0040000 +#define RTB_CHR 0020000 +#define RTB_MB_MASK 0017777 + +#define RM45_V_BNK 14 +#define RM45_M_BNK 003 +#define RM48_V_BNK 12 +#define RM48_M_BNK 017 + +#define RN45_SIZE 4 + /* IOT subroutine return codes */ #define IOT_V_SKP 18 /* skip */ @@ -100,8 +134,9 @@ #define IOS_V_PTP 13 /* paper tape punch */ #define IOS_V_DRM 12 /* drum */ #define IOS_V_SQB 11 /* sequence break */ -#define IOS_V_PNT 2 /* print done */ -#define IOS_V_SPC 1 /* space done */ +#define IOS_V_PNT 3 /* print done */ +#define IOS_V_SPC 2 /* space done */ +#define IOS_V_DCS 1 /* data comm sys */ #define IOS_V_DRP 0 /* parallel drum busy */ #define IOS_LPN (1 << IOS_V_LPN) @@ -113,6 +148,7 @@ #define IOS_SQB (1 << IOS_V_SQB) #define IOS_PNT (1 << IOS_V_PNT) #define IOS_SPC (1 << IOS_V_SPC) +#define IOS_DCS (1 << IOS_V_DCS) #define IOS_DRP (1 << IOS_V_DRP) /* Completion pulses */ @@ -128,7 +164,7 @@ #define CPLS_LPT (1 << CPLS_V_LPT) #define CPLS_DPY (1 << CPLS_V_DPY) -/* Sequence break flags */ +/* One channel sequence break */ #define SB_V_IP 0 /* in progress */ #define SB_V_RQ 1 /* request */ @@ -138,4 +174,21 @@ #define SB_RQ (1 << SB_V_RQ) #define SB_ON (1 << SB_V_ON) +/* 16 channel sequence break */ + +#define SBS_LVLS 16 /* num levels */ +#define SBS_LVL_MASK (SBS_LVLS - 1) +#define SBS_LVL_RMV 14 /* restrict level */ +#define SBS_MASK(x) (1u << (SBS_LVLS - 1 - (x))) /* level to mask */ + +/* Timers */ + +#define TMR_CLK 0 + +/* Device routines */ + +t_stat dev_req_int (int32 lvl); +t_stat dev_set_sbs (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat dev_show_sbs (FILE *st, UNIT *uptr, int32 val, void *desc); + #endif diff --git a/PDP1/pdp1_drm.c b/PDP1/pdp1_drm.c index f8669e27..beffa0a4 100644 --- a/PDP1/pdp1_drm.c +++ b/PDP1/pdp1_drm.c @@ -1,6 +1,6 @@ /* pdp1_drm.c: PDP-1 drum simulator - Copyright (c) 1993-2005, Robert M Supnik + Copyright (c) 1993-2006, 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"), @@ -26,6 +26,7 @@ drp Type 23 parallel drum drm Type 24 serial drum + 21-Dec-06 RMS Added 16-chan SBS support 08-Dec-03 RMS Added parallel drum support Fixed bug in DBL/DCN decoding 26-Oct-03 RMS Cleaned up buffer copy code @@ -71,7 +72,7 @@ ((double) DRM_NUMWDT))) extern int32 M[]; -extern int32 iosta, sbs; +extern int32 iosta; extern int32 stop_inst; extern UNIT cpu_unit; @@ -82,6 +83,7 @@ uint32 drm_ma = 0; /* memory address */ uint32 drm_err = 0; /* error flag */ uint32 drm_wlk = 0; /* write lock */ int32 drm_time = 4; /* inter-word time */ +int32 drm_sbs = 0; /* SBS level */ int32 drm_stopioe = 1; /* stop on error */ /* Parallel drum variables */ @@ -123,12 +125,19 @@ REG drm_reg[] = { { FLDATA (ERR, drm_err, 0) }, { ORDATA (WLK, drm_wlk, 32) }, { DRDATA (TIME, drm_time, 24), REG_NZ + PV_LEFT }, + { DRDATA (SBSLVL, drm_sbs, 4), REG_HRO }, { FLDATA (STOP_IOE, drm_stopioe, 0) }, { NULL } }; +MTAB drm_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "APILVL", "APILVL", + &dev_set_sbs, &dev_show_sbs, (void *) &drm_sbs }, + { 0 } + }; + DEVICE drm_dev = { - "DRM", &drm_unit, drm_reg, NULL, + "DRM", &drm_unit, drm_reg, drm_mod, 1, 8, 20, 1, 8, 18, NULL, NULL, &drm_reset, NULL, NULL, NULL, @@ -159,6 +168,7 @@ REG drp_reg[] = { { FLDATA (ERR, drp_err, 0) }, { DRDATA (TIME, drp_time, 24), REG_NZ + PV_LEFT }, { FLDATA (STOP_IOE, drp_stopioe, 0) }, + { DRDATA (SBSLVL, drm_sbs, 4), REG_HRO }, { NULL } }; @@ -266,7 +276,7 @@ uint32 *fbuf = uptr->filebuf; if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */ drm_err = 1; /* set error */ iosta = iosta | IOS_DRM; /* set done */ - sbs = sbs | SB_RQ; /* req intr */ + dev_req_int (drm_sbs); /* req intr */ return IORETURN (drm_stopioe, SCPE_UNATT); } @@ -287,7 +297,7 @@ for (i = 0; i < DRM_NUMWDS; i++, da++) { /* do transfer */ } drm_da = (drm_da + 1) & DRM_SMASK; /* incr dev addr */ iosta = iosta | IOS_DRM; /* set done */ -sbs = sbs | SB_RQ; /* req intr */ +dev_req_int (drm_sbs); /* req intr */ return SCPE_OK; } @@ -314,7 +324,7 @@ uint32 *fbuf = uptr->filebuf; if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */ drp_err = 1; /* set error */ iosta = iosta & ~IOS_DRP; /* clear busy */ - if (uptr->FUNC) sbs = sbs | SB_RQ; /* req intr */ + if (uptr->FUNC) dev_req_int (drm_sbs); /* req intr */ return IORETURN (drp_stopioe, SCPE_UNATT); } @@ -330,7 +340,7 @@ if (uptr->FUNC == DRP_RW) { /* read/write? */ } /* end for */ } /* end if */ iosta = iosta & ~IOS_DRP; /* clear busy */ -if (uptr->FUNC) sbs = sbs | SB_RQ; /* req intr */ +if (uptr->FUNC) dev_req_int (drm_sbs); /* req intr */ return SCPE_OK; } diff --git a/PDP1/pdp1_dt.c b/PDP1/pdp1_dt.c index 9a1ff5bc..731fc8f6 100644 --- a/PDP1/pdp1_dt.c +++ b/PDP1/pdp1_dt.c @@ -25,6 +25,7 @@ dt Type 550/555 DECtape + 21-Dec-06 RMS Added 16-channel SBS support 23-Jun-06 RMS Fixed conflict in ATTACH switches Revised header format 16-Aug-05 RMS Fixed C++ declaration and cast problems @@ -179,7 +180,7 @@ #define DTA_RW 077 #define DTA_GETUNIT(x) map_unit[(((x) >> DTA_V_UNIT) & DTA_M_UNIT)] #define DT_UPDINT if (dtsb & (DTB_DTF | DTB_BEF | DTB_ERF)) \ - sbs = sbs | SB_RQ; + dev_req_int (dt_sbs); #define DTA_GETMOT(x) (((x) >> DTA_V_MOT) & DTA_M_MOT) #define DTA_GETFNC(x) (((x) >> DTA_V_FNC) & DTA_M_FNC) @@ -247,7 +248,6 @@ #define ABS(x) (((x) < 0)? (-(x)): (x)) extern int32 M[]; -extern int32 sbs; extern int32 stop_inst; extern UNIT cpu_unit; extern int32 sim_switches; @@ -257,6 +257,7 @@ extern FILE *sim_deb; int32 dtsa = 0; /* status A */ int32 dtsb = 0; /* status B */ int32 dtdb = 0; /* data buffer */ +int32 dt_sbs = 0; /* SBS level */ int32 dt_ltime = 12; /* interline time */ int32 dt_dctime = 40000; /* decel time */ int32 dt_substate = 0; @@ -326,10 +327,13 @@ REG dt_reg[] = { { URDATA (LASTT, dt_unit[0].LASTT, 10, 32, 0, DT_NUMDR, REG_HRO) }, { FLDATA (STOP_OFFR, dt_stopoffr, 0) }, + { DRDATA (SBSLVL, dt_sbs, 4), REG_HRO }, { NULL } }; MTAB dt_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL", + &dev_set_sbs, &dev_show_sbs, (void *) &dt_sbs }, { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, { UNIT_8FMT + UNIT_11FMT, 0, "18b", NULL, NULL }, diff --git a/PDP1/pdp1_lp.c b/PDP1/pdp1_lp.c index faea4467..f7b52c18 100644 --- a/PDP1/pdp1_lp.c +++ b/PDP1/pdp1_lp.c @@ -1,6 +1,6 @@ /* pdp1_lp.c: PDP-1 line printer simulator - Copyright (c) 1993-2005, Robert M. Supnik + Copyright (c) 1993-2006, 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 @@ lpt Type 62 line printer for the PDP-1 + 21-Dec-06 RMS Added 16-channel SBS support 07-Sep-03 RMS Changed ioc to ios 23-Jul-03 RMS Fixed bugs in instruction decoding, overprinting Revised to detect I/O wait hang @@ -43,6 +44,7 @@ int32 lpt_spc = 0; /* print (0) vs spc */ int32 lpt_ovrpr = 0; /* overprint */ int32 lpt_stopioe = 0; /* stop on error */ int32 lpt_bptr = 0; /* buffer ptr */ +int32 lpt_sbs = 0; /* SBS level */ char lpt_buf[LPT_BSIZE + 1] = { 0 }; static const unsigned char lpt_trans[64] = { ' ','1','2','3','4','5','6','7','8','9','\'','~','#','V','^','<', @@ -51,7 +53,7 @@ static const unsigned char lpt_trans[64] = { '_','A','B','C','D','E','F','G','H','I','*','.','+',']','|','[' }; -extern int32 ios, cpls, sbs, iosta; +extern int32 ios, cpls, iosta; extern int32 stop_inst; t_stat lpt_svc (UNIT *uptr); @@ -80,11 +82,18 @@ REG lpt_reg[] = { { DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, lpt_stopioe, 0) }, { BRDATA (LBUF, lpt_buf, 8, 8, LPT_BSIZE) }, + { DRDATA (SBSLVL, lpt_sbs, 4), REG_HRO }, { NULL } }; +MTAB lpt_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL", + &dev_set_sbs, &dev_show_sbs, (void *) &lpt_sbs }, + { 0 } + }; + DEVICE lpt_dev = { - "LPT", &lpt_unit, lpt_reg, NULL, + "LPT", &lpt_unit, lpt_reg, lpt_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &lpt_reset, NULL, NULL, NULL, @@ -151,7 +160,7 @@ if (cpls & CPLS_LPT) { /* completion pulse? */ ios = 1; /* restart */ cpls = cpls & ~CPLS_LPT; /* clr pulse pending */ } -sbs = sbs | SB_RQ; /* req seq break */ +dev_req_int (lpt_sbs); /* req interrupt */ if (lpt_spc) { /* space? */ iosta = iosta | IOS_SPC; /* set flag */ if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ diff --git a/PDP1/pdp1_stddev.c b/PDP1/pdp1_stddev.c index c19a9ce9..4ddd114f 100644 --- a/PDP1/pdp1_stddev.c +++ b/PDP1/pdp1_stddev.c @@ -1,6 +1,6 @@ /* pdp1_stddev.c: PDP-1 standard devices - Copyright (c) 1993-2005, Robert M. Supnik + Copyright (c) 1993-2006, 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"), @@ -28,6 +28,7 @@ tti keyboard tto teleprinter + 21-Dec-06 RMS Added 16-channel sequence break support 29-Oct-03 RMS Added PTR FIODEC-to-ASCII translation (from Phil Budne) 07-Sep-03 RMS Changed ioc to ios 30-Aug-03 RMS Revised PTR to conform to Maintenance Manual; @@ -58,8 +59,6 @@ #define BOTH (1 << (UC_V + 1)) /* both cases */ #define CW (1 << (UC_V + 2)) /* char waiting */ #define TT_WIDTH 077 -#define TTI 0 -#define TTO 1 #define UNIT_V_ASCII (UNIT_V_UF + 0) /* ASCII/binary mode */ #define UNIT_ASCII (1 << UNIT_V_ASCII) #define PTR_LEADER 20 /* ASCII leader chars */ @@ -70,12 +69,16 @@ int32 ptr_stopioe = 0; int32 ptr_uc = 0; /* upper/lower case */ int32 ptr_hold = 0; /* holding buffer */ int32 ptr_leader = PTR_LEADER; /* leader count */ +int32 ptr_sbs = 0; /* SBS level */ int32 ptp_stopioe = 0; +int32 ptp_sbs = 0; /* SBS level */ int32 tti_hold = 0; /* tti hold buf */ +int32 tti_sbs = 0; /* SBS level */ int32 tty_buf = 0; /* tty buffer */ int32 tty_uc = 0; /* tty uc/lc */ +int32 tto_sbs = 0; -extern int32 sbs, ios, ioh, cpls, iosta; +extern int32 ios, ioh, cpls, iosta; extern int32 PF, IO, PC, TA; extern int32 M[]; @@ -154,10 +157,13 @@ REG ptr_reg[] = { { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, { DRDATA (LEADER, ptr_leader, 6), REG_HRO }, { FLDATA (STOP_IOE, ptr_stopioe, 0) }, + { DRDATA (SBSLVL, ptr_sbs, 4), REG_HRO }, { NULL } }; MTAB ptr_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL", + &dev_set_sbs, &dev_show_sbs, (void *) &ptr_sbs }, { UNIT_ASCII, UNIT_ASCII, "ASCII", "ASCII", NULL }, { UNIT_ASCII, 0, "FIODEC", "FIODEC", NULL }, { 0 } @@ -189,46 +195,87 @@ REG ptp_reg[] = { { DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT }, { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptp_stopioe, 0) }, + { DRDATA (SBSLVL, ptp_sbs, 4), REG_HRO }, { NULL } }; +MTAB ptp_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL", + &dev_set_sbs, &dev_show_sbs, (void *) &ptp_sbs }, + { 0 } + }; + DEVICE ptp_dev = { - "PTP", &ptp_unit, ptp_reg, NULL, + "PTP", &ptp_unit, ptp_reg, ptp_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptp_reset, NULL, NULL, NULL, NULL, 0 }; -/* TTY data structures +/* TTI data structures - tty_dev TTY device descriptor - tty_unit TTY unit - tty_reg TTY register list + tti_dev TTI device descriptor + tti_unit TTI unit + tti_reg TTI register list */ -UNIT tty_unit[] = { - { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT }, - { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT * 10 } - }; +UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT }; -REG tty_reg[] = { +REG tti_reg[] = { { ORDATA (BUF, tty_buf, 6) }, { FLDATA (UC, tty_uc, UC_V) }, - { FLDATA (RPLS, cpls, CPLS_V_TTO) }, { ORDATA (HOLD, tti_hold, 9), REG_HRO }, - { FLDATA (KDONE, iosta, IOS_V_TTI) }, - { DRDATA (KPOS, tty_unit[TTI].pos, T_ADDR_W), PV_LEFT }, - { DRDATA (KTIME, tty_unit[TTI].wait, 24), REG_NZ + PV_LEFT }, - { FLDATA (TDONE, iosta, IOS_V_TTO) }, - { DRDATA (TPOS, tty_unit[TTO].pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TTIME, tty_unit[TTO].wait, 24), PV_LEFT }, + { FLDATA (DONE, iosta, IOS_V_TTI) }, + { DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT }, + { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, + { DRDATA (SBSLVL, tti_sbs, 4), REG_HRO }, { NULL } }; -DEVICE tty_dev = { - "TTY", tty_unit, tty_reg, NULL, - 2, 10, 31, 1, 8, 8, +MTAB tti_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL", + &dev_set_sbs, &dev_show_sbs, (void *) &tti_sbs }, + { 0 } + }; + +DEVICE tti_dev = { + "TTI", &tti_unit, tti_reg, tti_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &tty_reset, + NULL, NULL, NULL, + NULL, 0 + }; + +/* TTO data structures + + tto_dev TTO device descriptor + tto_unit TTO unit + tto_reg TTO register list +*/ + +UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT * 10 }; + +REG tto_reg[] = { + { ORDATA (BUF, tty_buf, 6) }, + { FLDATA (UC, tty_uc, UC_V) }, + { FLDATA (RPLS, cpls, CPLS_V_TTO) }, + { FLDATA (DONE, iosta, IOS_V_TTO) }, + { DRDATA (POS, tto_unit.pos, T_ADDR_W), PV_LEFT }, + { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT }, + { DRDATA (SBSLVL, tto_sbs, 4), REG_HRO }, + { NULL } + }; + +MTAB tto_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL", + &dev_set_sbs, &dev_show_sbs, (void *) &tto_sbs }, + { 0 } + }; + +DEVICE tto_dev = { + "TTO", &tto_unit, tto_reg, tto_mod, + 1, 10, 31, 1, 8, 8, NULL, NULL, &tty_reset, NULL, NULL, NULL, NULL, 0 @@ -309,7 +356,7 @@ if (ptr_state == 0) { /* done? */ } else { /* no, interrupt */ iosta = iosta | IOS_PTR; /* set flag */ - sbs = sbs | SB_RQ; /* req seq break */ + dev_req_int (ptr_sbs); /* req interrupt */ } } else sim_activate (uptr, uptr->wait); /* get next char */ @@ -443,7 +490,7 @@ if (cpls & CPLS_PTP) { /* completion pulse? */ cpls = cpls & ~CPLS_PTP; } iosta = iosta | IOS_PTP; /* set flag */ -sbs = sbs | SB_RQ; /* req seq break */ +dev_req_int (ptp_sbs); /* req interrupt */ if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ return IORETURN (ptp_stopioe, SCPE_UNATT); if (putc (uptr->buf, uptr->fileref) == EOF) { /* I/O error? */ @@ -485,7 +532,7 @@ if (GEN_CPLS (inst)) { /* comp pulse? */ cpls = cpls | CPLS_TTO; } else cpls = cpls & ~CPLS_TTO; -sim_activate (&tty_unit[TTO], tty_unit[TTO].wait); /* activate unit */ +sim_activate (&tto_unit, tto_unit.wait); /* activate unit */ return dat; } @@ -518,8 +565,8 @@ else { } } iosta = iosta | IOS_TTI; /* set flag */ -sbs = sbs | SB_RQ; /* req seq break */ -PF = PF | 040; /* set prog flag 1 */ +dev_req_int (tti_sbs); /* req interrupt */ +PF = PF | PF_SS_1; /* set prog flag 1 */ uptr->pos = uptr->pos + 1; return SCPE_OK; } @@ -543,7 +590,7 @@ if (cpls & CPLS_TTO) { /* completion pulse? */ cpls = cpls & ~CPLS_TTO; } iosta = iosta | IOS_TTO; /* set flag */ -sbs = sbs | SB_RQ; /* req seq break */ +dev_req_int (tto_sbs); /* req interrupt */ uptr->pos = uptr->pos + 1; if (c == '\r') { /* cr? add lf */ sim_putchar ('\n'); @@ -561,7 +608,7 @@ tty_uc = 0; /* clear case */ tti_hold = 0; /* clear hold buf */ cpls = cpls & ~CPLS_TTO; iosta = (iosta & ~IOS_TTI) | IOS_TTO; /* clear flag */ -sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* activate keyboard */ -sim_cancel (&tty_unit[TTO]); /* stop printer */ +sim_activate (&tti_unit, tti_unit.wait); /* activate keyboard */ +sim_cancel (&tto_unit); /* stop printer */ return SCPE_OK; } diff --git a/PDP1/pdp1_sys.c b/PDP1/pdp1_sys.c index d817d5b0..fd3470c1 100644 --- a/PDP1/pdp1_sys.c +++ b/PDP1/pdp1_sys.c @@ -1,6 +1,6 @@ /* pdp1_sys.c: PDP-1 simulator interface - Copyright (c) 1993-2004, Robert M. Supnik + Copyright (c) 1993-2007, 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,8 @@ 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-07 RMS Fixed bugs in block loader, char input + 21-Dec-06 RMS Added 16-channel sequence break support, PDP-1D support 06-Apr-04 RMS Fixed bug in binary loader (found by Mark Crispin) 08-Feb-04 PLB Merged display support 08-Dec-03 RMS Added parallel drum support, drum mnemonics @@ -46,13 +48,16 @@ #include extern DEVICE cpu_dev; +extern DEVICE clk_dev; extern DEVICE ptr_dev; extern DEVICE ptp_dev; -extern DEVICE tty_dev; +extern DEVICE tti_dev; +extern DEVICE tto_dev; extern DEVICE lpt_dev; extern DEVICE dt_dev; extern DEVICE drm_dev; extern DEVICE drp_dev; +extern DEVICE dcs_dev, dcsl_dev; extern DEVICE dpy_dev; extern UNIT cpu_unit; extern REG cpu_reg[]; @@ -80,13 +85,17 @@ int32 sim_emax = 1; DEVICE *sim_devices[] = { &cpu_dev, + &clk_dev, &ptr_dev, &ptp_dev, - &tty_dev, + &tti_dev, + &tto_dev, &lpt_dev, &dt_dev, &drm_dev, &drp_dev, + &dcs_dev, + &dcsl_dev, /* &dpy_dev, */ NULL }; @@ -152,13 +161,13 @@ for (;;) { if ((val = pdp1_getw (inf)) < 0) return SCPE_FMT; if ((val & 0760000) != OP_DIO) return SCPE_FMT; csum = csum + val; - if (csum > 0777777) csum = (csum + 1) & 0777777; - count = (val & DAMASK) - start + 1; /* block count */ + if (csum > DMASK) csum = (csum + 1) & DMASK; + count = (val & DAMASK) - start; /* block count */ if (count <= 0) return SCPE_FMT; while (count--) { /* loop on data */ if ((val = pdp1_getw (inf)) < 0) return SCPE_FMT; csum = csum + val; - if (csum > 0777777) csum = (csum + 1) & 0777777; + if (csum > DMASK) csum = (csum + 1) & DMASK; M[fld | start] = val; start = (start + 1) & DAMASK; } @@ -196,7 +205,7 @@ return SCPE_OK; /* Symbol tables */ #define I_V_FL 18 /* inst class */ -#define I_M_FL 07 /* class mask */ +#define I_M_FL 017 /* class mask */ #define I_V_NPN 0 /* no operand */ #define I_V_IOT 1 /* IOT */ #define I_V_LAW 2 /* LAW */ @@ -205,6 +214,7 @@ return SCPE_OK; #define I_V_OPR 5 /* OPR */ #define I_V_SKP 6 /* skip */ #define I_V_SHF 7 /* shift */ +#define I_V_SPC 8 /* special */ #define I_NPN (I_V_NPN << I_V_FL) /* no operand */ #define I_IOT (I_V_IOT << I_V_FL) /* IOT */ #define I_LAW (I_V_LAW << I_V_FL) /* LAW */ @@ -213,10 +223,12 @@ return SCPE_OK; #define I_OPR (I_V_OPR << I_V_FL) /* OPR */ #define I_SKP (I_V_SKP << I_V_FL) /* skip */ #define I_SHF (I_V_SHF << I_V_FL) /* shift */ +#define I_SPC (I_V_SPC << I_V_FL) static const int32 masks[] = { - 0777777, 0763777, 0760000, 0760000, - 0770000, 0760017, 0760077, 0777000 + 0777777, 0760077, 0760000, 0760000, + 0770000, 0760017, 0760077, 0777000, + 0760003 }; static const char *opcode[] = { @@ -224,22 +236,30 @@ static const char *opcode[] = { "LAC", "LIO", "DAC", "DAP", "DIP", "DIO", "DZM", "ADD", "SUB", "IDX", "ISP", "SAD", - "SAS", "MUL", "DIV", "JMP", "JSP", + "SAS", "MUL", "DIV", "JMP", + "JSP", "LCH", "DCH", "TAD", "CAL", "JDA", /* mem ref no ind */ + "LAW", + "IOH", "RPA", "RPB", "RRB", /* I/O instructions */ "PPA", "PPB", "TYO", "TYI", "DPY", + "DSC", "ASC", "ISC", "CAC", "LSM", "ESM", "CBS", "LEM", "EEM", "CKS", "MSE", "MLC", "MRD", "MWR", "MRS", "DIA", "DBA", "DWC", "DRA", "DCL", "DRD", "DWR", "DBL", "DCN", "DTD", "DSE", "DSP", + "LRG", "ERG", "LRM", "ERM", + "RNM", "RSM", "RCK", "CTB", + "RCH", "RCC", "TCC", "TCB", + "RRC", "SSB", "RSC", - "SKP", "SKP I", "CLO", - "SFT", "LAW", "OPR", + "SKP", "SKP I", "CLO", /* base as NPNs */ + "SFT", "SPC", "OPR", "RAL", "RIL", "RCL", /* shifts */ "SAL", "SIL", "SCL", @@ -268,12 +288,24 @@ static const char *opcode[] = { "STF1", "STF2", "STF3", "STF4", "STF5", "STF6", "STF7", - "SZA", "SPA", "SMA", /* encode only */ - "SZO", "SPI", "I", + "FF1", "FF2", "FF3", /* specials */ + + "SZA", "SPA", "SMA", /* uprog skips */ + "SZO", "SPI", "SNI", + "I", /* encode only */ + + "LIA", "LAI", "SWP", /* uprog opers */ "LAP", "CLA", "HLT", "CMA", "LAT", "CLI", - NULL, NULL, /* decode only */ - NULL + "CMI", + + "CML", "CLL", "SZL", /* uprog specials */ + "SCF", "SCI", "SCM", + "IDA", "IDC", "IFI", + "IIF", + + NULL, NULL, NULL, /* decode only */ + NULL, }; static const int32 opc_val[] = { @@ -281,22 +313,30 @@ static const int32 opc_val[] = { 0200000+I_MRF, 0220000+I_MRF, 0240000+I_MRF, 0260000+I_MRF, 0300000+I_MRF, 0320000+I_MRF, 0340000+I_MRF, 0400000+I_MRF, 0420000+I_MRF, 0440000+I_MRF, 0460000+I_MRF, 0500000+I_MRF, - 0520000+I_MRF, 0540000+I_MRF, 0560000+I_MRF, 0600000+I_MRF, 0620000+I_MRF, + 0520000+I_MRF, 0540000+I_MRF, 0560000+I_MRF, 0600000+I_MRF, + 0620000+I_MRF, 0120000+I_MRF, 0140000+I_MRF, 0360000+I_MRF, 0160000+I_MRI, 0170000+I_MRI, + 0700000+I_LAW, + 0730000+I_NPN, 0720001+I_IOT, 0720002+I_IOT, 0720030+I_IOT, 0720005+I_IOT, 0720006+I_IOT, 0720003+I_IOT, 0720004+I_IOT, 0720007+I_IOT, + 0720050+I_IOT, 0720051+I_IOT, 0720052+I_IOT, 0720053+I_NPN, 0720054+I_NPN, 0720055+I_NPN, 0720056+I_NPN, 0720074+I_NPN, 0724074+I_NPN, 0720033+I_NPN, 0720301+I_NPN, 0720401+I_NPN, 0720501+I_NPN, 0720601+I_NPN, 0720701+I_NPN, 0720061+I_NPN, 0722061+I_NPN, 0720062+I_NPN, 0722062+I_NPN, 0720063+I_NPN, 0720161+I_NPN, 0721161+I_NPN, 0720162+I_NPN, 0721162+I_NPN, 0720163+I_NPN, 0720164+I_NPN, 0721164+I_NPN, + 0720010+I_NPN, 0720011+I_NPN, 0720064+I_NPN, 0720065+I_NPN, + 0720066+I_IOT, 0720067+I_NPN, 0720032+I_NPN, 0720035+I_NPN, + 0720022+I_NPN, 0721022+I_NPN, 0725022+I_NPN, 0724022+I_NPN, + 0720122+I_NPN, 0724122+I_NPN, 0721122+I_NPN, 0640000+I_NPN, 0650000+I_NPN, 0651600+I_NPN, - 0660000+I_NPN, 0700000+I_LAW, 0760000+I_NPN, + 0660000+I_NPN, 0740000+I_NPN, 0760000+I_NPN, 0661000+I_SHF, 0662000+I_SHF, 0663000+I_SHF, 0665000+I_SHF, 0666000+I_SHF, 0667000+I_SHF, @@ -325,12 +365,23 @@ static const int32 opc_val[] = { 0760011+I_OPR, 0760012+I_OPR, 0760013+I_OPR, 0760014+I_OPR, 0760015+I_OPR, 0760016+I_OPR, 0760017+I_OPR, - 0640100+I_SKP, 0640200+I_SKP, 0640400+I_SKP, /* encode only */ - 0641000+I_SKP, 0642000+I_SKP, 0010000+I_SKP, + 0740001+I_SPC, 0740002+I_SPC, 0740003+I_OPR, + + 0640100+I_SKP, 0640200+I_SKP, 0640400+I_SKP, + 0641000+I_SKP, 0642000+I_SKP, 0644000+I_SKP, + 0010000+I_SKP, /* encode only */ + + 0760020+I_OPR, 0760040+I_OPR, 0760060+I_NPN, 0760100+I_OPR, 0760200+I_OPR, 0760400+I_OPR, 0761000+I_OPR, 0762000+I_OPR, 0764000+I_OPR, + 0770000+I_OPR, - 0640000+I_SKP, 0760000+I_OPR, /* decode only */ + 0740004+I_SPC, 0740010+I_SPC, 0740020+I_SPC, + 0740040+I_SPC, 0740100+I_SPC, 0740200+I_SPC, + 0740400+I_SPC, 0741000+I_SPC, 0742000+I_SPC, + 0744000+I_SPC, + + 0640000+I_SKP, 0740000+I_SPC, 0760000+I_OPR, /* decode only */ -1 }; @@ -406,7 +457,7 @@ disp = inst & 007777; ma = (addr & EPCMASK) | disp; for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */ - if ((opc_val[i] & 0777777) == (inst & masks[j])) { /* match? */ + if ((opc_val[i] & DMASK) == (inst & masks[j])) { /* match? */ switch (j) { /* case on class */ @@ -433,7 +484,7 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ break; case I_V_OPR: /* operates */ - sp = fprint_opr (of, inst & 007700, j, 0); + sp = fprint_opr (of, inst & 017760, j, 0); if (opcode[i]) fprintf (of, (sp? " %s": "%s"), opcode[i]); break; @@ -443,6 +494,12 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ if (inst & IA) fprintf (of, sp? " I": "I"); break; + case I_V_SPC: /* specials */ + sp = fprint_opr (of, inst & 007774, j, 0); + if (opcode[i]) sp = fprintf (of, (sp? " %s": "%s"), opcode[i]); + if (inst & IA) fprintf (of, sp? " I": "I"); + break; + case I_V_SHF: /* shifts */ fprintf (of, "%s %-d", opcode[i], sc_map[inst & 0777]); break; @@ -475,7 +532,7 @@ else if (*cptr == '-') { *sign = -1; cptr++; } -return get_uint (cptr, 8, 0777777, status); +return get_uint (cptr, 8, DMASK, status); } /* Symbolic input @@ -508,16 +565,16 @@ if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ } if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* sixbit string? */ if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ - val[0] = (ASCTOSIX (cptr[0] & 077) << 12) | - (ASCTOSIX (cptr[1] & 077) << 6) | - ASCTOSIX (cptr[2] & 077); + val[0] = ((ASCTOSIX (cptr[0]) & 077) << 12) | + ((ASCTOSIX (cptr[1]) & 077) << 6) | + (ASCTOSIX (cptr[2]) & 077); return SCPE_OK; } cptr = get_glyph (cptr, gbuf, 0); /* get opcode */ for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ; if (opcode[i] == NULL) return SCPE_ARG; -val[0] = opc_val[i] & 0777777; /* get value */ +val[0] = opc_val[i] & DMASK; /* get value */ j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */ switch (j) { /* case on class */ @@ -545,13 +602,14 @@ switch (j) { /* case on class */ val[0] = val[0] | sc_enc[d]; break; - case I_V_NPN: case I_V_IOT: case I_V_OPR: case I_V_SKP: + case I_V_NPN: case I_V_IOT: + case I_V_OPR: case I_V_SKP: case I_V_SPC: for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0; cptr = get_glyph (cptr, gbuf, 0)) { for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0); i++) ; if (opcode[i] != NULL) { - k = opc_val[i] & 0777777; + k = opc_val[i] & DMASK; if ((k != IA) && (((k ^ val[0]) & 0760000) != 0)) return SCPE_ARG; val[0] = val[0] | k; diff --git a/PDP10/pdp10_cpu.c b/PDP10/pdp10_cpu.c index 6dc6266b..9ae82377 100644 --- a/PDP10/pdp10_cpu.c +++ b/PDP10/pdp10_cpu.c @@ -136,8 +136,6 @@ #define PCQ_SIZE 64 /* must be 2**n */ #define PCQ_MASK (PCQ_SIZE - 1) #define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC -#define UNIT_V_MSIZE (UNIT_V_T20V41 + 1) /* dummy mask */ -#define UNIT_MSIZE (1 << UNIT_V_MSIZE) #define HIST_PC 0x40000000 #define HIST_MIN 64 @@ -188,6 +186,7 @@ int32 stop_op0 = 0; /* stop on 0 */ int32 rlog = 0; /* extend fixup log */ int32 ind_max = 32; /* nested ind limit */ int32 xct_max = 32; /* nested XCT limit */ +int32 t20_idlelock = 0; /* TOPS-20 idle lock */ a10 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ int32 pcq_p = 0; /* PC queue ptr */ REG *pcq_r = NULL; /* PC queue reg ptr */ @@ -321,6 +320,7 @@ extern t_bool wrpcst (a10 ea, int32 prv); extern t_bool spm (a10 ea, int32 prv); extern t_bool lpmr (a10 ea, int32 prv); extern int32 pi_ub_vec (int32 lvl, int32 *uba); +extern t_stat tim_set_mod (UNIT *uptr, int32 val, char *cptr, void *desc); /* CPU data structures @@ -390,9 +390,14 @@ REG cpu_reg[] = { }; MTAB cpu_mod[] = { - { UNIT_ITS+UNIT_T20V41, 0, "Standard microcode", "STANDARD", NULL }, - { UNIT_ITS+UNIT_T20V41, UNIT_T20V41, "TOPS-20 V4.1", "TOPS20V41", NULL }, - { UNIT_ITS+UNIT_T20V41, UNIT_ITS, "ITS microcode", "ITS", NULL }, + { UNIT_KLAD+UNIT_ITS+UNIT_T20, 0, "TOPS-10", "TOPS-10", &tim_set_mod }, + { UNIT_KLAD+UNIT_ITS+UNIT_T20, 0, NULL , "TOPS10", &tim_set_mod }, + { UNIT_KLAD+UNIT_ITS+UNIT_T20, UNIT_T20, "TOPS-20", "TOPS-20", &tim_set_mod }, + { UNIT_KLAD+UNIT_ITS+UNIT_T20, UNIT_T20, NULL, "TOPS20", &tim_set_mod }, + { UNIT_KLAD+UNIT_ITS+UNIT_T20, UNIT_ITS, "ITS", "ITS", &tim_set_mod }, + { UNIT_KLAD+UNIT_ITS+UNIT_T20, UNIT_KLAD, "diagnostic mode", "KLAD", &tim_set_mod }, + { MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL }, { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "IOSPACE", NULL, NULL, &show_iospace }, { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", @@ -593,11 +598,11 @@ static t_stat jrst_tab[16] = { #define T__N if ((AC(ac) & mb) != 0) INCPC #define T__A INCPC #define IOC if (TSTF (F_USR) && !TSTF (F_UIO)) goto MUUO; -#define IO7(x,y) IOC; fptr = ((ITS)? x[ac]: y[ac]); \ +#define IO7(x,y) IOC; fptr = ((Q_ITS)? x[ac]: y[ac]); \ if (fptr == NULL) goto MUUO; \ if (fptr (ea, MM_OPND)) INCPC; break; -#define IOA IOC; if (!ITS) ea = calc_ioea (inst, pflgs) -#define IOAM IOC; ea = ((ITS)? ((a10) Read (ea, MM_OPND)): \ +#define IOA IOC; if (!Q_ITS) ea = calc_ioea (inst, pflgs) +#define IOAM IOC; ea = ((Q_ITS)? ((a10) Read (ea, MM_OPND)): \ calc_ioea (inst, pflgs)) /* Flag tests */ @@ -629,7 +634,8 @@ pager_pi = FALSE; /* not in pi sequence */ rlog = 0; /* not in extend */ pi_eval (); /* eval pi system */ sim_rtc_init (tim_unit.wait); /* init calibration */ -if (!ITS) its_1pr = 0; /* ~ITS, clr 1-proc */ +if (!Q_ITS) its_1pr = 0; /* ~ITS, clr 1-proc */ +t20_idlelock = 0; /* clr T20 idle lock */ /* Abort handling @@ -656,7 +662,7 @@ else if (abortval == PAGE_FAIL) { /* page fail */ if (rlog) xtcln (rlog); /* clean up extend */ rlog = 0; /* clear log */ if (pager_tc) flags = pager_flags; /* trap? get flags */ - if (T20) { /* TOPS-20 */ + if (T20PAG) { /* TOPS-20 paging? */ WriteP (upta + UPT_T20_PFL, pager_word); /* write page fail wd */ WriteP (upta + UPT_T20_OFL, XWD (flags, 0)); WriteP (upta + UPT_T20_OPC, pager_PC); @@ -664,7 +670,7 @@ else if (abortval == PAGE_FAIL) { /* page fail */ } else { a10 ea; /* TOPS-10 or ITS */ - if (ITS) { /* ITS? */ + if (Q_ITS) { /* ITS? */ ea = epta + EPT_ITS_PAG + (pi_m2lvl[pi_act] * 3); if (its_1pr) flags = flags | F_1PR; /* store 1-proc */ its_1pr = 0; /* clear 1-proc */ @@ -715,7 +721,7 @@ if (qintr) { else inst = ReadP (epta + EPT_PIIT + (2 * qintr)); op = GET_OP (inst); /* get opcode */ ac = GET_AC (inst); /* get ac */ - if (its_1pr && ITS) { /* 1-proc set? */ + if (its_1pr && Q_ITS) { /* 1-proc set? */ flags = flags | F_1PR; /* store 1-proc */ its_1pr = 0; /* clear 1-proc */ } @@ -846,12 +852,12 @@ case 0037: Write (040, UUOWORD, MM_CUR); /* store op, ac, ea */ /* case 0100: MUUO /* UJEN */ /* case 0101: MUUO /* unassigned */ -case 0102: if (ITS && !TSTF (F_USR)) { /* GFAD (KL), XCTRI (ITS) */ +case 0102: if (Q_ITS && !TSTF (F_USR)) { /* GFAD (KL), XCTRI (ITS) */ inst = Read (ea, MM_OPND); pflgs = pflgs | ac; goto XCT; } goto MUUO; -case 0103: if (ITS && !TSTF (F_USR)) { /* GFSB (KL), XCTR (ITS) */ +case 0103: if (Q_ITS && !TSTF (F_USR)) { /* GFSB (KL), XCTR (ITS) */ inst = Read (ea, MM_OPND); pflgs = pflgs | ac; goto XCT; } @@ -977,7 +983,7 @@ case 0243: AC(P1) = jffo (AC(ac)); /* JFFO */ case 0244: ashc (ac, ea); break; /* ASHC */ case 0245: rotc (ac, ea); break; /* ROTC */ case 0246: lshc (ac, ea); break; /* LSHC */ -case 0247: if (ITS) circ (ac, ea); break; /* (ITS) CIRC */ +case 0247: if (Q_ITS) circ (ac, ea); break; /* (ITS) CIRC */ case 0250: RM; WRAC; AC(ac) = mb; break; /* EXCH */ case 0251: blt (ac, ea, pflgs); break; /* BLT */ case 0252: AOBAC; if (TGE (AC(ac))) JUMP (ea); break; /* AOBJP */ @@ -991,9 +997,10 @@ case 0255: if (flags & (ac << 14)) { /* JFCL */ case 0256: if (xct_cnt++ >= xct_max) /* XCT */ ABORT (STOP_XCT); inst = Read (ea, MM_OPND); - if (ac && !TSTF (F_USR) && !ITS) pflgs = pflgs | ac; + if (ac && !TSTF (F_USR) && !Q_ITS) + pflgs = pflgs | ac; goto XCT; -case 0257: if (ITS) goto MUUO; /* MAP */ +case 0257: if (Q_ITS) goto MUUO; /* MAP */ AC(ac) = map (ea, MM_OPND); break; case 0260: WRP (FLPC); AOBAC; /* PUSHJ */ SUBJ (ea); PUSHF; break; @@ -1054,7 +1061,12 @@ case 0340: AOJ; break; /* AOJ */ case 0341: AOJ; if (TL (AC(ac))) JUMP (ea); break; /* AOJL */ case 0342: AOJ; if (TE (AC(ac))) JUMP (ea); break; /* AOJE */ case 0343: AOJ; if (TLE (AC(ac))) JUMP (ea); break; /* AOJLE */ -case 0344: AOJ; JUMP(ea); break; /* AOJA */ +case 0344: AOJ; JUMP(ea); /* AOJA */ + if (Q_ITS && Q_IDLE && /* ITS idle? */ + TSTF (F_USR) && (pager_PC == 017) && /* user mode, loc 17? */ + (ac == 0) && (ea == 017)) /* AOJA 0,17? */ + sim_idle (0, FALSE); + break; case 0345: AOJ; if (TGE (AC(ac))) JUMP (ea); break; /* AOJGE */ case 0346: AOJ; if (TN (AC(ac))) JUMP (ea); break; /* AOJN */ case 0347: AOJ; if (TG (AC(ac))) JUMP (ea); break; /* AOJG */ @@ -1073,7 +1085,22 @@ case 0363: SOJ; if (TLE (AC(ac))) JUMP (ea); break; /* SOJLE */ case 0364: SOJ; JUMP(ea); break; /* SOJA */ case 0365: SOJ; if (TGE (AC(ac))) JUMP (ea); break; /* SOJGE */ case 0366: SOJ; if (TN (AC(ac))) JUMP (ea); break; /* SOJN */ -case 0367: SOJ; if (TG (AC(ac))) JUMP (ea); break; /* SOJG */ +case 0367: SOJ; if (TG (AC(ac))) JUMP (ea); /* SOJG */ + if ((ea == pager_PC) && Q_IDLE) { /* to self, idle enab? */ + extern int32 tmr_poll; + if ((ac == 6) && (ea == 1) && /* SOJG 6,1? */ + TSTF (F_USR) && Q_T10) /* T10, user mode? */ + sim_idle (0, FALSE); + else if (!t20_idlelock && /* interlock off? */ + (ac == 2) && (ea == 3) && /* SOJG 2,3? */ + !TSTF (F_USR) && Q_T20 && /* T20, mon mode? */ + (sim_interval > (tmr_poll >> 1))) { /* >= half clock? */ + t20_idlelock = 1; /* set interlock */ + if (sim_os_ms_sleep (1)) /* sleep 1ms */ + sim_interval = 0; /* if ok, sched event */ + } + } + break; case 0370: SOS; break; /* SOS */ case 0371: SOS; if (TL (mb)) INCPC; break; /* SOSL */ case 0372: SOS; if (TE (mb)) INCPC; break; /* SOSE */ @@ -1331,7 +1358,7 @@ case 0725: IOA; io725 (AC(ac), ea); break; /* BCIOB, IOWRBQ */ default: MUUO: its_2pr = 0; /* clear trap */ - if (T20) { /* TOPS20? */ + if (T20PAG) { /* TOPS20 paging? */ int32 tf = (op << (INST_V_OP - 18)) | (ac << (INST_V_AC - 18)); WriteP (upta + UPT_MUUO, XWD ( /* store flags,,op+ac */ flags & ~(F_T2 | F_T1), tf)); /* traps clear */ @@ -1425,7 +1452,7 @@ case 0254: /* JRST */ break; case 015: /* JRST 15 = XJRST */ - if (!T20) goto MUUO; /* only in TOPS20 */ + if (!T20PAG) goto MUUO; /* only in TOPS20 paging */ JUMP (Read (ea, MM_OPND)); /* jump to M[ea] */ break; } /* end case subop */ @@ -1434,14 +1461,14 @@ case 0254: /* JRST */ if (its_2pr) { /* 1-proc trap? */ its_1pr = its_2pr = 0; /* clear trap */ - if (ITS) { /* better be ITS */ + if (Q_ITS) { /* better be ITS */ WriteP (upta + UPT_1PO, FLPC); /* wr old flgs, PC */ mb = ReadP (upta + UPT_1PN); /* rd new flgs, PC */ JUMP (mb); /* set PC */ set_newflags (mb, TRUE); /* set new flags */ } } /* end if 2-proc */ -} /* end for */ +} /* end for */ /* Should never get here */ @@ -2017,7 +2044,7 @@ return; t_bool aprid (a10 ea, int32 prv) { -Write (ea, (ITS)? UC_AIDITS: UC_AIDDEC, prv); +Write (ea, (Q_ITS)? UC_AIDITS: UC_AIDDEC, prv); return FALSE; } @@ -2069,7 +2096,7 @@ if (jrst && TSTF (F_USR)) { /* if in user now */ fl = fl | F_USR; /* can't clear user */ if (!TSTF (F_UIO)) fl = fl & ~F_UIO; /* if !UIO, can't set */ } -if (ITS && (fl & F_1PR)) { /* ITS 1-proceed? */ +if (Q_ITS && (fl & F_1PR)) { /* ITS 1-proceed? */ its_1pr = 1; /* set flag */ fl = fl & ~F_1PR; /* vanish bit */ } @@ -2177,7 +2204,7 @@ pi_enb = pi_act = pi_prq = 0; /* clear PI */ apr_enb = apr_flg = apr_lvl = 0; /* clear APR */ pcst = 0; /* clear PC samp */ rlog = 0; /* clear reg log */ -hsb = (ITS)? UC_HSBITS: UC_HSBDEC; /* set HSB */ +hsb = (Q_ITS)? UC_HSBITS: UC_HSBDEC; /* set HSB */ set_dyn_ptrs (); set_ac_display (ac_cur); pi_eval (); diff --git a/PDP10/pdp10_defs.h b/PDP10/pdp10_defs.h index 62d4df48..7bd35852 100644 --- a/PDP10/pdp10_defs.h +++ b/PDP10/pdp10_defs.h @@ -1,6 +1,6 @@ /* pdp10_defs.h: PDP-10 simulator definitions - Copyright (c) 1993-2005, Robert M Supnik + Copyright (c) 1993-2007, 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,8 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 01-Feb-07 RMS Added CD support + 29-Oct-06 RMS Added clock coscheduling function 29-Dec-03 RMS Added Q18 definition for PDP11 compatibility 19-May-03 RMS Revised for new conditional compilation scheme 09-Jan-03 RMS Added DEUNA/DELUA support @@ -122,10 +124,16 @@ typedef t_int64 d10; /* PDP-10 data (36b) */ /* Operating system flags, kept in cpu_unit.flags */ #define UNIT_V_ITS (UNIT_V_UF) /* ITS */ +#define UNIT_V_T20 (UNIT_V_UF + 1) /* TOPS-20 */ +#define UNIT_V_KLAD (UNIT_V_UF + 2) /* diagnostics */ #define UNIT_ITS (1 << UNIT_V_ITS) -#define UNIT_V_T20V41 (UNIT_V_UF + 1) /* TOPS-20 V4.1 */ -#define UNIT_T20V41 (1 << UNIT_V_T20V41) -#define ITS (cpu_unit.flags & UNIT_ITS) +#define UNIT_T20 (1 << UNIT_V_T20) +#define UNIT_KLAD (1 << UNIT_V_KLAD) +#define Q_T10 ((cpu_unit.flags & (UNIT_ITS|UNIT_T20|UNIT_KLAD)) == 0) +#define Q_ITS (cpu_unit.flags & UNIT_ITS) +#define Q_T20 (cpu_unit.flags & UNIT_T20) +#define Q_KLAD (cpu_unit.flags & UNIT_KLAD) +#define Q_IDLE (sim_idle_enab) /* Architectural constants */ @@ -384,7 +392,7 @@ typedef t_int64 d10; /* PDP-10 data (36b) */ #define EBR_MASK (EBR_T20P | EBR_PGON | (EBR_M_EBR << EBR_V_EBR)) #define EBR_GETEBR(x) ((int32) (((x) >> EBR_V_EBR) & PAG_M_PPN)) #define PAGING (ebr & EBR_PGON) -#define T20 (ebr & EBR_T20P) +#define T20PAG (ebr & EBR_T20P) /* AC and mapping contexts @@ -647,6 +655,8 @@ typedef struct pdp_dib DIB; #define IOLN_UBMNT3 001 #define IOBA_XU (IO_UBA3 + 0774510) /* DEUNA/DELUA */ #define IOLN_XU 010 +#define IOBA_CR (IO_UBA3 + 0777160) /* CD/CR/CM */ +#define IOLN_CR 010 #define IOBA_RY (IO_UBA3 + 0777170) /* RX211 */ #define IOLN_RY 004 #define IOBA_TU (IO_UBA3 + 0772440) /* RH11/tape */ @@ -689,6 +699,7 @@ typedef struct pdp_dib DIB; #define INT_V_PTR 24 /* PC11 */ #define INT_V_PTP 25 #define INT_V_LP20 26 /* LPT20 */ +#define INT_V_CR 27 /* CD20 (CD11) */ #define INT_RP (1u << INT_V_RP) #define INT_TU (1u << INT_V_TU) @@ -699,6 +710,7 @@ typedef struct pdp_dib DIB; #define INT_PTR (1u << INT_V_PTR) #define INT_PTP (1u << INT_V_PTP) #define INT_LP20 (1u << INT_V_LP20) +#define INT_CR (1u << INT_V_CR) #define IPL_RP 6 /* int levels */ #define IPL_TU 6 @@ -709,6 +721,7 @@ typedef struct pdp_dib DIB; #define IPL_PTR 4 #define IPL_PTP 4 #define IPL_LP20 4 +#define IPL_CR 4 #define INT_UB1 INT_RP /* on Unibus 1 */ #define INT_UB3 (0xFFFFFFFFu & ~INT_UB1) /* on Unibus 3 */ @@ -723,6 +736,7 @@ typedef struct pdp_dib DIB; #define VEC_PTP 0074 #define VEC_XU 0120 #define VEC_TU 0224 +#define VEC_CR 0230 #define VEC_RP 0254 #define VEC_RY 0264 #define VEC_DZRX 0340 @@ -748,4 +762,10 @@ t_stat set_vec (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat show_vec (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat auto_config (char *name, int32 num); +int32 clk_cosched (int32 wait); + +/* Global data */ + +extern t_bool sim_idle_enab; + #endif diff --git a/PDP10/pdp10_fe.c b/PDP10/pdp10_fe.c index 9fc91794..119551e9 100644 --- a/PDP10/pdp10_fe.c +++ b/PDP10/pdp10_fe.c @@ -1,6 +1,6 @@ /* pdp10_fe.c: PDP-10 front end (console terminal) simulator - Copyright (c) 1993-2004, Robert M Supnik + Copyright (c) 1993-2006, 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 @@ fe KS10 console front end + 17-Oct-06 RMS Synced keyboard to clock for idling 28-May-04 RMS Removed SET FE CTRL-C 29-Dec-03 RMS Added console backpressure support 25-Apr-03 RMS Revised for extended file support @@ -40,6 +41,7 @@ extern d10 *M; extern int32 apr_flg; +extern int32 tmxr_poll; t_stat fei_svc (UNIT *uptr); t_stat feo_svc (UNIT *uptr); t_stat fe_reset (DEVICE *dptr); @@ -56,14 +58,14 @@ t_stat fe_stop_os (UNIT *uptr, int32 val, char *cptr, void *desc); #define feo_unit fe_unit[1] UNIT fe_unit[] = { - { UDATA (&fei_svc, 0, 0), KBD_POLL_WAIT }, + { UDATA (&fei_svc, 0, 0), 0 }, { UDATA (&feo_svc, 0, 0), SERIAL_OUT_WAIT } }; REG fe_reg[] = { { ORDATA (IBUF, fei_unit.buf, 8) }, { DRDATA (ICOUNT, fei_unit.pos, T_ADDR_W), REG_RO + PV_LEFT }, - { DRDATA (ITIME, fei_unit.wait, 24), REG_NZ + PV_LEFT }, + { DRDATA (ITIME, fei_unit.wait, 24), PV_LEFT }, { ORDATA (OBUF, feo_unit.buf, 8) }, { DRDATA (OCOUNT, feo_unit.pos, T_ADDR_W), REG_RO + PV_LEFT }, { DRDATA (OTIME, feo_unit.wait, 24), REG_NZ + PV_LEFT }, @@ -139,12 +141,12 @@ t_stat fei_svc (UNIT *uptr) { int32 temp; -sim_activate (&fei_unit, fei_unit.wait); /* continue poll */ +sim_activate (uptr, KBD_WAIT (uptr->wait, tmxr_poll)); /* continue poll */ if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */ if (temp & SCPE_BREAK) return SCPE_OK; /* ignore break */ -fei_unit.buf = temp & 0177; -fei_unit.pos = fei_unit.pos + 1; -M[FE_CTYIN] = fei_unit.buf | FE_CVALID; /* put char in mem */ +uptr->buf = temp & 0177; +uptr->pos = uptr->pos + 1; +M[FE_CTYIN] = uptr->buf | FE_CVALID; /* put char in mem */ apr_flg = apr_flg | APRF_CON; /* interrupt KS10 */ return SCPE_OK; } @@ -156,7 +158,7 @@ t_stat fe_reset (DEVICE *dptr) fei_unit.buf = feo_unit.buf = 0; M[FE_CTYIN] = M[FE_CTYOUT] = 0; apr_flg = apr_flg & ~(APRF_ITC | APRF_CON); -sim_activate (&fei_unit, fei_unit.wait); /* start input poll */ +sim_activate_abs (&fei_unit, KBD_WAIT (fei_unit.wait, tmxr_poll)); return SCPE_OK; } diff --git a/PDP10/pdp10_ksio.c b/PDP10/pdp10_ksio.c index 4dbf90d1..5ec67958 100644 --- a/PDP10/pdp10_ksio.c +++ b/PDP10/pdp10_ksio.c @@ -188,14 +188,14 @@ DIB *std_dib[] = { /* standard DIBs */ /* IO 710 (DEC) TIOE - test I/O word, skip if zero (ITS) IORDI - read word from Unibus 3 - returns TRUE if skip, FALSE otherwise + returns TRUE if skip, FALSE otherwise */ t_bool io710 (int32 ac, a10 ea) { d10 val; -if (ITS) AC(ac) = ReadIO (IO_UBA3 | ea); /* IORDI */ +if (Q_ITS) AC(ac) = ReadIO (IO_UBA3 | ea); /* IORDI */ else { /* TIOE */ val = ReadIO (ea); /* read word */ if ((AC(ac) & val) == 0) return TRUE; @@ -205,14 +205,14 @@ return FALSE; /* IO 711 (DEC) TION - test I/O word, skip if non-zero (ITS) IORDQ - read word from Unibus 1 - returns TRUE if skip, FALSE otherwise + returns TRUE if skip, FALSE otherwise */ t_bool io711 (int32 ac, a10 ea) { d10 val; -if (ITS) AC(ac) = ReadIO (IO_UBA1 | ea); /* IORDQ */ +if (Q_ITS) AC(ac) = ReadIO (IO_UBA1 | ea); /* IORDQ */ else { /* TION */ val = ReadIO (ea); /* read word */ if ((AC(ac) & val) != 0) return TRUE; @@ -248,7 +248,7 @@ void io714 (d10 val, a10 ea) d10 temp; val = val & 0177777; -if (ITS) WriteIO (IO_UBA3 | ea, val, WRITE); /* IOWRI */ +if (Q_ITS) WriteIO (IO_UBA3 | ea, val, WRITE); /* IOWRI */ else { temp = ReadIO (ea); /* BSIO */ temp = temp | val; @@ -266,7 +266,7 @@ void io715 (d10 val, a10 ea) d10 temp; val = val & 0177777; -if (ITS) WriteIO (IO_UBA1 | ea, val, WRITE); /* IOWRQ */ +if (Q_ITS) WriteIO (IO_UBA1 | ea, val, WRITE); /* IOWRQ */ else { temp = ReadIO (ea); /* BCIO */ temp = temp & ~val; @@ -277,14 +277,14 @@ return; /* IO 720 (DEC) TIOEB - test I/O byte, skip if zero (ITS) IORDBI - read byte from Unibus 3 - returns TRUE if skip, FALSE otherwise + returns TRUE if skip, FALSE otherwise */ t_bool io720 (int32 ac, a10 ea) { d10 val; -if (ITS) { /* IORDBI */ +if (Q_ITS) { /* IORDBI */ val = ReadIO (IO_UBA3 | eaRB); AC(ac) = GETBYTE (ea, val); } @@ -298,14 +298,14 @@ return FALSE; /* IO 721 (DEC) TIONB - test I/O word, skip if non-zero (ITS) IORDBQ - read word from Unibus 1 - returns TRUE if skip, FALSE otherwise + returns TRUE if skip, FALSE otherwise */ t_bool io721 (int32 ac, a10 ea) { d10 val; -if (ITS) { /* IORDBQ */ +if (Q_ITS) { /* IORDBQ */ val = ReadIO (IO_UBA1 | eaRB); AC(ac) = GETBYTE (ea, val); } @@ -348,7 +348,7 @@ void io724 (d10 val, a10 ea) d10 temp; val = val & 0377; -if (ITS) WriteIO (IO_UBA3 | ea, val, WRITEB); /* IOWRBI */ +if (Q_ITS) WriteIO (IO_UBA3 | ea, val, WRITEB); /* IOWRBI */ else { temp = ReadIO (eaRB); /* BSIOB */ temp = GETBYTE (ea, temp); @@ -367,7 +367,7 @@ void io725 (d10 val, a10 ea) d10 temp; val = val & 0377; -if (ITS) WriteIO (IO_UBA1 | ea, val, WRITEB); /* IOWRBQ */ +if (Q_ITS) WriteIO (IO_UBA1 | ea, val, WRITEB); /* IOWRBQ */ else { temp = ReadIO (eaRB); /* BCIOB */ temp = GETBYTE (ea, temp); diff --git a/PDP10/pdp10_pag.c b/PDP10/pdp10_pag.c index 07a1ae35..07b5eebc 100644 --- a/PDP10/pdp10_pag.c +++ b/PDP10/pdp10_pag.c @@ -312,7 +312,7 @@ int32 ptbl_fill (a10 ea, int32 *tbl, int32 mode) ITS has no MAP instruction, therefore, physical NXM traps are ok. */ -if (ITS) { /* ITS paging */ +if (Q_ITS) { /* ITS paging */ int32 acc, decvpn, pte, vpn, ptead, xpte; d10 ptewd; @@ -349,7 +349,7 @@ if (ITS) { /* ITS paging */ user process tables. */ -else if (!T20) { /* TOPS-10 paging */ +else if (!T20PAG) { /* TOPS-10 paging */ int32 pte, vpn, ptead, xpte; d10 ptewd; @@ -377,7 +377,7 @@ else if (!T20) { /* TOPS-10 paging */ PAGE_FAIL_TRAP; } /* end TOPS10 paging */ -/* TOPS-20 paging - checked against KS10 ucode. +/* TOPS-20 paging - checked against KS10 microcode TOPS-20 paging has three phases: @@ -549,7 +549,7 @@ else { } t = EBR_GETEBR (ebr); epta = t << PAG_V_PN; -if (ITS) upta = (int32) ubr & PAMASK; +if (Q_ITS) upta = (int32) ubr & PAMASK; else { t = UBR_GETUBR (ubr); upta = t << PAG_V_PN; @@ -601,7 +601,7 @@ t_bool clrpt (a10 ea, int32 prv) { int32 vpn = PAG_GETVPN (ea); /* get page num */ -if (ITS) { /* ITS? */ +if (Q_ITS) { /* ITS? */ uptbl[vpn & ~1] = 0; /* clear double size */ uptbl[vpn | 1] = 0; /* entries in */ eptbl[vpn & ~1] = 0; /* both page tables */ @@ -631,7 +631,7 @@ return FALSE; t_bool wrubr (a10 ea, int32 prv) { d10 val = Read (ea, prv); -d10 ubr_mask = (ITS)? PAMASK: UBR_UBRMASK; /* ITS: ubr is wd addr */ +d10 ubr_mask = (Q_ITS)? PAMASK: UBR_UBRMASK; /* ITS: ubr is wd addr */ if (val & UBR_SETACB) ubr = ubr & ~UBR_ACBMASK; /* set AC's? */ else val = val & ~UBR_ACBMASK; /* no, keep old val */ @@ -647,7 +647,7 @@ return FALSE; t_bool rdubr (a10 ea, int32 prv) { -ubr = ubr & (UBR_ACBMASK | (ITS? PAMASK: UBR_UBRMASK)); +ubr = ubr & (UBR_ACBMASK | (Q_ITS? PAMASK: UBR_UBRMASK)); Write (ea, UBRWORD, prv); return FALSE; } @@ -705,7 +705,7 @@ return FALSE; t_bool wrcstm (a10 ea, int32 prv) { cstm = Read (ea, prv); -if ((cpu_unit.flags & UNIT_T20V41) && (ea == 040127)) +if ((cpu_unit.flags & UNIT_T20) && (ea == 040127)) cstm = 0770000000000; return FALSE; } diff --git a/PDP10/pdp10_rp.c b/PDP10/pdp10_rp.c index 40763dde..c384eb6b 100644 --- a/PDP10/pdp10_rp.c +++ b/PDP10/pdp10_rp.c @@ -803,8 +803,8 @@ switch (fnc) { /* case on function */ break; } if ((GET_CY (dc) >= drv_tab[dtype].cyl) || /* bad cylinder */ - (GET_SF (rpda[drv]) >= drv_tab[dtype].surf) || /* bad surface */ - (GET_SC (rpda[drv]) >= drv_tab[dtype].sect)) { /* or bad sector? */ + (GET_SF (rpda[drv]) >= drv_tab[dtype].surf) || /* bad surface */ + (GET_SC (rpda[drv]) >= drv_tab[dtype].sect)) { /* or bad sector? */ set_rper (ER1_IAE, drv); break; } @@ -827,8 +827,8 @@ switch (fnc) { /* case on function */ rpcs2 = rpcs2 & ~CS2_ERR; /* clear errors */ rpcs1 = rpcs1 & ~(CS1_TRE | CS1_MCPE | CS1_DONE); if ((GET_CY (dc) >= drv_tab[dtype].cyl) || /* bad cylinder */ - (GET_SF (rpda[drv]) >= drv_tab[dtype].surf) || /* bad surface */ - (GET_SC (rpda[drv]) >= drv_tab[dtype].sect)) { /* or bad sector? */ + (GET_SF (rpda[drv]) >= drv_tab[dtype].surf) || /* bad surface */ + (GET_SC (rpda[drv]) >= drv_tab[dtype].sect)) { /* or bad sector? */ set_rper (ER1_IAE, drv); break; } @@ -909,7 +909,7 @@ switch (uptr->FUNC) { /* case on function */ case FNC_READH: /* read headers */ ba = GET_UAE (rpcs1) | rpba; /* get byte addr */ wc10 = (0200000 - rpwc) >> 1; /* get PDP-10 wc */ - da = GET_DA (rpdc[drv], rpda[drv], dtype) * RP_NUMWD; /* get disk addr */ + da = GET_DA (rpdc[drv], rpda[drv], dtype) * RP_NUMWD; /* get disk addr */ if ((da + wc10) > drv_tab[dtype].size) { /* disk overrun? */ set_rper (ER1_AOE, drv); if (wc10 > (drv_tab[dtype].size - da)) @@ -1256,7 +1256,7 @@ extern a10 saved_PC; M[FE_UNIT] = unitno & CS2_M_UNIT; for (i = 0; i < BOOT_LEN; i++) - M[BOOT_START + i] = ITS? boot_rom_its[i]: boot_rom_dec[i]; + M[BOOT_START + i] = Q_ITS? boot_rom_its[i]: boot_rom_dec[i]; saved_PC = BOOT_START; return SCPE_OK; } diff --git a/PDP10/pdp10_sys.c b/PDP10/pdp10_sys.c index 47b2ffde..e22c6d7f 100644 --- a/PDP10/pdp10_sys.c +++ b/PDP10/pdp10_sys.c @@ -1,6 +1,6 @@ /* pdp10_sys.c: PDP-10 simulator interface - Copyright (c) 1993-2005, Robert M Supnik + Copyright (c) 1993-2007, 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. + 01-Feb-07 RMS Added CD support 22-Jul-05 RMS Fixed warning from Solaris C (from Doug Gwyn) 09-Jan-03 RMS Added DEUNA/DELUA support 12-Sep-02 RMS Added RX211 support @@ -40,11 +41,18 @@ #include "pdp10_defs.h" #include -extern DEVICE cpu_dev, pag_dev; -extern DEVICE tim_dev, fe_dev, uba_dev; -extern DEVICE ptr_dev, ptp_dev; -extern DEVICE rp_dev, tu_dev; -extern DEVICE dz_dev, ry_dev; +extern DEVICE cpu_dev; +extern DEVICE pag_dev; +extern DEVICE tim_dev; +extern DEVICE fe_dev; +extern DEVICE uba_dev; +extern DEVICE ptr_dev; +extern DEVICE ptp_dev; +extern DEVICE rp_dev; +extern DEVICE tu_dev; +extern DEVICE dz_dev; +extern DEVICE ry_dev; +extern DEVICE cr_dev; extern DEVICE lp20_dev; extern DEVICE xu_dev; extern UNIT cpu_unit; @@ -78,6 +86,7 @@ DEVICE *sim_devices[] = { &ptp_dev, &ry_dev, &lp20_dev, + &cr_dev, &rp_dev, &tu_dev, &dz_dev, @@ -693,7 +702,7 @@ dev = GET_DEV (inst); for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ j = (int32) ((opc_val[i] >> I_V_FL) & I_M_FL); /* get class */ if (((opc_val[i] & DMASK) == (inst & masks[j])) && /* match? */ - (((opc_val[i] & I_ITS) == 0) || ITS)) { + (((opc_val[i] & I_ITS) == 0) || Q_ITS)) { fprintf (of, "%s ", opcode[i]); /* opcode */ switch (j) { /* case on class */ diff --git a/PDP10/pdp10_tim.c b/PDP10/pdp10_tim.c index 3029d54b..7ff193f4 100644 --- a/PDP10/pdp10_tim.c +++ b/PDP10/pdp10_tim.c @@ -1,6 +1,6 @@ /* pdp10_tim.c: PDP-10 tim subsystem simulator - Copyright (c) 1993-2005, Robert M Supnik + Copyright (c) 1993-2006, 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 @@ tim timer subsystem + 03-Nov-06 RMS Rewritten to support idling + 29-Oct-06 RMS Added clock coscheduling function 02-Feb-04 RMS Exported variables needed by Ethernet simulator 29-Jan-02 RMS New data structures 06-Jan-02 RMS Added enable/disable support @@ -37,41 +39,61 @@ #include "pdp10_defs.h" #include -#define TIM_N_HWRE 12 /* hwre bits */ -#define TIM_HWRE 0000000010000 /* hwre incr */ -#define TIM_DELAY 500 -#define TIM_TPS 1001 /* ticks per sec */ -#define DZ_MULT (TIM_TPS / 60) /* DZ poll multiplier */ -#define TB_MASK 037777777777777777777; /* 71 - 12 bits */ -#define UNIT_V_Y2K (UNIT_V_UF) /* Y2K compliant OS */ +/* Invariants */ + +#define TIM_HW_FREQ 4100000 /* 4.1Mhz */ +#define TIM_HWRE_MASK 07777 +#define UNIT_V_Y2K (UNIT_V_UF + 0) /* Y2K compliant OS */ #define UNIT_Y2K (1u << UNIT_V_Y2K) +/* Clock mode TOPS-10/ITS */ + +#define TIM_TPS_T10 60 +#define TIM_WAIT_T10 8000 +#define TIM_MULT_T10 1 +#define TIM_ITS_QUANT (TIM_HW_FREQ / TIM_TPS_T10) + +/* Clock mode TOPS-20/KLAD */ + +#define TIM_TPS_T20 1001 +#define TIM_WAIT_T20 500 +#define TIM_MULT_T20 16 + +/* Probability function for TOPS-20 idlelock */ + +#define PROB(x) (((rand() * 100) / RAND_MAX) >= (x)) + +d10 tim_base[2] = { 0, 0 }; /* 71b timebase */ +d10 tim_ttg = 0; /* time to go */ +d10 tim_period = 0; /* period */ +d10 quant = 0; /* ITS quantum */ +int32 tim_mult = TIM_MULT_T10; /* tmxr poll mult */ +int32 tim_t20_prob = 33; /* TOPS-20 prob */ + +/* Exported variables */ + +int32 clk_tps = TIM_TPS_T10; /* clock ticks/sec */ +int32 tmr_poll = TIM_WAIT_T10; /* clock poll */ +int32 tmxr_poll = TIM_WAIT_T10 * TIM_MULT_T10; /* term mux poll */ + extern int32 apr_flg, pi_act; extern UNIT cpu_unit; extern d10 pcst; extern a10 pager_PC; -t_int64 timebase = 0; /* 71b timebase */ -d10 ttg = 0; /* time to go */ -d10 period = 0; /* period */ -d10 quant = 0; /* ITS quantum */ -int32 diagflg = 0; /* diagnostics? */ -int32 tmxr_poll = TIM_DELAY * DZ_MULT; /* term mux poll */ - -/* Exported variables */ - -int32 clk_tps = TIM_TPS; /* clock ticks/sec */ -int32 tmr_poll = TIM_DELAY; /* clock poll */ +extern int32 t20_idlelock; DEVICE tim_dev; t_stat tcu_rd (int32 *data, int32 PA, int32 access); -extern t_stat wr_nop (int32 data, int32 PA, int32 access); t_stat tim_svc (UNIT *uptr); t_stat tim_reset (DEVICE *dptr); +void tim_incr_base (d10 *base, d10 incr); + extern d10 Read (a10 ea, int32 prv); extern d10 ReadM (a10 ea, int32 prv); extern void Write (a10 ea, d10 val, int32 prv); extern void WriteP (a10 ea, d10 val); extern int32 pi_eval (void); +extern t_stat wr_nop (int32 data, int32 PA, int32 access); /* TIM data structures @@ -82,16 +104,19 @@ extern int32 pi_eval (void); DIB tcu_dib = { IOBA_TCU, IOLN_TCU, &tcu_rd, &wr_nop, 0 }; -UNIT tim_unit = { UDATA (&tim_svc, 0, 0), TIM_DELAY }; +UNIT tim_unit = { UDATA (&tim_svc, 0, 0), TIM_WAIT_T10 }; REG tim_reg[] = { - { ORDATA (TIMEBASE, timebase, 71 - TIM_N_HWRE) }, - { ORDATA (TTG, ttg, 36) }, - { ORDATA (PERIOD, period, 36) }, + { BRDATA (TIMEBASE, tim_base, 8, 36, 2) }, + { ORDATA (TTG, tim_ttg, 36) }, + { ORDATA (PERIOD, tim_period, 36) }, { ORDATA (QUANT, quant, 36) }, { DRDATA (TIME, tim_unit.wait, 24), REG_NZ + PV_LEFT }, - { FLDATA (DIAG, diagflg, 0) }, - { FLDATA (Y2K, tim_unit.flags, UNIT_V_Y2K), REG_HRO }, + { DRDATA (PROB, tim_t20_prob, 6), REG_NZ + PV_LEFT + REG_HIDDEN }, + { DRDATA (POLL, tmr_poll, 32), REG_HRO + PV_LEFT }, + { DRDATA (MUXPOLL, tmxr_poll, 32), REG_HRO + PV_LEFT }, + { DRDATA (MULT, tim_mult, 6), REG_HRO + PV_LEFT }, + { DRDATA (TPS, clk_tps, 12), REG_HRO + PV_LEFT }, { NULL } }; @@ -108,79 +133,135 @@ DEVICE tim_dev = { 1, 0, 0, 0, 0, 0, NULL, NULL, &tim_reset, NULL, NULL, NULL, - &tcu_dib, DEV_DISABLE | DEV_UBUS + &tcu_dib, DEV_UBUS }; /* Timer instructions */ +/* Timer - if the timer is running at less than hardware frequency, + need to interpolate the value by calculating how much of the current + clock tick has elapsed, and what that equates to in msec. */ + t_bool rdtim (a10 ea, int32 prv) { -ReadM (INCA (ea), prv); -Write (ea, (timebase >> (35 - TIM_N_HWRE)) & DMASK, prv); -Write (INCA(ea), (timebase << TIM_N_HWRE) & MMASK, prv); +d10 tempbase[2]; + +ReadM (INCA (ea), prv); /* check 2nd word */ +tempbase[0] = tim_base[0]; /* copy time base */ +tempbase[1] = tim_base[1]; +if (tim_mult != TIM_MULT_T20) { /* interpolate? */ + int32 used; + d10 incr; + used = tmr_poll - (sim_is_active (&tim_unit) - 1); + incr = (d10) (((double) used * TIM_HW_FREQ) / + ((double) tmr_poll * (double) clk_tps)); + tim_incr_base (tempbase, incr); + } +tempbase[0] = tempbase[0] & ~((d10) TIM_HWRE_MASK); /* clear low 12b */ +Write (ea, tempbase[0], prv); +Write (INCA(ea), tempbase[1], prv); return FALSE; } t_bool wrtim (a10 ea, int32 prv) { -timebase = (Read (ea, prv) << (35 - TIM_N_HWRE)) | - (CLRS (Read (INCA (ea), prv)) >> TIM_N_HWRE); +tim_base[0] = Read (ea, prv); +tim_base[1] = CLRS (Read (INCA (ea), prv)); return FALSE; } t_bool rdint (a10 ea, int32 prv) { -Write (ea, period, prv); +Write (ea, tim_period, prv); return FALSE; } t_bool wrint (a10 ea, int32 prv) { -period = Read (ea, prv); -ttg = period; +tim_period = Read (ea, prv); +tim_ttg = tim_period; return FALSE; } -/* Timer routines - - tim_svc process event (timer tick) - tim_reset process reset -*/ +/* Timer service - the timer is only serviced when the 'ttg' register + has reached 0 based on the expected frequency of clock interrupts. */ t_stat tim_svc (UNIT *uptr) { -int32 t; - -t = diagflg? tim_unit.wait: sim_rtc_calb (TIM_TPS); /* calibrate clock */ -sim_activate (&tim_unit, t); /* reactivate unit */ -tmr_poll = t; /* set timer poll */ -tmxr_poll = t * DZ_MULT; /* set mux poll */ -timebase = (timebase + 1) & TB_MASK; /* increment timebase */ -ttg = ttg - TIM_HWRE; /* decrement timer */ -if (ttg <= 0) { /* timeout? */ - ttg = period; /* reload */ - apr_flg = apr_flg | APRF_TIM; /* request interrupt */ - } -if (ITS) { /* ITS? */ - if (pi_act == 0) quant = (quant + TIM_HWRE) & DMASK; +if (cpu_unit.flags & UNIT_KLAD) /* diags? */ + tmr_poll = uptr->wait; /* fixed clock */ +else tmr_poll = sim_rtc_calb (clk_tps); /* else calibrate */ +sim_activate (uptr, tmr_poll); /* reactivate unit */ +tmxr_poll = tmr_poll * tim_mult; /* set mux poll */ +tim_incr_base (tim_base, tim_period); /* incr time base */ +tim_ttg = tim_period; /* reload */ +apr_flg = apr_flg | APRF_TIM; /* request interrupt */ +if (Q_ITS) { /* ITS? */ + if (pi_act == 0) + quant = (quant + TIM_ITS_QUANT) & DMASK; if (TSTS (pcst)) { /* PC sampling? */ WriteP ((a10) pcst & AMASK, pager_PC); /* store sample */ pcst = AOB (pcst); /* add 1,,1 */ } } /* end ITS */ +else if (t20_idlelock && PROB (100 - tim_t20_prob)) + t20_idlelock = 0; return SCPE_OK; } -t_stat tim_reset (DEVICE *dptr) +/* Clock coscheduling routine */ + +int32 clk_cosched (int32 wait) { int32 t; -period = ttg = 0; /* clear timer */ +if (tim_mult == TIM_MULT_T20) return wait; +t = sim_is_active (&tim_unit); +return (t? t - 1: wait); +} + +void tim_incr_base (d10 *base, d10 incr) +{ +base[1] = base[1] + incr; /* add on incr */ +base[0] = base[0] + (base[1] >> 35); /* carry to high */ +base[0] = base[0] & DMASK; /* mask high */ +base[1] = base[1] & MMASK; /* mask low */ +return; +} + +/* Timer reset */ + +t_stat tim_reset (DEVICE *dptr) +{ +tim_period = 0; /* clear timer */ +tim_ttg = 0; apr_flg = apr_flg & ~APRF_TIM; /* clear interrupt */ -t = sim_rtc_init (tim_unit.wait); /* init timer */ -sim_activate (&tim_unit, t); /* activate unit */ -tmr_poll = t; /* set timer poll */ -tmxr_poll = t * DZ_MULT; /* set mux poll */ +tmr_poll = sim_rtc_init (tim_unit.wait); /* init timer */ +sim_activate_abs (&tim_unit, tmr_poll); /* activate unit */ +tmxr_poll = tmr_poll * tim_mult; /* set mux poll */ +return SCPE_OK; +} + +/* Set timer parameters from CPU model */ + +t_stat tim_set_mod (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (val & (UNIT_T20|UNIT_KLAD)) { + clk_tps = TIM_TPS_T20; + uptr->wait = TIM_WAIT_T20; + tmr_poll = TIM_WAIT_T20; + tim_mult = TIM_MULT_T20; + uptr->flags = uptr->flags | UNIT_Y2K; + } +else { + clk_tps = TIM_TPS_T10; + uptr->wait = TIM_WAIT_T10; + tmr_poll = TIM_WAIT_T10; + tim_mult = TIM_MULT_T10; + if (Q_ITS) uptr->flags = uptr->flags | UNIT_Y2K; + else uptr->flags = uptr->flags & ~UNIT_Y2K; + } +tmxr_poll = tmr_poll * tim_mult; return SCPE_OK; } diff --git a/PDP10/pdp10_tu.c b/PDP10/pdp10_tu.c index eca2c472..e511383e 100644 --- a/PDP10/pdp10_tu.c +++ b/PDP10/pdp10_tu.c @@ -839,7 +839,7 @@ switch (fnc) { /* case on function */ tufs = tufs | FS_ATA; break; - case FNC_WREOF: /* write end of file */ + case FNC_WREOF: /* write end of file */ if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ r = tu_map_err (uptr, st, 0); /* map error */ tufs = tufs | FS_ATA; @@ -1225,7 +1225,7 @@ M[FE_UNIT] = 0; M[FE_MTFMT] = (unitno & TC_M_UNIT) | (TC_1600 << TC_V_DEN) | (TC_10C << TC_V_FMT); tu_unit[unitno].pos = 0; for (i = 0; i < BOOT_LEN; i++) - M[BOOT_START + i] = ITS? boot_rom_its[i]: boot_rom_dec[i]; + M[BOOT_START + i] = Q_ITS? boot_rom_its[i]: boot_rom_dec[i]; saved_PC = BOOT_START; return SCPE_OK; } diff --git a/PDP11/pdp11_cis.c b/PDP11/pdp11_cis.c index 162137b3..3f1e2e6b 100644 --- a/PDP11/pdp11_cis.c +++ b/PDP11/pdp11_cis.c @@ -700,7 +700,7 @@ switch (op) { /* case on opcode */ fpd = 1; /* set FPD */ R[4] = R[4] & 0377; /* mask fill */ c = t = 0; - for (i = 0; (R[0] || R[2]); ) { /* until cnts == 0 */ + for (i = 0; (R[0] || R[2]); ) { /* until cnts == 0 */ if (R[0]) c = ReadB (R[1] | dsenable); /* get src1 or fill */ else c = R[4]; if (R[2]) t = ReadB (R[3] | dsenable); /* get src2 or fill */ @@ -1192,15 +1192,18 @@ return TestDstr (src); /* clean -0 */ dsrc = decimal string descriptor src = decimal string structure flag = numeric/packed flag + PSW.NZ are also set to their proper values PSW.V will be set on overflow; it must be initialized elsewhere - (to allow for external overflow calculations) + (to allow for external overflow calculations) The rules for the stored sign and the PSW sign are: - - Stored sign is negative if input is negative, string type - is signed, and the result is non-zero or there was overflow - - PSW sign is negative if input is negative, string type is - signed, and the result is non-zero + + - Stored sign is negative if input is negative, string type + is signed, and the result is non-zero or there was overflow + - PSW sign is negative if input is negative, string type is + signed, and the result is non-zero + Thus, the stored sign and the PSW sign will differ in one case: a negative zero generated by overflow is stored with a negative sign, but PSW.N is clear @@ -1265,16 +1268,18 @@ return; cy = carry in Output = 1 if carry, 0 if no carry - This algorithm courtesy Anton Chernoff, circa 1992 or even earlier + This algorithm courtesy Anton Chernoff, circa 1992 or even earlier. We trace the history of a pair of adjacent digits to see how the carry is fixed; each parenthesized item is a 4b digit. Assume we are adding: + (a)(b) I + (x)(y) J First compute I^J: + (a^x)(b^y) TMP Note that the low bit of each digit is the same as the low bit of @@ -1283,6 +1288,7 @@ return; Now compute I+J+66 to get decimal addition with carry forced left one digit: + (a+x+6+carry mod 16)(b+y+6 mod 16) SUM Note that if there was a carry from b+y+6, then the low bit of the @@ -1357,6 +1363,7 @@ return 0; Arguments: dsrc = decimal string structure + Returns the non-zero length of the string, in int32 units If the string is zero, the sign is cleared */ @@ -1395,8 +1402,8 @@ return ((nz - 1) * 8) + i; mtable[10] = array of decimal string structures Note that dsrc has a high order zero nibble; this - guarantees that the largest multiple won't overflow - Also note that mtable[0] is not filled in + guarantees that the largest multiple won't overflow. + Also note that mtable[0] is not filled in. */ void CreateTable (DSTR *dsrc, DSTR mtable[10]) @@ -1560,7 +1567,7 @@ fpd = 0; /* instr done */ return; } -/* Test for CIS mid-instruction interrupt - stub for now */ +/* Test for CIS mid-instruction interrupt */ t_bool cis_int_test (int32 cycles, int32 oldpc, t_stat *st) { diff --git a/PDP11/pdp11_cpu.c b/PDP11/pdp11_cpu.c index 0bf28d5b..f40dd71c 100644 --- a/PDP11/pdp11_cpu.c +++ b/PDP11/pdp11_cpu.c @@ -25,6 +25,8 @@ cpu PDP-11 CPU + 27-Oct-06 RMS Added idle support + 18-Oct-06 RMS Fixed bug in ASH -32 C value 24-May-06 RMS Added instruction history 03-May-06 RMS Fixed XOR operand fetch order for 11/70-style systems 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) @@ -220,8 +222,8 @@ #define calc_is(md) ((md) << VA_V_MODE) #define calc_ds(md) (calc_is((md)) | ((MMR3 & dsmask[(md)])? VA_DS: 0)) #define calc_MMR1(val) ((MMR1)? (((val) << 8) | MMR1): (val)) -#define GET_SIGN_W(v) ((v) >> 15) -#define GET_SIGN_B(v) ((v) >> 7) +#define GET_SIGN_W(v) (((v) >> 15) & 1) +#define GET_SIGN_B(v) (((v) >> 7) & 1) #define GET_Z(v) ((v) == 0) #define JMP_PC(x) PCQ_ENTRY; PC = (x) #define BRANCH_F(x) PCQ_ENTRY; PC = (PC + (((x) + (x)) & 0377)) & 0177777 @@ -300,6 +302,7 @@ extern UNIT clk_unit, pclk_unit; extern int32 sim_int_char; extern uint32 sim_switches; extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern t_bool sim_idle_enab; extern DEVICE *sim_devices[]; extern CPUTAB cpu_tab[]; @@ -376,7 +379,7 @@ int32 trap_clear[TRAP_V_MAX] = { /* trap clears */ cpu_mod CPU modifier list */ -UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, INIMEMSIZE) }; +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX|UNIT_BINK, INIMEMSIZE) }; REG cpu_reg[] = { { ORDATA (PC, saved_PC, 16) }, @@ -533,7 +536,7 @@ REG cpu_reg[] = { { BRDATA (IREQ, int_req, 8, 32, IPL_HLVL), REG_RO }, { ORDATA (TRAPS, trap_req, TRAP_V_MAX) }, { FLDATA (WAIT, wait_state, 0) }, - { FLDATA (WAIT_ENABLE, wait_enable, 0) }, + { FLDATA (WAIT_ENABLE, wait_enable, 0), REG_HIDDEN }, { ORDATA (STOP_TRAPS, stop_trap, TRAP_V_MAX) }, { FLDATA (STOP_VECA, stop_vecabort, 0) }, { FLDATA (STOP_SPA, stop_spabort, 0) }, @@ -583,6 +586,8 @@ MTAB cpu_mod[] = { { MTAB_XTD|MTAB_VDV, OPT_CIS, NULL, "NOCIS", &cpu_clr_opt }, { MTAB_XTD|MTAB_VDV, OPT_MMU, NULL, "MMU", &cpu_set_opt }, { MTAB_XTD|MTAB_VDV, OPT_MMU, NULL, "NOMMU", &cpu_clr_opt }, + { MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL }, { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size}, { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size}, { UNIT_MSIZE, 49152, NULL, "48K", &cpu_set_size}, @@ -786,8 +791,11 @@ while (reason == 0) { if (tbit) setTRAP (TRAP_TRC); if (wait_state) { /* wait state? */ - if (sim_qcount () != 0) sim_interval = 0; /* force check */ - else reason = STOP_WAIT; + if (sim_idle_enab) /* idle enabled? */ + sim_idle (TMR_CLK, TRUE); + else if (wait_enable) /* old style idle? */ + sim_interval = 0; /* force check */ + else sim_interval = sim_interval - 1; /* count cycle */ continue; } @@ -846,7 +854,7 @@ while (reason == 0) { else setTRAP (TRAP_ILL); /* no, ill inst */ break; case 1: /* WAIT */ - if (wait_enable) wait_state = 1; + wait_state = 1; break; case 3: /* BPT */ setTRAP (TRAP_BPT); @@ -1374,7 +1382,7 @@ while (reason == 0) { else PWriteW (dst, last_pa); break; -/* Opcode 07: EIS, FIS (not implemented), CIS +/* Opcode 07: EIS, FIS, CIS Notes: - The code assumes that the host int length is at least 32 bits. @@ -1471,7 +1479,8 @@ while (reason == 0) { } else if (src2 == 32) { /* [32] = -32 */ dst = -sign; - V = C = 0; + V = 0; + C = sign; } else { /* [33,63] = -31,-1 */ dst = (src >> (64 - src2)) | (-sign << (src2 - 32)); @@ -1505,7 +1514,7 @@ while (reason == 0) { else if (src2 == 32) { /* [32] = -32 */ dst = -sign; V = 0; - C = (src >> 31) & 1; + C = sign; } else { /* [33,63] = -31,-1 */ dst = (src >> (64 - src2)) | (-sign << (src2 - 32)); @@ -2136,7 +2145,7 @@ if ((va & 1) && CPUT (HAS_ODD)) { /* odd address? */ } pa = relocR (va); /* relocate */ if (ADDR_IS_MEM (pa)) return (M[pa >> 1]); /* memory address? */ -if ((pa < IOPAGEBASE) || /* I/O address */ +if ((pa < IOPAGEBASE) || /* not I/O address */ (CPUT (CPUT_J) && (pa >= IOBA_CPU))) { /* or J11 int reg? */ setCPUERR (CPUE_NXM); ABORT (TRAP_NXM); @@ -2158,7 +2167,7 @@ if ((va & 1) && CPUT (HAS_ODD)) { /* odd address? */ } pa = relocR (va); /* relocate */ if (ADDR_IS_MEM (pa)) return (M[pa >> 1]); /* memory address? */ -if (pa < IOPAGEBASE) { /* I/O address? */ +if (pa < IOPAGEBASE) { /* not I/O address? */ setCPUERR (CPUE_NXM); ABORT (TRAP_NXM); } @@ -2175,7 +2184,7 @@ int32 pa, data; pa = relocR (va); /* relocate */ if (ADDR_IS_MEM (pa)) return (va & 1? M[pa >> 1] >> 8: M[pa >> 1]) & 0377; -if (pa < IOPAGEBASE) { /* I/O address? */ +if (pa < IOPAGEBASE) { /* not I/O address? */ setCPUERR (CPUE_NXM); ABORT (TRAP_NXM); } @@ -2196,7 +2205,7 @@ if ((va & 1) && CPUT (HAS_ODD)) { /* odd address? */ } last_pa = relocW (va); /* reloc, wrt chk */ if (ADDR_IS_MEM (last_pa)) return (M[last_pa >> 1]); /* memory address? */ -if (last_pa < IOPAGEBASE) { /* I/O address? */ +if (last_pa < IOPAGEBASE) { /* not I/O address? */ setCPUERR (CPUE_NXM); ABORT (TRAP_NXM); } @@ -2214,7 +2223,7 @@ int32 data; last_pa = relocW (va); /* reloc, wrt chk */ if (ADDR_IS_MEM (last_pa)) return (va & 1? M[last_pa >> 1] >> 8: M[last_pa >> 1]) & 0377; -if (last_pa < IOPAGEBASE) { /* I/O address? */ +if (last_pa < IOPAGEBASE) { /* not I/O address? */ setCPUERR (CPUE_NXM); ABORT (TRAP_NXM); } @@ -2247,7 +2256,7 @@ if (ADDR_IS_MEM (pa)) { /* memory address? */ M[pa >> 1] = data; return; } -if (pa < IOPAGEBASE) { /* I/O address? */ +if (pa < IOPAGEBASE) { /* not I/O address? */ setCPUERR (CPUE_NXM); ABORT (TRAP_NXM); } @@ -2268,7 +2277,7 @@ if (ADDR_IS_MEM (pa)) { /* memory address? */ else M[pa >> 1] = (M[pa >> 1] & ~0377) | data; return; } -if (pa < IOPAGEBASE) { /* I/O address? */ +if (pa < IOPAGEBASE) { /* not I/O address? */ setCPUERR (CPUE_NXM); ABORT (TRAP_NXM); } @@ -2285,7 +2294,7 @@ if (ADDR_IS_MEM (pa)) { /* memory address? */ M[pa >> 1] = data; return; } -if (pa < IOPAGEBASE) { /* I/O address? */ +if (pa < IOPAGEBASE) { /* not I/O address? */ setCPUERR (CPUE_NXM); ABORT (TRAP_NXM); } @@ -2303,7 +2312,7 @@ if (ADDR_IS_MEM (pa)) { /* memory address? */ else M[pa >> 1] = (M[pa >> 1] & ~0377) | data; return; } -if (pa < IOPAGEBASE) { /* I/O address? */ +if (pa < IOPAGEBASE) { /* not I/O address? */ setCPUERR (CPUE_NXM); ABORT (TRAP_NXM); } @@ -2574,8 +2583,8 @@ switch ((pa >> 1) & 3) { /* decode pa<2:1> */ case 3: /* MMR2 */ *data = MMR2; break; - } - /* end switch pa */ + } /* end switch pa */ + return SCPE_OK; } diff --git a/PDP11/pdp11_cpumod.c b/PDP11/pdp11_cpumod.c index f41bde4e..4431c847 100644 --- a/PDP11/pdp11_cpumod.c +++ b/PDP11/pdp11_cpumod.c @@ -1024,7 +1024,7 @@ t_stat r; for (i = 0; cnf_tab[i].dib != NULL; i++) { /* loop thru config tab */ if (((cnf_tab[i].cpum == 0) || (cpu_type & cnf_tab[i].cpum)) && ((cnf_tab[i].optm == 0) || (cpu_opt & cnf_tab[i].optm))) { - if (r = build_ubus_tab (&cpu_dev, cnf_tab[i].dib)) /* add to dispatch tab */ + if (r = build_ubus_tab (&cpu_dev, cnf_tab[i].dib)) /* add to dispatch tab */ return r; } } diff --git a/PDP11/pdp11_cr.c b/PDP11/pdp11_cr.c index 82504f7b..981fedf1 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, John A. Dundas III + Copyright (c) 2005-2007, John A. Dundas III Portions derived from work by Douglas W. Jones, jones@cs.uiowa.edu Portions derived from work by Robert M Supnik @@ -51,8 +51,8 @@ http://www.cs.uiowa.edu/~jones/cards/ Paul Mattes' x026 keypunch simulator http://x3270.bgp.nu/x026.html - CDRSER.MAC - TOPS card reader driver source - http://pdp-10.trailing-edge.com/custsupcuspmar86_bb-x130b-sb/02/cdrser.mac + CD2SER.MAC - TOPS card reader driver source + http://pdp-10.trailing-edge.com/custsupcuspmar86_bb-x130b-sb/02/cd2ser.mac The Card Image format code and documentation is adapted from Prof. Jones's site, with his permission. Please see his site for additional @@ -66,14 +66,13 @@ 3. No testing under RSX; volunteers needed 4. No testing under Ultrix or Unix for PDP-11; volunteers needed 5. No testing under Ultrix or Unix for VAX; volunteers needed - 6. No PDP-10 support; volunteers needed - 7. The simulator implements a single controller/reader combination + 6. The simulator implements a single controller/reader combination Operating System Notes RT-11 (and CTS-300) support one CR11 or CM11, but no CD11. - VMS supports multiple CR11 controllers. + VMS supports multiple CR11 controllers, but no CD11. RSTS/E supports either the CR11/CM11 or CD11 but not both in the same SIL. It appears to support only one unit. @@ -84,12 +83,11 @@ Don't have any information about Unix or Ultrix-11 yet. Same for VAX Unices. - TOPS: it appears that both the CD11 and CR11 were supported. - I don't have any knowledge on how to make this work with the - PDP-10 simulation, though. + TOPS: only the CD11 is supported, under the name CD20. Revision History: + 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 the DEBUG bit. @@ -168,14 +166,23 @@ #if defined (VM_PDP10) /* PDP10 version */ #include "pdp10_defs.h" extern int32 int_req; +#define DFLT_DIS (DEV_DIS) +#define DFLT_CR11 (0) /* CD11 only */ +#define DFLT_CPM 1000 #elif defined (VM_VAX) /* VAX version */ #include "vax_defs.h" extern int32 int_req[IPL_HLVL]; +#define DFLT_DIS (0) +#define DFLT_CR11 (UNIT_CR11) +#define DFLT_CPM 285 #else /* PDP-11 version */ #include "pdp11_defs.h" extern int32 int_req[IPL_HLVL]; +#define DFLT_DIS (0) +#define DFLT_CR11 (UNIT_CR11) +#define DFLT_CPM 285 #endif extern FILE *sim_deb; /* sim_console.c */ @@ -294,7 +301,7 @@ static int32 blowerState = BLOW_OFF; /* reader vacuum/blower static int32 spinUp = 3000; /* blower spin-up time: 3 seconds */ static int32 spinDown = 2000; /* blower spin-down time: 2 seconds */ static t_bool EOFcard = FALSE; /* played special card yet? */ -static int32 cpm = 285; /* reader rate: cards per minute */ +static int32 cpm = DFLT_CPM; /* reader rate: cards per minute */ /* card image in various formats */ static int16 hcard[82]; /* Hollerith format */ static char ccard[82]; /* DEC compressed format */ @@ -343,8 +350,8 @@ static DIB cr_dib = { IOBA_CR, IOLN_CR, &cr_rd, &cr_wr, static UNIT cr_unit = { UDATA (&cr_svc, UNIT_ATTABLE+UNIT_SEQ+UNIT_ROABLE+UNIT_DISABLE+ - UNIT_CR11+UNIT_AUTOEOF, 0), - (60 * 1000) / 285 }; + DFLT_CR11+UNIT_AUTOEOF, 0), + (60 * 1000) / DFLT_CPM }; static const REG cr_reg[] = { { GRDATA (BUF, cr_unit.buf, DEV_RDX, 8, 0) }, @@ -367,8 +374,13 @@ static const REG cr_reg[] = { { NULL } }; static const MTAB cr_mod[] = { +#if defined (VM_PDP11) { UNIT_CR11, UNIT_CR11, "CR11", "CR11", &cr_set_type }, { UNIT_CR11, 0, "CD11", "CD11", &cr_set_type }, +#else + { UNIT_CR11, UNIT_CR11, "CR11", NULL }, + { UNIT_CR11, 0, "CD11", NULL }, +#endif { UNIT_AUTOEOF, UNIT_AUTOEOF, "auto EOF", "AUTOEOF", NULL }, { UNIT_AUTOEOF, 0, "no auto EOF", "NOAUTOEOF", NULL }, /* card reader RESET switch */ @@ -395,7 +407,7 @@ DEVICE cr_dev = { 1, 10, 31, 1, DEV_RDX, 8, NULL, NULL, &cr_reset, NULL, &cr_attach, &cr_detach, - &cr_dib, DEV_DISABLE | DEV_UBUS | DEV_DEBUG }; + &cr_dib, DEV_DISABLE | DFLT_DIS | DEV_UBUS | DEV_DEBUG }; /* Utility routines */ diff --git a/PDP11/pdp11_defs.h b/PDP11/pdp11_defs.h index 85ba923a..c879efec 100644 --- a/PDP11/pdp11_defs.h +++ b/PDP11/pdp11_defs.h @@ -26,6 +26,8 @@ The author gratefully acknowledges the help of Max Burnet, Megan Gentry, and John Wilson in resolving questions about the PDP-11 + 16-Dec-06 RMS Added TA11 support + 29-Oct-06 RMS Added clock coscheduling 06-Jul-06 RMS Added multiple KL11/DL11 support 26-Jun-06 RMS Added RF11 support 24-May-06 RMS Added 11/44 DR support (from CIS diagnostic) @@ -569,6 +571,8 @@ typedef struct pdp_dib DIB; #define IOLN_HK 040 #define IOBA_RF (IOPAGEBASE + 017460) /* RF11 */ #define IOLN_RF 020 +#define IOBA_TA (IOPAGEBASE + 017500) /* TA11 */ +#define IOLN_TA 004 #define IOBA_LPT (IOPAGEBASE + 017514) /* LP11 */ #define IOLN_LPT 004 #define IOBA_CTL (IOPAGEBASE + 017520) /* board ctrl */ @@ -613,7 +617,8 @@ typedef struct pdp_dib DIB; #define INT_V_CLK 0 /* BR6 */ #define INT_V_PCLK 1 #define INT_V_DTA 2 -#define INT_V_PIR6 3 +#define INT_V_TA 3 +#define INT_V_PIR6 4 #define INT_V_RK 0 /* BR5 */ #define INT_V_RL 1 @@ -653,6 +658,7 @@ typedef struct pdp_dib DIB; #define INT_CLK (1u << INT_V_CLK) #define INT_PCLK (1u << INT_V_PCLK) #define INT_DTA (1u << INT_V_DTA) +#define INT_TA (1u << INT_V_TA) #define INT_PIR6 (1u << INT_V_PIR6) #define INT_RK (1u << INT_V_RK) #define INT_RL (1u << INT_V_RL) @@ -689,6 +695,7 @@ typedef struct pdp_dib DIB; #define IPL_CLK 6 /* int pri levels */ #define IPL_PCLK 6 #define IPL_DTA 6 +#define IPL_TA 6 #define IPL_RK 5 #define IPL_RL 5 #define IPL_RX 5 @@ -749,6 +756,7 @@ typedef struct pdp_dib DIB; #define VEC_CR 0230 #define VEC_RP 0254 #define VEC_TQ 0260 +#define VEC_TA 0260 #define VEC_RX 0264 #define VEC_RY 0264 #define VEC_TTIX 0300 @@ -810,4 +818,6 @@ void mba_set_don (uint32 mbus); void mba_set_enbdis (uint32 mb, t_bool dis); t_stat mba_show_num (FILE *st, UNIT *uptr, int32 val, void *desc); +int32 clk_cosched (int32 wait); + #endif diff --git a/PDP11/pdp11_dz.c b/PDP11/pdp11_dz.c index 355e9364..340a0cb5 100644 --- a/PDP11/pdp11_dz.c +++ b/PDP11/pdp11_dz.c @@ -1,6 +1,6 @@ /* pdp11_dz.c: DZ11 terminal multiplexor simulator - Copyright (c) 2001-2005, Robert M Supnik + Copyright (c) 2001-2006, 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 @@ dz DZ11 terminal multiplexor + 29-Oct-06 RMS Synced poll and clock 22-Nov-05 RMS Revised for new terminal processing routines 07-Jul-05 RMS Removed extraneous externs 15-Jun-05 RMS Revised for new autoconfigure interface @@ -304,7 +305,8 @@ switch ((PA >> 1) & 03) { /* case on PA<2:1> */ (dz_csr[dz] & 0377) | (data << 8): (dz_csr[dz] & ~0377) | data; if (data & CSR_CLR) dz_clear (dz, FALSE); /* clr? reset */ - if (data & CSR_MSE) sim_activate (&dz_unit, tmxr_poll); + if (data & CSR_MSE) /* MSE? start poll */ + sim_activate (&dz_unit, clk_cosched (tmxr_poll)); else dz_csr[dz] &= ~(CSR_SA | CSR_RDONE | CSR_TRDY); if ((data & CSR_RIE) == 0) dz_clr_rxint (dz); /* RIE = 0? */ else if (((dz_csr[dz] & CSR_IE) == 0) && /* RIE 0->1? */ diff --git a/PDP11/pdp11_fp.c b/PDP11/pdp11_fp.c index ad079aa5..dc2f9564 100644 --- a/PDP11/pdp11_fp.c +++ b/PDP11/pdp11_fp.c @@ -145,47 +145,55 @@ /* Double precision operations on 64b quantities */ -#define F_LOAD(qd,ac,ds) ds.h = ac.h; ds.l = (qd)? ac.l: 0 -#define F_LOAD_P(qd,ac,ds) ds->h = ac.h; ds->l = (qd)? ac.l: 0 -#define F_LOAD_FRAC(qd,ac,ds) ds.h = (ac.h & FP_FRACH) | FP_HB; \ - ds.l = (qd)? ac.l: 0 -#define F_STORE(qd,sr,ac) ac.h = sr.h; if ((qd)) ac.l = sr.l -#define F_STORE_P(qd,sr,ac) ac.h = sr->h; if ((qd)) ac.l = sr->l -#define F_GET_FRAC_P(sr,ds) ds.l = sr->l; \ - ds.h = (sr->h & FP_FRACH) | FP_HB -#define F_ADD(s2,s1,ds) ds.l = (s1.l + s2.l) & 0xFFFFFFFF; \ - ds.h = (s1.h + s2.h + (ds.l < s2.l)) & 0xFFFFFFFF -#define F_SUB(s2,s1,ds) ds.h = (s1.h - s2.h - (s1.l < s2.l)) & 0xFFFFFFFF; \ - ds.l = (s1.l - s2.l) & 0xFFFFFFFF -#define F_LT(x,y) ((x.h < y.h) || ((x.h == y.h) && (x.l < y.l))) -#define F_LT_AP(x,y) (((x->h & ~FP_SIGN) < (y->h & ~FP_SIGN)) || \ - (((x->h & ~FP_SIGN) == (y->h & ~FP_SIGN)) && (x->l < y->l))) +#define F_LOAD(qd,ac,ds) \ + ds.h = ac.h; ds.l = (qd)? ac.l: 0 +#define F_LOAD_P(qd,ac,ds) \ + ds->h = ac.h; ds->l = (qd)? ac.l: 0 +#define F_LOAD_FRAC(qd,ac,ds) \ + ds.h = (ac.h & FP_FRACH) | FP_HB; \ + ds.l = (qd)? ac.l: 0 +#define F_STORE(qd,sr,ac) \ + ac.h = sr.h; if ((qd)) ac.l = sr.l +#define F_STORE_P(qd,sr,ac) \ + ac.h = sr->h; if ((qd)) ac.l = sr->l +#define F_GET_FRAC_P(sr,ds) \ + ds.l = sr->l; \ + ds.h = (sr->h & FP_FRACH) | FP_HB +#define F_ADD(s2,s1,ds) \ + ds.l = (s1.l + s2.l) & 0xFFFFFFFF; \ + ds.h = (s1.h + s2.h + (ds.l < s2.l)) & 0xFFFFFFFF +#define F_SUB(s2,s1,ds) \ + ds.h = (s1.h - s2.h - (s1.l < s2.l)) & 0xFFFFFFFF; \ + ds.l = (s1.l - s2.l) & 0xFFFFFFFF +#define F_LT(x,y) ((x.h < y.h) || ((x.h == y.h) && (x.l < y.l))) +#define F_LT_AP(x,y) (((x->h & ~FP_SIGN) < (y->h & ~FP_SIGN)) || \ + (((x->h & ~FP_SIGN) == (y->h & ~FP_SIGN)) && (x->l < y->l))) #define F_LSH_V(sr,n,ds) \ - ds.h = (((n) >= 32)? (sr.l << ((n) - 32)): \ - (sr.h << (n)) | ((sr.l >> (32 - (n))) & and_mask[n])) \ - & 0xFFFFFFFF; \ - ds.l = ((n) >= 32)? 0: (sr.l << (n)) & 0xFFFFFFFF + ds.h = (((n) >= 32)? (sr.l << ((n) - 32)): \ + (sr.h << (n)) | ((sr.l >> (32 - (n))) & and_mask[n])) \ + & 0xFFFFFFFF; \ + ds.l = ((n) >= 32)? 0: (sr.l << (n)) & 0xFFFFFFFF #define F_RSH_V(sr,n,ds) \ - ds.l = (((n) >= 32)? (sr.h >> ((n) - 32)) & and_mask[64 - (n)]: \ - ((sr.l >> (n)) & and_mask[32 - (n)]) | \ - (sr.h << (32 - (n)))) & 0xFFFFFFFF; \ - ds.h = ((n) >= 32)? 0: \ - ((sr.h >> (n)) & and_mask[32 - (n)]) & 0xFFFFFFFF + ds.l = (((n) >= 32)? (sr.h >> ((n) - 32)) & and_mask[64 - (n)]: \ + ((sr.l >> (n)) & and_mask[32 - (n)]) | \ + (sr.h << (32 - (n)))) & 0xFFFFFFFF; \ + ds.h = ((n) >= 32)? 0: \ + ((sr.h >> (n)) & and_mask[32 - (n)]) & 0xFFFFFFFF /* For the constant shift macro, arguments must in the range [2,31] */ -#define F_LSH_1(ds) ds.h = ((ds.h << 1) | ((ds.l >> 31) & 1)) & 0xFFFFFFFF; \ - ds.l = (ds.l << 1) & 0xFFFFFFFF -#define F_RSH_1(ds) ds.l = ((ds.l >> 1) & 0x7FFFFFFF) | ((ds.h & 1) << 31); \ - ds.h = ((ds.h >> 1) & 0x7FFFFFFF) +#define F_LSH_1(ds) ds.h = ((ds.h << 1) | ((ds.l >> 31) & 1)) & 0xFFFFFFFF; \ + ds.l = (ds.l << 1) & 0xFFFFFFFF +#define F_RSH_1(ds) ds.l = ((ds.l >> 1) & 0x7FFFFFFF) | ((ds.h & 1) << 31); \ + ds.h = ((ds.h >> 1) & 0x7FFFFFFF) #define F_LSH_K(sr,n,ds) \ - ds.h = ((sr.h << (n)) | ((sr.l >> (32 - (n))) & and_mask[n])) \ - & 0xFFFFFFFF; \ - ds.l = (sr.l << (n)) & 0xFFFFFFFF + ds.h = ((sr.h << (n)) | ((sr.l >> (32 - (n))) & and_mask[n])) \ + & 0xFFFFFFFF; \ + ds.l = (sr.l << (n)) & 0xFFFFFFFF #define F_RSH_K(sr,n,ds) \ - ds.l = (((sr.l >> (n)) & and_mask[32 - (n)]) | \ - (sr.h << (32 - (n)))) & 0xFFFFFFFF; \ - ds.h = ((sr.h >> (n)) & and_mask[32 - (n)]) & 0xFFFFFFFF + ds.l = (((sr.l >> (n)) & and_mask[32 - (n)]) | \ + (sr.h << (32 - (n)))) & 0xFFFFFFFF; \ + ds.h = ((sr.h >> (n)) & and_mask[32 - (n)]) & 0xFFFFFFFF #define F_LSH_GUARD(ds) F_LSH_K(ds,FP_GUARD,ds) #define F_RSH_GUARD(ds) F_RSH_K(ds,FP_GUARD,ds) @@ -252,7 +260,8 @@ int32 i, qdouble, lenf, leni; int32 newV, exp, sign; fpac_t fac, fsrc, modfrac; static const uint32 i_limit[2][2] = { - { 0x80000000, 0x80010000 }, { 0x80000000, 0x80000001 } + { 0x80000000, 0x80010000 }, + { 0x80000000, 0x80000001 } }; backup_PC = PC; /* save PC for FEA */ @@ -433,7 +442,7 @@ switch ((IR >> 8) & 017) { /* decode IR<11:8> */ if (FPS & FPS_L) { leni = LONG; i = FP_BIAS + 32; - } + } else { leni = WORD; i = FP_BIAS + 16; @@ -602,7 +611,8 @@ return 0; uint32 ReadI (int32 VA, int32 spec, int32 len) { if ((len == WORD) || (spec == 027)) return (ReadW (VA) << 16); -return ((ReadW (VA) << 16) | ReadW ((VA & ~0177777) | ((VA + 2) & 0177777))); +return ((ReadW (VA) << 16) | + ReadW ((VA & ~0177777) | ((VA + 2) & 0177777))); } /* Read floating operand diff --git a/PDP11/pdp11_hk.c b/PDP11/pdp11_hk.c index bc55d8cc..ed2da536 100644 --- a/PDP11/pdp11_hk.c +++ b/PDP11/pdp11_hk.c @@ -469,7 +469,7 @@ int32 drv, i, j; drv = GET_UNIT (hkcs2); /* get current unit */ j = (PA >> 1) & 017; /* get reg offset */ -if (reg_in_drive[j] && (hk_unit[drv].flags & UNIT_DIS)) { /* nx disk */ +if (reg_in_drive[j] && (hk_unit[drv].flags & UNIT_DIS)) { /* nx disk */ hkcs2 = hkcs2 | CS2_NED; /* set error flag */ update_hkcs (0, drv); *data = 0; @@ -705,6 +705,7 @@ switch (fnc) { /* case on function */ case FNC_NOP: /* no operation */ update_hkcs (CS1_DONE, drv); /* done */ break; + case FNC_PACK: /* pack acknowledge */ hkds[drv] = hkds[drv] | DS_VV; /* set volume valid */ update_hkcs (CS1_DONE, drv); /* done */ diff --git a/PDP11/pdp11_rf.c b/PDP11/pdp11_rf.c index 52d410eb..246957d6 100644 --- a/PDP11/pdp11_rf.c +++ b/PDP11/pdp11_rf.c @@ -25,6 +25,7 @@ rf RF11 fixed head disk + 25-Dec-06 RMS Fixed bug in unit mask (found by John Dundas) 26-Jun-06 RMS Cloned from RF08 simulator The RF11 is a head-per-track disk. To minimize overhead, the entire RF11 @@ -42,7 +43,7 @@ #define UNIT_V_AUTO (UNIT_V_UF + 0) /* autosize */ #define UNIT_V_PLAT (UNIT_V_UF + 1) /* #platters - 1 */ -#define UNIT_M_PLAT 03 +#define UNIT_M_PLAT (RF_NUMDK - 1) #define UNIT_GETP(x) ((((x) >> UNIT_V_PLAT) & UNIT_M_PLAT) + 1) #define UNIT_AUTO (1 << UNIT_V_AUTO) #define UNIT_PLAT (UNIT_M_PLAT << UNIT_V_PLAT) diff --git a/PDP11/pdp11_rh.c b/PDP11/pdp11_rh.c index cda0bc8b..382bf4f6 100644 --- a/PDP11/pdp11_rh.c +++ b/PDP11/pdp11_rh.c @@ -31,12 +31,15 @@ WARNING: The interupt logic of the RH11/RH70 is unusual and must be simulated with great precision. The RH11 has an internal interrupt request flop, CSTB INTR, which is controlled as follows: + - Writing IE and DONE simultaneously sets CSTB INTR - Controller clear, INIT, and interrupt acknowledge clear CSTB INTR (and also clear IE) - A transition of DONE from 0 to 1 sets CSTB INTR from IE + The output of CSTB INTR is OR'd with the AND of RPCS1 to create the interrupt request signal. Thus, + - The DONE interrupt is edge sensitive, but the SC interrupt is level sensitive. - The DONE interrupt, once set, is not disabled if IE is cleared, diff --git a/PDP11/pdp11_rk.c b/PDP11/pdp11_rk.c index 194da02e..cb77801e 100644 --- a/PDP11/pdp11_rk.c +++ b/PDP11/pdp11_rk.c @@ -75,7 +75,8 @@ #define RK_NUMTR (RK_NUMCY * RK_NUMSF) /* tracks/drive */ #define RK_NUMDR 8 /* drives/controller */ #define RK_M_NUMDR 07 -#define RK_SIZE (RK_NUMCY * RK_NUMSF * RK_NUMSC * RK_NUMWD) /* words/drive */ +#define RK_SIZE (RK_NUMCY * RK_NUMSF * RK_NUMSC * RK_NUMWD) + /* words/drive */ #define RK_CTLI 1 /* controller int */ #define RK_SCPI(x) (2u << (x)) /* drive int */ #define RK_MAXFR (1 << 16) /* max transfer */ @@ -172,8 +173,8 @@ #define RKBA_IMP 0177776 /* implemented */ -#define RK_MIN 10 -#define MAX(x,y) (((x) > (y))? (x): (y)) +#define RK_MIN 10 +#define MAX(x,y) (((x) > (y))? (x): (y)) extern uint16 *M; /* memory */ extern int32 int_req[IPL_HLVL]; @@ -297,8 +298,10 @@ switch ((PA >> 1) & 07) { /* decode PA<3:1> */ rkds = (rkds & RKDS_ID) | RKDS_RK05 | RKDS_SC_OK | (rand () % RK_NUMSC); /* random sector */ uptr = rk_dev.units + GET_DRIVE (rkda); /* selected unit */ - if (uptr->flags & UNIT_ATT) rkds = rkds | RKDS_RDY; /* attached? */ - if (!sim_is_active (uptr)) rkds = rkds | RKDS_RWS; /* idle? */ + if (uptr->flags & UNIT_ATT) /* attached? */ + rkds = rkds | RKDS_RDY; + if (!sim_is_active (uptr)) /* idle? */ + rkds = rkds | RKDS_RWS; if (uptr->flags & UNIT_WPRT) rkds = rkds | RKDS_WLK; if (GET_SECT (rkda) == (rkds & RKDS_SC)) rkds = rkds | RKDS_ON_SC; *data = rkds; @@ -356,7 +359,8 @@ switch ((PA >> 1) & 07) { /* decode PA<3:1> */ SET_INT (RK); /* set int request */ } rkcs = (rkcs & ~RKCS_RW) | (data & RKCS_RW); - if ((rkcs & CSR_DONE) && (data & CSR_GO)) rk_go (); /* new function? */ + if ((rkcs & CSR_DONE) && (data & CSR_GO)) /* new function? */ + rk_go (); return SCPE_OK; case 3: /* RKWC */ @@ -410,8 +414,9 @@ if (uptr->flags & UNIT_DIS) { /* not present? */ rk_set_done (RKER_NXD); return; } -if (((uptr->flags & UNIT_ATT) == 0) || sim_is_active (uptr)) { - rk_set_done (RKER_DRE); /* not att or busy */ +if (((uptr->flags & UNIT_ATT) == 0) || /* not att or busy? */ + sim_is_active (uptr)) { + rk_set_done (RKER_DRE); return; } if ((rkcs & RKCS_FMT) && /* format and */ @@ -419,8 +424,9 @@ if ((rkcs & RKCS_FMT) && /* format and */ rk_set_done (RKER_PGE); return; } -if ((func == RKCS_WRITE) && (uptr->flags & UNIT_WPRT)) { - rk_set_done (RKER_WLK); /* write and locked? */ +if ((func == RKCS_WRITE) && /* write and locked? */ + (uptr->flags & UNIT_WPRT)) { + rk_set_done (RKER_WLK); return; } if (func == RKCS_WLK) { /* write lock? */ @@ -530,7 +536,7 @@ if (wc && (err == 0)) { /* seek ok? */ for ( ; i < wc; i++) rkxb[i] = 0; /* fill buf */ } if (rkcs & RKCS_INH) { /* incr inhibit? */ - if (t = Map_WriteW (ma, 2, &rkxb[wc - 1])) { /* store last */ + if (t = Map_WriteW (ma, 2, &rkxb[wc - 1])) { /* store last */ rker = rker | RKER_NXM; /* NXM? set flag */ wc = 0; /* no transfer */ } @@ -558,7 +564,7 @@ if (wc && (err == 0)) { /* seek ok? */ } } if (wc) { /* any xfer? */ - awc = (wc + (RK_NUMWD - 1)) & ~(RK_NUMWD - 1); /* clr to */ + awc = (wc + (RK_NUMWD - 1)) & ~(RK_NUMWD - 1); /* clr to */ for (i = wc; i < awc; i++) rkxb[i] = 0; /* end of blk */ fxwrite (rkxb, sizeof (int16), awc, uptr->fileref); err = ferror (uptr->fileref); diff --git a/PDP11/pdp11_rp.c b/PDP11/pdp11_rp.c index 11ec7b44..cabbf336 100644 --- a/PDP11/pdp11_rp.c +++ b/PDP11/pdp11_rp.c @@ -72,7 +72,7 @@ #define RP_NUMWD 256 /* words/sector */ #define RP_MAXFR (1 << 16) /* max transfer */ #define GET_SECTOR(x,d) ((int) fmod (sim_gtime() / ((double) (x)), \ - ((double) drv_tab[d].sect))) + ((double) drv_tab[d].sect))) #define RM_OF (MBA_RMASK + 1) /* Flags in the unit flags word */ diff --git a/PDP11/pdp11_rx.c b/PDP11/pdp11_rx.c index 78cff3d2..6cd580cc 100644 --- a/PDP11/pdp11_rx.c +++ b/PDP11/pdp11_rx.c @@ -369,12 +369,12 @@ switch (rx_state) { /* case on state */ break; } uptr->TRACK = rx_track; /* now on track */ - if ((rx_sector == 0) || (rx_sector > RX_NUMSC)) { /* bad sect? */ + if ((rx_sector == 0) || (rx_sector > RX_NUMSC)) { /* bad sect? */ rx_done (0, 0070); /* done, error */ break; } da = CALC_DA (rx_track, rx_sector); /* get disk address */ - if (func == RXCS_WRDEL) rx_esr = rx_esr | RXES_DD; /* del data? */ + if (func == RXCS_WRDEL) rx_esr = rx_esr | RXES_DD; /* del data? */ if (func == RXCS_READ) { /* read? */ for (i = 0; i < RX_NUMBY; i++) rx_buf[i] = fbuf[da + i]; diff --git a/PDP11/pdp11_ry.c b/PDP11/pdp11_ry.c index fe23b4f5..8b42dd03 100644 --- a/PDP11/pdp11_ry.c +++ b/PDP11/pdp11_ry.c @@ -427,7 +427,7 @@ switch (ry_state) { /* case on state */ break; } uptr->TRACK = ry_track; /* now on track */ - if ((ry_sector == 0) || (ry_sector > RX_NUMSC)) { /* bad sect? */ + if ((ry_sector == 0) || (ry_sector > RX_NUMSC)) { /* bad sect? */ ry_done (0, 0070); /* done, error */ break; } @@ -437,7 +437,7 @@ switch (ry_state) { /* case on state */ break; } da = CALC_DA (ry_track, ry_sector, bps); /* get disk address */ - if (func == RYCS_WRDEL) ry_esr = ry_esr | RYES_DD; /* del data? */ + if (func == RYCS_WRDEL) ry_esr = ry_esr | RYES_DD; /* del data? */ if (func == RYCS_READ) { /* read? */ for (i = 0; i < bps; i++) rx2xb[i] = fbuf[da + i]; diff --git a/PDP11/pdp11_stddev.c b/PDP11/pdp11_stddev.c index 4386218a..c0f6689a 100644 --- a/PDP11/pdp11_stddev.c +++ b/PDP11/pdp11_stddev.c @@ -26,6 +26,8 @@ tti,tto DL11 terminal input/output clk KW11L (and other) line frequency clock + 29-Oct-06 RMS Synced keyboard and clock + Added clock coscheduling support 05-Jul-06 RMS Added UC only support for early DOS/RSTS 22-Nov-05 RMS Revised for new terminal processing routines 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) @@ -107,7 +109,7 @@ DIB tti_dib = { 1, IVCL (TTI), VEC_TTI, { NULL } }; -UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT }; +UNIT tti_unit = { UDATA (&tti_svc, 0, 0), 0 }; REG tti_reg[] = { { ORDATA (BUF, tti_unit.buf, 8) }, @@ -117,7 +119,7 @@ REG tti_reg[] = { { FLDATA (DONE, tti_csr, CSR_V_DONE) }, { FLDATA (IE, tti_csr, CSR_V_IE) }, { DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, + { DRDATA (TIME, tti_unit.wait, 24), PV_LEFT }, { NULL } }; @@ -153,7 +155,7 @@ DIB tto_dib = { 1, IVCL (TTO), VEC_TTO, { NULL } }; -UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT }; +UNIT tto_unit = { UDATA (&tto_svc, TT_MODE_7P, 0), SERIAL_OUT_WAIT }; REG tto_reg[] = { { ORDATA (BUF, tto_unit.buf, 8) }, @@ -281,7 +283,7 @@ t_stat tti_svc (UNIT *uptr) { int32 c; -sim_activate (uptr, uptr->wait); /* continue poll */ +sim_activate (uptr, KBD_WAIT (uptr->wait, tmr_poll)); /* continue poll */ if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */ if (c & SCPE_BREAK) uptr->buf = 0; /* break? */ else uptr->buf = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags)); @@ -298,7 +300,7 @@ t_stat tti_reset (DEVICE *dptr) tti_unit.buf = 0; tti_csr = 0; CLR_INT (TTI); -sim_activate (&tti_unit, tti_unit.wait); /* activate unit */ +sim_activate_abs (&tti_unit, KBD_WAIT (tti_unit.wait, tmr_poll)); return SCPE_OK; } @@ -404,7 +406,7 @@ t_stat clk_wr (int32 data, int32 PA, int32 access) if (clk_fnxm) return SCPE_NXM; /* not there??? */ if (PA & 1) return SCPE_OK; clk_csr = (clk_csr & ~CLKCSR_RW) | (data & CLKCSR_RW); -if (CPUT (HAS_LTCM) && ((data & CSR_DONE) == 0)) /* monitor bit? */ +if (CPUT (HAS_LTCM) && ((data & CSR_DONE) == 0)) /* monitor bit? */ clk_csr = clk_csr & ~CSR_DONE; /* clr if zero */ if ((((clk_csr & CSR_IE) == 0) && !clk_fie) || /* unless IE+DONE */ ((clk_csr & CSR_DONE) == 0)) CLR_INT (CLK); /* clr intr */ @@ -434,6 +436,16 @@ if (CPUT (CPUT_24)) clk_csr = clk_csr & ~CSR_DONE; return clk_dib.vec; } +/* Clock coscheduling routine */ + +int32 clk_cosched (int32 wait) +{ +int32 t; + +t = sim_is_active (&clk_unit); +return (t? t - 1: wait); +} + /* Clock reset */ t_stat clk_reset (DEVICE *dptr) diff --git a/PDP11/pdp11_sys.c b/PDP11/pdp11_sys.c index 1324f922..17009d24 100644 --- a/PDP11/pdp11_sys.c +++ b/PDP11/pdp11_sys.c @@ -23,6 +23,8 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 20-Dec-06 RMS Added TA11 support + 12-Nov-06 RMS Fixed operand order in EIS instructions (found by W.F.J. Mueller) 14-Jul-06 RMS Reordered device list 06-Jul-06 RMS Added multiple KL11/DL11 support 26-Jun-06 RMS Added RF11 support @@ -85,6 +87,7 @@ extern DEVICE tm_dev; extern DEVICE tq_dev; extern DEVICE ts_dev; extern DEVICE tu_dev; +extern DEVICE ta_dev; extern DEVICE xq_dev, xqb_dev; extern DEVICE xu_dev, xub_dev; extern UNIT cpu_unit; @@ -141,6 +144,7 @@ DEVICE *sim_devices[] = { &ts_dev, &tq_dev, &tu_dev, + &ta_dev, &xq_dev, &xqb_dev, &xu_dev, @@ -311,7 +315,7 @@ return SCPE_OK; /* Warning: for literals, the class number MUST equal the field width!! */ #define I_V_CL 18 /* class bits */ -#define I_M_CL 017 /* class mask */ +#define I_M_CL 037 /* class mask */ #define I_V_NPN 0 /* no operands */ #define I_V_REG 1 /* reg */ #define I_V_SOP 2 /* operand */ @@ -328,6 +332,7 @@ return SCPE_OK; #define I_V_DOP 13 /* double operand */ #define I_V_CCC 14 /* CC clear */ #define I_V_CCS 15 /* CC set */ +#define I_V_SOPR 16 /* operand, reg */ #define I_NPN (I_V_NPN << I_V_CL) #define I_REG (I_V_REG << I_V_CL) #define I_3B (I_V_3B << I_V_CL) @@ -344,12 +349,14 @@ return SCPE_OK; #define I_DOP (I_V_DOP << I_V_CL) #define I_CCC (I_V_CCC << I_V_CL) #define I_CCS (I_V_CCS << I_V_CL) +#define I_SOPR (I_V_SOPR << I_V_CL) static const int32 masks[] = { 0177777, 0177770, 0177700, 0177770, 0177700+I_D, 0177400+I_D, 0177700, 0177400, 0177400, 0177000, 0177000, 0177400, -0177400+I_D+I_L, 0170000, 0177777, 0177777 +0177400+I_D+I_L, 0170000, 0177777, 0177777, +0177000 }; static const char *opcode[] = { @@ -443,7 +450,7 @@ static const int32 opc_val[] = { 0007000+I_SOP, 0007200+I_SOP, 0007300+I_SOP, 0010000+I_DOP, 0020000+I_DOP, 0030000+I_DOP, 0040000+I_DOP, 0050000+I_DOP, 0060000+I_DOP, -0070000+I_RSOP, 0071000+I_RSOP, 0072000+I_RSOP, 0073000+I_RSOP, +0070000+I_SOPR, 0071000+I_SOPR, 0072000+I_SOPR, 0073000+I_SOPR, 0074000+I_RSOP, 0075000+I_REG, 0075010+I_REG, 0075020+I_REG, 0075030+I_REG, 0076020+I_REG, @@ -662,7 +669,7 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ case I_V_BR: /* cond branch */ fprintf (of, "%s ", opcode[i]); brdisp = (l8b + l8b + ((l8b & 0200)? 0177002: 2)) & 0177777; - if (cflag) fprintf (of, "%-o", (addr + brdisp) & 0177777); + if (cflag) fprintf (of, "%-o", (addr + brdisp) & 0177777); else if (brdisp < 01000) fprintf (of, ".+%-o", brdisp); else fprintf (of, ".-%-o", 0200000 - brdisp); break; @@ -684,6 +691,12 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ wd1 = fprint_spec (of, addr, dstm, val[1], cflag, TRUE); break; + case I_V_SOPR: /* sopr */ + fprintf (of, "%s ", opcode[i]); + wd1 = fprint_spec (of, addr, dstm, val[1], cflag, TRUE); + fprintf (of, ",%s", rname[srcr]); + break; + case I_V_ASOP: case I_V_ASMD: /* asop, asmd */ fprintf (of, "%s %s,", opcode[i], fname[fac]); wd1 = fprint_spec (of, addr, dstm, val[1], cflag, TRUE); @@ -987,13 +1000,23 @@ switch (j) { /* case on class */ cptr = get_glyph (cptr, gbuf, ','); /* get glyph */ if ((reg = get_reg (gbuf, rname, 0)) < 0) return SCPE_ARG; val[0] = val[0] | (reg << 6); /* fall through */ - case I_V_SOP: /* sop */ + case I_V_SOP: /* sop */ cptr = get_glyph (cptr, gbuf, 0); /* get glyph */ if ((n1 = get_spec (gbuf, addr, 0, &spec, &val[1], cflag, TRUE)) > 0) return SCPE_ARG; val[0] = val[0] | spec; break; + case I_V_SOPR: /* dop, reg */ + cptr = get_glyph (cptr, gbuf, ','); /* get glyph */ + if ((n1 = get_spec (gbuf, addr, 0, &spec, &val[1], cflag, TRUE)) > 0) + return SCPE_ARG; + val[0] = val[0] | spec; + cptr = get_glyph (cptr, gbuf, 0); /* get glyph */ + if ((reg = get_reg (gbuf, rname, 0)) < 0) return SCPE_ARG; + val[0] = val[0] | (reg << 6); + break; + case I_V_AFOP: case I_V_ASOP: case I_V_ASMD: /* fac, (s)fop */ cptr = get_glyph (cptr, gbuf, ','); /* get glyph */ if ((reg = get_reg (gbuf, fname, 0)) < 0) return SCPE_ARG; diff --git a/PDP11/pdp11_ta.c b/PDP11/pdp11_ta.c new file mode 100644 index 00000000..6eef09dc --- /dev/null +++ b/PDP11/pdp11_ta.c @@ -0,0 +1,584 @@ +/* pdp11_ta.c: PDP-11 cassette tape simulator + + Copyright (c) 2006, 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"), + 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 ATAION OF CONTRATA, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNETAION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not 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. + + ta TA11/TU60 cassette tape + + Magnetic tapes are represented as a series of variable records + of the form: + + 32b byte count + byte 0 + byte 1 + : + byte n-2 + byte n-1 + 32b byte count + + If the byte count is odd, the record is padded with an extra byte + of junk. File marks are represented by a byte count of 0. + + Cassette format differs in one very significant way: it has file gaps + rather than file marks. If the controller spaces or reads into a file + gap and then reverses direction, the file gap is not seen again. This + is in contrast to magnetic tapes, where the file mark is a character + sequence and is seen again if direction is reversed. +*/ + +#include "pdp11_defs.h" +#include "sim_tape.h" + +#define TA_NUMDR 2 /* #drives */ +#define FNC u3 /* unit function */ +#define UST u4 /* unit status */ +#define TA_SIZE 93000 /* chars/tape */ +#define TA_MAXFR (TA_SIZE) /* max record lnt */ + +/* Control/status - TACS */ + +#define TACS_ERR (1 << CSR_V_ERR) /* error */ +#define TACS_CRC 0040000 /* CRC */ +#define TACS_BEOT 0020000 /* BOT/EOT */ +#define TACS_WLK 0010000 /* write lock */ +#define TACS_EOF 0004000 /* end file */ +#define TACS_TIM 0002000 /* timing */ +#define TACS_EMP 0001000 /* empty */ +#define TACS_V_UNIT 8 /* unit */ +#define TACS_M_UNIT (TA_NUMDR - 1) +#define TACS_UNIT (TACS_M_UNIT << TACS_V_UNIT) +#define TACS_TR (1 << CSR_V_DONE) /* transfer req */ +#define TACS_IE (1 << CSR_V_IE) /* interrupt enable */ +#define TACS_RDY 0000040 /* ready */ +#define TACS_ILBS 0000020 /* start CRC */ +#define TACS_V_FNC 1 /* function */ +#define TACS_M_FNC 07 +#define TACS_WFG 00 +#define TACS_WRITE 01 +#define TACS_READ 02 +#define TACS_SRF 03 +#define TACS_SRB 04 +#define TACS_SFF 05 +#define TACS_SFB 06 +#define TACS_REW 07 +#define TACS_2ND 010 +#define TACS_3RD 030 +#define TACS_FNC (TACS_M_FNC << TACS_V_FNC) +#define TACS_GO (1 << CSR_V_GO) /* go */ +#define TACS_W (TACS_UNIT|TACS_IE|TACS_ILBS|TACS_FNC) +#define TACS_XFRERR (TACS_ERR|TACS_CRC|TACS_WLK|TACS_EOF|TACS_TIM) +#define GET_UNIT(x) (((x) >> TACS_V_UNIT) & TACS_M_UNIT) +#define GET_FNC(x) (((x) >> TACS_V_FNC) & TACS_M_FNC) + +/* Function code flags */ + +#define OP_WRI 01 /* op is a write */ +#define OP_REV 02 /* op is rev motion */ +#define OP_FWD 04 /* op is fwd motion */ + +/* Unit status flags */ + +#define UST_REV (OP_REV) /* last op was rev */ +#define UST_GAP 01 /* last op hit gap */ + +extern int32 int_req[IPL_HLVL]; +extern FILE *sim_deb; + +uint32 ta_cs = 0; /* control/status */ +uint32 ta_idb = 0; /* input data buf */ +uint32 ta_odb = 0; /* output data buf */ +uint32 ta_write = 0; /* TU60 write flag */ +uint32 ta_bptr = 0; /* buf ptr */ +uint32 ta_blnt = 0; /* buf length */ +int32 ta_stime = 1000; /* start time */ +int32 ta_ctime = 100; /* char latency */ +uint32 ta_stopioe = 1; /* stop on error */ +uint8 *ta_xb = NULL; /* transfer buffer */ +static uint8 ta_fnc_tab[TACS_M_FNC + 1] = { + OP_WRI|OP_FWD, OP_WRI|OP_FWD, OP_FWD, OP_REV, + OP_REV , OP_FWD, OP_FWD, 0 + }; + +DEVICE ta_dev; +t_stat ta_rd (int32 *data, int32 PA, int32 access); +t_stat ta_wr (int32 data, int32 PA, int32 access); +t_stat ta_svc (UNIT *uptr); +t_stat ta_reset (DEVICE *dptr); +t_stat ta_attach (UNIT *uptr, char *cptr); +t_stat ta_detach (UNIT *uptr); +void ta_go (void); +t_stat ta_map_err (UNIT *uptr, t_stat st); +UNIT *ta_busy (void); +void ta_set_tr (void); +uint32 ta_updsta (UNIT *uptr); +uint32 ta_crc (uint8 *buf, uint32 cnt); + +/* TA data structures + + ta_dev TA device descriptor + ta_unit TA unit list + ta_reg TA register list + ta_mod TA modifier list +*/ + +DIB ta_dib = { + IOBA_TA, IOLN_TA, &ta_rd, &ta_wr, + 1, IVCL (TA), VEC_TA, { NULL } + }; + +UNIT ta_unit[] = { + { UDATA (&ta_svc, UNIT_ATTABLE+UNIT_ROABLE, TA_SIZE) }, + { UDATA (&ta_svc, UNIT_ATTABLE+UNIT_ROABLE, TA_SIZE) }, + }; + +REG ta_reg[] = { + { ORDATA (TACS, ta_cs, 16) }, + { ORDATA (TAIDB, ta_idb, 8) }, + { ORDATA (TAODB, ta_odb, 8) }, + { FLDATA (WRITE, ta_write, 0) }, + { FLDATA (INT, IREQ (TA), INT_V_TA) }, + { FLDATA (ERR, ta_cs, CSR_V_ERR) }, + { FLDATA (TR, ta_cs, CSR_V_DONE) }, + { FLDATA (IE, ta_cs, CSR_V_IE) }, + { DRDATA (BPTR, ta_bptr, 17) }, + { DRDATA (BLNT, ta_blnt, 17) }, + { DRDATA (STIME, ta_stime, 24), PV_LEFT + REG_NZ }, + { DRDATA (CTIME, ta_ctime, 24), PV_LEFT + REG_NZ }, + { FLDATA (STOP_IOE, ta_stopioe, 0) }, + { URDATA (UFNC, ta_unit[0].FNC, 8, 5, 0, TA_NUMDR, 0), REG_HRO }, + { URDATA (UST, ta_unit[0].UST, 8, 2, 0, TA_NUMDR, 0), REG_HRO }, + { URDATA (POS, ta_unit[0].pos, 10, T_ADDR_W, 0, + TA_NUMDR, PV_LEFT | REG_RO) }, + { ORDATA (DEVADDR, ta_dib.ba, 32), REG_HRO }, + { ORDATA (DEVVEC, ta_dib.vec, 16), REG_HRO }, + { NULL } + }; + +MTAB ta_mod[] = { + { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL }, + { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, +// { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT", +// &sim_tape_set_fmt, &sim_tape_show_fmt, NULL }, + { MTAB_XTD|MTAB_VUN, 0, "CAPACITY", NULL, + NULL, &sim_tape_show_capac, NULL }, + { MTAB_XTD|MTAB_VDV, IOLN_TA, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", + &set_vec, &show_vec, NULL }, + { 0 } + }; + +DEVICE ta_dev = { + "TA", ta_unit, ta_reg, ta_mod, + TA_NUMDR, 10, 31, 1, 8, 8, + NULL, NULL, &ta_reset, + NULL, &ta_attach, &ta_detach, + &ta_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG + }; + +/* I/O dispatch routines, I/O addresses 17777500 - 17777503 + + 17777500 TACS read/write + 17777502 TADB read/write +*/ + +t_stat ta_rd (int32 *data, int32 PA, int32 access) +{ +switch ((PA >> 1) & 01) { /* decode PA<1> */ + + case 0: /* TACSR */ + *data = ta_updsta (NULL); /* update status */ + break; + + case 1: /* TADB */ + *data = ta_idb; /* return byte */ + ta_cs &= ~TACS_TR; /* clear tra req */ + ta_updsta (NULL); + break; + } + +return SCPE_OK; +} + +t_stat ta_wr (int32 data, int32 PA, int32 access) +{ +switch ((PA >> 1) & 01) { /* decode PA<1> */ + + case 0: /* TACS */ + if (access == WRITEB) data = (PA & 1)? /* byte write? */ + (ta_cs & 0377) | (data << 8): /* merge old */ + (ta_cs & ~0377) | data; + ta_cs = (ta_cs & ~TACS_W) | (data & TACS_W); /* merge new */ + if ((data & CSR_GO) && !ta_busy ()) /* go, not busy? */ + ta_go (); /* start operation */ + if (ta_cs & TACS_ILBS) ta_cs &= ~TACS_TR; /* ILBS inhibits TR */ + break; + + case 1: /* TADB */ + if (PA & 1) break; /* ignore odd byte */ + ta_odb = data; /* return byte */ + ta_cs &= ~TACS_TR; /* clear tra req */ + break; + } /* end switch */ + +ta_updsta (NULL); /* update status */ +return SCPE_OK; +} + +/* Start a new operation - cassette is not busy */ + +void ta_go (void) +{ +UNIT *uptr = ta_dev.units + GET_UNIT (ta_cs); +uint32 fnc = GET_FNC (ta_cs); +uint32 flg = ta_fnc_tab[fnc]; +uint32 old_ust = uptr->UST; + +if (DEBUG_PRS (ta_dev)) fprintf (sim_deb, + ">>TA start: op=%o, old_sta = %o, pos=%d\n", + fnc, uptr->UST, uptr->pos); +ta_cs &= ~(TACS_XFRERR|TACS_EMP|TACS_TR|TACS_RDY); /* clr err, tr, rdy */ +ta_bptr = 0; /* init buffer */ +ta_blnt = 0; +if ((uptr->flags & UNIT_ATT) == 0) { + ta_cs |= TACS_ERR|TACS_EMP|TACS_RDY; + return; + } +if (flg & OP_WRI) { /* write op? */ + if (sim_tape_wrp (uptr)) { /* locked? */ + ta_cs |= TACS_ERR|TACS_WLK|TACS_RDY; /* don't start */ + return; + } + ta_odb = 0; + ta_write = 1; + } +else { + ta_idb = 0; + ta_write = 0; + } +ta_cs &= ~TACS_BEOT; /* tape in motion */ +uptr->FNC = fnc; /* save function */ +if ((fnc != TACS_REW) && !(flg & OP_WRI)) { /* read cmd? */ + uptr->UST = flg & UST_REV; /* save direction */ + if ((old_ust ^ uptr->UST) == (UST_REV|UST_GAP)) { /* reverse in gap? */ + t_mtrlnt t; /* skip file mark */ + if (uptr->UST) sim_tape_rdrecr (uptr, ta_xb, &t, TA_MAXFR); + else sim_tape_rdrecf (uptr, ta_xb, &t, TA_MAXFR); + if (DEBUG_PRS (ta_dev)) fprintf (sim_deb, + ">>TA skip gap: op=%o, old_sta = %o, pos=%d\n", + fnc, uptr->UST, uptr->pos); + } + } +else uptr->UST = 0; +sim_activate (uptr, ta_stime); /* schedule op */ +return; +} + +/* Unit service */ + +t_stat ta_svc (UNIT *uptr) +{ +uint32 i, crc; +uint32 flg = ta_fnc_tab[uptr->FNC & TACS_M_FNC]; +t_mtrlnt tbc; +t_stat st, r; + +if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ + ta_cs |= TACS_ERR|TACS_EMP|TACS_RDY; + ta_updsta (uptr); /* update status */ + return (ta_stopioe? SCPE_UNATT: SCPE_OK); + } +if (((flg & OP_FWD) && sim_tape_eot (uptr)) || /* illegal motion? */ + ((flg & OP_REV) && sim_tape_bot (uptr))) { + ta_cs |= TACS_ERR|TACS_BEOT|TACS_RDY; /* error */ + ta_updsta (uptr); + return SCPE_OK; + } + +r = SCPE_OK; +switch (uptr->FNC) { /* case on function */ + + case TACS_READ: /* read start */ + st = sim_tape_rdrecf (uptr, ta_xb, &ta_blnt, TA_MAXFR); /* get rec */ + if (st == MTSE_RECE) ta_cs |= TACS_ERR|TACS_CRC; /* rec in err? */ + else if (st != MTSE_OK) { /* other error? */ + r = ta_map_err (uptr, st); /* map error */ + break; + } + crc = ta_crc (ta_xb, ta_blnt); /* calculate CRC */ + ta_xb[ta_blnt++] = (crc >> 8) & 0377; /* append to buffer */ + ta_xb[ta_blnt++] = crc & 0377; + uptr->FNC |= TACS_2ND; /* next state */ + sim_activate (uptr, ta_ctime); /* sched next char */ + return SCPE_OK; + + case TACS_READ|TACS_2ND: /* read char */ + if (ta_bptr < ta_blnt) /* more chars? */ + ta_idb = ta_xb[ta_bptr++]; + else { /* no */ + ta_idb = 0; + ta_cs |= TACS_ERR|TACS_CRC; /* overrun */ + break; /* tape stops */ + } + if (ta_cs & TACS_ILBS) { /* CRC seq? */ + uptr->FNC |= TACS_3RD; /* next state */ + sim_activate (uptr, ta_stime); /* sched CRC chk */ + } + else { + ta_set_tr (); /* set tra req */ + sim_activate (uptr, ta_ctime); /* sched next char */ + } + return SCPE_OK; + + case TACS_READ|TACS_3RD: /* second read CRC */ + if (ta_bptr != ta_blnt) { /* partial read? */ + crc = ta_crc (ta_xb, ta_bptr + 2); /* actual CRC */ + if (crc != 0) ta_cs |= TACS_ERR|TACS_CRC; /* must be zero */ + } + break; /* read done */ + + case TACS_WRITE: /* write start */ + for (i = 0; i < TA_MAXFR; i++) ta_xb[i] = 0; /* clear buffer */ + ta_set_tr (); /* set tra req */ + uptr->FNC |= TACS_2ND; /* next state */ + sim_activate (uptr, ta_ctime); /* sched next char */ + return SCPE_OK; + + case TACS_WRITE|TACS_2ND: /* write char */ + if (ta_cs & TACS_ILBS) { /* CRC seq? */ + uptr->FNC |= TACS_3RD; /* next state */ + sim_activate (uptr, ta_stime); /* sched wri done */ + } + else { + if ((ta_bptr < TA_MAXFR) && /* room in buf? */ + ((uptr->pos + ta_bptr) < uptr->capac)) /* room on tape? */ + ta_xb[ta_bptr++] = ta_odb; /* store char */ + ta_set_tr (); /* set tra req */ + sim_activate (uptr, ta_ctime); /* sched next char */ + } + return SCPE_OK; + + case TACS_WRITE|TACS_3RD: /* write CRC */ + if (ta_bptr) { /* anything to write? */ + if (st = sim_tape_wrrecf (uptr, ta_xb, ta_bptr)) /* write, err? */ + r = ta_map_err (uptr, st); /* map error */ + } + break; /* op done */ + + case TACS_WFG: /* write file gap */ + if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + r = ta_map_err (uptr, st); /* map error */ + break; + + case TACS_REW: /* rewind */ + sim_tape_rewind (uptr); + ta_cs |= TACS_BEOT; /* bot, no error */ + break; + + case TACS_SRB: /* space rev blk */ + if (st = sim_tape_sprecr (uptr, &tbc)) /* space rev, err? */ + r = ta_map_err (uptr, st); /* map error */ + break; + + case TACS_SRF: /* space rev file */ + while ((st = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ; + if (st == MTSE_TMK) /* if tape mark, */ + ta_cs |= TACS_EOF; /* set EOF, no err */ + else r = ta_map_err (uptr, st); /* else map error */ + break; + + case TACS_SFB: /* space fwd blk */ + if (st = sim_tape_sprecf (uptr, &tbc)) /* space rev, err? */ + r = ta_map_err (uptr, st); /* map error */ + ta_cs |= TACS_CRC; /* CRC sets, no err */ + break; + + case TACS_SFF: /* space fwd file */ + while ((st = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) ; + if (st == MTSE_TMK) /* if tape mark, */ + ta_cs |= TACS_EOF; /* set EOF, no err */ + else r = ta_map_err (uptr, st); /* else map error */ + break; + + default: /* never get here! */ + return SCPE_IERR; + } /* end case */ + +ta_cs |= TACS_RDY; /* set ready */ +ta_updsta (uptr); /* update status */ +if (DEBUG_PRS (ta_dev)) fprintf (sim_deb, + ">>TA done: op=%o, status = %o, pos=%d\n", + uptr->FNC, ta_cs, uptr->pos); +return r; +} + +/* Update controller status */ + +uint32 ta_updsta (UNIT *uptr) +{ +if (uptr == NULL) { /* unit specified? */ + if ((uptr = ta_busy ()) == NULL) /* use busy */ + uptr = ta_dev.units + GET_UNIT (ta_cs); /* use sel unit */ + } +else if (ta_cs & TACS_EOF) uptr->UST |= UST_GAP; /* save EOF */ +if (uptr->flags & UNIT_ATT) ta_cs &= ~TACS_EMP; /* attached? */ +else ta_cs |= TACS_EMP|TACS_RDY; /* no, empty, ready */ +if ((ta_cs & TACS_IE) && /* int enabled? */ + (ta_cs & (TACS_TR|TACS_RDY))) /* req or ready? */ + SET_INT (TA); /* set int req */ +else CLR_INT (TA); /* no, clr int req */ +return ta_cs; +} + +/* Set transfer request */ + +void ta_set_tr (void) +{ +if (ta_cs & TACS_TR) ta_cs |= (TACS_ERR|TACS_TIM); /* flag still set? */ +else ta_cs |= TACS_TR; /* set xfr req */ +if (ta_cs & TACS_IE) SET_INT (TA); /* if ie, int req */ +return; +} + +/* Test if controller busy */ + +UNIT *ta_busy (void) +{ +uint32 u; +UNIT *uptr; + +for (u = 0; u < TA_NUMDR; u++) { /* loop thru units */ + uptr = ta_dev.units + u; + if (sim_is_active (uptr)) return uptr; + } +return NULL; +} + +/* Calculate CRC on buffer */ + +uint32 ta_crc (uint8 *buf, uint32 cnt) +{ +uint32 crc, i, j; + +crc = 0; +for (i = 0; i < cnt; i++) { + crc = crc ^ (((uint32) buf[i]) << 8); + for (j = 0; j < 8; j++) { + if (crc & 1) crc = (crc >> 1) ^ 0xA001; + else crc = crc >> 1; + } + } +return crc; +} + +/* Map error status */ + +t_stat ta_map_err (UNIT *uptr, t_stat st) +{ +switch (st) { + + case MTSE_FMT: /* illegal fmt */ + case MTSE_UNATT: /* unattached */ + ta_cs |= TACS_ERR|TACS_CRC; + case MTSE_OK: /* no error */ + return SCPE_IERR; /* never get here! */ + + case MTSE_TMK: /* end of file */ + ta_cs |= TACS_ERR|TACS_EOF; + break; + + case MTSE_IOERR: /* IO error */ + ta_cs |= TACS_ERR|TACS_CRC; /* set crc err */ + if (ta_stopioe) return SCPE_IOERR; + break; + + case MTSE_INVRL: /* invalid rec lnt */ + ta_cs |= TACS_ERR|TACS_CRC; /* set crc err */ + return SCPE_MTRLNT; + + case MTSE_RECE: /* record in error */ + case MTSE_EOM: /* end of medium */ + ta_cs |= TACS_ERR|TACS_CRC; /* set crc err */ + break; + + case MTSE_BOT: /* reverse into BOT */ + ta_cs |= TACS_ERR|TACS_BEOT; /* set bot */ + break; + + case MTSE_WRP: /* write protect */ + ta_cs |= TACS_ERR|TACS_WLK; /* set wlk err */ + break; + } + +return SCPE_OK; +} + +/* Reset routine */ + +t_stat ta_reset (DEVICE *dptr) +{ +uint32 u; +UNIT *uptr; + +ta_cs = 0; +ta_idb = 0; +ta_odb = 0; +ta_write = 0; +ta_bptr = 0; +ta_blnt = 0; +CLR_INT (TA); /* clear interrupt */ +for (u = 0; u < TA_NUMDR; u++) { /* loop thru units */ + uptr = ta_dev.units + u; + sim_cancel (uptr); /* cancel activity */ + sim_tape_reset (uptr); /* reset tape */ + } +if (ta_xb == NULL) ta_xb = (uint8 *) calloc (TA_MAXFR + 2, sizeof (uint8)); +if (ta_xb == NULL) return SCPE_MEM; +return SCPE_OK; +} + +/* Attach routine */ + +t_stat ta_attach (UNIT *uptr, char *cptr) +{ +t_stat r; + +r = sim_tape_attach (uptr, cptr); +if (r != SCPE_OK) return r; +ta_updsta (NULL); +uptr->UST = 0; +return r; +} + +/* Detach routine */ + +t_stat ta_detach (UNIT* uptr) +{ +t_stat r; + +if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* check attached */ +r = sim_tape_detach (uptr); +ta_updsta (NULL); +uptr->UST = 0; +return r; +} diff --git a/PDP11/pdp11_tc.c b/PDP11/pdp11_tc.c index dd1f3c82..d1ea2d65 100644 --- a/PDP11/pdp11_tc.c +++ b/PDP11/pdp11_tc.c @@ -640,7 +640,7 @@ switch (fnc) { /* case function */ case DTS_OFR: /* off reel */ if (dir) newpos = -1000; /* rev? < start */ - else newpos = DTU_FWDEZ (uptr) + DT_EZLIN + 1000; /* fwd? > end */ + else newpos = DTU_FWDEZ (uptr) + DT_EZLIN + 1000; /* fwd? > end */ break; case FNC_SRCH: /* search */ @@ -811,7 +811,7 @@ switch (mot) { return IORETURN (dt_stopoffr, STOP_DTOFF); uptr->STATE = DTS_NXTSTA (uptr->STATE); /* advance state */ if (uptr->STATE) /* not stopped? */ - sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* reversing */ + sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* reversing */ return SCPE_OK; case DTS_ACCF: case DTS_ACCR: /* accelerating */ @@ -1061,9 +1061,9 @@ int32 wrd = relpos / DT_WSIZE; if (wrd == DT_BLKWD) return blk; /* fwd blknum */ if (wrd == DT_CSMWD) return 077; /* rev csum */ -if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_CSMWD - 1)) /* fwd csum */ +if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_CSMWD - 1)) /* fwd csum */ return (dt_csum (uptr, blk) << 12); -if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_BLKWD - 1)) /* rev blkno */ +if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_BLKWD - 1)) /* rev blkno */ return dt_comobv (blk); return 0; /* all others */ } @@ -1107,43 +1107,43 @@ return SCPE_OK; #define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) static const uint16 boot_rom[] = { - 0042124, /* "TD" */ - 0012706, BOOT_START, /* MOV #boot_start, SP */ - 0012700, 0000000, /* MOV #unit, R0 ; unit number */ - 0010003, /* MOV R0, R3 */ - 0000303, /* SWAB R3 */ - 0012701, 0177342, /* MOV #TCCM, R1 ; csr */ - 0012702, 0004003, /* RW: MOV #4003, R2 ; rev+rnum+go */ - 0050302, /* BIS R3, R2 */ - 0010211, /* MOV R2, (R1) ; load csr */ - 0032711, 0100200, /* BIT #100200, (R1) ; wait */ - 0001775, /* BEQ .-4 */ - 0100370, /* BPL RW ; no err, cont */ - 0005761, 0177776, /* TST -2(R1) ; end zone? */ - 0100036, /* BPL ER ; no, err */ - 0012702, 0000003, /* MOV #3, R2 ; rnum+go */ - 0050302, /* BIS R3, R2 */ - 0010211, /* MOV R2, (R1) ; load csr */ - 0032711, 0100200, /* BIT #100200, (R1) ; wait */ - 0001775, /* BEQ .-4 */ - 0100426, /* BMI ER ; err, die */ - 0005761, 0000006, /* TST 6(R1) ; blk 0? */ - 0001023, /* BNE ER ; no, die */ - 0012761, 0177000, 0000002, /* MOV #-256.*2, 2(R1) ; load wc */ - 0005061, 0000004, /* CLR 4(R1) ; clear ba */ - 0012702, 0000005, /* MOV #READ+GO, R2 ; read & go */ - 0050302, /* BIS R3, R2 */ - 0010211, /* MOV R2, (R1) ; load csr */ - 0005002, /* CLR R2 */ - 0005003, /* CLR R3 */ - 0012704, BOOT_START+020, /* MOV #START+20, R4 */ - 0005005, /* CLR R5 */ - 0032711, 0100200, /* BIT #100200, (R1) ; wait */ - 0001775, /* BEQ .-4 */ - 0100401, /* BMI ER ; err, die */ - 0005007, /* CLR PC */ - 0012711, 0000001, /* ER: MOV #1, (R1) ; stop all */ - 0000000 /* HALT */ + 0042124, /* "TD" */ + 0012706, BOOT_START, /* MOV #boot_start, SP */ + 0012700, 0000000, /* MOV #unit, R0 ; unit number */ + 0010003, /* MOV R0, R3 */ + 0000303, /* SWAB R3 */ + 0012701, 0177342, /* MOV #TCCM, R1 ; csr */ + 0012702, 0004003, /* RW: MOV #4003, R2 ; rev+rnum+go */ + 0050302, /* BIS R3, R2 */ + 0010211, /* MOV R2, (R1) ; load csr */ + 0032711, 0100200, /* BIT #100200, (R1) ; wait */ + 0001775, /* BEQ .-4 */ + 0100370, /* BPL RW ; no err, cont */ + 0005761, 0177776, /* TST -2(R1) ; end zone? */ + 0100036, /* BPL ER ; no, err */ + 0012702, 0000003, /* MOV #3, R2 ; rnum+go */ + 0050302, /* BIS R3, R2 */ + 0010211, /* MOV R2, (R1) ; load csr */ + 0032711, 0100200, /* BIT #100200, (R1) ; wait */ + 0001775, /* BEQ .-4 */ + 0100426, /* BMI ER ; err, die */ + 0005761, 0000006, /* TST 6(R1) ; blk 0? */ + 0001023, /* BNE ER ; no, die */ + 0012761, 0177000, 0000002, /* MOV #-256.*2, 2(R1) ; load wc */ + 0005061, 0000004, /* CLR 4(R1) ; clear ba */ + 0012702, 0000005, /* MOV #READ+GO, R2 ; read & go */ + 0050302, /* BIS R3, R2 */ + 0010211, /* MOV R2, (R1) ; load csr */ + 0005002, /* CLR R2 */ + 0005003, /* CLR R3 */ + 0012704, BOOT_START+020, /* MOV #START+20, R4 */ + 0005005, /* CLR R5 */ + 0032711, 0100200, /* BIT #100200, (R1) ; wait */ + 0001775, /* BEQ .-4 */ + 0100401, /* BMI ER ; err, die */ + 0005007, /* CLR PC */ + 0012711, 0000001, /* ER: MOV #1, (R1) ; stop all */ + 0000000 /* HALT */ }; t_stat dt_boot (int32 unitno, DEVICE *dptr) @@ -1179,7 +1179,7 @@ t_stat r; r = attach_unit (uptr, cptr); /* attach */ if (r != SCPE_OK) return r; /* fail? */ if ((sim_switches & SIM_SW_REST) == 0) { /* not from rest? */ - uptr->flags = (uptr->flags | UNIT_11FMT) & ~UNIT_8FMT; /* default 16b */ + uptr->flags = (uptr->flags | UNIT_11FMT) & ~UNIT_8FMT; /* default 16b */ if (sim_switches & SWMASK ('T')) /* att 12b? */ uptr->flags = (uptr->flags | UNIT_8FMT) & ~UNIT_11FMT; else if (sim_switches & SWMASK ('F')) /* att 18b? */ diff --git a/PDP11/pdp11_tm.c b/PDP11/pdp11_tm.c index ce387d24..0be12fe1 100644 --- a/PDP11/pdp11_tm.c +++ b/PDP11/pdp11_tm.c @@ -118,7 +118,7 @@ #define MTC_FNC (MTC_M_FNC << MTC_V_FNC) #define MTC_GO (1 << CSR_V_GO) /* go */ #define MTC_RW (MTC_DEN | MTC_LPAR | MTC_UNIT | MTC_IE | \ - MTC_EMA | MTC_FNC) + MTC_EMA | MTC_FNC) #define GET_EMA(x) (((x) & MTC_EMA) << (16 - MTC_V_EMA)) #define GET_UNIT(x) (((x) >> MTC_V_UNIT) & MTC_M_UNIT) #define GET_FNC(x) (((x) >> MTC_V_FNC) & MTC_M_FNC) @@ -422,7 +422,7 @@ if ((uptr->flags & UNIT_ATT) == 0) { /* if not attached */ } if (DEBUG_PRS (tm_dev)) fprintf (sim_deb, - ">>TM: op=%o, ma=%o, bc=%o, pos=%d\n", f, xma, cbc, uptr->pos); + ">>TM: op=%o, ma=%o, bc=%o, pos=%d\n", f, xma, tm_bc, uptr->pos); switch (f) { /* case on function */ case MTC_READ: /* read */ @@ -488,7 +488,7 @@ tm_ca = xma & 0177777; /* update mem addr */ tm_set_done (); /* set done */ tm_updcsta (uptr); /* update status */ if (DEBUG_PRS (tm_dev)) fprintf (sim_deb, - ">>TM: sta=%o, ma=%o, wc=%o, pos=%d\n", + ">>TM: sta=%o, ma=%o, bc=%o, pos=%d\n", tm_sta, tm_ca, tm_bc, uptr->pos); return r; } diff --git a/PDP11/pdp11_tu.c b/PDP11/pdp11_tu.c index de5b67ca..21815c4b 100644 --- a/PDP11/pdp11_tu.c +++ b/PDP11/pdp11_tu.c @@ -653,7 +653,7 @@ switch (fnc) { /* case on function */ else tutc = tutc & ~TC_FCS; break; - case FNC_WREOF: /* write end of file */ + case FNC_WREOF: /* write end of file */ if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ r = tu_map_err (drv, st, 0); /* map error */ break; diff --git a/PDP11/pdp11_vh.c b/PDP11/pdp11_vh.c index fa7f6dab..f7f131c2 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-2005, John A. Dundas III + Copyright (c) 2004-2006, 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 + 29-Oct-06 RMS Synced poll and clock 07-Jul-05 RMS Removed extraneous externs 15-Jun-05 RMS Revised for new autoconfigure interface Fixed bug in vector display routine @@ -382,7 +383,7 @@ DEVICE vh_dev = { &vh_attach, /* attach routine */ &vh_detach, /* detach routine */ (void *)&vh_dib, /* context */ - DEV_FLTA | DEV_DISABLE | DEV_NET | DEV_QBUS | DEV_UBUS, /* flags */ + DEV_FLTA | DEV_DISABLE | DEV_DIS |DEV_NET | DEV_QBUS | DEV_UBUS, /* flags */ }; /* Interrupt routines */ @@ -791,7 +792,7 @@ static t_stat vh_wr ( int32 data, if (data & CSR_MASTER_RESET) { if ((vh_unit[vh].flags & UNIT_MODEDHU) && (data & CSR_SKIP)) data &= ~CSR_MASTER_RESET; - sim_activate (&vh_unit[vh], tmxr_poll); + sim_activate (&vh_unit[vh], clk_cosched (tmxr_poll)); /* vh_mcount[vh] = 72; */ /* 1.2 seconds */ vh_mcount[vh] = MS2SIMH (1200); /* 1.2 seconds */ } diff --git a/PDP11/pdp11_xq.c b/PDP11/pdp11_xq.c index 2901b2f5..f1323745 100644 --- a/PDP11/pdp11_xq.c +++ b/PDP11/pdp11_xq.c @@ -66,6 +66,7 @@ Modification history: + 29-Oct-06 RMS Synced poll and clock 27-Jan-06 RMS Fixed unaligned accesses in XQB (found by Doug Carman) 07-Jan-06 RMS Fixed unaligned access bugs (found by Doug Carman) 07-Sep-05 DTH Removed unused variable @@ -209,7 +210,7 @@ #include "pdp11_xq.h" #include "pdp11_xq_bootrom.h" -extern int32 tmr_poll, clk_tps; +extern int32 tmxr_poll; extern FILE* sim_deb; extern char* read_line (char *ptr, int32 size, FILE *stream); @@ -1621,7 +1622,7 @@ t_stat xq_wr_csr(CTLR* xq, int32 data) /* start/stop receive timer when RE transitions */ if ((xq->var->csr ^ data) & XQ_CSR_RE) { if (data & XQ_CSR_RE) - sim_activate(&xq->unit[0], (clk_tps * tmr_poll)/xq->var->poll); + sim_activate(&xq->unit[0], clock_cosched (tmxr_poll)); else sim_cancel(&xq->unit[0]); } @@ -1682,8 +1683,6 @@ t_stat xq_reset(DEVICE* dptr) t_stat status; CTLR* xq = xq_dev2ctlr(dptr); const uint16 set_bits = XQ_CSR_RL | XQ_CSR_XL; - /* must be recalculated each time since tmr_poll is a dynamic number */ - const int32 one_second = clk_tps * tmr_poll; sim_debug(DBG_TRC, xq->dev, "xq_reset()\n"); @@ -1721,7 +1720,7 @@ t_stat xq_reset(DEVICE* dptr) xq_csr_set_clr(xq, XQ_CSR_OK, 0); /* start service timer */ - sim_activate(&xq->unit[0], one_second/xq->var->poll); + sim_activate_abs(&xq->unit[0], tmxr_poll); } /* set hardware sanity controls */ @@ -1826,9 +1825,6 @@ t_stat xq_svc(UNIT* uptr) { CTLR* xq = xq_unit2ctlr(uptr); - /* must be recalculated each time since tmr_poll is a dynamic number */ - const int32 one_second = clk_tps * tmr_poll; - /* if the receiver is enabled */ if (xq->var->csr & XQ_CSR_RE) { t_stat status; @@ -1867,7 +1863,7 @@ t_stat xq_svc(UNIT* uptr) } /* resubmit service timer */ - sim_activate(&xq->unit[0], one_second/xq->var->poll); + sim_activate(&xq->unit[0], tmxr_poll); return SCPE_OK; } diff --git a/PDP11/pdp11_xu.c b/PDP11/pdp11_xu.c index 2eb96e0a..87ba7992 100644 --- a/PDP11/pdp11_xu.c +++ b/PDP11/pdp11_xu.c @@ -1,7 +1,7 @@ /* pdp11_xu.c: DEUNA/DELUA ethernet controller simulator ------------------------------------------------------------------------------ - Copyright (c) 2003-2005, David T. Hittner + Copyright (c) 2003-2006, David T. Hittner Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -57,6 +57,7 @@ Modification history: + 29-Oct-06 RMS Synced poll and clock 08-Dec-05 DTH Implemented ancilliary functions 022/023/024/025 18-Nov-05 DTH Corrected time between system ID packets 07-Sep-05 DTH Corrected runt packet processing (found by Tim Chapman), @@ -83,7 +84,7 @@ #include "pdp11_xu.h" -extern int32 tmr_poll, clk_tps, cpu_astop; +extern int32 tmxr_poll, tmr_poll, clk_tps, cpu_astop; extern FILE *sim_log; t_stat xu_rd(int32* data, int32 PA, int32 access); @@ -449,8 +450,8 @@ t_stat xu_svc(UNIT* uptr) int queue_size; t_stat status; CTLR* xu = xu_unit2ctlr(uptr); - const int one_second = clk_tps * tmr_poll; /* recalibrate timer */ const ETH_MAC mop_multicast = {0xAB, 0x00, 0x00, 0x02, 0x00, 0x00}; + const int one_second = clk_tps * tmr_poll; /* First pump any queued packets into the system */ if ((xu->var->ReadQ.count > 0) && ((xu->var->pcsr1 & PCSR1_STATE) == STATE_RUNNING)) @@ -486,7 +487,7 @@ t_stat xu_svc(UNIT* uptr) switch (xu->var->pcsr1 & PCSR1_STATE) { case STATE_READY: case STATE_RUNNING: - sim_activate(&xu->unit[0], one_second/XU_SERVICE_INTERVAL); + sim_activate(&xu->unit[0], tmxr_poll); break; }; @@ -522,7 +523,6 @@ void xu_setclrint(CTLR* xu, int32 bits) t_stat xu_sw_reset (CTLR* xu) { t_stat status; - const int one_second = clk_tps * tmr_poll; /* recalibrate timer */ sim_debug(DBG_TRC, xu->dev, "xu_sw_reset()\n"); @@ -564,10 +564,9 @@ t_stat xu_sw_reset (CTLR* xu) &xu->var->mac, xu->var->setup.multicast, xu->var->setup.promiscuous); - /* activate device if not disabled - cancel first, just in case */ + /* activate device if not disabled */ if ((xu->dev->flags & DEV_DIS) == 0) { - sim_cancel(&xu->unit[0]); - sim_activate(&xu->unit[0], one_second/XU_SERVICE_INTERVAL); + sim_activate_abs(&xu->unit[0], clk_cosched (tmxr_poll)); } /* clear load_server address */ @@ -727,9 +726,9 @@ sim_debug(DBG_TRC, xu->dev, "FC_WAL: mtlen=%d\n", mtlen); xu->var->rrlen = xu->var->udb[5]; xu->var->rxnext = 0; xu->var->txnext = 0; -xu_dump_rxring(xu); -xu_dump_txring(xu); -/*cpu_astop=1;*/ +// xu_dump_rxring(xu); +// xu_dump_txring(xu); + break; case FC_RDCTR: /* read counters */ @@ -1072,7 +1071,7 @@ void xu_process_receive(CTLR* xu) /* set or clear interrupt, depending on what happened */ xu_setclrint(xu, 0); -xu_dump_rxring(xu); /* debug receive ring */ +// xu_dump_rxring(xu); /* debug receive ring */ } diff --git a/PDP18B/pdp18b_cpu.c b/PDP18B/pdp18b_cpu.c index 3cbc50a0..b2563876 100644 --- a/PDP18B/pdp18b_cpu.c +++ b/PDP18B/pdp18b_cpu.c @@ -25,6 +25,13 @@ cpu PDP-4/7/9/15 central processor + 26-Dec-06 RMS Fixed boundary test in KT15/XVM (reported by Andrew Warkentin) + 30-Oct-06 RMS Added idle and infinite loop detection + 08-Oct-06 RMS Added RDCLK instruction + Fixed bug, PC off by one on fetch mem mmgt error + PDP-15 sets API 3 on mem mmgt trap (like PI) + PDP-15 sets API 4 on CAL only if 0-3 inactive + CAF clears memory management mode register 27-Jun-06 RMS Reset clears AC, L, and MQ 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) 16-Aug-05 RMS Fixed C++ declaration and cast problems @@ -285,6 +292,7 @@ #define UNIT_RELOC (1 << UNIT_V_RELOC) #define UNIT_XVM (1 << UNIT_V_XVM) #define UNIT_MSIZE (1 << UNIT_V_MSIZE) +#define OP_KSF 0700301 #define HIST_API 0x40000000 #define HIST_PI 0x20000000 @@ -373,6 +381,7 @@ InstHistory *hst = NULL; /* instruction history * extern int32 sim_int_char; extern int32 sim_interval; extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern t_bool sim_idle_enab; extern DEVICE *sim_devices[]; extern FILE *sim_log; @@ -383,6 +392,7 @@ t_stat cpu_reset (DEVICE *dptr); t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc); +void cpu_caf (void); void cpu_inst_hist (int32 addr, int32 inst); void cpu_intr_hist (int32 flag, int32 lvl); int32 upd_iors (void); @@ -398,6 +408,7 @@ int32 Prot15 (int32 ma, t_bool bndchk); int32 Reloc15 (int32 ma, int32 acc); int32 RelocXVM (int32 ma, int32 acc); extern t_stat fp15 (int32 ir); +extern int32 clk_task_upd (t_bool clr); #else #define INDEX(i,x) #endif @@ -530,6 +541,8 @@ MTAB cpu_mod[] = { { UNIT_PROT+UNIT_RELOC+UNIT_XVM, UNIT_PROT+UNIT_RELOC+UNIT_XVM, "XVM", "XVM", NULL }, #endif + { MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL }, #if defined (PDP4) { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size }, #endif @@ -566,6 +579,7 @@ t_stat sim_instr (void) { int32 api_int, api_usmd, skp; int32 iot_data, device, pulse; +int32 last_IR; t_stat reason; extern UNIT clk_unit; @@ -574,6 +588,7 @@ PC = PC & AMASK; /* clean variables */ LAC = LAC & LACMASK; MQ = MQ & DMASK; reason = 0; +last_IR = -1; sim_rtc_init (clk_unit.wait); /* init calibration */ if (cpu_unit.flags & UNIT_NOAPI) api_enb = api_req = api_act = 0; api_int = api_eval (&int_pend); /* eval API */ @@ -642,8 +657,18 @@ while (reason == 0) { /* loop until halted */ if (trap_pending) { /* trap pending? */ PCQ_ENTRY; /* save old PC */ MB = Jms_word (1); /* save state */ - MA = ion? 0: 020; /* save in 0/20 */ - ion = 0; /* interrupts off */ + if (ion) { /* int on? */ + ion = 0; /* interrupts off */ + MA = 0; /* treat like PI */ +#if defined (PDP15) + ion_defer = 2; /* free instruction */ + if (!(cpu_unit.flags & UNIT_NOAPI)) { /* API? */ + api_act = api_act | API_ML3; /* set lev 3 active */ + api_int = api_eval (&int_pend); /* re-evaluate */ + } +#endif + } + else MA = 020; /* sortof like CAL */ emir_pending = rest_pending = trap_pending = 0; /* emir,rest,trap off */ usmd = usmd_buf = 0; /* user mode off */ Write (MA, MB, WR); /* physical write */ @@ -676,6 +701,7 @@ while (reason == 0) { /* loop until halted */ usmd = usmd_buf = 0; /* user mode off */ emir_pending = rest_pending = 0; /* emir, restore off */ xct_count = 0; + Read (MA, &IR, FE); /* fetch instruction */ goto xct_instr; } @@ -685,10 +711,10 @@ while (reason == 0) { /* loop until halted */ if (hst_lnt) cpu_intr_hist (HIST_PI, 0); /* record */ MB = Jms_word (usmd); /* save state */ ion = 0; /* interrupts off */ + ion_defer = 2; /* free instruction */ #if defined (PDP9) /* PDP-9, */ memm = 0; /* extend off */ #else /* PDP-15 */ - ion_defer = 2; /* free instruction */ if (!(cpu_unit.flags & UNIT_NOAPI)) { /* API? */ api_act = api_act | API_ML3; /* set lev 3 active */ api_int = api_eval (&int_pend); /* re-evaluate */ @@ -713,10 +739,10 @@ while (reason == 0) { /* loop until halted */ xct_count = 0; /* track nested XCT's */ MA = PC; /* fetch at PC */ + if (Read (MA, &IR, FE)) continue; /* fetch instruction */ PC = Incr_addr (PC); /* increment PC */ - xct_instr: /* label for XCT */ - if (Read (MA, &IR, FE)) continue; /* fetch instruction */ + xct_instr: /* label for API, XCT */ if (hst_lnt) cpu_inst_hist (MA, IR); /* history? */ if (ion_defer) ion_defer = ion_defer - 1; /* count down defer */ if (sim_interval) sim_interval = sim_interval - 1; @@ -846,6 +872,7 @@ while (reason == 0) { /* loop until halted */ #if defined (PDP9) ion_defer = 1; /* defer intr */ #endif + if (Read (MA, &IR, FE)) break; /* fetch inst, mm err? */ goto xct_instr; /* go execute */ /* CAL: opcode 00 - api_usmd records whether usmd = 1 at start of API cycle @@ -867,7 +894,10 @@ while (reason == 0) { /* loop until halted */ #if defined (PDP9) || defined (PDP15) usmd = usmd_buf = 0; /* clear user mode */ if ((cpu_unit.flags & UNIT_NOAPI) == 0) { /* if API, act lvl 4 */ - api_act = api_act | 010; +#if defined (PDP15) /* PDP15: if 0-3 inactive */ + if ((api_act & (API_ML0|API_ML1|API_ML2|API_ML3)) == 0) +#endif + api_act = api_act | API_ML4; api_int = api_eval (&int_pend); } #endif @@ -899,9 +929,29 @@ while (reason == 0) { /* loop until halted */ case 031: /* JMP, indir */ if (Ia (MA, &MA, 1)) break; + INDEX (IR, MA); + PCQ_ENTRY; /* save old PC */ + PC = MA & AMASK; + break; + +/* JMP direct - check for idle */ + case 030: /* JMP, dir */ INDEX (IR, MA); PCQ_ENTRY; /* save old PC */ + if (sim_idle_enab) { /* idling enabled? */ + t_bool iof = (ion_inh != 0) || /* IOF if inhibited */ + ((ion == 0) && (api_enb == 0)); /* or PI and api off */ + if (((MA ^ (PC - 2)) & AMASK) == 0) { /* 1) JMP *-1? */ + if (iof && (last_IR == OP_KSF) && /* iof, prv KSF, */ + !TST_INT (TTI)) /* no TTI flag? */ + sim_idle (0, FALSE); /* we're idle */ + } + else if (((MA ^ (PC - 1)) & AMASK) == 0) { /* 2) JMP *? */ + if (iof) reason = STOP_LOOP; /* iof? inf loop */ + else sim_idle (0, FALSE); /* ion? idle */ + } + } /* end idle */ PC = MA & AMASK; break; @@ -1369,12 +1419,15 @@ while (reason == 0) { /* loop until halted */ case 017: /* mem protection */ if (PROT) { /* enabled? */ - if ((pulse == 001) && prvn) PC = Incr_addr (PC); - else if ((pulse == 041) && nexm) PC = Incr_addr (PC); - else if (pulse == 002) prvn = 0; - else if (pulse == 042) usmd_buf = 1; - else if (pulse == 004) BR = LAC & BRMASK; - else if (pulse == 044) nexm = 0; + if ((pulse == 001) && prvn) /* MPSK */ + PC = Incr_addr (PC); + else if ((pulse == 041) && nexm) /* MPSNE */ + PC = Incr_addr (PC); + else if (pulse == 002) prvn = 0; /* MPCV */ + else if (pulse == 042) usmd_buf = 1; /* MPEU */ + else if (pulse == 004) /* MPLD */ + BR = LAC & BRMASK; + else if (pulse == 044) nexm = 0; /* MPCNE */ } else reason = stop_inst; break; @@ -1388,7 +1441,7 @@ while (reason == 0) { /* loop until halted */ if ((pulse == 001) || (pulse == 041)) PC = Incr_addr (PC); else if (pulse == 002) { /* CAF */ reset_all (1); /* reset all exc CPU */ - api_enb = api_req = api_act = 0; /* reset API system */ + cpu_caf (); /* CAF to CPU */ } else if (pulse == 044) rest_pending = 1; /* DBR */ if (((cpu_unit.flags & UNIT_NOAPI) == 0) && (pulse & 004)) { @@ -1444,13 +1497,19 @@ while (reason == 0) { /* loop until halted */ case 017: /* mem protection */ if (PROT) { /* enabled? */ t = XVM? BRMASK_XVM: BRMASK; - if ((pulse == 001) && prvn) PC = Incr_addr (PC); - else if ((pulse == 041) && nexm) PC = Incr_addr (PC); - else if (pulse == 002) prvn = 0; - else if (pulse == 042) usmd_buf = 1; - else if (pulse == 004) BR = LAC & t; - else if (RELOC && (pulse == 024)) RR = LAC & t; - else if (pulse == 044) nexm = 0; + if ((pulse == 001) && prvn) /* MPSK */ + PC = Incr_addr (PC); + else if ((pulse == 041) && nexm) /* MPSNE */ + PC = Incr_addr (PC); + else if (pulse == 002) prvn = 0; /* MPCV */ + else if (pulse == 042) /* MPEU */ + usmd_buf = 1; + else if (XVM && (pulse == 062)) /* RDCLK */ + iot_data = clk_task_upd (TRUE); + else if (pulse == 004) BR = LAC & t; /* MPLD */ + else if (RELOC && (pulse == 024)) /* MPLR */ + RR = LAC & t; + else if (pulse == 044) nexm = 0; /* MPCNE */ } else reason = stop_inst; break; @@ -1464,7 +1523,7 @@ while (reason == 0) { /* loop until halted */ if ((pulse == 001) || (pulse == 041)) PC = Incr_addr (PC); else if (pulse == 002) { /* CAF */ reset_all (2); /* reset all exc CPU, FP15 */ - api_enb = api_req = api_act = 0; /* reset API system */ + cpu_caf (); /* CAF to CPU */ } else if (pulse == 044) rest_pending = 1; /* DBR */ if (((cpu_unit.flags & UNIT_NOAPI) == 0) && (pulse & 004)) { @@ -1519,6 +1578,7 @@ while (reason == 0) { /* loop until halted */ } /* end switch opcode */ api_usmd = 0; /* API cycle over */ + last_IR = IR; /* save IR for next */ } /* end while */ /* Simulation halted */ @@ -1835,7 +1895,7 @@ int32 Reloc15 (int32 ma, int32 rc) int32 pa; ma = ma & AMASK; /* 17b addressing */ -if (ma >= (BR | 0377)) { /* boundary viol? */ +if (ma > (BR | 0377)) { /* boundary viol? */ if (rc != REL_C) prvn = trap_pending = 1; /* set flag, trap */ return -1; } @@ -1871,7 +1931,7 @@ else if ((MMR & MM_SH) && /* shared enabled and */ else pa = RR + (ma & 0377); /* no, ISAS reloc */ } else { - if (ma >= (BR | 0377)) { /* normal reloc, viol? */ + if (ma > (BR | 0377)) { /* normal reloc, viol? */ if (rc != REL_C) prvn = trap_pending = 1; /* set flag, trap */ return -1; } @@ -1911,6 +1971,17 @@ sim_brk_types = sim_brk_dflt = SWMASK ('E'); return SCPE_OK; } +/* CAF routine (CPU reset isn't called by CAF) */ + +void cpu_caf (void) +{ +api_enb = api_req = api_act = 0; /* reset API system */ +nexm = prvn = trap_pending = 0; /* reset MM system */ +usmd = usmd_buf = usmd_defer = 0; +MMR = 0; +return; +} + /* Memory examine */ t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) diff --git a/PDP18B/pdp18b_defs.h b/PDP18B/pdp18b_defs.h index 7f451415..d4e4e903 100644 --- a/PDP18B/pdp18b_defs.h +++ b/PDP18B/pdp18b_defs.h @@ -1,6 +1,6 @@ /* pdp18b_defs.h: 18b PDP simulator definitions - Copyright (c) 1993-2005, Robert M Supnik + Copyright (c) 1993-2006, 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. + 30-Oct-06 RMS Added infinite loop stop 14-Jan-04 RMS Revised IO device call interface 18-Oct-03 RMS Added DECtape off reel message 18-Jul-03 RMS Added FP15 support @@ -113,6 +114,7 @@ #define STOP_MME 7 /* mem mgt error */ #define STOP_FPDIS 8 /* fp inst, fpp disabled */ #define STOP_DTOFF 9 /* DECtape off reel */ +#define STOP_LOOP 10 /* infinite loop */ /* Peripheral configuration */ diff --git a/PDP18B/pdp18b_fpp.c b/PDP18B/pdp18b_fpp.c index 805004fe..c5749908 100644 --- a/PDP18B/pdp18b_fpp.c +++ b/PDP18B/pdp18b_fpp.c @@ -414,7 +414,7 @@ if (ir & FI_FP) { /* fp? */ numwd = 3; /* 3 words */ } else { /* single */ - if (!(ir & FI_NORND) && (a->lo & UFP_FL_SRND)) { /* round? */ + if (!(ir & FI_NORND) && (a->lo & UFP_FL_SRND)) { /* round? */ a->lo = (a->lo + UFP_FL_SRND) & UFP_FL_SMASK; a->hi = (a->hi + (a->lo == 0)) & UFP_FH_MASK; if ((a->hi | a->lo) == 0) { /* carry out? */ @@ -424,7 +424,7 @@ if (ir & FI_FP) { /* fp? */ } if (a->exp > 0377) return FP_OVF; /* sp ovf? */ if (a->exp < -0400) return FP_UNF; /* sp unf? */ - wd[0] = (a->exp & 0777) | (a->lo & UFP_FL_SMASK); /* low frac'exp */ + wd[0] = (a->exp & 0777) | (a->lo & UFP_FL_SMASK); /* low frac'exp */ wd[1] = (a->sign << 17) | a->hi; /* hi frac */ numwd = 2; /* 2 words */ } diff --git a/PDP18B/pdp18b_lp.c b/PDP18B/pdp18b_lp.c index f5a346f3..c930a160 100644 --- a/PDP18B/pdp18b_lp.c +++ b/PDP18B/pdp18b_lp.c @@ -225,8 +225,8 @@ return SCPE_OK; int32 lp62_iors (void) { -return (TST_INT (LPT)? IOS_LPT: 0) | - (TST_INT (LPTSPC)? IOS_LPT1: 0); +return (TST_INT (LPT)? IOS_LPT: 0) | + (TST_INT (LPTSPC)? IOS_LPT1: 0); } #endif @@ -718,7 +718,7 @@ int32 header, sb; sb = pulse & 060; /* subopcode */ if (pulse & 01) { - if ((sb == 000) && (lp15_sta & (STA_ERR | STA_DON))) /* LPSF */ + if ((sb == 000) && (lp15_sta & (STA_ERR | STA_DON))) /* LPSF */ dat = IOT_SKP | dat; else if ((sb == 020) || (sb == 040)) { /* LPP1, LPPM */ sim_activate (&lp15_unit, lp15_unit.wait); /* activate */ @@ -732,7 +732,7 @@ if (pulse & 01) { } else if (sb == 060) lp15_ie = 0; /* LPDI */ } -if ((pulse & 02) && (sb == 040)) dat = dat | lp15_updsta (0); /* LPOS, LPRS */ +if ((pulse & 02) && (sb == 040)) dat = dat | lp15_updsta (0); /* LPOS, LPRS */ if ((pulse & 04) && (sb == 040)) lp15_ie = 1; /* LPEI */ lp15_updsta (0); /* update status */ return dat; @@ -799,7 +799,7 @@ for (more = 1; more != 0; ) { /* loop until ctrl */ lp15_bp = more = 0; } else { - if (lp15_bp < LP15_BSIZE) lp15_buf[lp15_bp++] = c[i]; + if (lp15_bp < LP15_BSIZE) lp15_buf[lp15_bp++] = c[i]; else lp15_sta = lp15_sta | STA_OVF; } } @@ -816,7 +816,7 @@ return SCPE_OK; int32 lp15_updsta (int32 new) { lp15_sta = (lp15_sta | new) & ~(STA_CLR | STA_ERR | STA_BUSY); -if (lp15_sta & STA_EFLGS) lp15_sta = lp15_sta | STA_ERR; /* update errors */ +if (lp15_sta & STA_EFLGS) lp15_sta = lp15_sta | STA_ERR; /* update errors */ if (sim_is_active (&lp15_unit)) lp15_sta = lp15_sta | STA_BUSY; if (lp15_ie && (lp15_sta & STA_DON)) SET_INT (LPT); else CLR_INT (LPT); /* update int */ diff --git a/PDP18B/pdp18b_rf.c b/PDP18B/pdp18b_rf.c index 73910382..51655485 100644 --- a/PDP18B/pdp18b_rf.c +++ b/PDP18B/pdp18b_rf.c @@ -26,6 +26,7 @@ rf (PDP-9) RF09/RF09 (PDP-15) RF15/RS09 + 04-Oct-06 RMS Fixed bug, DSCD does not clear function register 15-May-06 RMS Fixed bug in autosize attach (reported by David Gesswein) 14-Jan-04 RMS Revised IO device call interface Changed sim_fsize calling sequence @@ -100,6 +101,7 @@ #define RFS_CLR 0000170 /* always clear */ #define RFS_EFLGS (RFS_HDW | RFS_APE | RFS_MXF | RFS_WCE | \ RFS_DPE | RFS_WLO | RFS_NED ) /* error flags */ +#define RFS_FR (RFS_FNC|RFS_IE) #define GET_FNC(x) (((x) >> RFS_V_FNC) & RFS_M_FNC) #define GET_POS(x) ((int) fmod (sim_gtime () / ((double) (x)), \ ((double) RF_NUMWD))) @@ -187,8 +189,8 @@ int32 t, sb; sb = pulse & 060; /* subopcode */ if (pulse & 01) { - if ((sb == 000) && (rf_sta & (RFS_ERR | RFS_DON))) - dat = IOT_SKP | dat; /* DSSF */ + if ((sb == 000) && (rf_sta & (RFS_ERR | RFS_DON))) /* DSSF */ + dat = IOT_SKP | dat; else if (sb == 020) rf_reset (&rf_dev); /* DSCC */ else if (sb == 040) { /* DSCF */ if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy inhibits */ @@ -237,7 +239,7 @@ if (pulse & 02) { (sim_is_active (&rf_unit)? 0400000: 0); else if (sb == 040) { /* DSCD */ if (RF_BUSY) rf_sta = rf_sta | RFS_PGE; /* busy inhibits */ - else rf_sta = 0; + else rf_sta = rf_sta & RFS_FR; rf_updsta (0); } else if (sb == 060) { /* DSRS */ diff --git a/PDP18B/pdp18b_rp.c b/PDP18B/pdp18b_rp.c index cd9e8564..b6df6151 100644 --- a/PDP18B/pdp18b_rp.c +++ b/PDP18B/pdp18b_rp.c @@ -46,7 +46,8 @@ #define RP_NUMSF 20 /* surfaces/cylinder */ #define RP_NUMCY 203 /* cylinders/drive */ #define RP_NUMDR 8 /* drives/controller */ -#define RP_SIZE (RP_NUMCY * RP_NUMSF * RP_NUMSC * RP_NUMWD) /* words/drive */ +#define RP_SIZE (RP_NUMCY * RP_NUMSF * RP_NUMSC * RP_NUMWD) + /* words/drive */ /* Unit specific flags */ @@ -262,7 +263,8 @@ if (pulse & 01) { if (sb == 020) dat = IOT_SKP | dat; /* DPSN */ } if (pulse & 02) { - if (sb == 000) dat = dat | rp_unit[GET_UNIT (rp_sta)].CYL; /* DPOU */ + if (sb == 000) /* DPOU */ + dat = dat | rp_unit[GET_UNIT (rp_sta)].CYL; else if (sb == 020) dat = dat | rp_da; /* DPOA */ else if (sb == 040) dat = dat | rp_ma; /* DPOC */ else if (sb == 060) dat = dat | rp_wc; /* DPOW */ @@ -272,9 +274,12 @@ if (pulse & 04) { rp_updsta (0, STB_PGE); return dat; } - if (sb == 000) rp_sta = rp_sta & ~STA_RW; /* DPCF */ - else if (sb == 020) rp_sta = rp_sta & (dat | ~STA_RW); /* DPLZ */ - else if (sb == 040) rp_sta = rp_sta | (dat & STA_RW); /* DPLO */ + if (sb == 000) /* DPCF */ + rp_sta = rp_sta & ~STA_RW; + else if (sb == 020) /* DPLZ */ + rp_sta = rp_sta & (dat | ~STA_RW); + else if (sb == 040) /* DPLO */ + rp_sta = rp_sta | (dat & STA_RW); else if (sb == 060) /* DPLF */ rp_sta = (rp_sta & ~STA_RW) | (dat & STA_RW); rp_sta = rp_sta & ~STA_DON; /* clear done */ diff --git a/PDP18B/pdp18b_stddev.c b/PDP18B/pdp18b_stddev.c index 83cc8f84..7a8f20ec 100644 --- a/PDP18B/pdp18b_stddev.c +++ b/PDP18B/pdp18b_stddev.c @@ -29,6 +29,11 @@ tto teleprinter clk clock + 18-Oct-06 RMS Added PDP-15 programmable duplex control + Fixed handling of non-printable characters in KSR mode + Changed clock to be free-running + Fixed out-of-tape behavior for PDP-9 vs PDP-15 + Synced keyboard to clock 30-Jun-06 RMS Fixed KSR-28 shift tracking 20-Jun-06 RMS Added KSR ASCII reader support 13-Jun-06 RMS Fixed Baudot letters/figures inversion for PDP-4 @@ -86,8 +91,11 @@ int32 ptr_err = 0, ptr_stopioe = 0, ptr_state = 0; int32 ptp_err = 0, ptp_stopioe = 0; int32 tti_2nd = 0; /* 2nd char waiting */ int32 tty_shift = 0; /* KSR28 shift state */ +int32 tti_fdpx = 0; /* prog mode full duplex */ int32 clk_tps = 60; /* ticks/second */ int32 tmxr_poll = 16000; /* term mux poll */ +uint32 clk_task_last = 0; +uint32 clk_task_timer = 0; const int32 asc_to_baud[128] = { 000,000,000,000,000,000,000,064, /* bell */ @@ -146,6 +154,7 @@ t_stat ptr_boot (int32 unitno, DEVICE *dptr); t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat clk_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc); +int32 clk_task_upd (t_bool clr); extern int32 upd_iors (void); @@ -164,6 +173,10 @@ REG clk_reg[] = { { FLDATA (INT, int_hwre[API_CLK], INT_V_CLK) }, { FLDATA (DONE, int_hwre[API_CLK], INT_V_CLK) }, { FLDATA (ENABLE, clk_state, 0) }, +#if defined (PDP15) + { ORDATA (TASKTIMER, clk_task_timer, 18) }, + { DRDATA (TASKLAST, clk_task_last, 32), REG_HRO }, +#endif { DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT }, { DRDATA (TPS, clk_tps, 8), PV_LEFT + REG_HRO }, { NULL } @@ -296,7 +309,7 @@ DEVICE ptp_dev = { DIB tti_dib = { DEV_TTI, 1, &tti_iors, { &tti } }; -UNIT tti_unit = { UDATA (&tti_svc, TT_MODE_KSR+TTUF_HDX, 0), KBD_POLL_WAIT }; +UNIT tti_unit = { UDATA (&tti_svc, TT_MODE_KSR+TTUF_HDX, 0), 0 }; REG tti_reg[] = { { ORDATA (BUF, tti_unit.buf, TTI_WIDTH) }, @@ -305,8 +318,11 @@ REG tti_reg[] = { #endif { FLDATA (INT, int_hwre[API_TTI], INT_V_TTI) }, { FLDATA (DONE, int_hwre[API_TTI], INT_V_TTI) }, +#if defined (PDP15) + { FLDATA (FDPX, tti_fdpx, 0) }, +#endif { DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, + { DRDATA (TIME, tti_unit.wait, 24), PV_LEFT }, { NULL } }; @@ -392,14 +408,9 @@ if (pulse & 001) { /* CLSF */ if (TST_INT (CLK)) dat = dat | IOT_SKP; } if (pulse & 004) { /* CLON/CLOF */ - if (pulse & 040) { /* CLON */ - CLR_INT (CLK); /* clear flag */ - clk_state = 1; /* clock on */ - if (!sim_is_active (&clk_unit)) /* already on? */ - sim_activate (&clk_unit, /* start, calibr */ - sim_rtc_init (clk_unit.wait)); - } - else clk_reset (&clk_dev); /* CLOF */ + CLR_INT (CLK); /* clear flag */ + if (pulse & 040) clk_state = 1; /* CLON */ + else clk_state = 0; /* CLOF */ } return dat; } @@ -410,16 +421,49 @@ t_stat clk_svc (UNIT *uptr) { int32 t; +t = sim_rtc_calb (clk_tps); /* calibrate clock */ +tmxr_poll = t; /* set mux poll */ +sim_activate (&clk_unit, t); /* reactivate unit */ +#if defined (PDP15) +clk_task_upd (FALSE); /* update task timer */ +#endif if (clk_state) { /* clock on? */ M[7] = (M[7] + 1) & DMASK; /* incr counter */ if (M[7] == 0) SET_INT (CLK); /* ovrflo? set flag */ - t = sim_rtc_calb (clk_tps); /* calibrate clock */ - sim_activate (&clk_unit, t); /* reactivate unit */ - tmxr_poll = t; /* set mux poll */ } return SCPE_OK; } +#if defined (PDP15) + +/* Task timer update (PDP-15 XVM only) + + The task timer increments monotonically at 100Khz. Since this can't be + simulated accurately, updates are done by interpolation since the last + reading. The timer is also updated at clock events to keep the cycle + counters from wrapping around more than once between updates. */ + +int32 clk_task_upd (t_bool clr) +{ +uint32 delta, val, iusec10; +uint32 cur = sim_grtime (); +uint32 old = clk_task_timer; +double usec10; + +if (cur > clk_task_last) delta = cur - clk_task_last; +else delta = clk_task_last - cur; +usec10 = ((((double) delta) * 100000.0) / + (((double) tmxr_poll) * ((double) clk_tps))); +iusec10 = (int32) usec10; +val = (clk_task_timer + iusec10) & DMASK; +if (clr) clk_task_timer = 0; +else clk_task_timer = val; +clk_task_last = cur; +return ((int32) val); +} + +#endif + /* IORS service */ int32 clk_iors (void) @@ -431,11 +475,16 @@ return (TST_INT (CLK)? IOS_CLK: 0); t_stat clk_reset (DEVICE *dptr) { +int32 t; + CLR_INT (CLK); /* clear flag */ -tmxr_poll = clk_unit.wait; /* set mux poll */ -if (!sim_is_running) { /* RESET? */ +if (!sim_is_running) { /* RESET (not CAF)? */ + t = sim_rtc_init (clk_unit.wait); /* init calibration */ + tmxr_poll = t; /* set mux poll */ + sim_activate_abs (&clk_unit, t); /* activate unit */ clk_state = 0; /* clock off */ - sim_cancel (&clk_unit); /* stop clock */ + clk_task_timer = 0; + clk_task_last = 0; } return SCPE_OK; } @@ -458,6 +507,19 @@ fprintf (st, (clk_tps == 50)? "50Hz": "60Hz"); return SCPE_OK; } +/* Paper tape reader out-of-tape handling + + The PDP-4 and PDP-7 readers behaved like most early DEC readers; when + they ran out of tape, they hung. It was up to the program to sense this + condition by running a timer. + + The PDP-9 reader controller synthesized the out of tape condition by + noticing whether there was a transition on the feed hole within a window. + The out-of-tape flag was treated like the reader flag in most cases. + + The PDP-15 reader controller received the out-of-tape flag as a static + condition from the reader itself and simply reported it via IORS. */ + /* Paper tape reader: IOT routine */ int32 ptr (int32 dev, int32 pulse, int32 dat) @@ -466,12 +528,15 @@ if (pulse & 001) { /* RSF */ if (TST_INT (PTR)) dat = dat | IOT_SKP; } if (pulse & 002) { /* RRB, RCF */ - CLR_INT (PTR); /* clear done */ + CLR_INT (PTR); /* clear flag */ dat = dat | ptr_unit.buf; /* return buffer */ } if (pulse & 004) { /* RSA, RSB */ ptr_state = (pulse & 040)? 18: 0; /* set mode */ - CLR_INT (PTR); /* clear done */ + CLR_INT (PTR); /* clear flag */ +#if !defined (PDP15) /* except on PDP15 */ + ptr_err = 0; /* clear error */ +#endif ptr_unit.buf = 0; /* clear buffer */ sim_activate (&ptr_unit, ptr_unit.wait); } @@ -486,15 +551,15 @@ int32 temp; if ((ptr_unit.flags & UNIT_ATT) == 0) { /* attached? */ #if defined (IOS_PTRERR) - SET_INT (PTR); /* if err, set int */ - ptr_err = 1; + SET_INT (PTR); /* if err, set flag */ + ptr_err = 1; /* set error */ #endif return IORETURN (ptr_stopioe, SCPE_UNATT); - } + } if ((temp = getc (ptr_unit.fileref)) == EOF) { /* end of file? */ #if defined (IOS_PTRERR) - SET_INT (PTR); /* if err, set done */ - ptr_err = 1; + SET_INT (PTR); /* if err, set flag */ + ptr_err = 1; /* set error */ #endif if (feof (ptr_unit.fileref)) { if (ptr_stopioe) printf ("PTR end of file\n"); @@ -532,7 +597,12 @@ t_stat ptr_reset (DEVICE *dptr) ptr_state = 0; /* clear state */ ptr_unit.buf = 0; CLR_INT (PTR); /* clear flag */ -ptr_err = (ptr_unit.flags & UNIT_ATT)? 0: 1; +#if defined (PDP15) /* PDP15, static err */ +if (((ptr_unit.flags & UNIT_ATT) == 0) || feof (ptr_unit.fileref)) + ptr_err = 1; +else +#endif +ptr_err = 0; /* all other, clr err */ sim_cancel (&ptr_unit); /* deactivate unit */ return SCPE_OK; } @@ -555,20 +625,23 @@ t_stat ptr_attach (UNIT *uptr, char *cptr) t_stat reason; reason = attach_unit (uptr, cptr); -ptr_err = (ptr_unit.flags & UNIT_ATT)? 0: 1; +if (reason != SCPE_OK) return reason; +ptr_err = 0; /* attach clrs error */ ptr_unit.flags = ptr_unit.flags & ~(UNIT_RASCII|UNIT_KASCII); if (sim_switches & SWMASK ('A')) ptr_unit.flags = ptr_unit.flags | UNIT_RASCII; if (sim_switches & SWMASK ('K')) ptr_unit.flags = ptr_unit.flags | UNIT_KASCII; -return reason; +return SCPE_OK; } /* Detach routine */ t_stat ptr_detach (UNIT *uptr) { +#if defined (PDP15) ptr_err = 1; +#endif ptr_unit.flags = ptr_unit.flags & ~UNIT_RASCII; return detach_unit (uptr); } @@ -606,7 +679,7 @@ for (;;) { /* word loop */ } else if (val == OP_HLT) return STOP_HALT; break; - } + } else if (MEM_ADDR_OK (origin)) M[origin++] = val; } return SCPE_FMT; @@ -810,7 +883,7 @@ return dat; t_stat ptp_svc (UNIT *uptr) { -SET_INT (PTP); /* set done flag */ +SET_INT (PTP); /* set flag */ if ((ptp_unit.flags & UNIT_ATT) == 0) { /* not attached? */ ptp_err = 1; /* set error */ return IORETURN (ptp_stopioe, SCPE_UNATT); @@ -859,7 +932,8 @@ t_stat ptp_attach (UNIT *uptr, char *cptr) t_stat reason; reason = attach_unit (uptr, cptr); -ptp_err = (ptp_unit.flags & UNIT_ATT)? 0: 1; +if (reason != SCPE_OK) return reason; +ptp_err = 0; ptp_unit.flags = ptp_unit.flags & ~UNIT_PASCII; if (sim_switches & SWMASK ('A')) ptp_unit.flags = ptp_unit.flags | UNIT_PASCII; @@ -882,9 +956,13 @@ int32 tti (int32 dev, int32 pulse, int32 dat) if (pulse & 001) { /* KSF */ if (TST_INT (TTI)) dat = dat | IOT_SKP; } -if (pulse & 002) { /* KRB */ +if (pulse & 002) { /* KRS/KRB */ CLR_INT (TTI); /* clear flag */ dat = dat | tti_unit.buf & TTI_MASK; /* return buffer */ +#if defined (PDP15) + if (pulse & 020) tti_fdpx = 1; /* KRS? */ + else tti_fdpx = 0; /* no, KRB */ +#endif } if (pulse & 004) { /* IORS */ dat = dat | upd_iors (); @@ -897,9 +975,9 @@ return dat; t_stat tti_svc (UNIT *uptr) { #if defined (KSR28) /* Baudot... */ -int32 in, c; +int32 in, c, out; -sim_activate (uptr, uptr->wait); /* continue poll */ +sim_activate (uptr, KBD_WAIT (uptr->wait, tmxr_poll)); /* continue poll */ if (tti_2nd) { /* char waiting? */ uptr->buf = tti_2nd; /* return char */ tti_2nd = 0; /* not waiting */ @@ -922,8 +1000,9 @@ else { } tti_2nd = c & TTI_MASK; /* save actual char */ } - if (uptr->flags & TTUF_HDX) { /* half duplex? */ - sim_putchar (sim_tt_outcvt (in, TTUF_MODE_UC)); + if ((uptr->flags & TTUF_HDX) && /* half duplex? */ + ((out = sim_tt_outcvt (in, TT_GET_MODE (uptr->flags) | TTUF_KSR)) >= 0)) { + sim_putchar (out); tto_unit.pos = tto_unit.pos + 1; } } @@ -931,13 +1010,13 @@ else { #else /* ASCII... */ int32 c, out; -sim_activate (uptr, uptr->wait); /* continue poll */ +sim_activate (uptr, KBD_WAIT (uptr->wait, tmxr_poll)); /* continue poll */ if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */ out = c & 0177; /* mask echo to 7b */ if (c & SCPE_BREAK) c = 0; /* break? */ else c = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags) | TTUF_KSR); -if ((uptr->flags & TTUF_HDX) && out && /* half duplex and */ - ((out = sim_tt_outcvt (out, TT_GET_MODE (uptr->flags))) >= 0)) { +if ((uptr->flags & TTUF_HDX) && !tti_fdpx && out && /* half duplex and */ + ((out = sim_tt_outcvt (out, TT_GET_MODE (uptr->flags) | TTUF_KSR)) >= 0)) { sim_putchar (out); /* echo */ tto_unit.pos = tto_unit.pos + 1; } @@ -963,8 +1042,9 @@ t_stat tti_reset (DEVICE *dptr) tti_unit.buf = 0; /* clear buffer */ tti_2nd = 0; tty_shift = 0; /* clear state */ +tti_fdpx = 0; /* clear dpx mode */ CLR_INT (TTI); /* clear flag */ -sim_activate (&tti_unit, tti_unit.wait); /* activate unit */ +sim_activate_abs (&tti_unit, KBD_WAIT (tti_unit.wait, tmxr_poll)); return SCPE_OK; } @@ -999,7 +1079,7 @@ else { c = baud_to_asc[uptr->buf | (tty_shift << 5)]; /* translate */ #else -c = sim_tt_outcvt (uptr->buf, TT_GET_MODE (uptr->flags)); +c = sim_tt_outcvt (uptr->buf, TT_GET_MODE (uptr->flags) | TTUF_KSR); if (c >= 0) { #endif diff --git a/PDP18B/pdp18b_sys.c b/PDP18B/pdp18b_sys.c index b51ac04f..c68d4004 100644 --- a/PDP18B/pdp18b_sys.c +++ b/PDP18B/pdp18b_sys.c @@ -23,6 +23,9 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 30-Oct-06 RMS Added infinite loop stop + 18-Oct-06 RMS Re-ordered device list + 02-Oct-06 RMS Added RDCLK instruction 12-Jun-06 RMS Added Fiodec, Baudot display RMS Generalized LOAD to handle HRI, RIM, or BIN files 22-Jul-05 RMS Removed AAS, error in V1 reference manual @@ -128,6 +131,7 @@ int32 sim_emax = 2; DEVICE *sim_devices[] = { &cpu_dev, + &clk_dev, #if defined (PDP15) &fpp_dev, #endif @@ -135,7 +139,6 @@ DEVICE *sim_devices[] = { &ptp_dev, &tti_dev, &tto_dev, - &clk_dev, #if defined (TYPE62) &lp62_dev, #endif @@ -180,7 +183,8 @@ const char *sim_stop_messages[] = { "Non-standard device number", "Memory management error", "FP15 instruction disabled", - "DECtape off reel" + "DECtape off reel", + "Infinite loop" }; /* Binary loaders */ @@ -493,7 +497,8 @@ static const char *opcode[] = { "SPCO", "SKP15", "RES", "SBA", "DBA", "EBA", "RDMM", "ORMM", "LDMM", "MPLR", - "ENB", "INH", "MPRC", "IPFH", + "ENB", "INH", + "RDCLK","MPRC", "IPFH", "PAX", "PAL", "AAC", "PXA", "AXS", "PXL", "PLA", "PLX", "CLAC","CLX", "CLLR", "AXR", @@ -529,7 +534,7 @@ static const char *opcode[] = { "DAD", "URDAD", "UNDAD", "UUDAD", "BZA", "BMA", "BLE", "BPA", "BRU", "BNA", "BAC", - "ISB*", "ESB*", /* indirect */ + "ISB*", "ESB*", /* indirect */ "FSB*", "URFSB*", "UNFSB*", "UUFSB*", "DSB*", "URDSB*", "UNDSB*", "UUDSB*", "IRS*", "ERS*", @@ -725,7 +730,8 @@ static const int32 opc_val[] = { 0703341+I_NPI, 0707741+I_NPI, 0707742+I_NPI, 0707761+I_NPI, 0707762+I_NPI, 0707764+I_NPI, 0700032+I_NPN, 0700022+I_NPI, 0700024+I_NPI, 0701724+I_NPI, - 0705521+I_NPI, 0705522+I_NPI, 0701722+I_NPI, 0701764+I_NPI, + 0705521+I_NPI, 0705522+I_NPI, + 0701772+I_NPN, 0701762+I_NPI, 0701764+I_NPI, 0721000+I_XR, 0722000+I_XR, 0723000+I_XR9, 0724000+I_XR, 0725000+I_XR9, 0726000+I_XR, 0730000+I_XR, 0731000+I_XR, 0734000+I_XR, 0735000+I_XR, 0736000+I_XR, 0737000+I_XR9, diff --git a/PDP18B/pdp18b_tt1.c b/PDP18B/pdp18b_tt1.c index 0df221c5..9efbde62 100644 --- a/PDP18B/pdp18b_tt1.c +++ b/PDP18B/pdp18b_tt1.c @@ -1,6 +1,6 @@ /* pdp15_ttx.c: PDP-15 additional terminals simulator - Copyright (c) 1993-2005, Robert M Supnik + Copyright (c) 1993-2006, 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 @@ ttix,ttox LT15/LT19 terminal input/output + 30-Sep-06 RMS Fixed handling of non-printable characters in KSR mode 22-Nov-05 RMS Revised for new terminal processing routines 29-Jun-05 RMS Added SET TTOXn DISCONNECT 21-Jun-05 RMS Fixed bug in SHOW CONN/STATS @@ -219,7 +220,7 @@ for (ln = 0; ln < TTX_MAXL; ln++) { /* loop thru lines */ if (ttx_ldsc[ln].conn) { /* connected? */ if (temp = tmxr_getc_ln (&ttx_ldsc[ln])) { /* get char */ if (temp & SCPE_BREAK) c = 0; /* break? */ - else c = sim_tt_inpcvt (temp, TT_GET_MODE (ttox_unit[ln].flags)); + else c = sim_tt_inpcvt (temp, TT_GET_MODE (ttox_unit[ln].flags) | TTUF_KSR); ttix_buf[ln] = c; ttix_set_done (ln); } @@ -280,7 +281,7 @@ int32 c, ln = uptr - ttox_unit; /* line # */ if (ttx_ldsc[ln].conn) { /* connected? */ if (ttx_ldsc[ln].xmte) { /* tx enabled? */ TMLN *lp = &ttx_ldsc[ln]; /* get line */ - c = sim_tt_outcvt (ttox_buf[ln], TT_GET_MODE (ttox_unit[ln].flags)); + c = sim_tt_outcvt (ttox_buf[ln], TT_GET_MODE (ttox_unit[ln].flags) | TTUF_KSR); if (c >= 0) tmxr_putc_ln (lp, c); /* output char */ tmxr_poll_tx (&ttx_desc); /* poll xmt */ } diff --git a/PDP8/pdp8_clk.c b/PDP8/pdp8_clk.c index 7d9a1dd3..13d79e91 100644 --- a/PDP8/pdp8_clk.c +++ b/PDP8/pdp8_clk.c @@ -152,10 +152,14 @@ return SCPE_OK; t_stat clk_reset (DEVICE *dptr) { +int32 t; + dev_done = dev_done & ~INT_CLK; /* clear done, int */ int_req = int_req & ~INT_CLK; int_enable = int_enable & ~INT_CLK; /* clear enable */ -sim_activate (&clk_unit, clk_unit.wait); /* activate unit */ +t = sim_rtcn_init (clk_unit.wait, TMR_CLK); +sim_activate_abs (&clk_unit, t); /* activate unit */ +tmxr_poll = t; return SCPE_OK; } diff --git a/PDP8/pdp8_cpu.c b/PDP8/pdp8_cpu.c index ccc524bc..43cf5952 100644 --- a/PDP8/pdp8_cpu.c +++ b/PDP8/pdp8_cpu.c @@ -1,6 +1,6 @@ /* pdp8_cpu.c: PDP-8 CPU simulator - Copyright (c) 1993-2005, Robert M Supnik + Copyright (c) 1993-2006, 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 central processor + 30-Oct-06 RMS Added idle and infinite loop detection + 30-Sep-06 RMS Fixed SC value after DVI overflow (found by Don North) 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) 16-Aug-05 RMS Fixed C++ declaration and cast problems 06-Nov-04 RMS Added =n to SHOW HISTORY @@ -191,8 +193,9 @@ #define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = MA #define UNIT_V_NOEAE (UNIT_V_UF) /* EAE absent */ #define UNIT_NOEAE (1 << UNIT_V_NOEAE) -#define UNIT_V_MSIZE (UNIT_V_UF+1) /* dummy mask */ +#define UNIT_V_MSIZE (UNIT_V_UF + 1) /* dummy mask */ #define UNIT_MSIZE (1 << UNIT_V_MSIZE) +#define OP_KSF 06031 /* for idle */ #define HIST_PC 0x40000000 #define HIST_MIN 64 @@ -242,6 +245,7 @@ extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ extern DEVICE *sim_devices[]; extern FILE *sim_log; extern UNIT clk_unit, ttix_unit; +extern t_bool sim_idle_enab; 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); @@ -294,6 +298,8 @@ REG cpu_reg[] = { MTAB cpu_mod[] = { { UNIT_NOEAE, UNIT_NOEAE, "no EAE", "NOEAE", NULL }, { UNIT_NOEAE, 0, "EAE", "EAE", NULL }, + { MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, 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 }, @@ -628,6 +634,7 @@ switch ((IR >> 7) & 037) { /* decode IR<0:4> */ register and the TSC8-75 I/O flag is raised. Then the JMP is performed as usual (including the setting of IF, UF and clearing the interrupt inhibit flag). */ + case 024: /* JMP, dir, zero */ PCQ_ENTRY; MA = IR & 0177; /* dir addr, page zero */ @@ -645,6 +652,8 @@ switch ((IR >> 7) & 037) { /* decode IR<0:4> */ PC = MA; break; +/* If JMP direct, also check for idle (KSF/JMP *-1) and infinite loop */ + case 025: /* JMP, dir, curr */ PCQ_ENTRY; MA = (MA & 007600) | (IR & 0177); /* dir addr, curr page */ @@ -656,6 +665,20 @@ switch ((IR >> 7) & 037) { /* decode IR<0:4> */ int_req = int_req | INT_TSC; /* request intr */ } } + if (sim_idle_enab && /* idling enabled? */ + (IF == IB)) { /* to same bank? */ + if (MA == ((PC - 2) & 07777)) { /* 1) JMP *-1? */ + if (!(int_req & (INT_ION|INT_TTI)) && /* iof, TTI flag off? */ + (M[IB|((PC - 2) & 07777)] == OP_KSF)) /* next is KSF? */ + sim_idle (TMR_CLK, FALSE); /* we're idle */ + } /* end JMP *-1 */ + else if (MA == ((PC - 1) & 07777)) { /* 2) JMP *? */ + if (!(int_req & INT_ION)) /* iof? */ + reason = STOP_LOOP; /* then infinite loop */ + else if (!(int_req & INT_ALL)) /* ion, not intr? */ + sim_idle (TMR_CLK, FALSE); /* we're idle */ + } /* end JMP */ + } /* end idle enabled */ IF = IB; /* change IF */ UF = UB; /* change UF */ int_req = int_req | INT_NO_CIF_PENDING; /* clr intr inhibit */ @@ -998,7 +1021,7 @@ switch ((IR >> 7) & 037) { /* decode IR<0:4> */ if ((LAC & 07777) >= M[MA]) { /* overflow? */ LAC = LAC | 010000; /* set link */ MQ = ((MQ << 1) + 1) & 07777; /* rotate MQ */ - SC = 01; /* 1 shift */ + SC = 0; /* no shifts */ } else { temp = ((LAC & 07777) << 12) | MQ; diff --git a/PDP8/pdp8_ct.c b/PDP8/pdp8_ct.c new file mode 100644 index 00000000..f2e1a491 --- /dev/null +++ b/PDP8/pdp8_ct.c @@ -0,0 +1,685 @@ +/* pdp8_ct.c: PDP-8 cassette tape simulator + + Copyright (c) 2006, 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"), + 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 Robert M Supnik shall not 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. + + ct TA8E/TU60 cassette tape + + Magnetic tapes are represented as a series of variable records + of the form: + + 32b byte count + byte 0 + byte 1 + : + byte n-2 + byte n-1 + 32b byte count + + If the byte count is odd, the record is padded with an extra byte + of junk. File marks are represented by a byte count of 0. + + Cassette format differs in one very significant way: it has file gaps + rather than file marks. If the controller spaces or reads into a file + gap and then reverses direction, the file gap is not seen again. This + is in contrast to magnetic tapes, where the file mark is a character + sequence and is seen again if direction is reversed. + + Note that the read and write sequences for the cassette are asymmetric: + + Read: KLSA /SELECT READ + KGOA /INIT READ, CLEAR DF + + KGOA /READ 1ST CHAR, CLEAR DF + DCA CHAR + : + + KGOA /READ LAST CHAR, CLEAR DF + DCA CHAR + + KLSA /SELECT CRC MODE + KGOA /READ 1ST CRC + + KGOA /READ 2ND CRC + + + Write: KLSA /SELECT WRITE + TAD CHAR /1ST CHAR + KGOA /INIT WRITE, CHAR TO BUF, CLEAR DF + + : + TAD CHAR /LAST CHAR + KGOA /CHAR TO BUF, CLEAR DF + + KLSA /SELECT CRC MODE + KGOA /WRITE CRC, CLEAR DF + +*/ + +#include "pdp8_defs.h" +#include "sim_tape.h" + +#define CT_NUMDR 2 /* #drives */ +#define FNC u3 /* unit function */ +#define UST u4 /* unit status */ +#define CT_MAXFR (CT_SIZE) /* max record lnt */ +#define CT_SIZE 93000 /* chars/tape */ + +/* Status Register A */ + +#define SRA_ENAB 0200 /* enable */ +#define SRA_V_UNIT 6 /* unit */ +#define SRA_M_UNIT (CT_NUMDR - 1) +#define SRA_V_FNC 3 /* function */ +#define SRA_M_FNC 07 +#define SRA_READ 00 +#define SRA_REW 01 +#define SRA_WRITE 02 +#define SRA_SRF 03 +#define SRA_WFG 04 +#define SRA_SRB 05 +#define SRA_CRC 06 +#define SRA_SFF 07 +#define SRA_2ND 010 +#define SRA_IE 0001 /* int enable */ +#define GET_UNIT(x) (((x) >> SRA_V_UNIT) & SRA_M_UNIT) +#define GET_FNC(x) (((x) >> SRA_V_FNC) & SRA_M_FNC) + +/* Function code flags */ + +#define OP_WRI 01 /* op is a write */ +#define OP_REV 02 /* op is rev motion */ +#define OP_FWD 04 /* op is fwd motion */ + +/* Unit status flags */ + +#define UST_REV (OP_REV) /* last op was rev */ +#define UST_GAP 01 /* last op hit gap */ + +/* Status Register B, ^ = computed on the fly */ + +#define SRB_WLE 0400 /* "write lock err" */ +#define SRB_CRC 0200 /* CRC error */ +#define SRB_TIM 0100 /* timing error */ +#define SRB_BEOT 0040 /* ^BOT/EOT */ +#define SRB_EOF 0020 /* end of file */ +#define SRB_EMP 0010 /* ^drive empty */ +#define SRB_REW 0004 /* rewinding */ +#define SRB_WLK 0002 /* ^write locked */ +#define SRB_RDY 0001 /* ^ready */ +#define SRB_ALLERR (SRB_WLE|SRB_CRC|SRB_TIM|SRB_BEOT|SRB_EOF|SRB_EMP) +#define SRB_XFRERR (SRB_WLE|SRB_CRC|SRB_TIM|SRB_EOF) + +extern int32 int_req, stop_inst; +extern UNIT cpu_unit; + +uint32 ct_sra = 0; /* status reg A */ +uint32 ct_srb = 0; /* status reg B */ +uint32 ct_db = 0; /* data buffer */ +uint32 ct_df = 0; /* data flag */ +uint32 ct_write = 0; /* TU60 write flag */ +uint32 ct_bptr = 0; /* buf ptr */ +uint32 ct_blnt = 0; /* buf length */ +int32 ct_stime = 1000; /* start time */ +int32 ct_ctime = 100; /* char latency */ +uint32 ct_stopioe = 1; /* stop on error */ +uint8 *ct_xb = NULL; /* transfer buffer */ +static uint8 ct_fnc_tab[SRA_M_FNC + 1] = { + OP_FWD, 0 , OP_WRI|OP_FWD, OP_REV, + OP_WRI|OP_FWD, OP_REV, 0, OP_FWD + }; + +DEVICE ct_dev; +int32 ct70 (int32 IR, int32 AC); +t_stat ct_svc (UNIT *uptr); +t_stat ct_reset (DEVICE *dptr); +t_stat ct_attach (UNIT *uptr, char *cptr); +t_stat ct_detach (UNIT *uptr); +t_stat ct_boot (int32 unitno, DEVICE *dptr); +uint32 ct_updsta (UNIT *uptr); +int32 ct_go_start (int32 AC); +int32 ct_go_cont (UNIT *uptr, int32 AC); +t_stat ct_map_err (UNIT *uptr, t_stat st); +UNIT *ct_busy (void); +void ct_set_df (t_bool timchk); +t_bool ct_read_char (void); +uint32 ct_crc (uint8 *buf, uint32 cnt); + +/* CT data structures + + ct_dev CT device descriptor + ct_unit CT unit list + ct_reg CT register list + ct_mod CT modifier list +*/ + +DIB ct_dib = { DEV_CT, 1, { &ct70 } }; + +UNIT ct_unit[] = { + { UDATA (&ct_svc, UNIT_ATTABLE+UNIT_ROABLE, CT_SIZE) }, + { UDATA (&ct_svc, UNIT_ATTABLE+UNIT_ROABLE, CT_SIZE) }, + }; + +REG ct_reg[] = { + { ORDATA (CTSRA, ct_sra, 8) }, + { ORDATA (CTSRB, ct_srb, 8) }, + { ORDATA (CTDB, ct_db, 8) }, + { FLDATA (CTDF, ct_df, 0) }, + { FLDATA (RDY, ct_srb, 0) }, + { FLDATA (WLE, ct_srb, 8) }, + { FLDATA (WRITE, ct_write, 0) }, + { FLDATA (INT, int_req, INT_V_CT) }, + { DRDATA (BPTR, ct_bptr, 17) }, + { DRDATA (BLNT, ct_blnt, 17) }, + { DRDATA (STIME, ct_stime, 24), PV_LEFT + REG_NZ }, + { DRDATA (CTIME, ct_ctime, 24), PV_LEFT + REG_NZ }, + { FLDATA (STOP_IOE, ct_stopioe, 0) }, + { URDATA (UFNC, ct_unit[0].FNC, 8, 4, 0, CT_NUMDR, 0), REG_HRO }, + { URDATA (UST, ct_unit[0].UST, 8, 2, 0, CT_NUMDR, 0), REG_HRO }, + { URDATA (POS, ct_unit[0].pos, 10, T_ADDR_W, 0, + CT_NUMDR, PV_LEFT | REG_RO) }, + { FLDATA (DEVNUM, ct_dib.dev, 6), REG_HRO }, + { NULL } + }; + +MTAB ct_mod[] = { + { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL }, + { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, +// { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT", +// &sim_tape_set_fmt, &sim_tape_show_fmt, NULL }, + { MTAB_XTD|MTAB_VUN, 0, "CAPACITY", NULL, + NULL, &sim_tape_show_capac, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", + &set_dev, &show_dev, NULL }, + { 0 } + }; + +DEVICE ct_dev = { + "CT", ct_unit, ct_reg, ct_mod, + CT_NUMDR, 10, 31, 1, 8, 8, + NULL, NULL, &ct_reset, + &ct_boot, &ct_attach, &ct_detach, + &ct_dib, DEV_DISABLE | DEV_DIS + }; + +/* IOT routines */ + +int32 ct70 (int32 IR, int32 AC) +{ +int32 srb; +UNIT *uptr; + +srb = ct_updsta (NULL); /* update status */ +switch (IR & 07) { /* decode IR<9:11> */ + + case 0: /* KCLR */ + ct_reset (&ct_dev); /* reset the world */ + break; + + case 1: /* KSDR */ + if (ct_df) AC |= IOT_SKP; + break; + + case 2: /* KSEN */ + if (srb & SRB_ALLERR) AC |= IOT_SKP; + break; + + case 3: /* KSBF */ + if ((srb & SRB_RDY) && !(srb & SRB_EMP)) + AC |= IOT_SKP; + break; + + case 4: /* KLSA */ + ct_sra = AC & 0377; + ct_updsta (NULL); + return ct_sra ^ 0377; + + case 5: /* KSAF */ + if (ct_df || (srb & (SRB_ALLERR|SRB_RDY))) + AC |= IOT_SKP; + break; + + case 6: /* KGOA */ + ct_df = 0; /* clear data flag */ + if (uptr = ct_busy ()) /* op in progress? */ + AC = ct_go_cont (uptr, AC); /* yes */ + else AC = ct_go_start (AC); /* no, start */ + ct_updsta (NULL); + break; + + case 7: /* KSRB */ + return srb & 0377; + } /* end switch */ + +return AC; +} + +/* Start a new operation - cassette is not busy */ + +int32 ct_go_start (int32 AC) +{ +UNIT *uptr = ct_dev.units + GET_UNIT (ct_sra); +uint32 fnc = GET_FNC (ct_sra); +uint32 flg = ct_fnc_tab[fnc]; +uint32 old_ust = uptr->UST; + +if ((ct_sra & SRA_ENAB) && (uptr->flags & UNIT_ATT)) { /* enabled, att? */ + ct_srb &= ~(SRB_XFRERR|SRB_REW); /* clear err, rew */ + if (flg & OP_WRI) { /* write-type op? */ + if (sim_tape_wrp (uptr)) { /* locked? */ + ct_srb |= SRB_WLE; /* set flag, abort */ + return AC; + } + ct_write = 1; /* set TU60 wr flag */ + ct_db = AC & 0377; + } + else { + ct_write = 0; + ct_db = 0; + } + if (fnc == SRA_REW) ct_srb |= SRB_REW; /* rew? set flag */ + if ((fnc != SRA_REW) && !(flg & OP_WRI)) { /* read cmd? */ + uptr->UST = flg & UST_REV; /* save direction */ + if ((old_ust ^ uptr->UST) == (UST_REV|UST_GAP)) { /* rev in gap? */ + t_mtrlnt t; /* skip tape mark */ + if (uptr->UST) sim_tape_rdrecr (uptr, ct_xb, &t, CT_MAXFR); + else sim_tape_rdrecf (uptr, ct_xb, &t, CT_MAXFR); + } + } + else uptr->UST = 0; + ct_bptr = 0; /* init buffer */ + ct_blnt = 0; + uptr->FNC = fnc; /* save function */ + sim_activate (uptr, ct_stime); /* schedule op */ + } +if ((fnc == SRA_READ) || (fnc == SRA_CRC)) /* read or CRC? */ + return 0; /* get "char" */ +return AC; +} + +/* Continue an in-progress operation - cassette is in motion */ + +int32 ct_go_cont (UNIT *uptr, int32 AC) +{ +int32 fnc = GET_FNC (ct_sra); + +switch (fnc) { /* case on function */ + + case SRA_READ: /* read */ + return ct_db; /* return data */ + + case SRA_WRITE: /* write */ + ct_db = AC & 0377; /* save data */ + break; + + case SRA_CRC: /* CRC */ + if ((uptr->FNC & SRA_M_FNC) != SRA_CRC) /* if not CRC */ + uptr->FNC = SRA_CRC; /* start CRC seq */ + if (!ct_write) return ct_db; /* read? AC <- buf */ + break; + + default: + break; + } + +return AC; +} + +/* Unit service */ + +t_stat ct_svc (UNIT *uptr) +{ +uint32 i, crc; +uint32 flgs = ct_fnc_tab[uptr->FNC & SRA_M_FNC]; +t_mtrlnt tbc; +t_stat st, r; + +if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ + ct_updsta (uptr); /* update status */ + return (ct_stopioe? SCPE_UNATT: SCPE_OK); + } +if (((flgs & OP_REV) && sim_tape_bot (uptr)) || /* rev at BOT or */ + ((flgs & OP_FWD) && sim_tape_eot (uptr))) { /* fwd at EOT? */ + ct_updsta (uptr); /* op done */ + return SCPE_OK; +} + +r = SCPE_OK; +switch (uptr->FNC) { /* case on function */ + + case SRA_READ: /* read start */ + st = sim_tape_rdrecf (uptr, ct_xb, &ct_blnt, CT_MAXFR); /* get rec */ + if (st == MTSE_RECE) ct_srb |= SRB_CRC; /* rec in err? */ + else if (st != MTSE_OK) { /* other error? */ + r = ct_map_err (uptr, st); /* map error */ + break; + } + crc = ct_crc (ct_xb, ct_blnt); /* calculate CRC */ + ct_xb[ct_blnt++] = (crc >> 8) & 0377; /* append to buffer */ + ct_xb[ct_blnt++] = crc & 0377; + uptr->FNC |= SRA_2ND; /* next state */ + sim_activate (uptr, ct_ctime); /* sched next char */ + return SCPE_OK; + + case SRA_READ|SRA_2ND: /* read char */ + if (!ct_read_char ()) break; /* read, overrun? */ + ct_set_df (TRUE); /* set data flag */ + sim_activate (uptr, ct_ctime); /* sched next char */ + return SCPE_OK; + + case SRA_WRITE: /* write start */ + for (i = 0; i < CT_MAXFR; i++) ct_xb[i] = 0; /* clear buffer */ + uptr->FNC |= SRA_2ND; /* next state */ + sim_activate (uptr, ct_ctime); /* sched next char */ + return SCPE_OK; + + case SRA_WRITE|SRA_2ND: /* write char */ + if ((ct_bptr < CT_MAXFR) && /* room in buf? */ + ((uptr->pos + ct_bptr) < uptr->capac)) /* room on tape? */ + ct_xb[ct_bptr++] = ct_db; /* store char */ + ct_set_df (TRUE); /* set data flag */ + sim_activate (uptr, ct_ctime); /* sched next char */ + return SCPE_OK; + + case SRA_CRC: /* CRC */ + if (ct_write) { /* write? */ + if (st = sim_tape_wrrecf (uptr, ct_xb, ct_bptr)) /* write, err? */ + r = ct_map_err (uptr, st); /* map error */ + break; /* write done */ + } + ct_read_char (); /* get second CRC */ + ct_set_df (FALSE); /* set df */ + uptr->FNC |= SRA_2ND; /* next state */ + sim_activate (uptr, ct_ctime); + return SCPE_OK; + + case SRA_CRC|SRA_2ND: /* second read CRC */ + if (ct_bptr != ct_blnt) { /* partial read? */ + crc = ct_crc (ct_xb, ct_bptr); /* actual CRC */ + if (crc != 0) ct_srb |= SRB_CRC; /* must be zero */ + } + break; /* read done */ + + case SRA_WFG: /* write file gap */ + if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + r = ct_map_err (uptr, st); /* map error */ + break; + + case SRA_REW: /* rewind */ + sim_tape_rewind (uptr); + break; + + case SRA_SRB: /* space rev blk */ + if (st = sim_tape_sprecr (uptr, &tbc)) /* space rev, err? */ + r = ct_map_err (uptr, st); /* map error */ + break; + + case SRA_SRF: /* space rev file */ + while ((st = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ; + r = ct_map_err (uptr, st); /* map error */ + break; + + case SRA_SFF: /* space fwd file */ + while ((st = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) ; + r = ct_map_err (uptr, st); /* map error */ + break; + + default: /* never get here! */ + return SCPE_IERR; + } /* end case */ + +ct_updsta (uptr); /* update status */ +return r; +} + +/* Update controller status */ + +uint32 ct_updsta (UNIT *uptr) +{ +int32 srb; + +if (uptr == NULL) { /* unit specified? */ + uptr = ct_busy (); /* use busy unit */ + if ((uptr == NULL) && (ct_sra & SRA_ENAB)) /* none busy? */ + uptr = uptr = ct_dev.units + GET_UNIT (ct_sra); /* use sel unit */ + } +else if (ct_srb & SRB_EOF) uptr->UST |= UST_GAP; /* save gap */ +if (uptr) { /* any unit? */ + ct_srb &= ~(SRB_WLK|SRB_BEOT|SRB_EMP|SRB_RDY); /* clear dyn flags */ + if ((uptr->flags & UNIT_ATT) == 0) /* unattached? */ + ct_srb = (ct_srb | SRB_EMP|SRB_WLK) & ~SRB_REW; /* empty, locked */ + if (!sim_is_active (uptr)) { /* not busy? */ + ct_srb = (ct_srb | SRB_RDY) & ~SRB_REW; /* ready, ~rew */ + if (sim_tape_bot (uptr) || sim_tape_eot (uptr)) /* update BEOT */ + ct_srb |= SRB_BEOT; + } + if (sim_tape_wrp (uptr) || (ct_srb & SRB_REW)) /* locked or rew? */ + ct_srb |= SRB_WLK; /* set locked */ + } +if (ct_sra & SRA_ENAB) srb = ct_srb; /* can TA see TU60? */ +else srb = 0; /* no */ +if ((ct_sra & SRA_IE) && /* int enabled? */ + (ct_df || (srb & (SRB_ALLERR|SRB_RDY)))) /* any flag? */ + int_req |= INT_CT; /* set int req */ +else int_req &= ~INT_CT; /* no, clr int req */ +return srb; +} + +/* Set data flag */ + +void ct_set_df (t_bool timchk) +{ +if (ct_df && timchk) ct_srb |= SRB_TIM; /* flag still set? */ +ct_df = 1; /* set data flag */ +if (ct_sra & SRA_IE) int_req |= INT_CT; /* if ie, int req */ +return; +} + +/* Read character */ + +t_bool ct_read_char (void) +{ +if (ct_bptr < ct_blnt) { /* more chars? */ + ct_db = ct_xb[ct_bptr++]; + return TRUE; + } +ct_db = 0; +ct_srb |= SRB_CRC; /* overrun */ +return FALSE; +} + +/* Test if controller busy */ + +UNIT *ct_busy (void) +{ +uint32 u; +UNIT *uptr; + +for (u = 0; u < CT_NUMDR; u++) { /* loop thru units */ + uptr = ct_dev.units + u; + if (sim_is_active (uptr)) return uptr; + } +return NULL; +} + +/* Calculate CRC on buffer */ + +uint32 ct_crc (uint8 *buf, uint32 cnt) +{ +uint32 crc, i, j; + +crc = 0; +for (i = 0; i < cnt; i++) { + crc = crc ^ (((uint32) buf[i]) << 8); + for (j = 0; j < 8; j++) { + if (crc & 1) crc = (crc >> 1) ^ 0xA001; + else crc = crc >> 1; + } + } +return crc; +} + +/* Map error status */ + +t_stat ct_map_err (UNIT *uptr, t_stat st) +{ +switch (st) { + + case MTSE_FMT: /* illegal fmt */ + case MTSE_UNATT: /* unattached */ + ct_srb |= SRB_CRC; + case MTSE_OK: /* no error */ + return SCPE_IERR; /* never get here! */ + + case MTSE_TMK: /* end of file */ + ct_srb |= SRB_EOF; + break; + + case MTSE_IOERR: /* IO error */ + ct_srb |= SRB_CRC; /* set crc err */ + if (ct_stopioe) return SCPE_IOERR; + break; + + case MTSE_INVRL: /* invalid rec lnt */ + ct_srb |= SRB_CRC; /* set crc err */ + return SCPE_MTRLNT; + + case MTSE_RECE: /* record in error */ + case MTSE_EOM: /* end of medium */ + ct_srb |= SRB_CRC; /* set crc err */ + break; + + case MTSE_BOT: /* reverse into BOT */ + break; + + case MTSE_WRP: /* write protect */ + ct_srb |= SRB_WLE; /* set wlk err */ + break; + } + +return SCPE_OK; +} + +/* Reset routine */ + +t_stat ct_reset (DEVICE *dptr) +{ +uint32 u; +UNIT *uptr; + +ct_sra = 0; +ct_srb = 0; +ct_df = 0; +ct_db = 0; +ct_write = 0; +ct_bptr = 0; +ct_blnt = 0; +int_req = int_req & ~INT_CT; /* clear interrupt */ +for (u = 0; u < CT_NUMDR; u++) { /* loop thru units */ + uptr = ct_dev.units + u; + sim_cancel (uptr); /* cancel activity */ + sim_tape_reset (uptr); /* reset tape */ + } +if (ct_xb == NULL) ct_xb = (uint8 *) calloc (CT_MAXFR + 2, sizeof (uint8)); +if (ct_xb == NULL) return SCPE_MEM; +return SCPE_OK; +} + +/* Attach routine */ + +t_stat ct_attach (UNIT *uptr, char *cptr) +{ +t_stat r; + +r = sim_tape_attach (uptr, cptr); +if (r != SCPE_OK) return r; +ct_updsta (NULL); +uptr->UST = 0; +return r; +} + +/* Detach routine */ + +t_stat ct_detach (UNIT* uptr) +{ +t_stat r; + +if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* check attached */ +r = sim_tape_detach (uptr); +ct_updsta (NULL); +uptr->UST = 0; +return r; +} + +/* Bootstrap routine */ + +#define BOOT_START 04000 +#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) + +static const uint16 boot_rom[] = { + 01237, /* BOOT, TAD M50 /change CRC to REW */ + 01206, /* CRCCHK, TAD L260 /crc op */ + 06704, /* KLSA /load op */ + 06706, /* KGOA /start */ + 06703, /* KSBF /ready? */ + 05204, /* RDCOD, JMP .-1 /loop */ + 07264, /* L260, CML STA RAL /L = 1, AC = halt */ + 06702, /* KSEN /error? */ + 07610, /* SKP CLA /halt on any error */ + 03211, /* DCA . /except REW or FFG */ + 03636, /* DCA I PTR /TAD I PTR mustn't change L */ + 01205, /* TAD RDCOD /read op */ + 06704, /* KLSA /load op */ + 06706, /* KGOA /start */ + 06701, /* LOOP, KSDF /data ready? */ + 05216, /* JMP .-1 /loop */ + 07002, /* BSW /to upper 6b */ + 07430, /* SZL /second byte? */ + 01636, /* TAD I PTR /yes */ + 07022, /* CML BSW /swap back */ + 03636, /* DCA I PTR /store in mem */ + 07420, /* SNL /done with both bytes? */ + 02236, /* ISZ PTR /yes, bump mem ptr */ + 02235, /* ISZ KNT /done with record? */ + 05215, /* JMP LOOP /next byte */ + 07346, /* STA CLL RTL */ + 07002, /* BSW /AC = 7757 */ + 03235, /* STA KNT /now read 200 byte record */ + 05201, /* JMP CRCCHK /go check CRC */ + 07737, /* KNT, 7737 /1's compl of byte count */ + 03557, /* PTR, 3557 /load point */ + 07730, /* M50, 7730 /CLA SPA SZL */ + }; + +t_stat ct_boot (int32 unitno, DEVICE *dptr) +{ +int32 i; +extern int32 saved_PC; +extern uint16 M[]; + +if ((ct_dib.dev != DEV_CT) || unitno) /* only std devno */ + return STOP_NOTSTD; +for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i]; +saved_PC = BOOT_START; +return SCPE_OK; +} diff --git a/PDP8/pdp8_defs.h b/PDP8/pdp8_defs.h index 0a0ac630..93f88ee0 100644 --- a/PDP8/pdp8_defs.h +++ b/PDP8/pdp8_defs.h @@ -1,6 +1,6 @@ /* pdp8_defs.h: PDP-8 simulator definitions - Copyright (c) 1993-2005, Robert M Supnik + Copyright (c) 1993-2006, 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,8 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 13-Dec-06 RMS Added TA8E support + 30-Oct-06 RMS Added infinite loop stop 13-Oct-03 RMS Added TSC8-75 support 04-Oct-02 RMS Added variable device number support 20-Jan-02 RMS Fixed bug in TTx interrupt enable initialization @@ -50,6 +52,7 @@ #define STOP_IBKPT 3 /* breakpoint */ #define STOP_NOTSTD 4 /* non-std devno */ #define STOP_DTOFF 5 /* DECtape off reel */ +#define STOP_LOOP 6 /* infinite loop */ /* Memory */ @@ -96,6 +99,7 @@ typedef struct { #define DEV_RL 060 /* RL8A */ #define DEV_LPT 066 /* line printer */ #define DEV_MT 070 /* TM8E */ +#define DEV_CT 070 /* TA8E */ #define DEV_RK 074 /* RK8E */ #define DEV_RX 075 /* RX8E/RX28 */ #define DEV_DTA 076 /* TC08 */ @@ -146,10 +150,11 @@ typedef struct { #define INT_V_MT (INT_V_DIRECT+4) /* TM8E */ #define INT_V_DTA (INT_V_DIRECT+5) /* TC08 */ #define INT_V_RL (INT_V_DIRECT+6) /* RL8A */ -#define INT_V_PWR (INT_V_DIRECT+7) /* power int */ -#define INT_V_UF (INT_V_DIRECT+8) /* user int */ -#define INT_V_TSC (INT_V_DIRECT+9) /* TSC8-75 int */ -#define INT_V_OVHD (INT_V_DIRECT+10) /* overhead start */ +#define INT_V_CT (INT_V_DIRECT+7) /* TA8E int */ +#define INT_V_PWR (INT_V_DIRECT+8) /* power int */ +#define INT_V_UF (INT_V_DIRECT+9) /* user int */ +#define INT_V_TSC (INT_V_DIRECT+10) /* TSC8-75 int */ +#define INT_V_OVHD (INT_V_DIRECT+11) /* overhead start */ #define INT_V_NO_ION_PENDING (INT_V_OVHD+0) /* ion pending */ #define INT_V_NO_CIF_PENDING (INT_V_OVHD+1) /* cif pending */ #define INT_V_ION (INT_V_OVHD+2) /* interrupts on */ @@ -175,6 +180,7 @@ typedef struct { #define INT_MT (1 << INT_V_MT) #define INT_DTA (1 << INT_V_DTA) #define INT_RL (1 << INT_V_RL) +#define INT_CT (1 << INT_V_CT) #define INT_PWR (1 << INT_V_PWR) #define INT_UF (1 << INT_V_UF) #define INT_TSC (1 << INT_V_TSC) @@ -184,8 +190,8 @@ typedef struct { #define INT_DEV_ENABLE ((1 << INT_V_DIRECT) - 1) /* devices w/enables */ #define INT_ALL ((1 << INT_V_OVHD) - 1) /* all interrupts */ #define INT_INIT_ENABLE (INT_TTI+INT_TTO+INT_PTR+INT_PTP+INT_LPT) | \ - (INT_TTI1+INT_TTI2+INT_TTI3+INT_TTI4) | \ - (INT_TTO1+INT_TTO2+INT_TTO3+INT_TTO4) + (INT_TTI1+INT_TTI2+INT_TTI3+INT_TTI4) | \ + (INT_TTO1+INT_TTO2+INT_TTO3+INT_TTO4) #define INT_PENDING (INT_ION+INT_NO_CIF_PENDING+INT_NO_ION_PENDING) #define INT_UPDATE ((int_req & ~INT_DEV_ENABLE) | (dev_done & int_enable)) diff --git a/PDP8/pdp8_dt.c b/PDP8/pdp8_dt.c index b9abc1de..398d35b2 100644 --- a/PDP8/pdp8_dt.c +++ b/PDP8/pdp8_dt.c @@ -827,7 +827,7 @@ switch (fnc) { /* at speed, check fnc * Wc ovf, start of block - schedule end zone */ - case FNC_WRIT: /* write */ + case FNC_WRIT: /* write */ wrd = DT_LIN2WD (uptr->pos, uptr); /* get word # */ switch (dt_substate) { /* case on substate */ diff --git a/PDP8/pdp8_rk.c b/PDP8/pdp8_rk.c index d22894a6..4d5beb80 100644 --- a/PDP8/pdp8_rk.c +++ b/PDP8/pdp8_rk.c @@ -42,7 +42,8 @@ #define RK_NUMSF 2 /* surfaces/cylinder */ #define RK_NUMCY 203 /* cylinders/drive */ #define RK_NUMWD 256 /* words/sector */ -#define RK_SIZE (RK_NUMCY * RK_NUMSF * RK_NUMSC * RK_NUMWD) /* words/drive */ +#define RK_SIZE (RK_NUMCY * RK_NUMSF * RK_NUMSC * RK_NUMWD) + /* words/drive */ #define RK_NUMDR 4 /* drives/controller */ #define RK_M_NUMDR 03 @@ -72,7 +73,7 @@ #define RKS_DLT 00004 /* data late error */ #define RKS_STAT 00002 /* drive status error */ #define RKS_CYL 00001 /* cyl address error */ -#define RKS_ERR (RKS_BUSY+RKS_TMO+RKS_WLK+RKS_CRC+RKS_DLT+RKS_STAT+RKS_CYL) +#define RKS_ERR (RKS_BUSY+RKS_TMO+RKS_WLK+RKS_CRC+RKS_DLT+RKS_STAT+RKS_CYL) /* Command register */ @@ -116,12 +117,12 @@ #define RKX_CLD 2 /* clear drive */ #define RKX_CLSA 3 /* clear status alt */ -#define RK_INT_UPDATE \ - if (((rk_sta & (RKS_DONE + RKS_ERR)) != 0) && \ - ((rk_cmd & RKC_IE) != 0)) int_req = int_req | INT_RK; \ - else int_req = int_req & ~INT_RK -#define RK_MIN 10 -#define MAX(x,y) (((x) > (y))? (x): (y)) +#define RK_INT_UPDATE if (((rk_sta & (RKS_DONE + RKS_ERR)) != 0) && \ + ((rk_cmd & RKC_IE) != 0)) \ + int_req = int_req | INT_RK; \ + else int_req = int_req & ~INT_RK +#define RK_MIN 10 +#define MAX(x,y) (((x) > (y))? (x): (y)) extern uint16 M[]; extern int32 int_req, stop_inst; diff --git a/PDP8/pdp8_sys.c b/PDP8/pdp8_sys.c index c2a9e1eb..5405702d 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-2005, Robert M Supnik + Copyright (c) 1993-2006, 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,9 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 15-Dec-06 RMS Added TA8E support, IOT disambiguation + 30-Oct-06 RMS Added infinite loop stop + 18-Oct-06 RMS Re-ordered device list 17-Oct-03 RMS Added TSC8-75, TD8E support, DECtape off reel message 25-Apr-03 RMS Revised for extended file support 30-Dec-01 RMS Revised for new TTX @@ -52,7 +55,7 @@ extern DEVICE rk_dev, rl_dev; extern DEVICE rx_dev; extern DEVICE df_dev, rf_dev; extern DEVICE dt_dev, td_dev; -extern DEVICE mt_dev; +extern DEVICE mt_dev, ct_dev; extern DEVICE ttix_dev, ttox_dev; extern REG cpu_reg[]; extern uint16 M[]; @@ -78,13 +81,13 @@ int32 sim_emax = 4; DEVICE *sim_devices[] = { &cpu_dev, &tsc_dev, + &clk_dev, &ptr_dev, &ptp_dev, &tti_dev, &tto_dev, &ttix_dev, &ttox_dev, - &clk_dev, &lpt_dev, &rk_dev, &rl_dev, @@ -94,6 +97,7 @@ DEVICE *sim_devices[] = { &dt_dev, &td_dev, &mt_dev, + &ct_dev, NULL }; @@ -103,9 +107,23 @@ const char *sim_stop_messages[] = { "HALT instruction", "Breakpoint", "Non-standard device number", - "DECtape off reel" + "DECtape off reel", + "Infinite loop" }; +/* Ambiguous device list - these devices have overlapped IOT codes */ + +DEVICE *amb_dev[] = { + &rl_dev, + &ct_dev, + &td_dev, + NULL + }; + +#define AMB_RL (1 << 12) +#define AMB_CT (2 << 12) +#define AMB_TD (3 << 12) + /* Binary loader Two loader formats are supported: RIM loader (-r) and BIN (-b) loader. @@ -213,6 +231,7 @@ return SCPE_FMT; /* eof? error */ #define I_V_OP1 4 /* operate 1 */ #define I_V_OP2 5 /* operate 2 */ #define I_V_OP3 6 /* operate 3 */ +#define I_V_IOA 7 /* ambiguous IOT */ #define I_NPN (I_V_NPN << I_V_FL) #define I_FLD (I_V_FLD << I_V_FL) #define I_MRF (I_V_MRF << I_V_FL) @@ -220,48 +239,55 @@ return SCPE_FMT; /* eof? error */ #define I_OP1 (I_V_OP1 << I_V_FL) #define I_OP2 (I_V_OP2 << I_V_FL) #define I_OP3 (I_V_OP3 << I_V_FL) +#define I_IOA (I_V_IOA << I_V_FL) static const int32 masks[] = { 07777, 07707, 07000, 07000, - 07416, 07571, 017457 + 07416, 07571, 017457, 077777, }; +/* Ambiguous device mnemonics must precede default mnemonics */ + static const char *opcode[] = { - "SKON", "ION", "IOF", "SRQ", + "SKON", "ION", "IOF", "SRQ", /* std IOTs */ "GTF", "RTF", "SGT", "CAF", - "RPE", "RSF", "RRB", "RFC", "RFC RRB", + "RPE", "RSF", "RRB", "RFC", "RFC RRB", /* reader/punch */ "PCE", "PSF", "PCF", "PPC", "PLS", - "KCF", "KSF", "KCC", "KRS", "KIE", "KRB", + "KCF", "KSF", "KCC", "KRS", "KIE", "KRB", /* console */ "TLF", "TSF", "TCF", "TPC", "SPI", "TLS", - "SBE", "SPL", "CAL", - "CLEI", "CLDI", "CLSC", "CLLE", "CLCL", "CLSK", - "CINT", "RDF", "RIF", "RIB", + "SBE", "SPL", "CAL", /* power fail */ + "CLEI", "CLDI", "CLSC", "CLLE", "CLCL", "CLSK", /* clock */ + "CINT", "RDF", "RIF", "RIB", /* mem mmgt */ "RMF", "SINT", "CUF", "SUF", - "ADCL", "ADLM", "ADST", "ADRB", + "RLDC", "RLSD", "RLMA", "RLCA", /* RL - ambiguous */ + "RLCB", "RLSA", "RLWC", + "RRER", "RRWC", "RRCA", "RRCB", + "RRSA", "RRSI", "RLSE", + "KCLR", "KSDR", "KSEN", "KSBF", /* CT - ambiguous */ + "KLSA", "KSAF", "KGOA", "KRSB", + "SDSS", "SDST", "SDSQ", /* TD - ambiguous */ + "SDLC", "SDLD", "SDRC", "SDRD", + "ADCL", "ADLM", "ADST", "ADRB", /* A/D */ "ADSK", "ADSE", "ADLE", "ADRS", - "DCMA", "DMAR", "DMAW", + "DCMA", "DMAR", "DMAW", /* DF/RF */ "DCIM", "DSAC", "DIML", "DIMA", "DCEA", "DEAL", "DEAC", "DFSE", "DFSC", "DISK", "DMAC", "DCXA", "DXAL", "DXAC", - "PSKF", "PCLF", "PSKE", + "PSKF", "PCLF", "PSKE", /* LPT */ "PSTB", "PSIE", "PCLF PSTB", "PCIE", - "LWCR", "CWCR", "LCAR", + "LWCR", "CWCR", "LCAR", /* MT */ "CCAR", "LCMR", "LFGR", "LDBR", "RWCR", "CLT", "RCAR", "RMSR", "RCMR", "RFSR", "RDBR", "SKEF", "SKCB", "SKJD", "SKTR", "CLF", - "DSKP", "DCLR", "DLAG", + "DSKP", "DCLR", "DLAG", /* RK */ "DLCA", "DRST", "DLDC", "DMAN", - "LCD", "XDR", "STR", + "LCD", "XDR", "STR", /* RX */ "SER", "SDN", "INTR", "INIT", - "DTRA", "DTCA", "DTXA", "DTLA", + "DTRA", "DTCA", "DTXA", "DTLA", /* DT */ "DTSF", "DTRB", "DTLB", - "RLDC", "RLSD", "RLMA", "RLCA", - "RLCB", "RLSA", "RLWC", - "RRER", "RRWC", "RRCA", "RRCB", - "RRSA", "RRSI", "RLSE", - "ETDS", "ESKP", "ECTF", "ECDF", + "ETDS", "ESKP", "ECTF", "ECDF", /* TSC75 */ "ERTB", "ESME", "ERIOT", "ETEN", "CDF", "CIF", "CIF CDF", @@ -297,31 +323,35 @@ static const int32 opc_val[] = { 06131+I_NPN, 06132+I_NPN, 06133+I_NPN, 06135+I_NPN, 06136+I_NPN, 06137+I_NPN, 06204+I_NPN, 06214+I_NPN, 06224+I_NPN, 06234+I_NPN, 06244+I_NPN, 06254+I_NPN, 06264+I_NPN, 06274+I_NPN, - 06530+I_NPN, 06531+I_NPN, 06532+I_NPN, 06533+I_NPN, + 06600+I_IOA+AMB_RL, 06601+I_IOA+AMB_RL, 06602+I_IOA+AMB_RL, 06603+I_IOA+AMB_RL, + 06604+I_IOA+AMB_RL, 06605+I_IOA+AMB_RL, 06607+I_IOA+AMB_RL, + 06610+I_IOA+AMB_RL, 06611+I_IOA+AMB_RL, 06612+I_IOA+AMB_RL, 06613+I_IOA+AMB_RL, + 06614+I_IOA+AMB_RL, 06615+I_IOA+AMB_RL, 06617+I_IOA+AMB_RL, + 06700+I_IOA+AMB_CT, 06701+I_IOA+AMB_CT, 06702+I_IOA+AMB_CT, 06703+I_IOA+AMB_CT, + 06704+I_IOA+AMB_CT, 06705+I_IOA+AMB_CT, 06706+I_IOA+AMB_CT, 06707+I_IOA+AMB_CT, + 06771+I_IOA+AMB_TD, 06772+I_IOA+AMB_TD, 06773+I_IOA+AMB_TD, + 06774+I_IOA+AMB_TD, 06775+I_IOA+AMB_TD, 06776+I_IOA+AMB_TD, 06777+I_IOA+AMB_TD, + 06530+I_NPN, 06531+I_NPN, 06532+I_NPN, 06533+I_NPN, /* AD */ 06534+I_NPN, 06535+I_NPN, 06536+I_NPN, 06537+I_NPN, - 06601+I_NPN, 06603+I_NPN, 06605+I_NPN, + 06601+I_NPN, 06603+I_NPN, 06605+I_NPN, /* DF/RF */ 06611+I_NPN, 06612+I_NPN, 06615+I_NPN, 06616+I_NPN, 06611+I_NPN, 06615+I_NPN, 06616+I_NPN, 06621+I_NPN, 06622+I_NPN, 06623+I_NPN, 06626+I_NPN, 06641+I_NPN, 06643+I_NPN, 06645+I_NPN, - 06661+I_NPN, 06662+I_NPN, 06663+I_NPN, + 06661+I_NPN, 06662+I_NPN, 06663+I_NPN, /* LPT */ 06664+I_NPN, 06665+I_NPN, 06666+I_NPN, 06667+I_NPN, - 06701+I_NPN, 06702+I_NPN, 06703+I_NPN, + 06701+I_NPN, 06702+I_NPN, 06703+I_NPN, /* MT */ 06704+I_NPN, 06705+I_NPN, 06706+I_NPN, 06707+I_NPN, 06711+I_NPN, 06712+I_NPN, 06713+I_NPN, 06714+I_NPN, 06715+I_NPN, 06716+I_NPN, 06717+I_NPN, 06721+I_NPN, 06722+I_NPN, 06723+I_NPN, 06724+I_NPN, 06725+I_NPN, - 06741+I_NPN, 06742+I_NPN, 06743+I_NPN, + 06741+I_NPN, 06742+I_NPN, 06743+I_NPN, /* RK */ 06744+I_NPN, 06745+I_NPN, 06746+I_NPN, 06747+I_NPN, - 06751+I_NPN, 06752+I_NPN, 06753+I_NPN, + 06751+I_NPN, 06752+I_NPN, 06753+I_NPN, /* RX */ 06754+I_NPN, 06755+I_NPN, 06756+I_NPN, 06757+I_NPN, - 06761+I_NPN, 06762+I_NPN, 06764+I_NPN, 06766+I_NPN, + 06761+I_NPN, 06762+I_NPN, 06764+I_NPN, 06766+I_NPN, /* DT */ 06771+I_NPN, 06772+I_NPN, 06774+I_NPN, - 06600+I_NPN, 06601+I_NPN, 06602+I_NPN, 06603+I_NPN, - 06604+I_NPN, 06605+I_NPN, 06607+I_NPN, - 06610+I_NPN, 06611+I_NPN, 06612+I_NPN, 06613+I_NPN, - 06614+I_NPN, 06615+I_NPN, 06617+I_NPN, - 06360+I_NPN, 06361+I_NPN, 06362+I_NPN, 06363+I_NPN, + 06360+I_NPN, 06361+I_NPN, 06362+I_NPN, 06363+I_NPN, /* TSC */ 06364+I_NPN, 06365+I_NPN, 06366+I_NPN, 06367+I_NPN, 06201+I_FLD, 06202+I_FLD, 06203+I_FLD, @@ -395,7 +425,7 @@ return sp; t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) { -int32 cflag, i, j, sp, inst, disp; +int32 cflag, i, j, sp, inst, disp, opc; extern int32 emode; cflag = (uptr == NULL) || (uptr == &cpu_unit); @@ -419,14 +449,32 @@ if (!(sw & SWMASK ('M'))) return SCPE_ARG; /* Instruction decode */ -inst = val[0] | ((emode & 1) << 12); /* include EAE mode */ +opc = (inst >> 9) & 07; /* get major opcode */ +if (opc == 07) /* operate? */ + inst = inst | ((emode & 1) << 12); /* include EAE mode */ +if (opc == 06) { /* IOT? */ + DEVICE *dptr; + DIB *dibp; + uint32 dno = (inst >> 3) & 077; + for (i = 0; (dptr = amb_dev[i]) != NULL; i++) { /* check amb devices */ + if ((dptr->ctxt == NULL) || /* no DIB or */ + (dptr->flags & DEV_DIS)) continue; /* disabled? skip */ + dibp = (DIB *) dptr->ctxt; /* get DIB */ + if ((dno >= dibp->dev) || /* IOT for this dev? */ + (dno < (dibp->dev + dibp->num))) { + inst = inst | ((i + 1) << 12); /* disambiguate */ + break; /* done */ + } + } + } + for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */ - if ((opc_val[i] & 017777) == (inst & masks[j])) { /* match? */ + if ((opc_val[i] & 077777) == (inst & masks[j])) { /* match? */ switch (j) { /* case on class */ - case I_V_NPN: /* no operands */ + case I_V_NPN: case I_V_IOA: /* no operands */ fprintf (of, "%s", opcode[i]); /* opcode */ break; @@ -454,7 +502,7 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ break; case I_V_OP2: /* operate group 2 */ - if (opcode[i]) fprintf (of, "%s", opcode[i]); /* skips */ + if (opcode[i]) fprintf (of, "%s", opcode[i]); /* skips */ fprint_opr (of, inst & 0206, j, opcode[i] != NULL); break; @@ -566,7 +614,8 @@ switch (j) { /* case on class */ } break; - case I_V_NPN: case I_V_OP1: case I_V_OP2: case I_V_OP3: /* operates */ + case I_V_OP1: case I_V_OP2: case I_V_OP3: /* operates */ + case I_V_NPN: case I_V_IOA: for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0; cptr = get_glyph (cptr, gbuf, 0)) { for (i = 0; (opcode[i] != NULL) && diff --git a/PDP8/pdp8_td.c b/PDP8/pdp8_td.c index 9f7edbf3..2f1cdd30 100644 --- a/PDP8/pdp8_td.c +++ b/PDP8/pdp8_td.c @@ -681,7 +681,7 @@ return SCPE_OK; /* Bootstrap routine - OS/8 only - 1) Read reverse until reverse end zone (mark track is complement obverse + 1) Read reverse until reverse end zone (mark track is complement obverse) 2) Read forward until mark track code 031. This is a composite code from the last 4b of the forward block number and the first two bits of the reverse guard (01 -0110 01- 1010). There are 16 lines before the first diff --git a/PDP8/pdp8_tt.c b/PDP8/pdp8_tt.c index 30a3f69d..74a3c363 100644 --- a/PDP8/pdp8_tt.c +++ b/PDP8/pdp8_tt.c @@ -1,6 +1,6 @@ /* pdp8_tt.c: PDP-8 console terminal simulator - Copyright (c) 1993-2005, Robert M Supnik + Copyright (c) 1993-2006, 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 @@ tti,tto KL8E terminal input/output + 18-Oct-06 RMS Synced keyboard to clock + 30-Sep-06 RMS Fixed handling of non-printable characters in KSR mode 22-Nov-05 RMS Revised for new terminal processing routines 28-May-04 RMS Removed SET TTI CTRL-C 29-Dec-03 RMS Added console output backpressure support @@ -41,6 +43,7 @@ #include extern int32 int_req, int_enable, dev_done, stop_inst; +extern int32 tmxr_poll; int32 tti (int32 IR, int32 AC); int32 tto (int32 IR, int32 AC); @@ -60,7 +63,7 @@ t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); DIB tti_dib = { DEV_TTI, 1, { &tti } }; -UNIT tti_unit = { UDATA (&tti_svc, TT_MODE_KSR, 0), KBD_POLL_WAIT }; +UNIT tti_unit = { UDATA (&tti_svc, TT_MODE_KSR, 0), 0 }; REG tti_reg[] = { { ORDATA (BUF, tti_unit.buf, 8) }, @@ -68,7 +71,7 @@ REG tti_reg[] = { { FLDATA (ENABLE, int_enable, INT_V_TTI) }, { FLDATA (INT, int_req, INT_V_TTI) }, { DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, + { DRDATA (TIME, tti_unit.wait, 24), PV_LEFT }, { NULL } }; @@ -170,7 +173,7 @@ t_stat tti_svc (UNIT *uptr) { int32 c; -sim_activate (uptr, uptr->wait); /* continue poll */ +sim_activate (uptr, KBD_WAIT (uptr->wait, tmxr_poll)); /* continue poll */ if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */ if (c & SCPE_BREAK) uptr->buf = 0; /* break? */ else uptr->buf = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags) | TTUF_KSR); @@ -188,7 +191,7 @@ tti_unit.buf = 0; dev_done = dev_done & ~INT_TTI; /* clear done, int */ int_req = int_req & ~INT_TTI; int_enable = int_enable | INT_TTI; /* set enable */ -sim_activate (&tti_unit, tti_unit.wait); /* activate unit */ +sim_activate_abs (&tti_unit, KBD_WAIT (tti_unit.wait, tmxr_poll)); return SCPE_OK; } @@ -234,7 +237,7 @@ t_stat tto_svc (UNIT *uptr) int32 c; t_stat r; -c = sim_tt_outcvt (uptr->buf, TT_GET_MODE (uptr->flags)); +c = sim_tt_outcvt (uptr->buf, TT_GET_MODE (uptr->flags) | TTUF_KSR); if (c >= 0) { if ((r = sim_putchar_s (c)) != SCPE_OK) { /* output char; error? */ sim_activate (uptr, uptr->wait); /* try again */ diff --git a/PDP8/pdp8_ttx.c b/PDP8/pdp8_ttx.c index e12609b8..3a723e40 100644 --- a/PDP8/pdp8_ttx.c +++ b/PDP8/pdp8_ttx.c @@ -283,7 +283,7 @@ switch (pulse) { /* case IR<9:11> */ case 1: /* TSF */ return (dev_done & itto)? IOT_SKP + AC: AC; - case 2: /* TCF */ + case 2: /* TCF */ dev_done = dev_done & ~itto; /* clear flag */ int_req = int_req & ~itto; /* clear intr */ break; @@ -295,7 +295,7 @@ switch (pulse) { /* case IR<9:11> */ dev_done = dev_done & ~itto; /* clear flag */ int_req = int_req & ~itto; /* clear int req */ case 4: /* TPC */ - sim_activate (&ttox_unit[ln], ttox_unit[ln].wait); /* activate */ + sim_activate (&ttox_unit[ln], ttox_unit[ln].wait); /* activate */ ttox_buf[ln] = AC & 0377; /* load buffer */ break; diff --git a/SDS/sds_cpu.c b/SDS/sds_cpu.c index 038dca10..d3a8e654 100644 --- a/SDS/sds_cpu.c +++ b/SDS/sds_cpu.c @@ -1,6 +1,6 @@ /* sds_cpu.c: SDS 940 CPU simulator - Copyright (c) 2001-2005, Robert M. Supnik + Copyright (c) 2001-2006, 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"), @@ -26,6 +26,7 @@ cpu central processor rtc real time clock + 29-Dec-06 RMS Fixed breakpoint variable declarations 16-Aug-05 RMS Fixed C++ declaration and cast problems 07-Nov-04 RMS Added instruction history 01-Mar-03 RMS Added SET/SHOW RTC FREQ support @@ -193,7 +194,7 @@ int32 rtc_pie = 0; /* rtc pulse ie */ int32 rtc_tps = 60; /* rtc ticks/sec */ extern int32 sim_int_char; -extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ extern UNIT mux_unit; t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); @@ -429,7 +430,7 @@ while (reason == 0) { /* loop until halted */ int_reqhi = api_findreq (); /* recalc int req */ } else { /* normal instr */ - if (sim_brk_summ && sim_brk_test (P, SWMASK ('E'))) { /* breakpoint? */ + if (sim_brk_summ && sim_brk_test (P, SWMASK ('E'))) { /* breakpoint? */ reason = STOP_IBKPT; /* stop simulation */ break; } @@ -498,7 +499,7 @@ if (inst & I_POP) { /* POP? */ usr_mode = 0; /* set mon mode */ } else { /* normal POP */ - dat = (OV << 23) | dat; /* ov in <0> */ + dat = (OV << 23) | dat; /* ov in <0> */ if (r = Write (0, dat)) return r; } } @@ -1369,7 +1370,7 @@ return SCPE_OK; t_stat rtc_svc (UNIT *uptr) { if (rtc_pie) int_req = int_req | INT_RTCP; /* set pulse intr */ -sim_activate (&rtc_unit, sim_rtcn_calb (rtc_tps, TMR_RTC)); /* reactivate unit */ +sim_activate (&rtc_unit, sim_rtcn_calb (rtc_tps, TMR_RTC)); /* reactivate */ return SCPE_OK; } diff --git a/SDS/sds_drm.c b/SDS/sds_drm.c index 01545bb1..9c468dfa 100644 --- a/SDS/sds_drm.c +++ b/SDS/sds_drm.c @@ -87,7 +87,7 @@ #define DRM_EIU 7 /* end int uncond */ #define GET_TWORD(x) ((int32) fmod (sim_gtime() / ((double) (x)), \ - ((double) (DRM_NUMSC * DRM_PHYWD)))) + ((double) (DRM_NUMSC * DRM_PHYWD)))) extern uint32 M[]; /* memory */ extern uint32 alert, int_req; diff --git a/SDS/sds_io.c b/SDS/sds_io.c index 11a057a2..9e2e37e4 100644 --- a/SDS/sds_io.c +++ b/SDS/sds_io.c @@ -223,7 +223,7 @@ uint32 dev_map[64][NUM_CHAN]; t_stat (*dev_dsp[64][NUM_CHAN])() = { NULL }; -/* dev_dsp maps system device numbers to dispatch routines */ +/* dev3_dsp maps system device numbers to dispatch routines */ t_stat (*dev3_dsp[64])() = { NULL }; @@ -324,14 +324,14 @@ switch (mod) { chan_war[ch] = chan_cnt[ch] = 0; /* init chan */ chan_flag[ch] = chan_dcr[ch] = 0; chan_mode[ch] = chan_uar[ch] = 0; - if (ch > CHAN_E) chan_mode[ch] = CHM_CE; + if (ch >= CHAN_E) chan_mode[ch] = CHM_CE; if (r = dev_dsp[dev][ch] (IO_CONN, inst, NULL)) /* connect */ return r; if ((inst & I_IND) || (ch >= CHAN_C)) { /* C-H? alert ilc */ alert = POT_ILCY + ch; chan_mar[ch] = chan_wcr[ch] = 0; } - if (chan_flag[ch] & CHF_24B) chan_cpw[ch] = 0; /* 24B? 1 ch/wd */ + if (chan_flag[ch] & CHF_24B) chan_cpw[ch] = 0; /* 24B? 1 ch/wd */ else if (chan_flag[ch] & CHF_12B) /* 12B? 2 ch/wd */ chan_cpw[ch] = CHC_GETCPW (inst) & 1; else chan_cpw[ch] = CHC_GETCPW (inst); /* 6b, 1-4 ch/wd */ @@ -704,7 +704,7 @@ uint32 chan_mar_inc (int32 ch) { uint32 t = (chan_mar[ch] + 1) & PAMASK; /* incr mar */ -if ((chan_flag[ch] & CHF_DCHN) && ((t & VA_POFF) == 0)) { /* chain? */ +if ((chan_flag[ch] & CHF_DCHN) && ((t & VA_POFF) == 0)) { /* chain? */ chan_flag[ch] = chan_flag[ch] & ~CHF_DCHN; /* clr flag */ if (chan_dcr[ch] & CHD_INT) /* if armed, intr */ int_req = int_req | int_zc[ch]; @@ -896,7 +896,7 @@ for (i = 0; i < NUM_CHAN; i++) { for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru devices */ dibp = (DIB *) dptr->ctxt; /* get DIB */ - if ((dibp == NULL) || (dptr->flags & DEV_DIS)) continue; /* exist, enabled? */ + if ((dibp == NULL) || (dptr->flags & DEV_DIS)) continue; /* exist, enabled? */ ch = dibp->chan; /* get channel */ dev = dibp->dev; /* get device num */ if (ch < 0) dev3_dsp[dev] = dibp->iop; /* special device */ diff --git a/SDS/sds_mux.c b/SDS/sds_mux.c index 3d8fe909..ed143602 100644 --- a/SDS/sds_mux.c +++ b/SDS/sds_mux.c @@ -1,6 +1,6 @@ /* sds_mux.c: SDS 940 terminal multiplexor simulator - Copyright (c) 2001-2005, Robert M Supnik + Copyright (c) 2001-2006, 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 @@ mux terminal multiplexor + 29-Dec-06 RMS Revised to use console conversion routines 29-Jun-05 RMS Added SET MUXLn DISCONNECT 21-Jun-05 RMS Fixed bug in SHOW CONN/STATS 05-Jan-04 RMS Revised for tmxr library changes @@ -47,8 +48,6 @@ #define MUX_FLAGMASK (MUX_FLAGS - 1) #define MUX_SCANMAX (MUX_LINES * MUX_FLAGS) /* flags to scan */ #define MUX_SCANMASK (MUX_SCANMAX - 1) -#define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */ -#define UNIT_UC (1 << UNIT_V_UC) #define MUX_INIT_POLL 8000 #define MUXL_WAIT 500 #define MUX_SETFLG(l,x) mux_flags[((l) * MUX_FLAGS) + (x)] = 1 @@ -182,43 +181,45 @@ DEVICE mux_dev = { */ UNIT muxl_unit[] = { - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT } + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT } }; MTAB muxl_mod[] = { - { UNIT_UC, 0, "lower case", "LC", NULL }, - { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, + { TT_MODE, TT_MODE_UC, "UC", "UC", NULL }, + { TT_MODE, TT_MODE_7B, "7b", "7B", NULL }, + { TT_MODE, TT_MODE_8B, "8b", "8B", NULL }, + { TT_MODE, TT_MODE_7P, "7p", "7P", NULL }, { MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT", &tmxr_dscln, NULL, &mux_desc }, { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG", @@ -362,9 +363,8 @@ for (ln = 0; ln < MUX_NUMLIN; ln++) { /* loop thru lines */ if (mux_sta[ln] & MUX_SCHP) /* already got one? */ mux_sta[ln] = mux_sta[ln] | MUX_SOVR; /* overrun */ else mux_sta[ln] = mux_sta[ln] | MUX_SCHP; /* char pending */ - c = c & 0177; /* mask to 7b */ - if ((muxl_unit[ln].flags & UNIT_UC) && /* cvt to UC? */ - islower (c & 0x7F)) c = toupper (c); + if (c & SCPE_BREAK) c = 0; /* break? */ + else c = sim_tt_inpcvt (c, TT_GET_MODE (muxl_unit[ln].flags)); mux_rbuf[ln] = c; /* save char */ MUX_SETFLG (ln, MUX_FRCV); /* set rcv flag */ mux_scan_next (); /* kick scanner */ @@ -384,10 +384,8 @@ uint32 ln = uptr - muxl_unit; /* line # */ if (mux_ldsc[ln].conn) { /* connected? */ if (mux_ldsc[ln].xmte) { /* xmt enabled? */ - c = mux_xbuf[ln] & 0177; /* get char */ - if ((muxl_unit[ln].flags & UNIT_UC) && islower (c)) - c = toupper (c); /* cvt to UC? */ - tmxr_putc_ln (&mux_ldsc[ln], c); /* output char */ + c = sim_tt_outcvt (mux_xbuf[ln], TT_GET_MODE (muxl_unit[ln].flags)); + if (c >= 0) tmxr_putc_ln (&mux_ldsc[ln], c); /* output char */ tmxr_poll_tx (&mux_desc); /* poll xmt */ } else { /* buf full */ diff --git a/SDS/sds_rad.c b/SDS/sds_rad.c index debd6cfe..2add471d 100644 --- a/SDS/sds_rad.c +++ b/SDS/sds_rad.c @@ -48,7 +48,7 @@ #define RAD_TRSCMASK ((RAD_NUMSC * RAD_NUMTR) - 1) /* track/sec mask */ #define GET_SECTOR(x) ((int) fmod (sim_gtime() / ((double) (x)), \ - ((double) RAD_NUMSC))) + ((double) RAD_NUMSC))) extern uint32 xfr_req; extern uint32 alert; diff --git a/SDS/sds_sys.c b/SDS/sds_sys.c index 1ea3f0de..c00823ae 100644 --- a/SDS/sds_sys.c +++ b/SDS/sds_sys.c @@ -158,7 +158,7 @@ extern int32 lpt_ccl, lpt_ccp, lpt_cct[CCT_LNT]; char *cptr, cbuf[CBUFSIZE], gbuf[CBUFSIZE]; ptr = 0; -for ( ; (cptr = fgets (cbuf, CBUFSIZE, fileref)) != NULL; ) { /* until eof */ +for ( ; (cptr = fgets (cbuf, CBUFSIZE, fileref)) != NULL; ) { /* until eof */ mask = 0; if (*cptr == '(') { /* repeat count? */ cptr = get_glyph (cptr + 1, gbuf, ')'); /* get 1st field */ diff --git a/VAX/vax780_defs.h b/VAX/vax780_defs.h index 90c7c620..6f178b2a 100644 --- a/VAX/vax780_defs.h +++ b/VAX/vax780_defs.h @@ -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. + 29-Oct-2006 RMS Added clock coscheduler function 17-May-2006 RMS Added CR11/CD11 support (from John Dundas) 10-May-2006 RMS Added model-specific reserved operand check macros @@ -418,5 +419,6 @@ t_stat mba_show_num (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat show_nexus (FILE *st, UNIT *uptr, int32 val, void *desc); void sbi_set_errcnf (void); +int32 clk_cosched (int32 wait); #endif diff --git a/VAX/vax780_stddev.c b/VAX/vax780_stddev.c index fa5f6d3c..727c2c18 100644 --- a/VAX/vax780_stddev.c +++ b/VAX/vax780_stddev.c @@ -29,6 +29,8 @@ todr TODR clock tmr interval timer + 29-Oct-2006 RMS Added clock coscheduler function + Synced keyboard to clock for idling 11-May-06 RMS Revised timer logic for EVKAE 22-Nov-05 RMS Revised for new terminal processing routines 10-Mar-05 RMS Fixed bug in timer schedule routine (from Mark Hittinger) @@ -102,7 +104,7 @@ #define TMR_CSR_WR (TMR_CSR_IE | TMR_CSR_RUN) #define TMR_INC 10000 /* usec/interval */ #define CLK_DELAY 5000 /* 100 Hz */ -#define TMXR_MULT 2 /* 50 Hz */ +#define TMXR_MULT 1 /* 100 Hz */ /* Floppy definitions */ @@ -210,7 +212,7 @@ void fl_protocol_error (void); tti_reg TTI register list */ -UNIT tti_unit = { UDATA (&tti_svc, TT_MODE_8B, 0), KBD_POLL_WAIT }; +UNIT tti_unit = { UDATA (&tti_svc, TT_MODE_8B, 0), 0 }; REG tti_reg[] = { { HRDATA (RXDB, tti_buf, 16) }, @@ -219,7 +221,7 @@ REG tti_reg[] = { { FLDATA (DONE, tti_csr, CSR_V_DONE) }, { FLDATA (IE, tti_csr, CSR_V_IE) }, { DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, + { DRDATA (TIME, tti_unit.wait, 24), PV_LEFT }, { NULL } }; @@ -253,7 +255,7 @@ REG tto_reg[] = { { FLDATA (DONE, tto_csr, CSR_V_DONE) }, { FLDATA (IE, tto_csr, CSR_V_IE) }, { DRDATA (POS, tto_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT }, + { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT + REG_NZ }, { NULL } }; @@ -416,7 +418,7 @@ t_stat tti_svc (UNIT *uptr) { int32 c; -sim_activate (uptr, uptr->wait); /* continue poll */ +sim_activate (uptr, KBD_WAIT (uptr->wait, tmr_poll)); /* continue poll */ if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */ if (c & SCPE_BREAK) /* break? */ tti_buf = RXDB_ERR | RXDB_FRM; @@ -434,7 +436,7 @@ t_stat tti_reset (DEVICE *dptr) tti_buf = 0; tti_csr = 0; tti_int = 0; -sim_activate (&tti_unit, tti_unit.wait); /* activate unit */ +sim_activate_abs (&tti_unit, KBD_WAIT (tti_unit.wait, tmr_poll)); return SCPE_OK; } @@ -613,12 +615,22 @@ else tmr_use_100hz = 1; /* let clk handle */ return; } +/* Clock coscheduling routine */ + +int32 clk_cosched (int32 wait) +{ +int32 t; + +t = sim_is_active (&clk_unit); +return (t? t - 1: wait); +} + /* 100Hz clock reset */ t_stat clk_reset (DEVICE *dptr) { tmr_poll = sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init 100Hz timer */ -sim_activate (&clk_unit, tmr_poll); /* activate 100Hz unit */ +sim_activate_abs (&clk_unit, tmr_poll); /* activate 100Hz unit */ tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */ return SCPE_OK; } diff --git a/VAX/vax_cis.c b/VAX/vax_cis.c index 4dc6fde4..a481cea5 100644 --- a/VAX/vax_cis.c +++ b/VAX/vax_cis.c @@ -1219,10 +1219,12 @@ return TestDstr (src); /* clean -0 */ (to allow for external overflow calculations) The rules for the stored sign and the PSW sign are: - - Stored sign is negative if input is negative, and the result - is non-zero or there was overflow - - PSL sign is negative if input is negative, and the result is - non-zero + + - Stored sign is negative if input is negative, and the result + is non-zero or there was overflow + - PSL sign is negative if input is negative, and the result is + non-zero + Thus, the stored sign and the PSL sign will differ in one case: a negative zero generated by overflow is stored with a negative sign, but PSL.N is clear @@ -1297,16 +1299,18 @@ return; cy = carry in Output = 1 if carry, 0 if no carry - This algorithm courtesy Anton Chernoff, circa 1992 or even earlier + This algorithm courtesy Anton Chernoff, circa 1992 or even earlier. We trace the history of a pair of adjacent digits to see how the carry is fixed; each parenthesized item is a 4b digit. Assume we are adding: + (a)(b) I + (x)(y) J First compute I^J: + (a^x)(b^y) TMP Note that the low bit of each digit is the same as the low bit of @@ -1315,6 +1319,7 @@ return; Now compute I+J+66 to get decimal addition with carry forced left one digit: + (a+x+6+carry mod 16)(b+y+6 mod 16) SUM Note that if there was a carry from b+y+6, then the low bit of the @@ -1429,7 +1434,7 @@ return ((nz - 1) * 8) + i; mtable[10] = array of decimal string structures Note that dsrc has a high order zero nibble; this - guarantees that the largest multiple won't overflow + guarantees that the largest multiple won't overflow Also note that mtable[0] is not filled in */ diff --git a/VAX/vax_cpu.c b/VAX/vax_cpu.c index c75c7d66..5fc6af33 100644 --- a/VAX/vax_cpu.c +++ b/VAX/vax_cpu.c @@ -25,6 +25,7 @@ cpu VAX central processor + 29-Oct-06 RMS Added idle support 22-May-06 RMS Fixed format error in CPU history (found by Peter Schorn) 10-May-06 RMS Added -kesu switches for virtual addressing modes Fixed bugs in examine virtual @@ -245,6 +246,8 @@ int32 cpu_astop = 0; int32 mchk_va, mchk_ref; /* mem ref param */ int32 ibufl, ibufh; /* prefetch buf */ int32 ibcnt, ppc; /* prefetch ctl */ +uint32 cpu_idle_ipl_mask = 0xB; /* idle if on IPL 0,1,3 */ +int32 cpu_idle_wait = 200; /* for this many cycles */ jmp_buf save_env; REG *pcq_r = NULL; /* PC queue reg ptr */ int32 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ @@ -280,6 +283,7 @@ extern int32 sim_interval; extern int32 sim_int_char; extern int32 sim_switches; extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern t_bool sim_idle_enab; extern UNIT clk_unit; extern t_stat build_dib_tab (void); @@ -371,6 +375,8 @@ int32 cpu_get_vsw (int32 sw); int32 get_istr (int32 lnt, int32 acc); int32 ReadOcta (int32 va, int32 *opnd, int32 j, int32 acc); t_bool cpu_show_opnd (FILE *st, InstHistory *h, int32 line); +int32 cpu_psl_ipl (int32 newpsl); +t_stat cpu_idle_svc (UNIT *uptr); /* CPU data structures @@ -380,7 +386,9 @@ t_bool cpu_show_opnd (FILE *st, InstHistory *h, int32 line); cpu_mod CPU modifier list */ -UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, INITMEMSIZE) }; +UNIT cpu_unit = { + UDATA (&cpu_idle_svc, UNIT_FIX|UNIT_BINK, INITMEMSIZE) + }; REG cpu_reg[] = { { HRDATA (PC, R[nPC], 32) }, @@ -425,6 +433,8 @@ REG cpu_reg[] = { { FLDATA (CRDERR, crd_err, 0) }, { FLDATA (MEMERR, mem_err, 0) }, { FLDATA (HLTPIN, hlt_pin, 0) }, + { HRDATA (IDLE_IPL, cpu_idle_ipl_mask, 16), REG_HIDDEN }, + { DRDATA (IDLE_WAIT, cpu_idle_wait, 16), REG_HIDDEN }, { BRDATA (PCQ, pcq, 16, 32, PCQ_SIZE), REG_RO+REG_CIRC }, { HRDATA (PCQP, pcq_p, 6), REG_HRO }, { HRDATA (BADABO, badabo, 32), REG_HRO }, @@ -433,6 +443,10 @@ REG cpu_reg[] = { }; MTAB cpu_mod[] = { + { UNIT_CONH, 0, "HALT to SIMH", "SIMHALT", NULL }, + { UNIT_CONH, UNIT_CONH, "HALT to console", "CONHALT", NULL }, + { MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL }, { UNIT_MSIZE, (1u << 23), NULL, "8M", &cpu_set_size }, { UNIT_MSIZE, (1u << 24), NULL, "16M", &cpu_set_size }, { UNIT_MSIZE, (1u << 25), NULL, "32M", &cpu_set_size }, @@ -443,8 +457,6 @@ MTAB cpu_mod[] = { { UNIT_MSIZE, (1u << 28), NULL, "256M", &cpu_set_size }, { UNIT_MSIZE, (1u << 29), NULL, "512M", &cpu_set_size }, #endif - { UNIT_CONH, 0, "HALT to SIMH", "SIMHALT", NULL }, - { UNIT_CONH, UNIT_CONH, "HALT to console", "CONHALT", NULL }, { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", &cpu_set_hist, &cpu_show_hist }, { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "VIRTUAL", NULL, @@ -1515,8 +1527,7 @@ for ( ;; ) { /* Single operand instructions with source, read only - TSTx src.rx opnd[0] = source - */ - +*/ case TSTB: CC_IIZZ_B (op0); /* set cc's */ @@ -2943,6 +2954,30 @@ opnd[j++] = Read (va + 12, L_LONG, acc); return j; } +/* Set new PSL IPL */ + +int32 cpu_psl_ipl (int32 newpsl) +{ +if (((newpsl ^ PSL) & PSL_IPL) != 0) { + sim_cancel (&cpu_unit); + if (sim_idle_enab && ((newpsl & PSL_CUR) == 0)) { + uint32 newipl = PSL_GETIPL (newpsl); + if (cpu_idle_ipl_mask & (1u << newipl)) + sim_activate (&cpu_unit, cpu_idle_wait); + } + } +return newpsl; +} + +/* Idle timer has expired with no PSL change */ + +t_stat cpu_idle_svc (UNIT *uptr) +{ +if (sim_idle_enab) + sim_idle (TMR_CLK, FALSE); +return SCPE_OK; +} + /* Reset */ t_stat cpu_reset (DEVICE *dptr) @@ -2950,7 +2985,7 @@ t_stat cpu_reset (DEVICE *dptr) hlt_pin = 0; mem_err = 0; crd_err = 0; -PSL = PSL_IS | PSL_IPL1F; +PSL = cpu_psl_ipl (PSL_IS | PSL_IPL1F); SISR = 0; ASTLVL = 4; mapen = 0; diff --git a/VAX/vax_cpu1.c b/VAX/vax_cpu1.c index 73bf3e02..79353dd6 100644 --- a/VAX/vax_cpu1.c +++ b/VAX/vax_cpu1.c @@ -111,6 +111,8 @@ extern t_bool chk_tb_ent (uint32 va); extern int32 ReadIPR (int32 rg); extern void WriteIPR (int32 rg, int32 val); extern t_bool BadCmPSL (int32 newpsl); +extern int32 cpu_psl_ipl (int32 newpsl); + extern jmp_buf save_env; /* Branch on bit and no modify @@ -1079,9 +1081,9 @@ else { SP = KSP; /* new stack */ } } -if (ei > 0) PSL = newpsl | (ipl << PSL_V_IPL); /* if int, new IPL */ -else PSL = newpsl | ((newpc & 1)? PSL_IPL1F: (oldpsl & PSL_IPL)) | - (oldcur << PSL_V_PRV); +if (ei > 0) PSL = cpu_psl_ipl (newpsl | (ipl << PSL_V_IPL)); /* if int, new IPL */ +else PSL = cpu_psl_ipl (newpsl | + ((newpc & 1)? PSL_IPL1F: (oldpsl & PSL_IPL)) | (oldcur << PSL_V_PRV)); if (DEBUG_PRI (cpu_dev, LOG_CPU_I)) fprintf (sim_deb, ">>IEX: PC=%08x, PSL=%08x, SP=%08x, VEC=%08x, nPSL=%08x, nSP=%08x\n", PC, oldpsl, oldsp, vec, PSL, SP); @@ -1124,7 +1126,7 @@ Write (tsp - 8, PC, L_LONG, WA); /* push PC */ Write (tsp - 4, PSL | cc, L_LONG, WA); /* push PSL */ SP = tsp - 12; /* set new stk */ PSL = (mode << PSL_V_CUR) | (PSL & PSL_IPL) | /* set new PSL */ - (cur << PSL_V_PRV); + (cur << PSL_V_PRV); /* IPL unchanged */ last_chm = fault_PC; JUMP (newpc & ~03); /* set new PC */ return 0; /* cc = 0 */ @@ -1184,7 +1186,7 @@ else STK[oldcur] = SP; if (DEBUG_PRI (cpu_dev, LOG_CPU_R)) fprintf (sim_deb, ">>REI: PC=%08x, PSL=%08x, SP=%08x, nPC=%08x, nPSL=%08x, nSP=%08x\n", PC, PSL, SP - 8, newpc, newpsl, ((newpsl & IS)? IS: STK[newcur])); -PSL = (PSL & PSL_TP) | (newpsl & ~CC_MASK); /* set new PSL */ +PSL = cpu_psl_ipl ((PSL & PSL_TP) | (newpsl & ~CC_MASK)); /* set new PSL */ if (PSL & PSL_IS) SP = IS; /* set new stack */ else { SP = STK[newcur]; /* if ~IS, chk AST */ @@ -1275,7 +1277,8 @@ if (PSL & PSL_IS) SP = SP + 8; /* int stack? */ else { KSP = SP + 8; /* pop kernel stack */ SP = IS; /* switch to int stk */ - if ((PSL & PSL_IPL) == 0) PSL = PSL | PSL_IPL1; /* make IPL > 0 */ + if ((PSL & PSL_IPL) == 0) /* make IPL > 0 */ + PSL = cpu_psl_ipl (PSL | PSL_IPL1); PSL = PSL | PSL_IS; /* set PSL */ } pcbpa = PCBB & PAMASK; @@ -1436,7 +1439,7 @@ switch (prn) { /* case on reg # */ break; case MT_IPL: /* IPL */ - PSL = (PSL & ~PSL_IPL) | ((val & PSL_M_IPL) << PSL_V_IPL); + PSL = cpu_psl_ipl ((PSL & ~PSL_IPL) | ((val & PSL_M_IPL) << PSL_V_IPL)); break; case MT_ASTLVL: /* ASTLVL */ diff --git a/VAX/vax_stddev.c b/VAX/vax_stddev.c index 224ef3b3..9de7ed72 100644 --- a/VAX/vax_stddev.c +++ b/VAX/vax_stddev.c @@ -1,6 +1,6 @@ /* vax_stddev.c: VAX 3900 standard I/O devices - Copyright (c) 1998-2005, Robert M Supnik + Copyright (c) 1998-2006, 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"), @@ -27,6 +27,7 @@ tto terminal output clk 100Hz and TODR clock + 17-Oct-06 RMS Synced keyboard poll to real-time clock for idling 22-Nov-05 RMS Revised for new terminal processing routines 09-Sep-04 RMS Integrated powerup into RESET (with -p) 28-May-04 RMS Removed SET TTI CTRL-C @@ -54,7 +55,7 @@ #define CLKCSR_IMP (CSR_IE) /* real-time clock */ #define CLKCSR_RW (CSR_IE) #define CLK_DELAY 5000 /* 100 Hz */ -#define TMXR_MULT 2 /* 50 Hz */ +#define TMXR_MULT 1 /* 100 Hz */ extern int32 int_req[IPL_HLVL]; extern int32 hlt_pin; @@ -87,7 +88,7 @@ extern int32 sysd_hlt_enb (void); DIB tti_dib = { 0, 0, NULL, NULL, 1, IVCL (TTI), SCB_TTI, { NULL } }; -UNIT tti_unit = { UDATA (&tti_svc, TT_MODE_8B, 0), KBD_POLL_WAIT }; +UNIT tti_unit = { UDATA (&tti_svc, TT_MODE_8B, 0), 0 }; REG tti_reg[] = { { HRDATA (BUF, tti_unit.buf, 16) }, @@ -96,7 +97,7 @@ REG tti_reg[] = { { FLDATA (DONE, tti_csr, CSR_V_DONE) }, { FLDATA (IE, tti_csr, CSR_V_IE) }, { DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, + { DRDATA (TIME, tti_unit.wait, 24), PV_LEFT }, { NULL } }; @@ -281,7 +282,7 @@ t_stat tti_svc (UNIT *uptr) { int32 c; -sim_activate (uptr, uptr->wait); /* continue poll */ +sim_activate (uptr, KBD_WAIT (uptr->wait, tmr_poll)); /* continue poll */ if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */ if (c & SCPE_BREAK) { /* break? */ if (sysd_hlt_enb ()) hlt_pin = 1; /* if enabled, halt */ @@ -299,7 +300,7 @@ t_stat tti_reset (DEVICE *dptr) tti_unit.buf = 0; tti_csr = 0; CLR_INT (TTI); -sim_activate (&tti_unit, tti_unit.wait); /* activate unit */ +sim_activate_abs (&tti_unit, KBD_WAIT (tti_unit.wait, tmr_poll)); return SCPE_OK; } @@ -356,6 +357,18 @@ if (!todr_blow) todr_reg = todr_reg + 1; /* incr TODR */ return SCPE_OK; } +/* Clock coscheduling routine */ + +int32 clk_cosched (int32 wait) +{ +int32 t; + +t = sim_is_active (&clk_unit); +return (t? t - 1: wait); +} + +/* Powerup routine */ + t_stat todr_powerup (void) { uint32 base; @@ -375,6 +388,8 @@ todr_blow = 0; return SCPE_OK; } +/* Reset routine */ + t_stat clk_reset (DEVICE *dptr) { int32 t; @@ -383,7 +398,7 @@ if (sim_switches & SWMASK ('P')) todr_powerup (); /* powerup? */ clk_csr = 0; CLR_INT (CLK); t = sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init timer */ -sim_activate (&clk_unit, t); /* activate unit */ +sim_activate_abs (&clk_unit, t); /* activate unit */ tmr_poll = t; /* set tmr poll */ tmxr_poll = t * TMXR_MULT; /* set mux poll */ return SCPE_OK; diff --git a/VAX/vax_syscm.c b/VAX/vax_syscm.c index 4e91ba5f..c209104a 100644 --- a/VAX/vax_syscm.c +++ b/VAX/vax_syscm.c @@ -1,6 +1,6 @@ /* vax_syscm.c: PDP-11 compatibility mode symbolic decode and parse - Copyright (c) 1993-2005, Robert M Supnik + Copyright (c) 1993-2006, 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,7 +23,8 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - 27-Sep-05 RMS Fixed warnings compiling with 64b addresses + 12-Nov-06 RMS Fixed operand order in EIS instructions (found by W.F.J. Mueller) + 27-Sep-05 RMS Fixed warnings compiling with 64b addresses 15-Sep-04 RMS Cloned from pdp11_sys.c */ @@ -49,6 +50,7 @@ extern UNIT cpu_unit; #define I_V_DOP 9 /* double operand */ #define I_V_CCC 10 /* CC clear */ #define I_V_CCS 11 /* CC set */ +#define I_V_SOPR 12 /* operand, reg */ #define I_NPN (I_V_NPN << I_V_CL) #define I_REG (I_V_REG << I_V_CL) #define I_SOP (I_V_SOP << I_V_CL) @@ -61,11 +63,13 @@ extern UNIT cpu_unit; #define I_DOP (I_V_DOP << I_V_CL) #define I_CCC (I_V_CCC << I_V_CL) #define I_CCS (I_V_CCS << I_V_CL) +#define I_SOPR (I_V_SOPR << I_V_CL) static const int32 masks[] = { 0177777, 0177770, 0177700, 0177770, 0177000, 0177400, 0177700, 0177000, - 0177400, 0170000, 0177777, 0177777 + 0177400, 0170000, 0177777, 0177777, + 0177000 }; static const char *opcode[] = { @@ -145,7 +149,7 @@ static const int32 opc_val[] = { 0007000+I_SOP, 0007200+I_SOP, 0007300+I_SOP, 0010000+I_DOP, 0020000+I_DOP, 0030000+I_DOP, 0040000+I_DOP, 0050000+I_DOP, 0060000+I_DOP, -0070000+I_RSOP, 0071000+I_RSOP, 0072000+I_RSOP, 0073000+I_RSOP, +0070000+I_SOPR, 0071000+I_SOPR, 0072000+I_SOPR, 0073000+I_SOPR, 0074000+I_RSOP, 0075000+I_REG, 0075010+I_REG, 0075020+I_REG, 0075030+I_REG, 0076020+I_REG, @@ -335,6 +339,12 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ wd1 = fprint_spec (of, addr, dstm, val[1]); break; + case I_V_SOPR: /* sopr */ + fprintf (of, "%s ", opcode[i]); + wd1 = fprint_spec (of, addr, dstm, val[1]); + fprintf (of, ",%s", rname[srcr]); + break; + case I_V_DOP: /* dop */ fprintf (of, "%s ", opcode[i]); wd1 = fprint_spec (of, addr, srcm, val[1]); @@ -609,6 +619,16 @@ switch (j) { /* case on class */ val[0] = val[0] | spec; break; + case I_V_SOPR: /* dop, reg */ + cptr = get_glyph (cptr, gbuf, ','); /* get glyph */ + if ((n1 = get_spec (gbuf, ad32, 0, &spec, &val[1])) > 0) + return SCPE_ARG; + val[0] = val[0] | spec; + cptr = get_glyph (cptr, gbuf, 0); /* get glyph */ + if ((reg = get_reg (gbuf, 0)) < 0) return SCPE_ARG; + val[0] = val[0] | (reg << 6); + break; + case I_V_DOP: /* double op */ cptr = get_glyph (cptr, gbuf, ','); /* get glyph */ if ((n1 = get_spec (gbuf, ad32, 0, &spec, &val[1])) > 0) diff --git a/VAX/vax_sysdev.c b/VAX/vax_sysdev.c index 1b850dff..ebad1e65 100644 --- a/VAX/vax_sysdev.c +++ b/VAX/vax_sysdev.c @@ -85,7 +85,7 @@ #define CMERR_BUS 0x00000080 /* bus err NI */ #define CMERR_SYN 0x0000007F /* syndrome NI */ #define CMERR_W1C (CMERR_RDS | CMERR_FRQ | CMERR_CRD | \ - CMERR_DMA | CMERR_BUS) + CMERR_DMA | CMERR_BUS) /* CMCTL control/status register */ @@ -97,7 +97,7 @@ #define CMCSR_DCM 0x00000080 /* diag mode NI */ #define CMCSR_SYN 0x0000007F /* syndrome NI */ #define CMCSR_MASK (CMCSR_PMI | CMCSR_CRD | CMCSR_DET | \ - CMCSR_FDT | CMCSR_DCM | CMCSR_SYN) + CMCSR_FDT | CMCSR_DCM | CMCSR_SYN) /* KA655 boot/diagnostic register */ @@ -276,6 +276,7 @@ extern void txcs_wr (int32 dat); extern void txdb_wr (int32 dat); extern void ioreset_wr (int32 dat); extern uint32 sim_os_msec(); +extern int32 cpu_psl_ipl (int32 newpsl); /* ROM data structures @@ -901,7 +902,7 @@ struct reglink { /* register linkage */ uint32 low; /* low addr */ uint32 high; /* high addr */ t_stat (*read)(int32 pa); /* read routine */ - void (*write)(int32 pa, int32 val, int32 lnt); /* write routine */ + void (*write)(int32 pa, int32 val, int32 lnt); /* write routine */ }; struct reglink regtable[] = { @@ -1047,10 +1048,10 @@ int32 rg = (pa - KABASE) >> 2; switch (rg) { - case 0: /* CACR */ + case 0: /* CACR */ return ka_cacr; - case 1: /* BDR */ + case 1: /* BDR */ return ka_bdr; } @@ -1500,7 +1501,7 @@ else STK[temp] = SP; /* save stack */ if (mapen) conpsl = conpsl | CON_MAPON; /* mapping on? */ mapen = 0; /* turn off map */ SP = IS; /* set SP from IS */ -PSL = PSL_IS | PSL_IPL1F; /* PSL = 41F0000 */ +PSL = cpu_psl_ipl (PSL_IS | PSL_IPL1F); /* PSL = 41F0000 */ JUMP (ROMBASE); /* PC = 20040000 */ return 0; /* new cc = 0 */ } @@ -1514,7 +1515,7 @@ extern FILE *sim_log; t_stat r; PC = ROMBASE; -PSL = PSL_IS | PSL_IPL1F; +PSL = cpu_psl_ipl (PSL_IS | PSL_IPL1F); conpc = 0; conpsl = PSL_IS | PSL_IPL1F | CON_PWRUP; if (rom == NULL) return SCPE_IERR; @@ -1569,4 +1570,3 @@ ssc_bto = 0; ssc_otp = 0; return SCPE_OK; } - diff --git a/VAX/vax_syslist.c b/VAX/vax_syslist.c index 3270a20a..f19fb28b 100644 --- a/VAX/vax_syslist.c +++ b/VAX/vax_syslist.c @@ -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. + 17-Oct-06 RMS Re-ordered device list 17-May-06 RMS Added CR11/CD11 support (from John Dundas) 01-Oct-2004 RMS Cloned from vax_sys.c */ @@ -63,11 +64,11 @@ DEVICE *sim_devices[] = { &nvr_dev, &sysd_dev, &qba_dev, + &clk_dev, &tti_dev, &tto_dev, &csi_dev, &cso_dev, - &clk_dev, &dz_dev, &vh_dev, &cr_dev, diff --git a/VAX/vaxmod_defs.h b/VAX/vaxmod_defs.h index 4653d4eb..cec46c3d 100644 --- a/VAX/vaxmod_defs.h +++ b/VAX/vaxmod_defs.h @@ -453,4 +453,6 @@ t_stat set_vec (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat show_vec (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat auto_config (char *name, int32 num); +int32 clk_cosched (int32 wait); + #endif diff --git a/descrip.mms b/descrip.mms index 46524a48..9b291c99 100644 --- a/descrip.mms +++ b/descrip.mms @@ -187,7 +187,8 @@ ALTAIRZ80_SOURCE = $(ALTAIRZ80_DIR)ALTAIRZ80_CPU.C,\ $(ALTAIRZ80_DIR)ALTAIRZ80_DSK.C,\ $(ALTAIRZ80_DIR)ALTAIRZ80_SIO.C,\ $(ALTAIRZ80_DIR)ALTAIRZ80_SYS.C,\ - $(ALTAIRZ80_DIR)ALTAIRZ80_HDSK.C + $(ALTAIRZ80_DIR)ALTAIRZ80_HDSK.C,\ + $(ALTAIRZ80_DIR)ALTAIRZ80_NET.C ALTAIRZ80_OPTIONS = /INCL=($(SIMH_DIR),$(ALTAIRZ80_DIR))/DEF=($(CC_DEFS)) # @@ -254,7 +255,9 @@ HP2100_SOURCE = $(HP2100_DIR)HP2100_STDDEV.C,$(HP2100_DIR)HP2100_DP.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_CPU1.C,\ + $(HP2100_DIR)HP2100_IPL.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_FP1.C .IF ALPHA_OR_IA64 HP2100_OPTIONS = /INCL=($(SIMH_DIR),$(HP2100_DIR))\ @@ -329,7 +332,8 @@ PDP1_DIR = SYS$DISK:[.PDP1] PDP1_LIB = $(LIB_DIR)PDP1-$(ARCH).OLB PDP1_SOURCE = $(PDP1_DIR)PDP1_LP.C,$(PDP1_DIR)PDP1_CPU.C,\ $(PDP1_DIR)PDP1_STDDEV.C,$(PDP1_DIR)PDP1_SYS.C,\ - $(PDP1_DIR)PDP1_DT.C,$(PDP1_DIR)PDP1_DRM.C + $(PDP1_DIR)PDP1_DT.C,$(PDP1_DIR)PDP1_DRM.C,\ + $(PDP1_DIR)PDP1_CLK.C,$(PDP1_DIR)PDP1_DCS.C PDP1_OPTIONS = /INCL=($(SIMH_DIR),$(PDP1_DIR))/DEF=($(CC_DEFS)) # @@ -344,7 +348,8 @@ PDP8_SOURCE = $(PDP8_DIR)PDP8_CPU.C,$(PDP8_DIR)PDP8_CLK.C,\ $(PDP8_DIR)PDP8_RK.C,$(PDP8_DIR)PDP8_RX.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_TSC.C,$(PDP8_DIR)PDP8_TD.C,\ + $(PDP8_DIR)PDP8_CT.C PDP8_OPTIONS = /INCL=($(SIMH_DIR),$(PDP8_DIR))/DEF=($(CC_DEFS)) # @@ -377,7 +382,8 @@ PDP11_SOURCE1 = $(PDP11_DIR)PDP11_FP.C,$(PDP11_DIR)PDP11_CPU.C,\ $(PDP11_DIR)PDP11_RL.C,$(PDP11_DIR)PDP11_RP.C,\ $(PDP11_DIR)PDP11_RX.C,$(PDP11_DIR)PDP11_STDDEV.C,\ $(PDP11_DIR)PDP11_SYS.C,$(PDP11_DIR)PDP11_TC.C, \ - $(PDP11_DIR)PDP11_CPUMOD.C,$(PDP11_DIR)PDP11_CR.C + $(PDP11_DIR)PDP11_CPUMOD.C,$(PDP11_DIR)PDP11_CR.C, + $(PDP11_DIR)PDP11_TA.C PDP11_LIB2 = $(LIB_DIR)PDP11L2-$(ARCH).OLB PDP11_SOURCE2 = $(PDP11_DIR)PDP11_TM.C,$(PDP11_DIR)PDP11_TS.C,\ $(PDP11_DIR)PDP11_IO.C,$(PDP11_DIR)PDP11_RQ.C,\ @@ -402,7 +408,8 @@ PDP10_SOURCE = $(PDP10_DIR)PDP10_FE.C,\ $(PDP10_DIR)PDP10_RP.C,$(PDP10_DIR)PDP10_SYS.C,\ $(PDP10_DIR)PDP10_TIM.C,$(PDP10_DIR)PDP10_TU.C,\ $(PDP11_DIR)PDP11_PT.C,$(PDP11_DIR)PDP11_DZ.C,\ - $(PDP11_DIR)PDP11_RY.C,$(PDP11_DIR)PDP11_XU.C + $(PDP11_DIR)PDP11_RY.C,$(PDP11_DIR)PDP11_XU.C,\ + $(PDP11_DIR)PDP11_CR.C PDP10_OPTIONS = /INCL=($(SIMH_DIR),$(PDP10_DIR),$(PDP11_DIR))\ /DEF=($(CC_DEFS),"USE_INT64=1","VM_PDP10=1"$(PCAP_DEFS)) diff --git a/makefile b/makefile index 99b512d4..b509dc59 100644 --- a/makefile +++ b/makefile @@ -10,14 +10,14 @@ OS_CCDEFS = -lsocket -lnsl -lpthread -D_GNU_SOURCE else OS_CCDEFS = -D_GNU_SOURCE endif -CC = gcc -std=c99 -O2 -U__STRICT_ANSI__ -g -lm $(OS_CCDEFS) -I . +CC = gcc -std=c99 -O2 -U__STRICT_ANSI__ -g -lm -lrt $(OS_CCDEFS) -I . ifeq ($(USE_NETWORK),) else NETWORK_OPT = -DUSE_NETWORK -isystem /usr/local/include /usr/local/lib/libpcap.a endif else #Win32 Environments -LDFLAGS = -lm -lwsock32 +LDFLAGS = -lm -lwsock32 -lwinmm CC = gcc -std=c99 -U__STRICT_ANSI__ -O0 -I. EXE = .exe ifeq ($(USE_NETWORK),) @@ -26,7 +26,6 @@ NETWORK_OPT = -DUSE_NETWORK -lwpcap -lpacket endif endif - # # Common Libraries # @@ -38,353 +37,348 @@ SIM = scp.c sim_console.c sim_fio.c sim_timer.c sim_sock.c \ # # Emulator source files and compile time options # -PDP1D = PDP1/ -PDP1 = ${PDP1D}pdp1_lp.c ${PDP1D}pdp1_cpu.c ${PDP1D}pdp1_stddev.c \ - ${PDP1D}pdp1_sys.c ${PDP1D}pdp1_dt.c ${PDP1D}pdp1_drm.c +PDP1D = PDP1 +PDP1 = ${PDP1D}/pdp1_lp.c ${PDP1D}/pdp1_cpu.c ${PDP1D}/pdp1_stddev.c \ + ${PDP1D}/pdp1_sys.c ${PDP1D}/pdp1_dt.c ${PDP1D}/pdp1_drm.c \ + ${PDP1D}/pdp1_clk.c ${PDP1D}/pdp1_dcs.c PDP1_OPT = -I ${PDP1D} -NOVAD = NOVA/ -NOVA = ${NOVAD}nova_sys.c ${NOVAD}nova_cpu.c ${NOVAD}nova_dkp.c \ - ${NOVAD}nova_dsk.c ${NOVAD}nova_lp.c ${NOVAD}nova_mta.c \ - ${NOVAD}nova_plt.c ${NOVAD}nova_pt.c ${NOVAD}nova_clk.c \ - ${NOVAD}nova_tt.c ${NOVAD}nova_tt1.c ${NOVAD}nova_qty.c +NOVAD = NOVA +NOVA = ${NOVAD}/nova_sys.c ${NOVAD}/nova_cpu.c ${NOVAD}/nova_dkp.c \ + ${NOVAD}/nova_dsk.c ${NOVAD}/nova_lp.c ${NOVAD}/nova_mta.c \ + ${NOVAD}/nova_plt.c ${NOVAD}/nova_pt.c ${NOVAD}/nova_clk.c \ + ${NOVAD}/nova_tt.c ${NOVAD}/nova_tt1.c ${NOVAD}/nova_qty.c NOVA_OPT = -I ${NOVAD} - -ECLIPSE = ${NOVAD}eclipse_cpu.c ${NOVAD}eclipse_tt.c ${NOVAD}nova_sys.c \ - ${NOVAD}nova_dkp.c ${NOVAD}nova_dsk.c ${NOVAD}nova_lp.c \ - ${NOVAD}nova_mta.c ${NOVAD}nova_plt.c ${NOVAD}nova_pt.c \ - ${NOVAD}nova_clk.c ${NOVAD}nova_tt1.c ${NOVAD}nova_qty.c +ECLIPSE = ${NOVAD}/eclipse_cpu.c ${NOVAD}/eclipse_tt.c ${NOVAD}/nova_sys.c \ + ${NOVAD}/nova_dkp.c ${NOVAD}/nova_dsk.c ${NOVAD}/nova_lp.c \ + ${NOVAD}/nova_mta.c ${NOVAD}/nova_plt.c ${NOVAD}/nova_pt.c \ + ${NOVAD}/nova_clk.c ${NOVAD}/nova_tt1.c ${NOVAD}/nova_qty.c ECLIPSE_OPT = -I ${NOVAD} -DECLIPSE -DUSE_INT64 - -PDP18BD = PDP18B/ -PDP18B = ${PDP18BD}pdp18b_dt.c ${PDP18BD}pdp18b_drm.c ${PDP18BD}pdp18b_cpu.c \ - ${PDP18BD}pdp18b_lp.c ${PDP18BD}pdp18b_mt.c ${PDP18BD}pdp18b_rf.c \ - ${PDP18BD}pdp18b_rp.c ${PDP18BD}pdp18b_stddev.c ${PDP18BD}pdp18b_sys.c \ - ${PDP18BD}pdp18b_rb.c ${PDP18BD}pdp18b_tt1.c ${PDP18BD}pdp18b_fpp.c +PDP18BD = PDP18B +PDP18B = ${PDP18BD}/pdp18b_dt.c ${PDP18BD}/pdp18b_drm.c ${PDP18BD}/pdp18b_cpu.c \ + ${PDP18BD}/pdp18b_lp.c ${PDP18BD}/pdp18b_mt.c ${PDP18BD}/pdp18b_rf.c \ + ${PDP18BD}/pdp18b_rp.c ${PDP18BD}/pdp18b_stddev.c ${PDP18BD}/pdp18b_sys.c \ + ${PDP18BD}/pdp18b_rb.c ${PDP18BD}/pdp18b_tt1.c ${PDP18BD}/pdp18b_fpp.c PDP4_OPT = -DPDP4 -I ${PDP18BD} PDP7_OPT = -DPDP7 -I ${PDP18BD} PDP9_OPT = -DPDP9 -I ${PDP18BD} PDP15_OPT = -DPDP15 -I ${PDP18BD} - -PDP11D = PDP11/ -PDP11 = ${PDP11D}pdp11_fp.c ${PDP11D}pdp11_cpu.c ${PDP11D}pdp11_dz.c \ - ${PDP11D}pdp11_cis.c ${PDP11D}pdp11_lp.c ${PDP11D}pdp11_rk.c \ - ${PDP11D}pdp11_rl.c ${PDP11D}pdp11_rp.c ${PDP11D}pdp11_rx.c \ - ${PDP11D}pdp11_stddev.c ${PDP11D}pdp11_sys.c ${PDP11D}pdp11_tc.c \ - ${PDP11D}pdp11_tm.c ${PDP11D}pdp11_ts.c ${PDP11D}pdp11_io.c \ - ${PDP11D}pdp11_rq.c ${PDP11D}pdp11_tq.c ${PDP11D}pdp11_pclk.c \ - ${PDP11D}pdp11_ry.c ${PDP11D}pdp11_pt.c ${PDP11D}pdp11_hk.c \ - ${PDP11D}pdp11_xq.c ${PDP11D}pdp11_xu.c ${PDP11D}pdp11_vh.c \ - ${PDP11D}pdp11_rh.c ${PDP11D}pdp11_tu.c ${PDP11D}pdp11_cpumod.c \ - ${PDP11D}pdp11_cr.c ${PDP11D}pdp11_rf.c ${PDP11D}pdp11_dl.c +PDP11D = PDP11 +PDP11 = ${PDP11D}/pdp11_fp.c ${PDP11D}/pdp11_cpu.c ${PDP11D}/pdp11_dz.c \ + ${PDP11D}/pdp11_cis.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_rk.c \ + ${PDP11D}/pdp11_rl.c ${PDP11D}/pdp11_rp.c ${PDP11D}/pdp11_rx.c \ + ${PDP11D}/pdp11_stddev.c ${PDP11D}/pdp11_sys.c ${PDP11D}/pdp11_tc.c \ + ${PDP11D}/pdp11_tm.c ${PDP11D}/pdp11_ts.c ${PDP11D}/pdp11_io.c \ + ${PDP11D}/pdp11_rq.c ${PDP11D}/pdp11_tq.c ${PDP11D}/pdp11_pclk.c \ + ${PDP11D}/pdp11_ry.c ${PDP11D}/pdp11_pt.c ${PDP11D}/pdp11_hk.c \ + ${PDP11D}/pdp11_xq.c ${PDP11D}/pdp11_xu.c ${PDP11D}/pdp11_vh.c \ + ${PDP11D}/pdp11_rh.c ${PDP11D}/pdp11_tu.c ${PDP11D}/pdp11_cpumod.c \ + ${PDP11D}/pdp11_cr.c ${PDP11D}/pdp11_rf.c ${PDP11D}/pdp11_dl.c \ + ${PDP11D}/pdp11_ta.c PDP11_OPT = -DVM_PDP11 -I ${PDP11D} ${NETWORK_OPT} - -VAXD = VAX/ -VAX = ${VAXD}vax_cpu.c ${VAXD}vax_cpu1.c ${VAXD}vax_fpa.c ${VAXD}vax_io.c \ - ${VAXD}vax_cis.c ${VAXD}vax_octa.c ${VAXD}vax_cmode.c \ - ${VAXD}vax_mmu.c ${VAXD}vax_stddev.c ${VAXD}vax_sysdev.c \ - ${VAXD}vax_sys.c ${VAXD}vax_syscm.c ${VAXD}vax_syslist.c \ - ${PDP11D}pdp11_rl.c ${PDP11D}pdp11_rq.c ${PDP11D}pdp11_ts.c \ - ${PDP11D}pdp11_dz.c ${PDP11D}pdp11_lp.c ${PDP11D}pdp11_tq.c \ - ${PDP11D}pdp11_xq.c ${PDP11D}pdp11_ry.c \ - ${PDP11D}pdp11_vh.c ${PDP11D}pdp11_cr.c +VAXD = VAX +VAX = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c ${VAXD}/vax_io.c \ + ${VAXD}/vax_cis.c ${VAXD}/vax_octa.c ${VAXD}/vax_cmode.c \ + ${VAXD}/vax_mmu.c ${VAXD}/vax_stddev.c ${VAXD}/vax_sysdev.c \ + ${VAXD}/vax_sys.c ${VAXD}/vax_syscm.c ${VAXD}/vax_syslist.c \ + ${PDP11D}/pdp11_rl.c ${PDP11D}/pdp11_rq.c ${PDP11D}/pdp11_ts.c \ + ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ + ${PDP11D}/pdp11_xq.c ${PDP11D}/pdp11_ry.c \ + ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_cr.c VAX_OPT = -DVM_VAX -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} - -VAX780 = ${VAXD}vax_cpu.c ${VAXD}vax_cpu1.c ${VAXD}vax_fpa.c \ - ${VAXD}vax_cis.c ${VAXD}vax_octa.c ${VAXD}vax_cmode.c \ - ${VAXD}vax_mmu.c ${VAXD}vax_sys.c ${VAXD}vax_syscm.c \ - ${VAXD}vax780_stddev.c ${VAXD}vax780_sbi.c \ - ${VAXD}vax780_mem.c ${VAXD}vax780_uba.c ${VAXD}vax780_mba.c \ - ${VAXD}vax780_fload.c ${VAXD}vax780_syslist.c \ - ${PDP11D}pdp11_rl.c ${PDP11D}pdp11_rq.c ${PDP11D}pdp11_ts.c \ - ${PDP11D}pdp11_dz.c ${PDP11D}pdp11_lp.c ${PDP11D}pdp11_tq.c \ - ${PDP11D}pdp11_xu.c ${PDP11D}pdp11_ry.c ${PDP11D}pdp11_cr.c \ - ${PDP11D}pdp11_rp.c ${PDP11D}pdp11_tu.c ${PDP11D}pdp11_hk.c -VAX780_OPT = -DVM_VAX -DVAX_780 -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} +VAX780 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ + ${VAXD}/vax_cis.c ${VAXD}/vax_octa.c ${VAXD}/vax_cmode.c \ + ${VAXD}/vax_mmu.c ${VAXD}/vax_sys.c ${VAXD}/vax_syscm.c \ + ${VAXD}/vax780_stddev.c ${VAXD}/vax780_sbi.c \ + ${VAXD}/vax780_mem.c ${VAXD}/vax780_uba.c ${VAXD}/vax780_mba.c \ + ${VAXD}/vax780_fload.c ${VAXD}/vax780_syslist.c \ + ${PDP11D}/pdp11_rl.c ${PDP11D}/pdp11_rq.c ${PDP11D}/pdp11_ts.c \ + ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ + ${PDP11D}/pdp11_xu.c ${PDP11D}/pdp11_ry.c ${PDP11D}/pdp11_cr.c \ + ${PDP11D}/pdp11_rp.c ${PDP11D}/pdp11_tu.c ${PDP11D}/pdp11_hk.c +VAX780_OPT = -DVM_VAX -DVAX_780 -DUSE_INT64 -DUSE_ADDR64 -I VAX -I ${PDP11D} ${NETWORK_OPT} - -PDP10D = PDP10/ -PDP10 = ${PDP10D}pdp10_fe.c ${PDP11D}pdp11_dz.c ${PDP10D}pdp10_cpu.c \ - ${PDP10D}pdp10_ksio.c ${PDP10D}pdp10_lp20.c ${PDP10D}pdp10_mdfp.c \ - ${PDP10D}pdp10_pag.c ${PDP10D}pdp10_rp.c ${PDP10D}pdp10_sys.c \ - ${PDP10D}pdp10_tim.c ${PDP10D}pdp10_tu.c ${PDP10D}pdp10_xtnd.c \ - ${PDP11D}pdp11_pt.c ${PDP11D}pdp11_ry.c ${PDP11D}pdp11_xu.c -PDP10_OPT = -DVM_PDP10 -DUSE_INT64 -I ${PDP10D} -I ${PDP11D} -I ${VAXD} ${NETWORK_OPT} +PDP10D = PDP10 +PDP10 = ${PDP10D}/pdp10_fe.c ${PDP11D}/pdp11_dz.c ${PDP10D}/pdp10_cpu.c \ + ${PDP10D}/pdp10_ksio.c ${PDP10D}/pdp10_lp20.c ${PDP10D}/pdp10_mdfp.c \ + ${PDP10D}/pdp10_pag.c ${PDP10D}/pdp10_rp.c ${PDP10D}/pdp10_sys.c \ + ${PDP10D}/pdp10_tim.c ${PDP10D}/pdp10_tu.c ${PDP10D}/pdp10_xtnd.c \ + ${PDP11D}/pdp11_pt.c ${PDP11D}/pdp11_ry.c ${PDP11D}/pdp11_xu.c \ + ${PDP11D}/pdp11_cr.c +PDP10_OPT = -DVM_PDP10 -DUSE_INT64 -I ${PDP10D} -I ${PDP11D} ${NETWORK_OPT} PDP8D = PDP8/ -PDP8 = ${PDP8D}pdp8_cpu.c ${PDP8D}pdp8_clk.c ${PDP8D}pdp8_df.c \ - ${PDP8D}pdp8_dt.c ${PDP8D}pdp8_lp.c ${PDP8D}pdp8_mt.c \ - ${PDP8D}pdp8_pt.c ${PDP8D}pdp8_rf.c ${PDP8D}pdp8_rk.c \ - ${PDP8D}pdp8_rx.c ${PDP8D}pdp8_sys.c ${PDP8D}pdp8_tt.c \ - ${PDP8D}pdp8_ttx.c ${PDP8D}pdp8_rl.c ${PDP8D}pdp8_tsc.c \ - ${PDP8D}pdp8_td.c +PDP8 = ${PDP8D}/pdp8_cpu.c ${PDP8D}/pdp8_clk.c ${PDP8D}/pdp8_df.c \ + ${PDP8D}/pdp8_dt.c ${PDP8D}/pdp8_lp.c ${PDP8D}/pdp8_mt.c \ + ${PDP8D}/pdp8_pt.c ${PDP8D}/pdp8_rf.c ${PDP8D}/pdp8_rk.c \ + ${PDP8D}/pdp8_rx.c ${PDP8D}/pdp8_sys.c ${PDP8D}/pdp8_tt.c \ + ${PDP8D}/pdp8_ttx.c ${PDP8D}/pdp8_rl.c ${PDP8D}/pdp8_tsc.c \ + ${PDP8D}/pdp8_td.c ${PDP8D}/pdp8_ct.c PDP8_OPT = -I ${PDP8D} - -H316D = H316/ -H316 = ${H316D}h316_stddev.c ${H316D}h316_lp.c ${H316D}h316_cpu.c \ - ${H316D}h316_sys.c ${H316D}h316_mt.c ${H316D}h316_fhd.c \ - ${H316D}h316_dp.c +H316D = H316 +H316 = ${H316D}/h316_stddev.c ${H316D}/h316_lp.c ${H316D}/h316_cpu.c \ + ${H316D}/h316_sys.c ${H316D}/h316_mt.c ${H316D}/h316_fhd.c \ + ${H316D}/h316_dp.c H316_OPT = -I ${H316D} - -HP2100D = HP2100/ -HP2100 = ${HP2100D}hp2100_stddev.c ${HP2100D}hp2100_dp.c ${HP2100D}hp2100_dq.c \ - ${HP2100D}hp2100_dr.c ${HP2100D}hp2100_lps.c ${HP2100D}hp2100_ms.c \ - ${HP2100D}hp2100_mt.c ${HP2100D}hp2100_mux.c ${HP2100D}hp2100_cpu.c \ - ${HP2100D}hp2100_fp.c ${HP2100D}hp2100_sys.c ${HP2100D}hp2100_lpt.c \ - ${HP2100D}hp2100_ipl.c ${HP2100D}hp2100_ds.c ${HP2100D}hp2100_cpu1.c \ - ${HP2100D}hp2100_fp1.c +HP2100D = HP2100 +HP2100 = ${HP2100D}/hp2100_stddev.c ${HP2100D}/hp2100_dp.c ${HP2100D}/hp2100_dq.c \ + ${HP2100D}/hp2100_dr.c ${HP2100D}/hp2100_lps.c ${HP2100D}/hp2100_ms.c \ + ${HP2100D}/hp2100_mt.c ${HP2100D}/hp2100_mux.c ${HP2100D}/hp2100_cpu.c \ + ${HP2100D}/hp2100_fp.c ${HP2100D}/hp2100_sys.c ${HP2100D}/hp2100_lpt.c \ + ${HP2100D}/hp2100_ipl.c ${HP2100D}/hp2100_ds.c ${HP2100D}/hp2100_cpu0.c \ + ${HP2100D}/hp2100_cpu1.c ${HP2100D}/hp2100_cpu2.c ${HP2100D}/hp2100_cpu3.c \ + ${HP2100D}/hp2100_cpu4.c ${HP2100D}/hp2100_fp1.c HP2100_OPT = -DHAVE_INT64 -I ${HP2100D} - -I1401D = I1401/ -I1401 = ${I1401D}i1401_lp.c ${I1401D}i1401_cpu.c ${I1401D}i1401_iq.c \ - ${I1401D}i1401_cd.c ${I1401D}i1401_mt.c ${I1401D}i1401_dp.c \ - ${I1401D}i1401_sys.c +I1401D = I1401 +I1401 = ${I1401D}/i1401_lp.c ${I1401D}/i1401_cpu.c ${I1401D}/i1401_iq.c \ + ${I1401D}/i1401_cd.c ${I1401D}/i1401_mt.c ${I1401D}/i1401_dp.c \ + ${I1401D}/i1401_sys.c I1401_OPT = -I ${I1401D} - -I1620D = I1620/ -I1620 = ${I1620D}i1620_cd.c ${I1620D}i1620_dp.c ${I1620D}i1620_pt.c \ - ${I1620D}i1620_tty.c ${I1620D}i1620_cpu.c ${I1620D}i1620_lp.c \ - ${I1620D}i1620_fp.c ${I1620D}i1620_sys.c +I1620D = I1620 +I1620 = ${I1620D}/i1620_cd.c ${I1620D}/i1620_dp.c ${I1620D}/i1620_pt.c \ + ${I1620D}/i1620_tty.c ${I1620D}/i1620_cpu.c ${I1620D}/i1620_lp.c \ + ${I1620D}/i1620_fp.c ${I1620D}/i1620_sys.c I1620_OPT = -I ${I1620D} - -I7094D = I7094/ -I7094 = ${I7094D}i7094_cpu.c ${I7094D}i7094_cpu1.c ${I7094D}i7094_io.c \ - ${I7094D}i7094_cd.c ${I7094D}i7094_clk.c ${I7094D}i7094_com.c \ - ${I7094D}i7094_drm.c ${I7094D}i7094_dsk.c ${I7094D}i7094_sys.c \ - ${I7094D}i7094_lp.c ${I7094D}i7094_mt.c ${I7094D}i7094_binloader.c +I7094D = I7094 +I7094 = ${I7094D}/i7094_cpu.c ${I7094D}/i7094_cpu1.c ${I7094D}/i7094_io.c \ + ${I7094D}/i7094_cd.c ${I7094D}/i7094_clk.c ${I7094D}/i7094_com.c \ + ${I7094D}/i7094_drm.c ${I7094D}/i7094_dsk.c ${I7094D}/i7094_sys.c \ + ${I7094D}/i7094_lp.c ${I7094D}/i7094_mt.c ${I7094D}/i7094_binloader.c I7094_OPT = -DUSE_INT64 -I ${I7094D} - -IBM1130D = Ibm1130/ -IBM1130 = ${IBM1130D}ibm1130_cpu.c ${IBM1130D}ibm1130_cr.c \ - ${IBM1130D}ibm1130_disk.c ${IBM1130D}ibm1130_stddev.c \ - ${IBM1130D}ibm1130_sys.c ${IBM1130D}ibm1130_gdu.c \ - ${IBM1130D}ibm1130_gui.c ${IBM1130D}ibm1130_prt.c \ - ${IBM1130D}ibm1130_fmt.c ${IBM1130D}ibm1130_ptrp.c +IBM1130D = Ibm1130 +IBM1130 = ${IBM1130D}/ibm1130_cpu.c ${IBM1130D}/ibm1130_cr.c \ + ${IBM1130D}/ibm1130_disk.c ${IBM1130D}/ibm1130_stddev.c \ + ${IBM1130D}/ibm1130_sys.c ${IBM1130D}/ibm1130_gdu.c \ + ${IBM1130D}/ibm1130_gui.c ${IBM1130D}/ibm1130_prt.c \ + ${IBM1130D}/ibm1130_fmt.c ${IBM1130D}/ibm1130_ptrp.c \ + ${IBM1130D}/ibm1130_plot.c ${IBM1130D}/ibm1130_sca.c \ + ${IBM1130D}/ibm1130_t2741.c IBM1130_OPT = -I ${IBM1130D} - -ID16D = Interdata/ -ID16 = ${ID16D}id16_cpu.c ${ID16D}id16_sys.c ${ID16D}id_dp.c \ - ${ID16D}id_fd.c ${ID16D}id_fp.c ${ID16D}id_idc.c ${ID16D}id_io.c \ - ${ID16D}id_lp.c ${ID16D}id_mt.c ${ID16D}id_pas.c ${ID16D}id_pt.c \ - ${ID16D}id_tt.c ${ID16D}id_uvc.c ${ID16D}id16_dboot.c ${ID16D}id_ttp.c +ID16D = Interdata +ID16 = ${ID16D}/id16_cpu.c ${ID16D}/id16_sys.c ${ID16D}/id_dp.c \ + ${ID16D}/id_fd.c ${ID16D}/id_fp.c ${ID16D}/id_idc.c ${ID16D}/id_io.c \ + ${ID16D}/id_lp.c ${ID16D}/id_mt.c ${ID16D}/id_pas.c ${ID16D}/id_pt.c \ + ${ID16D}/id_tt.c ${ID16D}/id_uvc.c ${ID16D}/id16_dboot.c ${ID16D}/id_ttp.c ID16_OPT = -I ${ID16D} - -ID32D = Interdata/ -ID32 = ${ID32D}id32_cpu.c ${ID32D}id32_sys.c ${ID32D}id_dp.c \ - ${ID32D}id_fd.c ${ID32D}id_fp.c ${ID32D}id_idc.c ${ID32D}id_io.c \ - ${ID32D}id_lp.c ${ID32D}id_mt.c ${ID32D}id_pas.c ${ID32D}id_pt.c \ - ${ID32D}id_tt.c ${ID32D}id_uvc.c ${ID32D}id32_dboot.c ${ID32D}id_ttp.c +ID32D = Interdata +ID32 = ${ID32D}/id32_cpu.c ${ID32D}/id32_sys.c ${ID32D}/id_dp.c \ + ${ID32D}/id_fd.c ${ID32D}/id_fp.c ${ID32D}/id_idc.c ${ID32D}/id_io.c \ + ${ID32D}/id_lp.c ${ID32D}/id_mt.c ${ID32D}/id_pas.c ${ID32D}/id_pt.c \ + ${ID32D}/id_tt.c ${ID32D}/id_uvc.c ${ID32D}/id32_dboot.c ${ID32D}/id_ttp.c ID32_OPT = -I ${ID32D} - -S3D = S3/ -S3 = ${S3D}s3_cd.c ${S3D}s3_cpu.c ${S3D}s3_disk.c ${S3D}s3_lp.c \ - ${S3D}s3_pkb.c ${S3D}s3_sys.c +S3D = S3 +S3 = ${S3D}/s3_cd.c ${S3D}/s3_cpu.c ${S3D}/s3_disk.c ${S3D}/s3_lp.c \ + ${S3D}/s3_pkb.c ${S3D}/s3_sys.c S3_OPT = -I ${S3D} - -ALTAIRD = ALTAIR/ -ALTAIR = ${ALTAIRD}altair_sio.c ${ALTAIRD}altair_cpu.c ${ALTAIRD}altair_dsk.c \ - ${ALTAIRD}altair_sys.c +ALTAIRD = ALTAIR +ALTAIR = ${ALTAIRD}/altair_sio.c ${ALTAIRD}/altair_cpu.c ${ALTAIRD}/altair_dsk.c \ + ${ALTAIRD}/altair_sys.c ALTAIR_OPT = -I ${ALTAIRD} - -ALTAIRZ80D = AltairZ80/ -ALTAIRZ80 = ${ALTAIRZ80D}altairz80_cpu.c ${ALTAIRZ80D}altairz80_dsk.c \ - ${ALTAIRZ80D}altairz80_sio.c ${ALTAIRZ80D}altairz80_sys.c \ - ${ALTAIRZ80D}altairz80_hdsk.c +ALTAIRZ80D = AltairZ80 +ALTAIRZ80 = ${ALTAIRZ80D}/altairz80_cpu.c ${ALTAIRZ80D}/altairz80_dsk.c \ + ${ALTAIRZ80D}/altairz80_sio.c ${ALTAIRZ80D}/altairz80_sys.c \ + ${ALTAIRZ80D}/altairz80_hdsk.c ${ALTAIRZ80D}/altairz80_net.c ALTAIRZ80_OPT = -I ${ALTAIRZ80D} - -GRID = GRI/ -GRI = ${GRID}gri_cpu.c ${GRID}gri_stddev.c ${GRID}gri_sys.c +GRID = GRI +GRI = ${GRID}/gri_cpu.c ${GRID}/gri_stddev.c ${GRID}/gri_sys.c GRI_OPT = -I ${GRID} - -LGPD = LGP/ -LGP = ${LGPD}lgp_cpu.c ${LGPD}lgp_stddev.c ${LGPD}lgp_sys.c +LGPD = LGP +LGP = ${LGPD}/lgp_cpu.c ${LGPD}/lgp_stddev.c ${LGPD}/lgp_sys.c LGP_OPT = -I ${LGPD} - -SDSD = SDS/ -SDS = ${SDSD}sds_cpu.c ${SDSD}sds_drm.c ${SDSD}sds_dsk.c ${SDSD}sds_io.c \ - ${SDSD}sds_lp.c ${SDSD}sds_mt.c ${SDSD}sds_mux.c ${SDSD}sds_rad.c \ - ${SDSD}sds_stddev.c ${SDSD}sds_sys.c +SDSD = SDS +SDS = ${SDSD}/sds_cpu.c ${SDSD}/sds_drm.c ${SDSD}/sds_dsk.c ${SDSD}/sds_io.c \ + ${SDSD}/sds_lp.c ${SDSD}/sds_mt.c ${SDSD}/sds_mux.c ${SDSD}/sds_rad.c \ + ${SDSD}/sds_stddev.c ${SDSD}/sds_sys.c SDS_OPT = -I ${SDSD} - - # # Build everything # -ALL = ${BIN}pdp1${EXE} ${BIN}pdp4${EXE} ${BIN}pdp7${EXE} ${BIN}pdp8${EXE} \ - ${BIN}pdp9${EXE} ${BIN}pdp15${EXE} ${BIN}pdp11${EXE} ${BIN}pdp10${EXE} \ - ${BIN}vax${EXE} ${BIN}vax780${EXE} ${BIN}nova${EXE} ${BIN}eclipse${EXE} \ - ${BIN}hp2100${EXE} ${BIN}i1401${EXE} ${BIN}i1620${EXE} ${BIN}s3${EXE} \ - ${BIN}altair${EXE} ${BIN}altairz80${EXE} ${BIN}gri${EXE} \ - ${BIN}i1620${EXE} ${BIN}i7094${EXE} ${BIN}ibm1130${EXE} ${BIN}id16${EXE} \ - ${BIN}id32${EXE} ${BIN}sds${EXE} ${BIN}lgp${EXE} ${BIN}h316${EXE} +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 all : ${ALL} clean : ifeq ($(WIN32),) - ${RM} ${ALL} + ${RM} ${BIN}* else if exist BIN\*.exe del /q BIN\*.exe endif + # # Individual builds # +pdp1 : ${BIN}pdp1${EXE} + ${BIN}pdp1${EXE} : ${PDP1} ${SIM} ${CC} ${PDP1} ${SIM} ${PDP1_OPT} -o $@ ${LDFLAGS} - +pdp4 : ${BIN}pdp4${EXE} ${BIN}pdp4${EXE} : ${PDP18B} ${SIM} ${CC} ${PDP18B} ${SIM} ${PDP4_OPT} -o $@ ${LDFLAGS} - +pdp7 : ${BIN}pdp7${EXE} ${BIN}pdp7${EXE} : ${PDP18B} ${SIM} ${CC} ${PDP18B} ${SIM} ${PDP7_OPT} -o $@ ${LDFLAGS} - +pdp8 : ${BIN}pdp8${EXE} ${BIN}pdp8${EXE} : ${PDP8} ${SIM} ${CC} ${PDP8} ${SIM} ${PDP8_OPT} -o $@ ${LDFLAGS} - +pdp9 : ${BIN}pdp9${EXE} ${BIN}pdp9${EXE} : ${PDP18B} ${SIM} ${CC} ${PDP18B} ${SIM} ${PDP9_OPT} -o $@ ${LDFLAGS} - +pdp15 : ${BIN}pdp15${EXE} ${BIN}pdp15${EXE} : ${PDP18B} ${SIM} ${CC} ${PDP18B} ${SIM} ${PDP15_OPT} -o $@ ${LDFLAGS} - +pdp10 : ${BIN}pdp10${EXE} ${BIN}pdp10${EXE} : ${PDP10} ${SIM} ${CC} ${PDP10} ${SIM} ${PDP10_OPT} -o $@ ${LDFLAGS} - +pdp11 : ${BIN}pdp11${EXE} ${BIN}pdp11${EXE} : ${PDP11} ${SIM} ${CC} ${PDP11} ${SIM} ${PDP11_OPT} -o $@ ${LDFLAGS} - +vax : ${BIN}vax${EXE} ${BIN}vax${EXE} : ${VAX} ${SIM} ${CC} ${VAX} ${SIM} ${VAX_OPT} -o $@ ${LDFLAGS} +vax780 : ${BIN}vax780${EXE} ${BIN}vax780${EXE} : ${VAX780} ${SIM} ${CC} ${VAX780} ${SIM} ${VAX780_OPT} -o $@ ${LDFLAGS} +nova : ${BIN}nova${EXE} ${BIN}nova${EXE} : ${NOVA} ${SIM} ${CC} ${NOVA} ${SIM} ${NOVA_OPT} -o $@ ${LDFLAGS} - +eclipse : ${BIN}eclipse${EXE} ${BIN}eclipse${EXE} : ${ECLIPSE} ${SIM} ${CC} ${ECLIPSE} ${SIM} ${ECLIPSE_OPT} -o $@ ${LDFLAGS} - +h316 : ${BIN}h316${EXE} ${BIN}h316${EXE} : ${H316} ${SIM} ${CC} ${H316} ${SIM} ${H316_OPT} -o $@ ${LDFLAGS} - +hp2100 : ${BIN}hp2100${EXE} ${BIN}hp2100${EXE} : ${HP2100} ${SIM} ${CC} ${HP2100} ${SIM} ${HP2100_OPT} -o $@ ${LDFLAGS} - +i1401 : ${BIN}i1401${EXE} ${BIN}i1401${EXE} : ${I1401} ${SIM} ${CC} ${I1401} ${SIM} ${I1401_OPT} -o $@ ${LDFLAGS} - +i1620 : ${BIN}i1620${EXE} ${BIN}i1620${EXE} : ${I1620} ${SIM} ${CC} ${I1620} ${SIM} ${I1620_OPT} -o $@ ${LDFLAGS} +i7094 : ${BIN}i7094${EXE} ${BIN}i7094${EXE} : ${I7094} ${SIM} ${CC} ${I7094} ${SIM} ${I7094_OPT} -o $@ ${LDFLAGS} - +ibm1130 : ${BIN}ibm1130${EXE} ${BIN}ibm1130${EXE} : ${IBM1130} ${CC} ${IBM1130} ${SIM} ${IBM1130_OPT} -o $@ ${LDFLAGS} +s3 : ${BIN}s3${EXE} ${BIN}s3${EXE} : ${S3} ${SIM} ${CC} ${S3} ${SIM} ${S3_OPT} -o $@ ${LDFLAGS} +altair : ${BIN}altair${EXE} ${BIN}altair${EXE} : ${ALTAIR} ${SIM} ${CC} ${ALTAIR} ${SIM} ${ALTAIR_OPT} -o $@ ${LDFLAGS} +altairz80 : ${BIN}altairz80${EXE} ${BIN}altairz80${EXE} : ${ALTAIRZ80} ${SIM} ${CC} ${ALTAIRZ80} ${SIM} ${ALTAIRZ80_OPT} -o $@ ${LDFLAGS} +gri : ${BIN}gri${EXE} ${BIN}gri${EXE} : ${GRI} ${SIM} ${CC} ${GRI} ${SIM} ${GRI_OPT} -o $@ ${LDFLAGS} +lgp : ${BIN}lgp${EXE} ${BIN}lgp${EXE} : ${LGP} ${SIM} ${CC} ${LGP} ${SIM} ${LGP_OPT} -o $@ ${LDFLAGS} +id16 : ${BIN}id16${EXE} ${BIN}id16${EXE} : ${ID16} ${SIM} ${CC} ${ID16} ${SIM} ${ID16_OPT} -o $@ ${LDFLAGS} +id32 : ${BIN}id32${EXE} ${BIN}id32${EXE} : ${ID32} ${SIM} ${CC} ${ID32} ${SIM} ${ID32_OPT} -o $@ ${LDFLAGS} +sds : ${BIN}sds${EXE} ${BIN}sds${EXE} : ${SDS} ${SIM} ${CC} ${SDS} ${SIM} ${SDS_OPT} -o $@ ${LDFLAGS} diff --git a/scp.c b/scp.c index aecbc14d..11c7bee2 100644 --- a/scp.c +++ b/scp.c @@ -1,6 +1,6 @@ /* scp.c: simulator control program - Copyright (c) 1993-2006, Robert M Supnik + Copyright (c) 1993-2007, 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,7 +23,12 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 30-Jan-07 RMS Fixed bugs in get_ipaddr + 17-Oct-06 RMS Added idle support + 04-Oct-06 JDB DO cmd failure now echoes cmd unless -q 14-Jul-06 RMS Added sim_activate_abs + 02-Jun-06 JDB Fixed do_cmd to exit nested files on assertion failure + Added -E switch to do_cmd to exit on any error 14-Feb-06 RMS Upgraded save file format to V3.5 18-Jan-06 RMS Added fprint_stopped_gen Added breakpoint spaces @@ -310,7 +315,7 @@ char *read_line (char *ptr, int32 size, FILE *stream); REG *find_reg_glob (char *ptr, char **optr, DEVICE **gdptr); char *sim_trim_endspc (char *cptr); -/* Forward references within commands */ +/* Forward references */ t_stat scp_attach_unit (DEVICE *dptr, UNIT *uptr, char *cptr); t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr); @@ -430,7 +435,7 @@ const char *scp_error_messages[] = { "Console Telnet connection lost", "Console Telnet connection timed out", "Console Telnet output stall", - "" /* printed by assert */ + "Assertion failed" }; const size_t size_map[] = { sizeof (int8), @@ -513,6 +518,10 @@ static CTAB cmd_table[] = { { "BYE", &exit_cmd, 0, NULL }, { "SET", &set_cmd, 0, "set console arg{,arg...} set console options\n" + "set break set breakpoints\n" + "set nobreak clear breakpoints\n" + "set throttle x{M|K|%} set simulation rate\n" + "set nothrottle set simulation rate to maximum\n" "set OCT|DEC|HEX set device display radix\n" "set ENABLED enable device\n" "set DISABLED disable device\n" @@ -524,14 +533,15 @@ static CTAB cmd_table[] = { "set arg{,arg...} set unit parameters\n" }, { "SHOW", &show_cmd, 0, - "sh{ow} br{eak} show breakpoints on address list\n" + "sh{ow} br{eak} show breakpoints\n" "sh{ow} con{figuration} show configuration\n" "sh{ow} cons{ole} {arg} show console options\n" "sh{ow} dev{ices} show devices\n" "sh{ow} m{odifiers} show modifiers\n" "sh{ow} n{ames} show logical names\n" "sh{ow} q{ueue} show event queue\n" - "sh{ow} ti{me} show simulated time\n" + "sh{ow} ti{me} show simulated time\n" + "sh{ow} th{rottle} show simulation rate\n" "sh{ow} ve{rsion} show simulator version\n" "sh{ow} RADIX show device display radix\n" "sh{ow} DEBUG show device debug flags\n" @@ -602,6 +612,7 @@ sim_clock_queue = NULL; sim_is_running = 0; sim_log = NULL; if (sim_emax <= 0) sim_emax = 1; +sim_timer_init (); if ((stat = sim_ttinit ()) != SCPE_OK) { fprintf (stderr, "Fatal terminal initialization error\n%s\n", @@ -628,18 +639,15 @@ if (!sim_quiet) { } if (sim_dflt_dev == NULL) sim_dflt_dev = sim_devices[0]; /* if no default */ -if (*cbuf) { /* cmd file arg? */ +if (*cbuf) /* cmd file arg? */ stat = do_cmd (0, cbuf); /* proc cmd file */ - if (stat == SCPE_OPENERR) /* error? */ - fprintf (stderr, "Can't open file %s\n", cbuf); - } else if (*argv[0]) { /* sim name arg? */ char nbuf[PATH_MAX + 7], *np; /* "path.ini" */ nbuf[0] = '"'; /* starting " */ strncpy (nbuf + 1, argv[0], PATH_MAX + 1); /* copy sim name */ if (np = match_ext (nbuf, "EXE")) *np = 0; /* remove .exe */ strcat (nbuf, ".ini\""); /* add .ini" */ - stat = do_cmd (0, nbuf); /* proc cmd file */ + stat = do_cmd (-1, nbuf); /* proc cmd file */ } while (stat != SCPE_EXIT) { /* in case exit */ @@ -757,19 +765,50 @@ if (sim_log) fprintf (sim_log, "%s\n", cptr); return SCPE_OK; } -/* Do command */ +/* Do command + + Syntax: DO {-E} {-V} {...} + + -E causes all command errors to be fatal; without it, only EXIT and ASSERT + failure will stop a command file. + + -V causes commands to be echoed before execution. + + Note that SCPE_STEP ("Step expired") is considered a note and not an error + and so does not abort command execution when using -E. + + Inputs: + flag = caller and nesting level indicator + fcptr = filename and optional arguments, space-separated + Outputs: + status = error status + + The "flag" input value indicates the source of the call, as follows: + + -1 = initialization file (no error if not found) + 0 = command line file + 1 = "DO" command + >1 = nested "DO" command +*/ + +#define SCPE_DOFAILED 0040000 /* fail in DO, not subproc */ t_stat do_cmd (int32 flag, char *fcptr) { char *cptr, cbuf[CBUFSIZE], gbuf[CBUFSIZE], *c, quote, *do_arg[10]; FILE *fpin; CTAB *cmdp; -int32 echo, nargs; -t_stat stat = SCPE_OK; +int32 echo, nargs, errabort; +t_bool interactive, isdo, staying; +t_stat stat; +char *ocptr; -if (flag > 0) { GET_SWITCHES (fcptr); } /* get switches */ -else flag = 1; /* start at level 1 */ +stat = SCPE_OK; +staying = TRUE; +interactive = (flag > 0); /* issued interactively? */ +if (interactive) { GET_SWITCHES (fcptr); } /* get switches */ echo = sim_switches & SWMASK ('V'); /* -v means echo */ +errabort = sim_switches & SWMASK ('E'); /* -e means abort on error */ c = fcptr; for (nargs = 0; nargs < 10; ) { /* extract arguments */ @@ -782,36 +821,62 @@ for (nargs = 0; nargs < 10; ) { /* extract arguments */ if (*c) *c++ = 0; /* term at quote/spc */ } /* end for */ if (nargs <= 0) return SCPE_2FARG; /* need at least 1 */ -if ((fpin = fopen (do_arg[0], "r")) == NULL) /* cmd file failed to open? */ - return SCPE_OPENERR; +if ((fpin = fopen (do_arg[0], "r")) == NULL) { /* file failed to open? */ + if (flag == 0) /* cmd line file? */ + fprintf (stderr, "Can't open file %s\n", do_arg[0]); + if (flag > 1) + return SCPE_OPENERR | SCPE_DOFAILED; /* return failure with flag */ + else + return SCPE_OPENERR; /* return failure */ + } +if (flag < 1) flag = 1; /* start at level 1 */ do { - cptr = read_line (cbuf, CBUFSIZE, fpin); /* get cmd line */ + ocptr = cptr = read_line (cbuf, CBUFSIZE, fpin); /* get cmd line */ sub_args (cbuf, gbuf, CBUFSIZE, nargs, do_arg); - if (cptr == NULL) break; /* exit on eof */ + if (cptr == NULL) { /* EOF? */ + stat = SCPE_OK; /* set good return */ + break; + } if (*cptr == 0) continue; /* ignore blank */ if (echo) printf("do> %s\n", cptr); /* echo if -v */ if (echo && sim_log) fprintf (sim_log, "do> %s\n", cptr); cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */ sim_switches = 0; /* init switches */ + isdo = FALSE; if (cmdp = find_cmd (gbuf)) { /* lookup command */ - if (cmdp->action == &do_cmd) { /* DO command? */ + isdo = (cmdp->action == &do_cmd); + if (isdo) { /* DO command? */ if (flag >= DO_NEST_LVL) stat = SCPE_NEST; /* nest too deep? */ else stat = do_cmd (flag + 1, cptr); /* exec DO cmd */ } else stat = cmdp->action (cmdp->arg, cptr); /* exec other cmd */ } else stat = SCPE_UNK; /* bad cmd given */ - if (stat >= SCPE_BASE) { /* error? */ + staying = (stat != SCPE_EXIT) && /* decide if staying */ + (stat != SCPE_AFAIL) && + (!errabort || (stat < SCPE_BASE) || (stat == SCPE_STEP)); + if ((stat >= SCPE_BASE) && (stat != SCPE_EXIT) && /* error from cmd? */ + (stat != SCPE_STEP)) { + if (!echo && !sim_quiet && /* report if not echoing */ + (!isdo || (stat & SCPE_DOFAILED))) { /* and not from DO return */ + printf("%s> %s\n", do_arg[0], ocptr); + if (sim_log) + fprintf (sim_log, "%s> %s\n", do_arg[0], ocptr); + } + stat = stat & ~SCPE_DOFAILED; /* remove possible flag */ + } + if ((staying || !interactive) && /* report error if staying */ + (stat >= SCPE_BASE)) { /* or in cmdline file */ printf ("%s\n", scp_error_messages[stat - SCPE_BASE]); if (sim_log) fprintf (sim_log, "%s\n", scp_error_messages[stat - SCPE_BASE]); } if (sim_vm_post != NULL) (*sim_vm_post) (TRUE); - } while ((stat != SCPE_EXIT) && (stat != SCPE_AFAIL)); + } while (staying); fclose (fpin); /* close file */ -return (stat == SCPE_EXIT)? SCPE_EXIT: SCPE_OK; +return stat; } /* Substitute_args - replace %n tokens in 'instr' with the do command's arguments @@ -886,8 +951,6 @@ if (!get_search (gbuf, rptr->radix, &sim_stab)) /* parse condition */ return SCPE_MISVAL; val = get_rval (rptr, idx); /* get register value */ if (test_search (val, &sim_stab)) return SCPE_OK; /* test condition */ -printf ("Assertion failed (%s)", aptr); /* report failing assertion */ -if (sim_log) fprintf (sim_log, "Assertion failed (%s)", aptr); return SCPE_AFAIL; /* condition fails */ } @@ -913,6 +976,8 @@ static CTAB set_glob_tab[] = { { "NOLOG", &sim_set_logoff, 0 }, /* deprecated */ { "DEBUG", &sim_set_debon, 0 }, /* deprecated */ { "NODEBUG", &sim_set_deboff, 0 }, /* deprecated */ + { "THROTTLE", &sim_set_throt, 1 }, + { "NOTHROTTLE", &sim_set_throt, 0 }, { NULL, NULL, 0 } }; @@ -1143,6 +1208,7 @@ static SHTAB show_glob_tab[] = { { "LOG", &sim_show_log, 0 }, /* deprecated */ { "TELNET", &sim_show_telnet, 0 }, /* deprecated */ { "DEBUG", &sim_show_debug, 0 }, /* deprecated */ + { "THROTTLE", &sim_show_throt, 0 }, { NULL, NULL, 0 } }; @@ -2313,6 +2379,7 @@ if ((r = sim_check_console (30)) != SCPE_OK) { /* check console, error? return r; } if (sim_step) sim_activate (&sim_step_unit, sim_step); /* set step timer */ +sim_throt_sched (); /* set throttle */ sim_is_running = 1; /* flag running */ sim_brk_clract (); /* defang actions */ r = sim_instr(); @@ -2321,6 +2388,7 @@ sim_is_running = 0; /* flag idle */ sim_ttcmd (); /* restore console */ signal (SIGINT, SIG_DFL); /* cancel WRU */ sim_cancel (&sim_step_unit); /* cancel step timer */ +sim_throt_cancel (); /* cancel throttle */ if (sim_clock_queue != NULL) { /* update sim time */ UPDATE_SIM_TIME (sim_clock_queue->time); } @@ -3166,7 +3234,7 @@ return tptr; cptr = pointer to input string Outputs: ipa = pointer to IP address (may be NULL), 0 = none - ipp = pointer to IP port (may be NULL) + ipp = pointer to IP port (may be NULL), 0 = none result = status */ @@ -3177,27 +3245,28 @@ char *addrp, *portp, *octetp; uint32 i, addr, port, octet; t_stat r; -if ((cptr == NULL) || (*cptr == 0) || (ipa == NULL) || (ipp == NULL)) +if ((cptr == NULL) || (*cptr == 0)) return SCPE_ARG; strncpy (gbuf, cptr, CBUFSIZE); addrp = gbuf; /* default addr */ -if (portp = strchr (gbuf, ':')) *portp++ = '.'; /* x:y? */ +if (portp = strchr (gbuf, ':')) *portp++ = 0; /* x:y? split */ else if (strchr (gbuf, '.')) portp = NULL; /* x.y...? */ else { portp = gbuf; /* port only */ - addrp = NULL; /* x is port */ + addrp = NULL; /* no addr */ } if (portp) { /* port string? */ + if (ipp == NULL) return SCPE_ARG; /* not wanted? */ port = (int32) get_uint (portp, 10, 65535, &r); if ((r != SCPE_OK) || (port == 0)) return SCPE_ARG; - *ipp = port; } -else *ipp = 0; -if (addrp) { - for (i = addr = 0; i < 4; i++) { - octetp = strchr (addrp, '.'); - if (octetp == NULL) return SCPE_ARG; - *octetp++ = 0; +else port = 0; +if (addrp) { /* addr string? */ + if (ipa == NULL) return SCPE_ARG; /* not wanted? */ + for (i = addr = 0; i < 4; i++) { /* four octets */ + octetp = strchr (addrp, '.'); /* find octet end */ + if (octetp != NULL) *octetp++ = 0; /* split string */ + else if (i < 3) return SCPE_ARG; /* except last */ octet = (int32) get_uint (addrp, 10, 255, &r); if (r != SCPE_OK) return SCPE_ARG; addr = (addr << 8) | octet; @@ -3205,9 +3274,10 @@ if (addrp) { } if (((addr & 0377) == 0) || ((addr & 0377) == 255)) return SCPE_ARG; - *ipa = addr; } -else *ipa = 0; +else addr = 0; +if (ipp) *ipp = port; /* return req values */ +if (ipa) *ipa = addr; return SCPE_OK; } @@ -3629,7 +3699,8 @@ nodigit = 1; for (c = *inptr; isalnum(c); c = *++inptr) { /* loop through char */ if (islower (c)) c = toupper (c); if (isdigit (c)) digit = c - (uint32) '0'; /* digit? */ - else digit = c + 10 - (uint32) 'A'; /* no, letter */ + else if (radix <= 10) break; /* stop if not expected */ + else digit = c + 10 - (uint32) 'A'; /* convert letter */ if (digit >= radix) return 0; /* valid in radix? */ val = (val * radix) + digit; /* add to value */ nodigit = 0; @@ -3844,7 +3915,10 @@ int32 accum; accum = 0; for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr->next) { - accum = accum + cptr->time; + if (cptr == sim_clock_queue) { + if (sim_interval > 0) accum = accum + sim_interval; + } + else accum = accum + cptr->time; if (cptr == uptr) return accum + 1; } return 0; diff --git a/scp.h b/scp.h index ed7c02aa..026e74bb 100644 --- a/scp.h +++ b/scp.h @@ -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. + 09-Aug-06 JDB Added assign_device and deassign_device 14-Jul-06 RMS Added sim_activate_abs 06-Jan-06 RMS Added fprint_stopped_gen Changed arg type in sim_brk_test @@ -85,6 +86,8 @@ uint32 sim_grtime (void); int32 sim_qcount (void); t_stat attach_unit (UNIT *uptr, char *cptr); t_stat detach_unit (UNIT *uptr); +t_stat assign_device (DEVICE *dptr, char *cptr); +t_stat deassign_device (DEVICE *dptr); t_stat reset_all (uint32 start_device); t_stat reset_all_p (uint32 start_device); char *sim_dname (DEVICE *dptr); diff --git a/sim_console.c b/sim_console.c index 9704c13e..6388c2c4 100644 --- a/sim_console.c +++ b/sim_console.c @@ -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. + 30-Sep-06 RMS Fixed non-printable characters in KSR mode 22-Jun-06 RMS Implemented SET/SHOW PCHAR 31-May-06 JDB Fixed bug if SET CONSOLE DEBUG with no argument 22-Nov-05 RMS Added central input/output conversion support @@ -474,7 +475,11 @@ uint32 md = mode & TTUF_M_MODE; if (md != TTUF_MODE_8B) { c = c & 0177; - if ((md == TTUF_MODE_UC) && islower (c)) c = toupper (c); + if (md == TTUF_MODE_UC) { + if (islower (c)) c = toupper (c); + if ((mode & TTUF_KSR) && (c >= 0140)) + return -1; + } if (((md == TTUF_MODE_UC) || (md == TTUF_MODE_7P)) && ((c == 0177) || ((c < 040) && !((sim_tt_pchar >> c) & 1)))) diff --git a/sim_defs.h b/sim_defs.h index 7c618861..a80fba13 100644 --- a/sim_defs.h +++ b/sim_defs.h @@ -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. + 18-Oct-06 RMS Added limit check for clock synchronized keyboard waits 13-Jul-06 RMS Guarantee CBUFSIZE is at least 256 07-Jan-06 RMS Added support for breakpoint spaces Added REG_FIT flag @@ -243,9 +244,12 @@ typedef uint32 t_addr; /* Default timing parameters */ #define KBD_POLL_WAIT 5000 /* keyboard poll */ +#define KBD_MAX_WAIT 500000 #define SERIAL_IN_WAIT 100 /* serial in time */ #define SERIAL_OUT_WAIT 100 /* serial output */ #define NOQUEUE_WAIT 10000 /* min check time */ +#define KBD_LIM_WAIT(x) (((x) > KBD_MAX_WAIT)? KBD_MAX_WAIT: (x)) +#define KBD_WAIT(w,s) ((w)? w: KBD_LIM_WAIT (s)) /* Convert switch letter to bit mask */ diff --git a/sim_ether.c b/sim_ether.c index 1010b1f9..d0843c31 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -135,6 +135,7 @@ Modification history: 10-Jul-06 RMS Fixed linux conditionalization (from Chaskiel Grundman) + 02-Jun-06 JDB Fixed compiler warning for incompatible sscanf parameter 15-Dec-05 DTH Patched eth_host_devices [remove non-ethernet devices] (from Mark Pizzolato and Galen Tackett, 08-Jun-05) Patched eth_open [tun fix](from Antal Ritter, 06-Oct-05) @@ -243,7 +244,7 @@ extern FILE *sim_log; t_stat eth_mac_scan (ETH_MAC* mac, char* strmac) { int i, j; - short int num; + short unsigned int num; char cptr[18]; int len = strlen(strmac); const ETH_MAC zeros = {0,0,0,0,0,0}; diff --git a/sim_rev.h b/sim_rev.h index af6079ee..0c22c146 100644 --- a/sim_rev.h +++ b/sim_rev.h @@ -28,13 +28,175 @@ #define _SIM_REV_H_ 0 #define SIM_MAJOR 3 -#define SIM_MINOR 6 -#define SIM_PATCH 1 +#define SIM_MINOR 7 +#define SIM_PATCH 0 -/* V3.6 revision history +/* V3.7 revision history patch date module(s) and fix(es) + 0 30-Jan-07 scp.c: + - implemented throttle commands + - added -e to control error processing in DO command files + (from Dave Bryan) + + sim_console.c: + - fixed handling of non-printable characters in KSR mode + + sim_tape.c: + - fixed bug in reverse operations for P7B-format tapes + - fixed bug in reverse operations across erase gaps + + sim_timer.c: + - added throttle support + - added idle support (based on work by Mark Pizzolato) + + gri_stddev.c, h316_stddev.c, pdp18b_tt1.c + - fixed handling of non-printable characters in KSR mode + + hp2100_cpu.c, hp2100_cpu0.c, hp2100_cpu1.c, hp2100_cpu2.c, + hp2100_cpu3.c, hp2100_cpu4.c (from Dave Bryan): + - reorganized CPU modules for easier addition of new instructions + - added Double Integer instructions, 1000-F CPU, 2114 and + 2115 CPUs, 12K and 24K memory sizes, 12607B and 12578A DMA + controllers, and 21xx binary loader protection + - fixed DMS self-test instruction execution on 1000-M + - fixed indirect interrupt holdoff logic + + hp2100_ds.c: + - fixed REQUEST STATUS to clear status-1 (from Dave Bryan) + + hp2100_fp1.c: + - Added Floating Point Processor (from Dave Bryan) + + hp2100_lps.c: + - fixed diag-mode CLC response + + i7094_cpu.c: + - fixed new bug in halt IO wait loop + - added IFT, EFT expanded core test instructions + + id16_cpu.c, id32_cpu.c: + - removed separate multiplexor clock + - added idle support + + id_pas.c: + - synced multiplexor poll to real-time clock + + id_tt.c, id_ttp.c: + - fixed handling of non-printable characters in KSR mode + - synced keyboard poll to real-time clock + + id_uvc.c: + - changed line-time clock to be free-running + + pdp1_cpu.c: + - added 16-channel sequence break system (API) support + - added PDP-1D support + + pdp1_clk.c: + - first release + + pdp1_dcs.c: + - first release + + pdp1_stddev.c: + - separated TTI, TTO for API support + + pdp1_sys.c: + - added PDP-1D, 16-channel SBS, clock, DCS support + - fixed bugs in character input, block loader + + pdp10_cpu.c: + - added idle support + + pdp10_defs.h, pdp10_sys.c: + - added CR support + + pdp10_fe.c, pdp10_tim.c: + - synced keyboard poll to real-time clock + + pdp11_cr.c: + - revised for PDP-10 compatibility (CD11 only) + + pdp11_cpu.c: + - added idle support + - fixed bug in ASH -32 C value + + pdp11_rf.c: + - fixed unit mask (found by John Dundas) + + pdp11_stddev.c, vax_stddev.c, vax780_stddev.c: + - synced keyboard poll to real-time clock + - added clock coscheduling support + + pdp11_ta.c: + - first release + + pdp11_vh.c: + - synced service poll to real-time clock + - changed device to be off by default + + pdp11_dz.c, pdp11_xq.c, pdp11_xu.c: + - synced service poll to real-time clock + + pdp11_sys.c: + - fixed operand order in EIS instructions (found by W.F.J. Mueller) + - added TA11 support + + pdp18b_cpu.c: + - fixed incorrect value of PC on instruction fetch mem mmgt error + - fixed PDP-15 handling of mem mmgt traps (sets API 3) + - fixed PDP-15 handling of CAL API 4 (sets only if 0-3 inactive) + - fixed PDP-15 CAF to clear memory management mode register + - fixed boundary test in KT15/XVM (reported by Andrew Warkentin) + - added XVM RDCLK instruction + - added idle support and infinite loop detection + + pdp18b_rf.c: + - fixed bug, DSCD does not clear function register + + pdp18b_stddev.c: + - added PDP-15 program-selectable duplex handling instruction + - fixed PDP-15 handling of reader out-of-tape + - fixed handling of non-printable characters in KSR mode + - added XVM RDCLK instruction + - changed real-time clock to be free running + - synced keyboard poll to real-time clock + + pdp18b_tt1.c + - fixed handling of non-printable characters in KSR mode + + pdp18b_sys.c: + - added XVM RDCLK instruction + + pdp8_cpu.c: + - fixed SC value after DVI overflow (found by Don North) + - added idle support and infinite loop detection + + pdp8_ct.c: + - first release + + pdp8_clk.c: + - changed real-time clock to be free running + + pdp8_sys.c: + - added TA8E support + - added ability to disambiguate overlapping IOT definitions + + pdp8_tt.c: + - fixed handling of non-printable characters in KSR mode + - synced keyboard poll to real-time clock + + vax_cpu.c, vax_cpu1.c: + - added idle support + + vax_syscm.c: + - fixed operand order in EIS instructions (found by W.F.J. Mueller) + + +/* V3.6 revision history + 1 25-Jul-06 sim_console.c: - implemented SET/SHOW PCHAR diff --git a/sim_tape.c b/sim_tape.c index b5e2d80f..b53cc06d 100644 --- a/sim_tape.c +++ b/sim_tape.c @@ -1,6 +1,6 @@ /* sim_tape.c: simulator tape support library - Copyright (c) 1993-2006, Robert M Supnik + Copyright (c) 1993-2007, 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"), @@ -26,6 +26,10 @@ Ultimately, this will be a place to hide processing of various tape formats, as well as OS-specific direct hardware access. + 23-Jan-07 JDB Fixed backspace over gap at BOT + 22-Jan-07 RMS Fixed bug in P7B format read reclnt rev (found by Rich Cornwell) + 15-Dec-06 RMS Added support for small capacity tapes + 30-Aug-06 JDB Added erase gap support 14-Feb-06 RMS Added variable tape capacity 23-Jan-06 JDB Fixed odd-byte-write problem in sim_tape_wrrecf 17-Dec-05 RMS Added write support for Paul Pierce 7b format @@ -48,6 +52,7 @@ sim_tape_sprecr space tape record reverse sim_tape_wrtmk write tape mark sim_tape_wreom erase remainder of tape + sim_tape_wrgap write erase gap sim_tape_rewind rewind sim_tape_reset reset unit sim_tape_bot TRUE if at beginning of tape @@ -165,6 +170,8 @@ return SCPE_OK; end of file/medium unchanged, PNU set tape mark updated data record updated, sim_fread will read record forward + + See notes at "sim_tape_wrgap" regarding erase gap implementation. */ t_stat sim_tape_rdlntf (UNIT *uptr, t_mtrlnt *bc) @@ -181,20 +188,28 @@ sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set tape pos */ switch (f) { /* switch on fmt */ case MTUF_F_STD: case MTUF_F_E11: - sim_fread (bc, sizeof (t_mtrlnt), 1, uptr->fileref); /* read rec lnt */ - sbc = MTR_L (*bc); /* save rec lnt */ - if (ferror (uptr->fileref)) { /* error? */ - MT_SET_PNU (uptr); /* pos not upd */ - return sim_tape_ioerr (uptr); + do { + sim_fread (bc, sizeof (t_mtrlnt), 1, uptr->fileref); /* read rec lnt */ + sbc = MTR_L (*bc); /* save rec lnt */ + if (ferror (uptr->fileref)) { /* error? */ + MT_SET_PNU (uptr); /* pos not upd */ + return sim_tape_ioerr (uptr); + } + if (feof (uptr->fileref) || (*bc == MTR_EOM)) { /* eof or eom? */ + MT_SET_PNU (uptr); /* pos not upd */ + return MTSE_EOM; + } + uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* spc over rec lnt */ + if (*bc == MTR_TMK) return MTSE_TMK; /* tape mark? */ + if (*bc == MTR_FHGAP) { /* half gap? */ + uptr->pos = uptr->pos + sizeof (t_mtrlnt) / 2; /* half space fwd */ + sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* resync */ + } + else if (*bc != MTR_GAP) + uptr->pos = uptr->pos + sizeof (t_mtrlnt) + /* spc over record */ + ((f == MTUF_F_STD)? ((sbc + 1) & ~1): sbc); } - if (feof (uptr->fileref) || (*bc == MTR_EOM)) { /* eof or eom? */ - MT_SET_PNU (uptr); /* pos not upd */ - return MTSE_EOM; - } - uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* spc over rec lnt */ - if (*bc == MTR_TMK) return MTSE_TMK; /* tape mark? */ - uptr->pos = uptr->pos + sizeof (t_mtrlnt) + /* spc over record */ - ((f == MTUF_F_STD)? ((sbc + 1) & ~1): sbc); + while ((*bc == MTR_GAP) || (*bc == MTR_FHGAP)); break; case MTUF_F_TPC: @@ -257,6 +272,8 @@ return MTSE_OK; end of medium updated tape mark updated data record updated, sim_fread will read record forward + + See notes at "sim_tape_wrgap" regarding erase gap implementation. */ t_stat sim_tape_rdlntr (UNIT *uptr, t_mtrlnt *bc) @@ -274,18 +291,29 @@ if (sim_tape_bot (uptr)) return MTSE_BOT; /* at BOT? */ switch (f) { /* switch on fmt */ case MTUF_F_STD: case MTUF_F_E11: - sim_fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt), SEEK_SET); - sim_fread (bc, sizeof (t_mtrlnt), 1, uptr->fileref); /* read rec lnt */ - sbc = MTR_L (*bc); - if (ferror (uptr->fileref)) /* error? */ - return sim_tape_ioerr (uptr); - if (feof (uptr->fileref)) return MTSE_EOM; /* eof? */ - uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over rec lnt */ - if (*bc == MTR_EOM) return MTSE_EOM; /* eom? */ - if (*bc == MTR_TMK) return MTSE_TMK; /* tape mark? */ - uptr->pos = uptr->pos - sizeof (t_mtrlnt) - /* spc over record */ - ((f == MTUF_F_STD)? ((sbc + 1) & ~1): sbc); - sim_fseek (uptr->fileref, uptr->pos + sizeof (t_mtrlnt), SEEK_SET); + do { + sim_fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt), SEEK_SET); + sim_fread (bc, sizeof (t_mtrlnt), 1, uptr->fileref); /* read rec lnt */ + sbc = MTR_L (*bc); + if (ferror (uptr->fileref)) /* error? */ + return sim_tape_ioerr (uptr); + if (feof (uptr->fileref)) return MTSE_EOM; /* eof? */ + uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over rec lnt */ + if (*bc == MTR_EOM) return MTSE_EOM; /* eom? */ + if (*bc == MTR_TMK) return MTSE_TMK; /* tape mark? */ + if ((*bc & MTR_M_RHGAP) == MTR_RHGAP) { /* half gap? */ + uptr->pos = uptr->pos + sizeof (t_mtrlnt) / 2; /* half space rev */ + sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* resync */ + } + else if (*bc != MTR_GAP) { + uptr->pos = uptr->pos - sizeof (t_mtrlnt) - /* spc over record */ + ((f == MTUF_F_STD)? ((sbc + 1) & ~1): sbc); + sim_fseek (uptr->fileref, uptr->pos + sizeof (t_mtrlnt), SEEK_SET); + } + else if (sim_tape_bot (uptr)) /* backed into BOT? */ + return MTSE_BOT; + } + while ((*bc == MTR_GAP) || (*bc == MTR_RHGAP)); break; case MTUF_F_TPC: @@ -312,6 +340,7 @@ switch (f) { /* switch on fmt */ if (c & P7B_SOR) break; /* start of record? */ } uptr->pos = uptr->pos - sbc; /* update position */ + *bc = sbc; /* save rec lnt */ sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* for read */ if (all_eof) return MTSE_TMK; /* tape mark? */ break; @@ -432,9 +461,10 @@ uint32 f = MT_GET_FMT (uptr); t_mtrlnt sbc; MT_CLR_PNU (uptr); +sbc = MTR_L (bc); if ((uptr->flags & UNIT_ATT) == 0) return MTSE_UNATT; /* not attached? */ if (sim_tape_wrp (uptr)) return MTSE_WRP; /* write prot? */ -sbc = MTR_L (bc); +if (sbc == 0) return MTSE_OK; /* nothing to do? */ sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set pos */ switch (f) { /* case on format */ @@ -502,6 +532,232 @@ if (MT_GET_FMT (uptr) == MTUF_F_P7B) return MTSE_FMT; /* cant do P7B */ return sim_tape_wrdata (uptr, MTR_EOM); } +/* Write erase gap + + Inputs: + uptr = pointer to tape unit + gaplen = length of gap in tenths of an inch + bpi = current recording density in bytes per inch + + Outputs: + status = operation status + + exit condition position + ------------------ ------------------ + unit unattached unchanged + unsupported format unchanged + write protected unchanged + read error unchanged, PNU set + write error unchanged, PNU set + gap written updated + + + An erase gap is represented in the tape image file by a special metadata + value. This value is chosen so that it is still recognizable even if it has + been "cut in half" by a subsequent data overwrite that does not end on a + metadatum-sized boundary. In addition, a range of metadata values are + reserved for detection in the reverse direction. Erase gaps are supported + only in SIMH tape format. + + This implementation supports erasing gaps in the middle of a populated tape + image and will always produce a valid image. It also produces valid images + when overwriting gaps with data records, with one exception: a data write + that leaves only two bytes of gap remaining will produce an invalid tape. + This limitation is deemed acceptable, as it is analogous to the existing + limitation that data records cannot overwrite other data records without + producing an invalid tape. + + Because SIMH tape images do not carry physical parameters (e.g., recording + density), overwriting a tape image file containing gap metadata is + problematic if the density setting is not the same as that used during + recording. There is no way to establish a gap of a certain length + unequivocally in an image file, so this implementation establishes a gap of a + certain number of bytes that reflect the desired gap length at the bpi used + during writing. + + To write an erase gap, the implementation uses one of two approaches, + depending on whether or not the current tape position is at EOM. Erasing at + EOM presents no special difficulties; gap metadata markers are written for + the prescribed number of bytes. If the tape is not at EOM, then erasing must + take into account the existing record structure to ensure that a valid tape + image is maintained. + + The general approach is to erase for the nominal number of bytes but to + increase that length, if necessary, to ensure that a partially overwritten + data record at the end of the gap can be altered to maintain validity. + Because the smallest legal tape record requires space for two metadata + markers plus two data bytes, an erasure that would leave less than that + is increased to consume the entire record. Otherwise, the final record is + truncated appropriately. + + When reading in either direction, gap metadata markers are ignored (skipped) + until a record length header, EOF marker, EOM marker, or physical EOF is + encountered. Thus, tape images containing gap metadata are transparent to + the calling simulator. + + The permissibility of data record lengths that are not multiples of the + metadatum size presents a difficulty when reading. If such an "odd length" + record is written over a gap, half of a metadata marker will exist + immediately after the trailing record length. + + This condition is detected when reading forward by the appearance of a + "reversed" marker. The value appears reversed because the value is made up + of half of one marker and half of the next. This is handled by seeking + forward two bytes to resync (the stipulation above that the overwrite cannot + leave only two bytes of gap means that at least one "whole" metadata marker + will follow). Reading in reverse presents a more complex problem, because + half of the marker is from the preceding trailing record length marker and + therefore could be any of a range of values. However, that range is + restricted by the SIMH tape specification requirement that record length + metadata values must have bits 30:24 set to zero. This allows unambiguous + detection of the condition. + + The value chosen for gap metadata and the values reserved for "half-gap" + detection are: + + 0xFFFFFFFE - primary gap value + 0xFFFEFFFF - reserved (indicates half-gap in forward reads) + 0xFFFF0000:0xFFFF00FF - reserved (indicates half-gap in reverse reads) + 0xFFFF8000:0xFFFF80FF - reserved (indicates half-gap in reverse reads) + */ + +t_stat sim_tape_wrgap (UNIT *uptr, uint32 gaplen, uint32 bpi) +{ +t_stat st; +t_mtrlnt meta, sbc, new_len, rec_size; +t_addr gap_pos = uptr->pos; +uint32 file_size, marker_count; +uint32 format = MT_GET_FMT (uptr); +uint32 gap_alloc = 0; /* gap allocated from tape */ +int32 gap_needed = (gaplen * bpi) / 10; /* gap remainder still needed */ +const uint32 meta_size = sizeof (t_mtrlnt); /* bytes per metadatum */ +const uint32 min_rec_size = 2 + sizeof (t_mtrlnt) * 2; /* smallest data record size */ + +MT_CLR_PNU (uptr); + +if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ + return MTSE_UNATT; +if (format != MTUF_F_STD) /* not SIMH fmt? */ + return MTSE_FMT; +if (sim_tape_wrp (uptr)) /* write protected? */ + return MTSE_WRP; + +file_size = sim_fsize (uptr->fileref); /* get file size */ +sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* position tape */ + +/* Read tape records and allocate to gap until amount required is consumed. + + Read next metadatum from tape: + - EOF or EOM: allocate remainder of bytes needed. + - TMK or GAP: allocate sizeof(metadatum) bytes. + - Reverse GAP: allocate sizeof(metadatum) / 2 bytes. + - Data record: see below. + + Loop until bytes needed = 0. +*/ + +do { + sim_fread (&meta, meta_size, 1, uptr->fileref); /* read metadatum */ + + if (ferror (uptr->fileref)) { /* read error? */ + uptr->pos = gap_pos; /* restore original position */ + MT_SET_PNU (uptr); /* position not updated */ + return sim_tape_ioerr (uptr); /* translate error */ + } + else + uptr->pos = uptr->pos + meta_size; /* move tape over datum */ + + if (feof (uptr->fileref) || (meta == MTR_EOM)) { /* at eof or eom? */ + gap_alloc = gap_alloc + gap_needed; /* allocate remainder */ + gap_needed = 0; + } + + else if ((meta == MTR_GAP) || (meta == MTR_TMK)) { /* gap or tape mark? */ + gap_alloc = gap_alloc + meta_size; /* allocate marker space */ + gap_needed = gap_needed - meta_size; /* reduce requirement */ + } + + else if (meta == MTR_FHGAP) { /* half gap? */ + uptr->pos = uptr->pos - meta_size / 2; /* backup to resync */ + sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* position tape */ + gap_alloc = gap_alloc + meta_size / 2; /* allocate marker space */ + gap_needed = gap_needed - meta_size / 2; /* reduce requirement */ + } + + else if (uptr->pos + + MTR_L (meta) + meta_size > file_size) { /* rec len out of range? */ + gap_alloc = gap_alloc + gap_needed; /* presume overwritten tape */ + gap_needed = 0; /* allocate remainder */ + } + +/* Allocate a data record: + - Determine record size in bytes (including metadata) + - If record size - bytes needed < smallest allowed record size, + allocate entire record to gap, else allocate needed amount and + truncate data record to reflect remainder. +*/ + else { /* data record */ + sbc = MTR_L (meta); /* get record data length */ + rec_size = ((sbc + 1) & ~1) + meta_size * 2; /* overall size in bytes */ + + if (rec_size < gap_needed + min_rec_size) { /* rec too small? */ + uptr->pos = uptr->pos - meta_size + rec_size; /* position past record */ + sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* move tape */ + gap_alloc = gap_alloc + rec_size; /* allocate record */ + gap_needed = gap_needed - rec_size; /* reduce requirement */ + } + + else { /* record size OK */ + uptr->pos = uptr->pos - meta_size + gap_needed; /* position to end of gap */ + new_len = MTR_F (meta) | (sbc - gap_needed); /* truncate to new len */ + st = sim_tape_wrdata (uptr, new_len); /* write new rec len */ + + if (st != MTSE_OK) { /* write OK? */ + uptr->pos = gap_pos; /* restore orig pos */ + return st; /* PNU was set by wrdata */ + } + + uptr->pos = uptr->pos + sbc - gap_needed; /* position to end of data */ + st = sim_tape_wrdata (uptr, new_len); /* write new rec len */ + + if (st != MTSE_OK) { /* write OK? */ + uptr->pos = gap_pos; /* restore orig pos */ + return st; /* PNU was set by wrdata */ + } + + gap_alloc = gap_alloc + gap_needed; /* allocate remainder */ + gap_needed = 0; + } + } + } +while (gap_needed > 0); + +uptr->pos = gap_pos; /* reposition to gap start */ + +if (gap_alloc & (meta_size - 1)) { /* gap size "odd?" */ + st = sim_tape_wrdata (uptr, MTR_FHGAP); /* write half gap marker */ + if (st != MTSE_OK) { /* write OK? */ + uptr->pos = gap_pos; /* restore orig pos */ + return st; /* PNU was set by wrdata */ + } + uptr->pos = uptr->pos - meta_size / 2; /* realign position */ + gap_alloc = gap_alloc - 2; /* decrease gap to write */ + } + +marker_count = gap_alloc / meta_size; /* count of gap markers */ + +do { + st = sim_tape_wrdata (uptr, MTR_GAP); /* write gap markers */ + if (st != MTSE_OK) { /* write OK? */ + uptr->pos = gap_pos; /* restore orig pos */ + return st; /* PNU was set by wrdata */ + } + } +while (--marker_count > 0); + +return MTSE_OK; +} + /* Space record forward */ t_stat sim_tape_sprecf (UNIT *uptr, t_mtrlnt *bc) @@ -669,7 +925,13 @@ return SCPE_OK; t_stat sim_tape_show_capac (FILE *st, UNIT *uptr, int32 val, void *desc) { -if (uptr->capac) fprintf (st, "capacity=%dMB", (uint32) (uptr->capac / ((t_addr) 1000000))); +if (uptr->capac) { + if (uptr->capac >= (t_addr) 1000000) + fprintf (st, "capacity=%dMB", (uint32) (uptr->capac / ((t_addr) 1000000))); + else if (uptr->capac >= (t_addr) 1000) + fprintf (st, "capacity=%dKB", (uint32) (uptr->capac / ((t_addr) 1000))); + else fprintf (st, "capacity=%dB", (uint32) uptr->capac); + } else fprintf (st, "unlimited capacity"); return SCPE_OK; } diff --git a/sim_tape.h b/sim_tape.h index ccfbab61..dfaadce5 100644 --- a/sim_tape.h +++ b/sim_tape.h @@ -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. + 30-Aug-06 JDB Added erase gap support 14-Feb-06 RMS Added variable tape capacity 17-Dec-05 RMS Added write support for Paul Pierce 7b format 02-May-05 RMS Added support for Paul Pierce 7b format @@ -37,6 +38,11 @@ typedef uint32 t_mtrlnt; /* magtape rec lnt */ #define MTR_TMK 0x00000000 /* tape mark */ #define MTR_EOM 0xFFFFFFFF /* end of medium */ +#define MTR_GAP 0xFFFFFFFE /* primary gap */ +#define MTR_FHGAP 0xFFFEFFFF /* fwd half gap (overwrite) */ +#define MTR_RHGAP 0xFFFF0000 /* rev half gap (overwrite) */ +#define MTR_M_RHGAP (~0x000080FF) /* range mask for rev gap */ +#define MTR_MAXLEN 0x00FFFFFF /* max len is 24b */ #define MTR_ERF 0x80000000 /* error flag */ #define MTR_F(x) ((x) & MTR_ERF) /* record error flg */ #define MTR_L(x) ((x) & ~MTR_ERF) /* record length */ @@ -107,6 +113,7 @@ t_stat sim_tape_rdrecr (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max); t_stat sim_tape_wrrecf (UNIT *uptr, uint8 *buf, t_mtrlnt bc); t_stat sim_tape_wrtmk (UNIT *uptr); t_stat sim_tape_wreom (UNIT *uptr); +t_stat sim_tape_wrgap (UNIT *uptr, uint32 gaplen, uint32 bpi); t_stat sim_tape_sprecf (UNIT *uptr, t_mtrlnt *bc); t_stat sim_tape_sprecr (UNIT *uptr, t_mtrlnt *bc); t_stat sim_tape_rewind (UNIT *uptr); diff --git a/sim_timer.c b/sim_timer.c index e136de4c..b7ba926c 100644 --- a/sim_timer.c +++ b/sim_timer.c @@ -1,6 +1,6 @@ /* sim_timer.c: simulator timer library - Copyright (c) 1993-2005, Robert M Supnik + Copyright (c) 1993-2006, 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,21 +23,45 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 17-Oct-06 RMS Added idle support (based on work by Mark Pizzolato) + Added throttle support 21-Aug-05 RMS Added sim_rtcn_init_all 16-Aug-05 RMS Fixed C++ declaration and cast problems 02-Jan-04 RMS Split out from SCP This library includes the following routines: + sim_timer_init - initialize timing system sim_rtc_init - initialize calibration sim_rtc_calb - calibrate clock + sim_timer_init - initialize timing system + sim_idle - virtual machine idle sim_os_msec - return elapsed time in msec sim_os_sleep - sleep specified number of seconds + sim_os_ms_sleep - sleep specified number of milliseconds - The calibration routines are OS-independent; the _os_ routines are not + The calibration, idle, and throttle routines are OS-independent; the _os_ + routines are not. */ #include "sim_defs.h" +#include + +t_bool sim_idle_enab = FALSE; /* global flag */ + +static uint32 sim_idle_rate_ms = 0; +static uint32 sim_throt_ms_start = 0; +static uint32 sim_throt_ms_stop = 0; +static uint32 sim_throt_type = 0; +static uint32 sim_throt_val = 0; +static uint32 sim_throt_state = 0; +static int32 sim_throt_wait = 0; +extern int32 sim_interval, sim_switches; +extern FILE *sim_log; + +t_stat sim_throt_svc (UNIT *uptr); + +UNIT sim_throt_unit = { UDATA (&sim_throt_svc, 0, 0) }; /* OS-dependent timer and clock routines */ @@ -45,7 +69,7 @@ #if defined (VMS) -#if defined(__VAX) +#if defined (__VAX) #define sys$gettim SYS$GETTIM #endif @@ -86,6 +110,28 @@ sleep (sec); return; } +uint32 sim_os_ms_sleep_init (void) +{ +#if defined (__VAX) +return 10; /* VAX/VMS is 10ms */ +#else +return 1; /* Alpha/VMS is 1ms */ +#endif +} + +uint32 sim_os_ms_sleep (unsigned int msec) +{ +uint32 stime = sim_os_msec (); +uint32 qtime[2]; +int32 nsfactor = -10000; +static int32 zero = 0; + +lib$emul (&msec, &nsfactor, &zero, qtime); +sys$setimr (2, qtime, 0, 0); +sys$waitfr (2); +return sim_os_msec () - stime; +} + /* Win32 routines */ #elif defined (_WIN32) @@ -96,7 +142,8 @@ const t_bool rtc_avail = TRUE; uint32 sim_os_msec () { -return GetTickCount (); +if (sim_idle_rate_ms) return timeGetTime (); +else return GetTickCount (); } void sim_os_sleep (unsigned int sec) @@ -105,6 +152,39 @@ Sleep (sec * 1000); return; } +void sim_timer_exit (void) +{ +timeEndPeriod (sim_idle_rate_ms); +return; +} + +uint32 sim_os_ms_sleep_init (void) +{ +TIMECAPS timers; + +if (timeGetDevCaps (&timers, sizeof (timers)) != TIMERR_NOERROR) + return 0; +if ((timers.wPeriodMin == 0) || (timers.wPeriodMin > SIM_IDLE_MAX)) + return 0; +if (timeBeginPeriod (timers.wPeriodMin) != TIMERR_NOERROR) + return 0; +atexit (sim_timer_exit); +Sleep (1); +Sleep (1); +Sleep (1); +Sleep (1); +Sleep (1); +return timers.wPeriodMin; /* sim_idle_rate_ms */ +} + +uint32 sim_os_ms_sleep (unsigned int msec) +{ +uint32 stime = sim_os_msec(); + +Sleep (msec); +return sim_os_msec () - stime; +} + /* OS/2 routines, from Bruce Ray */ #elif defined (__OS2__) @@ -121,6 +201,16 @@ void sim_os_sleep (unsigned int sec) return; } +t_bool sim_os_ms_sleep_init (void) +{ +return FALSE; +} + +uint32 sim_os_ms_sleep (unsigned int msec) +{ +return 0; +} + /* Metrowerks CodeWarrior Macintosh routines, from Ben Supnik */ #elif defined (__MWERKS__) && defined (macintosh) @@ -130,6 +220,8 @@ return; #include #include #include +#define NANOS_PER_MILLI 1000000 +#define MILLIS_PER_SEC 1000 const t_bool rtc_avail = TRUE; @@ -151,12 +243,32 @@ sleep (sec); return; } +uint32 sim_os_ms_sleep_init (void) +{ +return 1; +} + +uint32 sim_os_ms_sleep (unsigned int milliseconds) +{ +uint32 stime = sim_os_msec (); +struct timespec treq; + +treq.tv_sec = milliseconds / MILLIS_PER_SEC; +treq.tv_nsec = (milliseconds % MILLIS_PER_SEC) * NANOS_PER_MILLI; +(void) nanosleep (&treq, NULL); +return sim_os_msec () - stime; +} + #else /* UNIX routines */ +#include #include #include +#define NANOS_PER_MILLI 1000000 +#define MILLIS_PER_SEC 1000 +#define sleep1Samples 100 const t_bool rtc_avail = TRUE; @@ -177,11 +289,54 @@ sleep (sec); return; } +uint32 sim_os_ms_sleep_init (void) +{ +#if defined (_POSIX_SOURCE) /* POSIX-compliant */ + +struct timespec treq; +uint32 msec; + +if (clock_getres (CLOCK_REALTIME, &treq) != 0) + return 0; +msec = (treq.tv_nsec + (NANOS_PER_MILLI >> 1)) / NANOS_PER_MILLI; +if (msec > SIM_IDLE_MAX) return 0; +return msec; + +#else /* others */ + +uint32 i, t1, t2, tot, tim; + +for (i = 0, tot = 0; i < sleep1Samples; i++) { + t1 = sim_os_msec (); + sim_os_ms_sleep (1); + t2 = sim_os_msec (); + tot += (t2 - t1); + } +tim = (tot + (sleep1Samples - 1)) / sleep1Samples; +if (tim == 0) tim = 1; +else if (tim > SIM_IDLE_MAX) tim = 0; +return tim; + +#endif +} + +uint32 sim_os_ms_sleep (unsigned int milliseconds) +{ +uint32 stime = sim_os_msec (); +struct timespec treq; + +treq.tv_sec = milliseconds / MILLIS_PER_SEC; +treq.tv_nsec = (milliseconds % MILLIS_PER_SEC) * NANOS_PER_MILLI; +(void) nanosleep (&treq, NULL); +return sim_os_msec () - stime; +} + #endif /* OS independent clock calibration package */ static int32 rtc_ticks[SIM_NTIMERS] = { 0 }; /* ticks */ +static int32 rtc_hz[SIM_NTIMERS] = { 0 }; /* tick rate */ static uint32 rtc_rtime[SIM_NTIMERS] = { 0 }; /* real time */ static uint32 rtc_vtime[SIM_NTIMERS] = { 0 }; /* virtual time */ static uint32 rtc_nxintv[SIM_NTIMERS] = { 0 }; /* next interval */ @@ -197,6 +352,7 @@ rtc_rtime[tmr] = sim_os_msec (); rtc_vtime[tmr] = rtc_rtime[tmr]; rtc_nxintv[tmr] = 1000; rtc_ticks[tmr] = 0; +rtc_hz[tmr] = 0; rtc_based[tmr] = time; rtc_currd[tmr] = time; rtc_initd[tmr] = time; @@ -209,6 +365,7 @@ uint32 new_rtime, delta_rtime; int32 delta_vtime; if ((tmr < 0) || (tmr >= SIM_NTIMERS)) return 10000; +rtc_hz[tmr] = ticksper; rtc_ticks[tmr] = rtc_ticks[tmr] + 1; /* count ticks */ if (rtc_ticks[tmr] < ticksper) return rtc_currd[tmr]; /* 1 sec yet? */ rtc_ticks[tmr] = 0; /* reset ticks */ @@ -249,3 +406,226 @@ int32 sim_rtc_calb (int32 ticksper) { return sim_rtcn_calb (ticksper, 0); } + +/* sim_timer_init - get minimum sleep time available on this host */ + +t_bool sim_timer_init (void) +{ +sim_idle_enab = FALSE; /* init idle off */ +sim_idle_rate_ms = sim_os_ms_sleep_init (); /* get OS timer rate */ +return (sim_idle_rate_ms != 0); +} + +/* sim_idle - idle simulator until next event or for specified interval + + Inputs: + tmr = calibrated timer to use + + Must solve the linear equation + + ms_to_wait = w * ms_per_wait + + Or + w = ms_to_wait / ms_per_wait +*/ + +t_bool sim_idle (uint32 tmr, t_bool sin_cyc) +{ +uint32 cyc_ms, w_ms, w_idle, act_ms; +int32 act_cyc; + +cyc_ms = (rtc_currd[tmr] * rtc_hz[tmr]) / 1000; /* cycles per msec */ +if ((sim_idle_rate_ms == 0) || (cyc_ms == 0)) { /* not possible? */ + if (sin_cyc) sim_interval = sim_interval - 1; + return FALSE; + } +w_ms = (uint32) sim_interval / cyc_ms; /* ms to wait */ +w_idle = w_ms / sim_idle_rate_ms; /* intervals to wait */ +if (w_idle == 0) { /* none? */ + if (sin_cyc) sim_interval = sim_interval - 1; + return FALSE; + } +act_ms = sim_os_ms_sleep (w_idle); /* wait */ +act_cyc = act_ms * cyc_ms; +if (sim_interval > act_cyc) + sim_interval = sim_interval - act_cyc; +else sim_interval = 1; +return TRUE; +} + +/* Set idling - implicitly disables throttling */ + +t_stat sim_set_idle (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (sim_idle_rate_ms == 0) return SCPE_NOFNC; +if ((val != 0) && (sim_idle_rate_ms > (uint32) val)) + return SCPE_NOFNC; +sim_idle_enab = TRUE; +if (sim_throt_type != SIM_THROT_NONE) { + sim_set_throt (0, NULL); + printf ("Throttling disabled\n"); + if (sim_log) fprintf (sim_log, "Throttling disabled\n"); + } +return SCPE_OK; +} + +/* Clear idling */ + +t_stat sim_clr_idle (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +sim_idle_enab = FALSE; +return SCPE_OK; +} + +/* Show idling */ + +t_stat sim_show_idle (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fprintf (st, sim_idle_enab? "idling enabled": "idling disabled"); +return SCPE_OK; +} + +/* Throttling package */ + +t_stat sim_set_throt (int32 arg, char *cptr) +{ +char *tptr, c; +t_value val; + +if (arg == 0) { + if ((cptr != 0) && (*cptr != 0)) return SCPE_ARG; + sim_throt_type = SIM_THROT_NONE; + sim_throt_cancel (); + } +else if (sim_idle_rate_ms == 0) return SCPE_NOFNC; +else { + val = strtotv (cptr, &tptr, 10); + if (cptr == tptr) return SCPE_ARG; + c = toupper (*tptr++); + if (*tptr != 0) return SCPE_ARG; + if (c == 'M') sim_throt_type = SIM_THROT_MCYC; + else if (c == 'K') sim_throt_type = SIM_THROT_KCYC; + else if ((c = '%') && (val > 0) && (val < 100)) + sim_throt_type = SIM_THROT_PCT; + else return SCPE_ARG; + if (sim_idle_enab) { + printf ("Idling disabled\n"); + if (sim_log) fprintf (sim_log, "Idling disabled\n"); + sim_clr_idle (NULL, 0, NULL, NULL); + } + sim_throt_val = (uint32) val; + } +return SCPE_OK; +} + +t_stat sim_show_throt (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, char *cptr) +{ +if (sim_idle_rate_ms == 0) + fprintf (st, "Throttling not available\n"); +else { + switch (sim_throt_type) { + + case SIM_THROT_MCYC: + fprintf (st, "Throttle = %d megacycles\n", sim_throt_val); + break; + + case SIM_THROT_KCYC: + fprintf (st, "Throttle = %d kilocycles\n", sim_throt_val); + break; + + case SIM_THROT_PCT: + fprintf (st, "Throttle = %d%%\n", sim_throt_val); + break; + + default: + fprintf (st, "Throttling disabled\n"); + break; + } + + if (sim_switches & SWMASK ('D')) { + fprintf (st, "Wait rate = %d ms\n", sim_idle_rate_ms); + if (sim_throt_type != 0) + fprintf (st, "Throttle interval = %d cycles\n", sim_throt_wait); + } + } +return SCPE_OK; +} + +void sim_throt_sched (void) +{ +sim_throt_state = 0; +if (sim_throt_type) + sim_activate (&sim_throt_unit, SIM_THROT_WINIT); +return; +} + +void sim_throt_cancel (void) +{ +sim_cancel (&sim_throt_unit); +} + +/* Throttle service + + Throttle service has three distinct states + + 0 take initial measurement + 1 take final measurement, calculate wait values + 2 periodic waits to slow down the CPU +*/ + +t_stat sim_throt_svc (UNIT *uptr) +{ +uint32 delta_ms; +double a_cps, d_cps; + +switch (sim_throt_state) { + + case 0: /* take initial reading */ + sim_throt_ms_start = sim_os_msec (); + sim_throt_wait = SIM_THROT_WST; + sim_throt_state++; /* next state */ + break; /* reschedule */ + + case 1: /* take final reading */ + sim_throt_ms_stop = sim_os_msec (); + delta_ms = sim_throt_ms_stop - sim_throt_ms_start; + if (delta_ms < SIM_THROT_MSMIN) { /* not enough time? */ + if (sim_throt_wait >= 100000000) { /* too many inst? */ + sim_throt_state = 0; /* fails in 32b! */ + return SCPE_OK; + } + sim_throt_wait = sim_throt_wait * SIM_THROT_WMUL; + sim_throt_ms_start = sim_throt_ms_stop; + } + else { /* long enough */ + a_cps = ((double) sim_throt_wait) * 1000.0 / (double) delta_ms; + if (sim_throt_type == SIM_THROT_MCYC) /* calc desired cps */ + d_cps = (double) sim_throt_val * 1000000.0; + else if (sim_throt_type == SIM_THROT_KCYC) + d_cps = (double) sim_throt_val * 1000.0; + else d_cps = (a_cps * ((double) sim_throt_val)) / 100.0; + if (d_cps >= a_cps) { + sim_throt_state = 0; + return SCPE_OK; + } + sim_throt_wait = (int32) /* time between waits */ + ((a_cps * d_cps * ((double) sim_idle_rate_ms)) / + (1000.0 * (a_cps - d_cps))); + if (sim_throt_wait < SIM_THROT_WMIN) { /* not long enough? */ + sim_throt_state = 0; + return SCPE_OK; + } + sim_throt_state++; +// fprintf (stderr, "Throttle values a_cps = %f, d_cps = %f, wait = %d\n", +// a_cps, d_cps, sim_throt_wait); + } + break; + + case 2: /* throttling */ + sim_os_ms_sleep (1); + break; + } + +sim_activate (uptr, sim_throt_wait); /* reschedule */ +return SCPE_OK; +} diff --git a/sim_timer.h b/sim_timer.h index 580c700a..ed0b9279 100644 --- a/sim_timer.h +++ b/sim_timer.h @@ -1,6 +1,6 @@ /* sim_timer.h: simulator timer library headers - Copyright (c) 1993-2005, Robert M Supnik + Copyright (c) 1993-2006, 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. + 17-Oct-06 RMS Added idle support 02-Jan-04 RMS Split out from SCP */ @@ -32,11 +33,35 @@ #define SIM_NTIMERS 8 /* # timers */ #define SIM_TMAX 500 /* max timer makeup */ +#define SIM_IDLE_CAL 10 /* ms to calibrate */ +#define SIM_IDLE_MAX 10 /* max granularity idle */ + +#define SIM_THROT_WINIT 1000 /* cycles to skip */ +#define SIM_THROT_WST 10000 /* initial wait */ +#define SIM_THROT_WMUL 4 /* multiplier */ +#define SIM_THROT_WMIN 100 /* min wait */ +#define SIM_THROT_MSMIN 10 /* min for measurement */ +#define SIM_THROT_NONE 0 /* throttle parameters */ +#define SIM_THROT_MCYC 1 +#define SIM_THROT_KCYC 2 +#define SIM_THROT_PCT 3 + +t_bool sim_timer_init (void); int32 sim_rtcn_init (int32 time, int32 tmr); int32 sim_rtcn_calb (int32 ticksper, int32 tmr); int32 sim_rtc_init (int32 time); int32 sim_rtc_calb (int32 ticksper); +t_bool sim_idle (uint32 tmr, t_bool sin_cyc); +t_stat sim_set_throt (int32 arg, char *cptr); +t_stat sim_show_throt (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, char *cptr); +t_stat sim_set_idle (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat sim_clr_idle (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat sim_show_idle (FILE *st, UNIT *uptr, int32 val, void *desc); +void sim_throt_sched (void); +void sim_throt_cancel (void); uint32 sim_os_msec (void); void sim_os_sleep (unsigned int sec); +uint32 sim_os_ms_sleep (unsigned int msec); +uint32 sim_os_ms_sleep_init (void); #endif