Initial commit

This commit is contained in:
g1n 2021-09-03 17:27:51 +03:00
commit c6d4c1bdfc
4 changed files with 202 additions and 0 deletions

16
README.org Normal file
View File

@ -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 :)

39
src/6502/6502.h Normal file
View File

@ -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
};

14
src/6502/Makefile Normal file
View File

@ -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)

133
src/6502/main.c Normal file
View File

@ -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;
}