Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Write battery-backed RAM to disk on shutdown, restore on launch

  • Loading branch information...
commit f4bd8fa008a8f0989bdc92c646c053d25d40f691 1 parent d73636d
Scott Ferguson authored
Showing with 104 additions and 40 deletions.
  1. +1 −0  .gitignore
  2. +42 −5 machine.go
  3. +8 −4 mmc1.go
  4. +53 −31 rom.go
1  .gitignore
View
@@ -23,4 +23,5 @@ _testmain.go
*.swp
games/*
*.state
+*.battery
.DS_Store
47 machine.go
View
@@ -21,8 +21,9 @@ var (
video Video
controller Controller
- gamename string
- game string
+ gamename string
+ saveStateFile string
+ batteryRamFile string
)
func setResetVector() {
@@ -35,7 +36,7 @@ func setResetVector() {
func LoadState() {
fmt.Println("Loading state")
- state, err := ioutil.ReadFile(game)
+ state, err := ioutil.ReadFile(saveStateFile)
if err != nil {
fmt.Println(err.Error())
return
@@ -136,11 +137,40 @@ func SaveState() {
buf.WriteByte(byte(v))
}
- if err := ioutil.WriteFile(game, buf.Bytes(), 0644); err != nil {
+ if err := ioutil.WriteFile(saveStateFile, buf.Bytes(), 0644); err != nil {
panic(err.Error())
}
}
+func loadBatteryRam() {
+ fmt.Println("Loading battery RAM")
+
+ batteryRam, err := ioutil.ReadFile(batteryRamFile)
+ if err != nil {
+ fmt.Println(err.Error())
+ return
+ }
+
+ for i, v := range batteryRam[:0x2000] {
+ Ram[0x6000+i] = Word(v)
+ }
+}
+
+func saveBatteryFile() {
+ buf := new(bytes.Buffer)
+
+ // Battery/Work RAM
+ for _, v := range Ram[0x6000:0x7FFF] {
+ buf.WriteByte(byte(v))
+ }
+
+ if err := ioutil.WriteFile(batteryRamFile, buf.Bytes(), 0644); err != nil {
+ panic(err.Error())
+ }
+
+ fmt.Println("Battery RAM saved to disk")
+}
+
func main() {
if len(os.Args) < 2 {
fmt.Println("Please specify a ROM file")
@@ -153,6 +183,7 @@ func main() {
controller.Init()
if contents, err := ioutil.ReadFile(os.Args[1]); err == nil {
+
if rom, err = LoadRom(contents); err != nil {
fmt.Println(err.Error())
return
@@ -161,7 +192,13 @@ func main() {
// Set the game name for save states
path := strings.Split(os.Args[1], "/")
gamename = strings.Split(path[len(path)-1], ".")[0]
- game = fmt.Sprintf(".%s.state", gamename)
+ saveStateFile = fmt.Sprintf(".%s.state", gamename)
+ batteryRamFile = fmt.Sprintf(".%s.battery", gamename)
+
+ if rom.BatteryBacked() {
+ loadBatteryRam()
+ defer saveBatteryFile()
+ }
setResetVector()
} else {
12 mmc1.go
View
@@ -13,10 +13,10 @@ type Mmc1 struct {
RomBanks [][]Word
VromBanks [][]Word
- PrgBankCount int
- ChrRomCount int
- BatteryBacked bool
- Data []byte
+ PrgBankCount int
+ ChrRomCount int
+ Battery bool
+ Data []byte
Buffer int
BufferCounter uint
@@ -50,6 +50,10 @@ func (m *Mmc1) Write(v Word, a int) {
}
}
+func (m *Mmc1) BatteryBacked() bool {
+ return m.Battery
+}
+
func (m *Mmc1) SetRegister(reg int, v int) {
switch reg {
// Control register
84 rom.go
View
@@ -14,6 +14,7 @@ const (
type Mapper interface {
Write(v Word, a int)
+ BatteryBacked() bool
}
// Nrom
@@ -21,10 +22,10 @@ type Rom struct {
RomBanks [][]Word
VromBanks [][]Word
- PrgBankCount int
- ChrRomCount int
- BatteryBacked bool
- Data []byte
+ PrgBankCount int
+ ChrRomCount int
+ Battery bool
+ Data []byte
}
type Unrom Rom
@@ -46,15 +47,27 @@ func (m *Rom) Write(v Word, a int) {
// Nothing to do
}
+func (m *Rom) BatteryBacked() bool {
+ return m.Battery
+}
+
func (m *Unrom) Write(v Word, a int) {
WriteRamBank(m.RomBanks, int(v&0x7), 0x8000, Size16k)
}
+func (m *Unrom) BatteryBacked() bool {
+ return m.Battery
+}
+
func (m *Cnrom) Write(v Word, a int) {
- bank := int(v&0x3)
+ bank := int(v & 0x3)
WriteVramBank(m.VromBanks, bank, 0x0000, Size4k)
}
+func (m *Cnrom) BatteryBacked() bool {
+ return m.Battery
+}
+
func LoadRom(rom []byte) (m Mapper, e error) {
r := new(Rom)
@@ -69,20 +82,23 @@ func LoadRom(rom []byte) (m Mapper, e error) {
r.PrgBankCount = int(rom[4])
r.ChrRomCount = int(rom[5])
- fmt.Printf("PRG-ROM Count: %d\n", r.PrgBankCount)
- fmt.Printf("CHR-ROM Count: %d\n", r.ChrRomCount)
+ fmt.Printf("-----------------\nROM:\n ")
+ fmt.Printf("PRG-ROM banks: %d\n ", r.PrgBankCount)
+ fmt.Printf("CHR-ROM banks: %d\n ", r.ChrRomCount)
+
+ fmt.Printf("Mirroring: ")
switch rom[6] & 0x1 {
case 0x0:
- fmt.Println("Horizontal mirroring")
+ fmt.Printf("Horizontal\n ")
ppu.Nametables.SetMirroring(MirroringHorizontal)
case 0x1:
- fmt.Println("Vertical mirroring")
+ fmt.Printf("Vertical\n ")
ppu.Nametables.SetMirroring(MirroringVertical)
}
if (rom[6]>>0x1)&0x1 == 0x1 {
- r.BatteryBacked = true
+ r.Battery = true
}
r.Data = rom[16:]
@@ -117,7 +133,6 @@ func LoadRom(rom []byte) (m Mapper, e error) {
if r.PrgBankCount > 1 {
// and the last ROM bank
- fmt.Printf("Writing bank %d to 0xC000, base value: 0x%X\n", r.PrgBankCount-1, r.RomBanks[r.PrgBankCount-1][0])
WriteRamBank(r.RomBanks, r.PrgBankCount-1, 0xC000, Size16k)
} else {
// Or write the first ROM bank to the upper region
@@ -138,7 +153,7 @@ func LoadRom(rom []byte) (m Mapper, e error) {
// Check mapper, get the proper type
mapper := (Word(rom[6])>>4 | (Word(rom[7]) & 0xF0))
- fmt.Printf("Mapper: 0x%X\n", mapper)
+ fmt.Printf("Mapper: ")
switch mapper {
case 0x00:
fallthrough
@@ -146,44 +161,51 @@ func LoadRom(rom []byte) (m Mapper, e error) {
fallthrough
case 0x41:
// NROM
+ fmt.Printf("NROM\n")
return r, nil
case 0x01:
// MMC1
+ fmt.Printf("MMC1\n")
m = &Mmc1{
- RomBanks: r.RomBanks,
- VromBanks: r.VromBanks,
- PrgBankCount: r.PrgBankCount,
- ChrRomCount: r.ChrRomCount,
- BatteryBacked: r.BatteryBacked,
- Data: r.Data,
- PrgSwapBank: BankLower,
+ RomBanks: r.RomBanks,
+ VromBanks: r.VromBanks,
+ PrgBankCount: r.PrgBankCount,
+ ChrRomCount: r.ChrRomCount,
+ Battery: r.Battery,
+ Data: r.Data,
+ PrgSwapBank: BankLower,
}
case 0x42:
fallthrough
case 0x02:
// Unrom
+ fmt.Printf("UNROM\n")
m = &Unrom{
- RomBanks: r.RomBanks,
- VromBanks: r.VromBanks,
- PrgBankCount: r.PrgBankCount,
- ChrRomCount: r.ChrRomCount,
- BatteryBacked: r.BatteryBacked,
- Data: r.Data,
+ RomBanks: r.RomBanks,
+ VromBanks: r.VromBanks,
+ PrgBankCount: r.PrgBankCount,
+ ChrRomCount: r.ChrRomCount,
+ Battery: r.Battery,
+ Data: r.Data,
}
case 0x03:
// Cnrom
+ fmt.Printf("CNROM\n")
m = &Cnrom{
- RomBanks: r.RomBanks,
- VromBanks: r.VromBanks,
- PrgBankCount: r.PrgBankCount,
- ChrRomCount: r.ChrRomCount,
- BatteryBacked: r.BatteryBacked,
- Data: r.Data,
+ RomBanks: r.RomBanks,
+ VromBanks: r.VromBanks,
+ PrgBankCount: r.PrgBankCount,
+ ChrRomCount: r.ChrRomCount,
+ Battery: r.Battery,
+ Data: r.Data,
}
default:
// Unsupported
+ fmt.Printf("Unsupported\n")
return m, errors.New(fmt.Sprintf("Unsupported memory mapper: 0x%X", mapper))
}
+ fmt.Printf("-----------------\n")
+
return
}
Please sign in to comment.
Something went wrong with that request. Please try again.