bsnes/higan/processor/hg51b/hg51b.cpp

125 lines
3.1 KiB
C++

#include <processor/processor.hpp>
#include "hg51b.hpp"
namespace Processor {
#include "registers.cpp"
#include "instruction.cpp"
#include "instructions.cpp"
#include "serialization.cpp"
auto HG51B::lock() -> void {
io.lock = 1;
}
auto HG51B::halt() -> void {
io.halt = 1;
}
auto HG51B::wait(uint24 address) -> uint {
if(isROM(address)) return 1 + io.wait.rom;
if(isRAM(address)) return 1 + io.wait.ram;
return 1;
}
auto HG51B::main() -> void {
if(io.lock) return step(1);
if(io.suspend.enable) return suspend();
if(io.cache.enable) return cache(), void();
if(io.dma.enable) return dma();
if(io.halt) return step(1);
return execute();
}
auto HG51B::step(uint clocks) -> void {
if(io.bus.enable) {
if(io.bus.pending > clocks) {
io.bus.pending -= clocks;
} else {
io.bus.enable = 0;
io.bus.pending = 0;
if(io.bus.reading) io.bus.reading = 0, r.mdr = read(io.bus.address);
if(io.bus.writing) io.bus.writing = 0, write(io.bus.address, r.mdr);
}
}
}
auto HG51B::execute() -> void {
if(!cache()) return halt();
auto opcode = programRAM[io.cache.page][r.pc];
advance();
step(1);
instructionTable[opcode]();
}
auto HG51B::advance() -> void {
if(++r.pc == 0) {
if(io.cache.page == 1) return halt();
io.cache.page = 1;
if(io.cache.lock[io.cache.page]) return halt();
r.pb = r.p;
if(!cache()) return halt();
}
}
auto HG51B::suspend() -> void {
if(!io.suspend.duration) return step(1); //indefinite
step(io.suspend.duration);
io.suspend.duration = 0;
io.suspend.enable = 0;
}
auto HG51B::cache() -> bool {
uint24 address = io.cache.base + r.pb * 512;
//try to use the current page ...
if(io.cache.address[io.cache.page] == address) return io.cache.enable = 0, true;
//if it's not valid, try to use the other page ...
io.cache.page ^= 1;
if(io.cache.address[io.cache.page] == address) return io.cache.enable = 0, true;
//if it's not valid, try to load into the other page ...
if(io.cache.lock[io.cache.page]) io.cache.page ^= 1;
//if it's locked, try to load into the first page ...
if(io.cache.lock[io.cache.page]) return io.cache.enable = 0, false;
io.cache.address[io.cache.page] = address;
for(uint offset : range(256)) {
step(wait(address)); programRAM[io.cache.page][offset].byte(0) = read(address++);
step(wait(address)); programRAM[io.cache.page][offset].byte(1) = read(address++);
}
return io.cache.enable = 0, true;
}
auto HG51B::dma() -> void {
for(uint offset : range(io.dma.length)) {
uint24 source = io.dma.source + offset;
uint24 target = io.dma.target + offset;
if(isROM(source) && isROM(target)) return lock();
if(isRAM(source) && isRAM(target)) return lock();
step(wait(source));
auto data = read(source);
step(wait(target));
write(target, data);
}
io.dma.enable = 0;
}
auto HG51B::running() const -> bool {
return io.cache.enable || io.dma.enable || io.bus.pending || !io.halt;
}
auto HG51B::busy() const -> bool {
return io.cache.enable || io.dma.enable || io.bus.pending;
}
auto HG51B::power() -> void {
r = {};
io = {};
}
}