Skip to content

Instantly share code, notes, and snippets.

@ilyakurdyukov
Created August 24, 2022 05:49
Show Gist options
  • Save ilyakurdyukov/6b80c55b17fbd0b77d888088c36b4910 to your computer and use it in GitHub Desktop.
Save ilyakurdyukov/6b80c55b17fbd0b77d888088c36b4910 to your computer and use it in GitHub Desktop.
Intel 4004 (mcs-4) emulator written from reading manual (not tested)
// looks correct but not tested at all
// temp
unsigned i, t, x;
// mcs-4 state
unsigned short pc, stack[3];
unsigned char r[16], a, c;
unsigned char test, ram, src, wpm_idx, sp;
unsigned char rom_out[16], rom_in[16], ram_out[4];
// 8 banks x 4 chips x 4 registers x (16 + 4) chars x 4 bits
unsigned char data[8][256], status[8][16][4];
#define NEXT t = prog[pc++]; pc &= 0xfff;
#define ADD a += t; c = a >> 4; a &= 15;
NEXT
switch (t & 0xf0) {
case 0x00: // 0000-0000 NOP (3.9)
if (t) goto illegal;
break;
case 0x10: // 0010-cccc JCN (3.7.3)
i = t & 15;
t = !test | c << 1 | !a << 2 | 16;
i = (i & t) + 15;
NEXT
if (i & 16) pc = (pc & ~0xff) | t;
break;
case 0x20:
i = t & 14;
if (t & 1) {
// 0010-ppp1 SRC (3.10.2)
src = r[i] << 4 | r[i + 1];
} else {
// 0010-ppp0 FIM (3.6.1)
NEXT
r[i] = t >> 4;
r[i + 1] = t & 15;
}
break;
case 0x30:
i = t & 14;
x = r[i] << 4 | r[i + 1];
x |= pc & ~0xff;
if (t & 1) {
// 0011-ppp1 JIN (3.7.2)
pc = x;
} else {
// 0011-ppp0 FIN (3.3.2)
t = prog[x];
r[i] = t >> 4;
r[i + 1] = t & 15;
}
break;
case 0x40: // 0100-xxxx JUN (3.7.1)
i = t & 15;
NEXT
pc = i << 8 | t;
break;
case 0x50: // 0101-xxxx JMS (3.8.1)
i = t & 15;
NEXT
stack[sp] = pc;
sp = sp < 2 ? sp + 1 : 0;
pc = i << 8 | t;
break;
case 0x60: // 0110-rrrr INC (3.3.1)
i = t & 15;
r[i] = (r[i] + 1) & 15;
break;
case 0x70: // 0111-rrrr ISZ (3.7.4)
i = t & 15;
i = r[i] = (r[i] + 1) & 15;
NEXT
if (i) pc = (pc & ~0xff) | t;
break;
case 0x80; // 1000-rrrr ADD (3.4.1)
i = t & 15;
t = r[i] + c;
ADD
break;
case 0x90; // 1001-rrrr SUB (3.4.2)
i = t & 15;
t = 16 - r[i] - c;
ADD
break;
case 0xa0: // 1010-rrrr LD (3.4.3)
i = t & 15;
a = r[i];
break;
case 0xb0: // 1011-rrrr XCH (3.4.4)
i = t & 15;
t = a;
a = r[i];
r[i] = t;
break;
case 0xc0; // 1100-xxxx BBL (3.8.2)
a = t & 15;
sp = sp ? sp - 1 : 2;
pc = stack[sp];
break;
case 0xd0: // 1101-xxxx LDM (3.6.2)
a = t & 15;
break;
case 0xe0: // 1101-xxxx IO (3.11)
switch (t) {
case 0xe0: // 1110-0000 WRM (3.11.4)
data[ram][src] = a; break;
case 0xe1: // 1110-0001 WMP (3.11.6)
ram_out_out[src >> 6] = a; break;
case 0xe2: // 1110-0010 WRR (3.11.7)
rom_out[src >> 4] = a; break;
case 0xe3: // 1110-0011 WPM (3.11.10)
wpm_idx ^= 4;
i = rom_out[15] << 8 | src;
t = prog[i];
if (rom_out[14]) {
prog[i] = (t & ~(15 << wpm_idx)) | a << wpm_idx;
} else {
rom_in[15 - (wpm_idx >> 3)] = t >> wpm_idx & 15;
}
break;
case 0xe4: // 1110-01xx WRn (3.11.5)
case 0xe5: case 0xe6: case 0xe7:
status[ram][src >> 4][t & 3] = a; break;
case 0xe8: // 1110-1000 SBM (3.11.9)
t = 16 - data[ram][src] - c; ADD break;
case 0xe9: // 1110-1001 RDM (3.11.1)
a = data[ram][src]; break;
case 0xea: // 1110-1010 RDR (3.11.3)
a = rom_in[src >> 4]; break;
case 0xeb: // 1110-1011 ADM (3.11.8)
t = data[ram][src] + c; ADD break;
case 0xec: // 1110-11xx RDn (3.11.2)
case 0xed: case 0xee: case 0xef:
a = status[src >> 4][t & 3]; break;
}
break;
case 0xf0:
switch (t) {
case 0xf0: // 1111-0000 CLB (3.5.1)
a = 0; c = 0; break;
case 0xf1: // 1111-0001 CLC (3.5.2)
c = 0; break;
case 0xf2: // 1111-0010 IAC (3.5.3)
t = 1; ADD break;
case 0xf3: // 1111-0011 CMC (3.5.4)
c ^= 1; break;
case 0xf4: // 1111-0011 CMA (3.5.5)
a ^= 15; break;
case 0xf5: // 1111-0101 RAL (3.5.6)
t = a + c; ADD break;
case 0xf6: // 1111-0110 RAR (3.5.7)
a |= c << 4; c = a & 1; a >>= 1; break;
case 0xf7: // 1111-0111 TCC (3.5.8)
a = c; c = 0; break;
case 0xf8: // 1111-1000 DAC (3.5.9)
t = 15; ADD break;
case 0xf9: // 1111-1001 TCS (3.5.10)
a = 9 + c; c = 0; break;
case 0xfa: // 1111-1010 STC (3.5.11)
c = 1; break;
case 0xfb: // 1111-1011 DAA (3.5.12)
if (a > 9 || c) {
a += 6; c = 1; a &= 15;
}
break;
case 0xfc: { // 1111-1100 KBP (3.5.13)
// a = a ? a & (a - 1) ? 15 : CTZ(a) + 1 : 0;
const unsigned char kbp_tab[16] =
{ 0,1,2,15, 3,15,15,15, 4,15,15,15, 15,15,15,15 };
a = kbp_tab[a]; break;
}
case 0xfd: // 1111-1101 DCL (3.10.1)
ram = a & 7; break;
default: goto illegal;
}
break;
default:
illegal:
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment