mirror of https://github.com/mlaux/gb6.git
Compare commits
8 Commits
b2a6890524
...
d69a3b35f1
Author | SHA1 | Date |
---|---|---|
Matthew Laux | d69a3b35f1 | |
Matthew Laux | f9f199dad2 | |
Matthew Laux | d22e2d9cba | |
Matthew Laux | aba7a9b847 | |
Matthew Laux | a3efa63361 | |
Matthew Laux | 5ed288eaa9 | |
Matthew Laux | bad415fa23 | |
Matthew Laux | ead7a3e17c |
|
@ -14,3 +14,4 @@ lib
|
||||||
imgui.ini
|
imgui.ini
|
||||||
.DS_Store
|
.DS_Store
|
||||||
roms
|
roms
|
||||||
|
examples/*.bin
|
||||||
|
|
|
@ -34,8 +34,8 @@ add_executable(gb6
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(gb6
|
target_link_libraries(gb6
|
||||||
"-framework OpenGL"
|
"-lGL"
|
||||||
"-framework CoreFoundation"
|
"-ldl"
|
||||||
"${SDL_LIBS}"
|
"${SDL_LIBS}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,15 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
for src_file in *.asm; do
|
||||||
|
[ -e "$src_file" ] || continue
|
||||||
|
|
||||||
|
|
||||||
|
obj_file="$(basename "$src_file" .asm).obj"
|
||||||
|
bin_file="$(basename "$src_file" .asm).bin"
|
||||||
|
echo "$src_file -> $bin_file"
|
||||||
|
|
||||||
|
rgbasm -o $obj_file $src_file
|
||||||
|
rgblink --nopad -o $bin_file $obj_file
|
||||||
|
done
|
||||||
|
|
||||||
|
rm -f *.obj
|
|
@ -0,0 +1,23 @@
|
||||||
|
section "main", rom0
|
||||||
|
|
||||||
|
nop
|
||||||
|
ld b, $0
|
||||||
|
ld c, $11
|
||||||
|
ld d, $22
|
||||||
|
ld e, $33
|
||||||
|
ld h, $44
|
||||||
|
ld l, $55
|
||||||
|
ld [hl], $66
|
||||||
|
ld a, $77
|
||||||
|
ld bc, $0123
|
||||||
|
ld de, $4567
|
||||||
|
ld hl, $89ab
|
||||||
|
ld sp, $cdef
|
||||||
|
simple_loop:
|
||||||
|
dec a
|
||||||
|
jr nz, simple_loop
|
||||||
|
|
||||||
|
end:
|
||||||
|
jr end
|
||||||
|
|
||||||
|
db $fd
|
|
@ -0,0 +1,156 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/mman.h> // mprotect
|
||||||
|
#include <unistd.h> // getpagesize
|
||||||
|
|
||||||
|
// A -> D0
|
||||||
|
// BC -> D1
|
||||||
|
// DE -> D2
|
||||||
|
// HL -> A0
|
||||||
|
// SP -> A7
|
||||||
|
|
||||||
|
uint8_t out_code[1024];
|
||||||
|
uint8_t memory[1024]; // ???
|
||||||
|
uint32_t out_ptr;
|
||||||
|
|
||||||
|
struct basic_block {
|
||||||
|
// in 68k space?
|
||||||
|
uint8_t code[256];
|
||||||
|
size_t length;
|
||||||
|
};
|
||||||
|
|
||||||
|
// need some kind of map from gb address to struct basic_block?
|
||||||
|
|
||||||
|
uint8_t test_code[] = {
|
||||||
|
0x00, // nop
|
||||||
|
0x06, 0x00, // ld b, $0
|
||||||
|
0x0e, 0x11, // ld c, $11
|
||||||
|
0x16, 0x22, // ld d, $22
|
||||||
|
0x1e, 0x33, // ld e, $33
|
||||||
|
0x26, 0x44, // ld h, $44
|
||||||
|
0x2e, 0x55, // ld l, $55
|
||||||
|
0x36, 0x66, // ld [hl], $66
|
||||||
|
0x3e, 0x77, // ld a, $77
|
||||||
|
0x01, 0x23, 0x01, // ld bc, $0123
|
||||||
|
0x11, 0x67, 0x45, // ld de, $4567
|
||||||
|
0x21, 0xab, 0x89, // ld hl, $89ab
|
||||||
|
0x31, 0xef, 0xcd, // ld sp, $cdef
|
||||||
|
0x3e, 0x0a, // .loop: ld a, 10
|
||||||
|
0x3d, // dec a
|
||||||
|
0x20, 0xfd, // jr nz, .loop
|
||||||
|
0x18, 0xfe, // jr $-1
|
||||||
|
0xc9 // ret
|
||||||
|
};
|
||||||
|
|
||||||
|
struct basic_block *compile_block(uint16_t src_address, uint8_t *gb_code)
|
||||||
|
{
|
||||||
|
uint8_t instruction;
|
||||||
|
struct basic_block *bblock;
|
||||||
|
uint32_t dst_ptr = 0;
|
||||||
|
uint16_t src_ptr = 0;
|
||||||
|
|
||||||
|
printf("compile block starting at 0x%04x\n", src_address);
|
||||||
|
|
||||||
|
bblock = malloc(sizeof *bblock);
|
||||||
|
// bblock->code = out_code + start;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
instruction = gb_code[src_ptr++];
|
||||||
|
if (instruction == 0xfd) {
|
||||||
|
// invalid opcode for testing
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bblock->length = 6;
|
||||||
|
bblock->code[0] = 0xb8; // mov eax, 1234h
|
||||||
|
bblock->code[1] = 0x34;
|
||||||
|
bblock->code[2] = 0x12;
|
||||||
|
bblock->code[3] = 0x00;
|
||||||
|
bblock->code[4] = 0x00;
|
||||||
|
bblock->code[5] = 0xc3; // ret
|
||||||
|
|
||||||
|
return bblock;
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_block(struct basic_block *bblock)
|
||||||
|
{
|
||||||
|
// calling convention? do i need to do this from asm?
|
||||||
|
uint16_t jump_target = ((uint16_t (*)()) bblock->code)();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
void block_cache_add(uint16_t src_address, struct basic_block *bblock)
|
||||||
|
{
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
struct basic_block *block_cache_get(uint16_t src_address)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. compile each block ending in a jump
|
||||||
|
// 2. turn the jump into a return
|
||||||
|
// 3. add the compiled code to some kind of cache
|
||||||
|
// 3. return back to check the cache and maybe compile the next block
|
||||||
|
|
||||||
|
void run_all(uint8_t *gb_code)
|
||||||
|
{
|
||||||
|
struct basic_block *bblock;
|
||||||
|
uint16_t jump_target = 0;
|
||||||
|
int page_size, ret;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
bblock = block_cache_get(jump_target);
|
||||||
|
if (!bblock) {
|
||||||
|
bblock = compile_block(jump_target, gb_code + jump_target);
|
||||||
|
if (bblock->length == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
block_cache_add(jump_target, bblock);
|
||||||
|
}
|
||||||
|
|
||||||
|
// for testing...
|
||||||
|
page_size = getpagesize();
|
||||||
|
ret = mprotect(
|
||||||
|
(void *) ((uint64_t) bblock & ~(page_size - 1)),
|
||||||
|
page_size,
|
||||||
|
PROT_READ | PROT_WRITE | PROT_EXEC
|
||||||
|
);
|
||||||
|
if (ret == -1) {
|
||||||
|
perror("mprotect");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
jump_target = ((uint16_t (*)()) bblock->code)();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
long len;
|
||||||
|
uint8_t *data;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
data = test_code;
|
||||||
|
} else {
|
||||||
|
fp = fopen(argv[1], "r");
|
||||||
|
fseek(fp, 0, SEEK_END);
|
||||||
|
len = ftell(fp);
|
||||||
|
rewind(fp);
|
||||||
|
data = malloc(len);
|
||||||
|
fread(data, 1, len, fp);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
run_all(data);
|
||||||
|
|
||||||
|
if (data != test_code) {
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
123
src/cpu.c
123
src/cpu.c
|
@ -73,13 +73,14 @@ static inline void write8(struct cpu *cpu, u16 address, u8 data)
|
||||||
|
|
||||||
static inline void write16(struct cpu *cpu, u16 address, u16 data)
|
static inline void write16(struct cpu *cpu, u16 address, u16 data)
|
||||||
{
|
{
|
||||||
dmg_write(cpu->dmg, address, data);
|
dmg_write(cpu->dmg, address, data & 0xff);
|
||||||
|
dmg_write(cpu->dmg, address + 1, data >> 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void inc_with_carry(struct cpu *regs, u8 *reg)
|
static void inc_with_carry(struct cpu *regs, u8 *reg)
|
||||||
{
|
{
|
||||||
clear_flag(regs, FLAG_SIGN);
|
clear_flag(regs, FLAG_SIGN);
|
||||||
if(*reg == 0xff || *reg == 0x0f)
|
if((*reg & 0xf) == 0xf)
|
||||||
set_flag(regs, FLAG_HALF_CARRY);
|
set_flag(regs, FLAG_HALF_CARRY);
|
||||||
else clear_flag(regs, FLAG_HALF_CARRY);
|
else clear_flag(regs, FLAG_HALF_CARRY);
|
||||||
(*reg)++;
|
(*reg)++;
|
||||||
|
@ -91,7 +92,7 @@ static void inc_with_carry(struct cpu *regs, u8 *reg)
|
||||||
static void dec_with_carry(struct cpu *regs, u8 *reg)
|
static void dec_with_carry(struct cpu *regs, u8 *reg)
|
||||||
{
|
{
|
||||||
set_flag(regs, FLAG_SIGN);
|
set_flag(regs, FLAG_SIGN);
|
||||||
if(*reg == 0x00 || *reg == 0x10)
|
if((*reg & 0xf) == 0)
|
||||||
set_flag(regs, FLAG_HALF_CARRY);
|
set_flag(regs, FLAG_HALF_CARRY);
|
||||||
else clear_flag(regs, FLAG_HALF_CARRY);
|
else clear_flag(regs, FLAG_HALF_CARRY);
|
||||||
(*reg)--;
|
(*reg)--;
|
||||||
|
@ -103,11 +104,20 @@ static void dec_with_carry(struct cpu *regs, u8 *reg)
|
||||||
static u8 rotate_left(struct cpu *regs, u8 reg)
|
static u8 rotate_left(struct cpu *regs, u8 reg)
|
||||||
{
|
{
|
||||||
int old_carry = flag_isset(regs, FLAG_CARRY);
|
int old_carry = flag_isset(regs, FLAG_CARRY);
|
||||||
// copy old leftmost bit to carry flag, clear Z, N, H
|
int result = (u8) ((reg & 0x7f) << 1) | old_carry;
|
||||||
regs->f = (reg & 0x80) >> 3;
|
|
||||||
// rotate
|
if (!result) {
|
||||||
int result = reg << 1 | old_carry;
|
set_flag(regs, FLAG_ZERO);
|
||||||
if (!result) set_flag(regs, FLAG_ZERO);
|
} else {
|
||||||
|
clear_flag(regs, FLAG_ZERO);
|
||||||
|
}
|
||||||
|
clear_flag(regs, FLAG_SIGN);
|
||||||
|
clear_flag(regs, FLAG_HALF_CARRY);
|
||||||
|
if (reg & 0x80) {
|
||||||
|
set_flag(regs, FLAG_CARRY);
|
||||||
|
} else {
|
||||||
|
clear_flag(regs, FLAG_CARRY);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,7 +164,7 @@ static u8 rrc(struct cpu *cpu, u8 val)
|
||||||
|
|
||||||
static u8 shift_left(struct cpu *cpu, u8 value)
|
static u8 shift_left(struct cpu *cpu, u8 value)
|
||||||
{
|
{
|
||||||
int result = value << 1;
|
u8 result = value << 1;
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
set_flag(cpu, FLAG_ZERO);
|
set_flag(cpu, FLAG_ZERO);
|
||||||
} else {
|
} else {
|
||||||
|
@ -172,7 +182,7 @@ static u8 shift_left(struct cpu *cpu, u8 value)
|
||||||
|
|
||||||
static u8 shift_right(struct cpu *cpu, u8 value)
|
static u8 shift_right(struct cpu *cpu, u8 value)
|
||||||
{
|
{
|
||||||
int result = (signed) value >> 1;
|
u8 result = (signed char) value >> 1;
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
set_flag(cpu, FLAG_ZERO);
|
set_flag(cpu, FLAG_ZERO);
|
||||||
} else {
|
} else {
|
||||||
|
@ -257,13 +267,9 @@ static void and(struct cpu *cpu, u8 value)
|
||||||
|
|
||||||
static void add(struct cpu *cpu, u8 value, int with_carry)
|
static void add(struct cpu *cpu, u8 value, int with_carry)
|
||||||
{
|
{
|
||||||
u8 sum_trunc;
|
|
||||||
int sum_full = cpu->a + value;
|
|
||||||
int carry = (with_carry && flag_isset(cpu, FLAG_CARRY)) ? 1 : 0;
|
int carry = (with_carry && flag_isset(cpu, FLAG_CARRY)) ? 1 : 0;
|
||||||
if (carry) {
|
int sum_full = cpu->a + value + carry;
|
||||||
sum_full++;
|
u8 sum_trunc = (u8) sum_full;
|
||||||
}
|
|
||||||
sum_trunc = (u8) sum_full;
|
|
||||||
if (sum_trunc == 0) {
|
if (sum_trunc == 0) {
|
||||||
set_flag(cpu, FLAG_ZERO);
|
set_flag(cpu, FLAG_ZERO);
|
||||||
} else {
|
} else {
|
||||||
|
@ -285,25 +291,21 @@ static void add(struct cpu *cpu, u8 value, int with_carry)
|
||||||
|
|
||||||
static void subtract(struct cpu *cpu, u8 value, int with_carry, int just_compare)
|
static void subtract(struct cpu *cpu, u8 value, int with_carry, int just_compare)
|
||||||
{
|
{
|
||||||
u8 sum_trunc;
|
|
||||||
int sum_full = cpu->a - value;
|
|
||||||
int carry = (with_carry && flag_isset(cpu, FLAG_CARRY)) ? 1 : 0;
|
int carry = (with_carry && flag_isset(cpu, FLAG_CARRY)) ? 1 : 0;
|
||||||
if (carry) {
|
int sum_full = cpu->a - value - carry;
|
||||||
sum_full--;
|
u8 sum_trunc = (u8) sum_full;
|
||||||
}
|
|
||||||
sum_trunc = (u8) sum_full;
|
|
||||||
if (!sum_trunc) {
|
if (!sum_trunc) {
|
||||||
set_flag(cpu, FLAG_ZERO);
|
set_flag(cpu, FLAG_ZERO);
|
||||||
} else {
|
} else {
|
||||||
clear_flag(cpu, FLAG_ZERO);
|
clear_flag(cpu, FLAG_ZERO);
|
||||||
}
|
}
|
||||||
set_flag(cpu, FLAG_SIGN);
|
set_flag(cpu, FLAG_SIGN);
|
||||||
if (value > cpu->a) {
|
if (sum_full < 0) {
|
||||||
set_flag(cpu, FLAG_CARRY);
|
set_flag(cpu, FLAG_CARRY);
|
||||||
} else {
|
} else {
|
||||||
clear_flag(cpu, FLAG_CARRY);
|
clear_flag(cpu, FLAG_CARRY);
|
||||||
}
|
}
|
||||||
if (((cpu->a & 0xf) - (value & 0xf)) & 0x10) {
|
if (((cpu->a & 0xf) - (value & 0xf) - carry) & 0x10) {
|
||||||
set_flag(cpu, FLAG_HALF_CARRY);
|
set_flag(cpu, FLAG_HALF_CARRY);
|
||||||
} else {
|
} else {
|
||||||
clear_flag(cpu, FLAG_HALF_CARRY);
|
clear_flag(cpu, FLAG_HALF_CARRY);
|
||||||
|
@ -336,21 +338,48 @@ static u16 pop(struct cpu *cpu)
|
||||||
|
|
||||||
static void add16(struct cpu *cpu, u16 src)
|
static void add16(struct cpu *cpu, u16 src)
|
||||||
{
|
{
|
||||||
clear_flag(cpu, FLAG_SIGN);
|
|
||||||
int total = read_hl(cpu) + src; // promoted to int
|
int total = read_hl(cpu) + src; // promoted to int
|
||||||
|
int trunc = total & 0xffff;
|
||||||
|
clear_flag(cpu, FLAG_SIGN);
|
||||||
if (total > 0xffff) {
|
if (total > 0xffff) {
|
||||||
set_flag(cpu, FLAG_CARRY);
|
set_flag(cpu, FLAG_CARRY);
|
||||||
} else {
|
} else {
|
||||||
clear_flag(cpu, FLAG_CARRY);
|
clear_flag(cpu, FLAG_CARRY);
|
||||||
}
|
}
|
||||||
if (((cpu->h & 0xf) + ((src >> 8) & 0xf)) & 0x10) {
|
if (((read_hl(cpu) & 0xfff) + (src & 0xfff)) & 0x1000) {
|
||||||
// true if carry from bit 11 to bit 12
|
// true if carry from bit 11 to bit 12
|
||||||
set_flag(cpu, FLAG_HALF_CARRY);
|
set_flag(cpu, FLAG_HALF_CARRY);
|
||||||
} else {
|
} else {
|
||||||
clear_flag(cpu, FLAG_HALF_CARRY);
|
clear_flag(cpu, FLAG_HALF_CARRY);
|
||||||
}
|
}
|
||||||
|
|
||||||
write_hl(cpu, total & 0xffff);
|
write_hl(cpu, trunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_sp(struct cpu *cpu, u8 value)
|
||||||
|
{
|
||||||
|
int total = cpu->sp + (signed char) value;
|
||||||
|
clear_flag(cpu, FLAG_ZERO);
|
||||||
|
clear_flag(cpu, FLAG_SIGN);
|
||||||
|
if (total > 0xffff) {
|
||||||
|
set_flag(cpu, FLAG_CARRY);
|
||||||
|
} else {
|
||||||
|
clear_flag(cpu, FLAG_CARRY);
|
||||||
|
}
|
||||||
|
cpu->sp = (u16) total;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ld_hl_sp(struct cpu *cpu, u8 value)
|
||||||
|
{
|
||||||
|
int total = cpu->sp + (signed char) value;
|
||||||
|
clear_flag(cpu, FLAG_ZERO);
|
||||||
|
clear_flag(cpu, FLAG_SIGN);
|
||||||
|
if (total > 0xffff) {
|
||||||
|
set_flag(cpu, FLAG_CARRY);
|
||||||
|
} else {
|
||||||
|
clear_flag(cpu, FLAG_CARRY);
|
||||||
|
}
|
||||||
|
write_hl(cpu, total);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8 read_reg(struct cpu *cpu, int index)
|
static u8 read_reg(struct cpu *cpu, int index)
|
||||||
|
@ -407,6 +436,8 @@ static void extended_insn(struct cpu *cpu, u8 insn)
|
||||||
srl,
|
srl,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// rl, sla, sra
|
||||||
|
|
||||||
#ifdef GB6_DEBUG
|
#ifdef GB6_DEBUG
|
||||||
printf(" %s\n", instructions[insn + 0x100].format);
|
printf(" %s\n", instructions[insn + 0x100].format);
|
||||||
#endif
|
#endif
|
||||||
|
@ -473,6 +504,24 @@ static void daa(struct cpu *cpu)
|
||||||
clear_flag(cpu, FLAG_HALF_CARRY);
|
clear_flag(cpu, FLAG_HALF_CARRY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void scf(struct cpu *cpu)
|
||||||
|
{
|
||||||
|
clear_flag(cpu, FLAG_SIGN);
|
||||||
|
clear_flag(cpu, FLAG_HALF_CARRY);
|
||||||
|
set_flag(cpu, FLAG_CARRY);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ccf(struct cpu *cpu)
|
||||||
|
{
|
||||||
|
clear_flag(cpu, FLAG_SIGN);
|
||||||
|
clear_flag(cpu, FLAG_HALF_CARRY);
|
||||||
|
if (flag_isset(cpu, FLAG_CARRY)) {
|
||||||
|
clear_flag(cpu, FLAG_CARRY);
|
||||||
|
} else {
|
||||||
|
set_flag(cpu, FLAG_CARRY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static u16 handlers[] = { 0x40, 0x48, 0x50, 0x58, 0x60 };
|
static u16 handlers[] = { 0x40, 0x48, 0x50, 0x58, 0x60 };
|
||||||
|
|
||||||
static u16 check_interrupts(struct cpu *cpu)
|
static u16 check_interrupts(struct cpu *cpu)
|
||||||
|
@ -508,10 +557,15 @@ void cpu_step(struct cpu *cpu)
|
||||||
intr_dest = check_interrupts(cpu);
|
intr_dest = check_interrupts(cpu);
|
||||||
if (intr_dest) {
|
if (intr_dest) {
|
||||||
push(cpu, cpu->pc);
|
push(cpu, cpu->pc);
|
||||||
|
cpu->halted = 0;
|
||||||
cpu->pc = intr_dest;
|
cpu->pc = intr_dest;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cpu->halted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
u8 opc = dmg_read(cpu->dmg, cpu->pc);
|
u8 opc = dmg_read(cpu->dmg, cpu->pc);
|
||||||
#ifdef GB6_DEBUG
|
#ifdef GB6_DEBUG
|
||||||
printf("0x%04x %s\n", cpu->pc, instructions[opc].format);
|
printf("0x%04x %s\n", cpu->pc, instructions[opc].format);
|
||||||
|
@ -531,6 +585,7 @@ void cpu_step(struct cpu *cpu)
|
||||||
break;
|
break;
|
||||||
case 0x0f: // RRCA
|
case 0x0f: // RRCA
|
||||||
cpu->a = rrc(cpu, cpu->a);
|
cpu->a = rrc(cpu, cpu->a);
|
||||||
|
clear_flag(cpu, FLAG_ZERO);
|
||||||
break;
|
break;
|
||||||
case 0x10: // STOP
|
case 0x10: // STOP
|
||||||
cpu->pc++;
|
cpu->pc++;
|
||||||
|
@ -541,6 +596,7 @@ void cpu_step(struct cpu *cpu)
|
||||||
break;
|
break;
|
||||||
case 0x07: // RLCA
|
case 0x07: // RLCA
|
||||||
cpu->a = rlc(cpu, cpu->a);
|
cpu->a = rlc(cpu, cpu->a);
|
||||||
|
clear_flag(cpu, FLAG_ZERO);
|
||||||
break;
|
break;
|
||||||
case 0x08: // LD (a16),SP
|
case 0x08: // LD (a16),SP
|
||||||
write16(cpu, read16(cpu, cpu->pc), cpu->sp);
|
write16(cpu, read16(cpu, cpu->pc), cpu->sp);
|
||||||
|
@ -554,16 +610,18 @@ void cpu_step(struct cpu *cpu)
|
||||||
break;
|
break;
|
||||||
case 0x17: // RLA
|
case 0x17: // RLA
|
||||||
cpu->a = rotate_left(cpu, cpu->a);
|
cpu->a = rotate_left(cpu, cpu->a);
|
||||||
|
clear_flag(cpu, FLAG_ZERO);
|
||||||
break;
|
break;
|
||||||
case 0x1f: // RRA
|
case 0x1f: // RRA
|
||||||
cpu->a = rotate_right(cpu, cpu->a);
|
cpu->a = rotate_right(cpu, cpu->a);
|
||||||
|
clear_flag(cpu, FLAG_ZERO);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x37: // SCF
|
case 0x37: // SCF
|
||||||
set_flag(cpu, FLAG_CARRY);
|
scf(cpu);
|
||||||
break;
|
break;
|
||||||
case 0x3f: // CCF
|
case 0x3f: // CCF
|
||||||
clear_flag(cpu, FLAG_CARRY);
|
ccf(cpu);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// incs and decs
|
// incs and decs
|
||||||
|
@ -944,6 +1002,7 @@ void cpu_step(struct cpu *cpu)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x76: // HALT
|
case 0x76: // HALT
|
||||||
|
//cpu->halted = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xc1: // POP BC
|
case 0xc1: // POP BC
|
||||||
|
@ -993,6 +1052,10 @@ void cpu_step(struct cpu *cpu)
|
||||||
case 0xe5: // PUSH HL
|
case 0xe5: // PUSH HL
|
||||||
push(cpu, read_hl(cpu));
|
push(cpu, read_hl(cpu));
|
||||||
break;
|
break;
|
||||||
|
case 0xe8:
|
||||||
|
add_sp(cpu, read8(cpu, cpu->pc));
|
||||||
|
cpu->pc++;
|
||||||
|
break;
|
||||||
case 0xe9: // JP HL
|
case 0xe9: // JP HL
|
||||||
cpu->pc = read_hl(cpu);
|
cpu->pc = read_hl(cpu);
|
||||||
break;
|
break;
|
||||||
|
@ -1018,7 +1081,7 @@ void cpu_step(struct cpu *cpu)
|
||||||
push(cpu, read_af(cpu));
|
push(cpu, read_af(cpu));
|
||||||
break;
|
break;
|
||||||
case 0xf8: // LD HL, SP+i8
|
case 0xf8: // LD HL, SP+i8
|
||||||
write_hl(cpu, cpu->sp + (signed) read8(cpu, cpu->pc));
|
ld_hl_sp(cpu, read8(cpu, cpu->pc));
|
||||||
cpu->pc++;
|
cpu->pc++;
|
||||||
break;
|
break;
|
||||||
case 0xf9: // LD SP, HL
|
case 0xf9: // LD SP, HL
|
||||||
|
|
|
@ -20,6 +20,8 @@ struct cpu
|
||||||
u32 cycle_count;
|
u32 cycle_count;
|
||||||
u8 interrupt_enable;
|
u8 interrupt_enable;
|
||||||
|
|
||||||
|
u8 halted;
|
||||||
|
|
||||||
struct dmg *dmg;
|
struct dmg *dmg;
|
||||||
// u8 (*mem_read)(void *, u16);
|
// u8 (*mem_read)(void *, u16);
|
||||||
// void (*mem_write)(void *, u16, u8);
|
// void (*mem_write)(void *, u16, u8);
|
||||||
|
|
33
src/dmg.c
33
src/dmg.c
|
@ -40,7 +40,7 @@ void dmg_set_button(struct dmg *dmg, int field, int button, int pressed)
|
||||||
|
|
||||||
static u8 get_button_state(struct dmg *dmg)
|
static u8 get_button_state(struct dmg *dmg)
|
||||||
{
|
{
|
||||||
u8 ret = 0;
|
u8 ret = 0xf0;
|
||||||
if (dmg->action_selected) {
|
if (dmg->action_selected) {
|
||||||
ret |= dmg->action_buttons;
|
ret |= dmg->action_buttons;
|
||||||
}
|
}
|
||||||
|
@ -50,8 +50,6 @@ static u8 get_button_state(struct dmg *dmg)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int counter;
|
|
||||||
|
|
||||||
u8 dmg_read(void *_dmg, u16 address)
|
u8 dmg_read(void *_dmg, u16 address)
|
||||||
{
|
{
|
||||||
struct dmg *dmg = (struct dmg *) _dmg;
|
struct dmg *dmg = (struct dmg *) _dmg;
|
||||||
|
@ -82,8 +80,13 @@ u8 dmg_read(void *_dmg, u16 address)
|
||||||
} else if (address == 0xff00) {
|
} else if (address == 0xff00) {
|
||||||
return get_button_state(dmg);
|
return get_button_state(dmg);
|
||||||
} else if (address == REG_TIMER_DIV) {
|
} else if (address == REG_TIMER_DIV) {
|
||||||
counter++;
|
return (dmg->timer_div & 0xff00) >> 8;
|
||||||
return counter;
|
} else if (address == REG_TIMER_COUNT) {
|
||||||
|
return dmg->timer_count;
|
||||||
|
} else if (address == REG_TIMER_MOD) {
|
||||||
|
return dmg->timer_mod;
|
||||||
|
} else if (address == REG_TIMER_CONTROL) {
|
||||||
|
return dmg->timer_control;
|
||||||
} else if (address == 0xff0f) {
|
} else if (address == 0xff0f) {
|
||||||
return dmg->interrupt_requested;
|
return dmg->interrupt_requested;
|
||||||
} else if (address == 0xffff) {
|
} else if (address == 0xffff) {
|
||||||
|
@ -116,6 +119,17 @@ void dmg_write(void *_dmg, u16 address, u8 data)
|
||||||
} else if (address < 0xe000) {
|
} else if (address < 0xe000) {
|
||||||
// printf("write ram %04x %02x\n", address, data);
|
// printf("write ram %04x %02x\n", address, data);
|
||||||
dmg->main_ram[address - 0xc000] = data;
|
dmg->main_ram[address - 0xc000] = data;
|
||||||
|
} else if (address == REG_TIMER_DIV) {
|
||||||
|
dmg->timer_div = 0;
|
||||||
|
} else if (address == REG_TIMER_COUNT) {
|
||||||
|
printf("write timer count\n");
|
||||||
|
dmg->timer_count = data;
|
||||||
|
} else if (address == REG_TIMER_MOD) {
|
||||||
|
printf("write timer mod\n");
|
||||||
|
dmg->timer_mod = data;
|
||||||
|
} else if (address == REG_TIMER_CONTROL) {
|
||||||
|
printf("write timer control\n");
|
||||||
|
dmg->timer_control = data;
|
||||||
} else if (address == 0xFF46) {
|
} else if (address == 0xFF46) {
|
||||||
u16 src = data << 8;
|
u16 src = data << 8;
|
||||||
int k = 0;
|
int k = 0;
|
||||||
|
@ -248,15 +262,14 @@ static void render_objs(struct dmg *dmg)
|
||||||
|
|
||||||
static void timer_step(struct dmg *dmg)
|
static void timer_step(struct dmg *dmg)
|
||||||
{
|
{
|
||||||
|
dmg->timer_div++;
|
||||||
|
return;
|
||||||
|
|
||||||
if (!(dmg_read(dmg, REG_TIMER_CONTROL) & TIMER_CONTROL_ENABLED)) {
|
if (!(dmg_read(dmg, REG_TIMER_CONTROL) & TIMER_CONTROL_ENABLED)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int passed = dmg->cpu->cycle_count - dmg->last_timer_update;
|
int passed = dmg->cpu->cycle_count - dmg->last_timer_update;
|
||||||
// TODO
|
|
||||||
if (passed < 10000) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
u8 counter = dmg_read(dmg, REG_TIMER_COUNT);
|
u8 counter = dmg_read(dmg, REG_TIMER_COUNT);
|
||||||
u8 modulo = dmg_read(dmg, REG_TIMER_MOD);
|
u8 modulo = dmg_read(dmg, REG_TIMER_MOD);
|
||||||
|
@ -278,7 +291,7 @@ void dmg_step(void *_dmg)
|
||||||
// order of dependencies? i think cpu needs to step first then update
|
// order of dependencies? i think cpu needs to step first then update
|
||||||
// all other hw
|
// all other hw
|
||||||
cpu_step(dmg->cpu);
|
cpu_step(dmg->cpu);
|
||||||
// timer_step(dmg);
|
timer_step(dmg);
|
||||||
|
|
||||||
// each line takes 456 cycles
|
// each line takes 456 cycles
|
||||||
int cycle_diff = dmg->cpu->cycle_count - dmg->last_lcd_update;
|
int cycle_diff = dmg->cpu->cycle_count - dmg->last_lcd_update;
|
||||||
|
|
|
@ -36,12 +36,16 @@ struct dmg {
|
||||||
u32 last_lcd_update;
|
u32 last_lcd_update;
|
||||||
u32 last_timer_update;
|
u32 last_timer_update;
|
||||||
int joypad_selected;
|
int joypad_selected;
|
||||||
int action_selected; // non-0 if A/B/start/select selected, 0 for directions
|
int action_selected;
|
||||||
u8 interrupt_enabled;
|
u8 interrupt_enabled;
|
||||||
u8 interrupt_requested;
|
u8 interrupt_requested;
|
||||||
|
|
||||||
u8 joypad;
|
u8 joypad;
|
||||||
u8 action_buttons;
|
u8 action_buttons;
|
||||||
|
u16 timer_div;
|
||||||
|
u8 timer_count;
|
||||||
|
u8 timer_mod;
|
||||||
|
u8 timer_control;
|
||||||
};
|
};
|
||||||
|
|
||||||
void dmg_new(struct dmg *dmg, struct cpu *cpu, struct rom *rom, struct lcd *lcd);
|
void dmg_new(struct dmg *dmg, struct cpu *cpu, struct rom *rom, struct lcd *lcd);
|
||||||
|
|
Loading…
Reference in New Issue