Update to v086r14 release.

byuu says:

Attempted to fix the bugs pointed out by Cydrak for the shifter carry
and subtraction flags. No way to know if I was successful.
The memory map should exactly match real hardware now.
Also simplified bus reading/writing: we can get fancy when it works,
I suppose.
Reduced some of the code repetition to try and minimize the chances for
bugs.
I hopefully fixed up register-based ror shifting to what the docs were
saying.
And lastly, the disassembler should handle every opcode in every mode
now.
ldr rn,[pc,n] adds (pc,n) [absolute address] after opcode. I didn't want
to actually read from ROM here (in case it ever touches I/O or
something), but I suppose we could try anyway.
At startup, it will write out "disassembly.txt" which is a disassembly
of the entire program ROM.
If anyone wants to look for disassembly errors, I'll go ahead and fix
them. Just note that I won't do common substitutions like mov pc,lr ==
ret.

At this point, we can make two moves and then the game tells us that
we've won.
So ... I'm back to thinking the problem is with bugs in the ARM core,
and that our bidirectional communication is strong enough to play the
game.
Although that's not perfect. The game definitely looks at d4 (and
possibly others later), but my hardware tests can't get anything but
d0/d3 set.
This commit is contained in:
Tim Allen 2012-03-01 23:23:05 +11:00
parent ad71e18e02
commit aa8ac7bbb8
10 changed files with 186 additions and 163 deletions

View File

@ -89,6 +89,6 @@ sync:
rm -r phoenix/test
archive-all:
tar -cjf bsnes.tar.bz2 base data gameboy libco nall nes obj out phoenix ruby snes ui ui-debugger ui-libsnes Makefile cc.bat clean.bat
tar -cjf bsnes.tar.bz2 base data gameboy libco nall nes obj out phoenix ruby snes ui ui-debugger ui-libsnes Makefile cc.bat purge.bat
help:;

View File

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

View File

@ -529,19 +529,10 @@ SnesCartridge::SnesCartridge(const uint8_t *data, unsigned size) {
if(has_st018) markup.append(
" <armdsp firmware='st0018.rom' sha256='6cceff3c6945bb2672040066d218efcd2f31492f3f5c28916c8e53435c2c887e'>\n"
" <map address='00-3f:3800-3805'/>\n"
" <map address='80-bf:3800-3805'/>\n"
" </armdsp>\n"
);
#if 0
if(has_st018) markup.append(
" <setarisc firmware='ST-0018'>\n"
" <map address='00-3f:3800-38ff'/>\n"
" <map address='80-bf:3800-38ff'/>\n"
" </setarisc>\n"
" </armdsp>\n"
);
#endif
markup.append("</cartridge>\n");
}

View File

@ -35,13 +35,13 @@ void ArmDSP::enter() {
if(pipeline.reload) {
pipeline.reload = false;
pipeline.prefetch.address = r[15];
pipeline.prefetch.opcode = bus_read<4>(r[15]);
pipeline.prefetch.opcode = bus_readword(r[15]);
r[15].step();
}
pipeline.instruction = pipeline.prefetch;
pipeline.prefetch.address = r[15];
pipeline.prefetch.opcode = bus_read<4>(r[15]);
pipeline.prefetch.opcode = bus_readword(r[15]);
r[15].step();
//if(pipeline.instruction.address == 0x0000ef5c) trace = 1;
@ -68,11 +68,15 @@ void ArmDSP::enter() {
}
}
//MMIO: $00-3f|80-bf:3800-38ff
//3800-3807 mirrored throughout
//a0 ignored
uint8 ArmDSP::mmio_read(unsigned addr) {
cpu.synchronize_coprocessors();
uint8 data = 0x00;
addr &= 0xffff;
addr &= 0xff06;
if(addr == 0x3800) {
if(bridge.armtocpu.ready) {
@ -104,7 +108,7 @@ void ArmDSP::mmio_write(unsigned addr, uint8 data) {
usleep(200000);
}
addr &= 0xffff;
addr &= 0xff06;
if(addr == 0x3802) {
bridge.cputoarm.ready = true;
@ -131,12 +135,21 @@ void ArmDSP::power() {
fp.read(dataROM, 32 * 1024);
fp.close();
}
filename = { dir(filename), "disassembly.txt" };
fp.open(filename, file::mode::write);
for(unsigned n = 0; n < 128 * 1024; n += 4) {
fp.print(disassemble_opcode(n), "\n");
}
fp.close();
}
void ArmDSP::reset() {
create(ArmDSP::Enter, 21477272);
for(auto &rd : r) rd = 0;
shiftercarry = 0;
exception = false;
pipeline.reload = true;

View File

@ -42,8 +42,12 @@ struct ArmDSP : public Coprocessor {
//memory.cpp
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);
uint32 bus_readbyte(uint32 addr);
uint32 bus_readword(uint32 addr);
void bus_writebyte(uint32 addr, uint32 data);
void bus_writeword(uint32 addr, uint32 data);
//disassembler.cpp
string disassemble_opcode(uint32 pc);

View File

@ -12,10 +12,11 @@ string ArmDSP::disassemble_opcode(uint32 pc) {
string output{hex<8>(pc), " "};
uint32 instruction = bus_read<4>(pc);
uint32 instruction = bus_readword(pc);
output.append(hex<8>(instruction), " ");
//multiply
//(mul,mla){condition}{s} rd,rm,rs,rn
if((instruction & 0x0fc000f0) == 0x00000090) {
uint4 condition = instruction >> 28;
uint1 accumulate = instruction >> 21;
@ -33,6 +34,7 @@ string ArmDSP::disassemble_opcode(uint32 pc) {
}
//move to register from status register
//mrs{condition} rd,(c,s)psr
if((instruction & 0x0fb000f0) == 0x01000000) {
uint4 condition = instruction >> 28;
uint1 psr = instruction >> 22;
@ -45,6 +47,7 @@ string ArmDSP::disassemble_opcode(uint32 pc) {
}
//move to status register from register
//msr{condition} (c,s)psr:{fields},rm
if((instruction & 0x0fb000f0) == 0x01200000) {
uint4 condition = instruction >> 28;
uint1 psr = instruction >> 22;
@ -89,6 +92,34 @@ string ArmDSP::disassemble_opcode(uint32 pc) {
return output;
}
//data register shift
//{opcode}{condition}{s} rd,rm {shift} rs
//{opcode}{condition} rn,rm {shift} rs
//{opcode}{condition}{s} rd,rn,rm {shift} rs
if((instruction & 0x0e000090) == 0x00000010) {
uint4 condition = instruction >> 28;
uint4 opcode = instruction >> 21;
uint1 save = instruction >> 20;
uint4 rn = instruction >> 16;
uint4 rd = instruction >> 12;
uint4 rs = instruction >> 8;
uint2 mode = instruction >> 5;
uint4 rm = instruction;
output.append(opcodes[opcode], conditions[condition]);
if(is_move(opcode)) output.append(save ? "s " : " ", registers[rd], ",");
if(is_comp(opcode)) output.append(registers[rn], ",");
if(is_math(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn], ",");
output.append(registers[rm]);
if(mode == 0) output.append(" lsl ");
if(mode == 1) output.append(" lsr ");
if(mode == 2) output.append(" asr ");
if(mode == 3) output.append(" ror ");
output.append(registers[rs]);
return output;
}
//data immediate
//{opcode}{condition}{s} rd,#immediate
//{opcode}{condition} rn,#immediate
@ -113,21 +144,58 @@ string ArmDSP::disassemble_opcode(uint32 pc) {
}
//move immediate offset
//(ldr,str){condition}{b} rd,[rn{+offset}]
//todo: support W flag
//(ldr,str){condition}{b} rd,[rn{,+/-offset}]{!}
//(ldr,str){condition}{b} rd,[rn]{,+/-offset}
if((instruction & 0x0e000000) == 0x04000000) {
uint4 condition = instruction >> 28;
uint1 p = instruction >> 24;
uint1 u = instruction >> 23;
uint1 b = instruction >> 22;
uint1 w = instruction >> 21;
uint1 load = instruction >> 20;
uint4 rn = instruction >> 16;
uint4 rd = instruction >> 12;
uint12 immediate = instruction;
output.append(load ? "ldr" : "str", conditions[condition]);
if(instruction & 0x00400000) output.append("b");
output.append(" ", registers[rd], ",[", registers[rn]);
if(immediate) output.append(u ? "+" : "-", "0x", hex<3>((uint12)instruction));
output.append("]");
output.append(load ? "ldr" : "str", conditions[condition], b ? "b " : " ");
output.append(registers[rd], ",[", registers[rn]);
if(p == 0) output.append("]");
if(immediate) output.append(",", u ? "+" : "-", "0x", hex<3>(immediate));
if(p == 1) output.append("]");
if(p == 1 && w == 1) output.append("!");
if(rn == 15) output.append(" (0x", hex<8>(pc + 8 + (u ? +immediate : -immediate)), ")");
return output;
}
//move register offset
//(ldr)(str){condition}{b} rd,[rn,rm {mode} #immediate]{!}
//(ldr)(str){condition}{b} rd,[rn],rm {mode} #immediate
if((instruction & 0x0e000010) == 0x06000000) {
uint4 condition = instruction >> 28;
uint1 p = instruction >> 24;
uint1 u = instruction >> 23;
uint1 b = instruction >> 22;
uint1 w = instruction >> 21;
uint1 load = instruction >> 20;
uint4 rn = instruction >> 16;
uint4 rd = instruction >> 12;
uint5 shift = instruction >> 7;
uint2 mode = instruction >> 5;
uint4 rm = instruction;
output.append(load ? "ldr" : "str", conditions[condition], b ? "b " : " ");
output.append(registers[rd], ",[", registers[rn]);
if(p == 0) output.append("]");
output.append(",", u ? "+" : "-", registers[rm]);
if(mode == 0 && shift != 0) output.append(" lsl #", shift);
if(mode == 1) output.append(" lsr #", shift == 0 ? 32u : (unsigned)shift);
if(mode == 2) output.append(" asr #", shift == 0 ? 32u : (unsigned)shift);
if(mode == 3 && shift != 0) output.append(" ror #", shift);
if(mode == 3 && shift == 0) output.append(" rrx");
if(p == 1) output.append("]");
if(p == 1 && w == 1) output.append("!");
return output;
}
@ -166,10 +234,12 @@ string ArmDSP::disassemble_opcode(uint32 pc) {
string ArmDSP::disassemble_registers() {
return {
"r0:", hex<8>(r[ 0]), " r1:", hex<8>(r[ 1]), " r2:", hex<8>(r[ 2]), " r3:", hex<8>(r[ 3]),
" r4:", hex<8>(r[ 4]), " r5:", hex<8>(r[ 5]), " r6:", hex<8>(r[ 6]), " r7:", hex<8>(r[ 7]), "\n",
" r4:", hex<8>(r[ 4]), " r5:", hex<8>(r[ 5]), " r6:", hex<8>(r[ 6]), " r7:", hex<8>(r[ 7]), " ",
"cpsr:", cpsr.n ? "N" : "n", cpsr.z ? "Z" : "z", cpsr.c ? "C" : "c", cpsr.v ? "V" : "v", "\n",
"r8:", hex<8>(r[ 8]), " r9:", hex<8>(r[ 9]), " r10:", hex<8>(r[10]), " r11:", hex<8>(r[11]),
" r12:", hex<8>(r[12]), " r13:", hex<8>(r[13]), " r14:", hex<8>(r[14]), " r15:", hex<8>(r[15]), "\n",
"cpsr:", cpsr.n ? "N" : "n", cpsr.z ? "Z" : "z", cpsr.c ? "C" : "c", cpsr.v ? "V" : "v"
" r12:", hex<8>(r[12]), " r13:", hex<8>(r[13]), " r14:", hex<8>(r[14]), " r15:", hex<8>(r[15]), " ",
"spsr:", spsr.n ? "N" : "n", spsr.z ? "Z" : "z", spsr.c ? "C" : "c", spsr.v ? "V" : "v"
};
}

View File

@ -58,61 +58,30 @@ void ArmDSP::bus_iwrite(uint32 addr, uint8 data) {
if((addr & 3) == 0) print("* ARM w", hex<8>(addr), " = ", hex<2>(data), "\n");
}
template<unsigned size>
uint32 ArmDSP::bus_read(uint32 addr) {
uint32 data = 0;
if(size == 1) {
uint32 mask = 255u << ((addr & ~3) << 3);
data |= bus_iread(addr) & mask;
uint32 ArmDSP::bus_readbyte(uint32 addr) {
return bus_iread(addr);
}
if(size == 4) {
uint32 ArmDSP::bus_readword(uint32 addr) {
addr &= ~3;
data |= bus_iread(addr + 0) << 0;
data |= bus_iread(addr + 1) << 8;
data |= bus_iread(addr + 2) << 16;
data |= bus_iread(addr + 3) << 24;
return (
(bus_iread(addr + 0) << 0)
| (bus_iread(addr + 1) << 8)
| (bus_iread(addr + 2) << 16)
| (bus_iread(addr + 3) << 24)
);
}
if(0&&addr >= 0x40000000 && addr <= 0x400000ff) {
if(addr != 0x40000020 || data != 0x80)
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);
}
void ArmDSP::bus_writebyte(uint32 addr, uint32 data) {
return bus_iwrite(addr, data);
}
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(0&&addr >= 0x40000000 && addr <= 0x400000ff) {
if(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) {
uint32 mask = 255u << ((addr & ~3) << 3);
bus_iwrite(addr, data);
}
if(size == 4) {
void ArmDSP::bus_writeword(uint32 addr, uint32 data) {
addr &= ~3;
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

View File

@ -29,56 +29,53 @@ bool ArmDSP::condition() {
//ro = modified target
void ArmDSP::opcode(uint32 rm) {
uint4 opcode = instruction >> 21;
uint1 s = instruction >> 20;
uint1 save = instruction >> 20;
uint4 n = instruction >> 16;
uint4 d = instruction >> 12;
uint32 rn = r[n];
auto &rd = r[d];
uint32 ri = rd, ro;
//comparison opcodes always update flags
if(opcode >= 8 && opcode <= 11) assert(s == 1);
//comparison opcodes always update flags (debug test)
//this can be removed later: s=0 opcode=8-11 is invalid
if(opcode >= 8 && opcode <= 11) assert(save == 1);
auto bit = [&](uint32 ro) {
if(!s) return;
cpsr.n = ro >> 31;
cpsr.z = ro == 0;
auto test = [&](uint32 result) {
if(save) {
cpsr.n = result >> 31;
cpsr.z = result == 0;
cpsr.c = shiftercarry;
}
return result;
};
auto add = [&](uint32 ro) {
if(!s) return;
cpsr.n = ro >> 31;
cpsr.z = ro == 0;
cpsr.c = ro < ri;
cpsr.v = ~(ri ^ rm) & (ri ^ ro) & (1u << 31);
};
auto sub = [&](uint32 ro) {
if(!s) return;
cpsr.n = ro >> 31;
cpsr.z = ro == 0;
cpsr.c = ro > ri;
cpsr.v = (ri ^ rm) & (ri ^ ro) & (1u << 31);
auto math = [&](uint32 source, uint32 modify, bool carry) {
uint32 result = source + modify + carry;
if(save) {
cpsr.n = result >> 31;
cpsr.z = result == 0;
cpsr.c = result < source;
cpsr.v = ~(source ^ modify) & (source ^ result) & (1u << 31);
}
return result;
};
switch(opcode) {
case 0: rd = rn & rm; bit(rd); break; //AND (logical and)
case 1: rd = rn ^ rm; bit(rd); break; //EOR (logical exclusive or)
case 2: rd = rn - rm; sub(rd); break; //SUB (subtract)
case 3: rd = rm - rn; sub(rd); break; //RSB (reverse subtract)
case 4: rd = rn + rm; add(rd); break; //ADD (add)
case 5: rd = rn + rm + cpsr.c; add(rd); break; //ADC (add with carry)
case 6: rd = rn - rm -!cpsr.c; sub(rd); break; //SBC (subtract with carry)
case 7: rd = rm - rn -!cpsr.c; sub(rd); break; //RSC (reverse subtract with carry)
case 8: ro = rn & rm; bit(ro); break; //TST (test)
case 9: ro = rn ^ rm; bit(ro); break; //TEQ (test equivalence)
case 10: ro = rn - rm; sub(ro); break; //CMP (compare)
case 11: ro = rn + rm; add(ro); break; //CMN (compare negated)
case 12: rd = rn | rm; bit(rd); break; //ORR (logical inclusive or)
case 13: rd = rm; bit(rd); break; //MOV (move)
case 14: rd = rn &~rm; bit(rd); break; //BIC (bit clear)
case 15: rd =~rm; bit(rd); break; //MVN (move not)
case 0: r[d] = test(rn & rm); break; //AND
case 1: r[d] = test(rn ^ rm); break; //EOR
case 2: r[d] = math(rn, ~rm, 1); break; //SUB
case 3: r[d] = math(rm, ~rn, 1); break; //RSB
case 4: r[d] = math(rn, rm, 0); break; //ADD
case 5: r[d] = math(rn, rm, cpsr.c); break; //ADC
case 6: r[d] = math(rn, ~rm, cpsr.c); break; //SBC
case 7: r[d] = math(rm, ~rn, cpsr.c); break; //RSC
case 8: test(rn & rm); break; //TST
case 9: test(rn ^ rm); break; //TEQ
case 10: math(rn, ~rm, 1); break; //CMP
case 11: math(rn, rm, 0); break; //CMN
case 12: r[d] = test(rn | rm); break; //ORR
case 13: r[d] = test(rm); break; //MOV
case 14: r[d] = test(rn &~rm); break; //BIC
case 15: r[d] = test(~rm); break; //MVN
}
}
@ -203,7 +200,7 @@ void ArmDSP::op_data_immediate_shift() {
if(mode == 2) asr(c, rm, rs ? rs : 32);
if(mode == 3) rs ? ror(c, rm, rs) : rrx(c, rm);
if(save) cpsr.c = c;
shiftercarry = c;
opcode(rm);
}
@ -232,9 +229,9 @@ void ArmDSP::op_data_register_shift() {
if(mode == 0) lsl(c, rm, rs < 33 ? rs : 33);
if(mode == 1) lsr(c, rm, rs < 33 ? rs : 33);
if(mode == 2) asr(c, rm, rs < 32 ? rs : 32);
if(mode == 3) ror(c, rm, rs < 32 ? rs : 32);
if(mode == 3 && rs) ror(c, rm, rs & 31 == 0 ? 32 : rs & 31);
if(save) cpsr.c = c;
shiftercarry = c;
opcode(rm);
}
@ -254,17 +251,15 @@ void ArmDSP::op_data_immediate() {
uint4 shift = instruction >> 8;
uint8 immediate = instruction;
bool c = cpsr.c;
uint32 rs = shift << 1;
uint32 rm = (immediate >> rs) | (immediate << (32 - rs));
if(rs) c = immediate >> 31;
if(rs) shiftercarry = immediate >> 31;
if(save) cpsr.c = c;
opcode(rm);
}
//(ldr,str){condition}{b} rd,[rn{+offset}]
//(ldr,str){condition}{b} rd,[rn{,+/-offset}]{!}
//(ldr,str){condition}{b} rd,[rn]{,+/-offset}
//cccc 010p ubwl nnnn dddd iiii iiii iiii
//c = condition
//p = pre (0 = post-indexed addressing)
@ -288,22 +283,16 @@ void ArmDSP::op_move_immediate_offset() {
uint32 rn = r[n];
auto &rd = r[d];
if(l) {
if(p == 1) rn = u ? rn + rm : rn - rm;
if(b) rd = bus_read<1>(rn);
else rd = bus_read<4>(rn);
if(l) rd = b ? bus_readbyte(rn) : bus_readword(rn);
else b ? bus_writebyte(rn, rd) : bus_writeword(rn, rd);
if(p == 0) rn = u ? rn + rm : rn - rm;
} else {
if(p == 1) rn = u ? rn + rm : rn - rm;
if(b) bus_write<1>(rn, rd);
else bus_write<4>(rn, rd);
if(p == 0) rn = u ? rn + rm : rn - rm;
}
if(p == 0 || w == 1) r[n] = rn;
}
//(ldr)(str){condition}{b} rd,rn,rm {mode} #immediate
//(ldr)(str){condition}{b} rd,[rn,rm {mode} #immediate]{!}
//(ldr)(str){condition}{b} rd,[rn],rm {mode} #immediate
//cccc 011p ubwl nnnn dddd llll lss0 mmmm
//c = condition
//p = pre (0 = post-indexed addressing)
@ -339,17 +328,10 @@ void ArmDSP::op_move_register_offset() {
if(mode == 2) asr(c, rm, rs ? rs : 32);
if(mode == 3) rs ? ror(c, rm, rs) : rrx(c, rm);
if(l) {
if(p == 1) rn = u ? rn + rm : rn - rm;
if(b) rd = bus_read<1>(rn);
else rd = bus_read<4>(rn);
if(l) rd = b ? bus_readbyte(rn) : bus_readword(rn);
else b ? bus_writebyte(rn, rd) : bus_writeword(rn, rd);
if(p == 0) rn = u ? rn + rm : rn - rm;
} else {
if(p == 1) rn = u ? rn + rm : rn - rm;
if(b) bus_write<1>(rn, rd);
else bus_write<4>(rn, rd);
if(p == 0) rn = u ? rn + rm : rn - rm;
}
if(p == 0 || w == 1) r[n] = rn;
}
@ -379,21 +361,13 @@ void ArmDSP::op_move_multiple() {
if(p == 1 && u == 0) rn = rn - bit::count(list) * 4 + 0; //DB
if(p == 0 && u == 0) rn = rn - bit::count(list) * 4 + 4; //DA
if(l) {
for(unsigned n = 0; n < 16; n++) {
if(list & (1 << n)) {
r[n] = bus_read<4>(rn);
if(l) r[n] = bus_readword(rn);
else bus_writeword(rn, r[n]);
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

View File

@ -101,6 +101,8 @@ struct Register {
}
} r[16];
bool shiftercarry;
struct Pipeline {
bool reload;
struct Instruction {