This guide provides essential information for AI coding agents working on the izapple2 Apple II emulator project.
izapple2 is an Apple II+/IIe emulator written in Go. The project emulates various Apple II models with support for disk drives, expansion cards, and multiple display modes.
- Language: Go 1.26.0+
- Main Package:
github.com/ivanizag/izapple2 - Architecture: Modular card-based system with memory management, CPU emulation, and video rendering
# Build the main package (library only)
go build .
# Build SDL2 frontend
cd frontend/a2sdl
go build .
# Build the experimental SDL3 frontend. Needs no cgo and no SDL developer
# files: SDL3 is embedded in the binary by github.com/Zyko0/go-sdl3
cd frontend/a2sdl3
go build .
# Build WASM frontend
cd frontend/a2wasm
go build .
# Build console frontend
cd frontend/console
go build .
# Build the libretro core, needs a C toolchain
cd frontend/a2libretro
make# Install Go dependencies
go get -v -t -d ./...
# On Linux, install SDL2 development files
sudo apt-get install libsdl2-dev
# On macOS
brew install SDL2# Run all tests
go test ./...
# Run tests with verbose output
go test -v ./...
# Run tests with coverage
go test -cover ./...# Run a specific test by name
go test -v -run TestName
# Run a specific test in a specific package
go test -v -run TestName ./storage
# Examples:
go test -v -run TestPlusBoots
go test -v -run TestNibBackAndForth ./storage
go test -v -run TestConfigurationModel# Test only the storage package
go test ./storage
# Test with race detector
go test -race ./...The project includes E2E boot tests (e2e_boot_test.go, e2e_woz_test.go) that boot various disk images and verify the emulator behavior. These tests use cycle counts and text matching to validate proper operation.
- Main emulator code is in the root package
izapple2 - Subpackages include:
storage,screen,fujinet,component - Frontend implementations are in
frontend/directory frontend/sharedhas the code more than one frontend needs and the emulator library has no place for, like the screen each frontend shows and the drop targets
- Use CamelCase for exported types:
Apple2,CardDisk2,VideoSource - Use camelCase for unexported types:
memoryManager,cardBase,trackTracer - Card implementations follow pattern:
Card<CardName>(e.g.,CardDisk2,CardSmartPort) - Card builders follow pattern:
cardBuilderfor the struct
- Exported functions: CamelCase starting with uppercase (e.g.,
NewKeyboardChannel,LoadResource) - Unexported functions: camelCase starting with lowercase (e.g.,
configure,setupCard) - Constructor functions:
New<Type>(e.g.,NewBlockDiskFile,NewSmartPortFujinetNetwork) - Factory functions for unexported types:
new<Type>(e.g.,newVideo,newTraceMonitor) - Boolean query methods: start with
IsorHas(e.g.,IsPaused,isFileWoz)
- Exported constants: CamelCase (e.g.,
MemoryTypeROM,DiskII) - Unexported constants: camelCase (e.g.,
noCardName,wozMaxTrack) - Constants for addresses often use hex:
addressLimitZero,ioC8Off
- Standard library imports first
- Third-party imports second
- Local package imports last
- Separate groups with blank lines
Example:
import (
"fmt"
"strings"
"github.com/ivanizag/iz6502"
"golang.org/x/exp/maps"
"github.com/ivanizag/izapple2/screen"
"github.com/ivanizag/izapple2/storage"
)- Use embedded structs for common functionality (e.g.,
cardBaseembedded in card implementations) - Keep interfaces small and focused
- Define interfaces in the package that uses them, not implements them
- Return errors rather than panicking in most cases
- Use
fmt.Errorf()for error wrapping with context - Check errors immediately after function calls
- Test functions should use
t.Fatal(err)for setup errors,t.Error(err)for assertion failures
Example:
if err != nil {
return fmt.Errorf("failed to load ROM: %v", err)
}- All exported functions, types, and methods must have doc comments
- Doc comments start with the name being documented
- Use full sentences with proper punctuation
- Include references to specifications or documentation when relevant
Example:
// NewCardDisk2 creates a DiskII controller card
// sectors13 enables support for 13-sector disks (DOS 3.2)
func NewCardDisk2(sectors13 bool) *CardDisk2 {- Test files end with
_test.go - Test function names:
Test<FunctionName>orTest<Feature> - Use table-driven tests when testing multiple scenarios
- Helper functions for tests:
test<Purpose>(e.g.,testBoots) - Use underscores for large numeric literals in tests:
200_000,100_000_000
- Use
gofmt(automatic with most Go tooling) - Line length: no strict limit, but keep it reasonable (~100-120 chars)
- Use tabs for indentation (Go standard)
- Memory addresses use
uint16 - Use hex notation for hardware addresses:
0xc000,0xbfff - Bit manipulation is common; comment complex operations
- Cycle counting is important for timing-sensitive operations
- Configuration uses string-based parameter system
- Card parameters follow format:
cardname,param1=value1,param2=value2 - Use
configurationstruct for managing settings - Support both command-line and config file configuration
- Define card struct embedding
cardBase - Implement
assign()method to set up ROM and memory handlers - Use builder pattern with
cardBuilderstruct - Register in
cardFactorymap
- Use
LoadResource()for files that can be internal, local files, or URLs - Internal resources use
<internal>/prefix - Support gzip and zip compression transparently
- Use
executionTracerinterface for CPU tracing - Implement tracers for different OSes (ProDOS, Pascal, CP/M)
- Use
traceparameter to enable debug output
The project uses GitHub Actions (.github/workflows/go.yml) and CircleCI (.circleci/config.yml):
- Builds are tested on Linux with SDL2
- Must pass
go buildandgo test ./... - Targets Go 1.26+ (currently using 1.26.0)
- See
README.mdfor user documentation - See
doc/features.mdfor the complete feature list and the default configuration - See
doc/command_line.mdfor command-line options - See
doc/frontend_*.mdfor a page per frontend: how to build it, how to use it and what it does not do - See
storage/WozSupportStatus.mdfor WOZ format support details - Reference implementation uses iz6502 CPU emulator: https://github.com/ivanizag/iz6502