Compare commits
2 Commits
b45ce4e76d
...
f5d89e0b9b
| Author | SHA1 | Date | |
|---|---|---|---|
| f5d89e0b9b | |||
| 63d1f6ef05 |
16
gbscreen.cpp
16
gbscreen.cpp
@@ -137,6 +137,7 @@ namespace gbscreen
|
|||||||
const uint8_t LCDC = mem::readMem(0xff40);
|
const uint8_t LCDC = mem::readMem(0xff40);
|
||||||
const uint8_t SCY = mem::readMem(0xff42);
|
const uint8_t SCY = mem::readMem(0xff42);
|
||||||
const uint8_t SCX = mem::readMem(0xff43);
|
const uint8_t SCX = mem::readMem(0xff43);
|
||||||
|
const uint8_t BGP = mem::readMem(0xff47);
|
||||||
const uint16_t ty = uint8_t(SCY+LY) >> 3;
|
const uint16_t ty = uint8_t(SCY+LY) >> 3;
|
||||||
const uint8_t ly = uint8_t(SCY+LY) & 0x7;
|
const uint8_t ly = uint8_t(SCY+LY) & 0x7;
|
||||||
uint16_t tx = SCX >> 3;
|
uint16_t tx = SCX >> 3;
|
||||||
@@ -156,7 +157,8 @@ namespace gbscreen
|
|||||||
uint8_t b = mem::readMem(tile_address+1);
|
uint8_t b = mem::readMem(tile_address+1);
|
||||||
for (int i=0; i<8; ++i) {
|
for (int i=0; i<8; ++i) {
|
||||||
if (ox==0) {
|
if (ox==0) {
|
||||||
line_buffer[pi++] = (a&0x80 ? 1 : 0) + (b&0x80 ? 2 : 0 );
|
uint8_t index = (a&0x80 ? 1 : 0) + (b&0x80 ? 2 : 0 );
|
||||||
|
line_buffer[pi++] = (BGP >> (index*2)) & 0x3;
|
||||||
} else {
|
} else {
|
||||||
ox--;
|
ox--;
|
||||||
}
|
}
|
||||||
@@ -176,6 +178,7 @@ namespace gbscreen
|
|||||||
void fill_line_buffer_obj(uint8_t LY)
|
void fill_line_buffer_obj(uint8_t LY)
|
||||||
{
|
{
|
||||||
const uint8_t LCDC = mem::readMem(0xff40);
|
const uint8_t LCDC = mem::readMem(0xff40);
|
||||||
|
const uint8_t OBP[2] = { mem::readMem(0xff48), mem::readMem(0xff49) };
|
||||||
if ((LCDC & 0x2) == 0) return;
|
if ((LCDC & 0x2) == 0) return;
|
||||||
|
|
||||||
oam = (oam_entry_t*)mem::rawPtr(0xfe00);
|
oam = (oam_entry_t*)mem::rawPtr(0xfe00);
|
||||||
@@ -195,7 +198,7 @@ namespace gbscreen
|
|||||||
// Pintem els sprites en el buffer de sprites
|
// Pintem els sprites en el buffer de sprites
|
||||||
uint8_t pixels[160];
|
uint8_t pixels[160];
|
||||||
uint8_t x_pos[160];
|
uint8_t x_pos[160];
|
||||||
for (int i=0;i<160;++i) { pixels[i] = 0; x_pos[i] = 255; }
|
for (int i=0;i<160;++i) { pixels[i] = 255; x_pos[i] = 255; }
|
||||||
obj=0;
|
obj=0;
|
||||||
while (obj_list[obj] != 255) {
|
while (obj_list[obj] != 255) {
|
||||||
oam_entry_t *o = &oam[obj_list[obj]];
|
oam_entry_t *o = &oam[obj_list[obj]];
|
||||||
@@ -213,10 +216,11 @@ namespace gbscreen
|
|||||||
if (o->x+i>=8) { // Si està dins de la pantalla...
|
if (o->x+i>=8) { // Si està dins de la pantalla...
|
||||||
if (x_pos[o->x+i-8]>o->x) { // Si te una x menor que la que tenía
|
if (x_pos[o->x+i-8]>o->x) { // Si te una x menor que la que tenía
|
||||||
//uint8_t xflip = o->attr&0x20 ? 8 : 0; // està invertit horitzontalment?
|
//uint8_t xflip = o->attr&0x20 ? 8 : 0; // està invertit horitzontalment?
|
||||||
uint8_t ppos = 1 << ( o->attr&0x20 ? i : 7-i);
|
const uint8_t ppos = 1 << ( o->attr&0x20 ? i : 7-i);
|
||||||
uint8_t val = (a&ppos ? 1 : 0) + (b&ppos ? 2 : 0 ); // agafem el pixel que toca
|
const uint8_t val = (a&ppos ? 1 : 0) + (b&ppos ? 2 : 0 ); // agafem el pixel que toca
|
||||||
if (val) { // Si el pixel no es transparent...
|
if (val) { // Si el pixel no es transparent...
|
||||||
pixels[o->x+i-8] = val | o->attr&0x80; // el pintem al buffer, amb el flag de prioritat respecte al BKG
|
const uint8_t color = (OBP[(LCDC>>4)&1] >> (val*2)) & 0x3;
|
||||||
|
pixels[o->x+i-8] = color | o->attr&0x80;; // el pintem al buffer, amb el flag de prioritat respecte al BKG
|
||||||
x_pos[o->x+i-8] = o->x; // I apuntem la seua x per a comparar després
|
x_pos[o->x+i-8] = o->x; // I apuntem la seua x per a comparar després
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -226,7 +230,7 @@ namespace gbscreen
|
|||||||
}
|
}
|
||||||
// Per últim, volquem els pixels que toque al buffer de linea
|
// Per últim, volquem els pixels que toque al buffer de linea
|
||||||
for (int i=0; i<160; ++i) {
|
for (int i=0; i<160; ++i) {
|
||||||
if (pixels[i]>0) { // si el pixel no es transparent...
|
if (pixels[i]!=255) { // si el pixel no es transparent...
|
||||||
if ( !(pixels[i]&0x80) || (line_buffer[i]==0) ) { // Si te prioritat o el color de fondo es 0...
|
if ( !(pixels[i]&0x80) || (line_buffer[i]==0) ) { // Si te prioritat o el color de fondo es 0...
|
||||||
line_buffer[i] = pixels[i]&0x03; // pintem el pixel (llevant el flag de prioritat)
|
line_buffer[i] = pixels[i]&0x03; // pintem el pixel (llevant el flag de prioritat)
|
||||||
}
|
}
|
||||||
|
|||||||
200
mbc1.cpp
Normal file
200
mbc1.cpp
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
#include "mbc1.h"
|
||||||
|
#include "mem.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
|
namespace mbc1
|
||||||
|
{
|
||||||
|
#define ROM_BANK_SIZE 0x4000
|
||||||
|
#define RAM_BANK_SIZE 0x2000
|
||||||
|
|
||||||
|
uint8_t bootrom[256];
|
||||||
|
uint8_t *rom;
|
||||||
|
uint8_t vram[8192];
|
||||||
|
uint8_t exram[4 * RAM_BANK_SIZE];
|
||||||
|
uint8_t wram[8192];
|
||||||
|
uint8_t hram[512];
|
||||||
|
|
||||||
|
uint8_t tags[65536];
|
||||||
|
|
||||||
|
uint8_t current_rom_bank = 1;
|
||||||
|
uint8_t current_ram_bank = 0;
|
||||||
|
bool ram_enabled = false;
|
||||||
|
bool banking_mode = false; // false = ROM banking mode, true = RAM banking mode
|
||||||
|
|
||||||
|
uint8_t getKeypad(uint8_t value)
|
||||||
|
{
|
||||||
|
const uint8_t *keys = SDL_GetKeyboardState(NULL);
|
||||||
|
value = value & 0xf0;
|
||||||
|
if (value & 0x10) {
|
||||||
|
if (!keys[SDL_SCANCODE_RETURN]) value = value | 0x8;
|
||||||
|
if (!keys[SDL_SCANCODE_SPACE]) value = value | 0x4;
|
||||||
|
if (!keys[SDL_SCANCODE_Z]) value = value | 0x2;
|
||||||
|
if (!keys[SDL_SCANCODE_X]) value = value | 0x1;
|
||||||
|
} else if (value & 0x20) {
|
||||||
|
if (!keys[SDL_SCANCODE_DOWN]) value = value | 0x8;
|
||||||
|
if (!keys[SDL_SCANCODE_UP]) value = value | 0x4;
|
||||||
|
if (!keys[SDL_SCANCODE_LEFT]) value = value | 0x2;
|
||||||
|
if (!keys[SDL_SCANCODE_RIGHT]) value = value | 0x1;
|
||||||
|
} else {
|
||||||
|
value = value | 0x0f;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t readMem(uint16_t address)
|
||||||
|
{
|
||||||
|
if (address < 0x8000) {
|
||||||
|
if ( (address < 0x0100) && ((hram[0x150]&0x01)==0) ) return bootrom[address];
|
||||||
|
if (address < 0x4000) {
|
||||||
|
// ROM Bank 0
|
||||||
|
return rom[address];
|
||||||
|
} else {
|
||||||
|
// Switchable ROM bank
|
||||||
|
uint32_t banked_address = (current_rom_bank * ROM_BANK_SIZE) + (address - 0x4000);
|
||||||
|
return rom[banked_address];
|
||||||
|
}
|
||||||
|
} else if (address < 0xA000) {
|
||||||
|
return vram[address - 0x8000];
|
||||||
|
} else if (address < 0xC000) {
|
||||||
|
if (ram_enabled) {
|
||||||
|
uint32_t banked_address = (current_ram_bank * RAM_BANK_SIZE) + (address - 0xA000);
|
||||||
|
return exram[banked_address];
|
||||||
|
}
|
||||||
|
return 0xFF; // Return open bus value when RAM is disabled
|
||||||
|
} else if (address < 0xE000) {
|
||||||
|
return wram[address - 0xC000];
|
||||||
|
} else if (address < 0xFE00) {
|
||||||
|
return wram[address - 0xE000];
|
||||||
|
} else {
|
||||||
|
if (address==0xFF00) {
|
||||||
|
hram[address - 0XFE00] = getKeypad(hram[address - 0XFE00]);
|
||||||
|
}
|
||||||
|
return hram[address - 0XFE00];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeMem(uint16_t address, uint8_t value)
|
||||||
|
{
|
||||||
|
if (address < 0x8000) {
|
||||||
|
if (address < 0x2000) {
|
||||||
|
// Enable/disable RAM
|
||||||
|
ram_enabled = (value & 0x0F) == 0x0A;
|
||||||
|
} else if (address < 0x4000) {
|
||||||
|
// Select ROM bank
|
||||||
|
value &= 0x1F; // Lower 5 bits are used
|
||||||
|
if (value == 0) value = 1; // Bank 0 is not allowed
|
||||||
|
current_rom_bank = (current_rom_bank & 0x60) | value;
|
||||||
|
} else if (address < 0x6000) {
|
||||||
|
// Select RAM bank or upper bits of ROM bank
|
||||||
|
if (banking_mode) {
|
||||||
|
current_ram_bank = value & 0x03; // 2 bits for RAM bank
|
||||||
|
} else {
|
||||||
|
current_rom_bank = (current_rom_bank & 0x1F) | ((value & 0x03) << 5);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Select banking mode
|
||||||
|
banking_mode = value & 0x01;
|
||||||
|
}
|
||||||
|
} else if (address < 0xA000) {
|
||||||
|
vram[address - 0x8000] = value;
|
||||||
|
} else if (address < 0xC000) {
|
||||||
|
if (ram_enabled) {
|
||||||
|
uint32_t banked_address = (current_ram_bank * RAM_BANK_SIZE) + (address - 0xA000);
|
||||||
|
exram[banked_address] = value;
|
||||||
|
}
|
||||||
|
} else if (address < 0xE000) {
|
||||||
|
wram[address - 0xC000] = value;
|
||||||
|
} else if (address < 0xFE00) {
|
||||||
|
wram[address - 0xE000] = value;
|
||||||
|
} else {
|
||||||
|
if ( (address==0xFF50) && ((value&0x01) != 1) ) return; //Only allow disabling boot room
|
||||||
|
if ( (address==0xFF00) ) { value = value & 0x30; }
|
||||||
|
if ( (address==0xFF04) ) { hram[address-0xFE00] = 0; return; }
|
||||||
|
if ( (address==0xFF46) ) mem::init_dma_transfer(value);
|
||||||
|
hram[address - 0xFE00] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t getTag(uint16_t address)
|
||||||
|
{
|
||||||
|
return tags[address];
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTag(uint16_t address, uint8_t value)
|
||||||
|
{
|
||||||
|
tags[address] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveState(FILE* f)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadState(FILE *f)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* rawPtr(uint16_t address)
|
||||||
|
{
|
||||||
|
if (address < 0x8000) {
|
||||||
|
if ( (address < 0x0100) && ((hram[0x150]&0x01)==0) ) return &bootrom[address];
|
||||||
|
if (address < 0x4000) {
|
||||||
|
// ROM Bank 0
|
||||||
|
return &rom[address];
|
||||||
|
} else {
|
||||||
|
// Switchable ROM bank
|
||||||
|
uint32_t banked_address = (current_rom_bank * ROM_BANK_SIZE) + (address - 0x4000);
|
||||||
|
return &rom[banked_address];
|
||||||
|
}
|
||||||
|
} else if (address < 0xA000) {
|
||||||
|
return &vram[address - 0x8000];
|
||||||
|
} else if (address < 0xC000) {
|
||||||
|
if (ram_enabled) {
|
||||||
|
uint32_t banked_address = (current_ram_bank * RAM_BANK_SIZE) + (address - 0xA000);
|
||||||
|
return &exram[banked_address];
|
||||||
|
}
|
||||||
|
return nullptr; // Return open bus value when RAM is disabled
|
||||||
|
} else if (address < 0xE000) {
|
||||||
|
return &wram[address - 0xC000];
|
||||||
|
} else if (address < 0xFE00) {
|
||||||
|
return &wram[address - 0xE000];
|
||||||
|
} else {
|
||||||
|
return &hram[address - 0XFE00];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
FILE *f = fopen("dmg_boot.bin", "rb");
|
||||||
|
if (!f) { printf("ABORTING: 'dmg_boot.bin' not found!\n"); exit(1); }
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
const int size = ftell(f);
|
||||||
|
fseek(f, 0, SEEK_SET);
|
||||||
|
fread(bootrom, size, 1, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
for (int i=0; i<8192; ++i) { vram[i] = 0; }
|
||||||
|
for (int i=0; i<4*RAM_BANK_SIZE; ++i) { exram[i] = 0; }
|
||||||
|
for (int i=0; i<8192; ++i) { wram[i] = 0; }
|
||||||
|
for (int i=0; i<512; ++i) { hram[i] = 0; }
|
||||||
|
for (int i=0; i<65536; ++i) { tags[i] = MEMTAG_NONE; }
|
||||||
|
}
|
||||||
|
|
||||||
|
void init(uint8_t *rom, uint32_t rom_size, uint32_t ram_size)
|
||||||
|
{
|
||||||
|
mem::readMem = mbc1::readMem;
|
||||||
|
mem::writeMem = mbc1::writeMem;
|
||||||
|
mem::getTag = mbc1::getTag;
|
||||||
|
mem::setTag = mbc1::setTag;
|
||||||
|
mem::saveState = mbc1::saveState;
|
||||||
|
mem::loadState = mbc1::loadState;
|
||||||
|
mem::reset = mbc1::reset;
|
||||||
|
mem::rawPtr = mbc1::rawPtr;
|
||||||
|
|
||||||
|
mbc1::rom = rom;
|
||||||
|
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
7
mbc1.h
Normal file
7
mbc1.h
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace mbc1
|
||||||
|
{
|
||||||
|
void init(uint8_t *rom, uint32_t rom_size, uint32_t ram_size);
|
||||||
|
}
|
||||||
6
mem.cpp
6
mem.cpp
@@ -4,6 +4,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "mbc_none.h"
|
#include "mbc_none.h"
|
||||||
|
#include "mbc1.h"
|
||||||
namespace mem
|
namespace mem
|
||||||
{
|
{
|
||||||
void (*reset)(void);
|
void (*reset)(void);
|
||||||
@@ -39,6 +40,11 @@ namespace mem
|
|||||||
case 0x00:
|
case 0x00:
|
||||||
mbc_none::init(rom, rom_size, ram_size);
|
mbc_none::init(rom, rom_size, ram_size);
|
||||||
break;
|
break;
|
||||||
|
case 0x01:
|
||||||
|
case 0x02:
|
||||||
|
case 0x03:
|
||||||
|
mbc1::init(rom, rom_size, ram_size);
|
||||||
|
break;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user