From df58bb40d33741f631da5fd07ee55d328bd792a8 Mon Sep 17 00:00:00 2001 From: yangkui <752544765@qq.com> Date: Thu, 7 Dec 2023 22:41:49 +0800 Subject: [PATCH] :boom: Improve code quality --- .../nes4j/app/control/CPUControlPane.java | 2 +- .../java/cn/navclub/nes4j/bin/NesConsole.java | 40 +++++----------- .../java/cn/navclub/nes4j/bin/core/CPU.java | 19 ++++---- .../cn/navclub/nes4j/bin/core/Mapper.java | 9 +--- .../nes4j/bin/core/MemoryBusAdapter.java | 46 +++++++++---------- .../nes4j/bin/core/impl/MMC3Mapper.java | 23 +++++++++- .../java/cn/navclub/nes4j/bin/ppu/PPU.java | 41 +++++++++-------- .../nes4j/bin/ppu/register/PPUControl.java | 15 +++--- .../cn/navclub/nes4j/bin/util/BinUtil.java | 6 ++- 9 files changed, 98 insertions(+), 103 deletions(-) diff --git a/app/src/main/java/cn/navclub/nes4j/app/control/CPUControlPane.java b/app/src/main/java/cn/navclub/nes4j/app/control/CPUControlPane.java index fd75ee3..95ec6c4 100644 --- a/app/src/main/java/cn/navclub/nes4j/app/control/CPUControlPane.java +++ b/app/src/main/java/cn/navclub/nes4j/app/control/CPUControlPane.java @@ -127,9 +127,9 @@ public void update(NesConsole console) { this.x.setText(Integer.toHexString(cpu.getRx())); this.y.setText(Integer.toHexString(cpu.getRy())); this.a.setText(Integer.toHexString(cpu.getRa())); + this.cycles.setText(String.format("%d", cpu.getCycles())); this.instructions.setText(Long.toString(cpu.getInstructions())); this.stackFlag.setText("Stack:$%s".formatted(Integer.toHexString(cpu.getSp()))); - this.cycles.setText(String.format("%d(+%d)", console.getCycles(), console.getDcycle())); var length = 0xff - cpu.getSp(); if (length > 0) { diff --git a/bin/src/main/java/cn/navclub/nes4j/bin/NesConsole.java b/bin/src/main/java/cn/navclub/nes4j/bin/NesConsole.java index 8dd788a..359516a 100644 --- a/bin/src/main/java/cn/navclub/nes4j/bin/NesConsole.java +++ b/bin/src/main/java/cn/navclub/nes4j/bin/NesConsole.java @@ -37,14 +37,10 @@ public class NesConsole { private int tfps; //cpu stall cycle private int stall; - // @Getter -// private int speed; //APU mute @Setter @Getter private boolean mute; - private long cycles; - private long dcycle; private Debugger debugger; private long lastFrameTime; private volatile boolean stop; @@ -88,27 +84,16 @@ public void execute() { while ((interrupt = queue.poll()) != null) { this.stall += this.cpu.NMI_IRQ_BRKInterrupt(interrupt); } - this.execute0(); - } - } - - private void execute0() { - var tmp = this.stall; - if (tmp == 0) { + var tmp = this.stall; + this.stall = 0; + while (tmp-- > 0) { + this.APU_PPuSync(); + } //Test line number has break point and block game loop if (this.debugger != null && this.debugger.hack(this)) { LockSupport.park(); - this.dcycle = 0; } - tmp = this.cpu.next(); - this.cycles += this.cpu.getCycle(); - this.dcycle += this.cpu.getCycle(); - } else { - this.stall = 0; - } - while (--tmp >= 0) { - this.apu.tick(); - this.ppu.tick(); + this.cpu.next(); } } @@ -142,8 +127,6 @@ private void reset() { this.fps = 0; this.tfps = 0; this.stall = 0; - this.dcycle = 0; - this.cycles = 0; this.apu.reset(); this.ppu.reset(); this.cpu.reset(); @@ -182,7 +165,6 @@ public void videoOutput(long nano, boolean renderEnable, Frame frame) { public void setStall(int span) { this.stall += span; - this.dcycle += span; } @@ -204,15 +186,15 @@ public synchronized void release() { LockSupport.unpark(this.thread); } - - public NMapper cartridgeMapper() { - return this.getCartridge().getMapper(); - } - public int TVFps() { return this.cartridge.getTv() == TV.NTSC ? 60 : 50; } + public void APU_PPuSync() { + this.apu.tick(); + this.ppu.tick(); + } + public static class Builder { private File file; diff --git a/bin/src/main/java/cn/navclub/nes4j/bin/core/CPU.java b/bin/src/main/java/cn/navclub/nes4j/bin/core/CPU.java index 1a48a99..ef92bc3 100644 --- a/bin/src/main/java/cn/navclub/nes4j/bin/core/CPU.java +++ b/bin/src/main/java/cn/navclub/nes4j/bin/core/CPU.java @@ -84,9 +84,6 @@ public class CPU { @Getter //Stack pointer private int sp; - @Getter - //Record single instruction consumer cycle - private int cycle; //Record game execute instruction number @Getter private long instructions; @@ -590,14 +587,14 @@ public byte getStatus() { return status.getBits(); } - public int next() { + public void next() { var openCode = this.bus.directRead(this.pc); var state = (++this.pc); var wrap = MWS6502.get(openCode); if (wrap == null) { logger.warning("Unknown opecode 0x{} in address 0x{}", Integer.toHexString(uint8(openCode)), Integer.toHexString(state - 1)); - return 0; + return; } var mode = wrap.addrMode(); var instruction = wrap.instruction(); @@ -620,8 +617,6 @@ public int next() { ); } - this.bus.reset(); - switch (instruction) { case RTI -> this.RTImpl(); case JSR -> this.JSRImpl(); @@ -672,6 +667,9 @@ public int next() { case CLC, CLD, CLI, CLV -> this.CLC_D_I_VImpl(instruction); } + this.instructions++; + this.bus._finally(wrap); + // // Judge whether it is necessary to change the value of the program counter according to whether the // redirection occurs @@ -679,11 +677,10 @@ public int next() { if (this.pc == state) { this.pc += (wrap.size() - 1); } + } - this.instructions++; - this.cycle = wrap.cycle() + this.bus.getBulking(); - - return wrap.cycle() + this.bus.calOffset(); + public long getCycles() { + return this.bus.getCycles(); } public static WS6502 IS6502Get(byte openCode) { diff --git a/bin/src/main/java/cn/navclub/nes4j/bin/core/Mapper.java b/bin/src/main/java/cn/navclub/nes4j/bin/core/Mapper.java index 8d8ffbe..cf5319f 100644 --- a/bin/src/main/java/cn/navclub/nes4j/bin/core/Mapper.java +++ b/bin/src/main/java/cn/navclub/nes4j/bin/core/Mapper.java @@ -96,18 +96,11 @@ public final int chrSize() { return this.cartridge.getChSize(); } - public final byte[] getRgbrom() { - return this.cartridge.getRgbrom(); - } - public final byte[] getChrom() { return this.cartridge.getChrom(); } - /** - * Some mapper implement need use extern {@link Component} cycle driver - */ - public void tick() { + public void PPUVideoAddrState(int addr) { } } diff --git a/bin/src/main/java/cn/navclub/nes4j/bin/core/MemoryBusAdapter.java b/bin/src/main/java/cn/navclub/nes4j/bin/core/MemoryBusAdapter.java index d2a3ed9..571ece4 100644 --- a/bin/src/main/java/cn/navclub/nes4j/bin/core/MemoryBusAdapter.java +++ b/bin/src/main/java/cn/navclub/nes4j/bin/core/MemoryBusAdapter.java @@ -2,6 +2,7 @@ import cn.navclub.nes4j.bin.NesConsole; import cn.navclub.nes4j.bin.config.AddressMode; +import cn.navclub.nes4j.bin.config.WS6502; import lombok.Getter; @@ -14,17 +15,16 @@ * @author GZYangKui */ public class MemoryBusAdapter implements Bus { + @Getter + private long cycles; private final CPU cpu; + private int variation; private final MemoryBus bus; private final NesConsole console; - //Page cross product extra cycle - @Getter - private int bulking; - //Sync system other component consumer cycle - private int decrement; public MemoryBusAdapter(CPU cpu, NesConsole console) { this.cpu = cpu; + this.cycles = 0; this.console = console; this.bus = console.getBus(); } @@ -90,56 +90,54 @@ public void pageCross(int base, int addr) { @Override public void WriteU8(int address, int value) { - this.APU_PPUSync(); + this.SyncOtherComponent(); this.bus.WriteU8(address, value); } @Override public int ReadU8(int address) { - this.APU_PPUSync(); + this.SyncOtherComponent(); return this.bus.ReadU8(address); } @Override public byte read(int address) { - this.APU_PPUSync(); + this.SyncOtherComponent(); return this.bus.read(address); } @Override public void write(int address, byte value) { - this.APU_PPUSync(); + this.SyncOtherComponent(); this.bus.write(address, value); } public void increment() { - this.bulking++; - this.APU_PPUSync(); + this.variation++; + this.SyncOtherComponent(); } @Override public int readInt(int address) { - this.APU_PPUSync(); + this.SyncOtherComponent(); return this.bus.readInt(address); } - private void APU_PPUSync() { - this.decrement--; - this.console.getPpu().tick(); - this.console.getApu().tick(); - } - - - public void reset() { - this.bulking = 0; - this.decrement = 0; + private void SyncOtherComponent() { + this.cycles++; + this.variation--; + this.console.APU_PPuSync(); } public byte directRead(int addr) { return this.bus.read(addr); } - public int calOffset() { - return this.decrement + this.bulking; + protected void _finally(WS6502 ws6502) { + var tmp = ws6502.cycle() + this.variation; + while (tmp-- > 0) { + this.SyncOtherComponent(); + } + this.variation = 0; } } diff --git a/bin/src/main/java/cn/navclub/nes4j/bin/core/impl/MMC3Mapper.java b/bin/src/main/java/cn/navclub/nes4j/bin/core/impl/MMC3Mapper.java index b858685..75cc44f 100644 --- a/bin/src/main/java/cn/navclub/nes4j/bin/core/impl/MMC3Mapper.java +++ b/bin/src/main/java/cn/navclub/nes4j/bin/core/impl/MMC3Mapper.java @@ -53,11 +53,14 @@ public class MMC3Mapper extends Mapper { private final int PRGMode; + private long a12LowCycle; + public MMC3Mapper(Cartridge cartridge, NesConsole console) { super(cartridge, console); this.r = 0; this.latch = 0; this.counter = 0; + this.a12LowCycle = 0; this.IRQEnable = false; this.reloadFlag = false; this.PRGBank = new int[4]; @@ -267,13 +270,15 @@ public byte CHRead(int address) { } @Override - public void tick() { + public void PPUVideoAddrState(int addr) { + if (!this.isRisingEdge(addr)) { + return; + } // When the IRQ is clocked (filtered A12 0→1), the counter value is checked - if zero // or the reload flag is true, it's reloaded with the IRQ latched value at $C000; otherwise, // it decrements. if (this.counter == 0 || reloadFlag) { this.counter = this.latch; - this.reloadFlag = false; } else { this.counter--; } @@ -284,5 +289,19 @@ public void tick() { if (this.counter == 0 && this.IRQEnable) { this.console.hardwareInterrupt(CPUInterrupt.IRQ); } + + this.reloadFlag = false; + } + + private boolean isRisingEdge(int addr) { + var risingEdge = false; + var cycles = this.console.getCpu().getCycles(); + if ((addr & 0x1000) == 0x1000) { + risingEdge = this.a12LowCycle > 0 && (cycles - this.a12LowCycle) >= 3; + this.a12LowCycle = 0; + } else if (a12LowCycle == 0) { + a12LowCycle = cycles; + } + return risingEdge; } } diff --git a/bin/src/main/java/cn/navclub/nes4j/bin/ppu/PPU.java b/bin/src/main/java/cn/navclub/nes4j/bin/ppu/PPU.java index 7415d37..2604dbd 100644 --- a/bin/src/main/java/cn/navclub/nes4j/bin/ppu/PPU.java +++ b/bin/src/main/java/cn/navclub/nes4j/bin/ppu/PPU.java @@ -159,11 +159,10 @@ public class PPU implements Component { protected byte w; //Fine X scroll (3 bits) protected byte x; + private int busAddr; //Suppress val or nmi flag private boolean suppress; private long lastFrameTime; - private int CpuM2; - private int PPU_A12; public PPU(final NesConsole console, NameMirror mirrors) { this.console = console; @@ -187,8 +186,7 @@ public void reset() { this.v = 0; this.w = 0; this.x = 0; - this.CpuM2 = 0; - this.PPU_A12 = 0; + this.busAddr = 0; this.oamAddr = 0; this.byteBuf = 0; this.render.reset(); @@ -204,22 +202,8 @@ public void tick() { if (this.lastFrameTime == 0) { this.lastFrameTime = System.nanoTime(); } - if (this.PPU_A12 == 0) { - this.CpuM2 = this.CpuM2 + 1; - } - var mapper = this.console.getMapper(); for (int i = 0; i < 3; i++) { this.render.tick(); - if (mapper.type() == NMapper.MMC3) { - var tmp = (this.v >> 12) & 1; - if (this.PPU_A12 == 0 && tmp == 1 && this.CpuM2 >= 3) { - mapper.tick(); - } - if ((tmp ^ this.PPU_A12) == 1) { - this.CpuM2 = 0; - } - this.PPU_A12 = tmp; - } } } @@ -241,6 +225,7 @@ private void updateVideoAddr(byte b) { this.w = 0; this.t = uint16(this.t & 0xff00 | uint8(b)); this.v = this.t; + this.setBusAddr(this.v); } } @@ -266,6 +251,7 @@ public byte read(int address) { } //Read name table else if (addr < 0x3f00) { + this.setBusAddr(addr); this.byteBuf = this.vram[VRAMirror(addr)]; } //Read palette table @@ -273,7 +259,7 @@ else if (addr < 0x3f20) { value = this.palette[this.paletteMirror(addr)]; } - this.v += this.ctr.inc(); + this.incrementVideoAddr(); } return value; } @@ -301,16 +287,25 @@ public void write(int address, byte b) { } //Update name table else if (addr < 0x3f00) { + this.setBusAddr(addr); this.vram[this.VRAMirror(addr)] = b; } //Update palette value else if (addr < 0x3f20) { this.palette[this.paletteMirror(addr)] = b; } - this.v += this.ctr.inc(); + this.incrementVideoAddr(); } } + private void incrementVideoAddr() { + if (this.render.scanline < 240 && this.mask.enableRender()) { + return; + } + this.v = (this.v + this.ctr.inc()) & 0x7FFF; + setBusAddr(this.v & 0x3FFF); + } + protected int iRead(int address) { final byte b; @@ -320,6 +315,7 @@ protected int iRead(int address) { } //Read name table data else if (address < 0x3f00) { + this.setBusAddr(address); b = this.vram[this.VRAMirror(address)]; } //unknown ppu read memory @@ -576,4 +572,9 @@ protected void calVideoPauseTime(long now) { public long getCycle() { return this.render.cycles; } + + private void setBusAddr(int addr) { + this.busAddr = addr; + this.console.getMapper().PPUVideoAddrState(addr); + } } diff --git a/bin/src/main/java/cn/navclub/nes4j/bin/ppu/register/PPUControl.java b/bin/src/main/java/cn/navclub/nes4j/bin/ppu/register/PPUControl.java index 1c6ae83..756a6c2 100644 --- a/bin/src/main/java/cn/navclub/nes4j/bin/ppu/register/PPUControl.java +++ b/bin/src/main/java/cn/navclub/nes4j/bin/ppu/register/PPUControl.java @@ -51,14 +51,15 @@ public int spritePattern8() { return this.contain(PControl.SPRITE_PATTERN_ADDR) ? 0x1000 : 0x000; } + /** + * 8x16 sprites use different pattern tables based on their index number. If the index number is + * even the sprite data is in the first pattern table at $0000, otherwise it is in the second pattern + * table at $1000. + * + * @param index Sprite index + */ public int spritePattern16(int index) { - // - // - // 8x16 sprites use different pattern tables based on their index number. If the index number is - // even the sprite data is in the first pattern table at $0000, otherwise it is in the second pattern - // table at $1000. - // - return (index & 0x01) == 0 ? 0x0000 : 0x1000; + return (index & 0x01) * 0x1000; } public int backgroundNameTable() { diff --git a/bin/src/main/java/cn/navclub/nes4j/bin/util/BinUtil.java b/bin/src/main/java/cn/navclub/nes4j/bin/util/BinUtil.java index 0c2133c..02c4c5a 100644 --- a/bin/src/main/java/cn/navclub/nes4j/bin/util/BinUtil.java +++ b/bin/src/main/java/cn/navclub/nes4j/bin/util/BinUtil.java @@ -61,10 +61,14 @@ public static String toHexStr(int b) { return sb.toString(); } - public static int uint8(int b) { + public static int uint8(byte b) { return (b & 0xff); } + public static int uint8(int b) { + return b & 0xff; + } + public static int uint16(int i) { return i & 0xffff;