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:
Tim Allen 2012-03-23 21:43:39 +11:00
parent 77578cd0a4
commit ec939065bd
80 changed files with 282 additions and 1088 deletions

View File

@ -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>

View File

@ -1,4 +1,4 @@
struct APU : Processor, MMIO {
struct APU : Thread, MMIO {
#include "square1/square1.hpp"
#include "square2/square2.hpp"
#include "wave/wave.hpp"

View File

@ -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);

View File

@ -1,4 +1,4 @@
struct CPU : Processor, MMIO {
struct CPU : Thread, MMIO {
#include "core/core.hpp"
#include "mmio/mmio.hpp"
#include "timing/timing.hpp"

View File

@ -1,7 +1,7 @@
#ifdef CPU_CPP
void CPU::serialize(serializer &s) {
Processor::serialize(s);
Thread::serialize(s);
s.array(wram);
s.array(hram);

View File

@ -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);
}
};

View File

@ -1,4 +1,4 @@
struct LCD : Processor, MMIO {
struct LCD : Thread, MMIO {
#include "mmio/mmio.hpp"
struct Status {

View File

@ -1,7 +1,7 @@
#ifdef LCD_CPP
void LCD::serialize(serializer &s) {
Processor::serialize(s);
Thread::serialize(s);
s.array(screen);
s.array(line);

View File

@ -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;

View File

@ -8,7 +8,6 @@ struct Scheduler : property<Scheduler> {
void enter();
void exit(ExitReason);
void swapto(Processor&);
void init();
Scheduler();

View File

@ -1,4 +1,4 @@
struct APU : Processor {
struct APU : Thread {
static void Enter();
void enter();
void step(unsigned clocks);

View File

@ -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();
};

View File

@ -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);

View File

@ -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();

View File

@ -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);
}
};

View File

@ -1,4 +1,4 @@
struct PPU : Processor {
struct PPU : Thread {
StaticMemory vram;
StaticMemory oam;
StaticMemory pram;

View File

@ -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();

View File

@ -1,4 +1,4 @@
struct APU : Processor {
struct APU : Thread {
static void Main();
void main();
void tick();

View File

@ -1,5 +1,5 @@
void APU::serialize(serializer &s) {
Processor::serialize(s);
Thread::serialize(s);
filter.serialize(s);

View File

@ -78,7 +78,7 @@ void Cartridge::scanline(unsigned y) {
}
void Cartridge::serialize(serializer &s) {
Processor::serialize(s);
Thread::serialize(s);
return board->serialize(s);
}

View File

@ -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();

View File

@ -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;

View File

@ -1,4 +1,4 @@
struct CPU : Processor {
struct CPU : Thread {
#include "core/core.hpp"
#include "memory/memory.hpp"
uint8 ram[0x0800];

View File

@ -1,5 +1,5 @@
void CPU::serialize(serializer &s) {
Processor::serialize(s);
Thread::serialize(s);
s.array(ram);

View File

@ -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);
}
};

View File

@ -1,4 +1,4 @@
struct PPU : Processor {
struct PPU : Thread {
static void Main();
void main();
void tick();

View File

@ -1,5 +1,5 @@
void PPU::serialize(serializer &s) {
Processor::serialize(s);
Thread::serialize(s);
s.integer(status.mdr);

6
bsnes/processor/Makefile Executable file
View File

@ -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)

View File

@ -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) {
}
}

22
bsnes/processor/arm/arm.hpp Executable file
View File

@ -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

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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();

6
bsnes/processor/processor.hpp Executable file
View File

@ -0,0 +1,6 @@
#ifndef PROCESSOR_HPP
#define PROCESSOR_HPP
#include <base/base.hpp>
#endif

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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);

View File

@ -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();

View File

@ -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];

View File

@ -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];

View File

@ -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);

View File

@ -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];

View File

@ -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);

View File

@ -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);

View File

@ -1,5 +1,4 @@
class SMP : public Processor {
public:
struct SMP : Thread {
static const uint8 iplrom[64];
uint8 *apuram;

View File

@ -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() {

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -1,4 +1,4 @@
struct Coprocessor : Processor {
struct Coprocessor : Thread {
alwaysinline void step(unsigned clocks);
alwaysinline void synchronize_cpu();
};

View File

@ -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);

View File

@ -1,4 +1,4 @@
class ICD2 : public GB::Interface, public Coprocessor {
class ICD2 : GB::Interface, public Coprocessor {
public:
unsigned revision;

View File

@ -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);

View File

@ -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);

View File

@ -1,7 +1,7 @@
#ifdef NECDSP_CPP
void NECDSP::serialize(serializer &s) {
Processor::serialize(s);
Thread::serialize(s);
s.array(dataRAM);

View File

@ -1,7 +1,7 @@
#ifdef SA1_CPP
void SA1::serialize(serializer &s) {
Processor::serialize(s);
Thread::serialize(s);
CPUcore::core_serialize(s);
//sa1.hpp

View File

@ -1,7 +1,7 @@
#ifdef SUPERFX_CPP
void SuperFX::serialize(serializer &s) {
Processor::serialize(s);
Thread::serialize(s);
//superfx.hpp
s.integer(clockmode);

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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);

View File

@ -1,4 +1,4 @@
struct DSP : public Processor {
struct DSP : Thread {
enum : bool { Threaded = true };
alwaysinline void step(unsigned clocks);
alwaysinline void synchronize_smp();

View File

@ -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);

View File

@ -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];

View File

@ -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);

View File

@ -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);

View File

@ -1,4 +1,4 @@
struct SMP : public Processor, public SMPcore {
struct SMP : Thread, public SMPcore {
static const uint8 iplrom[64];
uint8 apuram[64 * 1024];

View File

@ -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);
}
};

View File

@ -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();
}

View File

@ -1,5 +1,8 @@
options += debugger
processor := arm
include processor/Makefile
include $(snes)/Makefile
name := laevateinn

View File

@ -1,3 +1,6 @@
processor := arm
include processor/Makefile
include $(snes)/Makefile
include $(gb)/Makefile
output := libsnes

View File

@ -1,3 +1,6 @@
processors := arm
include processor/Makefile
include $(nes)/Makefile
include $(snes)/Makefile
include $(gb)/Makefile