mirror of https://github.com/bsnes-emu/bsnes.git
Update to v086r08 release.
byuu says: Contains the fledgling beginnings of an ARM CPU core, which can execute the first three and a half instructions of the ST-0018. It's a start, I guess.
This commit is contained in:
parent
f1d6325bcd
commit
482b4119f6
|
@ -1,7 +1,7 @@
|
|||
#ifndef BASE_HPP
|
||||
#define BASE_HPP
|
||||
|
||||
const char Version[] = "086.07";
|
||||
const char Version[] = "086.08";
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/algorithm.hpp>
|
||||
|
|
|
@ -527,12 +527,21 @@ SnesCartridge::SnesCartridge(const uint8_t *data, unsigned size) {
|
|||
" </necdsp>\n"
|
||||
);
|
||||
|
||||
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"
|
||||
);
|
||||
#endif
|
||||
|
||||
markup.append("</cartridge>\n");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
#ifndef NALL_SNES_USART_HPP
|
||||
#define NALL_SNES_USART_HPP
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/function.hpp>
|
||||
#include <nall/serial.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
|
||||
#define usartproc dllexport
|
||||
|
||||
static nall::function<void (unsigned milliseconds)> usart_usleep;
|
||||
static nall::function<uint8_t ()> usart_read;
|
||||
static nall::function<void (uint8_t data)> usart_write;
|
||||
|
||||
extern "C" usartproc void usart_init(
|
||||
nall::function<void (unsigned milliseconds)> usleep,
|
||||
nall::function<uint8_t ()> read,
|
||||
nall::function<void (uint8_t data)> write
|
||||
) {
|
||||
usart_usleep = usleep;
|
||||
usart_read = read;
|
||||
usart_write = write;
|
||||
}
|
||||
|
||||
extern "C" usartproc void usart_main();
|
||||
|
||||
//
|
||||
|
||||
static nall::serial usart;
|
||||
static bool usart_is_virtual = true;
|
||||
|
||||
static bool usart_virtual() {
|
||||
return usart_is_virtual;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
static void usarthw_usleep(unsigned milliseconds) {
|
||||
usleep(milliseconds);
|
||||
}
|
||||
|
||||
static uint8_t usarthw_read() {
|
||||
while(true) {
|
||||
uint8_t buffer[1];
|
||||
signed length = usart.read((uint8_t*)&buffer, 1);
|
||||
if(length > 0) return buffer[0];
|
||||
}
|
||||
}
|
||||
|
||||
static void usarthw_write(uint8_t data) {
|
||||
uint8_t buffer[1] = { data };
|
||||
usart.write((uint8_t*)&buffer, 1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
bool result = false;
|
||||
if(argc == 1) result = usart.open("/dev/ttyACM0", 57600, true);
|
||||
if(argc == 2) result = usart.open(argv[1], 57600, true);
|
||||
if(result == false) {
|
||||
printf("error: unable to open USART hardware device\n");
|
||||
return 0;
|
||||
}
|
||||
usart_is_virtual = false;
|
||||
usart_init(usarthw_usleep, usarthw_read, usarthw_write);
|
||||
usart_main();
|
||||
usart.close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef NALL_STACK_HPP
|
||||
#define NALL_STACK_HPP
|
||||
|
||||
#include <nall/vector.hpp>
|
||||
|
||||
namespace nall {
|
||||
template<typename T> struct stack : public linear_vector<T> {
|
||||
void push(const T &value) {
|
||||
linear_vector<T>::append(value);
|
||||
}
|
||||
|
||||
T pull() {
|
||||
if(linear_vector<T>::size() == 0) throw;
|
||||
T value = linear_vector<T>::operator[](linear_vector<T>::size() - 1);
|
||||
linear_vector<T>::remove(linear_vector<T>::size() - 1);
|
||||
return value;
|
||||
}
|
||||
|
||||
T& operator()() {
|
||||
if(linear_vector<T>::size() == 0) throw;
|
||||
return linear_vector<T>::operator[](linear_vector<T>::size() - 1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -25,13 +25,12 @@
|
|||
#include <nall/string/base.hpp>
|
||||
#include <nall/string/bml.hpp>
|
||||
#include <nall/string/bsv.hpp>
|
||||
#include <nall/string/core.hpp>
|
||||
#include <nall/string/cast.hpp>
|
||||
#include <nall/string/compare.hpp>
|
||||
#include <nall/string/convert.hpp>
|
||||
#include <nall/string/core.hpp>
|
||||
#include <nall/string/cstring.hpp>
|
||||
#include <nall/string/filename.hpp>
|
||||
#include <nall/string/math.hpp>
|
||||
#include <nall/string/math-fixed-point.hpp>
|
||||
#include <nall/string/math-floating-point.hpp>
|
||||
#include <nall/string/platform.hpp>
|
||||
|
@ -40,6 +39,7 @@
|
|||
#include <nall/string/trim.hpp>
|
||||
#include <nall/string/replace.hpp>
|
||||
#include <nall/string/split.hpp>
|
||||
#include <nall/string/utf8.hpp>
|
||||
#include <nall/string/utility.hpp>
|
||||
#include <nall/string/variadic.hpp>
|
||||
#include <nall/string/wildcard.hpp>
|
||||
|
|
|
@ -1,167 +0,0 @@
|
|||
#ifdef NALL_STRING_INTERNAL_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
static function<int64_t (const char *&)> eval_fallback;
|
||||
|
||||
static int eval_integer(const char *&s) {
|
||||
if(!*s) throw "unrecognized_integer";
|
||||
int value = 0, x = *s, y = *(s + 1);
|
||||
|
||||
//hexadecimal
|
||||
if(x == '0' && (y == 'X' || y == 'x')) {
|
||||
s += 2;
|
||||
while(true) {
|
||||
if(*s >= '0' && *s <= '9') { value = value * 16 + (*s++ - '0'); continue; }
|
||||
if(*s >= 'A' && *s <= 'F') { value = value * 16 + (*s++ - 'A' + 10); continue; }
|
||||
if(*s >= 'a' && *s <= 'f') { value = value * 16 + (*s++ - 'a' + 10); continue; }
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
//binary
|
||||
if(x == '0' && (y == 'B' || y == 'b')) {
|
||||
s += 2;
|
||||
while(true) {
|
||||
if(*s == '0' || *s == '1') { value = value * 2 + (*s++ - '0'); continue; }
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
//octal (or decimal '0')
|
||||
if(x == '0') {
|
||||
s += 1;
|
||||
while(true) {
|
||||
if(*s >= '0' && *s <= '7') { value = value * 8 + (*s++ - '0'); continue; }
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
//decimal
|
||||
if(x >= '0' && x <= '9') {
|
||||
while(true) {
|
||||
if(*s >= '0' && *s <= '9') { value = value * 10 + (*s++ - '0'); continue; }
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
//char
|
||||
if(x == '\'' && y != '\'') {
|
||||
s += 1;
|
||||
while(true) {
|
||||
value = value * 256 + *s++;
|
||||
if(*s == '\'') { s += 1; return value; }
|
||||
if(!*s) throw "mismatched_char";
|
||||
}
|
||||
}
|
||||
|
||||
throw "unrecognized_integer";
|
||||
}
|
||||
|
||||
static int eval(const char *&s, int depth = 0) {
|
||||
while(*s == ' ' || *s == '\t') s++; //trim whitespace
|
||||
if(!*s) throw "unrecognized_token";
|
||||
int value = 0, x = *s, y = *(s + 1);
|
||||
|
||||
if(*s == '(') {
|
||||
value = eval(++s, 1);
|
||||
if(*s++ != ')') throw "mismatched_group";
|
||||
}
|
||||
|
||||
else if(x == '!') value = !eval(++s, 13);
|
||||
else if(x == '~') value = ~eval(++s, 13);
|
||||
else if(x == '+') value = +eval(++s, 13);
|
||||
else if(x == '-') value = -eval(++s, 13);
|
||||
|
||||
else if((x >= '0' && x <= '9') || x == '\'') value = eval_integer(s);
|
||||
|
||||
else if(eval_fallback) value = eval_fallback(s); //optional user-defined syntax parsing
|
||||
|
||||
else throw "unrecognized_token";
|
||||
|
||||
while(true) {
|
||||
while(*s == ' ' || *s == '\t') s++; //trim whitespace
|
||||
if(!*s) break;
|
||||
x = *s, y = *(s + 1);
|
||||
|
||||
if(depth >= 13) break;
|
||||
if(x == '*') { value *= eval(++s, 13); continue; }
|
||||
if(x == '/') { int result = eval(++s, 13); if(result == 0) throw "division_by_zero"; value /= result; continue; }
|
||||
if(x == '%') { int result = eval(++s, 13); if(result == 0) throw "division_by_zero"; value %= result; continue; }
|
||||
|
||||
if(depth >= 12) break;
|
||||
if(x == '+') { value += eval(++s, 12); continue; }
|
||||
if(x == '-') { value -= eval(++s, 12); continue; }
|
||||
|
||||
if(depth >= 11) break;
|
||||
if(x == '<' && y == '<') { value <<= eval(++++s, 11); continue; }
|
||||
if(x == '>' && y == '>') { value >>= eval(++++s, 11); continue; }
|
||||
|
||||
if(depth >= 10) break;
|
||||
if(x == '<' && y == '=') { value = value <= eval(++++s, 10); continue; }
|
||||
if(x == '>' && y == '=') { value = value >= eval(++++s, 10); continue; }
|
||||
if(x == '<') { value = value < eval(++s, 10); continue; }
|
||||
if(x == '>') { value = value > eval(++s, 10); continue; }
|
||||
|
||||
if(depth >= 9) break;
|
||||
if(x == '=' && y == '=') { value = value == eval(++++s, 9); continue; }
|
||||
if(x == '!' && y == '=') { value = value != eval(++++s, 9); continue; }
|
||||
|
||||
if(depth >= 8) break;
|
||||
if(x == '&' && y != '&') { value = value & eval(++s, 8); continue; }
|
||||
|
||||
if(depth >= 7) break;
|
||||
if(x == '^' && y != '^') { value = value ^ eval(++s, 7); continue; }
|
||||
|
||||
if(depth >= 6) break;
|
||||
if(x == '|' && y != '|') { value = value | eval(++s, 6); continue; }
|
||||
|
||||
if(depth >= 5) break;
|
||||
if(x == '&' && y == '&') { value = eval(++++s, 5) && value; continue; }
|
||||
|
||||
if(depth >= 4) break;
|
||||
if(x == '^' && y == '^') { value = (!eval(++++s, 4) != !value); continue; }
|
||||
|
||||
if(depth >= 3) break;
|
||||
if(x == '|' && y == '|') { value = eval(++++s, 3) || value; continue; }
|
||||
|
||||
if(x == '?') {
|
||||
int lhs = eval(++s, 2);
|
||||
if(*s != ':') throw "mismatched_ternary";
|
||||
int rhs = eval(++s, 2);
|
||||
value = value ? lhs : rhs;
|
||||
continue;
|
||||
}
|
||||
if(depth >= 2) break;
|
||||
|
||||
if(depth > 0 && x == ')') break;
|
||||
|
||||
throw "unrecognized_token";
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
bool strint(const char *s, int &result) {
|
||||
try {
|
||||
result = eval_integer(s);
|
||||
return true;
|
||||
} catch(const char*) {
|
||||
result = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool strmath(const char *s, int &result) {
|
||||
try {
|
||||
result = eval(s);
|
||||
return true;
|
||||
} catch(const char*) {
|
||||
result = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,43 @@
|
|||
#ifdef NALL_STRING_INTERNAL_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct UTF8 {
|
||||
unsigned size; //size of encoded codepoint
|
||||
uint64_t data; //encoded codepoint
|
||||
unsigned codepoint; //decoded codepoint
|
||||
};
|
||||
|
||||
inline UTF8 utf8_read(const char *s) {
|
||||
UTF8 utf8;
|
||||
|
||||
if((*s & 0xfe) == 0xfc) utf8.size = 6;
|
||||
else if((*s & 0xfc) == 0xf8) utf8.size = 5;
|
||||
else if((*s & 0xf8) == 0xf0) utf8.size = 4;
|
||||
else if((*s & 0xf0) == 0xe0) utf8.size = 3;
|
||||
else if((*s & 0xe0) == 0xc0) utf8.size = 2;
|
||||
else utf8.size = 1;
|
||||
|
||||
utf8.data = 0;
|
||||
for(unsigned n = 0; n < utf8.size; n++) {
|
||||
utf8.data = (utf8.data << 8) | (uint8_t)s[n];
|
||||
}
|
||||
|
||||
static uint8_t mask[] = { 0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
|
||||
utf8.codepoint = s[0] & mask[utf8.size];
|
||||
for(unsigned n = 1; n < utf8.size; n++) {
|
||||
utf8.codepoint = (utf8.codepoint << 6) | (s[n] & 0x3f);
|
||||
}
|
||||
|
||||
return utf8;
|
||||
}
|
||||
|
||||
inline void utf8_write(char *s, const UTF8 &utf8) {
|
||||
for(signed n = utf8.size - 1, shift = 0; n >= 0; n--, shift += 8) {
|
||||
s[n] = utf8.data >> shift;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -2,7 +2,8 @@ snes_objects := snes-interface snes-system snes-controller
|
|||
snes_objects += snes-cartridge snes-cheat
|
||||
snes_objects += snes-memory snes-cpucore snes-smpcore
|
||||
snes_objects += snes-cpu snes-smp snes-dsp snes-ppu
|
||||
snes_objects += snes-icd2 snes-nss snes-superfx snes-sa1 snes-necdsp snes-hitachidsp
|
||||
snes_objects += snes-icd2 snes-nss snes-superfx snes-sa1
|
||||
snes_objects += snes-necdsp snes-hitachidsp snes-armdsp
|
||||
snes_objects += snes-bsx snes-srtc snes-sdd1 snes-spc7110
|
||||
snes_objects += snes-obc1 snes-st0018 snes-sufamiturbo
|
||||
snes_objects += snes-msu1 snes-link
|
||||
|
@ -47,6 +48,7 @@ obj/snes-superfx.o : $(snes)/chip/superfx/superfx.cpp $(call rwildcard,$(snes
|
|||
obj/snes-sa1.o : $(snes)/chip/sa1/sa1.cpp $(call rwildcard,$(snes)/chip/sa1/)
|
||||
obj/snes-necdsp.o : $(snes)/chip/necdsp/necdsp.cpp $(call rwildcard,$(snes)/chip/necdsp/)
|
||||
obj/snes-hitachidsp.o : $(snes)/chip/hitachidsp/hitachidsp.cpp $(call rwildcard,$(snes)/chip/hitachidsp/)
|
||||
obj/snes-armdsp.o : $(snes)/chip/armdsp/armdsp.cpp $(call rwildcard,$(snes)/chip/armdsp/)
|
||||
obj/snes-bsx.o : $(snes)/chip/bsx/bsx.cpp $(call rwildcard,$(snes)/chip/bsx/)
|
||||
obj/snes-srtc.o : $(snes)/chip/srtc/srtc.cpp $(snes)/chip/srtc/*
|
||||
obj/snes-sdd1.o : $(snes)/chip/sdd1/sdd1.cpp $(snes)/chip/sdd1/*
|
||||
|
|
|
@ -22,6 +22,7 @@ void Cartridge::load(Mode cartridge_mode, const char *markup) {
|
|||
has_sa1 = false;
|
||||
has_necdsp = false;
|
||||
has_hitachidsp = false;
|
||||
has_armdsp = false;
|
||||
has_srtc = false;
|
||||
has_sdd1 = false;
|
||||
has_spc7110 = false;
|
||||
|
|
|
@ -38,6 +38,7 @@ struct Cartridge : property<Cartridge> {
|
|||
readonly<bool> has_sa1;
|
||||
readonly<bool> has_necdsp;
|
||||
readonly<bool> has_hitachidsp;
|
||||
readonly<bool> has_armdsp;
|
||||
readonly<bool> has_srtc;
|
||||
readonly<bool> has_sdd1;
|
||||
readonly<bool> has_spc7110;
|
||||
|
@ -101,6 +102,7 @@ private:
|
|||
void parse_markup_sa1(XML::Node&);
|
||||
void parse_markup_necdsp(XML::Node&);
|
||||
void parse_markup_hitachidsp(XML::Node&);
|
||||
void parse_markup_armdsp(XML::Node&);
|
||||
void parse_markup_bsx(XML::Node&);
|
||||
void parse_markup_sufamiturbo(XML::Node&);
|
||||
void parse_markup_srtc(XML::Node&);
|
||||
|
|
|
@ -16,6 +16,7 @@ void Cartridge::parse_markup(const char *markup) {
|
|||
parse_markup_superfx(cartridge["superfx"]);
|
||||
parse_markup_necdsp(cartridge["necdsp"]);
|
||||
parse_markup_hitachidsp(cartridge["hitachidsp"]);
|
||||
parse_markup_armdsp(cartridge["armdsp"]);
|
||||
parse_markup_bsx(cartridge["bsx"]);
|
||||
parse_markup_sufamiturbo(cartridge["sufamiturbo"]);
|
||||
parse_markup_srtc(cartridge["srtc"]);
|
||||
|
@ -238,7 +239,7 @@ void Cartridge::parse_markup_necdsp(XML::Node &root) {
|
|||
for(unsigned n = 0; n < promsize; n++) necdsp.programROM[n] = fp.readm(3);
|
||||
for(unsigned n = 0; n < dromsize; n++) necdsp.dataROM[n] = fp.readm(2);
|
||||
|
||||
if(sha256 != "") {
|
||||
if(!sha256.empty()) {
|
||||
//XML file specified SHA256 sum for program. Verify file matches the hash.
|
||||
fp.seek(0);
|
||||
uint8_t data[filesize];
|
||||
|
@ -298,7 +299,7 @@ void Cartridge::parse_markup_hitachidsp(XML::Node &root) {
|
|||
} else {
|
||||
for(unsigned n = 0; n < 1024; n++) hitachidsp.dataROM[n] = fp.readl(3);
|
||||
|
||||
if(sha256 != "") {
|
||||
if(!sha256.empty()) {
|
||||
//XML file specified SHA256 sum for program. Verify file matches the hash.
|
||||
fp.seek(0);
|
||||
uint8 data[3072];
|
||||
|
@ -331,6 +332,41 @@ void Cartridge::parse_markup_hitachidsp(XML::Node &root) {
|
|||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_armdsp(XML::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_armdsp = true;
|
||||
|
||||
for(auto &byte : armdsp.programROM) byte = 0x00;
|
||||
string firmware = root["firmware"].data;
|
||||
string sha256 = root["sha256"].data;
|
||||
|
||||
string path = interface->path(Slot::Base, firmware);
|
||||
file fp;
|
||||
if(fp.open(path, file::mode::read) == false) {
|
||||
interface->message({ "Warning: ARM DSP firmware ", firmware, " is missing." });
|
||||
} else if(fp.size() != 128 * 1024) {
|
||||
interface->message({ "Warning: ARM DSP firmware ", firmware, " is of the wrong file size." });
|
||||
fp.close();
|
||||
} else {
|
||||
for(auto &byte : armdsp.programROM) byte = fp.read();
|
||||
|
||||
if(!sha256.empty()) {
|
||||
if(sha256 != nall::sha256(armdsp.programROM, 128 * 1024)) {
|
||||
interface->message({ "Warning: ARM DSP firmware ", firmware, " SHA256 sum is incorrect." });
|
||||
}
|
||||
}
|
||||
|
||||
fp.close();
|
||||
}
|
||||
|
||||
for(auto &node : root) {
|
||||
if(node.name != "map") continue;
|
||||
Mapping m({ &ArmDSP::mmio_read, &armdsp }, { &ArmDSP::mmio_write, &armdsp });
|
||||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_bsx(XML::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
if(mode != Mode::BsxSlotted && mode != Mode::Bsx) return;
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
#include <snes/snes.hpp>
|
||||
|
||||
#define ARMDSP_CPP
|
||||
namespace SNES {
|
||||
|
||||
#include "opcodes.cpp"
|
||||
#include "memory.cpp"
|
||||
#include "disassembler.cpp"
|
||||
#include "serialization.cpp"
|
||||
ArmDSP armdsp;
|
||||
|
||||
void ArmDSP::Enter() { armdsp.enter(); }
|
||||
|
||||
void ArmDSP::enter() {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
step(16);
|
||||
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; }
|
||||
|
||||
print("* ARM unknown instruction\n");
|
||||
while(true) {
|
||||
step(21477272);
|
||||
synchronize_cpu();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8 ArmDSP::mmio_read(unsigned addr) {
|
||||
//print("* r", hex<4>(addr), "\n");
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void ArmDSP::mmio_write(unsigned addr, uint8 data) {
|
||||
print("* w", hex<4>(addr), "w = ", hex<2>(data), "\n");
|
||||
}
|
||||
|
||||
void ArmDSP::init() {
|
||||
}
|
||||
|
||||
void ArmDSP::load() {
|
||||
}
|
||||
|
||||
void ArmDSP::unload() {
|
||||
}
|
||||
|
||||
void ArmDSP::power() {
|
||||
}
|
||||
|
||||
void ArmDSP::reset() {
|
||||
create(ArmDSP::Enter, 21477272);
|
||||
|
||||
for(auto &rd : r) rd = 0x00000000;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
//ARM v3 (ARM6?)
|
||||
|
||||
struct ArmDSP : public Coprocessor {
|
||||
uint8 programROM[128 * 1024];
|
||||
|
||||
#include "registers.hpp"
|
||||
|
||||
static void Enter();
|
||||
void enter();
|
||||
|
||||
void init();
|
||||
void load();
|
||||
void unload();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
|
||||
//opcodes.cpp
|
||||
bool condition();
|
||||
void opcode(uint32 &rd, uint32 &rn, uint32 shifter);
|
||||
void flags(uint32 rd);
|
||||
|
||||
void op_branch();
|
||||
void op_data_immediate();
|
||||
void op_move_immediate_offset();
|
||||
|
||||
//memory.cpp
|
||||
uint32 bus_read(uint32 addr);
|
||||
void bus_write(uint32 addr, uint32 data);
|
||||
|
||||
//disassembler.cpp
|
||||
string disassemble_opcode(uint32 pc);
|
||||
string disassemble_registers();
|
||||
|
||||
//serialization.cpp
|
||||
void serialize(serializer&);
|
||||
};
|
||||
|
||||
extern ArmDSP armdsp;
|
|
@ -0,0 +1,46 @@
|
|||
#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 opcodes[] = { "and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc", "tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn" };
|
||||
|
||||
string output{hex<8>(pc), " "};
|
||||
|
||||
uint32 instruction = bus_read(pc);
|
||||
output.append(hex<8>(instruction), " ");
|
||||
|
||||
uint4 condition = instruction >> 28;
|
||||
uint4 opcode = instruction >> 21;
|
||||
uint4 rn = instruction >> 16;
|
||||
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));
|
||||
return output;
|
||||
}
|
||||
|
||||
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));
|
||||
return output;
|
||||
}
|
||||
|
||||
output.append("???");
|
||||
return output;
|
||||
}
|
||||
|
||||
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",
|
||||
"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"
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,18 @@
|
|||
#ifdef ARMDSP_CPP
|
||||
|
||||
uint32 ArmDSP::bus_read(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 0x00000000;
|
||||
}
|
||||
|
||||
void ArmDSP::bus_write(uint32 addr, uint32 data) {
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,96 @@
|
|||
#ifdef ARMDSP_CPP
|
||||
|
||||
bool ArmDSP::condition() {
|
||||
switch((uint4)(instruction >> 28)) { default:
|
||||
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)
|
||||
case 3: return cpsr.c == 0; //CC (carry clear)
|
||||
case 4: return cpsr.n == 1; //MI (negative)
|
||||
case 5: return cpsr.n == 0; //PL (positive)
|
||||
case 6: return cpsr.v == 1; //VS (overflow)
|
||||
case 7: return cpsr.v == 0; //VC (no overflow)
|
||||
case 8: return cpsr.c == 1 && cpsr.z == 0; //HI (unsigned higher)
|
||||
case 9: return cpsr.c == 0 || cpsr.z == 1; //LS (unsigned lower or same)
|
||||
case 10: return cpsr.n == cpsr.v; //GE (signed greater than or equal)
|
||||
case 11: return cpsr.n != cpsr.v; //LT (signed less than)
|
||||
case 12: return cpsr.z == 0 && cpsr.n == cpsr.v; //GT (signed greater than)
|
||||
case 13: return cpsr.z == 1 || cpsr.n != cpsr.v; //LE (signed less than or equal)
|
||||
case 14: return true; //AL (always)
|
||||
case 15: return false; //NV (never)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
//D = displacement (24-bit signed)
|
||||
void ArmDSP::op_branch() {
|
||||
if(!condition()) return;
|
||||
|
||||
int24 displacement = (int24)instruction;
|
||||
r[15] += displacement * 4;
|
||||
}
|
||||
|
||||
//CCCC 001O OOOS NNNN DDDD RRRR IIII IIII
|
||||
//C = condition
|
||||
//O = opcode
|
||||
//S = update flags
|
||||
//N = Rn
|
||||
//D = Rd
|
||||
//R = rotate
|
||||
//I = immediate
|
||||
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));
|
||||
|
||||
opcode(r[d], r[n], immediate);
|
||||
}
|
||||
|
||||
//CCCC 010P UBWL NNNN DDDD IIII IIII
|
||||
//C = condition
|
||||
//P = pre/post-indexed addressing
|
||||
//U = add/sub offset to base
|
||||
//B = byte/word access
|
||||
//W = ...
|
||||
//L = load/save
|
||||
//N = Rn
|
||||
//D = Rd
|
||||
//I = immediate
|
||||
void ArmDSP::op_move_immediate_offset() {
|
||||
if(!condition()) return;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,41 @@
|
|||
//Exceptions:
|
||||
//00000000 = reset
|
||||
//00000004 = undefined instruction
|
||||
//00000008 = software interrupt
|
||||
//0000000c = prefetch abort
|
||||
//00000010 = data abort
|
||||
//00000018 = IRQ (interrupt)
|
||||
//0000001c = FIQ (fast interrupt)
|
||||
|
||||
struct CPSR {
|
||||
bool n;
|
||||
bool z;
|
||||
bool c;
|
||||
bool v;
|
||||
bool i;
|
||||
bool f;
|
||||
uint5 m;
|
||||
|
||||
operator unsigned() const {
|
||||
return (n << 31) | (z << 30) | (c << 29) | (v << 28) | (i << 7) | (f << 6) | (m << 0);
|
||||
}
|
||||
|
||||
CPSR& operator=(uint32 data) {
|
||||
n = data & 0x80000000;
|
||||
z = data & 0x40000000;
|
||||
c = data & 0x20000000;
|
||||
v = data & 0x10000000;
|
||||
i = data & 0x00000080;
|
||||
f = data & 0x00000040;
|
||||
m = data & 0x0000001f;
|
||||
return *this;
|
||||
}
|
||||
} cpsr;
|
||||
|
||||
//r13 = SP (stack pointer)
|
||||
//r14 = LR (link register)
|
||||
//r15 = PC (program counter)
|
||||
uint32 r[16];
|
||||
|
||||
uint32 instruction;
|
||||
uint32 prefetch;
|
|
@ -0,0 +1,7 @@
|
|||
#ifdef ARMDSP_CPP
|
||||
|
||||
void ArmDSP::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -12,6 +12,7 @@ struct Coprocessor : Processor {
|
|||
#include <snes/chip/sa1/sa1.hpp>
|
||||
#include <snes/chip/necdsp/necdsp.hpp>
|
||||
#include <snes/chip/hitachidsp/hitachidsp.hpp>
|
||||
#include <snes/chip/armdsp/armdsp.hpp>
|
||||
#include <snes/chip/bsx/bsx.hpp>
|
||||
#include <snes/chip/srtc/srtc.hpp>
|
||||
#include <snes/chip/sdd1/sdd1.hpp>
|
||||
|
|
|
@ -17,8 +17,10 @@
|
|||
// GND GND
|
||||
|
||||
void USART::enter() {
|
||||
init({ &USART::usleep, this }, { &USART::read, this }, { &USART::write, this });
|
||||
main();
|
||||
if(init && main) {
|
||||
init({ &USART::usleep, this }, { &USART::read, this }, { &USART::write, this });
|
||||
main();
|
||||
}
|
||||
while(true) step(1000000); //fallback; main should never return
|
||||
}
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@ void System::serialize_all(serializer &s) {
|
|||
if(cartridge.has_sa1()) sa1.serialize(s);
|
||||
if(cartridge.has_necdsp()) necdsp.serialize(s);
|
||||
if(cartridge.has_hitachidsp()) hitachidsp.serialize(s);
|
||||
if(cartridge.has_armdsp()) armdsp.serialize(s);
|
||||
if(cartridge.has_srtc()) srtc.serialize(s);
|
||||
if(cartridge.has_sdd1()) sdd1.serialize(s);
|
||||
if(cartridge.has_spc7110()) spc7110.serialize(s);
|
||||
|
|
|
@ -72,6 +72,7 @@ void System::init() {
|
|||
sa1.init();
|
||||
necdsp.init();
|
||||
hitachidsp.init();
|
||||
armdsp.init();
|
||||
bsxsatellaview.init();
|
||||
bsxcartridge.init();
|
||||
bsxflash.init();
|
||||
|
@ -115,6 +116,7 @@ void System::load() {
|
|||
if(cartridge.has_sa1()) sa1.load();
|
||||
if(cartridge.has_necdsp()) necdsp.load();
|
||||
if(cartridge.has_hitachidsp()) hitachidsp.load();
|
||||
if(cartridge.has_armdsp()) armdsp.load();
|
||||
if(cartridge.has_srtc()) srtc.load();
|
||||
if(cartridge.has_sdd1()) sdd1.load();
|
||||
if(cartridge.has_spc7110()) spc7110.load();
|
||||
|
@ -141,6 +143,7 @@ void System::unload() {
|
|||
if(cartridge.has_sa1()) sa1.unload();
|
||||
if(cartridge.has_necdsp()) necdsp.unload();
|
||||
if(cartridge.has_hitachidsp()) hitachidsp.unload();
|
||||
if(cartridge.has_armdsp()) armdsp.unload();
|
||||
if(cartridge.has_srtc()) srtc.unload();
|
||||
if(cartridge.has_sdd1()) sdd1.unload();
|
||||
if(cartridge.has_spc7110()) spc7110.unload();
|
||||
|
@ -179,6 +182,7 @@ void System::power() {
|
|||
if(cartridge.has_sa1()) sa1.power();
|
||||
if(cartridge.has_necdsp()) necdsp.power();
|
||||
if(cartridge.has_hitachidsp()) hitachidsp.power();
|
||||
if(cartridge.has_armdsp()) armdsp.power();
|
||||
if(cartridge.has_srtc()) srtc.power();
|
||||
if(cartridge.has_sdd1()) sdd1.power();
|
||||
if(cartridge.has_spc7110()) spc7110.power();
|
||||
|
@ -209,6 +213,7 @@ void System::reset() {
|
|||
if(cartridge.has_sa1()) sa1.reset();
|
||||
if(cartridge.has_necdsp()) necdsp.reset();
|
||||
if(cartridge.has_hitachidsp()) hitachidsp.reset();
|
||||
if(cartridge.has_armdsp()) armdsp.reset();
|
||||
if(cartridge.has_srtc()) srtc.reset();
|
||||
if(cartridge.has_sdd1()) sdd1.reset();
|
||||
if(cartridge.has_spc7110()) spc7110.reset();
|
||||
|
@ -224,6 +229,7 @@ void System::reset() {
|
|||
if(cartridge.has_sa1()) cpu.coprocessors.append(&sa1);
|
||||
if(cartridge.has_necdsp()) cpu.coprocessors.append(&necdsp);
|
||||
if(cartridge.has_hitachidsp()) cpu.coprocessors.append(&hitachidsp);
|
||||
if(cartridge.has_armdsp()) cpu.coprocessors.append(&armdsp);
|
||||
if(cartridge.has_msu1()) cpu.coprocessors.append(&msu1);
|
||||
if(cartridge.has_link()) cpu.coprocessors.append(&link);
|
||||
|
||||
|
|
Loading…
Reference in New Issue