mirror of
https://github.com/ivanizag/izapple2.git
synced 2025-01-18 03:29:52 +00:00
Reverse 6 colors mod
This commit is contained in:
parent
7cd5ce02ec
commit
5cf351f05c
@ -19,6 +19,7 @@ type Apple2 struct {
|
|||||||
softVideoSwitch *SoftVideoSwitch
|
softVideoSwitch *SoftVideoSwitch
|
||||||
board string
|
board string
|
||||||
isApple2e bool
|
isApple2e bool
|
||||||
|
isFourColors bool // An Apple II without the 6 color mod
|
||||||
commandChannel chan command
|
commandChannel chan command
|
||||||
|
|
||||||
cycleDurationNs float64 // Current speed. Inverse of the cpu clock in Ghz
|
cycleDurationNs float64 // Current speed. Inverse of the cpu clock in Ghz
|
||||||
|
@ -5,6 +5,7 @@ profile: false
|
|||||||
forceCaps: false
|
forceCaps: false
|
||||||
ramworks: none
|
ramworks: none
|
||||||
nsc: none
|
nsc: none
|
||||||
|
mods:
|
||||||
rgb: false
|
rgb: false
|
||||||
romx: false
|
romx: false
|
||||||
chargenmap: 2e
|
chargenmap: 2e
|
||||||
|
@ -6,6 +6,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
const configSuffix = ".cfg"
|
const configSuffix = ".cfg"
|
||||||
@ -28,6 +30,7 @@ const (
|
|||||||
confForceCaps = "forceCaps"
|
confForceCaps = "forceCaps"
|
||||||
confRgb = "rgb"
|
confRgb = "rgb"
|
||||||
confRomx = "romx"
|
confRomx = "romx"
|
||||||
|
confMods = "mods"
|
||||||
confS0 = "s0"
|
confS0 = "s0"
|
||||||
confS1 = "s1"
|
confS1 = "s1"
|
||||||
confS2 = "s2"
|
confS2 = "s2"
|
||||||
@ -204,6 +207,7 @@ func getConfigurationFromCommandLine() (*configuration, string, error) {
|
|||||||
confCharRom: "rom file for the character generator",
|
confCharRom: "rom file for the character generator",
|
||||||
confCpu: "cpu type, can be '6502' or '65c02'",
|
confCpu: "cpu type, can be '6502' or '65c02'",
|
||||||
confSpeed: "cpu speed in Mhz, can be 'ntsc', 'pal', 'full' or a decimal nunmber",
|
confSpeed: "cpu speed in Mhz, can be 'ntsc', 'pal', 'full' or a decimal nunmber",
|
||||||
|
confMods: "comma separated list of mods applied to the board, available mods are 'shift', 'four-colors",
|
||||||
confRamworks: "memory to use with RAMWorks card, max is 16384",
|
confRamworks: "memory to use with RAMWorks card, max is 16384",
|
||||||
confNsc: "add a DS1216 No-Slot-Clock on the main ROM (use 'main') or a slot ROM",
|
confNsc: "add a DS1216 No-Slot-Clock on the main ROM (use 'main') or a slot ROM",
|
||||||
confTrace: "trace CPU execution with one or more comma separated tracers",
|
confTrace: "trace CPU execution with one or more comma separated tracers",
|
||||||
@ -221,10 +225,6 @@ func getConfigurationFromCommandLine() (*configuration, string, error) {
|
|||||||
confS7: "slot 7 configuration.",
|
confS7: "slot 7 configuration.",
|
||||||
}
|
}
|
||||||
|
|
||||||
stringParams := []string{
|
|
||||||
confRom, confCharRom, confCpu, confSpeed, confRamworks, confNsc, confTrace, confModel,
|
|
||||||
confS0, confS1, confS2, confS3, confS4, confS5, confS6, confS7,
|
|
||||||
}
|
|
||||||
boolParams := []string{confProfile, confForceCaps, confRgb, confRomx}
|
boolParams := []string{confProfile, confForceCaps, confRgb, confRomx}
|
||||||
|
|
||||||
configuration, err := configurationModels.getFromModel(defaultConfiguration)
|
configuration, err := configurationModels.getFromModel(defaultConfiguration)
|
||||||
@ -233,20 +233,16 @@ func getConfigurationFromCommandLine() (*configuration, string, error) {
|
|||||||
}
|
}
|
||||||
configuration.set(confModel, defaultConfiguration)
|
configuration.set(confModel, defaultConfiguration)
|
||||||
|
|
||||||
for _, name := range stringParams {
|
for name, description := range paramDescription {
|
||||||
defaultValue, ok := configuration.getHas(name)
|
defaultValue, ok := configuration.getHas(name)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, "", fmt.Errorf("default value not found for %s", name)
|
return nil, "", fmt.Errorf("default value not found for %s", name)
|
||||||
}
|
}
|
||||||
flag.String(name, defaultValue, paramDescription[name])
|
if slices.Contains(boolParams, name) {
|
||||||
}
|
flag.Bool(name, defaultValue == "true", description)
|
||||||
|
} else {
|
||||||
for _, name := range boolParams {
|
flag.String(name, defaultValue, description)
|
||||||
defaultValue, ok := configuration.getHas(name)
|
|
||||||
if !ok {
|
|
||||||
return nil, "", fmt.Errorf("default value not found for %s", name)
|
|
||||||
}
|
}
|
||||||
flag.Bool(name, defaultValue == "true", paramDescription[name])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
flag.Usage = func() {
|
flag.Usage = func() {
|
||||||
|
@ -124,11 +124,15 @@ func (k *sdlKeyboard) putKey(keyEvent *sdl.KeyboardEvent) {
|
|||||||
case sdl.K_F12:
|
case sdl.K_F12:
|
||||||
fallthrough
|
fallthrough
|
||||||
case sdl.K_PRINTSCREEN:
|
case sdl.K_PRINTSCREEN:
|
||||||
err := screen.SaveSnapshot(k.a, screen.ScreenModeNTSC, "snapshot.png")
|
if ctrl {
|
||||||
if err != nil {
|
screen.AddScenario(k.a, "../../screen/test_resources/")
|
||||||
fmt.Printf("Error saving snapshoot: %v.\n.", err)
|
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Saving snapshot 'snapshot.png'")
|
err := screen.SaveSnapshot(k.a, screen.ScreenModeNTSC, "snapshot.png")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error saving snapshoot: %v.\n.", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Saving snapshot 'snapshot.png'")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case sdl.K_PAUSE:
|
case sdl.K_PAUSE:
|
||||||
k.a.SendCommand(izapple2.CommandPauseUnpause)
|
k.a.SendCommand(izapple2.CommandPauseUnpause)
|
||||||
|
@ -117,7 +117,7 @@ func (mmu *memoryManager) accessCArea(address uint16) memoryHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (mmu *memoryManager) accessUpperRAMArea(address uint16) memoryHandler {
|
func (mmu *memoryManager) accessUpperRAMArea(address uint16) memoryHandler {
|
||||||
if mmu.altZeroPage {
|
if mmu.altZeroPage && mmu.hasExtendedRAM() {
|
||||||
// Use extended RAM
|
// Use extended RAM
|
||||||
block := mmu.extendedRAMBlock
|
block := mmu.extendedRAMBlock
|
||||||
if mmu.lcAltBank && address <= addressLimitDArea {
|
if mmu.lcAltBank && address <= addressLimitDArea {
|
||||||
@ -135,14 +135,14 @@ func (mmu *memoryManager) accessUpperRAMArea(address uint16) memoryHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (mmu *memoryManager) getPhysicalMainRAM(ext bool) memoryHandler {
|
func (mmu *memoryManager) getPhysicalMainRAM(ext bool) memoryHandler {
|
||||||
if ext {
|
if ext && mmu.hasExtendedRAM() {
|
||||||
return mmu.physicalExtRAM[mmu.extendedRAMBlock]
|
return mmu.physicalExtRAM[mmu.extendedRAMBlock]
|
||||||
}
|
}
|
||||||
return mmu.physicalMainRAM
|
return mmu.physicalMainRAM
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mmu *memoryManager) getVideoRAM(ext bool) *memoryRange {
|
func (mmu *memoryManager) getVideoRAM(ext bool) *memoryRange {
|
||||||
if ext {
|
if ext && mmu.hasExtendedRAM() {
|
||||||
// The video memory uses the first extended RAM block, even with RAMWorks
|
// The video memory uses the first extended RAM block, even with RAMWorks
|
||||||
return mmu.physicalExtRAM[0]
|
return mmu.physicalExtRAM[0]
|
||||||
}
|
}
|
||||||
@ -334,6 +334,10 @@ func (mmu *memoryManager) setExtendedRAMActiveBlock(block uint8) {
|
|||||||
mmu.extendedRAMBlock = block
|
mmu.extendedRAMBlock = block
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mmu *memoryManager) hasExtendedRAM() bool {
|
||||||
|
return len(mmu.physicalExtRAM) > 0
|
||||||
|
}
|
||||||
|
|
||||||
func (mmu *memoryManager) reset() {
|
func (mmu *memoryManager) reset() {
|
||||||
if mmu.apple2.isApple2e {
|
if mmu.apple2.isApple2e {
|
||||||
// MMU UtA2e 4-14, 5-22
|
// MMU UtA2e 4-14, 5-22
|
||||||
|
@ -12,9 +12,9 @@ const (
|
|||||||
hiResHeightMixed = 160
|
hiResHeightMixed = 160
|
||||||
)
|
)
|
||||||
|
|
||||||
func snapshotHiRes(vs VideoSource, isSecondPage bool, light color.Color) *image.RGBA {
|
func snapshotHiRes(vs VideoSource, isSecondPage bool, light color.Color, shiftSupported bool) *image.RGBA {
|
||||||
data := vs.GetVideoMemory(isSecondPage, false)
|
data := vs.GetVideoMemory(isSecondPage, false)
|
||||||
return renderHiRes(data, light)
|
return renderHiRes(data, light, shiftSupported)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getHiResLineOffset(line int) uint16 {
|
func getHiResLineOffset(line int) uint16 {
|
||||||
@ -26,7 +26,7 @@ func getHiResLineOffset(line int) uint16 {
|
|||||||
return uint16(section*40 + outerEighth*0x80 + innerEighth*0x400)
|
return uint16(section*40 + outerEighth*0x80 + innerEighth*0x400)
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderHiRes(data []uint8, light color.Color) *image.RGBA {
|
func renderHiRes(data []uint8, light color.Color, shiftSupported bool) *image.RGBA {
|
||||||
// As described in "Undertanding the Apple II", with half pixel shifts
|
// As described in "Undertanding the Apple II", with half pixel shifts
|
||||||
size := image.Rect(0, 0, 2*hiResWidth, hiResHeight)
|
size := image.Rect(0, 0, 2*hiResWidth, hiResHeight)
|
||||||
img := image.NewRGBA(size)
|
img := image.NewRGBA(size)
|
||||||
@ -37,7 +37,7 @@ func renderHiRes(data []uint8, light color.Color) *image.RGBA {
|
|||||||
x := 0
|
x := 0
|
||||||
var previousColour color.Color = color.Black
|
var previousColour color.Color = color.Black
|
||||||
for _, b := range bytes {
|
for _, b := range bytes {
|
||||||
shifted := b>>7 == 1
|
shifted := shiftSupported && b>>7 == 1
|
||||||
for j := uint(0); j < 7; j++ {
|
for j := uint(0); j < 7; j++ {
|
||||||
bit := (b >> j) & 1
|
bit := (b >> j) & 1
|
||||||
colour := light
|
colour := light
|
||||||
|
@ -52,6 +52,7 @@ func snapshotByMode(vs VideoSource, videoMode uint16, screenMode int) *image.RGB
|
|||||||
isSecondPage := (videoMode & VideoSecondPage) != 0
|
isSecondPage := (videoMode & VideoSecondPage) != 0
|
||||||
isAltText := (videoMode & VideoAltText) != 0
|
isAltText := (videoMode & VideoAltText) != 0
|
||||||
isRGBCard := (videoMode & VideoRGBCard) != 0
|
isRGBCard := (videoMode & VideoRGBCard) != 0
|
||||||
|
shiftSupported := (videoMode & VideoFourColors) == 0
|
||||||
|
|
||||||
var lightColor color.Color = color.White
|
var lightColor color.Color = color.White
|
||||||
if screenMode == ScreenModeGreen {
|
if screenMode == ScreenModeGreen {
|
||||||
@ -76,7 +77,7 @@ func snapshotByMode(vs VideoSource, videoMode uint16, screenMode int) *image.RGB
|
|||||||
case VideoDGR:
|
case VideoDGR:
|
||||||
snap = snapshotMeRes(vs, isSecondPage, lightColor)
|
snap = snapshotMeRes(vs, isSecondPage, lightColor)
|
||||||
case VideoHGR:
|
case VideoHGR:
|
||||||
snap = snapshotHiRes(vs, isSecondPage, lightColor)
|
snap = snapshotHiRes(vs, isSecondPage, lightColor, shiftSupported)
|
||||||
case VideoDHGR:
|
case VideoDHGR:
|
||||||
snap, _ = snapshotDoubleHiRes(vs, isSecondPage, false /*isRGBMixMode*/, lightColor)
|
snap, _ = snapshotDoubleHiRes(vs, isSecondPage, false /*isRGBMixMode*/, lightColor)
|
||||||
case VideoMono560:
|
case VideoMono560:
|
||||||
|
@ -85,6 +85,10 @@ func VideoModeName(vs VideoSource) string {
|
|||||||
name += "-ALT"
|
name += "-ALT"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (videoMode & VideoFourColors) != 0 {
|
||||||
|
name += "-4COLORS"
|
||||||
|
}
|
||||||
|
|
||||||
switch mixMode {
|
switch mixMode {
|
||||||
case VideoMixText40:
|
case VideoMixText40:
|
||||||
name += "-MIX40"
|
name += "-MIX40"
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
"image/png"
|
"image/png"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@ -58,7 +57,7 @@ func cloneSlice(src []uint8) []uint8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func loadTestScenario(filename string) (*TestScenario, error) {
|
func loadTestScenario(filename string) (*TestScenario, error) {
|
||||||
bytes, err := ioutil.ReadFile(filename)
|
bytes, err := os.ReadFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -79,7 +78,7 @@ func (ts *TestScenario) save(dir string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pattern := fmt.Sprintf("%v_*.json", strings.ToLower(ts.VideoModeName))
|
pattern := fmt.Sprintf("%v_*.json", strings.ToLower(ts.VideoModeName))
|
||||||
file, err := ioutil.TempFile(dir, pattern)
|
file, err := os.CreateTemp(dir, pattern)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
1
screen/test_resources/hgr-4colors_455831825.json
Normal file
1
screen/test_resources/hgr-4colors_455831825.json
Normal file
File diff suppressed because one or more lines are too long
BIN
screen/test_resources/hgr-4colors_455831825green.png
Normal file
BIN
screen/test_resources/hgr-4colors_455831825green.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
screen/test_resources/hgr-4colors_455831825ntsc.png
Normal file
BIN
screen/test_resources/hgr-4colors_455831825ntsc.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
screen/test_resources/hgr-4colors_455831825plain.png
Normal file
BIN
screen/test_resources/hgr-4colors_455831825plain.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
1
screen/test_resources/hgr_1008339458.json
Normal file
1
screen/test_resources/hgr_1008339458.json
Normal file
File diff suppressed because one or more lines are too long
BIN
screen/test_resources/hgr_1008339458green.png
Normal file
BIN
screen/test_resources/hgr_1008339458green.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
BIN
screen/test_resources/hgr_1008339458ntsc.png
Normal file
BIN
screen/test_resources/hgr_1008339458ntsc.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
BIN
screen/test_resources/hgr_1008339458plain.png
Normal file
BIN
screen/test_resources/hgr_1008339458plain.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
@ -36,6 +36,7 @@ const (
|
|||||||
VideoSecondPage uint16 = 0x1000
|
VideoSecondPage uint16 = 0x1000
|
||||||
VideoAltText uint16 = 0x2000
|
VideoAltText uint16 = 0x2000
|
||||||
VideoRGBCard uint16 = 0x4000
|
VideoRGBCard uint16 = 0x4000
|
||||||
|
VideoFourColors uint16 = 0x8000
|
||||||
)
|
)
|
||||||
|
|
||||||
// VideoSource provides the info to build the video output
|
// VideoSource provides the info to build the video output
|
||||||
|
14
setup.go
14
setup.go
@ -3,6 +3,7 @@ package izapple2
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/ivanizag/iz6502"
|
"github.com/ivanizag/iz6502"
|
||||||
)
|
)
|
||||||
@ -62,6 +63,19 @@ func configure(configuration *configuration) (*Apple2, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add mods
|
||||||
|
mods := strings.Split(configuration.get(confMods), ",")
|
||||||
|
for _, mod := range mods {
|
||||||
|
switch strings.TrimSpace(mod) {
|
||||||
|
//case "shift":
|
||||||
|
// setupShiftedKeyboard(a)
|
||||||
|
case "four-colors":
|
||||||
|
// This removes the mod to have 6 colors sent by Wozniak to Byte
|
||||||
|
// magazine. See: https://archive.org/details/byte-magazine-1979-06/page/n67/mode/2up?view=theater
|
||||||
|
a.isFourColors = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add optional accesories including the aux slot
|
// Add optional accesories including the aux slot
|
||||||
ramWorksSize := configuration.get(confRamworks)
|
ramWorksSize := configuration.get(confRamworks)
|
||||||
if ramWorksSize != "" && ramWorksSize != "none" {
|
if ramWorksSize != "" && ramWorksSize != "none" {
|
||||||
|
@ -92,6 +92,9 @@ func (a *Apple2) GetCurrentVideoMode() uint16 {
|
|||||||
if isRGBCard {
|
if isRGBCard {
|
||||||
mode |= screen.VideoRGBCard
|
mode |= screen.VideoRGBCard
|
||||||
}
|
}
|
||||||
|
if a.isFourColors {
|
||||||
|
mode |= screen.VideoFourColors
|
||||||
|
}
|
||||||
|
|
||||||
return mode
|
return mode
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user