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:
Tim Allen 2017-08-09 21:11:59 +10:00
parent 559eeccc89
commit 1067566834
22 changed files with 489 additions and 118 deletions

View File

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

View File

@ -1,4 +1,4 @@
processors += arm arm7tdmi
processors += arm7tdmi
objects += gba-memory gba-interface gba-system
objects += gba-cartridge gba-player

View File

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

View File

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

View File

@ -1,5 +1,5 @@
auto CPU::serialize(serializer& s) -> void {
ARM::serialize(s);
ARM7TDMI::serialize(s);
Thread::serialize(s);
s.array(iwram);

View File

@ -7,7 +7,6 @@
#include <emulator/thread.hpp>
#include <emulator/scheduler.hpp>
#include <processor/arm/arm.hpp>
#include <processor/arm7tdmi/arm7tdmi.hpp>
namespace GameBoyAdvance {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
//ARMv3 (ARM60)
struct ArmDSP : Processor::ARM, Thread {
struct ArmDSP : Processor::ARM7TDMI, Thread {
#include "registers.hpp"
ArmDSP();

View File

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

View File

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

View File

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