2002 lines
50 KiB
C
2002 lines
50 KiB
C
/* i8008.c: Intel 8008 CPU simulator
|
|
|
|
Copyright (c) 2011, William A. Beech
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
|
copy of this software and associated documentation files (the "Software"),
|
|
to deal in the Software without restriction, including without limitation
|
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
and/or sell copies of the Software, and to permit persons to whom the
|
|
Software is furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of William A. Beech shall not be
|
|
used in advertising or otherwise to promote the sale, use or other dealings
|
|
in this Software without prior written authorization from William A. Beech.
|
|
|
|
cpu 8008 CPU
|
|
|
|
The register state for the 8008 CPU is:
|
|
|
|
A<0:7> Accumulator
|
|
B<0:7> B Register
|
|
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
|
|
|
|
The 8008 is an 8-bit CPU, which uses 14-bit registers to address
|
|
up to 16KB of memory.
|
|
|
|
The 57 basic instructions come in 1, 2, and 3-byte flavors.
|
|
|
|
This routine is the instruction decode routine for the 8008.
|
|
It is called from the simulator control program to execute
|
|
instructions in simulated memory, starting at the simulated PC.
|
|
It runs until 'reason' is set non-zero.
|
|
|
|
General notes:
|
|
|
|
1. Reasons to stop. The simulator can be stopped by:
|
|
|
|
HLT 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.
|
|
|
|
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.
|
|
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.
|
|
|
|
*/
|
|
|
|
#include "system_defs.h"
|
|
|
|
#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)
|
|
|
|
/* register masks */
|
|
#define BYTE_R 0xFF
|
|
#define WORD_R14 0x3FFF
|
|
|
|
/* 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 PCX; /* External view of PC */
|
|
int32 PC;
|
|
UNIT *uptr;
|
|
|
|
/* 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);
|
|
|
|
/* external function prototypes */
|
|
|
|
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 */
|
|
|
|
|
|
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
|
|
*/
|
|
|
|
extern struct idev dev_table[];
|
|
|
|
/* 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) },
|
|
{ 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 },
|
|
{ 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 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",
|
|
};
|
|
|
|
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 */
|
|
};
|
|
|
|
uint16 stack_frame[7]; /* processor stack frame */
|
|
|
|
void set_cpuint(int32 int_num)
|
|
{
|
|
int_req |= int_num;
|
|
}
|
|
|
|
/* 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 */
|
|
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");
|
|
}
|
|
|
|
if (sim_interval <= 0) { /* check clock queue */
|
|
if (reason = sim_process_event())
|
|
break;
|
|
}
|
|
|
|
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 */
|
|
|
|
if (sim_brk_summ &&
|
|
sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
|
|
reason = STOP_IBKPT; /* stop simulation */
|
|
break;
|
|
}
|
|
|
|
sim_interval--; /* countdown clock */
|
|
PCX = PC;
|
|
|
|
if (uptr->flags & UNIT_TRACE) {
|
|
dumpregs();
|
|
sim_printf("\n");
|
|
}
|
|
IR = OP = fetch_byte(0); /* instruction fetch */
|
|
|
|
if (OP == 0x00 || OP == 0x01 || OP == 0xFF) { /* HLT Instruction*/
|
|
reason = STOP_HALT;
|
|
PC--;
|
|
continue;
|
|
}
|
|
|
|
/* The Big 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) {
|
|
reason = STOP_OPCODE;
|
|
PC--;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Simulation halted */
|
|
|
|
saved_PC = PC;
|
|
return reason;
|
|
}
|
|
|
|
/* store byte to (HL) */
|
|
void store_m(uint32 val)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
PC = (PC + 1) & ADDRMASK; /* increment PC */
|
|
val &= BYTE_R;
|
|
return val;
|
|
}
|
|
|
|
/* fetch a word */
|
|
int32 fetch_word(void)
|
|
{
|
|
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 <C>arry, <S>ign, <Z>ero and <O>verflow flags following
|
|
an operation on 'reg'.
|
|
*/
|
|
|
|
void setflag4(int32 reg)
|
|
{
|
|
if (reg & 0x100)
|
|
CF = 1;
|
|
else
|
|
CF = 0;
|
|
if (reg & 0x80)
|
|
SF = 0;
|
|
else
|
|
SF = 1;
|
|
if ((reg & BYTE_R) == 0)
|
|
ZF = 1;
|
|
else
|
|
ZF = 0;
|
|
parity(reg);
|
|
}
|
|
|
|
/* Set the <C>arry, <S>ign and <Z>ero flags following
|
|
an operation on 'reg'.
|
|
*/
|
|
|
|
void setflag3(int32 reg)
|
|
{
|
|
CF = 0;
|
|
if (reg & 0x80)
|
|
SF = 0;
|
|
else
|
|
SF = 1;
|
|
if ((reg & BYTE_R) == 0)
|
|
ZF = 1;
|
|
else
|
|
ZF = 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
|
|
*/
|
|
|
|
void parity(int32 reg)
|
|
{
|
|
int32 bc = 0;
|
|
|
|
if (reg & 0x01) bc++;
|
|
if (reg & 0x02) bc++;
|
|
if (reg & 0x04) bc++;
|
|
if (reg & 0x08) bc++;
|
|
if (reg & 0x10) bc++;
|
|
if (reg & 0x20) bc++;
|
|
if (reg & 0x40) bc++;
|
|
if (reg & 0x80) bc++;
|
|
if (bc & 0x01)
|
|
PF = 0;
|
|
else
|
|
PF = 1;
|
|
}
|
|
|
|
|
|
|
|
/* Reset routine */
|
|
|
|
t_stat i8008_reset (DEVICE *dptr)
|
|
{
|
|
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");
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Memory examine */
|
|
|
|
t_stat i8008_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
|
|
{
|
|
if (addr >= MEMSIZE)
|
|
return SCPE_NXM;
|
|
if (vptr != NULL)
|
|
*vptr = get_mbyte(addr);
|
|
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);
|
|
}
|
|
|
|
/* Symbolic output
|
|
|
|
Inputs:
|
|
*of = output stream
|
|
addr = current PC
|
|
*val = pointer to values
|
|
*uptr = pointer to unit
|
|
sw = switches
|
|
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;
|
|
|
|
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);
|
|
}
|
|
|
|
/* Symbolic input
|
|
|
|
Inputs:
|
|
*cptr = pointer to input string
|
|
addr = current PC
|
|
*uptr = pointer to unit
|
|
*val = pointer to output values
|
|
sw = switches
|
|
Outputs:
|
|
status = error status
|
|
*/
|
|
|
|
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
|
|
{
|
|
int32 cflag, i = 0, j, r;
|
|
char gbuf[CBUFSIZE];
|
|
|
|
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;
|
|
}
|
|
|
|
/* An instruction: get opcode (all characters until null, comma,
|
|
or numeric (including spaces).
|
|
*/
|
|
|
|
while (1) {
|
|
if (*cptr == ',' || *cptr == '\0' ||
|
|
isdigit(*cptr))
|
|
break;
|
|
gbuf[i] = toupper(*cptr);
|
|
cptr++;
|
|
i++;
|
|
}
|
|
|
|
/* Allow for RST which has numeric as part of opcode */
|
|
|
|
if (toupper(gbuf[0]) == 'R' &&
|
|
toupper(gbuf[1]) == 'S' &&
|
|
toupper(gbuf[2]) == 'T') {
|
|
gbuf[i] = toupper(*cptr);
|
|
cptr++;
|
|
i++;
|
|
}
|
|
|
|
/* kill trailing spaces if any */
|
|
gbuf[i] = '\0';
|
|
for (j = i - 1; gbuf[j] == ' '; j--) {
|
|
gbuf[j] = '\0';
|
|
}
|
|
|
|
/* find opcode in table */
|
|
for (j = 0; j < 256; j++) {
|
|
if (strcmp(gbuf, opcode[j]) == 0)
|
|
break;
|
|
}
|
|
if (j > 255) /* not found */
|
|
return SCPE_ARG;
|
|
|
|
val[0] = j; /* store opcode */
|
|
if (oplen[j] < 2) /* if 1-byter we are done */
|
|
return SCPE_OK;
|
|
if (*cptr == ',') cptr++;
|
|
cptr = get_glyph(cptr, gbuf, 0); /* get address */
|
|
sscanf(gbuf, "%o", &r);
|
|
if (oplen[j] == 2) {
|
|
val[1] = r & 0xFF;
|
|
return (-1);
|
|
}
|
|
val[1] = r & 0xFF;
|
|
val[2] = (r >> 8) & 0xFF;
|
|
return (-2);
|
|
}
|