mirror of https://github.com/bsnes-emu/bsnes.git
Update to v087r07 release.
There was a "v087r07pre" release that I unfortunately missed. byuu says (about v087r07pre): Creates the bsnes/processor folder. This has a shared ARM core there which both the GBA and ST018 inherit. There are going to be separate decoders, and revision-specific checks, to support the differences between v3+. In the future, I also want to move the other processor cores here: - GBZ80 (GB, GBC) - 65816 (SNES CPU, SA-1) - NEC uPD (7725, 96050, maybe 7720 just for fun) - Hitachi HG51B169 - SuperFX - SPC700 - 65(C?)02 Basically, the GBA/ST018 forces my hand to start coding a bit more like a multi-system emulator. Right now, the ST018 is broken. Hence the pre. Apparently the GBA core being used now has some bugs. So this'll be a nice way to stress-test the GBA core a bit before we make it to ARMwrestler. byuu says (about v087r07): Both snes/chip/armdsp and gba/cpu use processor/arm now. Fixed THUMB to execute the BL prefix and suffix separately. I can now get the GBA BIOS stuck in some kind of infinite loop. Hooray ... I guess?
This commit is contained in:
parent
77578cd0a4
commit
ec939065bd
|
@ -1,7 +1,7 @@
|
|||
#ifndef BASE_HPP
|
||||
#define BASE_HPP
|
||||
|
||||
static const char Version[] = "087.06";
|
||||
static const char Version[] = "087.07";
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/algorithm.hpp>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
struct APU : Processor, MMIO {
|
||||
struct APU : Thread, MMIO {
|
||||
#include "square1/square1.hpp"
|
||||
#include "square2/square2.hpp"
|
||||
#include "wave/wave.hpp"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifdef APU_CPP
|
||||
|
||||
void APU::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(mmio_data);
|
||||
s.integer(sequencer_base);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
struct CPU : Processor, MMIO {
|
||||
struct CPU : Thread, MMIO {
|
||||
#include "core/core.hpp"
|
||||
#include "mmio/mmio.hpp"
|
||||
#include "timing/timing.hpp"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifdef CPU_CPP
|
||||
|
||||
void CPU::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(wram);
|
||||
s.array(hram);
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace GB {
|
|||
#include <nall/gameboy/cartridge.hpp>
|
||||
|
||||
namespace GB {
|
||||
struct Processor {
|
||||
struct Thread {
|
||||
cothread_t thread;
|
||||
unsigned frequency;
|
||||
int64 clock;
|
||||
|
@ -38,10 +38,10 @@ namespace GB {
|
|||
s.integer(clock);
|
||||
}
|
||||
|
||||
inline Processor() : thread(nullptr) {
|
||||
inline Thread() : thread(nullptr) {
|
||||
}
|
||||
|
||||
inline ~Processor() {
|
||||
inline ~Thread() {
|
||||
if(thread) co_delete(thread);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
struct LCD : Processor, MMIO {
|
||||
struct LCD : Thread, MMIO {
|
||||
#include "mmio/mmio.hpp"
|
||||
|
||||
struct Status {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifdef LCD_CPP
|
||||
|
||||
void LCD::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(screen);
|
||||
s.array(line);
|
||||
|
|
|
@ -16,11 +16,6 @@ void Scheduler::exit(ExitReason reason) {
|
|||
co_switch(host_thread);
|
||||
}
|
||||
|
||||
void Scheduler::swapto(Processor &p) {
|
||||
active_thread = p.thread;
|
||||
co_switch(active_thread);
|
||||
}
|
||||
|
||||
void Scheduler::init() {
|
||||
host_thread = co_active();
|
||||
active_thread = cpu.thread;
|
||||
|
|
|
@ -8,7 +8,6 @@ struct Scheduler : property<Scheduler> {
|
|||
|
||||
void enter();
|
||||
void exit(ExitReason);
|
||||
void swapto(Processor&);
|
||||
|
||||
void init();
|
||||
Scheduler();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
struct APU : Processor {
|
||||
struct APU : Thread {
|
||||
static void Enter();
|
||||
void enter();
|
||||
void step(unsigned clocks);
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
struct ARM {
|
||||
#include "registers.hpp"
|
||||
#include "arm.hpp"
|
||||
#include "thumb.hpp"
|
||||
#include "disassembler.hpp"
|
||||
virtual void step(unsigned clocks) = 0;
|
||||
|
||||
void power();
|
||||
};
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace GBA {
|
||||
|
||||
#include "core/core.cpp"
|
||||
CPU cpu;
|
||||
|
||||
void CPU::Enter() { cpu.enter(); }
|
||||
|
@ -25,6 +24,16 @@ void CPU::step(unsigned clocks) {
|
|||
if(apu.clock < 0) co_switch(apu.thread);
|
||||
}
|
||||
|
||||
uint32 CPU::bus_read(uint32 addr, uint32 size) {
|
||||
step(1);
|
||||
return bus.read(addr, size);
|
||||
}
|
||||
|
||||
void CPU::bus_write(uint32 addr, uint32 size, uint32 word) {
|
||||
step(1);
|
||||
return bus.write(addr, size, word);
|
||||
}
|
||||
|
||||
void CPU::power() {
|
||||
create(CPU::Enter, 16777216);
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
#include "core/core.hpp"
|
||||
|
||||
struct CPU : Processor, ARM {
|
||||
struct CPU : Processor::ARM, Thread {
|
||||
StaticMemory iram;
|
||||
StaticMemory eram;
|
||||
|
||||
static void Enter();
|
||||
void enter();
|
||||
void step(unsigned clocks);
|
||||
uint32 bus_read(uint32 addr, uint32 size);
|
||||
void bus_write(uint32 addr, uint32 size, uint32 word);
|
||||
|
||||
void power();
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define GBA_HPP
|
||||
|
||||
#include <base/base.hpp>
|
||||
#include <processor/arm/arm.hpp>
|
||||
|
||||
namespace GBA {
|
||||
namespace Info {
|
||||
|
@ -22,7 +23,7 @@ namespace GBA {
|
|||
namespace GBA {
|
||||
enum : unsigned { Byte = 8, Half = 16, Word = 32 };
|
||||
|
||||
struct Processor {
|
||||
struct Thread {
|
||||
cothread_t thread;
|
||||
unsigned frequency;
|
||||
signed clock;
|
||||
|
@ -39,10 +40,10 @@ namespace GBA {
|
|||
s.integer(clock);
|
||||
}
|
||||
|
||||
inline Processor() : thread(nullptr) {
|
||||
inline Thread() : thread(nullptr) {
|
||||
}
|
||||
|
||||
inline ~Processor() {
|
||||
inline ~Thread() {
|
||||
if(thread) co_delete(thread);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
struct PPU : Processor {
|
||||
struct PPU : Thread {
|
||||
StaticMemory vram;
|
||||
StaticMemory oam;
|
||||
StaticMemory pram;
|
||||
|
|
|
@ -92,7 +92,7 @@ void APU::power() {
|
|||
}
|
||||
|
||||
void APU::reset() {
|
||||
Processor::create(APU::Main, 21477272);
|
||||
create(APU::Main, 21477272);
|
||||
|
||||
pulse[0].reset();
|
||||
pulse[1].reset();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
struct APU : Processor {
|
||||
struct APU : Thread {
|
||||
static void Main();
|
||||
void main();
|
||||
void tick();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
void APU::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
filter.serialize(s);
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ void Cartridge::scanline(unsigned y) {
|
|||
}
|
||||
|
||||
void Cartridge::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
return board->serialize(s);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "chip/chip.hpp"
|
||||
#include "board/board.hpp"
|
||||
|
||||
struct Cartridge : Processor, property<Cartridge> {
|
||||
struct Cartridge : Thread, property<Cartridge> {
|
||||
static void Main();
|
||||
void main();
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ void CPU::power() {
|
|||
}
|
||||
|
||||
void CPU::reset() {
|
||||
Processor::create(CPU::Main, 21477272);
|
||||
create(CPU::Main, 21477272);
|
||||
|
||||
regs.mdr = 0x00;
|
||||
regs.s -= 3;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
struct CPU : Processor {
|
||||
struct CPU : Thread {
|
||||
#include "core/core.hpp"
|
||||
#include "memory/memory.hpp"
|
||||
uint8 ram[0x0800];
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
void CPU::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(ram);
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace NES {
|
|||
#include <libco/libco.h>
|
||||
|
||||
namespace NES {
|
||||
struct Processor {
|
||||
struct Thread {
|
||||
cothread_t thread;
|
||||
unsigned frequency;
|
||||
int64 clock;
|
||||
|
@ -37,10 +37,10 @@ namespace NES {
|
|||
s.integer(clock);
|
||||
}
|
||||
|
||||
inline Processor() : thread(nullptr) {
|
||||
inline Thread() : thread(nullptr) {
|
||||
}
|
||||
|
||||
inline ~Processor() {
|
||||
inline ~Thread() {
|
||||
if(thread) co_delete(thread);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
struct PPU : Processor {
|
||||
struct PPU : Thread {
|
||||
static void Main();
|
||||
void main();
|
||||
void tick();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
void PPU::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
s.integer(status.mdr);
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
processor_objects :=
|
||||
processor_objects += $(if $(findstring arm,$(processors)),processor-arm)
|
||||
objects += $(processor_objects)
|
||||
|
||||
processor := processor
|
||||
obj/processor-arm.o: $(processor)/arm/arm.cpp $(call rwildcard,$(processor)/arm)
|
|
@ -1,6 +1,11 @@
|
|||
#include <processor/processor.hpp>
|
||||
#include "arm.hpp"
|
||||
|
||||
namespace Processor {
|
||||
|
||||
#include "registers.cpp"
|
||||
#include "arm.cpp"
|
||||
#include "thumb.cpp"
|
||||
#include "instructions-arm.cpp"
|
||||
#include "instructions-thumb.cpp"
|
||||
#include "disassembler.cpp"
|
||||
|
||||
void ARM::power() {
|
||||
|
@ -12,3 +17,8 @@ void ARM::power() {
|
|||
r(15).data &= cpsr().t ? ~1 : ~3;
|
||||
};
|
||||
}
|
||||
|
||||
void ARM::serialize(serializer &s) {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef PROCESSOR_ARM_HPP
|
||||
#define PROCESSOR_ARM_HPP
|
||||
|
||||
namespace Processor {
|
||||
|
||||
struct ARM {
|
||||
enum : unsigned { Byte = 8, Half = 16, Word = 32 };
|
||||
#include "registers.hpp"
|
||||
#include "instructions-arm.hpp"
|
||||
#include "instructions-thumb.hpp"
|
||||
#include "disassembler.hpp"
|
||||
virtual void step(unsigned clocks) = 0;
|
||||
virtual uint32 bus_read(uint32 addr, uint32 size) = 0;
|
||||
virtual void bus_write(uint32 addr, uint32 size, uint32 word) = 0;
|
||||
|
||||
void power();
|
||||
void serialize(serializer&);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -30,7 +30,7 @@ string ARM::disassemble_arm_opcode(uint32 pc) {
|
|||
|
||||
string output{hex<8>(pc), " "};
|
||||
|
||||
uint32 instruction = bus.read(pc, Word);
|
||||
uint32 instruction = bus_read(pc, Word);
|
||||
output.append(hex<8>(instruction), " ");
|
||||
|
||||
//multiply()
|
||||
|
@ -198,7 +198,7 @@ string ARM::disassemble_arm_opcode(uint32 pc) {
|
|||
if(pre == 1) output.append("]");
|
||||
if(pre == 0 || writeback == 1) output.append("!");
|
||||
|
||||
if(rn == 15) output.append(" =0x", hex<8>(bus.read(pc + 8 + (up ? +immediate : -immediate), byte ? Byte : Word)));
|
||||
if(rn == 15) output.append(" =0x", hex<8>(bus_read(pc + 8 + (up ? +immediate : -immediate), byte ? Byte : Word)));
|
||||
return output;
|
||||
}
|
||||
|
||||
|
@ -286,7 +286,7 @@ string ARM::disassemble_thumb_opcode(uint32 pc) {
|
|||
|
||||
string output{hex<8>(pc), " "};
|
||||
|
||||
uint16 instruction = bus.read(pc, Half);
|
||||
uint16 instruction = bus_read(pc, Half);
|
||||
output.append(hex<4>(instruction), " ");
|
||||
|
||||
//adjust_register()
|
||||
|
@ -400,7 +400,7 @@ string ARM::disassemble_thumb_opcode(uint32 pc) {
|
|||
|
||||
unsigned rm = ((pc + 4) & ~3) + displacement * 4;
|
||||
output.append("ldr ", registers[rd], ",[pc,#0x", hex<3>(rm), "]");
|
||||
output.append(" =0x", hex<8>(bus.read(rm, Word)));
|
||||
output.append(" =0x", hex<8>(bus_read(rm, Word)));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -565,16 +565,23 @@ string ARM::disassemble_thumb_opcode(uint32 pc) {
|
|||
return output;
|
||||
}
|
||||
|
||||
//branch_long()
|
||||
//branch_long_prefix()
|
||||
//bl address
|
||||
if((instruction & 0xf800) == 0xf000) {
|
||||
uint11 offsethi = instruction;
|
||||
instruction = bus.read(pc + 2, Half);
|
||||
instruction = bus_read(pc + 2, Half);
|
||||
uint11 offsetlo = instruction;
|
||||
|
||||
int22 displacement = (offsethi << 11) | (offsetlo << 0);
|
||||
output.append("bl 0x", hex<8>(pc + 4 + displacement * 2));
|
||||
output.append("\n", hex<8>(pc + 2), " ", hex<4>(instruction), " ...");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//branch_long_suffix()
|
||||
//bl address
|
||||
if((instruction & 0xf800) == 0xf800) {
|
||||
output.append("...");
|
||||
|
||||
return output;
|
||||
}
|
|
@ -3,12 +3,12 @@ void ARM::arm_step() {
|
|||
pipeline.reload = false;
|
||||
|
||||
pipeline.fetch.address = r(15);
|
||||
pipeline.fetch.instruction = bus.read(r(15), Word);
|
||||
pipeline.fetch.instruction = bus_read(r(15), Word);
|
||||
|
||||
r(15).data += 4;
|
||||
pipeline.decode = pipeline.fetch;
|
||||
pipeline.fetch.address = r(15);
|
||||
pipeline.fetch.instruction = bus.read(r(15), Word);
|
||||
pipeline.fetch.instruction = bus_read(r(15), Word);
|
||||
step(2);
|
||||
}
|
||||
|
||||
|
@ -16,11 +16,11 @@ void ARM::arm_step() {
|
|||
pipeline.execute = pipeline.decode;
|
||||
pipeline.decode = pipeline.fetch;
|
||||
pipeline.fetch.address = r(15);
|
||||
pipeline.fetch.instruction = bus.read(r(15), Word);
|
||||
pipeline.fetch.instruction = bus_read(r(15), Word);
|
||||
step(2);
|
||||
|
||||
//print(disassemble_registers(), "\n");
|
||||
print(disassemble_arm_opcode(pipeline.execute.address), "\n");
|
||||
//print(disassemble_arm_opcode(pipeline.execute.address), "\n");
|
||||
|
||||
if(arm_condition() == false) return;
|
||||
if((instruction() & 0x0fc000f0) == 0x00000090) { arm_op_multiply(); return; }
|
||||
|
@ -365,9 +365,9 @@ void ARM::arm_op_move_immediate_offset() {
|
|||
|
||||
if(pre == 1) rn = up ? rn + rm : rn - rm;
|
||||
if(load) {
|
||||
rd = bus.read(rn, byte ? Byte : Word);
|
||||
rd = bus_read(rn, byte ? Byte : Word);
|
||||
} else {
|
||||
bus.write(rn, byte ? Byte : Word, rd);
|
||||
bus_write(rn, byte ? Byte : Word, rd);
|
||||
}
|
||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||
|
||||
|
@ -413,9 +413,9 @@ void ARM::arm_op_move_register_offset() {
|
|||
|
||||
if(pre == 1) rn = up ? rn + rm : rn - rm;
|
||||
if(load) {
|
||||
rd = bus.read(rn, byte ? Byte : Word);
|
||||
rd = bus_read(rn, byte ? Byte : Word);
|
||||
} else {
|
||||
bus.write(rn, byte ? Byte : Word, rd);
|
||||
bus_write(rn, byte ? Byte : Word, rd);
|
||||
}
|
||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||
|
||||
|
@ -456,8 +456,8 @@ void ARM::arm_op_move_multiple() {
|
|||
|
||||
for(unsigned n = 0; n < 16; n++) {
|
||||
if(list & (1 << n)) {
|
||||
if(load) r(n) = bus.read(rn, Word);
|
||||
else bus.write(rn, Word, r(n));
|
||||
if(load) r(n) = bus_read(rn, Word);
|
||||
else bus_write(rn, Word, r(n));
|
||||
rn += 4;
|
||||
}
|
||||
}
|
|
@ -3,12 +3,12 @@ void ARM::thumb_step() {
|
|||
pipeline.reload = false;
|
||||
|
||||
pipeline.fetch.address = r(15);
|
||||
pipeline.fetch.instruction = bus.read(r(15), Half);
|
||||
pipeline.fetch.instruction = bus_read(r(15), Half);
|
||||
|
||||
r(15).data += 2;
|
||||
pipeline.decode = pipeline.fetch;
|
||||
pipeline.fetch.address = r(15);
|
||||
pipeline.fetch.instruction = bus.read(r(15), Half);
|
||||
pipeline.fetch.instruction = bus_read(r(15), Half);
|
||||
step(1);
|
||||
}
|
||||
|
||||
|
@ -16,11 +16,11 @@ void ARM::thumb_step() {
|
|||
pipeline.execute = pipeline.decode;
|
||||
pipeline.decode = pipeline.fetch;
|
||||
pipeline.fetch.address = r(15);
|
||||
pipeline.fetch.instruction = bus.read(r(15), Half);
|
||||
pipeline.fetch.instruction = bus_read(r(15), Half);
|
||||
step(1);
|
||||
|
||||
//print(disassemble_registers(), "\n");
|
||||
print(disassemble_thumb_opcode(pipeline.execute.address), "\n");
|
||||
//print(disassemble_thumb_opcode(pipeline.execute.address), "\n");
|
||||
|
||||
if((instruction() & 0xfc00) == 0x1800) { thumb_op_adjust_register(); return; }
|
||||
if((instruction() & 0xfc00) == 0x1c00) { thumb_op_adjust_immediate(); return; }
|
||||
|
@ -42,7 +42,8 @@ void ARM::thumb_step() {
|
|||
if((instruction() & 0xff00) == 0xdf00) { thumb_op_software_interrupt(); return; }
|
||||
if((instruction() & 0xf000) == 0xd000) { thumb_op_branch_conditional(); return; }
|
||||
if((instruction() & 0xf800) == 0xe000) { thumb_op_branch_short(); return; }
|
||||
if((instruction() & 0xf800) == 0xf000) { thumb_op_branch_long(); return; }
|
||||
if((instruction() & 0xf800) == 0xf000) { thumb_op_branch_long_prefix(); return; }
|
||||
if((instruction() & 0xf800) == 0xf800) { thumb_op_branch_long_suffix(); return; }
|
||||
|
||||
exception = true;
|
||||
}
|
||||
|
@ -294,7 +295,7 @@ void ARM::thumb_op_load_literal() {
|
|||
uint8 displacement = instruction();
|
||||
|
||||
unsigned rm = (r(15) & ~3) + displacement * 4;
|
||||
r(d) = bus.read(rm, Word);
|
||||
r(d) = bus_read(rm, Word);
|
||||
}
|
||||
|
||||
//(ld(r,s),str){b,h} rd,[rn,rm]
|
||||
|
@ -310,14 +311,14 @@ void ARM::thumb_op_move_register_offset() {
|
|||
uint3 d = instruction() >> 0;
|
||||
|
||||
switch(opcode) {
|
||||
case 0: bus.write(r(n) + r(m), Word, r(d)); break; //STR
|
||||
case 1: bus.write(r(n) + r(m), Half, r(d)); break; //STRH
|
||||
case 2: bus.write(r(n) + r(m), Byte, r(d)); break; //STRB
|
||||
case 3: r(d) = (int8)bus.read(r(n) + r(m), Byte); break; //LDSB
|
||||
case 4: r(d) = bus.read(r(n) + r(m), Word); break; //LDR
|
||||
case 5: r(d) = bus.read(r(n) + r(m), Half); break; //LDRH
|
||||
case 6: r(d) = bus.read(r(n) + r(m), Byte); break; //LDRB
|
||||
case 7: r(d) = (int16)bus.read(r(n) + r(m), Half); break; //LDSH
|
||||
case 0: bus_write(r(n) + r(m), Word, r(d)); break; //STR
|
||||
case 1: bus_write(r(n) + r(m), Half, r(d)); break; //STRH
|
||||
case 2: bus_write(r(n) + r(m), Byte, r(d)); break; //STRB
|
||||
case 3: r(d) = (int8)bus_read(r(n) + r(m), Byte); break; //LDSB
|
||||
case 4: r(d) = bus_read(r(n) + r(m), Word); break; //LDR
|
||||
case 5: r(d) = bus_read(r(n) + r(m), Half); break; //LDRH
|
||||
case 6: r(d) = bus_read(r(n) + r(m), Byte); break; //LDRB
|
||||
case 7: r(d) = (int16)bus_read(r(n) + r(m), Half); break; //LDSH
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -333,8 +334,8 @@ void ARM::thumb_op_move_word_immediate() {
|
|||
uint3 n = instruction() >> 3;
|
||||
uint3 d = instruction() >> 0;
|
||||
|
||||
if(load == 1) r(d) = bus.read(r(n) + offset * 4, Word);
|
||||
if(load == 0) bus.write(r(d) + offset * 4, Word, r(n));
|
||||
if(load == 1) r(d) = bus_read(r(n) + offset * 4, Word);
|
||||
if(load == 0) bus_write(r(d) + offset * 4, Word, r(n));
|
||||
}
|
||||
|
||||
//(ldr,str)b rd,[rn,#offset]
|
||||
|
@ -349,8 +350,8 @@ void ARM::thumb_op_move_byte_immediate() {
|
|||
uint3 n = instruction() >> 3;
|
||||
uint4 d = instruction() >> 0;
|
||||
|
||||
if(load == 1) r(d) = bus.read(r(n) + offset, Byte);
|
||||
if(load == 0) bus.write(r(d) + offset, Byte, r(n));
|
||||
if(load == 1) r(d) = bus_read(r(n) + offset, Byte);
|
||||
if(load == 0) bus_write(r(d) + offset, Byte, r(n));
|
||||
}
|
||||
|
||||
//(ldr,str)h rd,[rn,#offset]
|
||||
|
@ -365,8 +366,8 @@ void ARM::thumb_op_move_half_immediate() {
|
|||
uint3 n = instruction() >> 3;
|
||||
uint3 d = instruction() >> 0;
|
||||
|
||||
if(load == 1) r(d) = bus.read(r(n) + offset * 2, Half);
|
||||
if(load == 0) bus.write(r(d) + offset * 2, Half, r(n));
|
||||
if(load == 1) r(d) = bus_read(r(n) + offset * 2, Half);
|
||||
if(load == 0) bus_write(r(d) + offset * 2, Half, r(n));
|
||||
}
|
||||
|
||||
//(ldr,str) rd,[sp,#relative]
|
||||
|
@ -379,8 +380,8 @@ void ARM::thumb_op_move_stack() {
|
|||
uint3 d = instruction() >> 8;
|
||||
int8 relative = instruction();
|
||||
|
||||
if(opcode == 0) bus.write(r(13) + relative * 4, Word, r(d));
|
||||
if(opcode == 1) r(d) = bus.read(r(13) + relative * 4, Word);
|
||||
if(opcode == 0) bus_write(r(13) + relative * 4, Word, r(d));
|
||||
if(opcode == 1) r(d) = bus_read(r(13) + relative * 4, Word);
|
||||
}
|
||||
|
||||
//add rd,{pc,sp},#immediate
|
||||
|
@ -423,12 +424,12 @@ void ARM::thumb_op_stack_multiple() {
|
|||
if(load == 1) {
|
||||
for(unsigned l = 0; l < 8; l++) {
|
||||
if(list & (1 << l)) {
|
||||
r(l) = bus.read(r(13), Word);
|
||||
r(l) = bus_read(r(13), Word);
|
||||
r(13) += 4;
|
||||
}
|
||||
}
|
||||
if(branch) {
|
||||
r(15) = bus.read(r(13), Word);
|
||||
r(15) = bus_read(r(13), Word);
|
||||
r(13) += 4;
|
||||
}
|
||||
}
|
||||
|
@ -437,12 +438,12 @@ void ARM::thumb_op_stack_multiple() {
|
|||
for(unsigned l = 0; l < 8; l++) {
|
||||
if(list & (1 << l)) {
|
||||
r(13) -= 4;
|
||||
bus.write(r(13), Word, r(l));
|
||||
bus_write(r(13), Word, r(l));
|
||||
}
|
||||
}
|
||||
if(branch) {
|
||||
r(13) -= 4;
|
||||
bus.write(r(13), Word, r(14));
|
||||
bus_write(r(13), Word, r(14));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -460,7 +461,7 @@ void ARM::thumb_op_move_multiple() {
|
|||
if(load == 1) {
|
||||
for(unsigned l = 0; l < 8; l++) {
|
||||
if(list & (1 << l)) {
|
||||
r(l) = bus.read(r(n), Word);
|
||||
r(l) = bus_read(r(n), Word);
|
||||
r(n) += 4;
|
||||
}
|
||||
}
|
||||
|
@ -470,7 +471,7 @@ void ARM::thumb_op_move_multiple() {
|
|||
for(unsigned l = 0; l < 8; l++) {
|
||||
if(list & (1 << l)) {
|
||||
r(n) -= 4;
|
||||
bus.write(r(n), Word, r(l));
|
||||
bus_write(r(n), Word, r(l));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -514,13 +515,20 @@ void ARM::thumb_op_branch_short() {
|
|||
|
||||
//bl address
|
||||
//1111 0ooo oooo oooo
|
||||
//o = offset
|
||||
void ARM::thumb_op_branch_long_prefix() {
|
||||
uint11 offsethi = instruction();
|
||||
|
||||
r(14) = offsethi;
|
||||
}
|
||||
|
||||
//bl address
|
||||
//1111 1ooo oooo oooo
|
||||
//o = offset
|
||||
void ARM::thumb_op_branch_long() {
|
||||
uint11 offsethi = instruction();
|
||||
uint11 offsetlo = pipeline.decode.instruction;
|
||||
void ARM::thumb_op_branch_long_suffix() {
|
||||
uint11 offsetlo = instruction();
|
||||
|
||||
int22 displacement = (offsethi << 11) | (offsetlo << 0);
|
||||
r(14) = (r(15) - 2) | 1;
|
||||
int22 displacement = ((uint11)r(14) << 11) | offsetlo;
|
||||
r(14) = r(15) | 1;
|
||||
r(15) += displacement * 2;
|
||||
}
|
|
@ -33,4 +33,5 @@ void thumb_op_move_multiple();
|
|||
void thumb_op_software_interrupt();
|
||||
void thumb_op_branch_conditional();
|
||||
void thumb_op_branch_short();
|
||||
void thumb_op_branch_long();
|
||||
void thumb_op_branch_long_prefix();
|
||||
void thumb_op_branch_long_suffix();
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef PROCESSOR_HPP
|
||||
#define PROCESSOR_HPP
|
||||
|
||||
#include <base/base.hpp>
|
||||
|
||||
#endif
|
|
@ -15,7 +15,7 @@ void CPU::step(unsigned clocks) {
|
|||
smp.clock -= clocks * (uint64)smp.frequency;
|
||||
ppu.clock -= clocks;
|
||||
for(unsigned i = 0; i < coprocessors.size(); i++) {
|
||||
Processor &chip = *coprocessors[i];
|
||||
auto &chip = *coprocessors[i];
|
||||
chip.clock -= clocks * (uint64)chip.frequency;
|
||||
}
|
||||
input.port1->clock -= clocks * (uint64)input.port1->frequency;
|
||||
|
@ -41,7 +41,7 @@ void CPU::synchronize_ppu() {
|
|||
|
||||
void CPU::synchronize_coprocessors() {
|
||||
for(unsigned i = 0; i < coprocessors.size(); i++) {
|
||||
Processor &chip = *coprocessors[i];
|
||||
auto &chip = *coprocessors[i];
|
||||
if(chip.clock < 0) co_switch(chip.thread);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
class CPU : public Processor, public CPUcore, public PPUcounter {
|
||||
public:
|
||||
struct CPU : Thread, public CPUcore, public PPUcounter {
|
||||
uint8 wram[128 * 1024];
|
||||
|
||||
enum : bool { Threaded = true };
|
||||
array<Processor*> coprocessors;
|
||||
array<Thread*> coprocessors;
|
||||
alwaysinline void step(unsigned clocks);
|
||||
alwaysinline void synchronize_smp();
|
||||
void synchronize_ppu();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifdef CPU_CPP
|
||||
|
||||
void CPU::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
CPUcore::core_serialize(s);
|
||||
PPUcounter::serialize(s);
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#include "SPC_DSP.h"
|
||||
|
||||
class DSP : public Processor {
|
||||
public:
|
||||
struct DSP : Thread {
|
||||
enum : bool { Threaded = false };
|
||||
alwaysinline void step(unsigned clocks);
|
||||
alwaysinline void synchronize_smp();
|
||||
|
|
|
@ -11,7 +11,7 @@ static void dsp_state_load(unsigned char **in, void *out, size_t size) {
|
|||
}
|
||||
|
||||
void DSP::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
s.array(samplebuffer);
|
||||
|
||||
unsigned char state[SPC_DSP::state_size];
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
class PPU : public Processor, public PPUcounter {
|
||||
public:
|
||||
struct PPU : Thread, public PPUcounter {
|
||||
uint8 vram[128 * 1024];
|
||||
uint8 oam[544];
|
||||
uint8 cgram[512];
|
||||
|
|
|
@ -13,7 +13,7 @@ void PPUcounter::serialize(serializer &s) {
|
|||
}
|
||||
|
||||
void PPU::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
PPUcounter::serialize(s);
|
||||
|
||||
s.array(vram);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
class PPU : public Processor, public PPUcounter {
|
||||
public:
|
||||
struct PPU : Thread, public PPUcounter {
|
||||
uint8 vram[64 * 1024];
|
||||
uint8 oam[544];
|
||||
uint8 cgram[512];
|
||||
|
|
|
@ -13,7 +13,7 @@ void PPUcounter::serialize(serializer &s) {
|
|||
}
|
||||
|
||||
void PPU::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
PPUcounter::serialize(s);
|
||||
|
||||
s.array(vram);
|
||||
|
|
|
@ -34,8 +34,8 @@ void SMP::enter() {
|
|||
}
|
||||
|
||||
void SMP::power() {
|
||||
Processor::frequency = system.apu_frequency();
|
||||
Processor::clock = 0;
|
||||
Thread::frequency = system.apu_frequency();
|
||||
Thread::clock = 0;
|
||||
|
||||
timer0.target = 0;
|
||||
timer1.target = 0;
|
||||
|
@ -82,7 +82,7 @@ void SMP::reset() {
|
|||
}
|
||||
|
||||
void SMP::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(apuram, 64 * 1024);
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
class SMP : public Processor {
|
||||
public:
|
||||
struct SMP : Thread {
|
||||
static const uint8 iplrom[64];
|
||||
uint8 *apuram;
|
||||
|
||||
|
|
|
@ -3,11 +3,7 @@
|
|||
#define ARMDSP_CPP
|
||||
namespace SNES {
|
||||
|
||||
static bool trace = 0;
|
||||
|
||||
#include "opcodes.cpp"
|
||||
#include "memory.cpp"
|
||||
#include "disassembler.cpp"
|
||||
#include "serialization.cpp"
|
||||
ArmDSP armdsp;
|
||||
|
||||
|
@ -16,13 +12,13 @@ void ArmDSP::Enter() { armdsp.enter(); }
|
|||
void ArmDSP::enter() {
|
||||
//reset hold delay
|
||||
while(bridge.reset) {
|
||||
tick();
|
||||
step(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
//reset sequence delay
|
||||
if(bridge.ready == false) {
|
||||
tick(65536);
|
||||
step(65536);
|
||||
bridge.ready = true;
|
||||
}
|
||||
|
||||
|
@ -33,55 +29,16 @@ void ArmDSP::enter() {
|
|||
|
||||
if(exception) {
|
||||
print("* ARM unknown instruction\n");
|
||||
print("\n", disassemble_registers());
|
||||
print("\n", disassemble_opcode(pipeline.instruction.address), "\n");
|
||||
while(true) tick(frequency);
|
||||
while(true) step(frequency);
|
||||
}
|
||||
|
||||
if(pipeline.reload) {
|
||||
pipeline.reload = false;
|
||||
pipeline.prefetch.address = r[15];
|
||||
pipeline.prefetch.opcode = bus_readword(r[15]);
|
||||
r[15].step();
|
||||
}
|
||||
|
||||
pipeline.instruction = pipeline.prefetch;
|
||||
pipeline.prefetch.address = r[15];
|
||||
pipeline.prefetch.opcode = bus_readword(r[15]);
|
||||
r[15].step();
|
||||
|
||||
//todo: bus_readword() calls tick(); so we need to prefetch this as well
|
||||
//pipeline.mdr.address = r[15];
|
||||
//pipeline.mdr.opcode = bus_readword(r[15]);
|
||||
|
||||
//if(pipeline.instruction.address == 0x00000208) trace = 1;
|
||||
if(trace) {
|
||||
print("\n", disassemble_registers(), "\n");
|
||||
print(disassemble_opcode(pipeline.instruction.address), "\n");
|
||||
usleep(200000);
|
||||
}
|
||||
//trace = 0;
|
||||
|
||||
instruction = pipeline.instruction.opcode;
|
||||
if(!condition()) continue;
|
||||
if((instruction & 0x0fc000f0) == 0x00000090) { op_multiply(); continue; }
|
||||
if((instruction & 0x0fb000f0) == 0x01000000) { op_move_to_register_from_status_register(); continue; }
|
||||
if((instruction & 0x0fb000f0) == 0x01200000) { op_move_to_status_register_from_register(); continue; }
|
||||
if((instruction & 0x0e000010) == 0x00000000) { op_data_immediate_shift(); continue; }
|
||||
if((instruction & 0x0e000090) == 0x00000010) { op_data_register_shift(); continue; }
|
||||
if((instruction & 0x0e000000) == 0x02000000) { op_data_immediate(); continue; }
|
||||
if((instruction & 0x0e000000) == 0x04000000) { op_move_immediate_offset(); continue; }
|
||||
if((instruction & 0x0e000010) == 0x06000000) { op_move_register_offset(); continue; }
|
||||
if((instruction & 0x0e000000) == 0x08000000) { op_move_multiple(); continue; }
|
||||
if((instruction & 0x0e000000) == 0x0a000000) { op_branch(); continue; }
|
||||
|
||||
exception = true;
|
||||
arm_step();
|
||||
}
|
||||
}
|
||||
|
||||
void ArmDSP::tick(unsigned clocks) {
|
||||
void ArmDSP::step(unsigned clocks) {
|
||||
if(bridge.timer && --bridge.timer == 0);
|
||||
step(clocks);
|
||||
Coprocessor::step(clocks);
|
||||
synchronize_cpu();
|
||||
}
|
||||
|
||||
|
@ -150,6 +107,7 @@ void ArmDSP::reset() {
|
|||
|
||||
void ArmDSP::arm_reset() {
|
||||
create(ArmDSP::Enter, 21477272);
|
||||
ARM::power();
|
||||
|
||||
bridge.ready = false;
|
||||
bridge.signal = false;
|
||||
|
@ -157,12 +115,6 @@ void ArmDSP::arm_reset() {
|
|||
bridge.timerlatch = 0;
|
||||
bridge.cputoarm.ready = false;
|
||||
bridge.armtocpu.ready = false;
|
||||
|
||||
for(auto &rd : r) rd = 0;
|
||||
shiftercarry = 0;
|
||||
exception = 0;
|
||||
pipeline.reload = true;
|
||||
r[15].write = [&] { pipeline.reload = true; };
|
||||
}
|
||||
|
||||
ArmDSP::ArmDSP() {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//ARMv3 (ARM6)
|
||||
|
||||
struct ArmDSP : public Coprocessor {
|
||||
struct ArmDSP : Processor::ARM, public Coprocessor {
|
||||
uint8 *firmware;
|
||||
uint8 *programROM;
|
||||
uint8 *dataROM;
|
||||
|
@ -10,7 +10,13 @@ struct ArmDSP : public Coprocessor {
|
|||
|
||||
static void Enter();
|
||||
void enter();
|
||||
void tick(unsigned clocks = 1);
|
||||
|
||||
void step(unsigned clocks);
|
||||
uint32 bus_read(uint32 addr, uint32 size);
|
||||
void bus_write(uint32 addr, uint32 size, uint32 word);
|
||||
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
|
||||
void init();
|
||||
void load();
|
||||
|
@ -19,46 +25,9 @@ struct ArmDSP : public Coprocessor {
|
|||
void reset();
|
||||
void arm_reset();
|
||||
|
||||
void serialize(serializer&);
|
||||
ArmDSP();
|
||||
~ArmDSP();
|
||||
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
|
||||
//opcodes.cpp
|
||||
bool condition();
|
||||
void opcode(uint32 data);
|
||||
void lsl(bool &c, uint32 &rm, uint32 rs);
|
||||
void lsr(bool &c, uint32 &rm, uint32 rs);
|
||||
void asr(bool &c, uint32 &rm, uint32 rs);
|
||||
void ror(bool &c, uint32 &rm, uint32 rs);
|
||||
void rrx(bool &c, uint32 &rm);
|
||||
|
||||
void op_multiply();
|
||||
void op_move_to_status_register_from_register();
|
||||
void op_move_to_register_from_status_register();
|
||||
void op_data_immediate_shift();
|
||||
void op_data_register_shift();
|
||||
void op_data_immediate();
|
||||
void op_move_immediate_offset();
|
||||
void op_move_register_offset();
|
||||
void op_move_multiple();
|
||||
void op_branch();
|
||||
|
||||
//memory.cpp
|
||||
uint8 bus_read(uint32 addr);
|
||||
void bus_write(uint32 addr, uint8 data);
|
||||
|
||||
uint32 bus_readword(uint32 addr);
|
||||
void bus_writeword(uint32 addr, uint32 data);
|
||||
void bus_writebyte(uint32 addr, uint32 data);
|
||||
|
||||
//disassembler.cpp
|
||||
string disassemble_opcode(uint32 pc);
|
||||
string disassemble_registers();
|
||||
|
||||
//serialization.cpp
|
||||
void serialize(serializer&);
|
||||
};
|
||||
|
||||
extern ArmDSP armdsp;
|
||||
|
|
|
@ -1,245 +0,0 @@
|
|||
#ifdef ARMDSP_CPP
|
||||
|
||||
string ArmDSP::disassemble_opcode(uint32 pc) {
|
||||
static string conditions[] = { "eq", "ne", "cs", "cc", "mi" ,"pl", "vs", "vc", "hi", "ls", "ge", "lt", "gt", "le", "" /*al*/, "nv" };
|
||||
static string opcodes[] = { "and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc", "tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn" };
|
||||
static string registers[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc" };
|
||||
static string indices[] = { "da", "ia", "db", "ib" };
|
||||
|
||||
static auto is_move = [](uint4 opcode) { return opcode == 13 || opcode == 15; };
|
||||
static auto is_comp = [](uint4 opcode) { return opcode >= 8 && opcode <= 11; };
|
||||
static auto is_math = [](uint4 opcode) { return opcode < 8 || opcode == 12 || opcode == 14; };
|
||||
|
||||
string output{hex<8>(pc), " "};
|
||||
|
||||
uint32 instruction = bus_readword(pc);
|
||||
output.append(hex<8>(instruction), " ");
|
||||
|
||||
//multiply
|
||||
//(mul,mla){condition}{s} rd,rm,rs,rn
|
||||
if((instruction & 0x0fc000f0) == 0x00000090) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint1 accumulate = instruction >> 21;
|
||||
uint1 save = instruction >> 20;
|
||||
uint4 rd = instruction >> 16;
|
||||
uint4 rn = instruction >> 12;
|
||||
uint4 rs = instruction >> 8;
|
||||
uint4 rm = instruction >> 0;
|
||||
|
||||
output.append(accumulate ? "mla" : "mul", conditions[condition], save ? "s " : " ");
|
||||
output.append(registers[rd], ",", registers[rm], ",", registers[rs]);
|
||||
if(accumulate) output.append(",", registers[rn]);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//move to register from status register
|
||||
//mrs{condition} rd,(c,s)psr
|
||||
if((instruction & 0x0fb000f0) == 0x01000000) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint1 psr = instruction >> 22;
|
||||
uint4 rd = instruction >> 12;
|
||||
|
||||
output.append("mrs", conditions[condition], " ");
|
||||
output.append(registers[rd], ",", psr ? "spsr" : "cpsr");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//move to status register from register
|
||||
//msr{condition} (c,s)psr:{fields},rm
|
||||
if((instruction & 0x0fb000f0) == 0x01200000) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint1 psr = instruction >> 22;
|
||||
uint4 field = instruction >> 16;
|
||||
|
||||
output.append("msr", conditions[condition], " ");
|
||||
output.append(psr ? "spsr:" : "cpsr:",
|
||||
field & 1 ? "c" : "",
|
||||
field & 2 ? "x" : "",
|
||||
field & 4 ? "s" : "",
|
||||
field & 8 ? "f" : "",
|
||||
",", registers[(uint4)instruction]);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//data immediate shift
|
||||
//{opcode}{condition}{s} rd,rm {shift} #immediate
|
||||
//{opcode}{condition} rn,rm {shift} #immediate
|
||||
//{opcode}{condition}{s} rd,rn,rm {shift} #immediate
|
||||
if((instruction & 0x0e000010) == 0x00000000) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint4 opcode = instruction >> 21;
|
||||
uint1 save = instruction >> 20;
|
||||
uint4 rn = instruction >> 16;
|
||||
uint4 rd = instruction >> 12;
|
||||
uint5 shift = instruction >> 7;
|
||||
uint2 op = instruction >> 5;
|
||||
uint4 rm = instruction;
|
||||
|
||||
output.append(opcodes[opcode], conditions[condition]);
|
||||
if(is_move(opcode)) output.append(save ? "s " : " ", registers[rd]);
|
||||
if(is_comp(opcode)) output.append(" ", registers[rn]);
|
||||
if(is_math(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn]);
|
||||
output.append(",", registers[rm]);
|
||||
if(op == 0 && shift != 0) output.append(" lsl #", shift);
|
||||
if(op == 1) output.append(" lsr #", shift == 0 ? 32u : (unsigned)shift);
|
||||
if(op == 2) output.append(" asr #", shift == 0 ? 32u : (unsigned)shift);
|
||||
if(op == 3 && shift != 0) output.append(" ror #", shift);
|
||||
if(op == 3 && shift == 0) output.append(" rrx");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//data register shift
|
||||
//{opcode}{condition}{s} rd,rm {shift} rs
|
||||
//{opcode}{condition} rn,rm {shift} rs
|
||||
//{opcode}{condition}{s} rd,rn,rm {shift} rs
|
||||
if((instruction & 0x0e000090) == 0x00000010) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint4 opcode = instruction >> 21;
|
||||
uint1 save = instruction >> 20;
|
||||
uint4 rn = instruction >> 16;
|
||||
uint4 rd = instruction >> 12;
|
||||
uint4 rs = instruction >> 8;
|
||||
uint2 mode = instruction >> 5;
|
||||
uint4 rm = instruction;
|
||||
|
||||
output.append(opcodes[opcode], conditions[condition]);
|
||||
if(is_move(opcode)) output.append(save ? "s " : " ", registers[rd], ",");
|
||||
if(is_comp(opcode)) output.append(registers[rn], ",");
|
||||
if(is_math(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn], ",");
|
||||
output.append(registers[rm]);
|
||||
if(mode == 0) output.append(" lsl ");
|
||||
if(mode == 1) output.append(" lsr ");
|
||||
if(mode == 2) output.append(" asr ");
|
||||
if(mode == 3) output.append(" ror ");
|
||||
output.append(registers[rs]);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//data immediate
|
||||
//{opcode}{condition}{s} rd,#immediate
|
||||
//{opcode}{condition} rn,#immediate
|
||||
//{opcode}{condition}{s} rd,rn,#immediate
|
||||
if((instruction & 0x0e000000) == 0x02000000) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint4 opcode = instruction >> 21;
|
||||
uint1 save = instruction >> 20;
|
||||
uint4 rn = instruction >> 16;
|
||||
uint4 rd = instruction >> 12;
|
||||
uint4 rotate = instruction >> 8;
|
||||
uint8 immediate = instruction;
|
||||
|
||||
uint32 shifter = (immediate >> (rotate << 1)) | (immediate << (32 - (rotate << 1)));
|
||||
output.append(opcodes[opcode], conditions[condition]);
|
||||
if(is_move(opcode)) output.append(save ? "s " : " ", registers[rd]);
|
||||
if(is_comp(opcode)) output.append(" ", registers[rn]);
|
||||
if(is_math(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn]);
|
||||
output.append(",#0x", hex<8>(shifter));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//move immediate offset
|
||||
//(ldr,str){condition}{b} rd,[rn{,+/-offset}]{!}
|
||||
//(ldr,str){condition}{b} rd,[rn]{,+/-offset}
|
||||
if((instruction & 0x0e000000) == 0x04000000) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint1 p = instruction >> 24;
|
||||
uint1 u = instruction >> 23;
|
||||
uint1 b = instruction >> 22;
|
||||
uint1 w = instruction >> 21;
|
||||
uint1 load = instruction >> 20;
|
||||
uint4 rn = instruction >> 16;
|
||||
uint4 rd = instruction >> 12;
|
||||
uint12 immediate = instruction;
|
||||
|
||||
output.append(load ? "ldr" : "str", conditions[condition], b ? "b " : " ");
|
||||
output.append(registers[rd], ",[", registers[rn]);
|
||||
if(p == 0) output.append("]");
|
||||
if(immediate) output.append(",", u ? "+" : "-", "0x", hex<3>(immediate));
|
||||
if(p == 1) output.append("]");
|
||||
if(p == 0 || w == 1) output.append("!");
|
||||
|
||||
if(rn == 15) output.append(" =0x", hex<8>(bus_readword(pc + 8 + (u ? +immediate : -immediate))));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//move register offset
|
||||
//(ldr)(str){condition}{b} rd,[rn,rm {mode} #immediate]{!}
|
||||
//(ldr)(str){condition}{b} rd,[rn],rm {mode} #immediate
|
||||
if((instruction & 0x0e000010) == 0x06000000) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint1 p = instruction >> 24;
|
||||
uint1 u = instruction >> 23;
|
||||
uint1 b = instruction >> 22;
|
||||
uint1 w = instruction >> 21;
|
||||
uint1 load = instruction >> 20;
|
||||
uint4 rn = instruction >> 16;
|
||||
uint4 rd = instruction >> 12;
|
||||
uint5 shift = instruction >> 7;
|
||||
uint2 mode = instruction >> 5;
|
||||
uint4 rm = instruction;
|
||||
|
||||
output.append(load ? "ldr" : "str", conditions[condition], b ? "b " : " ");
|
||||
output.append(registers[rd], ",[", registers[rn]);
|
||||
if(p == 0) output.append("]");
|
||||
output.append(",", u ? "+" : "-", registers[rm]);
|
||||
if(mode == 0 && shift != 0) output.append(" lsl #", shift);
|
||||
if(mode == 1) output.append(" lsr #", shift == 0 ? 32u : (unsigned)shift);
|
||||
if(mode == 2) output.append(" asr #", shift == 0 ? 32u : (unsigned)shift);
|
||||
if(mode == 3 && shift != 0) output.append(" ror #", shift);
|
||||
if(mode == 3 && shift == 0) output.append(" rrx");
|
||||
if(p == 1) output.append("]");
|
||||
if(p == 0 || w == 1) output.append("!");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//move multiple
|
||||
//(ldm,stm){condition}{mode} rn{!},{r...}
|
||||
if((instruction & 0x0e000000) == 0x08000000) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint4 rn = instruction >> 16;
|
||||
|
||||
output.append(instruction & 0x00100000 ? "ldm" : "stm", conditions[condition], indices[(uint2)(instruction >> 23)]);
|
||||
output.append(" ", registers[rn], instruction & 0x00200000 ? "!" : "", ",{");
|
||||
for(unsigned n = 0; n < 16; n++) if(instruction & (1 << n)) output.append(registers[n], ",");
|
||||
output.rtrim<1>(",");
|
||||
output.append("}");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//branch
|
||||
//b{l}{condition} address
|
||||
if((instruction & 0x0e000000) == 0x0a000000) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint1 l = instruction >> 24;
|
||||
|
||||
output.append("b", l ? "l" : "", conditions[condition]);
|
||||
output.append(" 0x", hex<8>(pc + 8 + (int24)instruction * 4));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
output.append("???");
|
||||
return output;
|
||||
}
|
||||
|
||||
string ArmDSP::disassemble_registers() {
|
||||
return {
|
||||
"r0:", hex<8>(r[ 0]), " r1:", hex<8>(r[ 1]), " r2:", hex<8>(r[ 2]), " r3:", hex<8>(r[ 3]),
|
||||
" r4:", hex<8>(r[ 4]), " r5:", hex<8>(r[ 5]), " r6:", hex<8>(r[ 6]), " r7:", hex<8>(r[ 7]), " ",
|
||||
"cpsr:", cpsr.n ? "N" : "n", cpsr.z ? "Z" : "z", cpsr.c ? "C" : "c", cpsr.v ? "V" : "v", "\n",
|
||||
"r8:", hex<8>(r[ 8]), " r9:", hex<8>(r[ 9]), " r10:", hex<8>(r[10]), " r11:", hex<8>(r[11]),
|
||||
" r12:", hex<8>(r[12]), " r13:", hex<8>(r[13]), " r14:", hex<8>(r[14]), " r15:", hex<8>(r[15]), " ",
|
||||
"spsr:", spsr.n ? "N" : "n", spsr.z ? "Z" : "z", spsr.c ? "C" : "c", spsr.v ? "V" : "v"
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,15 +1,31 @@
|
|||
#ifdef ARMDSP_CPP
|
||||
|
||||
uint8 ArmDSP::bus_read(uint32 addr) {
|
||||
uint32 ArmDSP::bus_read(uint32 addr, uint32 size) {
|
||||
static auto adjust = [&](uint32 word, uint32 addr, uint32 size) {
|
||||
unsigned rotate = (addr & 3) << 3;
|
||||
word = (word >> rotate) | (word << (32 - rotate));
|
||||
return word & (~0u >> (32 - size));
|
||||
};
|
||||
|
||||
static auto memory = [&](const uint8 *memory, uint32 addr, uint32 size) {
|
||||
memory += addr & ~3;
|
||||
uint32 word = 0;
|
||||
word |= *memory++ << 0;
|
||||
word |= *memory++ << 8;
|
||||
word |= *memory++ << 16;
|
||||
word |= *memory++ << 24;
|
||||
return adjust(word, addr, size);
|
||||
};
|
||||
|
||||
switch(addr & 0xe0000000) {
|
||||
case 0x00000000: return programROM[addr & 0x0001ffff];
|
||||
case 0x20000000: return pipeline.mdr.opcode >> ((addr & 3) << 3);
|
||||
case 0x40000000: break; //MMIO
|
||||
case 0x60000000: return 0x40404001 >> ((addr & 3) << 3);
|
||||
case 0x80000000: return pipeline.mdr.opcode >> ((addr & 3) << 3);
|
||||
case 0xa0000000: return dataROM[addr & 0x00007fff];
|
||||
case 0xc0000000: return pipeline.mdr.opcode >> ((addr & 3) << 3);
|
||||
case 0xe0000000: return programRAM[addr & 0x00003fff];
|
||||
case 0x00000000: return memory(programROM, addr & 0x1ffff, size);
|
||||
case 0x20000000: return adjust(pipeline.fetch.instruction, addr, size);
|
||||
case 0x40000000: break;
|
||||
case 0x60000000: return adjust(0x40404001, addr, size);
|
||||
case 0x80000000: return adjust(pipeline.fetch.instruction, addr, size);
|
||||
case 0xa0000000: return memory(dataROM, addr & 0x7fff, size);
|
||||
case 0xc0000000: return adjust(pipeline.fetch.instruction, addr, size);
|
||||
case 0xe0000000: return memory(programRAM, addr & 0x3fff, size);
|
||||
}
|
||||
|
||||
addr &= 0xe000003f;
|
||||
|
@ -17,29 +33,51 @@ uint8 ArmDSP::bus_read(uint32 addr) {
|
|||
if(addr == 0x40000010) {
|
||||
if(bridge.cputoarm.ready) {
|
||||
bridge.cputoarm.ready = false;
|
||||
return bridge.cputoarm.data;
|
||||
return adjust(bridge.cputoarm.data, addr, size);
|
||||
}
|
||||
}
|
||||
|
||||
if(addr == 0x40000020) {
|
||||
return bridge.status();
|
||||
return adjust(bridge.status(), addr, size);
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
return 0u;
|
||||
}
|
||||
|
||||
void ArmDSP::bus_write(uint32 addr, uint8 data) {
|
||||
void ArmDSP::bus_write(uint32 addr, uint32 size, uint32 word) {
|
||||
static auto memory = [](uint8 *memory, uint32 addr, uint32 size, uint32 word) {
|
||||
switch(size) {
|
||||
case Word:
|
||||
memory += addr & ~3;
|
||||
*memory++ = word >> 0;
|
||||
*memory++ = word >> 8;
|
||||
*memory++ = word >> 16;
|
||||
*memory++ = word >> 24;
|
||||
break;
|
||||
case Byte:
|
||||
memory += addr;
|
||||
*memory++ = word >> 0;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
switch(addr & 0xe0000000) {
|
||||
case 0x40000000: break; //MMIO
|
||||
case 0xe0000000: programRAM[addr & 0x00003fff] = data; return;
|
||||
default: return;
|
||||
case 0x00000000: return;
|
||||
case 0x20000000: return;
|
||||
case 0x40000000: break;
|
||||
case 0x60000000: return;
|
||||
case 0x80000000: return;
|
||||
case 0xa0000000: return;
|
||||
case 0xc0000000: return;
|
||||
case 0xe0000000: return memory(programRAM, addr & 0x3fff, size, word);
|
||||
}
|
||||
|
||||
addr &= 0xe000003f;
|
||||
word &= 0x000000ff;
|
||||
|
||||
if(addr == 0x40000000) {
|
||||
bridge.armtocpu.ready = true;
|
||||
bridge.armtocpu.data = data;
|
||||
bridge.armtocpu.data = word;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -48,38 +86,14 @@ void ArmDSP::bus_write(uint32 addr, uint8 data) {
|
|||
return;
|
||||
}
|
||||
|
||||
if(addr == 0x40000020) bridge.timerlatch = (bridge.timerlatch & 0xffff00) | (data << 0);
|
||||
if(addr == 0x40000024) bridge.timerlatch = (bridge.timerlatch & 0xff00ff) | (data << 8);
|
||||
if(addr == 0x40000028) bridge.timerlatch = (bridge.timerlatch & 0x00ffff) | (data << 16);
|
||||
if(addr == 0x40000020) { bridge.timerlatch = (bridge.timerlatch & 0xffff00) | (word << 0); return; }
|
||||
if(addr == 0x40000024) { bridge.timerlatch = (bridge.timerlatch & 0xff00ff) | (word << 8); return; }
|
||||
if(addr == 0x40000028) { bridge.timerlatch = (bridge.timerlatch & 0x00ffff) | (word << 16); return; }
|
||||
|
||||
if(addr == 0x40000028) {
|
||||
if(addr == 0x4000002c) {
|
||||
bridge.timer = bridge.timerlatch;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 ArmDSP::bus_readword(uint32 addr) {
|
||||
tick();
|
||||
addr &= ~3;
|
||||
return (
|
||||
(bus_read(addr + 0) << 0)
|
||||
| (bus_read(addr + 1) << 8)
|
||||
| (bus_read(addr + 2) << 16)
|
||||
| (bus_read(addr + 3) << 24)
|
||||
);
|
||||
}
|
||||
|
||||
void ArmDSP::bus_writeword(uint32 addr, uint32 data) {
|
||||
tick();
|
||||
addr &= ~3;
|
||||
bus_write(addr + 0, data >> 0);
|
||||
bus_write(addr + 1, data >> 8);
|
||||
bus_write(addr + 2, data >> 16);
|
||||
bus_write(addr + 3, data >> 24);
|
||||
}
|
||||
|
||||
void ArmDSP::bus_writebyte(uint32 addr, uint32 data) {
|
||||
tick();
|
||||
return bus_write(addr, data);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,414 +0,0 @@
|
|||
#ifdef ARMDSP_CPP
|
||||
|
||||
bool ArmDSP::condition() {
|
||||
uint4 condition = instruction >> 28;
|
||||
switch(condition) {
|
||||
case 0: return cpsr.z == 1; //EQ (equal)
|
||||
case 1: return cpsr.z == 0; //NE (not equal)
|
||||
case 2: return cpsr.c == 1; //CS (carry set)
|
||||
case 3: return cpsr.c == 0; //CC (carry clear)
|
||||
case 4: return cpsr.n == 1; //MI (negative)
|
||||
case 5: return cpsr.n == 0; //PL (positive)
|
||||
case 6: return cpsr.v == 1; //VS (overflow)
|
||||
case 7: return cpsr.v == 0; //VC (no overflow)
|
||||
case 8: return cpsr.c == 1 && cpsr.z == 0; //HI (unsigned higher)
|
||||
case 9: return cpsr.c == 0 || cpsr.z == 1; //LS (unsigned lower or same)
|
||||
case 10: return cpsr.n == cpsr.v; //GE (signed greater than or equal)
|
||||
case 11: return cpsr.n != cpsr.v; //LT (signed less than)
|
||||
case 12: return cpsr.z == 0 && cpsr.n == cpsr.v; //GT (signed greater than)
|
||||
case 13: return cpsr.z == 1 || cpsr.n != cpsr.v; //LE (signed less than or equal)
|
||||
case 14: return true; //AL (always)
|
||||
case 15: return false; //NV (never)
|
||||
}
|
||||
}
|
||||
|
||||
//rd = target
|
||||
//rn = source
|
||||
//rm = modifier
|
||||
//ri = original target
|
||||
//ro = modified target
|
||||
void ArmDSP::opcode(uint32 rm) {
|
||||
uint4 opcode = instruction >> 21;
|
||||
uint1 save = instruction >> 20;
|
||||
uint4 n = instruction >> 16;
|
||||
uint4 d = instruction >> 12;
|
||||
|
||||
uint32 rn = r[n];
|
||||
|
||||
//comparison opcodes always update flags (debug test)
|
||||
//this can be removed later: s=0 opcode=8-11 is invalid
|
||||
if(opcode >= 8 && opcode <= 11) assert(save == 1);
|
||||
|
||||
auto test = [&](uint32 result) {
|
||||
if(save) {
|
||||
cpsr.n = result >> 31;
|
||||
cpsr.z = result == 0;
|
||||
cpsr.c = shiftercarry;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
auto math = [&](uint32 source, uint32 modify, bool carry) {
|
||||
uint32 result = source + modify + carry;
|
||||
if(save) {
|
||||
uint32 overflow = ~(source ^ modify) & (source ^ result);
|
||||
cpsr.n = result >> 31;
|
||||
cpsr.z = result == 0;
|
||||
cpsr.c = (1u << 31) & (overflow ^ source ^ modify ^ result);
|
||||
cpsr.v = (1u << 31) & (overflow);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
switch(opcode) {
|
||||
case 0: r[d] = test(rn & rm); break; //AND
|
||||
case 1: r[d] = test(rn ^ rm); break; //EOR
|
||||
case 2: r[d] = math(rn, ~rm, 1); break; //SUB
|
||||
case 3: r[d] = math(rm, ~rn, 1); break; //RSB
|
||||
case 4: r[d] = math(rn, rm, 0); break; //ADD
|
||||
case 5: r[d] = math(rn, rm, cpsr.c); break; //ADC
|
||||
case 6: r[d] = math(rn, ~rm, cpsr.c); break; //SBC
|
||||
case 7: r[d] = math(rm, ~rn, cpsr.c); break; //RSC
|
||||
case 8: test(rn & rm); break; //TST
|
||||
case 9: test(rn ^ rm); break; //TEQ
|
||||
case 10: math(rn, ~rm, 1); break; //CMP
|
||||
case 11: math(rn, rm, 0); break; //CMN
|
||||
case 12: r[d] = test(rn | rm); break; //ORR
|
||||
case 13: r[d] = test(rm); break; //MOV
|
||||
case 14: r[d] = test(rn &~rm); break; //BIC
|
||||
case 15: r[d] = test(~rm); break; //MVN
|
||||
}
|
||||
}
|
||||
|
||||
//logical shift left
|
||||
void ArmDSP::lsl(bool &c, uint32 &rm, uint32 rs) {
|
||||
while(rs--) {
|
||||
c = rm >> 31;
|
||||
rm <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
//logical shift right
|
||||
void ArmDSP::lsr(bool &c, uint32 &rm, uint32 rs) {
|
||||
while(rs--) {
|
||||
c = rm & 1;
|
||||
rm >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
//arithmetic shift right
|
||||
void ArmDSP::asr(bool &c, uint32 &rm, uint32 rs) {
|
||||
while(rs--) {
|
||||
c = rm & 1;
|
||||
rm = (int32)rm >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
//rotate right
|
||||
void ArmDSP::ror(bool &c, uint32 &rm, uint32 rs) {
|
||||
while(rs--) {
|
||||
c = rm & 1;
|
||||
rm = (rm << 31) | (rm >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
//rotate right with extend
|
||||
void ArmDSP::rrx(bool &c, uint32 &rm) {
|
||||
bool carry = c;
|
||||
c = rm & 1;
|
||||
rm = (carry << 31) | (rm >> 1);
|
||||
}
|
||||
|
||||
//(mul,mla){condition}{s} rd,rm,rs,rn
|
||||
//cccc 0000 00as dddd nnnn ssss 1001 mmmm
|
||||
//c = condition
|
||||
//a = accumulate
|
||||
//s = save flags
|
||||
//d = rd
|
||||
//n = rn
|
||||
//s = rs
|
||||
//n = rm
|
||||
void ArmDSP::op_multiply() {
|
||||
uint1 accumulate = instruction >> 21;
|
||||
uint1 save = instruction >> 20;
|
||||
uint4 d = instruction >> 16;
|
||||
uint4 n = instruction >> 12;
|
||||
uint4 s = instruction >> 8;
|
||||
uint4 m = instruction >> 0;
|
||||
|
||||
//Booth's algorithm: two bit steps
|
||||
uint32 temp = r[s];
|
||||
while(temp) {
|
||||
temp >>= 2;
|
||||
tick();
|
||||
}
|
||||
r[d] = r[m] * r[s];
|
||||
|
||||
if(accumulate) {
|
||||
tick();
|
||||
r[d] += r[n];
|
||||
}
|
||||
|
||||
if(save) {
|
||||
cpsr.n = r[d] >> 31;
|
||||
cpsr.z = r[d] == 0;
|
||||
cpsr.c = 0; //undefined
|
||||
}
|
||||
}
|
||||
|
||||
//mrs{condition} rd,(c,s)psr
|
||||
//cccc 0001 0r00 ++++ dddd ---- 0000 ----
|
||||
//c = condition
|
||||
//r = SPSR (0 = CPSR)
|
||||
//d = rd
|
||||
void ArmDSP::op_move_to_register_from_status_register() {
|
||||
uint1 source = instruction >> 22;
|
||||
uint4 d = instruction >> 12;
|
||||
|
||||
r[d] = source ? spsr : cpsr;
|
||||
}
|
||||
|
||||
//msr{condition} (c,s)psr:{fields},rm
|
||||
//cccc 0001 0r10 ffff ++++ ---- 0000 mmmm
|
||||
//c = condition
|
||||
//r = SPSR (0 = CPSR)
|
||||
//f = field mask
|
||||
//m = rm
|
||||
void ArmDSP::op_move_to_status_register_from_register() {
|
||||
uint1 source = instruction >> 22;
|
||||
uint4 field = instruction >> 16;
|
||||
uint4 m = instruction;
|
||||
|
||||
PSR &psr = source ? spsr : cpsr;
|
||||
if(field & 1) psr.setc(r[m]);
|
||||
if(field & 2) psr.setx(r[m]);
|
||||
if(field & 4) psr.sets(r[m]);
|
||||
if(field & 8) psr.setf(r[m]);
|
||||
}
|
||||
|
||||
//{opcode}{condition}{s} rd,rm {shift} #immediate
|
||||
//{opcode}{condition} rn,rm {shift} #immediate
|
||||
//{opcode}{condition}{s} rd,rn,rm {shift} #immediate
|
||||
//cccc 000o ooos nnnn dddd llll lss0 mmmm
|
||||
//c = condition
|
||||
//o = opcode
|
||||
//s = save flags
|
||||
//n = rn
|
||||
//d = rd
|
||||
//l = shift immmediate
|
||||
//s = shift
|
||||
//m = rm
|
||||
void ArmDSP::op_data_immediate_shift() {
|
||||
uint1 save = instruction >> 20;
|
||||
uint5 shift = instruction >> 7;
|
||||
uint2 mode = instruction >> 5;
|
||||
uint4 m = instruction;
|
||||
|
||||
uint32 rs = shift;
|
||||
uint32 rm = r[m];
|
||||
bool c = cpsr.c;
|
||||
|
||||
if(mode == 0) lsl(c, rm, rs);
|
||||
if(mode == 1) lsr(c, rm, rs ? rs : 32);
|
||||
if(mode == 2) asr(c, rm, rs ? rs : 32);
|
||||
if(mode == 3) rs ? ror(c, rm, rs) : rrx(c, rm);
|
||||
|
||||
shiftercarry = c;
|
||||
opcode(rm);
|
||||
}
|
||||
|
||||
//{opcode}{condition}{s} rd,rm {shift} rs
|
||||
//{opcode}{condition} rn,rm {shift} rs
|
||||
//{opcode}{condition}{s} rd,rn,rm {shift} rs
|
||||
//cccc 000o ooos nnnn dddd ssss 0ss1 mmmm
|
||||
//c = condition
|
||||
//o = opcode
|
||||
//s = save flags
|
||||
//n = rn
|
||||
//d = rd
|
||||
//s = rs
|
||||
//s = shift
|
||||
//m = rm
|
||||
void ArmDSP::op_data_register_shift() {
|
||||
uint1 save = instruction >> 20;
|
||||
uint4 s = instruction >> 8;
|
||||
uint2 mode = instruction >> 5;
|
||||
uint4 m = instruction;
|
||||
|
||||
uint8 rs = r[s];
|
||||
uint32 rm = r[m];
|
||||
bool c = cpsr.c;
|
||||
|
||||
if(mode == 0) lsl(c, rm, rs < 33 ? rs : 33);
|
||||
if(mode == 1) lsr(c, rm, rs < 33 ? rs : 33);
|
||||
if(mode == 2) asr(c, rm, rs < 32 ? rs : 32);
|
||||
if(mode == 3 && rs) ror(c, rm, rs & 31 == 0 ? 32 : rs & 31);
|
||||
|
||||
shiftercarry = c;
|
||||
opcode(rm);
|
||||
}
|
||||
|
||||
//{opcode}{condition}{s} rd,#immediate
|
||||
//{opcode}{condition} rn,#immediate
|
||||
//{opcode}{condition}{s} rd,rn,#immediate
|
||||
//cccc 001o ooos nnnn dddd llll iiii iiii
|
||||
//c = condition
|
||||
//o = opcode
|
||||
//s = save flags
|
||||
//n = rn
|
||||
//d = rd
|
||||
//l = shift immediate
|
||||
//i = immediate
|
||||
void ArmDSP::op_data_immediate() {
|
||||
uint1 save = instruction >> 20;
|
||||
uint4 shift = instruction >> 8;
|
||||
uint8 immediate = instruction;
|
||||
|
||||
uint32 rs = shift << 1;
|
||||
uint32 rm = (immediate >> rs) | (immediate << (32 - rs));
|
||||
if(rs) shiftercarry = immediate >> 31;
|
||||
|
||||
opcode(rm);
|
||||
}
|
||||
|
||||
//(ldr,str){condition}{b} rd,[rn{,+/-offset}]{!}
|
||||
//(ldr,str){condition}{b} rd,[rn]{,+/-offset}
|
||||
//cccc 010p ubwl nnnn dddd iiii iiii iiii
|
||||
//c = condition
|
||||
//p = pre (0 = post-indexed addressing)
|
||||
//u = up (add/sub offset to base)
|
||||
//b = byte (1 = 32-bit)
|
||||
//w = writeback
|
||||
//l = load (0 = save)
|
||||
//n = rn
|
||||
//d = rd
|
||||
//i = immediate
|
||||
void ArmDSP::op_move_immediate_offset() {
|
||||
uint1 p = instruction >> 24;
|
||||
uint1 u = instruction >> 23;
|
||||
uint1 b = instruction >> 22;
|
||||
uint1 w = instruction >> 21;
|
||||
uint1 l = instruction >> 20;
|
||||
uint4 n = instruction >> 16;
|
||||
uint4 d = instruction >> 12;
|
||||
uint12 rm = instruction;
|
||||
|
||||
uint32 rn = r[n];
|
||||
auto &rd = r[d];
|
||||
|
||||
if(p == 1) rn = u ? rn + rm : rn - rm;
|
||||
if(l) {
|
||||
rd = bus_readword(rn);
|
||||
ror(shiftercarry, rd.data, 8 * (rn & 3));
|
||||
if(b) rd &= 0xff;
|
||||
} else {
|
||||
b ? bus_writebyte(rn, rd) : bus_writeword(rn, rd);
|
||||
}
|
||||
if(p == 0) rn = u ? rn + rm : rn - rm;
|
||||
|
||||
if(p == 0 || w == 1) r[n] = rn;
|
||||
}
|
||||
|
||||
//(ldr,str){condition}{b} rd,[rn,rm {mode} #immediate]{!}
|
||||
//(ldr,str){condition}{b} rd,[rn],rm {mode} #immediate
|
||||
//cccc 011p ubwl nnnn dddd llll lss0 mmmm
|
||||
//c = condition
|
||||
//p = pre (0 = post-indexed addressing)
|
||||
//u = up
|
||||
//b = byte (1 = 32-bit)
|
||||
//w = writeback
|
||||
//l = load (0 = save)
|
||||
//n = rn
|
||||
//d = rd
|
||||
//l = shift immediate
|
||||
//s = shift mode
|
||||
//m = rm
|
||||
void ArmDSP::op_move_register_offset() {
|
||||
uint1 p = instruction >> 24;
|
||||
uint1 u = instruction >> 23;
|
||||
uint1 b = instruction >> 22;
|
||||
uint1 w = instruction >> 21;
|
||||
uint1 l = instruction >> 20;
|
||||
uint4 n = instruction >> 16;
|
||||
uint4 d = instruction >> 12;
|
||||
uint5 immediate = instruction >> 7;
|
||||
uint2 mode = instruction >> 5;
|
||||
uint4 m = instruction;
|
||||
|
||||
uint32 rn = r[n];
|
||||
auto &rd = r[d];
|
||||
uint32 rs = immediate;
|
||||
uint32 rm = r[m];
|
||||
bool c = cpsr.c;
|
||||
|
||||
if(mode == 0) lsl(c, rm, rs);
|
||||
if(mode == 1) lsr(c, rm, rs ? rs : 32);
|
||||
if(mode == 2) asr(c, rm, rs ? rs : 32);
|
||||
if(mode == 3) rs ? ror(c, rm, rs) : rrx(c, rm);
|
||||
|
||||
if(p == 1) rn = u ? rn + rm : rn - rm;
|
||||
if(l) {
|
||||
rd = bus_readword(rn);
|
||||
ror(shiftercarry, rd.data, 8 * (rn & 3));
|
||||
if(b) rd &= 0xff;
|
||||
} else {
|
||||
b ? bus_writebyte(rn, rd) : bus_writeword(rn, rd);
|
||||
}
|
||||
if(p == 0) rn = u ? rn + rm : rn - rm;
|
||||
|
||||
if(p == 0 || w == 1) r[n] = rn;
|
||||
}
|
||||
|
||||
//(ldm,stm){condition}{mode} rn{!},{r...}
|
||||
//cccc 100p uswl nnnn llll llll llll llll
|
||||
//c = condition
|
||||
//p = pre (0 = post-indexed addressing)
|
||||
//u = up (add/sub offset to base)
|
||||
//s = ???
|
||||
//w = writeback
|
||||
//l = load (0 = save)
|
||||
//n = rn
|
||||
//l = register list
|
||||
void ArmDSP::op_move_multiple() {
|
||||
uint1 p = instruction >> 24;
|
||||
uint1 u = instruction >> 23;
|
||||
uint1 s = instruction >> 22;
|
||||
uint1 w = instruction >> 21;
|
||||
uint1 l = instruction >> 20;
|
||||
uint4 n = instruction >> 16;
|
||||
uint16 list = instruction;
|
||||
|
||||
uint32 rn = r[n];
|
||||
if(p == 0 && u == 1) rn = rn + 0; //IA
|
||||
if(p == 1 && u == 1) rn = rn + 4; //IB
|
||||
if(p == 1 && u == 0) rn = rn - bit::count(list) * 4 + 0; //DB
|
||||
if(p == 0 && u == 0) rn = rn - bit::count(list) * 4 + 4; //DA
|
||||
|
||||
for(unsigned n = 0; n < 16; n++) {
|
||||
if(list & (1 << n)) {
|
||||
if(l) r[n] = bus_readword(rn);
|
||||
else bus_writeword(rn, r[n]);
|
||||
rn += 4;
|
||||
}
|
||||
}
|
||||
|
||||
if(w) {
|
||||
if(u == 1) r[n] = r[n] + bit::count(list) * 4; //IA, IB
|
||||
if(u == 0) r[n] = r[n] - bit::count(list) * 4; //DA, DB
|
||||
}
|
||||
}
|
||||
|
||||
//b{l}{condition} address
|
||||
//cccc 101l dddd dddd dddd dddd dddd dddd
|
||||
//c = condition
|
||||
//l = link
|
||||
//d = displacement (24-bit signed)
|
||||
void ArmDSP::op_branch() {
|
||||
uint1 l = instruction >> 24;
|
||||
int24 displacement = instruction;
|
||||
|
||||
if(l) r[14] = r[15] - 4;
|
||||
r[15] += displacement * 4;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -15,101 +15,3 @@ struct Bridge {
|
|||
return (ready << 7) | (cputoarm.ready << 3) | (signal << 2) | (armtocpu.ready << 0);
|
||||
}
|
||||
} bridge;
|
||||
|
||||
struct PSR {
|
||||
bool n;
|
||||
bool z;
|
||||
bool c;
|
||||
bool v;
|
||||
bool i;
|
||||
bool f;
|
||||
uint5 m;
|
||||
|
||||
uint32 getf() const {
|
||||
return (n << 31) | (z << 30) | (c << 29) | (v << 28);
|
||||
}
|
||||
|
||||
uint32 gets() const {
|
||||
return 0u;
|
||||
}
|
||||
|
||||
uint32 getx() const {
|
||||
return 0u;
|
||||
}
|
||||
|
||||
uint32 getc() const {
|
||||
return (i << 7) | (f << 6) | (m << 0);
|
||||
}
|
||||
|
||||
void setf(uint32 data) {
|
||||
n = data & 0x80000000;
|
||||
z = data & 0x40000000;
|
||||
c = data & 0x20000000;
|
||||
v = data & 0x10000000;
|
||||
}
|
||||
|
||||
void sets(uint32 data) {
|
||||
}
|
||||
|
||||
void setx(uint32 data) {
|
||||
}
|
||||
|
||||
void setc(uint32 data) {
|
||||
i = data & 0x00000080;
|
||||
f = data & 0x00000040;
|
||||
m = data & 0x0000001f;
|
||||
}
|
||||
|
||||
operator uint32() const {
|
||||
return getf() | gets() | getx() | getc();
|
||||
}
|
||||
|
||||
PSR& operator=(uint32 data) {
|
||||
setf(data), sets(data), setx(data), setc(data);
|
||||
return *this;
|
||||
}
|
||||
} cpsr, spsr;
|
||||
|
||||
//r13 = SP (stack pointer)
|
||||
//r14 = LR (link register)
|
||||
//r15 = PC (program counter)
|
||||
struct Register {
|
||||
uint32 data;
|
||||
function<void ()> write;
|
||||
|
||||
operator unsigned() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
Register& operator=(uint32 n) {
|
||||
data = n;
|
||||
if(write) write();
|
||||
}
|
||||
|
||||
Register& operator=(const Register &source) { return operator=(source.data); }
|
||||
|
||||
Register& operator+=(uint32 n) { return operator=(data + n); }
|
||||
Register& operator-=(uint32 n) { return operator=(data - n); }
|
||||
Register& operator&=(uint32 n) { return operator=(data & n); }
|
||||
Register& operator|=(uint32 n) { return operator=(data | n); }
|
||||
Register& operator^=(uint32 n) { return operator=(data ^ n); }
|
||||
|
||||
void step() {
|
||||
data += 4;
|
||||
}
|
||||
} r[16];
|
||||
|
||||
bool shiftercarry;
|
||||
uint32 instruction;
|
||||
bool exception;
|
||||
|
||||
struct Pipeline {
|
||||
bool reload;
|
||||
struct Instruction {
|
||||
uint32 opcode;
|
||||
uint32 address;
|
||||
};
|
||||
Instruction instruction;
|
||||
Instruction prefetch;
|
||||
Instruction mdr;
|
||||
} pipeline;
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#ifdef ARMDSP_CPP
|
||||
|
||||
void ArmDSP::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
ARM::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(programRAM, 16 * 1024);
|
||||
|
||||
|
@ -14,51 +15,6 @@ void ArmDSP::serialize(serializer &s) {
|
|||
s.integer(bridge.reset);
|
||||
s.integer(bridge.ready);
|
||||
s.integer(bridge.signal);
|
||||
|
||||
s.integer(cpsr.n);
|
||||
s.integer(cpsr.z);
|
||||
s.integer(cpsr.c);
|
||||
s.integer(cpsr.v);
|
||||
s.integer(cpsr.i);
|
||||
s.integer(cpsr.f);
|
||||
s.integer(cpsr.m);
|
||||
|
||||
s.integer(spsr.n);
|
||||
s.integer(spsr.z);
|
||||
s.integer(spsr.c);
|
||||
s.integer(spsr.v);
|
||||
s.integer(spsr.i);
|
||||
s.integer(spsr.f);
|
||||
s.integer(spsr.m);
|
||||
|
||||
s.integer(r[ 0].data);
|
||||
s.integer(r[ 1].data);
|
||||
s.integer(r[ 2].data);
|
||||
s.integer(r[ 3].data);
|
||||
s.integer(r[ 4].data);
|
||||
s.integer(r[ 5].data);
|
||||
s.integer(r[ 6].data);
|
||||
s.integer(r[ 7].data);
|
||||
s.integer(r[ 8].data);
|
||||
s.integer(r[ 9].data);
|
||||
s.integer(r[10].data);
|
||||
s.integer(r[11].data);
|
||||
s.integer(r[12].data);
|
||||
s.integer(r[13].data);
|
||||
s.integer(r[14].data);
|
||||
s.integer(r[15].data);
|
||||
|
||||
s.integer(shiftercarry);
|
||||
s.integer(instruction);
|
||||
s.integer(exception);
|
||||
|
||||
s.integer(pipeline.reload);
|
||||
s.integer(pipeline.instruction.opcode);
|
||||
s.integer(pipeline.instruction.address);
|
||||
s.integer(pipeline.prefetch.opcode);
|
||||
s.integer(pipeline.prefetch.address);
|
||||
s.integer(pipeline.mdr.opcode);
|
||||
s.integer(pipeline.mdr.address);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
struct Coprocessor : Processor {
|
||||
struct Coprocessor : Thread {
|
||||
alwaysinline void step(unsigned clocks);
|
||||
alwaysinline void synchronize_cpu();
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifdef HITACHIDSP_CPP
|
||||
|
||||
void HitachiDSP::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(dataRAM);
|
||||
for(auto &n : stack) s.integer(n);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class ICD2 : public GB::Interface, public Coprocessor {
|
||||
class ICD2 : GB::Interface, public Coprocessor {
|
||||
public:
|
||||
unsigned revision;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifdef ICD2_CPP
|
||||
|
||||
void ICD2::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
GB::system.serialize_all(s);
|
||||
|
||||
for(unsigned n = 0; n < 64; n++) s.array(packet[n].data);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifdef MSU1_CPP
|
||||
|
||||
void MSU1::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
s.integer(mmio.data_offset);
|
||||
s.integer(mmio.audio_offset);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifdef NECDSP_CPP
|
||||
|
||||
void NECDSP::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(dataRAM);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifdef SA1_CPP
|
||||
|
||||
void SA1::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
CPUcore::core_serialize(s);
|
||||
|
||||
//sa1.hpp
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifdef SUPERFX_CPP
|
||||
|
||||
void SuperFX::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
//superfx.hpp
|
||||
s.integer(clockmode);
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// 6: iobit $4201.d6 write; $4213.d6 read $4201.d7 write; $4213.d7 read
|
||||
// 7: gnd
|
||||
|
||||
struct Controller : Processor {
|
||||
struct Controller : Thread {
|
||||
enum : bool { Port1 = 0, Port2 = 1 };
|
||||
const bool port;
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ void CPU::step(unsigned clocks) {
|
|||
smp.clock -= clocks * (uint64)smp.frequency;
|
||||
ppu.clock -= clocks;
|
||||
for(unsigned i = 0; i < coprocessors.size(); i++) {
|
||||
Processor &chip = *coprocessors[i];
|
||||
auto &chip = *coprocessors[i];
|
||||
chip.clock -= clocks * (uint64)chip.frequency;
|
||||
}
|
||||
input.port1->clock -= clocks * (uint64)input.port1->frequency;
|
||||
|
@ -41,7 +41,7 @@ void CPU::synchronize_ppu() {
|
|||
|
||||
void CPU::synchronize_coprocessors() {
|
||||
for(unsigned i = 0; i < coprocessors.size(); i++) {
|
||||
Processor &chip = *coprocessors[i];
|
||||
auto &chip = *coprocessors[i];
|
||||
if(chip.clock < 0) co_switch(chip.thread);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
struct CPU : public Processor, public CPUcore, public PPUcounter {
|
||||
struct CPU : Thread, public CPUcore, public PPUcounter {
|
||||
uint8 wram[128 * 1024];
|
||||
|
||||
enum : bool { Threaded = true };
|
||||
array<Processor*> coprocessors;
|
||||
array<Thread*> coprocessors;
|
||||
alwaysinline void step(unsigned clocks);
|
||||
alwaysinline void synchronize_smp();
|
||||
void synchronize_ppu();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifdef CPU_CPP
|
||||
|
||||
void CPU::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
CPUcore::core_serialize(s);
|
||||
PPUcounter::serialize(s);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
struct DSP : public Processor {
|
||||
struct DSP : Thread {
|
||||
enum : bool { Threaded = true };
|
||||
alwaysinline void step(unsigned clocks);
|
||||
alwaysinline void synchronize_smp();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifdef DSP_CPP
|
||||
|
||||
void DSP::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(state.regs, 128);
|
||||
state.echo_hist[0].serialize(s);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
struct PPU : public Processor, public PPUcounter {
|
||||
struct PPU : Thread, public PPUcounter {
|
||||
uint8 vram[64 * 1024];
|
||||
uint8 oam[544];
|
||||
uint8 cgram[512];
|
||||
|
|
|
@ -13,7 +13,7 @@ void PPUcounter::serialize(serializer &s) {
|
|||
}
|
||||
|
||||
void PPU::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
PPUcounter::serialize(s);
|
||||
|
||||
s.array(vram);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifdef SMP_CPP
|
||||
|
||||
void SMP::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
SMPcore::core_serialize(s);
|
||||
|
||||
s.array(apuram);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
struct SMP : public Processor, public SMPcore {
|
||||
struct SMP : Thread, public SMPcore {
|
||||
static const uint8 iplrom[64];
|
||||
uint8 apuram[64 * 1024];
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define SNES_HPP
|
||||
|
||||
#include <base/base.hpp>
|
||||
#include <processor/arm/arm.hpp>
|
||||
|
||||
namespace SNES {
|
||||
namespace Info {
|
||||
|
@ -24,7 +25,7 @@ namespace SNES {
|
|||
#endif
|
||||
|
||||
namespace SNES {
|
||||
struct Processor {
|
||||
struct Thread {
|
||||
cothread_t thread;
|
||||
unsigned frequency;
|
||||
int64 clock;
|
||||
|
@ -41,10 +42,10 @@ namespace SNES {
|
|||
s.integer(clock);
|
||||
}
|
||||
|
||||
inline Processor() : thread(nullptr) {
|
||||
inline Thread() : thread(nullptr) {
|
||||
}
|
||||
|
||||
inline ~Processor() {
|
||||
inline ~Thread() {
|
||||
if(thread) co_delete(thread);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -45,7 +45,7 @@ void System::runtosave() {
|
|||
}
|
||||
|
||||
for(unsigned i = 0; i < cpu.coprocessors.size(); i++) {
|
||||
Processor &chip = *cpu.coprocessors[i];
|
||||
auto &chip = *cpu.coprocessors[i];
|
||||
scheduler.thread = chip.thread;
|
||||
runthreadtosave();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
options += debugger
|
||||
|
||||
processor := arm
|
||||
include processor/Makefile
|
||||
|
||||
include $(snes)/Makefile
|
||||
name := laevateinn
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
processor := arm
|
||||
include processor/Makefile
|
||||
|
||||
include $(snes)/Makefile
|
||||
include $(gb)/Makefile
|
||||
output := libsnes
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
processors := arm
|
||||
include processor/Makefile
|
||||
|
||||
include $(nes)/Makefile
|
||||
include $(snes)/Makefile
|
||||
include $(gb)/Makefile
|
||||
|
|
Loading…
Reference in New Issue