mirror of https://github.com/bsnes-emu/bsnes.git
Update to v087r23 release.
byuu says: Changelog: - fixed cascading timers and readouts (speed hit from 320fps to 240fps; would be 155fps with r20 timers) (fixes Spyro) - OBJ mode 3 acts like OBJ mode 2 now (may not be correct, but nobody has info on it) - added background + object vertical+horizontal mosaic in all modes (linear+affine+bitmap) - object mosaic uses sprite (0,0) for start coordinates, not screen (0,0) (again, nobody seems to have info on it) - BIOS cannot be read by r(15)>=0x02000000; returns last BIOS read instead (I can't believe games rely on this to work ... fixes SMA Mario Bros.) Mosaic is what concerns me the most, I've no idea if I'm doing it correctly. But anything is probably better than nothing, so there's that. I don't really notice the effect in Metroid Fusion. So either it's broken, or it's really subtle.
This commit is contained in:
parent
d423ae0a29
commit
28885db586
|
@ -1,7 +1,7 @@
|
||||||
#ifndef BASE_HPP
|
#ifndef BASE_HPP
|
||||||
#define BASE_HPP
|
#define BASE_HPP
|
||||||
|
|
||||||
static const char Version[] = "087.22";
|
static const char Version[] = "087.23";
|
||||||
|
|
||||||
#include <nall/platform.hpp>
|
#include <nall/platform.hpp>
|
||||||
#include <nall/algorithm.hpp>
|
#include <nall/algorithm.hpp>
|
||||||
|
|
|
@ -69,9 +69,9 @@ void CPU::power() {
|
||||||
dma.control = 0;
|
dma.control = 0;
|
||||||
}
|
}
|
||||||
for(auto &timer : regs.timer) {
|
for(auto &timer : regs.timer) {
|
||||||
|
timer.period = 0;
|
||||||
timer.reload = 0;
|
timer.reload = 0;
|
||||||
timer.control = 0;
|
timer.control = 0;
|
||||||
timer.counter = 0;
|
|
||||||
}
|
}
|
||||||
regs.keypad.control = 0;
|
regs.keypad.control = 0;
|
||||||
regs.ime = 0;
|
regs.ime = 0;
|
||||||
|
|
|
@ -26,7 +26,7 @@ uint8 CPU::read(uint32 addr) {
|
||||||
case 0x0400010c: case 0x0400010d: {
|
case 0x0400010c: case 0x0400010d: {
|
||||||
auto &timer = regs.timer[(addr >> 2) & 3];
|
auto &timer = regs.timer[(addr >> 2) & 3];
|
||||||
unsigned shift = (addr & 1) * 8;
|
unsigned shift = (addr & 1) * 8;
|
||||||
return timer.counter >> shift;
|
return timer.period >> shift;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TIM0CNT_H
|
//TIM0CNT_H
|
||||||
|
@ -178,9 +178,7 @@ void CPU::write(uint32 addr, uint8 byte) {
|
||||||
bool enable = timer.control.enable;
|
bool enable = timer.control.enable;
|
||||||
timer.control = byte;
|
timer.control = byte;
|
||||||
if(enable == 0 && timer.control.enable == 1) {
|
if(enable == 0 && timer.control.enable == 1) {
|
||||||
timer.counter = timer.period();
|
timer.period = timer.reload;
|
||||||
} else if(timer.control.enable == 0) {
|
|
||||||
timer.counter = 0;
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,11 +23,6 @@ uint16 CPU::Registers::DMAControl::operator=(uint16 source) {
|
||||||
return operator uint16();
|
return operator uint16();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned CPU::Registers::TimerControl::multiplier() const {
|
|
||||||
static unsigned multiplier[] = { 1, 64, 256, 1024 };
|
|
||||||
return multiplier[frequency];
|
|
||||||
}
|
|
||||||
|
|
||||||
CPU::Registers::TimerControl::operator uint8() const {
|
CPU::Registers::TimerControl::operator uint8() const {
|
||||||
return (
|
return (
|
||||||
(frequency << 0)
|
(frequency << 0)
|
||||||
|
@ -45,11 +40,6 @@ uint8 CPU::Registers::TimerControl::operator=(uint8 source) {
|
||||||
return operator uint8();
|
return operator uint8();
|
||||||
}
|
}
|
||||||
|
|
||||||
//return number of clocks before counter overflow
|
|
||||||
signed CPU::Registers::Timer::period() const {
|
|
||||||
return (65536 - reload) * control.multiplier() + counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
CPU::Registers::KeypadControl::operator uint16() const {
|
CPU::Registers::KeypadControl::operator uint16() const {
|
||||||
return (
|
return (
|
||||||
(a << 0)
|
(a << 0)
|
||||||
|
|
|
@ -34,19 +34,15 @@ struct Registers {
|
||||||
uint1 irq;
|
uint1 irq;
|
||||||
uint1 enable;
|
uint1 enable;
|
||||||
|
|
||||||
unsigned multiplier() const;
|
|
||||||
operator uint8() const;
|
operator uint8() const;
|
||||||
uint8 operator=(uint8 source);
|
uint8 operator=(uint8 source);
|
||||||
TimerControl& operator=(const TimerControl&) = delete;
|
TimerControl& operator=(const TimerControl&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Timer {
|
struct Timer {
|
||||||
|
uint16 period;
|
||||||
uint16 reload;
|
uint16 reload;
|
||||||
TimerControl control;
|
TimerControl control;
|
||||||
|
|
||||||
//internal
|
|
||||||
signed period() const;
|
|
||||||
signed counter;
|
|
||||||
} timer[4];
|
} timer[4];
|
||||||
|
|
||||||
struct KeypadControl {
|
struct KeypadControl {
|
||||||
|
|
|
@ -1,23 +1,31 @@
|
||||||
void CPU::timer_step(unsigned clocks) {
|
void CPU::timer_step(unsigned clocks) {
|
||||||
for(unsigned n = 0; n < 4; n++) {
|
for(unsigned c = 0; c < clocks; c++) {
|
||||||
auto &timer = regs.timer[n];
|
for(unsigned n = 0; n < 4; n++) {
|
||||||
if(timer.control.enable == false || timer.control.cascade == true) continue;
|
auto &timer = regs.timer[n];
|
||||||
|
if(timer.control.enable == false || timer.control.cascade == true) continue;
|
||||||
|
|
||||||
timer.counter -= clocks;
|
static unsigned mask[] = { 0, 63, 255, 1023 };
|
||||||
while(timer.counter <= 0) {
|
if((regs.clock & mask[timer.control.frequency]) == 0) {
|
||||||
timer_increment(n);
|
timer_increment(n);
|
||||||
timer.counter = timer.period();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
regs.clock++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::timer_increment(unsigned n) {
|
void CPU::timer_increment(unsigned n) {
|
||||||
if(regs.timer[n].control.irq) regs.irq.flag.timer[n] = 1;
|
auto &timer = regs.timer[n];
|
||||||
|
if(++timer.period == 0) {
|
||||||
|
timer.period = timer.reload;
|
||||||
|
|
||||||
if(apu.fifo[0].timer == n) apu.fifo[0].read();
|
if(timer.control.irq) regs.irq.flag.timer[n] = 1;
|
||||||
if(apu.fifo[1].timer == n) apu.fifo[1].read();
|
|
||||||
|
|
||||||
if(n < 3 && regs.timer[n + 1].control.enable && regs.timer[n + 1].control.cascade) {
|
if(apu.fifo[0].timer == n) apu.fifo[0].read();
|
||||||
timer_increment(n + 1);
|
if(apu.fifo[1].timer == n) apu.fifo[1].read();
|
||||||
|
|
||||||
|
if(n < 3 && regs.timer[n + 1].control.enable && regs.timer[n + 1].control.cascade) {
|
||||||
|
timer_increment(n + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,8 +96,8 @@ uint32 Bus::read(uint32 addr, uint32 size) {
|
||||||
if(addr & 0x08000000) return cartridge.read(addr, size);
|
if(addr & 0x08000000) return cartridge.read(addr, size);
|
||||||
|
|
||||||
switch(addr & 0x07000000) {
|
switch(addr & 0x07000000) {
|
||||||
case 0x00000000: return system.bios.read(addr & 0x3fff, size);
|
case 0x00000000: return bios.read(addr, size);
|
||||||
case 0x01000000: return system.bios.read(addr & 0x3fff, size);
|
case 0x01000000: return bios.read(addr, size);
|
||||||
case 0x02000000: return cpu.ewram.read(addr & 0x3ffff, size);
|
case 0x02000000: return cpu.ewram.read(addr & 0x3ffff, size);
|
||||||
case 0x03000000: return cpu.iwram.read(addr & 0x7fff, size);
|
case 0x03000000: return cpu.iwram.read(addr & 0x7fff, size);
|
||||||
case 0x04000000:
|
case 0x04000000:
|
||||||
|
|
|
@ -25,7 +25,11 @@ void PPU::render_background_linear(Registers::Background &bg) {
|
||||||
if(regs.control.enable[bg.id] == false) return;
|
if(regs.control.enable[bg.id] == false) return;
|
||||||
auto &output = layer[bg.id];
|
auto &output = layer[bg.id];
|
||||||
|
|
||||||
uint9 voffset = regs.vcounter + bg.voffset;
|
if(bg.control.mosaic == false || (regs.vcounter % (1 + regs.mosaic.bgvsize)) == 0) {
|
||||||
|
bg.vmosaic = regs.vcounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint9 voffset = bg.vmosaic + bg.voffset;
|
||||||
uint9 hoffset = bg.hoffset;
|
uint9 hoffset = bg.hoffset;
|
||||||
|
|
||||||
unsigned basemap = bg.control.screenbaseblock << 11;
|
unsigned basemap = bg.control.screenbaseblock << 11;
|
||||||
|
@ -83,8 +87,13 @@ void PPU::render_background_affine(Registers::Background &bg) {
|
||||||
unsigned screensize = 16 << bg.control.screensize;
|
unsigned screensize = 16 << bg.control.screensize;
|
||||||
unsigned screenwrap = (1 << (bg.control.affinewrap ? 7 + bg.control.screensize : 20)) - 1;
|
unsigned screenwrap = (1 << (bg.control.affinewrap ? 7 + bg.control.screensize : 20)) - 1;
|
||||||
|
|
||||||
int28 fx = bg.lx;
|
if(bg.control.mosaic == false || (regs.vcounter % (1 + regs.mosaic.bgvsize)) == 0) {
|
||||||
int28 fy = bg.ly;
|
bg.hmosaic = bg.lx;
|
||||||
|
bg.vmosaic = bg.ly;
|
||||||
|
}
|
||||||
|
|
||||||
|
int28 fx = bg.hmosaic;
|
||||||
|
int28 fy = bg.vmosaic;
|
||||||
|
|
||||||
for(unsigned x = 0; x < 240; x++) {
|
for(unsigned x = 0; x < 240; x++) {
|
||||||
unsigned cx = (fx >> 8) & screenwrap, tx = cx / 8, px = cx & 7;
|
unsigned cx = (fx >> 8) & screenwrap, tx = cx / 8, px = cx & 7;
|
||||||
|
@ -115,8 +124,13 @@ void PPU::render_background_bitmap(Registers::Background &bg) {
|
||||||
unsigned height = regs.control.bgmode == 5 ? 128 : 160;
|
unsigned height = regs.control.bgmode == 5 ? 128 : 160;
|
||||||
unsigned size = depth ? Half : Byte;
|
unsigned size = depth ? Half : Byte;
|
||||||
|
|
||||||
int28 fx = bg.lx;
|
if(bg.control.mosaic == false || (regs.vcounter % (1 + regs.mosaic.bgvsize)) == 0) {
|
||||||
int28 fy = bg.ly;
|
bg.hmosaic = bg.lx;
|
||||||
|
bg.vmosaic = bg.ly;
|
||||||
|
}
|
||||||
|
|
||||||
|
int28 fx = bg.hmosaic;
|
||||||
|
int28 fy = bg.vmosaic;
|
||||||
|
|
||||||
for(unsigned x = 0; x < 240; x++) {
|
for(unsigned x = 0; x < 240; x++) {
|
||||||
unsigned px = fx >> 8;
|
unsigned px = fx >> 8;
|
||||||
|
|
|
@ -1,43 +1,28 @@
|
||||||
void PPU::render_objects() {
|
void PPU::render_objects() {
|
||||||
if(regs.control.enable[OBJ] == false) return;
|
if(regs.control.enable[OBJ] == false) return;
|
||||||
|
for(unsigned n = 0; n < 128; n++) render_object(object[n]);
|
||||||
for(unsigned n = 0; n < 128; n++) {
|
|
||||||
auto &obj = object[n];
|
|
||||||
uint8 py = regs.vcounter - obj.y;
|
|
||||||
if(py >= obj.height << obj.affinesize) continue; //offscreen
|
|
||||||
if(obj.affine == 0 && obj.affinesize == 1) continue; //hidden
|
|
||||||
|
|
||||||
if(obj.affine == 0) render_object_linear(obj);
|
|
||||||
if(obj.affine == 1) render_object_affine(obj);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPU::render_object_linear(Object &obj) {
|
//px,py = pixel coordinates within sprite [0,0 - width,height)
|
||||||
auto &output = layer[OBJ];
|
//fx,fy = affine pixel coordinates
|
||||||
|
//pa,pb,pc,pd = affine pixel adjustments
|
||||||
|
//x,y = adjusted coordinates within sprite (linear = vflip/hflip, affine = rotation/zoom)
|
||||||
|
void PPU::render_object(Object &obj) {
|
||||||
uint8 py = regs.vcounter - obj.y;
|
uint8 py = regs.vcounter - obj.y;
|
||||||
if(obj.vflip) py ^= obj.height - 1;
|
if(obj.affine == 0 && obj.affinesize == 1) return; //hidden
|
||||||
|
if(py >= obj.height << obj.affinesize) return; //offscreen
|
||||||
|
|
||||||
|
auto &output = layer[OBJ];
|
||||||
unsigned rowsize = regs.control.objmapping == 0 ? 32 >> obj.colors : obj.width / 8;
|
unsigned rowsize = regs.control.objmapping == 0 ? 32 >> obj.colors : obj.width / 8;
|
||||||
unsigned baseaddr = 0x10000 + obj.character * 32;
|
unsigned baseaddr = 0x10000 + obj.character * 32;
|
||||||
uint9 sx = obj.x;
|
|
||||||
|
|
||||||
for(unsigned x = 0; x < obj.width; x++, sx++) {
|
if(obj.vflip && obj.affine == 0) {
|
||||||
unsigned px = x;
|
py ^= obj.height - 1;
|
||||||
if(obj.hflip) px ^= obj.width - 1;
|
|
||||||
|
|
||||||
if(sx < 240) {
|
|
||||||
render_object_pixel(obj, sx, px, py, rowsize, baseaddr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void PPU::render_object_affine(Object &obj) {
|
if(obj.mosaic && regs.mosaic.objvsize) {
|
||||||
auto &output = layer[OBJ];
|
py = (py / (1 + regs.mosaic.objvsize)) * (1 + regs.mosaic.objvsize);
|
||||||
uint8 py = regs.vcounter - obj.y;
|
}
|
||||||
|
|
||||||
unsigned rowsize = regs.control.objmapping == 0 ? 32 >> obj.colors : obj.width / 8;
|
|
||||||
unsigned baseaddr = 0x10000 + obj.character * 32;
|
|
||||||
uint9 sx = obj.x;
|
|
||||||
|
|
||||||
int16 pa = objectparam[obj.affineparam].pa;
|
int16 pa = objectparam[obj.affineparam].pa;
|
||||||
int16 pb = objectparam[obj.affineparam].pb;
|
int16 pb = objectparam[obj.affineparam].pb;
|
||||||
|
@ -52,41 +37,43 @@ void PPU::render_object_affine(Object &obj) {
|
||||||
int28 originx = -(centerx << obj.affinesize);
|
int28 originx = -(centerx << obj.affinesize);
|
||||||
int28 originy = -(centery << obj.affinesize) + py;
|
int28 originy = -(centery << obj.affinesize) + py;
|
||||||
|
|
||||||
|
//fractional pixel coordinates
|
||||||
int28 fx = originx * pa + originy * pb;
|
int28 fx = originx * pa + originy * pb;
|
||||||
int28 fy = originx * pc + originy * pd;
|
int28 fy = originx * pc + originy * pd;
|
||||||
|
|
||||||
for(unsigned x = 0; x < (obj.width << obj.affinesize); x++, sx++) {
|
for(unsigned px = 0; px < (obj.width << obj.affinesize); px++) {
|
||||||
unsigned px = (fx >> 8) + centerx;
|
unsigned x, y;
|
||||||
unsigned py = (fy >> 8) + centery;
|
if(obj.affine == 0) {
|
||||||
|
x = px;
|
||||||
|
y = py;
|
||||||
|
if(obj.hflip) x ^= obj.width - 1;
|
||||||
|
} else {
|
||||||
|
x = (fx >> 8) + centerx;
|
||||||
|
y = (fy >> 8) + centery;
|
||||||
|
}
|
||||||
|
|
||||||
if(sx < 240 && px < obj.width && py < obj.height) {
|
if(obj.mosaic && regs.mosaic.objhsize) {
|
||||||
render_object_pixel(obj, sx, px, py, rowsize, baseaddr);
|
x = (x / (1 + regs.mosaic.objhsize)) * (1 + regs.mosaic.objhsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned ox = obj.x + px;
|
||||||
|
if(ox < 240 && x < obj.width && y < obj.height) {
|
||||||
|
unsigned offset = (y / 8) * rowsize + (x / 8);
|
||||||
|
offset = offset * 64 + (y & 7) * 8 + (x & 7);
|
||||||
|
|
||||||
|
uint8 color = vram[baseaddr + (offset >> !obj.colors)];
|
||||||
|
if(obj.colors == 0) color = (x & 1) ? color >> 4 : color & 15;
|
||||||
|
if(color) {
|
||||||
|
if(obj.mode & 2) {
|
||||||
|
windowmask[Obj][ox] = true;
|
||||||
|
} else if(output[ox].enable == false || obj.priority < output[ox].priority) {
|
||||||
|
if(obj.colors == 0) color = obj.palette * 16 + color;
|
||||||
|
output[ox] = { true, obj.mode == 1, obj.priority, pram[256 + color] };
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fx += pa;
|
fx += pa;
|
||||||
fy += pc;
|
fy += pc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPU::render_object_pixel(Object &obj, unsigned x, unsigned px, unsigned py, unsigned rowsize, unsigned baseaddr) {
|
|
||||||
auto &output = layer[OBJ];
|
|
||||||
|
|
||||||
unsigned offset = (py / 8) * rowsize + (px / 8);
|
|
||||||
if(obj.colors == 0) offset = baseaddr + offset * 32 + (py & 7) * 4 + (px & 7) / 2;
|
|
||||||
if(obj.colors == 1) offset = baseaddr + offset * 64 + (py & 7) * 8 + (px & 7);
|
|
||||||
|
|
||||||
uint8 color = vram[offset];
|
|
||||||
if(obj.colors == 0) color = (px & 1) ? color >> 4 : color & 15;
|
|
||||||
|
|
||||||
if(color == 0) return; //transparent
|
|
||||||
|
|
||||||
if(obj.mode == 2) {
|
|
||||||
windowmask[Obj][x] = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(output[x].enable == false || obj.priority < output[x].priority) {
|
|
||||||
if(obj.colors == 0) output[x] = { true, obj.mode == 1, obj.priority, pram[256 + obj.palette * 16 + color] };
|
|
||||||
if(obj.colors == 1) output[x] = { true, obj.mode == 1, obj.priority, pram[256 + color] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -32,12 +32,11 @@ struct PPU : Thread, MMIO {
|
||||||
void render_background_bitmap(Registers::Background&);
|
void render_background_bitmap(Registers::Background&);
|
||||||
|
|
||||||
void render_objects();
|
void render_objects();
|
||||||
void render_object_linear(Object&);
|
void render_object(Object&);
|
||||||
void render_object_affine(Object&);
|
|
||||||
void render_object_pixel(Object&, unsigned x, unsigned px, unsigned py, unsigned rowsize, unsigned baseaddr);
|
|
||||||
|
|
||||||
void render_forceblank();
|
void render_forceblank();
|
||||||
void render_screen();
|
void render_screen();
|
||||||
|
void render_mosaic(unsigned id, unsigned width);
|
||||||
void render_window(unsigned window);
|
void render_window(unsigned window);
|
||||||
unsigned blend(unsigned above, unsigned eva, unsigned below, unsigned evb);
|
unsigned blend(unsigned above, unsigned eva, unsigned below, unsigned evb);
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,8 @@ struct Registers {
|
||||||
|
|
||||||
//internal
|
//internal
|
||||||
int28 lx, ly;
|
int28 lx, ly;
|
||||||
|
unsigned vmosaic;
|
||||||
|
unsigned hmosaic;
|
||||||
unsigned id;
|
unsigned id;
|
||||||
} bg[4];
|
} bg[4];
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,11 @@ void PPU::render_screen() {
|
||||||
uint16 *line = output + regs.vcounter * 240;
|
uint16 *line = output + regs.vcounter * 240;
|
||||||
uint16 *last = blur + regs.vcounter * 240;
|
uint16 *last = blur + regs.vcounter * 240;
|
||||||
|
|
||||||
|
if(regs.bg[0].control.mosaic) render_mosaic(BG0, regs.mosaic.bghsize);
|
||||||
|
if(regs.bg[1].control.mosaic) render_mosaic(BG1, regs.mosaic.bghsize);
|
||||||
|
if(regs.bg[2].control.mosaic) render_mosaic(BG2, regs.mosaic.bghsize);
|
||||||
|
if(regs.bg[3].control.mosaic) render_mosaic(BG3, regs.mosaic.bghsize);
|
||||||
|
|
||||||
for(unsigned x = 0; x < 240; x++) {
|
for(unsigned x = 0; x < 240; x++) {
|
||||||
Registers::WindowFlags flags;
|
Registers::WindowFlags flags;
|
||||||
flags = ~0; //enable all layers if no windows are enabled
|
flags = ~0; //enable all layers if no windows are enabled
|
||||||
|
@ -58,6 +63,19 @@ void PPU::render_screen() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PPU::render_mosaic(unsigned id, unsigned width) {
|
||||||
|
if(++width == 1) return;
|
||||||
|
auto &buffer = layer[id];
|
||||||
|
|
||||||
|
for(unsigned x = 0; x < 240;) {
|
||||||
|
for(unsigned m = 1; m < width; m++) {
|
||||||
|
if(x + m >= 240) break;
|
||||||
|
buffer[x + m] = buffer[x];
|
||||||
|
}
|
||||||
|
x += width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PPU::render_window(unsigned w) {
|
void PPU::render_window(unsigned w) {
|
||||||
unsigned y = regs.vcounter;
|
unsigned y = regs.vcounter;
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@ struct Pixel {
|
||||||
} layer[6][240];
|
} layer[6][240];
|
||||||
|
|
||||||
bool windowmask[3][240];
|
bool windowmask[3][240];
|
||||||
|
unsigned vmosaic[5];
|
||||||
|
unsigned hmosaic[5];
|
||||||
|
|
||||||
struct Object {
|
struct Object {
|
||||||
uint8 y;
|
uint8 y;
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
void BIOS::load(const uint8 *biosdata, unsigned biossize) {
|
||||||
|
memcpy(data, biosdata, min(size, biossize));
|
||||||
|
|
||||||
|
string sha256 = nall::sha256(data, size);
|
||||||
|
if(sha256 != "fd2547724b505f487e6dcb29ec2ecff3af35a841a77ab2e85fd87350abd36570") {
|
||||||
|
interface->message("Warning: Game Boy Advance BIOS SHA256 sum is incorrect.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 BIOS::read(uint32 addr, uint32 size) {
|
||||||
|
//GBA BIOS is read-protected; only the BIOS itself can read its own memory
|
||||||
|
//when accessed elsewhere; this returns the last value read by the BIOS program
|
||||||
|
if(cpu.r(15) >= 0x02000000) return mdr;
|
||||||
|
|
||||||
|
if(size == Word) return mdr = read(addr &~ 2, Half) << 0 | read(addr | 2, Half) << 16;
|
||||||
|
if(size == Half) return mdr = read(addr &~ 1, Byte) << 0 | read(addr | 1, Byte) << 8;
|
||||||
|
return mdr = data[addr & 0x3fff];
|
||||||
|
}
|
||||||
|
|
||||||
|
void BIOS::write(uint32 addr, uint32 size, uint32 word) {
|
||||||
|
}
|
||||||
|
|
||||||
|
BIOS::BIOS() {
|
||||||
|
data = new uint8[size = 16384]();
|
||||||
|
}
|
||||||
|
|
||||||
|
BIOS::~BIOS() {
|
||||||
|
delete[] data;
|
||||||
|
}
|
|
@ -2,21 +2,10 @@
|
||||||
|
|
||||||
namespace GBA {
|
namespace GBA {
|
||||||
|
|
||||||
|
#include "bios.cpp"
|
||||||
|
BIOS bios;
|
||||||
System system;
|
System system;
|
||||||
|
|
||||||
void System::BIOS::load(const uint8_t *biosdata, unsigned biossize) {
|
|
||||||
memcpy(data, biosdata, min(size, biossize));
|
|
||||||
|
|
||||||
string sha256 = nall::sha256(data, size);
|
|
||||||
if(sha256 != "fd2547724b505f487e6dcb29ec2ecff3af35a841a77ab2e85fd87350abd36570") {
|
|
||||||
interface->message("Warning: Game Boy Advance BIOS SHA256 sum is incorrect.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
System::BIOS::BIOS() {
|
|
||||||
data = new uint8[size = 16384]();
|
|
||||||
}
|
|
||||||
|
|
||||||
void System::init() {
|
void System::init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,16 +2,25 @@ enum class Input : unsigned {
|
||||||
A, B, Select, Start, Right, Left, Up, Down, R, L,
|
A, B, Select, Start, Right, Left, Up, Down, R, L,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct System {
|
struct BIOS : Memory {
|
||||||
struct BIOS : StaticMemory {
|
uint8 *data;
|
||||||
void load(const uint8_t *data, unsigned size);
|
unsigned size;
|
||||||
BIOS();
|
uint32 mdr;
|
||||||
} bios;
|
|
||||||
|
|
||||||
|
void load(const uint8 *data, unsigned size);
|
||||||
|
uint32 read(uint32 addr, uint32 size);
|
||||||
|
void write(uint32 addr, uint32 size, uint32 word);
|
||||||
|
|
||||||
|
BIOS();
|
||||||
|
~BIOS();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct System {
|
||||||
void init();
|
void init();
|
||||||
void term();
|
void term();
|
||||||
void power();
|
void power();
|
||||||
void run();
|
void run();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern BIOS bios;
|
||||||
extern System system;
|
extern System system;
|
||||||
|
|
|
@ -41,7 +41,7 @@ bool InterfaceGBA::loadCartridge(const string &filename) {
|
||||||
string markup;
|
string markup;
|
||||||
markup.readfile(interface->base.filename("manifest.xml", ".xml"));
|
markup.readfile(interface->base.filename("manifest.xml", ".xml"));
|
||||||
|
|
||||||
GBA::system.bios.load(biosdata, biossize);
|
GBA::bios.load(biosdata, biossize);
|
||||||
GBA::cartridge.load(markup, cartdata, cartsize);
|
GBA::cartridge.load(markup, cartdata, cartsize);
|
||||||
GBA::system.power();
|
GBA::system.power();
|
||||||
delete[] biosdata;
|
delete[] biosdata;
|
||||||
|
|
Loading…
Reference in New Issue