mirror of https://github.com/bsnes-emu/bsnes.git
Update to v086r09 release.
byuu says: A lot more work on the ARMv3 core.
This commit is contained in:
parent
482b4119f6
commit
3ed42af8a1
|
@ -1,7 +1,7 @@
|
|||
#ifndef BASE_HPP
|
||||
#define BASE_HPP
|
||||
|
||||
const char Version[] = "086.08";
|
||||
const char Version[] = "086.09";
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/algorithm.hpp>
|
||||
|
|
|
@ -38,6 +38,13 @@ namespace nall {
|
|||
return x | (x + 1);
|
||||
}
|
||||
|
||||
//count number of bits set in a byte
|
||||
inline unsigned count(unsigned x) {
|
||||
unsigned count = 0;
|
||||
do count += x & 1; while(x >>= 1);
|
||||
return count;
|
||||
}
|
||||
|
||||
//round up to next highest single bit:
|
||||
//round(15) == 16, round(16) == 16, round(17) == 32
|
||||
inline unsigned round(unsigned x) {
|
||||
|
|
|
@ -17,30 +17,61 @@ void ArmDSP::enter() {
|
|||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
step(16);
|
||||
step(4); //todo: how many cycles per instruction?
|
||||
synchronize_cpu();
|
||||
|
||||
print(disassemble_opcode(r[15]), "\n", disassemble_registers(), "\n");
|
||||
|
||||
instruction = bus_read(r[15]);
|
||||
r[15] += 8; //pipeline adjust
|
||||
if((instruction & 0x0e000000) == 0x0a000000) { op_branch(); continue; }
|
||||
if((instruction & 0x0e000000) == 0x02000000) { op_data_immediate(); r[15] -= 4; continue; }
|
||||
|
||||
if(exception) {
|
||||
print("* ARM unknown instruction\n");
|
||||
print("\n", disassemble_registers());
|
||||
print("\n", disassemble_opcode(pipeline.instruction.address), "\n");
|
||||
while(true) {
|
||||
step(21477272);
|
||||
synchronize_cpu();
|
||||
}
|
||||
}
|
||||
|
||||
if(pipeline.reload) {
|
||||
pipeline.reload = false;
|
||||
pipeline.prefetch.address = r[15];
|
||||
pipeline.prefetch.opcode = bus_read<4>(r[15]);
|
||||
r[15].step();
|
||||
}
|
||||
|
||||
pipeline.instruction = pipeline.prefetch;
|
||||
pipeline.prefetch.address = r[15];
|
||||
pipeline.prefetch.opcode = bus_read<4>(r[15]);
|
||||
r[15].step();
|
||||
|
||||
//print("\n", disassemble_registers(), "\n");
|
||||
//print(disassemble_opcode(pipeline.instruction.address), "\n");
|
||||
|
||||
instruction = pipeline.instruction.opcode;
|
||||
if((instruction & 0x0fb000f0) == 0x01200000) { op_move_status_register_to_register(); continue; }
|
||||
if((instruction & 0x0e000010) == 0x00000000) { op_data_immediate_shift(); continue; }
|
||||
if((instruction & 0x0e000000) == 0x02000000) { op_data_immediate(); continue; }
|
||||
if((instruction & 0x0e000000) == 0x04000000) { op_move_immediate_offset(); continue; }
|
||||
if((instruction & 0x0e000000) == 0x08000000) { op_move_multiple(); continue; }
|
||||
if((instruction & 0x0e000000) == 0x0a000000) { op_branch(); continue; }
|
||||
|
||||
exception = true;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 ArmDSP::mmio_read(unsigned addr) {
|
||||
//print("* r", hex<4>(addr), "\n");
|
||||
addr &= 0xffff;
|
||||
if(addr == 0x3800) return armport[0];
|
||||
if(addr == 0x3802) return armport[1];
|
||||
if(addr == 0x3804) return armport[3];
|
||||
|
||||
print("* r", hex<4>(addr), "\n");
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void ArmDSP::mmio_write(unsigned addr, uint8 data) {
|
||||
addr &= 0xffff;
|
||||
if(addr == 0x3802) cpuport[1] = data;
|
||||
if(addr == 0x3804) cpuport[0] = data;
|
||||
|
||||
print("* w", hex<4>(addr), "w = ", hex<2>(data), "\n");
|
||||
}
|
||||
|
||||
|
@ -59,7 +90,12 @@ void ArmDSP::power() {
|
|||
void ArmDSP::reset() {
|
||||
create(ArmDSP::Enter, 21477272);
|
||||
|
||||
for(auto &rd : r) rd = 0x00000000;
|
||||
for(auto &rd : r) rd = 0;
|
||||
exception = false;
|
||||
|
||||
pipeline.reload = true;
|
||||
|
||||
r[15].write = [&] { pipeline.reload = true; };
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,9 +2,13 @@
|
|||
|
||||
struct ArmDSP : public Coprocessor {
|
||||
uint8 programROM[128 * 1024];
|
||||
uint8 programRAM[16 * 1024];
|
||||
|
||||
#include "registers.hpp"
|
||||
|
||||
uint8 cpuport[4];
|
||||
uint8 armport[4];
|
||||
|
||||
static void Enter();
|
||||
void enter();
|
||||
|
||||
|
@ -19,16 +23,21 @@ struct ArmDSP : public Coprocessor {
|
|||
|
||||
//opcodes.cpp
|
||||
bool condition();
|
||||
void opcode(uint32 &rd, uint32 &rn, uint32 shifter);
|
||||
void opcode(uint32 data);
|
||||
void flags(uint32 rd);
|
||||
|
||||
void op_branch();
|
||||
void op_data_immediate();
|
||||
void op_data_immediate_shift();
|
||||
void op_move_immediate_offset();
|
||||
void op_move_status_register_to_register();
|
||||
void op_move_multiple();
|
||||
|
||||
//memory.cpp
|
||||
uint32 bus_read(uint32 addr);
|
||||
void bus_write(uint32 addr, uint32 data);
|
||||
uint8 bus_iread(uint32 addr);
|
||||
void bus_iwrite(uint32 addr, uint8 data);
|
||||
template<unsigned size> uint32 bus_read(uint32 addr);
|
||||
template<unsigned size> void bus_write(uint32 addr, uint32 data);
|
||||
|
||||
//disassembler.cpp
|
||||
string disassemble_opcode(uint32 pc);
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
#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 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" };
|
||||
|
||||
string output{hex<8>(pc), " "};
|
||||
|
||||
uint32 instruction = bus_read(pc);
|
||||
uint32 instruction = bus_read<4>(pc);
|
||||
output.append(hex<8>(instruction), " ");
|
||||
|
||||
uint4 condition = instruction >> 28;
|
||||
|
@ -15,18 +17,80 @@ string ArmDSP::disassemble_opcode(uint32 pc) {
|
|||
uint4 rd = instruction >> 12;
|
||||
uint4 rs = instruction >> 8;
|
||||
|
||||
if((instruction & 0x0e000000) == 0x0a000000) {
|
||||
output.append("b");
|
||||
if(condition != 14) output.append(conditions[condition]);
|
||||
output.append(" 0x", hex<8>(pc + 8 + (int24)instruction * 4));
|
||||
//move status register to register
|
||||
if((instruction & 0x0fb000f0) == 0x01200000) {
|
||||
uint1 psr = instruction >> 22;
|
||||
uint4 field = instruction >> 16;
|
||||
output.append("msr ", psr ? "spsr:" : "cpsr:",
|
||||
field & 1 ? "c" : "",
|
||||
field & 2 ? "x" : "",
|
||||
field & 4 ? "s" : "",
|
||||
field & 8 ? "f" : "",
|
||||
",", registers[(uint4)instruction]);
|
||||
return output;
|
||||
}
|
||||
|
||||
//data immediate shift
|
||||
if((instruction & 0x0e000000) == 0x00000000) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint4 opcode = instruction >> 21;
|
||||
uint1 save = instruction >> 20;
|
||||
uint4 rd = instruction >> 16;
|
||||
uint4 rn = instruction >> 12;
|
||||
uint8 rm = instruction;
|
||||
uint5 shift = instruction >> 7;
|
||||
uint2 op = instruction >> 2;
|
||||
|
||||
output.append(opcodes[opcode], conditions[condition], save ? "s " : " ");
|
||||
output.append(registers[rd], ",");
|
||||
output.append(registers[rn], ",");
|
||||
output.append(registers[rm], " ");
|
||||
if(op == 0) output.append("lsl #", shift);
|
||||
if(op == 1) output.append("lsr #", 1 + shift);
|
||||
if(op == 2) output.append("asr #", 1 + shift);
|
||||
if(op == 3 && shift != 0) output.append("ror #", shift);
|
||||
if(op == 3 && shift == 0) output.append("rrx");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//data immediate
|
||||
if((instruction & 0x0e000000) == 0x02000000) {
|
||||
uint5 rotate = 2 * (uint4)(instruction >> 8);
|
||||
uint32 immediate = (uint8)instruction;
|
||||
immediate = (immediate >> rotate) | (immediate << (32 - rotate));
|
||||
output.append(opcodes[opcode], " r", rd, ",#0x", hex<8>(immediate));
|
||||
output.append(opcodes[opcode], " ", registers[rd], ",#0x", hex<8>(immediate));
|
||||
return output;
|
||||
}
|
||||
|
||||
//move immediate offset
|
||||
//todo: support W flag
|
||||
if((instruction & 0x0e000000) == 0x04000000) {
|
||||
uint1 u = instruction >> 23;
|
||||
uint1 load = instruction >> 20;
|
||||
uint12 immediate = instruction;
|
||||
output.append(load ? "ldr" : "str", conditions[condition]);
|
||||
output.append(" ", registers[rd], ",[", registers[rn]);
|
||||
if(immediate) output.append(u ? "+" : "-", "0x", hex<3>((uint12)instruction));
|
||||
output.append("]");
|
||||
return output;
|
||||
}
|
||||
|
||||
//move multiple
|
||||
if((instruction & 0x0e000000) == 0x08000000) {
|
||||
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
|
||||
if((instruction & 0x0e000000) == 0x0a000000) {
|
||||
uint1 l = instruction >> 24;
|
||||
output.append("b", l ? "l" : "", conditions[condition]);
|
||||
output.append(" 0x", hex<8>(pc + 8 + (int24)instruction * 4));
|
||||
return output;
|
||||
}
|
||||
|
||||
|
@ -39,7 +103,8 @@ string ArmDSP::disassemble_registers() {
|
|||
"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]), "\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]), "\n"
|
||||
" r12:", hex<8>(r[12]), " r13:", hex<8>(r[13]), " r14:", hex<8>(r[14]), " r15:", hex<8>(r[15]), "\n",
|
||||
"cpsr:", cpsr.n ? "N" : "n", cpsr.z ? "Z" : "z", cpsr.c ? "C" : "c", cpsr.v ? "V" : "v"
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,18 +1,62 @@
|
|||
#ifdef ARMDSP_CPP
|
||||
|
||||
uint32 ArmDSP::bus_read(uint32 addr) {
|
||||
uint8 ArmDSP::bus_iread(uint32 addr) {
|
||||
if(addr >= 0x00000000 && addr <= 0x0001ffff) {
|
||||
addr &= 0x0001ffff;
|
||||
return (programROM[addr + 0] << 0)
|
||||
+ (programROM[addr + 1] << 8)
|
||||
+ (programROM[addr + 2] << 16)
|
||||
+ (programROM[addr + 3] << 24);
|
||||
return programROM[addr & 0x0001ffff];
|
||||
}
|
||||
|
||||
return 0x00000000;
|
||||
if(addr >= 0x40000020 && addr <= 0x4000002f) {
|
||||
if(addr == 0x40000020) return cpuport[0];
|
||||
if(addr == 0x40000024) return cpuport[1];
|
||||
if(addr == 0x40000028) return cpuport[2];
|
||||
if(addr == 0x4000002c) return cpuport[3];
|
||||
}
|
||||
|
||||
if(addr >= 0xe0000000 && addr <= 0xe0003fff) {
|
||||
return programRAM[addr & 0x00003fff];
|
||||
}
|
||||
|
||||
//print("* ARM r", hex<8>(addr), "\n");
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void ArmDSP::bus_iwrite(uint32 addr, uint8 data) {
|
||||
if(addr >= 0x40000020 && addr <= 0x4000002f) {
|
||||
if(addr == 0x40000020) armport[0] = data;
|
||||
if(addr == 0x40000024) armport[1] = data;
|
||||
if(addr == 0x40000028) armport[2] = data;
|
||||
if(addr == 0x4000002c) armport[3] = data;
|
||||
if(data) print("* ARM w", hex<8>(addr), " = ", hex<2>(data), "\n");
|
||||
}
|
||||
|
||||
if(addr >= 0xe0000000 && addr <= 0xe0003fff) {
|
||||
programRAM[addr & 0x00003fff] = data;
|
||||
return;
|
||||
}
|
||||
|
||||
//print("* ARM w", hex<8>(addr), " = ", hex<2>(data), "\n");
|
||||
}
|
||||
|
||||
template<unsigned size>
|
||||
uint32 ArmDSP::bus_read(uint32 addr) {
|
||||
uint32 result = 0;
|
||||
result |= bus_iread(addr + 0) << 0;
|
||||
result |= bus_iread(addr + 1) << 8;
|
||||
result |= bus_iread(addr + 2) << 16;
|
||||
result |= bus_iread(addr + 3) << 24;
|
||||
if(size == 1) return result & 0xff;
|
||||
if(size == 2) return result & 0xffff;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<unsigned size>
|
||||
void ArmDSP::bus_write(uint32 addr, uint32 data) {
|
||||
if(size == 1) data = (bus_read<1>(addr) & 0xffffff00) | (data & 0x000000ff);
|
||||
if(size == 2) data = (bus_read<2>(addr) & 0xffff0000) | (data & 0x0000ffff);
|
||||
bus_iwrite(addr + 0, data >> 0);
|
||||
bus_iwrite(addr + 1, data >> 8);
|
||||
bus_iwrite(addr + 2, data >> 16);
|
||||
bus_iwrite(addr + 3, data >> 24);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -21,24 +21,52 @@ bool ArmDSP::condition() {
|
|||
}
|
||||
}
|
||||
|
||||
void ArmDSP::opcode(uint32 &rd, uint32 &rn, uint32 shifter) {
|
||||
switch((uint4)(instruction >> 21)) {
|
||||
case 0: rd = rn & shifter; break; //AND (logical and)
|
||||
case 1: rd = rn & shifter; break; //EOR (logical exclusive or)
|
||||
case 2: rd = rn - shifter; break; //SUB (subtract)
|
||||
case 3: rd = shifter - rn; break; //RSB (reverse subtract)
|
||||
case 4: rd = rn + shifter; break; //ADD (add)
|
||||
case 5: rd = rn + shifter + cpsr.c; break; //ADC (add with carry)
|
||||
case 6: rd = rn - shifter - !cpsr.c; break; //SBC (subtract with carry)
|
||||
case 7: rd = shifter - rn - !cpsr.c; break; //RSC (reverse subtract with carry)
|
||||
case 8: flags(rn & shifter); break; //TST (test)
|
||||
case 9: flags(rn ^ shifter); break; //TEQ (test equivalence)
|
||||
case 10: flags(rn - shifter); break; //CMP (compare)
|
||||
case 11: flags(rn + shifter); break; //CMN (compare negated)
|
||||
case 12: rd = rn | shifter; break; //ORR (logical inclusive or)
|
||||
case 13: rd = shifter; break; //MOV (move)
|
||||
case 14: rd = rn & ~shifter; break; //BIC (bit clear)
|
||||
case 15: rd = ~shifter; //MVN (move not)
|
||||
//rd = target
|
||||
//rn = source
|
||||
//rm = modifier
|
||||
//ri = original target
|
||||
//ro = modified target
|
||||
void ArmDSP::opcode(uint32 rm) {
|
||||
uint4 opcode = instruction >> 21;
|
||||
uint1 s = instruction >> 20;
|
||||
auto &rn = r[(uint4)(instruction >> 16)];
|
||||
auto &rd = r[(uint4)(instruction >> 12)];
|
||||
uint32 ri = rd, ro;
|
||||
|
||||
//comparison opcodes always update flags
|
||||
if(opcode >= 8 && opcode <= 11) s = 1;
|
||||
|
||||
static auto nz = [&](uint32 ro) {
|
||||
if(!s) return;
|
||||
cpsr.n = ro & 0x80000000;
|
||||
cpsr.z = ro == 0;
|
||||
};
|
||||
|
||||
static auto nzcv = [&](uint32 ro) {
|
||||
if(!s) return;
|
||||
cpsr.n = ro & 0x80000000;
|
||||
cpsr.z = ro == 0;
|
||||
cpsr.c = ro < ri;
|
||||
cpsr.v = ~(ri ^ rm) & (ri ^ ro) & 0x80000000;
|
||||
};
|
||||
|
||||
switch(opcode) {
|
||||
case 0: rd = rn & rm; nz(rd); break; //AND (logical and)
|
||||
case 1: rd = rn ^ rm; nz(rd); break; //EOR (logical exclusive or)
|
||||
case 2: rd = rn +~rm; nzcv(rd); break; //SUB (subtract)
|
||||
case 3: rd = rm +~rn; nzcv(rd); break; //RSB (reverse subtract)
|
||||
case 4: rd = rn + rm; nzcv(rd); break; //ADD (add)
|
||||
case 5: rd = rn + rm + cpsr.c; nzcv(rd); break; //ADC (add with carry)
|
||||
case 6: rd = rn +~rm + cpsr.c; nzcv(rd); break; //SBC (subtract with carry)
|
||||
case 7: rd = rm +~rn + cpsr.c; nzcv(rd); break; //RSC (reverse subtract with carry)
|
||||
case 8: ro = rn & rm; nz(ro); break; //TST (test)
|
||||
case 9: ro = rn ^ rm; nz(ro); break; //TEQ (test equivalence)
|
||||
case 10: ro = rn +~rm; nzcv(ro); break; //CMP (compare)
|
||||
case 11: ro = rn + rm; nzcv(ro); break; //CMN (compare negated)
|
||||
case 12: rd = rn | rm; nz(rd); break; //ORR (logical inclusive or)
|
||||
case 13: rd = rm; nz(rd); break; //MOV (move)
|
||||
case 14: rd = rn &~rm; nz(rd); break; //BIC (bit clear)
|
||||
case 15: rd =~rm; nz(rd); break; //MVN (move not)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,7 +82,10 @@ void ArmDSP::flags(uint32 rd) {
|
|||
void ArmDSP::op_branch() {
|
||||
if(!condition()) return;
|
||||
|
||||
int24 displacement = (int24)instruction;
|
||||
uint1 l = instruction >> 24;
|
||||
int24 displacement = instruction;
|
||||
|
||||
if(l) r[14] = r[15] - 4;
|
||||
r[15] += displacement * 4;
|
||||
}
|
||||
|
||||
|
@ -69,28 +100,162 @@ void ArmDSP::op_branch() {
|
|||
void ArmDSP::op_data_immediate() {
|
||||
if(!condition()) return;
|
||||
|
||||
bool s = (uint1)(instruction >> 20);
|
||||
uint4 n = (uint4)(instruction >> 16);
|
||||
uint4 d = (uint4)(instruction >> 12);
|
||||
uint5 rotate = 2 * (uint4)(instruction >> 8);
|
||||
uint32 immediate = (uint8)instruction;
|
||||
immediate = (immediate >> rotate) | (immediate << (32 - rotate));
|
||||
uint4 rotate = instruction >> 8;
|
||||
uint8 immediate = instruction >> 0;
|
||||
|
||||
opcode(r[d], r[n], immediate);
|
||||
opcode(
|
||||
(immediate >> (rotate << 1)) | (immediate << (32 - (rotate << 1)))
|
||||
);
|
||||
|
||||
//todo: set carry for non-add/sub opcodes here
|
||||
}
|
||||
|
||||
//CCCC 010P UBWL NNNN DDDD IIII IIII
|
||||
//CCCC 000O OOOS NNNN DDDD LLLL LSS0 MMMM
|
||||
//C = condition
|
||||
//P = pre/post-indexed addressing
|
||||
//U = add/sub offset to base
|
||||
//B = byte/word access
|
||||
//W = ...
|
||||
//L = load/save
|
||||
//O = opcode
|
||||
//S = update flags
|
||||
//N = Rn
|
||||
//D = Rd
|
||||
//L = shift amount
|
||||
//S = shift
|
||||
//M = Rm
|
||||
void ArmDSP::op_data_immediate_shift() {
|
||||
if(!condition()) return;
|
||||
|
||||
uint5 shift = instruction >> 7;
|
||||
uint2 op = instruction >> 5;
|
||||
uint32 rm = r[(uint4)instruction];
|
||||
|
||||
if(op == 0) { //LSL (logical shift left)
|
||||
rm = rm << shift;
|
||||
}
|
||||
|
||||
if(op == 1) { //LSR (logical shift right)
|
||||
rm = rm >> (1 + shift);
|
||||
}
|
||||
|
||||
if(op == 2) { //ASR (arithmetic shift right)
|
||||
rm = (int32)rm >> (1 + shift);
|
||||
}
|
||||
|
||||
if(op == 3) { //ROR (rotate right)
|
||||
if(shift == 0) { //RRX (rorate right with extend)
|
||||
rm = (cpsr.c << 31) | (rm >> 1);
|
||||
} else {
|
||||
rm = (rm >> shift) + (rm << (32 - shift));
|
||||
}
|
||||
}
|
||||
|
||||
opcode(rm);
|
||||
|
||||
//todo: set carry
|
||||
}
|
||||
|
||||
//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() {
|
||||
if(!condition()) return;
|
||||
|
||||
uint1 p = instruction >> 24;
|
||||
uint1 u = instruction >> 23;
|
||||
uint1 b = instruction >> 22;
|
||||
uint1 w = instruction >> 21;
|
||||
uint1 l = instruction >> 20;
|
||||
uint4 n = instruction >> 16;
|
||||
auto &rd = r[(uint4)(instruction >> 12)];
|
||||
uint12 immediate = instruction;
|
||||
|
||||
uint32 rn = r[n];
|
||||
|
||||
if(l) {
|
||||
if(p == 1) rn = u ? rn + immediate : rn - immediate;
|
||||
if(b) rd = bus_read<1>(rn);
|
||||
else rd = bus_read<4>(rn);
|
||||
if(p == 0) rn = u ? rn + immediate : rn - immediate;
|
||||
} else {
|
||||
if(p == 1) rn = u ? rn + immediate : rn - immediate;
|
||||
if(b) bus_write<1>(rn, rd);
|
||||
else bus_write<4>(rn, rd);
|
||||
if(p == 0) rn = u ? rn + immediate : rn - immediate;
|
||||
}
|
||||
|
||||
if(p == 1 && w == 1) r[n] = rn;
|
||||
}
|
||||
|
||||
//CCCC 0001 0R10 FFFF ++++ ---- 0000 MMMM
|
||||
//C = condition
|
||||
//R = SPSR (0 = CPSR)
|
||||
//F = field mask
|
||||
//M = Rm
|
||||
void ArmDSP::op_move_status_register_to_register() {
|
||||
if(!condition()) return;
|
||||
|
||||
uint1 source = instruction >> 22;
|
||||
uint4 field = instruction >> 16;
|
||||
|
||||
auto &rm = r[(uint4)instruction];
|
||||
PSR &psr = source ? spsr : cpsr;
|
||||
|
||||
if(field & 1) psr.setc(rm);
|
||||
if(field & 2) psr.setx(rm);
|
||||
if(field & 4) psr.sets(rm);
|
||||
if(field & 8) psr.setf(rm);
|
||||
}
|
||||
|
||||
//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() {
|
||||
if(!condition()) return;
|
||||
|
||||
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;
|
||||
if(p == 0 && u == 1) rn = r[n] + 0; //IA
|
||||
if(p == 1 && u == 1) rn = r[n] + 4; //IB
|
||||
if(p == 1 && u == 0) rn = r[n] - bit::count(list) * 4 + 0; //DB
|
||||
if(p == 0 && u == 0) rn = r[n] - bit::count(list) * 4 + 4; //DA
|
||||
|
||||
if(l) {
|
||||
for(unsigned n = 0; n < 16; n++) {
|
||||
if(list & (1 << n)) {
|
||||
r[n] = bus_read<4>(rn);
|
||||
rn += 4;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(unsigned n = 0; n < 16; n++) {
|
||||
if(list & (1 << n)) {
|
||||
bus_write<4>(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
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
//00000018 = IRQ (interrupt)
|
||||
//0000001c = FIQ (fast interrupt)
|
||||
|
||||
struct CPSR {
|
||||
struct PSR {
|
||||
bool n;
|
||||
bool z;
|
||||
bool c;
|
||||
|
@ -16,26 +16,87 @@ struct CPSR {
|
|||
bool f;
|
||||
uint5 m;
|
||||
|
||||
operator unsigned() const {
|
||||
return (n << 31) | (z << 30) | (c << 29) | (v << 28) | (i << 7) | (f << 6) | (m << 0);
|
||||
uint32 getf() const {
|
||||
return (n << 31) | (z << 30) | (c << 29) | (v << 28);
|
||||
}
|
||||
|
||||
CPSR& operator=(uint32 data) {
|
||||
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;
|
||||
} cpsr, spsr;
|
||||
|
||||
//r13 = SP (stack pointer)
|
||||
//r14 = LR (link register)
|
||||
//r15 = PC (program counter)
|
||||
uint32 r[16];
|
||||
struct Register {
|
||||
uint32 data;
|
||||
function<void ()> write;
|
||||
|
||||
operator unsigned() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
Register& operator=(uint32 n) {
|
||||
data = n;
|
||||
if(write) write();
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
struct Pipeline {
|
||||
bool reload;
|
||||
struct Instruction {
|
||||
uint32 opcode;
|
||||
uint32 address;
|
||||
};
|
||||
Instruction instruction;
|
||||
Instruction prefetch;
|
||||
} pipeline;
|
||||
|
||||
uint32 instruction;
|
||||
uint32 prefetch;
|
||||
bool exception;
|
||||
|
|
Loading…
Reference in New Issue