diff --git a/bsnes/base/base.hpp b/bsnes/base/base.hpp index c160d6a8..be888faf 100755 --- a/bsnes/base/base.hpp +++ b/bsnes/base/base.hpp @@ -1,7 +1,7 @@ #ifndef BASE_HPP #define BASE_HPP -const char Version[] = "086.07"; +const char Version[] = "086.08"; #include #include diff --git a/bsnes/nall/snes/cartridge.hpp b/bsnes/nall/snes/cartridge.hpp index c24dcaa1..0dfbba85 100755 --- a/bsnes/nall/snes/cartridge.hpp +++ b/bsnes/nall/snes/cartridge.hpp @@ -527,12 +527,21 @@ SnesCartridge::SnesCartridge(const uint8_t *data, unsigned size) { " \n" ); + if(has_st018) markup.append( + " \n" + " \n" + " \n" + " \n" + ); + + #if 0 if(has_st018) markup.append( " \n" " \n" " \n" " \n" ); + #endif markup.append("\n"); } diff --git a/bsnes/nall/snes/usart.hpp b/bsnes/nall/snes/usart.hpp new file mode 100755 index 00000000..e0d9a224 --- /dev/null +++ b/bsnes/nall/snes/usart.hpp @@ -0,0 +1,70 @@ +#ifndef NALL_SNES_USART_HPP +#define NALL_SNES_USART_HPP + +#include +#include +#include +#include + +#define usartproc dllexport + +static nall::function usart_usleep; +static nall::function usart_read; +static nall::function usart_write; + +extern "C" usartproc void usart_init( + nall::function usleep, + nall::function read, + nall::function 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 diff --git a/bsnes/nall/stack.hpp b/bsnes/nall/stack.hpp new file mode 100755 index 00000000..fe8e16a1 --- /dev/null +++ b/bsnes/nall/stack.hpp @@ -0,0 +1,26 @@ +#ifndef NALL_STACK_HPP +#define NALL_STACK_HPP + +#include + +namespace nall { + template struct stack : public linear_vector { + void push(const T &value) { + linear_vector::append(value); + } + + T pull() { + if(linear_vector::size() == 0) throw; + T value = linear_vector::operator[](linear_vector::size() - 1); + linear_vector::remove(linear_vector::size() - 1); + return value; + } + + T& operator()() { + if(linear_vector::size() == 0) throw; + return linear_vector::operator[](linear_vector::size() - 1); + } + }; +} + +#endif diff --git a/bsnes/nall/string.hpp b/bsnes/nall/string.hpp index 996cd68a..1233dcfb 100755 --- a/bsnes/nall/string.hpp +++ b/bsnes/nall/string.hpp @@ -25,13 +25,12 @@ #include #include #include -#include #include #include #include +#include #include #include -#include #include #include #include @@ -40,6 +39,7 @@ #include #include #include +#include #include #include #include diff --git a/bsnes/nall/string/math.hpp b/bsnes/nall/string/math.hpp deleted file mode 100755 index 8356e162..00000000 --- a/bsnes/nall/string/math.hpp +++ /dev/null @@ -1,167 +0,0 @@ -#ifdef NALL_STRING_INTERNAL_HPP - -namespace nall { - -static function 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 diff --git a/bsnes/nall/string/utf8.hpp b/bsnes/nall/string/utf8.hpp new file mode 100755 index 00000000..77397bf2 --- /dev/null +++ b/bsnes/nall/string/utf8.hpp @@ -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 diff --git a/bsnes/snes/Makefile b/bsnes/snes/Makefile index 32b5d1c7..28a1c96c 100755 --- a/bsnes/snes/Makefile +++ b/bsnes/snes/Makefile @@ -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/* diff --git a/bsnes/snes/cartridge/cartridge.cpp b/bsnes/snes/cartridge/cartridge.cpp index fdfff8a0..fc20832b 100755 --- a/bsnes/snes/cartridge/cartridge.cpp +++ b/bsnes/snes/cartridge/cartridge.cpp @@ -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; diff --git a/bsnes/snes/cartridge/cartridge.hpp b/bsnes/snes/cartridge/cartridge.hpp index 015b9ccf..50844ac5 100755 --- a/bsnes/snes/cartridge/cartridge.hpp +++ b/bsnes/snes/cartridge/cartridge.hpp @@ -38,6 +38,7 @@ struct Cartridge : property { readonly has_sa1; readonly has_necdsp; readonly has_hitachidsp; + readonly has_armdsp; readonly has_srtc; readonly has_sdd1; readonly 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&); diff --git a/bsnes/snes/cartridge/markup.cpp b/bsnes/snes/cartridge/markup.cpp index f67cd171..2957430a 100755 --- a/bsnes/snes/cartridge/markup.cpp +++ b/bsnes/snes/cartridge/markup.cpp @@ -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; diff --git a/bsnes/snes/chip/armdsp/armdsp.cpp b/bsnes/snes/chip/armdsp/armdsp.cpp new file mode 100755 index 00000000..cb713d97 --- /dev/null +++ b/bsnes/snes/chip/armdsp/armdsp.cpp @@ -0,0 +1,65 @@ +#include + +#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; +} + +} diff --git a/bsnes/snes/chip/armdsp/armdsp.hpp b/bsnes/snes/chip/armdsp/armdsp.hpp new file mode 100755 index 00000000..bf8ef7fb --- /dev/null +++ b/bsnes/snes/chip/armdsp/armdsp.hpp @@ -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; diff --git a/bsnes/snes/chip/armdsp/disassembler.cpp b/bsnes/snes/chip/armdsp/disassembler.cpp new file mode 100755 index 00000000..85d63d76 --- /dev/null +++ b/bsnes/snes/chip/armdsp/disassembler.cpp @@ -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 diff --git a/bsnes/snes/chip/armdsp/memory.cpp b/bsnes/snes/chip/armdsp/memory.cpp new file mode 100755 index 00000000..af30cd57 --- /dev/null +++ b/bsnes/snes/chip/armdsp/memory.cpp @@ -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 diff --git a/bsnes/snes/chip/armdsp/opcodes.cpp b/bsnes/snes/chip/armdsp/opcodes.cpp new file mode 100755 index 00000000..9cb87535 --- /dev/null +++ b/bsnes/snes/chip/armdsp/opcodes.cpp @@ -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 diff --git a/bsnes/snes/chip/armdsp/registers.hpp b/bsnes/snes/chip/armdsp/registers.hpp new file mode 100755 index 00000000..13120cac --- /dev/null +++ b/bsnes/snes/chip/armdsp/registers.hpp @@ -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; diff --git a/bsnes/snes/chip/armdsp/serialization.cpp b/bsnes/snes/chip/armdsp/serialization.cpp new file mode 100755 index 00000000..9affc7c8 --- /dev/null +++ b/bsnes/snes/chip/armdsp/serialization.cpp @@ -0,0 +1,7 @@ +#ifdef ARMDSP_CPP + +void ArmDSP::serialize(serializer &s) { + Processor::serialize(s); +} + +#endif diff --git a/bsnes/snes/chip/chip.hpp b/bsnes/snes/chip/chip.hpp index 35419378..0ea01f41 100755 --- a/bsnes/snes/chip/chip.hpp +++ b/bsnes/snes/chip/chip.hpp @@ -12,6 +12,7 @@ struct Coprocessor : Processor { #include #include #include +#include #include #include #include diff --git a/bsnes/snes/controller/usart/usart.cpp b/bsnes/snes/controller/usart/usart.cpp index 88a07088..2dfdeddf 100755 --- a/bsnes/snes/controller/usart/usart.cpp +++ b/bsnes/snes/controller/usart/usart.cpp @@ -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 } diff --git a/bsnes/snes/system/serialization.cpp b/bsnes/snes/system/serialization.cpp index 9f5273d1..f746c3a8 100755 --- a/bsnes/snes/system/serialization.cpp +++ b/bsnes/snes/system/serialization.cpp @@ -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); diff --git a/bsnes/snes/system/system.cpp b/bsnes/snes/system/system.cpp index 284e389d..c7edec02 100755 --- a/bsnes/snes/system/system.cpp +++ b/bsnes/snes/system/system.cpp @@ -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);