diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index f9045b27..3dd5714a 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -11,7 +11,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "100.03"; + static const string Version = "100.04"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/md/cpu/cpu.cpp b/higan/md/cpu/cpu.cpp index 41142d61..afeb5340 100644 --- a/higan/md/cpu/cpu.cpp +++ b/higan/md/cpu/cpu.cpp @@ -10,8 +10,8 @@ auto CPU::Enter() -> void { } auto CPU::boot() -> void { - r.sp = readLong(0); - r.pc = readLong(4); + r.ssp = readLong(0); + r.pc = readLong(4); } auto CPU::main() -> void { @@ -20,8 +20,8 @@ auto CPU::main() -> void { auto CPU::step(uint clocks) -> void { clock += clocks; - while(clock >= frequency) { - clock -= frequency; + if(clock >= frequency / 60) { + clock -= frequency / 60; scheduler.exit(Scheduler::Event::Frame); } } diff --git a/higan/md/interface/interface.cpp b/higan/md/interface/interface.cpp index 4720d3e0..7b5d27cf 100644 --- a/higan/md/interface/interface.cpp +++ b/higan/md/interface/interface.cpp @@ -10,8 +10,8 @@ Interface::Interface() { information.manufacturer = "Sega"; information.name = "Mega Drive"; - information.width = 1280; - information.height = 480; + information.width = 320; //1280 + information.height = 240; // 480 information.overscan = true; information.aspectRatio = 4.0 / 3.0; information.resettable = true; diff --git a/higan/md/system/system.cpp b/higan/md/system/system.cpp index 92eb06c6..a3ba28e3 100644 --- a/higan/md/system/system.cpp +++ b/higan/md/system/system.cpp @@ -7,8 +7,8 @@ Scheduler scheduler; auto System::run() -> void { if(scheduler.enter() == Scheduler::Event::Frame) { - static uint32 output[1280 * 480] = {0}; - Emulator::video.refresh(output, 1280 * sizeof(uint32), 1280, 480); + static uint32 output[320 * 240] = {0}; + Emulator::video.refresh(output, 320 * sizeof(uint32), 320, 240); } } diff --git a/higan/processor/m68k/disassembler.cpp b/higan/processor/m68k/disassembler.cpp new file mode 100644 index 00000000..17d7b0f9 --- /dev/null +++ b/higan/processor/m68k/disassembler.cpp @@ -0,0 +1,96 @@ +auto M68K::disassemble(uint32 pc) -> string { + auto readByte = [&](uint32 addr) -> uint8 { + return read(addr); + }; + auto readWord = [&](uint32 addr) -> uint16 { + uint16 data = read(addr + 0) << 8; + return data |= read(addr + 1) << 0; + }; + auto readLong = [&](uint32 addr) -> uint32 { + uint32 data = readWord(addr + 0) << 16; + return data |= readWord(addr + 2) << 0; + }; + auto readWordPC = [&]() -> uint16 { + auto data = readWord(pc); + pc += 2; + return data; + }; + auto readLongPC = [&]() -> uint32 { + uint32 data = readWordPC() << 16; + return data |= readWordPC() << 0; + }; + + auto suffix = [&](uint2 size) -> string { + if(size == 0) return ".b"; + if(size == 1) return ".w"; + if(size == 2) return ".l"; + return ".?"; + }; + + auto branch = [&](uint8 displacementByte) -> string { + uint16 displacementWord = readWordPC(); + if(displacementByte) pc -= 2; + return {"$", hex(pc + (displacementByte ? (int8_t)displacementByte : ((int16_t)displacementWord - 2)), 6L)}; + }; + + auto cc = [&](uint4 condition) -> string { + switch(condition) { + case 0: return "ra"; + case 1: return "sr"; + case 2: return "hi"; + case 3: return "ls"; + case 4: return "cc"; + case 5: return "cs"; + case 6: return "ne"; + case 7: return "eq"; + case 8: return "vc"; + case 9: return "vs"; + case 10: return "pl"; + case 11: return "mi"; + case 12: return "ge"; + case 13: return "lt"; + case 14: return "gt"; + case 15: return "le"; + } + unreachable; + }; + + auto ea = [&](uint2 size, uint3 mode, uint3 reg) -> string { + if(mode == 7) { + if(reg == 0) return {"($", hex((int16)readWordPC(), 6L), ")", suffix(size)}; + if(reg == 1) return {"($", hex(readLongPC(), 6L), ")", suffix(size)}; + } + + return "???"; + }; + + string s, op; + s.append(hex(pc, 6L), " "); + + auto opcode = readWordPC(); + s.append(hex(opcode, 4L), " "); + + if(0); + + //bcc + else if(opcode >> 12 == 0b0110) { + op = {"b", cc(opcode >> 8), " ", branch(opcode >> 0)}; + } + + //nop + else if(opcode == 0b0100'1110'0111'0001) { + op = {"nop"}; + } + + //tst + else if(opcode >> 8 == 0b0100'1010) { + op = {"tst", suffix(opcode >> 6), " ", ea(opcode >> 6, opcode >> 3, opcode >> 0)}; + } + + else { + op = {"???"}; + } + + s.append(op); + return s; +} diff --git a/higan/processor/m68k/ea.cpp b/higan/processor/m68k/ea.cpp new file mode 100644 index 00000000..c3de8727 --- /dev/null +++ b/higan/processor/m68k/ea.cpp @@ -0,0 +1,25 @@ +auto M68K::signExtend(uint2 size, uint32 data) -> int32 { + if(size == 0) return (int8)data; + if(size == 1) return (int16)data; + if(size == 2) return (int32)data; + return 0; +} + +auto M68K::readEA(uint2 size, uint3 mode, uint3 reg) -> uint32 { + if(mode == 7) { + if(reg == 0) { + uint32 addr = (int16)readWordPC(); + return readAbsolute(size, addr); + } + + if(reg == 1) { + uint32 addr = readLongPC(); + return readAbsolute(size, addr); + } + } + + return 0; +} + +auto M68K::writeEA(uint2 size, uint3 mode, uint3 reg, uint32 data) -> void { +} diff --git a/higan/processor/m68k/instruction.cpp b/higan/processor/m68k/instruction.cpp new file mode 100644 index 00000000..e02c7464 --- /dev/null +++ b/higan/processor/m68k/instruction.cpp @@ -0,0 +1,34 @@ +auto M68K::trap() -> void { + instructionsExecuted--; + r.pc -= 2; + print("[M68K] unimplemented instruction: ", hex(r.pc, 6L), " = ", hex(opcode, 4L), "\n"); + print("[M68K] instructions executed: ", instructionsExecuted, "\n"); + while(true) step(5); +} + +auto M68K::instruction() -> void { + instructionsExecuted++; + print(disassemble(r.pc), "\n"); + + opcode = readWordPC(); + + //bcc + //0110 cccc dddd dddd + if(opcode >> 12 == 0b0110) { + return instructionBCC(opcode >> 8, opcode >> 0); + } + + //nop + //0100 1110 0111 0001 + if(opcode == 0b0100'1110'0111'0001) { + return instructionNOP(); + } + + //tst + //0100 1010 ssmm mrrr + if(opcode >> 8 == 0b0100'1010) { + return instructionTST(opcode >> 6, opcode >> 3, opcode >> 0); + } + + trap(); +} diff --git a/higan/processor/m68k/instructions.cpp b/higan/processor/m68k/instructions.cpp new file mode 100644 index 00000000..121e0267 --- /dev/null +++ b/higan/processor/m68k/instructions.cpp @@ -0,0 +1,47 @@ +auto M68K::testCondition(uint4 condition) -> bool { + switch(condition) { + case 0: return true; //RA + case 1: return false; //NV,SR + case 2: return !r.c && !r.z; //HI + case 3: return r.c || r.z; //LS + case 4: return !r.c; //CC,HS + case 5: return r.c; //CS,LO + case 6: return !r.z; //NE + case 7: return r.z; //EQ + case 8: return !r.v; //VC + case 9: return r.v; //VS + case 10: return !r.n; //PL + case 11: return r.n; //MI + case 12: return r.n == r.v; //GE + case 13: return r.n != r.v; //LT + case 14: return r.n == r.v && !r.z; //GT + case 15: return r.n != r.v || r.z; //LE + } + unreachable; +} + +// + +auto M68K::instructionBCC(uint4 condition, uint8 displacementByte) -> void { + uint16 displacementWord = readWordPC(); + if(displacementByte) r.pc -= 2; + if(condition == 1) { + condition = 0; + //pushLong(r.pc); + } + if(testCondition(condition)) { + r.pc += displacementByte ? (int8_t)displacementByte : ((int16_t)displacementWord - 2); + } +} + +auto M68K::instructionNOP() -> void { +} + +auto M68K::instructionTST(uint2 size, uint3 rdMode, uint3 rdReg) -> void { + auto data = readEA(size, rdMode, rdReg); + + r.c = 0; + r.v = 0; + r.z = data == 0; + r.n = signExtend(size, data) < 0; +} diff --git a/higan/processor/m68k/m68k.cpp b/higan/processor/m68k/m68k.cpp index c170ae94..6829dd38 100644 --- a/higan/processor/m68k/m68k.cpp +++ b/higan/processor/m68k/m68k.cpp @@ -4,34 +4,10 @@ namespace Processor { #include "memory.cpp" - -auto M68K::instruction() -> void { - instructionsExecuted++; - - auto opcode = readWord(r.pc); - r.pc += 2; - - //nop - if(opcode == 0x4e71) { - step(5); - return; - } - - //bra disp - if((opcode & 0xff00) == 0x6000) { - int displacement = (int8)opcode; - if(!displacement) displacement = (int16)readWord(r.pc); - r.pc += displacement; - step(12); - return; - } - - instructionsExecuted--; - r.pc -= 2; - print("[M68K] unimplemented instruction: ", hex(r.pc, 6L), " = ", hex(opcode, 4L), "\n"); - print("[M68K] executed ", instructionsExecuted, " instructions\n"); - while(true) step(5); -} +#include "ea.cpp" +#include "instruction.cpp" +#include "instructions.cpp" +#include "disassembler.cpp" auto M68K::power() -> void { } @@ -39,10 +15,10 @@ auto M68K::power() -> void { auto M68K::reset() -> void { instructionsExecuted = 0; - for(auto& n : r.d) n = 0; - for(auto& n : r.a) n = 0; - r.pc = 0x000200; - r.ccr.value = 0; + r.d0 = r.d1 = r.d2 = r.d3 = r.d4 = r.d5 = r.d6 = r.d7 = 0; + r.a0 = r.a1 = r.a2 = r.a3 = r.a4 = r.a5 = r.a6 = r.usp = r.ssp = 0; + r.pc = 0; + r.ccr = 0; } } diff --git a/higan/processor/m68k/m68k.hpp b/higan/processor/m68k/m68k.hpp index 8fb2f87e..1b160b02 100644 --- a/higan/processor/m68k/m68k.hpp +++ b/higan/processor/m68k/m68k.hpp @@ -11,35 +11,53 @@ struct M68K { auto power() -> void; auto reset() -> void; - auto instruction() -> void; //memory.cpp auto readByte(uint32 addr) -> uint8; auto readWord(uint32 addr) -> uint16; auto readLong(uint32 addr) -> uint32; - auto readQuad(uint32 addr) -> uint64; + + auto readWordPC() -> uint16; + auto readLongPC() -> uint32; + + auto readAbsolute(uint2 size, uint32 addr) -> uint32; + + //ea.cpp + auto signExtend(uint2 size, uint32 data) -> int32; + auto readEA(uint2 size, uint3 mode, uint3 reg) -> uint32; + auto writeEA(uint2 size, uint3 mode, uint3 reg, uint32 data) -> void; + + //instruction.cpp + auto trap() -> void; + auto instruction() -> void; + + //instructions.cpp + auto testCondition(uint4 condition) -> bool; + auto instructionBCC(uint4 condition, uint8 displacementByte) -> void; + auto instructionNOP() -> void; + auto instructionTST(uint2 size, uint3 rdMode, uint3 rdReg) -> void; + + //disassembler.cpp + auto disassemble(uint32 pc) -> string; struct Registers { - //todo: this is almost certainly UB or IB due to alignment rules ... - union { - uint32_t d[8]; - struct { uint32_t d0, d1, d2, d3, d4, d5, d6, d7; }; - }; - union { - uint32_t a[8]; - struct { uint32_t a0, a1, a2, a3, a4, a5, a6; union { uint32_t a7, sp; }; }; - }; + uint32 d0, d1, d2, d3, d4, d5, d6, d7; + uint32 a0, a1, a2, a3, a4, a5, a6, usp, ssp; uint32 pc; - union CCR { - uint8_t value = 0; + + union { + uint8 ccr; BooleanBitField c; //carry BooleanBitField v; //overflow BooleanBitField z; //zero BooleanBitField n; //negative BooleanBitField x; //extend - } ccr; + }; + + Registers() : ccr(0) {} } r; + uint16 opcode = 0; uint instructionsExecuted = 0; }; diff --git a/higan/processor/m68k/memory.cpp b/higan/processor/m68k/memory.cpp index ff174f86..bd247a08 100644 --- a/higan/processor/m68k/memory.cpp +++ b/higan/processor/m68k/memory.cpp @@ -1,32 +1,37 @@ auto M68K::readByte(uint32 addr) -> uint8 { + step(4); return read(addr); } auto M68K::readWord(uint32 addr) -> uint16 { - uint16 data; - data |= read(addr + 0) << 8; - data |= read(addr + 1) << 0; - return data; + step(4); + uint16 data = read(addr + 0) << 8; + return data |= read(addr + 1) << 0; } auto M68K::readLong(uint32 addr) -> uint32 { - uint32 data; - data |= read(addr + 0) << 24; - data |= read(addr + 1) << 16; - data |= read(addr + 2) << 8; - data |= read(addr + 3) << 0; + uint32 data = readWord(addr + 0) << 16; + return data |= readWord(addr + 2) << 0; +} + +// + +auto M68K::readWordPC() -> uint16 { + uint16 data = readWord(r.pc); + r.pc += 2; return data; } -auto M68K::readQuad(uint32 addr) -> uint64 { - uint64 data; - data |= (uint64)read(addr + 0) << 56; - data |= (uint64)read(addr + 1) << 48; - data |= (uint64)read(addr + 2) << 40; - data |= (uint64)read(addr + 3) << 32; - data |= (uint64)read(addr + 4) << 24; - data |= (uint64)read(addr + 5) << 16; - data |= (uint64)read(addr + 6) << 8; - data |= (uint64)read(addr + 7) << 0; - return data; +auto M68K::readLongPC() -> uint32 { + uint32 data = readWordPC() << 16; + return data |= readWordPC() << 0; +} + +// + +auto M68K::readAbsolute(uint2 size, uint32 addr) -> uint32 { + if(size == 0) return readByte(addr); + if(size == 1) return readWord(addr); + if(size == 2) return readLong(addr); + return 0; }