DEBUG (major bug found)
This commit is contained in:
parent
0aaddea28e
commit
ba3a89628a
1 changed files with 120 additions and 69 deletions
189
emulator_shell.c
189
emulator_shell.c
|
@ -2,40 +2,12 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdint.h> // for the uintx_t's
|
||||
#include <unistd.h> // for sleep
|
||||
#include <string.h> // for memset
|
||||
|
||||
// gcc emulator_shell.c -o emulator
|
||||
|
||||
typedef struct buffer {
|
||||
unsigned char* buffer;
|
||||
int length;
|
||||
} buffer;
|
||||
|
||||
buffer* read_file(char** argv) {
|
||||
FILE* file = fopen(argv[1], "rb");
|
||||
if (file == NULL) {
|
||||
printf("Issue opening the file.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//Get the file size and read it into a memory buffer
|
||||
fseek(file, 0L, SEEK_END);
|
||||
int fsize = ftell(file);
|
||||
fseek(file, 0L, SEEK_SET);
|
||||
|
||||
buffer *b = malloc(sizeof(buffer));
|
||||
b->buffer=malloc(fsize);
|
||||
b->length=fsize;
|
||||
|
||||
fread(b->buffer, fsize, 1, file);
|
||||
fclose(file);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
int disassemble8080(buffer* b, int pc) {
|
||||
unsigned char *code = &(b->buffer[pc]);
|
||||
int disassemble8080(unsigned char* code) {
|
||||
int opbytes = 1;
|
||||
printf("%04x ", pc);
|
||||
switch (*code) {
|
||||
case 0x00: printf("NOP"); break;
|
||||
|
||||
|
@ -344,7 +316,8 @@ typedef struct ConditionCodes {
|
|||
uint8_t cy:1;
|
||||
uint8_t ac:1;
|
||||
uint8_t pad:3;
|
||||
} ConditionCodes;
|
||||
} ConditionCodes;
|
||||
|
||||
|
||||
typedef struct State8080 {
|
||||
uint8_t a;
|
||||
|
@ -357,7 +330,7 @@ typedef struct State8080 {
|
|||
uint16_t sp;
|
||||
uint16_t pc;
|
||||
uint8_t *memory;
|
||||
struct ConditionCodes cc;
|
||||
ConditionCodes cc;
|
||||
uint8_t int_enable;
|
||||
} State8080;
|
||||
|
||||
|
@ -382,7 +355,10 @@ int parity(int x, int size)
|
|||
int emulate8080(State8080* state) {
|
||||
unsigned char *opcode = &(state->memory[state->pc]);
|
||||
|
||||
disassemble8080(buff, pc);
|
||||
printf("%04x ", state->pc);
|
||||
|
||||
disassemble8080(opcode);
|
||||
state->pc++;
|
||||
|
||||
switch(*opcode) {
|
||||
case 0x00: break; // NOP does nothing
|
||||
|
@ -392,68 +368,82 @@ int emulate8080(State8080* state) {
|
|||
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.s = (0x80 == (res & 0x80));
|
||||
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 result = h1 + bc;
|
||||
state->h = (result & 0xff) >> 8;
|
||||
state->h = (result & 0xff00) >> 8;
|
||||
state->l = result & 0xff;
|
||||
state->cc.cy = ((res & 0xffff0000) != 0);
|
||||
state->cc.cy = ((result & 0xffff0000) != 0);
|
||||
}
|
||||
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.s = ((res & 0x80) == 0x80);
|
||||
state->cc.p = parity(res, 8);
|
||||
}
|
||||
break;
|
||||
case 0x0e: // MVI C, byte
|
||||
state->c = opcode[1];
|
||||
state->pc += 1;
|
||||
state->pc++;
|
||||
break;
|
||||
case 0x0f: // RRC
|
||||
{
|
||||
uint8_t x = state->a;
|
||||
state->a = ((x & 1) << 7) | (x >> 1);
|
||||
state->cc.cy = (1 == (x & 1));
|
||||
}
|
||||
break;
|
||||
case 0x11: // LXI D, word
|
||||
state->d = opcode[2];
|
||||
state->e = opcode[1];
|
||||
state->pc += 2;
|
||||
break;
|
||||
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 result = h1 + de;
|
||||
state->h = (result & 0xff) >> 8;
|
||||
state->h = (result & 0xff00) >> 8;
|
||||
state->l = result & 0xff;
|
||||
state->cc.cy = ((result & 0xffff0000) != 0);
|
||||
}
|
||||
break;
|
||||
case 0x1a: // LDAX D
|
||||
{
|
||||
uint16_t de = (state->d << 8) | state->e;
|
||||
state->a = state->memory[de];
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x21: // LXI H, word
|
||||
state->h = opcode[2];
|
||||
state->l = opcode[1];
|
||||
state->pc += 2;
|
||||
break;
|
||||
case 0x23: // INX H
|
||||
state->l++;
|
||||
if (state->l == 0) {
|
||||
|
@ -462,38 +452,48 @@ int emulate8080(State8080* state) {
|
|||
break;
|
||||
case 0x26: // MVI H, byte
|
||||
state->h = opcode[1];
|
||||
state->pc += 1;
|
||||
state->pc++;
|
||||
break;
|
||||
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);
|
||||
{
|
||||
uint32_t hl = (state->h << 8) | state->l;
|
||||
uint32_t result = hl + hl;
|
||||
state->h = (result & 0xff00) >> 8;
|
||||
state->l = result & 0xff;
|
||||
state->cc.cy = ((result & 0xffff0000) != 0);
|
||||
}
|
||||
break;
|
||||
case 0x31: // LXI SP, word
|
||||
state->sp = ((opcode[2] << 8) | opcode[1]);
|
||||
state->pc += 2;
|
||||
break;
|
||||
case 0x32: // STA adress
|
||||
{
|
||||
uint16_t adress = (opcode[2]<<8) | (opcode[1]);
|
||||
state->memory[offset] = state->a;
|
||||
state->memory[adress] = state->a;
|
||||
state->pc += 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x36: // MVI M, byte
|
||||
{
|
||||
uint16_t adress = (state->h <<8) | (state->l);
|
||||
state->memory[adress] = opcode[1];
|
||||
state->pc += 1;
|
||||
state->pc++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x3a: // LDA adress
|
||||
{
|
||||
uint16_t adress = (opcode[2]<<8) | (opcode[1]);
|
||||
state->a = state->memory[adress];
|
||||
state->pc += 2;
|
||||
}
|
||||
break;
|
||||
case 0x3e: // MVI A, byte
|
||||
state->a = opcode[1];
|
||||
state->pc += 1;
|
||||
state->pc++;
|
||||
break;
|
||||
case 0x41: // MOV B, C
|
||||
state->b = state->c;
|
||||
break;
|
||||
|
@ -504,23 +504,31 @@ int emulate8080(State8080* state) {
|
|||
state->b = state->e;
|
||||
break;
|
||||
case 0x56: // MOV D, M
|
||||
{
|
||||
uint16_t adress = (state->h<<8) | (state->l);
|
||||
state->d = state->memory[adress];
|
||||
}
|
||||
break;
|
||||
case 0x5e: // MOV E, M
|
||||
{
|
||||
uint16_t adress = (state->h<<8) | (state->l);
|
||||
state->e = state->memory[adress];
|
||||
}
|
||||
break;
|
||||
case 0x66: // MOV H, M
|
||||
{
|
||||
uint16_t adress = (state->h<<8) | (state->l);
|
||||
state->h = state->memory[adress];
|
||||
}
|
||||
break;
|
||||
case 0x6f: // MOV L, A
|
||||
state->l = state->a;
|
||||
break;
|
||||
case 0x77: // MOV M, A
|
||||
{
|
||||
uint16_t adress = (state->h<<8) | (state->l);
|
||||
state->memory[adress] = state->a;
|
||||
}
|
||||
break;
|
||||
case 0x7a: // MOV A, D
|
||||
state->a = state->d;
|
||||
|
@ -532,19 +540,24 @@ int emulate8080(State8080* state) {
|
|||
state->a = state->h;
|
||||
break;
|
||||
case 0x7e: // MOV A, M
|
||||
{
|
||||
uint16_t adress = (state->h<<8) | (state->l);
|
||||
state->a = state->memory[adress];
|
||||
}
|
||||
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, 8);
|
||||
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);
|
||||
|
@ -552,17 +565,20 @@ int emulate8080(State8080* state) {
|
|||
state->cc.cy = (answer > 0xff);
|
||||
state->cc.p = parity(answer & 0xff, 8);
|
||||
state->a = answer & 0xff;
|
||||
}
|
||||
break;
|
||||
case 0x1f: // RAR
|
||||
{
|
||||
uint8_t x = state->a;
|
||||
state->a = (state->cc.cy << 7) | (x >> 1);
|
||||
state->cc.cy = (1 == (x & 1));
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xa7: // ANA A
|
||||
state->a &= state->a;
|
||||
state->cc.z = (state->a == 0);
|
||||
state->cc.s = (0 != (state->a & 0x80));
|
||||
state->cc.s = (0x80 == (state->a & 0x80));
|
||||
state->cc.p = parity(state->a, 8);
|
||||
state->cc.cy = 0;
|
||||
state->cc.ac = 0;
|
||||
|
@ -570,7 +586,7 @@ int emulate8080(State8080* state) {
|
|||
case 0xaf: // XRA A
|
||||
state->a ^= state->a;
|
||||
state->cc.z = (state->a == 0);
|
||||
state->cc.s = (0 != (state->a & 0x80));
|
||||
state->cc.s = (0x80 == (state->a & 0x80));
|
||||
state->cc.p = parity(state->a, 8);
|
||||
state->cc.cy = 0;
|
||||
state->cc.ac = 0;
|
||||
|
@ -582,7 +598,7 @@ int emulate8080(State8080* state) {
|
|||
break;
|
||||
|
||||
case 0xc2: // JNZ adress
|
||||
if (0 = state-> cc.z) {
|
||||
if (0 == state-> cc.z) {
|
||||
state->pc = (opcode[2] << 8) | opcode[1];
|
||||
} else {
|
||||
state->pc += 2;
|
||||
|
@ -599,23 +615,27 @@ int emulate8080(State8080* state) {
|
|||
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.s = ((state->a & 0x80) == 0x80);
|
||||
state->cc.cy = (state->a > 0xff);
|
||||
state->cc.p = parity(state->a & 0xff, 8);
|
||||
state->pc += 1;
|
||||
state->pc++;
|
||||
}
|
||||
break;
|
||||
case 0xc9: // RET
|
||||
state->sp += 2;
|
||||
state->pc = (state->memory[state->sp+1] << 8) | state->memory[state->sp];
|
||||
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 0xd1: // POP D
|
||||
state->e = state->memory[state->sp];
|
||||
|
@ -647,24 +667,29 @@ int emulate8080(State8080* state) {
|
|||
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;
|
||||
|
||||
case 0xeb: // XCHG
|
||||
{
|
||||
uint8_t tmp = state->h;
|
||||
state->h = state->d;
|
||||
state->d = tmp;
|
||||
tmp = state->l;
|
||||
state->l = state->e;
|
||||
state->e = tmp;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xf1: // POP PSW
|
||||
{
|
||||
state->a = state->memory[state->sp+1];
|
||||
uint8_t psw = state->memory[state->sp];
|
||||
state->cc.z = (0x01 == (psw & 0x01));
|
||||
|
@ -673,6 +698,7 @@ int emulate8080(State8080* state) {
|
|||
state->cc.cy = (0x08 == (psw & 0x08));
|
||||
state->cc.ac = (0x10 == (psw & 0x10));
|
||||
state->sp += 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xf5: // PUSH PSW
|
||||
|
@ -686,12 +712,14 @@ int emulate8080(State8080* state) {
|
|||
break;
|
||||
|
||||
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;
|
||||
|
@ -701,35 +729,58 @@ int emulate8080(State8080* state) {
|
|||
printf("\tA $%02x B $%02x C $%02x D $%02x E $%02x H $%02x L $%02x SP %04x\n",
|
||||
state->a, state->b, state->c, state->d,
|
||||
state->e, state->h, state->l, state->sp);
|
||||
state->pc+1;
|
||||
|
||||
}
|
||||
|
||||
int main (int argc, char** argv) {
|
||||
|
||||
buffer* buff = read_file(argv);
|
||||
if (buff == NULL) {
|
||||
printf("Fatal error.\n");
|
||||
return 1;
|
||||
void read_Space_Invaders_ROM(State8080* state, const char* filename, int offset) {
|
||||
//Works exclusively with the memory system of Space Invaders
|
||||
FILE* file = fopen(filename, "rb");
|
||||
if (file == NULL) {
|
||||
printf("Issue opening the file.\n");
|
||||
exit(1);
|
||||
}
|
||||
//Get the file size and read it into a memory buffer
|
||||
fseek(file, 0L, SEEK_END);
|
||||
int fsize = ftell(file);
|
||||
fseek(file, 0L, SEEK_SET);
|
||||
|
||||
uint8_t *buffer = &state->memory[offset];
|
||||
|
||||
fread(buffer, fsize, 1, file);
|
||||
fclose(file);
|
||||
|
||||
}
|
||||
|
||||
int main (void) {
|
||||
|
||||
//Initializations
|
||||
|
||||
ConditionCodes *cc = malloc(sizeof(ConditionCodes));
|
||||
State8080 *state = (State8080*) malloc(sizeof(State8080));
|
||||
memset(state, 0, sizeof(State8080));
|
||||
memset(cc, 0, sizeof(ConditionCodes));
|
||||
state->cc = cc;
|
||||
state->cc.z = 1;
|
||||
state->cc.s = 1;
|
||||
state->cc.p = 1;
|
||||
state->cc.cy = 0;
|
||||
state->cc.ac = 1;
|
||||
state->pc = 0;
|
||||
state->memory = (uint8_t*) buff->buffer;
|
||||
state->memory = malloc(0x10000);
|
||||
|
||||
read_Space_Invaders_ROM(state, "ROM/invaders.h", 0);
|
||||
read_Space_Invaders_ROM(state, "ROM/invaders.g", 0x800);
|
||||
read_Space_Invaders_ROM(state, "ROM/invaders.f", 0x1000);
|
||||
read_Space_Invaders_ROM(state, "ROM/invaders.e", 0x1800);
|
||||
|
||||
int i = 0;
|
||||
|
||||
while (1) {
|
||||
//Show the command in the code
|
||||
int a = disassemble8080(buff, state->pc);
|
||||
printf("%d\t\t:", i);
|
||||
emulate8080(state);
|
||||
sleep(0.5);
|
||||
i++;
|
||||
sleep(0.00001);
|
||||
}
|
||||
|
||||
free(buff);
|
||||
free(state->memory);
|
||||
free(state);
|
||||
return 0;
|
||||
|
||||
}
|
Loading…
Reference in a new issue