mirror of https://github.com/bsnes-emu/bsnes.git
Update to v087r18 release.
byuu says: Merged Cydrak's r17c changes: - BG affine mode added - BG bitmap mode added - OBJ affine mode added - fixed IRQ bug in THUMB mode (fixed almost every game) - timers added (broke almost every game, whee.) Cydrak is absolutely amazingly awesome and patient. This really wouldn't be happening without him. Also fixed some things from my end, including greatly improved sprite priorities, and a much better priority sorter. Mr. Driller looks a lot better now.
This commit is contained in:
parent
1de484262c
commit
6189c93f3d
|
@ -1,7 +1,7 @@
|
|||
#ifndef BASE_HPP
|
||||
#define BASE_HPP
|
||||
|
||||
static const char Version[] = "087.17";
|
||||
static const char Version[] = "087.18";
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/algorithm.hpp>
|
||||
|
|
|
@ -20,36 +20,18 @@ void APU::Master::run() {
|
|||
if(channel2_left_enable) sample += apu.square2.output;
|
||||
if(channel3_left_enable) sample += apu.wave.output;
|
||||
if(channel4_left_enable) sample += apu.noise.output;
|
||||
left = (sample * 512) - 16384;
|
||||
|
||||
switch(left_volume) {
|
||||
case 0: left >>= 3; break; // 12.5%
|
||||
case 1: left >>= 2; break; // 25.0%
|
||||
case 2: left = (left >> 2) + (left >> 3); break; // 37.5%
|
||||
case 3: left >>= 1; break; // 50.0%
|
||||
case 4: left = (left >> 1) + (left >> 3); break; // 62.5%
|
||||
case 5: left -= (left >> 2); break; // 75.0%
|
||||
case 6: left -= (left >> 3); break; // 87.5%
|
||||
//case 7: break; //100.0%
|
||||
}
|
||||
sample = (sample * 512) - 16384;
|
||||
sample = (sample * (left_volume + 1)) / 8;
|
||||
left = sample;
|
||||
|
||||
sample = 0;
|
||||
if(channel1_right_enable) sample += apu.square1.output;
|
||||
if(channel2_right_enable) sample += apu.square2.output;
|
||||
if(channel3_right_enable) sample += apu.wave.output;
|
||||
if(channel4_right_enable) sample += apu.noise.output;
|
||||
right = (sample * 512) - 16384;
|
||||
|
||||
switch(right_volume) {
|
||||
case 0: right >>= 3; break; // 12.5%
|
||||
case 1: right >>= 2; break; // 25.0%
|
||||
case 2: right = (right >> 2) + (right >> 3); break; // 37.5%
|
||||
case 3: right >>= 1; break; // 50.0%
|
||||
case 4: right = (right >> 1) + (right >> 3); break; // 62.5%
|
||||
case 5: right -= (right >> 2); break; // 75.0%
|
||||
case 6: right -= (right >> 3); break; // 87.5%
|
||||
//case 7: break; //100.0%
|
||||
}
|
||||
sample = (sample * 512) - 16384;
|
||||
sample = (sample * (right_volume + 1)) / 8;
|
||||
right = sample;
|
||||
}
|
||||
|
||||
void APU::Master::write(unsigned r, uint8 data) {
|
||||
|
|
|
@ -145,6 +145,10 @@ void APU::write(uint32 addr, uint8 byte) {
|
|||
case 0x04000084: return sequencer.write(2, byte);
|
||||
case 0x04000085: return;
|
||||
|
||||
//SOUNDBIAS
|
||||
case 0x04000088: regs.bias = (regs.bias & 0xff00) | (byte << 0); return;
|
||||
case 0x04000089: regs.bias = (regs.bias & 0x00ff) | (byte << 8); return;
|
||||
|
||||
//WAVE_RAM0_L
|
||||
case 0x04000090: return wave.writeram( 0, byte);
|
||||
case 0x04000091: return wave.writeram( 1, byte);
|
||||
|
@ -177,9 +181,5 @@ void APU::write(uint32 addr, uint8 byte) {
|
|||
case 0x0400009e: return wave.writeram(14, byte);
|
||||
case 0x0400009f: return wave.writeram(15, byte);
|
||||
|
||||
//SOUNDBIAS
|
||||
case 0x04000088: regs.bias = (regs.bias & 0xff00) | (byte << 0); return;
|
||||
case 0x04000089: regs.bias = (regs.bias & 0x00ff) | (byte << 8); return;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ struct Registers {
|
|||
uint16 operator=(uint16 source);
|
||||
SoundBias& operator=(const SoundBias&) = delete;
|
||||
} bias;
|
||||
|
||||
unsigned clock;
|
||||
} regs;
|
||||
|
||||
struct Sweep {
|
||||
|
@ -130,8 +132,31 @@ struct Sequencer {
|
|||
int16 lsample;
|
||||
int16 rsample;
|
||||
|
||||
signed volumeadjust(signed sample, uint3 volume);
|
||||
uint8 read(unsigned addr) const;
|
||||
void write(unsigned addr, uint8 byte);
|
||||
void power();
|
||||
} sequencer;
|
||||
|
||||
struct FIFO {
|
||||
int8 sample[32];
|
||||
uint5 rdoffset;
|
||||
uint5 wroffset;
|
||||
uint6 size;
|
||||
|
||||
inline int8 pull() {
|
||||
size--;
|
||||
return sample[rdoffset++];
|
||||
}
|
||||
|
||||
inline void push(int8 data) {
|
||||
size++;
|
||||
sample[wroffset++] = data;
|
||||
}
|
||||
|
||||
inline void reset() {
|
||||
rdoffset = 0;
|
||||
wroffset = 0;
|
||||
size = 0;
|
||||
for(auto &byte : sample) byte = 0;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -31,7 +31,7 @@ void APU::runsequencer() {
|
|||
if(r.lenable[2]) lsample += wave.output;
|
||||
if(r.lenable[3]) lsample += noise.output;
|
||||
lsample = (lsample * 512) - 15360;
|
||||
lsample = r.volumeadjust(lsample, r.lvolume);
|
||||
lsample = (lsample * (r.lvolume + 1)) / 8;
|
||||
r.lsample = lsample;
|
||||
|
||||
signed rsample = 0;
|
||||
|
@ -40,7 +40,7 @@ void APU::runsequencer() {
|
|||
if(r.renable[2]) rsample += wave.output;
|
||||
if(r.renable[3]) rsample += noise.output;
|
||||
rsample = (rsample * 512) - 15360;
|
||||
rsample = r.volumeadjust(rsample, r.rvolume);
|
||||
rsample = (rsample * (r.rvolume + 1)) / 8;
|
||||
r.rsample = rsample;
|
||||
|
||||
if(r.masterenable == false) {
|
||||
|
@ -49,19 +49,6 @@ void APU::runsequencer() {
|
|||
}
|
||||
}
|
||||
|
||||
signed APU::Sequencer::volumeadjust(signed sample, uint3 volume) {
|
||||
switch(volume) {
|
||||
case 0: return (sample >> 3); // 12.5%
|
||||
case 1: return (sample >> 2); // 25.0%
|
||||
case 2: return (sample >> 2) + (sample >> 3); // 37.5%
|
||||
case 3: return (sample >> 1); // 50.0%
|
||||
case 4: return (sample >> 1) + (sample >> 3); // 62.5%
|
||||
case 5: return (sample >> 0) - (sample >> 2); // 75.0%
|
||||
case 6: return (sample >> 0) - (sample >> 3); // 87.5%
|
||||
case 7: return (sample >> 0); //100.0%
|
||||
}
|
||||
}
|
||||
|
||||
uint8 APU::Sequencer::read(unsigned addr) const {
|
||||
switch(addr) {
|
||||
case 0: return (rvolume << 0) | (lvolume << 4);
|
||||
|
|
|
@ -6,16 +6,8 @@ void APU::Wave::run() {
|
|||
}
|
||||
|
||||
output = patternsample;
|
||||
switch(volume) {
|
||||
case 0: output = 0; // 0%
|
||||
case 1: break; //100%
|
||||
case 2: output >>= 1; // 50%
|
||||
case 3: output >>= 2; // 25%
|
||||
case 4: output -= output >> 2; // 75%
|
||||
case 5: output -= output >> 2; // 75%
|
||||
case 6: output -= output >> 2; // 75%
|
||||
case 7: output -= output >> 2; // 75%
|
||||
}
|
||||
static unsigned multiplier[] = { 0, 4, 2, 1, 3, 3, 3, 3};
|
||||
output = (output * multiplier[volume]) / 4;
|
||||
if(enable == false) output = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace GBA {
|
|||
#include "registers.cpp"
|
||||
#include "mmio.cpp"
|
||||
#include "dma.cpp"
|
||||
#include "timer.cpp"
|
||||
CPU cpu;
|
||||
|
||||
void CPU::Enter() { cpu.enter(); }
|
||||
|
@ -35,6 +36,8 @@ void CPU::enter() {
|
|||
}
|
||||
|
||||
void CPU::step(unsigned clocks) {
|
||||
for(unsigned n = 0; n < clocks; n++) timer_tick();
|
||||
|
||||
ppu.clock -= clocks;
|
||||
if(ppu.clock < 0) co_switch(ppu.thread);
|
||||
|
||||
|
@ -59,12 +62,18 @@ void CPU::power() {
|
|||
for(unsigned n = 0; n < iwram.size; n++) iwram.data[n] = 0;
|
||||
for(unsigned n = 0; n < ewram.size; n++) ewram.data[n] = 0;
|
||||
|
||||
regs.dma[0].source = regs.dma[1].source = regs.dma[2].source = regs.dma[3].source = 0;
|
||||
regs.dma[0].target = regs.dma[1].target = regs.dma[2].target = regs.dma[3].target = 0;
|
||||
regs.dma[0].length = regs.dma[1].length = regs.dma[2].length = regs.dma[3].length = 0;
|
||||
regs.dma[0].control = regs.dma[1].control = regs.dma[2].control = regs.dma[3].control = 0;
|
||||
regs.timer[0].reload = regs.timer[1].reload = regs.timer[2].reload = regs.timer[3].reload = 0;
|
||||
regs.timer[0].control = regs.timer[1].control = regs.timer[2].control = regs.timer[3].control = 0;
|
||||
for(auto &dma : regs.dma) {
|
||||
dma.source = 0;
|
||||
dma.target = 0;
|
||||
dma.length = 0;
|
||||
dma.control = 0;
|
||||
dma.active = 0;
|
||||
}
|
||||
for(auto &timer : regs.timer) {
|
||||
timer.counter = 0;
|
||||
timer.reload = 0;
|
||||
timer.control = 0;
|
||||
}
|
||||
regs.keypad.control = 0;
|
||||
regs.ime = 0;
|
||||
regs.irq.enable = 0;
|
||||
|
@ -72,6 +81,7 @@ void CPU::power() {
|
|||
regs.wait.control = 0;
|
||||
regs.postboot = 0;
|
||||
regs.mode = Registers::Mode::Normal;
|
||||
regs.clock = 0;
|
||||
regs.memory.control = 0x0d000020;
|
||||
|
||||
pending.dma.vblank = 0;
|
||||
|
|
|
@ -16,7 +16,10 @@ struct CPU : Processor::ARM, Thread, MMIO {
|
|||
void write(uint32 addr, uint8 byte);
|
||||
|
||||
void dma_run();
|
||||
void dma_transfer(uint2 channel);
|
||||
void dma_transfer(Registers::DMA &dma);
|
||||
|
||||
void timer_tick();
|
||||
void timer_increment(unsigned n);
|
||||
|
||||
CPU();
|
||||
};
|
||||
|
|
|
@ -1,13 +1,29 @@
|
|||
void CPU::dma_run() {
|
||||
for(unsigned n = 0; n < 4; n++) {
|
||||
if(regs.dma[n].control.enable == false) continue;
|
||||
switch(regs.dma[n].control.timingmode) {
|
||||
auto &dma = regs.dma[n];
|
||||
|
||||
if(dma.control.enable == false) {
|
||||
dma.active = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(dma.active == false) {
|
||||
dma.active = true;
|
||||
dma.run.target = dma.target;
|
||||
dma.run.source = dma.source;
|
||||
dma.run.length = dma.length;
|
||||
step(2);
|
||||
}
|
||||
|
||||
switch(dma.control.timingmode) {
|
||||
case 0: break;
|
||||
case 1: if(pending.dma.vblank == false) continue; break;
|
||||
case 2: if(pending.dma.hblank == false) continue; break;
|
||||
case 3: if(pending.dma.hdma == false || n != 3) continue; break;
|
||||
}
|
||||
dma_transfer(n);
|
||||
|
||||
dma_transfer(dma);
|
||||
if(dma.control.irq) regs.irq.flag.dma[n] = 1;
|
||||
}
|
||||
|
||||
pending.dma.vblank = false;
|
||||
|
@ -15,31 +31,28 @@ void CPU::dma_run() {
|
|||
pending.dma.hdma = false;
|
||||
}
|
||||
|
||||
void CPU::dma_transfer(uint2 n) {
|
||||
auto &channel = regs.dma[n];
|
||||
void CPU::dma_transfer(Registers::DMA &dma) {
|
||||
unsigned size = dma.control.size ? Word : Half;
|
||||
unsigned seek = dma.control.size ? 4 : 2;
|
||||
|
||||
unsigned size = channel.control.size ? Word : Half;
|
||||
unsigned seek = channel.control.size ? 4 : 2;
|
||||
uint16 length = channel.length;
|
||||
|
||||
channel.basetarget = channel.target;
|
||||
do {
|
||||
uint32 word = bus.read(channel.source, size);
|
||||
bus.write(channel.target, size, word);
|
||||
uint32 word = bus.read(dma.run.source, size);
|
||||
bus.write(dma.run.target, size, word);
|
||||
step(2);
|
||||
|
||||
switch(channel.control.sourcemode) {
|
||||
case 0: channel.source += seek; break;
|
||||
case 1: channel.source -= seek; break;
|
||||
switch(dma.control.sourcemode) {
|
||||
case 0: dma.run.source += seek; break;
|
||||
case 1: dma.run.source -= seek; break;
|
||||
}
|
||||
|
||||
switch(channel.control.targetmode) {
|
||||
case 0: channel.target += seek; break;
|
||||
case 1: channel.target -= seek; break;
|
||||
case 3: channel.target += seek; break;
|
||||
switch(dma.control.targetmode) {
|
||||
case 0: dma.run.target += seek; break;
|
||||
case 1: dma.run.target -= seek; break;
|
||||
case 3: dma.run.target += seek; break;
|
||||
}
|
||||
} while(--length);
|
||||
if(channel.control.targetmode == 3) channel.target = channel.basetarget;
|
||||
} while(--dma.run.length);
|
||||
|
||||
channel.control.enable = false;
|
||||
if(channel.control.irq) regs.irq.flag.dma[n] = 1;
|
||||
if(dma.control.targetmode == 3) dma.run.target = dma.target;
|
||||
if(dma.control.repeat == 1) dma.run.length = dma.length;
|
||||
if(dma.control.repeat == 0) dma.active = false, dma.control.enable = false;
|
||||
}
|
||||
|
|
|
@ -3,9 +3,25 @@ uint8 CPU::read(uint32 addr) {
|
|||
|
||||
switch(addr) {
|
||||
|
||||
//DMA0CNT_H
|
||||
case 0x040000ba: return regs.dma[0].control >> 0;
|
||||
case 0x040000bb: return regs.dma[0].control >> 8;
|
||||
|
||||
//DMA1CNT_H
|
||||
case 0x040000c6: return regs.dma[1].control >> 0;
|
||||
case 0x040000c7: return regs.dma[1].control >> 8;
|
||||
|
||||
//DMA2CNT_H
|
||||
case 0x040000d2: return regs.dma[2].control >> 0;
|
||||
case 0x040000d3: return regs.dma[2].control >> 8;
|
||||
|
||||
//DMA3CNT_H
|
||||
case 0x040000de: return regs.dma[3].control >> 0;
|
||||
case 0x040000df: return regs.dma[3].control >> 8;
|
||||
|
||||
//TM0CNT_L
|
||||
case 0x04000100: return regs.timer[0].reload >> 0;
|
||||
case 0x04000101: return regs.timer[0].reload >> 8;
|
||||
case 0x04000100: return regs.timer[0].counter >> 0;
|
||||
case 0x04000101: return regs.timer[0].counter >> 8;
|
||||
|
||||
//TIM0CNT_H
|
||||
case 0x04000102: return regs.timer[0].control >> 0;
|
||||
|
@ -170,33 +186,34 @@ void CPU::write(uint32 addr, uint8 byte) {
|
|||
case 0x04000100: regs.timer[0].reload = (regs.timer[0].reload & 0xff00) | (byte << 0); return;
|
||||
case 0x04000101: regs.timer[0].reload = (regs.timer[0].reload & 0x00ff) | (byte << 8); return;
|
||||
|
||||
//TM0CNT_H
|
||||
case 0x04000102: regs.timer[0].control = (regs.timer[0].control & 0xff00) | (byte << 0); return;
|
||||
case 0x04000103: regs.timer[0].control = (regs.timer[0].control & 0x00ff) | (byte << 8); return;
|
||||
|
||||
//TM1CNT_L
|
||||
case 0x04000104: regs.timer[1].reload = (regs.timer[1].reload & 0xff00) | (byte << 0); return;
|
||||
case 0x04000105: regs.timer[1].reload = (regs.timer[1].reload & 0x00ff) | (byte << 8); return;
|
||||
|
||||
//TM1CNT_H
|
||||
case 0x04000106: regs.timer[1].control = (regs.timer[1].control & 0xff00) | (byte << 0); return;
|
||||
case 0x04000107: regs.timer[1].control = (regs.timer[1].control & 0x00ff) | (byte << 8); return;
|
||||
|
||||
//TM2CNT_L
|
||||
case 0x04000108: regs.timer[2].reload = (regs.timer[2].reload & 0xff00) | (byte << 0); return;
|
||||
case 0x04000109: regs.timer[2].reload = (regs.timer[2].reload & 0x00ff) | (byte << 8); return;
|
||||
|
||||
//TM2CNT_H
|
||||
case 0x0400010a: regs.timer[2].control = (regs.timer[2].control & 0xff00) | (byte << 0); return;
|
||||
case 0x0400010b: regs.timer[2].control = (regs.timer[2].control & 0x00ff) | (byte << 8); return;
|
||||
|
||||
//TM3CNT_L
|
||||
case 0x0400010c: regs.timer[3].reload = (regs.timer[3].reload & 0xff00) | (byte << 0); return;
|
||||
case 0x0400010d: regs.timer[3].reload = (regs.timer[3].reload & 0x00ff) | (byte << 8); return;
|
||||
|
||||
//TM0CNT_H
|
||||
//TM1CNT_H
|
||||
//TM2CNT_H
|
||||
//TM3CNT_H
|
||||
case 0x0400010e: regs.timer[3].control = (regs.timer[3].control & 0xff00) | (byte << 0); return;
|
||||
case 0x0400010f: regs.timer[3].control = (regs.timer[3].control & 0x00ff) | (byte << 8); return;
|
||||
case 0x04000102:
|
||||
case 0x04000106:
|
||||
case 0x0400010a:
|
||||
case 0x0400010e: {
|
||||
auto &timer = regs.timer[(addr >> 2) & 3];
|
||||
bool enable = timer.control.enable;
|
||||
if(timer.control.enable == 0 && enable == 1) {
|
||||
timer.counter = timer.reload;
|
||||
}
|
||||
timer.control = byte;
|
||||
return;
|
||||
}
|
||||
|
||||
//KEYCNT
|
||||
case 0x04000132: regs.keypad.control = (regs.keypad.control & 0xff00) | (byte << 0); return;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
CPU::Registers::DMA::Control::operator uint16() const {
|
||||
CPU::Registers::DMAControl::operator uint16() const {
|
||||
return (
|
||||
(targetmode << 5)
|
||||
| (sourcemode << 7)
|
||||
|
@ -11,7 +11,7 @@ CPU::Registers::DMA::Control::operator uint16() const {
|
|||
);
|
||||
}
|
||||
|
||||
uint16 CPU::Registers::DMA::Control::operator=(uint16 source) {
|
||||
uint16 CPU::Registers::DMAControl::operator=(uint16 source) {
|
||||
targetmode = source >> 5;
|
||||
sourcemode = source >> 7;
|
||||
repeat = source >> 9;
|
||||
|
@ -23,21 +23,21 @@ uint16 CPU::Registers::DMA::Control::operator=(uint16 source) {
|
|||
return operator uint16();
|
||||
}
|
||||
|
||||
CPU::Registers::TimerControl::operator uint16() const {
|
||||
CPU::Registers::TimerControl::operator uint8() const {
|
||||
return (
|
||||
(prescalar << 0)
|
||||
| (countup << 2)
|
||||
(frequency << 0)
|
||||
| (cascade << 2)
|
||||
| (irq << 6)
|
||||
| (enable << 7)
|
||||
);
|
||||
}
|
||||
|
||||
uint16 CPU::Registers::TimerControl::operator=(uint16 source) {
|
||||
prescalar = (source >> 0) & 3;
|
||||
countup = (source >> 2) & 1;
|
||||
irq = (source >> 6) & 1;
|
||||
enable = (source >> 7) & 1;
|
||||
return operator uint16();
|
||||
uint8 CPU::Registers::TimerControl::operator=(uint8 source) {
|
||||
frequency = source >> 0;
|
||||
cascade = source >> 2;
|
||||
irq = source >> 6;
|
||||
enable = source >> 7;
|
||||
return operator uint8();
|
||||
}
|
||||
|
||||
CPU::Registers::KeypadControl::operator uint16() const {
|
||||
|
|
|
@ -1,41 +1,53 @@
|
|||
struct Registers {
|
||||
struct DMAControl {
|
||||
uint2 targetmode;
|
||||
uint2 sourcemode;
|
||||
uint1 repeat;
|
||||
uint1 size;
|
||||
uint1 drq;
|
||||
uint2 timingmode;
|
||||
uint1 irq;
|
||||
uint1 enable;
|
||||
|
||||
operator uint16() const;
|
||||
uint16 operator=(uint16 source);
|
||||
DMAControl& operator=(const DMAControl&) = delete;
|
||||
};
|
||||
|
||||
struct DMA {
|
||||
uint32 source;
|
||||
uint32 target;
|
||||
uint16 length;
|
||||
struct Control {
|
||||
uint2 targetmode;
|
||||
uint2 sourcemode;
|
||||
uint1 repeat;
|
||||
uint1 size;
|
||||
uint1 drq;
|
||||
uint2 timingmode;
|
||||
uint1 irq;
|
||||
uint1 enable;
|
||||
|
||||
operator uint16() const;
|
||||
uint16 operator=(uint16 source);
|
||||
DMA& operator=(const DMA&) = delete;
|
||||
} control;
|
||||
DMAControl control;
|
||||
|
||||
//internal
|
||||
uint1 active;
|
||||
struct Run {
|
||||
uint32 target;
|
||||
uint32 source;
|
||||
uint32 length;
|
||||
} run;
|
||||
uint32 basetarget;
|
||||
} dma[4];
|
||||
|
||||
struct TimerControl {
|
||||
uint2 prescalar;
|
||||
bool countup;
|
||||
bool irq;
|
||||
bool enable;
|
||||
uint2 frequency;
|
||||
uint1 cascade;
|
||||
uint1 irq;
|
||||
uint1 enable;
|
||||
|
||||
operator uint16() const;
|
||||
uint16 operator=(uint16 source);
|
||||
operator uint8() const;
|
||||
uint8 operator=(uint8 source);
|
||||
TimerControl& operator=(const TimerControl&) = delete;
|
||||
};
|
||||
|
||||
struct Timer {
|
||||
uint16 counter;
|
||||
uint16 reload;
|
||||
TimerControl control;
|
||||
|
||||
//internal
|
||||
uint1 active;
|
||||
} timer[4];
|
||||
|
||||
struct KeypadControl {
|
||||
|
@ -122,4 +134,5 @@ struct Registers {
|
|||
|
||||
bool postboot;
|
||||
enum class Mode : unsigned { Normal, Halt, Stop } mode;
|
||||
unsigned clock;
|
||||
} regs;
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
void CPU::timer_tick() {
|
||||
for(unsigned n = 0; n < 4; n++) {
|
||||
if(regs.timer[n].control.cascade) continue;
|
||||
|
||||
static unsigned mask[] = { 0, 63, 255, 1023 };
|
||||
if((regs.clock & mask[regs.timer[n].control.frequency]) == 0) {
|
||||
timer_increment(n);
|
||||
}
|
||||
}
|
||||
|
||||
regs.clock++;
|
||||
}
|
||||
|
||||
void CPU::timer_increment(unsigned n) {
|
||||
if(regs.timer[n].control.enable == false) return;
|
||||
|
||||
if(++regs.timer[n].counter == 0) {
|
||||
if(regs.timer[n].control.irq) regs.irq.flag.timer[n] = 1;
|
||||
|
||||
regs.timer[n].counter = regs.timer[n].reload;
|
||||
if(n < 3 && regs.timer[n + 1].control.cascade) {
|
||||
timer_increment(n + 1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,28 +1,30 @@
|
|||
void PPU::render_backgrounds() {
|
||||
if(regs.control.bgmode == 0) {
|
||||
render_background_linear(0);
|
||||
render_background_linear(1);
|
||||
render_background_linear(2);
|
||||
switch(regs.control.bgmode) {
|
||||
case 0:
|
||||
render_background_linear(3);
|
||||
}
|
||||
|
||||
if(regs.control.bgmode == 1) {
|
||||
render_background_linear(0);
|
||||
render_background_linear(2);
|
||||
render_background_linear(1);
|
||||
//render_background_affine(2);
|
||||
}
|
||||
|
||||
if(regs.control.bgmode == 2) {
|
||||
//render_background_affine(2);
|
||||
//render_background_affine(3);
|
||||
render_background_linear(0);
|
||||
break;
|
||||
case 1:
|
||||
render_background_affine(2);
|
||||
render_background_linear(1);
|
||||
render_background_linear(0);
|
||||
break;
|
||||
case 2:
|
||||
render_background_affine(3);
|
||||
render_background_affine(2);
|
||||
break;
|
||||
case 3: case 4: case 5:
|
||||
render_background_bitmap(2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::render_background_linear(unsigned bgnumber) {
|
||||
for(unsigned n = 0; n < 240; n++) pixel[bgnumber][n].exists = false;
|
||||
if(regs.control.enablebg[bgnumber] == false) return;
|
||||
|
||||
auto &bg = regs.bg[bgnumber];
|
||||
|
||||
uint9 voffset = regs.vcounter + bg.voffset;
|
||||
uint9 hoffset = bg.hoffset;
|
||||
|
||||
|
@ -64,9 +66,77 @@ void PPU::render_background_linear(unsigned bgnumber) {
|
|||
|
||||
hoffset++;
|
||||
uint8 color = data[px++ ^ (tile.hflip ? 7 : 0)];
|
||||
if(color == 0) continue; //transparent
|
||||
|
||||
if(bg.control.colormode == 0) pixel[bgnumber][x] = { true, palette(tile.palette * 16 + color), bg.control.priority };
|
||||
if(bg.control.colormode == 1) pixel[bgnumber][x] = { true, palette(color), bg.control.priority };
|
||||
if(color) {
|
||||
if(bg.control.colormode == 0) layer[bg.control.priority][x] = { true, palette(tile.palette * 16 + color) };
|
||||
if(bg.control.colormode == 1) layer[bg.control.priority][x] = { true, palette(color) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::render_background_affine(unsigned bgnumber) {
|
||||
if(regs.control.enablebg[bgnumber] == false) return;
|
||||
auto &bg = regs.bg[bgnumber];
|
||||
|
||||
unsigned basemap = bg.control.screenbaseblock << 11;
|
||||
unsigned basechr = bg.control.characterbaseblock << 14;
|
||||
unsigned screensize = 16 << bg.control.screensize;
|
||||
unsigned screenwrap = (1 << (bg.control.affinewrap ? 7 + bg.control.screensize : 20)) - 1;
|
||||
|
||||
int28 fx = bg.lx;
|
||||
int28 fy = bg.ly;
|
||||
|
||||
for(unsigned x = 0; x < 240; x++) {
|
||||
unsigned cx = (fx >> 8) & screenwrap, tx = cx / 8, px = cx & 7;
|
||||
unsigned cy = (fy >> 8) & screenwrap, ty = cy / 8, py = cy & 7;
|
||||
|
||||
if(tx < screensize && ty < screensize) {
|
||||
uint8 character = vram[basemap + ty * screensize + tx];
|
||||
uint8 color = vram[basechr + (character * 64) + py * 8 + px];
|
||||
if(color) layer[bg.control.priority][x] = { true, palette(color) };
|
||||
}
|
||||
|
||||
fx += bg.pa;
|
||||
fy += bg.pc;
|
||||
}
|
||||
|
||||
bg.lx += bg.pb;
|
||||
bg.ly += bg.pd;
|
||||
}
|
||||
|
||||
void PPU::render_background_bitmap(unsigned bgnumber) {
|
||||
if(regs.control.enablebg[bgnumber] == false) return;
|
||||
auto &bg = regs.bg[bgnumber];
|
||||
|
||||
uint1 depth = regs.control.bgmode != 4; //0 = 8-bit (Mode 4), 1 = 15-bit (Mode 3, Mode 5)
|
||||
unsigned basemap = regs.control.bgmode == 3 ? 0 : 0xa000 * regs.control.frame;
|
||||
|
||||
unsigned width = regs.control.bgmode == 5 ? 160 : 240;
|
||||
unsigned height = regs.control.bgmode == 5 ? 128 : 160;
|
||||
unsigned size = depth ? Half : Byte;
|
||||
|
||||
int28 fx = bg.lx;
|
||||
int28 fy = bg.ly;
|
||||
|
||||
for(unsigned x = 0; x < 240; x++) {
|
||||
unsigned px = fx >> 8;
|
||||
unsigned py = fy >> 8;
|
||||
|
||||
if(px < width && py < height) {
|
||||
unsigned offset = py * width + px;
|
||||
unsigned color = vram.read(basemap + (offset << depth), size);
|
||||
|
||||
if(depth || color) { //8bpp color 0 is transparent; 15bpp color is always opaque
|
||||
if(depth == 0) color = palette(color);
|
||||
if(depth == 1) color = color & 0x7fff;
|
||||
layer[bg.control.priority][x] = { true, color };
|
||||
}
|
||||
}
|
||||
|
||||
fx += bg.pa;
|
||||
fy += bg.pc;
|
||||
}
|
||||
|
||||
bg.lx += bg.pb;
|
||||
bg.ly += bg.pd;
|
||||
}
|
||||
|
|
|
@ -127,27 +127,27 @@ void PPU::write(uint32 addr, uint8 byte) {
|
|||
|
||||
//BG2PC
|
||||
case 0x04000024: regs.bg[2].pc = (regs.bg[2].pc & 0xff00) | (byte << 0); return;
|
||||
case 0x04000025: regs.bg[2].pc = (regs.bg[2].pc & 0x00ff) | (byte << 0); return;
|
||||
case 0x04000025: regs.bg[2].pc = (regs.bg[2].pc & 0x00ff) | (byte << 8); return;
|
||||
|
||||
//BG2PD
|
||||
case 0x04000026: regs.bg[2].pd = (regs.bg[2].pd & 0xff00) | (byte << 0); return;
|
||||
case 0x04000027: regs.bg[2].pd = (regs.bg[2].pd & 0x00ff) | (byte << 8); return;
|
||||
|
||||
//BG2X_L
|
||||
case 0x04000028: regs.bg[2].x = (regs.bg[2].x & 0xffffff00) | (byte << 0); return;
|
||||
case 0x04000029: regs.bg[2].x = (regs.bg[2].x & 0xffff00ff) | (byte << 8); return;
|
||||
case 0x04000028: regs.bg[2].lx = regs.bg[2].x = (regs.bg[2].x & 0xffffff00) | (byte << 0); return;
|
||||
case 0x04000029: regs.bg[2].lx = regs.bg[2].x = (regs.bg[2].x & 0xffff00ff) | (byte << 8); return;
|
||||
|
||||
//BG2X_H
|
||||
case 0x0400002a: regs.bg[2].x = (regs.bg[2].x & 0xff00ffff) | (byte << 16); return;
|
||||
case 0x0400002b: regs.bg[2].x = (regs.bg[2].x & 0x00ffffff) | (byte << 24); return;
|
||||
case 0x0400002a: regs.bg[2].lx = regs.bg[2].x = (regs.bg[2].x & 0xff00ffff) | (byte << 16); return;
|
||||
case 0x0400002b: regs.bg[2].lx = regs.bg[2].x = (regs.bg[2].x & 0x00ffffff) | (byte << 24); return;
|
||||
|
||||
//BG2Y_L
|
||||
case 0x0400002c: regs.bg[2].y = (regs.bg[2].y & 0xffffff00) | (byte << 0); return;
|
||||
case 0x0400002d: regs.bg[2].y = (regs.bg[2].y & 0xffff00ff) | (byte << 8); return;
|
||||
case 0x0400002c: regs.bg[2].ly = regs.bg[2].y = (regs.bg[2].y & 0xffffff00) | (byte << 0); return;
|
||||
case 0x0400002d: regs.bg[2].ly = regs.bg[2].y = (regs.bg[2].y & 0xffff00ff) | (byte << 8); return;
|
||||
|
||||
//BG2Y_H
|
||||
case 0x0400002e: regs.bg[2].y = (regs.bg[2].y & 0xff00ffff) | (byte << 16); return;
|
||||
case 0x0400002f: regs.bg[2].y = (regs.bg[2].y & 0x00ffffff) | (byte << 24); return;
|
||||
case 0x0400002e: regs.bg[2].ly = regs.bg[2].y = (regs.bg[2].y & 0xff00ffff) | (byte << 16); return;
|
||||
case 0x0400002f: regs.bg[2].ly = regs.bg[2].y = (regs.bg[2].y & 0x00ffffff) | (byte << 24); return;
|
||||
|
||||
//BG3PA
|
||||
case 0x04000030: regs.bg[3].pa = (regs.bg[3].pa & 0xff00) | (byte << 0); return;
|
||||
|
@ -166,20 +166,20 @@ void PPU::write(uint32 addr, uint8 byte) {
|
|||
case 0x04000037: regs.bg[3].pd = (regs.bg[3].pd & 0x00ff) | (byte << 8); return;
|
||||
|
||||
//BG3X_L
|
||||
case 0x04000038: regs.bg[3].x = (regs.bg[3].x & 0xffffff00) | (byte << 0); return;
|
||||
case 0x04000039: regs.bg[3].x = (regs.bg[3].x & 0xffff00ff) | (byte << 8); return;
|
||||
case 0x04000038: regs.bg[3].lx = regs.bg[3].x = (regs.bg[3].x & 0xffffff00) | (byte << 0); return;
|
||||
case 0x04000039: regs.bg[3].lx = regs.bg[3].x = (regs.bg[3].x & 0xffff00ff) | (byte << 8); return;
|
||||
|
||||
//BG3X_H
|
||||
case 0x0400003a: regs.bg[3].x = (regs.bg[3].x & 0xff00ffff) | (byte << 16); return;
|
||||
case 0x0400003b: regs.bg[3].x = (regs.bg[3].x & 0x00ffffff) | (byte << 24); return;
|
||||
case 0x0400003a: regs.bg[3].lx = regs.bg[3].x = (regs.bg[3].x & 0xff00ffff) | (byte << 16); return;
|
||||
case 0x0400003b: regs.bg[3].lx = regs.bg[3].x = (regs.bg[3].x & 0x00ffffff) | (byte << 24); return;
|
||||
|
||||
//BG3Y_L
|
||||
case 0x0400003c: regs.bg[3].y = (regs.bg[3].y & 0xffffff00) | (byte << 0); return;
|
||||
case 0x0400003d: regs.bg[3].y = (regs.bg[3].y & 0xffff00ff) | (byte << 8); return;
|
||||
case 0x0400003c: regs.bg[3].ly = regs.bg[3].y = (regs.bg[3].y & 0xffffff00) | (byte << 0); return;
|
||||
case 0x0400003d: regs.bg[3].ly = regs.bg[3].y = (regs.bg[3].y & 0xffff00ff) | (byte << 8); return;
|
||||
|
||||
//BG3Y_H
|
||||
case 0x0400003e: regs.bg[3].y = (regs.bg[3].y & 0xff00ffff) | (byte << 16); return;
|
||||
case 0x0400003f: regs.bg[3].y = (regs.bg[3].y & 0x00ffffff) | (byte << 24); return;
|
||||
case 0x0400003e: regs.bg[3].ly = regs.bg[3].y = (regs.bg[3].y & 0xff00ffff) | (byte << 16); return;
|
||||
case 0x0400003f: regs.bg[3].ly = regs.bg[3].y = (regs.bg[3].y & 0x00ffffff) | (byte << 24); return;
|
||||
|
||||
//WIN0H
|
||||
case 0x04000040: regs.window[0].x2 = byte; return;
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
void PPU::render_objects() {
|
||||
for(unsigned n = 0; n < 240; n++) pixel[4][n].exists = false;
|
||||
if(regs.control.enableobj == false) return;
|
||||
|
||||
for(unsigned n = 0; n < 128; n++) {
|
||||
for(signed n = 127; n >= 0; n--) {
|
||||
auto &obj = object[n];
|
||||
uint16 attr0 = oam.read(n * 8 + 0, Half);
|
||||
uint16 attr1 = oam.read(n * 8 + 2, Half);
|
||||
|
@ -43,25 +42,25 @@ void PPU::render_objects() {
|
|||
obj.width = widths [obj.shape * 4 + obj.size];
|
||||
obj.height = heights[obj.shape * 4 + obj.size];
|
||||
|
||||
if(regs.vcounter < obj.y) continue;
|
||||
if(regs.vcounter >= (obj.y + obj.height) & 255) continue;
|
||||
uint8 py = regs.vcounter - obj.y;
|
||||
if(py >= obj.height << obj.affinesize) continue;
|
||||
if(obj.affine == 0 && obj.affinesize == 1) continue; //hidden
|
||||
|
||||
if(obj.affine == 0 && obj.affinesize == 1) continue; //invalid mode
|
||||
if(obj.affine == 0) render_object_linear(obj);
|
||||
if(obj.affine == 1) render_object_affine(obj);
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::render_object_linear(Object &obj) {
|
||||
unsigned py = regs.vcounter - obj.y;
|
||||
uint8 py = regs.vcounter - obj.y;
|
||||
if(obj.vflip) py ^= obj.height - 1;
|
||||
|
||||
unsigned rowsize = regs.control.objmapping == 0 ? 32 >> obj.colors : obj.width / 8;
|
||||
unsigned baseaddr = 0x10000 + obj.character * 32;
|
||||
uint9 sx = obj.x;
|
||||
|
||||
for(unsigned x = 0; x < obj.width; x++) {
|
||||
if(sx++ >= 240) continue;
|
||||
for(unsigned x = 0; x < obj.width; x++, sx++) {
|
||||
if(sx >= 240) continue;
|
||||
unsigned px = x;
|
||||
if(obj.hflip) px ^= obj.width - 1;
|
||||
|
||||
|
@ -71,12 +70,56 @@ void PPU::render_object_linear(Object &obj) {
|
|||
|
||||
uint8 color = vram[offset];
|
||||
if(obj.colors == 0) color = (px & 1) ? color >> 4 : color & 15;
|
||||
if(color == 0) continue; //transparent
|
||||
|
||||
if(obj.colors == 0) pixel[4][sx] = { true, palette(256 + obj.palette * 16 + color), obj.priority };
|
||||
if(obj.colors == 1) pixel[4][sx] = { true, palette(256 + color), obj.priority };
|
||||
if(color) {
|
||||
if(obj.colors == 0) layer[obj.priority][sx] = { true, palette(256 + obj.palette * 16 + color) };
|
||||
if(obj.colors == 1) layer[obj.priority][sx] = { true, palette(256 + color) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::render_object_affine(Object &obj) {
|
||||
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 = oam.read(obj.affineparam * 32 + 0x06, Half);
|
||||
int16 pb = oam.read(obj.affineparam * 32 + 0x0e, Half);
|
||||
int16 pc = oam.read(obj.affineparam * 32 + 0x16, Half);
|
||||
int16 pd = oam.read(obj.affineparam * 32 + 0x1e, Half);
|
||||
|
||||
//center-of-sprite coordinates
|
||||
int16 centerx = obj.width / 2;
|
||||
int16 centery = obj.height / 2;
|
||||
|
||||
//origin coordinates (top-left of sprite)
|
||||
int28 originx = -(centerx << obj.affinesize);
|
||||
int28 originy = -(centery << obj.affinesize) + py;
|
||||
|
||||
int28 fx = originx * pa + originy * pb;
|
||||
int28 fy = originx * pc + originy * pd;
|
||||
|
||||
for(unsigned x = 0; x < (obj.width << obj.affinesize); x++, sx++) {
|
||||
unsigned px = (fx >> 8) + centerx;
|
||||
unsigned py = (fy >> 8) + centery;
|
||||
|
||||
if(sx < 240 && px < obj.width && py < obj.height) {
|
||||
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) {
|
||||
if(obj.colors == 0) layer[obj.priority][sx] = { true, palette(256 + obj.palette * 16 + color) };
|
||||
if(obj.colors == 1) layer[obj.priority][sx] = { true, palette(256 + color) };
|
||||
}
|
||||
}
|
||||
|
||||
fx += pa;
|
||||
fy += pc;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,6 +54,8 @@ void PPU::power() {
|
|||
bg.pd = 0;
|
||||
bg.x = 0;
|
||||
bg.y = 0;
|
||||
bg.lx = 0;
|
||||
bg.ly = 0;
|
||||
}
|
||||
for(auto &w : regs.window) {
|
||||
w.x1 = 0;
|
||||
|
@ -82,6 +84,12 @@ void PPU::scanline() {
|
|||
|
||||
if(regs.vcounter == 0) {
|
||||
frame();
|
||||
|
||||
regs.bg[2].lx = regs.bg[2].x;
|
||||
regs.bg[2].ly = regs.bg[2].y;
|
||||
|
||||
regs.bg[3].lx = regs.bg[3].x;
|
||||
regs.bg[3].ly = regs.bg[3].y;
|
||||
}
|
||||
|
||||
if(regs.vcounter == 160) {
|
||||
|
@ -94,21 +102,28 @@ void PPU::scanline() {
|
|||
}
|
||||
|
||||
if(regs.vcounter < 160) {
|
||||
for(unsigned x = 0; x < 240; x++) {
|
||||
layer[0][x].exists = false;
|
||||
layer[1][x].exists = false;
|
||||
layer[2][x].exists = false;
|
||||
layer[3][x].exists = false;
|
||||
}
|
||||
|
||||
render_backgrounds();
|
||||
render_objects();
|
||||
render_screen();
|
||||
}
|
||||
|
||||
step(1024);
|
||||
step(960);
|
||||
regs.status.hblank = 1;
|
||||
if(regs.status.irqhblank) cpu.regs.irq.flag.hblank = 1;
|
||||
cpu.pending.dma.hblank = true;
|
||||
|
||||
step(200);
|
||||
step(240);
|
||||
regs.status.hblank = 0;
|
||||
cpu.pending.dma.hdma = true;
|
||||
if(regs.vcounter < 160) cpu.pending.dma.hdma = true;
|
||||
|
||||
step(8);
|
||||
step(32);
|
||||
if(++regs.vcounter == 228) regs.vcounter = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@ struct PPU : Thread, MMIO {
|
|||
|
||||
void render_backgrounds();
|
||||
void render_background_linear(unsigned bgnumber);
|
||||
void render_background_affine(unsigned bgnumber);
|
||||
void render_background_bitmap(unsigned bgnumber);
|
||||
|
||||
void render_objects();
|
||||
void render_object_linear(Object&);
|
||||
|
|
|
@ -65,6 +65,7 @@ PPU::Registers::BackgroundControl::operator uint16() const {
|
|||
| (mosaic << 6)
|
||||
| (colormode << 7)
|
||||
| (screenbaseblock << 8)
|
||||
| (affinewrap << 13)
|
||||
| (screensize << 14)
|
||||
);
|
||||
}
|
||||
|
@ -75,6 +76,7 @@ uint16 PPU::Registers::BackgroundControl::operator=(uint16 source) {
|
|||
mosaic = source >> 6;
|
||||
colormode = source >> 7;
|
||||
screenbaseblock = source >> 8;
|
||||
affinewrap = source >> 13;
|
||||
screensize = source >> 14;
|
||||
return operator uint16();
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ struct Registers {
|
|||
uint1 mosaic;
|
||||
uint1 colormode;
|
||||
uint5 screenbaseblock;
|
||||
uint1 affinewrap; //BG2,3 only
|
||||
uint2 screensize;
|
||||
|
||||
operator uint16() const;
|
||||
|
@ -53,8 +54,11 @@ struct Registers {
|
|||
uint9 voffset;
|
||||
|
||||
//BG2,3 only
|
||||
uint16 pa, pb, pc, pd;
|
||||
uint28 x, y;
|
||||
int16 pa, pb, pc, pd;
|
||||
int28 x, y;
|
||||
|
||||
//internal
|
||||
int28 lx, ly;
|
||||
} bg[4];
|
||||
|
||||
struct WindowFlags {
|
||||
|
|
|
@ -10,13 +10,10 @@ void PPU::render_screen() {
|
|||
|
||||
for(unsigned x = 0; x < 240; x++) {
|
||||
uint15 color = palette(0) & 0x7fff;
|
||||
for(signed p = 3; p >= 0; p--) {
|
||||
if(pixel[3][x].exists && pixel[3][x].priority == p) color = pixel[3][x].color;
|
||||
if(pixel[2][x].exists && pixel[2][x].priority == p) color = pixel[2][x].color;
|
||||
if(pixel[1][x].exists && pixel[1][x].priority == p) color = pixel[1][x].color;
|
||||
if(pixel[0][x].exists && pixel[0][x].priority == p) color = pixel[0][x].color;
|
||||
if(pixel[4][x].exists && pixel[4][x].priority == p) color = pixel[4][x].color;
|
||||
}
|
||||
if(layer[3][x].exists) color = layer[3][x].color;
|
||||
if(layer[2][x].exists) color = layer[2][x].color;
|
||||
if(layer[1][x].exists) color = layer[1][x].color;
|
||||
if(layer[0][x].exists) color = layer[0][x].color;
|
||||
line[x] = color;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
struct Pixel {
|
||||
bool exists;
|
||||
uint15 color;
|
||||
uint2 priority;
|
||||
} pixel[5][256];
|
||||
} layer[4][240];
|
||||
|
||||
struct Object {
|
||||
uint8 y;
|
||||
|
|
|
@ -23,11 +23,6 @@ void ARM::power() {
|
|||
}
|
||||
|
||||
void ARM::exec() {
|
||||
if(processor.irqline && cpsr().i == 0) {
|
||||
vector(0x00000018, Processor::Mode::IRQ);
|
||||
r(14) += 4;
|
||||
}
|
||||
|
||||
cpsr().t ? thumb_step() : arm_step();
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,11 @@ void ARM::arm_step() {
|
|||
pipeline_step();
|
||||
step(2);
|
||||
|
||||
if(processor.irqline && cpsr().i == 0) {
|
||||
vector(0x00000018, Processor::Mode::IRQ);
|
||||
return;
|
||||
}
|
||||
|
||||
instructions++;
|
||||
if(pipeline.execute.address == 0x08000000) print("Entry Point\n");
|
||||
if(trace) {
|
||||
|
|
|
@ -15,6 +15,12 @@ void ARM::thumb_step() {
|
|||
pipeline_step();
|
||||
step(1);
|
||||
|
||||
if(processor.irqline && cpsr().i == 0) {
|
||||
vector(0x00000018, Processor::Mode::IRQ);
|
||||
r(14) += 2;
|
||||
return;
|
||||
}
|
||||
|
||||
instructions++;
|
||||
if(trace) {
|
||||
print(disassemble_registers(), "\n");
|
||||
|
|
Loading…
Reference in New Issue