139 lines
2.3 KiB
Go
139 lines
2.3 KiB
Go
|
package memory
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"sync"
|
||
|
)
|
||
|
|
||
|
type MemoryByte struct {
|
||
|
Value byte
|
||
|
Valid bool
|
||
|
Changed bool
|
||
|
}
|
||
|
|
||
|
func (b MemoryByte) Hex() string {
|
||
|
if !b.Valid {
|
||
|
return "??"
|
||
|
}
|
||
|
return fmt.Sprintf("%02x", b.Value)
|
||
|
}
|
||
|
|
||
|
func (b MemoryByte) Dec() string {
|
||
|
if !b.Valid {
|
||
|
return "???"
|
||
|
}
|
||
|
return fmt.Sprintf("%d", b.Value)
|
||
|
}
|
||
|
|
||
|
func (b MemoryByte) Bin() string {
|
||
|
if !b.Valid {
|
||
|
return "????????"
|
||
|
}
|
||
|
return fmt.Sprintf("%08b", b.Value)
|
||
|
}
|
||
|
|
||
|
type MemorySrc interface {
|
||
|
io.ReaderAt
|
||
|
io.WriterAt
|
||
|
}
|
||
|
|
||
|
type Memory struct {
|
||
|
src MemorySrc
|
||
|
|
||
|
mu sync.Mutex
|
||
|
bytes []MemoryByte
|
||
|
pendingWrites map[int]byte
|
||
|
}
|
||
|
|
||
|
func New(src MemorySrc, size int) *Memory {
|
||
|
ret := &Memory{
|
||
|
src: src,
|
||
|
bytes: make([]MemoryByte, size),
|
||
|
pendingWrites: map[int]byte{},
|
||
|
}
|
||
|
return ret
|
||
|
}
|
||
|
|
||
|
func (m *Memory) Len() int {
|
||
|
m.mu.Lock()
|
||
|
defer m.mu.Unlock()
|
||
|
return len(m.bytes)
|
||
|
}
|
||
|
|
||
|
func (m *Memory) Load(start, count int) error {
|
||
|
if m.needsRefresh(start, count) {
|
||
|
return m.Refresh(start, count)
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (m *Memory) needsRefresh(start, count int) bool {
|
||
|
m.mu.Lock()
|
||
|
defer m.mu.Unlock()
|
||
|
for _, b := range m.bytes {
|
||
|
if !b.Valid {
|
||
|
return true
|
||
|
}
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func (m *Memory) Refresh(start, count int) error {
|
||
|
bs := make([]byte, count)
|
||
|
if _, err := m.src.ReadAt(bs, int64(start)); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
m.mu.Lock()
|
||
|
defer m.mu.Unlock()
|
||
|
for i, v := range bs {
|
||
|
m.bytes[start+i] = MemoryByte{v, true, false}
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (m *Memory) At(addr int) MemoryByte {
|
||
|
m.mu.Lock()
|
||
|
defer m.mu.Unlock()
|
||
|
if addr >= len(m.bytes) {
|
||
|
return MemoryByte{}
|
||
|
}
|
||
|
if v, ok := m.pendingWrites[addr]; ok {
|
||
|
return MemoryByte{v, true, true}
|
||
|
}
|
||
|
return m.bytes[addr]
|
||
|
}
|
||
|
|
||
|
func (m *Memory) Slice(start, end int) []MemoryByte {
|
||
|
ret := make([]MemoryByte, end-start)
|
||
|
for i := range ret {
|
||
|
ret[i] = m.At(start + i)
|
||
|
}
|
||
|
return ret
|
||
|
}
|
||
|
|
||
|
func (m *Memory) Write(addr int, val byte) {
|
||
|
m.mu.Lock()
|
||
|
defer m.mu.Unlock()
|
||
|
m.pendingWrites[addr] = val
|
||
|
}
|
||
|
|
||
|
func (m *Memory) Commit() error {
|
||
|
m.mu.Lock()
|
||
|
defer m.mu.Unlock()
|
||
|
for addr, val := range m.pendingWrites {
|
||
|
if _, err := m.src.WriteAt([]byte{val}, int64(addr)); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
delete(m.pendingWrites, addr)
|
||
|
m.bytes[addr] = MemoryByte{val, true, false}
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (m *Memory) HasPendingWrites() bool {
|
||
|
m.mu.Lock()
|
||
|
defer m.mu.Unlock()
|
||
|
return len(m.pendingWrites) > 0
|
||
|
}
|