/emu_68000_alt
/emu_6809
/emu_6809_alt
+/emu_8080
+/emu_8080_alt
/emu_8086
/emu_8086_alt
/emu_mips
[submodule "intel-8080"]
path = intel-8080
url = https://github.com/nickd4/intel-8080.git
+[submodule "jefftranter_8080"]
+ path = jefftranter_8080
+ url = https://github.com/nickd4/jefftranter_8080.git
zexall.ihx \
zexdoc.ihx \
mbasic.ihx \
+emu_8080 \
emu_8080_alt
-#emu_8080
#emu_mips
#emu_pdp11
#emu_68000
rm __temp__.ihx
# 8080
-#emu_8080: emu_8080.o cpu_8080.o
-# ${CC} ${CFLAGS} -o $@ $^
+emu_8080: emu_8080.o cpu_8080.o
+ ${CC} ${CFLAGS} -o $@ $^
-#emu_8080.o: cpu_8080.h
+emu_8080.o: cpu_8080.h
-#cpu_8080.o: cpu_8080.h
+cpu_8080.o: cpu_8080.h
emu_8080_alt: emu_8080_alt.o 8080_cpu.o
${CC} ${CFLAGS} -o $@ $^
--- /dev/null
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include "cpu_8080.h"
+
+// initialization
+void cpu_8080_init(
+ struct cpu_8080 *self,
+ int (*read_byte)(void *context, int addr),
+ void *read_byte_context,
+ void (*write_byte)(void *context, int addr, int data),
+ void *write_byte_context,
+ int (*in_byte)(void *context, int addr),
+ void *in_byte_context,
+ void (*out_byte)(void *context, int addr, int data),
+ void *out_byte_context
+) {
+ memset(self, 0, sizeof(struct cpu_8080));
+ self->read_byte = read_byte;
+ self->read_byte_context = read_byte_context;
+ self->write_byte = write_byte;
+ self->write_byte_context = write_byte_context;
+ self->in_byte = in_byte;
+ self->in_byte_context = in_byte_context;
+ self->out_byte = out_byte;
+ self->out_byte_context = out_byte_context;
+}
+
+void cpu_8080_reset(struct cpu_8080 *self) {
+ self->regs.word.pc = CPU_8080_RESET_ADDR;
+ self->regs.word.psw = 0; //0xffff;
+ self->regs.word.sp = 0xffff;
+ self->regs.word.iflags = 0;
+}
+
+// instruction decode
+void cpu_8080_execute(struct cpu_8080 *self) {
+ if (self->regs.bit.nmi_pending) {
+ self->regs.bit.nmi_pending = false;
+
+ self->regs.word.pc += self->regs.bit.halt_flag;
+ self->regs.bit.halt_flag = false;
+
+ self->regs.bit.iff1 = false;
+ cpu_8080_call(self, CPU_8080_NMI_ADDR);
+ return;
+ }
+
+ if (
+ self->regs.bit.irq_pending &&
+ self->regs.bit.iff1 &&
+ !self->regs.bit.ei_flag
+ ) {
+ self->regs.bit.irq_pending = false;
+
+ self->regs.word.pc += self->regs.bit.halt_flag;
+ self->regs.bit.halt_flag = false;
+
+ self->regs.bit.iff1 = false;
+ self->regs.bit.iff2 = false;
+ switch (self->regs.bit.im) {
+ case 0:
+ // self->regs.byte.v contains the opcode placed on bus by peripheral
+ // only RST instructions are supported at the moment (systems with
+ // 8259 / 8228 could also use CALL, that would be extra complexity)
+ assert((self->regs.byte.v & 0xc7) == 0xc7);
+ cpu_8080_call(self, self->regs.byte.v & 0x38);
+ break;
+ case 1:
+ cpu_8080_call(self, CPU_8080_IRQ_ADDR);
+ break;
+ case 2:
+ // self->regs.byte.v contains the vector placed on bus by peripheral
+ // it is combined with self->regs.byte.i to create vector word "iv"
+ cpu_8080_call(self, cpu_8080_read_word(self, self->regs.word.iv & 0xfffe));
+ break;
+ default:
+ abort();
+ }
+ return;
+ }
+
+ self->regs.bit.halt_flag = false;
+ self->regs.bit.ei_flag = false;
+ switch (cpu_8080_fetch_byte(self)) {
+ case 0x00:
+ cpu_8080_nop(self);
+ break;
+ case 0x01:
+ cpu_8080_lxi(self, CPU_8080_EA_BC, cpu_8080_fetch_word(self));
+ break;
+ case 0x02:
+ cpu_8080_stax(self, self->regs.word.bc);
+ break;
+ case 0x03:
+ cpu_8080_inx(self, CPU_8080_EA_BC);
+ break;
+ case 0x04:
+ cpu_8080_inr(self, CPU_8080_EA_B);
+ break;
+ case 0x05:
+ cpu_8080_dcr(self, CPU_8080_EA_B);
+ break;
+ case 0x06:
+ cpu_8080_mvi(self, CPU_8080_EA_B, cpu_8080_fetch_byte(self));
+ break;
+ case 0x07:
+ cpu_8080_rlc(self);
+ break;
+ case 0x08:
+ cpu_8080_nop(self);
+ break;
+ case 0x09:
+ cpu_8080_dad(self, self->regs.word.bc);
+ break;
+ case 0x0a:
+ cpu_8080_ldax(self, self->regs.word.bc);
+ break;
+ case 0x0b:
+ cpu_8080_dcx(self, CPU_8080_EA_BC);
+ break;
+ case 0x0c:
+ cpu_8080_inr(self, CPU_8080_EA_C);
+ break;
+ case 0x0d:
+ cpu_8080_dcr(self, CPU_8080_EA_C);
+ break;
+ case 0x0e:
+ cpu_8080_mvi(self, CPU_8080_EA_C, cpu_8080_fetch_byte(self));
+ break;
+ case 0x0f:
+ cpu_8080_rrc(self);
+ break;
+ case 0x10:
+ cpu_8080_nop(self);
+ break;
+ case 0x11:
+ cpu_8080_lxi(self, CPU_8080_EA_DE, cpu_8080_fetch_word(self));
+ break;
+ case 0x12:
+ cpu_8080_stax(self, self->regs.word.de);
+ break;
+ case 0x13:
+ cpu_8080_inx(self, CPU_8080_EA_DE);
+ break;
+ case 0x14:
+ cpu_8080_inr(self, CPU_8080_EA_D);
+ break;
+ case 0x15:
+ cpu_8080_dcr(self, CPU_8080_EA_D);
+ break;
+ case 0x16:
+ cpu_8080_mvi(self, CPU_8080_EA_D, cpu_8080_fetch_byte(self));
+ break;
+ case 0x17:
+ cpu_8080_ral(self);
+ break;
+ case 0x18:
+ cpu_8080_nop(self);
+ break;
+ case 0x19:
+ cpu_8080_dad(self, self->regs.word.de);
+ break;
+ case 0x1a:
+ cpu_8080_ldax(self, self->regs.word.de);
+ break;
+ case 0x1b:
+ cpu_8080_dcx(self, CPU_8080_EA_DE);
+ break;
+ case 0x1c:
+ cpu_8080_inr(self, CPU_8080_EA_E);
+ break;
+ case 0x1d:
+ cpu_8080_dcr(self, CPU_8080_EA_E);
+ break;
+ case 0x1e:
+ cpu_8080_mvi(self, CPU_8080_EA_E, cpu_8080_fetch_byte(self));
+ break;
+ case 0x1f:
+ cpu_8080_rar(self);
+ break;
+ case 0x20:
+ cpu_8080_nop(self);
+ break;
+ case 0x21:
+ cpu_8080_lxi(self, CPU_8080_EA_HL, cpu_8080_fetch_word(self));
+ break;
+ case 0x22:
+ cpu_8080_shld(self, cpu_8080_fetch_word(self));
+ break;
+ case 0x23:
+ cpu_8080_inx(self, CPU_8080_EA_HL);
+ break;
+ case 0x24:
+ cpu_8080_inr(self, CPU_8080_EA_H);
+ break;
+ case 0x25:
+ cpu_8080_dcr(self, CPU_8080_EA_H);
+ break;
+ case 0x26:
+ cpu_8080_mvi(self, CPU_8080_EA_H, cpu_8080_fetch_byte(self));
+ break;
+ case 0x27:
+ cpu_8080_daa(self);
+ break;
+ case 0x28:
+ cpu_8080_nop(self);
+ break;
+ case 0x29:
+ cpu_8080_dad(self, self->regs.word.hl);
+ break;
+ case 0x2a:
+ cpu_8080_lhld(self, cpu_8080_fetch_word(self));
+ break;
+ case 0x2b:
+ cpu_8080_dcx(self, CPU_8080_EA_HL);
+ break;
+ case 0x2c:
+ cpu_8080_inr(self, CPU_8080_EA_L);
+ break;
+ case 0x2d:
+ cpu_8080_dcr(self, CPU_8080_EA_L);
+ break;
+ case 0x2e:
+ cpu_8080_mvi(self, CPU_8080_EA_L, cpu_8080_fetch_byte(self));
+ break;
+ case 0x2f:
+ cpu_8080_cma(self);
+ break;
+ case 0x30:
+ cpu_8080_nop(self);
+ break;
+ case 0x31:
+ cpu_8080_lxi(self, CPU_8080_EA_SP, cpu_8080_fetch_word(self));
+ break;
+ case 0x32:
+ cpu_8080_sta(self, cpu_8080_fetch_word(self));
+ break;
+ case 0x33:
+ cpu_8080_inx(self, CPU_8080_EA_SP);
+ break;
+ case 0x34:
+ cpu_8080_inr(self, self->regs.word.hl);
+ break;
+ case 0x35:
+ cpu_8080_dcr(self, self->regs.word.hl);
+ break;
+ case 0x36:
+ cpu_8080_mvi(self, self->regs.word.hl, cpu_8080_fetch_byte(self));
+ break;
+ case 0x37:
+ cpu_8080_stc(self);
+ break;
+ case 0x38:
+ cpu_8080_nop(self);
+ break;
+ case 0x39:
+ cpu_8080_dad(self, self->regs.word.sp);
+ break;
+ case 0x3a:
+ cpu_8080_lda(self, cpu_8080_fetch_word(self));
+ break;
+ case 0x3b:
+ cpu_8080_dcx(self, CPU_8080_EA_SP);
+ break;
+ case 0x3c:
+ cpu_8080_inr(self, CPU_8080_EA_A);
+ break;
+ case 0x3d:
+ cpu_8080_dcr(self, CPU_8080_EA_A);
+ break;
+ case 0x3e:
+ cpu_8080_mvi(self, CPU_8080_EA_A, cpu_8080_fetch_byte(self));
+ break;
+ case 0x3f:
+ cpu_8080_cmc(self);
+ break;
+ case 0x40:
+ cpu_8080_mov(self, CPU_8080_EA_B, self->regs.byte.b);
+ break;
+ case 0x41:
+ cpu_8080_mov(self, CPU_8080_EA_B, self->regs.byte.c);
+ break;
+ case 0x42:
+ cpu_8080_mov(self, CPU_8080_EA_B, self->regs.byte.d);
+ break;
+ case 0x43:
+ cpu_8080_mov(self, CPU_8080_EA_B, self->regs.byte.e);
+ break;
+ case 0x44:
+ cpu_8080_mov(self, CPU_8080_EA_B, self->regs.byte.h);
+ break;
+ case 0x45:
+ cpu_8080_mov(self, CPU_8080_EA_B, self->regs.byte.l);
+ break;
+ case 0x46:
+ cpu_8080_mov(self, CPU_8080_EA_B, cpu_8080_read_byte(self, self->regs.word.hl));
+ break;
+ case 0x47:
+ cpu_8080_mov(self, CPU_8080_EA_B, self->regs.byte.a);
+ break;
+ case 0x48:
+ cpu_8080_mov(self, CPU_8080_EA_C, self->regs.byte.b);
+ break;
+ case 0x49:
+ cpu_8080_mov(self, CPU_8080_EA_C, self->regs.byte.c);
+ break;
+ case 0x4a:
+ cpu_8080_mov(self, CPU_8080_EA_C, self->regs.byte.d);
+ break;
+ case 0x4b:
+ cpu_8080_mov(self, CPU_8080_EA_C, self->regs.byte.e);
+ break;
+ case 0x4c:
+ cpu_8080_mov(self, CPU_8080_EA_C, self->regs.byte.h);
+ break;
+ case 0x4d:
+ cpu_8080_mov(self, CPU_8080_EA_C, self->regs.byte.l);
+ break;
+ case 0x4e:
+ cpu_8080_mov(self, CPU_8080_EA_C, cpu_8080_read_byte(self, self->regs.word.hl));
+ break;
+ case 0x4f:
+ cpu_8080_mov(self, CPU_8080_EA_C, self->regs.byte.a);
+ break;
+ case 0x50:
+ cpu_8080_mov(self, CPU_8080_EA_D, self->regs.byte.b);
+ break;
+ case 0x51:
+ cpu_8080_mov(self, CPU_8080_EA_D, self->regs.byte.c);
+ break;
+ case 0x52:
+ cpu_8080_mov(self, CPU_8080_EA_D, self->regs.byte.d);
+ break;
+ case 0x53:
+ cpu_8080_mov(self, CPU_8080_EA_D, self->regs.byte.e);
+ break;
+ case 0x54:
+ cpu_8080_mov(self, CPU_8080_EA_D, self->regs.byte.h);
+ break;
+ case 0x55:
+ cpu_8080_mov(self, CPU_8080_EA_D, self->regs.byte.l);
+ break;
+ case 0x56:
+ cpu_8080_mov(self, CPU_8080_EA_D, cpu_8080_read_byte(self, self->regs.word.hl));
+ break;
+ case 0x57:
+ cpu_8080_mov(self, CPU_8080_EA_D, self->regs.byte.a);
+ break;
+ case 0x58:
+ cpu_8080_mov(self, CPU_8080_EA_E, self->regs.byte.b);
+ break;
+ case 0x59:
+ cpu_8080_mov(self, CPU_8080_EA_E, self->regs.byte.c);
+ break;
+ case 0x5a:
+ cpu_8080_mov(self, CPU_8080_EA_E, self->regs.byte.d);
+ break;
+ case 0x5b:
+ cpu_8080_mov(self, CPU_8080_EA_E, self->regs.byte.e);
+ break;
+ case 0x5c:
+ cpu_8080_mov(self, CPU_8080_EA_E, self->regs.byte.h);
+ break;
+ case 0x5d:
+ cpu_8080_mov(self, CPU_8080_EA_E, self->regs.byte.l);
+ break;
+ case 0x5e:
+ cpu_8080_mov(self, CPU_8080_EA_E, cpu_8080_read_byte(self, self->regs.word.hl));
+ break;
+ case 0x5f:
+ cpu_8080_mov(self, CPU_8080_EA_E, self->regs.byte.a);
+ break;
+ case 0x60:
+ cpu_8080_mov(self, CPU_8080_EA_H, self->regs.byte.b);
+ break;
+ case 0x61:
+ cpu_8080_mov(self, CPU_8080_EA_H, self->regs.byte.c);
+ break;
+ case 0x62:
+ cpu_8080_mov(self, CPU_8080_EA_H, self->regs.byte.d);
+ break;
+ case 0x63:
+ cpu_8080_mov(self, CPU_8080_EA_H, self->regs.byte.e);
+ break;
+ case 0x64:
+ cpu_8080_mov(self, CPU_8080_EA_H, self->regs.byte.h);
+ break;
+ case 0x65:
+ cpu_8080_mov(self, CPU_8080_EA_H, self->regs.byte.l);
+ break;
+ case 0x66:
+ cpu_8080_mov(self, CPU_8080_EA_H, cpu_8080_read_byte(self, self->regs.word.hl));
+ break;
+ case 0x67:
+ cpu_8080_mov(self, CPU_8080_EA_H, self->regs.byte.a);
+ break;
+ case 0x68:
+ cpu_8080_mov(self, CPU_8080_EA_L, self->regs.byte.b);
+ break;
+ case 0x69:
+ cpu_8080_mov(self, CPU_8080_EA_L, self->regs.byte.c);
+ break;
+ case 0x6a:
+ cpu_8080_mov(self, CPU_8080_EA_L, self->regs.byte.d);
+ break;
+ case 0x6b:
+ cpu_8080_mov(self, CPU_8080_EA_L, self->regs.byte.e);
+ break;
+ case 0x6c:
+ cpu_8080_mov(self, CPU_8080_EA_L, self->regs.byte.h);
+ break;
+ case 0x6d:
+ cpu_8080_mov(self, CPU_8080_EA_L, self->regs.byte.l);
+ break;
+ case 0x6e:
+ cpu_8080_mov(self, CPU_8080_EA_L, cpu_8080_read_byte(self, self->regs.word.hl));
+ break;
+ case 0x6f:
+ cpu_8080_mov(self, CPU_8080_EA_L, self->regs.byte.a);
+ break;
+ case 0x70:
+ cpu_8080_mov(self, self->regs.word.hl, self->regs.byte.b);
+ break;
+ case 0x71:
+ cpu_8080_mov(self, self->regs.word.hl, self->regs.byte.c);
+ break;
+ case 0x72:
+ cpu_8080_mov(self, self->regs.word.hl, self->regs.byte.d);
+ break;
+ case 0x73:
+ cpu_8080_mov(self, self->regs.word.hl, self->regs.byte.e);
+ break;
+ case 0x74:
+ cpu_8080_mov(self, self->regs.word.hl, self->regs.byte.h);
+ break;
+ case 0x75:
+ cpu_8080_mov(self, self->regs.word.hl, self->regs.byte.l);
+ break;
+ case 0x76:
+ cpu_8080_hlt(self);
+ break;
+ case 0x77:
+ cpu_8080_mov(self, self->regs.word.hl, self->regs.byte.a);
+ break;
+ case 0x78:
+ cpu_8080_mov(self, CPU_8080_EA_A, self->regs.byte.b);
+ break;
+ case 0x79:
+ cpu_8080_mov(self, CPU_8080_EA_A, self->regs.byte.c);
+ break;
+ case 0x7a:
+ cpu_8080_mov(self, CPU_8080_EA_A, self->regs.byte.d);
+ break;
+ case 0x7b:
+ cpu_8080_mov(self, CPU_8080_EA_A, self->regs.byte.e);
+ break;
+ case 0x7c:
+ cpu_8080_mov(self, CPU_8080_EA_A, self->regs.byte.h);
+ break;
+ case 0x7d:
+ cpu_8080_mov(self, CPU_8080_EA_A, self->regs.byte.l);
+ break;
+ case 0x7e:
+ cpu_8080_mov(self, CPU_8080_EA_A, cpu_8080_read_byte(self, self->regs.word.hl));
+ break;
+ case 0x7f:
+ cpu_8080_mov(self, CPU_8080_EA_A, self->regs.byte.a);
+ break;
+ case 0x80:
+ cpu_8080_add(self, self->regs.byte.b);
+ break;
+ case 0x81:
+ cpu_8080_add(self, self->regs.byte.c);
+ break;
+ case 0x82:
+ cpu_8080_add(self, self->regs.byte.d);
+ break;
+ case 0x83:
+ cpu_8080_add(self, self->regs.byte.e);
+ break;
+ case 0x84:
+ cpu_8080_add(self, self->regs.byte.h);
+ break;
+ case 0x85:
+ cpu_8080_add(self, self->regs.byte.l);
+ break;
+ case 0x86:
+ cpu_8080_add(self, cpu_8080_read_byte(self, self->regs.word.hl));
+ break;
+ case 0x87:
+ cpu_8080_add(self, self->regs.byte.a);
+ break;
+ case 0x88:
+ cpu_8080_adc(self, self->regs.byte.b);
+ break;
+ case 0x89:
+ cpu_8080_adc(self, self->regs.byte.c);
+ break;
+ case 0x8a:
+ cpu_8080_adc(self, self->regs.byte.d);
+ break;
+ case 0x8b:
+ cpu_8080_adc(self, self->regs.byte.e);
+ break;
+ case 0x8c:
+ cpu_8080_adc(self, self->regs.byte.h);
+ break;
+ case 0x8d:
+ cpu_8080_adc(self, self->regs.byte.l);
+ break;
+ case 0x8e:
+ cpu_8080_adc(self, cpu_8080_read_byte(self, self->regs.word.hl));
+ break;
+ case 0x8f:
+ cpu_8080_adc(self, self->regs.byte.a);
+ break;
+ case 0x90:
+ cpu_8080_sub(self, self->regs.byte.b);
+ break;
+ case 0x91:
+ cpu_8080_sub(self, self->regs.byte.c);
+ break;
+ case 0x92:
+ cpu_8080_sub(self, self->regs.byte.d);
+ break;
+ case 0x93:
+ cpu_8080_sub(self, self->regs.byte.e);
+ break;
+ case 0x94:
+ cpu_8080_sub(self, self->regs.byte.h);
+ break;
+ case 0x95:
+ cpu_8080_sub(self, self->regs.byte.l);
+ break;
+ case 0x96:
+ cpu_8080_sub(self, cpu_8080_read_byte(self, self->regs.word.hl));
+ break;
+ case 0x97:
+ cpu_8080_sub(self, self->regs.byte.a);
+ break;
+ case 0x98:
+ cpu_8080_sbb(self, self->regs.byte.b);
+ break;
+ case 0x99:
+ cpu_8080_sbb(self, self->regs.byte.c);
+ break;
+ case 0x9a:
+ cpu_8080_sbb(self, self->regs.byte.d);
+ break;
+ case 0x9b:
+ cpu_8080_sbb(self, self->regs.byte.e);
+ break;
+ case 0x9c:
+ cpu_8080_sbb(self, self->regs.byte.h);
+ break;
+ case 0x9d:
+ cpu_8080_sbb(self, self->regs.byte.l);
+ break;
+ case 0x9e:
+ cpu_8080_sbb(self, cpu_8080_read_byte(self, self->regs.word.hl));
+ break;
+ case 0x9f:
+ cpu_8080_sbb(self, self->regs.byte.a);
+ break;
+ case 0xa0:
+ cpu_8080_ana(self, self->regs.byte.b);
+ break;
+ case 0xa1:
+ cpu_8080_ana(self, self->regs.byte.c);
+ break;
+ case 0xa2:
+ cpu_8080_ana(self, self->regs.byte.d);
+ break;
+ case 0xa3:
+ cpu_8080_ana(self, self->regs.byte.e);
+ break;
+ case 0xa4:
+ cpu_8080_ana(self, self->regs.byte.h);
+ break;
+ case 0xa5:
+ cpu_8080_ana(self, self->regs.byte.l);
+ break;
+ case 0xa6:
+ cpu_8080_ana(self, cpu_8080_read_byte(self, self->regs.word.hl));
+ break;
+ case 0xa7:
+ cpu_8080_ana(self, self->regs.byte.a);
+ break;
+ case 0xa8:
+ cpu_8080_xra(self, self->regs.byte.b);
+ break;
+ case 0xa9:
+ cpu_8080_xra(self, self->regs.byte.c);
+ break;
+ case 0xaa:
+ cpu_8080_xra(self, self->regs.byte.d);
+ break;
+ case 0xab:
+ cpu_8080_xra(self, self->regs.byte.e);
+ break;
+ case 0xac:
+ cpu_8080_xra(self, self->regs.byte.h);
+ break;
+ case 0xad:
+ cpu_8080_xra(self, self->regs.byte.l);
+ break;
+ case 0xae:
+ cpu_8080_xra(self, cpu_8080_read_byte(self, self->regs.word.hl));
+ break;
+ case 0xaf:
+ cpu_8080_xra(self, self->regs.byte.a);
+ break;
+ case 0xb0:
+ cpu_8080_ora(self, self->regs.byte.b);
+ break;
+ case 0xb1:
+ cpu_8080_ora(self, self->regs.byte.c);
+ break;
+ case 0xb2:
+ cpu_8080_ora(self, self->regs.byte.d);
+ break;
+ case 0xb3:
+ cpu_8080_ora(self, self->regs.byte.e);
+ break;
+ case 0xb4:
+ cpu_8080_ora(self, self->regs.byte.h);
+ break;
+ case 0xb5:
+ cpu_8080_ora(self, self->regs.byte.l);
+ break;
+ case 0xb6:
+ cpu_8080_ora(self, cpu_8080_read_byte(self, self->regs.word.hl));
+ break;
+ case 0xb7:
+ cpu_8080_ora(self, self->regs.byte.a);
+ break;
+ case 0xb8:
+ cpu_8080_cmp(self, self->regs.byte.b);
+ break;
+ case 0xb9:
+ cpu_8080_cmp(self, self->regs.byte.c);
+ break;
+ case 0xba:
+ cpu_8080_cmp(self, self->regs.byte.d);
+ break;
+ case 0xbb:
+ cpu_8080_cmp(self, self->regs.byte.e);
+ break;
+ case 0xbc:
+ cpu_8080_cmp(self, self->regs.byte.h);
+ break;
+ case 0xbd:
+ cpu_8080_cmp(self, self->regs.byte.l);
+ break;
+ case 0xbe:
+ cpu_8080_cmp(self, cpu_8080_read_byte(self, self->regs.word.hl));
+ break;
+ case 0xbf:
+ cpu_8080_cmp(self, self->regs.byte.a);
+ break;
+ case 0xc0:
+ cpu_8080_rnz(self);
+ break;
+ case 0xc1:
+ cpu_8080_pop(self, CPU_8080_EA_BC);
+ break;
+ case 0xc2:
+ cpu_8080_jnz(self, cpu_8080_fetch_word(self));
+ break;
+ case 0xc3:
+ cpu_8080_jmp(self, cpu_8080_fetch_word(self));
+ break;
+ case 0xc4:
+ cpu_8080_cnz(self, cpu_8080_fetch_word(self));
+ break;
+ case 0xc5:
+ cpu_8080_push(self, self->regs.word.bc);
+ break;
+ case 0xc6:
+ cpu_8080_adi(self, cpu_8080_fetch_byte(self));
+ break;
+ case 0xc7:
+ cpu_8080_rst(self, 0);
+ break;
+ case 0xc8:
+ cpu_8080_rz(self);
+ break;
+ case 0xc9:
+ cpu_8080_ret(self);
+ break;
+ case 0xca:
+ cpu_8080_jz(self, cpu_8080_fetch_word(self));
+ break;
+ case 0xcb:
+ cpu_8080_jmp(self, cpu_8080_fetch_word(self));
+ break;
+ case 0xcc:
+ cpu_8080_cz(self, cpu_8080_fetch_word(self));
+ break;
+ case 0xcd:
+ cpu_8080_call(self, cpu_8080_fetch_word(self));
+ break;
+ case 0xce:
+ cpu_8080_aci(self, cpu_8080_fetch_byte(self));
+ break;
+ case 0xcf:
+ cpu_8080_rst(self, 1);
+ break;
+ case 0xd0:
+ cpu_8080_rnc(self);
+ break;
+ case 0xd1:
+ cpu_8080_pop(self, CPU_8080_EA_DE);
+ break;
+ case 0xd2:
+ cpu_8080_jnc(self, cpu_8080_fetch_word(self));
+ break;
+ case 0xd3:
+ cpu_8080_out(self, cpu_8080_fetch_byte(self));
+ break;
+ case 0xd4:
+ cpu_8080_cnc(self, cpu_8080_fetch_word(self));
+ break;
+ case 0xd5:
+ cpu_8080_push(self, self->regs.word.de);
+ break;
+ case 0xd6:
+ cpu_8080_sui(self, cpu_8080_fetch_byte(self));
+ break;
+ case 0xd7:
+ cpu_8080_rst(self, 2);
+ break;
+ case 0xd8:
+ cpu_8080_rc(self);
+ break;
+ case 0xd9:
+ cpu_8080_ret(self);
+ break;
+ case 0xda:
+ cpu_8080_jc(self, cpu_8080_fetch_word(self));
+ break;
+ case 0xdb:
+ cpu_8080_in(self, cpu_8080_fetch_byte(self));
+ break;
+ case 0xdc:
+ cpu_8080_cc(self, cpu_8080_fetch_word(self));
+ break;
+ case 0xdd:
+ cpu_8080_call(self, cpu_8080_fetch_word(self));
+ break;
+ case 0xde:
+ cpu_8080_sbi(self, cpu_8080_fetch_byte(self));
+ break;
+ case 0xdf:
+ cpu_8080_rst(self, 3);
+ break;
+ case 0xe0:
+ cpu_8080_rpo(self);
+ break;
+ case 0xe1:
+ cpu_8080_pop(self, CPU_8080_EA_HL);
+ break;
+ case 0xe2:
+ cpu_8080_jpo(self, cpu_8080_fetch_word(self));
+ break;
+ case 0xe3:
+ cpu_8080_xthl(self);
+ break;
+ case 0xe4:
+ cpu_8080_cpo(self, cpu_8080_fetch_word(self));
+ break;
+ case 0xe5:
+ cpu_8080_push(self, self->regs.word.hl);
+ break;
+ case 0xe6:
+ cpu_8080_ani(self, cpu_8080_fetch_byte(self));
+ break;
+ case 0xe7:
+ cpu_8080_rst(self, 4);
+ break;
+ case 0xe8:
+ cpu_8080_rpe(self);
+ break;
+ case 0xe9:
+ cpu_8080_pchl(self);
+ break;
+ case 0xea:
+ cpu_8080_jpe(self, cpu_8080_fetch_word(self));
+ break;
+ case 0xeb:
+ cpu_8080_xchg(self);
+ break;
+ case 0xec:
+ cpu_8080_cpe(self, cpu_8080_fetch_word(self));
+ break;
+ case 0xed:
+ cpu_8080_call(self, cpu_8080_fetch_word(self));
+ break;
+ case 0xee:
+ cpu_8080_xri(self, cpu_8080_fetch_byte(self));
+ break;
+ case 0xef:
+ cpu_8080_rst(self, 5);
+ break;
+ case 0xf0:
+ cpu_8080_rp(self);
+ break;
+ case 0xf1:
+ cpu_8080_pop(self, CPU_8080_EA_PSW);
+ break;
+ case 0xf2:
+ cpu_8080_jp(self, cpu_8080_fetch_word(self));
+ break;
+ case 0xf3:
+ cpu_8080_di(self);
+ break;
+ case 0xf4:
+ cpu_8080_cp(self, cpu_8080_fetch_word(self));
+ break;
+ case 0xf5:
+ cpu_8080_push(self, self->regs.word.psw);
+ break;
+ case 0xf6:
+ cpu_8080_ori(self, cpu_8080_fetch_byte(self));
+ break;
+ case 0xf7:
+ cpu_8080_rst(self, 6);
+ break;
+ case 0xf8:
+ cpu_8080_rm(self);
+ break;
+ case 0xf9:
+ cpu_8080_sphl(self);
+ break;
+ case 0xfa:
+ cpu_8080_jm(self, cpu_8080_fetch_word(self));
+ break;
+ case 0xfb:
+ cpu_8080_ei(self);
+ break;
+ case 0xfc:
+ cpu_8080_cm(self, cpu_8080_fetch_word(self));
+ break;
+ case 0xfd:
+ cpu_8080_call(self, cpu_8080_fetch_word(self));
+ break;
+ case 0xfe:
+ cpu_8080_cpi(self, cpu_8080_fetch_byte(self));
+ break;
+ case 0xff:
+ cpu_8080_rst(self, 7);
+ break;
+ }
+}
--- /dev/null
+#ifndef _CPU_8080_H
+#define _CPU_8080_H
+
+#include <endian.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+// gcc specific
+#ifndef ALWAYS_INLINE
+#define ALWAYS_INLINE __attribute__((always_inline))
+#endif
+
+#define CPU_8080_NMI_ADDR 0x66
+#define CPU_8080_RESET_ADDR 0
+#define CPU_8080_IRQ_ADDR 0x38
+
+// bits within REG_F
+#define CPU_8080_REG_F_BIT_C 0
+#define CPU_8080_REG_F_BIT_P 2
+#define CPU_8080_REG_F_BIT_AC 4
+#define CPU_8080_REG_F_BIT_Z 6
+#define CPU_8080_REG_F_BIT_S 7
+
+// special memory locations (negative address)
+// note: CPU_8080_EA_SINK is a byte-wide sink for implementing the "in f,(c)"
+// and DDCB/FDCB undocumented instructions, to store into and never read back
+#define CPU_8080_EA_PC (-0x1e)
+#define CPU_8080_EA_PSW (-0x1c)
+#define CPU_8080_EA_BC (-0x1a)
+#define CPU_8080_EA_DE (-0x18)
+#define CPU_8080_EA_HL (-0x16)
+#define CPU_8080_EA_SP (-0x14)
+#define CPU_8080_EA_IX (-0x12)
+#define CPU_8080_EA_IY (-0x10)
+#define CPU_8080_EA_AF_PRIME (-0xe)
+#define CPU_8080_EA_BC_PRIME (-0xc)
+#define CPU_8080_EA_DE_PRIME (-0xa)
+#define CPU_8080_EA_HL_PRIME (-8)
+#define CPU_8080_EA_IFLAGS (-6)
+#define CPU_8080_EA_IV (-4)
+
+// pc (-0x1e)
+#define CPU_8080_EA_F (-0x1c)
+#define CPU_8080_EA_A (-0x1b)
+#define CPU_8080_EA_C (-0x1a)
+#define CPU_8080_EA_B (-0x19)
+#define CPU_8080_EA_E (-0x18)
+#define CPU_8080_EA_D (-0x17)
+#define CPU_8080_EA_L (-0x16)
+#define CPU_8080_EA_H (-0x15)
+// sp (-0x14)
+#define CPU_8080_EA_IXL (-0x12)
+#define CPU_8080_EA_IXH (-0x11)
+#define CPU_8080_EA_IYL (-0x10)
+#define CPU_8080_EA_IYH (-0xf)
+// af_prime (-0xe)
+// bc_prime (-0xc)
+// de_prime (-0xa)
+// hl_prime (-8)
+// iflags (-6)
+#define CPU_8080_EA_V (-4)
+#define CPU_8080_EA_I (-3)
+#define CPU_8080_EA_R (-2)
+#define CPU_8080_EA_SINK (-1)
+
+// registers, in same order as special memory locations, but reversed on
+// big endian hardware where special memory address will be complemented
+// (this allows special memory to always look like it is little endian)
+union cpu_8080_regs {
+#if __BYTE_ORDER == __BIG_ENDIAN
+ struct {
+ uint8_t _fill_sink;
+ uint8_t _fill_r;
+ uint16_t _fill_iv;
+ uint16_t _fill_iflags : 7;
+ uint16_t reti_flag : 1;
+ uint16_t ei_flag : 1;
+ uint16_t halt_flag : 1;
+ uint16_t nmi_pending : 1;
+ uint16_t irq_pending : 1;
+ uint16_t iff2 : 1;
+ uint16_t iff1 : 1;
+ uint16_t im : 2;
+ uint16_t _fill_hl_prime;
+ uint16_t _fill_de_prime;
+ uint16_t _fill_bc_prime;
+ uint16_t _fill_af_prime;
+ uint16_t _fill_iy;
+ uint16_t _fill_ix;
+ uint16_t _fill_sp;
+ uint16_t _fill_hl;
+ uint16_t _fill_de;
+ uint16_t _fill_bc;
+ uint8_t _fill_a;
+ uint8_t sf : 1;
+ uint8_t zf : 1;
+ uint8_t _fill_5f: 1;
+ uint8_t acf : 1;
+ uint8_t _fill_3f: 1;
+ uint8_t pf: 1;
+ uint8_t _fill_1f : 1;
+ uint8_t cf : 1;
+ uint16_t _fill_pc;
+ } bit;
+ struct {
+ uint8_t sink;
+ uint8_t r;
+ uint8_t i;
+ uint8_t v;
+ uint16_t _fill_iflags;
+ uint16_t _fill_hl_prime;
+ uint16_t _fill_de_prime;
+ uint16_t _fill_bc_prime;
+ uint16_t _fill_af_prime;
+ uint8_t r;
+ uint8_t i;
+ uint8_t iyh;
+ uint8_t iyl;
+ uint8_t ixh;
+ uint8_t ixl;
+ uint16_t _fill_sp;
+ uint8_t h;
+ uint8_t l;
+ uint8_t d;
+ uint8_t e;
+ uint8_t b;
+ uint8_t c;
+ uint8_t a;
+ uint8_t f;
+ uint16_t _fill_pc;
+ } byte;
+ struct {
+ uint8_t _fill_sink;
+ uint8_t _fill_r;
+ uint16_t iv;
+ uint16_t iflags;
+ uint16_t hl_prime;
+ uint16_t de_prime;
+ uint16_t bc_prime;
+ uint16_t af_prime;
+ uint16_t iy;
+ uint16_t ix;
+ uint16_t sp;
+ uint16_t hl;
+ uint16_t de;
+ uint16_t bc;
+ uint16_t psw;
+ uint16_t pc;
+ } word;
+ uint8_t mem_be[0x1e];
+#else
+ struct {
+ uint16_t _fill_pc;
+ uint8_t cf : 1;
+ uint8_t _fill_1f : 1;
+ uint8_t pf: 1;
+ uint8_t _fill_3f: 1;
+ uint8_t acf : 1;
+ uint8_t _fill_5f: 1;
+ uint8_t zf : 1;
+ uint8_t sf : 1;
+ uint8_t _fill_a;
+ uint16_t _fill_bc;
+ uint16_t _fill_de;
+ uint16_t _fill_hl;
+ uint16_t _fill_sp;
+ uint16_t _fill_ix;
+ uint16_t _fill_iy;
+ uint16_t _fill_af_prime;
+ uint16_t _fill_bc_prime;
+ uint16_t _fill_de_prime;
+ uint16_t _fill_hl_prime;
+ uint16_t im : 2;
+ uint16_t iff1 : 1;
+ uint16_t iff2 : 1;
+ uint16_t irq_pending : 1;
+ uint16_t nmi_pending : 1;
+ uint16_t halt_flag : 1;
+ uint16_t ei_flag : 1;
+ uint16_t reti_flag : 1;
+ uint16_t _fill_iflags : 7;
+ uint16_t _fill_iv;
+ uint8_t _fill_r;
+ uint8_t _fill_sink;
+ } bit;
+ struct {
+ uint16_t _fill_pc;
+ uint8_t f;
+ uint8_t a;
+ uint8_t c;
+ uint8_t b;
+ uint8_t e;
+ uint8_t d;
+ uint8_t l;
+ uint8_t h;
+ uint16_t _fill_sp;
+ uint8_t ixl;
+ uint8_t ixh;
+ uint8_t iyl;
+ uint8_t iyh;
+ uint16_t _fill_af_prime;
+ uint16_t _fill_bc_prime;
+ uint16_t _fill_de_prime;
+ uint16_t _fill_hl_prime;
+ uint16_t _fill_iflags;
+ uint8_t v;
+ uint8_t i;
+ uint8_t r;
+ uint8_t sink;
+ } byte;
+ struct {
+ uint16_t pc;
+ uint16_t psw;
+ uint16_t bc;
+ uint16_t de;
+ uint16_t hl;
+ uint16_t sp;
+ uint16_t ix;
+ uint16_t iy;
+ uint16_t af_prime;
+ uint16_t bc_prime;
+ uint16_t de_prime;
+ uint16_t hl_prime;
+ uint16_t iflags;
+ uint16_t iv;
+ uint8_t _fill_r;
+ uint8_t _fill_sink;
+ } word;
+ uint8_t mem_le[0x1e];
+#endif
+};
+
+struct cpu_8080 {
+ int cycles;
+ int (*read_byte)(void *context, int addr);
+ void *read_byte_context;
+ void (*write_byte)(void *context, int addr, int data);
+ void *write_byte_context;
+ int (*in_byte)(void *context, int addr);
+ void *in_byte_context;
+ void (*out_byte)(void *context, int addr, int data);
+ void *out_byte_context;
+ union cpu_8080_regs regs;
+};
+
+// memory or special memory access
+static ALWAYS_INLINE int cpu_8080_read_byte(struct cpu_8080 *self, int addr) {
+ if (addr < 0)
+#if __BYTE_ORDER == __BIG_ENDIAN
+ return self->regs.mem_be[~addr];
+#else
+ return self->regs.mem_le[sizeof(union cpu_8080_regs) + addr];
+#endif
+ self->cycles += 1;
+ return self->read_byte(self->read_byte_context, addr & 0xffff);
+}
+
+static ALWAYS_INLINE int cpu_8080_read_word(struct cpu_8080 *self, int addr) {
+ int data = cpu_8080_read_byte(self, addr);
+ return data | (cpu_8080_read_byte(self, addr + 1) << 8);
+}
+
+static ALWAYS_INLINE void cpu_8080_write_byte(struct cpu_8080 *self, int addr, int data) {
+ self->cycles += 1;
+ if (addr < 0)
+#if __BYTE_ORDER == __BIG_ENDIAN
+ self->regs.mem_be[~addr] = data;
+#else
+ self->regs.mem_le[sizeof(union cpu_8080_regs) + addr] = data;
+#endif
+ else
+ self->write_byte(self->write_byte_context, addr, data);
+}
+
+static ALWAYS_INLINE void cpu_8080_write_word(struct cpu_8080 *self, int addr, int data) {
+ cpu_8080_write_byte(self, addr, data & 0xff);
+ cpu_8080_write_byte(self, addr + 1, data >> 8);
+}
+
+static ALWAYS_INLINE int cpu_8080_fetch_byte(struct cpu_8080 *self) {
+ int data = cpu_8080_read_byte(self, self->regs.word.pc++);
+ return data;
+}
+
+static ALWAYS_INLINE int cpu_8080_fetch_word(struct cpu_8080 *self) {
+ int data = cpu_8080_fetch_byte(self);
+ return data | (cpu_8080_fetch_byte(self) << 8);
+}
+
+static ALWAYS_INLINE void cpu_8080_push_word(struct cpu_8080 *self, int data) {
+ self->regs.word.sp -= 2;
+ cpu_8080_write_word(self, self->regs.word.sp, data);
+}
+
+static ALWAYS_INLINE int cpu_8080_pop_word(struct cpu_8080 *self) {
+ int data = cpu_8080_read_word(self, self->regs.word.sp);
+ self->regs.word.sp += 2;
+ return data;
+}
+
+static ALWAYS_INLINE int cpu_8080_in_byte(struct cpu_8080 *self, int addr) {
+ self->cycles += 1;
+ return self->in_byte(self->in_byte_context, addr);
+}
+
+static ALWAYS_INLINE void cpu_8080_out_byte(struct cpu_8080 *self, int addr, int data) {
+ self->cycles += 1;
+ self->out_byte(self->out_byte_context, addr, data);
+}
+
+// effective address calculation
+static ALWAYS_INLINE int cpu_8080_relative(struct cpu_8080 *self) {
+ return (int8_t)cpu_8080_fetch_byte(self);
+}
+
+static ALWAYS_INLINE int cpu_8080_displacement(struct cpu_8080 *self, int base) {
+ return (base + (int8_t)cpu_8080_fetch_byte(self)) & 0xffff;
+}
+
+// byte-addressed ports are extended to word using a as high 8 bits
+static ALWAYS_INLINE int cpu_8080_port_word(struct cpu_8080 *self) {
+ return cpu_8080_fetch_byte(self) | (self->regs.byte.a << 8);
+}
+
+// instruction execute
+static ALWAYS_INLINE void cpu_8080_aci(struct cpu_8080 *self, int rvalue) {
+ int result0 = (self->regs.byte.a & 0xf) + (rvalue & 0xf) + self->regs.bit.cf;
+ int result1 = result0 + (self->regs.byte.a & 0x70) + (rvalue & 0x70);
+ int result2 = result1 + (self->regs.byte.a & 0x80) + (rvalue & 0x80);
+
+ int parity = result2;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+
+ self->regs.byte.a = result2 & 0xff;
+ self->regs.bit.cf = result2 >> 8;
+ self->regs.bit.pf = (parity & 1) == 0;
+ self->regs.bit.acf = result0 >> 4;
+ self->regs.bit.zf = (result2 & 0xff) == 0;
+ self->regs.bit.sf = (result2 >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_8080_adc(struct cpu_8080 *self, int rvalue) {
+ int result0 = (self->regs.byte.a & 0xf) + (rvalue & 0xf) + self->regs.bit.cf;
+ int result1 = result0 + (self->regs.byte.a & 0x70) + (rvalue & 0x70);
+ int result2 = result1 + (self->regs.byte.a & 0x80) + (rvalue & 0x80);
+
+ int parity = result2;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+
+ self->regs.byte.a = result2 & 0xff;
+ self->regs.bit.cf = result2 >> 8;
+ self->regs.bit.pf = (parity & 1) == 0;
+ self->regs.bit.acf = result0 >> 4;
+ self->regs.bit.zf = (result2 & 0xff) == 0;
+ self->regs.bit.sf = (result2 >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_8080_add(struct cpu_8080 *self, int rvalue) {
+ int result0 = (self->regs.byte.a & 0xf) + (rvalue & 0xf);
+ int result1 = result0 + (self->regs.byte.a & 0x70) + (rvalue & 0x70);
+ int result2 = result1 + (self->regs.byte.a & 0x80) + (rvalue & 0x80);
+
+ int parity = result2;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+
+ self->regs.byte.a = result2 & 0xff;
+ self->regs.bit.cf = result2 >> 8;
+ self->regs.bit.pf = (parity & 1) == 0;
+ self->regs.bit.acf = result0 >> 4;
+ self->regs.bit.zf = (result2 & 0xff) == 0;
+ self->regs.bit.sf = (result2 >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_8080_adi(struct cpu_8080 *self, int rvalue) {
+ int result0 = (self->regs.byte.a & 0xf) + (rvalue & 0xf);
+ int result1 = result0 + (self->regs.byte.a & 0x70) + (rvalue & 0x70);
+ int result2 = result1 + (self->regs.byte.a & 0x80) + (rvalue & 0x80);
+
+ int parity = result2;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+
+ self->regs.byte.a = result2 & 0xff;
+ self->regs.bit.cf = result2 >> 8;
+ self->regs.bit.pf = (parity & 1) == 0;
+ self->regs.bit.acf = result0 >> 4;
+ self->regs.bit.zf = (result2 & 0xff) == 0;
+ self->regs.bit.sf = (result2 >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_8080_ana(struct cpu_8080 *self, int rvalue) {
+ int result = self->regs.byte.a & rvalue;
+
+ int parity = result;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+
+ self->regs.byte.a = result;
+ self->regs.bit.cf = false;
+ self->regs.bit.pf = (parity & 1) == 0;
+ self->regs.bit.acf = true;
+ self->regs.bit.zf = result == 0;
+ self->regs.bit.sf = result >> 7;
+}
+
+static ALWAYS_INLINE void cpu_8080_ani(struct cpu_8080 *self, int rvalue) {
+ int result = self->regs.byte.a & rvalue;
+
+ int parity = result;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+
+ self->regs.byte.a = result;
+ self->regs.bit.cf = false;
+ self->regs.bit.pf = (parity & 1) == 0;
+ self->regs.bit.acf = true;
+ self->regs.bit.zf = result == 0;
+ self->regs.bit.sf = result >> 7;
+}
+
+static ALWAYS_INLINE void cpu_8080_call(struct cpu_8080 *self, int rvalue) {
+ cpu_8080_push_word(self, self->regs.word.pc);
+ self->regs.word.pc = rvalue;
+}
+
+static ALWAYS_INLINE void cpu_8080_cc(struct cpu_8080 *self, int rvalue) {
+ if (self->regs.bit.cf) {
+ cpu_8080_push_word(self, self->regs.word.pc);
+ self->regs.word.pc = rvalue;
+ }
+}
+
+static ALWAYS_INLINE void cpu_8080_cm(struct cpu_8080 *self, int rvalue) {
+ if (self->regs.bit.sf) {
+ cpu_8080_push_word(self, self->regs.word.pc);
+ self->regs.word.pc = rvalue;
+ }
+}
+
+static ALWAYS_INLINE void cpu_8080_cma(struct cpu_8080 *self) {
+ self->regs.byte.a = ~self->regs.byte.a;
+ self->regs.bit.acf = true;
+}
+
+static ALWAYS_INLINE void cpu_8080_cmc(struct cpu_8080 *self) {
+ self->regs.bit.acf = self->regs.bit.cf;
+ self->regs.bit.cf = !self->regs.bit.cf;
+}
+
+static ALWAYS_INLINE void cpu_8080_cmp(struct cpu_8080 *self, int rvalue) {
+ int result0 = (self->regs.byte.a & 0xf) - (rvalue & 0xf);
+ int result1 = result0 + (self->regs.byte.a & 0x70) - (rvalue & 0x70);
+ int result2 = result1 + (self->regs.byte.a & 0x80) - (rvalue & 0x80);
+
+ int parity = result2;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+
+ self->regs.bit.cf = (result2 >> 8) & 1;
+ self->regs.bit.pf = (parity & 1) == 0;
+ self->regs.bit.acf = (result0 >> 4) & 1;
+ self->regs.bit.zf = (result2 & 0xff) == 0;
+ self->regs.bit.sf = (result2 >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_8080_cnc(struct cpu_8080 *self, int rvalue) {
+ if (!self->regs.bit.cf) {
+ cpu_8080_push_word(self, self->regs.word.pc);
+ self->regs.word.pc = rvalue;
+ }
+}
+
+static ALWAYS_INLINE void cpu_8080_cnz(struct cpu_8080 *self, int rvalue) {
+ if (!self->regs.bit.zf) {
+ cpu_8080_push_word(self, self->regs.word.pc);
+ self->regs.word.pc = rvalue;
+ }
+}
+
+static ALWAYS_INLINE void cpu_8080_cp(struct cpu_8080 *self, int rvalue) {
+ if (!self->regs.bit.sf) {
+ cpu_8080_push_word(self, self->regs.word.pc);
+ self->regs.word.pc = rvalue;
+ }
+}
+
+static ALWAYS_INLINE void cpu_8080_cpe(struct cpu_8080 *self, int rvalue) {
+ if (self->regs.bit.pf) {
+ cpu_8080_push_word(self, self->regs.word.pc);
+ self->regs.word.pc = rvalue;
+ }
+}
+
+static ALWAYS_INLINE void cpu_8080_cpi(struct cpu_8080 *self, int rvalue) {
+ int result0 = (self->regs.byte.a & 0xf) - (rvalue & 0xf);
+ int result1 = result0 + (self->regs.byte.a & 0x70) - (rvalue & 0x70);
+ int result2 = result1 + (self->regs.byte.a & 0x80) - (rvalue & 0x80);
+
+ int parity = result2;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+
+ self->regs.bit.cf = (result2 >> 8) & 1;
+ self->regs.bit.pf = (parity & 1) == 0;
+ self->regs.bit.acf = (result0 >> 4) & 1;
+ self->regs.bit.zf = (result2 & 0xff) == 0;
+ self->regs.bit.sf = (result2 >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_8080_cpo(struct cpu_8080 *self, int rvalue) {
+ if (!self->regs.bit.pf) {
+ cpu_8080_push_word(self, self->regs.word.pc);
+ self->regs.word.pc = rvalue;
+ }
+}
+
+static ALWAYS_INLINE void cpu_8080_cz(struct cpu_8080 *self, int rvalue) {
+ if (self->regs.bit.zf) {
+ cpu_8080_push_word(self, self->regs.word.pc);
+ self->regs.word.pc = rvalue;
+ }
+}
+
+static ALWAYS_INLINE void cpu_8080_daa(struct cpu_8080 *self) {
+ int correction = 0;
+ if (self->regs.bit.acf || (self->regs.byte.a & 0xf) >= 0xa)
+ correction = 6;
+ if (self->regs.bit.cf || self->regs.byte.a >= 0x9a) {
+ correction |= 0x60;
+ self->regs.bit.cf = true;
+ }
+
+ int result0 = (self->regs.byte.a & 0xf) + (correction & 0xf);
+ int result1 = result0 + (self->regs.byte.a & 0xf0) + (correction & 0xf0);
+
+ int parity = result1;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+
+ self->regs.byte.a = result1 & 0xff;
+ //self->regs.bit.cf |= (result1 >> 8) & 1;
+ self->regs.bit.pf = (parity & 1) == 0;
+ self->regs.bit.acf = (result0 >> 4) & 1;
+ self->regs.bit.zf = (result1 & 0xff) == 0;
+ self->regs.bit.sf = (result1 >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_8080_dad(struct cpu_8080 *self, int rvalue) {
+ int result0 = (self->regs.word.hl & 0xfff) + (rvalue & 0xfff);
+ int result1 = result0 + (self->regs.word.hl & 0xf000) + (rvalue & 0xf000);
+
+ self->regs.word.hl = result1 & 0xffff;
+ self->regs.bit.cf = result1 >> 16;
+ self->regs.bit.acf = result0 >> 12;
+}
+
+static ALWAYS_INLINE void cpu_8080_dcr(struct cpu_8080 *self, int lvalue) {
+ int data = cpu_8080_read_byte(self, lvalue);
+
+ int result0 = (data & 0xf) - 1;
+ int result1 = result0 + (data & 0x70);
+ int result2 = result1 + (data & 0x80);
+
+ int parity = result2;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+
+ cpu_8080_write_byte(self, lvalue, result2 & 0xff);
+ self->regs.bit.pf = (parity & 1) == 0;
+ self->regs.bit.acf = (result0 >> 4) & 1;
+ self->regs.bit.zf = (result2 & 0xff) == 0;
+ self->regs.bit.sf = (result2 >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_8080_dcx(struct cpu_8080 *self, int lvalue) {
+ int result = (cpu_8080_read_word(self, lvalue) - 1) & 0xffff;
+ cpu_8080_write_word(self, lvalue, result);
+}
+
+static ALWAYS_INLINE void cpu_8080_di(struct cpu_8080 *self) {
+ self->regs.bit.iff1 = false;
+ self->regs.bit.iff2 = false;
+}
+
+static ALWAYS_INLINE void cpu_8080_ei(struct cpu_8080 *self) {
+ self->regs.bit.iff1 = true;
+ self->regs.bit.iff2 = true;
+ self->regs.bit.ei_flag = true; // causes one-cycle interrupt delay
+}
+
+static ALWAYS_INLINE void cpu_8080_hlt(struct cpu_8080 *self) {
+ self->regs.bit.halt_flag = true;
+ --self->regs.word.pc;
+}
+
+static ALWAYS_INLINE void cpu_8080_in(struct cpu_8080 *self, int rvalue) {
+ self->regs.byte.a = cpu_8080_in_byte(self, rvalue);
+}
+
+static ALWAYS_INLINE void cpu_8080_inr(struct cpu_8080 *self, int lvalue) {
+ int data = cpu_8080_read_byte(self, lvalue);
+
+ int result0 = (data & 0xf) + 1;
+ int result1 = result0 + (data & 0x70);
+ int result2 = result1 + (data & 0x80);
+
+ int parity = result2;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+
+ cpu_8080_write_byte(self, lvalue, result2 & 0xff);
+ self->regs.bit.pf = (parity & 1) == 0;
+ self->regs.bit.acf = result0 >> 4;
+ self->regs.bit.zf = (result2 & 0xff) == 0;
+ self->regs.bit.sf = (result2 >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_8080_inx(struct cpu_8080 *self, int lvalue) {
+ int result = (cpu_8080_read_word(self, lvalue) + 1) & 0xffff;
+ cpu_8080_write_word(self, lvalue, result);
+}
+
+static ALWAYS_INLINE void cpu_8080_jc(struct cpu_8080 *self, int rvalue) {
+ if (self->regs.bit.cf)
+ self->regs.word.pc = rvalue;
+}
+
+static ALWAYS_INLINE void cpu_8080_jm(struct cpu_8080 *self, int rvalue) {
+ if (self->regs.bit.sf)
+ self->regs.word.pc = rvalue;
+}
+
+
+static ALWAYS_INLINE void cpu_8080_jmp(struct cpu_8080 *self, int rvalue) {
+ self->regs.word.pc = rvalue;
+}
+
+static ALWAYS_INLINE void cpu_8080_jnc(struct cpu_8080 *self, int rvalue) {
+ if (!self->regs.bit.cf)
+ self->regs.word.pc = rvalue;
+}
+
+static ALWAYS_INLINE void cpu_8080_jnz(struct cpu_8080 *self, int rvalue) {
+ if (!self->regs.bit.zf)
+ self->regs.word.pc = rvalue;
+}
+
+static ALWAYS_INLINE void cpu_8080_jp(struct cpu_8080 *self, int rvalue) {
+ if (!self->regs.bit.sf)
+ self->regs.word.pc = rvalue;
+}
+
+static ALWAYS_INLINE void cpu_8080_jpe(struct cpu_8080 *self, int rvalue) {
+ if (self->regs.bit.pf)
+ self->regs.word.pc = rvalue;
+}
+
+static ALWAYS_INLINE void cpu_8080_jpo(struct cpu_8080 *self, int rvalue) {
+ if (!self->regs.bit.pf)
+ self->regs.word.pc = rvalue;
+}
+
+static ALWAYS_INLINE void cpu_8080_jz(struct cpu_8080 *self, int rvalue) {
+ if (self->regs.bit.zf)
+ self->regs.word.pc = rvalue;
+}
+
+static ALWAYS_INLINE void cpu_8080_lda(struct cpu_8080 *self, int rvalue) {
+ self->regs.byte.a = cpu_8080_read_byte(self, rvalue);
+}
+
+static ALWAYS_INLINE void cpu_8080_ldax(struct cpu_8080 *self, int rvalue) {
+ self->regs.byte.a = cpu_8080_read_byte(self, rvalue);
+}
+
+static ALWAYS_INLINE void cpu_8080_lhld(struct cpu_8080 *self, int rvalue) {
+ self->regs.word.hl = cpu_8080_read_word(self, rvalue);
+}
+
+static ALWAYS_INLINE void cpu_8080_lxi(struct cpu_8080 *self, int lvalue, int rvalue) {
+ cpu_8080_write_word(self, lvalue, rvalue);
+}
+
+static ALWAYS_INLINE void cpu_8080_mov(struct cpu_8080 *self, int lvalue, int rvalue) {
+ cpu_8080_write_byte(self, lvalue, rvalue);
+}
+
+static ALWAYS_INLINE void cpu_8080_mvi(struct cpu_8080 *self, int lvalue, int rvalue) {
+ cpu_8080_write_byte(self, lvalue, rvalue);
+}
+
+static ALWAYS_INLINE void cpu_8080_nop(struct cpu_8080 *self) {
+}
+
+static ALWAYS_INLINE void cpu_8080_ora(struct cpu_8080 *self, int rvalue) {
+ int result = self->regs.byte.a | rvalue;
+
+ int parity = result;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+
+ self->regs.byte.a = result;
+ self->regs.bit.cf = false;
+ self->regs.bit.pf = (parity & 1) == 0;
+ self->regs.bit.acf = false;
+ self->regs.bit.zf = result == 0;
+ self->regs.bit.sf = result >> 7;
+}
+
+static ALWAYS_INLINE void cpu_8080_ori(struct cpu_8080 *self, int rvalue) {
+ int result = self->regs.byte.a | rvalue;
+
+ int parity = result;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+
+ self->regs.byte.a = result;
+ self->regs.bit.cf = false;
+ self->regs.bit.pf = (parity & 1) == 0;
+ self->regs.bit.acf = false;
+ self->regs.bit.zf = result == 0;
+ self->regs.bit.sf = result >> 7;
+}
+
+static ALWAYS_INLINE void cpu_8080_out(struct cpu_8080 *self, int rvalue) {
+ cpu_8080_out_byte(self, rvalue, self->regs.byte.a);
+}
+
+static ALWAYS_INLINE void cpu_8080_pchl(struct cpu_8080 *self) {
+ self->regs.word.pc = self->regs.word.hl;
+}
+
+static ALWAYS_INLINE void cpu_8080_pop(struct cpu_8080 *self, int lvalue) {
+ cpu_8080_write_word(self, lvalue, cpu_8080_pop_word(self));
+}
+
+static ALWAYS_INLINE void cpu_8080_push(struct cpu_8080 *self, int rvalue) {
+ cpu_8080_push_word(self, rvalue);
+}
+
+static ALWAYS_INLINE void cpu_8080_ral(struct cpu_8080 *self) {
+ int result = self->regs.bit.cf | (self->regs.byte.a << 1);
+
+ self->regs.byte.a = result & 0xff;
+ self->regs.bit.cf = result >> 8;
+ self->regs.bit.acf = false;
+}
+
+static ALWAYS_INLINE void cpu_8080_rar(struct cpu_8080 *self) {
+ int result = self->regs.byte.a | (self->regs.bit.cf << 8);
+
+ self->regs.byte.a = result >> 1;
+ self->regs.bit.cf = result & 1;
+ self->regs.bit.acf = false;
+}
+
+static ALWAYS_INLINE void cpu_8080_rc(struct cpu_8080 *self) {
+ if (self->regs.bit.cf)
+ self->regs.word.pc = cpu_8080_pop_word(self);
+}
+
+static ALWAYS_INLINE void cpu_8080_ret(struct cpu_8080 *self) {
+ self->regs.word.pc = cpu_8080_pop_word(self);
+}
+
+static ALWAYS_INLINE void cpu_8080_rlc(struct cpu_8080 *self) {
+ int result = (self->regs.byte.a >> 7) | (self->regs.byte.a << 1);
+
+ self->regs.byte.a = result & 0xff;
+ self->regs.bit.cf = result >> 8;
+ self->regs.bit.acf = false;
+}
+
+static ALWAYS_INLINE void cpu_8080_rm(struct cpu_8080 *self) {
+ if (self->regs.bit.sf)
+ self->regs.word.pc = cpu_8080_pop_word(self);
+}
+
+static ALWAYS_INLINE void cpu_8080_rnc(struct cpu_8080 *self) {
+ if (!self->regs.bit.cf)
+ self->regs.word.pc = cpu_8080_pop_word(self);
+}
+
+static ALWAYS_INLINE void cpu_8080_rnz(struct cpu_8080 *self) {
+ if (!self->regs.bit.zf)
+ self->regs.word.pc = cpu_8080_pop_word(self);
+}
+
+static ALWAYS_INLINE void cpu_8080_rp(struct cpu_8080 *self) {
+ if (!self->regs.bit.sf)
+ self->regs.word.pc = cpu_8080_pop_word(self);
+}
+
+static ALWAYS_INLINE void cpu_8080_rpe(struct cpu_8080 *self) {
+ if (self->regs.bit.pf)
+ self->regs.word.pc = cpu_8080_pop_word(self);
+}
+
+static ALWAYS_INLINE void cpu_8080_rpo(struct cpu_8080 *self) {
+ if (!self->regs.bit.pf)
+ self->regs.word.pc = cpu_8080_pop_word(self);
+}
+
+static ALWAYS_INLINE void cpu_8080_rrc(struct cpu_8080 *self) {
+ int result = self->regs.byte.a | ((self->regs.byte.a & 1) << 8);
+
+ self->regs.byte.a = result >> 1;
+ self->regs.bit.cf = result & 1;
+ self->regs.bit.acf = false;
+}
+
+static ALWAYS_INLINE void cpu_8080_rst(struct cpu_8080 *self, int rvalue) {
+ cpu_8080_push_word(self, self->regs.word.pc);
+ self->regs.word.pc = rvalue << 3;
+}
+
+static ALWAYS_INLINE void cpu_8080_rz(struct cpu_8080 *self) {
+ if (self->regs.bit.zf)
+ self->regs.word.pc = cpu_8080_pop_word(self);
+}
+
+static ALWAYS_INLINE void cpu_8080_sbb(struct cpu_8080 *self, int rvalue) {
+ int result0 = (self->regs.byte.a & 0xf) - (rvalue & 0xf) - self->regs.bit.cf;
+ int result1 = result0 + (self->regs.byte.a & 0x70) - (rvalue & 0x70);
+ int result2 = result1 + (self->regs.byte.a & 0x80) - (rvalue & 0x80);
+
+ int parity = result2;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+
+ self->regs.byte.a = result2 & 0xff;
+ self->regs.bit.cf = (result2 >> 8) & 1;
+ self->regs.bit.pf = (parity & 1) == 0;
+ self->regs.bit.acf = (result0 >> 4) & 1;
+ self->regs.bit.zf = (result2 & 0xff) == 0;
+ self->regs.bit.sf = (result2 >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_8080_sbi(struct cpu_8080 *self, int rvalue) {
+ int result0 = (self->regs.byte.a & 0xf) - (rvalue & 0xf) - self->regs.bit.cf;
+ int result1 = result0 + (self->regs.byte.a & 0x70) - (rvalue & 0x70);
+ int result2 = result1 + (self->regs.byte.a & 0x80) - (rvalue & 0x80);
+
+ int parity = result2;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+
+ self->regs.byte.a = result2 & 0xff;
+ self->regs.bit.cf = (result2 >> 8) & 1;
+ self->regs.bit.pf = (parity & 1) == 0;
+ self->regs.bit.acf = (result0 >> 4) & 1;
+ self->regs.bit.zf = (result2 & 0xff) == 0;
+ self->regs.bit.sf = (result2 >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_8080_shld(struct cpu_8080 *self, int rvalue) {
+ cpu_8080_write_word(self, rvalue, self->regs.word.hl);
+}
+
+static ALWAYS_INLINE void cpu_8080_sphl(struct cpu_8080 *self) {
+ self->regs.word.sp = self->regs.word.hl;
+}
+
+static ALWAYS_INLINE void cpu_8080_sta(struct cpu_8080 *self, int rvalue) {
+ cpu_8080_write_byte(self, rvalue, self->regs.byte.a);
+}
+
+static ALWAYS_INLINE void cpu_8080_stax(struct cpu_8080 *self, int rvalue) {
+ cpu_8080_write_byte(self, rvalue, self->regs.byte.a);
+}
+
+static ALWAYS_INLINE void cpu_8080_stc(struct cpu_8080 *self) {
+ self->regs.bit.cf = true;
+ self->regs.bit.acf = false;
+}
+
+static ALWAYS_INLINE void cpu_8080_sub(struct cpu_8080 *self, int rvalue) {
+ int result0 = (self->regs.byte.a & 0xf) - (rvalue & 0xf);
+ int result1 = result0 + (self->regs.byte.a & 0x70) - (rvalue & 0x70);
+ int result2 = result1 + (self->regs.byte.a & 0x80) - (rvalue & 0x80);
+
+ int parity = result2;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+
+ self->regs.byte.a = result2 & 0xff;
+ self->regs.bit.cf = (result2 >> 8) & 1;
+ self->regs.bit.pf = (parity & 1) == 0;
+ self->regs.bit.acf = (result0 >> 4) & 1;
+ self->regs.bit.zf = (result2 & 0xff) == 0;
+ self->regs.bit.sf = (result2 >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_8080_sui(struct cpu_8080 *self, int rvalue) {
+ int result0 = (self->regs.byte.a & 0xf) - (rvalue & 0xf);
+ int result1 = result0 + (self->regs.byte.a & 0x70) - (rvalue & 0x70);
+ int result2 = result1 + (self->regs.byte.a & 0x80) - (rvalue & 0x80);
+
+ int parity = result2;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+
+ self->regs.byte.a = result2 & 0xff;
+ self->regs.bit.cf = (result2 >> 8) & 1;
+ self->regs.bit.pf = (parity & 1) == 0;
+ self->regs.bit.acf = (result0 >> 4) & 1;
+ self->regs.bit.zf = (result2 & 0xff) == 0;
+ self->regs.bit.sf = (result2 >> 7) & 1;
+}
+
+static ALWAYS_INLINE void cpu_8080_xchg(struct cpu_8080 *self) {
+ int data = self->regs.word.hl;
+ self->regs.word.hl = self->regs.word.de;
+ self->regs.word.de = data;
+}
+
+static ALWAYS_INLINE void cpu_8080_xra(struct cpu_8080 *self, int rvalue) {
+ int result = self->regs.byte.a ^ rvalue;
+
+ int parity = result;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+
+ self->regs.byte.a = result;
+ self->regs.bit.cf = false;
+ self->regs.bit.pf = (parity & 1) == 0;
+ self->regs.bit.acf = false;
+ self->regs.bit.zf = result == 0;
+ self->regs.bit.sf = result >> 7;
+}
+
+static ALWAYS_INLINE void cpu_8080_xri(struct cpu_8080 *self, int rvalue) {
+ int result = self->regs.byte.a ^ rvalue;
+
+ int parity = result;
+ parity ^= parity >> 4;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+
+ self->regs.byte.a = result;
+ self->regs.bit.cf = false;
+ self->regs.bit.pf = (parity & 1) == 0;
+ self->regs.bit.acf = false;
+ self->regs.bit.zf = result == 0;
+ self->regs.bit.sf = result >> 7;
+}
+
+static ALWAYS_INLINE void cpu_8080_xthl(struct cpu_8080 *self) {
+ int data = cpu_8080_read_word(self, self->regs.word.sp);
+ cpu_8080_write_word(self, self->regs.word.sp, self->regs.word.hl);
+ self->regs.word.hl = data;
+}
+
+// prototypes
+void cpu_8080_init(
+ struct cpu_8080 *self,
+ int (*read_byte)(void *context, int addr),
+ void *read_byte_context,
+ void (*write_byte)(void *context, int addr, int data),
+ void *write_byte_context,
+ int (*in_byte)(void *context, int addr),
+ void *in_byte_context,
+ void (*out_byte)(void *context, int addr, int data),
+ void *out_byte_context
+);
+void cpu_8080_reset(struct cpu_8080 *self);
+void cpu_8080_execute(struct cpu_8080 *self);
+
+#endif
--- /dev/null
+#!/usr/bin/env python3
+
+import sys
+
+# end-relative range of operands that are rvalues
+rvalue_opcodes = {
+ 'aci': -1,
+ 'adc': -1,
+ 'add': -1,
+ 'adi': -1,
+ 'ana': -1,
+ 'ani': -1,
+ 'call': -1,
+ 'cc': -1,
+ 'cm': -1,
+ 'cmp': -1,
+ 'cnc': -1,
+ 'cnz': -1,
+ 'cp': -1,
+ 'cpe': -1,
+ 'cpi': -1,
+ 'cpo': -1,
+ 'cz': -1,
+ 'dad': -1,
+ 'in': -1,
+ 'jc': -1,
+ 'jm': -1,
+ 'jmp': -1,
+ 'jnc': -1,
+ 'jnz': -1,
+ 'jp': -1,
+ 'jpe': -1,
+ 'jpo': -1,
+ 'jz': -1,
+ 'lda': -1,
+ 'ldax': -1,
+ 'lhld': -1,
+ 'lxi': -1,
+ 'mov': -1,
+ 'mvi': -1,
+ 'ora': -1,
+ 'ori': -1,
+ 'out': -1,
+ 'push': -1,
+ 'rst': -1,
+ 'sbb': -1,
+ 'sbi': -1,
+ 'shld': -1,
+ 'sta': -1,
+ 'stax': -1,
+ 'sub': -1,
+ 'sui': -1,
+ 'xra': -1,
+ 'xri': -1,
+}
+
+byte_opcodes = {
+ 'aci',
+ 'adc',
+ 'add',
+ 'adi',
+ 'ana',
+ 'ani',
+ 'cmp',
+ 'cpi',
+ 'dcr',
+ 'in',
+ 'inr',
+ 'mov',
+ 'mvi',
+ 'ora',
+ 'ori',
+ 'out',
+ 'rst',
+ 'sbb',
+ 'sbi',
+ 'sub',
+ 'sui',
+ 'xra',
+ 'xri',
+}
+byte_rvalue_modes = {
+ '0x12': 'cpu_8080_fetch_byte(self)',
+ 'a': 'self->regs.byte.a',
+ 'b': 'self->regs.byte.b',
+ 'c': 'self->regs.byte.c',
+ 'd': 'self->regs.byte.d',
+ 'e': 'self->regs.byte.e',
+ 'l': 'self->regs.byte.l',
+ 'h': 'self->regs.byte.h',
+}
+byte_lvalue_modes = {
+ 'a': 'CPU_8080_EA_A',
+ 'b': 'CPU_8080_EA_B',
+ 'c': 'CPU_8080_EA_C',
+ 'd': 'CPU_8080_EA_D',
+ 'e': 'CPU_8080_EA_E',
+ 'l': 'CPU_8080_EA_L',
+ 'h': 'CPU_8080_EA_H',
+ 'm': 'self->regs.word.hl',
+}
+
+word_rvalue_modes = {
+ '0x3412': 'cpu_8080_fetch_word(self)',
+ 'psw': 'self->regs.word.psw',
+ 'b': 'self->regs.word.bc',
+ 'd': 'self->regs.word.de',
+ 'h': 'self->regs.word.hl',
+ 'sp': 'self->regs.word.sp',
+}
+word_lvalue_modes = {
+ 'psw': 'CPU_8080_EA_PSW',
+ 'b': 'CPU_8080_EA_BC',
+ 'd': 'CPU_8080_EA_DE',
+ 'h': 'CPU_8080_EA_HL',
+ 'sp': 'CPU_8080_EA_SP',
+}
+
+print('void cpu_8080_execute(struct cpu_8080 *self) {')
+print(' switch (cpu_8080_fetch_byte(self)) {')
+
+for i in range(0x100):
+ line = sys.stdin.readline().strip()
+
+ print(f' case 0x{i:02x}:')
+ instr = line.split()
+ if len(instr) == 0:
+ instr = ['ill']
+ elif len(instr) >= 2:
+ instr[1:] = [l for j in instr[1:] for l in j.split(',')]
+ #print('xxx', instr)
+
+ # work out which operands are rvalue
+ j = len(instr) + rvalue_opcodes.get(instr[0], 0)
+
+ # translate operands
+ if instr[0] in byte_opcodes:
+ # operands [1, j) are lvalue
+ for l in range(1, j):
+ if instr[l] in byte_lvalue_modes:
+ instr[l] = byte_lvalue_modes[instr[l]]
+
+ # operands [j, n) are rvalue
+ for l in range(j, len(instr)):
+ if instr[l] in byte_rvalue_modes:
+ instr[l] = byte_rvalue_modes[instr[l]]
+ elif instr[l] in byte_lvalue_modes:
+ instr[l] = 'cpu_8080_read_byte(self, {0:s})'.format(
+ byte_lvalue_modes[instr[l]]
+ )
+ else:
+ # operands [1, j] are lvalue
+ for l in range(1, j):
+ if instr[l] in word_lvalue_modes:
+ instr[l] = word_lvalue_modes[instr[l]]
+
+ # operands [j, n) are rvalue
+ for l in range(j, len(instr)):
+ if instr[l] in word_rvalue_modes:
+ instr[l] = word_rvalue_modes[instr[l]]
+ elif instr[l] in word_lvalue_modes:
+ instr[l] = 'cpu_8080_read_word(self, {0:s})'.format(
+ word_lvalue_modes[instr[l]]
+ )
+
+ print(
+ ' cpu_8080_{0:s}(self{1:s});'.format(
+ instr[0],
+ ''.join([', ' + j for j in instr[1:]])
+ )
+ )
+ print(' break;')
+
+line = sys.stdin.readline().strip()
+assert len(line) == 0
+
+print(' }')
+print('}')
+print()
--- /dev/null
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if ALT_BACKEND
+#include "intel-8080/cpu.h"
+#else
+#include "cpu_8080.h"
+#endif
+
+#define REG_TRACE 0
+#define MEM_TRACE 0
+#define IO_TRACE 0
+
+#define BDOS 0xffbb // ret
+#define JMP_BOOT 0xffbc // -3: Cold start routine
+#define JMP_WBOOT 0xffbf // 0: Warm boot - reload command processor
+#define JMP_CONST 0xffc2 // 3: Console status
+#define JMP_CONIN 0xffc5 // 6: Console input
+#define JMP_CONOUT 0xffc8 // 9: Console output
+#define JMP_LIST 0xffcb // 12: Printer output
+#define JMP_PUNCH 0xffce // 15: Paper tape punch output
+#define JMP_READER 0xffd1 // 18: Paper tape reader input
+#define JMP_HOME 0xffd4 // 21: Move disc head to track 0
+#define JMP_SELDSK 0xffd7 // 24: Select disc drive
+#define JMP_SETTRK 0xffda // 27: Set track number
+#define JMP_SETSEC 0xffdd // 30: Set sector number
+#define JMP_SETDMA 0xffe0 // 33: Set DMA address
+#define JMP_READ 0xffe3 // 36: Read a sector
+#define JMP_WRITE 0xffe6 // 39: Write a sector
+#define JMP_LISTST 0xffe9 // 42: Status of list device
+#define JMP_SECTRAN 0xffec // 45: Sector translation for skewing
+#define BIOS_BOOT 0xffef // ret
+#define BIOS_WBOOT 0xfff0 // ret
+#define BIOS_CONST 0xfff1 // ret
+#define BIOS_CONIN 0xfff2 // ret
+#define BIOS_CONOUT 0xfff3 // ret
+#define BIOS_LIST 0xfff4 // ret
+#define BIOS_PUNCH 0xfff5 // ret
+#define BIOS_READER 0xfff6 // ret
+#define BIOS_HOME 0xfff7 // ret
+#define BIOS_SELDSK 0xfff8 // ret
+#define BIOS_SETTRK 0xfff9 // ret
+#define BIOS_SETSEC 0xfffa // ret
+#define BIOS_SETDMA 0xfffb // ret
+#define BIOS_READ 0xfffc // ret
+#define BIOS_WRITE 0xfffd // ret
+#define BIOS_LISTST 0xfffe // ret
+#define BIOS_SECTRAN 0xffff // ret
+
+#define MEM_SIZE 0x10000
+uint8_t mem[MEM_SIZE];
+
+// read and write are separated for I/O
+#define IO_SIZE 0x100
+uint8_t io_read[IO_SIZE];
+uint8_t io_write[IO_SIZE];
+
+int load_ihx(char *name) {
+ FILE *fp = fopen(name, "r");
+ if (fp == NULL) {
+ perror(name);
+ exit(EXIT_FAILURE);
+ }
+
+ int base = 0, entry_point = 0;
+ bool had_eof = false;
+ char line[0x100];
+ while (fgets(line, 0x100, fp)) {
+ for (char *p = line; *p; ++p)
+ if (*p == '\n') {
+ *p = 0;
+ break;
+ }
+
+ if (had_eof) {
+ fprintf(stderr, "garbage after EOF record: %s\n", line);
+ exit(EXIT_FAILURE);
+ }
+
+ if (line[0] != ':') {
+ fprintf(stderr, "require colon: %s\n", line);
+ exit(EXIT_FAILURE);
+ }
+
+ uint8_t buf[0x7f];
+ int len;
+ for (len = 0; len < 0x7f; ++len) {
+ char *p = line + 1 + len * 2;
+ if (*p == 0)
+ break;
+ if (*p == '\n') {
+ *p = 0;
+ break;
+ }
+ uint8_t c = p[2];
+ p[2] = 0;
+
+ char *q;
+ buf[len] = (uint8_t)strtol(p, &q, 16);
+ p[2] = c;
+ if (q != p + 2) {
+ fprintf(stderr, "not hex byte: %s\n", p);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (len == 0) {
+ fprintf(stderr, "empty line: %s\n", line);
+ exit(EXIT_FAILURE);
+ }
+
+ uint8_t checksum = 0;
+ for (int i = 0; i < len; ++i)
+ checksum += buf[i];
+ if (checksum) {
+ checksum -= buf[len - 1];
+ fprintf(
+ stderr,
+ "checksum %02x, should be %02x\n",
+ checksum,
+ buf[len - 1]
+ );
+ exit(EXIT_FAILURE);
+ }
+
+ len -= 5;
+ if (len != buf[0]) {
+ fprintf(stderr, "incorrect length: %s\n", line);
+ exit(EXIT_FAILURE);
+ }
+
+ int addr = (buf[1] << 8) | buf[2], end_addr;
+ switch (buf[3]) {
+ case 0:
+ addr += base;
+ end_addr = addr + len;
+ if (end_addr < addr || end_addr > MEM_SIZE) {
+ fprintf(stderr, "invalid load range: [0x%x, 0x%x)\n", addr, end_addr);
+ exit(EXIT_FAILURE);
+ }
+ memcpy(mem + addr, buf + 4, len);
+ break;
+ case 1:
+ had_eof = true;
+ break;
+ case 4:
+ if (len < 2) {
+ fprintf(stderr, "invalid extended linear address record: %s\n", line);
+ exit(EXIT_FAILURE);
+ }
+ base = (buf[4] << 24) | (buf[5] << 16);
+ break;
+ case 5:
+ if (len < 4) {
+ fprintf(stderr, "invalid start linear address record: %s\n", line);
+ exit(EXIT_FAILURE);
+ }
+ entry_point = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
+ break;
+ default:
+ fprintf(stderr, "unknown record type: 0x%x\n", buf[3]);
+ exit(EXIT_FAILURE);
+ }
+ }
+ if (!had_eof) {
+ fprintf(stderr, "no EOF record\n");
+ exit(EXIT_FAILURE);
+ }
+
+ fclose(fp);
+ return entry_point;
+}
+
+int bdos(int a, int c, int de, uint16_t *hl) {
+ switch (c) {
+ case 2:
+ // Character output
+ de &= 0xff;
+ switch (de) {
+ case '\n':
+ break;
+ case '\r':
+ de = '\n';
+ default:
+ putchar(de);
+ break;
+ }
+ break;
+#if 0 // unlike MS-DOS version, the CP/M BASIC-80 uses direct BIOS calls
+ case 6:
+ // Direct console I/O
+ de &= 0xff;
+ if (de == 0xff) {
+ int data = getchar();
+ switch (data) {
+ case '\n':
+ data = '\r';
+ goto avail;
+ case 0x7f:
+ data = '\b';
+ //goto avail;
+ default:
+ avail:
+ a = data;
+ break;
+ case EOF:
+ a = 0;
+ break;
+ }
+ break;
+ }
+ switch (de) {
+ case '\n':
+ break;
+ case '\r':
+ de = '\n';
+ default:
+ putchar(de);
+ break;
+ }
+ break;
+#endif
+ case 9:
+ // Display string
+ for (int data; (data = mem[de]) != '$'; de = (de + 1) & 0xffff)
+ switch (data) {
+ case '\n':
+ break;
+ case '\r':
+ data = '\n';
+ default:
+ putchar(data);
+ break;
+ }
+ break;
+ case 0xc:
+ // Get CP/M version
+ *hl = 0x22;
+ break;
+ case 0x29: // DRV_ROVEC - Return bitmap of read-only drives
+ *hl = 0;
+ break;
+ default:
+ fprintf(stderr, "unimplemented BDOS call 0x%02x\n", c);
+ exit(EXIT_FAILURE);
+ }
+ return a;
+}
+
+int bios(int pc, int a, int c) {
+ switch (pc) {
+ case BIOS_WBOOT:
+ exit(EXIT_SUCCESS);
+ case BIOS_CONST:
+ a = 0; // defeat BASIC Ctrl-C checking
+ break;
+ case BIOS_CONIN:
+ {
+ int data = getchar();
+ switch (data) {
+ case '\n':
+ data = '\r';
+ goto avail;
+ case 0x7f:
+ data = '\b';
+ //goto avail;
+ default:
+ avail:
+ a = data;
+ break;
+ case EOF:
+ a = 0;
+ break;
+ }
+ }
+ break;
+ case BIOS_CONOUT:
+ switch (c) {
+ case '\n':
+ break;
+ case '\r':
+ c = '\n';
+ default:
+ putchar(c);
+ break;
+ }
+ break;
+ default:
+ fprintf(stderr, "unimplemented BIOS call 0x%04x\n", pc);
+ exit(EXIT_FAILURE);
+ }
+ return a;
+}
+
+#if ALT_BACKEND
+uint8_t read_byte(uint16_t addr)
+#else
+int read_byte(void *context, int addr)
+#endif
+{
+#if MEM_TRACE
+ int data = mem[addr];
+ fprintf(stderr, "addr=%04x rd=%02x\n", addr, data);
+ return data;
+#else
+ return mem[addr];
+#endif
+}
+
+#if ALT_BACKEND
+void write_byte(uint16_t addr, uint8_t data)
+#else
+void write_byte(void *context, int addr, int data)
+#endif
+{
+#if MEM_TRACE
+ fprintf(stderr, "addr=%04x wr=%02x\n", addr, data);
+#endif
+ mem[addr] = data;
+}
+
+int in_byte(void *context, int addr) {
+ addr &= 0xff;
+#if IO_TRACE
+ int data = io_read[addr];
+ printf("io=%02x rd=%02x\n", addr, data);
+ return data;
+#else
+ return io_read[addr];
+#endif
+}
+
+void out_byte(void *context, int addr, int data) {
+ addr &= 0xff;
+#if IO_TRACE
+ printf("io=%02x wr=%02x\n", addr, data);
+#endif
+ io_write[addr] = data;
+}
+
+int main(int argc, char **argv) {
+ if (argc < 2) {
+ printf("usage: %s image.ihx\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ int entry_point = load_ihx(argv[1]);
+
+ mem[0] = 0xc3; // jmp
+ mem[1] = (uint8_t)JMP_WBOOT;
+ mem[2] = (uint8_t)(JMP_WBOOT >> 8);
+
+ mem[5] = 0xc3; // jmp
+ mem[6] = (uint8_t)BDOS;
+ mem[7] = (uint8_t)(BDOS >> 8);
+
+ mem[BDOS] = 0xc9; // ret
+
+ mem[JMP_BOOT] = 0xc3; // jmp
+ mem[JMP_BOOT + 1] = (uint8_t)BIOS_BOOT;
+ mem[JMP_BOOT + 2] = (uint8_t)(BIOS_BOOT >> 8);
+
+ mem[JMP_WBOOT] = 0xc3; // jmp
+ mem[JMP_WBOOT + 1] = (uint8_t)BIOS_WBOOT;
+ mem[JMP_WBOOT + 2] = (uint8_t)(BIOS_WBOOT >> 8);
+
+ mem[JMP_CONST] = 0xc3; // jmp
+ mem[JMP_CONST + 1] = (uint8_t)BIOS_CONST;
+ mem[JMP_CONST + 2] = (uint8_t)(BIOS_CONST >> 8);
+
+ mem[JMP_CONIN] = 0xc3; // jmp
+ mem[JMP_CONIN + 1] = (uint8_t)BIOS_CONIN;
+ mem[JMP_CONIN + 2] = (uint8_t)(BIOS_CONIN >> 8);
+
+ mem[JMP_CONOUT] = 0xc3; // jmp
+ mem[JMP_CONOUT + 1] = (uint8_t)BIOS_CONOUT;
+ mem[JMP_CONOUT + 2] = (uint8_t)(BIOS_CONOUT >> 8);
+
+ mem[JMP_LIST] = 0xc3; // jmp
+ mem[JMP_LIST + 1] = (uint8_t)BIOS_LIST;
+ mem[JMP_LIST + 2] = (uint8_t)(BIOS_LIST >> 8);
+
+ mem[JMP_PUNCH] = 0xc3; // jmp
+ mem[JMP_PUNCH + 1] = (uint8_t)BIOS_PUNCH;
+ mem[JMP_PUNCH + 2] = (uint8_t)(BIOS_PUNCH >> 8);
+
+ mem[JMP_READER] = 0xc3; // jmp
+ mem[JMP_READER + 1] = (uint8_t)BIOS_READER;
+ mem[JMP_READER + 2] = (uint8_t)(BIOS_READER >> 8);
+
+ mem[JMP_HOME] = 0xc3; // jmp
+ mem[JMP_HOME + 1] = (uint8_t)BIOS_HOME;
+ mem[JMP_HOME + 2] = (uint8_t)(BIOS_HOME >> 8);
+
+ mem[JMP_SELDSK] = 0xc3; // jmp
+ mem[JMP_SELDSK + 1] = (uint8_t)BIOS_SELDSK;
+ mem[JMP_SELDSK + 2] = (uint8_t)(BIOS_SELDSK >> 8);
+
+ mem[JMP_SETTRK] = 0xc3; // jmp
+ mem[JMP_SETTRK + 1] = (uint8_t)BIOS_SETTRK;
+ mem[JMP_SETTRK + 2] = (uint8_t)(BIOS_SETTRK >> 8);
+
+ mem[JMP_SETSEC] = 0xc3; // jmp
+ mem[JMP_SETSEC + 1] = (uint8_t)BIOS_SETSEC;
+ mem[JMP_SETSEC + 2] = (uint8_t)(BIOS_SETSEC >> 8);
+
+ mem[JMP_SETDMA] = 0xc3; // jmp
+ mem[JMP_SETDMA + 1] = (uint8_t)BIOS_SETDMA;
+ mem[JMP_SETDMA + 2] = (uint8_t)(BIOS_SETDMA >> 8);
+
+ mem[JMP_READ] = 0xc3; // jmp
+ mem[JMP_READ + 1] = (uint8_t)BIOS_READ;
+ mem[JMP_READ + 2] = (uint8_t)(BIOS_READ >> 8);
+
+ mem[JMP_WRITE] = 0xc3; // jmp
+ mem[JMP_WRITE + 1] = (uint8_t)BIOS_WRITE;
+ mem[JMP_WRITE + 2] = (uint8_t)(BIOS_WRITE >> 8);
+
+ mem[JMP_LISTST] = 0xc3; // jmp
+ mem[JMP_LISTST + 1] = (uint8_t)BIOS_LISTST;
+ mem[JMP_LISTST + 2] = (uint8_t)(BIOS_LISTST >> 8);
+
+ mem[JMP_SECTRAN] = 0xc3; // jmp
+ mem[JMP_SECTRAN + 1] = (uint8_t)BIOS_SECTRAN;
+ mem[JMP_SECTRAN + 2] = (uint8_t)(BIOS_SECTRAN >> 8);
+
+ mem[BIOS_BOOT] = 0xc9; // ret
+ mem[BIOS_WBOOT] = 0xc9; // ret
+ mem[BIOS_CONST] = 0xc9; // ret
+ mem[BIOS_CONIN] = 0xc9; // ret
+ mem[BIOS_CONOUT] = 0xc9; // ret
+ mem[BIOS_LIST] = 0xc9; // ret
+ mem[BIOS_PUNCH] = 0xc9; // ret
+ mem[BIOS_READER] = 0xc9; // ret
+ mem[BIOS_HOME] = 0xc9; // ret
+ mem[BIOS_SELDSK] = 0xc9; // ret
+ mem[BIOS_SETTRK] = 0xc9; // ret
+ mem[BIOS_SETSEC] = 0xc9; // ret
+ mem[BIOS_SETDMA] = 0xc9; // ret
+ mem[BIOS_READ] = 0xc9; // ret
+ mem[BIOS_WRITE] = 0xc9; // ret
+ mem[BIOS_LISTST] = 0xc9; // ret
+ mem[BIOS_SECTRAN] = 0xc9; // ret
+
+#if ALT_BACKEND
+ regs.pc = entry_point;
+ regs.sp = BDOS - 2; // assume word at BDOS - 2 is initialized to 0
+
+ while (true) {
+#if REG_TRACE
+ fprintf(
+ stderr,
+ "pc=%04x psw=%04x bc=%04x de=%04x hl=%04x sp=%04x cf=%d pf=%d acf=%d zf=%d sf=%d\n",
+ regs.pc,
+ regs.cf |
+ (regs.pf << 2) |
+ (regs.acf << 4) |
+ (regs.zf << 6) |
+ (regs.sf << 7) |
+ (regs.a << 8),
+ regs.c | (regs.b << 8),
+ regs.e | (regs.d << 8),
+ regs.l | (regs.h << 8),
+ regs.sp,
+ regs.cf,
+ regs.pf,
+ regs.acf,
+ regs.zf,
+ regs.sf
+ );
+#endif
+
+ if (regs.pc == BDOS) {
+ int de = regs.e | (regs.d << 8);
+ uint16_t hl = regs.l | (regs.h << 8);
+ regs.a = bdos(regs.a, regs.c, de, &hl);
+ regs.l = (uint8_t)hl;
+ regs.h = (uint8_t)(hl >> 8);
+ }
+ else if (regs.pc >= BIOS_BOOT)
+ regs.a = bios(regs.pc, regs.a, regs.c);
+
+ instruction(read_next_byte()); // should check return code (HLT, RST)
+ }
+#else
+ struct cpu_8080 cpu;
+ cpu_8080_init(
+ &cpu,
+ read_byte,
+ NULL,
+ write_byte,
+ NULL,
+ in_byte,
+ NULL,
+ out_byte,
+ NULL
+ );
+ cpu_8080_reset(&cpu);
+ cpu.regs.word.pc = entry_point;
+ cpu.regs.word.sp = BDOS - 2; // assume word at BDOS - 2 is initialized to 0
+
+ while (true) {
+#if REG_TRACE
+ fprintf(
+ stderr,
+ "pc=%04x psw=%04x bc=%04x de=%04x hl=%04x sp=%04x cf=%d pf=%d acf=%d zf=%d sf=%d\n",
+ cpu.regs.word.pc,
+ cpu.regs.word.psw,
+ cpu.regs.word.bc,
+ cpu.regs.word.de,
+ cpu.regs.word.hl,
+ cpu.regs.word.sp,
+ cpu.regs.bit.cf,
+ cpu.regs.bit.pf,
+ cpu.regs.bit.acf,
+ cpu.regs.bit.zf,
+ cpu.regs.bit.sf
+ );
+#endif
+
+ if (cpu.regs.word.pc == BDOS)
+ cpu.regs.byte.a = bdos(
+ cpu.regs.byte.a,
+ cpu.regs.byte.c,
+ cpu.regs.word.de,
+ &cpu.regs.word.hl
+ );
+ else if (cpu.regs.word.pc >= BIOS_BOOT)
+ cpu.regs.byte.a = bios(
+ cpu.regs.word.pc,
+ cpu.regs.byte.a,
+ cpu.regs.byte.c
+ );
+
+ cpu_8080_execute(&cpu);
+ }
+#endif
+
+ return 0;
+}
--- /dev/null
+nop
+lxi b,0x3412
+stax b
+inx b
+inr b
+dcr b
+mvi b,0x12
+rlc
+nop
+dad b
+ldax b
+dcx b
+inr c
+dcr c
+mvi c,0x12
+rrc
+nop
+lxi d,0x3412
+stax d
+inx d
+inr d
+dcr d
+mvi d,0x12
+ral
+nop
+dad d
+ldax d
+dcx d
+inr e
+dcr e
+mvi e,0x12
+rar
+nop
+lxi h,0x3412
+shld 0x3412
+inx h
+inr h
+dcr h
+mvi h,0x12
+daa
+nop
+dad h
+lhld 0x3412
+dcx h
+inr l
+dcr l
+mvi l,0x12
+cma
+nop
+lxi sp,0x3412
+sta 0x3412
+inx sp
+inr m
+dcr m
+mvi m,0x12
+stc
+nop
+dad sp
+lda 0x3412
+dcx sp
+inr a
+dcr a
+mvi a,0x12
+cmc
+mov b,b
+mov b,c
+mov b,d
+mov b,e
+mov b,h
+mov b,l
+mov b,m
+mov b,a
+mov c,b
+mov c,c
+mov c,d
+mov c,e
+mov c,h
+mov c,l
+mov c,m
+mov c,a
+mov d,b
+mov d,c
+mov d,d
+mov d,e
+mov d,h
+mov d,l
+mov d,m
+mov d,a
+mov e,b
+mov e,c
+mov e,d
+mov e,e
+mov e,h
+mov e,l
+mov e,m
+mov e,a
+mov h,b
+mov h,c
+mov h,d
+mov h,e
+mov h,h
+mov h,l
+mov h,m
+mov h,a
+mov l,b
+mov l,c
+mov l,d
+mov l,e
+mov l,h
+mov l,l
+mov l,m
+mov l,a
+mov m,b
+mov m,c
+mov m,d
+mov m,e
+mov m,h
+mov m,l
+hlt
+mov m,a
+mov a,b
+mov a,c
+mov a,d
+mov a,e
+mov a,h
+mov a,l
+mov a,m
+mov a,a
+add b
+add c
+add d
+add e
+add h
+add l
+add m
+add a
+adc b
+adc c
+adc d
+adc e
+adc h
+adc l
+adc m
+adc a
+sub b
+sub c
+sub d
+sub e
+sub h
+sub l
+sub m
+sub a
+sbb b
+sbb c
+sbb d
+sbb e
+sbb h
+sbb l
+sbb m
+sbb a
+ana b
+ana c
+ana d
+ana e
+ana h
+ana l
+ana m
+ana a
+xra b
+xra c
+xra d
+xra e
+xra h
+xra l
+xra m
+xra a
+ora b
+ora c
+ora d
+ora e
+ora h
+ora l
+ora m
+ora a
+cmp b
+cmp c
+cmp d
+cmp e
+cmp h
+cmp l
+cmp m
+cmp a
+rnz
+pop b
+jnz 0x3412
+jmp 0x3412
+cnz 0x3412
+push b
+adi 0x12
+rst 0
+rz
+ret
+jz 0x3412
+jmp 0x3412
+cz 0x3412
+call 0x3412
+aci 0x12
+rst 1
+rnc
+pop d
+jnc 0x3412
+out 0x12
+cnc 0x3412
+push d
+sui 0x12
+rst 2
+rc
+ret
+jc 0x3412
+in 0x12
+cc 0x3412
+call 0x3412
+sbi 0x12
+rst 3
+rpo
+pop h
+jpo 0x3412
+xthl
+cpo 0x3412
+push h
+ani 0x12
+rst 4
+rpe
+pchl
+jpe 0x3412
+xchg
+cpe 0x3412
+call 0x3412
+xri 0x12
+rst 5
+rp
+pop psw
+jp 0x3412
+di
+cp 0x3412
+push psw
+ori 0x12
+rst 6
+rm
+sphl
+jm 0x3412
+ei
+cm 0x3412
+call 0x3412
+cpi 0x12
+rst 7
--- /dev/null
+Subproject commit 12a4ffb689b4499b4a835206182ab1a49bbcb09c