working on mooneye test suite
This commit is contained in:
@ -7,6 +7,8 @@ typedef struct {
|
|||||||
u8 tima;
|
u8 tima;
|
||||||
u8 tma;
|
u8 tma;
|
||||||
u8 tac;
|
u8 tac;
|
||||||
|
bool tima_needs_reset;
|
||||||
|
bool tima_just_reset;
|
||||||
} timer_context;
|
} timer_context;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -18,7 +18,7 @@ FILE *log;
|
|||||||
void cpu_init() {
|
void cpu_init() {
|
||||||
ctx.regs.a = 0x01;
|
ctx.regs.a = 0x01;
|
||||||
ctx.regs.f = 0xB0;
|
ctx.regs.f = 0xB0;
|
||||||
ctx.regs.b = 0x00;
|
ctx.regs.b = 0x19;
|
||||||
ctx.regs.c = 0x13;
|
ctx.regs.c = 0x13;
|
||||||
ctx.regs.d = 0x00;
|
ctx.regs.d = 0x00;
|
||||||
ctx.regs.e = 0xD8;
|
ctx.regs.e = 0xD8;
|
||||||
@ -55,6 +55,10 @@ static void execute() {
|
|||||||
|
|
||||||
bool cpu_step() {
|
bool cpu_step() {
|
||||||
|
|
||||||
|
if(ctx.regs.pc == 0x4348) {
|
||||||
|
printf("made it!\n");
|
||||||
|
}
|
||||||
|
|
||||||
if(!ctx.halted) {
|
if(!ctx.halted) {
|
||||||
u16 pc = ctx.regs.pc;
|
u16 pc = ctx.regs.pc;
|
||||||
fetch_instruction();
|
fetch_instruction();
|
||||||
|
@ -74,7 +74,9 @@ void fetch_data() {
|
|||||||
cpu_set_reg(RT_HL, cpu_read_reg(RT_HL)-1);
|
cpu_set_reg(RT_HL, cpu_read_reg(RT_HL)-1);
|
||||||
return;
|
return;
|
||||||
case AM_R_A8:
|
case AM_R_A8:
|
||||||
ctx.fetched_data = bus_read(ctx.regs.pc);
|
u16 addr = bus_read(ctx.regs.pc) | 0xFF00;
|
||||||
|
emu_cycles(1);
|
||||||
|
ctx.fetched_data = bus_read(addr);
|
||||||
emu_cycles(1);
|
emu_cycles(1);
|
||||||
ctx.regs.pc++;
|
ctx.regs.pc++;
|
||||||
return;
|
return;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include <emu.h>
|
#include <emu.h>
|
||||||
#include <bus.h>
|
#include <bus.h>
|
||||||
#include <stack.h>
|
#include <stack.h>
|
||||||
|
#include <timer.h>
|
||||||
|
|
||||||
|
|
||||||
reg_type decode_reg(u8 reg);
|
reg_type decode_reg(u8 reg);
|
||||||
@ -51,7 +52,7 @@ static void proc_daa(cpu_context *ctx) {
|
|||||||
|
|
||||||
ctx->regs.a += CPU_FLAG_N ? -u : u;
|
ctx->regs.a += CPU_FLAG_N ? -u : u;
|
||||||
|
|
||||||
cpu_set_flags(ctx, ctx->regs.a == 0, -1, 0, fc);
|
cpu_set_flags(ctx, ctx->regs.a == 0, CPU_FLAG_N, 0, fc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void proc_cpl(cpu_context *ctx) {
|
static void proc_cpl(cpu_context *ctx) {
|
||||||
@ -72,6 +73,7 @@ static void proc_halt(cpu_context *ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void proc_stop(cpu_context *ctx) {
|
static void proc_stop(cpu_context *ctx) {
|
||||||
|
timer_get_context()->div = 0;
|
||||||
printf("CPU STOP!\n");
|
printf("CPU STOP!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,10 +305,6 @@ static void proc_add(cpu_context *ctx) {
|
|||||||
|
|
||||||
bool is_16bit = is_16_bit(ctx->cur_inst->reg_1);
|
bool is_16bit = is_16_bit(ctx->cur_inst->reg_1);
|
||||||
|
|
||||||
if(is_16bit) {
|
|
||||||
emu_cycles(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ctx->cur_inst->reg_1 == RT_SP) {
|
if(ctx->cur_inst->reg_1 == RT_SP) {
|
||||||
val = cpu_read_reg(ctx->cur_inst->reg_1) + (char)ctx->fetched_data;
|
val = cpu_read_reg(ctx->cur_inst->reg_1) + (char)ctx->fetched_data;
|
||||||
}
|
}
|
||||||
@ -329,6 +327,12 @@ static void proc_add(cpu_context *ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cpu_set_reg(ctx->cur_inst->reg_1, val & 0xFFFF);
|
cpu_set_reg(ctx->cur_inst->reg_1, val & 0xFFFF);
|
||||||
|
if(is_16bit) {
|
||||||
|
emu_cycles(1);
|
||||||
|
}
|
||||||
|
if(ctx->cur_inst->reg_1 == RT_SP) {
|
||||||
|
emu_cycles(1);
|
||||||
|
}
|
||||||
cpu_set_flags(ctx, z, 0, h, c);
|
cpu_set_flags(ctx, z, 0, h, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,10 +362,6 @@ static void proc_inc(cpu_context *ctx) {
|
|||||||
static void proc_dec(cpu_context *ctx) {
|
static void proc_dec(cpu_context *ctx) {
|
||||||
u16 val = cpu_read_reg(ctx->cur_inst->reg_1) - 1;
|
u16 val = cpu_read_reg(ctx->cur_inst->reg_1) - 1;
|
||||||
|
|
||||||
if(is_16_bit(ctx->cur_inst->reg_1)) {
|
|
||||||
//emu_cycles(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctx->cur_inst->reg_1 == RT_HL && ctx->dest_is_mem) {
|
if (ctx->cur_inst->reg_1 == RT_HL && ctx->dest_is_mem) {
|
||||||
val = ctx->fetched_data - 1;
|
val = ctx->fetched_data - 1;
|
||||||
val &= 0xFF;
|
val &= 0xFF;
|
||||||
@ -371,6 +371,10 @@ static void proc_dec(cpu_context *ctx) {
|
|||||||
val = cpu_read_reg(ctx->cur_inst->reg_1);
|
val = cpu_read_reg(ctx->cur_inst->reg_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(is_16_bit(ctx->cur_inst->reg_1)) {
|
||||||
|
emu_cycles(1);
|
||||||
|
}
|
||||||
|
|
||||||
if((ctx->cur_opcode & 0x0B) == 0x0B) {
|
if((ctx->cur_opcode & 0x0B) == 0x0B) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -394,21 +398,20 @@ static void proc_pop(cpu_context *ctx) {
|
|||||||
|
|
||||||
static void proc_push(cpu_context *ctx) {
|
static void proc_push(cpu_context *ctx) {
|
||||||
u16 val = cpu_read_reg(ctx->cur_inst->reg_1);
|
u16 val = cpu_read_reg(ctx->cur_inst->reg_1);
|
||||||
|
emu_cycles(1);
|
||||||
stack_push((val >> 8) & 0xFF);
|
stack_push((val >> 8) & 0xFF);
|
||||||
emu_cycles(1);
|
emu_cycles(1);
|
||||||
stack_push((val & 0xFF));
|
stack_push((val & 0xFF));
|
||||||
emu_cycles(1);
|
emu_cycles(1);
|
||||||
|
|
||||||
emu_cycles(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void proc_ldh(cpu_context *ctx) {
|
static void proc_ldh(cpu_context *ctx) {
|
||||||
if (!ctx->dest_is_mem) {
|
if (!ctx->dest_is_mem) {
|
||||||
cpu_set_reg(ctx->cur_inst->reg_1, bus_read(0XFF00 | ctx->fetched_data));
|
cpu_set_reg(ctx->cur_inst->reg_1, ctx->fetched_data);
|
||||||
} else {
|
} else {
|
||||||
bus_write(0xFF00 | ctx->mem_dest, cpu_read_reg(ctx->cur_inst->reg_2));
|
bus_write(0xFF00 | ctx->mem_dest, cpu_read_reg(ctx->cur_inst->reg_2));
|
||||||
}
|
|
||||||
emu_cycles(1);
|
emu_cycles(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void proc_di(cpu_context *ctx) {
|
static void proc_di(cpu_context *ctx) {
|
||||||
@ -458,12 +461,12 @@ static bool check_condition(cpu_context *ctx) {
|
|||||||
|
|
||||||
static void goto_addr(cpu_context *ctx, u16 addr, bool pushpc){
|
static void goto_addr(cpu_context *ctx, u16 addr, bool pushpc){
|
||||||
if (check_condition(ctx)) {
|
if (check_condition(ctx)) {
|
||||||
|
emu_cycles(1);
|
||||||
if(pushpc) {
|
if(pushpc) {
|
||||||
stack_push16(ctx->regs.pc);
|
stack_push16(ctx->regs.pc);
|
||||||
emu_cycles(2);
|
emu_cycles(2);
|
||||||
}
|
}
|
||||||
ctx->regs.pc = addr;
|
ctx->regs.pc = addr;
|
||||||
emu_cycles(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ void int_handle(cpu_context *ctx, u16 address) {
|
|||||||
stack_push16(ctx->regs.pc);
|
stack_push16(ctx->regs.pc);
|
||||||
emu_cycles(2);
|
emu_cycles(2);
|
||||||
ctx->regs.pc = address;
|
ctx->regs.pc = address;
|
||||||
emu_cycles(1);
|
//emu_cycles(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool int_check(cpu_context *ctx, u16 address, interrupt_type t){
|
bool int_check(cpu_context *ctx, u16 address, interrupt_type t){
|
||||||
@ -25,14 +25,14 @@ void cpu_request_interrupt(interrupt_type t);
|
|||||||
|
|
||||||
void cpu_handle_interrupts(cpu_context *ctx) {
|
void cpu_handle_interrupts(cpu_context *ctx) {
|
||||||
if (int_check(ctx, 0x40, IT_VBLANK)) {
|
if (int_check(ctx, 0x40, IT_VBLANK)) {
|
||||||
|
//printf("VBLANK!\n");
|
||||||
} else if(int_check(ctx, 0x48, IT_LCD_STAT)){
|
} else if(int_check(ctx, 0x48, IT_LCD_STAT)){
|
||||||
|
//printf("LCD!\n");
|
||||||
} else if(int_check(ctx, 0x50, IT_TIMER)){
|
} else if(int_check(ctx, 0x50, IT_TIMER)){
|
||||||
|
//printf("TIMER!\n");
|
||||||
} else if(int_check(ctx, 0x58, IT_SERIAL)){
|
} else if(int_check(ctx, 0x58, IT_SERIAL)){
|
||||||
|
//printf("Serial!\n");
|
||||||
} else if(int_check(ctx, 0x60, IT_JOYPAD)){
|
} else if(int_check(ctx, 0x60, IT_JOYPAD)){
|
||||||
|
//printf("Joy!\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
2
lib/io.c
2
lib/io.c
@ -37,7 +37,7 @@ u8 io_read(u16 address){
|
|||||||
}
|
}
|
||||||
|
|
||||||
printf("UNSUPPORTED io_read(%04X)\n", address);
|
printf("UNSUPPORTED io_read(%04X)\n", address);
|
||||||
return 0;
|
return 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
74
lib/timer.c
74
lib/timer.c
@ -5,40 +5,58 @@
|
|||||||
|
|
||||||
static timer_context ctx = {0};
|
static timer_context ctx = {0};
|
||||||
|
|
||||||
|
bool selected_bit() {
|
||||||
|
switch(ctx.tac & 0b11) {
|
||||||
|
case 0b00:
|
||||||
|
return (ctx.div & (1 << 9));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0b01:
|
||||||
|
return (ctx.div & (1 << 3));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0b10:
|
||||||
|
return (ctx.div & (1 << 5));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0b11:
|
||||||
|
return (ctx.div & (1 << 7));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void inc_tima() {
|
||||||
|
ctx.tima++;
|
||||||
|
if(ctx.tima == 0x00){
|
||||||
|
ctx.tima_needs_reset = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void timer_init() {
|
void timer_init() {
|
||||||
ctx.div = 0XAC00;
|
ctx.div = 0XAC00;
|
||||||
}
|
}
|
||||||
|
|
||||||
void timer_tick() {
|
void timer_tick() {
|
||||||
u16 prev_div = ctx.div;
|
u16 prev_div = ctx.div;
|
||||||
|
bool old = selected_bit();
|
||||||
ctx.div++;
|
ctx.div++;
|
||||||
bool timer_update = false;
|
bool new = selected_bit();
|
||||||
switch(ctx.tac & 0b11) {
|
|
||||||
case 0b00:
|
|
||||||
timer_update = (prev_div & (1 << 9)) && (!(ctx.div & (1 << 9)));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0b01:
|
if((prev_div & (1 << 1)) && (!(ctx.div & (1 << 1)))){
|
||||||
timer_update = (prev_div & (1 << 3)) && (!(ctx.div & (1 << 3)));
|
if(ctx.tima_just_reset)
|
||||||
break;
|
ctx.tima_just_reset = false;
|
||||||
|
if(ctx.tima_needs_reset){
|
||||||
case 0b10:
|
|
||||||
timer_update = (prev_div & (1 << 5)) && (!(ctx.div & (1 << 5)));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0b11:
|
|
||||||
timer_update = (prev_div & (1 << 7)) && (!(ctx.div & (1 << 7)));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(timer_update && ctx.tac & (1 << 2)) {
|
|
||||||
ctx.tima++;
|
|
||||||
if(ctx.tima == 0xFF){
|
|
||||||
ctx.tima = ctx.tma;
|
ctx.tima = ctx.tma;
|
||||||
|
ctx.tima_needs_reset = false;
|
||||||
|
ctx.tima_just_reset = true;
|
||||||
cpu_request_interrupt(IT_TIMER);
|
cpu_request_interrupt(IT_TIMER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(ctx.tac & 0b100 && old && !new) {
|
||||||
|
inc_tima();
|
||||||
|
}
|
||||||
|
|
||||||
audio_sample_tick();
|
audio_sample_tick();
|
||||||
|
|
||||||
if((prev_div & (1 << 12)) && (!(ctx.div & (1 << 12)))){
|
if((prev_div & (1 << 12)) && (!(ctx.div & (1 << 12)))){
|
||||||
@ -54,22 +72,36 @@ void timer_write(u16 address, u8 value){
|
|||||||
switch(address) {
|
switch(address) {
|
||||||
case 0xFF04:
|
case 0xFF04:
|
||||||
//DIV
|
//DIV
|
||||||
|
if(selected_bit()) {
|
||||||
|
inc_tima();
|
||||||
|
}
|
||||||
ctx.div = 0;
|
ctx.div = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xFF05:
|
case 0xFF05:
|
||||||
//TIMA
|
//TIMA
|
||||||
|
if(ctx.tima_just_reset)
|
||||||
|
return;
|
||||||
|
ctx.tima_needs_reset = false;
|
||||||
ctx.tima = value;
|
ctx.tima = value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xFF06:
|
case 0xFF06:
|
||||||
//TMA
|
//TMA
|
||||||
|
if(ctx.tima_just_reset)
|
||||||
|
ctx.tima = value;
|
||||||
ctx.tma = value;
|
ctx.tma = value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xFF07:
|
case 0xFF07:
|
||||||
//TAC
|
//TAC
|
||||||
|
bool current = selected_bit();
|
||||||
|
bool old_enable = ctx.tac & 0b100;
|
||||||
ctx.tac = value;
|
ctx.tac = value;
|
||||||
|
bool new = selected_bit();
|
||||||
|
if(((current && !new) && (ctx.tac & 0b100)) || (current && old_enable && !(ctx.tac & 0b100))) {
|
||||||
|
inc_tima();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user