mirror of
https://github.com/mlaux/gb6.git
synced 2024-09-28 01:54:29 +00:00
Compare commits
No commits in common. "0351226479501244a554d4d994e8070b777f7680" and "8d87ee1f2640bb0083fff131717d71d6cc467929" have entirely different histories.
0351226479
...
8d87ee1f26
21
LICENSE
21
LICENSE
@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Matthew Laux
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
@ -54,8 +54,8 @@ GLuint make_output_texture() {
|
||||
glGenTextures(1, &image_texture);
|
||||
glBindTexture(GL_TEXTURE_2D, image_texture);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
return image_texture;
|
||||
}
|
||||
@ -66,8 +66,7 @@ void convert_output(struct lcd *lcd) {
|
||||
for (y = 0; y < 256; y++) {
|
||||
for (x = 0; x < 256; x++) {
|
||||
int val = lcd->buf[y * 256 + x];
|
||||
int fill = 255 - val * 85;
|
||||
//int fill = val ? 255 : 0;
|
||||
int fill = val ? 255 : 0;
|
||||
output_image[out_index++] = fill;
|
||||
output_image[out_index++] = fill;
|
||||
output_image[out_index++] = fill;
|
||||
|
17
src/cpu.c
17
src/cpu.c
@ -174,16 +174,7 @@ static u8 shift_right(struct cpu *cpu, u8 value)
|
||||
|
||||
static u8 swap(struct cpu *cpu, u8 value)
|
||||
{
|
||||
u8 ret = ((value & 0xf0) >> 4) | ((value & 0x0f) << 4);
|
||||
if(ret == 0) {
|
||||
set_flag(cpu, FLAG_ZERO);
|
||||
} else {
|
||||
clear_flag(cpu, FLAG_ZERO);
|
||||
}
|
||||
clear_flag(cpu, FLAG_SIGN);
|
||||
clear_flag(cpu, FLAG_HALF_CARRY);
|
||||
clear_flag(cpu, FLAG_CARRY);
|
||||
return ret;
|
||||
return ((value & 0xf0) >> 4) | ((value & 0x0f) << 4);
|
||||
}
|
||||
|
||||
static void xor(struct cpu *regs, u8 value)
|
||||
@ -643,8 +634,6 @@ void cpu_step(struct cpu *cpu)
|
||||
break;
|
||||
case 0x2f: // CPL
|
||||
cpu->a = ~cpu->a;
|
||||
set_flag(cpu, FLAG_SIGN);
|
||||
set_flag(cpu, FLAG_HALF_CARRY);
|
||||
break;
|
||||
case 0x31: // LD SP,d16
|
||||
cpu->sp = read16(cpu, cpu->pc);
|
||||
@ -767,10 +756,6 @@ void cpu_step(struct cpu *cpu)
|
||||
case 0xb5: or(cpu, cpu->l); break;
|
||||
case 0xb6: or(cpu, read8(cpu, read_hl(cpu))); break;
|
||||
case 0xb7: or(cpu, cpu->a); break;
|
||||
case 0xf6:
|
||||
or(cpu, read8(cpu, cpu->pc));
|
||||
cpu->pc++;
|
||||
break;
|
||||
|
||||
// CP
|
||||
case 0xb8: subtract(cpu, cpu->b, 0, 1); break;
|
||||
|
40
src/dmg.c
40
src/dmg.c
@ -39,18 +39,9 @@ void dmg_set_button(struct dmg *dmg, int field, int button, int pressed)
|
||||
|
||||
static u8 get_button_state(struct dmg *dmg)
|
||||
{
|
||||
u8 ret = 0;
|
||||
if (dmg->action_selected) {
|
||||
ret |= dmg->action_buttons;
|
||||
}
|
||||
if (dmg->joypad_selected) {
|
||||
ret |= dmg->joypad;
|
||||
}
|
||||
return ret;
|
||||
return dmg->action_selected ? dmg->action_buttons : dmg->joypad;
|
||||
}
|
||||
|
||||
static int counter;
|
||||
|
||||
u8 dmg_read(void *_dmg, u16 address)
|
||||
{
|
||||
struct dmg *dmg = (struct dmg *) _dmg;
|
||||
@ -75,9 +66,6 @@ u8 dmg_read(void *_dmg, u16 address)
|
||||
return dmg->zero_page[address - 0xff80];
|
||||
} else if (address == 0xff00) {
|
||||
return get_button_state(dmg);
|
||||
} else if (address == 0xff04) {
|
||||
counter++;
|
||||
return counter;
|
||||
} else if (address == 0xff0f) {
|
||||
return dmg->interrupt_requested;
|
||||
} else if (address == 0xffff) {
|
||||
@ -105,21 +93,12 @@ void dmg_write(void *_dmg, u16 address, u8 data)
|
||||
} else if (address < 0xc000) {
|
||||
// TODO switchable ram bank
|
||||
} else if (address < 0xe000) {
|
||||
// printf("write ram %04x %02x\n", address, data);
|
||||
dmg->main_ram[address - 0xc000] = data;
|
||||
} else if (address == 0xFF46) {
|
||||
u16 src = data << 8;
|
||||
int k = 0;
|
||||
// printf("oam dma %04x\n", src);
|
||||
for (u16 addr = src; addr < src + 0xa0; addr++) {
|
||||
dmg->lcd->oam[k++] = dmg_read(dmg, addr);
|
||||
}
|
||||
} else if (lcd_is_valid_addr(address)) {
|
||||
lcd_write(dmg->lcd, address, data);
|
||||
} else if (address >= 0xff80 && address <= 0xfffe) {
|
||||
dmg->zero_page[address - 0xff80] = data;
|
||||
} else if (address == 0xff00) {
|
||||
dmg->joypad_selected = data & (1 << 4);
|
||||
dmg->action_selected = data & (1 << 5);
|
||||
} else if (address == 0xff0f) {
|
||||
dmg->interrupt_requested = data;
|
||||
@ -147,19 +126,9 @@ void dmg_step(void *_dmg)
|
||||
if (dmg->cpu->cycle_count - dmg->last_lcd_update >= 456) {
|
||||
dmg->last_lcd_update = dmg->cpu->cycle_count;
|
||||
int next_scanline = lcd_step(dmg->lcd);
|
||||
|
||||
// update LYC
|
||||
if (next_scanline == lcd_read(dmg->lcd, REG_LYC)) {
|
||||
lcd_set_bit(dmg->lcd, REG_STAT, STAT_FLAG_MATCH);
|
||||
dmg_request_interrupt(dmg, INT_LCDSTAT);
|
||||
} else {
|
||||
lcd_clear_bit(dmg->lcd, REG_STAT, STAT_FLAG_MATCH);
|
||||
}
|
||||
|
||||
if (next_scanline == 144) {
|
||||
// vblank has started, draw all the stuff from ram into the lcd
|
||||
dmg_request_interrupt(dmg, INT_VBLANK);
|
||||
dmg_request_interrupt(dmg, INT_SERIAL);
|
||||
|
||||
int lcdc = lcd_read(dmg->lcd, REG_LCDC);
|
||||
int bg_base = (lcdc & LCDC_BG_TILE_MAP) ? 0x9c00 : 0x9800;
|
||||
@ -167,7 +136,7 @@ void dmg_step(void *_dmg)
|
||||
int use_unsigned = lcdc & LCDC_BG_TILE_DATA;
|
||||
int tilebase = use_unsigned ? 0x8000 : 0x9000;
|
||||
|
||||
//printf("%04x %04x %04x\n", bg_base, window_base, tilebase);
|
||||
printf("%04x %04x %04x\n", bg_base, window_base, tilebase);
|
||||
|
||||
int k = 0, off = 0;
|
||||
int tile_y = 0, tile_x = 0;
|
||||
@ -186,8 +155,9 @@ void dmg_step(void *_dmg)
|
||||
int data1 = dmg_read(dmg, eff_addr + b);
|
||||
int data2 = dmg_read(dmg, eff_addr + b + 1);
|
||||
for (i = 7; i >= 0; i--) {
|
||||
dmg->lcd->buf[off] = ((data1 & (1 << i)) ? 1 : 0);// << 1;
|
||||
//dmg->lcd->buf[off] |= (data1 & (1 << i)) ? 1 : 0;
|
||||
// monochrome for now
|
||||
dmg->lcd->buf[off] = (data1 & (1 << i)) ? 1 : 0;
|
||||
//dmg->lcd->buf[off] |= (data2 & (1 << i)) ? 1 : 0;
|
||||
off++;
|
||||
}
|
||||
off += 248;
|
||||
|
@ -25,7 +25,6 @@ struct dmg {
|
||||
u8 video_ram[0x2000];
|
||||
u8 zero_page[0x80];
|
||||
u32 last_lcd_update;
|
||||
int joypad_selected;
|
||||
int action_selected; // non-0 if A/B/start/select selected, 0 for directions
|
||||
u8 interrupt_enabled;
|
||||
u8 interrupt_requested;
|
||||
|
15
src/lcd.c
15
src/lcd.c
@ -5,12 +5,12 @@
|
||||
#include "types.h"
|
||||
#include "lcd.h"
|
||||
|
||||
void lcd_set_bit(struct lcd *lcd, u16 addr, u8 bit)
|
||||
static void set_bit(struct lcd *lcd, u16 addr, u8 bit)
|
||||
{
|
||||
lcd_write(lcd, addr, lcd_read(lcd, addr) | (1 << bit));
|
||||
}
|
||||
|
||||
void lcd_clear_bit(struct lcd *lcd, u16 addr, u8 bit)
|
||||
static void clear_bit(struct lcd *lcd, u16 addr, u8 bit)
|
||||
{
|
||||
lcd_write(lcd, addr, lcd_read(lcd, addr) & ~(1 << bit));
|
||||
}
|
||||
@ -18,7 +18,6 @@ void lcd_clear_bit(struct lcd *lcd, u16 addr, u8 bit)
|
||||
void lcd_new(struct lcd *lcd)
|
||||
{
|
||||
lcd->buf = malloc(256 * 256);
|
||||
memset(lcd->buf, 0, 256 * 256);
|
||||
// todo < 8 bpp
|
||||
lcd->pixels = malloc(LCD_WIDTH * LCD_HEIGHT);
|
||||
}
|
||||
@ -42,6 +41,9 @@ void lcd_write(struct lcd *lcd, u16 addr, u8 value)
|
||||
lcd->oam[addr - 0xfe00] = value;
|
||||
} else {
|
||||
lcd->regs[addr - REG_LCD_BASE] = value;
|
||||
if (addr == 0xFF46) {
|
||||
// OAM DMA
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,6 +64,13 @@ void lcd_copy(struct lcd *lcd)
|
||||
|
||||
int lcd_step(struct lcd *lcd)
|
||||
{
|
||||
// update LYC
|
||||
if (lcd_read(lcd, REG_LY) == lcd_read(lcd, REG_LYC)) {
|
||||
set_bit(lcd, REG_STAT, STAT_FLAG_MATCH);
|
||||
} else {
|
||||
clear_bit(lcd, REG_STAT, STAT_FLAG_MATCH);
|
||||
}
|
||||
|
||||
// step to next scanline 0-153
|
||||
u8 next_scanline = (lcd_read(lcd, REG_LY) + 1) % 154;
|
||||
lcd_write(lcd, REG_LY, next_scanline);
|
||||
|
@ -48,9 +48,6 @@ void lcd_write(struct lcd *lcd, u16 addr, u8 value);
|
||||
|
||||
void lcd_put_pixel(struct lcd *lcd, u8 x, u8 y, u8 value);
|
||||
|
||||
void lcd_set_bit(struct lcd *lcd, u16 addr, u8 bit);
|
||||
void lcd_clear_bit(struct lcd *lcd, u16 addr, u8 bit);
|
||||
|
||||
// i feel like i'm going to need to call this every cycle and update regs
|
||||
int lcd_step(struct lcd *lcd);
|
||||
void lcd_copy(struct lcd *lcd);
|
||||
|
@ -19,7 +19,6 @@ int rom_load(struct rom *rom, const char *filename)
|
||||
|
||||
rom->type = 0; // TODO read type from cart
|
||||
rom->data = malloc(len);
|
||||
rom->length = len;
|
||||
if (fread(rom->data, 1, len, fp) < len) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -4,11 +4,11 @@
|
||||
#include "types.h"
|
||||
|
||||
struct rom {
|
||||
u32 length;
|
||||
int type;
|
||||
u8 *data;
|
||||
};
|
||||
|
||||
|
||||
int rom_load(struct rom *rom, const char *filename);
|
||||
|
||||
void rom_free(struct rom *rom);
|
||||
|
@ -3,8 +3,6 @@ cmake_minimum_required(VERSION 3.9)
|
||||
|
||||
include_directories(../src)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "-O3")
|
||||
|
||||
add_application(Emulator
|
||||
../src/bootstrap.c
|
||||
../src/cpu.c
|
||||
|
@ -1,4 +1,7 @@
|
||||
/* Game Boy emulator for 68k Macs
|
||||
Compiled with Symantec THINK C 5.0
|
||||
(c) 2013 Matt Laux
|
||||
|
||||
emulator.c - entry point */
|
||||
|
||||
#include <stdio.h>
|
||||
@ -14,24 +17,14 @@
|
||||
|
||||
#include "emulator.h"
|
||||
|
||||
#include "dmg.h"
|
||||
#include "cpu.h"
|
||||
#include "rom.h"
|
||||
#include "lcd.h"
|
||||
|
||||
WindowPtr g_wp;
|
||||
DialogPtr stateDialog;
|
||||
unsigned char g_running;
|
||||
unsigned char emulationOn;
|
||||
|
||||
static Point windowPt = { WINDOW_Y, WINDOW_X };
|
||||
|
||||
static Rect windowBounds = { WINDOW_Y, WINDOW_X, WINDOW_Y + WINDOW_HEIGHT, WINDOW_X + WINDOW_WIDTH };
|
||||
|
||||
struct cpu cpu;
|
||||
struct rom rom;
|
||||
struct lcd lcd;
|
||||
struct dmg dmg;
|
||||
emu_state theState;
|
||||
|
||||
void InitEverything(void)
|
||||
{
|
||||
@ -52,35 +45,10 @@ void InitEverything(void)
|
||||
g_running = 1;
|
||||
}
|
||||
|
||||
char offscreen[32 * 256];
|
||||
Rect offscreenRect = { 0, 0, 256, 256 };
|
||||
|
||||
BitMap offscreenBmp;
|
||||
|
||||
int lastTicks;
|
||||
|
||||
void Render(void)
|
||||
{
|
||||
long k = 0, dst;
|
||||
for (dst = 0; dst < 32 * 256; dst++) {
|
||||
offscreen[dst] = lcd.buf[k++] << 7
|
||||
| lcd.buf[k++] << 6
|
||||
| lcd.buf[k++] << 5
|
||||
| lcd.buf[k++] << 4
|
||||
| lcd.buf[k++] << 3
|
||||
| lcd.buf[k++] << 2
|
||||
| lcd.buf[k++] << 1
|
||||
| lcd.buf[k++];
|
||||
}
|
||||
SetPort(g_wp);
|
||||
CopyBits(&offscreenBmp, &g_wp->portBits, &offscreenRect, &g_wp->portRect, srcCopy, NULL);
|
||||
|
||||
//EraseRect(&g_wp->portRect);
|
||||
MoveTo(10, 160);
|
||||
char debug[128];
|
||||
sprintf(debug, "PC: %04x", cpu.pc);
|
||||
C2PStr(debug);
|
||||
DrawString(debug);
|
||||
MoveTo(10, 10);
|
||||
DrawString("\pTest 123");
|
||||
}
|
||||
|
||||
void StartEmulation(void)
|
||||
@ -89,10 +57,7 @@ void StartEmulation(void)
|
||||
noGrowDocProc, (WindowPtr) -1, true, 0);
|
||||
SetPort(g_wp);
|
||||
|
||||
offscreenBmp.baseAddr = offscreen;
|
||||
offscreenBmp.bounds = offscreenRect;
|
||||
offscreenBmp.rowBytes = 32;
|
||||
emulationOn = 1;
|
||||
|
||||
}
|
||||
|
||||
bool LoadRom(StrFileName fileName, short vRefNum)
|
||||
@ -101,11 +66,12 @@ bool LoadRom(StrFileName fileName, short vRefNum)
|
||||
short fileNo;
|
||||
long amtRead;
|
||||
|
||||
if(rom.data != NULL) {
|
||||
if(theState.rom != NULL) {
|
||||
// unload existing ROM
|
||||
free((char *) rom.data);
|
||||
rom.length = 0;
|
||||
free((char *) theState.rom);
|
||||
theState.romLength = 0;
|
||||
}
|
||||
|
||||
|
||||
err = FSOpen(fileName, vRefNum, &fileNo);
|
||||
|
||||
@ -113,16 +79,16 @@ bool LoadRom(StrFileName fileName, short vRefNum)
|
||||
return false;
|
||||
}
|
||||
|
||||
GetEOF(fileNo, (long *) &rom.length);
|
||||
rom.data = (unsigned char *) malloc(rom.length);
|
||||
if(rom.data == NULL) {
|
||||
GetEOF(fileNo, (long *) &theState.romLength);
|
||||
theState.rom = (unsigned char *) malloc(theState.romLength);
|
||||
if(theState.rom == NULL) {
|
||||
Alert(ALRT_NOT_ENOUGH_RAM, NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
amtRead = rom.length;
|
||||
amtRead = theState.romLength;
|
||||
|
||||
FSRead(fileNo, &amtRead, rom.data);
|
||||
FSRead(fileNo, &amtRead, theState.rom);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -146,6 +112,7 @@ bool ShowOpenBox(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
DialogPtr stateDialog;
|
||||
void ShowStateDialog(void)
|
||||
{
|
||||
DialogPtr dp;
|
||||
@ -240,34 +207,15 @@ void OnMouseDown(EventRecord *pEvt)
|
||||
}
|
||||
|
||||
// -- ENTRY POINT --
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
EventRecord evt;
|
||||
|
||||
int executed;
|
||||
int paused = 0;
|
||||
int pause_next = 0;
|
||||
|
||||
InitEverything();
|
||||
|
||||
lcd_new(&lcd);
|
||||
dmg_new(&dmg, &cpu, &rom, &lcd);
|
||||
cpu_bind_mem_model(&cpu, &dmg, dmg_read, dmg_write);
|
||||
|
||||
cpu.pc = 0x100;
|
||||
|
||||
int start = TickCount();
|
||||
while(g_running) {
|
||||
if (emulationOn) {
|
||||
dmg_step(&dmg);
|
||||
int now = TickCount();
|
||||
if (now > lastTicks + 100) {
|
||||
lastTicks = now;
|
||||
Render();
|
||||
}
|
||||
}
|
||||
|
||||
if(WaitNextEvent(everyEvent, &evt, 0, 0) != nullEvent) {
|
||||
if(WaitNextEvent(everyEvent, &evt, 10, 0) != nullEvent) {
|
||||
if (IsDialogEvent(&evt)) {
|
||||
DialogRef hitBox;
|
||||
DialogItemIndex hitItem;
|
||||
|
@ -1,4 +1,7 @@
|
||||
/* Game Boy emulator for 68k Macs
|
||||
Compiled with Symantec THINK C 5.0
|
||||
(c) 2013 Matt Laux
|
||||
|
||||
emulator.h - declarations for emulator.c */
|
||||
|
||||
#ifndef EMULATOR_H
|
||||
@ -41,4 +44,12 @@ typedef unsigned char bool;
|
||||
#define true 1
|
||||
#define false 0
|
||||
|
||||
typedef struct _emu_state {
|
||||
struct dmg *cpu;
|
||||
u8 *rom;
|
||||
unsigned long int romLength;
|
||||
} emu_state;
|
||||
|
||||
extern emu_state theState;
|
||||
|
||||
#endif
|
@ -4,3 +4,4 @@ void lcd_draw(struct lcd *lcd)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user