Initial commit
This commit is contained in:
commit
c6d4c1bdfc
|
@ -0,0 +1,16 @@
|
|||
#TITLE: GRU yemu - Yet another EMUlator
|
||||
|
||||
* Currenty supported platforms
|
||||
- 6502 (implemented some LDA commands and JSR instructions)
|
||||
|
||||
* How to build
|
||||
(Currently only one platform supported but when other platforms/processors will be made other Makefile for all platforms)
|
||||
- cd src/6502
|
||||
- make
|
||||
- now you should see `yemu-6502` executable in src/6502/ directory
|
||||
|
||||
* How to change program
|
||||
Currently ROM files not supported so you'll need to change code of main function in main.c in src/6502 directory.
|
||||
- PC is 0xFFFC by default so your program should start from there
|
||||
- type mem.memory[WHERE] = OPCODE (where WHERE is location in memory and OPCODE is instruction)
|
||||
- remake executable and after running you should see how registers changed in emulator :)
|
|
@ -0,0 +1,39 @@
|
|||
typedef unsigned char byte; // 8 bit
|
||||
typedef unsigned short word; // 16 bit
|
||||
|
||||
#define MAX_MEMORY 1024*64
|
||||
|
||||
// Opcodes
|
||||
|
||||
#define INS_LDA_IM 0xA9 // LDA Immediate
|
||||
#define INS_LDA_ZP 0xA5 // LDA Zero Page
|
||||
#define INS_LDA_ZPX 0xB5 // LDA Zero Page.X
|
||||
|
||||
#define INS_LDX_IM 0xA2 // LDX Immediate
|
||||
#define INS_LDX_ZP 0xA6 // LDX Zero Page
|
||||
|
||||
#define INS_JSR 0x20 // JSR
|
||||
#define INS_RTS 0x60 // RTS
|
||||
|
||||
struct MEMORY {
|
||||
byte memory[MAX_MEMORY];
|
||||
};
|
||||
|
||||
struct CPU {
|
||||
word PC; // The program counter is a 16 bit register which points to the next instruction to be executed.
|
||||
byte SP; // The stack pointer is an 8 bit register and holds the low 8 bits of the next free location on the stack.
|
||||
|
||||
byte A;
|
||||
byte X;
|
||||
byte Y;
|
||||
|
||||
// Flags (or Processor Status)
|
||||
byte C; // Carry Flag
|
||||
byte Z; // Zero Flag
|
||||
byte I; // Interrupt Disable
|
||||
byte D; // Decimal Mode
|
||||
byte B; // Break Command
|
||||
byte V; // Overflow Flag
|
||||
byte N; // Negative Flag
|
||||
};
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
CC = gcc
|
||||
CFLAGS= -O2 -Wall -Wextra
|
||||
LFLAGS=
|
||||
|
||||
SRCFILES= main.c
|
||||
OBJFILES= yemu-6502
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: main
|
||||
|
||||
main:
|
||||
$(CC) $(CFLAGS) $(SRCFILES) -o $(OBJFILES)
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
#include "6502.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct CPU cpu;
|
||||
struct MEMORY mem;
|
||||
byte cycles;
|
||||
|
||||
void memory_init (){ // FIXME: Warning: mem not used
|
||||
for (int i = 0; i < MAX_MEMORY; i++){
|
||||
mem.memory[i] = 0;
|
||||
}
|
||||
}
|
||||
void reset () {
|
||||
cpu.PC = 0xFFFC;
|
||||
cpu.SP = 0x0000; //FIXME
|
||||
cpu.A = cpu.X = cpu.Y = 0;
|
||||
cpu.C = cpu.Z = cpu.I = cpu.D = cpu.B = cpu.V = cpu.N = 0;
|
||||
memory_init(mem);
|
||||
}
|
||||
|
||||
void dump_cpu(struct CPU cpu) {
|
||||
printf("PC: %04X\n", cpu.PC);
|
||||
printf("SP: %04X\n", cpu.SP);
|
||||
printf("A: %04X\n", cpu.A);
|
||||
printf("X: %04X\n", cpu.X);
|
||||
printf("Y: %04X\n", cpu.Y);
|
||||
printf("Flags: C: %X, Z: %X, I: %X, ", cpu.C, cpu.Z, cpu.I);
|
||||
printf("D: %X, V: %X, N: %X\n", cpu.D, cpu.V, cpu.N);
|
||||
}
|
||||
|
||||
byte fetch_byte() {
|
||||
byte data = mem.memory[cpu.PC];
|
||||
cpu.PC++;
|
||||
cycles--;
|
||||
return data;
|
||||
}
|
||||
|
||||
word fetch_word() {
|
||||
word data = mem.memory[cpu.PC];
|
||||
cpu.PC++;
|
||||
|
||||
data |= (mem.memory[cpu.PC] << 8);
|
||||
cpu.PC++;
|
||||
cycles -= 2;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
byte read_byte(byte addr) {
|
||||
byte data = mem.memory[addr];
|
||||
cycles--;
|
||||
return data;
|
||||
}
|
||||
|
||||
word read_word(byte addr) {
|
||||
word data = mem.memory[addr];
|
||||
data |= (mem.memory[addr+1] << 8);
|
||||
cycles -= 2;
|
||||
return data;
|
||||
}
|
||||
|
||||
void write_byte(byte addr, byte value) {
|
||||
mem.memory[addr] = value;
|
||||
cycles--;
|
||||
}
|
||||
|
||||
void write_word(byte addr, word value) {
|
||||
mem.memory[addr] = value & 0xFF;
|
||||
mem.memory[addr+1] = (value >> 8);
|
||||
cycles -= 2;
|
||||
}
|
||||
|
||||
void execute(byte exec_cycles) {
|
||||
cycles = exec_cycles;
|
||||
if (cycles <= 0) {
|
||||
printf("ERROR\n");
|
||||
exit(1);
|
||||
}
|
||||
while (cycles > 0) {
|
||||
byte instruction = fetch_byte();
|
||||
switch(instruction) {
|
||||
case INS_LDA_IM:
|
||||
byte value = fetch_byte();
|
||||
cpu.A = value;
|
||||
cpu.Z = (cpu.A == 0);
|
||||
cpu.N = (cpu.A & 0b1000000) > 0;
|
||||
break;
|
||||
case INS_LDA_ZP:
|
||||
byte zero_page_addr = fetch_byte();
|
||||
cpu.A = read_byte(zero_page_addr);
|
||||
cpu.Z = (cpu.A == 0);
|
||||
cpu.N = (cpu.A & 0b1000000) > 0;
|
||||
break;
|
||||
case INS_LDA_ZPX:
|
||||
byte zero_page_x_addr = cpu.X + fetch_byte();
|
||||
cycles--;
|
||||
cpu.A = read_byte(zero_page_x_addr);
|
||||
cpu.Z = (cpu.A == 0);
|
||||
cpu.N = (cpu.A & 0b1000000) > 0;
|
||||
break;
|
||||
case INS_JSR:
|
||||
word jsr_addr = fetch_word();
|
||||
write_word(cpu.PC - 1, cpu.SP);
|
||||
cpu.SP++;
|
||||
cpu.PC = jsr_addr;
|
||||
cycles--;
|
||||
break;
|
||||
case INS_RTS:
|
||||
// TODO
|
||||
break;
|
||||
default:
|
||||
printf("Unhandled instruction: %04X\n", instruction);
|
||||
cycles--;
|
||||
}
|
||||
}
|
||||
}
|
||||
int main() {
|
||||
reset();
|
||||
|
||||
mem.memory[0xFFFC] = INS_JSR;
|
||||
mem.memory[0xFFFD] = 0x42;
|
||||
mem.memory[0xFFFE] = 0x42;
|
||||
|
||||
mem.memory[0x4242] = INS_LDA_IM;
|
||||
mem.memory[0x4243] = 0x66;
|
||||
mem.memory[0x4244] = INS_LDA_IM;
|
||||
mem.memory[0x4245] = 0x68;
|
||||
|
||||
execute(10);
|
||||
dump_cpu(cpu);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue