Test boot process for all models
This commit is contained in:
parent
9d6393f078
commit
cde673a552
|
@ -0,0 +1,37 @@
|
|||
package izapple2
|
||||
|
||||
import (
|
||||
"github.com/ivanizag/izapple2/screen"
|
||||
)
|
||||
|
||||
type apple2Tester struct {
|
||||
a *Apple2
|
||||
terminateCondition func(a *Apple2) bool
|
||||
}
|
||||
|
||||
func makeApple2Tester(model string) *apple2Tester {
|
||||
a := newApple2()
|
||||
a.setup(0, true) // Full speed
|
||||
initModel(a, model, defaultInternal, defaultInternal)
|
||||
|
||||
a.AddLanguageCard(0)
|
||||
|
||||
var at apple2Tester
|
||||
at.a = a
|
||||
a.addTracer(&at)
|
||||
return &at
|
||||
}
|
||||
|
||||
func (at *apple2Tester) inspect() {
|
||||
if at.terminateCondition(at.a) {
|
||||
at.a.SendCommand(CommandKill)
|
||||
}
|
||||
}
|
||||
|
||||
func (at *apple2Tester) run() {
|
||||
at.a.Run()
|
||||
}
|
||||
|
||||
func (at *apple2Tester) getText() string {
|
||||
return screen.RenderTextModeString(at.a, false, false, false, at.a.isApple2e)
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
package izapple2
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPlusBoots(t *testing.T) {
|
||||
at := makeApple2Tester("2plus")
|
||||
at.terminateCondition = func(a *Apple2) bool {
|
||||
return a.cpu.GetCycles() > 200_000
|
||||
}
|
||||
at.run()
|
||||
|
||||
text := at.getText()
|
||||
if !strings.Contains(text, "APPLE ][") {
|
||||
t.Errorf("Expected 'APPLE ][', got '%s'", text)
|
||||
}
|
||||
if !strings.Contains(text, "\n]") {
|
||||
t.Errorf("Expected ] prompt, got '%s'", text)
|
||||
}
|
||||
}
|
||||
|
||||
func Test2EBoots(t *testing.T) {
|
||||
at := makeApple2Tester("2e")
|
||||
at.terminateCondition = func(a *Apple2) bool {
|
||||
return a.cpu.GetCycles() > 200_000
|
||||
}
|
||||
at.run()
|
||||
|
||||
text := at.getText()
|
||||
if !strings.Contains(text, "Apple ][") {
|
||||
t.Errorf("Expected 'Apple ][', got '%s'", text)
|
||||
}
|
||||
if !strings.Contains(text, "\n]") {
|
||||
t.Errorf("Expected ] prompt, got '%s'", text)
|
||||
}
|
||||
}
|
||||
|
||||
func Test2EnhancedBoots(t *testing.T) {
|
||||
at := makeApple2Tester("2enh")
|
||||
at.terminateCondition = func(a *Apple2) bool {
|
||||
return a.cpu.GetCycles() > 200_000
|
||||
}
|
||||
at.run()
|
||||
|
||||
text := at.getText()
|
||||
if !strings.Contains(text, "Apple //e") {
|
||||
t.Errorf("Expected 'Apple //e', got '%s'", text)
|
||||
}
|
||||
if !strings.Contains(text, "\n]") {
|
||||
t.Errorf("Expected ] prompt, got '%s'", text)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBase64Boots(t *testing.T) {
|
||||
at := makeApple2Tester("base64a")
|
||||
at.terminateCondition = func(a *Apple2) bool {
|
||||
return a.cpu.GetCycles() > 1_000_000
|
||||
}
|
||||
at.run()
|
||||
|
||||
text := at.getText()
|
||||
if !strings.Contains(text, "BASE 64A") {
|
||||
t.Errorf("Expected 'BASE 64A', got '%s'", text)
|
||||
}
|
||||
if !strings.Contains(text, "\n]") {
|
||||
t.Errorf("Expected ] prompt, got '%s'", text)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPlusDOS33Boots(t *testing.T) {
|
||||
at := makeApple2Tester("2plus")
|
||||
|
||||
err := at.a.AddDisk2(6, "<internal>/dos33.dsk", "")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
at.terminateCondition = func(a *Apple2) bool {
|
||||
return a.cpu.GetCycles() > 100_000_000
|
||||
}
|
||||
at.run()
|
||||
|
||||
text := at.getText()
|
||||
if !strings.Contains(text, "DOS VERSION 3.3") {
|
||||
t.Errorf("Expected 'APPLE ][', got '%s'", text)
|
||||
}
|
||||
if !strings.Contains(text, "\n]") {
|
||||
t.Errorf("Expected ] prompt, got '%s'", text)
|
||||
}
|
||||
}
|
144
apple2main.go
144
apple2main.go
|
@ -189,86 +189,24 @@ func MainApple() *Apple2 {
|
|||
a.addTracer(newTraceApplecorn(a, false))
|
||||
}
|
||||
|
||||
var charGenMap charColumnMap
|
||||
initialCharGenPage := 0
|
||||
initModel(a, *model, *romFile, *charRomFile)
|
||||
a.cpu.SetTrace(*traceCPU)
|
||||
|
||||
// Disable incompatible cards
|
||||
switch *model {
|
||||
case "2plus":
|
||||
setApple2plus(a)
|
||||
if *romFile == defaultInternal {
|
||||
*romFile = "<internal>/Apple2_Plus.rom"
|
||||
}
|
||||
if *charRomFile == defaultInternal {
|
||||
*charRomFile = "<internal>/Apple2rev7CharGen.rom"
|
||||
}
|
||||
charGenMap = charGenColumnsMap2Plus
|
||||
*vidHDCardSlot = -1
|
||||
|
||||
case "2e":
|
||||
setApple2e(a)
|
||||
if *romFile == defaultInternal {
|
||||
*romFile = "<internal>/Apple2e.rom"
|
||||
}
|
||||
if *charRomFile == defaultInternal {
|
||||
*charRomFile = "<internal>/Apple IIe Video Unenhanced - 342-0133-A - 2732.bin"
|
||||
}
|
||||
a.isApple2e = true
|
||||
charGenMap = charGenColumnsMap2e
|
||||
|
||||
*videxCardSlot = -1
|
||||
case "2enh":
|
||||
setApple2eEnhanced(a)
|
||||
if *romFile == defaultInternal {
|
||||
*romFile = "<internal>/Apple2e_Enhanced.rom"
|
||||
}
|
||||
if *charRomFile == defaultInternal {
|
||||
*charRomFile = "<internal>/Apple IIe Video Enhanced - 342-0265-A - 2732.bin"
|
||||
}
|
||||
a.isApple2e = true
|
||||
charGenMap = charGenColumnsMap2e
|
||||
|
||||
*videxCardSlot = -1
|
||||
case "base64a":
|
||||
setBase64a(a)
|
||||
if *romFile == defaultInternal {
|
||||
err := loadBase64aRom(a)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
*romFile = ""
|
||||
}
|
||||
if *charRomFile == defaultInternal {
|
||||
*charRomFile = "<internal>/BASE64A_ROM7_CharGen.BIN"
|
||||
initialCharGenPage = 1
|
||||
}
|
||||
charGenMap = charGenColumnsMapBase64a
|
||||
*vidHDCardSlot = -1
|
||||
*videxCardSlot = -1 // The videx firmware crashes the BASE64A, probably by use of ANN0
|
||||
|
||||
default:
|
||||
panic("Model not supported")
|
||||
}
|
||||
|
||||
if a.isApple2e {
|
||||
// Videx not used on Apple IIe
|
||||
*videxCardSlot = -1
|
||||
}
|
||||
|
||||
a.cpu.SetTrace(*traceCPU)
|
||||
|
||||
// Load ROM if not loaded already
|
||||
if *romFile != "" {
|
||||
err := a.LoadRom(*romFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Load character generator if it loaded already
|
||||
cg, err := newCharacterGenerator(*charRomFile, charGenMap, a.isApple2e)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
cg.setPage(initialCharGenPage)
|
||||
a.cg = cg
|
||||
|
||||
// Externsion cards
|
||||
if *languageCardSlot >= 0 {
|
||||
a.AddLanguageCard(*languageCardSlot)
|
||||
|
@ -362,3 +300,73 @@ func MainApple() *Apple2 {
|
|||
|
||||
return a
|
||||
}
|
||||
|
||||
func initModel(a *Apple2, model string, romFile string, charRomFile string) {
|
||||
var charGenMap charColumnMap
|
||||
initialCharGenPage := 0
|
||||
switch model {
|
||||
case "2plus":
|
||||
setApple2plus(a)
|
||||
if romFile == defaultInternal {
|
||||
romFile = "<internal>/Apple2_Plus.rom"
|
||||
}
|
||||
if charRomFile == defaultInternal {
|
||||
charRomFile = "<internal>/Apple2rev7CharGen.rom"
|
||||
}
|
||||
charGenMap = charGenColumnsMap2Plus
|
||||
|
||||
case "2e":
|
||||
setApple2e(a)
|
||||
if romFile == defaultInternal {
|
||||
romFile = "<internal>/Apple2e.rom"
|
||||
}
|
||||
if charRomFile == defaultInternal {
|
||||
charRomFile = "<internal>/Apple IIe Video Unenhanced - 342-0133-A - 2732.bin"
|
||||
}
|
||||
charGenMap = charGenColumnsMap2e
|
||||
|
||||
case "2enh":
|
||||
setApple2eEnhanced(a)
|
||||
if romFile == defaultInternal {
|
||||
romFile = "<internal>/Apple2e_Enhanced.rom"
|
||||
}
|
||||
if charRomFile == defaultInternal {
|
||||
charRomFile = "<internal>/Apple IIe Video Enhanced - 342-0265-A - 2732.bin"
|
||||
}
|
||||
charGenMap = charGenColumnsMap2e
|
||||
|
||||
case "base64a":
|
||||
setBase64a(a)
|
||||
if romFile == defaultInternal {
|
||||
err := loadBase64aRom(a)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
romFile = ""
|
||||
}
|
||||
if charRomFile == defaultInternal {
|
||||
charRomFile = "<internal>/BASE64A_ROM7_CharGen.BIN"
|
||||
initialCharGenPage = 1
|
||||
}
|
||||
charGenMap = charGenColumnsMapBase64a
|
||||
|
||||
default:
|
||||
panic("Model not supported")
|
||||
}
|
||||
|
||||
// Load ROM if not loaded already
|
||||
if romFile != "" {
|
||||
err := a.LoadRom(romFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Load character generator if it loaded already
|
||||
cg, err := newCharacterGenerator(charRomFile, charGenMap, a.isApple2e)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
cg.setPage(initialCharGenPage)
|
||||
a.cg = cg
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ func RenderTextModeAnsi(vs VideoSource, is80Columns bool, isSecondPage bool, isA
|
|||
line := ""
|
||||
for c := 0; c < columns; c++ {
|
||||
char := text[l*columns+c]
|
||||
line += textMemoryByteToString(char, isAltText, isApple2e)
|
||||
line += textMemoryByteToString(char, isAltText, isApple2e, true)
|
||||
}
|
||||
content += fmt.Sprintf("# %v #\n", line)
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ $e0-$ff Low Nor Low Nor Low Nor Low Nor
|
|||
----------------------------------------------------
|
||||
*/
|
||||
|
||||
func textMemoryByteToString(value uint8, isAltCharSet bool, isApple2e bool) string {
|
||||
func textMemoryByteToString(value uint8, isAltCharSet bool, isApple2e bool, ansi bool) string {
|
||||
// Normal, inverse or flash
|
||||
topBits := value >> 6
|
||||
isInverse := topBits == 0
|
||||
|
@ -80,13 +80,13 @@ func textMemoryByteToString(value uint8, isAltCharSet bool, isApple2e bool) stri
|
|||
value = '_'
|
||||
}
|
||||
|
||||
if isFlash {
|
||||
if ansi && isFlash {
|
||||
if value == ' ' {
|
||||
// Flashing space in Apple is the full box. It can't be done with ANSI codes
|
||||
value = '_'
|
||||
}
|
||||
return fmt.Sprintf("\033[5m%v\033[0m", string(value))
|
||||
} else if isInverse {
|
||||
} else if ansi && isInverse {
|
||||
return fmt.Sprintf("\033[7m%v\033[0m", string(value))
|
||||
} else {
|
||||
return string(value)
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
package screen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// RenderTextModeString returns the text mode contents ignoring reverse and flash
|
||||
func RenderTextModeString(vs VideoSource, is80Columns bool, isSecondPage bool, isAltText bool, isApple2e bool) string {
|
||||
|
||||
var text []uint8
|
||||
if is80Columns {
|
||||
text = getText80FromMemory(vs, isSecondPage)
|
||||
} else {
|
||||
text = getTextFromMemory(vs, isSecondPage, false)
|
||||
}
|
||||
columns := len(text) / textLines
|
||||
|
||||
content := ""
|
||||
for l := 0; l < textLines; l++ {
|
||||
line := ""
|
||||
for c := 0; c < columns; c++ {
|
||||
char := text[l*columns+c]
|
||||
line += textMemoryByteToString(char, isAltText, isApple2e, false)
|
||||
}
|
||||
content += fmt.Sprintf("%v\n", line)
|
||||
}
|
||||
return content
|
||||
}
|
|
@ -26,7 +26,7 @@ func TestTextMemoryByteToString(t *testing.T) {
|
|||
}
|
||||
|
||||
func charExpectation(t *testing.T, arg uint8, alt bool, expect string) {
|
||||
s := textMemoryByteToString(arg, alt, alt)
|
||||
s := textMemoryByteToString(arg, alt, alt, true)
|
||||
if s != expect {
|
||||
t.Errorf("For 0x%02x:%v, got %v, expected %v", arg, alt, s, expect)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue