forked from fogleman/nes
/
memory.go
134 lines (118 loc) · 3.21 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
package nes
import "log"
type Memory interface {
Read(address uint16) byte
Write(address uint16, value byte)
}
// CPU Memory Map
type cpuMemory struct {
console *Console
}
func NewCPUMemory(console *Console) Memory {
return &cpuMemory{console}
}
func (mem *cpuMemory) Read(address uint16) byte {
switch {
case address < 0x2000:
return mem.console.RAM[address%0x0800]
case address < 0x4000:
return mem.console.PPU.readRegister(0x2000 + address%8)
case address == 0x4014:
return mem.console.PPU.readRegister(address)
case address == 0x4015:
return mem.console.APU.readRegister(address)
case address == 0x4016:
return mem.console.Controller1.Read()
case address == 0x4017:
return mem.console.Controller2.Read()
case address < 0x6000:
// TODO: I/O registers
case address >= 0x6000:
return mem.console.Mapper.Read(address)
default:
log.Fatalf("unhandled cpu memory read at address: 0x%04X", address)
}
return 0
}
func (mem *cpuMemory) Write(address uint16, value byte) {
switch {
case address < 0x2000:
mem.console.RAM[address%0x0800] = value
case address < 0x4000:
mem.console.PPU.writeRegister(0x2000+address%8, value)
case address < 0x4014:
mem.console.APU.writeRegister(address, value)
case address == 0x4014:
mem.console.PPU.writeRegister(address, value)
case address == 0x4015:
mem.console.APU.writeRegister(address, value)
case address == 0x4016:
mem.console.Controller1.Write(value)
mem.console.Controller2.Write(value)
case address == 0x4017:
mem.console.APU.writeRegister(address, value)
case address < 0x6000:
// TODO: I/O registers
case address >= 0x6000:
mem.console.Mapper.Write(address, value)
default:
log.Fatalf("unhandled cpu memory write at address: 0x%04X", address)
}
}
// PPU Memory Map
type ppuMemory struct {
console *Console
}
func NewPPUMemory(console *Console) Memory {
return &ppuMemory{console}
}
func (mem *ppuMemory) Read(address uint16) byte {
address = address % 0x4000
switch {
case address < 0x2000:
return mem.console.Mapper.Read(address)
case address < 0x3F00:
mode := mem.console.Cartridge.Mirror
return mem.console.PPU.nameTableData[MirrorAddress(mode, address)%2048]
case address < 0x4000:
return mem.console.PPU.readPalette(address % 32)
default:
log.Fatalf("unhandled ppu memory read at address: 0x%04X", address)
}
return 0
}
func (mem *ppuMemory) Write(address uint16, value byte) {
address = address % 0x4000
switch {
case address < 0x2000:
mem.console.Mapper.Write(address, value)
case address < 0x3F00:
mode := mem.console.Cartridge.Mirror
mem.console.PPU.nameTableData[MirrorAddress(mode, address)%2048] = value
case address < 0x4000:
mem.console.PPU.writePalette(address%32, value)
default:
log.Fatalf("unhandled ppu memory write at address: 0x%04X", address)
}
}
// Mirroring Modes
const (
MirrorHorizontal = 0
MirrorVertical = 1
MirrorSingle0 = 2
MirrorSingle1 = 3
MirrorFour = 4
)
var MirrorLookup = [...][4]uint16{
{0, 0, 1, 1},
{0, 1, 0, 1},
{0, 0, 0, 0},
{1, 1, 1, 1},
{0, 1, 2, 3},
}
func MirrorAddress(mode byte, address uint16) uint16 {
address = (address - 0x2000) % 0x1000
table := address / 0x0400
offset := address % 0x0400
return 0x2000 + MirrorLookup[mode][table]*0x0400 + offset
}