Skip to content

Commit

Permalink
Make CPU stall on DMA
Browse files Browse the repository at this point in the history
  • Loading branch information
tyfkda committed Mar 8, 2024
1 parent c1de200 commit 9bf4ba5
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 23 deletions.
11 changes: 11 additions & 0 deletions src/nes/cpu/cpu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export class Cpu {

private pc: Address // Program counter
private irqRequest = 0
private stallCycles = 0

// For debug
private breakPoints = new Set<Address | BreakType>()
Expand Down Expand Up @@ -148,6 +149,10 @@ export class Cpu {
this.irqRequest &= ~(1 << type)
}

public stall(cycles: number): void {
this.stallCycles = cycles
}

public step(): number {
if (this.irqRequest !== 0 && this.irqBlocked === 0) {
this.irqRequest = 0
Expand All @@ -156,6 +161,12 @@ export class Cpu {
return 0
}

if (this.stallCycles > 0) {
const cycles = this.stallCycles
this.stallCycles = 0
return cycles
}

let pc = this.pc
const op = this.read8(pc++)
const inst = kInstTable[op]
Expand Down
52 changes: 33 additions & 19 deletions src/nes/mapper/mapper023.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,41 +79,55 @@ class Mapper023Base extends Mapper {
if (0xc000 <= adr && adr <= 0xefff) { // CHR Select 2...7
const reg = mapping[adr & 0xff]
let ofs = 0, hi = false
if (reg === 0) {
switch (reg) {
case 0:
ofs = 0
} else if (reg === 2) {
break
case 2:
ofs = 0
hi = true
} else if (reg === 4) {
break
case 4:
ofs = 1
} else if (reg === 6) {
break
case 6:
ofs = 1
hi = true
} else {
break
default:
return
}
const bank = ((adr & 0x3000) >> 11) + 2 + ofs
let newValue
let newValue: number
if (hi)
newValue = (this.chrBank[bank] & ~0x1f0) | ((value & 0x1f) << 4)
else
newValue = (this.chrBank[bank] & ~0x0f) | (value & 0x0f)
this.setChrBankOffset(bank, newValue)
} else { // IRQ
const reg = mapping[adr & 0xff]
if (reg === 0) { // IRQ Latch: low 4 bits
switch (reg) {
case 0: // IRQ Latch: low 4 bits
this.irqLatch = (this.irqLatch & ~0x0f) | (value & 0x0f)
} else if (reg === 2) { // IRQ Latch: high 4 bits
break
case 2: // IRQ Latch: high 4 bits
this.irqLatch = (this.irqLatch & ~0xf0) | ((value & 0x0f) << 4)
} else if (reg === 4) { // IRQ Control
break
case 4: // IRQ Control
this.irqControl = value
if ((this.irqControl & IRQ_ENABLE) !== 0) {
this.irqCounter = this.irqLatch
}
} else if (reg === 6) { // IRQ Acknowledge
this.options.clearIrqRequest(IrqType.EXTERNAL)
break
case 6: // IRQ Acknowledge
// Copy to enable
const ea = this.irqControl & IRQ_ENABLE_AFTER
this.irqControl = (this.irqControl & ~IRQ_ENABLE) | (ea << 1)
{
const ea = this.irqControl & IRQ_ENABLE_AFTER
this.irqControl = (this.irqControl & ~IRQ_ENABLE) | (ea << 1)
this.options.clearIrqRequest(IrqType.EXTERNAL)
}
break
}
}
})
Expand Down Expand Up @@ -153,14 +167,14 @@ class Mapper023Base extends Mapper {
public onHblank(_hcount: number): void {
if ((this.irqControl & IRQ_ENABLE) !== 0) {
let c = this.irqCounter
if ((this.irqControl & IRQ_MODE) === 0) { // scanline mode
c += 1
} else { // cycle mode
c += 185 // TODO: Calculate.
}
if (c > 255) {
c = this.irqLatch
if (c >= 255) {
c += this.irqLatch - 255
this.options.requestIrq(IrqType.EXTERNAL)
} else {
if ((this.irqControl & IRQ_MODE) === 0) // scanline mode
c += 1
else // cycle mode
c += 114 // 341 / 3
}
this.irqCounter = c
}
Expand Down
9 changes: 5 additions & 4 deletions src/nes/nes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,11 +224,13 @@ export class Nes {
case OAMDMA:
if (0 <= value && value <= 0x1f) { // RAM
this.ppu.copyWithDma(this.ram, value << 8)
// TODO: Consume CPU or GPU cycles.
this.cpu.stall(513)
} else if (0x60 <= value && value <= 0x7f) {
const sram = this.mapper.getSram()
if (sram != null)
if (sram != null) {
this.ppu.copyWithDma(sram, (value - 0x60) << 8)
this.cpu.stall(513)
}
} else {
console.error(`OAMDMA not implemented except for RAM: ${Util.hex(value, 2)}`)
}
Expand Down Expand Up @@ -297,11 +299,10 @@ export class Nes {

this.ppu.setHcount(hcount)
this.apu.onHblank(hcount)
this.mapper.onHblank(hcount)

if (hcount === VBlank.START)
this.eventCallback(NesEvent.VBlank, (leftCycles / VCYCLE) | 0)

this.mapper.onHblank(hcount)
}
this.cycleCount = nextCycleCount
}
Expand Down

0 comments on commit 9bf4ba5

Please sign in to comment.