mirror of
https://github.com/JetSetIlly/Gopher2600.git
synced 2024-05-20 05:40:49 -04:00
84ad23c03e
this means that a mapper only needs to implement the Patch() if it makes sense mappers that don't need it have had the Patch function removed. implemented function for SCABS and UA corrected error messages for atari mappers - some messages weren't referencing the correct atari mapper and simply stated "atari"
217 lines
5.8 KiB
Go
217 lines
5.8 KiB
Go
// This file is part of Gopher2600.
|
|
//
|
|
// Gopher2600 is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Gopher2600 is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Gopher2600. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
package cartridge
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/jetsetilly/gopher2600/environment"
|
|
"github.com/jetsetilly/gopher2600/hardware/memory/cartridge/mapper"
|
|
"github.com/jetsetilly/gopher2600/hardware/memory/memorymap"
|
|
"github.com/jetsetilly/gopher2600/logger"
|
|
)
|
|
|
|
// from http://www.taswegian.com/WoodgrainWizard/tiki-index.php?page=CV
|
|
//
|
|
// $F000-$F3FF read from RAM
|
|
// $F400-$F7FF write to RAM
|
|
// $F800-$FFFF ROM
|
|
//
|
|
// this seems to be the same principle as other simple RAM cartridges, like the
|
|
// Atari Superchip or CBS cartridges
|
|
//
|
|
// from bankswitch_sizes.txt:
|
|
//
|
|
// cartridges:
|
|
// - MagiCard
|
|
// - Video Lfe
|
|
//
|
|
// and the reason why I implemented this format for Gopher2600:
|
|
//
|
|
// https://forums.atariage.com/topic/342021-new-512-bytes-demo-released-gar-nix/
|
|
type commavid struct {
|
|
env *environment.Environment
|
|
|
|
mappingID string
|
|
|
|
bankSize int
|
|
bankData []uint8
|
|
|
|
// rewindable state
|
|
state *commavidState
|
|
}
|
|
|
|
func newCommaVid(env *environment.Environment, data []byte) (mapper.CartMapper, error) {
|
|
cart := &commavid{
|
|
env: env,
|
|
bankSize: 4096,
|
|
mappingID: "CV",
|
|
state: newCommaVidState(),
|
|
}
|
|
|
|
cart.bankData = make([]uint8, cart.bankSize)
|
|
if len(data) < 2048 {
|
|
// place undersized binaries at the end of memory
|
|
copy(cart.bankData[4096-len(data):], data)
|
|
logger.Logf("CV", "placing undersized commavid data at end of cartridge memory")
|
|
} else if len(data) == 2048 {
|
|
copy(cart.bankData[2048:], data[:2048])
|
|
logger.Logf("CV", "placing 2k commavid data at end of cartridge memory")
|
|
} else {
|
|
return nil, fmt.Errorf("CV: unhandled size for commavid cartridges (%d)", len(data))
|
|
}
|
|
|
|
return cart, nil
|
|
}
|
|
|
|
// MappedBanks implements the mapper.CartMapper interface.
|
|
func (cart *commavid) MappedBanks() string {
|
|
return fmt.Sprintf("Bank: 0")
|
|
}
|
|
|
|
// ID implements the mapper.CartMapper interface.
|
|
func (cart *commavid) ID() string {
|
|
return cart.mappingID
|
|
}
|
|
|
|
// Snapshot implements the mapper.CartMapper interface.
|
|
func (cart *commavid) Snapshot() mapper.CartMapper {
|
|
n := *cart
|
|
n.state = cart.state.Snapshot()
|
|
return &n
|
|
}
|
|
|
|
// Plumb implements the mapper.CartMapper interface.
|
|
func (cart *commavid) Plumb(env *environment.Environment) {
|
|
cart.env = env
|
|
}
|
|
|
|
// Reset implements the mapper.CartMapper interface.
|
|
func (cart *commavid) Reset() {
|
|
// always starting with random state. this is because Video Life, one of
|
|
// the few original CommaVid cartridges, expects it for the opening effect
|
|
for i := range cart.state.ram {
|
|
cart.state.ram[i] = uint8(cart.env.Random.NoRewind(0xff))
|
|
}
|
|
}
|
|
|
|
// Access implements the mapper.CartMapper interface.
|
|
func (cart *commavid) Access(addr uint16, _ bool) (uint8, uint8, error) {
|
|
if addr >= 0x0000 && addr <= 0x03ff {
|
|
return cart.state.ram[addr], mapper.CartDrivenPins, nil
|
|
}
|
|
if addr >= 0x0400 && addr <= 0x07ff {
|
|
return 0, 0, nil
|
|
}
|
|
|
|
return cart.bankData[addr], mapper.CartDrivenPins, nil
|
|
}
|
|
|
|
// AccessVolatile implements the mapper.CartMapper interface.
|
|
func (cart *commavid) AccessVolatile(addr uint16, data uint8, poke bool) error {
|
|
if addr >= 0x0400 && addr <= 0x07ff {
|
|
cart.state.ram[addr&0x03ff] = data
|
|
return nil
|
|
}
|
|
|
|
if poke {
|
|
cart.bankData[addr] = data
|
|
return nil
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// NumBanks implements the mapper.CartMapper interface.
|
|
func (cart *commavid) NumBanks() int {
|
|
return 1
|
|
}
|
|
|
|
// GetBank implements the mapper.CartMapper interface.
|
|
func (cart *commavid) GetBank(addr uint16) mapper.BankInfo {
|
|
// commavid cartridges are like atari cartridges in that the entire address
|
|
// space points to the selected bank
|
|
return mapper.BankInfo{Number: 0, IsRAM: addr <= 0x07ff}
|
|
}
|
|
|
|
// Patch implements the mapper.CartPatchable interface
|
|
func (cart *commavid) Patch(offset int, data uint8) error {
|
|
if offset >= cart.bankSize {
|
|
return fmt.Errorf("CV: patch offset too high (%d)", offset)
|
|
}
|
|
cart.bankData[offset] = data
|
|
return nil
|
|
}
|
|
|
|
// AccessPassive implements the mapper.CartMapper interface.
|
|
func (cart *commavid) AccessPassive(addr uint16, data uint8) error {
|
|
return nil
|
|
}
|
|
|
|
// Step implements the mapper.CartMapper interface.
|
|
func (cart *commavid) Step(_ float32) {
|
|
}
|
|
|
|
// GetRAM implements the mapper.CartRAMBus interface.
|
|
func (cart *commavid) GetRAM() []mapper.CartRAM {
|
|
r := make([]mapper.CartRAM, 1)
|
|
r[0] = mapper.CartRAM{
|
|
Label: "CommaVid",
|
|
Origin: 0x0,
|
|
Data: make([]uint8, len(cart.state.ram)),
|
|
Mapped: true,
|
|
}
|
|
copy(r[0].Data, cart.state.ram)
|
|
return r
|
|
}
|
|
|
|
// PutRAM implements the mapper.CartRAMBus interface.
|
|
func (cart *commavid) PutRAM(_ int, idx int, data uint8) {
|
|
cart.state.ram[idx] = data
|
|
}
|
|
|
|
// IterateBank implements the mapper.CartMapper interface.
|
|
func (cart *commavid) CopyBanks() []mapper.BankContent {
|
|
c := make([]mapper.BankContent, 1)
|
|
c[0] = mapper.BankContent{Number: 0,
|
|
Data: cart.bankData,
|
|
Origins: []uint16{memorymap.OriginCart},
|
|
}
|
|
return c
|
|
}
|
|
|
|
// rewindable state for commavid cartridges
|
|
type commavidState struct {
|
|
// commavid cartridges are distinguished for having 1k of onboard ram
|
|
ram []uint8
|
|
}
|
|
|
|
func newCommaVidState() *commavidState {
|
|
const commavidRAMsize = 1024
|
|
|
|
return &commavidState{
|
|
ram: make([]uint8, commavidRAMsize),
|
|
}
|
|
}
|
|
|
|
// Snapshot implements the mapper.CartMapper interface.
|
|
func (s *commavidState) Snapshot() *commavidState {
|
|
n := *s
|
|
n.ram = make([]uint8, len(s.ram))
|
|
copy(n.ram, s.ram)
|
|
return &n
|
|
}
|