Update to v086r15 release.

byuu says:

Most importantly ... I'm now using "st018.rom" which is the program ROM
+ data ROM in one "firmware" file. Since all three Seta DSPs have the
ST01N stamp, unlike some of the arcade variants, I'm just going to go
with ST01N from now on instead of ST-001N. I was using the latter as
that's what Overload called them.

Moving on ...
The memory map should match real hardware now, and I even match the open
bus read results.
I also return the funky 0x40404001 for 60000000-7fffffff, for whatever
that's worth.
The CPU-side registers are also mirrored correctly, as they were in the
last WIP, so we should be good there.
I also simulate the reset pulse now, and a 0->!0 transition of $3804
will destroy the ARM CPU thread.
It will wait until the value is set back to zero to resume execution.
At startup, the ARM CPU will sleep for a while, thus simulating the
reset delay behavior.
Still need to figure out the exact cycle length, but that's really not
important for emulation.

Note in registers.hpp, the |4 in status() is basically what allows the
CPU program to keep going, and hit the checkmate condition.
If we remove that, the CPU deadlocks. Still need to figure out how and
when d4 is set on $3804 reads.
I can run any test program on both real hardware and in my emulator and
compare results, so by all means ... if you can come up with a test,
I'll run it.
This commit is contained in:
Tim Allen 2012-03-02 22:07:17 +11:00
parent aa8ac7bbb8
commit d118b70b30
8 changed files with 112 additions and 85 deletions

View File

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

View File

@ -494,7 +494,7 @@ SnesCartridge::SnesCartridge(const uint8_t *data, unsigned size) {
); );
if(has_st010) markup.append( if(has_st010) markup.append(
" <necdsp model='uPD96050' frequency='10000000' firmware='st0010.rom' sha256='55c697e864562445621cdf8a7bf6e84ae91361e393d382a3704e9aa55559041e'>\n" " <necdsp model='uPD96050' frequency='10000000' firmware='st010.rom' sha256='55c697e864562445621cdf8a7bf6e84ae91361e393d382a3704e9aa55559041e'>\n"
" <dr>\n" " <dr>\n"
" <map address='60:0000'/>\n" " <map address='60:0000'/>\n"
" <map address='e0:0000'/>\n" " <map address='e0:0000'/>\n"
@ -511,7 +511,7 @@ SnesCartridge::SnesCartridge(const uint8_t *data, unsigned size) {
); );
if(has_st011) markup.append( if(has_st011) markup.append(
" <necdsp model='uPD96050' frequency='15000000' firmware='st0011.rom' sha256='651b82a1e26c4fa8dd549e91e7f923012ed2ca54c1d9fd858655ab30679c2f0e'>\n" " <necdsp model='uPD96050' frequency='15000000' firmware='st011.rom' sha256='651b82a1e26c4fa8dd549e91e7f923012ed2ca54c1d9fd858655ab30679c2f0e'>\n"
" <dr>\n" " <dr>\n"
" <map address='60:0000'/>\n" " <map address='60:0000'/>\n"
" <map address='e0:0000'/>\n" " <map address='e0:0000'/>\n"
@ -528,7 +528,7 @@ SnesCartridge::SnesCartridge(const uint8_t *data, unsigned size) {
); );
if(has_st018) markup.append( if(has_st018) markup.append(
" <armdsp firmware='st0018.rom' sha256='6cceff3c6945bb2672040066d218efcd2f31492f3f5c28916c8e53435c2c887e'>\n" " <armdsp firmware='st018.rom' sha256='6df209ab5d2524d1839c038be400ae5eb20dafc14a3771a3239cd9e8acd53806'>\n"
" <map address='00-3f:3800-38ff'/>\n" " <map address='00-3f:3800-38ff'/>\n"
" <map address='80-bf:3800-38ff'/>\n" " <map address='80-bf:3800-38ff'/>\n"
" </armdsp>\n" " </armdsp>\n"

View File

@ -336,7 +336,6 @@ void Cartridge::parse_markup_armdsp(XML::Node &root) {
if(root.exists() == false) return; if(root.exists() == false) return;
has_armdsp = true; has_armdsp = true;
for(auto &byte : armdsp.programROM) byte = 0x00;
string firmware = root["firmware"].data; string firmware = root["firmware"].data;
string sha256 = root["sha256"].data; string sha256 = root["sha256"].data;
@ -344,14 +343,14 @@ void Cartridge::parse_markup_armdsp(XML::Node &root) {
file fp; file fp;
if(fp.open(path, file::mode::read) == false) { if(fp.open(path, file::mode::read) == false) {
interface->message({ "Warning: ARM DSP firmware ", firmware, " is missing." }); interface->message({ "Warning: ARM DSP firmware ", firmware, " is missing." });
} else if(fp.size() != 128 * 1024) { } else if(fp.size() != 160 * 1024) {
interface->message({ "Warning: ARM DSP firmware ", firmware, " is of the wrong file size." }); interface->message({ "Warning: ARM DSP firmware ", firmware, " is of the wrong file size." });
fp.close(); fp.close();
} else { } else {
for(auto &byte : armdsp.programROM) byte = fp.read(); fp.read(armdsp.firmware, fp.size());
if(!sha256.empty()) { if(!sha256.empty()) {
if(sha256 != nall::sha256(armdsp.programROM, 128 * 1024)) { if(sha256 != nall::sha256(armdsp.firmware, fp.size())) {
interface->message({ "Warning: ARM DSP firmware ", firmware, " SHA256 sum is incorrect." }); interface->message({ "Warning: ARM DSP firmware ", firmware, " SHA256 sum is incorrect." });
} }
} }

View File

@ -14,6 +14,20 @@ ArmDSP armdsp;
void ArmDSP::Enter() { armdsp.enter(); } void ArmDSP::Enter() { armdsp.enter(); }
void ArmDSP::enter() { void ArmDSP::enter() {
//reset hold delay
while(bridge.reset) {
step(4);
synchronize_cpu();
continue;
}
//reset sequence delay
if(bridge.ready == false) {
step(4096); //todo: verify cycle count
synchronize_cpu();
bridge.ready = true;
}
while(true) { while(true) {
if(scheduler.sync == Scheduler::SynchronizeMode::All) { if(scheduler.sync == Scheduler::SynchronizeMode::All) {
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
@ -44,12 +58,16 @@ void ArmDSP::enter() {
pipeline.prefetch.opcode = bus_readword(r[15]); pipeline.prefetch.opcode = bus_readword(r[15]);
r[15].step(); r[15].step();
//if(pipeline.instruction.address == 0x0000ef5c) trace = 1; pipeline.mdr.address = r[15];
pipeline.mdr.opcode = bus_readword(r[15]);
if(pipeline.instruction.address == 0x00000208) trace = 1;
if(trace) { if(trace) {
print("\n", disassemble_registers(), "\n"); print("\n", disassemble_registers(), "\n");
print(disassemble_opcode(pipeline.instruction.address), "\n"); print(disassemble_opcode(pipeline.instruction.address), "\n");
usleep(200000); usleep(200000);
} }
trace = 0;
instruction = pipeline.instruction.opcode; instruction = pipeline.instruction.opcode;
if(!condition()) continue; if(!condition()) continue;
@ -86,7 +104,8 @@ uint8 ArmDSP::mmio_read(unsigned addr) {
} }
} }
if(addr == 0x3802); if(addr == 0x3802) {
}
if(addr == 0x3804) { if(addr == 0x3804) {
data = bridge.status(); data = bridge.status();
@ -116,7 +135,10 @@ void ArmDSP::mmio_write(unsigned addr, uint8 data) {
print("* w3802 = ", hex<2>(data), "\n"); print("* w3802 = ", hex<2>(data), "\n");
} }
if(addr == 0x3804); if(addr == 0x3804) {
if(!bridge.reset && data) arm_reset();
bridge.reset = data;
}
} }
void ArmDSP::init() { void ArmDSP::init() {
@ -129,32 +151,44 @@ void ArmDSP::unload() {
} }
void ArmDSP::power() { void ArmDSP::power() {
string filename = interface->path(Cartridge::Slot::Base, "st0018d.rom"); string filename = { dir(interface->path(Cartridge::Slot::Base, "st018.rom")), "disassembly.txt" };
file fp; file fp;
if(fp.open(filename, file::mode::read)) {
fp.read(dataROM, 32 * 1024);
fp.close();
}
filename = { dir(filename), "disassembly.txt" };
fp.open(filename, file::mode::write); fp.open(filename, file::mode::write);
for(unsigned n = 0; n < 128 * 1024; n += 4) { for(unsigned n = 0; n < 128 * 1024; n += 4) {
fp.print(disassemble_opcode(n), "\n"); fp.print(disassemble_opcode(n), "\n");
} }
fp.close(); fp.close();
for(unsigned n = 0; n < 16 * 1024; n++) programRAM[n] = random(0x00);
} }
void ArmDSP::reset() { void ArmDSP::reset() {
bridge.reset = false;
arm_reset();
}
void ArmDSP::arm_reset() {
bridge.ready = false;
create(ArmDSP::Enter, 21477272); create(ArmDSP::Enter, 21477272);
for(auto &rd : r) rd = 0; for(auto &rd : r) rd = 0;
shiftercarry = 0; shiftercarry = 0;
exception = 0;
exception = false;
pipeline.reload = true; pipeline.reload = true;
r[15].write = [&] { pipeline.reload = true; }; r[15].write = [&] { pipeline.reload = true; };
} }
ArmDSP::ArmDSP() {
firmware = new uint8[160 * 1024];
programRAM = new uint8[16 * 1024];
programROM = &firmware[0];
dataROM = &firmware[128 * 1024];
}
ArmDSP::~ArmDSP() {
delete[] firmware;
delete[] programRAM;
}
} }

View File

@ -1,9 +1,10 @@
//ARMv3 (ARM6) //ARMv3 (ARM6)
struct ArmDSP : public Coprocessor { struct ArmDSP : public Coprocessor {
uint8 programROM[128 * 1024]; uint8 *firmware;
uint8 programRAM[16 * 1024]; uint8 *programROM;
uint8 dataROM[32 * 1024]; uint8 *dataROM;
uint8 *programRAM;
#include "registers.hpp" #include "registers.hpp"
@ -15,6 +16,10 @@ struct ArmDSP : public Coprocessor {
void unload(); void unload();
void power(); void power();
void reset(); void reset();
void arm_reset();
ArmDSP();
~ArmDSP();
uint8 mmio_read(unsigned addr); uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data); void mmio_write(unsigned addr, uint8 data);
@ -40,13 +45,13 @@ struct ArmDSP : public Coprocessor {
void op_branch(); void op_branch();
//memory.cpp //memory.cpp
uint8 bus_iread(uint32 addr); uint8 bus_read(uint32 addr);
void bus_iwrite(uint32 addr, uint8 data); void bus_write(uint32 addr, uint8 data);
uint32 bus_readbyte(uint32 addr); uint32 bus_readbyte(uint32 addr);
uint32 bus_readword(uint32 addr);
void bus_writebyte(uint32 addr, uint32 data); void bus_writebyte(uint32 addr, uint32 data);
uint32 bus_readword(uint32 addr);
void bus_writeword(uint32 addr, uint32 data); void bus_writeword(uint32 addr, uint32 data);
//disassembler.cpp //disassembler.cpp

View File

@ -164,7 +164,7 @@ string ArmDSP::disassemble_opcode(uint32 pc) {
if(p == 1) output.append("]"); if(p == 1) output.append("]");
if(p == 1 && w == 1) output.append("!"); if(p == 1 && w == 1) output.append("!");
if(rn == 15) output.append(" (0x", hex<8>(pc + 8 + (u ? +immediate : -immediate)), ")"); if(rn == 15) output.append(" =0x", hex<8>(bus_readword(pc + 8 + (u ? +immediate : -immediate))));
return output; return output;
} }

View File

@ -1,87 +1,73 @@
#ifdef ARMDSP_CPP #ifdef ARMDSP_CPP
uint8 ArmDSP::bus_iread(uint32 addr) { uint8 ArmDSP::bus_read(uint32 addr) {
if(addr >= 0x00000000 && addr <= 0x0001ffff) { switch(addr & 0xe0000000) {
return programROM[addr & 0x0001ffff]; case 0x00000000: return programROM[addr & 0x0001ffff];
case 0x20000000: return pipeline.mdr.opcode >> ((addr & 3) << 3);
case 0x40000000: break; //MMIO
case 0x60000000: return 0x40404001 >> ((addr & 3) << 3);
case 0x80000000: return pipeline.mdr.opcode >> ((addr & 3) << 3);
case 0xa0000000: return dataROM[addr & 0x00007fff];
case 0xc0000000: return pipeline.mdr.opcode >> ((addr & 3) << 3);
case 0xe0000000: return programRAM[addr & 0x00003fff];
} }
if(addr >= 0x40000000 && addr <= 0x400000ff) { addr &= 0xe000003f;
if(addr == 0x40000000) return 0x00;
if(addr == 0x40000010) { if(addr == 0x40000010) {
if(bridge.cputoarm.ready) { if(bridge.cputoarm.ready) {
bridge.cputoarm.ready = false; bridge.cputoarm.ready = false;
return bridge.cputoarm.data; return bridge.cputoarm.data;
}
} }
if(addr == 0x40000020) {
return bridge.status();
}
if(addr == 0x40000024) return 0x00;
if(addr == 0x40000028) return 0x00;
if(addr == 0x4000002c) return 0x00;
} }
if(addr >= 0xa0000000 && addr <= 0xa0007fff) { if(addr == 0x40000020) {
return dataROM[addr & 0x00007fff]; return bridge.status();
} }
if(addr >= 0xe0000000 && addr <= 0xe0003fff) {
return programRAM[addr & 0x00003fff];
}
if((addr & 3) == 0) print("* ARM r", hex<8>(addr), "\n");
return 0x00; return 0x00;
} }
void ArmDSP::bus_iwrite(uint32 addr, uint8 data) { void ArmDSP::bus_write(uint32 addr, uint8 data) {
if(addr >= 0x40000000 && addr <= 0x400000ff) { switch(addr & 0xe0000000) {
if(addr == 0x40000000) { case 0x40000000: break; //MMIO
bridge.armtocpu.ready = true; case 0xe0000000: programRAM[addr & 0x00003fff] = data; return;
bridge.armtocpu.data = data; default: return;
return;
}
if(addr == 0x40000020) return;
if(addr == 0x40000024) return;
if(addr == 0x40000028) return;
if(addr == 0x4000002c) return print("* w4000002c = ", hex<2>(data), "\n");
} }
if(addr >= 0xe0000000 && addr <= 0xe0003fff) { addr &= 0xe000003f;
programRAM[addr & 0x00003fff] = data;
if(addr == 0x40000000) {
bridge.armtocpu.ready = true;
bridge.armtocpu.data = data;
return; return;
} }
if((addr & 3) == 0) print("* ARM w", hex<8>(addr), " = ", hex<2>(data), "\n");
} }
uint32 ArmDSP::bus_readbyte(uint32 addr) { uint32 ArmDSP::bus_readbyte(uint32 addr) {
return bus_iread(addr); return bus_read(addr);
}
void ArmDSP::bus_writebyte(uint32 addr, uint32 data) {
return bus_write(addr, data);
} }
uint32 ArmDSP::bus_readword(uint32 addr) { uint32 ArmDSP::bus_readword(uint32 addr) {
addr &= ~3; addr &= ~3;
return ( return (
(bus_iread(addr + 0) << 0) (bus_read(addr + 0) << 0)
| (bus_iread(addr + 1) << 8) | (bus_read(addr + 1) << 8)
| (bus_iread(addr + 2) << 16) | (bus_read(addr + 2) << 16)
| (bus_iread(addr + 3) << 24) | (bus_read(addr + 3) << 24)
); );
} }
void ArmDSP::bus_writebyte(uint32 addr, uint32 data) {
return bus_iwrite(addr, data);
}
void ArmDSP::bus_writeword(uint32 addr, uint32 data) { void ArmDSP::bus_writeword(uint32 addr, uint32 data) {
addr &= ~3; addr &= ~3;
bus_iwrite(addr + 0, data >> 0); bus_write(addr + 0, data >> 0);
bus_iwrite(addr + 1, data >> 8); bus_write(addr + 1, data >> 8);
bus_iwrite(addr + 2, data >> 16); bus_write(addr + 2, data >> 16);
bus_iwrite(addr + 3, data >> 24); bus_write(addr + 3, data >> 24);
} }
#endif #endif

View File

@ -14,9 +14,11 @@ struct Bridge {
}; };
Buffer cputoarm; Buffer cputoarm;
Buffer armtocpu; Buffer armtocpu;
bool reset;
bool ready;
uint8 status() const { uint8 status() const {
return 0x84 | (cputoarm.ready << 3) | (armtocpu.ready << 0); return (ready << 7) | (cputoarm.ready << 3) | (armtocpu.ready << 0) | 4;
} }
} bridge; } bridge;
@ -111,6 +113,7 @@ struct Pipeline {
}; };
Instruction instruction; Instruction instruction;
Instruction prefetch; Instruction prefetch;
Instruction mdr;
} pipeline; } pipeline;
uint32 instruction; uint32 instruction;