mirror of https://github.com/bsnes-emu/bsnes.git
Update to v087r08 release.
byuu says: Added some more ARM opcodes, hooked up MMIO. Bind it with mmio[(addr 000-3ff)] = this; inside CPU/PPU/APU, goes to read(), write(). Also moved the Hitachi HG51B core to processor/, and split it apart from the snes/chip/hitachidsp implementation. This one actually worked really well. Very clean split between MMIO/DMA and the processor core. I may move a more generic DMA function inside the core, not sure yet. I still believe the HG51B169 to be a variant of the HG51BS family, but given they're meant to be incredibly flexible microcontrollers, it's possible that each variant gets its own instruction set. So, who knows. We'll worry about it if we ever find another HG51B DSP, I guess. GBA BIOS is constantly reading from 04000300, but it never writes. If I return prng()&1, I can get it to proceed until it hits a bad opcode (stc opcode, which the GBA lacks a coprocessor so ... bad codepath.) Without it, it just reads that register forever and keeps resetting the system, or something ... I guess we're going to have to try and get ARMwrestler working, because the BIOS seems to need too much emulation code to do anything at all.
This commit is contained in:
parent
ec939065bd
commit
395e5a5639
|
@ -14,7 +14,7 @@ target := ui
|
|||
c := $(compiler) -std=gnu99
|
||||
cpp := $(subst cc,++,$(compiler)) -std=gnu++0x
|
||||
flags := -I. -march=native -O3 -fomit-frame-pointer
|
||||
link :=
|
||||
link := -s
|
||||
objects := libco
|
||||
|
||||
# profile-guided optimization mode
|
||||
|
@ -30,11 +30,11 @@ endif
|
|||
|
||||
# platform
|
||||
ifeq ($(platform),x)
|
||||
link += -s -ldl -lX11 -lXext
|
||||
link += -ldl -lX11 -lXext
|
||||
else ifeq ($(platform),osx)
|
||||
else ifeq ($(platform),win)
|
||||
link += $(if $(findstring console,$(options)),-mconsole,-mwindows)
|
||||
link += -mthreads -s -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32 -lole32
|
||||
link += -mthreads -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32 -lole32
|
||||
link += -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc
|
||||
else
|
||||
unknown_platform: help;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef BASE_HPP
|
||||
#define BASE_HPP
|
||||
|
||||
static const char Version[] = "087.07";
|
||||
static const char Version[] = "087.08";
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/algorithm.hpp>
|
||||
|
|
|
@ -18,6 +18,13 @@ void APU::step(unsigned clocks) {
|
|||
if(clock >= 0) co_switch(cpu.thread);
|
||||
}
|
||||
|
||||
uint32 APU::read(uint32 addr, uint32 size) {
|
||||
return 0u;
|
||||
}
|
||||
|
||||
void APU::write(uint32 addr, uint32 size, uint32 word) {
|
||||
}
|
||||
|
||||
void APU::power() {
|
||||
create(APU::Enter, 16777216);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
struct APU : Thread {
|
||||
struct APU : Thread, Memory {
|
||||
static void Enter();
|
||||
void enter();
|
||||
void step(unsigned clocks);
|
||||
|
||||
uint32 read(uint32 addr, uint32 size);
|
||||
void write(uint32 addr, uint32 size, uint32 word);
|
||||
void power();
|
||||
};
|
||||
|
||||
|
|
|
@ -9,6 +9,9 @@ bool Cartridge::load(const string &markup, const uint8_t *data, unsigned size) {
|
|||
cartridge.rom.data = new uint8[cartridge.rom.size = size];
|
||||
memcpy(cartridge.rom.data, data, size);
|
||||
|
||||
if(cartridge.ram.data) delete[] cartridge.ram.data;
|
||||
cartridge.ram.data = new uint8[cartridge.ram.size = 64 * 1024]();
|
||||
|
||||
sha256 = nall::sha256(cartridge.rom.data, cartridge.rom.size);
|
||||
|
||||
return loaded = true;
|
||||
|
|
|
@ -9,6 +9,8 @@ void CPU::Enter() { cpu.enter(); }
|
|||
void CPU::enter() {
|
||||
while(true) {
|
||||
if(exception) {
|
||||
print(cpsr().t ? disassemble_thumb_instruction(pipeline.execute.address)
|
||||
: disassemble_arm_instruction(pipeline.execute.address), "\n");
|
||||
print(disassemble_registers(), "\n");
|
||||
while(true) step(frequency);
|
||||
}
|
||||
|
@ -38,13 +40,26 @@ void CPU::power() {
|
|||
create(CPU::Enter, 16777216);
|
||||
|
||||
ARM::power();
|
||||
for(unsigned n = 0; n < iram.size; n++) iram.data[n] = 0;
|
||||
for(unsigned n = 0; n < eram.size; n++) eram.data[n] = 0;
|
||||
for(unsigned n = 0; n < iwram.size; n++) iwram.data[n] = 0;
|
||||
for(unsigned n = 0; n < ewram.size; n++) ewram.data[n] = 0;
|
||||
|
||||
bus.mmio[0x0300] = this;
|
||||
bus.mmio[0x0301] = this;
|
||||
bus.mmio[0x0302] = this;
|
||||
bus.mmio[0x0303] = this;
|
||||
}
|
||||
|
||||
uint32 CPU::read(uint32 addr, uint32 size) {
|
||||
if(addr == 0x04000300) return prng() & 1;
|
||||
return 0u;
|
||||
}
|
||||
|
||||
void CPU::write(uint32 addr, uint32 size, uint32 word) {
|
||||
}
|
||||
|
||||
CPU::CPU() {
|
||||
iram.data = new uint8[iram.size = 32 * 1024];
|
||||
eram.data = new uint8[eram.size = 256 * 1024];
|
||||
iwram.data = new uint8[iwram.size = 32 * 1024];
|
||||
ewram.data = new uint8[ewram.size = 256 * 1024];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
struct CPU : Processor::ARM, Thread {
|
||||
StaticMemory iram;
|
||||
StaticMemory eram;
|
||||
struct CPU : Processor::ARM, Thread, Memory {
|
||||
StaticMemory iwram;
|
||||
StaticMemory ewram;
|
||||
|
||||
static void Enter();
|
||||
void enter();
|
||||
|
@ -10,6 +10,9 @@ struct CPU : Processor::ARM, Thread {
|
|||
|
||||
void power();
|
||||
|
||||
uint32 read(uint32 addr, uint32 size);
|
||||
void write(uint32 addr, uint32 size, uint32 word);
|
||||
|
||||
CPU();
|
||||
};
|
||||
|
||||
|
|
|
@ -4,6 +4,13 @@ namespace GBA {
|
|||
|
||||
Bus bus;
|
||||
|
||||
struct UnmappedMemory : Memory {
|
||||
uint32 read(uint32 addr, uint32 size) { return 0u; }
|
||||
void write(uint32 addr, uint32 size, uint32 word) {}
|
||||
};
|
||||
|
||||
static UnmappedMemory unmappedMemory;
|
||||
|
||||
uint32 StaticMemory::read(uint32 addr, uint32 size) {
|
||||
uint32 word = 0;
|
||||
|
||||
|
@ -63,9 +70,9 @@ uint32 Bus::read(uint32 addr, uint32 size) {
|
|||
switch(addr & 0x0f000000) {
|
||||
case 0x00000000: return system.bios.read(addr & 0x3fff, size);
|
||||
case 0x01000000: return system.bios.read(addr & 0x3fff, size);
|
||||
case 0x02000000: return cpu.eram.read(addr & 0x3ffff, size);
|
||||
case 0x03000000: return cpu.iram.read(addr & 0x7fff, size);
|
||||
case 0x04000000: return 0u; //MMIO [0x400]
|
||||
case 0x02000000: return cpu.ewram.read(addr & 0x3ffff, size);
|
||||
case 0x03000000: return cpu.iwram.read(addr & 0x7fff, size);
|
||||
case 0x04000000: return mmio[addr & 0x3ff]->read(addr, size);
|
||||
case 0x05000000: return ppu.pram.read(addr & 0x3ff, size);
|
||||
case 0x06000000: return ppu.vram.read(addr & 0x10000 ? (0x10000 + (addr & 0x7fff)) : (addr & 0xffff), size);
|
||||
case 0x07000000: return ppu.oam.read(addr & 0x3ff, size);
|
||||
|
@ -84,9 +91,9 @@ void Bus::write(uint32 addr, uint32 size, uint32 word) {
|
|||
switch(addr & 0x0f000000) {
|
||||
case 0x00000000: return;
|
||||
case 0x01000000: return;
|
||||
case 0x02000000: return cpu.eram.write(addr & 0x3ffff, size, word);
|
||||
case 0x03000000: return cpu.iram.write(addr & 0x7fff, size, word);
|
||||
case 0x04000000: return; //MMIO [0x400]
|
||||
case 0x02000000: return cpu.ewram.write(addr & 0x3ffff, size, word);
|
||||
case 0x03000000: return cpu.iwram.write(addr & 0x7fff, size, word);
|
||||
case 0x04000000: return mmio[addr & 0x3ff]->write(addr, size, word);
|
||||
case 0x05000000: return ppu.pram.write(addr & 0x3ff, size, word);
|
||||
case 0x06000000: return ppu.vram.write(addr & 0x10000 ? (0x10000 + (addr & 0x7fff)) : (addr & 0xffff), size, word);
|
||||
case 0x07000000: return ppu.oam.write(addr & 0x3ff, size, word);
|
||||
|
@ -101,4 +108,8 @@ void Bus::write(uint32 addr, uint32 size, uint32 word) {
|
|||
}
|
||||
}
|
||||
|
||||
void Bus::power() {
|
||||
for(unsigned n = 0; n < 0x400; n++) mmio[n] = &unmappedMemory;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ struct Memory {
|
|||
virtual void write(uint32 addr, uint32 size, uint32 word) = 0;
|
||||
};
|
||||
|
||||
struct StaticMemory {
|
||||
struct StaticMemory : Memory {
|
||||
uint8_t *data;
|
||||
unsigned size;
|
||||
|
||||
|
@ -14,8 +14,11 @@ struct StaticMemory {
|
|||
};
|
||||
|
||||
struct Bus : Memory {
|
||||
Memory *mmio[0x400];
|
||||
|
||||
uint32 read(uint32 addr, uint32 size);
|
||||
void write(uint32 addr, uint32 size, uint32 word);
|
||||
void power();
|
||||
};
|
||||
|
||||
extern Bus bus;
|
||||
|
|
|
@ -56,6 +56,13 @@ void PPU::frame() {
|
|||
scheduler.exit(Scheduler::ExitReason::FrameEvent);
|
||||
}
|
||||
|
||||
uint32 PPU::read(uint32 addr, uint32 size) {
|
||||
return 0u;
|
||||
}
|
||||
|
||||
void PPU::write(uint32 addr, uint32 size, uint32 word) {
|
||||
}
|
||||
|
||||
PPU::PPU() {
|
||||
vram.data = new uint8[vram.size = 96 * 1024];
|
||||
oam.data = new uint8[oam.size = 1024];
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
struct PPU : Thread {
|
||||
struct PPU : Thread, Memory {
|
||||
StaticMemory vram;
|
||||
StaticMemory oam;
|
||||
StaticMemory pram;
|
||||
|
@ -10,6 +10,9 @@ struct PPU : Thread {
|
|||
void power();
|
||||
void frame();
|
||||
|
||||
uint32 read(uint32 addr, uint32 size);
|
||||
void write(uint32 addr, uint32 size, uint32 word);
|
||||
|
||||
PPU();
|
||||
};
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ void System::term() {
|
|||
}
|
||||
|
||||
void System::power() {
|
||||
bus.power();
|
||||
cpu.power();
|
||||
ppu.power();
|
||||
apu.power();
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
processor_objects :=
|
||||
processor_objects += $(if $(findstring arm,$(processors)),processor-arm)
|
||||
processor_objects += $(if $(findstring hg51b,$(processors)),processor-hg51b)
|
||||
objects += $(processor_objects)
|
||||
|
||||
processor := processor
|
||||
obj/processor-arm.o: $(processor)/arm/arm.cpp $(call rwildcard,$(processor)/arm)
|
||||
obj/processor-arm.o: $(processor)/arm/arm.cpp $(call rwildcard,$(processor)/arm)
|
||||
obj/processor-hg51b.o: $(processor)/hg51b/hg51b.cpp $(call rwildcard,$(processor)/hg51b)
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace Processor {
|
|||
|
||||
void ARM::power() {
|
||||
processor.power();
|
||||
vector(0x00000000, Processor::Mode::SVC);
|
||||
pipeline.reload = true;
|
||||
exception = false;
|
||||
r(15).modify = [&] {
|
||||
|
@ -18,6 +19,17 @@ void ARM::power() {
|
|||
};
|
||||
}
|
||||
|
||||
void ARM::vector(uint32 addr, Processor::Mode mode) {
|
||||
auto psr = cpsr();
|
||||
processor.setMode(mode);
|
||||
spsr() = psr;
|
||||
cpsr().i = 1;
|
||||
cpsr().f = mode == Processor::Mode::FIQ;
|
||||
cpsr().t = 0;
|
||||
r(14) = pipeline.decode.address;
|
||||
r(15) = addr;
|
||||
}
|
||||
|
||||
void ARM::serialize(serializer &s) {
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
namespace Processor {
|
||||
|
||||
//ARMv3, ARMv4TM
|
||||
|
||||
struct ARM {
|
||||
enum : unsigned { Byte = 8, Half = 16, Word = 32 };
|
||||
#include "registers.hpp"
|
||||
|
@ -14,6 +16,8 @@ struct ARM {
|
|||
virtual void bus_write(uint32 addr, uint32 size, uint32 word) = 0;
|
||||
|
||||
void power();
|
||||
void vector(uint32 addr, Processor::Mode mode);
|
||||
|
||||
void serialize(serializer&);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
string ARM::disassemble_arm_opcode(uint32 pc) {
|
||||
#ifdef PROCESSOR_ARM_HPP
|
||||
|
||||
string ARM::disassemble_arm_instruction(uint32 pc) {
|
||||
static string conditions[] = {
|
||||
"eq", "ne", "cs", "cc",
|
||||
"mi", "pl", "vs", "vc",
|
||||
|
@ -65,6 +67,21 @@ string ARM::disassemble_arm_opcode(uint32 pc) {
|
|||
return output;
|
||||
}
|
||||
|
||||
//memory_swap()
|
||||
//swp{condition}{b} rd,rm,[rn]
|
||||
if((instruction & 0x0fb000f0) == 0x01000090) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint1 byte = instruction >> 22;
|
||||
uint4 rn = instruction >> 16;
|
||||
uint4 rd = instruction >> 12;
|
||||
uint4 rm = instruction;
|
||||
|
||||
output.append("swp", conditions[condition], byte ? "b " : " ");
|
||||
output.append(registers[rd], ",", registers[rm], "[", registers[rn], "]");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//move_to_status_from_register()
|
||||
//msr{condition} (c,s)psr:{fields},rm
|
||||
if((instruction & 0x0fb000f0) == 0x01200000) {
|
||||
|
@ -98,6 +115,30 @@ string ARM::disassemble_arm_opcode(uint32 pc) {
|
|||
return output;
|
||||
}
|
||||
|
||||
//move_to_status_from_immediate()
|
||||
//msr{condition} (c,s)psr:{fields},#immediate
|
||||
if((instruction & 0x0fb00000) == 0x03200000) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint1 psr = instruction >> 22;
|
||||
uint4 field = instruction >> 16;
|
||||
uint4 rotate = instruction >> 8;
|
||||
uint8 immediate = instruction;
|
||||
|
||||
uint32 rm = (immediate >> (rotate * 2)) | (immediate << (32 - (rotate * 2)));
|
||||
|
||||
output.append("msr", conditions[condition], " ");
|
||||
output.append(psr ? "spsr:" : "cpsr:");
|
||||
output.append(
|
||||
field & 1 ? "c" : "",
|
||||
field & 2 ? "x" : "",
|
||||
field & 4 ? "s" : "",
|
||||
field & 8 ? "f" : ""
|
||||
);
|
||||
output.append(",#0x", hex<8>(immediate));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//data_immediate_shift()
|
||||
//{opcode}{condition}{s} rd,rm {shift} #immediate
|
||||
//{opcode}{condition} rn,rm {shift} #immediate
|
||||
|
@ -265,11 +306,21 @@ string ARM::disassemble_arm_opcode(uint32 pc) {
|
|||
return output;
|
||||
}
|
||||
|
||||
//software_interrupt()
|
||||
//swi #immediate
|
||||
if((instruction & 0x0f000000) == 0x0f000000) {
|
||||
uint24 immediate = instruction;
|
||||
|
||||
output.append("swi #0x", hex<6>(immediate));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
output.append("???");
|
||||
return output;
|
||||
}
|
||||
|
||||
string ARM::disassemble_thumb_opcode(uint32 pc) {
|
||||
string ARM::disassemble_thumb_instruction(uint32 pc) {
|
||||
static string conditions[] = {
|
||||
"eq", "ne", "cs", "cc",
|
||||
"mi", "pl", "vs", "vc",
|
||||
|
@ -602,3 +653,5 @@ string ARM::disassemble_registers() {
|
|||
output.append( spsr().n ? "N" : "n", spsr().z ? "Z" : "z", spsr().c ? "C" : "c", spsr().v ? "V" : "v");
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
string disassemble_arm_opcode(uint32 pc);
|
||||
string disassemble_thumb_opcode(uint32 pc);
|
||||
string disassemble_arm_instruction(uint32 pc);
|
||||
string disassemble_thumb_instruction(uint32 pc);
|
||||
string disassemble_registers();
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#ifdef PROCESSOR_ARM_HPP
|
||||
|
||||
void ARM::arm_step() {
|
||||
if(pipeline.reload) {
|
||||
pipeline.reload = false;
|
||||
|
@ -20,13 +22,17 @@ void ARM::arm_step() {
|
|||
step(2);
|
||||
|
||||
//print(disassemble_registers(), "\n");
|
||||
//print(disassemble_arm_opcode(pipeline.execute.address), "\n");
|
||||
//print(disassemble_arm_instruction(pipeline.execute.address), "\n");
|
||||
|
||||
if(arm_condition() == false) return;
|
||||
|
||||
if((instruction() & 0x0fc000f0) == 0x00000090) { arm_op_multiply(); return; }
|
||||
if((instruction() & 0x0fb000f0) == 0x01000000) { arm_op_move_to_register_from_status(); return; }
|
||||
if((instruction() & 0x0fb000f0) == 0x01000090) { arm_op_memory_swap(); return; }
|
||||
if((instruction() & 0x0fb000f0) == 0x01200000) { arm_op_move_to_status_from_register(); return; }
|
||||
if((instruction() & 0x0ff000f0) == 0x01200010) { arm_op_branch_exchange_register(); return; }
|
||||
if((instruction() & 0x0ff000f0) == 0x01200010) { arm_op_branch_exchange_register(); return; } //ARMv4
|
||||
if((instruction() & 0x0fb00000) == 0x03200000) { arm_op_move_to_status_from_immediate(); return; }
|
||||
|
||||
if((instruction() & 0x0e000010) == 0x00000000) { arm_op_data_immediate_shift(); return; }
|
||||
if((instruction() & 0x0e000090) == 0x00000010) { arm_op_data_register_shift(); return; }
|
||||
if((instruction() & 0x0e000000) == 0x02000000) { arm_op_data_immediate(); return; }
|
||||
|
@ -34,6 +40,7 @@ void ARM::arm_step() {
|
|||
if((instruction() & 0x0e000010) == 0x06000000) { arm_op_move_register_offset(); return; }
|
||||
if((instruction() & 0x0e000000) == 0x08000000) { arm_op_move_multiple(); return; }
|
||||
if((instruction() & 0x0e000000) == 0x0a000000) { arm_op_branch(); return; }
|
||||
if((instruction() & 0x0f000000) == 0x0f000000) { arm_op_software_interrupt(); return; }
|
||||
|
||||
exception = true;
|
||||
}
|
||||
|
@ -110,6 +117,35 @@ void ARM::arm_opcode(uint32 rm) {
|
|||
}
|
||||
}
|
||||
|
||||
void ARM::arm_move_to_status(uint32 rm) {
|
||||
uint1 source = instruction() >> 22;
|
||||
uint4 field = instruction() >> 16;
|
||||
|
||||
if(source == 1) {
|
||||
if(mode() == Processor::Mode::USR) return;
|
||||
if(mode() == Processor::Mode::SYS) return;
|
||||
}
|
||||
|
||||
PSR &psr = source ? spsr() : cpsr();
|
||||
|
||||
if(field & 1) {
|
||||
if(source == 1 || (Processor::Mode)cpsr().m != Processor::Mode::USR) {
|
||||
psr.i = rm & 0x00000080;
|
||||
psr.f = rm & 0x00000040;
|
||||
psr.t = rm & 0x00000020;
|
||||
psr.m = rm & 0x0000001f;
|
||||
if(source == 0) processor.setMode((Processor::Mode)psr.m);
|
||||
}
|
||||
}
|
||||
|
||||
if(field & 8) {
|
||||
psr.n = rm & 0x80000000;
|
||||
psr.z = rm & 0x40000000;
|
||||
psr.c = rm & 0x20000000;
|
||||
psr.v = rm & 0x10000000;
|
||||
}
|
||||
}
|
||||
|
||||
//logical shift left
|
||||
void ARM::lsl(bool &c, uint32 &rm, uint32 rs) {
|
||||
while(rs--) {
|
||||
|
@ -167,23 +203,35 @@ void ARM::arm_op_multiply() {
|
|||
uint4 s = instruction() >> 8;
|
||||
uint4 m = instruction() >> 0;
|
||||
|
||||
//Booth's algorithm: two bit steps
|
||||
uint32 temp = r(s);
|
||||
while(temp) {
|
||||
temp >>= 2;
|
||||
step(1);
|
||||
}
|
||||
r(d) = r(m) * r(s);
|
||||
auto &rd = r(d);
|
||||
uint32 rs = r(s);
|
||||
auto &rm = r(m);
|
||||
|
||||
if(accumulate) {
|
||||
rd = accumulate ? r(n) : 0u;
|
||||
step(1);
|
||||
|
||||
//Modified Booth Encoding
|
||||
bool carry = 0;
|
||||
unsigned place = 0;
|
||||
|
||||
do {
|
||||
step(1);
|
||||
r(d) += r(n);
|
||||
}
|
||||
signed factor = (int2)rs + carry;
|
||||
|
||||
if(factor == -2) rd -= rm << (place + 1);
|
||||
if(factor == -1) rd -= rm << (place + 0);
|
||||
if(factor == +1) rd += rm << (place + 0);
|
||||
if(factor == +2) rd += rm << (place + 1);
|
||||
|
||||
carry = rs & 2;
|
||||
place += 2;
|
||||
rs >>= 2;
|
||||
} while(rs + carry && place < 32);
|
||||
|
||||
if(save) {
|
||||
cpsr().n = r(d) >> 31;
|
||||
cpsr().z = r(d) == 0;
|
||||
cpsr().c = 0; //undefined
|
||||
cpsr().c = carry;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,6 +252,24 @@ void ARM::arm_op_move_to_register_from_status() {
|
|||
r(d) = source ? spsr() : cpsr();
|
||||
}
|
||||
|
||||
//swp{condition}{b} rd,rm,[rn]
|
||||
//cccc 0001 0b00 nnnn dddd ---- 1001 mmmm
|
||||
//c = condition
|
||||
//b = byte (0 = word)
|
||||
//n = rn
|
||||
//d = rd
|
||||
//m = rm
|
||||
void ARM::arm_op_memory_swap() {
|
||||
uint1 byte = instruction() >> 22;
|
||||
uint4 n = instruction() >> 16;
|
||||
uint4 d = instruction() >> 12;
|
||||
uint4 m = instruction();
|
||||
|
||||
uint32 word = bus_read(r(n), byte ? Byte : Word);
|
||||
bus_write(r(n), byte ? Byte : Word, r(m));
|
||||
r(d) = word;
|
||||
}
|
||||
|
||||
//msr{condition} (c,s)psr:{fields},rm
|
||||
//cccc 0001 0r10 ffff ++++ ---- 0000 mmmm
|
||||
//c = condition
|
||||
|
@ -211,35 +277,9 @@ void ARM::arm_op_move_to_register_from_status() {
|
|||
//f = field mask
|
||||
//m = rm
|
||||
void ARM::arm_op_move_to_status_from_register() {
|
||||
uint1 source = instruction() >> 22;
|
||||
uint4 field = instruction() >> 16;
|
||||
uint4 m = instruction();
|
||||
|
||||
if(source) {
|
||||
if(mode() == Processor::Mode::USR) return;
|
||||
if(mode() == Processor::Mode::SYS) return;
|
||||
}
|
||||
|
||||
PSR &psr = source ? spsr() : cpsr();
|
||||
uint32 rm = r(m);
|
||||
|
||||
if(field & 1) {
|
||||
psr.i = rm & 0x00000080;
|
||||
psr.f = rm & 0x00000040;
|
||||
psr.t = rm & 0x00000020;
|
||||
psr.m = rm & 0x0000001f;
|
||||
|
||||
if(source == 0) {
|
||||
processor.setMode((Processor::Mode)psr.m);
|
||||
}
|
||||
}
|
||||
|
||||
if(field & 8) {
|
||||
psr.n = rm & 0x80000000;
|
||||
psr.z = rm & 0x40000000;
|
||||
psr.c = rm & 0x20000000;
|
||||
psr.v = rm & 0x10000000;
|
||||
}
|
||||
arm_move_to_status(r(m));
|
||||
}
|
||||
|
||||
//bx{condition} rm
|
||||
|
@ -253,6 +293,24 @@ void ARM::arm_op_branch_exchange_register() {
|
|||
cpsr().t = r(m) & 1;
|
||||
}
|
||||
|
||||
//msr{condition} (c,s)psr:{fields},#immediate
|
||||
//cccc 0011 0r10 ffff ++++ rrrr iiii iiii
|
||||
//c = condition
|
||||
//r = SPSR (0 = CPSR)
|
||||
//f = field mask
|
||||
//r = rotate
|
||||
//i = immediate
|
||||
void ARM::arm_op_move_to_status_from_immediate() {
|
||||
uint4 rotate = instruction() >> 8;
|
||||
uint8 immediate = instruction();
|
||||
|
||||
uint32 rm = immediate;
|
||||
bool c = cpsr().c;
|
||||
if(rotate) ror(c, rm, 2 * rotate);
|
||||
|
||||
arm_move_to_status(rm);
|
||||
}
|
||||
|
||||
//{opcode}{condition}{s} rd,rm {shift} #immediate
|
||||
//{opcode}{condition} rn,rm {shift} #immediate
|
||||
//{opcode}{condition}{s} rd,rn,rm {shift} #immediate
|
||||
|
@ -489,3 +547,15 @@ void ARM::arm_op_branch() {
|
|||
if(link) r(14) = r(15) - 4;
|
||||
r(15) += displacement * 4;
|
||||
}
|
||||
|
||||
//swi #immediate
|
||||
//cccc 1111 iiii iiii iiii iiii iiii iiii
|
||||
//c = condition
|
||||
//i = immediate
|
||||
void ARM::arm_op_software_interrupt() {
|
||||
uint24 immediate = instruction();
|
||||
|
||||
vector(0x00000008, Processor::Mode::SVC);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,6 +2,7 @@ void arm_step();
|
|||
|
||||
bool arm_condition();
|
||||
void arm_opcode(uint32 rm);
|
||||
void arm_move_to_status(uint32 rm);
|
||||
|
||||
void lsl(bool &c, uint32 &rm, uint32 rs);
|
||||
void lsr(bool &c, uint32 &rm, uint32 rs);
|
||||
|
@ -11,8 +12,10 @@ void rrx(bool &c, uint32 &rm);
|
|||
|
||||
void arm_op_multiply();
|
||||
void arm_op_move_to_register_from_status();
|
||||
void arm_op_memory_swap();
|
||||
void arm_op_move_to_status_from_register();
|
||||
void arm_op_branch_exchange_register();
|
||||
void arm_op_move_to_status_from_immediate();
|
||||
void arm_op_data_immediate_shift();
|
||||
void arm_op_data_register_shift();
|
||||
void arm_op_data_immediate();
|
||||
|
@ -20,3 +23,4 @@ void arm_op_move_immediate_offset();
|
|||
void arm_op_move_register_offset();
|
||||
void arm_op_move_multiple();
|
||||
void arm_op_branch();
|
||||
void arm_op_software_interrupt();
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#ifdef PROCESSOR_ARM_HPP
|
||||
|
||||
void ARM::thumb_step() {
|
||||
if(pipeline.reload) {
|
||||
pipeline.reload = false;
|
||||
|
@ -20,7 +22,7 @@ void ARM::thumb_step() {
|
|||
step(1);
|
||||
|
||||
//print(disassemble_registers(), "\n");
|
||||
//print(disassemble_thumb_opcode(pipeline.execute.address), "\n");
|
||||
//print(disassemble_thumb_instruction(pipeline.execute.address), "\n");
|
||||
|
||||
if((instruction() & 0xfc00) == 0x1800) { thumb_op_adjust_register(); return; }
|
||||
if((instruction() & 0xfc00) == 0x1c00) { thumb_op_adjust_immediate(); return; }
|
||||
|
@ -483,13 +485,7 @@ void ARM::thumb_op_move_multiple() {
|
|||
void ARM::thumb_op_software_interrupt() {
|
||||
uint8 immediate = instruction();
|
||||
|
||||
auto psr = cpsr();
|
||||
processor.setMode(Processor::Mode::SVC);
|
||||
r(14) = r(15) - 2;
|
||||
spsr() = psr;
|
||||
cpsr().t = 0;
|
||||
cpsr().i = 1;
|
||||
r(15) = 0x00000008;
|
||||
vector(0x00000008, Processor::Mode::SVC);
|
||||
}
|
||||
|
||||
//b{condition}
|
||||
|
@ -532,3 +528,5 @@ void ARM::thumb_op_branch_long_suffix() {
|
|||
r(14) = r(15) | 1;
|
||||
r(15) += displacement * 2;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#ifdef PROCESSOR_ARM_HPP
|
||||
|
||||
void ARM::Processor::power() {
|
||||
r0 = r1 = r2 = r3 = r4 = r5 = r6 = r7 = 0;
|
||||
usr.r8 = usr.r9 = usr.r10 = usr.r11 = usr.r12 = usr.sp = usr.lr = 0;
|
||||
|
@ -26,8 +28,6 @@ void ARM::Processor::power() {
|
|||
r[7] = &r7;
|
||||
|
||||
r[15] = &pc;
|
||||
|
||||
setMode(Mode::SYS);
|
||||
}
|
||||
|
||||
void ARM::Processor::setMode(Mode mode) {
|
||||
|
@ -56,3 +56,5 @@ void ARM::Processor::setMode(Mode mode) {
|
|||
default: r[13] = &usr.sp; r[14] = &usr.lr; spsr = nullptr; break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
#include <processor/processor.hpp>
|
||||
#include "hg51b.hpp"
|
||||
|
||||
namespace Processor {
|
||||
|
||||
#include "registers.cpp"
|
||||
#include "instructions.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
void HG51B::exec(uint24 addr) {
|
||||
if(regs.halt) return;
|
||||
addr = addr + regs.pc * 2;
|
||||
opcode = bus_read(addr++) << 0;
|
||||
opcode |= bus_read(addr++) << 8;
|
||||
regs.pc = (regs.pc & 0xffff00) | ((regs.pc + 1) & 0x0000ff);
|
||||
instruction();
|
||||
}
|
||||
|
||||
void HG51B::power() {
|
||||
regs.halt = true;
|
||||
|
||||
regs.n = 0;
|
||||
regs.z = 0;
|
||||
regs.c = 0;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef PROCESSOR_HG51B_HPP
|
||||
#define PROCESSOR_HG51B_HPP
|
||||
|
||||
namespace Processor {
|
||||
|
||||
//Hitachi HG51B169 (HG51BS family/derivative?)
|
||||
|
||||
struct HG51B {
|
||||
//uint16 programROM[2][256];
|
||||
uint24 dataROM[1024];
|
||||
uint8 dataRAM[3072];
|
||||
#include "registers.hpp"
|
||||
void exec(uint24 addr);
|
||||
virtual uint8 bus_read(uint24 addr) = 0;
|
||||
virtual void bus_write(uint24 addr, uint8 data) = 0;
|
||||
|
||||
void power();
|
||||
void serialize(serializer&);
|
||||
|
||||
protected:
|
||||
void push();
|
||||
void pull();
|
||||
unsigned sa();
|
||||
unsigned ri();
|
||||
unsigned np();
|
||||
void instruction();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,6 +1,6 @@
|
|||
#ifdef HITACHIDSP_CPP
|
||||
#ifdef PROCESSOR_HG51B_HPP
|
||||
|
||||
void HitachiDSP::push() {
|
||||
void HG51B::push() {
|
||||
stack[7] = stack[6];
|
||||
stack[6] = stack[5];
|
||||
stack[5] = stack[4];
|
||||
|
@ -11,7 +11,7 @@ void HitachiDSP::push() {
|
|||
stack[0] = regs.pc;
|
||||
}
|
||||
|
||||
void HitachiDSP::pull() {
|
||||
void HG51B::pull() {
|
||||
regs.pc = stack[0];
|
||||
stack[0] = stack[1];
|
||||
stack[1] = stack[2];
|
||||
|
@ -24,7 +24,7 @@ void HitachiDSP::pull() {
|
|||
}
|
||||
|
||||
//Shift-A: math opcodes can shift A register prior to ALU operation
|
||||
unsigned HitachiDSP::sa() {
|
||||
unsigned HG51B::sa() {
|
||||
switch(opcode & 0x0300) { default:
|
||||
case 0x0000: return regs.a << 0;
|
||||
case 0x0100: return regs.a << 1;
|
||||
|
@ -34,18 +34,18 @@ unsigned HitachiDSP::sa() {
|
|||
}
|
||||
|
||||
//Register-or-Immediate: most opcodes can load from a register or immediate
|
||||
unsigned HitachiDSP::ri() {
|
||||
unsigned HG51B::ri() {
|
||||
if(opcode & 0x0400) return opcode & 0xff;
|
||||
return reg_read(opcode & 0xff);
|
||||
}
|
||||
|
||||
//New-PC: determine jump target address; opcode.d9 = long jump flag (1 = yes)
|
||||
unsigned HitachiDSP::np() {
|
||||
unsigned HG51B::np() {
|
||||
if(opcode & 0x0200) return (regs.p << 8) | (opcode & 0xff);
|
||||
return (regs.pc & 0xffff00) | (opcode & 0xff);
|
||||
}
|
||||
|
||||
void HitachiDSP::exec() {
|
||||
void HG51B::instruction() {
|
||||
if((opcode & 0xffff) == 0x0000) {
|
||||
//0000 0000 0000 0000
|
||||
//nop
|
||||
|
@ -344,12 +344,12 @@ void HitachiDSP::exec() {
|
|||
else if((opcode & 0xffff) == 0xfc00) {
|
||||
//1111 1100 0000 0000
|
||||
//halt
|
||||
state = State::Idle;
|
||||
regs.halt = true;
|
||||
}
|
||||
|
||||
else {
|
||||
print("Hitachi DSP: invalid opcode @ ", hex<4>(regs.pc - 1), " = ", hex<4>(opcode), "\n");
|
||||
state = State::Idle;
|
||||
print("Hitachi DSP: unknown opcode @ ", hex<4>(regs.pc - 1), " = ", hex<4>(opcode), "\n");
|
||||
regs.halt = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#ifdef HITACHIDSP_CPP
|
||||
#ifdef PROCESSOR_HG51B_HPP
|
||||
|
||||
unsigned HitachiDSP::reg_read(unsigned n) const {
|
||||
switch(n) {
|
||||
uint24 HG51B::reg_read(uint8 addr) const {
|
||||
switch(addr) {
|
||||
case 0x00: return regs.a;
|
||||
case 0x01: return regs.acch;
|
||||
case 0x02: return regs.accl;
|
||||
|
@ -46,8 +46,8 @@ unsigned HitachiDSP::reg_read(unsigned n) const {
|
|||
return 0x000000;
|
||||
}
|
||||
|
||||
void HitachiDSP::reg_write(unsigned n, unsigned data) {
|
||||
switch(n) {
|
||||
void HG51B::reg_write(uint8 addr, uint24 data) {
|
||||
switch(addr) {
|
||||
case 0x00: regs.a = data; return;
|
||||
case 0x01: regs.acch = data; return;
|
||||
case 0x02: regs.accl = data; return;
|
|
@ -0,0 +1,25 @@
|
|||
struct Registers {
|
||||
bool halt;
|
||||
|
||||
uint24 pc;
|
||||
uint16 p;
|
||||
bool n;
|
||||
bool z;
|
||||
bool c;
|
||||
|
||||
uint24 a;
|
||||
uint24 acch;
|
||||
uint24 accl;
|
||||
uint24 busdata;
|
||||
uint24 romdata;
|
||||
uint24 ramdata;
|
||||
uint24 busaddr;
|
||||
uint24 ramaddr;
|
||||
uint24 gpr[16];
|
||||
} regs;
|
||||
|
||||
uint24 stack[8];
|
||||
uint16 opcode;
|
||||
|
||||
uint24 reg_read(uint8 addr) const;
|
||||
void reg_write(uint8 addr, uint24 data);
|
|
@ -0,0 +1,27 @@
|
|||
#ifdef PROCESSOR_HG51B_HPP
|
||||
|
||||
void HG51B::serialize(serializer &s) {
|
||||
s.array(dataRAM);
|
||||
for(auto &n : stack) s.integer(n);
|
||||
s.integer(opcode);
|
||||
|
||||
s.integer(regs.halt);
|
||||
|
||||
s.integer(regs.pc);
|
||||
s.integer(regs.p);
|
||||
s.integer(regs.n);
|
||||
s.integer(regs.z);
|
||||
s.integer(regs.c);
|
||||
|
||||
s.integer(regs.a);
|
||||
s.integer(regs.acch);
|
||||
s.integer(regs.accl);
|
||||
s.integer(regs.busdata);
|
||||
s.integer(regs.romdata);
|
||||
s.integer(regs.ramdata);
|
||||
s.integer(regs.busaddr);
|
||||
s.integer(regs.ramaddr);
|
||||
for(auto &n : regs.gpr) s.integer(n);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -4,8 +4,6 @@
|
|||
namespace SNES {
|
||||
|
||||
#include "memory.cpp"
|
||||
#include "opcodes.cpp"
|
||||
#include "registers.cpp"
|
||||
#include "serialization.cpp"
|
||||
HitachiDSP hitachidsp;
|
||||
|
||||
|
@ -17,27 +15,17 @@ void HitachiDSP::enter() {
|
|||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
switch(state) {
|
||||
case State::Idle:
|
||||
step(1);
|
||||
break;
|
||||
case State::DMA:
|
||||
for(unsigned n = 0; n < regs.dma_length; n++) {
|
||||
bus.write(regs.dma_target + n, bus.read(regs.dma_source + n));
|
||||
if(mmio.dma) {
|
||||
for(unsigned n = 0; n < mmio.dma_length; n++) {
|
||||
bus.write(mmio.dma_target + n, bus.read(mmio.dma_source + n));
|
||||
step(2);
|
||||
}
|
||||
state = State::Idle;
|
||||
break;
|
||||
case State::Execute:
|
||||
unsigned offset = regs.program_offset + regs.pc * 2;
|
||||
opcode = bus_read(offset + 0) << 0;
|
||||
opcode |= bus_read(offset + 1) << 8;
|
||||
regs.pc = (regs.pc & 0xffff00) | ((regs.pc + 1) & 0x0000ff);
|
||||
exec();
|
||||
step(1);
|
||||
break;
|
||||
mmio.dma = false;
|
||||
}
|
||||
|
||||
exec(mmio.program_offset);
|
||||
step(1);
|
||||
|
||||
synchronize_cpu();
|
||||
}
|
||||
}
|
||||
|
@ -52,27 +40,24 @@ void HitachiDSP::unload() {
|
|||
}
|
||||
|
||||
void HitachiDSP::power() {
|
||||
mmio.dma = false;
|
||||
|
||||
mmio.dma_source = 0x000000;
|
||||
mmio.dma_length = 0x0000;
|
||||
mmio.dma_target = 0x000000;
|
||||
mmio.r1f48 = 0x00;
|
||||
mmio.program_offset = 0x000000;
|
||||
mmio.r1f4c = 0x00;
|
||||
mmio.page_number = 0x0000;
|
||||
mmio.program_counter = 0x00;
|
||||
mmio.r1f50 = 0x33;
|
||||
mmio.r1f51 = 0x00;
|
||||
mmio.r1f52 = 0x01;
|
||||
}
|
||||
|
||||
void HitachiDSP::reset() {
|
||||
create(HitachiDSP::Enter, frequency);
|
||||
state = State::Idle;
|
||||
|
||||
regs.n = 0;
|
||||
regs.z = 0;
|
||||
regs.c = 0;
|
||||
|
||||
regs.dma_source = 0x000000;
|
||||
regs.dma_length = 0x0000;
|
||||
regs.dma_target = 0x000000;
|
||||
regs.r1f48 = 0x00;
|
||||
regs.program_offset = 0x000000;
|
||||
regs.r1f4c = 0x00;
|
||||
regs.page_number = 0x0000;
|
||||
regs.program_counter = 0x00;
|
||||
regs.r1f50 = 0x33;
|
||||
regs.r1f51 = 0x00;
|
||||
regs.r1f52 = 0x01;
|
||||
HG51B::power();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,15 +1,6 @@
|
|||
//Hitachi HG51B169
|
||||
|
||||
class HitachiDSP : public Coprocessor {
|
||||
public:
|
||||
struct HitachiDSP : Processor::HG51B, Coprocessor {
|
||||
unsigned frequency;
|
||||
//uint16 programROM[2][256];
|
||||
uint24 dataROM[1024];
|
||||
uint8 dataRAM[3072];
|
||||
uint24 stack[8];
|
||||
uint16 opcode;
|
||||
enum class State : unsigned { Idle, DMA, Execute } state;
|
||||
#include "registers.hpp"
|
||||
#include "mmio.hpp"
|
||||
|
||||
static void Enter();
|
||||
void enter();
|
||||
|
@ -20,28 +11,18 @@ public:
|
|||
void power();
|
||||
void reset();
|
||||
|
||||
//memory.cpp
|
||||
uint8 bus_read(unsigned addr);
|
||||
void bus_write(unsigned addr, uint8 data);
|
||||
//HG51B read/write
|
||||
uint8 bus_read(uint24 addr);
|
||||
void bus_write(uint24 addr, uint8 data);
|
||||
|
||||
//CPU ROM read/write
|
||||
uint8 rom_read(unsigned addr);
|
||||
void rom_write(unsigned addr, uint8 data);
|
||||
|
||||
//CPU MMIO read/write
|
||||
uint8 dsp_read(unsigned addr);
|
||||
void dsp_write(unsigned addr, uint8 data);
|
||||
|
||||
//opcodes.cpp
|
||||
void push();
|
||||
void pull();
|
||||
unsigned sa();
|
||||
unsigned ri();
|
||||
unsigned np();
|
||||
void exec();
|
||||
|
||||
//registers.cpp
|
||||
unsigned reg_read(unsigned n) const;
|
||||
void reg_write(unsigned n, unsigned data);
|
||||
|
||||
void serialize(serializer&);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
#ifdef HITACHIDSP_CPP
|
||||
|
||||
uint8 HitachiDSP::bus_read(unsigned addr) {
|
||||
uint8 HitachiDSP::bus_read(uint24 addr) {
|
||||
if((addr & 0x408000) == 0x008000) return bus.read(addr);
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void HitachiDSP::bus_write(unsigned addr, uint8 data) {
|
||||
void HitachiDSP::bus_write(uint24 addr, uint8 data) {
|
||||
if((addr & 0x40e000) == 0x006000) return bus.write(addr, data);
|
||||
}
|
||||
|
||||
uint8 HitachiDSP::rom_read(unsigned addr) {
|
||||
if(co_active() == cpu.thread) {
|
||||
if(state == State::Idle) return cartridge.rom.read(addr);
|
||||
if((addr & 0x40ffe0) == 0x00ffe0) return regs.vector[addr & 0x1f];
|
||||
if(regs.halt) return cartridge.rom.read(addr);
|
||||
if((addr & 0x40ffe0) == 0x00ffe0) return mmio.vector[addr & 0x1f];
|
||||
return cpu.regs.mdr;
|
||||
}
|
||||
if(co_active() == hitachidsp.thread) {
|
||||
|
@ -34,34 +34,34 @@ uint8 HitachiDSP::dsp_read(unsigned addr) {
|
|||
|
||||
//MMIO
|
||||
switch(addr) {
|
||||
case 0x1f40: return regs.dma_source >> 0;
|
||||
case 0x1f41: return regs.dma_source >> 8;
|
||||
case 0x1f42: return regs.dma_source >> 16;
|
||||
case 0x1f43: return regs.dma_length >> 0;
|
||||
case 0x1f44: return regs.dma_length >> 8;
|
||||
case 0x1f45: return regs.dma_target >> 0;
|
||||
case 0x1f46: return regs.dma_target >> 8;
|
||||
case 0x1f47: return regs.dma_target >> 16;
|
||||
case 0x1f48: return regs.r1f48;
|
||||
case 0x1f49: return regs.program_offset >> 0;
|
||||
case 0x1f4a: return regs.program_offset >> 8;
|
||||
case 0x1f4b: return regs.program_offset >> 16;
|
||||
case 0x1f4c: return regs.r1f4c;
|
||||
case 0x1f4d: return regs.page_number >> 0;
|
||||
case 0x1f4e: return regs.page_number >> 8;
|
||||
case 0x1f4f: return regs.program_counter;
|
||||
case 0x1f50: return regs.r1f50;
|
||||
case 0x1f51: return regs.r1f51;
|
||||
case 0x1f52: return regs.r1f52;
|
||||
case 0x1f40: return mmio.dma_source >> 0;
|
||||
case 0x1f41: return mmio.dma_source >> 8;
|
||||
case 0x1f42: return mmio.dma_source >> 16;
|
||||
case 0x1f43: return mmio.dma_length >> 0;
|
||||
case 0x1f44: return mmio.dma_length >> 8;
|
||||
case 0x1f45: return mmio.dma_target >> 0;
|
||||
case 0x1f46: return mmio.dma_target >> 8;
|
||||
case 0x1f47: return mmio.dma_target >> 16;
|
||||
case 0x1f48: return mmio.r1f48;
|
||||
case 0x1f49: return mmio.program_offset >> 0;
|
||||
case 0x1f4a: return mmio.program_offset >> 8;
|
||||
case 0x1f4b: return mmio.program_offset >> 16;
|
||||
case 0x1f4c: return mmio.r1f4c;
|
||||
case 0x1f4d: return mmio.page_number >> 0;
|
||||
case 0x1f4e: return mmio.page_number >> 8;
|
||||
case 0x1f4f: return mmio.program_counter;
|
||||
case 0x1f50: return mmio.r1f50;
|
||||
case 0x1f51: return mmio.r1f51;
|
||||
case 0x1f52: return mmio.r1f52;
|
||||
case 0x1f53: case 0x1f54: case 0x1f55: case 0x1f56:
|
||||
case 0x1f57: case 0x1f58: case 0x1f59: case 0x1f5a:
|
||||
case 0x1f5b: case 0x1f5c: case 0x1f5d: case 0x1f5e:
|
||||
case 0x1f5f: return ((state != State::Idle) << 6) | ((state == State::Idle) << 1);
|
||||
case 0x1f5f: return ((regs.halt == false) << 6) | ((regs.halt == true) << 1);
|
||||
}
|
||||
|
||||
//Vector
|
||||
if(addr >= 0x1f60 && addr <= 0x1f7f) {
|
||||
return regs.vector[addr & 0x1f];
|
||||
return mmio.vector[addr & 0x1f];
|
||||
}
|
||||
|
||||
//GPRs
|
||||
|
@ -85,37 +85,37 @@ void HitachiDSP::dsp_write(unsigned addr, uint8 data) {
|
|||
|
||||
//MMIO
|
||||
switch(addr) {
|
||||
case 0x1f40: regs.dma_source = (regs.dma_source & 0xffff00) | (data << 0); return;
|
||||
case 0x1f41: regs.dma_source = (regs.dma_source & 0xff00ff) | (data << 8); return;
|
||||
case 0x1f42: regs.dma_source = (regs.dma_source & 0x00ffff) | (data << 16); return;
|
||||
case 0x1f43: regs.dma_length = (regs.dma_length & 0xff00) | (data << 0); return;
|
||||
case 0x1f44: regs.dma_length = (regs.dma_length & 0x00ff) | (data << 8); return;
|
||||
case 0x1f45: regs.dma_target = (regs.dma_target & 0xffff00) | (data << 0); return;
|
||||
case 0x1f46: regs.dma_target = (regs.dma_target & 0xff00ff) | (data << 8); return;
|
||||
case 0x1f47: regs.dma_target = (regs.dma_target & 0x00ffff) | (data << 16);
|
||||
if(state == State::Idle) state = State::DMA;
|
||||
case 0x1f40: mmio.dma_source = (mmio.dma_source & 0xffff00) | (data << 0); return;
|
||||
case 0x1f41: mmio.dma_source = (mmio.dma_source & 0xff00ff) | (data << 8); return;
|
||||
case 0x1f42: mmio.dma_source = (mmio.dma_source & 0x00ffff) | (data << 16); return;
|
||||
case 0x1f43: mmio.dma_length = (mmio.dma_length & 0xff00) | (data << 0); return;
|
||||
case 0x1f44: mmio.dma_length = (mmio.dma_length & 0x00ff) | (data << 8); return;
|
||||
case 0x1f45: mmio.dma_target = (mmio.dma_target & 0xffff00) | (data << 0); return;
|
||||
case 0x1f46: mmio.dma_target = (mmio.dma_target & 0xff00ff) | (data << 8); return;
|
||||
case 0x1f47: mmio.dma_target = (mmio.dma_target & 0x00ffff) | (data << 16);
|
||||
if(regs.halt) mmio.dma = true;
|
||||
return;
|
||||
case 0x1f48: regs.r1f48 = data & 0x01; return;
|
||||
case 0x1f49: regs.program_offset = (regs.program_offset & 0xffff00) | (data << 0); return;
|
||||
case 0x1f4a: regs.program_offset = (regs.program_offset & 0xff00ff) | (data << 8); return;
|
||||
case 0x1f4b: regs.program_offset = (regs.program_offset & 0x00ffff) | (data << 16); return;
|
||||
case 0x1f4c: regs.r1f4c = data & 0x03; return;
|
||||
case 0x1f4d: regs.page_number = (regs.page_number & 0x7f00) | ((data & 0xff) << 0); return;
|
||||
case 0x1f4e: regs.page_number = (regs.page_number & 0x00ff) | ((data & 0x7f) << 8); return;
|
||||
case 0x1f4f: regs.program_counter = data;
|
||||
if(state == State::Idle) {
|
||||
regs.pc = regs.page_number * 256 + regs.program_counter;
|
||||
state = State::Execute;
|
||||
case 0x1f48: mmio.r1f48 = data & 0x01; return;
|
||||
case 0x1f49: mmio.program_offset = (mmio.program_offset & 0xffff00) | (data << 0); return;
|
||||
case 0x1f4a: mmio.program_offset = (mmio.program_offset & 0xff00ff) | (data << 8); return;
|
||||
case 0x1f4b: mmio.program_offset = (mmio.program_offset & 0x00ffff) | (data << 16); return;
|
||||
case 0x1f4c: mmio.r1f4c = data & 0x03; return;
|
||||
case 0x1f4d: mmio.page_number = (mmio.page_number & 0x7f00) | ((data & 0xff) << 0); return;
|
||||
case 0x1f4e: mmio.page_number = (mmio.page_number & 0x00ff) | ((data & 0x7f) << 8); return;
|
||||
case 0x1f4f: mmio.program_counter = data;
|
||||
if(regs.halt) {
|
||||
regs.pc = mmio.page_number * 256 + mmio.program_counter;
|
||||
regs.halt = false;
|
||||
}
|
||||
return;
|
||||
case 0x1f50: regs.r1f50 = data & 0x77; return;
|
||||
case 0x1f51: regs.r1f51 = data & 0x01; return;
|
||||
case 0x1f52: regs.r1f52 = data & 0x01; return;
|
||||
case 0x1f50: mmio.r1f50 = data & 0x77; return;
|
||||
case 0x1f51: mmio.r1f51 = data & 0x01; return;
|
||||
case 0x1f52: mmio.r1f52 = data & 0x01; return;
|
||||
}
|
||||
|
||||
//Vector
|
||||
if(addr >= 0x1f60 && addr <= 0x1f7f) {
|
||||
regs.vector[addr & 0x1f] = data;
|
||||
mmio.vector[addr & 0x1f] = data;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,21 +1,6 @@
|
|||
struct Registers {
|
||||
uint24 pc;
|
||||
uint16 p;
|
||||
bool n;
|
||||
bool z;
|
||||
bool c;
|
||||
struct MMIO {
|
||||
bool dma; //true during DMA transfers
|
||||
|
||||
uint24 a;
|
||||
uint24 acch;
|
||||
uint24 accl;
|
||||
uint24 busdata;
|
||||
uint24 romdata;
|
||||
uint24 ramdata;
|
||||
uint24 busaddr;
|
||||
uint24 ramaddr;
|
||||
uint24 gpr[16];
|
||||
|
||||
//MMIO
|
||||
uint24 dma_source; //$1f40-$1f42
|
||||
uint24 dma_length; //$1f43-$1f44
|
||||
uint24 dma_target; //$1f45-$1f47
|
||||
|
@ -28,4 +13,4 @@ struct Registers {
|
|||
uint8 r1f51; //$1f51
|
||||
uint8 r1f52; //$1f52
|
||||
uint8 vector[32]; //$1f60-$1f7f
|
||||
} regs;
|
||||
} mmio;
|
|
@ -1,41 +1,22 @@
|
|||
#ifdef HITACHIDSP_CPP
|
||||
|
||||
void HitachiDSP::serialize(serializer &s) {
|
||||
HG51B::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(dataRAM);
|
||||
for(auto &n : stack) s.integer(n);
|
||||
s.integer(opcode);
|
||||
s.integer((unsigned&)state);
|
||||
|
||||
s.integer(regs.pc);
|
||||
s.integer(regs.p);
|
||||
s.integer(regs.n);
|
||||
s.integer(regs.z);
|
||||
s.integer(regs.c);
|
||||
|
||||
s.integer(regs.a);
|
||||
s.integer(regs.acch);
|
||||
s.integer(regs.accl);
|
||||
s.integer(regs.busdata);
|
||||
s.integer(regs.romdata);
|
||||
s.integer(regs.ramdata);
|
||||
s.integer(regs.busaddr);
|
||||
s.integer(regs.ramaddr);
|
||||
for(auto &n : regs.gpr) s.integer(n);
|
||||
|
||||
s.integer(regs.dma_source);
|
||||
s.integer(regs.dma_length);
|
||||
s.integer(regs.dma_target);
|
||||
s.integer(regs.r1f48);
|
||||
s.integer(regs.program_offset);
|
||||
s.integer(regs.r1f4c);
|
||||
s.integer(regs.page_number);
|
||||
s.integer(regs.program_counter);
|
||||
s.integer(regs.r1f50);
|
||||
s.integer(regs.r1f51);
|
||||
s.integer(regs.r1f52);
|
||||
s.array(regs.vector);
|
||||
s.integer(mmio.dma);
|
||||
s.integer(mmio.dma_source);
|
||||
s.integer(mmio.dma_length);
|
||||
s.integer(mmio.dma_target);
|
||||
s.integer(mmio.r1f48);
|
||||
s.integer(mmio.program_offset);
|
||||
s.integer(mmio.r1f4c);
|
||||
s.integer(mmio.page_number);
|
||||
s.integer(mmio.program_counter);
|
||||
s.integer(mmio.r1f50);
|
||||
s.integer(mmio.r1f51);
|
||||
s.integer(mmio.r1f52);
|
||||
s.array(mmio.vector);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <base/base.hpp>
|
||||
#include <processor/arm/arm.hpp>
|
||||
#include <processor/hg51b/hg51b.hpp>
|
||||
|
||||
namespace SNES {
|
||||
namespace Info {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
options += debugger
|
||||
|
||||
processor := arm
|
||||
processor := arm hg51b
|
||||
include processor/Makefile
|
||||
|
||||
include $(snes)/Makefile
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
processor := arm
|
||||
processor := arm hg51b
|
||||
include processor/Makefile
|
||||
|
||||
include $(snes)/Makefile
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
processors := arm
|
||||
processors := arm hg51b
|
||||
include processor/Makefile
|
||||
|
||||
include $(nes)/Makefile
|
||||
|
|
Loading…
Reference in New Issue