From 202e49cfdf35975ca6888d0a2f647f58aa694d11 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 13 Sep 2017 05:59:25 -0700 Subject: [PATCH] =?UTF-8?q?scelbi:=20New=20SCELBI=20(SCientic-ELectronics-?= =?UTF-8?q?BIology)=20Simulator=20from=20Hans-=C3=85ke=20Lund?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Intel-Systems/common/i8008.c | 2848 ++++++++++---------------- Intel-Systems/scelbi/scelbi.txt | 139 ++ Intel-Systems/scelbi/scelbi_io.c | 345 ++++ Intel-Systems/scelbi/scelbi_sys.c | 97 + Intel-Systems/scelbi/system_defs.h | 50 + README.md | 2 + Visual Studio Projects/Simh.sln | 9 + Visual Studio Projects/scelbi.vcproj | 317 +++ makefile | 14 +- 9 files changed, 2011 insertions(+), 1810 deletions(-) create mode 100644 Intel-Systems/scelbi/scelbi.txt create mode 100644 Intel-Systems/scelbi/scelbi_io.c create mode 100644 Intel-Systems/scelbi/scelbi_sys.c create mode 100644 Intel-Systems/scelbi/system_defs.h create mode 100644 Visual Studio Projects/scelbi.vcproj diff --git a/Intel-Systems/common/i8008.c b/Intel-Systems/common/i8008.c index 461d77a5..100e7f96 100644 --- a/Intel-Systems/common/i8008.c +++ b/Intel-Systems/common/i8008.c @@ -1,6 +1,6 @@ -/* i8008.c: Intel 8008 CPU simulator +/* i8008.c: Intel 8008 CPU simulator. - Copyright (c) 2011, William A. Beech + Copyright (c) 2017, Hans-Ake Lund Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -15,13 +15,13 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + HANS-AKE LUND BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - Except as contained in this notice, the name of William A. Beech shall not be + Except as contained in this notice, the name of Hans-Ake Lund shall not be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from William A. Beech. + in this Software without prior written authorization from Hans-Ake Lund. cpu 8008 CPU @@ -32,16 +32,21 @@ C<0:7> C Register D<0:7> D Register E<0:7> E Register - H<0:7> H Register - L<0:7> L Register - PC<0:13> Program counter + HL<0:15> HL Register Pair + CF Carry flag + ZF Zero flag + SF Sign bit + PF Parity bit + PC<0:13> Program Counter + SP<0:2> Stack Pointer into return stack with 7 levels + (the SP register is not available for 8008 programs) - The 8008 is an 8-bit CPU, which uses 14-bit registers to address - up to 16KB of memory. + The 8008 is an 8-bit CPU, which uses 14 bits of 16-bit registers + to address up to 16KB of memory. - The 57 basic instructions come in 1, 2, and 3-byte flavors. + The basic instructions come in 1, 2, and 3-byte flavors. - This routine is the instruction decode routine for the 8008. + This routine is the instruction decode routine for the 8080. It is called from the simulator control program to execute instructions in simulated memory, starting at the simulated PC. It runs until 'reason' is set non-zero. @@ -50,1749 +55,869 @@ 1. Reasons to stop. The simulator can be stopped by: - HLT instruction + HALT instruction I/O error in I/O simulator Invalid OP code (if ITRAP is set on CPU) 2. Interrupts. - There are 8 possible levels of interrupt, and in effect they - do a hardware CALL instruction to one of 8 possible low - memory addresses. + Hardware external to the CPU supplies an instruction + this could be an RST instruction making a call to one + of 8 possibe memory addresses. 3. Non-existent memory. On the 8008, reads to non-existent memory - return 0FFh, and writes are ignored. In the simulator, the - largest possible memory is instantiated and initialized to zero. + return 0377, and writes are ignored. In the simulator, the + largest possible memory is instantiated and initialized to 0377. Thus, only writes need be checked against actual memory size. 4. Adding I/O devices. These modules must be modified: - 15 Feb 15 - Original file. + _io.c add I/O service routines to dev_table + _sys.c add pointer to data structures in sim_devices + + CPU documentation: http://www.classiccmp.org/8008/8008UM.pdf + + 04-Sep-17 HAL Working version of CPU simulator for SCELBI computer + 12-Sep-17 HAL Modules restructured in "Intel-Systems" directory */ +#include #include "system_defs.h" -#define UNIT_V_OPSTOP (UNIT_V_UF) /* Stop on Invalid OP? */ +#define UNIT_V_OPSTOP (UNIT_V_UF) /* Stop on Invalid OP? */ #define UNIT_OPSTOP (1 << UNIT_V_OPSTOP) -#define UNIT_V_TRACE (UNIT_V_UF+1) /* Trace switch */ -#define UNIT_TRACE (1 << UNIT_V_TRACE) +#define UNIT_V_CHIP (UNIT_V_UF+1) /* 8008 */ +#define UNIT_CHIP (1 << UNIT_V_CHIP) +#define UNIT_V_MSIZE (UNIT_V_UF+2) /* Memory Size */ +#define UNIT_MSIZE (1 << UNIT_V_MSIZE) -/* register masks */ -#define BYTE_R 0xFF -#define WORD_R14 0x3FFF +unsigned char Mem[MAXMEMSIZE]; /* Memory */ +unsigned int Smem[8]; /* Stack memory with 7 levels + (TODO: and program counter) */ +int32 Areg = 0; /* accumulator */ +int32 Breg = 0; /* B register */ +int32 Creg = 0; /* C register */ +int32 Dreg = 0; /* D register */ +int32 Ereg = 0; /* E register */ +int32 HLreg = 0; /* HL register pair */ +int32 SPreg = 0; /* Stack pointer 3 bits */ +int32 Cflag = 0; /* Carry flag */ +int32 Zflag = 0; /* Zero flag */ +int32 Sflag = 0; /* Sign flag */ +int32 Pflag = 0; /* Parity flag */ +int32 saved_PCreg = 0; /* Program Counter */ +int32 INTEflag = 0; /* Interrupt Enable */ +int32 int_req = 0; /* Interrupt Request */ -/* storage for the rest of the registers */ -uint32 A = 0; /* accumulator */ -uint32 B = 0; /* B register */ -uint32 C = 0; /* C register */ -uint32 D = 0; /* D register */ -uint32 E = 0; /* E register */ -uint32 H = 0; /* H register */ -uint32 L = 0; /* L register */ -uint32 CF = 0; /* C - carry flag */ -uint32 PF = 0; /* P - parity flag */ -uint32 ZF = 0; /* Z - zero flag */ -uint32 SF = 0; /* S - sign flag */ -uint32 SP = 0; /* stack frame pointer */ -uint32 saved_PC = 0; /* program counter */ -uint32 int_req = 0; /* Interrupt request */ +int32 PCXreg; /* External view of PC */ -int32 PCX; /* External view of PC */ -int32 PC; -UNIT *uptr; +/* Function prototypes */ -/* function prototypes */ -void store_m(unit32 val); -unit32 fetch_m(void); -void set_cpuint(int32 int_num); -void dumpregs(void); -int32 fetch_byte(int32 flag); -int32 fetch_word(void); -uint16 pop_word(void); -void push_word(uint16 val); -void setflag4(int32 reg); -void setlogical(int32 reg); -void setinc(int32 reg); -int32 getreg(int32 reg); -void putreg(int32 reg, int32 val); -int32 getpair(int32 reg); -int32 getpush(int32 reg); -void putpush(int32 reg, int32 data); -void putpair(int32 reg, int32 val); -void parity(int32 reg); -int32 cond(int32 con); -t_stat i8008_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); -t_stat i8008_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); -t_stat i8008_reset (DEVICE *dptr); +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_reset (DEVICE *dptr); +t_stat cpu_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc); +t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw); +t_stat parse_sym (CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw); -/* external function prototypes */ +void setarith(int32 reg); +void setlogical(int32 reg); +void setinc(int32 reg); +int32 getreg(int32 reg); +void putreg(int32 reg, int32 val); +void parity(int32 reg); +int32 cond(int32 con); -extern t_stat i8008_reset (DEVICE *dptr); -extern int32 get_mbyte(int32 addr); -extern int32 get_mword(int32 addr); -extern void put_mbyte(int32 addr, int32 val); -extern void put_mword(int32 addr, int32 val); -extern int32 sim_int_char; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern struct idev dev_table[32]; +/* 8008 CPU data structures -struct idev { - int32 (*routine)(); -}; - -/* This is the I/O configuration table. There are 256 possible -device addresses, if a device is plugged to a port it's routine -address is here, 'nulldev' means no device is available + cpu_dev CPU device descriptor + cpu_unit CPU unit descriptor + cpu_reg CPU register list + cpu_mod CPU modifiers list */ -extern struct idev dev_table[]; +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) }; -/* CPU data structures - - i8008_dev CPU device descriptor - i8008_unit CPU unit descriptor - i8008_reg CPU register list - i8008_mod CPU modifiers list -*/ - -UNIT i8008_unit = { UDATA (NULL, 0, 65535) }; /* default 8008 */ - -REG i8008_reg[] = { - { HRDATA (PC, saved_PC, 16) }, /* must be first for sim_PC */ - { HRDATA (A, A, 8) }, - { HRDATA (B, B, 8) }, - { HRDATA (C, C, 8) }, - { HRDATA (D, D, 8) }, - { HRDATA (E, E, 8) }, - { HRDATA (H, H, 8) }, - { HRDATA (L, L, 8) }, - { HRDATA (CF, CF, 1) }, - { HRDATA (PF, PF, 1) }, - { HRDATA (ZF, SF, 1) }, - { HRDATA (SF, SF, 1) }, - { HRDATA (INTR, int_req, 32) }, - { HRDATA (WRU, sim_int_char, 8) }, +REG cpu_reg[] = { + { ORDATA (PC, saved_PCreg, 16) }, + { ORDATA (A, Areg, 8) }, + { ORDATA (B, Breg, 8) }, + { ORDATA (C, Creg, 8) }, + { ORDATA (D, Dreg, 8) }, + { ORDATA (E, Ereg, 8) }, + { ORDATA (HL, HLreg, 16) }, + { ORDATA (SP, SPreg, 16) }, + { FLDATA (CF, Cflag, 16) }, + { FLDATA (ZF, Zflag, 16) }, + { FLDATA (SF, Sflag, 16) }, + { FLDATA (PF, Pflag, 16) }, + { FLDATA (INTE, INTEflag, 16) }, + { ORDATA (WRU, sim_int_char, 8) }, { NULL } }; -MTAB i8008_mod[] = { - { UNIT_OPSTOP, 0, "ITRAP", "ITRAP", NULL }, - { UNIT_OPSTOP, UNIT_OPSTOP, "NOITRAP", "NOITRAP", NULL }, - { UNIT_TRACE, 0, "NOTRACE", "NOTRACE", NULL }, - { UNIT_TRACE, UNIT_TRACE, "TRACE", "TRACE", NULL }, +MTAB cpu_mod[] = { + { UNIT_CHIP, 0, "8008", "8008", NULL }, + { UNIT_OPSTOP, UNIT_OPSTOP, "ITRAP", "ITRAP", NULL }, + { UNIT_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL }, + { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size }, + { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size }, + { UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size }, + { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size }, { 0 } }; -DEBTAB i8008_debug[] = { - { "ALL", DEBUG_all }, - { "FLOW", DEBUG_flow }, - { "READ", DEBUG_read }, - { "WRITE", DEBUG_write }, - { "LEV1", DEBUG_level1 }, - { "LEV2", DEBUG_level2 }, - { "REG", DEBUG_reg }, - { "ASM", DEBUG_asm }, - { NULL } +DEVICE cpu_dev = { + "I8008", &cpu_unit, cpu_reg, cpu_mod, // name, units, registers, modifiers + 1, 8, 16, 1, // numunits, aradix, awidth, aincr + 8, 8, // dradix, dwidth + &cpu_ex, &cpu_dep, &cpu_reset, // examine, deposit, reset + NULL, NULL, NULL // boot, attach, detach }; -DEVICE i8008_dev = { - "I8008", //name - &i8008_unit, //units - i8008_reg, //registers - i8008_mod, //modifiers - 1, //numunits - 16, //aradix - 16, //awidth - 1, //aincr - 16, //dradix - 8, //dwidth - &i8008_ex, //examine - &i8008_dep, //deposit -// &i8008_reset, //reset - NULL, //reset - NULL, //boot - NULL, //attach - NULL, //detach - NULL, //ctxt - DEV_DEBUG, //flags - 0, //dctrl - i8008_debug, //debflags - NULL, //msize - NULL //lname -}; - -/* tables for the disassembler */ -char *opcode[] = { -"*HLT", "*HLT", "RLC", "RFC", /* 0x00 */ -"ADI ", "RST 0", "LAI ,", "RET", -"INB", "DCB", "RRC", "RFZ", -"ACI ", "RST 1", "LBI ", "*RET", -"INC", "DCC", "RAL", "RFS", /* 0x10 */ -"SUI ", "RST 2", "LCI ", "*RET", -"IND", "DCD", "RAR", "RFP", -"SBI ", "RST 3", "LDI ", "*RET", -"INE", "DCE", "???", "RTC", /* 0x20 */ -"NDI ", "RST 4", "LEI ", "*RET", -"INH", "DCH", "???", "RTZ", -"XRI ", "RST 5", "LHI ", "*RET", -"INL", "DCL", "???", "RTS", /* 0x30 */ -"ORI ", "RST 6", "LLI ", "*RET", -"???", "???", "???", "RTP", -"CPI ", "RST 7", "LMI ", "*RET", -"JFC ", "INP ", "CFC ", "INP ", /* 0x40 */ -"JMP ", "INP ", "CAL ", "INP ", -"JFZ ", "INP ", "CFZ ", "INP ", -"*JMP ", "INP ", "*CAL ", "INP ", -"JFS", "OUT ", "CFS ", "OUT ", /* 0x50 */ -"*JMP ", "OUT ", "*CAL ", "OUT ", -"JFP ", "OUT ", "CFP ", "OUT ", -"*JMP ", "OUT ", "*CAL ", "OUT ", -"JTC ", "OUT ", "CTC ", "OUT ", /* 0x60 */ -"*JMP ", "OUT ", "*CAL ", "OUT ", -"JTZ ", "OUT ", "CTZ", "OUT ", -"*JMP ", "OUT ", "*CAL", "OUT ", -"JTS ", "OUT ", "CTS ", "OUT ", /* 0x70 */ -"*JMP ", "OUT ", "*CAL ", "OUT ", -"JTP ", "OUT ", "CTP", "OUT ", -"*JMP ", "OUT ", "*CAL ", "OUT ", -"ADA", "ADB", "ADC", "ADD", /* 0x80 */ -"ADE", "ADH", "ADL", "ADM", -"ACA", "ACB", "ACC", "ACD", -"ACE", "ACH", "ACL", "ACM", -"SUA", "SUB", "SUC", "SUD", /* 0x90 */ -"SUE", "SUH", "SUL", "SUM", -"SBA", "SBB", "SBC", "SBD", -"SBE", "SBH", "SBL", "SBM", -"NDA", "NDB", "NDC", "NDD", /* 0xA0 */ -"NDE", "NDH", "NDL", "NDM", -"XRA", "XRB", "XRC", "XRD", -"XRE", "XRH", "XRL", "XRM", -"ORA", "ORB", "ORC", "ORD", /* 0xB0 */ -"ORE", "ORH", "ORL", "ORM", -"CPA", "CPB", "CPC", "CPD", -"CPE", "CPH", "CPL", "CPM", -"NOP", "LAB", "LAC", "LAD", /* 0xC0 */ -"LAE", "LAH", "LAL", "LAM", -"LBA", "LBB", "LBC", "LBD", -"LBE", "LBH ", "LBL", "LBM", -"LCA", "LCB", "LCC", "LCD", /* 0xD0 */ -"LCE", "LCH", "LCL", "LCM", -"LDA", "LDB", "LDC", "LDD", -"LDE", "LDH", "LDL", "LDM", -"LEA", "LEB", "LEC", "LED", /* 0xE0 */ -"LEE", "LEH", "LEL", "LEM", -"LHA", "LHB", "LHC", "LHD", -"LHE", "LHH", "LHL", "LHM", -"LLA", "LLB", "LLC", "LLD", /* 0xF0 */ -"LLE", "LLH", "LLL", "LLM", -"LMA", "LMB", "LMC", "LMD", -"LME", "LMH", "LML", "HLT", +/* Intel 8008 opcodes + */ +static const char *opcode[] = { +"HLT", "HLT", "RLC", "RFC", /* 000-003 */ +"ADI", "RST0", "LAI", "RET", /* 004-007 */ +"INB", "DCB", "RRC", "RFZ", /* 010-013 */ +"ACI", "RST1", "LBI", "RET", /* 014-017 */ +"INC", "DCC", "RAL", "RFS", /* 020-023 */ +"SUI", "RST2", "LCI", "RET", /* 024-027 */ +"IND", "DCD", "RAR", "RFP", /* 030-033 */ +"SBI", "RST3", "LDI", "RET", /* 034-037 */ +"INE", "DCE", "???", "RTC", /* 040-043 */ +"NDI", "RST4", "LEI", "RET", /* 044-047 */ +"ICH", "DCH", "???", "RTZ", /* 050-053 */ +"XRI", "RST5", "LHI", "RET", /* 054-057 */ +"INL", "DCL", "???", "RTS", /* 060-063 */ +"ORI", "RST6", "LLI", "RET", /* 064-067 */ +"???", "???", "???", "RTP", /* 070-073 */ +"CPI", "RST7", "LMI", "RET", /* 074-077 */ +"JFC", "INP", "CFC", "INP", /* 100-103 */ +"JMP", "INP", "CAL", "INP", /* 104-107 */ +"JFZ", "INP", "CFZ", "INP", /* 110-113 */ +"JMP", "INP", "CAL", "INP", /* 114-117 */ +"JFS", "OUT", "CFS", "OUT", /* 120-123 */ +"JMP", "OUT", "CAL", "OUT", /* 124-127 */ +"JFP", "OUT", "CFP", "OUT", /* 130-133 */ +"JMP", "OUT", "CAL", "OUT", /* 134-137 */ +"JTC", "OUT", "CTC", "OUT", /* 140-143 */ +"JMP", "OUT", "CAL", "OUT", /* 144-147 */ +"JTZ", "OUT", "CTZ", "OUT", /* 150-153 */ +"JMP", "OUT", "CAL", "OUT", /* 154-157 */ +"JTS", "OUT", "CTS", "OUT", /* 160-163 */ +"JMP", "OUT", "CAL", "OUT", /* 164-167 */ +"JTP", "OUT", "CTP", "OUT", /* 170-173 */ +"JMP", "OUT", "CAL", "OUT", /* 174-177 */ +"ADA", "ADB", "ADC", "ADD", /* 200-203 */ +"ADE", "ADH", "ADL", "ADM", /* 204-207 */ +"ACA", "ACB", "ACC", "ACD", /* 210-213 */ +"ACE", "ACH", "ACL", "ACM", /* 214-217 */ +"SUA", "SUB", "SUC", "SUD", /* 220-223 */ +"SUE", "SUH", "SUL", "SUM", /* 224-227 */ +"SBA", "SBB", "SBC", "SBD", /* 230-233 */ +"SBE", "SBH", "SBL", "SBM", /* 234-237 */ +"NDA", "NDB", "NDC", "NDD", /* 240-243 */ +"NDE", "NDH", "NDL", "NDM", /* 244-247 */ +"XRA", "XRB", "XRC", "XRD", /* 250-253 */ +"XRE", "XRH", "XRL", "XRM", /* 254-257 */ +"ORA", "ORB", "ORC", "ORD", /* 260-263 */ +"ORE", "ORH", "ORL", "ORM", /* 264-267 */ +"CPA", "CPB", "CPC", "CPD", /* 270-273 */ +"CPE", "CPH", "CPL", "CPM", /* 274-277 */ +"LAA", "LAB", "LAC", "LAD", /* 300-303 */ +"LAE", "LAH", "LAL", "LAM", /* 304-307 */ +"LBA", "LBB", "LBC", "LBD", /* 310-313 */ +"LBE", "LBH", "LBL", "LBM", /* 314-317 */ +"LCA", "LCB", "LCC", "LCD", /* 320-323 */ +"LCE", "LCH", "LCL", "LCM", /* 324-327 */ +"LDA", "LDB", "LDC", "LDD", /* 330-333 */ +"LDE", "LDH", "LDL", "LDM", /* 334-337 */ +"LEA", "LEB", "LEC", "LED", /* 340-343 */ +"LEE", "LEH", "LEL", "LEM", /* 344-347 */ +"LHA", "LHB", "LHC", "LHD", /* 350-353 */ +"LHE", "LHH", "LHL", "LHM", /* 354-357 */ +"LLA", "LLB", "LLC", "LLD", /* 360-363 */ +"LLE", "LLH", "LLL", "LLM", /* 364-367 */ +"LMA", "LMB", "LMC", "LMD", /* 370-373 */ +"LME", "LMH", "LML", "HLT" /* 374-377 */ }; +/* Intel 8008 opcode lengths + */ int32 oplen[256] = { -/* - 0 1 2 3 4 5 6 7 8 9 A B C D E F */ - 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, /* 0X */ - 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, /* 1X */ - 1, 1, 0, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, /* 2X */ - 1, 1, 0, 1, 2, 1, 2, 1, 0, 0, 0, 1, 2, 1, 2, 1, /* 3X */ - 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, /* 4X */ - 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, /* 5X */ - 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, /* 6X */ - 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, /* 7X */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 8X */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 9X */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* AX */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* BX */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* CX */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* DX */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* EX */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* FX */ +1,1,1,1,2,1,2,1, /* 000 - 007 */ +1,1,1,1,2,1,2,1, /* 010 - 017 */ +1,1,1,1,2,1,2,1, /* 020 - 027 */ +1,1,1,1,2,1,2,1, /* 030 - 037 */ +1,1,0,1,2,1,2,1, /* 040 - 047 */ +1,1,0,1,2,1,2,1, /* 050 - 057 */ +1,1,0,1,2,1,2,1, /* 060 - 067 */ +0,0,0,1,2,1,2,1, /* 070 - 077 */ +3,1,3,1,3,1,3,1, /* 100 - 107 */ +3,1,3,1,3,1,3,1, /* 110 - 117 */ +3,1,3,1,3,1,3,1, /* 120 - 127 */ +3,1,3,1,3,1,3,1, /* 130 - 137 */ +3,1,3,1,3,1,3,1, /* 140 - 147 */ +3,1,3,1,3,1,3,1, /* 150 - 157 */ +3,1,3,1,3,1,3,1, /* 160 - 167 */ +3,1,3,1,3,1,3,1, /* 170 - 177 */ +1,1,1,1,1,1,1,1, /* 200 - 207 */ +1,1,1,1,1,1,1,1, /* 210 - 217 */ +1,1,1,1,1,1,1,1, /* 220 - 227 */ +1,1,1,1,1,1,1,1, /* 230 - 237 */ +1,1,1,1,1,1,1,1, /* 240 - 247 */ +1,1,1,1,1,1,1,1, /* 250 - 257 */ +1,1,1,1,1,1,1,1, /* 260 - 267 */ +1,1,1,1,1,1,1,1, /* 270 - 277 */ +1,1,1,1,1,1,1,1, /* 300 - 307 */ +1,1,1,1,1,1,1,1, /* 310 - 317 */ +1,1,1,1,1,1,1,1, /* 320 - 327 */ +1,1,1,1,1,1,1,1, /* 330 - 337 */ +1,1,1,1,1,1,1,1, /* 340 - 347 */ +1,1,1,1,1,1,1,1, /* 350 - 357 */ +1,1,1,1,1,1,1,1, /* 360 - 367 */ +1,1,1,1,1,1,1,1 /* 370 - 377 */ }; -uint16 stack_frame[7]; /* processor stack frame */ - -void set_cpuint(int32 int_num) +/* Decode instructions + */ +t_stat sim_instr (void) { - int_req |= int_num; -} + int32 PC, IR, OP, DAR, reason, hi, lo, carry, states; + /* states (Machine States) are recorded for each instruction + but not used yet */ -/* instruction simulator */ -int32 sim_instr (void) -{ - extern int32 sim_interval; - uint32 IR, OP, DAR, reason, hi, lo, i, adr, val; - - PC = saved_PC & WORD_R14; /* load local PC */ + PC = saved_PCreg & ADDRMASK; /* load local PC */ + Cflag = Cflag & 0200000; reason = 0; - uptr = i8008_dev.units; - /* Main instruction fetch/decode loop */ - while (reason == 0) { /* loop until halted */ - -// if (PC == 0x1000) { /* turn on debugging */ -// i8008_dev.dctrl = DEBUG_asm + DEBUG_reg; -// reason = STOP_HALT; -// } - if (i8008_dev.dctrl & DEBUG_reg) { - dumpregs(); - sim_printf("\n"); + while (reason == 0) { /* loop until halted */ + if (sim_interval <= 0) { /* check clock queue */ + if ((reason = sim_process_event ())) break; } - if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event()) - break; - } + if (int_req > 0) { /* interrupt? */ - if (int_req > 0) { /* interrupt? */ -// sim_printf("\ni8008: int_req=%04X", int_req); - ; - } else { /* 8008 */ - if (IE) { /* enabled? */ - push_word(PC); /* do an RST 7 */ - PC = 0x0038; - int_req &= ~INT_R; -// sim_printf("\ni8008: int_req=%04X", int_req); - } - } /* end interrupt */ + /* 8008 interrupts not implemented yet. */ - if (sim_brk_summ && - sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ + } /* end interrupt */ + + if (sim_brk_summ && + sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ break; } - sim_interval--; /* countdown clock */ - PCX = PC; + PCXreg = PC; - if (uptr->flags & UNIT_TRACE) { - dumpregs(); - sim_printf("\n"); - } - IR = OP = fetch_byte(0); /* instruction fetch */ + IR = OP = Mem[PC]; /* fetch instruction */ - if (OP == 0x00 || OP == 0x01 || OP == 0xFF) { /* HLT Instruction*/ + PC = (PC + 1) & ADDRMASK; /* increment PC */ + + sim_interval--; + + if ((OP == 0377) || ((OP & 0376) == 0)) { /* HLT Instructions */ reason = STOP_HALT; PC--; + states = 4; continue; } - /* The Big Instruction Decode Switch */ + /* Handle below all operations which refer to registers, also + handle jump, call, return and i/o. + After that, a large switch statement takes care of all other opcodes. + The original mnemonics for 8008 published 1972 are used. + For the instructions: "s" source register, "d" destination register. + Octal notation is used in most cases just like in the + original documentation. + */ + + if ((OP & 0307) == 0307) { /* LdM */ + if (HLreg & 0xC000) { + sim_printf("LdM addr > 16K: %o", HLreg); + PC--; + reason = SCPE_STOP; + continue; + } + DAR = Mem[HLreg]; + DAR = DAR & 0377; + putreg((OP >> 3) & 07, DAR); + states = 8; + continue; + } + if ((OP & 0370) == 0370) { /* LMs */ + if (HLreg & 0xC000) { + sim_printf("LMs addr > 16K: %o", HLreg); + PC--; + reason = SCPE_STOP; + continue; + } + DAR = getreg(OP & 07); + DAR = DAR & 0377; + Mem[HLreg] = DAR; + states = 7; + continue; + } + if ((OP & 0300) == 0300) { /* Lds */ + DAR = getreg(OP & 07); + DAR = DAR & 0377; + putreg((OP >> 3) & 07, DAR); + states = 5; + continue; + } + if (OP == 0076) { /* LMI */ + if (HLreg & 0xc000) { + sim_printf("LMI addr > 16K: %o", HLreg); + PC--; + reason = SCPE_STOP; + continue; + } + DAR = Mem[PC]; + PC++; + Mem[HLreg] = DAR; + states = 9; + continue; + } + if ((OP & 0307) == 0006) { /* LdI */ + putreg((OP >> 3) & 07, Mem[PC]); + PC++; + states = 8; + continue; + } + if ((OP & 0307) == 0000) { /* INd */ + DAR = getreg((OP >> 3) & 07); + DAR++; + setinc(DAR); + DAR = DAR & 0377; + putreg((OP >> 3) & 07, DAR); + states = 5; + continue; + } + if ((OP & 0307) == 0001) { /* DCd */ + DAR = getreg((OP >> 3) & 07); + DAR--; + setinc(DAR); + DAR = DAR & 0377; + putreg((OP >> 3) & 07, DAR); + states = 5; + continue; + } + if (OP == 0207) { /* ADM */ + if (HLreg & 0xC000) { + sim_printf("LDM addr > 16K: %o", HLreg); + PC--; + reason = SCPE_STOP; + continue; + } + Areg += Mem[HLreg]; + setarith(Areg); + Areg = Areg & 0377; + states = 8; + continue; + } + if ((OP & 0370) == 0200) { /* ADs */ + Areg += getreg(OP & 07); + setarith(Areg); + Areg = Areg & 0377; + states = 5; + continue; + } + if (OP == 0217) { /* ACM */ + if (HLreg & 0xC000) { + sim_printf("ACM addr > 16K: %o", HLreg); + PC--; + reason = SCPE_STOP; + continue; + } + carry = 0; + if (Cflag) carry = 1; + Areg += Mem[HLreg]; + Areg += carry; + setarith(Areg); + Areg = Areg & 0377; + states = 8; + continue; + } + if ((OP & 0370) == 0210) { /* ACs */ + carry = 0; + if (Cflag) carry = 1; + Areg += getreg(OP & 07); + Areg += carry; + setarith(Areg); + Areg = Areg & 0377; + states = 5; + continue; + } + if (OP == 0227) { /* SUM */ + if (HLreg & 0xC000) { + sim_printf("SUM addr > 16K: %o", HLreg); + PC--; + reason = SCPE_STOP; + continue; + } + Areg -= Mem[HLreg]; + setarith(Areg); + Areg = Areg & 0377; + states = 8; + continue; + } + if ((OP & 0370) == 0220) { /* SUs */ + Areg -= getreg(OP & 07); + setarith(Areg); + Areg = Areg & 0377; + states = 5; + continue; + } + if (OP == 0237) { /* SBM */ + if (HLreg & 0xC000) { + sim_printf("SBM addr > 16K: %o", HLreg); + PC--; + reason = SCPE_STOP; + continue; + } + carry = 0; + if (Cflag) carry = 1; + Areg -= (Mem[HLreg] + carry); + setarith(Areg); + Areg = Areg & 0377; + states = 8; + continue; + } + if ((OP & 0370) == 0230) { /* SBs */ + carry = 0; + if (Cflag) carry = 1; + Areg -= (getreg(OP & 07)) + carry ; + setarith(Areg); + Areg = Areg & 0377; + states = 5; + continue; + } + if (OP == 0247) { /* NDM */ + if (HLreg & 0xC000) { + sim_printf("NDM addr > 16K: %o", HLreg); + PC--; + reason = SCPE_STOP; + continue; + } + Areg &= Mem[HLreg]; + setlogical(Areg); + Areg = Areg & 0377; + states = 8; + continue; + } + if ((OP & 0370) == 0240) { /* NDs */ + Areg &= getreg(OP & 07); + setlogical(Areg); + Areg = Areg & 0377; + states = 5; + continue; + } + if (OP == 0257) { /* XRM */ + if (HLreg & 0xC000) { + sim_printf("XRM addr > 16K: %o", HLreg); + PC--; + reason = SCPE_STOP; + continue; + } + Areg ^= Mem[HLreg]; + setlogical(Areg); + Areg &= 0377; + states = 8; + continue; + } + if ((OP & 0370) == 0250) { /* XRs */ + Areg ^= getreg(OP & 07); + setlogical(Areg); + Areg &= 0377; + continue; + } + if (OP == 0267) { /* ORM */ + if (HLreg & 0xC000) { + sim_printf("ORM addr > 16K: %o", HLreg); + PC--; + reason = SCPE_STOP; + continue; + } + Areg |= Mem[HLreg]; + setlogical(Areg); + Areg &= 0377; + states = 8; + continue; + } + if ((OP & 0370) == 0260) { /* ORs */ + Areg |= getreg(OP & 07); + setlogical(Areg); + Areg &= 0377; + states = 5; + continue; + } + if (OP == 0277) { /* CPM */ + if (HLreg & 0xC000) { + sim_printf("CPM addr > 16K: %o", HLreg); + PC--; + reason = SCPE_STOP; + continue; + } + DAR = Areg & 0377; + DAR -= Mem[HLreg]; + setarith(DAR); + states = 8; + continue; + } + if ((OP & 0370) == 0270) { /* CPs */ + DAR = Areg & 0377; + DAR -= getreg(OP & 07); + setarith(DAR); + states = 5; + continue; + } + if ((OP & 0307) == 0104) { /* JMP */ + lo = Mem[PC]; + PC++; + hi = Mem[PC]; + PC++; + PC = ((hi << 8) + lo) & 0x3fff; + states = 11; + continue; + } + if ((OP & 0347) == 0100) { /* JFc */ + if (cond((OP >> 3) & 03) == 0) { + lo = Mem[PC]; + PC++; + hi = Mem[PC]; + PC++; + PC = ((hi << 8) + lo) & 0x3fff; + states = 11; + } else { + PC += 2; + states = 9; + } + continue; + } + if ((OP & 0347) == 0140) { /* JTc */ + if (cond((OP >> 3) & 03) == 1) { + lo = Mem[PC]; + PC++; + hi = Mem[PC]; + PC++; + PC = ((hi << 8) + lo) & 0x3fff; + states = 11; + } else { + PC += 2; + states = 9; + } + continue; + } + if ((OP & 0307) == 0106) { /* CAL */ + lo = Mem[PC]; + PC++; + hi = Mem[PC]; + PC++; + Smem[SPreg] = PC & 0x3fff; + SPreg++; + SPreg = SPreg & 07; + PC = ((hi << 8) + lo) & 0x3fff; + states = 11; + continue; + } + if ((OP & 0347) == 0102) { /* CFc */ + if (cond((OP >> 3) & 03) == 0) { + lo = Mem[PC]; + PC++; + hi = Mem[PC]; + PC++; + Smem[SPreg] = PC & 0x3fff; + SPreg++; + SPreg = SPreg & 07; + PC = ((hi << 8) + lo) & 0x3fff; + states = 11; + } else { + PC += 2; + states = 9; + } + continue; + } + if ((OP & 0347) == 0142) { /* CTc */ + if (cond((OP >> 3) & 03) == 1) { + lo = Mem[PC]; + PC++; + hi = Mem[PC]; + PC++; + Smem[SPreg] = PC & 0x3fff; + SPreg++; + SPreg = SPreg & 07; + PC = ((hi << 8) + lo) & 0x3fff; + states = 11; + } else { + PC += 2; + states = 9; + } + continue; + } + if ((OP & 0307) == 0007) { /* RET */ + SPreg--; + SPreg = SPreg & 07; + PC = Smem[SPreg]; + states = 5; + continue; + } + if ((OP & 0347) == 0003) { /* RFc */ + if (cond((OP >> 3) & 03) == 0) { + SPreg--; + SPreg = SPreg & 07; + PC = Smem[SPreg]; + states = 5; + } else { + states = 3; + } + continue; + } + if ((OP & 0347) == 0043) { /* RTc */ + if (cond((OP >> 3) & 03) == 1) { + SPreg--; + SPreg = SPreg & 07; + PC = Smem[SPreg]; + states = 5; + } else { + states = 3; + } + continue; + } + if ((OP & 0307) == 0005) { /* RST */ + Smem[SPreg] = PC & 0x3fff; + SPreg++; + SPreg = SPreg & 07; + PC = OP & 0070; + states = 5; + continue; + } + if ((OP & 0301) == 0101) { /* INP/OUT */ + DAR = (OP & 0076) >> 1; + if (DAR < 8) /* INP */{ + Areg = dev_table[DAR].routine(0, 0); + states = 8; + } else /* OUT */{ + dev_table[DAR].routine(1, Areg); + states = 6; + } + continue; + } + + /* The Instruction Decode Switch */ switch (IR) { - case 0x02: /* RLC */ - if (A & 0x80) - CF = 1; - else - CF = 0; - A = (A << 1) & 0xFF; - if (CF) - A |= 0x01; - A &= BYTE_R; - break; - - case 0x03: /* RFC */ - if (CF) - ; - else - PC = pop_word(); - break; - - case 0x04: /* ADI */ - A += fetch_byte(1); - setflag3(A); - A &= BYTE_R; - break; - - case 0x05: /* RST 0 */ - case 0x0D: /* RST 1 */ - case 0x15: /* RST 2 */ - case 0x1D: /* RST 3 */ - case 0x25: /* RST 4 */ - case 0x2D: /* RST 5 */ - case 0x35: /* RST 6 */ - case 0x3D: /* RST 7 */ - val = fetch_byte(); - push_word(PC); - PC = val << 3; - break; - - case 0x06: /* LAI */ - A = fetch_byte(1); - A &= BYTE_R; - break; - - case 0x07: /* RET */ - PC = pop_word(); - break; - - case 0x08: /* INB */ - B++; - setflag3(B); - B &= BYTE_R; - break; - - case 0x09: /* DCB */ - B--; - setflag3(B); - B &= BYTE_R; - break; - - case 0x0A: /* RRC */ - if (A & 0x01) - CF = 1; - else - CF = 0; - A = (A >> 1) & 0xFF; - if (CF) - A |= 0x80; - A &= BYTE_R; - break; - - case 0x0B: /* RFZ */ - if (ZF) - ; - else - PC = pop_word(); - break; - - case 0x0C: /* ACI */ - A += fetch_byte(1); - if (CF) - A++; - setflag3(A); - A &= BYTE_R; - break; - - case 0x0E: /* LBI */ - B = fetch_byte(1); - B &= BYTE_R; - break; - - case 0x0F: /* *RET */ - PC = pop_word(); - break; - - case 0x10: /* INC */ - C++; - setflag3(C); - C &= BYTE_R; - break; - - case 0x11: /* DCC */ - C--; - setflag3(C); - C &= BYTE_R; - break; - - case 0x12: /* RAL */ - if (A & 0x80) - CF = 1; - else - CF = 0; - A = (A << 1) & 0xFF; - if (CF) - A |= 0x01; - A &= BYTE_R; - break; - - case 0x13: /* RFS */ - if (SF) - ; - else - PC = pop_word(); - break; - - case 0x14: /* SUI */ - A -= fetch_byte(1); - setflag3(A); - A &= BYTE_R; - break; - - case 0x16: /* LCI */ - C = fetch_byte(1); - C &= BYTE_R; - break; - - case 0x17: /* *RET */ - PC = pop_word(); - break; - - case 0x18: /* IND */ - D++; - setflag3(D); - D &= BYTE_R; - break; - - case 0x19: /* DCD */ - D--; - setflag3(D); - D &= BYTE_R; - break; - - case 0x1A: /* RAR */ - if (A & 0x01) - CF = 1; - else - CF = 0; - A = (A >> 1) & 0xFF; - if (CF) - A |= 0x80; - A &= BYTE_R; - break; - - case 0x1B: /* RFP */ - if (PF) - ; - else - PC = pop_word(); - break; - - case 0x1C: /* SBI */ - A -= fetch_byte(1); - if (CF) - A--; - setflag3(A); - A &= BYTE_R; - break; - - case 0x1E: /* LDI */ - D = fetch_byte(1); - D &= BYTE_R; - break; - - case 0x1F: /* *RET */ - PC = pop_word(); - break; - - case 0x20: /* INE */ - E++; - setflag3(E); - E &= BYTE_R; - break; - - case 0x21: /* DCE */ - E--; - setflag3(E); - E &= BYTE_R; - break; - - case 0x23: /* RTC */ - if (CF) - PC = pop_word(); - break; - - case 0x24: /* NDI */ - A &= fetch_byte(1); - setflag3(A); - A &= BYTE_R; - break; - - case 0x26: /* LEI */ - E = fetch_byte(1); - E &= BYTE_R; - break; - - case 0x27: /* *RET */ - PC = pop_word(); - break; - - case 0x28: /* INH */ - H++; - setflag3(H); - H &= BYTE_R; - break; - - case 0x29: /* DCH */ - H--; - setflag3(H); - H &= BYTE_R; - break; - - case 0x2B: /* RTZ */ - if (ZF) - PC = pop_word(); - break; - - case 0x2C: /* XRI */ - A ^= fetch_byte(1); - setflag3(A); - break; - - case 0x2E: /* LHI */ - H = fetch_byte(1); - H &= BYTE_R; - break; - - case 0x2F: /* *RET */ - PC = pop_word(); - break; - - case 0x30: /* INL */ - L++; - setflag3(L); - L &= BYTE_R; - break; - - case 0x31: /* DCL */ - L--; - setflag3(L); - L &= BYTE_R; - break; - - case 0x33: /* RTS */ - if (SF) - PC = pop_word(); - break; - - case 0x34: /* ORI */ - A |= fetch_byte(1); - setflag3(A); - A &= BYTE_R; - break; - - case 0x36: /* LLI */ - L = fetch_byte(1); - L &= BYTE_R; - break; - - case 0x37: /* *RET */ - PC = pop_word(); - break; - - case 0x3B: /* RTP */ - if (PF) - PC = pop_word(); - break; - - case 0x3C: /* CPI */ - DAR = A; - DAR -= fetch_byte(1); - setflag3(DAR); - break; - - case 0x3E: /* LMI */ - val = fetch_byte(1); - store_m(val); - break; - - case 0x3F: /* *RET */ - PC = pop_word(); - break; - - case 0x40: /* JFC */ - DAR = fetch_word(); - if (CF) - ; - else - PC = DAR; - break; - - case 0x41: /* INP 0 */ - case 0x43: /* INP 1 */ - case 0x45: /* INP 2 */ - case 0x47: /* INP 3 */ - case 0x49: /* INP 4 */ - case 0x4B: /* INP 5 */ - case 0x4D: /* INP 6 */ - case 0x4F: /* INP 7 */ - /**** fix me! */ - break; - - case 0x42: /* CFC */ - adr = fetch_word(); - if (CF) - ; - else { - push_word(PC); - PC = adr; - } - break; - - case 0x44: /* JMP */ - PC = fetch_word(); - break; - - case 0x46: /* CAL */ - adr = fetch_word(); - push_word(PC); - PC = adr; - break; - - case 0x48: /* JFZ */ - DAR = fetch_word(); - if (ZF) - ; - else - PC = DAR; - break; - - case 0x4A: /* CFZ */ - adr = fetch_word(); - if (ZF) - ; - else { - push_word(PC); - PC = adr; - } - break; - - case 0x4C: /* *JMP */ - PC = fetch_word(); - break; - - case 0x4E: /* *CAL */ - adr = fetch_word(); - push_word(PC); - PC = adr; - break; - - case 0x50: /* JFS */ - DAR = fetch_word(); - if (SF) - ; - else - PC = DAR; - break; - - case 0x51: /* OUT 8 */ - case 0x53: /* OUT 9 */ - case 0x55: /* OUT 10 */ - case 0x57: /* OUT 11 */ - case 0x59: /* OUT 12 */ - case 0x5B: /* OUT 13 */ - case 0x5D: /* OUT 14 */ - case 0x5E: /* OUT 15 */ - case 0x61: /* OUT 16 */ - case 0x63: /* OUT 17 */ - case 0x65: /* OUT 18 */ - case 0x67: /* OUT 19 */ - case 0x69: /* OUT 20 */ - case 0x6B: /* OUT 21 */ - case 0x6D: /* OUT 22 */ - case 0x6E: /* OUT 23 */ - case 0x71: /* OUT 24 */ - case 0x73: /* OUT 25 */ - case 0x75: /* OUT 26 */ - case 0x77: /* OUT 27 */ - case 0x79: /* OUT 28 */ - case 0x7B: /* OUT 29 */ - case 0x7D: /* OUT 30 */ - case 0x7E: /* OUT 31 */ - /**** fix me! */ - break; - - case 0x52: /* CFS */ - adr = fetch_word(); - if (SF) - ; - else { - push_word(PC); - PC = adr; - } - break; - - case 0x54: /* *JMP */ - PC = fetch_word(); - break; - - case 0x56: /* *CAL */ - adr = fetch_word(); - push_word(PC); - PC = adr; - break; - - case 0x58: /* JFP */ - DAR = fetch_word(); - if (PF) - ; - else - PC = DAR; - break; - - case 0x5A: /* CFP */ - adr = fetch_word(); - if (PF) - ; - else { - push_word(PC); - PC = adr; - } - break; - - case 0x5C: /* *JMP */ - PC = fetch_word(); - break; - - case 0x5E: /* *CAL */ - adr = fetch_word(); - push_word(PC); - PC = adr; - break; - - case 0x60: /* JTC */ - DAR = fetch_word(); - if (CF) - PC = DAR; - break; - - case 0x62: /* CTC */ - adr = fetch_word(); - if (CF) { - push_word(PC); - PC = adr; - } - break; - - case 0x64: /* *JMP */ - PC = fetch_word(); - break; - - case 0x66: /* *CAL */ - adr = fetch_word(); - push_word(PC); - PC = adr; - break; - - case 0x68: /* JTZ */ - DAR = fetch_word(); - if (ZF) - PC = DAR; - break; - - case 0x6A: /* CTZ */ - adr = fetch_word(); - if (ZF) { - push_word(PC); - PC = adr; - } - break; - - case 0x6C: /* *JMP */ - PC = fetch_word(); - break; - - case 0x6E: /* *CAL */ - adr = fetch_word(); - push_word(PC); - PC = adr; - break; - - case 0x70: /* JTS */ - DAR = fetch_word(); - if (SF) - PC = DAR; - break; - - case 0x72: /* CTS */ - adr = fetch_word(); - if (SF) { - push_word(PC); - PC = adr; - } - break; - - case 0x74: /* *JMP */ - PC = fetch_word(); - break; - - case 0x76: /* *CAL */ - adr = fetch_word(); - push_word(PC); - PC = adr; - break; - - case 0x78: /* JTP */ - DAR = fetch_word(); - if (PF) - PC = DAR; - break; - - case 0x7A: /* CTP */ - adr = fetch_word(); - if (PF) { - push_word(PC); - PC = adr; - } - break; - - case 0x7C: /* *JMP */ - PC = fetch_word(); - break; - - case 0x7E: /* *CAL */ - adr = fetch_word(); - push_word(PC); - PC = adr; - break; - - case 0x80: /* ADA */ - A += A; - setflag4(A); - A &= BYTE_R; - break; - - case 0x81: /* ADB */ - A += B; - setflag4(A); - A &= BYTE_R; - break; - - case 0x82: /* ADC */ - A += C; - setflag4(A); - A &= BYTE_R; - break; - - case 0x83: /* ADD */ - A += D; - setflag4(A); - A &= BYTE_R; - break; - - case 0x84: /* ADE */ - A += E; - setflag4(A); - A &= BYTE_R; - break; - - case 0x85: /* ADH */ - A += H; - setflag4(A); - A &= BYTE_R; - break; - - case 0x86: /* ADL */ - A += L; - setflag4(A); - A &= BYTE_R; - break; - - case 0x87: /* ADM */ - A += fetch_m(); - setflag4(A); - A &= BYTE_R; - break; - - case 0x88: /* ACA */ - A += A; - if (CF) - A++; - setflag4(A); - A &= BYTE_R; - break; - - case 0x89: /* ACB */ - A += B; - if (CF) - A++; - setflag4(A); - A &= BYTE_R; - break; - - case 0x8A: /* ACC */ - A += C; - if (CF) - A++; - setflag4(A); - A &= BYTE_R; - break; - - case 0x8B: /* ACD */ - A += D; - if (CF) - A++; - setflag4(A); - A &= BYTE_R; - break; - - case 0x8C: /* ACE */ - A += E; - if (CF) - A++; - setflag4(A); - A &= BYTE_R; - break; - - case 0x8D: /* ACH */ - A += H; - if (CF) - A++; - setflag4(A); - A &= BYTE_R; - break; - - case 0x8E: /* ACL */ - A += L; - if (CF) - A++; - setflag4(A); - A &= BYTE_R; - break; - - case 0x8F: /* ACM */ - A += fetch_m(); - if (CF) - A++; - setflag4(A); - A &= BYTE_R; - break; - - case 0x90: /* SUA */ - A -= A; - setflag4(A); - A &= BYTE_R; - break; - - case 0x91: /* SUB */ - A -= B; - setflag4(A); - A &= BYTE_R; - break; - - case 0x92: /* SUC */ - A -= C; - setflag4(A); - A &= BYTE_R; - break; - - case 0x93: /* SUD */ - A -= D; - setflag4(A); - A &= BYTE_R; - break; - - case 0x94: /* SUE */ - A -= E; - setflag4(A); - A &= BYTE_R; - break; - - case 0x95: /* SUH */ - A -= H; - setflag4(A); - A &= BYTE_R; - break; - - case 0x96: /* SUL */ - A -= L; - setflag4(A); - A &= BYTE_R; - break; - - case 0x97: /* SUM */ - A -= fetch_m(); - setflag4(A); - A &= BYTE_R; - break; - - case 0x98: /* SBA */ - A -= A; - if (CF) - A--; - setflag4(A); - A &= BYTE_R; - break; - - case 0x99: /* SBB */ - A -= B; - if (CF) - A--; - setflag4(A); - A &= BYTE_R; - break; - - case 0x9A: /* SBC */ - A -= C; - if (CF) - A--; - setflag4(A); - A &= BYTE_R; - break; - - case 0x9B: /* SBD */ - A -= D; - if (CF) - A--; - setflag4(A); - A &= BYTE_R; - break; - - case 0x9C: /* SBE */ - A -= E; - if (CF) - A--; - setflag4(A); - A &= BYTE_R; - break; - - case 0x9D: /* SBH */ - A -= H; - if (CF) - A--; - setflag4(A); - A &= BYTE_R; - break; - - case 0x9E: /* SBL */ - A -= L; - if (CF) - A--; - setflag4(A); - A &= BYTE_R; - break; - - case 0x9F: /* SBM */ - A -= fetch_m(); - if (CF) - A - ; - setflag4(A); - A &= BYTE_R; - break; - - case 0xA0: /* NDA */ - A &= A; - setflag4(A); - A &= BYTE_R; - break; - - case 0xA1: /* NDB */ - A &= B; - setflag4(A); - A &= BYTE_R; - break; - - case 0xA2: /* NDC */ - A &= C; - setflag4(A); - A &= BYTE_R; - break; - - case 0xA3: /* NDD */ - A &= D; - setflag4(A); - A &= BYTE_R; - break; - - case 0xA4: /* NDE */ - A &= E; - setflag4(A); - A &= BYTE_R; - break; - - case 0xA5: /* NDH */ - A &= H; - setflag4(A); - A &= BYTE_R; - break; - - case 0xA6: /* NDL */ - A &= L; - setflag4(A); - A &= BYTE_R; - break; - - case 0xA7: /* NDM */ - A &= fetch_m(); - setflag4(A); - A &= BYTE_R; - break; - - case 0xA8: /* XRA */ - A ^= A; - setflag4(A); - A &= BYTE_R; - break; - - case 0xA9: /* XRB */ - A ^= B; - setflag4(A); - A &= BYTE_R; - break; - - case 0xAA: /* XRC */ - A ^= C; - setflag4(A); - A &= BYTE_R; - break; - - case 0xAB: /* XRD */ - A ^= D; - setflag4(A); - A &= BYTE_R; - break; - - case 0xAC: /* XRE */ - A ^= E; - setflag4(A); - A &= BYTE_R; - break; - - case 0xAD: /* XRH */ - A ^= H; - setflag4(A); - A &= BYTE_R; - break; - - case 0xAE: /* XRL */ - A ^= L; - setflag4(A); - A &= BYTE_R; - break; - - case 0xAF: /* XRM */ - A |= fetch_m(); - setflag4(A); - A &= BYTE_R; - break; - - case 0xB0: /* ORA */ - A |= A; - setflag4(A); - A &= BYTE_R; - break; - - case 0xB1: /* ORB */ - A |= B; - setflag4(A); - A &= BYTE_R; - break; - - case 0xB2: /* ORC */ - A |= C; - setflag4(A); - A &= BYTE_R; - break; - - case 0xB3: /* ORD */ - A |= D; - setflag4(A); - A &= BYTE_R; - break; - - case 0xB4: /* ORE */ - A |= E; - setflag4(A); - A &= BYTE_R; - break; - - case 0xB5: /* ORH */ - A |= H; - setflag4(A); - A &= BYTE_R; - break; - - case 0xB6: /* ORL */ - A |= L; - setflag4(A); - A &= BYTE_R; - break; - - case 0xB7: /* ORM */ - A |= fetch_m(); - setflag4(A); - A &= BYTE_R; - break; - - case 0xB8: /* CPA */ - DAR -= A; - setflag4(DAR); - A &= BYTE_R; - break; - - case 0xB9: /* CPB */ - DAR -= B; - setflag4(DAR); - A &= BYTE_R; - break; - - case 0xBA: /* CPC */ - DAR -= C; - setflag4(DAR); - A &= BYTE_R; - break; - - case 0xBB: /* CPD */ - DAR -= D; - setflag4(DAR); - A &= BYTE_R; - break; - - case 0xBC: /* CPE */ - DAR -= E; - setflag4(DAR); - A &= BYTE_R; - break; - - case 0xBD: /* CPH */ - DAR -= H; - setflag4(DAR); - A &= BYTE_R; - break; - - case 0xBE: /* CPL */ - DAR -= L; - setflag4(DAR); - A &= BYTE_R; - break; - - case 0xBF: /* CPM */ - DAR -= fetch_m(); - setflag4(DAR); - A &= BYTE_R; - break; - - case 0xC0: /* NOP */ - break; - - case 0xC1: /* LAB */ - A = B; - A &= BYTE_R; - break; - - case 0xC2: /* LAC */ - A = C; - A &= BYTE_R; - break; - - case 0xC3: /* LAD */ - A = D; - A &= BYTE_R; - break; - - case 0xC4: /* LAE */ - A = E; - A &= BYTE_R; - break; - - case 0xC5: /* LAH */ - A = H; - A &= BYTE_R; - break; - - case 0xC6: /* LAL */ - A = L; - A &= BYTE_R; - break; - - case 0xC7: /* LAM */ - A = FETCH_M(); - A &= BYTE_R; - break; - - case 0xC8: /* LBA */ - B = A; - B &= BYTE_R; - break; - - case 0xC9: /* LBB */ - B = B; - B &= BYTE_R; - break; - - case 0xCA: /* LBC */ - B = C; - B &= BYTE_R; - break; - - case 0xCB: /* LBD */ - B = D; - B &= BYTE_R; - break; - - case 0xCC: /* LBE */ - B = E; - B &= BYTE_R; - break; - - case 0xCD: /* LBH */ - B = H; - B &= BYTE_R; - break; - - case 0xCE: /* LBL */ - B = L; - B &= BYTE_R; - break; - - case 0xCF: /* LBM */ - B = FETCH_M(); - B &= BYTE_R; - break; - - case 0xD0: /* LCA */ - C = A; - C &= BYTE_R; - break; - - case 0xD1: /* LCB */ - C = B; - C &= BYTE_R; - break; - - case 0xD2: /* LCC */ - C = C; - C &= BYTE_R; - break; - - case 0xD3: /* LCD */ - C = D; - C &= BYTE_R; - break; - - case 0xD4: /* LCE */ - C = E; - C &= BYTE_R; - break; - - case 0xD5: /* LCH */ - C = H; - C &= BYTE_R; - break; - - case 0xD6: /* LCL */ - C = L; - C &= BYTE_R; - break; - - case 0xD7: /* LCM */ - C = FETCH_M(); - C &= BYTE_R; - break; - - case 0xD8: /* LDA */ - D = A; - D &= BYTE_R; - break; - - case 0xD9: /* LDB */ - D = B; - D &= BYTE_R; - break; - - case 0xDA: /* LDC */ - D = C; - D &= BYTE_R; - break; - - case 0xDB: /* LDD */ - D = D; - D &= BYTE_R; - break; - - case 0xDC: /* LDE */ - D = E; - D &= BYTE_R; - break; - - case 0xDD: /* LDH */ - D = H; - D &= BYTE_R; - break; - - case 0xDE: /* LDL */ - D = L; - D &= BYTE_R; - break; - - case 0xDF: /* LDM */ - D = FETCH_M(); - D &= BYTE_R; - break; - - case 0xE0: /* LEA */ - E = A; - E &= BYTE_R; - break; - - case 0xE1: /* LEB */ - E = B; - E &= BYTE_R; - break; - - case 0xE2: /* LEC */ - E = C; - E &= BYTE_R; - break; - - case 0xE3: /* LED */ - E = D; - E &= BYTE_R; - break; - - case 0xE4: /* LEE */ - E = E; - E &= BYTE_R; - break; - - case 0xE5: /* LEH */ - E = H; - E &= BYTE_R; - break; - - case 0xE6: /* LEL */ - E = L; - E &= BYTE_R; - break; - - case 0xE7: /* LEM */ - E = FETCH_M(); - E &= BYTE_R; - break; - - case 0xE8: /* LHA */ - H = A; - H &= BYTE_R; - break; - - case 0xE9: /* LHB */ - H = B; - H &= BYTE_R; - break; - - case 0xEA: /* LHC */ - H = C; - H &= BYTE_R; - break; - - case 0xEB: /* LHD */ - H = D; - H &= BYTE_R; - break; - - case 0xEC: /* LHE */ - H = E; - H &= BYTE_R; - break; - - case 0xED: /* LHH */ - H = H; - H &= BYTE_R; - break; - - case 0xEE: /* LHL */ - H = L; - H &= BYTE_R; - break; - - case 0xEF: /* LHM */ - H = FETCH_M(); - H &= BYTE_R; - break; - - case 0xF0: /* LLA */ - L = A; - L &= BYTE_R; - break; - - case 0xF1: /* LLB */ - L = B; - L &= BYTE_R; - break; - - case 0xF2: /* LLC */ - L = C; - L &= BYTE_R; - break; - - case 0xF3: /* LLD */ - L = D; - L &= BYTE_R; - break; - - case 0xF4: /* LLE */ - L = E; - L &= BYTE_R; - break; - - case 0xF5: /* LLH */ - L = H; - L &= BYTE_R; - break; - - case 0xF6: /* LLL */ - L = L; - L &= BYTE_R; - break; - - case 0xF7: /* LLM */ - L = FETCH_M(); - L &= BYTE_R; - break; - - case 0xF8: /* LMA */ - store_m(A); - break; - - case 0xF9: /* LMB */ - store_m(B); - break; - - case 0xFA: /* LMC */ - store_m(C); - break; - - case 0xFB: /* LMD */ - store_m(D); - break; - - case 0xFC: /* LME */ - store_m(E); - break; - - case 0xFD: /* LMH */ - store_m(H); - break; - - case 0xFE: /* LML */ - store_m(L); - break; - - case 0xFF: /* LMM */ - val = FETCH_M(); - store_m(val); - break; - - default: /* undefined opcode */ - if (i8008_unit.flags & UNIT_OPSTOP) { + /* Arithmetic Group */ + + case 0004: { /* ADI */ + Areg += Mem[PC]; + PC++; + setarith(Areg); + Areg = Areg & 0377; + states = 8; + break; + } + case 0014: { /* ACI */ + carry = 0; + if (Cflag) carry = 1; + Areg += Mem[PC]; + Areg += carry; + PC++; + setarith(Areg); + Areg = Areg & 0377; + states = 8; + break; + } + case 0024: { /* SUI */ + Areg -= Mem[PC]; + PC++; + setarith(Areg); + Areg = Areg & 0377; + states = 8; + break; + } + case 0034: { /* SBI */ + carry = 0; + if (Cflag) carry = 1; + Areg -= (Mem[PC] + carry); + PC++; + setarith(Areg); + Areg = Areg & 0377; + states = 8; + break; + } + + /* Logical instructions */ + + case 0044: { /* NDI */ + Areg &= Mem[PC]; + PC++; + setlogical(Areg); + Areg &= 0377; + states = 8; + break; + } + case 0054: { /* XRI */ + Areg ^= Mem[PC]; + PC++; + setlogical(Areg); + Areg &= 0377; + states = 8; + break; + } + case 0064: { /* ORI */ + Areg |= Mem[PC]; + PC++; + setlogical(Areg); + Areg &= 0377; + states = 8; + break; + } + case 0074: { /* CPI */ + DAR = Areg & 0377; + DAR -= Mem[PC]; + PC++; + setarith(DAR); + states = 8; + break; + } + case 0002: { /* RLC */ + if (Areg & 0x80) + Cflag = 0200000; + else + Cflag = 0; + Areg = (Areg << 1) & 0377; + if (Cflag) + Areg |= 01; + states = 5; + break; + } + case 0012: { /* RRC */ + if (Areg & 0x01) + Cflag = 0200000; + else + Cflag = 0; + Areg = (Areg >> 1) & 0377; + if (Cflag) + Areg |= 0x80; + states = 5; + break; + } + case 0022: { /* RAL */ + DAR = Cflag; + if (Areg & 0x80) + Cflag = 0200000; + else + Cflag = 0; + Areg = (Areg << 1) & 0377; + if (DAR) + Areg |= 0x01; + else + Areg &= 0xFE; + states = 5; + break; + } + case 0032: { /* RAR */ + DAR = Cflag; + if (Areg & 0x01) + Cflag = 0200000; + else + Cflag = 0; + Areg = (Areg >> 1) & 0377; + if (DAR) + Areg |= 0x80; + else + Areg &= 0x7F; + states = 5; + break; + } + default: { + if (cpu_unit.flags & UNIT_OPSTOP) { reason = STOP_OPCODE; PC--; } break; } } +} + /* Simulation halted */ - saved_PC = PC; - return reason; +saved_PCreg = PC; +return reason; } -/* store byte to (HL) */ -void store_m(uint32 val) +/* Test an 8008 flag condition and return 1 if true, 0 if false + */ +int32 cond(int32 con) { - DAR = (H << 8) + L; - DAR &= WORD_R14; - ret get_mword(DAR); -} - -/* get byte from (HL) */ -uint32 fetch_m(void) -{ - DAR = (H << 8) + L; - DAR &= WORD_R14; - put_mword(DAR, val); -} - -/* dump the registers */ -void dumpregs(void) -{ - sim_printf(" A=%02X B=%02X C=%02X D=%04X E=%02X H=%04X L=%02X\n", - A, B, C, D, E, H, L); - sim_printf(" CF=%d ZF=%d SF=%d PF=%d\n", - CF, ZF, SF, PF); -} - -/* fetch an instruction or byte */ -int32 fetch_byte(int32 flag) -{ - uint32 val; - - val = get_mbyte(PC) & 0xFF; /* fetch byte */ - if (i8008_dev.dctrl & DEBUG_asm || uptr->flags & UNIT_TRACE) { /* display source code */ - switch (flag) { - case 0: /* opcode fetch */ - sim_printf("OP=%02X %04X %s", val, PC, opcode[val]); - break; - case 1: /* byte operand fetch */ - sim_printf("0%02XH", val); - break; - } + switch (con) { + case 0: /* carry */ + if (Cflag != 0) return (1); + break; + case 1: /* zero */ + if (Zflag != 0) return (1); + break; + case 2: /* sign */ + if (Sflag != 0) return (1); + break; + case 3: /* parity */ + if (Pflag != 0) return (1); + break; + default: + break; } - PC = (PC + 1) & ADDRMASK; /* increment PC */ - val &= BYTE_R; - return val; + return (0); } -/* fetch a word */ -int32 fetch_word(void) +/* Set the arry, ign, ero and

arity flags following + an arithmetic operation on 'reg'. + */ +void setarith(int32 reg) { - uint16 val; - val = get_mbyte(PC) & BYTE_R; /* fetch low byte */ - val |= get_mbyte(PC + 1) << 8; /* fetch high byte */ - if (i8008_dev.dctrl & DEBUG_asm || uptr->flags & UNIT_TRACE) /* display source code */ - sim_printf("0%04XH", val); - PC = (PC + 2) & ADDRMASK; /* increment PC */ - val &= WORD_R14; - return val; -} - -/* push a word to the stack frame */ -void push_word(uint16 val) -{ - stack_frame[SP] = val; - SP++; - if (SP == 8) - SP = 0; -} - -/* pop a word from the stack frame */ -uint16 pop_word(void) -{ - SP--; - if (SP < 0) - SP = 7; - return stack_frame[SP]; -} - - -/* Set the arry, ign, ero and verflow flags following - an operation on 'reg'. -*/ - -void setflag4(int32 reg) -{ if (reg & 0x100) - CF = 1; - else - CF = 0; + Cflag = 0200000; + else + Cflag = 0; if (reg & 0x80) - SF = 0; - else - SF = 1; - if ((reg & BYTE_R) == 0) - ZF = 1; - else - ZF = 0; + Sflag = 0200000; + else + Sflag = 0; + if ((reg & 0xff) == 0) + Zflag = 0200000; + else + Zflag = 0; parity(reg); } -/* Set the arry, ign and ero flags following - an operation on 'reg'. -*/ - -void setflag3(int32 reg) +/* Set the arry, ign, ero amd

arity flags following + a logical (bitwise) operation on 'reg'. + */ +void setlogical(int32 reg) { - CF = 0; + Cflag = 0; if (reg & 0x80) - SF = 0; - else - SF = 1; - if ((reg & BYTE_R) == 0) - ZF = 1; - else - ZF = 0; + Sflag = 0200000; + else + Sflag = 0; + if ((reg & 0xff) == 0) + Zflag = 0200000; + else + Zflag = 0; parity(reg); } -/* Set the Parity (PF) flag based on parity of 'reg', i.e., number -of bits on even: PF=1, else PF=0 -*/ - +/* Set the Parity (P) flag based on parity of 'reg', i.e., number + of bits on even: P=1, else P=0 + */ void parity(int32 reg) { int32 bc = 0; @@ -1805,69 +930,136 @@ void parity(int32 reg) if (reg & 0x20) bc++; if (reg & 0x40) bc++; if (reg & 0x80) bc++; - if (bc & 0x01) - PF = 0; - else - PF = 1; + if (bc & 1) /* odd number of bits */ + Pflag = 0; + else + Pflag = 0200000; } - - -/* Reset routine */ - -t_stat i8008_reset (DEVICE *dptr) +/* Set the ign, ero amd

arity flags following + an INR/DCR operation on 'reg'. + */ +void setinc(int32 reg) { - int i; - CF = SF = ZF = PF = 0; - saved_PC = 0; - int_req = 0; - for (i = 0; i < 7; i++) - stack_frame[i] = 0; - sim_brk_types = sim_brk_dflt = SWMASK ('E'); - sim_printf(" 8008: Reset\n"); + if (reg & 0x80) + Sflag = 0200000; + else + Sflag = 0; + if ((reg & 0xff) == 0) + Zflag = 0200000; + else + Zflag = 0; + parity(reg); +} + +/* Get an 8008 register and return it + */ +int32 getreg(int32 reg) +{ + switch (reg) { + case 0: + return (Areg & 0377); + case 1: + return (Breg & 0377); + case 2: + return (Creg & 0377); + case 3: + return (Dreg & 0377); + case 4: + return (Ereg & 0377); + case 5: + return ((HLreg >> 8) & 0377); + case 6: + return (HLreg & 0377); + default: + break; + } + return 0; +} + +/* Put a value into an 8008 register + */ +void putreg(int32 reg, int32 val) +{ + switch (reg) { + case 0: + Areg = val & 0377; + break; + case 1: + Breg = val & 0377; + break; + case 2: + Creg = val & 0377; + break; + case 3: + Dreg = val & 0377; + break; + case 4: + Ereg = val & 0377; + break; + case 5: + HLreg = HLreg & 0x00ff; + HLreg = HLreg | ((val <<8) & 0xff00); + break; + case 6: + HLreg = HLreg & 0xff00; + HLreg = HLreg | (val & 0x00ff); + break; + default: + break; + } +} + +/* Reset routine + */ +t_stat cpu_reset (DEVICE *dptr) +{ +Cflag = 0; +Zflag = 0; +saved_PCreg = 0; +int_req = 0; +sim_brk_types = sim_brk_dflt = SWMASK ('E'); +return SCPE_OK; +} + +/* Memory examine + */ +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ +if (addr >= MEMSIZE) + return SCPE_NXM; +if (vptr != NULL) + *vptr = Mem[addr] & 0377; +return SCPE_OK; +} + +/* Memory deposit + */ +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ + if (addr >= MEMSIZE) return SCPE_NXM; + Mem[addr] = val & 0377; return SCPE_OK; } -/* Memory examine */ - -t_stat i8008_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +/* Set memory size + */ +t_stat cpu_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc) { - if (addr >= MEMSIZE) - return SCPE_NXM; - if (vptr != NULL) - *vptr = get_mbyte(addr); +int32 mc = 0; +uint32 i; + +if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0)) + return SCPE_ARG; +for (i = val; i < MEMSIZE; i++) + mc = mc | Mem[i]; +if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) return SCPE_OK; -} - -/* Memory deposit */ - -t_stat i8008_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) -{ - if (addr >= MEMSIZE) - return SCPE_NXM; - put_mbyte(addr, val); - return SCPE_OK; -} - -/* This is the binary loader. The input file is considered to be - a string of literal bytes with no special format. The load - starts at the current value of the PC. -*/ - -int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag) -{ - int32 i, addr = 0, cnt = 0; - - if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; - addr = saved_PC; - while ((i = getc (fileref)) != EOF) { - put_mbyte(addr, i); - addr++; - cnt++; - } /* end while */ - sim_printf ("%d Bytes loaded.\n", cnt); - return (SCPE_OK); +MEMSIZE = val; +for (i = MEMSIZE; i < MAXMEMSIZE; i++) + Mem[i] = 0377; +return SCPE_OK; } /* Symbolic output @@ -1881,42 +1073,48 @@ int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag) Outputs: status = error code */ - t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) { - int32 cflag, c1, c2, inst, adr; +int32 cflag, c1, c2, inst, adr; - cflag = (uptr == NULL) || (uptr == &i8008_unit); - c1 = (val[0] >> 8) & 0x7F; - c2 = val[0] & 0x7F; - if (sw & SWMASK ('A')) { - fprintf (of, (c2 < 0x20)? "<%02X>": "%c", c2); - return SCPE_OK; - } - if (sw & SWMASK ('C')) { - fprintf (of, (c1 < 0x20)? "<%02X>": "%c", c1); - fprintf (of, (c2 < 0x20)? "<%02X>": "%c", c2); - return SCPE_OK; - } - if (!(sw & SWMASK ('M'))) return SCPE_ARG; - inst = val[0]; - fprintf (of, "%s", opcode[inst]); - if (oplen[inst] == 2) { - if (strchr(opcode[inst], ' ') != NULL) - fprintf (of, ","); - else fprintf (of, " "); - fprintf (of, "%h", val[1]); - } - if (oplen[inst] == 3) { - adr = val[1] & 0xFF; - adr |= (val[2] << 8) & 0xff00; - if (strchr(opcode[inst], ' ') != NULL) - fprintf (of, ","); - else fprintf (of, " "); - fprintf (of, "%h", adr); - } - return -(oplen[inst] - 1); +cflag = (uptr == NULL) || (uptr == &cpu_unit); +c1 = (val[0] >> 8) & 0177; +c2 = val[0] & 0177; +if (sw & SWMASK ('A')) { + fprintf (of, (c2 < 040)? "<%03o>": "%c", c2); + return SCPE_OK; +} +if (sw & SWMASK ('C')) { + fprintf (of, (c1 < 040)? "<%03o>": "%c", c1); + fprintf (of, (c2 < 040)? "<%03o>": "%c", c2); + return SCPE_OK; +} +if (!(sw & SWMASK ('M'))) + return SCPE_ARG; +inst = val[0]; +fprintf (of, "%s", opcode[inst]); + +/* Handle INP/OUT op codes */ +if ((inst & 0301) == 0101) { + fprintf (of, " %o", (inst & 076) >> 1); +} + +if (oplen[inst] == 2) { + if (strchr(opcode[inst], ' ') != NULL) + fprintf (of, ","); + else fprintf (of, " "); + fprintf (of, "%o", val[1]); +} +if (oplen[inst] == 3) { + adr = val[1] & 0xFF; + adr |= (val[2] << 8) & 0xff00; + if (strchr(opcode[inst], ' ') != NULL) + fprintf (of, ","); + else fprintf (of, " "); + fprintf (of, "%o", adr); +} +return -(oplen[inst] - 1); } /* Symbolic input @@ -1930,73 +1128,105 @@ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, Outputs: status = error status */ - -t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) +t_stat parse_sym (CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) { - int32 cflag, i = 0, j, r; - char gbuf[CBUFSIZE]; +int32 cflag, i = 0, j, r; +char gbuf[CBUFSIZE]; +int32 opcode_inp = 0; +int32 opcode_out = 0; - cflag = (uptr == NULL) || (uptr == &i8008_unit); - while (isspace (*cptr)) cptr++; /* absorb spaces */ - if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ - if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ - val[0] = (uint32) cptr[0]; - return SCPE_OK; - } - if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */ - if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ - val[0] = ((uint32) cptr[0] << 8) + (uint32) cptr[1]; - return SCPE_OK; - } +memset (gbuf, 0, sizeof (gbuf)); +cflag = (uptr == NULL) || (uptr == &cpu_unit); +while (isspace (*cptr)) + cptr++; /* absorb spaces */ +if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ + if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ + val[0] = (uint32) cptr[0]; + return SCPE_OK; +} +if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */ + if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ + val[0] = ((uint32) cptr[0] << 8) + (uint32) cptr[1]; + return SCPE_OK; +} /* An instruction: get opcode (all characters until null, comma, - or numeric (including spaces). -*/ - - while (1) { - if (*cptr == ',' || *cptr == '\0' || - isdigit(*cptr)) - break; - gbuf[i] = toupper(*cptr); - cptr++; - i++; - } + or numeric (including spaces). */ +while (i < sizeof (gbuf) - 4) { + if (*cptr == ',' || *cptr == '\0' || + sim_isdigit(*cptr)) + break; + gbuf[i] = toupper(*cptr); + cptr++; + i++; +} /* Allow for RST which has numeric as part of opcode */ +if (toupper(gbuf[0]) == 'R' && + toupper(gbuf[1]) == 'S' && + toupper(gbuf[2]) == 'T') { + gbuf[i] = toupper(*cptr); + cptr++; + i++; +} - if (toupper(gbuf[0]) == 'R' && - toupper(gbuf[1]) == 'S' && - toupper(gbuf[2]) == 'T') { - gbuf[i] = toupper(*cptr); - cptr++; - i++; - } +/* Handle INP and OUT opcodes */ +if (toupper(gbuf[0]) == 'I' && + toupper(gbuf[1]) == 'N' && + toupper(gbuf[2]) == 'P') { + opcode_inp = 1; +} +if (toupper(gbuf[0]) == 'O' && + toupper(gbuf[1]) == 'U' && + toupper(gbuf[2]) == 'T') { + opcode_out = 1; +} /* kill trailing spaces if any */ - gbuf[i] = '\0'; - for (j = i - 1; gbuf[j] == ' '; j--) { - gbuf[j] = '\0'; - } +gbuf[i] = '\0'; +sim_trim_endspc (gbuf); + +/* kill trailing spaces if any */ +gbuf[i] = '\0'; +sim_trim_endspc (gbuf); /* find opcode in table */ - for (j = 0; j < 256; j++) { - if (strcmp(gbuf, opcode[j]) == 0) - break; - } - if (j > 255) /* not found */ - return SCPE_ARG; - - val[0] = j; /* store opcode */ - if (oplen[j] < 2) /* if 1-byter we are done */ - return SCPE_OK; - if (*cptr == ',') cptr++; - cptr = get_glyph(cptr, gbuf, 0); /* get address */ - sscanf(gbuf, "%o", &r); - if (oplen[j] == 2) { - val[1] = r & 0xFF; - return (-1); - } - val[1] = r & 0xFF; - val[2] = (r >> 8) & 0xFF; - return (-2); +for (j = 0; j < 256; j++) { + if (strcmp(gbuf, opcode[j]) == 0) + break; } +if (j > 255) /* not found */ + return sim_messagef (SCPE_ARG, "No such opcode: %s\n", gbuf); + +val[0] = j; /* store opcode */ +if ((oplen[j] < 2) && (opcode_inp == 0) && (opcode_out == 0)) /* if 1-byter */ + return SCPE_OK; /* or not INP/OUT we are done */ +if (*cptr == ',') + cptr++; +cptr = get_glyph(cptr, gbuf, 0); /* get address */ +sscanf(gbuf, "%o", &r); +if (opcode_inp) { + if (r <= 7) { + val[0] |= r << 1; + return SCPE_OK; + } else { + return SCPE_ARG; + } +} +if (opcode_out) { + if ((8 <= r) && (r <= 31)) { + val[0] |= r << 1; + return SCPE_OK; + } else { + return SCPE_ARG; + } +} +if (oplen[j] == 2) { + val[1] = r & 0xFF; + return (-1); +} +val[1] = r & 0xFF; +val[2] = (r >> 8) & 0xFF; +return (-2); +} + diff --git a/Intel-Systems/scelbi/scelbi.txt b/Intel-Systems/scelbi/scelbi.txt new file mode 100644 index 00000000..b65c16c8 --- /dev/null +++ b/Intel-Systems/scelbi/scelbi.txt @@ -0,0 +1,139 @@ +SCELBI Sumulator with Intel 8008 CPU +==================================== + +1. Background. + + The SCELBI (SCientic-ELectronics-BIology) computer was probably +the first commercially available micro-computer marketed toward hobbyist. +The first market announce for SCELBI-8H was a tiny advertisement in the +back of the March 1974 issue of QST, an amateur radio magazine. +The computer was built around the Intel 8008 architecture. There were two +versions of the SCELBI. The first version was called the 8H. The H standing +for hobbyist. The second version was called the 8B, the B standing for +business. It had all the features of the 8H, but added support for up +to 16K of memory. As the default memory configuration for the SCELBI simulator +is 16K, it is really a SCELBI-8B that is simulated. More information about the +SCELBI computer can be found at: http://www.willegal.net/scelbi/scelbi.html +and http://history-computer.com/ModernComputer/Personal/Scelbi.html. + +2. Hardware + + We are simulating a SCELBI-8B from about 1975, with the following +configuration: + + device simulates + name(s) + + CPU SCELBI-8B with Intel 8008 CPU, 16KB of RAM. + TTY Serial "bit banger" interface (commonly to an + ASR-33), is assumed to be connected to a serial + "glass TTY" that is your terminal running the Simulator. + PTR Paper Tape Reader, but not implemented yet. + +2.1 CPU + + You may select different memory sizes, the default size is 16K. + + SET CPU 4K + SET CPU 8K + SET CPU 12K + SET CPU 16K + +CPU Registers include the following: + + name size comments + + PC 14 The Program Counter + A 8 The accumulator + B 8 The B register. + C 8 The C register. + D 8 The E register. + E 8 The E register. + HL 16 The HL register pair. H is the top 8 bits, L is + the bottom 8 bits. + SP 3 Stack Pointer to return address in stack. + CF 1 Carry Flag. + ZF 1 Zero Flag. + PF 1 Parity Flag. + SF 1 Sign Flag. + WRU 8 The interrupt character. This starts as 005 + (Ctrl-E) + +2.2 The TTY Serial Interface + + This interface simulates a "bitbanger" TTY interface as +implemented on the SCELBI computer in the SCELBAL source code. +Inport 2 bit 7 is used as input from the TTY and Outport 2 bit 0 +is used as output to the TTY. In other SCELBI documentation Inport 5 +is used for input from the TTY and Outport 6 is used for output to the TTY. +The I/O simulation routines are mapped in the i/o configuration table +to both port variants. + + There are also functions that support simulated I/O for +an Intel 8008 computer built for a master thesis in 1975. +These functions are however not mapped in the i/o configuration +table as they conflict with the SCELBI TTY interface. + +3. Sample Software + + SCELBAL was called the SCientific ELementary BAsic for the 8008 +and 8080 by SCELBI Computer Consulting. SCELBAL could be run on a SCELBI +or other 8008 based machine that had 8K of memory. SCELBAL completely +supported floating point math with 6 digits of precision. As time went on, +additional packages including matrix arithmetic and math functions were added. + +SCELBAL can be downloaded from http://www.willegal.net/scelbi/scelbal.html +there are assembler source, hex and binary images available for three +variants of SCELBAL. The web page also includes information about SCELBAL +and a link to a scan of the SCELBI's SCELBAL book: +http://www.scelbi.com/files/docs/scelbal/SCELBAL.pdf +In chapter 14 of the SCELBAL book there is a language reference. + +To run SCELBAL on the SCELBI simulator, download the binary code from: +http://www.willegal.net/scelbi/software/sc1.bin + +Then start the simulator, load the code and run: + +SCELBI simulator V4.0-0 Beta git commit id: ba447399 +sim> d pc 100 +sim> load sc1.bin +11942 Bytes loaded. +sim> g + +READY + +SCR + +READY + +10 A=1 +20 B=7 +30 PRINT "A + B ="; +40 PRINT A+B +50 END +LIST +10 A=1 +20 B=7 +30 PRINT "A + B ="; +40 PRINT A+B +50 END + +READY + +RUN +A + B = 8.0 + +READY + + +Simulation stopped, PC: 000103 (INP 5) +sim> exit + + +Some notes on SCELBAL: + Only upper case is recognized. + Always do SCR before entering a program, otherwise strange + things will happen. + The binary code at the web page above shall be loaded starting + at address 0100. The program shall also start to run from + address 0100. diff --git a/Intel-Systems/scelbi/scelbi_io.c b/Intel-Systems/scelbi/scelbi_io.c new file mode 100644 index 00000000..22fa6e6c --- /dev/null +++ b/Intel-Systems/scelbi/scelbi_io.c @@ -0,0 +1,345 @@ +/* scelbi_io.c: I/O for the SCELBI computer. + + Copyright (c) 2017, Hans-Ake Lund + + 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. + + + This interface simulates a "bitbanger" TTY interface as implemented + on the SCELBI computer in the SCELBAL source code. + Inport 2 bit 7 is used as input from the TTY and + Outport 2 bit 0 is used as output to the TTY. + In SCELBI documentation Inport 5 is used for input from the TTY + and Outport 6 is used for output to the TTY. + The I/O simulation routines are mapped to both port combinations. + + + There are also functions that support simulated I/O for + the Intel 8008 computer built for a master thesis in 1975. + These functiona are however not mapped in the i/o configuration + table as they conflict with the SCELBI TTY interface. + Note that Inport 0 is read by the assembler code as INP 0 + Outport 0 is written by the AS Macro Assembler code as OUT 10 (octal) + + The following i/o ports were used in this computer: + Outport 0: used to select device for reading from Inport 0 + and writing to Outport 3. + Inport 0: used to read external data. + Outport 3: used to write external data. + + Outport 1: used to save interupt state, connected to Inport 1. + Outport 2: used to save interupt state, connected to Inport 2. + + Inport 3: used to input data from tape-reader + Outport 4: used to output character to printer (implemented). + Inport 5: used to input character from keyboard (implemented). + + Inport 4: used for status flags for the ports (Flagport). + Flag 1 (bit 0): set to 1 when printer ready (implemented). + Flag 2 (bit 1): set to 1 when input available from tape-reader. + Flag 3 (bit 2): set to 1 when tape in tape-reader. + Flag 5 (bit 4): set to 1 when character available from keyboard (implemented). + Flag 7 (bit 6): set to 1 when the reset key on the computer is pressed. + + Inport 7: used to start the printer motor, just using an output pulse, + no data is read. + + 04-Sep-17 HAL Working version of SCELBI simulator + 12-Sep-17 HAL Modules restructured in "Intel-Systems" directory + +*/ + +#include +#include "system_defs.h" + +/* This is the I/O configuration table. There are 8 possible + input device addresses (octal 0 - 7) and 24 possible output + device addresses (octal 10 - 37). + The port numbers are specified as for the 8008 AS Macro Assembler, + in other 8008 assemblers outport 012 (octal) may be specified as 2. + If a device is plugged to a port it's routine + address is here, 'nulldev' means no device is available. + */ +int32 ttyout_d(int32 io, int32 data); +int32 ttyin_d(int32 io, int32 data); +int32 prt_d(int32 io, int32 data); +int32 kbd_d(int32 io, int32 data); +int32 iostat_s(int32 io, int32 data); +int32 nulldev(int32 io, int32 data); + +struct idev dev_table[32] = { +{&nulldev}, {&nulldev}, {&ttyin_d}, {&nulldev}, /* 000 input 0 - 3 */ +{&nulldev}, {&ttyin_d}, {&nulldev}, {&nulldev}, /* 004 input 4 - 7 */ +{&nulldev}, {&nulldev}, {&ttyout_d}, {&nulldev}, /* 010 output 8 - 11 */ +{&nulldev}, {&nulldev}, {&ttyout_d}, {&nulldev}, /* 014 output 12 - 15 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 020 output 16 - 19 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 024 output 20 - 23 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 030 output 24 - 27 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev} /* 034 output 28 - 31 */ +}; + +#define UNIT_V_ANSI (UNIT_V_UF + 0) /* ANSI mode */ +#define UNIT_ANSI (1 << UNIT_V_ANSI) + +t_stat tty_svc (UNIT *uptr); +t_stat tty_reset (DEVICE *dptr); +t_stat ptr_svc (UNIT *uptr); +t_stat ptr_reset (DEVICE *dptr); + +/* I/O Data Structures */ + +/* TTY, TeleTYpewriter - console input/output + */ +UNIT tty_unit = { UDATA (&tty_svc, 0, 0), KBD_POLL_WAIT }; + +REG tty_reg[] = { + { ORDATA (DATA, tty_unit.buf, 8) }, + { ORDATA (STAT, tty_unit.u3, 8) }, + { NULL } +}; + +MTAB tty_mod[] = { + { UNIT_ANSI, 0, "TTY", "TTY", NULL }, + { UNIT_ANSI, UNIT_ANSI, "ANSI", "ANSI", NULL }, + { 0 } +}; + +DEVICE tty_dev = { + "TTY", &tty_unit, tty_reg, tty_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &tty_reset, + NULL, NULL, NULL +}; + +/* PTR, Paper Tape Reader - not implemented yet + */ +UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ + UNIT_ATTABLE, 0), KBD_POLL_WAIT }; + +REG ptr_reg[] = { + { ORDATA (DATA, ptr_unit.buf, 8) }, + { ORDATA (STAT, ptr_unit.u3, 8) }, + { ORDATA (POS, ptr_unit.pos, T_ADDR_W) }, + { NULL } +}; + +DEVICE ptr_dev = { + "PTR", &ptr_unit, ptr_reg, NULL, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &ptr_reset, + NULL, NULL, NULL +}; + +/* Service routines to handle simulator functions */ + +/* Service routine for TTY - actually gets char & places in buffer + */ +t_stat tty_svc (UNIT *uptr) +{ + int32 temp; + + sim_activate (&tty_unit, tty_unit.wait); /* continue poll */ + if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) + return (temp); /* no char or error? */ + tty_unit.buf = temp & 0377; /* Save char */ + tty_unit.u3 |= 0x10; /* Set status + Flag 5 (bit 3) == 1 */ + + /* Do any special character handling here */ + + tty_unit.pos++; + return SCPE_OK; +} + +/* Service routine for Paper Tape Reader - not implemented yet + */ +t_stat ptr_svc (UNIT *uptr) +{ + return SCPE_OK; +} + +/* Reset routines */ + +/* Reset routine for TTY + */ +t_stat tty_reset (DEVICE *dptr) +{ + tty_unit.buf = 0; /* Data */ + tty_unit.u3 = 0x01; /* Status + Flag 1 (bit 0) == 1 + printer always ready */ + sim_activate (&tty_unit, tty_unit.wait); /* activate unit */ + return SCPE_OK; +} + +/* Reset routine for Paper Tape Reader - not implemented yet + */ +t_stat ptr_reset (DEVICE *dptr) +{ + ptr_unit.buf = 0; + ptr_unit.u3 = 0; + sim_cancel (&ptr_unit); /* deactivate unit */ + return SCPE_OK; +} + +/* I/O instruction handlers for the 8008 simulator. + Called from the CPU module when an IN or OUT instruction is issued. + Each function is passed an 'io' flag, where 0 means a read from + the port, and 1 means a write to the port. On input, the actual + input (io == 0) is passed as the return value, + on output (io != 0), 'data' is written to the device. + */ + +/* I/O instruction handlers for the SCELBI bitbanger serial interface + */ +int32 ttyin_bitcntr = 0; +int32 ttyin_charin = 0; + +/* TTY input routine, assumes 1 start bit, 8 databits and 2 stop bits. + the assumed number of INP instructions for each character are 9 + */ +int32 ttyin_d(int32 io, int32 data) +{ + int32 newbit; + + /* if (ttyin_bitcntr != 0) { + sim_printf("io: %d, bitcntr: %d, charin: 0%o\n", + io, ttyin_bitcntr, ttyin_charin); + } + */ + if (io != 0) { /* not an INP instruction */ + return 0; + } + if (ttyin_bitcntr == 0) { + if (tty_unit.u3 & 0x10) { + /* Character available if Flag 5 (bit 4) set */ + ttyin_charin = tty_unit.buf | 0x80; /* bit 7 always set in SCELBAL */ + tty_unit.u3 = tty_unit.u3 & 0xEF; /* Reset Flag 5 (bit 4) */ + ttyin_bitcntr = 1; + return (0); /* start bit */ + } + else { + return (0x80); /* no start bit */ + } + } + if (ttyin_bitcntr > 7) { /* last data bit */ + if (ttyin_charin & 1) + newbit = 0x80; + else + newbit = 0x00; + ttyin_bitcntr = 0; + return (newbit); + } + if (ttyin_charin & 1) + newbit = 0x80; + else + newbit = 0x00; + ttyin_bitcntr++; + ttyin_charin = ttyin_charin >> 1; + return (newbit); +} + +int32 ttyout_bitcntr = 0; +int32 ttyout_charout = 0; + +/* TTY output routine, assumes 1 start bit, 8 databits and 2 stop bits. + the assumed number of OUT instructions for each character are 10 + */ +int32 ttyout_d(int32 io, int32 data) +{ + int32 newbit; + + /* sim_printf("io: %d, data: 0%o, bit0: %d, bitcntr: %d, charout: 0%o\n", + io, data, (data & 1), ttyout_bitcntr, ttyout_charout); + */ + + if (io == 0) { /* not an OUT instruction */ + return 0; + } + if ((ttyout_bitcntr == 0) && ((data & 1) == 0)) { /* start bit */ + ttyout_bitcntr = 1; + return 0; + } + if (ttyout_bitcntr == 8) { /* last bit in character */ + if (data & 1) + newbit = 0x80; + else + newbit = 0x00; + ttyout_charout = ttyout_charout >> 1; + ttyout_charout = ttyout_charout | newbit; + if (ttyout_charout != 0224) /* avoid printing CTRL-T */ + sim_putchar(ttyout_charout & 0x7f); /* bit 7 always set in SCELBAL */ + ttyout_bitcntr++; + return 0; + } + if (ttyout_bitcntr > 8) { /* stop bit */ + ttyout_charout = 0; + ttyout_bitcntr = 0; + return 0; + } + if (data & 1) + newbit = 0x80; + else + newbit = 0x00; + ttyout_charout = ttyout_charout >> 1; + ttyout_charout = ttyout_charout | newbit; + ttyout_bitcntr++; + return 0; +} + +/* I/O instruction handlers for the master thesis computer hardware. + */ + +/* Get status byte from Flagport + */ +int32 iostat_s(int32 io, int32 data) +{ + if (io == 0) + return (tty_unit.u3); + else + return (0); +} + +/* Get character from keyboard + */ +int32 kbd_d(int32 io, int32 data) +{ + if (io == 0) { + tty_unit.u3 = tty_unit.u3 & 0xEF; /* Reset Flag 5 (bit 4) */ + return (tty_unit.buf | 0x80); /* bit 7 always set in SCELBAL */ + } + return 0; +} + +/* Put character to printer + */ +int32 prt_d(int32 io, int32 data) +{ + if (io != 0) { + sim_putchar(data & 0x7f); /* bit 7 always set in SCELBAL */ + } + return 0; +} + +/* I/O instruction handler for unused ports + */ +int32 nulldev(int32 flag, int32 data) +{ + if (flag == 0) + return (0377); + return 0; +} diff --git a/Intel-Systems/scelbi/scelbi_sys.c b/Intel-Systems/scelbi/scelbi_sys.c new file mode 100644 index 00000000..180ae5be --- /dev/null +++ b/Intel-Systems/scelbi/scelbi_sys.c @@ -0,0 +1,97 @@ + +/* scelbi_sys.c: Intel 8008 CPU system interface for the SCELBI computer. + + Copyright (c) 2017, Hans-Ake Lund + + 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 Hans-Ake Lund shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Hans-Ake Lund. + + 04-Sep-17 HAL Working version of CPU simulator for SCELBI computer + 12-Sep-17 HAL Modules restructured in "Intel-Systems" directory + +*/ + +#include "system_defs.h" + +extern DEVICE cpu_dev; +extern UNIT cpu_unit; +extern REG cpu_reg[]; +extern DEVICE tty_dev; +extern DEVICE ptr_dev; +extern unsigned char Mem[]; +extern int32 saved_PCreg; + +/* SCP data structures + + sim_name simulator name string + sim_PC pointer to saved PC register descriptor + sim_emax number of words needed for examine + sim_devices array of pointers to simulated devices + sim_stop_messages array of pointers to stop messages + sim_load binary loader +*/ + +char sim_name[] = "SCELBI"; + +REG *sim_PC = &cpu_reg[0]; + +int32 sim_emax = 4; + +DEVICE *sim_devices[] = { + &cpu_dev, + &tty_dev, + &ptr_dev, + NULL +}; + +const char *sim_stop_messages[] = { + "Unknown error", + "Unknown I/O Instruction", + "HALT instruction", + "Breakpoint", + "Invalid Opcode" +}; + +/* This is the binary loader. The input file is considered to be + a string of literal bytes with no format special format. The + load starts at the current value of the PC. +*/ +t_stat sim_load (FILE *fileref, CONST char *cptr, CONST char *fnam, int flag) +{ +int32 i, addr = 0, cnt = 0; + +if (*cptr != 0) + return SCPE_ARG; +if (flag != 0) { + sim_printf ("DUMP command not supported.\n"); + return SCPE_ARG; + } +addr = saved_PCreg; +while ((i = getc (fileref)) != EOF) { + if (addr >= MAXMEMSIZE) + return (SCPE_NXM); + Mem[addr] = i; + addr++; + cnt++; +} /* end while */ +sim_printf ("%d Bytes loaded.\n", cnt); +return (SCPE_OK); +} diff --git a/Intel-Systems/scelbi/system_defs.h b/Intel-Systems/scelbi/system_defs.h new file mode 100644 index 00000000..9dbfd96c --- /dev/null +++ b/Intel-Systems/scelbi/system_defs.h @@ -0,0 +1,50 @@ +/* system_defs.h: Definitions for the SCELBI computer. + + Copyright (c) 2017, Hans-Ake Lund + + 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 Hans-Ake Lund shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Hans-Ake Lund. + + 04-Sep-17 HAL Working version of SCELBI simulator + 12-Sep-17 HAL Modules restructured in "Intel-Systems" directory + +*/ + +#include "sim_defs.h" /* simulator defines */ + +/* Memory */ + +#define MAXMEMSIZE 16384 /* max memory size */ +#define MEMSIZE (cpu_unit.capac) /* actual memory size */ +#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */ +#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) + +/* Simulator stop codes */ + +#define STOP_RSRV 1 /* must be 1 */ +#define STOP_HALT 2 /* HALT */ +#define STOP_IBKPT 3 /* breakpoint */ +#define STOP_OPCODE 4 + +/* I/O device entries */ +struct idev { + int32 (*routine)(int32, int32); +}; diff --git a/README.md b/README.md index 256c29ab..69894f5b 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,8 @@ #### CDC 1700 simulator from John Forecast +#### Hans-Åke Lund has implemented an SCELBI (SCientic-ELectronics-BIology) simulator. + ### New Host Platform support - HP-UX and AIX ### Simulator Front Panel API diff --git a/Visual Studio Projects/Simh.sln b/Visual Studio Projects/Simh.sln index 3249ced8..ca9e4c2b 100644 --- a/Visual Studio Projects/Simh.sln +++ b/Visual Studio Projects/Simh.sln @@ -249,6 +249,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ibmpc", "ibmpc.vcproj", "{7 EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ibmpcxt", "ibmpcxt.vcproj", "{0026A4C2-655A-4C03-B6CA-B1EAF79FA4D1}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scelbi", "scelbi.vcproj", "{1E92CC4B-9ED5-4CD4-BD35-061F25126523}" + ProjectSection(ProjectDependencies) = postProject + {D40F3AF1-EEE7-4432-9807-2AD287B490F8} = {D40F3AF1-EEE7-4432-9807-2AD287B490F8} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -463,6 +468,10 @@ Global {0026A4C2-655A-4C03-B6CA-B1EAF79FA4D1}.Debug|Win32.Build.0 = Debug|Win32 {0026A4C2-655A-4C03-B6CA-B1EAF79FA4D1}.Release|Win32.ActiveCfg = Release|Win32 {0026A4C2-655A-4C03-B6CA-B1EAF79FA4D1}.Release|Win32.Build.0 = Release|Win32 + {1E92CC4B-9ED5-4CD4-BD35-061F25126523}.Debug|Win32.ActiveCfg = Debug|Win32 + {1E92CC4B-9ED5-4CD4-BD35-061F25126523}.Debug|Win32.Build.0 = Debug|Win32 + {1E92CC4B-9ED5-4CD4-BD35-061F25126523}.Release|Win32.ActiveCfg = Release|Win32 + {1E92CC4B-9ED5-4CD4-BD35-061F25126523}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Visual Studio Projects/scelbi.vcproj b/Visual Studio Projects/scelbi.vcproj new file mode 100644 index 00000000..bc7ba092 --- /dev/null +++ b/Visual Studio Projects/scelbi.vcproj @@ -0,0 +1,317 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/makefile b/makefile index bf147f90..d5544bbb 100644 --- a/makefile +++ b/makefile @@ -1435,6 +1435,12 @@ IBMPCXT = ${IBMPCXTC}/i8088.c ${IBMPCXTD}/ibmpcxt_sys.c \ IBMPCXT_OPT = -I ${IBMPCXTD} +SCELBID = Intel-Systems/scelbi +SCELBIC = Intel-Systems/common +SCELBI = ${SCELBIC}/i8008.c ${SCELBID}/scelbi_sys.c ${SCELBID}/scelbi_io.c +SCELBI_OPT = -I ${SCELBID} + + TX0D = TX-0 TX0 = ${TX0D}/tx0_cpu.c ${TX0D}/tx0_dpy.c ${TX0D}/tx0_stddev.c \ ${TX0D}/tx0_sys.c ${TX0D}/tx0_sys_orig.c ${DISPLAYL} @@ -1550,7 +1556,7 @@ ALL = pdp1 pdp4 pdp7 pdp8 pdp9 pdp15 pdp11 pdp10 \ nova eclipse hp2100 hp3000 i1401 i1620 s3 altair altairz80 gri \ i7094 ibm1130 id16 id32 sds lgp h316 cdc1700 \ swtp6800mp-a swtp6800mp-a2 tx-0 ssem b5500 isys8010 isys8020 \ - isys8030 isys8024 imds-225 + isys8030 isys8024 imds-225 scelbi all : ${ALL} @@ -1864,6 +1870,12 @@ ${BIN}ibmpcxt${EXE} : ${IBMPCXT} ${SIM} ${BUILD_ROMS} ${MKDIRBIN} ${CC} ${IBMPCXT} ${SIM} ${IBMPCXT_OPT} $(CC_OUTSPEC) ${LDFLAGS} +scelbi: ${BIN}scelbi${EXE} + +${BIN}scelbi${EXE} : ${SCELBI} ${SIM} ${BUILD_ROMS} + ${MKDIRBIN} + ${CC} ${SCELBI} ${SIM} ${SCELBI_OPT} $(CC_OUTSPEC) ${LDFLAGS} + tx-0 : ${BIN}tx-0${EXE} ${BIN}tx-0${EXE} : ${TX0} ${SIM}