-
Notifications
You must be signed in to change notification settings - Fork 0
/
memory.go
137 lines (109 loc) · 2.8 KB
/
memory.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package gophernes
import (
"fmt"
"github.com/sirupsen/logrus"
)
func (c *Console) CPURead(addr uint16) byte {
if addr < 0x2000 {
// Main RAM - mirrored for several address ranges, so drop excess bytes
// 0x0000 - 0x07ff
// 0x0800 - 0x0fff
// 0x1000 - 0x17ff
// 0x1800 - 0x1fff
return c.ram[addr&(internalRAMSize-1)]
} else if addr >= 0x2000 && addr < 0x4000 {
// PPU registers
return c.ppu.ReadReg(byte(addr & 0x7))
} else if addr >= 0x4000 && addr < 0x4020 {
// Memory-mapped registers
switch addr & 0x1F {
case 0x15:
return c.apu.ReadReg(0x15)
case 0x16:
return 0
case 0x17:
return 0x03
default:
logrus.Infof("Read from unhandled IO addr: %#X", addr)
// TODO: Handle more of these
}
return 0
} else if addr >= 0x4020 {
// Cartridge
return c.cartridge.CPURead(addr)
}
panic(fmt.Sprintf("unhandled cpu memory read from address %#x", addr))
}
func (c *Console) CPUWrite(addr uint16, val byte) {
if addr < 0x2000 {
c.ram[addr&(internalRAMSize-1)] = val
} else if addr >= 0x2000 && addr < 0x4000 {
c.ppu.WriteReg(byte(addr&0x7), val)
} else if addr >= 0x4000 && addr < 0x4020 {
switch addr & 0x1F {
case 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0xA, 0xB, 0xC, 0xE, 0xF, 0x10, 0x11, 0x12, 0x13, 0x15:
// APU
c.apu.WriteReg(byte(addr&0x1F), val)
case 0x16, 0x17:
// Controllers
case 0x14:
// OAM DMA
oamData := make([]byte, 256)
srcAddr := uint16(val) << 8
for i := range oamData {
oamData[i] = c.CPURead(srcAddr)
srcAddr++
}
c.ppu.OAMDMA(oamData)
c.cpu.Sleep(513)
if c.cpu.Cycles()%2 == 1 {
c.cpu.Sleep(1)
}
default:
logrus.Infof("Write to unhandled IO addr: %#X", addr)
}
} else if addr >= 0x4020 {
c.cartridge.CPUWrite(addr, val)
} else {
panic(fmt.Sprintf("unhandled cpu memory write to address %#x", addr))
}
}
func (c *Console) PPURead(addr uint16, vram []byte) byte {
// Palette is a special case unaffected by the cartridge
if addr >= 0x3F00 && addr <= 0x3FFF {
return c.ppu.ReadPalette(addr % 0x20)
}
// The rest of PPU memory is custom mapped by the cartridge
return c.cartridge.PPURead(addr, vram)
}
func (c *Console) PPUWrite(addr uint16, val byte, vram []byte) {
if addr >= 0x3F00 && addr <= 0x3FFF {
c.ppu.WritePalette(addr%0x20, val)
} else {
c.cartridge.PPUWrite(addr, val, vram)
}
}
func (c *Console) NMI() {
c.cpu.NMI()
}
func (c *Console) IRQ() {
c.cpu.IRQ()
}
type cpuMemory struct {
*Console
}
func (c *cpuMemory) Read(addr uint16) byte {
return c.CPURead(addr)
}
func (c *cpuMemory) Write(addr uint16, val byte) {
c.CPUWrite(addr, val)
}
type ppuMemory struct {
*Console
}
func (p *ppuMemory) Read(addr uint16, vram []byte) byte {
return p.PPURead(addr, vram)
}
func (p *ppuMemory) Write(addr uint16, val byte, vram []byte) {
p.PPUWrite(addr, val, vram)
}