-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathmemory.go
136 lines (121 loc) · 2.72 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
package zog
import (
"fmt"
"sync"
)
type Memory struct {
sync.Mutex
buf []byte
debug bool
watches Regions
watchFunc func(addr uint16, old byte, new byte)
readonly Regions
}
func NewMemory(size uint16) *Memory {
intSize := int(size)
if intSize == 0 {
intSize = 64 * 1024
}
m := &Memory{
buf: make([]byte, intSize),
readonly: make([]Region, 0),
}
return m
}
func (m *Memory) SetDebug(debug bool) {
m.debug = debug
}
func (m *Memory) SetWatchFunc(wf func(uint16, byte, byte)) {
m.watchFunc = wf
}
func (m *Memory) Len() int {
return len(m.buf)
}
func (m *Memory) Peek(addr uint16) (byte, error) {
m.Lock()
defer m.Unlock()
if int(addr) >= m.Len() {
return 0, fmt.Errorf("Out of bounds memory read: 0x%04X > 0x%04X", addr, m.Len())
}
n := m.buf[addr]
// if m.debug || m.watches.contains(addr) {
// fmt.Printf("MEM: %04X -> %02X\n", addr, n)
// }
return n, nil
}
func (m *Memory) Poke(addr uint16, n byte) error {
m.Lock()
defer m.Unlock()
// Poke to ROM is a NOP
if m.readonly.contains(addr) {
fmt.Printf("Deny RO POKE [%04X] [%02X]\n", addr, n)
return nil
}
if int(addr) >= m.Len() {
return fmt.Errorf("Out of bounds memory write: %d (%d)", addr, n)
}
if m.debug || m.watches.contains(addr) {
// fmt.Printf("MEM: %04X <- %02X\n", addr, n)
m.watchFunc(addr, m.buf[addr], n)
}
m.buf[addr] = n
return nil
}
func (m *Memory) Peek16(addr uint16) (uint16, error) {
l, err := m.Peek(addr)
if err != nil {
return 0, err
}
h, err := m.Peek(addr + 1) // overflow correct
if err != nil {
return 0, err
}
return uint16(h)<<8 | uint16(l), nil
}
func (m *Memory) Poke16(addr uint16, nn uint16) error {
if m.readonly.contains(addr) {
return nil
}
l := byte(nn)
h := byte(nn >> 8)
err := m.Poke(addr, l)
if err != nil {
return err
}
err = m.Poke(addr+1, h)
if err != nil {
return err
}
return nil
}
func (m *Memory) Clear() {
m.Lock()
defer m.Unlock()
m.buf = make([]byte, int(m.Len()))
}
func (m *Memory) Copy(addr uint16, buf []byte) error {
m.Lock()
defer m.Unlock()
if int(addr)+len(buf) > int(m.Len()) {
panic(fmt.Sprintf("Can't load - base addr %04X length %04X memsize %04X", addr, len(buf), m.Len()))
}
for i := 0; i < len(buf); i++ {
m.buf[addr+uint16(i)] = buf[i]
}
return nil
}
// Fetch a chunk of memory. Error if overflows end.
// Don't write to this please.
func (m *Memory) PeekBuf(addr uint16, size int) ([]byte, error) {
m.Lock()
defer m.Unlock()
if size <= 0 || size > 64*1024*1024 {
return nil, fmt.Errorf("PeekBuf invalid size: %d", size)
}
if size+int(addr) > len(m.buf) {
return nil, fmt.Errorf("PeekBuf invalid size+addr: %04x - %04x", addr, size)
}
buf := make([]byte, size)
copy(buf, m.buf[addr:int(addr)+size])
return buf, nil
}