2024-01-06 19:33:56 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdint.h> // for the uintx_t's
|
2024-01-06 21:23:36 +00:00
|
|
|
#include "disassembler.c"
|
|
|
|
|
|
|
|
// gcc emulator_shell.c disassembler.c -o disassembler
|
|
|
|
|
|
|
|
int disassemble8080(buffer* b, int pc);
|
2024-01-06 19:33:56 +00:00
|
|
|
|
|
|
|
|
|
|
|
typedef struct ConditionCodes {
|
|
|
|
//bitfields for condition codes
|
|
|
|
//the number following the variables sets the number of bits
|
|
|
|
uint8_t z:1;
|
|
|
|
uint8_t s:1;
|
|
|
|
uint8_t p:1;
|
|
|
|
uint8_t cy:1;
|
|
|
|
uint8_t ac:1;
|
|
|
|
uint8_t pad:3;
|
|
|
|
} ConditionCodes;
|
|
|
|
|
|
|
|
typedef struct State8080 {
|
|
|
|
uint8_t a;
|
|
|
|
uint8_t b;
|
|
|
|
uint8_t c;
|
|
|
|
uint8_t d;
|
|
|
|
uint8_t e;
|
|
|
|
uint8_t h;
|
|
|
|
uint8_t l;
|
|
|
|
uint16_t sp;
|
|
|
|
uint16_t pc;
|
|
|
|
uint8_t *memory;
|
|
|
|
struct ConditionCodes cc;
|
|
|
|
uint8_t int_enable;
|
|
|
|
} State8080;
|
|
|
|
|
|
|
|
int unknownInstruction(State8080* state) {
|
|
|
|
printf("Error: Unknown instruction");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int parity(int x, int size)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int p = 0;
|
|
|
|
x = (x & ((1<<size)-1));
|
|
|
|
for (i=0; i<size; i++)
|
|
|
|
{
|
|
|
|
if (x & 0x1) p++;
|
|
|
|
x = x >> 1;
|
|
|
|
}
|
|
|
|
return (0 == (p & 0x1));
|
|
|
|
}
|
|
|
|
|
|
|
|
int emulate8080(State8080* state) {
|
|
|
|
unsigned char *opcode = &(state->memory[state->pc]);
|
|
|
|
|
|
|
|
switch(*opcode) {
|
|
|
|
case 0x00: break; // NOP does nothing
|
|
|
|
case 0x01: // LXI B, word
|
|
|
|
state->c = opcode[1];
|
|
|
|
state->b = opcode[2];
|
|
|
|
state->pc += 2;
|
|
|
|
break;
|
|
|
|
case 0x05: // DCR B
|
|
|
|
uint8_t res = state->b - 1;
|
|
|
|
state->b = res;
|
|
|
|
state->cc.z = (res == 0);
|
|
|
|
state->cc.s = ((res & 0x80) != 0);
|
|
|
|
state->cc.p = parity(res, 8);
|
|
|
|
break;
|
|
|
|
case 0x06: // MVI B, byte
|
|
|
|
state->b = opcode[1];
|
|
|
|
state->pc += 1;
|
|
|
|
break;
|
|
|
|
case 0x09: // DAD B
|
|
|
|
uint32_t h1 = (state->h << 8) | state->l;
|
|
|
|
uint32_t bc = (state->b << 8) | state->c;
|
|
|
|
uint32_t res = h1 + bc;
|
|
|
|
state->h = (res & 0xff) >> 8;
|
|
|
|
state->l = res & 0xff;
|
2024-01-06 21:47:44 +00:00
|
|
|
state->cc.cy = ((res & 0xffff0000) != 0);
|
2024-01-06 21:23:36 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x0d: // DCR C
|
|
|
|
uint8_t res = state->c - 1;
|
|
|
|
state->c = res;
|
|
|
|
state->cc.z = (res == 0);
|
|
|
|
state->cc.s = ((res & 0x80) != 0);
|
|
|
|
state->cc.p = parity(res, 8);
|
2024-01-06 19:33:56 +00:00
|
|
|
break;
|
|
|
|
case 0x0e: // MVI C, byte
|
|
|
|
state->c = opcode[1];
|
|
|
|
state->pc += 1;
|
|
|
|
break;
|
2024-01-06 21:23:36 +00:00
|
|
|
case 0x0f: // RRC
|
|
|
|
uint8_t x = state->a;
|
|
|
|
state->a = ((x & 1) << 7) | (x >> 1);
|
|
|
|
state->cc.cy = (1 == (x & 1));
|
|
|
|
break;
|
2024-01-06 19:33:56 +00:00
|
|
|
case 0x11: // LXI D, word
|
|
|
|
state->d = opcode[2];
|
|
|
|
state->e = opcode[1];
|
|
|
|
state->pc += 2;
|
2024-01-06 21:23:36 +00:00
|
|
|
case 0x13: // INX D
|
|
|
|
state->e++;
|
|
|
|
if (state->e == 0) {
|
|
|
|
state->d++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 0x19: // DAD D
|
|
|
|
uint32_t h1 = (state->h << 8) | state->l;
|
|
|
|
uint32_t de = (state->d << 8) | state->e;
|
|
|
|
uint32_t res = h1 + de;
|
|
|
|
state->h = (res & 0xff) >> 8;
|
|
|
|
state->l = res & 0xff;
|
|
|
|
state->cc.cy = ((res & 0xffff0000) != 0);
|
|
|
|
break;
|
|
|
|
case 0x1a: // LDAX D
|
|
|
|
uint16_t de = (state->d << 8) | state->e;
|
|
|
|
state->a = state->memory[de];
|
|
|
|
break;
|
|
|
|
|
2024-01-06 19:33:56 +00:00
|
|
|
case 0x21: // LXI H, word
|
|
|
|
state->h = opcode[2];
|
|
|
|
state->l = opcode[1];
|
|
|
|
state->pc += 2;
|
2024-01-06 21:23:36 +00:00
|
|
|
case 0x23: // INX H
|
|
|
|
state->l++;
|
|
|
|
if (state->l == 0) {
|
|
|
|
state->h++;
|
|
|
|
}
|
|
|
|
break;
|
2024-01-06 19:33:56 +00:00
|
|
|
case 0x26: // MVI H, byte
|
|
|
|
state->h = opcode[1];
|
|
|
|
state->pc += 1;
|
|
|
|
break;
|
2024-01-06 21:47:44 +00:00
|
|
|
case 0x29: // DAD H
|
|
|
|
uint32_t h1 = (state->h << 8) | state->l;
|
|
|
|
uint32_t res = hl + hl;
|
|
|
|
state->h = (res & 0xff00) >> 8;
|
|
|
|
state->l = res & 0xff;
|
|
|
|
state->cc.cy = ((res & 0xffff0000) != 0);
|
2024-01-06 19:33:56 +00:00
|
|
|
case 0x31: // LXI SP, word
|
|
|
|
state->sp = (opcode[2] << 8) | opcode[1]);
|
|
|
|
state->pc += 2;
|
|
|
|
case 0x36: // MVI M, byte
|
|
|
|
state->m = opcode[1];
|
|
|
|
state->pc += 1;
|
|
|
|
break;
|
|
|
|
case 0x3e: // MVI A, byte
|
|
|
|
state->a = opcode[1];
|
|
|
|
state->pc += 1;
|
|
|
|
case 0x41: // MOV B, C
|
|
|
|
state->b = state->c;
|
|
|
|
break;
|
|
|
|
case 0x42: // MOV B, D
|
|
|
|
state->b = state->d;
|
|
|
|
break;
|
|
|
|
case 0x43: // MOV B, E
|
|
|
|
state->b = state->e;
|
|
|
|
break;
|
|
|
|
case 0x80: // ADD B
|
|
|
|
uint16_t answer = (uint16_t) state->a + (uint16_t) state->b;
|
|
|
|
state->cc.z = ((answer & 0xff) == 0);
|
|
|
|
state->cc.s = ((answer & 0x80) != 0);
|
|
|
|
state->cc.cy = (answer > 0xff);
|
|
|
|
state->cc.p = parity(answer & 0xff);
|
|
|
|
state->a = answer & 0xff;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x86: // ADD M
|
|
|
|
uint16_t offset = (state->h<<8) | (state->l);
|
|
|
|
uint16_t answer = (uint16_t) state->a + state->memory[offset];
|
|
|
|
state->cc.z = ((answer & 0xff) == 0);
|
|
|
|
state->cc.s = ((answer & 0x80) != 0);
|
|
|
|
state->cc.cy = (answer > 0xff);
|
|
|
|
state->cc.p = parity(answer & 0xff);
|
|
|
|
state->a = answer & 0xff;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xc1: // POP B
|
|
|
|
state->c = state->memory[state->sp];
|
|
|
|
state->b = state->memory[state->sp+1];
|
|
|
|
state->sp += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xc2: // JNZ adress
|
|
|
|
if (0 = state-> cc.z) {
|
|
|
|
state->pc = (opcode[2] << 8) | opcode[1];
|
|
|
|
} else {
|
|
|
|
state->pc += 2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xc3: // JMP adress
|
|
|
|
state->pc = (opcode[2] << 8) | opcode[1];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xc5: // PUSH B
|
|
|
|
state->memory[state->sp-1] = state->b;
|
|
|
|
state->memory[state->sp-2] = state->c;
|
|
|
|
state->sp -= 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case 0xc6: // ADI byte
|
|
|
|
uint16_t answer = (uint16_t) state->a + (uint16_t) opcode[1];
|
|
|
|
state->cc.z = ((state->a & 0xff) == 0);
|
|
|
|
state->cc.s = ((state->a & 0x80) != 0);
|
|
|
|
state->cc.cy = (state->a > 0xff);
|
|
|
|
state->cc.p = parity(state->a & 0xff);
|
|
|
|
state->pc += 1;
|
|
|
|
break;
|
|
|
|
case 0xcd: // CALL adress
|
|
|
|
uint16_t ret = state -> pc+2;
|
|
|
|
state->memory[state->sp-1] = (ret >> 8) & 0xff;
|
|
|
|
state->memory[state->sp-2] = (ret & 0xff);
|
|
|
|
state->sp -= 2;
|
|
|
|
state->pc = (opcode[2] << 8) | opcode[1];
|
|
|
|
break;
|
|
|
|
case 0xc9: // RET
|
|
|
|
state->sp += 2;
|
|
|
|
state->pc = (state->memory[state->sp+1] << 8) | state->memory[state->sp];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x2f: // CMA (NOT)
|
|
|
|
state->a = ~state->a;
|
|
|
|
break;
|
|
|
|
case 0xe6: // ANI byte
|
|
|
|
uint8_t x = state->a & opcode[1];
|
|
|
|
state->cc.z = (x == 0);
|
|
|
|
state->cc.s = (0x80 == (x & 0x80));
|
|
|
|
state->cc.cy = 0;
|
|
|
|
state->cc.p = parity(x, 8);
|
|
|
|
state->pc++;
|
|
|
|
break;
|
|
|
|
|
2024-01-06 21:23:36 +00:00
|
|
|
|
2024-01-06 19:33:56 +00:00
|
|
|
|
|
|
|
case 0x1f: // RAR
|
|
|
|
uint8_t x = state->a;
|
|
|
|
state->a = (state->cc.cy << 7) | (x >> 1);
|
|
|
|
state->cc.cy = (1 == (x & 1));
|
|
|
|
break;
|
|
|
|
|
2024-01-06 21:23:36 +00:00
|
|
|
case 0xf1: // POP PSW
|
|
|
|
state->a = state->memory[state->sp+1];
|
|
|
|
uint8_t psw = state->memory[state->sp];
|
|
|
|
state->cc.z = (0x01 == (psw & 0x01));
|
|
|
|
state->cc.s = (0x02 == (psw & 0x02));
|
|
|
|
state->cc.p = (0x04 == (psw & 0x04));
|
|
|
|
state->cc.cy = (0x08 == (psw & 0x08));
|
|
|
|
state->cc.ac = (0x10 == (psw & 0x10));
|
|
|
|
state->sp += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xf5: // PUSH PSW
|
|
|
|
state->memory[state->sp-1] = state->a;
|
|
|
|
state->memory[state->sp-2] = (state->cc.z | (state->cc.s << 1) | (state->cc.p << 2) | (state->cc.cy << 3) | (state->cc.ac << 4));
|
|
|
|
state->sp -= 2;
|
|
|
|
break;
|
|
|
|
|
2024-01-06 19:33:56 +00:00
|
|
|
case 0xfe: // CPI byte
|
|
|
|
uint8_t x = state->a - opcode[1];
|
|
|
|
state->cc.z = (x == 0);
|
|
|
|
state->cc.s = (0x80 == (x & 0x80));
|
|
|
|
state->cc.cy = (state->a < opcode[1]);
|
|
|
|
state->cc.p = parity(x, 8);
|
|
|
|
state->pc++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: unknownInstruction(state); break;
|
|
|
|
}
|
|
|
|
state->pc+1;
|
|
|
|
}
|