Skip to content

Commit

Permalink
add asic regs, support CDD interrupt
Browse files Browse the repository at this point in the history
  • Loading branch information
Federico Berti committed Dec 29, 2023
1 parent 01714c3 commit 759ab67
Show file tree
Hide file tree
Showing 10 changed files with 405 additions and 124 deletions.
2 changes: 1 addition & 1 deletion src/main/java/omegadrive/bus/md/GenesisBus.java
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ private void cartWrite(int addressL, int data, Size size) {
return;
}
//Batman&Robin writes to address 0 - tries to enable debug mode?
LOG.warn("Unexpected write to ROM address {}, value {} {}", th(addressL),
LogHelper.logWarnOnceSh(LOG, "Unexpected write to ROM address {}, value {} {}", th(addressL),
th(data), size);
}

Expand Down
40 changes: 30 additions & 10 deletions src/main/java/omegadrive/bus/megacd/MegaCdDict.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import static omegadrive.bus.megacd.MegaCdMemoryContext.MCD_WORD_RAM_2M_SIZE;
import static omegadrive.bus.model.GenesisBusProvider.MEGA_CD_EXP_START;
import static omegadrive.util.Util.th;
import static s32x.util.S32xUtil.CpuDeviceAccess.M68K;
import static s32x.util.S32xUtil.CpuDeviceAccess.Z80;

/**
Expand Down Expand Up @@ -44,13 +45,14 @@ public enum McdRegType {NONE, SYS, COMM, CD, ASIC}
}

public enum RegSpecMcd {
MCD_RESET(SYS, 0, 0x103, 0xFFFF), //Reset
MCD_RESET(SYS, 0, 0x103, 0x301), //Reset
MCD_MEM_MODE(SYS, 2, 0xFFC2, 0xFFFF), //Memory Mode, write protect
MCD_CDC_MODE(CD, 4, 0, 0xFFFF), //CDC Mode, MAIN read-only

MCD_HINT_VECTOR(SYS, 6, 0xFFFF, 0xFFFF), //CDC Mode, MAIN read-only
MCD_HINT_VECTOR(SYS, REG_MAIN, 6, 0xFFFF, 0), //HINT vector (level 4)
MCD_CDC_REG_DATA(SYS, REG_SUB, 6, 0, 0xFF), //CDC Register data

MCD_CDC_HOST(SYS, 8, 0, 0xFFFF), //CDC host data
MCD_CDC_HOST(SYS, 8, 0, 0), //CDC host data

MCD_STOPWATCH(SYS, 0xC, 0, 0xFFFF), //Stopwatch

Expand Down Expand Up @@ -80,6 +82,18 @@ public enum RegSpecMcd {
MCD_CD_FADER(CD, 0x34, 0, 0x7FFE), //CD Fader
MCD_CDD_CONTROL(CD, 0x36, 0, 0x7), //CDD Control

MCD_CDD_COMM0(CD, 0x38, 0, 0xFFFF), //CDD Comm
MCD_CDD_COMM1(CD, 0x3A, 0, 0xFFFF), //CDD Comm
MCD_CDD_COMM2(CD, 0x3C, 0, 0xFFFF), //CDD Comm
MCD_CDD_COMM3(CD, 0x3E, 0, 0xFFFF), //CDD Comm

MCD_CDD_COMM4(CD, 0x40, 0, 0xFFFF), //CDD Comm
MCD_CDD_COMM5(CD, 0x42, 0, 0xFFFF), //CDD Comm
MCD_CDD_COMM6(CD, 0x44, 0, 0xFFFF), //CDD Comm
MCD_CDD_COMM7(CD, 0x46, 0, 0xFFFF), //CDD Comm
MCD_CDD_COMM8(CD, 0x48, 0, 0xFFFF), //CDD Comm
MCD_CDD_COMM9(CD, 0x4A, 0, 0xFFFF), //CDD Comm

MCD_FONT_COLOR(SYS, 0x4C, 0, 0xFF), //Font color
MCD_FONT_BIT(SYS, 0x4E, 0, 0xFFFF), //Font bit
MCD_FONT_DATA0(SYS, 0x50, 0, 0), //Font data
Expand Down Expand Up @@ -111,9 +125,13 @@ public enum RegSpecMcd {

//defaults to 16 bit wide register
RegSpecMcd(McdRegType deviceType, int addr, int writeAndMaskMain, int writeAndMaskSub) {
this(deviceType, REG_BOTH, addr, writeAndMaskMain, writeAndMaskSub);
}

RegSpecMcd(McdRegType deviceType, McdRegCpuType cpuType, int addr, int writeAndMaskMain, int writeAndMaskSub) {
this.deviceType = deviceType;
this.deviceAccessTypeDelay = S32xMemAccessDelay.SYS_REG;
this.regCpuType = getCpuTypeFromDevice(deviceType, name());
this.regCpuType = getCpuTypeFromDevice(deviceType, cpuType);
this.regSpec = createRegSpec(addr, writeAndMaskMain, writeAndMaskSub);
this.addr = regSpec.bufferAddr;
init();
Expand All @@ -139,10 +157,10 @@ private void init() {
}
int addrLen = regSpec.regSize.getByteSize();
for (int i = regSpec.fullAddr; i < regSpec.fullAddr + addrLen; i++) {
mcdRegMapping[regCpuType.ordinal()][i] = this;
if (regCpuType == REG_BOTH) {
mcdRegMapping[REG_MAIN.ordinal()][i] = this;
mcdRegMapping[REG_SUB.ordinal()][i] = this;
mcdRegMapping[REG_BOTH.ordinal()][i] = this;
} else {
mcdRegMapping[regCpuType.ordinal()][i] = this;
}
}
}
Expand All @@ -152,8 +170,9 @@ public String getName() {
}
}

private static McdRegCpuType getCpuTypeFromDevice(McdRegType deviceType, String name) {
return deviceType == NONE || deviceType == COMM || deviceType == SYS ? McdRegCpuType.REG_BOTH : REG_SUB;
private static McdRegCpuType getCpuTypeFromDevice(McdRegType deviceType, McdRegCpuType baseType) {
//override ASIC as subOnly
return deviceType == ASIC ? REG_SUB : baseType;
}

public static void logAccess(RegSpecMcd regSpec, CpuDeviceAccess cpu, int address, int value, Size size, boolean read) {
Expand All @@ -167,7 +186,8 @@ public static RegSpecMcd getRegSpec(CpuDeviceAccess cpu, int address) {
assert cpu != Z80; //TODO
RegSpecMcd r = mcdRegMapping[REG_BOTH.ordinal()][address & MDC_SUB_GATE_REGS_MASK];
if (r == null) {
r = mcdRegMapping[REG_SUB.ordinal()][address & MDC_SUB_GATE_REGS_MASK];
int idx = cpu == M68K ? REG_MAIN.ordinal() : REG_SUB.ordinal();
r = mcdRegMapping[idx][address & MDC_SUB_GATE_REGS_MASK];
if (r == null) {
LOG.error("{} unknown register at address: {}", cpu, th(address));
r = RegSpecMcd.INVALID;
Expand Down
160 changes: 97 additions & 63 deletions src/main/java/omegadrive/bus/megacd/MegaCdMainCpuBus.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,24 @@
import java.nio.ByteBuffer;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.function.BiConsumer;

import static omegadrive.bus.megacd.MegaCdDict.*;
import static omegadrive.bus.megacd.MegaCdDict.RegSpecMcd.*;
import static omegadrive.bus.megacd.MegaCdMemoryContext.MCD_GATE_REGS_MASK;
import static omegadrive.bus.megacd.MegaCdMemoryContext.WramSetup;
import static omegadrive.bus.megacd.MegaCdRegWriteHandlers.setByteHandlersMain;
import static omegadrive.util.S32xUtil.*;
import static omegadrive.util.Util.random;
import static omegadrive.util.Util.th;
import static s32x.util.S32xUtil.CpuDeviceAccess.M68K;

/**
* Federico Berti
* <p>
* Copyright 2023
* <p>
* TODO DMNA, RET etc bit/reg sync
*/
public class MegaCdMainCpuBus extends GenesisBus {

Expand All @@ -40,7 +46,7 @@ public class MegaCdMainCpuBus extends GenesisBus {
* 0x400000 instead of 0x000000. So the BIOS ROM is at 0x400_000, the
* Program RAM bank is at 0x420_000, and the Word RAM is at 0x600_000.
*/
private ByteBuffer prgRam, gateRegs;
private ByteBuffer prgRam, sysGateRegs, commonGateRegs;
private int prgRamBankValue = 0, prgRamBankShift = 0;

private boolean enableMCDBus = true, enableMode1 = true;
Expand Down Expand Up @@ -68,12 +74,14 @@ public class MegaCdMainCpuBus extends GenesisBus {
}

public MegaCdMainCpuBus(MegaCdMemoryContext ctx) {
cpu = M68K;
prgRam = ByteBuffer.wrap(ctx.prgRam);
gateRegs = ByteBuffer.wrap(ctx.gateRegs);
sysGateRegs = ByteBuffer.wrap(ctx.getGateSysRegs(cpu));
commonGateRegs = ByteBuffer.wrap(ctx.commonGateRegs);
memCtx = ctx;
cpu = S32xUtil.CpuDeviceAccess.M68K;

writeBuffer(gateRegs, 3, 1, Size.BYTE); //DMNA=0, RET=1
writeBuffer(sysGateRegs, MCD_RESET.addr, 2, Size.WORD); //DMNA=0, RET=1
writeBuffer(sysGateRegs, MCD_MEM_MODE.addr + 1, 1, Size.BYTE); //DMNA=0, RET=1
writeBuffer(sysGateRegs, MCD_CDC_REG_DATA.addr, 0xFFFF, Size.WORD);
}

@Override
Expand Down Expand Up @@ -157,7 +165,8 @@ private int handleMegaCdExpRead(int address, Size size) {
LOG.error("M read unknown MEGA_CD_EXP reg: {}", th(address));
return 0;
}
int res = readBuffer(gateRegs, address & MCD_GATE_REGS_MASK, size);
ByteBuffer regs = getRegBuffer(regSpec);
int res = readBuffer(regs, address & MCD_GATE_REGS_MASK, size);
//TODO bios_us.bin RET bit
//TODO subCpu never returns WRAM to main as subCpu is stuck in CDD
if (!enableMode1 && address == 0xA12003 && size == Size.BYTE) {
Expand All @@ -182,76 +191,94 @@ private void handleMegaCdExpWrite(int address, int data, Size size) {

private void handleSysRegWrite(RegSpecMcd regSpec, int address, int data, Size size) {
assert size != Size.LONG;
int regEven = (address & MCD_GATE_REGS_MASK) & ~1;
int regVal = readBuffer(gateRegs, regEven, Size.WORD);
writeBuffer(gateRegs, address & MCD_GATE_REGS_MASK, data, size);
int newVal = readBuffer(gateRegs, regEven, Size.WORD);
if (regVal == newVal) {
return;
}
switch (regSpec) {
case MCD_RESET -> {
int v = regVal & 0x8103;
int v2 = data & 0x8103;
writeBuffer(gateRegs, regSpec.addr, v, Size.WORD);
if (v == v2) {
return;
}
int sreset = v2 & 1;
int sbusreq = (v2 >> 1) & 1;
int subIntReg = (v2 >> 8) & 1;
setBitVal(gateRegs, regSpec.addr, 0, sreset, Size.WORD);
setBitVal(gateRegs, regSpec.addr, 1, sbusreq, Size.WORD);
setBitVal(gateRegs, regSpec.addr, 8, subIntReg, Size.WORD);
int val = setBitVal(gateRegs, regSpec.addr, 15, (v2 >> 15) & 1, Size.WORD);
LOG.info("M SubCpu reset: {}, busReq: {}", (sreset == 0 ? "Reset" : "Run"), (sbusreq == 0 ? "Cancel" : "Request"));
MC68000Wrapper m68k = (MC68000Wrapper) MegaCd.subCpuBusHack.getBusDeviceIfAny(M68kProvider.class).get();
if (sreset > 0) {
if (sbusreq == 0) {
m68k.reset();
MegaCd.subCpuBusHack.resetDone();
LOG.info("M SubCpu reset done, now running");
}
m68k.setStop(sbusreq > 0);
} else { //sreset = 0
m68k.setStop(true);
LOG.info("M SubCpu stopped");
}
if (subIntReg > 0) {
LOG.info("M trigger SubCpu int2 request");
m68k.raiseInterrupt(2);
}
}
case MCD_MEM_MODE -> {
if ((data & 0xFF00) != 0) {
LOG.warn("M Mem Write protect bits set: {}", th(data));
}
WramSetup ws = memCtx.update(cpu, newVal);
if (ws == WramSetup.W_2M_SUB) { //set RET=0
newVal = setBitVal(gateRegs, regEven + 1, 0, 0, Size.BYTE);
}
logWram(newVal);
//bk0,1
int bval = (newVal >> 5) & 3;
if (bval != prgRamBankValue) {
prgRamBankValue = (newVal >> 5) & 3;
prgRamBankShift = prgRamBankValue << 17;
LOG.info("M PRG_RAM bank set: {} {}", prgRamBankValue, th(prgRamBankShift));
}
}
case MCD_RESET -> handleReg0Write(address, data, size);
case MCD_MEM_MODE -> handleReg2Write(address, data, size);
case MCD_CDC_MODE, MCD_CDC_HOST -> {
assert false : regSpec;
} //not writable
case MCD_COMM_FLAGS -> {
//main can only write to MSB
assert size == Size.BYTE && (address & 1) == 0;
LOG.info("M write COMM_FLAG: {} {}", th(data), size);
}
case MCD_HINT_VECTOR -> {
LOG.info("M write MCD_HINT_VECTOR: {} {}", th(data), size);
writeBuffer(sysGateRegs, regSpec.addr, data, size);
}
default -> LOG.error("M write unknown MEGA_CD_EXP reg: {}", th(address));
}
}

private void handleReg0Write(int address, int data, Size size) {
int curr = readBuffer(sysGateRegs, MCD_RESET.addr, Size.WORD);
int res = handleRegWrite(MCD_RESET, address, data, size);
int sreset = res & 1;
int sbusreq = (res >> 1) & 1;
int subIntReg = (res >> 8) & 1;

MC68000Wrapper m68k = (MC68000Wrapper) MegaCd.subCpuBusHack.getBusDeviceIfAny(M68kProvider.class).get();
if (subIntReg > 0) {
LOG.info("M trigger SubCpu int2 request");
m68k.raiseInterrupt(2);
}
if ((address & 1) == 0 && size == Size.BYTE) {
return;
}
LOG.info("M SubCpu reset: {}, busReq: {}", (sreset == 0 ? "Reset" : "Run"), (sbusreq == 0 ? "Cancel" : "Request"));
if ((curr & 3) == (res & 3)) {
return;
}
if (sreset > 0) {
if (sbusreq == 0) {
m68k.reset();
MegaCd.subCpuBusHack.resetDone();
LOG.info("M SubCpu reset done, now running");
}
m68k.setStop(sbusreq > 0);
} else { //sreset = 0
m68k.setStop(true);
LOG.info("M SubCpu stopped");
}
}

private void handleReg2Write(int address, int data, Size size) {
int res = handleRegWrite(MCD_MEM_MODE, address, data, size);
if ((res & 0xFF00) != 0) {
LOG.warn("M Mem Write protect bits set: {}", th(data));
}
WramSetup ws = memCtx.update(cpu, res);
if (ws == WramSetup.W_2M_SUB) { //set RET=0
res = setBitVal(sysGateRegs, MCD_MEM_MODE.addr + 1, 0, 0, Size.BYTE);
}
logWram(res);
//bk0,1
int bval = (res >> 5) & 3;
if (bval != prgRamBankValue) {
prgRamBankValue = bval;
prgRamBankShift = prgRamBankValue << 17;
LOG.info("M PRG_RAM bank set: {} {}", prgRamBankValue, th(prgRamBankShift));
}
}

private int handleRegWrite(RegSpecMcd regSpec, int address, int data, Size size) {
BiConsumer<ByteBuffer, Integer>[] setByteRegHandler = setByteHandlersMain[regSpec.addr];
ByteBuffer b = getRegBuffer(regSpec);
assert setByteRegHandler != null;
switch (size) {
case WORD -> {
setByteRegHandler[1].accept(b, data); //LSB
setByteRegHandler[0].accept(b, data >> 8); //MSB
}
case BYTE -> setByteRegHandler[address & 1].accept(b, data);
}
return readBuffer(b, 0, Size.WORD);
}

private void handleCommWrite(RegSpecMcd regSpec, int address, int data, Size size) {
if (address >= START_MCD_MAIN_GA_COMM_W && address < END_MCD_MAIN_GA_COMM_W) { //MAIN COMM
LOG.info("M Write MEGA_CD_COMM: {}, {}, {}", th(address), th(data), size);
writeBuffer(gateRegs, address & MCD_GATE_REGS_MASK, data, size);
writeBuffer(commonGateRegs, address & MCD_GATE_REGS_MASK, data, size);
return;
}
if (address >= END_MCD_MAIN_GA_COMM_W && address < END_MCD_MAIN_GA_COMM_R) { //MAIN COMM READ ONLY
Expand All @@ -265,6 +292,13 @@ public void logAccess(RegSpecMcd regSpec, S32xUtil.CpuDeviceAccess cpu, int addr
size, regSpec.getName(), th(address), !read ? ": " + th(value) : "");
}

private ByteBuffer getRegBuffer(MegaCdDict.RegSpecMcd regSpec) {
if (regSpec.addr >= 8) {
return commonGateRegs;
}
return sysGateRegs;
}

private void logWram(int newVal) {
int mode = newVal & 4;
int dmna = newVal & 2;
Expand Down
12 changes: 10 additions & 2 deletions src/main/java/omegadrive/bus/megacd/MegaCdMemoryContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ public class MegaCdMemoryContext implements Serializable {
public static final int MCD_WORD_RAM_2M_MASK = MCD_WORD_RAM_2M_SIZE - 1;
public static final int MCD_PRG_RAM_MASK = MCD_PRG_RAM_SIZE - 1;

public byte[] prgRam, gateRegs;
public byte[] prgRam;
public byte[][] sysGateRegs;
public byte[] commonGateRegs;
public byte[][] wordRam01 = new byte[2][1];

public WramSetup wramSetup = WramSetup.W_2M_MAIN;
Expand All @@ -58,7 +60,8 @@ public MegaCdMemoryContext() {
prgRam = new byte[MCD_PRG_RAM_SIZE];
wordRam01[0] = new byte[MCD_WORD_RAM_1M_SIZE];
wordRam01[1] = new byte[MCD_WORD_RAM_1M_SIZE];
gateRegs = new byte[MDC_SUB_GATE_REGS_SIZE];
sysGateRegs = new byte[2][8];
commonGateRegs = new byte[MDC_SUB_GATE_REGS_SIZE];
}

public void writeWordRam(CpuDeviceAccess cpu, int address, int value, Size size) {
Expand Down Expand Up @@ -101,4 +104,9 @@ public WramSetup update(CpuDeviceAccess c, int reg2) {
}
return wramSetup;
}

public byte[] getGateSysRegs(CpuDeviceAccess cpu) {
assert cpu == M68K || cpu == SUB_M68K;
return sysGateRegs[cpu == M68K ? 0 : 1];
}
}
Loading

0 comments on commit 759ab67

Please sign in to comment.