diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index b4909108..23e16c8f 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 = "101.12"; + static const string Version = "101.13"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/md/apu/apu.cpp b/higan/md/apu/apu.cpp index 36210098..9bc68c89 100644 --- a/higan/md/apu/apu.cpp +++ b/higan/md/apu/apu.cpp @@ -30,6 +30,13 @@ auto APU::write(uint16 addr, uint8 data) -> void { step(1); } +auto APU::in(uint8 addr) -> uint8 { + return 0x00; +} + +auto APU::out(uint8 addr, uint8 data) -> void { +} + auto APU::power() -> void { } diff --git a/higan/md/apu/apu.hpp b/higan/md/apu/apu.hpp index 629bde82..f66c87c8 100644 --- a/higan/md/apu/apu.hpp +++ b/higan/md/apu/apu.hpp @@ -8,6 +8,8 @@ struct APU : Processor::Z80, Thread { auto wait() -> void override; auto read(uint16 addr) -> uint8 override; auto write(uint16 addr, uint8 data) -> void override; + auto in(uint8 addr) -> uint8 override; + auto out(uint8 addr, uint8 data) -> void override; auto power() -> void; auto reset() -> void; diff --git a/higan/md/controller/gamepad/gamepad.cpp b/higan/md/controller/gamepad/gamepad.cpp index 7a630b42..516dd613 100644 --- a/higan/md/controller/gamepad/gamepad.cpp +++ b/higan/md/controller/gamepad/gamepad.cpp @@ -7,6 +7,8 @@ auto Gamepad::readData() -> uint8 { if(select == 0) { data.bit(0) = interface->inputPoll(port, ID::Device::Gamepad, Up); data.bit(1) = interface->inputPoll(port, ID::Device::Gamepad, Down); + data.bit(2) = 1; + data.bit(3) = 1; data.bit(4) = interface->inputPoll(port, ID::Device::Gamepad, A); data.bit(5) = interface->inputPoll(port, ID::Device::Gamepad, Start); } else { diff --git a/higan/md/vdp/background.cpp b/higan/md/vdp/background.cpp index 42d71f95..8c683a41 100644 --- a/higan/md/vdp/background.cpp +++ b/higan/md/vdp/background.cpp @@ -1,27 +1,68 @@ -auto VDP::Background::scanline(uint y) -> void { +auto VDP::Background::isWindowed(uint x, uint y) -> bool { + if((x < io.horizontalOffset) ^ io.horizontalDirection) return true; + if((y < io.verticalOffset ) ^ io.verticalDirection ) return true; + return false; +} + +auto VDP::Background::updateHorizontalScroll(uint y) -> void { + if(id == ID::Window) return; + uint15 address = io.horizontalScrollAddress; static const uint mask[] = {0u, 7u, ~7u, ~0u}; address += (y & mask[io.horizontalScrollMode]) << 1; - address += (this == &vdp.planeB); + address += id == ID::PlaneB; state.horizontalScroll = vdp.vram[address].bits(0,9); } +auto VDP::Background::updateVerticalScroll(uint x, uint y) -> void { + if(id == ID::Window) return; + + auto address = (x >> 4 & 0 - io.verticalScrollMode) << 1; + address += id == ID::PlaneB; + + state.verticalScroll = vdp.vsram[address]; +} + +auto VDP::Background::nametableAddress() -> uint15 { + if(id == ID::Window && vdp.screenWidth() == 320) return io.nametableAddress & ~0x0400; + return io.nametableAddress; +} + +auto VDP::Background::nametableWidth() -> uint { + if(id == ID::Window) return vdp.screenWidth() == 320 ? 64 : 32; + return 32 * (1 + io.nametableWidth); +} + +auto VDP::Background::nametableHeight() -> uint { + if(id == ID::Window) return 32; + return 32 * (1 + io.nametableHeight); +} + +auto VDP::Background::scanline(uint y) -> void { + updateHorizontalScroll(y); +} + auto VDP::Background::run(uint x, uint y) -> void { + updateVerticalScroll(x, y); + output.priority = 0; output.color = 0; - static const uint tiles[] = {32, 64, 96, 128}; - y += vdp.vsram[((x >> 4) & (io.verticalScrollMode ? ~0u : 0u)) * 2 + (this == &vdp.planeB)]; x -= state.horizontalScroll; + y += state.verticalScroll; - uint tileX = x >> 3 & (tiles[io.nametableWidth ] - 1); - uint tileY = y >> 3 & (tiles[io.nametableHeight] - 1); - uint15 nametableAddress = io.nametableAddress; - nametableAddress += (tileY * tiles[io.nametableWidth] + tileX) & 0x0fff; + uint width = nametableWidth(); + uint height = nametableHeight(); - uint16 tileAttributes = vdp.vram[nametableAddress]; + uint tileX = x >> 3 & width - 1; + uint tileY = y >> 3 & height - 1; + + auto address = nametableAddress(); + address += (tileY * width + tileX) & 0x0fff; + + uint16 tileAttributes = vdp.vram[address]; uint15 tileAddress = tileAttributes.bits(0,10) << 4; uint pixelX = (x & 7) ^ (tileAttributes.bit(11) ? 7 : 0); uint pixelY = (y & 7) ^ (tileAttributes.bit(12) ? 7 : 0); diff --git a/higan/md/vdp/io.cpp b/higan/md/vdp/io.cpp index fd185192..66932ddc 100644 --- a/higan/md/vdp/io.cpp +++ b/higan/md/vdp/io.cpp @@ -217,10 +217,8 @@ auto VDP::writeControlPort(uint16 data) -> void { //mode register 3 case 0x0b: { planeA.io.horizontalScrollMode = data.bits(0,1); - window.io.horizontalScrollMode = data.bits(0,1); planeB.io.horizontalScrollMode = data.bits(0,1); planeA.io.verticalScrollMode = data.bit(2); - window.io.verticalScrollMode = data.bit(2); planeB.io.verticalScrollMode = data.bit(2); io.externalInterruptEnable = data.bit(3); return; @@ -240,7 +238,6 @@ auto VDP::writeControlPort(uint16 data) -> void { //horizontal scroll data location case 0x0d: { planeA.io.horizontalScrollAddress = data.bits(0,6) << 9; - window.io.horizontalScrollAddress = data.bits(0,6) << 9; planeB.io.horizontalScrollAddress = data.bits(0,6) << 9; return; } @@ -261,47 +258,23 @@ auto VDP::writeControlPort(uint16 data) -> void { //plane size case 0x10: { planeA.io.nametableWidth = data.bits(0,1); - window.io.nametableWidth = data.bits(0,1); planeB.io.nametableWidth = data.bits(0,1); planeA.io.nametableHeight = data.bits(4,5); - window.io.nametableHeight = data.bits(4,5); planeB.io.nametableHeight = data.bits(4,5); return; } //window plane horizontal position case 0x11: { - if(!data) { - //disable - io.windowHorizontalLo = ~0; - io.windowHorizontalHi = ~0; - } else if(data.bit(7) == 0) { - //left - io.windowHorizontalLo = 0; - io.windowHorizontalHi = (data.bits(0,4) << 4) - 1; - } else { - //right - io.windowHorizontalLo = (data.bits(0,4) << 4) - 1; - io.windowHorizontalHi = ~0; - } + window.io.horizontalDirection = data.bit(7); + window.io.horizontalOffset = data.bits(0,4) << 4; return; } //window plane vertical position case 0x12: { - if(!data) { - //disable - io.windowVerticalLo = ~0; - io.windowVerticalHi = ~0; - } else if(data.bit(7) == 0) { - //up - io.windowVerticalLo = 0; - io.windowVerticalHi = (data.bits(0,4) << 3) - 1; - } else { - //down - io.windowVerticalLo = (data.bits(0,4) << 3) - 1; - io.windowVerticalHi = ~0; - } + window.io.verticalDirection = data.bit(7); + window.io.verticalOffset = data.bits(0,4) << 3; return; } diff --git a/higan/md/vdp/render.cpp b/higan/md/vdp/render.cpp index 761ba9ab..ea456bb0 100644 --- a/higan/md/vdp/render.cpp +++ b/higan/md/vdp/render.cpp @@ -18,11 +18,7 @@ auto VDP::run() -> void { if(!io.displayEnable) return outputPixel(0); if(state.y >= screenHeight()) return outputPixel(0); - bool windowed = false; //todo: broken - windowed &= state.x >= io.windowHorizontalLo && state.x <= io.windowHorizontalHi; - windowed &= state.y >= io.windowVerticalLo && state.y <= io.windowVerticalHi; - auto& planeA = windowed ? this->window : this->planeA; - + auto& planeA = window.isWindowed(state.x, state.y) ? window : this->planeA; planeA.run(state.x, state.y); planeB.run(state.x, state.y); sprite.run(state.x, state.y); diff --git a/higan/md/vdp/vdp.hpp b/higan/md/vdp/vdp.hpp index bb9d6cfe..8eb1ec33 100644 --- a/higan/md/vdp/vdp.hpp +++ b/higan/md/vdp/vdp.hpp @@ -32,6 +32,17 @@ struct VDP : Thread { //background.cpp struct Background { + enum class ID : uint { PlaneA, Window, PlaneB } id; + + auto isWindowed(uint x, uint y) -> bool; + + auto updateHorizontalScroll(uint y) -> void; + auto updateVerticalScroll(uint x, uint y) -> void; + + auto nametableAddress() -> uint15; + auto nametableWidth() -> uint; + auto nametableHeight() -> uint; + auto scanline(uint y) -> void; auto run(uint x, uint y) -> void; @@ -40,15 +51,24 @@ struct VDP : Thread { struct IO { uint15 nametableAddress; + + //PlaneA, PlaneB uint2 nametableWidth; uint2 nametableHeight; uint15 horizontalScrollAddress; uint2 horizontalScrollMode; uint1 verticalScrollMode; + + //Window + uint1 horizontalDirection; + uint10 horizontalOffset; + uint1 verticalDirection; + uint10 verticalOffset; } io; struct State { uint10 horizontalScroll; + uint10 verticalScroll; } state; struct Output { @@ -56,9 +76,9 @@ struct VDP : Thread { boolean priority; } output; }; - Background planeA; - Background window; - Background planeB; + Background planeA{Background::ID::PlaneA}; + Background window{Background::ID::Window}; + Background planeB{Background::ID::PlaneB}; //sprite.cpp struct Sprite { @@ -154,14 +174,6 @@ private: //$0f data port auto-increment value uint8 dataIncrement; - //$11 window plane horizontal position - uint10 windowHorizontalLo; - uint10 windowHorizontalHi; - - //$12 window plane vertical position - uint10 windowVerticalLo; - uint10 windowVerticalHi; - //$13-$14 DMA length uint16 dmaLength; diff --git a/higan/ms/GNUmakefile b/higan/ms/GNUmakefile index 21a36e0f..4ee4a384 100644 --- a/higan/ms/GNUmakefile +++ b/higan/ms/GNUmakefile @@ -2,7 +2,7 @@ processors += z80 objects += ms-interface objects += ms-cpu ms-vdp ms-psg -objects += ms-system ms-cartridge +objects += ms-system ms-cartridge ms-bus obj/ms-interface.o: ms/interface/interface.cpp $(call rwildcard,ms/interface) obj/ms-cpu.o: ms/cpu/cpu.cpp $(call rwildcard,ms/cpu) @@ -10,3 +10,4 @@ obj/ms-vdp.o: ms/vdp/vdp.cpp $(call rwildcard,ms/vdp) obj/ms-psg.o: ms/psg/psg.cpp $(call rwildcard,ms/psg) obj/ms-system.o: ms/system/system.cpp $(call rwildcard,ms/system) obj/ms-cartridge.o: ms/cartridge/cartridge.cpp $(call rwildcard,ms/cartridge) +obj/ms-bus.o: ms/bus/bus.cpp $(call rwildcard,ms/bus) diff --git a/higan/ms/bus/bus.cpp b/higan/ms/bus/bus.cpp new file mode 100644 index 00000000..2ff3c580 --- /dev/null +++ b/higan/ms/bus/bus.cpp @@ -0,0 +1,28 @@ +#include + +namespace MasterSystem { + +Bus bus; + +auto Bus::read(uint16 addr) -> uint8 { + if(addr < 0xc000) return cartridge.read(addr); + return ram[addr & 0x1fff]; +} + +auto Bus::write(uint16 addr, uint8 data) -> void { + if(addr < 0xc000) return cartridge.write(addr, data); + ram[addr & 0x1fff] = data; +} + +auto Bus::in(uint8 addr) -> uint8 { + switch(addr) { + case 0x7e: return vdp.in(addr); + case 0x7f: return vdp.in(addr); + } + return 0x00; +} + +auto Bus::out(uint8 addr, uint8 data) -> void { +} + +} diff --git a/higan/ms/bus/bus.hpp b/higan/ms/bus/bus.hpp new file mode 100644 index 00000000..268d2279 --- /dev/null +++ b/higan/ms/bus/bus.hpp @@ -0,0 +1,12 @@ +struct Bus { + auto read(uint16 addr) -> uint8; + auto write(uint16 addr, uint8 data) -> void; + + auto in(uint8 addr) -> uint8; + auto out(uint8 addr, uint8 data) -> void; + +private: + uint8 ram[0x2000]; +}; + +extern Bus bus; diff --git a/higan/ms/cpu/cpu.cpp b/higan/ms/cpu/cpu.cpp index e0ecf92f..ee8f5dda 100644 --- a/higan/ms/cpu/cpu.cpp +++ b/higan/ms/cpu/cpu.cpp @@ -24,14 +24,22 @@ auto CPU::wait() -> void { auto CPU::read(uint16 addr) -> uint8 { step(1); - if(addr < 0xc000) return cartridge.read(addr); - return ram[addr & 0x1fff]; + return bus.read(addr); } auto CPU::write(uint16 addr, uint8 data) -> void { step(1); - if(addr < 0xc000) return cartridge.write(addr, data); - ram[addr & 0x1fff] = data; + return bus.write(addr, data); +} + +auto CPU::in(uint8 addr) -> uint8 { + step(1); + return bus.in(addr); +} + +auto CPU::out(uint8 addr, uint8 data) -> void { + step(1); + return bus.out(addr, data); } auto CPU::power() -> void { diff --git a/higan/ms/cpu/cpu.hpp b/higan/ms/cpu/cpu.hpp index bcdff0d6..9f873e36 100644 --- a/higan/ms/cpu/cpu.hpp +++ b/higan/ms/cpu/cpu.hpp @@ -8,12 +8,11 @@ struct CPU : Processor::Z80, Thread { auto wait() -> void override; auto read(uint16 addr) -> uint8 override; auto write(uint16 addr, uint8 data) -> void override; + auto in(uint8 addr) -> uint8 override; + auto out(uint8 addr, uint8 data) -> void override; auto power() -> void; auto reset() -> void; - -private: - uint8 ram[0x2000]; //8KB }; extern CPU cpu; diff --git a/higan/ms/ms.hpp b/higan/ms/ms.hpp index 4dc63286..471ade7d 100644 --- a/higan/ms/ms.hpp +++ b/higan/ms/ms.hpp @@ -36,6 +36,7 @@ namespace MasterSystem { #include #include + #include } #include diff --git a/higan/ms/vdp/vdp.cpp b/higan/ms/vdp/vdp.cpp index da0f6f61..a8998375 100644 --- a/higan/ms/vdp/vdp.cpp +++ b/higan/ms/vdp/vdp.cpp @@ -26,6 +26,18 @@ auto VDP::refresh() -> void { Emulator::video.refresh(buffer, 256 * sizeof(uint32), 256, 240); } +auto VDP::in(uint8 addr) -> uint8 { + switch(addr) { + } + + return 0xb0; +} + +auto VDP::out(uint8 addr, uint8 data) -> void { + switch(addr) { + } +} + auto VDP::power() -> void { } diff --git a/higan/ms/vdp/vdp.hpp b/higan/ms/vdp/vdp.hpp index 2a84de45..b0fb8fea 100644 --- a/higan/ms/vdp/vdp.hpp +++ b/higan/ms/vdp/vdp.hpp @@ -6,6 +6,9 @@ struct VDP : Thread { auto step(uint clocks) -> void; auto refresh() -> void; + auto in(uint8 addr) -> uint8; + auto out(uint8 addr, uint8 data) -> void; + auto power() -> void; auto reset() -> void; diff --git a/higan/processor/z80/disassembler.cpp b/higan/processor/z80/disassembler.cpp new file mode 100644 index 00000000..8b3b1848 --- /dev/null +++ b/higan/processor/z80/disassembler.cpp @@ -0,0 +1,120 @@ +auto Z80::disassemble(uint16 pc) -> string { + string output{hex(pc, 4L), " "}; + + output.append(pad(disassembleOpcode(pc), -18, ' ')); + + output.append( + " AF:", hex(r.af, 4L), + " BC:", hex(r.bc, 4L), + " DE:", hex(r.de, 4L), + " HL:", hex(r.hl, 4L), + " IX:", hex(r.ix, 4L), + " IY:", hex(r.iy, 4L), + " SP:", hex(r.sp, 4L) + ); + + return output; +} + +#define X hex(x, 2L) +#define Y hex(y, 2L) +#define Z hex(z, 2L) +#define W hex(y << 8 | x << 0, 4L) +#define R hex(pc + 2 + (int8)x, 4L) + +auto Z80::disassembleOpcode(uint16 pc) -> string { + auto o = read(pc + 0); + auto x = read(pc + 1); + auto y = read(pc + 2); + auto z = read(pc + 3); + + switch(o) { + case 0x00: return {"nop "}; + case 0x18: return {"jr $", R}; + case 0x20: return {"jr nz,$", R}; + case 0x28: return {"jr z,$", R}; + case 0x30: return {"jr nc,$", R}; + case 0x38: return {"jr c,$", R}; + case 0xb8: return {"cp b"}; + case 0xb9: return {"cp c"}; + case 0xba: return {"cp d"}; + case 0xbb: return {"cp e"}; + case 0xbc: return {"cp h"}; + case 0xbd: return {"cp l"}; + case 0xbe: return {"cp (hl)"}; + case 0xbf: return {"cp a"}; + case 0xc2: return {"jp nz,$", W}; + case 0xc3: return {"jp $", W}; + case 0xca: return {"jp z,$", W}; + case 0xd2: return {"jp nc,$", W}; + case 0xda: return {"jp c,$", W}; + case 0xdb: return {"in a,($", X, ")"}; + case 0xdd: return disassembleOpcodeDD(pc + 1); + case 0xe2: return {"jp po,$", W}; + case 0xe9: return {"jp hl"}; + case 0xea: return {"jp pe,$", W}; + case 0xed: return disassembleOpcodeED(pc + 1); + case 0xf2: return {"jp p,$", W}; + case 0xf3: return {"di "}; + case 0xfa: return {"jp m,$", W}; + case 0xfd: return disassembleOpcodeFD(pc + 1); + case 0xfe: return {"cp $", X}; + } + + return {"??? (", hex(o, 2L), " ", X, " ", Y, " ", Z, ")"}; +} + +auto Z80::disassembleOpcodeDD(uint16 pc) -> string { + auto o = read(pc + 0); + auto x = read(pc + 1); + auto y = read(pc + 2); + auto z = read(pc + 3); + + switch(o) { + case 0xe9: return {"jp ix"}; + } + + return {"??? (dd ", hex(o, 2L), " ", X, " ", Y, ")"}; +} + +auto Z80::disassembleOpcodeED(uint16 pc) -> string { + auto o = read(pc + 0); + auto x = read(pc + 1); + auto y = read(pc + 2); + auto z = read(pc + 3); + + switch(o) { + case 0x40: return {"in b,(c)"}; + case 0x46: return {"im 0"}; + case 0x48: return {"in c,(c)"}; + case 0x50: return {"in d,(c)"}; + case 0x56: return {"im 1"}; + case 0x58: return {"in e,(c)"}; + case 0x5e: return {"im 2"}; + case 0x60: return {"in h,(c)"}; + case 0x68: return {"in l,(c)"}; + case 0x70: return {"in (c)"}; + case 0x78: return {"in a,(c)"}; + } + + return {"??? (ed ", hex(o, 2L), " ", X, " ", Y, ")"}; +} + +auto Z80::disassembleOpcodeFD(uint16 pc) -> string { + auto o = read(pc + 0); + auto x = read(pc + 1); + auto y = read(pc + 2); + auto z = read(pc + 3); + + switch(o) { + case 0xe9: return {"jp iy"}; + } + + return {"??? (fd ", hex(o, 2L), " ", X, " ", Y, ")"}; +} + +#undef X +#undef Y +#undef Z +#undef W +#undef R diff --git a/higan/processor/z80/instruction.cpp b/higan/processor/z80/instruction.cpp index 594bc8a7..e2548419 100644 --- a/higan/processor/z80/instruction.cpp +++ b/higan/processor/z80/instruction.cpp @@ -1,6 +1,17 @@ +auto Z80::trap(uint8_t prefix, uint8_t opcode) -> void { + print("[Z80] unimplemented instruction: ", prefix ? pad(hex(prefix, 2L), ' ', -3) : "", hex(opcode, 2L), "\n"); + print("[Z80] instructions executed: ", --instructionsExecuted, "\n"); + while(true) wait(); +} + #define op(id, name, ...) case id: return instruction##name(__VA_ARGS__); auto Z80::instruction() -> void { + #if 1 + if(instructionsExecuted < 20) + print(disassemble(r.pc), "\n"); + #endif + instructionsExecuted++; r.r = (r.r & 0x80) | (r.r + 1 & 0x7f); @@ -8,12 +19,71 @@ auto Z80::instruction() -> void { auto opcode = read(r.pc++); switch(opcode) { op(0x00, NOP) + op(0x18, JR_c, true) + op(0x20, JR_c, r.p.z == 0) + op(0x28, JR_c, r.p.z == 1) + op(0x30, JR_c, r.p.c == 0) + op(0x38, JR_c, r.p.c == 1) + op(0xb8, CP_r, r.b) + op(0xb9, CP_r, r.c) + op(0xba, CP_r, r.d) + op(0xbb, CP_r, r.e) + op(0xbc, CP_r, r.h) + op(0xbd, CP_r, r.l) + op(0xbe, CP_ihl) + op(0xbf, CP_r, r.a) + op(0xc2, JP_c_nn, r.p.z == 0) + op(0xc3, JP_c_nn, true) + op(0xca, JP_c_nn, r.p.z == 1) + op(0xd2, JP_c_nn, r.p.c == 0) + op(0xda, JP_c_nn, r.p.c == 1) + op(0xdb, IN_a_in) + op(0xdd, DD) + op(0xe2, JP_c_nn, r.p.p == 0) + op(0xe9, JP_rr, r.hl) + op(0xea, JP_c_nn, r.p.p == 1) + op(0xed, ED) + op(0xf2, JP_c_nn, r.p.s == 0) op(0xf3, DI) + op(0xfa, JP_c_nn, r.p.s == 1) + op(0xfd, FD) + op(0xfe, CP_n) } + trap(0x00, opcode); +} - print("[Z80] unimplemented instruction: ", hex(opcode, 2L), "\n"); - print("[Z80] instructions executed: ", --instructionsExecuted, "\n"); - while(true) wait(); +auto Z80::instructionDD() -> void { + auto opcode = read(r.pc++); + switch(opcode) { + op(0xe9, JP_rr, r.ix) + } + trap(0xdd, opcode); +} + +auto Z80::instructionED() -> void { + auto opcode = read(r.pc++); + switch(opcode) { + op(0x40, IN_r_ic, r.b) + op(0x46, IM, 0) + op(0x48, IN_r_ic, r.c) + op(0x50, IN_r_ic, r.d) + op(0x56, IM, 1) + op(0x58, IN_r_ic, r.e) + op(0x5e, IM, 2) + op(0x60, IN_r_ic, r.h) + op(0x68, IN_r_ic, r.l) + op(0x70, IN_r_ic, r.flag) + op(0x78, IN_r_ic, r.a) + } + trap(0xed, opcode); +} + +auto Z80::instructionFD() -> void { + auto opcode = read(r.pc++); + switch(opcode) { + op(0xe9, JP_rr, r.iy) + } + trap(0xfd, opcode); } #undef op diff --git a/higan/processor/z80/instructions.cpp b/higan/processor/z80/instructions.cpp index 7260a18a..63bd156d 100644 --- a/higan/processor/z80/instructions.cpp +++ b/higan/processor/z80/instructions.cpp @@ -1,4 +1,60 @@ +auto Z80::CP(uint8 x) -> void { + uint16 y = r.a - x; + + r.p.c = y > 0xff; + r.p.n = 1; + r.p.v = (r.a ^ x) & (r.a ^ y) & 0x80; + r.p.h = (r.a ^ y ^ x) & 0x10; + r.p.z = y == 0; + r.p.s = y & 0x80; +} + +auto Z80::instructionCP_ihl() -> void { + CP(read(r.hl)); +} + +auto Z80::instructionCP_n() -> void { + CP(read(r.pc++)); +} + +auto Z80::instructionCP_r(uint8_t& x) -> void { + CP(x); +} + auto Z80::instructionDI() -> void { + r.di = 1; +} + +auto Z80::instructionIM(uint mode) -> void { + r.im = mode; +} + +auto Z80::instructionIN_a_in() -> void { + r.a = in(read(r.pc++)); +} + +auto Z80::instructionIN_r_ic(uint8_t& x) -> void { + x = in(read(r.c)); + r.p.n = 0; + r.p.p = parity(x); + r.p.h = 0; + r.p.z = x == 0; + r.p.s = x & 0x80; +} + +auto Z80::instructionJP_c_nn(bool c) -> void { + auto lo = read(r.pc++); + auto hi = read(r.pc++); + if(c) r.pc = hi << 8 | lo << 0; +} + +auto Z80::instructionJP_rr(uint16_t& x) -> void { + r.pc = x; +} + +auto Z80::instructionJR_c(bool c) -> void { + auto d = read(r.pc++); + if(c) r.pc += (int8)d; } auto Z80::instructionNOP() -> void { diff --git a/higan/processor/z80/z80.cpp b/higan/processor/z80/z80.cpp index 32ff12be..2604195e 100644 --- a/higan/processor/z80/z80.cpp +++ b/higan/processor/z80/z80.cpp @@ -5,6 +5,7 @@ namespace Processor { #include "instruction.cpp" #include "instructions.cpp" +#include "disassembler.cpp" auto Z80::power() -> void { } @@ -20,6 +21,17 @@ auto Z80::reset() -> void { r.pc = 0x0000; r.i = 0x00; r.r = 0x00; + + r.di = false; + r.ei = false; + r.im = 0; +} + +auto Z80::parity(uint8_t value) const -> bool { + value ^= value >> 4; + value ^= value >> 2; + value ^= value >> 1; + return !(value & 1); } } diff --git a/higan/processor/z80/z80.hpp b/higan/processor/z80/z80.hpp index 08243506..a15a6a20 100644 --- a/higan/processor/z80/z80.hpp +++ b/higan/processor/z80/z80.hpp @@ -8,31 +8,57 @@ struct Z80 { virtual auto wait() -> void = 0; virtual auto read(uint16 addr) -> uint8 = 0; virtual auto write(uint16 addr, uint8 data) -> void = 0; + virtual auto in(uint8 addr) -> uint8 = 0; + virtual auto out(uint8 addr, uint8 data) -> void = 0; //z80.cpp auto power() -> void; auto reset() -> void; + auto parity(uint8_t) const -> bool; + //instruction.cpp + auto trap(uint8_t prefix, uint8_t opcode) -> void; auto instruction() -> void; + auto instructionDD() -> void; + auto instructionED() -> void; + auto instructionFD() -> void; //instructions.cpp + auto CP(uint8 x) -> void; + auto instructionCP_ihl() -> void; + auto instructionCP_n() -> void; + auto instructionCP_r(uint8_t&) -> void; auto instructionDI() -> void; + auto instructionIM(uint) -> void; + auto instructionIN_a_in() -> void; + auto instructionIN_r_ic(uint8_t&) -> void; + auto instructionJP_c_nn(bool) -> void; + auto instructionJP_rr(uint16_t&) -> void; + auto instructionJR_c(bool) -> void; auto instructionNOP() -> void; + //disassembler.cpp + auto disassemble(uint16 pc) -> string; + auto disassembleOpcode(uint16 pc) -> string; + auto disassembleOpcodeDD(uint16 pc) -> string; + auto disassembleOpcodeED(uint16 pc) -> string; + auto disassembleOpcodeFD(uint16 pc) -> string; + struct Registers { union { uint16_t af; struct { uint8_t order_msb2(a, f); }; union { BooleanBitField c; //carry - BooleanBitField s; //subtract + BooleanBitField n; //add / subtract + BooleanBitField p; //parity BooleanBitField v; //overflow - //BooleanBitField _; //unused (copy of bit 3 of result) + BooleanBitField x; //unused (copy of bit 3 of result) BooleanBitField h; //half-carry - //BooleanBitField _; //unused (copy of bit 5 of result) + BooleanBitField y; //unused (copy of bit 5 of result) BooleanBitField z; //zero - BooleanBitField n; //negative + BooleanBitField s; //sign } p; }; @@ -58,6 +84,12 @@ struct Z80 { uint8_t i; uint8_t r; + + boolean di; //disable interrupt + boolean ei; //enable interrupt + uint2 im; //interrupt mode (0-2) + + uint8_t flag; } r; private: