From 1c0ef793fea25a70212313ac1d744be4c80ad89b Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Tue, 12 Jul 2016 20:19:31 +1000 Subject: [PATCH] Update to v100r04 release. byuu says: I now have enough of three instructions implemented to get through the first four instructions in Sonic the Hedgehog. But they're far from complete. The very first instruction uses EA addressing, which is similar to x86's ModRM in terms of how disgustingly complex it is. And it also accesses Z80 control registers, which obviously isn't going to do anything yet. The slow speed was me being stupid again. It's not 7.6MHz per frame, it's 7.67MHz per second. So yeah, speed is so far acceptable again. But we'll see how things go as I keep emulating more. The 68K decode is not pretty at all. --- higan/emulator/emulator.hpp | 2 +- higan/md/cpu/cpu.cpp | 8 +-- higan/md/interface/interface.cpp | 4 +- higan/md/system/system.cpp | 4 +- higan/processor/m68k/disassembler.cpp | 96 +++++++++++++++++++++++++++ higan/processor/m68k/ea.cpp | 25 +++++++ higan/processor/m68k/instruction.cpp | 34 ++++++++++ higan/processor/m68k/instructions.cpp | 47 +++++++++++++ higan/processor/m68k/m68k.cpp | 40 +++-------- higan/processor/m68k/m68k.hpp | 46 +++++++++---- higan/processor/m68k/memory.cpp | 45 +++++++------ 11 files changed, 276 insertions(+), 75 deletions(-) create mode 100644 higan/processor/m68k/disassembler.cpp create mode 100644 higan/processor/m68k/ea.cpp create mode 100644 higan/processor/m68k/instruction.cpp create mode 100644 higan/processor/m68k/instructions.cpp 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; }