project-sls-6502-emulator / src / 6502.c
6502.c
Raw
#include "6502.h"
#include "test_vals.h"


typedef void (*opcode_function)(byte, address); 
opcode_function functions[] = {&ADC ,&ADC ,&ADC ,&ADC ,&ADC ,&ADC ,&ADC ,&ADC ,&AND ,&AND ,&AND ,&AND ,&AND ,&AND ,&AND ,&AND ,&ASL ,&ASL ,&ASL ,&ASL ,&BCC ,&BCS ,&BEQ ,&BIT ,&BIT ,&BMI ,&BNE ,&BPL ,&BVC ,&BVS ,&CMP ,&CMP ,&CMP ,&CMP ,&CMP ,&CMP ,&CMP ,&CMP ,&CPX ,&CPX ,&CPX ,&CPY ,&CPY ,&CPY ,&DEC ,&DEC ,&DEC ,&DEC ,&EOR ,&EOR ,&EOR ,&EOR ,&EOR ,&EOR ,&EOR ,&EOR ,&INC ,&INC ,&INC ,&INC ,&JMP ,&JMP ,&JSR ,&LDA ,&LDA ,&LDA ,&LDA ,&LDA ,&LDA ,&LDA ,&LDA ,&LDX ,&LDX ,&LDX ,&LDX ,&LDX ,&LDY ,&LDY ,&LDY ,&LDY ,&LDY ,&LSR ,&LSR ,&LSR ,&LSR ,&ORA ,&ORA ,&ORA ,&ORA ,&ORA ,&ORA ,&ORA ,&ORA ,&ROL ,&ROL ,&ROL ,&ROL ,&ROR ,&ROR ,&ROR ,&ROR ,&SBC ,&SBC ,&SBC ,&SBC ,&SBC ,&SBC ,&SBC ,&SBC ,&STA ,&STA ,&STA ,&STA ,&STA ,&STA ,&STA ,&STX ,&STX ,&STX ,&STY ,&STY ,&STY ,&BRK ,&CLC ,&CLD ,&CLI ,&CLV ,&DEX ,&DEY ,&INX ,&INY ,&NOP ,&PHA ,&PHP ,&PLA ,&PLP ,&RTI ,&RTS ,&SEC ,&SED ,&SEI ,&TAX ,&TAY ,&TSX ,&TXA ,&TXS ,&TYA};

void read_in_binary_image(char* image_name){
  int n, fd;
  if((fd=open(image_name, O_RDONLY)) < 0){
    exit(-1);
  }
  if((n = read(fd, OurComputer->RAM, RAMSIZE)) != RAMSIZE){
    exit(-1);
  }
  close(fd);
}

void initialize_registers() {
    OurComputer->cpu_inst->pc = 0;
    OurComputer->cpu_inst->accumulator = 0;
    OurComputer->cpu_inst->register_x = 0;
    OurComputer->cpu_inst->register_y = 0;
    OurComputer->cpu_inst->status_register = 0;
    OurComputer->cpu_inst->stack_pointer = 0xFF; 
    return;
}

void execute(byte opcode, address pc) {
  struct opcode_table *s; // used in execute(byte, address)
  HASH_FIND_BYTE(OurComputer->opcodes, &opcode, s);
  if(s == NULL){
    printf("Byte not in table \n"); 
    printf("opcode = %x \n", opcode); 
    exit(-1); 
  }
  (*s->opcode_function) (opcode, pc);
  return; 
}

// Builds opcode table
void build_opcode_table(){
  int n, fd;
  byte* opcodes_keys;
  OurComputer->opcodes = NULL;
  // need to read in the opcodes
  if((opcodes_keys = (byte*) malloc((opcode_size) * sizeof(byte))) == NULL){
    exit(-1);
  }
  if((fd=open("opcode_values", O_RDONLY)) < 0){
    exit(-1);
  }
  if((n = read(fd, opcodes_keys, opcode_size)) != opcode_size){
    exit(-1);
  }
  close(fd);

  struct opcode_table* s = NULL;
  for (int i = 0; i  < opcode_size; i++){
    s = (struct opcode_table*) malloc(sizeof(*s)); // check if NULL?
    if(s == NULL){
      printf("Memory allocation err");
      exit(-1);
    }
    s->opcodes_key = opcodes_keys[i]; // initializing key for s
    s->opcode_function = functions[i]; // initializing the value for s
    HASH_ADD(hh,OurComputer->opcodes, opcodes_key, sizeof(uint8_t),s);
  }

  s = (struct opcode_table*) malloc(sizeof(*s));
  if(s == NULL){
      printf("Memory allocation err");
      exit(-1);
  }
  s->opcodes_key = 0x4a; // not stored in binary image correctly
  s->opcode_function = &LSR; 
  HASH_ADD(hh,OurComputer->opcodes, opcodes_key, sizeof(uint8_t),s);

  s = (struct opcode_table*) malloc(sizeof(*s));
  if(s == NULL){
      printf("Memory allocation err");
      exit(-1);
  }
  s->opcodes_key = 0xa; // not stored in binary image correctly
  s->opcode_function = &ASL; 
  HASH_ADD(hh,OurComputer->opcodes, opcodes_key, sizeof(uint8_t),s);

  s = (struct opcode_table*) malloc(sizeof(*s));
  if(s == NULL){
      printf("Memory allocation err");
      exit(-1);
  }
  s->opcodes_key = 0x6a; // not stored in binary image correctly
  s->opcode_function = &ROR; 
  HASH_ADD(hh,OurComputer->opcodes, opcodes_key, sizeof(uint8_t),s);

  s = (struct opcode_table*) malloc(sizeof(*s));
  if(s == NULL){
      printf("Memory allocation err");
      exit(-1);
  }
  s->opcodes_key = 0x2a; // not stored in binary image correctly
  s->opcode_function = &ROL; 
  HASH_ADD(hh,OurComputer->opcodes, opcodes_key, sizeof(uint8_t),s);

  free(s); 
  return; 
}

// Assumes little endian
void printBits(size_t const size, void const * const ptr)
{
    unsigned char *b = (unsigned char*) ptr;
    unsigned char byte;
    int i, j;
    
    for (i = size-1; i >= 0; i--) {
        for (j = 7; j >= 0; j--) {
            byte = (b[i] >> j) & 1;
            printf("%u", byte);
        }
    }
    puts("");
}

void test_registers(address index){
  if(OurComputer->cpu_inst->pc != PCs[index]){
      printf("Our PC = %x \n", OurComputer->cpu_inst->pc); 
      printf("Correct PC = %x \n", PCs[index]); 
      printf("Wrong pc address at index %hu \n", index); 
      exit(-1);
    }
  if(OurComputer->cpu_inst->accumulator != A[index]){
    printf("Our accumulator value =");
    printBits(sizeof(OurComputer->cpu_inst->accumulator), &OurComputer->cpu_inst->accumulator);
    printf("\n");
    printf("Correct accumulator value ="); 
    printBits(sizeof(A[index]), &A[index]);
    printf("\n");
    printf("Wrong accumulator value at index %hu \n", index);
    exit(-1);
  }
  if(OurComputer->cpu_inst->register_x != X[index]){
    printf("Our register X value = %u \n", OurComputer->cpu_inst->register_x); 
    printf("Correct register X value = %u \n", X[index]); 
    printf("Wrong value in register X at index %hu \n", index);
    exit(-1);
  }
  if(OurComputer->cpu_inst->register_y != Y[index]){
    printf("Our register Y value = %u \n", OurComputer->cpu_inst->register_y); 
    printf("Correct register Y value = %u \n", Y[index]); 
    printf("Wrong value in register Y at index %hu \n", index);
    exit(-1);
  }
  if(OurComputer->cpu_inst->stack_pointer != SP[index]){
    printf("Our stack pointer value = %u \n", OurComputer->cpu_inst->stack_pointer); 
    printf("Correct stack pointer value = %u \n", SP[index]); 
    printf("Wrong stack pointer value at index %hu \n", index); 
    exit(-1);
  }
} 


void start_cpu(){
  OurComputer->cpu_inst->pc = 0xC000; // starting address of the test opcodes
  OurComputer->cpu_inst->stack_pointer = 0xFD; 
  address stack_ptr;
  byte temp_stck_ptr; 

  for(address i = 0; i < 8991; i++){ // 8991 is the amount of test opcodes
    temp_stck_ptr = OurComputer->cpu_inst->stack_pointer + 1; 
    stack_ptr = 1U << 8 | temp_stck_ptr; 

    //printf("current index = %hu, carry flag = %d \n", i, ((OurComputer->cpu_inst->status_register) & 0b1) );
    printf("current index = %hu, ", i);
    printf("Our stack register value =");
    printBits(sizeof(OurComputer->cpu_inst->status_register), &OurComputer->cpu_inst->status_register);
    printf("\n");

    test_registers(i); 
    execute(OurComputer->RAM[OurComputer->cpu_inst->pc], OurComputer->cpu_inst->pc);
  }
}

int main(int argc, char* argv[]) {
  // user must pass in binary image to simulate RAM
  if (argc != 2){
    printf("%s outfile", argv[0]);
    return 1;
  }

  char* file_name = argv[1];
  // allocate memory for Computer Structure
  if((OurComputer = (struct Computer*) malloc(sizeof(struct Computer))) == NULL){
    exit(-1);
  }
  // initializing size of the RAM to 2^16
  if ((OurComputer->RAM = (byte*) malloc(RAMSIZE * sizeof(byte))) == NULL){
    exit(-1);
  }
  // initializing cpu structure inside of computer
  if((OurComputer->cpu_inst = (struct cpu*) malloc(sizeof(struct cpu))) == NULL){
    exit(-1);
  }

  read_in_binary_image(file_name); // fill struct->RAM with file_name
  build_opcode_table(); // link opcodes to functions in void_functions.c
  initialize_registers();
  start_cpu();

  free(OurComputer->RAM);
  free(OurComputer->cpu_inst);
  free(OurComputer);
  return 0;
}