diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 74c38fff..00adc838 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -12,7 +12,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "103.05"; + static const string Version = "103.06"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/processor/spc700/algorithms.cpp b/higan/processor/spc700/algorithms.cpp index 10caa61c..d7e3745e 100644 --- a/higan/processor/spc700/algorithms.cpp +++ b/higan/processor/spc700/algorithms.cpp @@ -95,10 +95,6 @@ auto SPC700::algorithmSBC(uint8 x, uint8 y) -> uint8 { return algorithmADC(x, ~y); } -auto SPC700::algorithmST(uint8 x, uint8 y) -> uint8 { - return y; -} - // auto SPC700::algorithmADW(uint16 x, uint16 y) -> uint16 { diff --git a/higan/processor/spc700/instruction.cpp b/higan/processor/spc700/instruction.cpp index ba7af3ec..907d917e 100644 --- a/higan/processor/spc700/instruction.cpp +++ b/higan/processor/spc700/instruction.cpp @@ -2,7 +2,7 @@ #define fp(name) &SPC700::algorithm##name auto SPC700::instruction() -> void { - switch(read(PC++)) { + switch(fetch()) { op(0x00, NoOperation) op(0x01, CallTable, 0) op(0x02, AbsoluteBitSet, 0, true) @@ -12,7 +12,7 @@ auto SPC700::instruction() -> void { op(0x06, IndirectXRead, fp(OR)) op(0x07, IndexedIndirectRead, fp(OR), X) op(0x08, ImmediateRead, fp(OR), A) - op(0x09, DirectWriteDirect, fp(OR)) + op(0x09, DirectDirectModify, fp(OR)) op(0x0a, AbsoluteBitModify, 0) op(0x0b, DirectModify, fp(ASL)) op(0x0c, AbsoluteModify, fp(ASL)) @@ -27,7 +27,7 @@ auto SPC700::instruction() -> void { op(0x15, AbsoluteIndexedRead, fp(OR), X) op(0x16, AbsoluteIndexedRead, fp(OR), Y) op(0x17, IndirectIndexedRead, fp(OR), Y) - op(0x18, DirectWriteImmediate, fp(OR)) + op(0x18, DirectImmediateModify, fp(OR)) op(0x19, IndirectXWriteIndirectY, fp(OR)) op(0x1a, DirectModifyWord, -1) op(0x1b, DirectIndexedModify, fp(ASL), X) @@ -44,7 +44,7 @@ auto SPC700::instruction() -> void { op(0x26, IndirectXRead, fp(AND)) op(0x27, IndexedIndirectRead, fp(AND), X) op(0x28, ImmediateRead, fp(AND), A) - op(0x29, DirectWriteDirect, fp(AND)) + op(0x29, DirectDirectModify, fp(AND)) op(0x2a, AbsoluteBitModify, 1) op(0x2b, DirectModify, fp(ROL)) op(0x2c, AbsoluteModify, fp(ROL)) @@ -59,7 +59,7 @@ auto SPC700::instruction() -> void { op(0x35, AbsoluteIndexedRead, fp(AND), X) op(0x36, AbsoluteIndexedRead, fp(AND), Y) op(0x37, IndirectIndexedRead, fp(AND), Y) - op(0x38, DirectWriteImmediate, fp(AND)) + op(0x38, DirectImmediateModify, fp(AND)) op(0x39, IndirectXWriteIndirectY, fp(AND)) op(0x3a, DirectModifyWord, +1) op(0x3b, DirectIndexedModify, fp(ROL), A) @@ -76,7 +76,7 @@ auto SPC700::instruction() -> void { op(0x46, IndirectXRead, fp(EOR)) op(0x47, IndexedIndirectRead, fp(EOR), X) op(0x48, ImmediateRead, fp(EOR), A) - op(0x49, DirectWriteDirect, fp(EOR)) + op(0x49, DirectDirectModify, fp(EOR)) op(0x4a, AbsoluteBitModify, 2) op(0x4b, DirectModify, fp(LSR)) op(0x4c, AbsoluteModify, fp(LSR)) @@ -91,9 +91,9 @@ auto SPC700::instruction() -> void { op(0x55, AbsoluteIndexedRead, fp(EOR), X) op(0x56, AbsoluteIndexedRead, fp(EOR), Y) op(0x57, IndirectIndexedRead, fp(EOR), Y) - op(0x58, DirectWriteImmediate, fp(EOR)) + op(0x58, DirectImmediateModify, fp(EOR)) op(0x59, IndirectXWriteIndirectY, fp(EOR)) - op(0x5a, DirectReadWord, fp(CPW)) + op(0x5a, DirectCompareWord, fp(CPW)) op(0x5b, DirectIndexedModify, fp(LSR), X) op(0x5c, ImpliedModify, fp(LSR), A) op(0x5d, Transfer, A, X) @@ -108,7 +108,7 @@ auto SPC700::instruction() -> void { op(0x66, IndirectXRead, fp(CMP)) op(0x67, IndexedIndirectRead, fp(CMP), X) op(0x68, ImmediateRead, fp(CMP), A) - op(0x69, DirectWriteDirect, fp(CMP)) + op(0x69, DirectDirectCompare, fp(CMP)) op(0x6a, AbsoluteBitModify, 3) op(0x6b, DirectModify, fp(ROR)) op(0x6c, AbsoluteModify, fp(ROR)) @@ -123,8 +123,8 @@ auto SPC700::instruction() -> void { op(0x75, AbsoluteIndexedRead, fp(CMP), X) op(0x76, AbsoluteIndexedRead, fp(CMP), Y) op(0x77, IndirectIndexedRead, fp(CMP), Y) - op(0x78, DirectWriteImmediate, fp(CMP)) - op(0x79, IndirectXWriteIndirectY, fp(CMP)) + op(0x78, DirectImmediateCompare, fp(CMP)) + op(0x79, IndirectXCompareIndirectY, fp(CMP)) op(0x7a, DirectReadWord, fp(ADW)) op(0x7b, DirectIndexedModify, fp(ROR), X) op(0x7c, ImpliedModify, fp(ROR), A) @@ -140,13 +140,13 @@ auto SPC700::instruction() -> void { op(0x86, IndirectXRead, fp(ADC)) op(0x87, IndexedIndirectRead, fp(ADC), X) op(0x88, ImmediateRead, fp(ADC), A) - op(0x89, DirectWriteDirect, fp(ADC)) + op(0x89, DirectDirectModify, fp(ADC)) op(0x8a, AbsoluteBitModify, 4) op(0x8b, DirectModify, fp(DEC)) op(0x8c, AbsoluteModify, fp(DEC)) op(0x8d, ImmediateRead, fp(LD), Y) op(0x8e, PullP) - op(0x8f, DirectWriteImmediate, fp(ST)) + op(0x8f, DirectImmediateWrite) op(0x90, Branch, CF == 0) op(0x91, CallTable, 9) op(0x92, AbsoluteBitSet, 4, false) @@ -155,7 +155,7 @@ auto SPC700::instruction() -> void { op(0x95, AbsoluteIndexedRead, fp(ADC), X) op(0x96, AbsoluteIndexedRead, fp(ADC), Y) op(0x97, IndirectIndexedRead, fp(ADC), Y) - op(0x98, DirectWriteImmediate, fp(ADC)) + op(0x98, DirectImmediateModify, fp(ADC)) op(0x99, IndirectXWriteIndirectY, fp(ADC)) op(0x9a, DirectReadWord, fp(SBW)) op(0x9b, DirectIndexedModify, fp(DEC), X) @@ -172,7 +172,7 @@ auto SPC700::instruction() -> void { op(0xa6, IndirectXRead, fp(SBC)) op(0xa7, IndexedIndirectRead, fp(SBC), X) op(0xa8, ImmediateRead, fp(SBC), A) - op(0xa9, DirectWriteDirect, fp(SBC)) + op(0xa9, DirectDirectModify, fp(SBC)) op(0xaa, AbsoluteBitModify, 5) op(0xab, DirectModify, fp(INC)) op(0xac, AbsoluteModify, fp(INC)) @@ -187,7 +187,7 @@ auto SPC700::instruction() -> void { op(0xb5, AbsoluteIndexedRead, fp(SBC), X) op(0xb6, AbsoluteIndexedRead, fp(SBC), Y) op(0xb7, IndirectIndexedRead, fp(SBC), Y) - op(0xb8, DirectWriteImmediate, fp(SBC)) + op(0xb8, DirectImmediateModify, fp(SBC)) op(0xb9, IndirectXWriteIndirectY, fp(SBC)) op(0xba, DirectReadWord, fp(LDW)) op(0xbb, DirectIndexedModify, fp(INC), X) @@ -253,7 +253,7 @@ auto SPC700::instruction() -> void { op(0xf7, IndirectIndexedRead, fp(LD), Y) op(0xf8, DirectRead, fp(LD), X) op(0xf9, DirectIndexedRead, fp(LD), X, Y) - op(0xfa, DirectWriteDirect, fp(ST)) + op(0xfa, DirectDirectWrite) op(0xfb, DirectIndexedRead, fp(LD), Y, X) op(0xfc, ImpliedModify, fp(INC), Y) op(0xfd, Transfer, A, Y) diff --git a/higan/processor/spc700/instructions.cpp b/higan/processor/spc700/instructions.cpp index daf20101..9f9b77f9 100644 --- a/higan/processor/spc700/instructions.cpp +++ b/higan/processor/spc700/instructions.cpp @@ -1,16 +1,16 @@ auto SPC700::instructionAbsoluteBitModify(uint3 mode) -> void { - uint16 address = read(PC++); - address |= read(PC++) << 8; + uint16 address = fetch(); + address |= fetch() << 8; uint3 bit = address >> 13; address &= 0x1fff; uint8 data = read(address); switch(mode) { case 0: //or addr:bit - idle(address); + idle(); CF |= data.bit(bit); break; case 1: //or !addr:bit - idle(address); + idle(); CF |= !data.bit(bit); break; case 2: //and addr:bit @@ -20,14 +20,14 @@ auto SPC700::instructionAbsoluteBitModify(uint3 mode) -> void { CF &= !data.bit(bit); break; case 4: //eor addr:bit - idle(address); + idle(); CF ^= data.bit(bit); break; case 5: //ld addr:bit CF = data.bit(bit); break; case 6: //st addr:bit - idle(address); + idle(); data.bit(bit) = CF; write(address, data); break; @@ -39,118 +39,118 @@ auto SPC700::instructionAbsoluteBitModify(uint3 mode) -> void { } auto SPC700::instructionAbsoluteBitSet(uint3 bit, bool value) -> void { - uint8 address = read(PC++); - uint8 data = read(page(address)); + uint8 address = fetch(); + uint8 data = load(address); data.bit(bit) = value; - write(page(address), data); + store(address, data); } auto SPC700::instructionAbsoluteRead(fpb op, uint8& target) -> void { - uint16 address = read(PC++); - address |= read(PC++) << 8; + uint16 address = fetch(); + address |= fetch() << 8; uint8 data = read(address); target = alu(target, data); } auto SPC700::instructionAbsoluteModify(fps op) -> void { - uint16 address = read(PC++); - address |= read(PC++) << 8; + uint16 address = fetch(); + address |= fetch() << 8; uint8 data = read(address); write(address, alu(data)); } auto SPC700::instructionAbsoluteWrite(uint8& data) -> void { - uint16 address = read(PC++); - address |= read(PC++) << 8; + uint16 address = fetch(); + address |= fetch() << 8; read(address); write(address, data); } auto SPC700::instructionAbsoluteIndexedRead(fpb op, uint8& index) -> void { - uint16 address = read(PC++); - address |= read(PC++) << 8; - idle(PC - 1); + uint16 address = fetch(); + address |= fetch() << 8; + idle(); uint8 data = read(address + index); A = alu(A, data); } auto SPC700::instructionAbsoluteIndexedWrite(uint8& index) -> void { - uint16 address = read(PC++); - address |= read(PC++) << 8; - idle(PC - 1); + uint16 address = fetch(); + address |= fetch() << 8; + idle(); read(address + index); write(address + index, A); } auto SPC700::instructionBranch(bool take) -> void { - uint8 data = read(PC++); + uint8 data = fetch(); if(!take) return; - idle(PC - 1); - idle(PC - 1); + idle(); + idle(); PC += (int8)data; } auto SPC700::instructionBranchBit(uint3 bit, bool match) -> void { - uint8 address = read(PC++); - uint8 data = read(page(address)); - idle(page(address)); - uint8 displacement = read(PC++); + uint8 address = fetch(); + uint8 data = load(address); + load(address); + uint8 displacement = fetch(); if(data.bit(bit) != match) return; - idle(PC - 1); - idle(PC - 1); + idle(); + idle(); PC += (int8)displacement; } auto SPC700::instructionBranchNotDirect() -> void { - uint8 address = read(PC++); - uint8 data = read(page(address)); - idle(page(address)); - uint8 displacement = read(PC++); + uint8 address = fetch(); + uint8 data = load(address); + load(address); + uint8 displacement = fetch(); if(A == data) return; - idle(PC - 1); - idle(PC - 1); + idle(); + idle(); PC += (int8)displacement; } auto SPC700::instructionBranchNotDirectDecrement() -> void { - uint8 address = read(PC++); - uint8 data = read(page(address)); - write(page(address), --data); - uint8 displacement = read(PC++); + uint8 address = fetch(); + uint8 data = load(address); + store(address, --data); + uint8 displacement = fetch(); if(data == 0) return; - idle(PC - 1); - idle(PC - 1); + idle(); + idle(); PC += (int8)displacement; } auto SPC700::instructionBranchNotDirectX() -> void { - uint8 address = read(PC++); - idle(PC - 1); - uint8 data = read(page(address + X)); - idle(page(address + X)); - uint8 displacement = read(PC++); + uint8 address = fetch(); + idle(); + uint8 data = load(address + X); + idle(); + uint8 displacement = fetch(); if(A == data) return; - idle(PC - 1); - idle(PC - 1); + idle(); + idle(); PC += (int8)displacement; } auto SPC700::instructionBranchNotYDecrement() -> void { - idle(PC); - idle(PC); - uint8 displacement = read(PC++); + read(PC); + idle(); + uint8 displacement = fetch(); if(--Y == 0) return; - idle(PC - 1); - idle(PC - 1); + idle(); + idle(); PC += (int8)displacement; } auto SPC700::instructionBreak() -> void { - idle(PC); - write(stack(S--), PC >> 8); - write(stack(S--), PC >> 0); - write(stack(S--), P); - idle(stack(S + 1)); + read(PC); + push(PC >> 8); + push(PC >> 0); + push(P); + idle(); uint16 address = read(0xffde + 0); address |= read(0xffde + 1) << 8; PC = address; @@ -159,31 +159,31 @@ auto SPC700::instructionBreak() -> void { } auto SPC700::instructionCallAbsolute() -> void { - uint16 address = read(PC++); - address |= read(PC++) << 8; - idle(stack(S)); - write(stack(S--), PC >> 8); - write(stack(S--), PC >> 0); - idle(stack(S + 1)); - idle(stack(S + 1)); + uint16 address = fetch(); + address |= fetch() << 8; + idle(); + push(PC >> 8); + push(PC >> 0); + idle(); + idle(); PC = address; } auto SPC700::instructionCallPage() -> void { - uint8 address = read(PC++); - idle(PC - 1); - write(stack(S--), PC >> 8); - write(stack(S--), PC >> 0); - idle(stack(S + 1)); + uint8 address = fetch(); + idle(); + push(PC >> 8); + push(PC >> 0); + idle(); PC = 0xff00 | address; } auto SPC700::instructionCallTable(uint4 vector) -> void { - idle(PC); - idle(stack(S)); - write(stack(S--), PC >> 8); - write(stack(S--), PC >> 0); - idle(stack(S + 1)); + read(PC); + idle(); + push(PC >> 8); + push(PC >> 0); + idle(); uint16 address = 0xffde - (vector << 1); uint16 pc = read(address + 0); pc |= read(address + 1) << 8; @@ -191,14 +191,14 @@ auto SPC700::instructionCallTable(uint4 vector) -> void { } auto SPC700::instructionComplementCarry() -> void { - idle(PC); - idle(PC); + read(PC); + idle(); CF = !CF; } auto SPC700::instructionDecimalAdjustAdd() -> void { - idle(PC); - idle(PC); + read(PC); + idle(); if(CF || A > 0x99) { A += 0x60; CF = 1; @@ -211,8 +211,8 @@ auto SPC700::instructionDecimalAdjustAdd() -> void { } auto SPC700::instructionDecimalAdjustSub() -> void { - idle(PC); - idle(PC); + read(PC); + idle(); if(!CF || A > 0x99) { A -= 0x60; CF = 0; @@ -225,99 +225,136 @@ auto SPC700::instructionDecimalAdjustSub() -> void { } auto SPC700::instructionDirectRead(fpb op, uint8& target) -> void { - uint8 address = read(PC++); - uint8 data = read(page(address)); + uint8 address = fetch(); + uint8 data = load(address); target = alu(target, data); } auto SPC700::instructionDirectModify(fps op) -> void { - uint8 address = read(PC++); - uint8 data = read(page(address)); - write(page(address), alu(data)); + uint8 address = fetch(); + uint8 data = load(address); + store(address, alu(data)); } -auto SPC700::instructionDirectWriteWord() -> void { - uint8 address = read(PC++); - idle(page(address + 0)); - write(page(address + 0), A); - write(page(address + 1), Y); +auto SPC700::instructionDirectWrite(uint8& data) -> void { + uint8 address = fetch(); + load(address); + store(address, data); } -auto SPC700::instructionDirectWriteDirect(fpb op) -> void { - uint8 source = read(PC++); - uint8 rhs = read(page(source)); - uint8 target = read(PC++); - uint8 lhs; - if(op != &SPC700::algorithmST) lhs = read(page(target)); +auto SPC700::instructionDirectDirectCompare(fpb op) -> void { + uint8 source = fetch(); + uint8 rhs = load(source); + uint8 target = fetch(); + uint8 lhs = load(target); lhs = alu(lhs, rhs); - op != &SPC700::algorithmCMP ? write(page(target), lhs) : idle(page(target)); + load(target); } -auto SPC700::instructionDirectWriteImmediate(fpb op) -> void { - uint8 immediate = read(PC++); - uint8 address = read(PC++); - uint8 data = read(page(address)); +auto SPC700::instructionDirectDirectModify(fpb op) -> void { + uint8 source = fetch(); + uint8 rhs = load(source); + uint8 target = fetch(); + uint8 lhs = load(target); + lhs = alu(lhs, rhs); + store(target, lhs); +} + +auto SPC700::instructionDirectDirectWrite() -> void { + uint8 source = fetch(); + uint8 data = load(source); + uint8 target = fetch(); + store(target, data); +} + +auto SPC700::instructionDirectImmediateCompare(fpb op) -> void { + uint8 immediate = fetch(); + uint8 address = fetch(); + uint8 data = load(address); data = alu(data, immediate); - op != &SPC700::algorithmCMP ? write(page(address), data) : idle(page(address)); + load(address); +} + +auto SPC700::instructionDirectImmediateModify(fpb op) -> void { + uint8 immediate = fetch(); + uint8 address = fetch(); + uint8 data = load(address); + data = alu(data, immediate); + store(address, data); +} + +auto SPC700::instructionDirectImmediateWrite() -> void { + uint8 immediate = fetch(); + uint8 address = fetch(); + load(address); + store(address, immediate); +} + +auto SPC700::instructionDirectCompareWord(fpw op) -> void { + uint8 address = fetch(); + uint16 data = load(address + 0); + data |= load(address + 1) << 8; + YA = alu(YA, data); } auto SPC700::instructionDirectReadWord(fpw op) -> void { - uint8 address = read(PC++); - uint16 data = read(page(address + 0)); - if(op != &SPC700::algorithmCPW) idle(page(address + 0)); - data |= read(page(address + 1)) << 8; + uint8 address = fetch(); + uint16 data = load(address + 0); + load(address + 0); + data |= load(address + 1) << 8; YA = alu(YA, data); } auto SPC700::instructionDirectModifyWord(int adjust) -> void { - uint8 address = read(PC++); - uint16 data = read(page(address + 0)) + adjust; - write(page(address + 0), data >> 0); - data += read(page(address + 1)) << 8; - write(page(address + 1), data >> 8); + uint8 address = fetch(); + uint16 data = load(address + 0) + adjust; + store(address + 0, data >> 0); + data += load(address + 1) << 8; + store(address + 1, data >> 8); ZF = data == 0; NF = data & 0x8000; } -auto SPC700::instructionDirectWrite(uint8& data) -> void { - uint8 address = read(PC++); - idle(page(address)); - write(page(address), data); +auto SPC700::instructionDirectWriteWord() -> void { + uint8 address = fetch(); + load(address + 0); + store(address + 0, A); + store(address + 1, Y); } auto SPC700::instructionDirectIndexedRead(fpb op, uint8& target, uint8& index) -> void { - uint8 address = read(PC++); - idle(PC - 1); - uint8 data = read(page(address + index)); + uint8 address = fetch(); + idle(); + uint8 data = load(address + index); target = alu(target, data); } auto SPC700::instructionDirectIndexedModify(fps op, uint8& index) -> void { - uint8 address = read(PC++); - idle(PC - 1); - uint8 data = read(page(address + index)); - write(page(address + index), alu(data)); + uint8 address = fetch(); + idle(); + uint8 data = load(address + index); + store(address + index, alu(data)); } auto SPC700::instructionDirectIndexedWrite(uint8& data, uint8& index) -> void { - uint8 address = read(PC++); - idle(PC - 1); - idle(page(address + index)); - write(page(address + index), data); + uint8 address = fetch(); + idle(); + load(address + index); + store(address + index, data); } auto SPC700::instructionDivide() -> void { - idle(PC); - idle(PC); - idle(PC); - idle(PC); - idle(PC); - idle(PC); - idle(PC); - idle(PC); - idle(PC); - idle(PC); - idle(PC); + read(PC); + idle(); + idle(); + idle(); + idle(); + idle(); + idle(); + idle(); + idle(); + idle(); + idle(); uint16 ya = YA; //overflow set if quotient >= 256 HF = (Y & 15) >= (X & 15); @@ -338,125 +375,133 @@ auto SPC700::instructionDivide() -> void { } auto SPC700::instructionExchangeNibble() -> void { - idle(PC); - idle(PC); - idle(PC); - idle(PC); + read(PC); + idle(); + idle(); + idle(); A = A >> 4 | A << 4; ZF = A == 0; NF = A & 0x80; } auto SPC700::instructionFlagSet(bool& flag, bool value) -> void { - idle(PC); - if(&flag == &IF) idle(PC); + read(PC); + if(&flag == &IF) idle(); flag = value; } auto SPC700::instructionImmediateRead(fpb op, uint8& target) -> void { - uint8 data = read(PC++); + uint8 data = fetch(); target = alu(target, data); } auto SPC700::instructionImpliedModify(fps op, uint8& target) -> void { - idle(PC); + read(PC); target = alu(target); } auto SPC700::instructionIndexedIndirectRead(fpb op, uint8& index) -> void { - uint8 indirect = read(PC++); - idle(PC - 1); - uint16 address = read(page(indirect + index + 0)); - address |= read(page(indirect + index + 1)) << 8; + uint8 indirect = fetch(); + idle(); + uint16 address = load(indirect + index + 0); + address |= load(indirect + index + 1) << 8; uint8 data = read(address); A = alu(A, data); } auto SPC700::instructionIndexedIndirectWrite(uint8& data, uint8& index) -> void { - uint8 indirect = read(PC++); - idle(PC - 1); - uint16 address = read(page(indirect + index + 0)); - address |= read(page(indirect + index + 1)) << 8; + uint8 indirect = fetch(); + idle(); + uint16 address = load(indirect + index + 0); + address |= load(indirect + index + 1) << 8; read(address); write(address, data); } auto SPC700::instructionIndirectIndexedRead(fpb op, uint8& index) -> void { - uint8 indirect = read(PC++); - uint16 address = read(page(indirect + 0)); - address |= read(page(indirect + 1)) << 8; - idle(page(indirect + 1)); + uint8 indirect = fetch(); + uint16 address = load(indirect + 0); + address |= load(indirect + 1) << 8; + idle(); uint8 data = read(address + index); A = alu(A, data); } auto SPC700::instructionIndirectIndexedWrite(uint8& data, uint8& index) -> void { - uint8 indirect = read(PC++); - uint16 address = read(page(indirect + 0)); - address |= read(page(indirect + 1)) << 8; - idle(page(indirect + 1)); + uint8 indirect = fetch(); + uint16 address = load(indirect + 0); + address |= load(indirect + 1) << 8; + idle(); read(address + index); write(address + index, data); } auto SPC700::instructionIndirectXRead(fpb op) -> void { - idle(PC); - uint8 data = read(page(X)); + read(PC); + uint8 data = load(X); A = alu(A, data); } auto SPC700::instructionIndirectXWrite(uint8& data) -> void { - idle(PC); - idle(page(X)); - write(page(X), data); + read(PC); + load(X); + store(X, data); } auto SPC700::instructionIndirectXIncrementRead(uint8& data) -> void { - idle(PC); - idle(page(X), false); //quirk: does not read internal SMP registers - data = read(page(X++)); + read(PC); + data = load(X++); + idle(); //quirk: consumes extra idle cycle compared to most read instructions ZF = data == 0; NF = data & 0x80; } auto SPC700::instructionIndirectXIncrementWrite(uint8& data) -> void { - idle(PC); - idle(page(X), false); //quirk: does not read internal SMP registers - write(page(X++), data); + read(PC); + idle(); //quirk: not a read cycle as with most write instructions + store(X++, data); +} + +auto SPC700::instructionIndirectXCompareIndirectY(fpb op) -> void { + read(PC); + uint8 rhs = load(Y); + uint8 lhs = load(X); + lhs = alu(lhs, rhs); + load(X); } auto SPC700::instructionIndirectXWriteIndirectY(fpb op) -> void { - idle(PC); - uint8 rhs = read(page(Y)); - uint8 lhs = read(page(X)); + read(PC); + uint8 rhs = load(Y); + uint8 lhs = load(X); lhs = alu(lhs, rhs); - op != &SPC700::algorithmCMP ? write(page(X), lhs) : idle(page(X)); + store(X, lhs); } auto SPC700::instructionJumpAbsolute() -> void { - uint16 address = read(PC++); - address |= read(PC++) << 8; + uint16 address = fetch(); + address |= fetch() << 8; PC = address; } auto SPC700::instructionJumpIndirectX() -> void { - uint16 address = read(PC++); - address |= read(PC++) << 8; - idle(PC - 1); + uint16 address = fetch(); + address |= fetch() << 8; + idle(); uint16 pc = read(address + X + 0); pc |= read(address + X + 1) << 8; PC = pc; } auto SPC700::instructionMultiply() -> void { - idle(PC); - idle(PC); - idle(PC); - idle(PC); - idle(PC); - idle(PC); - idle(PC); - idle(PC); + read(PC); + idle(); + idle(); + idle(); + idle(); + idle(); + idle(); + idle(); uint16 ya = Y * A; A = ya >> 0; Y = ya >> 8; @@ -466,70 +511,70 @@ auto SPC700::instructionMultiply() -> void { } auto SPC700::instructionNoOperation() -> void { - idle(PC); + read(PC); } auto SPC700::instructionOverflowClear() -> void { - idle(PC); + read(PC); HF = 0; VF = 0; } auto SPC700::instructionPull(uint8& data) -> void { - idle(PC); - idle(stack(S)); - data = read(stack(++S)); + read(PC); + idle(); + data = pull(); } auto SPC700::instructionPullP() -> void { - idle(PC); - idle(stack(S)); - P = read(stack(++S)); + read(PC); + idle(); + P = pull(); } auto SPC700::instructionPush(uint8 data) -> void { - idle(PC); - write(stack(S--), data); - idle(stack(S + 1)); + read(PC); + push(data); + idle(); } auto SPC700::instructionReturnInterrupt() -> void { - idle(PC); - idle(stack(S)); - P = read(stack(++S)); - uint16 address = read(stack(++S)); - address |= read(stack(++S)) << 8; + read(PC); + idle(); + P = pull(); + uint16 address = pull(); + address |= pull() << 8; PC = address; } auto SPC700::instructionReturnSubroutine() -> void { - idle(PC); - idle(stack(S)); - uint16 address = read(stack(++S)); - address |= read(stack(++S)) << 8; + read(PC); + idle(); + uint16 address = pull(); + address |= pull() << 8; PC = address; } auto SPC700::instructionStop() -> void { r.stop = true; while(r.stop && !synchronizing()) { - idle(PC); - idle(PC); + read(PC); + idle(); } } auto SPC700::instructionTestSetBitsAbsolute(bool set) -> void { - uint16 address = read(PC++); - address |= read(PC++) << 8; + uint16 address = fetch(); + address |= fetch() << 8; uint8 data = read(address); ZF = (A - data) == 0; NF = (A - data) & 0x80; - idle(address); + read(address); write(address, set ? data | A : data & ~A); } auto SPC700::instructionTransfer(uint8& from, uint8& to) -> void { - idle(PC); + read(PC); to = from; if(&to == &S) return; ZF = to == 0; @@ -539,7 +584,7 @@ auto SPC700::instructionTransfer(uint8& from, uint8& to) -> void { auto SPC700::instructionWait() -> void { r.wait = true; while(r.wait && !synchronizing()) { - idle(PC); - idle(PC); + read(PC); + idle(); } } diff --git a/higan/processor/spc700/memory.cpp b/higan/processor/spc700/memory.cpp new file mode 100644 index 00000000..3c0f92a7 --- /dev/null +++ b/higan/processor/spc700/memory.cpp @@ -0,0 +1,19 @@ +auto SPC700::fetch() -> uint8 { + return read(PC++); +} + +auto SPC700::load(uint8 address) -> uint8 { + return read(PF << 8 | address); +} + +auto SPC700::store(uint8 address, uint8 data) -> void { + return write(PF << 8 | address, data); +} + +auto SPC700::pull() -> uint8 { + return read(1 << 8 | ++S); +} + +auto SPC700::push(uint8 data) -> void { + return write(1 << 8 | S--, data); +} diff --git a/higan/processor/spc700/spc700.cpp b/higan/processor/spc700/spc700.cpp index c0cf0bd1..69ec693c 100644 --- a/higan/processor/spc700/spc700.cpp +++ b/higan/processor/spc700/spc700.cpp @@ -22,20 +22,13 @@ namespace Processor { #define alu (this->*op) +#include "memory.cpp" #include "algorithms.cpp" #include "instructions.cpp" #include "instruction.cpp" #include "serialization.cpp" #include "disassembler.cpp" -auto SPC700::page(uint8 address) const -> uint16 { - return PF << 8 | address; -} - -auto SPC700::stack(uint8 address) const -> uint16 { - return 1 << 8 | address; -} - auto SPC700::power() -> void { PC = 0x0000; YA = 0x0000; diff --git a/higan/processor/spc700/spc700.hpp b/higan/processor/spc700/spc700.hpp index 243bd7ea..71e75956 100644 --- a/higan/processor/spc700/spc700.hpp +++ b/higan/processor/spc700/spc700.hpp @@ -3,7 +3,7 @@ namespace Processor { struct SPC700 { - virtual auto idle(uint16 address, bool read = true) -> void = 0; + virtual auto idle() -> void = 0; virtual auto read(uint16 address) -> uint8 = 0; virtual auto write(uint16 addessr, uint8 data) -> void = 0; virtual auto synchronizing() const -> bool = 0; @@ -11,11 +11,15 @@ struct SPC700 { virtual auto readDisassembler(uint16 address) -> uint8 { return 0; } //spc700.cpp - inline auto page(uint8 address) const -> uint16; - inline auto stack(uint8 address) const -> uint16; - auto power() -> void; + //memory.cpp + inline auto fetch() -> uint8; + inline auto load(uint8 address) -> uint8; + inline auto store(uint8 address, uint8 data) -> void; + inline auto pull() -> uint8; + inline auto push(uint8 data) -> void; + //instruction.cpp auto instruction() -> void; @@ -33,7 +37,6 @@ struct SPC700 { auto algorithmROL(uint8) -> uint8; auto algorithmROR(uint8) -> uint8; auto algorithmSBC(uint8, uint8) -> uint8; - auto algorithmST (uint8, uint8) -> uint8; auto algorithmADW(uint16, uint16) -> uint16; auto algorithmCPW(uint16, uint16) -> uint16; auto algorithmLDW(uint16, uint16) -> uint16; @@ -67,8 +70,13 @@ struct SPC700 { auto instructionDirectRead(fpb, uint8&) -> void; auto instructionDirectModify(fps) -> void; auto instructionDirectWrite(uint8&) -> void; - auto instructionDirectWriteDirect(fpb) -> void; - auto instructionDirectWriteImmediate(fpb) -> void; + auto instructionDirectDirectCompare(fpb) -> void; + auto instructionDirectDirectModify(fpb) -> void; + auto instructionDirectDirectWrite() -> void; + auto instructionDirectImmediateCompare(fpb) -> void; + auto instructionDirectImmediateModify(fpb) -> void; + auto instructionDirectImmediateWrite() -> void; + auto instructionDirectCompareWord(fpw) -> void; auto instructionDirectReadWord(fpw) -> void; auto instructionDirectModifyWord(int) -> void; auto instructionDirectWriteWord() -> void; @@ -88,6 +96,7 @@ struct SPC700 { auto instructionIndirectXWrite(uint8&) -> void; auto instructionIndirectXIncrementRead(uint8&) -> void; auto instructionIndirectXIncrementWrite(uint8&) -> void; + auto instructionIndirectXCompareIndirectY(fpb) -> void; auto instructionIndirectXWriteIndirectY(fpb) -> void; auto instructionJumpAbsolute() -> void; auto instructionJumpIndirectX() -> void; diff --git a/higan/sfc/smp/memory.cpp b/higan/sfc/smp/memory.cpp index c325de0b..a29eccca 100644 --- a/higan/sfc/smp/memory.cpp +++ b/higan/sfc/smp/memory.cpp @@ -92,14 +92,12 @@ auto SMP::busWrite(uint16 addr, uint8 data) -> void { case 0xf0: //TEST if(r.p.p) break; //writes only valid when P flag is clear - io.timersDisable = data.bit (0); - io.ramWritable = data.bit (1); - io.ramDisable = data.bit (2); - io.timersEnable = data.bit (3); - io.ramSpeed = data.bits(4,5); - io.romIOSpeed = data.bits(6,7); - - io.timerStep = (1 << io.romIOSpeed) + (2 << io.ramSpeed); + io.timersDisable = data.bit (0); + io.ramWritable = data.bit (1); + io.ramDisable = data.bit (2); + io.timersEnable = data.bit (3); + io.externalWaitStates = data.bits(4,5); + io.internalWaitStates = data.bits(6,7); timer0.synchronizeStage1(); timer1.synchronizeStage1(); @@ -199,30 +197,19 @@ auto SMP::busWrite(uint16 addr, uint8 data) -> void { ramWrite(addr, data); //all writes, even to I/O registers, appear on bus } -auto SMP::speed(uint16 addr) const -> uint { - static const uint waitStates[4] = {1, 2, 5, 10}; - if((addr & 0xfff0) == 0x00f0) return waitStates[io.romIOSpeed]; - if(addr >= 0xffc0 && io.iplromEnable) return waitStates[io.romIOSpeed]; - return waitStates[io.ramSpeed]; -} - -auto SMP::idle(uint16 addr, bool read) -> void { - step(24 * speed(addr)); - if(read) busRead(addr); - cycleEdge(); +auto SMP::idle() -> void { + wait(); } auto SMP::read(uint16 addr) -> uint8 { - step(24 * speed(addr)); + wait(addr); uint8 data = busRead(addr); - cycleEdge(); return data; } auto SMP::write(uint16 addr, uint8 data) -> void { - step(24 * speed(addr)); + wait(addr); busWrite(addr, data); - cycleEdge(); } auto SMP::readDisassembler(uint16 addr) -> uint8 { diff --git a/higan/sfc/smp/serialization.cpp b/higan/sfc/smp/serialization.cpp index f68c2ec4..0a1c82b4 100644 --- a/higan/sfc/smp/serialization.cpp +++ b/higan/sfc/smp/serialization.cpp @@ -4,7 +4,6 @@ auto SMP::serialize(serializer& s) -> void { s.integer(io.clockCounter); s.integer(io.dspCounter); - s.integer(io.timerStep); s.integer(io.apu0); s.integer(io.apu1); @@ -15,8 +14,8 @@ auto SMP::serialize(serializer& s) -> void { s.integer(io.ramWritable); s.integer(io.ramDisable); s.integer(io.timersEnable); - s.integer(io.ramSpeed); - s.integer(io.romIOSpeed); + s.integer(io.externalWaitStates); + s.integer(io.internalWaitStates); s.integer(io.iplromEnable); diff --git a/higan/sfc/smp/smp.cpp b/higan/sfc/smp/smp.cpp index a73de9e9..ac32fb12 100644 --- a/higan/sfc/smp/smp.cpp +++ b/higan/sfc/smp/smp.cpp @@ -34,7 +34,7 @@ auto SMP::load(Markup::Node node) -> bool { auto SMP::power() -> void { SPC700::power(); - create(Enter, system.apuFrequency()); + create(Enter, system.apuFrequency() / 12.0); r.pc.byte.l = iplrom[62]; r.pc.byte.h = iplrom[63]; @@ -42,7 +42,6 @@ auto SMP::power() -> void { //timing io.clockCounter = 0; io.dspCounter = 0; - io.timerStep = (1 << 0) + (2 << 0); //external io.apu0 = 0x00; @@ -55,8 +54,8 @@ auto SMP::power() -> void { io.ramWritable = true; io.ramDisable = false; io.timersEnable = true; - io.ramSpeed = 0; - io.romIOSpeed = 0; + io.externalWaitStates = 0; + io.internalWaitStates = 0; //$00f1 io.iplromEnable = true; diff --git a/higan/sfc/smp/smp.hpp b/higan/sfc/smp/smp.hpp index a1a35391..2eab3f69 100644 --- a/higan/sfc/smp/smp.hpp +++ b/higan/sfc/smp/smp.hpp @@ -21,7 +21,6 @@ private: //timing uint clockCounter; uint dspCounter; - uint timerStep; //external uint8 apu0; @@ -34,8 +33,8 @@ private: uint1 ramWritable; uint1 ramDisable; uint1 timersEnable; - uint2 ramSpeed; - uint2 romIOSpeed; + uint2 externalWaitStates; + uint2 internalWaitStates; //$00f1 bool iplromEnable; @@ -63,8 +62,7 @@ private: auto busRead(uint16 addr) -> uint8; auto busWrite(uint16 addr, uint8 data) -> void; - auto speed(uint16 addr) const -> uint; - auto idle(uint16 addr, bool read = true) -> void override; + auto idle() -> void override; auto read(uint16 addr) -> uint8 override; auto write(uint16 addr, uint8 data) -> void override; @@ -80,16 +78,17 @@ private: bool enable; uint8 target; - auto tick() -> void; + auto step(uint clocks) -> void; auto synchronizeStage1() -> void; }; - Timer<192> timer0; - Timer<192> timer1; - Timer< 24> timer2; + Timer<128> timer0; + Timer<128> timer1; + Timer< 16> timer2; - alwaysinline auto step(uint clocks) -> void; - alwaysinline auto cycleEdge() -> void; + inline auto wait(maybe address = nothing) -> void; + inline auto step(uint clocks) -> void; + inline auto stepTimers(uint clocks) -> void; }; extern SMP smp; diff --git a/higan/sfc/smp/timing.cpp b/higan/sfc/smp/timing.cpp index 27fa9769..56ba817b 100644 --- a/higan/sfc/smp/timing.cpp +++ b/higan/sfc/smp/timing.cpp @@ -1,3 +1,24 @@ +//DSP clock (~24576khz) / 12 (~2048khz) is fed into the SMP +//from here, the wait states value is really a clock divider of {2, 4, 8, 16} +//because dividers of 8 and 16 are not evenly divislbe into 12, the SMP glitches +//in these two cases, the SMP ends up consuming 10 and 20 cycles instead +//this causes unpredictable behavior on real hardware +//sometimes the SMP will run far slower than expected +//other times (and more likely), the SMP will deadlock until the system is reset +//the timers are not affected by this and advance by their expected values +auto SMP::wait(maybe addr) -> void { + static const uint cycleWaitStates[4] = {2, 4, 10, 20}; + static const uint timerWaitStates[4] = {2, 4, 8, 16}; + + uint waitStates = io.externalWaitStates; + if(!addr) waitStates = io.internalWaitStates; //idle cycles + else if((*addr & 0xfff0) == 0x00f0) waitStates = io.internalWaitStates; //IO registers + else if(*addr >= 0xffc0 && io.iplromEnable) waitStates = io.internalWaitStates; //IPLROM + + step(cycleWaitStates[waitStates]); + stepTimers(timerWaitStates[waitStates]); +} + auto SMP::step(uint clocks) -> void { Thread::step(clocks); synchronize(dsp); @@ -11,15 +32,15 @@ auto SMP::step(uint clocks) -> void { #endif } -auto SMP::cycleEdge() -> void { - timer0.tick(); - timer1.tick(); - timer2.tick(); +auto SMP::stepTimers(uint clocks) -> void { + timer0.step(clocks); + timer1.step(clocks); + timer2.step(clocks); } -template auto SMP::Timer::tick() -> void { +template auto SMP::Timer::step(uint clocks) -> void { //stage 0 increment - stage0 += smp.io.timerStep; + stage0 += clocks; if(stage0 < Frequency) return; stage0 -= Frequency;