mirror of https://github.com/bsnes-emu/bsnes.git
Update to v103r30 release.
byuu says: Changelog: - processor/arm7tdmi: completed implemented - gba/cpu, sfc/coprocessor/armdsp: use arm7tdmi instead of arm - sfc/cpu: experimental fix for newly discovered HDMA emulation issue Notes: The ARM7TDMI core crashes pretty quickly when trying to run GBA games, and I'm certain the same will be the case with the ST018. It was never all that likely I could rewrite 70KiB of code in 20 hours and have it work perfectly on the first try. So, now it's time for lots and lots of debugging. Any help would *really* be appreciated, if anyone were up for comparing the two implementations for regressions =^-^= I often have a really hard time spotting simple typos that I make. Also, the SNES HDMA fix is temporary. I would like it if testers could run through a bunch of games that are known for being tricky with HDMA (or if these aren't known to said tester, any games are fine then.) If we can confirm regressions, then we'll know the fix is either incorrect or incomplete. But if we don't find any, then it's a good sign that we're on the right path.
This commit is contained in:
parent
559eeccc89
commit
1067566834
|
@ -12,7 +12,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "103.29";
|
||||
static const string Version = "103.30";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
processors += arm arm7tdmi
|
||||
processors += arm7tdmi
|
||||
|
||||
objects += gba-memory gba-interface gba-system
|
||||
objects += gba-cartridge gba-player
|
||||
|
|
|
@ -17,7 +17,7 @@ auto CPU::Enter() -> void {
|
|||
}
|
||||
|
||||
auto CPU::main() -> void {
|
||||
processor.irqline = irq.ime && (irq.enable & irq.flag);
|
||||
ARM7TDMI::irq = irq.ime && (irq.enable & irq.flag);
|
||||
|
||||
if(stopped()) {
|
||||
if(!(irq.enable & irq.flag & Interrupt::Keypad)) return step(16);
|
||||
|
@ -29,7 +29,7 @@ auto CPU::main() -> void {
|
|||
context.halted = false;
|
||||
}
|
||||
|
||||
exec();
|
||||
instruction();
|
||||
}
|
||||
|
||||
auto CPU::step(uint clocks) -> void {
|
||||
|
@ -60,7 +60,7 @@ auto CPU::step(uint clocks) -> void {
|
|||
}
|
||||
|
||||
auto CPU::power() -> void {
|
||||
ARM::power();
|
||||
ARM7TDMI::power();
|
||||
create(CPU::Enter, system.frequency());
|
||||
|
||||
for(auto& byte : iwram) byte = 0x00;
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
struct CPU : Processor::ARM, Thread, IO {
|
||||
using ARM::read;
|
||||
using ARM::write;
|
||||
|
||||
struct CPU : Processor::ARM7TDMI, Thread, IO {
|
||||
struct Interrupt { enum : uint {
|
||||
VBlank = 0x0001,
|
||||
HBlank = 0x0002,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
auto CPU::serialize(serializer& s) -> void {
|
||||
ARM::serialize(s);
|
||||
ARM7TDMI::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(iwram);
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include <emulator/thread.hpp>
|
||||
#include <emulator/scheduler.hpp>
|
||||
|
||||
#include <processor/arm/arm.hpp>
|
||||
#include <processor/arm7tdmi/arm7tdmi.hpp>
|
||||
|
||||
namespace GameBoyAdvance {
|
||||
|
|
|
@ -15,7 +15,7 @@ auto BIOS::read(uint mode, uint32 addr) -> uint32 {
|
|||
|
||||
//GBA BIOS is read-protected; only the BIOS itself can read its own memory
|
||||
//when accessed elsewhere; this should return the last value read by the BIOS program
|
||||
if(cpu.r(15) >= 0x0000'4000) return mdr;
|
||||
if(cpu.processor.r15 >= 0x0000'4000) return mdr;
|
||||
|
||||
if(mode & Word) return mdr = read(Half, addr &~ 2) << 0 | read(Half, addr | 2) << 16;
|
||||
if(mode & Half) return mdr = read(Byte, addr &~ 1) << 0 | read(Byte, addr | 1) << 8;
|
||||
|
|
|
@ -562,13 +562,13 @@ auto ARM::disassembleInstructionTHUMB(uint32 pc) -> string {
|
|||
}
|
||||
|
||||
//load_literal()
|
||||
//ldr rd,[pc,#+/-offset]
|
||||
//ldr rd,[pc,#offset]
|
||||
if((instruction & 0xf800) == 0x4800) {
|
||||
uint3 rd = instruction >> 8;
|
||||
uint8 displacement = instruction;
|
||||
|
||||
uint rm = ((pc + 4) & ~3) + displacement * 4;
|
||||
output.append("ldr ", registers[rd], ",[pc,#0x", hex(rm, 3L), "]");
|
||||
output.append("ldr ", registers[rd], ",[pc,#0x", hex(rm, 8L), "]");
|
||||
output.append(" =0x", hex(read(Word | Nonsequential, rm), 8L));
|
||||
|
||||
return output;
|
||||
|
@ -636,9 +636,9 @@ auto ARM::disassembleInstructionTHUMB(uint32 pc) -> string {
|
|||
if((instruction & 0xf000) == 0x9000) {
|
||||
uint1 opcode = instruction >> 11;
|
||||
uint3 rd = instruction >> 8;
|
||||
int8 relative = instruction;
|
||||
uint8 immediate = instruction;
|
||||
|
||||
output.append(opcode ? "ldr" : "str", " ", registers[rd], ",[sp,#0x", hex(relative * 4, 3L), "]");
|
||||
output.append(opcode ? "ldr" : "str", " ", registers[rd], ",[sp,#0x", hex(immediate * 4, 3L), "]");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -750,7 +750,7 @@ auto ARM::disassembleInstructionTHUMB(uint32 pc) -> string {
|
|||
//branch_long_suffix()
|
||||
//bl address
|
||||
if((instruction & 0xf800) == 0xf800) {
|
||||
output.append("...");
|
||||
output.append("b (suffix)");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
|
|
@ -496,6 +496,7 @@ auto ARM::arm_op_move_register_offset() {
|
|||
uint32 rd = r(d);
|
||||
uint32 rs = immediate;
|
||||
uint32 rm = r(m);
|
||||
carryout() = cpsr().c;
|
||||
|
||||
if(mode == 0) rm = lsl(rm, rs);
|
||||
if(mode == 1) rm = lsr(rm, rs ? rs : (uint32)32);
|
||||
|
|
|
@ -134,7 +134,7 @@ auto ARM::thumb_op_alu_hi() {
|
|||
}
|
||||
}
|
||||
|
||||
//ldr rd,[pc,#+/-offset]
|
||||
//ldr rd,[pc,#offset]
|
||||
//0100 1ddd oooo oooo
|
||||
//d = rd
|
||||
//o = offset
|
||||
|
|
|
@ -26,21 +26,4 @@ auto ARM7TDMI::power() -> void {
|
|||
irq = 0;
|
||||
}
|
||||
|
||||
struct CPU : ARM7TDMI {
|
||||
auto step(uint) -> void {}
|
||||
auto sleep() -> void {}
|
||||
auto get(uint, uint32) -> uint32 {}
|
||||
auto set(uint, uint32, uint32) -> void {}
|
||||
|
||||
CPU() {
|
||||
/*
|
||||
uint32 opcode = 0x00337e92;
|
||||
uint12 id = (opcode & 0x0ff00000) >> 16 | (opcode & 0x000000f0) >> 4;
|
||||
print("!!", hex(id), "\n");
|
||||
armInstruction[id](opcode);
|
||||
print(armDisassemble[id](opcode), "\n");
|
||||
*/
|
||||
}
|
||||
} cpu;
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
//ARMv3 (ARM60)
|
||||
//ARMv4 (ARM7TDMI)
|
||||
|
||||
#pragma once
|
||||
|
@ -88,17 +87,34 @@ struct ARM7TDMI {
|
|||
|
||||
//instructions-thumb.cpp
|
||||
auto thumbInstructionALU(uint3, uint3, uint4) -> void;
|
||||
auto thumbInstructionALUExtended(uint4, uint4, uint2) -> void;
|
||||
auto thumbInstructionAddRegister(uint8, uint3, uint1) -> void;
|
||||
auto thumbInstructionAdjustImmediate(uint3, uint3, uint3, uint1) -> void;
|
||||
auto thumbInstructionAdjustRegister(uint3, uint3, uint3, uint1) -> void;
|
||||
auto thumbInstructionAdjustStack(uint7, uint1) -> void;
|
||||
auto thumbInstructionBranchExchange(uint4) -> void;
|
||||
auto thumbInstructionBranchFarPrefix(int11) -> void;
|
||||
auto thumbInstructionBranchFarSuffix(uint11) -> void;
|
||||
auto thumbInstructionBranchNear(int11) -> void;
|
||||
auto thumbInstructionBranchTest(int8, uint4) -> void;
|
||||
auto thumbInstructionImmediate(uint8, uint3, uint2) -> void;
|
||||
auto thumbInstructionLoadLiteral(uint8, uint3) -> void;
|
||||
auto thumbInstructionMoveByteImmediate(uint3, uint3, uint5, uint1) -> void;
|
||||
auto thumbInstructionMoveHalfImmediate(uint3, uint3, uint5, uint1) -> void;
|
||||
auto thumbInstructionMoveMultiple(uint8, uint3, uint1) -> void;
|
||||
auto thumbInstructionMoveRegisterOffset(uint3, uint3, uint3, uint3) -> void;
|
||||
auto thumbInstructionMoveStack(uint8, uint3, uint1) -> void;
|
||||
auto thumbInstructionMoveWordImmediate(uint3, uint3, uint5, uint1) -> void;
|
||||
auto thumbInstructionShiftImmediate(uint3, uint3, uint5, uint2) -> void;
|
||||
auto thumbInstructionSoftwareInterrupt(uint8) -> void;
|
||||
auto thumbInstructionStackMultiple(uint8, uint1, uint1) -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
//disassembler.cpp
|
||||
auto disassemble(uint32 pc) -> string;
|
||||
auto disassemble(maybe<uint32> pc = nothing, maybe<uint1> thumb = nothing) -> string;
|
||||
auto disassembleRegisters() -> string;
|
||||
|
||||
struct GPR {
|
||||
inline operator uint32_t() const {
|
||||
|
@ -241,11 +257,30 @@ struct ARM7TDMI {
|
|||
auto armDisassembleSoftwareInterrupt(uint24) -> string;
|
||||
|
||||
auto thumbDisassembleALU(uint3, uint3, uint4) -> string;
|
||||
auto thumbDisassembleALUExtended(uint4, uint4, uint2) -> string;
|
||||
auto thumbDisassembleAddRegister(uint8, uint3, uint1) -> string;
|
||||
auto thumbDisassembleAdjustImmediate(uint3, uint3, uint3, uint1) -> string;
|
||||
auto thumbDisassembleAdjustRegister(uint3, uint3, uint3, uint1) -> string;
|
||||
auto thumbDisassembleAdjustStack(uint7, uint1) -> string;
|
||||
auto thumbDisassembleBranchExchange(uint4) -> string;
|
||||
auto thumbDisassembleBranchFarPrefix(int11) -> string;
|
||||
auto thumbDisassembleBranchFarSuffix(uint11) -> string;
|
||||
auto thumbDisassembleBranchNear(int11) -> string;
|
||||
auto thumbDisassembleBranchTest(int8, uint4) -> string;
|
||||
auto thumbDisassembleImmediate(uint8, uint3, uint2) -> string;
|
||||
auto thumbDisassembleLoadLiteral(uint8, uint3) -> string;
|
||||
auto thumbDisassembleMoveByteImmediate(uint3, uint3, uint5, uint1) -> string;
|
||||
auto thumbDisassembleMoveHalfImmediate(uint3, uint3, uint5, uint1) -> string;
|
||||
auto thumbDisassembleMoveMultiple(uint8, uint3, uint1) -> string;
|
||||
auto thumbDisassembleMoveRegisterOffset(uint3, uint3, uint3, uint3) -> string;
|
||||
auto thumbDisassembleMoveStack(uint8, uint3, uint1) -> string;
|
||||
auto thumbDisassembleMoveWordImmediate(uint3, uint3, uint5, uint1) -> string;
|
||||
auto thumbDisassembleShiftImmediate(uint3, uint3, uint5, uint2) -> string;
|
||||
auto thumbDisassembleSoftwareInterrupt(uint8) -> string;
|
||||
auto thumbDisassembleStackMultiple(uint8, uint1, uint1) -> string;
|
||||
|
||||
uint32 _pc;
|
||||
string _c;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,17 +1,59 @@
|
|||
static uint32 _pc;
|
||||
static string _c;
|
||||
static const string _r[] = {
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc"
|
||||
};
|
||||
static const string _conditions[] = {
|
||||
"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
|
||||
"hi", "ls", "ge", "lt", "gt", "le", "", "nv",
|
||||
};
|
||||
#define _s save ? "s" : ""
|
||||
#define _move(mode) (mode == 13 || mode == 15)
|
||||
#define _comp(mode) (mode >= 8 && mode <= 11)
|
||||
#define _math(mode) (mode <= 7 || mode == 12 || mode == 14)
|
||||
|
||||
#define isMove(mode) (mode == 13 || mode == 15)
|
||||
#define isComp(mode) (mode >= 8 && mode <= 11)
|
||||
#define isMath(mode) (mode <= 7 || mode == 12 || mode == 14)
|
||||
auto ARM7TDMI::disassemble(maybe<uint32> pc, maybe<uint1> thumb) -> string {
|
||||
if(!pc) pc = pipeline.execute.address;
|
||||
if(!thumb) thumb = cpsr().t;
|
||||
|
||||
auto ARM7TDMI::disassemble(uint32 pc) -> string {
|
||||
return "";
|
||||
_pc = pc();
|
||||
if(!thumb()) {
|
||||
uint32 opcode = read(Word | Nonsequential, _pc & ~3);
|
||||
uint12 index = (opcode & 0x0ff00000) >> 16 | (opcode & 0x000000f0) >> 4;
|
||||
_c = _conditions[opcode >> 28];
|
||||
return armDisassemble[index](opcode);
|
||||
} else {
|
||||
uint16 opcode = read(Half | Nonsequential, _pc & ~1);
|
||||
return thumbDisassemble[opcode]();
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::disassembleRegisters() -> string {
|
||||
string output;
|
||||
for(uint n : range(16)) {
|
||||
output.append(_r[n], ":", hex(r(n), 8L), " ");
|
||||
}
|
||||
|
||||
output.append("cpsr:");
|
||||
output.append(cpsr().n ? "N" : "n");
|
||||
output.append(cpsr().z ? "Z" : "z");
|
||||
output.append(cpsr().c ? "C" : "c");
|
||||
output.append(cpsr().v ? "V" : "v", "/");
|
||||
output.append(cpsr().i ? "I" : "i");
|
||||
output.append(cpsr().f ? "F" : "f");
|
||||
output.append(cpsr().t ? "T" : "t", "/");
|
||||
output.append(hex(cpsr().m, 2L));
|
||||
if(cpsr().m == PSR::USR || cpsr().m == PSR::SYS) return output;
|
||||
|
||||
output.append("spsr:");
|
||||
output.append(spsr().n ? "N" : "n");
|
||||
output.append(spsr().z ? "Z" : "z");
|
||||
output.append(spsr().c ? "C" : "c");
|
||||
output.append(spsr().v ? "V" : "v", "/");
|
||||
output.append(spsr().i ? "I" : "i");
|
||||
output.append(spsr().f ? "F" : "f");
|
||||
output.append(spsr().t ? "T" : "t", "/");
|
||||
output.append(hex(spsr().m, 2L));
|
||||
return output;
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -34,9 +76,9 @@ auto ARM7TDMI::armDisassembleDataImmediate
|
|||
};
|
||||
uint32 data = immediate >> (shift << 1) | immediate << 32 - (shift << 1);
|
||||
return {opcode[mode], _c,
|
||||
isMove(mode) ? string{_s, " ", _r[d]} : string{},
|
||||
isComp(mode) ? string{" ", _r[n]} : string{},
|
||||
isMath(mode) ? string{_s, " ", _r[d], ",", _r[n]} : string{},
|
||||
_move(mode) ? string{_s, " ", _r[d]} : string{},
|
||||
_comp(mode) ? string{" ", _r[n]} : string{},
|
||||
_math(mode) ? string{_s, " ", _r[d], ",", _r[n]} : string{},
|
||||
",#0x", hex(data, 8L)};
|
||||
}
|
||||
|
||||
|
@ -47,9 +89,9 @@ auto ARM7TDMI::armDisassembleDataImmediateShift
|
|||
"tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn",
|
||||
};
|
||||
return {opcode[mode], _c,
|
||||
isMove(mode) ? string{_s, " ", _r[d]} : string{},
|
||||
isComp(mode) ? string{" ", _r[n]} : string{},
|
||||
isMath(mode) ? string{_s, " ", _r[d], ",", _r[n]} : string{},
|
||||
_move(mode) ? string{_s, " ", _r[d]} : string{},
|
||||
_comp(mode) ? string{" ", _r[n]} : string{},
|
||||
_math(mode) ? string{_s, " ", _r[d], ",", _r[n]} : string{},
|
||||
",", _r[m],
|
||||
type == 0 && shift ? string{" lsl #", shift} : string{},
|
||||
type == 1 ? string{" lsr #", shift ? (uint)shift : 32} : string{},
|
||||
|
@ -65,9 +107,9 @@ auto ARM7TDMI::armDisassembleDataRegisterShift
|
|||
"tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn",
|
||||
};
|
||||
return {opcode[mode], _c,
|
||||
isMove(mode) ? string{_s, " ", _r[d]} : string{},
|
||||
isComp(mode) ? string{" ", _r[n]} : string{},
|
||||
isMath(mode) ? string{_s, " ", _r[d], ",", _r[n]} : string{},
|
||||
_move(mode) ? string{_s, " ", _r[d]} : string{},
|
||||
_comp(mode) ? string{" ", _r[n]} : string{},
|
||||
_math(mode) ? string{_s, " ", _r[d], ",", _r[n]} : string{},
|
||||
",", _r[m], " ",
|
||||
type == 0 ? "lsl" : "",
|
||||
type == 1 ? "lsr" : "",
|
||||
|
@ -227,6 +269,18 @@ auto ARM7TDMI::thumbDisassembleALU
|
|||
return {opcode[mode], " ", _r[d], ",", _r[m]};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleALUExtended
|
||||
(uint4 d, uint4 m, uint2 mode) -> string {
|
||||
static const string opcode[] = {"add", "sub", "mov"};
|
||||
if(d == 8 && m == 8 && mode == 2) return {"nop"};
|
||||
return {opcode[mode], " ", _r[d], ",", _r[m]};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleAddRegister
|
||||
(uint8 immediate, uint3 d, uint1 mode) -> string {
|
||||
return {"add ", _r[d], ",", mode ? "sp" : "pc", ",#0x", hex(immediate, 2L)};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleAdjustImmediate
|
||||
(uint3 d, uint3 n, uint3 immediate, uint1 mode) -> string {
|
||||
return {!mode ? "add" : "sub", " ", _r[d], ",", _r[n], ",#", immediate};
|
||||
|
@ -237,51 +291,113 @@ auto ARM7TDMI::thumbDisassembleAdjustRegister
|
|||
return {!mode ? "add" : "sub", " ", _r[d], ",", _r[n], ",", _r[m]};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleAdjustStack
|
||||
(uint7 immediate, uint1 mode) -> string {
|
||||
return {!mode ? "add" : "sub", " sp,#0x", hex(immediate * 4, 3L)};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleBranchExchange
|
||||
(uint4 m) -> string {
|
||||
return {"bx ", _r[m]};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleBranchFarPrefix
|
||||
(int11 displacementHi) -> string {
|
||||
uint11 displacementLo = read(Half | Nonsequential, (_pc & ~1) + 2);
|
||||
int22 displacement = displacementHi << 11 | displacementLo << 0;
|
||||
uint32 address = _pc + 4 + displacement * 2;
|
||||
return {"b 0x", hex(address, 8L)};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleBranchFarSuffix
|
||||
(uint11 displacement) -> string {
|
||||
return {"b (suffix)"};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleBranchNear
|
||||
(int11 displacement) -> string {
|
||||
uint32 address = _pc + 4 + displacement * 2;
|
||||
return {"b 0x", hex(address, 8L)};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleBranchTest
|
||||
(int8 displacement, uint4 condition) -> string {
|
||||
uint32 address = _pc + 4 + displacement * 2;
|
||||
return {"b", _conditions[condition], " 0x", hex(address, 8L)};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleImmediate
|
||||
(uint8 immediate, uint3 d, uint2 mode) -> string {
|
||||
static const string opcode[] = {"mov", "cmp", "add", "sub"};
|
||||
return {opcode[mode], " ", _r[d], ",#0x", hex(immediate, 2L)};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleLoadLiteral
|
||||
(uint8 displacement, uint3 d) -> string {
|
||||
uint32 address = ((_pc + 4) & ~3) + (displacement << 2);
|
||||
uint32 data = read(Word | Nonsequential, address);
|
||||
return {"ldr ", _r[d], ",[pc,#0x", hex(address, 8L), "] =0x", hex(data, 8L)};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleMoveByteImmediate
|
||||
(uint3 d, uint3 n, uint5 offset, uint1 mode) -> string {
|
||||
return {mode ? "ldrb" : "strb", " ", _r[d], ",[", _r[n], ",#0x", hex(offset, 2L), "]"};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleMoveHalfImmediate
|
||||
(uint3 d, uint3 n, uint5 offset, uint1 mode) -> string {
|
||||
return {mode ? "ldrh" : "strh", " ", _r[d], ",[", _r[n], ",#0x", hex(offset * 2, 2L), "]"};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleMoveMultiple
|
||||
(uint8 list, uint3 n, uint1 mode) -> string {
|
||||
string registers;
|
||||
for(uint m : range(8)) {
|
||||
if(list.bit(m)) registers.append(_r[m], ",");
|
||||
}
|
||||
registers.trimRight(",", 1L);
|
||||
return {mode ? "ldmia" : "stmia", " ", _r[n], "!,{", registers, "}"};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleMoveRegisterOffset
|
||||
(uint3 d, uint3 n, uint3 m, uint3 mode) -> string {
|
||||
static const string opcode[] = {"str", "strh", "strb", "ldsb", "ldr", "ldrh", "ldrb", "ldsh"};
|
||||
return {opcode[mode], " ", _r[d], ",[", _r[n], ",", _r[m], "]"};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleMoveStack
|
||||
(uint8 immediate, uint3 d, uint1 mode) -> string {
|
||||
return {mode ? "ldr" : "str", " ", _r[d], ",[sp,#0x", hex(immediate * 4, 3L), "]"};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleMoveWordImmediate
|
||||
(uint3 d, uint3 n, uint5 offset, uint1 mode) -> string {
|
||||
return {mode ? "ldr" : "str", " ", _r[d], ",[", _r[n], ",#0x", hex(offset * 4, 2L), "]"};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleShiftImmediate
|
||||
(uint3 d, uint3 m, uint5 immediate, uint2 mode) -> string {
|
||||
static const string opcode[] = {"lsl", "lsr", "asr"};
|
||||
return {opcode[mode], " ", _r[d], ",", _r[m], ",#", immediate};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleSoftwareInterrupt
|
||||
(uint8 immediate) -> string {
|
||||
return {"swi #0x", hex(immediate, 2L)};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleStackMultiple
|
||||
(uint8 list, uint1 lrpc, uint1 mode) -> string {
|
||||
string registers;
|
||||
for(uint m : range(8)) {
|
||||
if(list.bit(m)) registers.append(_r[m], ",");
|
||||
}
|
||||
if(lrpc) registers.append(!mode ? "lr," : "pc,");
|
||||
registers.trimRight(",", 1L);
|
||||
return {!mode ? "push" : "pop", " {", registers, "}"};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#undef _s
|
||||
#undef _move
|
||||
#undef _comp
|
||||
#undef _save
|
||||
|
|
|
@ -38,9 +38,10 @@ auto ARM7TDMI::instruction() -> void {
|
|||
opcode = pipeline.execute.instruction;
|
||||
if(!cpsr().t) {
|
||||
if(!TST(opcode.bits(28,31))) return;
|
||||
armInstruction[(opcode & 0x0ff00000) >> 16 | (opcode & 0x000000f0) >> 4](opcode);
|
||||
uint12 index = (opcode & 0x0ff00000) >> 16 | (opcode & 0x000000f0) >> 4;
|
||||
armInstruction[index](opcode);
|
||||
} else {
|
||||
thumbInstruction[opcode & 0xffff]();
|
||||
thumbInstruction[(uint16)opcode]();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -372,6 +373,21 @@ auto ARM7TDMI::thumbInitialize() -> void {
|
|||
bind(opcode, ALU, d, m, mode);
|
||||
}
|
||||
|
||||
for(uint4 d : range(16))
|
||||
for(uint4 m : range(16))
|
||||
for(uint2 mode : range(4)) {
|
||||
if(mode == 3) continue;
|
||||
auto opcode = pattern("0100 01?? ???? ????") | d.bits(0,2) << 0 | m << 3 | d.bit(3) << 7 | mode << 8;
|
||||
bind(opcode, ALUExtended, d, m, mode);
|
||||
}
|
||||
|
||||
for(uint8 immediate : range(256))
|
||||
for(uint3 d : range(8))
|
||||
for(uint1 mode : range(2)) {
|
||||
auto opcode = pattern("1010 ???? ???? ????") | immediate << 0 | d << 8 | mode << 11;
|
||||
bind(opcode, AddRegister, immediate, d, mode);
|
||||
}
|
||||
|
||||
for(uint3 d : range(8))
|
||||
for(uint3 n : range(8))
|
||||
for(uint3 immediate : range(8))
|
||||
|
@ -388,12 +404,40 @@ auto ARM7TDMI::thumbInitialize() -> void {
|
|||
bind(opcode, AdjustRegister, d, n, m, mode);
|
||||
}
|
||||
|
||||
for(uint7 immediate : range(128))
|
||||
for(uint1 mode : range(2)) {
|
||||
auto opcode = pattern("1011 0000 ???? ????") | immediate << 0 | mode << 7;
|
||||
bind(opcode, AdjustStack, immediate, mode);
|
||||
}
|
||||
|
||||
for(uint3 _ : range(8))
|
||||
for(uint4 m : range(16)) {
|
||||
auto opcode = pattern("0100 0111 0??? ?---") | _ << 0 | m << 3;
|
||||
bind(opcode, BranchExchange, m);
|
||||
}
|
||||
|
||||
for(uint11 displacement : range(2048)) {
|
||||
auto opcode = pattern("1111 0??? ???? ????") | displacement << 0;
|
||||
bind(opcode, BranchFarPrefix, displacement);
|
||||
}
|
||||
|
||||
for(uint11 displacement : range(2048)) {
|
||||
auto opcode = pattern("1111 1??? ???? ????") | displacement << 0;
|
||||
bind(opcode, BranchFarSuffix, displacement);
|
||||
}
|
||||
|
||||
for(uint11 displacement : range(2048)) {
|
||||
auto opcode = pattern("1110 0??? ???? ????") | displacement << 0;
|
||||
bind(opcode, BranchNear, displacement);
|
||||
}
|
||||
|
||||
for(uint8 displacement : range(256))
|
||||
for(uint4 condition : range(16)) {
|
||||
if(condition == 15) continue; //BNV
|
||||
auto opcode = pattern("1101 ???? ???? ????") | displacement << 0 | condition << 8;
|
||||
bind(opcode, BranchTest, displacement, condition);
|
||||
}
|
||||
|
||||
for(uint8 immediate : range(256))
|
||||
for(uint3 d : range(8))
|
||||
for(uint2 mode : range(4)) {
|
||||
|
@ -401,6 +445,58 @@ auto ARM7TDMI::thumbInitialize() -> void {
|
|||
bind(opcode, Immediate, immediate, d, mode);
|
||||
}
|
||||
|
||||
for(uint8 displacement : range(256))
|
||||
for(uint3 d : range(8)) {
|
||||
auto opcode = pattern("0100 1??? ???? ????") | displacement << 0 | d << 8;
|
||||
bind(opcode, LoadLiteral, displacement, d);
|
||||
}
|
||||
|
||||
for(uint3 d : range(8))
|
||||
for(uint3 n : range(8))
|
||||
for(uint5 immediate : range(32))
|
||||
for(uint1 mode : range(2)) {
|
||||
auto opcode = pattern("0111 ???? ???? ????") | d << 0 | n << 3 | immediate << 6 | mode << 11;
|
||||
bind(opcode, MoveByteImmediate, d, n, immediate, mode);
|
||||
}
|
||||
|
||||
for(uint3 d : range(8))
|
||||
for(uint3 n : range(8))
|
||||
for(uint5 immediate : range(32))
|
||||
for(uint1 mode : range(2)) {
|
||||
auto opcode = pattern("1000 ???? ???? ????") | d << 0 | n << 3 | immediate << 6 | mode << 11;
|
||||
bind(opcode, MoveHalfImmediate, d, n, immediate, mode);
|
||||
}
|
||||
|
||||
for(uint8 list : range(256))
|
||||
for(uint3 n : range(8))
|
||||
for(uint1 mode : range(2)) {
|
||||
auto opcode = pattern("1100 ???? ???? ????") | list << 0 | n << 8 | mode << 11;
|
||||
bind(opcode, MoveMultiple, list, n, mode);
|
||||
}
|
||||
|
||||
for(uint3 d : range(8))
|
||||
for(uint3 n : range(8))
|
||||
for(uint3 m : range(8))
|
||||
for(uint3 mode : range(8)) {
|
||||
auto opcode = pattern("0101 ???? ???? ????") | d << 0 | n << 3 | m << 6 | mode << 9;
|
||||
bind(opcode, MoveRegisterOffset, d, n, m, mode);
|
||||
}
|
||||
|
||||
for(uint8 immediate : range(256))
|
||||
for(uint3 d : range(8))
|
||||
for(uint1 mode : range(2)) {
|
||||
auto opcode = pattern("1001 ???? ???? ????") | immediate << 0 | d << 8 | mode << 11;
|
||||
bind(opcode, MoveStack, immediate, d, mode);
|
||||
}
|
||||
|
||||
for(uint3 d : range(8))
|
||||
for(uint3 n : range(8))
|
||||
for(uint5 offset : range(32))
|
||||
for(uint1 mode : range(2)) {
|
||||
auto opcode = pattern("0110 ???? ???? ????") | d << 0 | n << 3 | offset << 6 | mode << 11;
|
||||
bind(opcode, MoveWordImmediate, d, n, offset, mode);
|
||||
}
|
||||
|
||||
for(uint3 d : range(8))
|
||||
for(uint3 m : range(8))
|
||||
for(uint5 immediate : range(32))
|
||||
|
@ -410,27 +506,18 @@ auto ARM7TDMI::thumbInitialize() -> void {
|
|||
bind(opcode, ShiftImmediate, d, m, immediate, mode);
|
||||
}
|
||||
|
||||
for(uint8 immediate : range(256)) {
|
||||
auto opcode = pattern("1101 1111 ???? ????") | immediate << 0;
|
||||
bind(opcode, SoftwareInterrupt, immediate);
|
||||
}
|
||||
|
||||
for(uint8 list : range(256))
|
||||
for(uint1 lrpc : range(2))
|
||||
for(uint1 mode : range(2)) {
|
||||
auto opcode = pattern("1011 ?10? ???? ????") | list << 0 | lrpc << 8 | mode << 11;
|
||||
bind(opcode, StackMultiple, list, lrpc, mode);
|
||||
}
|
||||
|
||||
#undef bind
|
||||
#undef pattern
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -225,6 +225,7 @@ auto ARM7TDMI::armInstructionMoveRegisterOffset
|
|||
uint32 rm = r(m);
|
||||
uint32 rd = r(d);
|
||||
uint32 rn = r(n);
|
||||
carry = cpsr().c;
|
||||
|
||||
switch(type) {
|
||||
case 0: rm = LSL(rm, shift); break;
|
||||
|
|
|
@ -20,6 +20,23 @@ auto ARM7TDMI::thumbInstructionALU
|
|||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionALUExtended
|
||||
(uint4 d, uint4 m, uint2 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: r(d) = r(d) + r(m); break; //ADD
|
||||
case 1: SUB(r(d), r(m), 1); break; //SUBS
|
||||
case 2: r(d) = r(m); break; //MOV
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionAddRegister
|
||||
(uint8 immediate, uint3 d, uint1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: r(d) = (r(15) & ~2) + immediate * 4; break; //ADD pc (todo: is this really &~2 and not &~3?)
|
||||
case 1: r(d) = r(13) + immediate * 4; break; //ADD sp
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionAdjustImmediate
|
||||
(uint3 d, uint3 n, uint3 immediate, uint1 mode) -> void {
|
||||
switch(mode) {
|
||||
|
@ -36,6 +53,14 @@ auto ARM7TDMI::thumbInstructionAdjustRegister
|
|||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionAdjustStack
|
||||
(uint7 immediate, uint1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: r(13) = r(13) + immediate * 4; break; //ADD
|
||||
case 1: r(13) = r(13) - immediate * 4; break; //SUB
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionBranchExchange
|
||||
(uint4 m) -> void {
|
||||
uint32 address = r(m);
|
||||
|
@ -43,6 +68,28 @@ auto ARM7TDMI::thumbInstructionBranchExchange
|
|||
r(15) = address;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionBranchFarPrefix
|
||||
(int11 displacement) -> void {
|
||||
r(14) = r(15) + (displacement * 2 << 11);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionBranchFarSuffix
|
||||
(uint11 displacement) -> void {
|
||||
r(15) = r(14) + (displacement * 2);
|
||||
r(14) = pipeline.decode.address | 1;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionBranchNear
|
||||
(int11 displacement) -> void {
|
||||
r(15) = r(15) + displacement * 2;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionBranchTest
|
||||
(int8 displacement, uint4 condition) -> void {
|
||||
if(!TST(condition)) return;
|
||||
r(15) = r(15) + displacement * 2;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionImmediate
|
||||
(uint8 immediate, uint3 d, uint2 mode) -> void {
|
||||
switch(mode) {
|
||||
|
@ -53,6 +100,75 @@ auto ARM7TDMI::thumbInstructionImmediate
|
|||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionLoadLiteral
|
||||
(uint8 displacement, uint3 d) -> void {
|
||||
uint32 address = (r(15) & ~3) + (displacement << 2);
|
||||
r(d) = load(Word | Nonsequential, address);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveByteImmediate
|
||||
(uint3 d, uint3 n, uint5 offset, uint1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Byte | Nonsequential, r(n) + offset, r(d)); break; //STRB
|
||||
case 1: r(d) = load(Byte | Nonsequential, r(n) + offset); break; //LDRB
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveHalfImmediate
|
||||
(uint3 d, uint3 n, uint5 offset, uint1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Half | Nonsequential, r(n) + offset * 2, r(d)); break; //STRH
|
||||
case 1: r(d) = load(Half | Nonsequential, r(n) + offset * 2); break; //LDRH
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveMultiple
|
||||
(uint8 list, uint3 n, uint1 mode) -> void {
|
||||
uint32 rn = r(n);
|
||||
|
||||
for(uint m : range(8)) {
|
||||
if(!list.bit(m)) continue;
|
||||
switch(mode) {
|
||||
case 0: write(Word | Nonsequential, rn, r(m)); break; //STMIA
|
||||
case 1: r(m) = read(Word | Nonsequential, rn); break; //LDMIA
|
||||
}
|
||||
rn += 4;
|
||||
}
|
||||
|
||||
if(mode == 0 || !list.bit(n)) r(n) = rn;
|
||||
if(mode == 1) idle();
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveRegisterOffset
|
||||
(uint3 d, uint3 n, uint3 m, uint3 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Word | Nonsequential, r(n) + r(m), r(d)); break; //STR
|
||||
case 1: store(Half | Nonsequential, r(n) + r(m), r(d)); break; //STRH
|
||||
case 2: store(Byte | Nonsequential, r(n) + r(m), r(d)); break; //STRB
|
||||
case 3: r(d) = load(Byte | Nonsequential | Signed, r(n) + r(m)); break; //LDSB
|
||||
case 4: r(d) = load(Word | Nonsequential, r(n) + r(m)); break; //LDR
|
||||
case 5: r(d) = load(Half | Nonsequential, r(n) + r(m)); break; //LDRH
|
||||
case 6: r(d) = load(Byte | Nonsequential, r(n) + r(m)); break; //LDRB
|
||||
case 7: r(d) = load(Half | Nonsequential | Signed, r(n) + r(m)); break; //LDSH
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveStack
|
||||
(uint8 immediate, uint3 d, uint1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Word | Nonsequential, r(13) + immediate * 4, r(d)); break; //STR
|
||||
case 1: r(d) = load(Word | Nonsequential, r(13) + immediate * 4); break; //LDR
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionMoveWordImmediate
|
||||
(uint3 d, uint3 n, uint5 offset, uint1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: store(Word | Nonsequential, r(n) + offset * 4, r(d)); break; //STR
|
||||
case 1: r(d) = load(Word | Nonsequential, r(n) + offset * 4); break; //LDR
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionShiftImmediate
|
||||
(uint3 d, uint3 m, uint5 immediate, uint2 mode) -> void {
|
||||
switch(mode) {
|
||||
|
@ -61,3 +177,44 @@ auto ARM7TDMI::thumbInstructionShiftImmediate
|
|||
case 2: r(d) = BIT(ASR(r(m), immediate ? (uint)immediate : 32)); break; //ASR
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionSoftwareInterrupt
|
||||
(uint8 immediate) -> void {
|
||||
interrupt(PSR::SVC, 0x08);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInstructionStackMultiple
|
||||
(uint8 list, uint1 lrpc, uint1 mode) -> void {
|
||||
uint32 sp;
|
||||
switch(mode) {
|
||||
case 0: sp = r(13) - (bit::count(list) + lrpc) * 4; break; //PUSH
|
||||
case 1: sp = r(13); //POP
|
||||
}
|
||||
|
||||
uint sequential = Nonsequential;
|
||||
for(uint m : range(8)) {
|
||||
if(!list.bit(m)) continue;
|
||||
switch(mode) {
|
||||
case 0: write(Word | sequential, sp, r(m)); break; //PUSH
|
||||
case 1: r(m) = read(Word | sequential, sp); break; //POP
|
||||
}
|
||||
sp += 4;
|
||||
sequential = Sequential;
|
||||
}
|
||||
|
||||
if(lrpc) {
|
||||
switch(mode) { //todo: is this really always nonsequential?
|
||||
case 0: write(Word | Nonsequential, sp, r(14)); break; //PUSH
|
||||
case 1: r(15) = read(Word | Nonsequential, sp); break; //POP
|
||||
}
|
||||
sp += 4;
|
||||
}
|
||||
|
||||
if(mode == 1) {
|
||||
idle();
|
||||
r(13) = r(13) + (bit::count(list) + lrpc) * 4; //POP
|
||||
} else {
|
||||
pipeline.nonsequential = true;
|
||||
r(13) = r(13) - (bit::count(list) + lrpc) * 4; //PUSH
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
processors += wdc65816 spc700 arm gsu hg51b upd96050
|
||||
processors += wdc65816 spc700 arm7tdmi gsu hg51b upd96050
|
||||
|
||||
objects += sfc-interface sfc-system sfc-controller
|
||||
objects += sfc-cartridge sfc-memory
|
||||
|
|
|
@ -38,14 +38,8 @@ auto ArmDSP::boot() -> void {
|
|||
}
|
||||
|
||||
auto ArmDSP::main() -> void {
|
||||
if(crash) {
|
||||
print(disassembleRegisters(), "\n");
|
||||
print(disassembleInstructionARM(pipeline.execute.address), "\n");
|
||||
print("Executed: ", instructions, "\n");
|
||||
while(true) step(21'477'272);
|
||||
}
|
||||
|
||||
stepARM();
|
||||
processor.cpsr.t = 0; //force ARM mode
|
||||
instruction();
|
||||
}
|
||||
|
||||
auto ArmDSP::step(uint clocks) -> void {
|
||||
|
@ -115,8 +109,8 @@ auto ArmDSP::power() -> void {
|
|||
}
|
||||
|
||||
auto ArmDSP::reset() -> void {
|
||||
ARM7TDMI::power();
|
||||
create(ArmDSP::Enter, 21'477'272);
|
||||
ARM::power();
|
||||
|
||||
bridge.ready = false;
|
||||
bridge.signal = false;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//ARMv3 (ARM60)
|
||||
|
||||
struct ArmDSP : Processor::ARM, Thread {
|
||||
struct ArmDSP : Processor::ARM7TDMI, Thread {
|
||||
#include "registers.hpp"
|
||||
|
||||
ArmDSP();
|
||||
|
|
|
@ -8,7 +8,7 @@ auto ArmDSP::firmware() const -> nall::vector<uint8> {
|
|||
}
|
||||
|
||||
auto ArmDSP::serialize(serializer& s) -> void {
|
||||
ARM::serialize(s);
|
||||
ARM7TDMI::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(programRAM, 16 * 1024);
|
||||
|
|
|
@ -227,6 +227,7 @@ auto CPU::hdmaInit() -> void {
|
|||
dmaWrite(false);
|
||||
|
||||
for(auto n : range(8)) {
|
||||
channel[n].hdmaDoTransfer = true; //note: needs hardware verification (2017-08-09)
|
||||
if(!channel[n].hdmaEnabled) continue;
|
||||
channel[n].dmaEnabled = false; //HDMA init during DMA will stop DMA mid-transfer
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include <emulator/scheduler.hpp>
|
||||
#include <emulator/cheat.hpp>
|
||||
|
||||
#include <processor/arm/arm.hpp>
|
||||
#include <processor/arm7tdmi/arm7tdmi.hpp>
|
||||
#include <processor/gsu/gsu.hpp>
|
||||
#include <processor/hg51b/hg51b.hpp>
|
||||
#include <processor/spc700/spc700.hpp>
|
||||
|
|
Loading…
Reference in New Issue