Update to v086r10 release.

byuu says:

More ARM work. ARM core now begins to act upon initial 0xf1 command, but
hangs.
This commit is contained in:
Tim Allen 2012-02-28 22:10:02 +11:00
parent 3ed42af8a1
commit 11d6f09359
6 changed files with 196 additions and 89 deletions

View File

@ -1,7 +1,7 @@
#ifndef BASE_HPP
#define BASE_HPP
const char Version[] = "086.09";
const char Version[] = "086.10";
#include <nall/platform.hpp>
#include <nall/algorithm.hpp>

View File

@ -3,6 +3,8 @@
#define ARMDSP_CPP
namespace SNES {
static bool trace = 0;
#include "opcodes.cpp"
#include "memory.cpp"
#include "disassembler.cpp"
@ -42,12 +44,17 @@ void ArmDSP::enter() {
pipeline.prefetch.opcode = bus_read<4>(r[15]);
r[15].step();
//print("\n", disassemble_registers(), "\n");
//print(disassemble_opcode(pipeline.instruction.address), "\n");
//if(pipeline.instruction.address == 0x00000208) trace = 1;
if(trace) {
print("\n", disassemble_registers(), "\n");
print(disassemble_opcode(pipeline.instruction.address), "\n");
usleep(200000);
}
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 & 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 & 0x0e000000) == 0x08000000) { op_move_multiple(); continue; }
@ -58,21 +65,27 @@ void ArmDSP::enter() {
}
uint8 ArmDSP::mmio_read(unsigned addr) {
addr &= 0xffff;
if(addr == 0x3800) return armport[0];
if(addr == 0x3802) return armport[1];
if(addr == 0x3804) return armport[3];
uint8 data = 0x00;
switch(addr & 0xffff) {
case 0x3800: data = w40000000; break;
case 0x3802: data = r3802; break;
case 0x3804: data = r3804; break;
}
print("* r", hex<4>(addr), "\n");
return 0x00;
print("* r", hex<6>(addr), " = ", hex<2>(data), "\n");
usleep(200000);
return data;
}
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<6>(addr), " = ", hex<2>(data), "\n");
usleep(200000);
print("* w", hex<4>(addr), "w = ", hex<2>(data), "\n");
switch(addr & 0xffff) {
case 0x3800: w3800 = data; break;
case 0x3802: w3802 = data; trace = 0; cputoarm = true; break;
case 0x3804: w3804 = data; break;
}
}
void ArmDSP::init() {
@ -96,6 +109,13 @@ void ArmDSP::reset() {
pipeline.reload = true;
r[15].write = [&] { pipeline.reload = true; };
r3800=r3802=r3804=0;
w3800=w3802=w3804=0;
r40000000=r40000010=r40000020=r40000024=r40000028=r4000002c=0;
w40000000=w40000010=w40000020=w40000024=w40000028=w4000002c=0;
cputoarm=0;
armtocpu=0;
}
}

View File

@ -6,8 +6,17 @@ struct ArmDSP : public Coprocessor {
#include "registers.hpp"
uint8 cpuport[4];
uint8 armport[4];
//CPU
uint8 r3800, r3802, r3804;
uint8 w3800, w3802, w3804;
//ARM
uint32 r40000000, r40000010, r40000020, r40000024, r40000028, r4000002c;
uint32 w40000000, w40000010, w40000020, w40000024, w40000028, w4000002c;
//Status
bool cputoarm;
bool armtocpu;
static void Enter();
void enter();
@ -24,11 +33,11 @@ struct ArmDSP : public Coprocessor {
//opcodes.cpp
bool condition();
void opcode(uint32 data);
void flags(uint32 rd);
void op_branch();
void op_data_immediate();
void op_data_immediate_shift();
void op_data_register_shift();
void op_move_immediate_offset();
void op_move_status_register_to_register();
void op_move_multiple();

View File

@ -6,6 +6,10 @@ string ArmDSP::disassemble_opcode(uint32 pc) {
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_read<4>(pc);
@ -31,45 +35,65 @@ string ArmDSP::disassemble_opcode(uint32 pc) {
}
//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 & 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;
uint4 rn = instruction >> 16;
uint4 rd = instruction >> 12;
uint5 shift = instruction >> 7;
uint2 op = instruction >> 2;
uint2 op = instruction >> 5;
uint4 rm = instruction;
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");
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 immediate
//{opcode}{condition}{s} rd,#immediate
//{opcode}{condition} rn,#immediate
//{opcode}{condition}{s} rd,rn,#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], " ", registers[rd], ",#0x", hex<8>(immediate));
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}]
//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]);
if(instruction & 0x00400000) output.append("b");
output.append(" ", registers[rd], ",[", registers[rn]);
if(immediate) output.append(u ? "+" : "-", "0x", hex<3>((uint12)instruction));
output.append("]");
@ -77,6 +101,7 @@ string ArmDSP::disassemble_opcode(uint32 pc) {
}
//move multiple
//(ldm,stm){condition}{mode} rn{!},{r...}
if((instruction & 0x0e000000) == 0x08000000) {
output.append(instruction & 0x00100000 ? "ldm" : "stm", conditions[condition], indices[(uint2)(instruction >> 23)]);
output.append(" ", registers[rn], instruction & 0x00200000 ? "!" : "", ",{");
@ -87,6 +112,7 @@ string ArmDSP::disassemble_opcode(uint32 pc) {
}
//branch
//b{l}{condition} address
if((instruction & 0x0e000000) == 0x0a000000) {
uint1 l = instruction >> 24;
output.append("b", l ? "l" : "", conditions[condition]);

View File

@ -5,52 +5,70 @@ uint8 ArmDSP::bus_iread(uint32 addr) {
return programROM[addr & 0x0001ffff];
}
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 >= 0x40000000 && addr <= 0x400000ff) {
if(addr == 0x40000000) { return r40000000; }
if(addr == 0x40000010) { return w3802; }
if(addr == 0x40000020) { return (cputoarm << 3); }
if(addr == 0x40000024) { return r40000024; }
if(addr == 0x40000028) { return r40000028; }
if(addr == 0x4000002c) { return r4000002c; }
}
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 >= 0x40000000 && addr <= 0x400000ff) {
if(addr == 0x40000000) { w40000000 = data; }
if(addr == 0x40000020) { w40000020 = data; }
if(addr == 0x40000024) { w40000024 = data; }
if(addr == 0x40000028) { w40000028 = data; }
if(addr == 0x4000002c) { w4000002c = data; if(data & 2) r3804 = 0x80; }
}
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;
uint32 data = 0;
data |= bus_iread(addr + 0) << 0;
data |= bus_iread(addr + 1) << 8;
data |= bus_iread(addr + 2) << 16;
data |= bus_iread(addr + 3) << 24;
if(addr >= 0x40000000 && addr <= 0x400000ff) {
if(data) {
if(size == 1) print("* ARM r", hex<8>(addr), " = ", hex<2>(data), "\n");
if(size == 2) print("* ARM r", hex<8>(addr), " = ", hex<4>(data), "\n");
if(size == 4) print("* ARM r", hex<8>(addr), " = ", hex<8>(data), "\n");
usleep(20000);
}
}
if(size == 1) return data & 0xff;
if(size == 2) return data & 0xffff;
return data;
}
template<unsigned size>
void ArmDSP::bus_write(uint32 addr, uint32 data) {
if(addr >= 0x40000000 && addr <= 0x400000ff) {
if(0||data) {
if(size == 1) print("* ARM w", hex<8>(addr), " = ", hex<2>(data), "\n");
if(size == 2) print("* ARM w", hex<8>(addr), " = ", hex<4>(data), "\n");
if(size == 4) print("* ARM w", hex<8>(addr), " = ", hex<8>(data), "\n");
usleep(20000);
}
}
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);

View File

@ -1,7 +1,7 @@
#ifdef ARMDSP_CPP
bool ArmDSP::condition() {
switch((uint4)(instruction >> 28)) { default:
switch((uint4)(instruction >> 28)) {
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)
@ -53,15 +53,15 @@ void ArmDSP::opcode(uint32 rm) {
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 2: rd = rn +~rm + 1; nzcv(rd); break; //SUB (subtract)
case 3: rd = rm +~rn + 1; 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 10: ro = rn +~rm + 1; 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)
@ -70,11 +70,6 @@ void ArmDSP::opcode(uint32 rm) {
}
}
void ArmDSP::flags(uint32 rd) {
cpsr.n = rd & 0x80000000;
cpsr.z = rd == 0;
}
//CCCC 101L DDDD DDDD DDDD DDDD DDDD DDDD
//C = condition
//L = link
@ -89,6 +84,9 @@ void ArmDSP::op_branch() {
r[15] += displacement * 4;
}
//{opcode}{condition}{s} rd,#immediate
//{opcode}{condition} rn,#immediate
//{opcode}{condition}{s} rd,rn,#immediate
//CCCC 001O OOOS NNNN DDDD RRRR IIII IIII
//C = condition
//O = opcode
@ -100,16 +98,18 @@ void ArmDSP::op_branch() {
void ArmDSP::op_data_immediate() {
if(!condition()) return;
uint4 rotate = instruction >> 8;
uint8 immediate = instruction >> 0;
uint4 shift = instruction >> 8;
uint8 immediate = instruction;
opcode(
(immediate >> (rotate << 1)) | (immediate << (32 - (rotate << 1)))
);
uint32 rs = shift << 1;
uint32 rm = (immediate >> rs) | (immediate << (32 - rs));
//todo: set carry for non-add/sub opcodes here
opcode(rm);
}
//{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
@ -123,34 +123,66 @@ void ArmDSP::op_data_immediate_shift() {
if(!condition()) return;
uint5 shift = instruction >> 7;
uint2 op = instruction >> 5;
uint32 rm = r[(uint4)instruction];
uint2 mode = instruction >> 5;
uint4 m = instruction;
if(op == 0) { //LSL (logical shift left)
rm = rm << shift;
}
uint32 rs = shift;
uint32 rm = r[m];
if(op == 1) { //LSR (logical shift right)
rm = rm >> (1 + shift);
}
switch(mode) {
case 0: //LSL
rm = rm << rs;
break;
if(op == 2) { //ASR (arithmetic shift right)
rm = (int32)rm >> (1 + shift);
}
case 1: //LSR
if(rs == 0) rs = 32;
rm = rm >> rs;
break;
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));
}
case 2: //ASR
if(rs == 0) rs = 32;
rm = (int32)rm >> rs;
break;
case 3: //ROR + RRX
if(rs == 0) rm = (cpsr.c << 31) | (rm >> 1); //RRX
if(rs != 0) rm = (rm >> rs) + (rm << (32 - rs)); //ROR
break;
}
opcode(rm);
//todo: set carry
}
//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() {
if(!condition()) return;
uint4 s = instruction >> 8;
uint2 mode = instruction >> 5;
uint4 m = instruction >> 0;
uint32 rs = r[s];
uint32 rm = r[m];
switch(mode) {
case 0: rm = rm << rs; break; //LSL
case 1: rm = rm >> rs; break; //LSR
case 2: rm = (int32)rm >> rs; break; //ASR
case 3: rm = (rm >> rs) + (rm << (32 - rs)); break; //ROR
}
opcode(rm);
}
//(ldr,str){condition}{b} rd,[rn{+offset}]
//CCCC 010P UBWL NNNN DDDD IIII IIII IIII
//C = condition
//P = pre (0 = post-indexed addressing)
@ -256,6 +288,8 @@ void ArmDSP::op_move_multiple() {
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
}
//if(l)exception=true;
}
#endif