diff --git a/CONFIG.md b/CONFIG.md index 8e85748f..463a7307 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -1,7 +1,7 @@ # Configuring the build -It's not possible to provide ROM builds that suit everyone needs - therefore configuration files were introduced, separately for each of the hardware targets: +It's not possible to provide ROM builds that suit everyone needs - therefore configuration files were introduced, few predefined configurations are provided with sane defaults: * [`c64/,,config_generic.s`](c64/,,config_generic.s) * [`c64/,,config_mega65.s`](c64/,,config_mega65.s) @@ -11,7 +11,33 @@ Just edit them and recompile the project. To enable particular option - uncommen Note however, that features do not came for free - enabling them needs some additional ROM space (in BASIC segment, in KERNAL segment, or in both), which is VERY limited on the target machines. Some options might be unavailable for speecific targets - read the comments in the configuration files. Some options might also carry compatibility and/or performance hit - so choose wisely. -Sane defaults are already present - different for each target. +## Hardware platform and brand + +### `CONFIG_PLATFORM_COMMODORE_64` + +Commodore 64 is the only hardware platform available now - and the main one, as the Open ROMs API is meant to be compatible with the Commodore 64. + +Since Open ROMs is highly modular, it should be possible to add other platforms in the future (like 8-bit Atari computers or Commander X16), if they share the following common characteristics: + +* MOS 6502 CPU or compatible +* 8KB ROM area `$A000`-`$BFFF` +* 8KB ROM area `$E000`-`$FFFF` + +### `CONFIG_MB_MEGA_65`, `CONFIG_MB_ULTIMATE_64` + +Select if the ROM is going to be used exclusively on the specific motherboard. It prevents from enabling options not having sense, skips initialization of C128-only registers, etc. + +### `CONFIG_BRAND_GENERIC` + +If you don't know which variant to choose - select this one. + +### `CONFIG_BRAND_TESTING` + +Use this one for any kind of testing/experimental build. + +### `CONFIG_BRAND_MEGA_65`, `CONFIG_BRAND_ULTIMATE_64` + +Select if you are using appropriate motherboard. ## Processor instruction set @@ -30,10 +56,17 @@ If unsure - select this one. Choose if your CPU supports the Western Design Center 65C02 instruction set, like: * WDC 65C02 - used in the Turbo Master accelerator -* CSG 65CE02 -* CSG 4510 - used in the Commodore 65 prototypes -It enables some speed/size code optimizations. Warning - this is untested! +It enables some speed/size code optimizations. + +### `CONFIG_CPU_CSG_65CE02` + +Choose if your CPU supports the Commodore Semiconductor Group 65CE02 instruction set, like: + +* CSG 65CE02 +* CSG 4510 - microcontroller used in the Commodore 65 prototypes + +It enables some speed/size code optimizations. ### `CONFIG_CPU_WDC_65816` @@ -42,9 +75,9 @@ Choose if your CPU supports the 16-bit Western Design Center 65816 instruction s * WDC 65C816 - used in the Flash 8 accelerator * WDC 65C816S - used in the SuperCPU accelerator -It enables some speed/size code optimizations. Warning - this is untested! +It enables some speed/size code optimizations. -## Memory models +## Memory model Different layouts of memory are possible - but they can be selected at compile time only. @@ -80,13 +113,83 @@ Cause the system to support SIDs in `$D4xx` and `$D5xx` ranges, respectively. Each of them needs a couple of bytes in KERNAL segment - but they can share some code, and `$D4xx` range support replaces the standard `$D400` address handling, so exact amount depends on the exact configuration. -## Miscelaneous features +## Keyboard + +Original keyboard support routine is just horrible. It does nothing to prevent ghosting - press A+S+D at the same time - it prints F. Try to use joystick connected to control port 1 - it outputs phantom characters. The Open ROMs provides much more sophisticated routines to prevent such problems. + +### `CONFIG_LEGACY_SCNKEY` + +Uses old Open ROMs keyboard scanning routine, which is basically example routine by TWW/CTR, hacked to work within Kernal. It's greatest advantage is multi-key rollover, it's disadvantages - it's much less compatible (uses several bytes of memory which are normally free for user software - thus, it is considered legacy for now), does not support all the system variables (`RPTFLG` and `KEYLOG` are unsupported), and ignores the configuration options - this can be changed, but it requires some effort. + +Needs 30-250 more space in KERNAL segment (depending on the features enabled for current default routine). If unsure - disable. + +### `CONFIG_KEYBOARD_C128` + +Allows to use additional keys found on the C128 keyboard. NOTE: might be buggy, on VICE emulator I can't get all the keys working. + +Needs about 130 bytes more space in KERNAL segment. If unsure - disable. + +### `CONFIG_KEYBOARD_C128_CAPS_LOCK` + +Allows to use CAPS LOCK key on the C128 keyboard, this is independent from `CONFIG_KEYBOARD_C128`. Support is C64-safe (there is a protection against false-positive reading on the C64). + +Needs about 50 bytes more space in KERNAL segment. If unsure - disable. + +### `CONFIG_KEY_REPEAT_DEFAULT` + +Enables key repetition by default during the startup (sets `RPTFLG`). + +Needs 5 bytes more space in KERNAL segment. + +### `CONFIG_KEY_REPEAT_ALWAYS` + +Enables the key repetition and ignores `RPTFLG`. + +Saves 22 bytes from KERNAL segment. + +### `CONFIG_KEY_FAST_SCAN` + +Performs somee speed optimizations in the keyboard scanning routine, at the eexpense of some more ROM space. + +Needs 13 bytes more space in KERNAL segment. Only disable if you are running out of ROM space. + +### `CONFIG_JOY1_CURSOR` and `CONFIG_JOY2_CURSOR` + +Joystick movement also moves the cursor. + +Needs about 65 bytes of ROM space to handle both joysticks. + +## Eye candy + +### `CONFIG_COLORS_BRAND` + +Tries to adjust the color scheme to the selected brand. Some brands might not support this. + +### `CONFIG_BANNER_SIMPLE`, `CONFIG_BANNER_FANCY`, `CONFIG_BANNER_BRAND` + +Select startup banner - either a simple one, or with some colorful elements. `CONFIG_BANNER_BRAND` heavily depends on the selected brand, not all the brands support it. + +Richer banners need more BASIC segment, varies between brands. + +### `CONFIG_BANNER_PAL_NTSC` + +If enabled, prints video system on startup banner. Eye candy only. + +Feature needs some bytes in BASIC (depending on banner type) and about 25 bytes in KERNAL segment. + +## Software features + +### `CONFIG_PANIC_SCREEN` + +If enabled, certain fatal errors will produce a nice bluescreen instead of just resetting the machine. + +Feature needs over 100 bytes in KERNAL segment. If unsure - enable. ### `CONFIG_DOS_WEDGE` If enabled, a simple DOS wedge is available from the direct mode - supports `@`, `@`, `@$`, `@$` and `@` commands. -Feature needs about 330 bytes in BASIC segment. +Feature needs about 330 bytes in BASIC segment. If unsure - enable. ### `CONFIG_BCD_SAFE_INTERRUPTS` @@ -104,4 +207,4 @@ Replaces `RTS` stubbed routines implementation with one causing a break. ### `CONFIG_DBG_PRINTF` -Makes 'printf' routine available. +Makes `printf` routine available. diff --git a/Makefile b/Makefile index 4495652a..931d9c24 100644 --- a/Makefile +++ b/Makefile @@ -1,17 +1,26 @@ # Source files -SRCDIR_COMMON = c64/aliases -SRCDIR_BASIC_COMMON = $(SRCDIR_COMMON) c64/basic -SRCDIR_KERNAL_COMMON = $(SRCDIR_COMMON) c64/kernal c64/kernal/assets c64/kernal/jumptable c64/kernal/iec c64/kernal/interrupts c64/kernal/print +SRCDIR_COMMON = c64/aliases -SRCDIR_BASIC_generic = $(SRCDIR_BASIC_COMMON) c64/basic/,target_generic -SRCDIR_BASIC_mega65 = $(SRCDIR_BASIC_COMMON) c64/basic/,target_mega65 -SRCDIR_BASIC_ultimate64 = $(SRCDIR_BASIC_COMMON) c64/basic/,target_ultimate64 +SRCDIR_BASIC = $(SRCDIR_COMMON) \ + c64/basic \ + c64/basic/commands \ + c64/basic/init \ + c64/basic/rom_revision -SRCDIR_KERNAL_generic = $(SRCDIR_KERNAL_COMMON) c64/kernal/,target_generic -SRCDIR_KERNAL_mega65 = $(SRCDIR_KERNAL_COMMON) c64/kernal/,target_mega65 -SRCDIR_KERNAL_ultimate64 = $(SRCDIR_KERNAL_COMMON) c64/kernal/,target_ultimate64 +SRCDIR_KERNAL = $(SRCDIR_COMMON) \ + c64/kernal \ + c64/kernal/assets \ + c64/kernal/jumptable \ + c64/kernal/iec \ + c64/kernal/init \ + c64/kernal/interrupts \ + c64/kernal/iostack \ + c64/kernal/keyboard \ + c64/kernal/print \ + c64/kernal/screen \ + c64/kernal/stubs SRC_TOOLS = $(wildcard src/tools/*.c,src/tools/*.cc) @@ -26,6 +35,7 @@ TOOL_COLLECT_DATA = build/tools/collect_data TOOL_COMPRESS_TEXT = build/tools/compress_text TOOL_PNGPREPARE = build/tools/pngprepare TOOL_BUILD_SEGMENT = build/tools/build_segment +TOOL_RELEASE = build/tools/release TOOL_SIMILARITY = build/tools/similarity TOOL_ASSEMBLER = assembler/KickAss.jar @@ -34,6 +44,7 @@ TOOLS_LIST = $(pathsubst src/tools/%,build/tools/%,$(basename $(SRC_TOOLS))) # List of targets STD_TARGET_LIST = build/kernal_generic.rom build/basic_generic.rom \ + build/kernal_testing.rom build/basic_testing.rom \ build/kernal_mega65.rom build/basic_mega65.rom \ build/kernal_ultimate64.rom build/basic_ultimate64.rom \ build/chargen.rom @@ -59,30 +70,25 @@ all: $(STD_TARGET_LIST) $(EXT_TARGET_LIST) clean: @rm -rf build -updatebin: $(STD_TARGET_LIST) +updatebin: $(STD_TARGET_LIST) $(TOOL_RELEASE) + $(TOOL_RELEASE) -i ./build -o ./bin basic_generic.rom kernal_generic.rom basic_testing.rom kernal_testing.rom basic_mega65.rom kernal_mega65.rom basic_ultimate64.rom kernal_ultimate64.rom cp build/chargen.rom bin/chargen.rom - cp build/basic_generic.rom bin/basic_generic.rom - cp build/kernal_generic.rom bin/kernal_generic.rom - cp build/basic_mega65.rom bin/basic_mega65.rom - cp build/kernal_mega65.rom bin/kernal_mega65.rom - cp build/basic_ultimate64.rom bin/basic_ultimate64.rom - cp build/kernal_ultimate64.rom bin/kernal_ultimate64.rom # Rules - tools -$(TOOL_PNGPREPARE): src/pngprepare.c Makefile +$(TOOL_PNGPREPARE): src/pngprepare.c @mkdir -p build/tools $(CC) -O2 -Wall -I/usr/local/include -L/usr/local/lib -o $@ $< -lpng -$(TOOL_COMPRESS_TEXT): src/compress_text.c Makefile +$(TOOL_COMPRESS_TEXT): src/compress_text.c @mkdir -p build/tools $(CC) -O2 -Wall -I/usr/local/include -L/usr/local/lib -o $@ $< -lm -build/tools/%: src/%.c Makefile +build/tools/%: src/%.c @mkdir -p build/tools $(CC) -O2 -Wall -o $@ $< -build/tools/%: src/%.cc Makefile +build/tools/%: src/%.cc src/common.h @mkdir -p build/tools $(CXX) -O2 -Wall -o $@ $< @@ -94,44 +100,56 @@ build/chargen.rom: $(TOOL_PNGPREPARE) assets/8x8font.png # Dependencies - BASIC and KERNAL build/target_generic/OUTB.BIN build/target_generic/BASIC_combined.vs: \ - $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(GEN_BASIC) $(SRCDIR_BASIC_generic) \ + $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(GEN_BASIC) $(SRCDIR_BASIC) \ c64/,,config_generic.s build/target_generic/KERNAL_combined.sym \ - $(foreach dir,$(SRCDIR_BASIC_generic),$(wildcard $(dir)/*.s)) + $(foreach dir,$(SRCDIR_BASIC),$(wildcard $(dir)/*.s)) +build/target_testing/OUTB.BIN build/target_generic/BASIC_combined.vs: \ + $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(GEN_BASIC) $(SRCDIR_BASIC) \ + c64/,,config_testing.s build/target_testing/KERNAL_combined.sym \ + $(foreach dir,$(SRCDIR_BASIC),$(wildcard $(dir)/*.s)) build/target_mega65/OUTB.BIN build/target_mega65/BASIC_combined.vs: \ - $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(GEN_BASIC) $(SRCDIR_BASIC_mega65) \ + $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(GEN_BASIC) $(SRCDIR_BASIC) \ c64/,,config_mega65.s build/target_mega65/KERNAL_combined.sym \ - $(foreach dir,$(SRCDIR_BASIC_mega65),$(wildcard $(dir)/*.s)) + $(foreach dir,$(SRCDIR_BASIC),$(wildcard $(dir)/*.s)) build/target_ultimate64/OUTB.BIN build/target_ultimate64/BASIC_combined.vs: \ - $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(GEN_BASIC) $(SRCDIR_BASIC_ultimate64) \ + $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(GEN_BASIC) $(SRCDIR_BASIC) \ c64/,,config_ultimate64.s build/target_ultimate64/KERNAL_combined.sym \ - $(foreach dir,$(SRCDIR_BASIC_ultimate64),$(wildcard $(dir)/*.s)) + $(foreach dir,$(SRCDIR_BASIC),$(wildcard $(dir)/*.s)) build/target_generic/OUTK.BIN build/target_generic/KERNAL_combined.vs build/target_generic/KERNAL_combined.sym: \ - $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(GEN_KERNAL) $(SRCDIR_KERNAL_generic) \ + $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(GEN_KERNAL) $(SRCDIR_KERNAL) \ c64/,,config_generic.s \ - $(foreach dir,$(SRCDIR_KERNAL_generic),$(wildcard $(dir)/*.s)) + $(foreach dir,$(SRCDIR_KERNAL),$(wildcard $(dir)/*.s)) +build/target_testing/OUTK.BIN build/target_testing/KERNAL_combined.vs build/target_testing/KERNAL_combined.sym: \ + $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(GEN_KERNAL) $(SRCDIR_KERNAL) \ + c64/,,config_testing.s \ + $(foreach dir,$(SRCDIR_KERNAL),$(wildcard $(dir)/*.s)) build/target_mega65/OUTK.BIN build/target_mega65/KERNAL_combined.vs build/target_mega65/KERNAL_combined.sym: \ - $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(GEN_KERNAL) $(SRCDIR_KERNAL_mega65) \ + $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(GEN_KERNAL) $(SRCDIR_KERNAL) \ c64/,,config_mega65.s \ - $(foreach dir,$(SRCDIR_KERNAL_mega65),$(wildcard $(dir)/*.s)) + $(foreach dir,$(SRCDIR_KERNAL),$(wildcard $(dir)/*.s)) build/target_ultimate64/OUTK.BIN build/target_ultimate64/KERNAL_combined.vs build/target_ultimate64/KERNAL_combined.sym: \ - $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(GEN_KERNAL) $(SRCDIR_KERNAL_ultimate64) \ + $(TOOL_ASSEMBLER) $(TOOL_BUILD_SEGMENT) $(GEN_KERNAL) $(SRCDIR_KERNAL) \ c64/,,config_ultimate64.s \ - $(foreach dir,$(SRCDIR_KERNAL_ultimate64),$(wildcard $(dir)/*.s)) + $(foreach dir,$(SRCDIR_KERNAL),$(wildcard $(dir)/*.s)) build/target_generic/newrom: build/target_generic/OUTB.BIN build/target_generic/OUTK.BIN +build/target_testing/newrom: build/target_testing/OUTB.BIN build/target_testing/OUTK.BIN build/target_mega65/newrom: build/target_mega65/OUTB.BIN build/target_mega65/OUTK.BIN build/target_ultimate64/newrom: build/target_ultimate64/OUTB.BIN build/target_ultimate64/OUTK.BIN build/kernal_generic.rom: build/target_generic/newrom +build/kernal_testing.rom: build/target_testing/newrom build/kernal_mega65.rom: build/target_mega65/newrom build/kernal_ultimate64.rom: build/target_ultimate64/newrom build/basic_generic.rom: build/target_generic/newrom +build/basic_testing.rom: build/target_testing/newrom build/basic_mega65.rom: build/target_mega65/newrom build/basic_ultimate64.rom: build/target_ultimate64/newrom build/symbols_generic.vs: build/target_generic/BASIC_combined.vs build/target_generic/KERNAL_combined.vs +build/symbols_testing.vs: build/target_testing/BASIC_combined.vs build/target_testing/KERNAL_combined.vs build/symbols_mega65.vs: build/target_mega65/BASIC_combined.vs build/target_mega65/KERNAL_combined.vs build/symbols_ultimate64.vs: build/target_ultimate64/BASIC_combined.vs build/target_ultimate64/KERNAL_combined.vs @@ -145,13 +163,13 @@ build/,generated/packed_messages.s: $(TOOL_COMPRESS_TEXT) build/target_%/OUTB.BIN build/target_%/BASIC_combined.vs: @mkdir -p build/target_$* @rm -f $@* build/target_$*/BASIC* - @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -s BASIC -i BASIC-$* -o OUTB.BIN -d build/target_$* -l a000 -h e4d2 c64/,,config_$*.s $(SRCDIR_BASIC_$*) $(GEN_BASIC) + @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -s BASIC -i BASIC-$* -o OUTB.BIN -d build/target_$* -l a000 -h e4d2 c64/,,config_$*.s $(SRCDIR_BASIC) $(GEN_BASIC) .PRECIOUS: build/target_%/OUTK.BIN build/target_%/KERNAL_combined.vs build/target_%/KERNAL_combined.sym build/target_%/OUTK.BIN build/target_%/KERNAL_combined.vs build/target_%/KERNAL_combined.sym: @mkdir -p build/target_$* @rm -f $@* build/target_$*/KERNAL* - @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -s KERNAL -i KERNAL-$* -o OUTK.BIN -d build/target_$* -l e4d3 -h ffff c64/,,config_$*.s $(SRCDIR_KERNAL_$*) $(GEN_KERNAL) + @$(TOOL_BUILD_SEGMENT) -a ../../$(TOOL_ASSEMBLER) -s KERNAL -i KERNAL-$* -o OUTK.BIN -d build/target_$* -l e4d3 -h ffff c64/,,config_$*.s $(SRCDIR_KERNAL) $(GEN_KERNAL) .PRECIOUS: build/target_%/newrom build/target_%/newrom: @@ -183,7 +201,7 @@ build/symbols_hybrid.vs: build/target_generic/KERNAL_combined.vs # Rules - platform 'Mega 65' specific -build/newc65.rom: build/kernal_mega65.rom build/basic_mega65.rom build/chargen.rom Makefile +build/newc65.rom: build/kernal_mega65.rom build/basic_mega65.rom build/chargen.rom dd if=/dev/zero bs=4096 count=10 of=build/newc65.rom cat build/basic_mega65.rom build/chargen.rom build/chargen.rom build/kernal_mega65.rom >> build/newc65.rom dd if=/dev/zero bs=65536 count=1 of=build/padding @@ -192,16 +210,28 @@ build/newc65.rom: build/kernal_mega65.rom build/basic_mega65.rom build/chargen.r # Rules - tests -.PHONY: test test_generic test_mega65 test_ultimate64 test_m65 testremote testsimilarity +.PHONY: test test_generic test_generic_x128 test_hybrid test_testing \ + test_mega65 test_mega65_xemu test_m65 \ + test_ultimate64 \ + testremote testsimilarity test: test_generic test_generic: build/kernal_generic.rom build/basic_generic.rom build/symbols_generic.vs x64 -kernal build/kernal_generic.rom -basic build/basic_generic.rom -moncommands build/symbols_generic.vs -8 empty.d64 +test_generic_x128: build/kernal_generic.rom build/basic_generic.rom build/symbols_generic.vs + x128 -go64 -kernal64 build/kernal_generic.rom -basic64 build/basic_generic.rom -moncommands build/symbols_generic.vs -8 empty.d64 + +test_testing: build/kernal_testing.rom build/basic_testing.rom build/symbols_testing.vs + x64 -kernal build/kernal_testing.rom -basic build/basic_testing.rom -moncommands build/symbols_testing.vs -8 empty.d64 + test_mega65: build/kernal_mega65.rom build/basic_mega65.rom build/symbols_mega65.vs x64 -kernal build/kernal_mega65.rom -basic build/basic_mega65.rom -moncommands build/symbols_mega65.vs -8 empty.d64 +test_mega65_xemu: build/newc65.rom + ../xemu/build/bin/xc65.native -dmarev 2 -rom build/newc65.rom + test_ultimate64: build/kernal_ultimate64.rom build/basic_ultimate64.rom build/symbols_ultimate64.vs x64 -kernal build/kernal_ultimate64.rom -basic build/basic_ultimate64.rom -moncommands build/symbols_ultimate64.vs -8 empty.d64 diff --git a/STATUS.md b/STATUS.md index 96d2da0c..a036e81e 100644 --- a/STATUS.md +++ b/STATUS.md @@ -3,8 +3,8 @@ Here are the features of the Open ROMs not found in the original ROMs from the 80s (many of them are [configurable](CONFIG.md)): -* improved keyboard scanning, supports multi-key roll-over and rejection of spurious joystick input -* joystick (port 1) can be used to move text cursor +* improved keyboard scanning, supports anti-ghosting and is resistant to joystick interference (one variant even supports multi-keyy rollover) +* joystick can be used to move text cursor * uses RAM under ROM and I/O: 61438 bytes free * cold/warm start silences multiple SID chips - all $D4xx and $D5xx addresses * wark start due to BRK prints out the instruction address @@ -29,7 +29,7 @@ The following ROM features are currently missing: * tape support * RS-232 support * breaking Kernal routines with RUN/STOP key -* NMI andling is incomplete +* NMI handling is incomplete # API status @@ -62,8 +62,8 @@ Note: vectors at `$0300` are not supported yet - for now only the locations belo | `(00306)` | `$A71A` | `QPLOP` | NOT DONE | some implementation exists, but not connected here | | `(00308)` | `$A7E4` | `GONE` | NOT DONE | some implementation exists, but not connected here | | `(0030A)` | `$AE86` | `EVAL` | NOT DONE | some implementation exists, but not connected here | -| `($A000)` | | cold start | PARTIAL | | -| `($A002)` | | warm start | PARTIAL | | +| `($A000)` | `$E394` | cold start | PARTIAL | | +| `($A002)` | `$E3B7` | warm start | PARTIAL | |
@@ -76,10 +76,15 @@ Not all of them - only these we want to have implemented. | Address | Name | Status | Remarks | | :-------: | :----------- | :------: | :------------------------------------------------: | | `$A004` | revision str | DONE | | -| `$A68E` | RUNC | NOT DONE | | -| `$A7AE` | NEWSTT | NOT DONE | | +| `$A408` | REASON | NOT DONE | | +| `$A453` | (unknown) | NOT DONE | | +| `$A533` | LINKPRG | DONE | | +| `$A644` | new | NOT DONE | | +| `$A659` | set txt ptr | NOT DONE | | +| `$A68E` | RUNC | DONE | | +| `$A7AE` | NEWSTT | PARTIAL | redirected to RUN command | | `$AB1E` | STROUT | DONE | | -| `$BDCD` | LINPRT | NOT DONE | | +| `$BDCD` | LINPRT | DONE | temporary implementation | | `$E3BF` | INIT | NOT DONE | | | `$E422` | INITMSG | DONE | | | `$E453` | RVECT | NOT DONE | | @@ -94,53 +99,53 @@ NOTE: Even the 'DONE' routines won't support features described as missing in on
-| Address | Unofficial | Name | Status | Remarks | -| :-------: | :--------: | :---------- | :------: | :------------------------------------------------: | -| `($028F)` | | `KEYLOG` | NOT DONE | | -| `$FF81` | `$FF5B` | `CINT` | DONE | | -| `$FF84` | `$FDA3` | `IOINIT` | PARTIAL | CIA initialization incomplete | -| `$FF87` | `$FD50` | `RAMTAS` | DONE | | -| `$FF8A` | `$FD15` | `RESTOR` | DONE | | -| `$FF8D` | `$FD1A` | `VECTOR` | DONE | | -| `$FF90` | | `SETMSG` | DONE | | -| `$FF93` | | `SECOND` | DONE | | -| `$FF96` | | `TKSA` | DONE | | -| `$FF99` | | `MEMTOP` | DONE | | -| `$FF9C` | | `MEMBOT` | DONE | | -| `$FF9F` | | `SCNKEY` | DONE | could be better integrated with ROM (aliases) | -| `$FFA2` | | `SETTMO` | DONE | | -| `$FFA5` | | `ACPTR` | DONE | | -| `$FFA8` | | `CIOUT` | DONE | | -| `$FFAB` | | `UNTLK` | DONE | | -| `$FFAE` | | `UNLSN` | DONE | | -| `$FFB1` | | `LISTEN` | DONE | | -| `$FFB4` | | `TALK` | DONE | | -| `$FFB7` | | `READST` | DONE | | -| `$FFBA` | | `SETFLS` | DONE | | -| `$FFBD` | | `SETNAM` | DONE | | -| `$FFC0` | `$F34A` | `OPEN` | DONE | | -| `$FFC3` | `$F291` | `CLOSE` | DONE | | -| `$FFC6` | `$F20E` | `CHKIN` | DONE | | -| `$FFC9` | `$F250` | `CKOUT` | PARTIAL | | -| `$FFCC` | `$F333` | `CLRCHN` | DONE | | -| `$FFCF` | `$F157` | `CHRIN` | PARTIAL | | -| `$FFD2` | `$F1CA` | `CHROUT` | PARTIAL | | -| `$FFD5` | `$F49E` | `LOAD` | PARTIAL | not yet clear what's this entry doing | -| `($0330)` | `$F4A5` | `LOAD` | PARTIAL | no VERIFY support, no STOP key, check $F49E addr | -| `$FFD8` | `$F5DD` | `SAVE` | NOT DONE | | -| `($0332)` | `$F5ED` | `SAVE` | NOT DONE | | -| `$FFDB` | | `SETTIM` | DONE | | -| `$FFDE` | | `RDTIM` | DONE | | -| `$FFE1` | `$F6ED` | `STOP` | DONE | | -| `$FFE4` | `$F13E` | `GETIN` | PARTIAL | only some devices supported | -| `$FFE7` | `$F32F` | `CLALL` | DONE | | -| `$FFEA` | | `UDTIM` | DONE | | -| `$FFED` | | `SCREEN` | DONE | | -| `$FFF0` | `$E50A` | `PLOT` | PARTIAL | | -| `$FFF3` | | `IOBASE` | DONE | | -| `($FFFA)` | | NMI vec | PARTIAL | | -| `($FFFC)` | | RESET vec | PARTIAL | | -| `($FFFE)` | | IRQ/BRK vec | PARTIAL | | +| Address | Unofficial | Name | Status | Remarks | +| :-------: | :--------: | :---------- | :------: | :--------------------------------------------------: | +| `($028F)` | | `KEYLOG` | DONE | | +| `$FF81` | `$FF5B` | `CINT` | DONE | | +| `$FF84` | `$FDA3` | `IOINIT` | PARTIAL | CIA initialization might be incomplete | +| `$FF87` | `$FD50` | `RAMTAS` | PARTIAL | probably shouldn't touch VIC and CIA's | +| `$FF8A` | `$FD15` | `RESTOR` | DONE | | +| `$FF8D` | `$FD1A` | `VECTOR` | DONE | | +| `$FF90` | | `SETMSG` | DONE | | +| `$FF93` | | `SECOND` | DONE | | +| `$FF96` | | `TKSA` | DONE | | +| `$FF99` | `$FE25` | `MEMTOP` | DONE | | +| `$FF9C` | | `MEMBOT` | DONE | | +| `$FF9F` | | `SCNKEY` | DONE | | +| `$FFA2` | | `SETTMO` | DONE | | +| `$FFA5` | | `ACPTR` | DONE | | +| `$FFA8` | | `CIOUT` | DONE | | +| `$FFAB` | | `UNTLK` | DONE | | +| `$FFAE` | | `UNLSN` | DONE | | +| `$FFB1` | | `LISTEN` | DONE | | +| `$FFB4` | | `TALK` | DONE | | +| `$FFB7` | | `READST` | DONE | | +| `$FFBA` | | `SETFLS` | DONE | | +| `$FFBD` | | `SETNAM` | DONE | | +| `$FFC0` | `$F34A` | `OPEN` | DONE | | +| `$FFC3` | `$F291` | `CLOSE` | DONE | | +| `$FFC6` | `$F20E` | `CHKIN` | DONE | | +| `$FFC9` | `$F250` | `CKOUT` | PARTIAL | | +| `$FFCC` | `$F333` | `CLRCHN` | DONE | | +| `$FFCF` | `$F157` | `CHRIN` | PARTIAL | | +| `$FFD2` | `$F1CA` | `CHROUT` | PARTIAL | | +| `$FFD5` | `$F49E` | `LOAD` | PARTIAL | not yet clear what's this entry doing | +| `($0330)` | `$F4A5` | `LOAD` | PARTIAL | no VERIFY support, no STOP key, check $F49E addr | +| `$FFD8` | `$F5DD` | `SAVE` | NOT DONE | | +| `($0332)` | `$F5ED` | `SAVE` | NOT DONE | | +| `$FFDB` | | `SETTIM` | DONE | | +| `$FFDE` | | `RDTIM` | DONE | | +| `$FFE1` | `$F6ED` | `STOP` | DONE | | +| `$FFE4` | `$F13E` | `GETIN` | PARTIAL | only keyboard supported | +| `$FFE7` | `$F32F` | `CLALL` | DONE | | +| `$FFEA` | | `UDTIM` | DONE | | +| `$FFED` | | `SCREEN` | DONE | | +| `$FFF0` | `$E50A` | `PLOT` | DONE | | +| `$FFF3` | | `IOBASE` | DONE | | +| `($FFFA)` | | NMI vec | PARTIAL | | +| `($FFFC)` | `$FCE2` | RESET vec | PARTIAL | | +| `($FFFE)` | | IRQ/BRK vec | PARTIAL | |
@@ -150,17 +155,31 @@ Not all of them - only these we want to have implemented.
-| Address | Name | Status | Remarks | -| :-------: | :------------------ | :------: | :------------------------------------------------: | -| `$E544` | clear screen | DONE | | -| `$E50C` | set cursor position | PARTIAL | | -| `$E5A0` | setup VIC II & IO | PARTIAL | | -| `$EA31` | default IRQ | PARTIAL | | -| `$EA7E` | ack CIA1 + below | DONE | | -| `$EA81` | ret from IRQ/NMI | DONE | | -| `$FD30` | default vectors | DONE | | -| `$FE47` | default NMI | PARTIAL | | -| `$FE66` | default BRK | DONE | | -| `$FF80` | revision byte | DONE | | +| Address | Name | Status | Remarks | +| :-------: | :--------------------------- | :------: | :------------------------------------------------: | +| `$E518` | legacy part of CINT | DONE | | +| `$E51B` | init screen keyboard, no VIC | DONE | | +| `$E544` | clear screen | DONE | | +| `$E50C` | set cursor position | PARTIAL | | +| `$E566` | home cursor | NOT DONE | | +| `$E5A0` | setup VIC II & IO | DONE | | +| `$E6B6` | advance cursor | NOT DONE | | +| `$E701` | previous line | NOT DONE | | +| `$E716` | screen CHROUT | NOT DONE | | +| `$E8EA` | scroll line | NOT DONE | | +| `$E96C` | insert line on top | NOT DONE | | +| `$E9FF` | clear line | NOT DONE | | +| `$EA31` | default IRQ | PARTIAL | | +| `$EA7E` | ack CIA1 + below | DONE | | +| `$EA81` | ret from IRQ/NMI | DONE | | +| `$F142` | get key from buffer | DONE | | +| `$F646` | IEC close | NOT DONE | | +| `$FD30` | default vectors | DONE | | +| `$FD90` | (unknown) | NOT DONE | | +| `$FD90` | (unknown) | NOT DONE | | +| `$FE2D` | memtop set part | DONE | | +| `$FE47` | default NMI | PARTIAL | | +| `$FE66` | default BRK | DONE | | +| `$FF80` | revision byte | DONE | |
diff --git a/bin/basic_generic.rom b/bin/basic_generic.rom index 7d407af1..a1e9f2ef 100644 Binary files a/bin/basic_generic.rom and b/bin/basic_generic.rom differ diff --git a/bin/basic_mega65.rom b/bin/basic_mega65.rom index 5ed25603..2d95059d 100644 Binary files a/bin/basic_mega65.rom and b/bin/basic_mega65.rom differ diff --git a/bin/basic_testing.rom b/bin/basic_testing.rom new file mode 100644 index 00000000..efbebfcd Binary files /dev/null and b/bin/basic_testing.rom differ diff --git a/bin/basic_ultimate64.rom b/bin/basic_ultimate64.rom index 64e0dd6f..d9cdeaf9 100644 Binary files a/bin/basic_ultimate64.rom and b/bin/basic_ultimate64.rom differ diff --git a/bin/kernal_generic.rom b/bin/kernal_generic.rom index 2ccae4bd..3833498b 100644 Binary files a/bin/kernal_generic.rom and b/bin/kernal_generic.rom differ diff --git a/bin/kernal_mega65.rom b/bin/kernal_mega65.rom index a598b2b0..b4a039f8 100644 Binary files a/bin/kernal_mega65.rom and b/bin/kernal_mega65.rom differ diff --git a/bin/kernal_testing.rom b/bin/kernal_testing.rom new file mode 100644 index 00000000..6731edb1 Binary files /dev/null and b/bin/kernal_testing.rom differ diff --git a/bin/kernal_ultimate64.rom b/bin/kernal_ultimate64.rom index 5278a59b..90de039e 100644 Binary files a/bin/kernal_ultimate64.rom and b/bin/kernal_ultimate64.rom differ diff --git a/c64/,,config_generic.s b/c64/,,config_generic.s index 3843ec00..8965f1dd 100644 --- a/c64/,,config_generic.s +++ b/c64/,,config_generic.s @@ -1,16 +1,44 @@ +.const CONFIG_ID = $00 // should be 1 byte, different for each config file! + // // Please read CONFIG.md before modifying this file! // +// Idea: +// - sane defaults for the original Commodore 64/128 machines +// - do not enable features which are a significant compatibility risk + + +// Hardware platform and brand + +#define CONFIG_PLATFORM_COMMODORE_64 + +// #define CONFIG_MB_MEGA_65 +// #define CONFIG_MB_ULTIMATE_64 + +#define CONFIG_BRAND_GENERIC +// #define CONFIG_BRAND_TESTING +// #define CONFIG_BRAND_MEGA_65 +// #define CONFIG_BRAND_ULTIMATE_64 + + +// Processor instruction set #define CONFIG_CPU_MOS_6502 // #define CONFIG_CPU_WDC_65C02 +// #define CONFIG_CPU_CSG_65CE02 // #define CONFIG_CPU_WDC_65816 + +// Memory model + #define CONFIG_MEMORY_MODEL_38K // #define CONFIG_MEMORY_MODEL_60K + +// Multiple SID support + // #define CONFIG_SID_2ND .const CONFIG_SID_2ND_ADDRESS = $D420 @@ -20,9 +48,36 @@ // #define CONFIG_SID_D4XX // #define CONFIG_SID_D5XX + +// Keyboard settings + +// #define CONFIG_LEGACY_SCNKEY +#define CONFIG_KEYBOARD_C128 // incomplete +#define CONFIG_KEYBOARD_C128_CAPS_LOCK +// #define CONFIG_KEY_REPEAT_DEFAULT +// #define CONFIG_KEY_REPEAT_ALWAYS +#define CONFIG_KEY_FAST_SCAN +#define CONFIG_JOY1_CURSOR +#define CONFIG_JOY2_CURSOR + + +// Eye candy + +#define CONFIG_COLORS_BRAND +// #define CONFIG_BANNER_SIMPLE +#define CONFIG_BANNER_FANCY +// #define CONFIG_BANNER_BRAND +#define CONFIG_SHOW_PAL_NTSC + + +// Software features + +#define CONFIG_PANIC_SCREEN #define CONFIG_DOS_WEDGE #define CONFIG_BCD_SAFE_INTERRUPTS -#define CONFIG_EXTENDED_SCNKEY // for now has to be enabled + + +// Debug options // #define CONFIG_DBG_STUBS_BRK // #define CONFIG_DBG_PRINTF diff --git a/c64/,,config_mega65.s b/c64/,,config_mega65.s index e856a52c..65169f8d 100644 --- a/c64/,,config_mega65.s +++ b/c64/,,config_mega65.s @@ -1,15 +1,45 @@ +.const CONFIG_ID = $01 // should be 1 byte, different for each config file! + // // Please read CONFIG.md before modifying this file! // +// Idea: +// - sane defaults for the Mega 65 FPGA computer +// - do not enable features which are a significant compatibility risk +// - unless VICE gains Commodore 65 (or at least Flash8 cartridge) emulation support, +// do not enable CPU-specific optimizations; ROMs would be hard to test + + +// Hardware platform and brand + +#define CONFIG_PLATFORM_COMMODORE_64 + +#define CONFIG_MB_MEGA_65 +// #define CONFIG_MB_ULTIMATE_64 + +// #define CONFIG_BRAND_GENERIC +// #define CONFIG_BRAND_TESTING +#define CONFIG_BRAND_MEGA_65 +// #define CONFIG_BRAND_ULTIMATE_64 + + +// Processor instruction set #define CONFIG_CPU_MOS_6502 // #define CONFIG_CPU_WDC_65C02 +// #define CONFIG_CPU_CSG_65CE02 // #define CONFIG_CPU_WDC_65816 -// #define CONFIG_MEMORY_MODEL_38K -#define CONFIG_MEMORY_MODEL_60K + +// Memory model configuration + +#define CONFIG_MEMORY_MODEL_38K +// #define CONFIG_MEMORY_MODEL_60K + + +// Multiple SID support #define CONFIG_SID_2ND .const CONFIG_SID_2ND_ADDRESS = $D420 @@ -20,9 +50,36 @@ // #define CONFIG_SID_D4XX // #define CONFIG_SID_D5XX + +// Keyboard settings + +// #define CONFIG_LEGACY_SCNKEY +// #define CONFIG_KEYBOARD_C128 // incomplete +// #define CONFIG_KEYBOARD_C128_CAPS_LOCK +// #define CONFIG_KEY_REPEAT_DEFAULT +// #define CONFIG_KEY_REPEAT_ALWAYS +#define CONFIG_KEY_FAST_SCAN +#define CONFIG_JOY1_CURSOR +#define CONFIG_JOY2_CURSOR + + +// Eye candy + +#define CONFIG_COLORS_BRAND +// #define CONFIG_BANNER_SIMPLE +// #define CONFIG_BANNER_FANCY +#define CONFIG_BANNER_BRAND +// #define CONFIG_SHOW_PAL_NTSC + + +// Software features + +#define CONFIG_PANIC_SCREEN #define CONFIG_DOS_WEDGE #define CONFIG_BCD_SAFE_INTERRUPTS -#define CONFIG_EXTENDED_SCNKEY // for now has to be enabled + + +// Debug options // #define CONFIG_DBG_STUBS_BRK // #define CONFIG_DBG_PRINTF diff --git a/c64/,,config_testing.s b/c64/,,config_testing.s new file mode 100644 index 00000000..877a5005 --- /dev/null +++ b/c64/,,config_testing.s @@ -0,0 +1,84 @@ + +.const CONFIG_ID = $F0 // should be 1 byte, different for each config file! + +// +// Please read CONFIG.md before modifying this file! +// + +// Idea: +// - enable compatibility-risky features +// - enable code not normally used - to make sure they still compile + + + +// Hardware platform and brand + +#define CONFIG_PLATFORM_COMMODORE_64 + +// #define CONFIG_MB_MEGA_65 +// #define CONFIG_MB_ULTIMATE_64 + +// #define CONFIG_BRAND_GENERIC +#define CONFIG_BRAND_TESTING +// #define CONFIG_BRAND_MEGA_65 +// #define CONFIG_BRAND_ULTIMATE_64 + + +// Processor instruction set + +#define CONFIG_CPU_MOS_6502 +// #define CONFIG_CPU_WDC_65C02 +// #define CONFIG_CPU_CSG_65CE02 +// #define CONFIG_CPU_WDC_65816 + + +// Memory model configuration + +// #define CONFIG_MEMORY_MODEL_38K +#define CONFIG_MEMORY_MODEL_60K + + +// Multiple SID support + +#define CONFIG_SID_2ND +.const CONFIG_SID_2ND_ADDRESS = $D420 + +// #define CONFIG_SID_3RD +.const CONFIG_SID_3RD_ADDRESS = $D440 + +// #define CONFIG_SID_D4XX +// #define CONFIG_SID_D5XX + + +// Keyboard settings + +#define CONFIG_LEGACY_SCNKEY +// #define CONFIG_KEYBOARD_C128 // incomplete +// #define CONFIG_KEYBOARD_C128_CAPS_LOCK +// #define CONFIG_KEY_REPEAT_DEFAULT +// #define CONFIG_KEY_REPEAT_ALWAYS +#define CONFIG_KEY_FAST_SCAN +#define CONFIG_JOY1_CURSOR +#define CONFIG_JOY2_CURSOR + + +// Eye candy + +// #define CONFIG_COLORS_BRAND +// #define CONFIG_BANNER_SIMPLE +#define CONFIG_BANNER_FANCY +// #define CONFIG_BANNER_BRAND +// #define CONFIG_SHOW_PAL_NTSC + + +// Software features + +#define CONFIG_PANIC_SCREEN +#define CONFIG_DOS_WEDGE +#define CONFIG_BCD_SAFE_INTERRUPTS + + +// Debug options + +// #define CONFIG_DBG_STUBS_BRK +#define CONFIG_DBG_PRINTF diff --git a/c64/,,config_ultimate64.s b/c64/,,config_ultimate64.s index f7ce1b93..1eda8501 100644 --- a/c64/,,config_ultimate64.s +++ b/c64/,,config_ultimate64.s @@ -1,16 +1,44 @@ +.const CONFIG_ID = $02 // should be 1 byte, different for each config file! + // // Please read CONFIG.md before modifying this file! // +// Idea: +// - sane defaults for the Ultimate 64 FPGA computer +// - do not enable features which are a significant compatibility risk + + +// Hardware platform and brand + +#define CONFIG_PLATFORM_COMMODORE_64 + +// #define CONFIG_MB_MEGA_65 +#define CONFIG_MB_ULTIMATE_64 + +// #define CONFIG_BRAND_GENERIC +// #define CONFIG_BRAND_TESTING +// #define CONFIG_BRAND_MEGA_65 +#define CONFIG_BRAND_ULTIMATE_64 + + +// Processor instruction set #define CONFIG_CPU_MOS_6502 // #define CONFIG_CPU_WDC_65C02 +// #define CONFIG_CPU_CSG_65CE02 // #define CONFIG_CPU_WDC_65816 + +// Memory model configuration + #define CONFIG_MEMORY_MODEL_38K // #define CONFIG_MEMORY_MODEL_60K + +// Multiple SID support + // #define CONFIG_SID_2ND .const CONFIG_SID_2ND_ADDRESS = $D420 @@ -20,9 +48,36 @@ #define CONFIG_SID_D4XX #define CONFIG_SID_D5XX + +// Keyboard settings + +// #define CONFIG_LEGACY_SCNKEY +// #define CONFIG_KEYBOARD_C128 // incomplete +// #define CONFIG_KEYBOARD_C128_CAPS_LOCK +// #define CONFIG_KEY_REPEAT_DEFAULT +// #define CONFIG_KEY_REPEAT_ALWAYS +#define CONFIG_KEY_FAST_SCAN +#define CONFIG_JOY1_CURSOR +#define CONFIG_JOY2_CURSOR + + +// Eye candy + +#define CONFIG_COLORS_BRAND +// #define CONFIG_BANNER_SIMPLE +#define CONFIG_BANNER_FANCY +// #define CONFIG_BANNER_BRAND +#define CONFIG_SHOW_PAL_NTSC + + +// Software features + +#define CONFIG_PANIC_SCREEN #define CONFIG_DOS_WEDGE #define CONFIG_BCD_SAFE_INTERRUPTS -#define CONFIG_EXTENDED_SCNKEY // for now has to be enabled + + +// Debug options // #define CONFIG_DBG_STUBS_BRK // #define CONFIG_DBG_PRINTF diff --git a/c64/aliases/,aliases_config.s b/c64/aliases/,aliases_config.s index 868fc670..ac668e61 100644 --- a/c64/aliases/,aliases_config.s +++ b/c64/aliases/,aliases_config.s @@ -1,9 +1,102 @@ - // Various configuration dependent aliases/macros/checks +// +// Various configuration dependent aliases/macros/checks +// - // Check that memory model configuration is correct +// Check that platform configuration is correct + +{ + .var selected = 0; + +#if CONFIG_PLATFORM_COMMODORE_64 + .eval selected++ +#endif + + .if (selected != 1) .error "Please select exactly one CONFIG_PLATFORM_* option" +} + + + +// Check that motherboard extras configuration is correct + +{ + .var selected = 0; + +#if CONFIG_MB_MEGA_65 + .eval selected++ +#endif +#if CONFIG_MB_ULTIMATE_64 + .eval selected++ +#endif + + .if (selected > 1) .error "Please select at most one CONFIG_MB_* option" + +#if !CONFIG_PLATFORM_COMMODORE_64 && CONFIG_BRAND_MEGA_65 && + .error "CONFIG_BRAND_MEGA_65 can only be used with CONFIG_PLATFORM_COMMODORE_64" +#endif +#if !CONFIG_PLATFORM_COMMODORE_64 && CONFIG_BRAND_ULTIMATE_64 && + .error "CONFIG_BRAND_ULTIMATE_64 can only be used with CONFIG_PLATFORM_COMMODORE_64" +#endif +} + + + +// Check that brand configuration is correct + +{ + .var selected = 0; + +#if CONFIG_BRAND_GENERIC + .eval selected++ +#endif +#if CONFIG_BRAND_TESTING + .eval selected++ +#endif +#if CONFIG_BRAND_MEGA_65 + .eval selected++ +#endif +#if CONFIG_BRAND_ULTIMATE_64 + .eval selected++ +#endif + + .if (selected != 1) .error "Please select exactly one CONFIG_BRAND_* option" + +#if CONFIG_MB_MEGA_65 && !(CONFIG_BRAND_MEGA_65 || CONFIG_BRAND_TESTING) + .error "Please select brand either matching the CONFIG_MB_*, or a testing one" +#endif +#if CONFIG_MB_ULTIMATE_64 && !(CONFIG_BRAND_ULTIMATE_64 || CONFIG_BRAND_TESTING) + .error "Please select brand either matching the CONFIG_MB_*, or a testing one" +#endif +} + + + +// Check that processor configuration is correct + +{ + .var selected = 0; + +#if CONFIG_CPU_MOS_6502 + .eval selected++ +#endif +#if CONFIG_CPU_WDC_65C02 + .eval selected++ +#endif +#if CONFIG_CPU_CSG_65CE02 + .eval selected++ +#endif +#if CONFIG_CPU_WDC_65816 + .eval selected++ +#endif + + .if (selected != 1) .error "Please select exactly one CONFIG_CPU_* option" +} + + + +// Check that memory model configuration is correct { .var selected = 0; @@ -20,32 +113,54 @@ - // Check that processor configuration is correct +// Check that startup banner configuration is correct { .var selected = 0; -#if CONFIG_CPU_MOS_6502 +#if CONFIG_BANNER_SIMPLE .eval selected++ #endif -#if CONFIG_CPU_WDC_65C02 +#if CONFIG_BANNER_FANCY .eval selected++ #endif -#if CONFIG_CPU_WDC_65816 +#if CONFIG_BANNER_BRAND .eval selected++ #endif - .if (selected != 1) .error "Please select exactly one CONFIG_CPU_* option" + .if (selected != 1) .error "Please select exactly one CONFIG_BANNER_* option" + +#if CONFIG_BANNER_BRAND && !CONFIG_BRAND_MEGA_65 + .error "CONFIG_BANNER_BRAND is not supported for your CONFIG_BRAND_*" +#endif + +#if CONFIG_BANNER_BRAND && CONFIG_BRAND_MEGA_65 && CONFIG_SHOW_PAL_NTSC + .error "MEGA65 brand banner does not support showing PAL/NTSC" +#endif + } - // Handle processor configuration +// Check if keyboard options are correct -#if CONFIG_CPU_WDC_65C02 || CONFIG_CPU_WDC_65816 +{ +#if CONFIG_LEGACY_SCNKEY && (CONFIG_KEYBOARD_C128 || CONFIG_KEYBOARD_C128_CAPS_LOCK) + .error "CONFIG_LEGACY_SCNKEY and CONFIG_KEYBOARD_C128* are mutually exclusive" +#endif + +#if (CONFIG_MB_MEGA_65 || CONFIG_MB_ULTIMATE_64) && (CONFIG_KEYBOARD_C128 || CONFIG_KEYBOARD_C128_CAPS_LOCK) + .error "Selected CONFIG_MB_* is not compatible with CONFIG_KEYBOARD_C128*" +#endif +} + + + +// Handle processor configuration + +#if CONFIG_CPU_WDC_65C02 || CONFIG_CPU_CSG_65CE02 || CONFIG_CPU_WDC_65816 #define HAS_BCD_SAFE_INTERRUPTS -#define HAS_BCD_SAFE_RESET .pseudocommand phx { .byte $DA } .pseudocommand phy { .byte $5A } @@ -54,13 +169,17 @@ #endif - // Handle misc configuration entrues + + +// Handle configuration of various features #if CONFIG_BCD_SAFE_INTERRUPTS #define HAS_BCD_SAFE_INTERRUPTS #endif - // Stub configuration + + +// Handle configuration of debug infrastructure .macro STUB_IMPLEMENTATION_RTS() { rts diff --git a/c64/aliases/,aliases_cpu.s b/c64/aliases/,aliases_cpu.s new file mode 100644 index 00000000..01b980b6 --- /dev/null +++ b/c64/aliases/,aliases_cpu.s @@ -0,0 +1,165 @@ +// +// Provide pseudocommands to make CPU optimizations easier +// + + +// +// These are not exactly for optimization - but to encourage proper usage of panic screen +// + +.pseudocommand panic code +{ + // If case no panic screen is used, we can skip providing error codes within Kernal +#if CONFIG_PANIC_SCREEN || !SEGMENT_KERNAL + lda code +#endif + jmp ($E4B7) +} + + +// +// Stack manipulation - some CPUs will leave .A unchanged, some will use it as temporary storage, so consider .A trashed +// + + +.pseudocommand phx_trash_a +{ +#if CONFIG_CPU_WDC_65C02 || CONFIG_CPU_CSG_65CE02 || CONFIG_CPU_WDC_65816 + phx +#else + txa + pha +#endif +} + +.pseudocommand phy_trash_a +{ +#if CONFIG_CPU_WDC_65C02 || CONFIG_CPU_CSG_65CE02 || CONFIG_CPU_WDC_65816 + phy +#else + tya + pha +#endif +} + +.pseudocommand plx_trash_a +{ +#if CONFIG_CPU_WDC_65C02 || CONFIG_CPU_CSG_65CE02 || CONFIG_CPU_WDC_65816 + plx +#else + pla + tax +#endif +} + +.pseudocommand ply_trash_a +{ +#if CONFIG_CPU_WDC_65C02 || CONFIG_CPU_CSG_65CE02 || CONFIG_CPU_WDC_65816 + ply +#else + pla + tay +#endif +} + + +// +// Branches with far offsets, substitutes by Bxx + JMP for CPUs not supporting the instruction +// + + +.pseudocommand bcs_far dst +{ +#if CONFIG_CPU_CSG_65CE02 + .var offset = mod($10000 + dst.getValue() - *, $10000) + .byte $B3, mod(offset, $100), floor(offset / $100) +#else + bcc __l + jmp dst +__l: +#endif +} + +.pseudocommand bcc_far dst +{ +#if CONFIG_CPU_CSG_65CE02 + .var offset = mod($10000 + dst.getValue() - *, $10000) + .byte $93, mod(offset, $100), floor(offset / $100) +#else + bcs __l + jmp dst +__l: +#endif +} + +.pseudocommand beq_far dst +{ +#if CONFIG_CPU_CSG_65CE02 + .var offset = mod($10000 + dst.getValue() - *, $10000) + .byte $F3, mod(offset, $100), floor(offset / $100) +#else + bne __l + jmp dst +__l: +#endif +} + +.pseudocommand bne_far dst +{ +#if CONFIG_CPU_CSG_65CE02 + .var offset = mod($10000 + dst.getValue() - *, $10000) + .byte $D3, mod(offset, $100), floor(offset / $100) +#else + beq __l + jmp dst +__l: +#endif +} + +.pseudocommand bmi_far dst +{ +#if CONFIG_CPU_CSG_65CE02 + .var offset = mod($10000 + dst.getValue() - *, $10000) + .byte $33, mod(offset, $100), floor(offset / $100) +#else + bpl __l + jmp dst +__l: +#endif +} + +.pseudocommand bpl_far dst +{ +#if CONFIG_CPU_CSG_65CE02 + .var offset = mod($10000 + dst.getValue() - *, $10000) + .byte $13, mod(offset, $100), floor(offset / $100) +#else + bmi __l + jmp dst +__l: +#endif +} + +.pseudocommand bvc_far dst +{ +#if CONFIG_CPU_CSG_65CE02 + .var offset = mod($10000 + dst.getValue() - *, $10000) + .byte $53, mod(offset, $100), floor(offset / $100) +#else + bvs __l + jmp dst +__l: +#endif +} + +.pseudocommand bvs_far dst +{ +#if CONFIG_CPU_CSG_65CE02 + .var offset = mod($10000 + dst.getValue() - *, $10000) + .byte $73, mod(offset, $100), floor(offset / $100) +#else + bvc __l + jmp dst +__l: +#endif +} diff --git a/c64/aliases/,aliases_error_codes.s b/c64/aliases/,aliases_error_codes.s index 5af898a1..fc30b384 100644 --- a/c64/aliases/,aliases_error_codes.s +++ b/c64/aliases/,aliases_error_codes.s @@ -1,4 +1,10 @@ + // Error codes for 'panic' pseudocommand + + .const P_ERR_NONE = $00 + .const P_ERR_ROM_MISMATCH = $01 // this value has to be stable as long as possible + + // Kernal error codes - returned in the A register // Described in 'Commodore 64 Programmer's Reference Guide', page 306 diff --git a/c64/aliases/,aliases_hardware.s b/c64/aliases/,aliases_hardware.s index 73abfd8c..63790da6 100644 --- a/c64/aliases/,aliases_hardware.s +++ b/c64/aliases/,aliases_hardware.s @@ -1,8 +1,11 @@ // -// Names of hardware registers - slightly modified names from C64 Programmer's Reference Guide +// Names of hardware registers - names from C64 Programmer's Reference Guide, sometimes slightly modified // + +#if CONFIG_PLATFORM_COMMODORE_64 + // CPU memory registers .label CPU_D6510 = $00 @@ -61,7 +64,14 @@ .label VIC_SP5COL = $D02C .label VIC_SP6COL = $D02D .label VIC_SP7COL = $D02E - + +#if !CONFIG_MB_MEGA_65 && !CONFIG_MB_ULTIMATE_64 + + .label VIC_XSCAN = $D02F // C128 only + .label VIC_CLKRATE = $D030 // C128 only + +#endif + // SID registers .label __SID_BASE = $D400 // base address of the chip @@ -154,3 +164,13 @@ .const BIT_CIA2_PRA_DAT_OUT = $20 // 1 - low (pulled), 0 - high (released) .const BIT_CIA2_PRA_CLK_IN = $40 // 0 - low (pulled), 1 - high (released) .const BIT_CIA2_PRA_DAT_IN = $80 // 0 - low (pulled), 1 - high (released) + +#if CONFIG_MB_MEGA_65 + + .const C65_EXTKEYS_PR = $D607 + .const C65_EXTKEYS_DDR = $D608 + +#endif + + +#endif diff --git a/c64/aliases/,aliases_petscii_codes.s b/c64/aliases/,aliases_petscii_codes.s new file mode 100644 index 00000000..d62bf4ec --- /dev/null +++ b/c64/aliases/,aliases_petscii_codes.s @@ -0,0 +1,154 @@ + +// +// PETSCII codes for all the supported keys, for all the keyboards +// +// - [CM64] Compute's Mapping the Commodore 64 +// - [CM128] Compute's Mapping the Commodore 128 +// - https://github.com/MEGA65/c65-specifications/blob/master/c65manualupdated.txt +// - https://en.wikipedia.org/wiki/PETSCII +// + + + +// Not really PETSCII codes, but bitmask values for SHFLAG variable +// [CM64] page 68, [CM128] page 212 + +.const KEY_FLAG_SHIFT = %00000001 +.const KEY_FLAG_VENDOR = %00000010 +.const KEY_FLAG_CTRL = %00000100 +.const KEY_FLAG_ALT = %00001000 // C65 / C128 +.const KEY_CAPS_LOCK = %00010000 // C65 / C128 +.const KEY_FLAG_NO_SCRL = %00100000 // C65 / C128, Open ROMs unofficial + + +// Note - the following PETSCII codes are currently unassigned, can be used for further extensions: +// +// $01, $04, $06, $0A, $0B, $0C, $0F, $18, $82 + + +.const KEY_NA = $00 // to indicate that no key is presed + + +// PETSCII codes for our extended screen editor XXX implement these + +.const KEY_BOTTOM = $02 // CTRL+B - Open ROMs unofficial, DolphinDOS compatible +.const KEY_TAB_FW = $8F // CTRL+>, TAB - Open ROMs unofficial, original TAB conflicts with C64 PETSCII +.const KEY_TAB_BW = $80 // CTRL+<, SHIFT+TAB - Open ROMs unofficial, original TAB conflicts with C64 PETSCII + + +// PETSCII codes for certain C128 and C65 functionalities XXX implement these + +.const KEY_BELL = $07 // C65 / C128, no key +.const KEY_ESC = $1B // C65 / C128 + + +// PETSCII codes for programmable keys + +.const KEY_STOP = $03 +.const KEY_RUN = $83 + +.const KEY_F1 = $85 +.const KEY_F2 = $86 +.const KEY_F3 = $87 +.const KEY_F4 = $88 +.const KEY_F5 = $89 +.const KEY_F6 = $8A +.const KEY_F7 = $8B +.const KEY_F8 = $8C + +.const KEY_F9 = $10 // C65 +.const KEY_F10 = $15 // C65 +.const KEY_F11 = $16 // C65 +.const KEY_F12 = $17 // C65 +.const KEY_F13 = $19 // C65 +.const KEY_F14 = $1A // C65 + +.const KEY_HELP = $84 // C65, also used for our C128 support + + +// PETSCII codes for cursor keys + +.const KEY_CRSR_UP = $91 +.const KEY_CRSR_DOWN = $11 +.const KEY_CRSR_LEFT = $9D +.const KEY_CRSR_RIGHT = $1D + + +// PETSCII codes for colors + +.const KEY_RVS_ON = $12 // CTRL+9 +.const KEY_RVS_OFF = $92 // CTRL+0 + +.const KEY_BLACK = $90 // CTRL+1 +.const KEY_WHITE = $05 // CTRL+2 +.const KEY_RED = $1C // CTRL+3 +.const KEY_CYAN = $9F // CTRL+4 +.const KEY_PURPLE = $9C // CTRL+5 +.const KEY_GREEN = $1E // CTRL+6 +.const KEY_BLUE = $1F // CTRL+7 +.const KEY_YELLOW = $9E // CTRL+8 + +.const KEY_ORANGE = $81 // VENDOR+1 +.const KEY_BROWN = $95 // VENDOR+2 +.const KEY_LT_RED = $96 // VENDOR+3 +.const KEY_GREY_1 = $97 // VENDOR+4 +.const KEY_GREY_2 = $98 // VENDOR+5 +.const KEY_LT_GREEN = $99 // VENDOR+6 +.const KEY_LT_BLUE = $9A // VENDOR+7 +.const KEY_GREY_3 = $9B // VENDOR+8 + + +// PETSCII codes for case toggle + +.const KEY_SHIFT_ON = $09 // no key +.const KEY_SHIFT_OFF = $08 // no key +.const KEY_TXT = $0E // no key +.const KEY_GFX = $8E // no key + + +// PETSCII codes for other non-printable characters + +.const KEY_RETURN = $0D +.const KEY_CLR = $93 +.const KEY_HOME = $13 +.const KEY_INS = $94 +.const KEY_DEL = $14 + + +// PETSCII codes for printable characters + +.const KEY_SPACE = $20 +.const KEY_EXCLAMATION = $21 +.const KEY_QUOTE = $22 +.const KEY_HASH = $23 +.const KEY_DOLLAR = $24 +.const KEY_PERCENT = $25 +.const KEY_AMPERSAND = $26 +.const KEY_APOSTROPHE = $27 +.const KEY_R_BRACKET_L = $28 +.const KEY_R_BRACKET_R = $29 +.const KEY_ASTERISK = $2A +.const KEY_PLUS = $2B +.const KEY_COMA = $2C +.const KEY_MINUS = $2D +.const KEY_FULLSTOP = $2E +.const KEY_SLASH = $2F + +.const KEY_0 = $30 +.const KEY_1 = $31 +.const KEY_2 = $32 +.const KEY_3 = $33 +.const KEY_4 = $34 +.const KEY_5 = $35 +.const KEY_6 = $36 +.const KEY_7 = $37 +.const KEY_8 = $38 +.const KEY_9 = $39 +.const KEY_COLON = $3A +.const KEY_SEMICOLON = $3B +.const KEY_LT = $3C +.const KEY_EQ = $3D +.const KEY_GT = $3E +.const KEY_QUESTION = $3F + +// XXX finish this: $4x, $5x, $6x, $7x, $Ax, $Bx, $Cx, $Dx, $Ex, $Fx diff --git a/c64/aliases/,aliases_ram_lowmem.s b/c64/aliases/,aliases_ram_lowmem.s index bc391aae..905446dc 100644 --- a/c64/aliases/,aliases_ram_lowmem.s +++ b/c64/aliases/,aliases_ram_lowmem.s @@ -104,51 +104,22 @@ .label CNTDN = $A5 // -- NOT IMPLEMENTED -- .label BUFPNT = $A6 // -- NOT IMPLEMENTED -- .label INBIT = $A7 // -- NOT IMPLEMENTED -- - -#if CONFIG_EXTENDED_SCNKEY - - // Reuse RS232 variables, since they should not be used by other things. - // Carefully avoid $A7 which is used by 64NET - .label KeyQuantity = $A8 // 1 byte - .label BufferNew = $A9 // 3 bytes - -#else +#if !CONFIG_LEGACY_SCNKEY .label BITCI = $A8 // -- NOT IMPLEMENTED -- .label RINONE = $A9 // -- NOT IMPLEMENTED -- .label RIDDATA = $AA // -- NOT IMPLEMENTED -- .label RIPRTY = $AB // -- NOT IMPLEMENTED -- - #endif - .label SAL = $AC // $AC-$AD -- NOT IMPLEMENTED -- (implemented screen part) .label EAL = $AE // $AE-$AF -- NOT IMPLEMENTED -- [!] used also by screen editor, for temporary color storage when scrolling .label CMP0 = $B0 // $B0-$B1 temporary tape storage, [!] here used for BRK instruction address .label TAPE1 = $B2 // $B2-$B3 tape buffer pointer - -#if CONFIG_EXTENDED_SCNKEY - - // Reuse RS232 variables, since they should not be used by other things. - // This one should be initialized in cinit to $FF - .label BufferQuantity = $B4 // 1 byte - -#else - +#if !CONFIG_LEGACY_SCNKEY .label BITTS = $B4 // -- NOT IMPLEMENTED -- - #endif - .label NXTBIT = $B5 // -- NOT IMPLEMENTED -- - -#if CONFIG_EXTENDED_SCNKEY - - // Reuse RS232 variables, since they should not be used by other things. - // Carefully avoiding $A7 which is used by 64NET - .label TempZP = $B6 // 1 byte - -#else - +#if !CONFIG_LEGACY_SCNKEY .label RODATA = $B6 // -- NOT IMPLEMENTED -- - #endif .label FNLEN = $B7 // current file name length @@ -182,7 +153,7 @@ .label INSRT = $D8 // insert mode flag/counter .label LDTBL = $D9 // $D9-$F2 screen line link table, [!] our usage is different XXX give more details .label USER = $F3 // $F3-$F4 pointer to current color RAM location - .label KEYTAB = $F5 // $F5-$F6 -- NOT IMPLEMENTED -- + .label KEYTAB = $F5 // $F5-$F6 pointer to keyboard lookup table .label RIBUF = $F7 // $F7-$F8 -- NOT IMPLEMENTED -- .label ROBUF = $F9 // $F9-$FA -- NOT IMPLEMENTED -- // $FB $FB-$FE -- UNUSED -- free for user software @@ -200,13 +171,8 @@ .label BUF = $200 // $200-$250, BASIC line editor input buffer (81 bytes) -#if CONFIG_EXTENDED_SCNKEY - // $250-$258 is the 81st - 88th characters in BASIC input, a carry over from VIC-20 - // and not used on C64, so safe for us to use, probably. - .label ScanResult = $250 // 8 bytes - -#endif + // and not used on C64 - they are used if CONFIG_LEGACY_SCNKEY is enabled. // [!] XXX document $251-$258 usage .label LAT = $259 // $259-$262, logical file numbers (table, 10 bytes) @@ -220,7 +186,7 @@ .label GDCOL = $287 // color of character under cursor .label HIBASE = $288 // high byte of start of screen .label XMAX = $289 // max keyboard buffer size - .label RPTFLG = $28A // -- NOT IMPLEMENTED -- + .label RPTFLG = $28A // whether to repeat keys (highest bit set = repeat) .label KOUNT = $28B // key repeat counter .label DELAY = $28C // -- NOT IMPLEMENTED -- .label SHFLAG = $28D // bucky keys (SHIFT/CTRL/C=) flags @@ -228,25 +194,14 @@ .label KEYLOG = $28F // $28F-$290 routine to setup keyboard decoding .label MODE = $291 // flag, is case switch allowed .label AUTODN = $292 // -- NOT IMPLEMENTED -- screen scroll disable - -#if CONFIG_EXTENDED_SCNKEY - - // Reuse RS232 variables, since they should not be used by other things. - // This one should be initialized in cinit to $FF - .label BufferOld = $293 // 3 bytes - .label Buffer = $297 // 4 bytes - -#else - +#if !CONFIG_LEGACY_SCNKEY .label M51CRT = $293 // -- NOT IMPLEMENTED -- mock 6551 .label M51CDR = $294 // -- NOT IMPLEMENTED -- mock 6551 .label M51AJB = $295 // $295-$296 -- NOT IMPLEMENTED -- mock 6551 .label RSSTAT = $297 // -- NOT IMPLEMENTED -- mock 6551, RS-232 status .label BITNUM = $298 // -- NOT IMPLEMENTED -- .label BAUDOF = $299 // $299-$29A -- NOT IMPLEMENTED -- - #endif - .label RIDBE = $29B // -- NOT IMPLEMENTED -- .label RIDBS = $29C // -- NOT IMPLEMENTED -- .label RODBS = $29D // -- NOT IMPLEMENTED -- @@ -275,7 +230,7 @@ #if SEGMENT_BASIC .label shift_mem_up = tiny_nmi_handler + shift_mem_up_routine - tiny_nmi_handler_routine .label shift_mem_down = tiny_nmi_handler + shift_mem_down_routine - tiny_nmi_handler_routine -#endif // SEGMENT_BASIC +#endif #endif // CONFIG_MEMORY_MODEL_60K diff --git a/c64/basic/,imports.s b/c64/basic/,imports.s index b195dcac..bc90a4cd 100644 --- a/c64/basic/,imports.s +++ b/c64/basic/,imports.s @@ -4,10 +4,21 @@ #import "KERNAL_combined.sym" +#if CONFIG_PANIC_SCREEN +.label panic = KERNAL.panic +#endif + +.label hw_entry_reset = KERNAL.hw_entry_reset + #if CONFIG_DBG_PRINTF .label printf = KERNAL.printf #endif +.label plot_set = KERNAL.plot_set .label print_hex_byte = KERNAL.print_hex_byte .label print_return = KERNAL.print_return .label print_space = KERNAL.print_space + +#if CONFIG_SHOW_PAL_NTSC +.label print_pal_ntsc = KERNAL.print_pal_ntsc +#endif diff --git a/c64/basic/,target_generic/,hooks_generic.s b/c64/basic/,target_generic/,hooks_generic.s deleted file mode 100644 index c87cffd9..00000000 --- a/c64/basic/,target_generic/,hooks_generic.s +++ /dev/null @@ -1,10 +0,0 @@ - -// Target-specific hooks - - -.macro TARGET_HOOK_BANNER() { - - .text " OPEN ROMS, " - .byte $00 - -} diff --git a/c64/basic/,target_ultimate64/,hooks_ultimate64.s b/c64/basic/,target_ultimate64/,hooks_ultimate64.s deleted file mode 100644 index 985ea57d..00000000 --- a/c64/basic/,target_ultimate64/,hooks_ultimate64.s +++ /dev/null @@ -1,12 +0,0 @@ - -// Target-specific hooks - - -.macro TARGET_HOOK_BANNER() { - - .text " OPEN ROMS FOR ULTIMATE 64" - .byte $0D, $0D - .text " " - .byte $00 - -} diff --git a/c64/basic/a408.interop b/c64/basic/a408.interop new file mode 100644 index 00000000..fe2f5c41 --- /dev/null +++ b/c64/basic/a408.interop @@ -0,0 +1,2 @@ + +This address is called at least by the Simon's BASIC cartridge. diff --git a/c64/kernal/setup_keydecode.s b/c64/basic/a408.reason.s similarity index 81% rename from c64/kernal/setup_keydecode.s rename to c64/basic/a408.reason.s index d6010685..f7613215 100644 --- a/c64/kernal/setup_keydecode.s +++ b/c64/basic/a408.reason.s @@ -1,5 +1,5 @@ // XXX provide documentation and implementation -setup_keydecode: +REASON: STUB_IMPLEMENTATION() diff --git a/c64/basic/a453.interop b/c64/basic/a453.interop new file mode 100644 index 00000000..f5dc0a42 --- /dev/null +++ b/c64/basic/a453.interop @@ -0,0 +1,3 @@ + +This routine is probably used by many cartridges and other software to initialize parts of the system. At least the UCart uses it - see here: +- https://www.elektroda.pl/rtvforum/topic3293027.html diff --git a/c64/basic/a453.unknown.s b/c64/basic/a453.unknown.s new file mode 100644 index 00000000..ecb53d23 --- /dev/null +++ b/c64/basic/a453.unknown.s @@ -0,0 +1,4 @@ + +// XXX provide documentation and implementation + + STUB_IMPLEMENTATION() \ No newline at end of file diff --git a/c64/basic/a533.interop b/c64/basic/a533.interop new file mode 100644 index 00000000..46ed7adf --- /dev/null +++ b/c64/basic/a533.interop @@ -0,0 +1,7 @@ +This routine is used to launch other software. It is used by: + +- Uncrunch (see https://github.com/mist64/pucrunch/blob/master/uncrunch.asm) +- FileBrowser64 (FB64) - found by debugging + +and probably others. + diff --git a/c64/basic/a533.linkprg.s b/c64/basic/a533.linkprg.s new file mode 100644 index 00000000..675a794e --- /dev/null +++ b/c64/basic/a533.linkprg.s @@ -0,0 +1,91 @@ + +// +// Well-known BASIC routine, described in: +// +// - [CM64] Compute's Mapping the Commodore 64 - page 95 +// - https://www.lemon64.com/forum/viewtopic.php?t=64721&sid=bc400a5a6d404f8f092e4d32a92f5de7 +// + +LINKPRG: + + // Start by getting pointer to the first line + jsr init_oldtxt + +linkprg_loop: + // Is the pointer to the end of the program + ldy #1 + +#if CONFIG_MEMORY_MODEL_60K + ldx #$0200 + lda #>BUF sta TXTPTR+1 jsr basic_parse_line_number @@ -94,13 +111,13 @@ rsl_l1: lda $0200,x // Skip any spaces after the line number ldx __tokenise_work1 skip_spaces: - lda $0200,x + lda BUF,x cmp #$20 bne !+ inx bne skip_spaces !: stx __tokenise_work1 - + // First, clear all variables, so that we only have to shove BASIC text around. // (We could later remove this requirement, and the only effect should be // to slow things down, and that you might have to either CLR if there is no @@ -131,9 +148,9 @@ not_a_line: // Actually interpret the line // Setup pointer to the statement - lda #<$0200 + lda #$0200 + lda #>BUF sta TXTPTR+1 // There is no stored line, so zero that pointer out @@ -144,7 +161,7 @@ not_a_line: // Put invalid line number in current line number value, // so that we know we are in direct mode // (Compute's Mapping the 64 p19) - lda #$ff + lda #$FF sta CURLIN+1 jmp basic_execute_statement diff --git a/c64/basic/bdcd.linprt.s b/c64/basic/bdcd.linprt.s index 32afbf1b..7e58bebe 100644 --- a/c64/basic/bdcd.linprt.s +++ b/c64/basic/bdcd.linprt.s @@ -7,4 +7,6 @@ LINPRT: - STUB_IMPLEMENTATION() + // XXX This is temporary, to allow some software to work! + // To be replaced by real impleementation. + jmp print_integer diff --git a/c64/basic/cmd_sys.s b/c64/basic/cmd_sys.s deleted file mode 100644 index 0f46f630..00000000 --- a/c64/basic/cmd_sys.s +++ /dev/null @@ -1,31 +0,0 @@ -cmd_sys: - - jsr basic_end_of_statement_check - bcc !+ - - // SYS requires an argument - jmp do_SYNTAX_error - -!: - jsr basic_parse_line_number - - // setup call - lda #$4C // JMP opcode - sta USRPOK - lda LINNUM+0 - sta USRADD+0 - lda LINNUM+1 - sta USRADD+1 - - // Setup the register values - lda SPREG - pha - ldy SYREG - ldx SXREG - lda SAREG - plp - - // Call the routine. - jsr USRPOK - - jmp basic_execute_statement diff --git a/c64/basic/cmd_break.s b/c64/basic/commands/cmd_break.s similarity index 89% rename from c64/basic/cmd_break.s rename to c64/basic/commands/cmd_break.s index d3aa3cd3..82909193 100644 --- a/c64/basic/cmd_break.s +++ b/c64/basic/commands/cmd_break.s @@ -1,5 +1,5 @@ cmd_stop: - ldx #38 // "BREAK" + ldx #30 // "BREAK" jsr print_packed_message // Are we in direct mode @@ -8,7 +8,7 @@ cmd_stop: beq !+ // Not direct mode - ldx #37 + ldx #31 jsr print_packed_message lda CURLIN+1 diff --git a/c64/basic/cmd_list.s b/c64/basic/commands/cmd_list.s similarity index 92% rename from c64/basic/cmd_list.s rename to c64/basic/commands/cmd_list.s index 2aef7ccb..6cf022e5 100644 --- a/c64/basic/cmd_list.s +++ b/c64/basic/commands/cmd_list.s @@ -4,10 +4,7 @@ cmd_list: // Set current line pointer to start of memory - lda TXTTAB+0 - sta OLDTXT+0 - lda TXTTAB+1 - sta OLDTXT+1 + jsr init_oldtxt list_loop: @@ -82,16 +79,20 @@ list_print_loop: cmp #$22 bne list_not_quote lda QTSW - eor #$ff + eor #$FF sta QTSW lda #$22 jmp list_is_literal + list_not_quote: // Check quote mode, and display as literal if required ldx QTSW bne list_is_literal - cmp #$7f + cmp #$FF + beq list_is_pi + + cmp #$7F bcc list_is_literal // Display a token @@ -99,8 +100,7 @@ list_not_quote: // Save registers tax pha - tya - pha + phy_trash_a // Get pointer to compressed keyword list lda #2060 + sta LINNUM+1 + bne cmd_sys_setup_call // always jumps + +cmd_sys_hack_not_needed: + + // + // XXX End of hack + // + + jsr basic_parse_line_number + +cmd_sys_setup_call: + lda #$4C // JMP opcode + sta USRPOK + lda LINNUM+0 + sta USRADD+0 + lda LINNUM+1 + sta USRADD+1 + + // Setup the register values + lda SPREG + pha + ldy SYREG + ldx SXREG + lda SAREG + plp + + // Call the routine. + jsr USRPOK + + jmp basic_execute_statement + + + // + // XXX Temporary ugly hack to support 'SYS PI*656' + // + +cmd_sys_hack_str: + .byte $FF, $AC, $36, $35, $36, $00 diff --git a/c64/basic/cmd_unimplemented.s b/c64/basic/commands/cmd_unimplemented.s similarity index 100% rename from c64/basic/cmd_unimplemented.s rename to c64/basic/commands/cmd_unimplemented.s diff --git a/c64/basic/do_basic_error.s b/c64/basic/do_basic_error.s index 31bd947f..1135e102 100644 --- a/c64/basic/do_basic_error.s +++ b/c64/basic/do_basic_error.s @@ -150,7 +150,7 @@ do_basic_error: beq !+ // We were in a program, so show IN - ldx #37 + ldx #31 jsr print_packed_message lda CURLIN+1 diff --git a/c64/basic/e422.initmsg.s b/c64/basic/e422.initmsg.s deleted file mode 100644 index 2520c5bd..00000000 --- a/c64/basic/e422.initmsg.s +++ /dev/null @@ -1,44 +0,0 @@ - -// -// Well-known BASIC routine, described in: -// -// - [CM64] Compute's Mapping the Commodore 64 - page 212 -// -// Prints the start-up messages -// - -INITMSG: - - // Print startup banner, up to 255 characters - ldx #$00 -!: - lda startup_banner, x - beq !+ // 0 means end of banner - jsr JCHROUT - inx - bne !- - -!: - // Print PAL/NTSC - ldx #30 // NTSC - lda TVSFLG - beq !+ - ldx #31 // PAL -!: - jsr print_packed_message - - // Work out free bytes, display them - jsr basic_do_new - sec - lda MEMSIZ+0 - sbc TXTTAB+0 - tax - lda MEMSIZ+1 - sbc TXTTAB+1 - - jsr print_integer - jsr print_space - - // Print rest of the start up message - ldx #34 - jmp print_packed_message diff --git a/c64/basic/a000.cold_start_vector.s b/c64/basic/init/a000.cold_start_vector.s similarity index 100% rename from c64/basic/a000.cold_start_vector.s rename to c64/basic/init/a000.cold_start_vector.s diff --git a/c64/basic/a002.warm_start_vector.s b/c64/basic/init/a002.warm_start_vector.s similarity index 100% rename from c64/basic/a002.warm_start_vector.s rename to c64/basic/init/a002.warm_start_vector.s diff --git a/c64/basic/basic_cold_start.s b/c64/basic/init/basic_cold_start_internal.s similarity index 84% rename from c64/basic/basic_cold_start.s rename to c64/basic/init/basic_cold_start_internal.s index 5f8d27e3..a7326089 100644 --- a/c64/basic/basic_cold_start.s +++ b/c64/basic/init/basic_cold_start_internal.s @@ -1,7 +1,9 @@ -// BASIC Cold start entry point -// Compute's Mapping the 64 p211 -basic_cold_start: +// +// Continuation of the BASIC cold start routine +// + +basic_cold_start_internal: // Setup vectors at $300 ldy #$0B diff --git a/c64/basic/basic_warm_start.s b/c64/basic/init/basic_warm_start_internal.s similarity index 73% rename from c64/basic/basic_warm_start.s rename to c64/basic/init/basic_warm_start_internal.s index 1416ec4e..b271b928 100644 --- a/c64/basic/basic_warm_start.s +++ b/c64/basic/init/basic_warm_start_internal.s @@ -1,6 +1,9 @@ -// Clear screen etc, show READY prompt. -basic_warm_start: +// +// Continuation of the BASIC cold start routine +// + +basic_warm_start_real: #if CONFIG_MEMORY_MODEL_60K // We need our helpers to get to filenames under ROMs or IO area @@ -8,6 +11,7 @@ basic_warm_start: #endif // If warm start caused by BRK, print it address + // XXX sys 58235 also triggers this - to be fixed lda CMP0 ora CMP0+1 beq !+ diff --git a/c64/basic/init/e394.basic_cold_start.s b/c64/basic/init/e394.basic_cold_start.s new file mode 100644 index 00000000..fe181381 --- /dev/null +++ b/c64/basic/init/e394.basic_cold_start.s @@ -0,0 +1,22 @@ +// BASIC Cold start entry point +// Compute's Mapping the 64 p211 + +basic_cold_start: + + // Before doing anything, check if we have a compatible BASIC/KERNAL pair + + ldy #(__rom_revision_basic_end - rom_revision_basic - 1) +!: + lda rom_revision_basic, y + cmp rom_revision_kernal, y + beq !+ + + panic #P_ERR_ROM_MISMATCH + +!: + dey + bpl !-- + + // Remaining part wouldn't fit here + + jmp basic_cold_start_internal diff --git a/c64/basic/init/e394.interop b/c64/basic/init/e394.interop new file mode 100644 index 00000000..ed2b4a81 --- /dev/null +++ b/c64/basic/init/e394.interop @@ -0,0 +1,8 @@ + +The address of the BASIC cold start routine (see Compute's Mapping the Commodore 64, page 211) is well known, see for example here: + +- https://www.lemon64.com/forum/viewtopic.php?t=70680&sid=3ff66caf7f5fdf2a3c2ff2ee31fc3fd8 + +Fixing this routine also has a great advantage for us - since it's address lies in the uppeer ROM region, it's easier to bailout +when someone tries to use our 'kernal.rom' with the original 'basic.rom'. + diff --git a/c64/basic/init/e3b7.basic_warm_start.jmp.s b/c64/basic/init/e3b7.basic_warm_start.jmp.s new file mode 100644 index 00000000..8ebcfbde --- /dev/null +++ b/c64/basic/init/e3b7.basic_warm_start.jmp.s @@ -0,0 +1,5 @@ +// Clear screen etc, show READY prompt. + +basic_warm_start: + + jmp basic_warm_start_real diff --git a/c64/basic/init/e3b7.interop b/c64/basic/init/e3b7.interop new file mode 100644 index 00000000..1af6a185 --- /dev/null +++ b/c64/basic/init/e3b7.interop @@ -0,0 +1,5 @@ + +This is a well-known address, needed even for some BASIC programming - it's a common target for a SYS command. See for example here: + +- http://ready64.org/articoli/_files/043_pokesc64.txt + sys 58235 - Warm Start diff --git a/c64/basic/init/e422.initmsg.jmp.s b/c64/basic/init/e422.initmsg.jmp.s new file mode 100644 index 00000000..5bb33656 --- /dev/null +++ b/c64/basic/init/e422.initmsg.jmp.s @@ -0,0 +1,11 @@ + +// +// Well-known BASIC routine, described in: +// +// - [CM64] Compute's Mapping the Commodore 64 - page 212 +// +// Prints the start-up messages +// + +INITMSG: + jmp initmsg_real diff --git a/c64/basic/e422.interop b/c64/basic/init/e422.interop similarity index 100% rename from c64/basic/e422.interop rename to c64/basic/init/e422.interop diff --git a/c64/basic/init/initmsg_bytes_free.s b/c64/basic/init/initmsg_bytes_free.s new file mode 100644 index 00000000..d4df557c --- /dev/null +++ b/c64/basic/init/initmsg_bytes_free.s @@ -0,0 +1,21 @@ + +// +// Print out the amount of free bytes - for the startup banner +// + + +initmsg_bytes_free: + + jsr basic_do_new + sec + lda MEMSIZ+0 + sbc TXTTAB+0 + tax + lda MEMSIZ+1 + sbc TXTTAB+1 + + jsr print_integer + + // Print rest of the start up message + ldx #34 + jmp print_packed_message diff --git a/c64/basic/init/initmsg_real.s b/c64/basic/init/initmsg_real.s new file mode 100644 index 00000000..169a8cd3 --- /dev/null +++ b/c64/basic/init/initmsg_real.s @@ -0,0 +1,95 @@ + +// Routine is too long to fit in the original location + + +initmsg_real: + +#if CONFIG_BANNER_SIMPLE + + lda #startup_banner + jsr STROUT + + ldx #$02 + ldy #$02 + jsr plot_set + + lda #rom_revision_basic_string + jsr STROUT + + ldx #$04 + ldy #$02 + jsr plot_set + +#if CONFIG_SHOW_PAL_NTSC + jsr print_pal_ntsc +#endif + + jsr initmsg_bytes_free + + ldx #$07 + ldy #$00 + jmp plot_set + +#elif CONFIG_BANNER_FANCY + + lda #rainbow_logo + jsr STROUT + + ldx #$01 + ldy #$0A + jsr plot_set + + lda #startup_banner + jsr STROUT + + ldx #$03 + ldy #$0A + jsr plot_set + + lda #pre_revision_string + jsr STROUT + + lda #rom_revision_basic_string + jsr STROUT + + ldx #$05 + ldy #$00 + jsr plot_set + +#if CONFIG_SHOW_PAL_NTSC + jsr print_pal_ntsc +#endif + + jsr initmsg_bytes_free + + ldx #$07 + ldy #$00 + jmp plot_set + +#elif CONFIG_BANNER_BRAND && CONFIG_BRAND_MEGA_65 + + lda #startup_banner + jsr STROUT + + lda #rom_revision_basic_string + jsr STROUT + + ldx #$03 + ldy #$12 + jsr plot_set + + jsr initmsg_bytes_free + + ldx #$05 + ldy #$00 + jmp plot_set + +#endif diff --git a/c64/basic/,target_mega65/,hooks_mega65.s b/c64/basic/init/startup_banner.s similarity index 64% rename from c64/basic/,target_mega65/,hooks_mega65.s rename to c64/basic/init/startup_banner.s index 07b2b58e..0fbc4049 100644 --- a/c64/basic/,target_mega65/,hooks_mega65.s +++ b/c64/basic/init/startup_banner.s @@ -1,10 +1,72 @@ -// Target-specific hooks +// +// Startup banner, to be displayed during cold start +// -.macro TARGET_HOOK_BANNER() { +.macro BANNER_TEXT() { - // New banner from Retrofan +#if CONFIG_BRAND_GENERIC + .text "OPEN ROMS GENERIC BUILD" +#elif CONFIG_BRAND_TESTING + .text "OPEN ROMS TESTING BUILD" +#elif CONFIG_BRAND_MEGA_65 + .text "OPEN ROMS FOR MEGA65" +#elif CONFIG_BRAND_ULTIMATE_64 + .text "OPEN ROMS FOR ULTIMATE 64" +#endif + +} + +startup_banner: + +#if CONFIG_BANNER_SIMPLE + + .text " " + BANNER_TEXT() + .byte $00 + +#elif CONFIG_BANNER_FANCY + + BANNER_TEXT() + .byte $00 + +rainbow_logo: + +{ +#if CONFIG_COLORS_BRAND && CONFIG_BRAND_MEGA_65 + + .var SET_COLOR_0 = $05 + .var SET_COLOR_1 = $9A + .var SET_COLOR_2 = $1E + .var SET_COLOR_3 = $9E + .var SET_COLOR_4 = $96 + +#else + + .var SET_COLOR_0 = $05 + .var SET_COLOR_1 = $1C + .var SET_COLOR_2 = $9E + .var SET_COLOR_3 = $1E + .var SET_COLOR_4 = $9F + +#endif + + .byte SET_COLOR_1, $12, $A4, $A4, $A4, $A4, $A4, $A4, $A4, $0D + .byte SET_COLOR_2, $12, $A4, $A4, $A4, $A4, $A4, $A4, $0D + .byte SET_COLOR_3, $12, $A4, $A4, $A4, $A4, $A4, $0D + .byte SET_COLOR_4, $12, $A4, $A4, $A4, $A4, $92 + .byte SET_COLOR_0, $00 +} + +pre_revision_string: + + .text "RELEASE " + .byte $00 + +#elif CONFIG_BANNER_BRAND && CONFIG_BRAND_MEGA_65 + + // Fancy Mega65 banner - from Retrofan .byte $9a, $12, $20, $20, $7f, $a9, $20, $20, $1f, $20, $9a, $20, $20, $20 .byte $20, $1f, $20, $9a, $a9, $20, $20, $20, $92, $a1, $1f, $12, $20, $9a, $a9, $20 .byte $20, $20, $7f, $1f, $20, $20, $9a, $a3, $a3, $a3, $a3, $a3, $a3, $a3, $1f, $20 @@ -21,7 +83,7 @@ .byte $20, $20, $1f, $20, $20, $96, $a3, $a3, $a3, $a3, $1f .byte $92, $0D, $0D, $05, $00 - // Original Deft-supplied banner + // Original Mega65 banner - supplied by Deft // .byte $9A,$12,$A3,$A3,$A3,$A3,$A3,$A3,$DF,$9B,$92,$20,$05,$12,$A0,$A0 // .byte $DF,$9B,$92,$20,$05,$12,$A0,$A0,$DF,$9B,$92,$20,$05,$12,$A0,$A0 // .byte $DF,$9B,$92,$20,$05,$12,$A0,$A0,$DF,$9A,$92,$20,$05,$20,$20,$20 @@ -38,4 +100,4 @@ // .byte $12,$DF,$92,$7F,$9B,$20,$9A,$20,$9B,"0.2.0.0",$0D // .byte $0D,$05,$92,$00 -} +#endif diff --git a/c64/basic/print_integer.s b/c64/basic/print_integer.s index ff9938fd..47d58223 100644 --- a/c64/basic/print_integer.s +++ b/c64/basic/print_integer.s @@ -5,8 +5,7 @@ print_integer: pha - txa - pha + phx_trash_a // Clear temporary output lda #$00 diff --git a/c64/basic/print_packed_message.s b/c64/basic/print_packed_message.s index 7012645b..efed0e6a 100644 --- a/c64/basic/print_packed_message.s +++ b/c64/basic/print_packed_message.s @@ -32,15 +32,13 @@ packed_message_search: found_message_in_token_stream: // Now print each word in the message - tya - pha + phy_trash_a lda packed_message_tokens,y cmp #$ff beq !+ jsr print_packed_word jsr print_space - pla - tay + ply_trash_a iny bne found_message_in_token_stream !: @@ -139,16 +137,14 @@ next_packed_word_char: tax // Save Y so it doesn't get clobbered by CHROUT - tya - pha + phy_trash_a // X=1-14 = first 14 chars, so subtract one lda packed_message_chars-1,x jsr JCHROUT // See if there is a char in the low nybl to print - pla - tay + ply_trash_a lda (FRESPC),y and #$0f beq end_of_packed_word @@ -158,8 +154,7 @@ next_packed_word_char: has_lo_nybl_char: // We need to print the low nybl char as well tax - tya - pha + phy_trash_a // Skip lower nybls of $F or $0 in nybl packed // bytes, as these do not encode characters @@ -173,8 +168,7 @@ has_nybl: lda packed_message_chars-1,x jsr JCHROUT !: - pla - tay + ply_trash_a // FALLTHROUGH no_lo_nybl_char: @@ -204,8 +198,7 @@ next_is_literal_char: unpack_literal_char: // Output the literal char, and ready for next char iny - tya - pha + phy_trash_a lda (FRESPC),y jsr JCHROUT pla @@ -222,7 +215,6 @@ is_uncommon_char: // We need to print the low nybl char as well tax - tya - pha + phy_trash_a jmp has_nybl diff --git a/c64/basic/a004.identifier.s b/c64/basic/rom_revision/a004.identifier.s similarity index 100% rename from c64/basic/a004.identifier.s rename to c64/basic/rom_revision/a004.identifier.s diff --git a/c64/basic/a483.interop b/c64/basic/rom_revision/a483.interop similarity index 100% rename from c64/basic/a483.interop rename to c64/basic/rom_revision/a483.interop diff --git a/c64/basic/rom_revision/bf52.interop b/c64/basic/rom_revision/bf52.interop new file mode 100644 index 00000000..b2a62a7b --- /dev/null +++ b/c64/basic/rom_revision/bf52.interop @@ -0,0 +1,2 @@ + +Special case - we need a constant memory location where we can put an ID and a revision string. According to Compute's Mapping the Commodore 64 (page 117) this area is unused - so a perfect place. diff --git a/c64/basic/rom_revision/bf52.rom_revision_basic.s b/c64/basic/rom_revision/bf52.rom_revision_basic.s new file mode 100644 index 00000000..30c9e65d --- /dev/null +++ b/c64/basic/rom_revision/bf52.rom_revision_basic.s @@ -0,0 +1,27 @@ + +// +// !!! PROPOSAL ONLY !!! PROPOSAL ONLY !!! NOT FOR USING EXTERNALLY YET !!! +// +// +// Do not change! Locations of the following data should be constant - now and forever! +// +// If you want to integrate Open ROMs support in your emulator, FPGA ccomputer, etc. - this +// is the official way to recognize the ROM and it's revision. +// + + +rom_revision_basic: + + // $BF52 + + .text "OR" // project signature, after "Open ROMs" + .byte CONFIG_ID // config file ID, might change between revisions + +rom_revision_basic_string: + + // $BF55 + + .text "(DEVEL SNAPSHOT)" // actual ROM revision string; up to 16 characters + .byte $00 // marks the end of string + +__rom_revision_basic_end: diff --git a/c64/basic/rom_revision/e4b7.interop b/c64/basic/rom_revision/e4b7.interop new file mode 100644 index 00000000..ed2951af --- /dev/null +++ b/c64/basic/rom_revision/e4b7.interop @@ -0,0 +1,2 @@ + +Special case - we need a constant memory location where we can put an ID and a revision string. According to Compute's Mapping the Commodore 64 (page 213) this area is unused - so a perfect place. diff --git a/c64/basic/rom_revision/e4b7.rom_revision_kernal.s b/c64/basic/rom_revision/e4b7.rom_revision_kernal.s new file mode 100644 index 00000000..996baeec --- /dev/null +++ b/c64/basic/rom_revision/e4b7.rom_revision_kernal.s @@ -0,0 +1,41 @@ + +// +// !!! PROPOSAL ONLY !!! PROPOSAL ONLY !!! NOT FOR USING EXTERNALLY YET !!! +// +// +// Do not change! Locations of the following data should be constant - now and forever! +// +// If you want to integrate Open ROMs support in your emulator, FPGA ccomputer, etc. - this +// is the official way to recognize the ROM and it's revision. +// + + + // $E4B7 + + // This vector is to be used by non-Kernal ROMs, if they want to + // complain about incompatible ROM releases - don't use it directly, + // use a 'panic' pseudocommand with error code (will be passed using .A) + // #P_ERR_ROM_MISMATCH - it should remain stable even between releases + +#if CONFIG_PANIC_SCREEN + .word panic +#else + .word hw_entry_reset +#endif + + +rom_revision_kernal: + + // $E4B9 + + .text "OR" // project signature, after "Open ROMs" + .byte CONFIG_ID // config file ID, might change between revisions + +rom_revision_kernal_string: + + // $E4BC + + .text "(DEVEL SNAPSHOT)" // actual ROM revision string; up to 16 characters + .byte $00 // marks the end of string + +__rom_revision_kernal_end: diff --git a/c64/basic/startup_banner.s b/c64/basic/startup_banner.s deleted file mode 100644 index 957ab11d..00000000 --- a/c64/basic/startup_banner.s +++ /dev/null @@ -1,7 +0,0 @@ - -// -// Startup banner, to be displayed durin cold start -// - -startup_banner: - TARGET_HOOK_BANNER() diff --git a/c64/basic/wedge_dos.s b/c64/basic/wedge_dos.s index 47322a6a..39e55ce9 100644 --- a/c64/basic/wedge_dos.s +++ b/c64/basic/wedge_dos.s @@ -1,8 +1,15 @@ #if CONFIG_DOS_WEDGE +// .X has to contain size of the buffer + wedge_dos: + // Prepare buffer - finish it with '0' + + lda #$00 + sta BUF,x + // Close all the channels, so that wedge has full control jsr JCLALL @@ -12,6 +19,16 @@ wedge_dos: ldy #$0F jsr JSETFLS + // Setup necessary parts of BASIC + + lda #<(BUF+1) + sta TXTPTR+0 + lda #>(BUF+1) + sta TXTPTR+1 + + lda #$FF + sta CURLIN+1 + // Now we have to check what the user wants us to do // Check if user asked for a status @@ -210,13 +227,12 @@ wedge_dos_clean_exit: jsr JCLALL // Print new line jsr print_return - jmp basic_end_of_line + jmp basic_main_loop wedge_dos_basic_error: pha jsr JCLALL - pla - tax + plx_trash_a dex jmp do_basic_error diff --git a/c64/kernal/,target_ultimate64/,aliases_ultimate64.s b/c64/kernal/,disabled/,aliases_ultimate64.s similarity index 100% rename from c64/kernal/,target_ultimate64/,aliases_ultimate64.s rename to c64/kernal/,disabled/,aliases_ultimate64.s diff --git a/c64/kernal/,target_ultimate64/u64_load.s.disabled b/c64/kernal/,disabled/u64_load.s similarity index 100% rename from c64/kernal/,target_ultimate64/u64_load.s.disabled rename to c64/kernal/,disabled/u64_load.s diff --git a/c64/kernal/,target_generic/,hooks_generic.s b/c64/kernal/,target_generic/,hooks_generic.s deleted file mode 100644 index 84c261a2..00000000 --- a/c64/kernal/,target_generic/,hooks_generic.s +++ /dev/null @@ -1,6 +0,0 @@ - -// Target-specific hooks - - -.macro TARGET_HOOK_LOAD() { -} diff --git a/c64/kernal/,target_mega65/,hooks_mega65.s b/c64/kernal/,target_mega65/,hooks_mega65.s deleted file mode 100644 index 84c261a2..00000000 --- a/c64/kernal/,target_mega65/,hooks_mega65.s +++ /dev/null @@ -1,6 +0,0 @@ - -// Target-specific hooks - - -.macro TARGET_HOOK_LOAD() { -} diff --git a/c64/kernal/,target_ultimate64/,hooks_ultimate64.s b/c64/kernal/,target_ultimate64/,hooks_ultimate64.s deleted file mode 100644 index efc1f52f..00000000 --- a/c64/kernal/,target_ultimate64/,hooks_ultimate64.s +++ /dev/null @@ -1,9 +0,0 @@ - -// Target-specific hooks - - -.macro TARGET_HOOK_LOAD() { - // XXX disabled for now - the current file opening API is not - // really suitable for easy usage from Kernal - // jsr u64_load -} diff --git a/c64/kernal/assets/kernal_messages.s b/c64/kernal/assets/kernal_messages.s index b87bce48..0e8b6abe 100644 --- a/c64/kernal/assets/kernal_messages.s +++ b/c64/kernal/assets/kernal_messages.s @@ -5,40 +5,74 @@ // Double underscore prevents labels from being passed to VICE (would confuse monitor) -.label __MSG_KERNAL_SEARCHING_FOR = __kernal_message_searching_for - __kernal_messages_start -.label __MSG_KERNAL_LOADING = __kernal_message_loading - __kernal_messages_start -.label __MSG_KERNAL_VERIFYING = __kernal_message_verifying - __kernal_messages_start -.label __MSG_KERNAL_SAVING = __kernal_message_saving - __kernal_messages_start -.label __MSG_KERNAL_FROM_HEX = __kernal_message_from_hex - __kernal_messages_start -.label __MSG_KERNAL_TO_HEX = __kernal_message_to_hex - __kernal_messages_start +.label __MSG_KERNAL_SEARCHING_FOR = __msg_kernalsearching_for - __msg_kernal_first +.label __MSG_KERNAL_LOADING = __msg_kernalloading - __msg_kernal_first +.label __MSG_KERNAL_VERIFYING = __msg_kernalverifying - __msg_kernal_first +.label __MSG_KERNAL_SAVING = __msg_kernalsaving - __msg_kernal_first +.label __MSG_KERNAL_FROM_HEX = __msg_kernalfrom_hex - __msg_kernal_first +.label __MSG_KERNAL_TO_HEX = __msg_kernalto_hex - __msg_kernal_first + +#if CONFIG_SHOW_PAL_NTSC +.label __MSG_KERNAL_PAL = __msg_kernalpal - __msg_kernal_first +.label __MSG_KERNAL_NTSC = __msg_kernalntsc - __msg_kernal_first +#endif + +#if CONFIG_PANIC_SCREEN +.label __MSG_KERNAL_PANIC = __msg_kernalpanic - __msg_kernal_first +.label __MSG_KERNAL_PANIC_ROM_MISMATCH = __msg_kernalpanic_rom_mismatch - __msg_kernal_first +#endif -__kernal_messages_start: +__msg_kernal_first: -__kernal_message_searching_for: +__msg_kernalsearching_for: .byte $0D .text "SEARCHING FOR" .byte $80 + $20 // end of string mark + space -__kernal_message_loading: +__msg_kernalloading: .byte $0D .text "LOADIN" .byte $80 + $47 // end of string mark + 'G' -__kernal_message_verifying: +__msg_kernalverifying: .byte $0D .text "VERIFYIN" .byte $80 + $47 // end of string mark + 'G' -__kernal_message_saving: +__msg_kernalsaving: .byte $0D .text "SAVIN" .byte $80 + $47 // end of string mark + 'G' -__kernal_message_from_hex: +__msg_kernalfrom_hex: .text " FROM " .byte $80 + $24 // end of string mark + '$' -__kernal_message_to_hex: +__msg_kernalto_hex: .text " TO " .byte $80 + $24 // end of string mark + '$' + +#if CONFIG_SHOW_PAL_NTSC + +__msg_kernalpal: + .text "PAL," + .byte $80 + $20 // end of string mark + space + +__msg_kernalntsc: + .text "NTSC," + .byte $80 + $20 // end of string mark + space + +#endif // CONFIG_SHOW_PAL_NTSC + +#if CONFIG_PANIC_SCREEN + +__msg_kernalpanic: + .text "KERNAL PANI" + .byte $80 + $43 // end of string mark + 'C' + +__msg_kernalpanic_rom_mismatch: + .text " - ROM MISMATC" + .byte $80 + $48 // end of string mark + 'H' + +#endif // CONFIG_PANIC_SCREEN diff --git a/c64/kernal/assets/keyboard_matrix.s b/c64/kernal/assets/keyboard_matrix.s deleted file mode 100644 index e4c58270..00000000 --- a/c64/kernal/assets/keyboard_matrix.s +++ /dev/null @@ -1,72 +0,0 @@ -// Key board matrixes: unshifted, shifted, control and C= modified -// 64 bytes for each - - -keyboard_matrixes: - // Unshifted matrix built by refering to - // Compute's Mapping the 64 p38-39 - // and C64 PRG pages 379-381 - .byte $14,$0D,$1D,$88,$85,$86,$87,17 - .byte $33,87,$41,$34,$5A,83,$45,$00 - .byte $35,$52,$44,$36,$43,$46,$54,88 - .byte $37,$59,$47,$38,$42,$48,$55,$56 - .byte $39,$49,$4A,$30,$4D,$4B,$4F,$4E - .byte $2B,$50,$4C,45,46,58,$40,44 - .byte $5C,$2A,59,$13,$00,$3D,$5E,$2F - .byte $31,$5F,$00,$32,$20,$00,$51,$03 - - // Shifted keyboard - // Values computed by running a program like: - // 10 GETA$:IFA$=""GOTO10 - // 20 ?ASC(A$):GOTO10 - // and converting the values - .byte $94,$8D,$9D,$8C,$89,$8A,$8B,$91 - .byte $23,$77,$61,$24,$7A,$73,$65,$00 - .byte $25,$72,$64,$26,$63,$66,$74,$78 - .byte $27,$79,$67,$28,$62,$68,$75,$76 - .byte $29,$69,$6A,$92,$6D,$6B,$6F,$6E - .byte $DB,$70,$6C,$DD,$3E,$5B,$BA,$3C - .byte $A9,$C0,$5D,$93,$00,$3D,$DE,$3F - .byte $21,$5F,$00,$22,$A0,$00,$71,$83 - - // Vendor key modified keyboard - .byte $94,$8D,$9D,$8C,$89,$8A,$8B,$91 - .byte $96,$B3,$B0,$97,$AD,$AE,$B1,$00 - .byte $98,$B2,$AC,$99,$BC,$BB,$A3,$BD - .byte $9A,$B7,$A5,$9B,$BF,$B4,$B8,$BE - .byte $30,$A2,$B5,$30,$A7,$A1,$B9,$AA - .byte $A6,$AF,$B6,$DC,$3E,$5B,$A4,$3C - .byte $A8,$DF,$5D,$93,$00,$3D,$DE,$3F - .byte $81,$5F,$00,$95,$a0,$00,$AB,$83 - - // Control modified keyboard - .byte $00,$00,$00,$00,$00,$00,$00,$00 - .byte $1C,$17,$01,$9F,$1A,$13,$05,$00 - .byte $9C,$12,$04,$1E,$03,$06,$14,$18 - .byte $1F,$19,$07,$9E,$02,$08,$15,$16 - .byte $12,$09,$0A,$92,$0D,$0B,$0F,$0E - .byte $00,$10,$0C,$00,$00,$1B,$00,$00 - .byte $1C,$00,$1D,$00,$00,$1F,$1E,$00 - .byte $90,$06,$00,$05,$00,$00,$11,$00 - - -keyboard_matrix_lookup: - // Work out if normal, shifted, control or Vendor - // modified keyboard. - // Table contains the offsets into keyboard_matrixes - // that should be used for different values of - // the bottom 3 bits of key_bucky_state - // Interaction is simple to work out when playing - // with a C64: - // CONTROL trumps SHIFT or Vendor - // Vendor + SHIFT = DOES NOTHING - // All 3 does CONTROL - .byte $00 // Normal - .byte $40 // Shifted - .byte $80 // Control - .byte $80 // Control + SHIFT - .byte $C0 // Vendor - .byte $C0 // Vendor + SHIFT - .byte $80 // Vendor+ CTRL - .byte $80 // Vendor + CTRL + SHIFT - diff --git a/c64/kernal/blink_cursor.s b/c64/kernal/blink_cursor.s deleted file mode 100644 index 5d3c5446..00000000 --- a/c64/kernal/blink_cursor.s +++ /dev/null @@ -1,96 +0,0 @@ -// We have the following variables: -// BLNSW (cursor blink switch) -// BLNCT (cursor blink countdown) -// GDBLN (cursor saved character) -// BLNON (if cursor is visible) -// GDCOL (colour under cursor) -// USER (current screen line colour pointer) -// PNT (current screen line pointer) -// PNTR (current screen x position) - -show_cursor_if_enabled: - lda BLNSW - beq !+ - rts -!: lda BLNON - beq show_cursor - rts - -show_cursor: - // Set cursor as though it had just finished the off phase, - // so that the call to blink_cursor paints it - lda #$00 - sta BLNCT - sta BLNON - jsr blink_cursor - // Then set the timeout to 1 frame, so that the cursor - // blinks under key repeat conditions, like on the original KERNAL - lda #$01 - sta BLNCT - rts - -blink_cursor: - // Is the cursor enabled? - lda BLNSW - bne no_blink_cursor - - // Do we need to redraw things? - dec BLNCT - bpl no_blink_cursor - - // Check if cursor was visible or not, and toggle - lda BLNON - bne undraw_cursor -draw_cursor: - jsr calculate_screen_line_pointer - - ldy PNTR - lda (PNT),y - sta GDBLN - eor #$80 - sta (PNT),y - // Also set cursor colour - lda (USER),y - sta GDCOL - lda COLOR - sta (USER),y - - lda #1 - sta BLNON - - jmp reset_blink_timer - -undraw_cursor: - jsr calculate_screen_line_pointer - - lda GDBLN - ldy PNTR - sta (PNT),y - lda GDCOL - sta (USER),y - - lda #0 - sta BLNON - // Fall through -reset_blink_timer: - // Rest blink counter - // (Compute's Mapping the 64, p39-40) - lda #20 - sta BLNCT -no_blink_cursor: - rts - -disable_cursor: - lda #$80 - sta BLNSW - // FALL THROUGH -hide_cursor_if_visible: - lda BLNON - bne undraw_cursor - rts - -enable_cursor: - lda #$00 - sta BLNSW - rts - diff --git a/c64/kernal/chkinout_real.s b/c64/kernal/chkinout_real.s index c52545e3..18bc6bc7 100644 --- a/c64/kernal/chkinout_real.s +++ b/c64/kernal/chkinout_real.s @@ -5,7 +5,7 @@ // - [RG64] C64 Programmer's Reference Guide - page 275 (CHKIN) / 276 (CKOUT) // - [CM64] Compute's Mapping the Commodore 64 - page 229 // -// CPU registers that has to be preserved (see [RG64]): .Y +// CPU registers that has to be preserved (see [RG64]): .Y, possibly .A (XXX - see [CM64], page 213) // @@ -14,8 +14,7 @@ chkin_real: // Store Y for preservation - tya - pha + phy_trash_a // Reset status jsr kernalstatus_reset @@ -59,6 +58,7 @@ chkin_set_device: // FALLTROUGH // Common part for booth CHKIN and CKOUT +// XXX add CPU-dependent optimizations here chkinout_end: tax diff --git a/c64/kernal/chrin_real.s b/c64/kernal/chrin_real.s index cbed585e..87b5ee8a 100644 --- a/c64/kernal/chrin_real.s +++ b/c64/kernal/chrin_real.s @@ -9,6 +9,7 @@ // // XXX keyboard part currently does not preserve register Y, to be fixed! +// XXX try to make chrin_real unnecessary (try to fit this into original location) // Reads a byte of input, unless from keyboard. // If from keyboard, then it gets a whole line of input, and returns the first char. @@ -43,8 +44,7 @@ chrin_done_fail: chrin_keyboard: // Save X - txa - pha + phx_trash_a chrin_repeat: @@ -64,8 +64,7 @@ chrin_repeat: // Return carriage return and clear pending input flag lda #$00 sta CRSW - pla - tax + plx_trash_a clc lda #$0d rts @@ -73,33 +72,31 @@ chrin_repeat: not_end_of_input: // Return next byte of waiting input and advance index tay - pla - tax + plx_trash_a lda (LXSP),y jsr screen_code_to_petscii inc CRSW clc rts - read_from_keyboard: - jsr enable_cursor - + jsr cursor_enable + // Wait for a key lda NDX beq chrin_repeat lda KEYD - cmp #$0d + cmp #$0D bne not_enter - jsr disable_cursor - + jsr cursor_disable + jsr pop_keyboard_buffer - jsr hide_cursor_if_visible - + jsr cursor_hide_if_visible + // It was enter. // Note that we have a line of input to return, and return the first byte thereof // after computing and storing its length. @@ -112,7 +109,7 @@ read_from_keyboard: sta LXSP+1 // Calculate length - jsr get_current_line_logical_length + jsr screen_get_current_line_logical_length tay iny !: dey @@ -126,8 +123,7 @@ read_from_keyboard: sta CRSW // Return first char of line ldy #$00 - pla - tax + plx_trash_a lda (LXSP),y jsr screen_code_to_petscii clc @@ -137,74 +133,19 @@ empty_line: // For an empty line, just return the carriage return // (and don't forget to actually print the carriage return, so that // the cursor advances and screen scrolls as required) - pla - tax + plx_trash_a clc lda #$0d rts not_enter: + // Print character lda KEYD + // XXX add support for SHIFT + RUN/STOP ($84) and function keys (should be configurable) jsr CHROUT jsr pop_keyboard_buffer // Keep looking for input from keyboard until carriage return jmp chrin_repeat - -pop_keyboard_buffer: - // Pop key out of keyboard buffer - // Disable interrupts while reading from keyboard buffer - // so that no race conditions can occur - sei - ldx #$00 - ldy #$01 -!: lda KEYD,y - sta KEYD,x - inx - iny - cpy XMAX - bne !- - dec NDX - cli - - rts - -screen_code_to_petscii: - cmp #$1b - bcs not_alpha - - clc - adc #$40 - rts - -not_alpha: - cmp #$40 - bcs not_punctuation - - rts - -not_punctuation: - cmp #$5b - bcs not_shifted - - clc - adc #$80 - - rts - -not_shifted: - - cmp #$80 - bcs not_vendor - - // $60-$7F -> $A0-$BF - - clc - adc #$40 - - // FALLTROUGH -not_vendor: - rts - diff --git a/c64/kernal/chrout_real.s b/c64/kernal/chrout_real.s deleted file mode 100644 index 578383c0..00000000 --- a/c64/kernal/chrout_real.s +++ /dev/null @@ -1,889 +0,0 @@ - -// -// Official Kernal routine, described in: -// -// - [RG64] C64 Programmer's Reference Guide - page 278/279 -// - [CM64] Compute's Mapping the Commodore 64 - page 228 -// -// CPU registers that has to be preserved (see [RG64]): .Y -// - - -chrout_real: - - sta SCHAR - - // Save X and Y values - // (Confirmed by writing a test program that X and Y - // don't get modified, in agreement with C64 PRG's - // description of CHROUT) - txa - pha - tya - pha - php - - // Determine the device number - lda DFLTO - - cmp #$03 // screen - beq chrout_screen - - jsr iec_check_devnum - bcs chrout_done_unknown_device // not a supported device - -chrout_iec: - - lda SCHAR - jsr JCIOUT - bcc chrout_done - - // FALLTROUGH - -chrout_done_fail: - jsr show_cursor_if_enabled - - plp - - // Restore X and Y - pla - tay - pla - tax - sec // indicate failure - rts - -chrout_done_unknown_device: - jsr show_cursor_if_enabled - - plp - - // Restore X and Y - pla - tay - pla - tax - - // End wioth error - jmp lvs_device_not_found_error - -chrout_done: - jsr show_cursor_if_enabled - - plp - - // Restore X and Y - pla - tay - pla - tax - lda SCHAR - clc // indicate success - rts - -chrout_screen: - - // Crude implementation of character output - sei // XXX why do we need to disable interrupts? - - jsr hide_cursor_if_visible - - lda SCHAR - tax - - // Check for special characters - - cmp #$00 - bne not_00 - jmp chrout_done -not_00: - - // Linefeed (simply ignored) - // Trivia: BASIC does CRLF with READY. prompt - cmp #$0a - bne not_0a - jmp chrout_done -not_0a: - - // Carriage return - cmp #$0d - bne not_0d - // RETURN clears quote and insert modes - lda #$00 - sta QTSW - sta INSRT - jmp screen_advance_to_next_line -not_0d: - - cmp #$94 - bne not_94 - - // Insert (shift-DELETE) - - // Abort if line already max length, ie 79th char is not a space - jsr get_current_line_logical_length - cmp #79 - bne definitely_not_too_long - tay - lda (PNT),y - cmp #$20 - beq definitely_not_too_long - - // Line is too long to extend - jmp chrout_done - -definitely_not_too_long: - // Work out if line needs to be expanded, and if so expand it - ldy #39 - lda (PNT),y - cmp #$20 - beq no_need_to_extend - - jsr screen_grow_logical_line - -no_need_to_extend: - // Shuffle chars towards end of line - jsr get_current_line_logical_length - tay -!: - // Note: While the following routine is obvious to any skilled - // in the art as the most obvious simple and efficient solution, - // if the screen writes are before the colour writes, it results - // in a relatively long verbatim stretch of bytes when compared to - // the C64 KERNAL. Thus we have swapped the order, just to reduce - // the potential for any argument of copyright infringement, even - // though we really don't believe that the routine can be copyrighted - // due to the lack of creativity. - dey - lda (USER),y - iny - sta (USER),y - dey - lda (PNT),y - iny - sta (PNT),y - - dey - cpy PNTR - bne !- - - // Increase insert mode count (which causes quote-mode like behaviour) - inc INSRT - - // Put space in the inserted gap - lda #$20 - sta (PNT),y - - jmp chrout_done -not_94: - - // DELETE in insert mode embeds control character - ldx INSRT - bne not_14 - - cmp #$14 - bne not_14 - - // Delete - ldx PNTR - bne delete_non_zero_column -delete_at_column_0: - ldy TBLX - bne not_row_0 - // delete from row 0, col 0 does nothing - jmp chrout_done -not_row_0: - // Column 0 delete just moves us to the end of the - // previous line, without actually deleting anything - dec TBLX - jsr get_current_line_logical_length - lda LNMX - - sta PNTR - jsr calculate_screen_line_pointer - jmp chrout_done - -delete_non_zero_column: - // Copy rest of line down - jsr get_current_line_logical_length - ldy PNTR - cpy LNMX - beq done_delete - dey -!: - iny - lda (PNT),y - dey - sta (PNT),y - iny - lda (USER),y - dey - sta (USER),y - iny - cpy LNMX - bne !- - - // Clear char at end of line - jsr get_current_line_logical_length - tay - lda #$20 - sta (PNT),y - -done_delete: - dec PNTR - jmp chrout_done -not_14: - - // Check for quote mode - ldx QTSW - bne is_quote_mode - ldx INSRT - bne is_quote_mode - jmp not_quote_mode - -is_quote_mode: - // Is it a control code? - // control codes are $00-$1f and $80-$9f - // (from reading C64 PRG p379-381) - // so we can just check if bits 5 or 6 are set, and if so, - // then it isn't a control character. - pha - and #$60 - bne !+ - - // Yes, a control code in quote mode means we display it as a reverse character - pla - - // Low control codes are just +$80 - clc - adc #$80 - // If it overflowed, then it is a high control code, - // so we need to make it be $80 + $40 + char - // as we will have flipped back to just $00 + char, we should - // now add $c0 if C is set from overflow - bcc low_ctrl_char - adc #$bf // C=1, so adding $BF + C = add $C0 -low_ctrl_char: - jmp output_literal_char -!: - pla -not_quote_mode: - - // Check for colours - ldx #$f -colour_check_loop: - cmp colour_codes,x - bne !+ - stx COLOR - jmp chrout_done -!: dex - bpl colour_check_loop - - // Compute's Mapping the 64 p38 - cmp #$12 - bne not_12 - lda #$80 - sta RVS - jmp chrout_done -not_12: - // Compute's Mapping the 64 p 38 - cmp #$92 - bne not_92 - lda #$00 - sta RVS - jmp chrout_done -not_92: - - // Check for cursor movement keys - cmp #$11 - bne not_11 - lda PNTR - clc - adc #40 - sta PNTR - // We need to advance the pointer manually, as normalising - // now will break things. The pointer update is required - // so that we can tell if we really are on the bottom phys - // screen line or not - jsr scroll_up_if_on_last_line - jsr calculate_screen_line_pointer - jmp chrout_done -not_11: - cmp #$1d - bne not_1d - inc PNTR - jsr calculate_screen_line_pointer - jmp chrout_done -not_1d: - cmp #$91 - bne not_91 - lda PNTR - sec - sbc #40 - sta PNTR - jsr calculate_screen_line_pointer - jmp chrout_done -not_91: - cmp #$9d - bne not_9d - dec PNTR - jsr calculate_screen_line_pointer - jmp chrout_done -not_9d: - - // Home cursor - cmp #$13 - bne not_13 - lda #0 - sta PNTR - sta TBLX - jsr calculate_screen_line_pointer - jmp chrout_done -not_13: - - // Clear screen - cmp #$93 - bne not_clearscreen - jsr clear_screen - jmp chrout_done - -not_clearscreen: - - // Convert PETSCII to screen code - - // Don't print other control codes - cmp #$1f - bcs !+ - jmp chrout_done -!: - - // Codes $C0-$DF become $40-$5F - // But - cmp #$e0 - bcs !+ - cmp #$c0 - bcc !+ - - and #$7f - jmp output_literal_char // not high char - -!: - // Range $20-$3F is unchanged - cmp #$40 - bcc output_literal_char // not high char - - // Unshifted letters and symbols from $40-$5F - // all end up being -$40 - // (C64 PRG p376) - - // But anything >= $80 needs to be -$40 - // (C64 PRG p380-381) - // And bit 7 should be cleared, only to be - // set by reverse video - sec - sbc #$40 - - // Fix shifted chars by adding $20 again - cmp #$20 - bcc output_literal_char // not high char - cmp #$40 - bcs output_literal_char // not high char - clc - adc #$20 - -output_literal_char: - - // Write normal character on the screen - - pha - - ldy PNTR - ora RVS // Compute's Mapping the 64 p38 - sta (PNT),y - - // Decrement number of chars waiting to be inserted - lda INSRT - beq !+ - dec INSRT -!: - pla - cmp #$22 - bne not_quote - - // Toggle quote flag if required - lda QTSW - eor #$80 - sta QTSW - -not_quote: - - // Set colour - lda COLOR - sta (USER),y - - // Advance the column, and scroll screen down if we need - // to insert a 2nd line in this logical line. - // (eg Compute's Mapping the 64 p41) - ldx TBLX - iny - sty PNTR - cpy #40 - bne !+ - jsr screen_grow_logical_line - ldy PNTR -!: - cpy #80 - bcc no_screen_advance_to_next_line - lda #0 - sta PNTR - jmp screen_advance_to_next_line -no_screen_advance_to_next_line: - jmp chrout_done - -screen_grow_logical_line: - ldy TBLX - // Don't grow line if it is already grown - lda LDTBL,y - bpl !+ - jmp not_last_line // doneb grow line -!: - lda #$80 - sta LDTBL,y - - // Now make space for the extra line added. - // If we are on the last physical line of the screen, - // Then we need to scroll the screen up - jsr scroll_up_if_on_last_line - - // Scroll screen down to make space - // As we are scrolling down, we start from the end, - // and work backwards. We can't be as simple and efficient - // here as we are for scrolling up, because we don't know - // how much must be scrolled. - // Simple solution is to work out how many physical lines - // need shifting down, and then move lines at a time after - // initialising the pointers to the end area of the screen. - ldx #25-2 - ldy #0 -count_rows_loop: - dex - lda LDTBL,y - bpl !+ - dex -!: iny - cpy TBLX - bne count_rows_loop - - cpx #0 - beq no_copy_down - bmi no_copy_down - - // Set pointers to end of screen line, and one line - // above. (It is always one physical line, because - // this can only happen when expanding a line from 40 to - // 80 characters). - // XXX - This is not very efficient, and longer than it - // needs to be. Better would be to work out size to - // copy, and count it down in a pointer somewhere, so - // that loop iteration logic is simpler. - lda HIBASE - clc - adc #3 - sta PNT+1 - sta SAL+1 - lda #>$DBC0 - sta EAL+1 - sta USER+1 - - lda #<$03C0 - sta PNT+0 - sta USER+0 - // souce address is line above - sec - sbc #40 - sta SAL+0 - sta EAL+0 - -copy_line_down_loop: - ldy #39 -cl_inner: - lda (EAL),y - sta (USER),y - lda (SAL),y - sta (PNT),y - dey - bpl cl_inner - - // Decrement all pointers by 40 - // Low bytes are in common pairs - - // Old source is new destination - // Use different registers to minimise byte similarity with C64 KERNAl - ldy SAL+1 - sty PNT+1 - lda EAL+1 - ldy SAL+0 - sta USER+1 - sty PNT+0 - sty USER+0 - - // Decrementing source pointers - lda SAL+0 - sec - sbc #<40 - sta SAL+0 - sta EAL+0 - lda SAL+1 - sbc #>40 - sta SAL+1 - // convert to screen equivalent - sec - sbc HIBASE - clc - adc #>$D800 - sta EAL+1 - - dex - bne copy_line_down_loop - -no_copy_down: - jsr calculate_screen_line_pointer - - // Erase newly inserted line - ldy #79 -!: - lda COLOR - sta (USER),y - lda #$20 - sta (PNT),y - dey - cpy #40 - bne !- - - rts - -not_last_line: - rts - -scroll_up_if_on_last_line: - - // Colour RAM is always in fixed place, so is easiest - // to use to check if we are on the last line. - // The last line is at $D800 + 24*40 = $DBC0 - lda USER+1 - cmp #>$DBC0 - bne not_last_line - - lda USER+0 - cmp #<$DBC0 - beq is_last_line - - jsr get_current_line_logical_length - clc - adc USER+0 - cmp #<$DBE7-1 - bcc not_last_line - -is_last_line: - - dec TBLX - - // FALL THROUGH - -scroll_screen_up: - // Now scroll the whole screen up either one or two lines - // based on whether the first screen line is linked or not. - - // Get pointers to start of screen + colour RAM - lda HIBASE - sta PNT+1 - sta SAL+1 - lda #>$D800 - sta USER+1 - sta EAL+1 - lda #$00 - sta PNT+0 - sta USER+0 - - // Get pointers to screen/colour RAM source - lda LDTBL+0 - bmi !+ - lda #40 - .byte $2C // BIT $nnnn to skip next instruction -!: - lda #80 - sta SAL+0 - sta EAL+0 - - // Copy first three pages - ldy #$00 - ldx #3 -scroll_copy_loop: - lda (EAL),y - sta (USER),y - lda (SAL),y - sta (PNT),y - - iny - bne scroll_copy_loop - - inc SAL+1 - inc PNT+1 - inc EAL+1 - inc USER+1 - dex - bne scroll_copy_loop - - // Copy last partial page - // We need to copy 1000-(3*256)-line length - // = 232 - line length - lda SAL+0 - lda #232 - sec - sbc SAL+0 - tax -scroll_copy_loop2: - lda (EAL),y - sta (USER),y - lda (SAL),y - sta (PNT),y - iny - dex - bne scroll_copy_loop2 - - // Fill in scrolled up area - ldx SAL+0 -scroll_copy_loop3: - lda COLOR - sta (USER),y - lda #$20 - sta (PNT),y - iny - dex - bne scroll_copy_loop3 - - // Shift line linkage list - ldy #0 - ldx #24 -link_copy: - lda LDTBL+1,y - sta LDTBL+0,y - iny - dex - bne link_copy - // Clear line link flag of last line - stx LDTBL+24 - - // Restore correct line pointers - jsr calculate_screen_line_pointer - - rts - -get_current_line_logical_length: - ldy TBLX - lda LDTBL,y - bpl line_not_linked_del - lda #79 - .byte $2c // BIT absolute mode, which we use to skip the next two instruction bytes -line_not_linked_del: - lda #39 - sta LNMX - rts - -screen_advance_to_next_line: - - // jsr hide_cursor_if_visible - - // Go to start of line - lda #0 - sta PNTR - // Advance line number - ldy TBLX - - // Do quick fix to line pointer to work out if it is off - // the bottom of the screen. - ldx #40 - lda LDTBL,y - bmi !+ - .byte $2c -!: ldx #80 - txa - clc - adc PNT+0 - sta PNT+0 - lda PNT+1 - adc #0 - sta PNT+1 - - inc TBLX - - // Check if it will trigger scrolling - // Work out if we have gone off the bottom of the screen? - // 1040 > 1024, so if high byte of screen pointer is >= (HIBASE+4), - // then we are off the bottom of the screen - lda PNT+1 - sec - sbc HIBASE - cmp #3 - bcc !+ - lda PNT+0 - cmp #$e7 - bcc !+ - - // Off the bottom of the screen - jsr scroll_screen_up -!: - - jsr calculate_screen_line_pointer - - jmp chrout_done - -add_40_to_screen_x: - lda PNTR - clc - adc #40 - sta PNTR - rts - -normalise_screen_x_y: - // Normalise X and Y values - - // If X < 0, then make X = X + 40 (or 80, if previous line is linked) -!: lda PNTR - bpl x_not_negative - dec TBLX - // Check that we didn't go backwards off the top of the screen - bpl !+ - lda #0 - sta TBLX - -!: jsr add_40_to_screen_x - - // Check if line is linked, if so, add 40 again - ldy TBLX - lda LDTBL,y - bpl !+ - jsr add_40_to_screen_x -!: - -x_not_negative: - // Work out if X is too big - ldy TBLX - lda LDTBL,y - bpl !+ - lda #79 - .byte $2C // BIT $nnnn, used to skip next instruction -!: lda #39 - cmp PNTR - bcs x_not_too_big - - // X value is too big, so subtract 40 and increment Y - lda PNTR - sec - sbc #40 - sta PNTR - inc TBLX - -x_not_too_big: - - // Make sure Y isn't negative - lda TBLX - bpl !+ - lda #0 - sta TBLX -!: - // Make sure Y isn't too large for absolute size of - // screen - cmp #24 - bcc !+ - lda #24 - sta TBLX -!: - // Make sure Y isn't too much for the screen, taking - // into account the line link table - ldy #24 // max allowable line - ldx #0 -link_count_loop: - lda LDTBL,x - bpl !+ - dey -!: inx - cpx #25 - bne link_count_loop - tya - cmp TBLX - bcs y_ok - sta TBLX -y_ok: - rts - -calculate_screen_line_pointer: - jsr normalise_screen_x_y - - // Reset pointer to start of screen - lda HIBASE - sta PNT+1 - lda #0 - sta PNT+0 - - // Add 40 for every line, or 80 if the lines are linked - ldx TBLX - -!: - // Stop if we have counted enough lines - beq !+ - - // Add 40 or 80 based on whether the line is linked - // or not. - ldy #40 - // -1 offset is because we count down from N to 1, not - // N-1 to 0. - lda LDTBL-1,x - bpl cslp_l1 - ldy #80 -cslp_l1: - // Add computed line length to pointer value - tya - clc - adc PNT+0 - sta PNT+0 - lda PNT+1 - adc #0 - sta PNT+1 - - // Loop back to next line - dex - jmp !- -!: - - // FALL THROUGH - -update_colour_line_pointer: - // Now setup pointer to colour RAM - lda PNT+0 - sta USER+0 - lda PNT+1 - sec - sbc HIBASE - clc - adc #>$d800 - sta USER+1 - - rts - -advance_screen_pointer_40_bytes: - lda PNT+0 - clc - adc #<40 - sta PNT+0 - sta USER+0 - lda PNT+1 - adc #>40 - sta PNT+1 - sec - sbc HIBASE - clc - adc #>$D800 - sta USER+1 - - jmp update_colour_line_pointer diff --git a/c64/kernal/cint_real.s b/c64/kernal/cint_real.s deleted file mode 100644 index 1daf056c..00000000 --- a/c64/kernal/cint_real.s +++ /dev/null @@ -1,105 +0,0 @@ - -// -// Official Kernal routine, described in: -// -// - [RG64] C64 Programmer's Reference Guide - page 280 -// - [CM64] Compute's Mapping the Commodore 64 - page 242 -// -// CPU registers that has to be preserved (see [RG64]): none -// - - -cint_real: - - // According to [CM64], this routine checks for PAL/NTSC. It's definitely not done - // within the 'BRK' part, this can be easily checked - POKE something - // to address 678 on a real C64, press STOP+RESTORE, the value won't change - - // Detect video system (PAL/NTSC), use Graham's method, as it's short and reliable - // see here: https://codebase64.org/doku.php?id=base:detect_pal_ntsc - - lda #$C8 // preparation, as the VIC might be uninitialized - sta VIC_SCROLX - -cint_w0: - lda VIC_RASTER -cint_w1: - cmp VIC_RASTER - beq cint_w1 - bmi cint_w0 - - // Result in A, if no interrupt happened during the test: - // #$37 -> 312 rasterlines, PAL, VIC 6569 - // #$06 -> 263 rasterlines, NTSC, VIC 6567R8 - // #$05 -> 262 rasterlines, NTSC, VIC 6567R56A - - cmp #$07 - bcs cint_pal - -cint_ntsc: - - // NTSC C64 (https://codebase64.org/doku.php?id=base:cpu_clocking), - // is clocked at 1.022727 MHz, so that 1/60s is 17045 CPU cycles - - ldy #<17045 - ldx #>17045 - - sty CIA1_TIMALO - stx CIA1_TIMAHI - - lda #$00 - beq !+ - -cint_pal: - - lda #$01 -!: - sta TVSFLG - - // Setup KEYLOG vector - XXX is it proper place? - - lda #setup_keydecode - sta KEYLOG+1 - -cint_brk: // entry for BRK and STOP+RESTORE - XXX, where should it start? - - jsr setup_vicii - - // Initialise cursor blink flags (Compute's Mapping the 64 p215) - lda #$00 - sta BLNSW - - // Set keyboard decode vector (Compute's Mapping the 64 p215) - - // Set initial variables for our improved keyboard scan routine - lda #$FF - ldx #6 -!: sta BufferOld,x - dex - bpl !- - sta BufferQuantity - - // Set key repeat delay (Compute's Mapping the 64 p215) - // Making some numbers up here: Repeat every ~1/10th sec - // But require key to be held for ~1/3sec before - // repeating (Compute's Mapping the 64 p58) - ldx #22-2 // Fudge factor to match speed - stx DELAY - - // Set current colour for text (Compute's Mapping the 64 p215) - ldx #$01 // default is light blue ($0E), but we use a different one - stx COLOR - - // Set maximum keyboard buffer size (Compute's Mapping the 64 p215) - ldx #10 - stx XMAX - // Put non-zero value in MODE to enable case switch - stx MODE - - // Set default I/O devices (see SCINIT description at http://sta.c64.org/cbm64krnfunc.html) - jsr clrchn_reset - - // Fallthrough/jump to screen clear routine (Compute's Mapping the 64 p215) - jmp clear_screen diff --git a/c64/kernal/clrchn_real.s b/c64/kernal/clrchn_real.s index b12177af..6c97cc4d 100644 --- a/c64/kernal/clrchn_real.s +++ b/c64/kernal/clrchn_real.s @@ -25,7 +25,7 @@ clrchn_real: // Handle IEC output device jsr UNLSN !: -clrchn_reset: // entry needed by CHRIN +clrchn_reset: // entry needed by setup_vicii // Set input device number to keyboard lda #$00 sta DFLTN diff --git a/c64/kernal/e5a0.setup_vicii.s b/c64/kernal/e5a0.setup_vicii.s deleted file mode 100644 index 7345dbc4..00000000 --- a/c64/kernal/e5a0.setup_vicii.s +++ /dev/null @@ -1,22 +0,0 @@ - -setup_vicii: - - // XXX there is more to setup within this routine - - // Set up default IO values (Compute's Mapping the 64 p215) - lda #$1B // Enable text mode - sta VIC_SCROLY - lda #$C8 // 40 column etc - sta VIC_SCROLX - - // Compute's Mapping the 64, p156 - // We use a different colour scheme of white text on all blue - lda #$06 - sta VIC_EXTCOL - sta VIC_BGCOL0 - - // Turn off sprites (observed hanging around after running programs and resetting) - lda #$00 - sta VIC_SPENA - - rts diff --git a/c64/kernal/f13e.getin.s b/c64/kernal/f13e.getin.s index 5eefc0ac..be8e3faa 100644 --- a/c64/kernal/f13e.getin.s +++ b/c64/kernal/f13e.getin.s @@ -8,26 +8,9 @@ // CPU registers that has to be preserved (see [RG64]): .X, .Y // -// XXX currently does not preserve registers, to be fixed! GETIN: - // Wait for a key - lda NDX - bne !+ + // XXX this should be a dispatcher for several different devices! - // Nothing in keyboard buffer to read - sec - lda #$00 - rts - -!: - lda KEYD - pha - - jsr pop_keyboard_buffer - - pla - clc - - rts + jmp read_kb_buf diff --git a/c64/kernal/f1ca.chrout.jmp.s b/c64/kernal/f1ca.chrout.jmp.s deleted file mode 100644 index 6a1993c3..00000000 --- a/c64/kernal/f1ca.chrout.jmp.s +++ /dev/null @@ -1,6 +0,0 @@ - -// Our implementation is longer than the original one, -// placing it here would cause a collision with CHKIN - -CHROUT: - jmp chrout_real diff --git a/c64/kernal/f1ca.chrout.s b/c64/kernal/f1ca.chrout.s new file mode 100644 index 00000000..6e51ea2b --- /dev/null +++ b/c64/kernal/f1ca.chrout.s @@ -0,0 +1,75 @@ + +// +// Official Kernal routine, described in: +// +// - [RG64] C64 Programmer's Reference Guide - page 278/279 +// - [CM64] Compute's Mapping the Commodore 64 - page 228 +// +// CPU registers that has to be preserved (see [RG64]): .Y +// + +CHROUT: + + sta SCHAR + + // Save X and Y values + // (Confirmed by writing a test program that X and Y + // don't get modified, in agreement with C64 PRG's + // description of CHROUT) + + phx_trash_a + phy_trash_a + + php + + // Determine the device number + lda DFLTO + + cmp #$03 // screen + bne !+ + jmp chrout_screen +!: + jsr iec_check_devnum + bcs chrout_done_unknown_device // not a supported device + +chrout_iec: + + lda SCHAR + jsr JCIOUT + bcc chrout_done_success + + // FALLTROUGH + +chrout_done_fail: + + plp + + // Restore X and Y + ply_trash_a + plx_trash_a + + sec // indicate failure + rts + +chrout_done_unknown_device: + + plp + + // Restore X and Y + ply_trash_a + plx_trash_a + + // End wioth error + jmp lvs_device_not_found_error + +chrout_done_success: + + plp + + // Restore X and Y + ply_trash_a + plx_trash_a + + lda SCHAR + clc // indicate success + rts diff --git a/c64/kernal/f4a5.load.s b/c64/kernal/f4a5.load.s index e1cccc1d..76307dc6 100644 --- a/c64/kernal/f4a5.load.s +++ b/c64/kernal/f4a5.load.s @@ -36,9 +36,6 @@ LOAD: jsr install_ram_routines #endif - // Allow platform-specific routine to takeover the flow - TARGET_HOOK_LOAD() - // Check whether we support the requested device lda FA and #$FC diff --git a/c64/kernal/fe25.interop b/c64/kernal/fe25.interop new file mode 100644 index 00000000..828e597b --- /dev/null +++ b/c64/kernal/fe25.interop @@ -0,0 +1,3 @@ + +Address adjusted to support $FE2D - routine which is probably used by many cartridges and other software to initialize parts of the system. At least the UCart uses it - see here: +- https://www.elektroda.pl/rtvforum/topic3293027.html \ No newline at end of file diff --git a/c64/kernal/memtop.s b/c64/kernal/fe25.memtop.s similarity index 79% rename from c64/kernal/memtop.s rename to c64/kernal/fe25.memtop.s index dd50497a..960152b0 100644 --- a/c64/kernal/memtop.s +++ b/c64/kernal/fe25.memtop.s @@ -14,9 +14,10 @@ MEMTOP: ldy MEMSIZK+1 ldx MEMSIZK+0 - rts -memtop_set: + // FALLTROUGH + +memtop_set: // for compatibility reasons this has to start at $FE2D sty MEMSIZK+1 stx MEMSIZK+0 diff --git a/c64/kernal/ff5b.cint.jmp.s b/c64/kernal/ff5b.cint.jmp.s deleted file mode 100644 index d692928f..00000000 --- a/c64/kernal/ff5b.cint.jmp.s +++ /dev/null @@ -1,6 +0,0 @@ - -// Our implementation is longer than the original one, -// placing it here would cause a collision with OPEN - -CINT: - jmp cint_real diff --git a/c64/kernal/home_cursor.s b/c64/kernal/home_cursor.s deleted file mode 100644 index 37965f96..00000000 --- a/c64/kernal/home_cursor.s +++ /dev/null @@ -1,10 +0,0 @@ -// Home the cursor -// (Compute's Mapping the 64 p216) - -home_cursor: - - lda #$00 - sta PNTR // x position - sta TBLX // y position - - jmp set_pointer_to_current_screen_line diff --git a/c64/kernal/acptr.s b/c64/kernal/iec/acptr.s similarity index 100% rename from c64/kernal/acptr.s rename to c64/kernal/iec/acptr.s diff --git a/c64/kernal/iec/iec_return.s b/c64/kernal/iec/iec_return.s index 149f781f..de3f8b01 100644 --- a/c64/kernal/iec/iec_return.s +++ b/c64/kernal/iec/iec_return.s @@ -14,10 +14,8 @@ iec_return_success: lda #$00 sta C3PO // Restore registers - pla - tay - pla - tax + ply_trash_a + plx_trash_a // Report success clc rts @@ -30,9 +28,7 @@ iec_return_DEVICE_NOT_FOUND: lda #$00 sta C3PO // Restore registers - pla - tay - pla - tax + ply_trash_a + plx_trash_a // Report error jmp kernalerror_DEVICE_NOT_FOUND diff --git a/c64/kernal/iec/iec_rx_byte.s b/c64/kernal/iec/iec_rx_byte.s index bb9328ef..2f859cf7 100644 --- a/c64/kernal/iec/iec_rx_byte.s +++ b/c64/kernal/iec/iec_rx_byte.s @@ -7,13 +7,13 @@ iec_rx_byte: // Store .X and .Y on the stack - preserve them - txa - pha - tya - pha + phx_trash_a + phy_trash_a // Timing is critical here - execute on disabled IRQs - php + // The best practice would be to do PHP first, but it seems this is not + // what the original ROM does; furthermore, pushing additional bytes to + // stack can wreck autostart softwaree loading at $0100 sei // First, we wait for the talker to release the CLK line @@ -107,8 +107,7 @@ iec_rx_clk_wait2: // Timeout jsr kernalstatus_EOI pla - plp - + // Restore registers pla tay @@ -116,6 +115,7 @@ iec_rx_clk_wait2: tax sec // XXX confirm that sec is really a way to report timeout here + cli rts !: // More bits? @@ -130,9 +130,6 @@ iec_rx_clk_wait2: // Retreive the received byte pla - - // Return no-error - plp // Restore registers sta TBTCNT // $A4 is a byte buffer according to http://sta.c64.org/cbm64mem.html @@ -143,5 +140,6 @@ iec_rx_clk_wait2: lda TBTCNT clc + cli rts diff --git a/c64/kernal/iec/iec_turnaround_to_listen.s b/c64/kernal/iec/iec_turnaround_to_listen.s index fb4cd078..be31bf02 100644 --- a/c64/kernal/iec/iec_turnaround_to_listen.s +++ b/c64/kernal/iec/iec_turnaround_to_listen.s @@ -5,10 +5,8 @@ iec_turnaround_to_listen: // Store .X and .Y on the stack - preserve them - txa - pha - tya - pha + phx_trash_a + phy_trash_a // Timing is critical here - execute on disabled IRQs php diff --git a/c64/kernal/iec/iec_turnaround_to_talk.s b/c64/kernal/iec/iec_turnaround_to_talk.s index f7ea9c9b..3612460c 100644 --- a/c64/kernal/iec/iec_turnaround_to_talk.s +++ b/c64/kernal/iec/iec_turnaround_to_talk.s @@ -5,10 +5,8 @@ iec_turnaround_to_talk: // Store .X and .Y on the stack - preserve them - txa - pha - tya - pha + phx_trash_a + phy_trash_a // Timing is critical here - execute on disabled IRQs php diff --git a/c64/kernal/iec/iec_tx_byte.s b/c64/kernal/iec/iec_tx_byte.s index 69e71f52..3866cff0 100644 --- a/c64/kernal/iec/iec_tx_byte.s +++ b/c64/kernal/iec/iec_tx_byte.s @@ -10,10 +10,8 @@ iec_tx_byte: // Store .X and .Y on the stack - preserve them - txa - pha - tya - pha + phx_trash_a + phy_trash_a // Notify all devices that we are going to send a byte // and it is going to be a data byte (released ATN) @@ -26,7 +24,9 @@ iec_tx_byte: iec_tx_common: // Timing is critical here - execute on disabled IRQs - php + // The best practice would be to do PHP first, but it seems this is not + // what the original ROM does; furthermore, pushing additional bytes to + // stack can wreck autostart softwaree loading at $0100 sei // Wait till all receivers are ready, they should all release DATA @@ -79,7 +79,7 @@ iec_tx_common_bit_is_sent: dex bpl iec_tx_common_sendbit - plp + cli // Give device time to tell if they are busy by pulling DATA // They should do it within 1ms diff --git a/c64/kernal/iec/iec_tx_command.s b/c64/kernal/iec/iec_tx_command.s index 42c98960..0f126d47 100644 --- a/c64/kernal/iec/iec_tx_command.s +++ b/c64/kernal/iec/iec_tx_command.s @@ -10,10 +10,8 @@ iec_tx_command: // Store .X and .Y on the stack - preserve them - txa - pha - tya - pha + phx_trash_a + phy_trash_a // Notify all devices that we are going to send a byte // and it is going to be a command (pulled ATN) diff --git a/c64/kernal/iec/iec_tx_command_finalize.s b/c64/kernal/iec/iec_tx_command_finalize.s index 6f11ea03..dc2a9c26 100644 --- a/c64/kernal/iec/iec_tx_command_finalize.s +++ b/c64/kernal/iec/iec_tx_command_finalize.s @@ -6,10 +6,8 @@ iec_tx_command_finalize: // Store .X and .Y on the stack - preserve them - txa - pha - tya - pha + phx_trash_a + phy_trash_a // Give device some time to complete command reception, release ATN, // give it some time again before (possible) next command diff --git a/c64/kernal/listen.s b/c64/kernal/iec/listen.s similarity index 100% rename from c64/kernal/listen.s rename to c64/kernal/iec/listen.s diff --git a/c64/kernal/second.s b/c64/kernal/iec/second.s similarity index 100% rename from c64/kernal/second.s rename to c64/kernal/iec/second.s diff --git a/c64/kernal/talk.s b/c64/kernal/iec/talk.s similarity index 100% rename from c64/kernal/talk.s rename to c64/kernal/iec/talk.s diff --git a/c64/kernal/tksa.s b/c64/kernal/iec/tksa.s similarity index 100% rename from c64/kernal/tksa.s rename to c64/kernal/iec/tksa.s diff --git a/c64/kernal/unlsn.s b/c64/kernal/iec/unlsn.s similarity index 100% rename from c64/kernal/unlsn.s rename to c64/kernal/iec/unlsn.s diff --git a/c64/kernal/untlk.s b/c64/kernal/iec/untlk.s similarity index 100% rename from c64/kernal/untlk.s rename to c64/kernal/iec/untlk.s diff --git a/c64/kernal/cartridge_check.s b/c64/kernal/init/cartridge_check.s similarity index 100% rename from c64/kernal/cartridge_check.s rename to c64/kernal/init/cartridge_check.s diff --git a/c64/kernal/init/cint_screen_keyboard.s b/c64/kernal/init/cint_screen_keyboard.s new file mode 100644 index 00000000..0470d710 --- /dev/null +++ b/c64/kernal/init/cint_screen_keyboard.s @@ -0,0 +1,71 @@ + +// +// This is a part CINT which initializes screen and keyboard +// +// For more details see: +// - [RG64] C64 Programmer's Reference Guide - page 280 +// - [CM64] Compute's Mapping the Commodore 64 - page 242 + +cint_screen_keyboard: + + // Setup KEYLOG vector + + lda #scnkey_set_keytab + sta KEYLOG+1 + + // Initialise cursor blink flags (Compute's Mapping the 64 p215) + + lda #$01 + sta BLNCT + sta BLNSW + + // Enable cursor repeat - XXX make it configurable + +#if CONFIG_KEY_REPEAT_DEFAULT && !CONFIG_KEY_REPEAT_ALWAYS + + lda #$80 + sta RPTFLG + +#endif + + // Set keyboard decode vector (Compute's Mapping the 64 p215) + +#if CONFIG_LEGACY_SCNKEY + + // Set initial variables for our improved keyboard scan routine + lda #$FF + ldx #6 +!: sta BufferOld,x + dex + bpl !- + sta BufferQuantity + + // Set key repeat delay (Compute's Mapping the 64 p215) + // Making some numbers up here: Repeat every ~1/10th sec + // But require key to be held for ~1/3sec before + // repeating (Compute's Mapping the 64 p58) + + // Not needed for default keyboard scanning code + + ldx #22-2 // Fudge factor to match speed + stx DELAY + +#endif + + // Set current colour for text (Compute's Mapping the 64 p215) + ldx #$01 // default is light blue ($0E), but we use a different one + stx COLOR + + // Set maximum keyboard buffer size (Compute's Mapping the 64 p215) + ldx #10 + stx XMAX + + // Put non-zero value in MODE to enable case switch + ldx #$00 + stx MODE + + // Fallthrough/jump to screen clear routine (Compute's Mapping the 64 p215) + + jmp clear_screen diff --git a/c64/kernal/init/e518.cint_legacy.s b/c64/kernal/init/e518.cint_legacy.s new file mode 100644 index 00000000..93effe63 --- /dev/null +++ b/c64/kernal/init/e518.cint_legacy.s @@ -0,0 +1,22 @@ + +// +// Part of the official Kernal routine, described in: +// +// - [RG64] C64 Programmer's Reference Guide - page 280 +// - [CM64] Compute's Mapping the Commodore 64 - page 242 +// +// CPU registers that has to be preserved (see [RG64]): none +// + + +cint_legacy: // $E518 + + // Setup video and I/O + // See here: https://csdb.dk/forums/index.php?roomid=11&topicid=17048&firstpost=22 + jsr setup_vicii + + // Code below must be placed under $E51B, or some code will break - see here: + // - https://csdb.dk/forums/index.php?roomid=11&topicid=17048&firstpost=2 + // Game 'Operacja Proboszcz' is one example. + + jmp cint_screen_keyboard // XXX try to fit the code here diff --git a/c64/kernal/init/e518.interop b/c64/kernal/init/e518.interop new file mode 100644 index 00000000..9d542a55 --- /dev/null +++ b/c64/kernal/init/e518.interop @@ -0,0 +1,3 @@ + +Game 'Operacja Proboszcz' explicitly calls $E51B - thus, it is sane +to place old CINT routine in it's original place diff --git a/c64/kernal/init/e5a0.setup_vicii.s b/c64/kernal/init/e5a0.setup_vicii.s new file mode 100644 index 00000000..78ab30a9 --- /dev/null +++ b/c64/kernal/init/e5a0.setup_vicii.s @@ -0,0 +1,66 @@ + +// +// Well-known Kernal routine, described in: +// +// - [CM64] Compute's Mapping the Commodore 64 - page 215 +// + + +setup_vicii: + + // Clear everything - turn off sprites (observed hanging around after + // running programs and resetting), etc. + + lda #$00 + ldx #$2E + !: + sta __VIC_BASE, x + dex + bpl !- + +#if !CONFIG_MB_MEGA_65 && !CONFIG_MB_ULTIMATE_64 + + // Disable C128 extra keys - just to be sure they won't interfere with anything + + stx VIC_XSCAN + + // Disable the C128 2MHz mode, it prevents VIC-II display from working correctly + + stx VIC_CLKRATE + +#endif + + // Set up default IO values + // - [CM64] page 129 - VIC_SCROLY + // - [CM64] pages 140-144 - VIC_SCROLX + // - [CM64] pages 145-146 - VIC_YMCSB + + lda #$1B // according to [CM64] page 137 some software assumes oldest bit is 0 + sta VIC_SCROLY + lda #$C8 + sta VIC_SCROLX // 40 column etc + lda #$14 + sta VIC_YMCSB + lda #$0F + sta VIC_IRQ // clear all interrupts + + // We use a different colour scheme of white text on all blue by default, + // but brand-specific color scheme can also be enabled + +#if CONFIG_COLORS_BRAND && CONFIG_BRAND_ULTIMATE_64 + + lda #$00 + sta VIC_EXTCOL + sta VIC_BGCOL0 + +#else + + lda #$06 + sta VIC_EXTCOL + sta VIC_BGCOL0 + +#endif + + // Setup default I/O devices + + jmp clrchn_reset diff --git a/c64/kernal/interrupts/hw_entry_reset.s b/c64/kernal/init/fce2.hw_entry_reset.s similarity index 73% rename from c64/kernal/interrupts/hw_entry_reset.s rename to c64/kernal/init/fce2.hw_entry_reset.s index ed498dfc..e0a3793e 100644 --- a/c64/kernal/interrupts/hw_entry_reset.s +++ b/c64/kernal/init/fce2.hw_entry_reset.s @@ -5,13 +5,18 @@ hw_entry_reset: // The GPL program at https://github.com/Klaus2m5/6502_65C02_functional_tests/blob/master/6502_functional_test.a65 - // uses the following initial reset sequence, affirmed by c64 PRG p269 -#if !HAS_BCD_SAFE_RESET - cld // for CPUs having undefined D flag after reset -#endif - ldx #$FF + // uses the similar initial reset sequence, affirmed by c64 PRG p269 + + sei // disable the interrupts, as fast as possible - they are disabled in case of HW reset, + // but this routine can be also called manually + + ldx #$00 + sta VIC_SCROLX // turn the display off - we want as little screen artifacts as possible + + cld // required for all CPUs - due to possibility of manual call + + dex // $FF - to initialize stack pointer txs - sei // The following routine is based on reading the public KERNAL jumptable routine // list, and making unimaginative assumptions about what should be done on reset. diff --git a/c64/kernal/init/fce2.interop b/c64/kernal/init/fce2.interop new file mode 100644 index 00000000..f9c9ce22 --- /dev/null +++ b/c64/kernal/init/fce2.interop @@ -0,0 +1,5 @@ +System reset routine has to be placed under it's original location due to 'SYS 64738' being extremaly popular to reset the C64, +to the point it went into popular culture. + +https://twitter.com/hashtag/SYS64738?src=hash +https://www.computerhope.com/jargon/s/sys64738.htm diff --git a/c64/kernal/fd50.interop b/c64/kernal/init/fd50.interop similarity index 100% rename from c64/kernal/fd50.interop rename to c64/kernal/init/fd50.interop diff --git a/c64/kernal/fd50.ramtas.jmp.s b/c64/kernal/init/fd50.ramtas.jmp.s similarity index 100% rename from c64/kernal/fd50.ramtas.jmp.s rename to c64/kernal/init/fd50.ramtas.jmp.s diff --git a/c64/kernal/fda3.ioinit.s b/c64/kernal/init/fda3.ioinit.s similarity index 76% rename from c64/kernal/fda3.ioinit.s rename to c64/kernal/init/fda3.ioinit.s index 778d5492..0337ec11 100644 --- a/c64/kernal/fda3.ioinit.s +++ b/c64/kernal/init/fda3.ioinit.s @@ -8,12 +8,13 @@ // CPU registers that has to be preserved (see [RG64]): none // + IOINIT: // Set $00/$01 port mode and value // We want BASIC and KERNAL ROMs mapped, and datasette motor off // (https://www.c64-wiki.com/wiki/Zeropage) - // XXX - Work around VICE bug: Writing $00 before $01 results in rubbish in $01 + // Work around for VICE bug: Writing $00 before $01 results in rubbish in $01 // after. https://sourceforge.net/p/vice-emu/bugs/1057/ lda #$27 ldx #$2F @@ -75,23 +76,6 @@ IOINIT: sta CIA2_ICR sta CIA1_ICR - // Set timer interval to ~1/60th of a second - - // (This value was calculated by running a custom IRQ handler on a C64 - // with original KERNAL, and writing the values of $DC04/5 to the screen - // in the IRQ handler to see roughly what value the timers must be set to) - // ldy #<16380 - // ldx #>16380 - - // PAL C64 (https://codebase64.org/doku.php?id=base:cpu_clocking), - // is clocked at 0.985248 MHz, so that 1/60s is 16421 CPU cycles - - ldy #<16421 - ldx #>16421 - - sty CIA1_TIMALO - stx CIA1_TIMAHI - // Enable timer interrupt lda #$81 sta CIA1_ICR @@ -101,10 +85,20 @@ IOINIT: sta CIA1_CRA lda CIA1_ICR + // Setup the CIA1 for reading the keyboard - 'POKE 56322, 0' on original ROMs proves this + // is done during initialization, not during the interrupt + + ldx #$FF + stx CIA1_DDRA // output + inx // $00 + stx CIA1_DDRB // input + + // Value checked on original ROM + stx CIA2_DDRA + // Set DDR on CIA2 for IEC bus, VIC-II banking - lda #$3B + lda #$3F sta CIA2_DDRA // Set IEC bus to its initial idle state jmp iec_set_idle - diff --git a/c64/kernal/init/ff5b.cint.s b/c64/kernal/init/ff5b.cint.s new file mode 100644 index 00000000..6f8fe591 --- /dev/null +++ b/c64/kernal/init/ff5b.cint.s @@ -0,0 +1,14 @@ + +// +// Official Kernal routine, described in: +// +// - [RG64] C64 Programmer's Reference Guide - page 280 +// - [CM64] Compute's Mapping the Commodore 64 - page 242 +// +// CPU registers that has to be preserved (see [RG64]): none +// + +CINT: + + jsr cint_legacy + jmp setup_pal_ntsc diff --git a/c64/kernal/ff5b.interop b/c64/kernal/init/ff5b.interop similarity index 100% rename from c64/kernal/ff5b.interop rename to c64/kernal/init/ff5b.interop diff --git a/c64/kernal/ramtas_real.s b/c64/kernal/init/ramtas_real.s similarity index 100% rename from c64/kernal/ramtas_real.s rename to c64/kernal/init/ramtas_real.s diff --git a/c64/kernal/init/setup_pal_ntsc.s b/c64/kernal/init/setup_pal_ntsc.s new file mode 100644 index 00000000..0b5ae619 --- /dev/null +++ b/c64/kernal/init/setup_pal_ntsc.s @@ -0,0 +1,65 @@ + +// Detect video system (PAL/NTSC), use Graham's method, as it's short and reliable +// see here: https://codebase64.org/doku.php?id=base:detect_pal_ntsc + + +setup_pal_ntsc: + + lda VIC_RASTER +!: + cmp VIC_RASTER + beq !- + bmi setup_pal_ntsc + + // Result in A, if no interrupt happened during the test: + // #$37 -> 312 rasterlines, PAL, VIC 6569 + // #$06 -> 263 rasterlines, NTSC, VIC 6567R8 + // #$05 -> 262 rasterlines, NTSC, VIC 6567R56A + + cmp #$07 + bcc setup_ntsc + + // FALLTROUGH + +setup_pal: + + // Set timer interval to ~1/60th of a second + + // (This value was calculated by running a custom IRQ handler on a C64 + // with original KERNAL, and writing the values of $DC04/5 to the screen + // in the IRQ handler to see roughly what value the timers must be set to) + // ldy #<16380 + // ldx #>16380 + + // PAL C64 (https://codebase64.org/doku.php?id=base:cpu_clocking), + // is clocked at 0.985248 MHz, so that 1/60s is 16421 CPU cycles + + ldy #<16421 + ldx #>16421 + + lda #$01 + + // FALLTROUGH + +setup_pal_ntsc_end: + + sty CIA1_TIMALO + stx CIA1_TIMAHI + + sta TVSFLG + + rts + +setup_ntsc: + + // Set timer interval to ~1/60th of a second + + // NTSC C64 (https://codebase64.org/doku.php?id=base:cpu_clocking), + // is clocked at 1.022727 MHz, so that 1/60s is 17045 CPU cycles + + ldy #<17045 + ldx #>17045 + + lda #$00 + + beq setup_pal_ntsc_end // branch always diff --git a/c64/kernal/interrupts/ea31.default_irq_handler.s b/c64/kernal/interrupts/ea31.default_irq_handler.s index 5ce46892..304fa343 100644 --- a/c64/kernal/interrupts/ea31.default_irq_handler.s +++ b/c64/kernal/interrupts/ea31.default_irq_handler.s @@ -1,7 +1,7 @@ default_irq_handler: - jsr blink_cursor + jsr cursor_blink jsr JSCNKEY jsr JUDTIM // update jiffy clock diff --git a/c64/kernal/interrupts/ea81.return_from_interrupt.s b/c64/kernal/interrupts/ea81.return_from_interrupt.s index 4908b8ed..4d22d7ea 100644 --- a/c64/kernal/interrupts/ea81.return_from_interrupt.s +++ b/c64/kernal/interrupts/ea81.return_from_interrupt.s @@ -12,15 +12,7 @@ return_from_interrupt: // Restore registers and return // Sequence according to Compute's Mapping the 64 p73 -#if CONFIG_CPU_MOS_6502 - pla - tay - pla - tax -#else - ply - plx -#endif + ply_trash_a + plx_trash_a pla rti - diff --git a/c64/kernal/interrupts/fe47.default_nmi_handler.s b/c64/kernal/interrupts/fe47.default_nmi_handler.s index 97cdb1d6..1fa8acc1 100644 --- a/c64/kernal/interrupts/fe47.default_nmi_handler.s +++ b/c64/kernal/interrupts/fe47.default_nmi_handler.s @@ -6,15 +6,8 @@ default_nmi_handler: // Save registers, sequence according to Compute's Mapping the Commodore 64, page 73 pha -#if CONFIG_CPU_MOS_6502 - txa - pha - tya - pha -#else - phx - phy -#endif + phx_trash_a + phy_trash_a // XXX: RS-232 support is not implemented diff --git a/c64/kernal/interrupts/fe66.default_brk_handler.s b/c64/kernal/interrupts/fe66.default_brk_handler.s index 75d1b4f4..78a63c72 100644 --- a/c64/kernal/interrupts/fe66.default_brk_handler.s +++ b/c64/kernal/interrupts/fe66.default_brk_handler.s @@ -5,9 +5,19 @@ default_brk_handler: sei // disable IRQs, to be sure they won't interfere + ldx #$00 + sta VIC_SCROLX // turn the display off - we want as little screen artifacts as possible + + cld // make sure this dangerous flag is disabled + jsr JRESTOR jsr JIOINIT - jsr cint_brk + + // Original routine calls just a part of CINT - but I'm not sure which one. Most likely it + // skips the PAL/NTSC check by calling $E518. I suspect bug in the original ROM, let's + // call the whole CINT, just to be sure everything is initialized. + + jsr CINT cli diff --git a/c64/kernal/interrupts/hw_entry_irq.s b/c64/kernal/interrupts/hw_entry_irq.s index 517100c4..e043ea0f 100644 --- a/c64/kernal/interrupts/hw_entry_irq.s +++ b/c64/kernal/interrupts/hw_entry_irq.s @@ -11,15 +11,8 @@ hw_entry_irq: // Save registers, sequence according to Compute's Mapping the Commodore 64, page 73 pha -#if CONFIG_CPU_MOS_6502 - txa - pha - tya - pha -#else - phx - phy -#endif + phx_trash_a + phy_trash_a #if CONFIG_CPU_MOS_6502 && CONFIG_BCD_SAFE_INTERRUPTS cld // clear decimal flag to allow using it without disabling interrupts diff --git a/c64/kernal/interrupts/udtim.s b/c64/kernal/interrupts/udtim.s new file mode 100644 index 00000000..769ab0e4 --- /dev/null +++ b/c64/kernal/interrupts/udtim.s @@ -0,0 +1,73 @@ + +// +// Official Kernal routine, described in: +// +// - [RG64] C64 Programmer's Reference Guide - page 303 +// - [CM64] Compute's Mapping the Commodore 64 - pages 27, 232 +// +// CPU registers that has to be preserved (see [RG64]): .Y +// + +UDTIM: + + // Update jiffy clock. The whole day is $4F1A00 jiffies (24 hours * 60 minutes * 60 seconds * 60 jiffies), + // after this time we have to reset the clock. + + inc TIME+0 + bne udtim_update_stkey // done with clock + inc TIME+1 + bne udtim_clock_rollover + inc TIME+2 + + // FALLTROUGH + +udtim_update_stkey: // entry to be used when interrupts are disabled + + // According to [CM64], page 27, another action we have to perform is to copy + // the last row of keyboard to RAM, so that various routines can detect the STOP + // key press. But something as simple as this would have created warm restart + // with M+N+SPACE+RESTORE due to ghosting - so the original ROM has to provide + // some protection here. I do not know what the mechanism there exactly does, + // but I hope the mechanism below will be compatible enough. + + lda #$80 + sta CIA1_PRA // select all the rows except the last one +#if CONFIG_KEYBOARD_C128 + ldx #$00 + stx VIC_XSCAN // connect all the extra C128 keys +#endif + + lda CIA1_PRB // read the keys + eor #$FF + sta STKEY // store reversed state - to filter out anything vulnerable to ghosting + +#if CONFIG_KEYBOARD_C128 + dex // puts $FF + stx VIC_XSCAN // disconnect the extra C128 keys +#endif + lda #$7F + sta CIA1_PRA // select the last row (bit to 0) + + lda CIA1_PRB // read the row + ora STKEY // filter out what might be the reason of ghosting + sta STKEY + + // Leave the CIA configured this way. It would be far better to disconnect + // the keyboard at this point, but certain software (mainly intros) is + // unable to, for example, read the space bar status. + + rts + +udtim_clock_rollover: + + // At this point TIME+0 contains 0 + lda TIME+1 + cmp #$1A + bne udtim_update_stkey // done with clock + lda TIME+2 + cmp #$4F + bne udtim_update_stkey // done with clock + lda #$00 + sta TIME+2 + sta TIME+1 + beq udtim_update_stkey // done with clock - will always jump diff --git a/c64/kernal/clall_real.s b/c64/kernal/iostack/clall_real.s similarity index 96% rename from c64/kernal/clall_real.s rename to c64/kernal/iostack/clall_real.s index 2a24af72..abdd9b69 100644 --- a/c64/kernal/clall_real.s +++ b/c64/kernal/iostack/clall_real.s @@ -12,8 +12,7 @@ clall_real: // Store .Y register - tya - pha + phy_trash_a // Original routine probably just sets LDTND to 0, but this is not really safe, // so we actually close all the channels; at least IDE64 does the same for @@ -27,8 +26,7 @@ clall_real: jmp !- !: // Restore .Y register - pla - tay + ply_trash_a // 'C64 Programmers Reference Guide', page 281, claims it calls CLRCHN too jsr CLRCHN diff --git a/c64/kernal/f32f.clall.jmp.s b/c64/kernal/iostack/f32f.clall.jmp.s similarity index 100% rename from c64/kernal/f32f.clall.jmp.s rename to c64/kernal/iostack/f32f.clall.jmp.s diff --git a/c64/kernal/f32f.interop b/c64/kernal/iostack/f32f.interop similarity index 100% rename from c64/kernal/f32f.interop rename to c64/kernal/iostack/f32f.interop diff --git a/c64/kernal/findfls.s b/c64/kernal/iostack/findfls.s similarity index 92% rename from c64/kernal/findfls.s rename to c64/kernal/iostack/findfls.s index f9cefadd..874fad51 100644 --- a/c64/kernal/findfls.s +++ b/c64/kernal/iostack/findfls.s @@ -1,5 +1,5 @@ -// Just a helper routines +// Just a helper routine // Find the LAT / SAT / FAT entry index where LAT corresponds to A, returns index in Y // Carry flag set means not found diff --git a/c64/kernal/lvs_helpers.s b/c64/kernal/iostack/lvs_helpers.s similarity index 97% rename from c64/kernal/lvs_helpers.s rename to c64/kernal/iostack/lvs_helpers.s index 4548f58e..948de153 100644 --- a/c64/kernal/lvs_helpers.s +++ b/c64/kernal/iostack/lvs_helpers.s @@ -41,6 +41,7 @@ lvs_handle_byte_load_verify: // Thus we have to use a helper routine in low memory // to do the memory access +#if CONFIG_MEMORY_MODEL_60K // Save byte under ROMs and IO if required php sei @@ -52,6 +53,11 @@ lvs_handle_byte_load_verify: ldx #$37 stx $01 plp +#else + ldy #0 + sta (STAL),y +#endif + rts lvs_advance_pointer: diff --git a/c64/kernal/readst.s b/c64/kernal/iostack/readst.s similarity index 100% rename from c64/kernal/readst.s rename to c64/kernal/iostack/readst.s diff --git a/c64/kernal/setfls.s b/c64/kernal/iostack/setfls.s similarity index 100% rename from c64/kernal/setfls.s rename to c64/kernal/iostack/setfls.s diff --git a/c64/kernal/setmsg.s b/c64/kernal/iostack/setmsg.s similarity index 100% rename from c64/kernal/setmsg.s rename to c64/kernal/iostack/setmsg.s diff --git a/c64/kernal/setnam.s b/c64/kernal/iostack/setnam.s similarity index 100% rename from c64/kernal/setnam.s rename to c64/kernal/iostack/setnam.s diff --git a/c64/kernal/settmo.s b/c64/kernal/iostack/settmo.s similarity index 100% rename from c64/kernal/settmo.s rename to c64/kernal/iostack/settmo.s diff --git a/c64/kernal/keyboard/f142.interop b/c64/kernal/keyboard/f142.interop new file mode 100644 index 00000000..73019c17 --- /dev/null +++ b/c64/kernal/keyboard/f142.interop @@ -0,0 +1,4 @@ +$F142 is a well-known address of keyboard reading routine, described for example here: +- http://sta.c64.org/cbm64kbdfunc.html + +It is used for eexample by a music eeditor here: https://github.com/martinpiper/C64Public/blob/master/MusicEditor/GetKey.a diff --git a/c64/kernal/keyboard/f142.read_kb_buf.s b/c64/kernal/keyboard/f142.read_kb_buf.s new file mode 100644 index 00000000..8b72b9e2 --- /dev/null +++ b/c64/kernal/keyboard/f142.read_kb_buf.s @@ -0,0 +1,30 @@ + +// +// Well-known Kernal routine, described in: +// +// - http://sta.c64.org/cbm64kbdfunc.html +// + + +read_kb_buf: + + // Check for a key + lda NDX + bne !+ + + // Nothing in keyboard buffer to read + sec + rts + +!: + lda KEYD + pha + phy_trash_a + + jsr pop_keyboard_buffer + + ply_trash_a + pla + clc + + rts diff --git a/c64/kernal/keyboard/kb_matrix.s b/c64/kernal/keyboard/kb_matrix.s new file mode 100644 index 00000000..e681f9f3 --- /dev/null +++ b/c64/kernal/keyboard/kb_matrix.s @@ -0,0 +1,56 @@ + +// +// Keyboard matrix, based on +// +// - [RG64] C64 Programmer's Reference Guide - pages 379-381 +// - [CM64] Compute's Mapping the Commodore 64 - pages 38-39 +// - http://commodore128.mirkosoft.sk/keyboard.html (C128 extension) +// - http://www.zimmers.net/cbmpics/cbm/c65/c65manual.txt + +// Values can be computed by running a program like: +// 10 GET A$ : IF A$ = "" GOTO10 +// 20 PRINT ASC(A$) : GOTO10 +// and converting the values + + +kb_matrix: + +__kb_matrix_normal: + .byte $14,$0D,$1D,$88,$85,$86,$87,$11 + .byte $33,$57,$41,$34,$5A,$53,$45,$00 + .byte $35,$52,$44,$36,$43,$46,$54,$58 + .byte $37,$59,$47,$38,$42,$48,$55,$56 + .byte $39,$49,$4A,$30,$4D,$4B,$4F,$4E + .byte $2B,$50,$4C,$2D,$2E,$3A,$40,$2C + .byte $5C,$2A,$3B,$13,$00,$3D,$5E,$2F + .byte $31,$5F,$00,$32,$20,$00,$51,$03 + +__kb_matrix_shift: + .byte $94,$8D,$9D,$8C,$89,$8A,$8B,$91 + .byte $23,$77,$61,$24,$7A,$73,$65,$00 + .byte $25,$72,$64,$26,$63,$66,$74,$78 + .byte $27,$79,$67,$28,$62,$68,$75,$76 + .byte $29,$69,$6A,$92,$6D,$6B,$6F,$6E + .byte $DB,$70,$6C,$DD,$3E,$5B,$BA,$3C + .byte $A9,$C0,$5D,$93,$00,$3D,$DE,$3F + .byte $21,$5F,$00,$22,$A0,$00,$71,$83 + +__kb_matrix_vendor: + .byte $94,$8D,$9D,$8C,$89,$8A,$8B,$91 + .byte $96,$B3,$B0,$97,$AD,$AE,$B1,$00 + .byte $98,$B2,$AC,$99,$BC,$BB,$A3,$BD + .byte $9A,$B7,$A5,$9B,$BF,$B4,$B8,$BE + .byte $30,$A2,$B5,$30,$A7,$A1,$B9,$AA + .byte $A6,$AF,$B6,$DC,$3E,$5B,$A4,$3C + .byte $A8,$DF,$5D,$93,$00,$3D,$DE,$3F + .byte $81,$5F,$00,$95,$a0,$00,$AB,$83 + +__kb_matrix_ctrl: + .byte $00,$00,$00,$00,$00,$00,$00,$00 + .byte $1C,$17,$01,$9F,$1A,$13,$05,$00 + .byte $9C,$12,$04,$1E,$03,$06,$14,$18 + .byte $1F,$19,$07,$9E,$02,$08,$15,$16 + .byte $12,$09,$0A,$92,$0D,$0B,$0F,$0E + .byte $00,$10,$0C,$00,$00,$1B,$00,$00 + .byte $1C,$00,$1D,$00,$00,$1F,$1E,$00 + .byte $90,$06,$00,$05,$00,$00,$11,$00 diff --git a/c64/kernal/keyboard/kb_matrix_128.s b/c64/kernal/keyboard/kb_matrix_128.s new file mode 100644 index 00000000..2c0d4b9e --- /dev/null +++ b/c64/kernal/keyboard/kb_matrix_128.s @@ -0,0 +1,30 @@ + +// +// Extended keyboard matrix for Commodore 128 keyboards, based on +// +// - [CM128] Compute's Mapping the Commodore 128 - page 290 +// - http://commodore128.mirkosoft.sk/keyboard.html +// + + +#if CONFIG_KEYBOARD_C128 && !CONFIG_LEGACY_SCNKEY + + +kb_matrix_128: + + .byte KEY_HELP,$38,$38,KEY_TAB_FW,$32,$34,$37,$31 + .byte KEY_ESC,$2B,$2D,$8D,$0D,$36,$39,$33 + .byte $00,$30,$2E,$91,$11,$9D,$1D,$00 + + +kb_matrix_128_bucky_filter: + + // values for OR with CIA1_PRB content to filter out bucky keys + + .byte %00000000 + .byte %00000000 + .byte %10000001 // ALT, NO_SCRL + + + +#endif // CONFIG_KEYBOARD_C128 and no CONFIG_LEGACY_SCNKEY diff --git a/c64/kernal/keyboard/kb_matrix_alwaysrepeat.s b/c64/kernal/keyboard/kb_matrix_alwaysrepeat.s new file mode 100644 index 00000000..ffb80e02 --- /dev/null +++ b/c64/kernal/keyboard/kb_matrix_alwaysrepeat.s @@ -0,0 +1,23 @@ + +// +// Matrix ids of keys which should be repeated regardless of RPTFLG +// +// Values based on: +// - [CM64] Compute's Mapping the Commodore 64 - page 58 +// + + +#if !CONFIG_LEGACY_SCNKEY && !CONFIG_KEY_REPEAT_ALWAYS + + +kb_matrix_alwaysrepeat: + + .byte $3C // SPACE + .byte $02 // CRSR LEFT/RIGHT + .byte $07 // CRSR UP/DOWN + .byte $00 // INS/DEL + +__kb_matrix_alwaysrepeat_end: + + +#endif // no CONFIG_LEGACY_SCNKEY and no CONFIG_KEY_REPEAT_ALWAYS diff --git a/c64/kernal/keyboard/kb_matrix_bucky.s b/c64/kernal/keyboard/kb_matrix_bucky.s new file mode 100644 index 00000000..4b685e0d --- /dev/null +++ b/c64/kernal/keyboard/kb_matrix_bucky.s @@ -0,0 +1,67 @@ + +// +// Matrix for retrieving bucky key status on the C64 keyboard +// +// Values based on: +// - [CM64] Compute's Mapping the Commodore 64 - pages 58 (SHFLAG), 173 (matrix) +// - [CM128] Compute's Mapping the Commodore 128 - pages 212 (SHFLAG), 290 (matrix) +// + +#if !CONFIG_LEGACY_SCNKEY + + +kb_matrix_bucky_confmask: // values to be written to CIA1_PRA + + .byte %11111101 // SHIFT (left) + .byte %10111111 // SHIFT (right) + .byte %01111111 // VENDOR + .byte %01111111 // CTRL +#if CONFIG_KEYBOARD_C128 + .byte %11111111 // C128 extra keys + .byte %11111111 +#endif + + +__kb_matrix_bucky_confmask_end: + + +#if CONFIG_KEYBOARD_C128 + +kb_matrix_bucky_confmask_c128: // values to be written to VIC_XSCAN + + .byte %11111111 + .byte %11111111 + .byte %11111111 + .byte %11111111 + + .byte %11111011 // ALT + .byte %11111011 // NO_SCRL + +#endif + + +kb_matrix_bucky_testmask: // for AND with CIA1_PRB value + + .byte %10000000 // SHIFT (left) + .byte %00010000 // SHIFT (right) + .byte %00100000 // VENDOR + .byte %00000100 // CTRL +#if CONFIG_KEYBOARD_C128 + .byte %10000000 // ALT + .byte %00000001 // NO_SCRL +#endif + + +kb_matrix_bucky_shflag: // mask to be ORed to SHFLAG to mark key status + + .byte KEY_FLAG_SHIFT + .byte KEY_FLAG_SHIFT + .byte KEY_FLAG_VENDOR + .byte KEY_FLAG_CTRL +#if CONFIG_KEYBOARD_C128 + .byte KEY_FLAG_ALT + .byte KEY_FLAG_NO_SCRL +#endif + + +#endif // no CONFIG_LEGACY_SCNKEY diff --git a/c64/kernal/keyboard/kb_matrix_bucky_filter.s b/c64/kernal/keyboard/kb_matrix_bucky_filter.s new file mode 100644 index 00000000..0e2a9b36 --- /dev/null +++ b/c64/kernal/keyboard/kb_matrix_bucky_filter.s @@ -0,0 +1,27 @@ + +// +// Matrix for filtering out bucky keys while scanning the C64 keyboard +// +// Values based on: +// - [CM64] Compute's Mapping the Commodore 64 - pags 58 (SHFLAG), 173 (matrix) +// + + +#if !CONFIG_LEGACY_SCNKEY + + +kb_matrix_bucky_filter: + + // values for OR with CIA1_PRB content to filter out bucky keys + + .byte %00000000 + .byte %10000000 // SHIFT (left) + .byte %00000000 + .byte %00000000 + .byte %00000000 + .byte %00000000 + .byte %00010000 // SHIFT (right) + .byte %00100100 // VENDOR + CONTROL + + +#endif // no CONFIG_LEGACY_SCNKEY diff --git a/c64/kernal/keyboard/kb_matrix_joy.s b/c64/kernal/keyboard/kb_matrix_joy.s new file mode 100644 index 00000000..8f9deaab --- /dev/null +++ b/c64/kernal/keyboard/kb_matrix_joy.s @@ -0,0 +1,38 @@ + +// +// Matrix for retrieving C64 joystick status and inject is as keyboard event +// + + +#if !CONFIG_LEGACY_SCNKEY && (CONFIG_JOY1_CURSOR || CONFIG_JOY2_CURSOR) + + +kb_matrix_joy_status: + + .byte %00001110 // up + .byte %00001101 // down + .byte %00001011 // left + .byte %00000111 // right + +kb_matrix_joy_keytab_idx: + + .byte $07 // up + .byte $07 // down + .byte $02 // left + .byte $02 // right + +kb_matrix_joy_keytab_lo: + + .byte <__kb_matrix_shift // up + .byte <__kb_matrix_normal // down + .byte <__kb_matrix_shift // left + .byte <__kb_matrix_normal // right + +kb_matrix_joy_keytab_hi: + + .byte >__kb_matrix_shift // up + .byte >__kb_matrix_normal // down + .byte >__kb_matrix_shift // left + .byte >__kb_matrix_normal // right + +#endif diff --git a/c64/kernal/keyboard/kb_matrix_lookup.s b/c64/kernal/keyboard/kb_matrix_lookup.s new file mode 100644 index 00000000..9e1b8f34 --- /dev/null +++ b/c64/kernal/keyboard/kb_matrix_lookup.s @@ -0,0 +1,23 @@ + +// +// Helper table for determining keyboard matrix decoding table on the C64 keyboard +// +// When more than one bucky keey is pressed, decoding keys is asking for trouble, +// so never allow this. +// + + +#if !CONFIG_LEGACY_SCNKEY + +kb_matrix_lookup: + + .byte (__kb_matrix_normal - kb_matrix) // %000 Normal + .byte (__kb_matrix_shift - kb_matrix) // %001 SHIFT + .byte (__kb_matrix_vendor - kb_matrix) // %010 VENDOR + .byte $FF // %011 SHIFT+VENDOR + .byte (__kb_matrix_ctrl - kb_matrix) // %100 CTRL + .byte $FF // %101 SHIFT+CTRL + .byte $FF // %110 VENDOR+CTRL + .byte $FF // %111 SHIFT+VENDOR+CTRL + +#endif diff --git a/c64/kernal/keyboard/kb_matrix_lookup_legacy.s b/c64/kernal/keyboard/kb_matrix_lookup_legacy.s new file mode 100644 index 00000000..62f2a932 --- /dev/null +++ b/c64/kernal/keyboard/kb_matrix_lookup_legacy.s @@ -0,0 +1,28 @@ + +// +// Work out if normal, shifted, control or Vendor modified keyboard. +// Table contains the offsets into keyboard_matrixes that should be used +// for different values of the bottom 3 bits of key_bucky_state XXX +// Interaction is simple to work out when playing with a C64: +// CTRL trumps SHIFT or VENDOR +// VENDOR + SHIFT = DOES NOTHING +// All 3 does CONTROL +// + +// This lookup table is used by TWW/CTR keyboard routine only! + + +#if CONFIG_LEGACY_SCNKEY + +kb_matrix_lookup: + + .byte $00 // Normal + .byte $40 // Shifted + .byte $80 // Control + .byte $80 // Control + SHIFT + .byte $C0 // Vendor + .byte $C0 // Vendor + SHIFT + .byte $80 // Vendor + CTRL + .byte $80 // Vendor + CTRL + SHIFT + +#endif // CONFIG_LEGACY_SCNKEY diff --git a/c64/kernal/keyboard/kb_matrix_row_keys.s b/c64/kernal/keyboard/kb_matrix_row_keys.s new file mode 100644 index 00000000..bb4b9afb --- /dev/null +++ b/c64/kernal/keyboard/kb_matrix_row_keys.s @@ -0,0 +1,29 @@ + +// +// Single row key codes for scanning the C64 keyboard +// +// Values based on: +// - [CM64] Compute's Mapping the Commodore 64 - pags 58 (SHFLAG), 173 (matrix) +// + + +#if !CONFIG_LEGACY_SCNKEY + + +kb_matrix_row_keys: + + // - values for CIA1_PRA to connect only the given row + // - first 3 values also meant for VIC_XSCAN for C128 keyboards + // - also used to scan a single row + + .byte %11111110 + .byte %11111101 + .byte %11111011 + .byte %11110111 + .byte %11101111 + .byte %11011111 + .byte %10111111 + .byte %01111111 + + +#endif // no CONFIG_LEGACY_SCNKEY diff --git a/c64/kernal/keyboard/kb_matrix_row_offsets.s b/c64/kernal/keyboard/kb_matrix_row_offsets.s new file mode 100644 index 00000000..efc2ceaf --- /dev/null +++ b/c64/kernal/keyboard/kb_matrix_row_offsets.s @@ -0,0 +1,23 @@ + +// +// Helper values to quickly determine row offset from the start of keyboard matrix +// + + +#if !CONFIG_LEGACY_SCNKEY + + +kb_matrix_row_offsets: + + // - offsets (in bytes) to the first bytes of keyboard matrix rows + + .byte 0*8 + .byte 1*8 + .byte 2*8 + .byte 3*8 + .byte 4*8 + .byte 5*8 + .byte 6*8 + .byte 7*8 + +#endif // no CONFIG_LEGACY_SCNKEY diff --git a/c64/kernal/keyboard/keyboard_disconnect.s b/c64/kernal/keyboard/keyboard_disconnect.s new file mode 100644 index 00000000..1fdae023 --- /dev/null +++ b/c64/kernal/keyboard/keyboard_disconnect.s @@ -0,0 +1,22 @@ + +// +// Helper routine - disconnects the keyboard from CIA1_PRB, +// leaves $FF in .X (behavior needed in some places) +// + + +#if !CONFIG_LEGACY_SCNKEY + + +keyboard_disconnect: + + ldx #$FF + stx CIA1_PRA // disconnect all the rows +#if CONFIG_KEYBOARD_C128 + stx VIC_XSCAN +#endif + + rts + + +#endif diff --git a/c64/kernal/keyboard/pop_keyboard_buffer.s b/c64/kernal/keyboard/pop_keyboard_buffer.s new file mode 100644 index 00000000..6f3b172b --- /dev/null +++ b/c64/kernal/keyboard/pop_keyboard_buffer.s @@ -0,0 +1,22 @@ + +// Pop key out of keyboard buffer +// Disable interrupts while reading from keyboard buffer +// so that no race conditions can occur +// +// CPU registers that has to be preserved: .X +// + +pop_keyboard_buffer: + + ldy #$01 + + sei +!: lda KEYD,y + sta KEYD-1,y + iny + cpy XMAX + bne !- + dec NDX + cli + + rts diff --git a/c64/kernal/keyboard/scnkey.s b/c64/kernal/keyboard/scnkey.s new file mode 100644 index 00000000..b1ed3a5f --- /dev/null +++ b/c64/kernal/keyboard/scnkey.s @@ -0,0 +1,411 @@ + +// +// Official Kernal routine, described in: +// +// - [RG64] C64 Programmer's Reference Guide - page 295 +// - [CM64] Compute's Mapping the Commodore 64 - page 220 +// +// CPU registers that has to be preserved (see [RG64]): none +// + +// Variables used: +// - KEYTAB - keyboard matrix pointer +// - DELAY - counter for first delay between key repeats +// - KOUNT - counter for next delays between key repeats +// - SHFLAG - SHIFT / CTRL / VENDOR keypress status +// - NDX - number of characters in keyboard buffer +// - XMAX - maximum size of keyboard buffer +// - LSTX - matrix coordinate of last pressed key +// - LSTSHF - previous status of SHFLAG +// - MODE - flag, whether charset toggle (SHIFT+VENDOR) is allowed +// - RPTFLG - whether key repeat is allowed + + + +#if !CONFIG_LEGACY_SCNKEY + +// Routine takes some ideas from TWW/CTR proposal, see here: +// - http://codebase64.org/doku.php?id=base:scanning_the_keyboard_the_correct_and_non_kernal_way + + +SCNKEY: + + // Prepare for SHFLAG update + + lda SHFLAG + sta LSTSHF + lda #$00 + sta SHFLAG + +#if !CONFIG_JOY2_CURSOR && CONFIG_KEY_FAST_SCAN + + // Check for any activity - speed optimization, but cannot be done + // that early if we are to scan the joystick #2 + + ldx #$00 + stx CIA1_PRA // connect all the rows +#if CONFIG_KEYBOARD_C128 + stx VIC_XSCAN +#endif + dex // puts $FF + cpx CIA1_PRB + beq scnkey_no_keys + +#endif + + // Retrieve SHIFT / VENDOR / CTRL / ALT / CAPS LOCK status + +#if CONFIG_KEYBOARD_C128_CAPS_LOCK + + // First check if this is really a C128 - to avoid false positive + ldx #$00 + stx VIC_XSCAN + dex // puts $FF + cpx VIC_XSCAN + beq !+ // branch if C64, C128 will keep some bits cleared + + lda CPU_R6510 + and #$40 + bne !+ // branch if no CAPS LOCK + + lda #KEY_CAPS_LOCK + sta SHFLAG +!: + +#if !CONFIG_KEYBOARD_C128 + stx VIC_XSCAN // disconnect C128 keys if no C128 keyboard is supported +#endif + +#endif + + ldy #(__kb_matrix_bucky_confmask_end - kb_matrix_bucky_confmask - 1) +scnkey_bucky_loop: + lda kb_matrix_bucky_confmask, y + sta CIA1_PRA +#if CONFIG_KEYBOARD_C128 + lda kb_matrix_bucky_confmask_c128, y + sta VIC_XSCAN +#endif + lda kb_matrix_bucky_testmask, y + and CIA1_PRB + bne !+ // branch if not pressed + lda SHFLAG + ora kb_matrix_bucky_shflag, y + sta SHFLAG +!: + dey + bpl scnkey_bucky_loop + + // Set KEYTAB vector + + jsr via_keylog // XXX for some CPUs we have indirect jsr + +#if CONFIG_JOY2_CURSOR + + // Check for control port 2 activity + + ldx #$00 + stx CIA1_DDRA // set port to input to read joystick + + lda CIA1_PRA // read the joystick 2 status + + dex // puts $FF + stx CIA1_DDRA // set port back to output + + and #%00001111 // filter out anything but joystick movement + cmp #%00001111 + + bne scnkey_joystick_filtered + +#if CONFIG_KEY_FAST_SCAN + + inx // puts $00 + stx CIA1_PRA // connect all the rows +#if CONFIG_KEYBOARD_C128 + stx VIC_XSCAN +#endif + dex // puts $FF + cpx CIA1_PRB + beq scnkey_no_keys + +#endif // CONFIG_KEY_FAST_SCAN + +#endif // CONFIG_JOY2_CURSOR + + // Check for control port 1 activity (can interfere with keyboard) + + jsr keyboard_disconnect // disconnect all the rows, .X will be $FF + cpx CIA1_PRB // only control port activity will be reported +#if CONFIG_JOY1_CURSOR + bne scnkey_joystick_1 // use joystick for cursor keys +#else + bne scnkey_no_keys // if activity detected do not scan the keyboard +#endif + + // Check if KEYTAB is not 0 (happens if more than one bucky key is pressed) + // High byte equal to 0 = table considered invalid + + lda KEYTAB+1 + beq scnkey_no_keys + + // Scan the keyboard matrix + + ldy #$FF // offset in key matrix table, $FF for not found yet +#if CONFIG_KEYBOARD_C128 + jsr scnkey_128 +#endif + ldx #$07 +scnkey_matrix_loop: + lda kb_matrix_row_keys, x + sta CIA1_PRA + lda kb_matrix_bucky_filter, x // filter out bucky keys + ora CIA1_PRB + cmp #$FF + beq scnkey_matrix_loop_next // skip if no key pressed from this row + cpy #$FF + bne scnkey_no_keys // jam, more than one key pressed + // We have at least one key pressed in this row, we need to find which one exactly + ldy #$07 +scnkey_matrix_loop_inner: + cmp kb_matrix_row_keys, y + bne !+ // not this particular key + tya // now .A contains key offset within a row + clc + adc kb_matrix_row_offsets, x // now .A contains key offset from the matrix start + tay + jmp scnkey_matrix_loop_next +!: + dey + bpl scnkey_matrix_loop_inner + bmi scnkey_no_keys // branch always, multiple keys must have been pressed +scnkey_matrix_loop_next: + dex + bpl scnkey_matrix_loop + + // Scanning complete - check if we got a key + + cpy #$FF + beq scnkey_no_keys + + // To be extra sure, check for possible control port 1 interference once again + + jsr keyboard_disconnect // disconnect all the rows, .X will be $FF + cpx CIA1_PRB // only control port activity will be reported + beq scnkey_got_key // branch if joystick activity NOT detected + + // FALLTROUGH + +scnkey_no_keys: + + // Mark no key press + + lda #$40 + sta LSTX + rts + +#if CONFIG_JOY1_CURSOR + +scnkey_joystick_1: + + // Prepare joystick 1 status + + lda CIA1_PRB + and #%00001111 // filter out anything but movement + + // FALLTROUGH + +#endif + +#if CONFIG_JOY1_CURSOR || CONFIG_JOY2_CURSOR + +scnkey_joystick_filtered: + + // Set appropriate keyboard matrix and key code for joystick event + + ldy #$03 +!: + cmp kb_matrix_joy_status, y + beq !+ + dey + bpl !- + + // Not found + + rts +!: + // Found + + lda kb_matrix_joy_keytab_lo, y + sta KEYTAB+0 + lda kb_matrix_joy_keytab_hi, y + sta KEYTAB+1 + lda kb_matrix_joy_keytab_idx, y + tay + + // FALLTROUGH + +#endif + +scnkey_got_key: // .Y should now contain the key offset in matrix pointed by KEYTAB + + cpy LSTX + beq scnkey_try_repeat // branch if the same key as previously + sty LSTX + + // Reset key repeat counters - see [CM64] page 58 + + // Note: according to [CM64] it should be $10 for initializing DELAY, $06 for + // initializing KOUNT for the first time and $04 for subsequent ones - but replicating + // this would make our implementation longer, probably without improving the compatibility. + // + // Besides - since I am the one who writes the code, I will make the values exactly how I like them :D + + lda #$16 + sta DELAY + + // FALLTROUGH + +scnkey_output_key: + + // Check if we have free space in the keyboard buffer + + lda NDX + cmp XMAX + bcs scnkey_early_repeat // no space in buffer + + // Reinitialize secondary counter + + lda #$03 + sta KOUNT + + // Retrieve the PETSCII code + +#if CONFIG_KEYBOARD_C128 + + cpy #$40 + bcc !+ + + lda kb_matrix_128 - $41, y // retrieve key code from C128 extended matrix + jmp scnkey_got_petscii +!: + lda (KEYTAB), y // retrieve key code from standard matrix + + // XXX this will be needed for extended screen editor + + // cmp KEY_TAB_FW // special handling for SHIFT+TAB + // bne scnkey_got_petscii // XXX or to scnkey_handle_caps_lock + // lda SHFLAG // special handling for SHIFT+TAB + // and #KEY_FLAG_SHIFT + // bne !+ + // lda KEY_TAB_FW + // bne scnkey_got_petscii // branch alWAYS + // !: + // lda KEY_TAB_BW // bne scnkey_got_petscii if CAPS LOCK is handled + +#endif // CONFIG_KEYBOARD_C128_CAPS_LOCK + +#if CONFIG_KEYBOARD_C128_CAPS_LOCK + + // Check if we need special handling for a CAPS LOCK key + // This is shorter than a separate set of tables + +scnkey_handle_caps_lock: + +#if !CONFIG_KEYBOARD_C128 + lda (KEYTAB), y +#endif + tax + lda SHFLAG + and #(%00000111 + KEY_CAPS_LOCK) + cmp #KEY_CAPS_LOCK + bne !+ // branch if no special CAPS LOCK handling needed + + cpx #$41 // 'A' + bcc !+ + cpx #$5B // 'Z' + 1 + bcs !+ + + txa + clc + adc #$20 // turn lowercase into uppercase + tax +!: + txa + +#endif // CONFIG_KEYBOARD_C128_CAPS_LOCK + +#if !CONFIG_KEYBOARD_C128 && !CONFIG_KEYBOARD_C128_CAPS_LOCK + + lda (KEYTAB), y + +#endif + + // Output PETSCII code to the keyboard buffer + +scnkey_got_petscii: + + beq scnkey_no_keys // branch if we have no PETSCII code for this key + ldy NDX + sta KEYD, y + inc NDX + + // FALLTROUGH + +scnkey_done: + + rts + +scnkey_try_repeat: + +#if !CONFIG_KEY_REPEAT_ALWAYS + + // Check whether we should repeat keys - first the flag, afterwards hardcoded list + + lda RPTFLG + bmi scnkey_handle_repeat // branch if we should repeat always + + tya + ldx #(__kb_matrix_alwaysrepeat_end - kb_matrix_alwaysrepeat - 1) +!: + cmp kb_matrix_alwaysrepeat, x + beq scnkey_handle_repeat + dex + bpl !- + bmi scnkey_done + +scnkey_handle_repeat: + +#endif // no CONFIG_KEY_REPEAT_ALWAYS + + // Countdown before first repeat + + lda DELAY + beq !+ + dec DELAY + + rts +!: + // Countdown before subsequent repeats + + lda KOUNT + beq scnkey_output_key // if second counter is also 0, we can repeat the key + dec KOUNT + + rts + +scnkey_early_repeat: + + // Keyboard buffer was full - at least make sure the key + // will be repeated as soon as possible + + lda #$00 + sta DELAY + sta KOUNT + + rts + +via_keylog: + jmp (KEYLOG) + + +#endif // no CONFIG_LEGACY_SCNKEY diff --git a/c64/kernal/keyboard/scnkey_128.s b/c64/kernal/keyboard/scnkey_128.s new file mode 100644 index 00000000..7fc8ddf5 --- /dev/null +++ b/c64/kernal/keyboard/scnkey_128.s @@ -0,0 +1,71 @@ + +// +// Keyboard scanning routine extension for C128 keyboards +// +// - [CM128] Compute's Mapping the Commodore 128 - pages 212 (SHFLAG), 290 (matrix) +// + + +#if CONFIG_KEYBOARD_C128 && !CONFIG_LEGACY_SCNKEY + + +// Inlining this within SCNKEY would both overcomplicate the implementation +// and disrupt a lot of branches (they would cross the 127 bytes distance limit) + +// .Y is now $FF - try to put there a key code from extended keyboard + + +scnkey_128: + + sty CIA1_PRA // disconnect all the classic keys first + + ldx #$02 +scnkey_matrix_128_loop: + lda kb_matrix_row_keys, x + sta VIC_XSCAN + lda kb_matrix_128_bucky_filter, x // filter out bucky keys + ora CIA1_PRB + cmp #$FF + beq scnkey_matrix_128_loop_next // skip if no key pressed from this row + cpy #$FF + bne scnkey_128_no_keys // jam, more than one key pressed + // We have at least one key pressed in this row, we need to find which one exactly + ldy #$07 +scnkey_matrix_128_loop_inner: + cmp kb_matrix_row_keys, y + bne !+ // not this particular key + tya // now .A contains key offset within a row + clc + adc kb_matrix_row_offsets, x // now .A contains key offset from the matrix start + adc #$41 // now .A contains offset after the standard matrix + tay + jmp scnkey_matrix_128_loop_next +!: + dey + bpl scnkey_matrix_128_loop_inner + bmi scnkey_128_no_keys // branch always, multiple keys must have been pressed +scnkey_matrix_128_loop_next: + dex + bpl scnkey_matrix_128_loop + + // Scanning the C128 keyboard part complete - check if we got a key + + cpy #$FF + beq scnkey_128_done + + // Continue with C64 keyboard scanning + +scnkey_128_done: + + rts + + +scnkey_128_no_keys: + + pla // get rid of return address from the stack + pla + + jmp scnkey_no_keys // pass controll to original routine + + +#endif // CONFIG_KEYBOARD_C128 and no CONFIG_LEGACY_SCNKEY diff --git a/c64/kernal/scnkey.s b/c64/kernal/keyboard/scnkey_legacy.s similarity index 85% rename from c64/kernal/scnkey.s rename to c64/kernal/keyboard/scnkey_legacy.s index ac22a7ca..fe25392b 100644 --- a/c64/kernal/scnkey.s +++ b/c64/kernal/keyboard/scnkey_legacy.s @@ -8,6 +8,15 @@ // CPU registers that has to be preserved (see [RG64]): none // + +// NOTE: The code here is described as legacy, because the algorithm (although working very well) +// requires much more RAM than the original Kernal routine uses; without any form of extended +// RAM available to Open ROMs it will always be a serious compatibility risk. + + +#if CONFIG_LEGACY_SCNKEY + + // Scan the keyboard.. // Here we don't use the horrible buggy original routine, // not just because of copyright. Instead, we use the @@ -46,6 +55,22 @@ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + // Low memory variables + + // Reuse RS232 variables, since they should not be used by other things. + // Carefully avoid $A7 which is used by 64NET + .label KeyQuantity = $A8 // 1 byte + .label BufferNew = $A9 // 3 bytes + .label TempZP = $B6 // 1 byte + // These should be initialized in CINT to $FF + .label BufferQuantity = $B4 // 1 byte + .label BufferOld = $293 // 3 bytes + .label Buffer = $297 // 4 bytes + + // $250-$258 is the 81st - 88th characters in BASIC input, a carry over from VIC-20 + // and not used on C64, so safe for us to use, probably. + .label ScanResult = $250 // 8 bytes + // Operational Variables .const MaxKeyRollover = 3 @@ -96,9 +121,9 @@ accept_key: tax pla and #$3f - ora keyboard_matrix_lookup,x + ora kb_matrix_lookup,x tax - lda keyboard_matrixes,x + lda kb_matrix,x // But don't insert $00 characters beq sk_nokey @@ -198,18 +223,15 @@ Main: sta BufferNew+0 sta BufferNew+1 sta BufferNew+2 - - ldx #$ff - stx $dc02 // Port A - Output - ldy #$00 - sty $dc03 // Port B - Input - // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Check for Port Activity - sty $dc00 // Connect all Keyboard Rows - cpx $dc01 + ldx #$FF + ldy #$00 + + sty CIA1_PRA // Connect all Keyboard Rows + cpx CIA1_PRB bne skip0 jmp NoActivityDetected @@ -220,7 +242,7 @@ JoystickActivity: lda #$00 sta SHFLAG - lda $dc01 + lda CIA1_PRB and #$03 cmp #$01 bne !+ @@ -247,7 +269,7 @@ JoystickActivity: beq !+ jmp skdone !: - lda $dc01 + lda CIA1_PRB and #$0c cmp #$04 bne !+ @@ -273,8 +295,8 @@ skip0: // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Check for Control Port #1 Activity - stx $dc00 // Disconnect all Keyboard Rows - cpx $dc01 // Only Control Port activity will be detected + stx CIA1_PRA // Disconnect all Keyboard Rows + cpx CIA1_PRB // Only Control Port activity will be detected bne JoystickActivity // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -283,9 +305,9 @@ skip0: ldx #7 lda #%11111110 next_row: - sta $dc00 + sta CIA1_PRA pha - lda $dc01 + lda CIA1_PRB sta ScanResult,x pla sec @@ -298,8 +320,8 @@ next_row: // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Check for Control Port #1 Activity (again) - stx $dc00 // Disconnect all Keyboard Rows - cpx $dc01 // Only Control Port activity will be detected + stx CIA1_PRA // Disconnect all Keyboard Rows + cpx CIA1_PRB // Only Control Port activity will be detected beq !+ jmp ReturnNoKeys !: @@ -355,19 +377,8 @@ next_row: ora SHFLAG sta SHFLAG - // Chick for shift + Vendor - cmp #$03 - bne no_case_toggle - lda LSTSHF - cmp #$03 - beq no_case_toggle - - lda MODE - beq no_case_toggle - - lda $D018 - eor #$02 - sta $d018 + // Handle SHIFT + VENDOR + jsr scnkey_toggle_if_needed no_case_toggle: @@ -513,3 +524,6 @@ KeyCanRepeat: KeyRepeatWait: pla jmp ConsiderNextKey + + +#endif // CONFIG_LEGACY_SCNKEY diff --git a/c64/kernal/keyboard/scnkey_set_keytab.s b/c64/kernal/keyboard/scnkey_set_keytab.s new file mode 100644 index 00000000..6c9a03b1 --- /dev/null +++ b/c64/kernal/keyboard/scnkey_set_keytab.s @@ -0,0 +1,81 @@ + +// +// Well-known Kernal routine, described in: +// +// - [CM64] Compute's Mapping the Commodore 64 - pages 220, 221 +// + + +scnkey_set_keytab: + + +#if CONFIG_LEGACY_SCNKEY // routine not compatible with legacy SCNKEY + + rts + +#else + + + // Set initial KEYTAB value + + lda #kb_matrix + sta KEYTAB+1 + + // Calculate table index + + lda SHFLAG + and #$07 // we are only interested in SHIFT / CTRL / VENDOR keys + tax + + // Retrieve table offset + lda kb_matrix_lookup, x + cmp #$FF + bne scnkey_valid_offset + + // $FF means we shouldn't decode anything, mark this by setting high byte + // of KEYTAB to 0 (I don't think anyone would put keyboard decoding table + // at zeropage) + lda #$00 + beq !+ // branch always + +scnkey_valid_offset: + + // Add offset to the vector + clc + adc KEYTAB+0 + sta KEYTAB+0 + lda #$00 + adc KEYTAB+1 +!: + sta KEYTAB+1 + + // FALLTROUGH + + +#endif // no CONFIG_LEGACY_SCNKEY + + +scnkey_toggle_if_needed: // entry for SCNKEY (TWW/CTR version) + + // Check if we should toggle the character set + + lda MODE + bne !+ // not allowed to toggle + lda SHFLAG + and #$03 + cmp #$03 + bne !+ // no SHIFT + VENDOR pressed + lda LSTSHF + and #$03 + cmp #$03 + beq !+ // alreeady toggled + + // Toggle char set + + lda VIC_YMCSB + eor #$02 + sta VIC_YMCSB +!: + rts diff --git a/c64/kernal/membot.s b/c64/kernal/membot.s index 086545c0..84e6ce44 100644 --- a/c64/kernal/membot.s +++ b/c64/kernal/membot.s @@ -12,13 +12,14 @@ MEMBOT: bcc membot_set - ldx MEMSTR+0 ldy MEMSTR+1 - rts + ldx MEMSTR+0 + + // FALLTROUGH membot_set: + sty MEMSTR+1 stx MEMSTR+0 - stx MEMSTR+1 rts diff --git a/c64/kernal/panic.s b/c64/kernal/panic.s new file mode 100644 index 00000000..ef34736a --- /dev/null +++ b/c64/kernal/panic.s @@ -0,0 +1,74 @@ + +// +// Something terrible happened - show the panic screen +// + + +#if CONFIG_PANIC_SCREEN + +panic: + + // Disable interrupts, store error code on stack + + sei + pha + + // Reinitialize the hardware + + jsr IOINIT + jsr setup_vicii + jsr clear_screen + + // Disable NMIs - our routine checks for NULL vector + + lda #$00 + sta NMINV+0 + sta NMINV+1 + + // Display KERNAL PANIC message + + ldx #$14 + ldy #$0E + jsr plot_set + + ldx #__MSG_KERNAL_PANIC + jsr print_kernal_message + + // Display error code and message (if known) + + pla + beq kernal_panic_infinite_loop + pha + + ldx #$02 + ldy #$02 + jsr plot_set + + pla + pha + jsr print_hex_byte + + pla + cmp #P_ERR_ROM_MISMATCH + bne kernal_panic_infinite_loop + + ldx #__MSG_KERNAL_PANIC_ROM_MISMATCH + jsr print_kernal_message + + // Display some raster effect in the infinitew loop + +kernal_panic_infinite_loop: + ldx #$00 + stx VIC_EXTCOL +!: + inx + bpl !- + + ldx #$06 + stx VIC_EXTCOL + + nop + + bne kernal_panic_infinite_loop // branch always + +#endif // CONFIG_PANIC_SCREEN diff --git a/c64/kernal/print/print_kernal_message.s b/c64/kernal/print/print_kernal_message.s index 6ae7a23d..6e75e634 100644 --- a/c64/kernal/print/print_kernal_message.s +++ b/c64/kernal/print/print_kernal_message.s @@ -9,7 +9,7 @@ print_kernal_message: - lda __kernal_messages_start, x + lda __msg_kernal_first, x bpl !- // 0 marks end of string and #$7F jmp JCHROUT diff --git a/c64/kernal/print/print_pal_ntsc.s b/c64/kernal/print/print_pal_ntsc.s new file mode 100644 index 00000000..ec4ae805 --- /dev/null +++ b/c64/kernal/print/print_pal_ntsc.s @@ -0,0 +1,17 @@ + +// +// Print video system on startup banner +// + +#if CONFIG_SHOW_PAL_NTSC + +print_pal_ntsc: + + ldx #__MSG_KERNAL_NTSC + lda TVSFLG + beq !+ + ldx #__MSG_KERNAL_PAL +!: + jmp print_kernal_message + +#endif // CONFIG_SHOW_PAL_NTSC \ No newline at end of file diff --git a/c64/kernal/screen/chrout_screen.s b/c64/kernal/screen/chrout_screen.s new file mode 100644 index 00000000..0b447fad --- /dev/null +++ b/c64/kernal/screen/chrout_screen.s @@ -0,0 +1,115 @@ + +// +// CHROUT routine - screen support (character output) +// + + +chrout_screen: + + jsr cursor_hide_if_visible + + lda SCHAR + tax + + // All the PETSCII control codes are within $0x, $1x, $8x, $9x, remaining + // ones are always printable characters; separate away control codes + + and #$60 + bne !+ + jmp chrout_screen_control +!: + txa + + // Literals - first convert PETSCII to screen code + + // Codes $C0-$DF become $40-$5F + cmp #$E0 + bcs !+ + cmp #$C0 + bcc !+ + + and #$7F + jmp output_literal_char // not high char + +!: + // Range $20-$3F is unchanged + cmp #$40 + bcc output_literal_char // not high char + + // Unshifted letters and symbols from $40-$5F + // all end up being -$40 + // (C64 PRG p376) + + // But anything >= $80 needs to be -$40 + // (C64 PRG p380-381) + // And bit 7 should be cleared, only to be + // set by reverse video + sec + sbc #$40 + + // Fix shifted chars by adding $20 again + cmp #$20 + bcc output_literal_char // not high char + cmp #$40 + bcs output_literal_char // not high char + clc + adc #$20 + +output_literal_char: + + // Write normal character on the screen + + pha + + ldy PNTR + ora RVS // Compute's Mapping the 64 p38 + sta (PNT),y + + // Decrement number of chars waiting to be inserted + lda INSRT + beq !+ + dec INSRT +!: + pla + cmp #$22 + bne not_quote + + // Toggle quote flag if required + lda QTSW + eor #$80 + sta QTSW + +not_quote: + + // Set colour + lda COLOR + sta (USER),y + + // Advance the column, and scroll screen down if we need + // to insert a 2nd line in this logical line. + // (eg Compute's Mapping the 64 p41) + ldx TBLX + iny + sty PNTR + cpy #40 + bne !+ + jsr screen_grow_logical_line + ldy PNTR +!: + cpy #80 + bcc chrout_screen_done + lda #0 + sta PNTR + jmp chrout_screen_advance_to_next_line + + +chrout_screen_calc_lptr_done: + + jsr screen_calculate_line_pointer + + // FALLTROUGH + +chrout_screen_done: + + jsr cursor_show_if_enabled + jmp chrout_done_success diff --git a/c64/kernal/screen/chrout_screen_advance_to_next_line.s b/c64/kernal/screen/chrout_screen_advance_to_next_line.s new file mode 100644 index 00000000..323c47e8 --- /dev/null +++ b/c64/kernal/screen/chrout_screen_advance_to_next_line.s @@ -0,0 +1,44 @@ + +chrout_screen_advance_to_next_line: + + // Go to start of line + lda #0 + sta PNTR + // Advance line number + ldy TBLX + + // Do quick fix to line pointer to work out if it is off + // the bottom of the screen. + ldx #40 + lda LDTBL,y + bmi !+ + .byte $2c +!: ldx #80 + txa + clc + adc PNT+0 + sta PNT+0 + lda PNT+1 + adc #0 + sta PNT+1 + + inc TBLX + + // Check if it will trigger scrolling + // Work out if we have gone off the bottom of the screen? + // 1040 > 1024, so if high byte of screen pointer is >= (HIBASE+4), + // then we are off the bottom of the screen + lda PNT+1 + sec + sbc HIBASE + cmp #3 + bcc !+ + lda PNT+0 + cmp #$e7 + bcc !+ + + // Off the bottom of the screen + jsr scroll_screen_up +!: + + jmp chrout_screen_calc_lptr_done diff --git a/c64/kernal/screen/chrout_screen_control.s b/c64/kernal/screen/chrout_screen_control.s new file mode 100644 index 00000000..ff4f5706 --- /dev/null +++ b/c64/kernal/screen/chrout_screen_control.s @@ -0,0 +1,182 @@ + +// +// CHROUT routine - screen support, control codes +// + +chrout_screen_control: + + txa + + // Order here is not random + // 1. First handle the ones that do not depend on quoote mode + // 2. Handle remaining control codes starting from the most commonly used + // in situations when speed might matter, we want to be + // as snappy as possible + +chrout_try_RETURN: + + cmp #$0D + bne !+ + + // RETURN clears quote and insert modes, it also clears reverse flag + lda #$00 + sta QTSW + sta INSRT + sta RVS + jmp chrout_screen_advance_to_next_line +!: +chrout_try_DEL: + + cmp #$14 + bne !+ + jmp chrout_screen_del +!: +chrout_try_quote: + + lda QTSW + ora INSRT + beq !+ + jmp chrout_screen_quote +!: + txa + +chrout_try_CRSR_UP: + + cmp #$91 + bne !+ + + lda PNTR + sec + sbc #40 + sta PNTR + jmp chrout_screen_calc_lptr_done +!: +chrout_try_CRSR_DOWN: + + cmp #$11 + bne !+ + + lda PNTR + clc + adc #40 + sta PNTR + // We need to advance the pointer manually, as normalising + // now will break things. The pointer update is required + // so that we can tell if we really are on the bottom phys + // screen line or not + jsr screen_scroll_up_if_on_last_line + jmp chrout_screen_calc_lptr_done +!: +chrout_try_CRSR_LEFT: + + cmp #$9D + bne !+ + + lda TBLX + ora PNTR + beq crsr_l1 // recalculating pointer is not really necessary, but this is a very rare case nevertheless + dec PNTR +crsr_l1: + jmp chrout_screen_calc_lptr_done +!: +chrout_try_CRSR_RIGHT: + + cmp #$1D + bne !+ + + inc PNTR + jmp chrout_screen_calc_lptr_done +!: +chrout_try_RVS_ON: + + cmp #$12 + bne !+ + + lda #$80 + bne rvs_l1 +!: +chrout_try_RVS_OFF: + + cmp #$92 + bne !+ + + lda #$00 +rvs_l1: + sta RVS + jmp chrout_screen_done +!: +chrout_try_MODE_GFX: + + cmp #$8E + bne !+ + + lda VIC_YMCSB + and #$02 // to upper case +mode_l1: + sta VIC_YMCSB + jmp chrout_screen_done +!: +chrout_try_MODE_TXT: + + cmp #$0E + bne !+ + + lda VIC_YMCSB + ora #$02 // to lower case + bne mode_l1 // branch always +!: +chrout_try_COLOR: + + ldx #$0F +colour_check_loop: + cmp colour_codes,x + bne !+ + stx COLOR + jmp chrout_screen_done +!: + dex + bpl colour_check_loop + +chrout_try_SHIFT_ENABLE: + + cmp #$09 + bne !+ + + lda #$00 // enable SHIFT+VENDOR combination + sta MODE + + jmp chrout_screen_done +!: +chrout_try_SHIFT_DISABLE: + + cmp #$08 + bne !+ + + lda #$80 // disable SHIFT+VENDOR combination + sta MODE + + jmp chrout_screen_done +!: +chrout_try_HOME: + + cmp #$13 + bne !+ + + jsr cursor_home + jmp chrout_screen_done +!: +chrout_try_CLR: + + cmp #$93 + bne !+ + + jsr clear_screen +clr_l1: + jmp chrout_screen_done +!: +chrout_try_INS: + + cmp #$94 + bne clr_l1 // unknown code or key does not need handling + + jmp chrout_screen_ins diff --git a/c64/kernal/screen/chrout_screen_del.s b/c64/kernal/screen/chrout_screen_del.s new file mode 100644 index 00000000..135f4777 --- /dev/null +++ b/c64/kernal/screen/chrout_screen_del.s @@ -0,0 +1,65 @@ + +// +// CHROUT routine - screen support, DEL key handling +// + +chrout_screen_del: + + // In insert mode it embeds control character + ldx INSRT + beq !+ + jmp chrout_screen_quote +!: + ldx PNTR + bne chrout_screen_del_column_non_0 + + // FALLTROUGH + +chrout_screen_del_column_0: + + ldy TBLX + beq chrout_screen_del_done // delete from row 0, col 0 does nothing + + // Column 0 delete just moves us to the end of the + // previous line, without actually deleting anything + + dec TBLX + jsr screen_get_current_line_logical_length + lda LNMX + sta PNTR + + jmp chrout_screen_calc_lptr_done + +chrout_screen_del_column_non_0: + + // Copy rest of line down + jsr screen_get_current_line_logical_length + ldy PNTR + cpy LNMX + beq !++ + dey +!: + iny + lda (PNT),y + dey + sta (PNT),y + iny + lda (USER),y + dey + sta (USER),y + iny + cpy LNMX + bne !- + + // Clear char at end of line + jsr screen_get_current_line_logical_length + tay + lda #$20 + sta (PNT),y +!: + dec PNTR + + // FALLTROUGH + +chrout_screen_del_done: + jmp chrout_screen_done diff --git a/c64/kernal/screen/chrout_screen_ins.s b/c64/kernal/screen/chrout_screen_ins.s new file mode 100644 index 00000000..8e0e7f63 --- /dev/null +++ b/c64/kernal/screen/chrout_screen_ins.s @@ -0,0 +1,64 @@ + +// +// CHROUT routine - screen support, INS key handling +// + +chrout_screen_ins: + + // Insert (shift-DELETE) + + // Abort if line already max length, ie 79th char is not a space + jsr screen_get_current_line_logical_length + cmp #79 + bne !+ + tay + lda (PNT),y + cmp #$20 + beq !+ + + // Line is too long to extend + jmp chrout_screen_done + +!: + // Work out if line needs to be expanded, and if so expand it + ldy #39 + lda (PNT),y + cmp #$20 + beq !+ + + jsr screen_grow_logical_line + +!: + // Shuffle chars towards end of line + jsr screen_get_current_line_logical_length + tay +!: + // Note: While the following routine is obvious to any skilled + // in the art as the most obvious simple and efficient solution, + // if the screen writes are before the colour writes, it results + // in a relatively long verbatim stretch of bytes when compared to + // the C64 KERNAL. Thus we have swapped the order, just to reduce + // the potential for any argument of copyright infringement, even + // though we really don't believe that the routine can be copyrighted + // due to the lack of creativity. + dey + lda (USER),y + iny + sta (USER),y + dey + lda (PNT),y + iny + sta (PNT),y + + dey + cpy PNTR + bne !- + + // Increase insert mode count (which causes quote-mode like behaviour) + inc INSRT + + // Put space in the inserted gap + lda #$20 + sta (PNT),y + + jmp chrout_screen_done diff --git a/c64/kernal/screen/chrout_screen_quote.s b/c64/kernal/screen/chrout_screen_quote.s new file mode 100644 index 00000000..266f6d36 --- /dev/null +++ b/c64/kernal/screen/chrout_screen_quote.s @@ -0,0 +1,20 @@ + +// +// CHROUT routine - screen support, control codes in quote mode +// + + +chrout_screen_quote: + + // Low control codes are just +$80 + clc + adc #$80 + + // If it overflowed, then it is a high control code, + // so we need to make it be $80 + $40 + char + // as we will have flipped back to just $00 + char, we should + // now add $c0 if C is set from overflow + bcc !+ + adc #$BF // C=1, so adding $BF + C = add $C0 +!: + jmp output_literal_char diff --git a/c64/kernal/e544.clear_screen.s b/c64/kernal/screen/clear_screen_real.s similarity index 92% rename from c64/kernal/e544.clear_screen.s rename to c64/kernal/screen/clear_screen_real.s index 90d1999d..df0b835a 100644 --- a/c64/kernal/e544.clear_screen.s +++ b/c64/kernal/screen/clear_screen_real.s @@ -1,7 +1,9 @@ // Clear screen and initialise line link table // (Compute's Mapping the 64 p215-216) -clear_screen: +clear_screen_real: + + // XXX it is probably a good idea to hide cursor first // Clear line link table // (Compute's Mapping the 64 p215) @@ -57,4 +59,4 @@ clearscreen_l3: bne clearscreen_l3 // (Compute's Mapping the 64 p216) - jmp home_cursor + jmp cursor_home diff --git a/c64/kernal/screen/cursor.s b/c64/kernal/screen/cursor.s new file mode 100644 index 00000000..0221cf18 --- /dev/null +++ b/c64/kernal/screen/cursor.s @@ -0,0 +1,81 @@ + +// +// Variables used: +// - BLNSW (cursor blink switch) +// - BLNCT (cursor blink countdown) +// - GDBLN (cursor saved character) +// - BLNON (if cursor is visible) +// - GDCOL (colour under cursor) +// - USER (current screen line colour pointer) +// - PNT (current screen line pointer) +// - PNTR (current screen x position) +// + + +cursor_blink: + // Is the cursor enabled? + lda BLNSW + bne cursor_blink_end + + // Do we need to redraw things? + dec BLNCT + bpl cursor_blink_end + + // Check if cursor was visible or not, and toggle + lda BLNON + bne cursor_undraw + + // FALLTROUGH + +cursor_draw: + jsr screen_calculate_line_pointer // XXX try to make this call not needed + + ldy PNTR + lda (PNT),y + sta GDBLN + eor #$80 + sta (PNT),y + // Also set cursor colour + lda (USER),y + sta GDCOL + lda COLOR + sta (USER),y + + lda #1 + sta BLNON + + bne cursor_blink_timer_reset // branches always + +cursor_disable: + lda #$80 + sta BLNSW + + // FALLTHROUGH + +cursor_hide_if_visible: + lda BLNON + beq cursor_blink_end + +cursor_undraw: + + lda GDBLN + ldy PNTR + sta (PNT),y + lda GDCOL + sta (USER),y + + lda #0 + sta BLNON + + // FALLTROUGH + +cursor_blink_timer_reset: + + // Rest blink counter (Mapping the 64, p39-40) + lda #20 + sta BLNCT + + // FALLTROUGH + +cursor_blink_end: + rts diff --git a/c64/kernal/screen/cursor_enable.s b/c64/kernal/screen/cursor_enable.s new file mode 100644 index 00000000..72646312 --- /dev/null +++ b/c64/kernal/screen/cursor_enable.s @@ -0,0 +1,10 @@ + +// +// Variables used: +// - BLNSW (cursor blink switch) +// + +cursor_enable: + lda #$00 + sta BLNSW + rts diff --git a/c64/kernal/screen/cursor_home.s b/c64/kernal/screen/cursor_home.s new file mode 100644 index 00000000..bb9d9bd2 --- /dev/null +++ b/c64/kernal/screen/cursor_home.s @@ -0,0 +1,12 @@ + +// +// Home the cursor (Compute's Mapping the 64 p216) +// + +cursor_home: + + lda #$00 + sta PNTR // x position + sta TBLX // y position + + jmp screen_calculate_line_pointer diff --git a/c64/kernal/screen/cursor_show.s b/c64/kernal/screen/cursor_show.s new file mode 100644 index 00000000..c21b092c --- /dev/null +++ b/c64/kernal/screen/cursor_show.s @@ -0,0 +1,34 @@ + +// +// Variables used: +// - BLNSW (cursor blink switch) +// - BLNON (if cursor is visible) +// - BLNCT (cursor blink countdown) +// + +cursor_show_if_enabled: + lda BLNSW + bne cursor_show_end + lda BLNON + bne cursor_show_end + + // FALLTROUGH + +cursor_show: + + // Set cursor as though it had just finished the off phase, + // so that the call to cursor_blink paints it + lda #$00 + sta BLNCT + sta BLNON + jsr cursor_blink + + // Then set the timeout to 1 frame, so that the cursor + // blinks under key repeat conditions, like on the original KERNAL + lda #$01 + sta BLNCT + + // FALLTROUGH + +cursor_show_end: + rts diff --git a/c64/kernal/e50a.interop b/c64/kernal/screen/e50a.interop similarity index 100% rename from c64/kernal/e50a.interop rename to c64/kernal/screen/e50a.interop diff --git a/c64/kernal/e50a.plot.s b/c64/kernal/screen/e50a.plot.s similarity index 84% rename from c64/kernal/e50a.plot.s rename to c64/kernal/screen/e50a.plot.s index 58afa453..a36dfc08 100644 --- a/c64/kernal/e50a.plot.s +++ b/c64/kernal/screen/e50a.plot.s @@ -17,15 +17,16 @@ PLOT: // - 'Duotris' game calls $E50C during startup screen initialization plot_set: - sty TBLX - stx PNTR - // XXX handle cursor blink - // XXX should we update some more variables? + sty PNTR + stx TBLX + + jsr screen_calculate_line_pointer // FALLTROUGH to save one byte on RTS plot_get: - ldy TBLX - ldx PNTR + + ldy PNTR + ldx TBLX rts diff --git a/c64/kernal/screen/e544.clear_screen.jmp.s b/c64/kernal/screen/e544.clear_screen.jmp.s new file mode 100644 index 00000000..50d16f38 --- /dev/null +++ b/c64/kernal/screen/e544.clear_screen.jmp.s @@ -0,0 +1,6 @@ +// Clear screen and initialise line link table +// (Compute's Mapping the 64 p215-216) + +clear_screen: + + jmp clear_screen_real diff --git a/c64/kernal/screen.s b/c64/kernal/screen/screen.s similarity index 100% rename from c64/kernal/screen.s rename to c64/kernal/screen/screen.s diff --git a/c64/kernal/screen/screen_calculate_line_pointer.s b/c64/kernal/screen/screen_calculate_line_pointer.s new file mode 100644 index 00000000..d982a38d --- /dev/null +++ b/c64/kernal/screen/screen_calculate_line_pointer.s @@ -0,0 +1,54 @@ + +screen_calculate_line_pointer: + jsr screen_normalize_xy + + // Reset pointer to start of screen + lda HIBASE + sta PNT+1 + lda #0 + sta PNT+0 + + // Add 40 for every line, or 80 if the lines are linked + ldx TBLX + +!: + // Stop if we have counted enough lines + beq !+ + + // Add 40 or 80 based on whether the line is linked + // or not. + ldy #40 + // -1 offset is because we count down from N to 1, not + // N-1 to 0. + lda LDTBL-1,x + bpl sclp_l1 + ldy #80 +sclp_l1: + // Add computed line length to pointer value + tya + clc + adc PNT+0 + sta PNT+0 + lda PNT+1 + adc #0 + sta PNT+1 + + // Loop back to next line + dex + jmp !- +!: + + // FALLTHROUGH + +update_colour_line_pointer: + // Now setup pointer to colour RAM + lda PNT+0 + sta USER+0 + lda PNT+1 + sec + sbc HIBASE + clc + adc #>$d800 + sta USER+1 + + rts diff --git a/c64/kernal/screen/screen_code_to_petscii.s b/c64/kernal/screen/screen_code_to_petscii.s new file mode 100644 index 00000000..3485a3b9 --- /dev/null +++ b/c64/kernal/screen/screen_code_to_petscii.s @@ -0,0 +1,36 @@ + +screen_code_to_petscii: + cmp #$1B + bcc s2p_adc_40 + +s2p_not_alpha: + cmp #$40 + bcc s2p_end + + // FALLTROUGH + +s2p_not_punctuation: + cmp #$5B + bcs s2p_not_shifted + + // carry already clear here + adc #$80 + + rts + +s2p_not_shifted: + + cmp #$80 + bcs s2p_end // not vendor + + // $60-$7F -> $A0-$BF + +s2p_adc_40: + + clc + adc #$40 + + // FALLTROUGH + +s2p_end: + rts diff --git a/c64/kernal/screen/screen_get_current_line_logical_length.s b/c64/kernal/screen/screen_get_current_line_logical_length.s new file mode 100644 index 00000000..9d8aafc1 --- /dev/null +++ b/c64/kernal/screen/screen_get_current_line_logical_length.s @@ -0,0 +1,11 @@ + +screen_get_current_line_logical_length: + ldy TBLX + lda LDTBL,y + bpl !+ + lda #79 + .byte $2c // BIT absolute mode, which we use to skip the next two instruction bytes +!: + lda #39 + sta LNMX + rts \ No newline at end of file diff --git a/c64/kernal/screen/screen_grow_logical_line.s b/c64/kernal/screen/screen_grow_logical_line.s new file mode 100644 index 00000000..d2995b3c --- /dev/null +++ b/c64/kernal/screen/screen_grow_logical_line.s @@ -0,0 +1,122 @@ + +screen_grow_logical_line: + ldy TBLX + // Don't grow line if it is already grown + lda LDTBL,y + bpl !+ + jmp not_last_line // doneb grow line +!: + lda #$80 + sta LDTBL,y + + // Now make space for the extra line added. + // If we are on the last physical line of the screen, + // Then we need to scroll the screen up + jsr screen_scroll_up_if_on_last_line + + // Scroll screen down to make space + // As we are scrolling down, we start from the end, + // and work backwards. We can't be as simple and efficient + // here as we are for scrolling up, because we don't know + // how much must be scrolled. + // Simple solution is to work out how many physical lines + // need shifting down, and then move lines at a time after + // initialising the pointers to the end area of the screen. + ldx #25-2 + ldy #0 +count_rows_loop: + dex + lda LDTBL,y + bpl !+ + dex +!: iny + cpy TBLX + bne count_rows_loop + + cpx #0 + beq no_copy_down + bmi no_copy_down + + // Set pointers to end of screen line, and one line + // above. (It is always one physical line, because + // this can only happen when expanding a line from 40 to + // 80 characters). + // XXX - This is not very efficient, and longer than it + // needs to be. Better would be to work out size to + // copy, and count it down in a pointer somewhere, so + // that loop iteration logic is simpler. + lda HIBASE + clc + adc #3 + sta PNT+1 + sta SAL+1 + lda #>$DBC0 + sta EAL+1 + sta USER+1 + + lda #<$03C0 + sta PNT+0 + sta USER+0 + // souce address is line above + sec + sbc #40 + sta SAL+0 + sta EAL+0 + +copy_line_down_loop: + ldy #39 +cl_inner: + lda (EAL),y + sta (USER),y + lda (SAL),y + sta (PNT),y + dey + bpl cl_inner + + // Decrement all pointers by 40 + // Low bytes are in common pairs + + // Old source is new destination + // Use different registers to minimise byte similarity with C64 KERNAl + ldy SAL+1 + sty PNT+1 + lda EAL+1 + ldy SAL+0 + sta USER+1 + sty PNT+0 + sty USER+0 + + // Decrementing source pointers + lda SAL+0 + sec + sbc #<40 + sta SAL+0 + sta EAL+0 + lda SAL+1 + sbc #>40 + sta SAL+1 + // convert to screen equivalent + sec + sbc HIBASE + clc + adc #>$D800 + sta EAL+1 + + dex + bne copy_line_down_loop + +no_copy_down: + jsr screen_calculate_line_pointer + + // Erase newly inserted line + ldy #79 +!: + lda COLOR + sta (USER),y + lda #$20 + sta (PNT),y + dey + cpy #40 + bne !- + + rts diff --git a/c64/kernal/screen/screen_normalize_xy.s b/c64/kernal/screen/screen_normalize_xy.s new file mode 100644 index 00000000..147895a4 --- /dev/null +++ b/c64/kernal/screen/screen_normalize_xy.s @@ -0,0 +1,82 @@ + +// +// Normalise X and Y values +// If X < 0, then make X = X + 40 (or 80, if previous line is linked) +// + +screen_normalize_xy: + + lda PNTR + bpl x_not_negative + dec TBLX + // Check that we didn't go backwards off the top of the screen + bpl !+ + lda #0 + sta TBLX + +!: jsr add_40_to_screen_x + + // Check if line is linked, if so, add 40 again + ldy TBLX + lda LDTBL,y + bpl !+ + jsr add_40_to_screen_x +!: + +x_not_negative: + // Work out if X is too big + ldy TBLX + lda LDTBL,y + bpl !+ + lda #79 + .byte $2C // BIT $nnnn, used to skip next instruction +!: lda #39 + cmp PNTR + bcs x_not_too_big + + // X value is too big, so subtract 40 and increment Y + lda PNTR + sec + sbc #40 + sta PNTR + inc TBLX + +x_not_too_big: + + // Make sure Y isn't negative + lda TBLX + bpl !+ + lda #0 + sta TBLX +!: + // Make sure Y isn't too large for absolute size of + // screen + cmp #24 + bcc !+ + lda #24 + sta TBLX +!: + // Make sure Y isn't too much for the screen, taking + // into account the line link table + ldy #24 // max allowable line + ldx #0 +link_count_loop: + lda LDTBL,x + bpl !+ + dey +!: inx + cpx #25 + bne link_count_loop + tya + cmp TBLX + bcs y_ok + sta TBLX +y_ok: + rts + +add_40_to_screen_x: + lda PNTR + clc + adc #40 + sta PNTR + rts diff --git a/c64/kernal/screen/screen_scroll_up_if_on_last_line.s b/c64/kernal/screen/screen_scroll_up_if_on_last_line.s new file mode 100644 index 00000000..8f8281b9 --- /dev/null +++ b/c64/kernal/screen/screen_scroll_up_if_on_last_line.s @@ -0,0 +1,115 @@ + +not_last_line: + rts + +screen_scroll_up_if_on_last_line: + + // Colour RAM is always in fixed place, so is easiest + // to use to check if we are on the last line. + // The last line is at $D800 + 24*40 = $DBC0 + lda USER+1 + cmp #>$DBC0 + bne not_last_line + + lda USER+0 + cmp #<$DBC0 + beq is_last_line + + jsr screen_get_current_line_logical_length + clc + adc USER+0 + cmp #<$DBE7-1 + bcc not_last_line + +is_last_line: + + dec TBLX + + // FALLTHROUGH + +scroll_screen_up: + // Now scroll the whole screen up either one or two lines + // based on whether the first screen line is linked or not. + + // Get pointers to start of screen + colour RAM + lda HIBASE + sta PNT+1 + sta SAL+1 + lda #>$D800 + sta USER+1 + sta EAL+1 + lda #$00 + sta PNT+0 + sta USER+0 + + // Get pointers to screen/colour RAM source + lda LDTBL+0 + bmi !+ + lda #40 + .byte $2C // BIT $nnnn to skip next instruction +!: + lda #80 + sta SAL+0 + sta EAL+0 + + // Copy first three pages + ldy #$00 + ldx #3 +scroll_copy_loop: + lda (EAL),y + sta (USER),y + lda (SAL),y + sta (PNT),y + + iny + bne scroll_copy_loop + + inc SAL+1 + inc PNT+1 + inc EAL+1 + inc USER+1 + dex + bne scroll_copy_loop + + // Copy last partial page + // We need to copy 1000-(3*256)-line length + // = 232 - line length + lda SAL+0 + lda #232 + sec + sbc SAL+0 + tax +scroll_copy_loop2: + lda (EAL),y + sta (USER),y + lda (SAL),y + sta (PNT),y + iny + dex + bne scroll_copy_loop2 + + // Fill in scrolled up area + ldx SAL+0 +scroll_copy_loop3: + lda COLOR + sta (USER),y + lda #$20 + sta (PNT),y + iny + dex + bne scroll_copy_loop3 + + // Shift line linkage list + ldy #0 + ldx #24 +link_copy: + lda LDTBL+1,y + sta LDTBL+0,y + iny + dex + bne link_copy + // Clear line link flag of last line + stx LDTBL+24 + + // Restore correct line pointers + jmp screen_calculate_line_pointer diff --git a/c64/kernal/set_pointer_to_current_screen_line.s b/c64/kernal/set_pointer_to_current_screen_line.s deleted file mode 100644 index a6edef4c..00000000 --- a/c64/kernal/set_pointer_to_current_screen_line.s +++ /dev/null @@ -1,34 +0,0 @@ - // Put the address of the screen current line - // into the pointer at $D1 (PNT). - // It must take into account the screen line link table - // (Compute's Mapping the 64 p216) -set_pointer_to_current_screen_line: - // Get pointer to start of the screen - lda HIBASE - sta PNT+1 - lda #$00 - sta PNT+0 - - // Now advance for the number of lines - ldx TBLX - -sptcsl_l2: - // XXX - Should we read the columns per line from - // somewhere? - ldy #<40 - // Double line length if line is linked - lda LDTBL,x - bpl sptcsl_l1 - ldy #<80 -sptcsl_l1: - tya - clc - adc PNT+0 - lda PNT+1 - adc #>40 - sta PNT+1 - - dex - bpl sptcsl_l2 - - rts diff --git a/c64/kernal/stubs/e566.home_cursor.s b/c64/kernal/stubs/e566.home_cursor.s new file mode 100644 index 00000000..4e5b7d5f --- /dev/null +++ b/c64/kernal/stubs/e566.home_cursor.s @@ -0,0 +1,4 @@ + +// XXX provide documentation and implementation + + STUB_IMPLEMENTATION() diff --git a/c64/kernal/stubs/e566.interop b/c64/kernal/stubs/e566.interop new file mode 100644 index 00000000..0d7630ac --- /dev/null +++ b/c64/kernal/stubs/e566.interop @@ -0,0 +1,5 @@ + +This is a well-known address, needed even for some BASIC programming - it's a common target for a SYS command. See for example here: + +- http://ready64.org/articoli/_files/043_pokesc64.txt + sys 58726 - CLR/HOME diff --git a/c64/kernal/stubs/e6b6.advance_cursor.s b/c64/kernal/stubs/e6b6.advance_cursor.s new file mode 100644 index 00000000..4e5b7d5f --- /dev/null +++ b/c64/kernal/stubs/e6b6.advance_cursor.s @@ -0,0 +1,4 @@ + +// XXX provide documentation and implementation + + STUB_IMPLEMENTATION() diff --git a/c64/kernal/stubs/e6b6.interop b/c64/kernal/stubs/e6b6.interop new file mode 100644 index 00000000..3c127ba7 --- /dev/null +++ b/c64/kernal/stubs/e6b6.interop @@ -0,0 +1,5 @@ + +This is a well-known address, needed even for some BASIC programming - it's a common target for a SYS command. See for example here: + +- http://ready64.org/articoli/_files/043_pokesc64.txt + sys 59062 - Advance Cursor diff --git a/c64/kernal/stubs/e701.interop b/c64/kernal/stubs/e701.interop new file mode 100644 index 00000000..89b3c8a9 --- /dev/null +++ b/c64/kernal/stubs/e701.interop @@ -0,0 +1,5 @@ + +This is a well-known address, needed even for some BASIC programming - it's a common target for a SYS command. See for example here: + +- http://ready64.org/articoli/_files/043_pokesc64.txt + sys 59137 - Previous Line diff --git a/c64/kernal/stubs/e701.previous_line.s b/c64/kernal/stubs/e701.previous_line.s new file mode 100644 index 00000000..4e5b7d5f --- /dev/null +++ b/c64/kernal/stubs/e701.previous_line.s @@ -0,0 +1,4 @@ + +// XXX provide documentation and implementation + + STUB_IMPLEMENTATION() diff --git a/c64/kernal/stubs/e716.chrout_screen.s b/c64/kernal/stubs/e716.chrout_screen.s new file mode 100644 index 00000000..423ed67b --- /dev/null +++ b/c64/kernal/stubs/e716.chrout_screen.s @@ -0,0 +1,4 @@ + +// Screen CHROUT + + STUB_IMPLEMENTATION() diff --git a/c64/kernal/stubs/e716.interop b/c64/kernal/stubs/e716.interop new file mode 100644 index 00000000..b47324fd --- /dev/null +++ b/c64/kernal/stubs/e716.interop @@ -0,0 +1,3 @@ + +This routine is called at least by the Final Cartridge III. See: +- https://github.com/mist64/final_cartridge/blob/master/core/kernal_c64.i diff --git a/c64/kernal/stubs/e8ea.interop b/c64/kernal/stubs/e8ea.interop new file mode 100644 index 00000000..fa5c0c1b --- /dev/null +++ b/c64/kernal/stubs/e8ea.interop @@ -0,0 +1,5 @@ + +This is a well-known address, needed even for some BASIC programming - it's a common target for a SYS command. See for example here: + +- http://ready64.org/articoli/_files/043_pokesc64.txt + sys 59626 - Scrolls a Line diff --git a/c64/kernal/stubs/e8ea.scroll_line.s b/c64/kernal/stubs/e8ea.scroll_line.s new file mode 100644 index 00000000..4e5b7d5f --- /dev/null +++ b/c64/kernal/stubs/e8ea.scroll_line.s @@ -0,0 +1,4 @@ + +// XXX provide documentation and implementation + + STUB_IMPLEMENTATION() diff --git a/c64/kernal/stubs/e96c.insert_line_at_top.s b/c64/kernal/stubs/e96c.insert_line_at_top.s new file mode 100644 index 00000000..f28c13c4 --- /dev/null +++ b/c64/kernal/stubs/e96c.insert_line_at_top.s @@ -0,0 +1,4 @@ + +// Insert line at top of screen + + STUB_IMPLEMENTATION() diff --git a/c64/kernal/stubs/e96c.interop b/c64/kernal/stubs/e96c.interop new file mode 100644 index 00000000..b47324fd --- /dev/null +++ b/c64/kernal/stubs/e96c.interop @@ -0,0 +1,3 @@ + +This routine is called at least by the Final Cartridge III. See: +- https://github.com/mist64/final_cartridge/blob/master/core/kernal_c64.i diff --git a/c64/kernal/stubs/e9ff.clear_line.s b/c64/kernal/stubs/e9ff.clear_line.s new file mode 100644 index 00000000..4e5b7d5f --- /dev/null +++ b/c64/kernal/stubs/e9ff.clear_line.s @@ -0,0 +1,4 @@ + +// XXX provide documentation and implementation + + STUB_IMPLEMENTATION() diff --git a/c64/kernal/stubs/e9ff.interop b/c64/kernal/stubs/e9ff.interop new file mode 100644 index 00000000..107072db --- /dev/null +++ b/c64/kernal/stubs/e9ff.interop @@ -0,0 +1,5 @@ + +This is a well-known address, needed even for some BASIC programming - it's a common target for a SYS command. See for example here: + +- http://ready64.org/articoli/_files/043_pokesc64.txt + sys 59903 - Clears Line of Text diff --git a/c64/kernal/stubs/f646.iec_close.s b/c64/kernal/stubs/f646.iec_close.s new file mode 100644 index 00000000..d4d05036 --- /dev/null +++ b/c64/kernal/stubs/f646.iec_close.s @@ -0,0 +1,5 @@ + + +// IEC close + + STUB_IMPLEMENTATION() diff --git a/c64/kernal/stubs/f646.interop b/c64/kernal/stubs/f646.interop new file mode 100644 index 00000000..b47324fd --- /dev/null +++ b/c64/kernal/stubs/f646.interop @@ -0,0 +1,3 @@ + +This routine is called at least by the Final Cartridge III. See: +- https://github.com/mist64/final_cartridge/blob/master/core/kernal_c64.i diff --git a/c64/kernal/stubs/fd90.interop b/c64/kernal/stubs/fd90.interop new file mode 100644 index 00000000..28ecfca7 --- /dev/null +++ b/c64/kernal/stubs/fd90.interop @@ -0,0 +1,4 @@ + +This routine is probably used by many cartridges and other software to initialize parts of the system. At least the UCart uses it - see here: + +- https://www.elektroda.pl/rtvforum/topic3293027.html diff --git a/c64/kernal/stubs/fd90.unknown.s b/c64/kernal/stubs/fd90.unknown.s new file mode 100644 index 00000000..4e5b7d5f --- /dev/null +++ b/c64/kernal/stubs/fd90.unknown.s @@ -0,0 +1,4 @@ + +// XXX provide documentation and implementation + + STUB_IMPLEMENTATION() diff --git a/c64/kernal/udtim.s b/c64/kernal/udtim.s deleted file mode 100644 index 2d8aac00..00000000 --- a/c64/kernal/udtim.s +++ /dev/null @@ -1,53 +0,0 @@ - -// -// Official Kernal routine, described in: -// -// - [RG64] C64 Programmer's Reference Guide - page 303 -// - [CM64] Compute's Mapping the Commodore 64 - page 232 -// -// CPU registers that has to be preserved (see [RG64]): .Y -// - -UDTIM: - - // Update jiffy clock. The whole day is $4F1A00 jiffies (24 hours * 60 minutes * 60 seconds * 60 jiffies), - // after this time we have to reset the clock. - - inc TIME+0 - bne udtim_update_stkey // done with clock - inc TIME+1 - bne udtim_clock_rollover - inc TIME+2 - - // FALLTROUGH - -udtim_update_stkey: // entry to be used when interrupts are disabled - - // Another action we have to perform is to copy the last row of keyboard to RAM, - // so that various routines can detect the STOP key press - // XXX scnkey contains similar sequence - deduplicate this! - lda #$FF - sta CIA1_DDRA // output - lda #$00 - sta CIA1_DDRB // input - - lda #$7F - sta CIA1_PRA // select the last row (bit to 0) - - lda CIA1_PRB // read the row - sta STKEY - rts - -udtim_clock_rollover: - - // At this point TIME+0 contains 0 - lda TIME+1 - cmp #$1A - bne udtim_update_stkey // done with clock - lda TIME+2 - cmp #$4F - bne udtim_update_stkey // done with clock - lda #$00 - sta TIME+2 - sta TIME+1 - beq udtim_update_stkey // done with clock - will always jump diff --git a/src/build_segment.cc b/src/build_segment.cc index 9c55842e..97614123 100644 --- a/src/build_segment.cc +++ b/src/build_segment.cc @@ -3,6 +3,8 @@ // source files, placing routines where they need to live // +#include "common.h" + #include #include #include @@ -13,19 +15,11 @@ #include #include #include -#include -#include #include #include #include #include -#if defined(WIN32) || defined(_WIN32) - #define DIR_SEPARATOR "\\" -#else - #define DIR_SEPARATOR "/" -#endif - const std::string ASM_CMD = "java -jar "; const std::string LAB_OUT_START = "__routine_START_"; @@ -33,8 +27,6 @@ const std::string LAB_OUT_END = "__routine_END_"; const std::string LAB_IN_START = ".label __routine_START_"; const std::string LAB_IN_END = ".label __routine_END_"; -const std::string BANNER_LINE = "//-------------------------------------------------------------------------------------------"; - // // Command line settings // @@ -53,17 +45,6 @@ std::list CMD_inList; // Common helper functions // -void ERROR() -{ - exit(-1); -} - -void ERROR(const std::string &message) -{ - std::cout << "\n" << "ERROR: " << message << "\n\n"; - exit(-1); -} - void printUsage() { std::cout << "\n" << @@ -73,16 +54,6 @@ void printUsage() " " << "\n\n"; } -void printBannerLineTop() -{ - std::cout << "\n\n\n" << BANNER_LINE << "\n"; -} - -void printBannerLineBottom() -{ - std::cout << BANNER_LINE << "\n\n"; -} - void printBannerCollectAnalyse() { printBannerLineTop(); @@ -101,24 +72,6 @@ void printBannerBinCompile() // Class definitions // -class DualStream -{ -public: - DualStream(std::ostream& str1, std::ostream& str2) : str1(str1), str2(str2) {} - - template DualStream &operator<<(const T& x) - { - str1 << x; - str2 << x; - - return *this; - } - -private: - std::ostream& str1; - std::ostream& str2; -}; - class SourceFile { public: @@ -764,7 +717,7 @@ void BinningProblem::fillGap(DualStream &logOutput, int gapAddress, const std::l } else if (!isSolved()) { - logOutput << "filled in - dropped bytes: " << gaps[gapAddress] << "\n"; + logOutput << "filled in - dropped bytes: " << gaps[gapAddress] - offset << "\n"; } else { diff --git a/src/common.h b/src/common.h new file mode 100644 index 00000000..861d6f0e --- /dev/null +++ b/src/common.h @@ -0,0 +1,58 @@ +// +// Common parts of utilities written in C++ +// for providing uniform user experience +// + +#include +#include + + +#if defined(WIN32) || defined(_WIN32) + #define DIR_SEPARATOR "\\" +#else + #define DIR_SEPARATOR "/" +#endif + + +const std::string BANNER_LINE = "//-------------------------------------------------------------------------------------------"; + + +void ERROR() +{ + exit(-1); +} + +void ERROR(const std::string &message) +{ + std::cout << "\n" << "ERROR: " << message << "\n\n"; + exit(-1); +} + +void printBannerLineTop() +{ + std::cout << "\n\n\n" << BANNER_LINE << "\n"; +} + +void printBannerLineBottom() +{ + std::cout << BANNER_LINE << "\n\n"; +} + + +class DualStream +{ +public: + DualStream(std::ostream& str1, std::ostream& str2) : str1(str1), str2(str2) {} + + template DualStream &operator<<(const T& x) + { + str1 << x; + str2 << x; + + return *this; + } + +private: + std::ostream& str1; + std::ostream& str2; +}; diff --git a/src/compress_text.c b/src/compress_text.c index 85a62d06..fcfc7dca 100644 --- a/src/compress_text.c +++ b/src/compress_text.c @@ -159,15 +159,13 @@ char *error_list[]={ "LOAD", // https://www.discogs.com/Gimmik-Load-Error/release/482462 // Non-error messages "READY.\r", // #29 // https://www.ibm.com/support/knowledgecenter/zosbasics/com.ibm.zos.zconcepts/zconc_whatistsonative.htm https://github.com/stefanhaustein/expressionparser - "NTSC, ", // #30 - "PAL, ", // #31 - "BREAK AT $", // #32 + "BREAK", // #30 + " IN ", // #31 + "BRK AT $", // #32 "ERROR", // #33 // Simply the word error that is attached to the other parts of messages https://fjkraan.home.xs4all.nl/comp/apple2faq/app2asoftfaq.html - "BYTES FREE\r\r", // #34 // https://github.com/stefanhaustein/expressionparser + " BASIC BYTES FREE", // #34 // https://github.com/stefanhaustein/expressionparser "MEMORY CORRUPT", // #35 "NOT IMPLEMENTED", // #36 - " IN ", // #37 - "BREAK", // #38 NULL}; // XXX: create separate list for Kernal diff --git a/src/release.cc b/src/release.cc new file mode 100644 index 00000000..af3144e9 --- /dev/null +++ b/src/release.cc @@ -0,0 +1,538 @@ +// +// Utility to prepare a release with automatically +// assigned version numbers +// + +#include "common.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +typedef struct +{ + std::string romTypeName; + size_t fileSize; + size_t signatureOffset; // offset to 'OR' string + bool requireIdBASIC; + bool requireIdKERNAL; + +} ROMTypeDescriptionEntry; + +const std::vector ROM_DEFINITIONS = +{ + { + "BASIC", + 8192, // file size + 0x1F52, // signature offset + true, // whether to require BASIC ID + false // whether to require KERNAL ID + }, + + { + "KERNAL", + 8192, // file size + 0x04B9, // signature offset + false, // whether to require BASIC ID + false // whether to require KERNAL ID + }, +}; + +const uint16_t MAX_FILE_SIZE = 8192; + +const std::vector STR_MEGABAS = { 0x4D, 0x45, 0x47, 0x41, 0x42, 0x41, 0x53, 0x32 }; +const std::vector STR_OR = { 0x4F, 0x52 }; +const std::vector STR_SNAPSHOT = { 0x28, 0x44, 0x45, 0x56, 0x45, 0x4C, 0x20, 0x53, + 0x4E, 0x41, 0x50, 0x53, 0x48, 0x4F, 0x54, 0x29, + 0x00 }; + +const std::string STR_DEV = "DEV."; + +// +// Command and enviroment line settings +// + +std::string CMD_inDir = "./build"; +std::string CMD_outDir = "./bin"; + +std::list CMD_fileList; + +std::string ENV_developerId; +std::string ENV_dateString; + +// +// Common helper functions +// + +void printUsage() +{ + std::cout << "\n" << + "usage: release [-i ] [-o ]" << "\n" << + " " << "\n\n"; +} + +// +// Class definitions +// + +class ROMFile +{ +public: + + ROMFile(const std::string &baseFileName); + + void embedRevisionStr(const std::string &newRevisionStr); + void save(); + + const ROMTypeDescriptionEntry *descPtr; + + bool sameContent; + bool sameDeveloper; + bool sameDate; // only set if sameDeveloper + uint8_t oldDailyRelId; // only set if sameDeveloper and sameDate + +private: + + void readSrcFile(); + void readDstFile(); + + void recognizeSrcFile(); + void dropUnmatchingDst(); + void analyzeContent(); + + std::string baseFileName; + + std::vector srcFileContent; + std::vector dstFileContent; +}; + +// +// Global variables +// + +size_t GLOBAL_maxFileNameLen = 0; +std::list GLOBAL_ROMFiles; + +// +// Top-level functions +// + +void parseCommandLine(int argc, char **argv) +{ + int opt; + + // Retrieve command line options + + while ((opt = getopt(argc, argv, "i:o:")) != -1) + { + switch(opt) + { + case 'i': CMD_inDir = optarg; break; + case 'o': CMD_outDir = optarg; break; + default: printUsage(); ERROR(); + } + } + + // Retrieve file/directory list + + for (int idx = optind; idx < argc; idx++) + { + CMD_fileList.push_back(argv[idx]); + } + + if (CMD_fileList.empty()) { printUsage(); ERROR("empty file list"); } +} + +void getDeveloperId() +{ + const char* id = getenv("OPEN_ROMS_DEVELOPER_ID"); + + // Check whether the developer ID is suitable + + if (id == nullptr) + { + ERROR("environment variable OPEN_ROMS_DEVELOPER_ID not set"); + } + + ENV_developerId = id; + + if (ENV_developerId.length() < 2 || ENV_developerId.length() > 3) + { + ERROR("OPEN_ROMS_DEVELOPER_ID has to be 2 or 3 characters long"); + } + + for (const char &c : ENV_developerId) + { + if (!(c >= 'A' && c <= 'Z')) + { + ERROR("OPEN_ROMS_DEVELOPER_ID can only contain uppercase letters"); + } + } +} + +void getDate() +{ + time_t t = time(NULL); + struct tm tm = *localtime(&t); + + const std::string year = std::to_string(tm.tm_year % 100); + const std::string month = std::to_string(tm.tm_mon + 1); + const std::string day = std::to_string(tm.tm_mday); + + const std::string zero = "0"; + + ENV_dateString = (year.size() == 2 ? year : zero + year) + + (month.size() == 2 ? month : zero + month) + + (day.size() == 2 ? day : zero + day); + + if (ENV_dateString.size() != 6) ERROR("could not retrieve date"); +} + +void printBanner() +{ + printBannerLineTop(); + std::cout << "// Preparing ROM set release" << "\n"; + printBannerLineBottom(); +} + +void readFiles() +{ + for (auto &fileName : CMD_fileList) GLOBAL_ROMFiles.push_back(ROMFile(fileName)); +} + +void decideIfUpdate() +{ + // Check if we have any file at all + + if (GLOBAL_ROMFiles.empty()) + { + ERROR("no files to update"); + } + + // Check if we have at least one file with changed content + + bool sameContent = true; + for (auto &file : GLOBAL_ROMFiles) + { + if (!file.sameContent) + { + sameContent = false; + break; + } + } + + if (sameContent) + { + ERROR("same content in all the files"); + } +} + +void saveFiles() +{ + // Determine a daily revision sequence ID + + uint8_t relId = 0; + for (auto &file : GLOBAL_ROMFiles) + { + if (file.sameDeveloper && file.sameDate) + { + relId = std::max(file.oldDailyRelId, relId); + } + } + relId++; + + if (relId > 9) + { + ERROR("too many releases this day"); + } + + // Create a new revision string + + const std::string newRevStr = STR_DEV + ENV_dateString + "." + ENV_developerId + "." + std::to_string(relId); + + for (auto &file : GLOBAL_ROMFiles) + { + file.embedRevisionStr(newRevStr); + } + + std::cout << "Files for release '" << newRevStr << "':\n\n"; + + // Save the files + + for (auto &file : GLOBAL_ROMFiles) + { + file.save(); + } +} + +// +// Main function +// + +int main(int argc, char **argv) +{ + parseCommandLine(argc, argv); + getDeveloperId(); + getDate(); + + printBanner(); + + readFiles(); + decideIfUpdate(); + saveFiles(); + + std::cout << "\n"; + + return 0; +} + +// +// Class 'ROMFile' +// + +ROMFile::ROMFile(const std::string &baseFileName) : + descPtr(nullptr), + sameContent(false), + sameDeveloper(false), + sameDate(false), + oldDailyRelId(0), + baseFileName(baseFileName) +{ + GLOBAL_maxFileNameLen = std::max(GLOBAL_maxFileNameLen, baseFileName.length()); + + readSrcFile(); + readDstFile(); + + recognizeSrcFile(); + dropUnmatchingDst(); + analyzeContent(); +} + +void ROMFile::readSrcFile() +{ + // Read the source file + + const std::string srcFileNamePath = CMD_inDir + DIR_SEPARATOR + baseFileName; + + std::ifstream srcFile; + srcFile.open(srcFileNamePath, std::ios::in | std::ios::binary | std::ios::ate); + + if (!srcFile.good()) ERROR(std::string("unable to open ROM file '") + srcFileNamePath + "'"); + + auto srcSize = srcFile.tellg(); + if (srcSize > MAX_FILE_SIZE) ERROR(std::string("incorrect size of ROM file '") + srcFileNamePath + "'"); + + srcFileContent.resize(srcSize); + srcFile.seekg (0, srcFile.beg); + srcFile.read((char *) srcFileContent.data(), srcFileContent.size()); + + if (!srcFile.good()) ERROR(std::string("unable to read ROM file '") + srcFileNamePath + "'"); + srcFile.close(); +} + +void ROMFile::readDstFile() +{ + // Read the destination file (if exists and it's size matches) + + const std::string dstFileNamePath = CMD_outDir + DIR_SEPARATOR + baseFileName; + + std::ifstream dstFile; + dstFile.open(dstFileNamePath, std::ios::in | std::ios::binary | std::ios::ate); + + bool continueReading = dstFile.good(); + + if (continueReading && dstFile.tellg() != unsigned(srcFileContent.size())) continueReading = false; + + if (continueReading) + { + dstFileContent.resize(srcFileContent.size()); + dstFile.seekg (0, dstFile.beg); + dstFile.read((char *) dstFileContent.data(), dstFileContent.size()); + } + + if (!dstFile.good()) dstFileContent.clear(); + dstFile.close(); +} + +void ROMFile::recognizeSrcFile() +{ + // Recognize source file type + + for (auto &SPEC : ROM_DEFINITIONS) + { + if (srcFileContent.size() != SPEC.fileSize) continue; + + if (SPEC.requireIdBASIC && memcmp(&srcFileContent[0x0004], STR_MEGABAS.data(), STR_MEGABAS.size()) != 0) + { + continue; + } + + if (SPEC.requireIdKERNAL && srcFileContent[0x1F80] != 0xF0) + { + continue; + } + + if (memcmp(&srcFileContent[SPEC.signatureOffset], STR_OR.data(), STR_OR.size()) != 0) + { + continue; + } + + auto snapshotStrOffset = SPEC.signatureOffset + STR_OR.size() + 1; + if (memcmp(&srcFileContent[snapshotStrOffset], STR_SNAPSHOT.data(), STR_SNAPSHOT.size()) != 0) + { + continue; + } + + auto zeroByteoffset = snapshotStrOffset + 0x10; + if (srcFileContent[zeroByteoffset] != 0) + { + continue; + } + + descPtr = &SPEC; + break; + } + + if (descPtr == nullptr) + { + ERROR(std::string("'") + CMD_inDir + DIR_SEPARATOR + baseFileName + + "' is not a supported unversioned Open ROMs image"); + } +} + +void ROMFile::dropUnmatchingDst() +{ + // Drop unmatching destination file data + + if (!dstFileContent.empty() && descPtr->requireIdBASIC && + memcmp(&dstFileContent[0x0004], STR_MEGABAS.data(), STR_MEGABAS.size()) != 0) + { + dstFileContent.clear(); + } + + if (!dstFileContent.empty() && descPtr->requireIdKERNAL && dstFileContent[0x1F80] != 0xF0) + { + dstFileContent.clear(); + } + + if (!dstFileContent.empty() && + memcmp(&dstFileContent[descPtr->signatureOffset], STR_OR.data(), STR_OR.size()) != 0) + { + dstFileContent.clear(); + } +} + +void ROMFile::analyzeContent() +{ + auto revOffset = descPtr->signatureOffset + 3; + + if (dstFileContent.empty()) + { + return; + } + + // Check if meaningful file content is really different + + if ((memcmp(&srcFileContent[0x0000], &dstFileContent[0x0000], revOffset) == 0) && + (memcmp(&srcFileContent[revOffset + 0x10], &dstFileContent[revOffset + 0x10], + descPtr->fileSize - revOffset - 0x10) == 0)) + { + sameContent = true; + } + + // Determine expected length of developer ID + + uint8_t devIdLen = ENV_developerId.length(); + + // Determine if old version is a devel version compatible with this tool + + if (memcmp(&dstFileContent[revOffset], STR_DEV.data(), STR_DEV.size()) != 0) + { + return; + } + + uint16_t idxDate = revOffset + STR_DEV.size(); + uint16_t idxLimit = idxDate + ENV_dateString.length(); + + uint16_t idx = idxDate; + for (; idx < idxLimit; idx++) + { + if (dstFileContent[idx] < '0' || dstFileContent[idx] > '9') + { + return; + } + } + + if (dstFileContent[idx] != '.' || + dstFileContent[idx + devIdLen + 1] != '.' || + dstFileContent[idx + devIdLen + 2] < '0' || + dstFileContent[idx + devIdLen + 2] > '9' || + dstFileContent[idx + devIdLen + 3] != 0) + { + return; + } + + // Retrieve release data + + if (memcmp(&dstFileContent[idx + 1], ENV_developerId.data(), ENV_developerId.size()) != 0) + { + return; // different developer + } + + sameDeveloper = true; + + if (memcmp(&dstFileContent[idxDate], ENV_dateString.data(), ENV_dateString.size()) != 0) + { + return; // different date + } + + sameDate = true; + oldDailyRelId = dstFileContent[idx + devIdLen + 2] - '0'; +} + +void ROMFile::embedRevisionStr(const std::string &newRevisionStr) +{ + std::string revStr = newRevisionStr; + + while (revStr.length() < 16) revStr = revStr + '\0'; + + memcpy(&srcFileContent[descPtr->signatureOffset + 3], + revStr.data(), revStr.size()); +} + +void ROMFile::save() +{ + const std::string outFileNamePath = CMD_outDir + DIR_SEPARATOR + baseFileName; + + // Print out file name and metadata + + std::string spacing; + spacing.resize(GLOBAL_maxFileNameLen + 4 - baseFileName.length(), ' '); + + std::cout << " " << outFileNamePath << spacing << descPtr->romTypeName; + + if (sameContent) + { + spacing.resize(10 - descPtr->romTypeName.length()); + std::cout << spacing << "(unchanged)"; + } + + std::cout << "\n"; + + std::ofstream outFile; + outFile.open(outFileNamePath, std::ios::out | std::ios::binary | std::ios::trunc); + + if (!outFile.good()) ERROR(std::string("unable to open output file '") + outFileNamePath + "'"); + + outFile.write((char *) srcFileContent.data(), srcFileContent.size()); + + if (!outFile.good()) ERROR(std::string("unable to write file '") + outFileNamePath + "'"); + outFile.close(); +} diff --git a/strings/008D9102 b/strings/008D9102 new file mode 100644 index 00000000..7ed9bd93 --- /dev/null +++ b/strings/008D9102 @@ -0,0 +1,3 @@ +$00 + STA $0291 + +Instruction (storing data in a documented location) and a part. Not copyrightable. diff --git a/strings/009D0002 b/strings/009D0002 new file mode 100644 index 00000000..ddb5420f --- /dev/null +++ b/strings/009D0002 @@ -0,0 +1,3 @@ +$00 + STA $0200,X + +Instruction (storing data in a documented location) and a part. Not copyrightable. diff --git a/strings/028C8202 b/strings/028C8202 new file mode 100644 index 00000000..9a916a11 --- /dev/null +++ b/strings/028C8202 @@ -0,0 +1,3 @@ +$02 + STY $0282 + +Instruction (storing data in a well-known location) + some part. Trivial, not copyrightable. diff --git a/strings/028C8402 b/strings/028C8402 new file mode 100644 index 00000000..24ced153 --- /dev/null +++ b/strings/028C8402 @@ -0,0 +1,3 @@ +$02 + STY $0284 + +Instruction (storing data in a documented location) and a part. Not copyrightable. diff --git a/strings/028D18D04C b/strings/028D18D04C new file mode 100644 index 00000000..7afc5a69 --- /dev/null +++ b/strings/028D18D04C @@ -0,0 +1,3 @@ +$02 + STA $D018 + JMP (addres does not match) + +One instruction (storing data in a docummented I/O register) + some parts. Not copyrightable. diff --git a/strings/028E8102 b/strings/028E8102 new file mode 100644 index 00000000..bfb09227 --- /dev/null +++ b/strings/028E8102 @@ -0,0 +1,3 @@ +$02 + STX $0281 + +Instruction (storing data in a documented location) and a part. Not copyrightable. diff --git a/strings/0BA90085 b/strings/0BA90085 new file mode 100644 index 00000000..bd9b77af --- /dev/null +++ b/strings/0BA90085 @@ -0,0 +1,3 @@ +$0B + LDA #$00 + STA (zeropage addreess does not match) + +One instruction + some parts. Not copyrightable. diff --git a/strings/13D00620 b/strings/13D00620 new file mode 100644 index 00000000..abb8e442 --- /dev/null +++ b/strings/13D00620 @@ -0,0 +1,3 @@ +$13 + BNE (offset match) + JSR (address does not match) + +Instruction + some parts. Not copyrightable. diff --git a/strings/20000000 b/strings/20000000 new file mode 100644 index 00000000..39095a19 --- /dev/null +++ b/strings/20000000 @@ -0,0 +1 @@ +A byte followed by some 0's - accidental result of ROMs not being full to the last byte. Nothing creative - not copyrightable. diff --git a/strings/204D49534D415443C8 b/strings/204D49534D415443C8 new file mode 100644 index 00000000..24490224 --- /dev/null +++ b/strings/204D49534D415443C8 @@ -0,0 +1,3 @@ +PETSCII: (space) MISMATCH + +Single word with a space character is not copyrightable. What's more, the MISMATCH word in our BASIC is stored in compressed form - this one must come from Kernal, from out 'panic screen' implementation, something not even present in the original ROM. diff --git a/strings/205BFF586C b/strings/205BFF586C new file mode 100644 index 00000000..4b9adedc --- /dev/null +++ b/strings/205BFF586C @@ -0,0 +1,3 @@ +JSR $FF5B (CINT) + CLI + JMP (vector does not match) + +Small part of the initialization routine, basically a sequence of 2 calls. Not creative - not copyrightable. diff --git a/strings/20A0E54C b/strings/20A0E54C new file mode 100644 index 00000000..edc5f21f --- /dev/null +++ b/strings/20A0E54C @@ -0,0 +1,3 @@ +JSR $E5A0 + JMP (address does not match) + +Instruction (call to unofficial, but a well-known routine) + some part. Trivial, not copyrightable. diff --git a/strings/29EF8D00DD b/strings/29EF8D00DD new file mode 100644 index 00000000..23471546 --- /dev/null +++ b/strings/29EF8D00DD @@ -0,0 +1,5 @@ +AND #$EF + STA $DD00 + +$DD00 is a hardware register, where one typically set/unset/read individual bits. +Having a set of trivial helper subroutines to set/clear individual bits (or groups of bits) is an obvious solution (thus not copyrightable), some similarities are unevitable. +Besides, in this case (since the similarity does not even cover a single subroutine from start to end) it is clear that the similar code actually performs slightly different actions. diff --git a/strings/49432042 b/strings/49432042 new file mode 100644 index 00000000..b61392d7 --- /dev/null +++ b/strings/49432042 @@ -0,0 +1,3 @@ +PETSCII: IC (space) B + +Short text fragment, not even a full syllable. Not copyrightable. diff --git a/strings/4C25FE4C b/strings/4C25FE4C new file mode 100644 index 00000000..fa745bee --- /dev/null +++ b/strings/4C25FE4C @@ -0,0 +1,3 @@ +JMP $FE25 (MEMTOP) + JMP (address doees not match) + +Very small part of Kernal jumptable - part of Kernal API, list of facts without any logic (see also fe25.interop). Not copyrightable. diff --git a/strings/6020A0E5 b/strings/6020A0E5 new file mode 100644 index 00000000..a44b9d86 --- /dev/null +++ b/strings/6020A0E5 @@ -0,0 +1,3 @@ +RTS (end of routine) + JSR $E5A0 (setup VIC and I/O) + +Similarity only because a routine starts with video chipset initialization - trivial, not copyrightable. diff --git a/strings/7BA9FF85 b/strings/7BA9FF85 new file mode 100644 index 00000000..acd243cc --- /dev/null +++ b/strings/7BA9FF85 @@ -0,0 +1,3 @@ +$7B + LDA #$FF + STA (zeropage address does not match) + +One instruction + some parts. Not copyrightable. diff --git a/strings/80000000 b/strings/80000000 new file mode 100644 index 00000000..39095a19 --- /dev/null +++ b/strings/80000000 @@ -0,0 +1 @@ +A byte followed by some 0's - accidental result of ROMs not being full to the last byte. Nothing creative - not copyrightable. diff --git a/strings/8000000000 b/strings/8000000000 new file mode 100644 index 00000000..39095a19 --- /dev/null +++ b/strings/8000000000 @@ -0,0 +1 @@ +A byte followed by some 0's - accidental result of ROMs not being full to the last byte. Nothing creative - not copyrightable. diff --git a/strings/81028C8202 b/strings/81028C8202 new file mode 100644 index 00000000..6b2ce942 --- /dev/null +++ b/strings/81028C8202 @@ -0,0 +1,3 @@ +$0281 + STY $0282 + +Instruction (storing data in a documented location) and a part. Not copyrightable. diff --git a/strings/857AA52C b/strings/857AA52C new file mode 100644 index 00000000..972422ee --- /dev/null +++ b/strings/857AA52C @@ -0,0 +1,3 @@ +STA $7A (TXTPTR low byte) + LDA $2C (TXTAB high byte) + +$7A and $2C are documented zeropage locations, they are related so it's normal that they are read/written one after another. Here the similarity is limited to just 2 instructions (does not even cover full access of the variables) - this is trivial and thus not copyrightable. diff --git a/strings/85F46020 b/strings/85F46020 new file mode 100644 index 00000000..3745a819 --- /dev/null +++ b/strings/85F46020 @@ -0,0 +1,3 @@ +STA $F4 + RTS (end of subroutine) + JSR (address does not match) + +Storing value in a documented memory location, followed by next subroutine started by JSR - not creative, not copyrightable. diff --git a/strings/8D8D02A0 b/strings/8D8D02A0 new file mode 100644 index 00000000..86535945 --- /dev/null +++ b/strings/8D8D02A0 @@ -0,0 +1,3 @@ +STA $028D + LDY #(value does not match) + +Instruction (storing data in a docummented location) + some part. Trivial, not copyrgihtable. diff --git a/strings/8D9002A9 b/strings/8D9002A9 new file mode 100644 index 00000000..0c47ce26 --- /dev/null +++ b/strings/8D9002A9 @@ -0,0 +1,3 @@ +STA $0290 + LDA (value does not match) + +Instruction (storing data in a documented location) and a part. Not copyrightable. diff --git a/strings/8D91024C b/strings/8D91024C new file mode 100644 index 00000000..54ac819b --- /dev/null +++ b/strings/8D91024C @@ -0,0 +1,3 @@ +STA $0291 + JMP (address does not match) + +Instruction (storing data in a well-known location) + some part. Trivial, not copyrightable. diff --git a/strings/8E03DC8E b/strings/8E03DC8E new file mode 100644 index 00000000..efbed2ba --- /dev/null +++ b/strings/8E03DC8E @@ -0,0 +1,3 @@ +STX $DC03 + STX (address does not match) + +Instruction (storing data in a documented location) and a part. Not copyrightable. diff --git a/strings/A59AC903D0 b/strings/A59AC903D0 new file mode 100644 index 00000000..7f7a8188 --- /dev/null +++ b/strings/A59AC903D0 @@ -0,0 +1,3 @@ +LDA $9A + CMP #$03 + BNE (offset does not match) + +Just a check whether the default output device is screen - trivial, not copyrightable. diff --git a/strings/A68BE383A47CA51AA7E4A786AE b/strings/A68BE383A47CA51AA7E4A786AE new file mode 100644 index 00000000..72f8a1d7 --- /dev/null +++ b/strings/A68BE383A47CA51AA7E4A786AE @@ -0,0 +1,6 @@ +$A6 (part of other compilation unit) + a list of vectors to be copied starting from $0300 + +Values of the vectors are already present in many autostart software - as it often overrides them, +sometimes changing one to trigger autostart (one of the possible techniques). We have to use the same +vector values to be compatible (in fact, it even complicates our implementation) - see *.interop files +for more details. diff --git a/strings/A6D8F0034C b/strings/A6D8F0034C new file mode 100644 index 00000000..d9e0b07c --- /dev/null +++ b/strings/A6D8F0034C @@ -0,0 +1,3 @@ +LDX $D8 + BEQ (skip next instruction) + JMP (address does not match) + +Just a check whether insert mode is active - trivial, not copyrightable. diff --git a/strings/A9802090FF b/strings/A9802090FF new file mode 100644 index 00000000..8757cd5a --- /dev/null +++ b/strings/A9802090FF @@ -0,0 +1,3 @@ +LDA #$80 + JSR $FF90 (SETMSG) + +There are just two standard parameters of SETMSG - $00 and $80 (to tell Kernal wheether to print out messages or not). This is typical call of Kernal API, not copyrightable. diff --git a/strings/ABA000B1 b/strings/ABA000B1 new file mode 100644 index 00000000..57f6b686 --- /dev/null +++ b/strings/ABA000B1 @@ -0,0 +1,3 @@ +$AB + LDY #$00 + LDA (zeropage addres does not match), Y + +Instruction + some parts. Not copyrightable. diff --git a/strings/C903F008 b/strings/C903F008 new file mode 100644 index 00000000..bfaddbf3 --- /dev/null +++ b/strings/C903F008 @@ -0,0 +1,3 @@ +CMP #$03 + BEQ (skip 8 bytes) + +Skip few bytes if accumulator value is 3 - not creative, not copyrightable. diff --git a/strings/C90ED007AD18D00902D0 b/strings/C90ED007AD18D00902D0 new file mode 100644 index 00000000..dff00ea1 --- /dev/null +++ b/strings/C90ED007AD18D00902D0 @@ -0,0 +1,3 @@ +CMP #$0E + BNE (7 bytes forward) + LDA $D018 + ORA #$02 + BNE (offset does not match) + +A piece of code that (depending on the PETSCII character) sets/unsets lowercase mode. Not many sane ways exists to do this, some similarities are unevitable. Overall, this code is trivial (and not even fully the same) - not copyrightable. diff --git a/strings/C912D004A9 b/strings/C912D004A9 new file mode 100644 index 00000000..d15f0f7d --- /dev/null +++ b/strings/C912D004A9 @@ -0,0 +1,3 @@ +CMP #$12 + BNE (skip 4 bytes) + LDA #(value does not match) + +Small part of the PETSCII control codes handling routine - do something if handling character $12 (not even the same thing is done). Not creative - not copyrightable. diff --git a/strings/C913D00620 b/strings/C913D00620 new file mode 100644 index 00000000..df6b9e6c --- /dev/null +++ b/strings/C913D00620 @@ -0,0 +1,3 @@ +CMP #$13 + BNE (skip 6 bytes) + JSR (address does not match) + +Small part of the PETSCII control codes handling routine - do something if handling character $13. Not creative - not copyrightable. diff --git a/strings/C98ED00BAD18D029 b/strings/C98ED00BAD18D029 new file mode 100644 index 00000000..fba842ca --- /dev/null +++ b/strings/C98ED00BAD18D029 @@ -0,0 +1,3 @@ +CMP #$8E + BNE (skip 11 bytes) + LDA $D018 + AND#(value does not match) + +A piece of code that (depending on the PETSCII character) sets/unsets lowercase mode. Not many sane ways exists to do this, some similarities are unevitable. Overall, this code is trivial (and not even fully the same) - not copyrightable. diff --git a/strings/CA8E02DC b/strings/CA8E02DC new file mode 100644 index 00000000..e0240c1e --- /dev/null +++ b/strings/CA8E02DC @@ -0,0 +1,3 @@ +DEX + STX $DC02 + +Optimization to store $FF in I/O register, when X is known to be $00 - trivial, not copyrightable. diff --git a/strings/D0036C0080 b/strings/D0036C0080 new file mode 100644 index 00000000..2ea7d000 --- /dev/null +++ b/strings/D0036C0080 @@ -0,0 +1,3 @@ +BNE (skip 3 bytes) + JMP ($8000) + +Jump through official (documented) vector depending on the flag state, could be 1 instruction in other architectures. Trivial, not copyrightable. diff --git a/strings/D0E4A90085 b/strings/D0E4A90085 new file mode 100644 index 00000000..2821832d --- /dev/null +++ b/strings/D0E4A90085 @@ -0,0 +1,3 @@ +BNE (offset match) + LDA #$00 + STA (zeropage address does not match) + +If value is 0, clear some zeropage addres (not even the same in original ROMs and our implementation). Nothing creative - not copyrightable. diff --git a/strings/D185F3A5 b/strings/D185F3A5 new file mode 100644 index 00000000..40a03bfd --- /dev/null +++ b/strings/D185F3A5 @@ -0,0 +1,3 @@ +$D1 + STA $F3 + LDA (zeropage address does not match) + +Instruction (storing data in a doccumented memory location) + some parts. Not copyrightable. diff --git a/strings/D8F0034C b/strings/D8F0034C new file mode 100644 index 00000000..7689027b --- /dev/null +++ b/strings/D8F0034C @@ -0,0 +1,3 @@ +$D8 + BEQ (skip next instruction) + JMP (address does not match) + +One instruction + some parts. Not copyrightable. diff --git a/strings/DD29EF8D00DD60AD00DD b/strings/DD29EF8D00DD60AD00DD new file mode 100644 index 00000000..44850259 --- /dev/null +++ b/strings/DD29EF8D00DD60AD00DD @@ -0,0 +1,5 @@ +$DD + AND #$EF + STA $DD00 + RTS (end of routine) + LDA $DD00 + +$DD00 is a hardware register, where one typically set/unset/read individual bits. +Having a set of trivial helper subroutines to set/clear individual bits (or groups of bits) is an obvious solution (thus not copyrightable), some similarities are unevitable. +Besides, in this case (since the similarity does not even cover a single subroutine from start to end) it is clear that the similar code actually performs slightly different actions. diff --git a/strings/DD29EF8D00DD60AD00DD09108D00DD b/strings/DD29EF8D00DD60AD00DD09108D00DD new file mode 100644 index 00000000..bd196812 --- /dev/null +++ b/strings/DD29EF8D00DD60AD00DD09108D00DD @@ -0,0 +1,5 @@ +$DD + AND #$EF + STA $DD00 + RTS (end of routine) + LDA $DD00 + ORA #$10 + STA $DD00 + +$DD00 is a hardware register, where one typically set/unset/read individual bits. +Having a set of trivial helper subroutines to set/clear individual bits (or groups of bits) is an obvious solution (thus not copyrightable), some similarities are unevitable. +Besides, in this case (since the similarity does not even cover a single subroutine from start to end) it is clear that the similar code actually performs slightly different actions. diff --git a/strings/DDA93F8D02DD b/strings/DDA93F8D02DD new file mode 100644 index 00000000..42fb9c20 --- /dev/null +++ b/strings/DDA93F8D02DD @@ -0,0 +1,3 @@ +$DD + LDA #$3F + STA $DD02 + +Some part + storing a default value in a documented I/O register - trivial, not copyrightablee. diff --git a/strings/DF8D00DD60 b/strings/DF8D00DD60 new file mode 100644 index 00000000..cfb40212 --- /dev/null +++ b/strings/DF8D00DD60 @@ -0,0 +1,5 @@ +$DF + STA $DD00 + RTS + +$DD00 is a hardware register, where one typically set/unset/read individual bits. +Having a set of trivial helper subroutines to set/clear individual bits (or groups of bits) is an obvious solution (thus not copyrightable), some similarities are unevitable. +Besides, in this case (since the similarity does not even cover a single subroutine from start to end) it is clear that the similar code actually performs slightly different actions. diff --git a/strings/E4A90085 b/strings/E4A90085 new file mode 100644 index 00000000..9c6a0d4f --- /dev/null +++ b/strings/E4A90085 @@ -0,0 +1,3 @@ +$E4 + LDA #$00 + STA (zeropage address does not match) + +Instruction + some parts. Not copyrightable. diff --git a/strings/E9A027B1 b/strings/E9A027B1 new file mode 100644 index 00000000..a541b31c --- /dev/null +++ b/strings/E9A027B1 @@ -0,0 +1,3 @@ +$E9 + LDY #$27 + LDA (zeropage address does not match),Y + +Instruction + some parts. Not copyrightable. diff --git a/strings/EAAD00DD b/strings/EAAD00DD new file mode 100644 index 00000000..444e31fa --- /dev/null +++ b/strings/EAAD00DD @@ -0,0 +1,3 @@ +$EA + LDA $DD00 + +Instruction and some part - trivial, not copyrightable. diff --git a/strings/EAAD00DD29DF b/strings/EAAD00DD29DF new file mode 100644 index 00000000..323da94a --- /dev/null +++ b/strings/EAAD00DD29DF @@ -0,0 +1,5 @@ +$EA + LDA $DD00 + AND #$DF + +$DD00 is a hardware register, where one typically set/unset/read individual bits. +Having a set of trivial helper subroutines to set/clear individual bits (or groups of bits) is an obvious solution (thus not copyrightable), some similarities are unevitable. +Besides, in this case (since the similarity does not even cover a single subroutine from start to end) it is clear that the similar code actually performs slightly different actions. diff --git a/strings/EF8D00DD60AD00DD09108D00DD b/strings/EF8D00DD60AD00DD09108D00DD new file mode 100644 index 00000000..930e2b7f --- /dev/null +++ b/strings/EF8D00DD60AD00DD09108D00DD @@ -0,0 +1,5 @@ +$EF + STA $DD00 + RTS (end of a routine) + LDA $DD00 + ORA #$10 + STA $DD00 + +$DD00 is a hardware register, where one typically set/unset/read individual bits. +Having a set of trivial helper subroutines to set/clear individual bits (or groups of bits) is an obvious solution (thus not copyrightable), some similarities are unevitable. +Besides, in this case (since the similarity does not even cover a single subroutine from start to end) it is clear that the similar code actually performs slightly different actions. diff --git a/strings/F88D00DC b/strings/F88D00DC new file mode 100644 index 00000000..5a861c89 --- /dev/null +++ b/strings/F88D00DC @@ -0,0 +1,3 @@ +$F8 + STA $DC00 + +Instruction (storing data in a documented location) and a part. Not copyrightable. diff --git a/strings/FF000000000000000000000000 b/strings/FF000000000000000000000000 new file mode 100644 index 00000000..39095a19 --- /dev/null +++ b/strings/FF000000000000000000000000 @@ -0,0 +1 @@ +A byte followed by some 0's - accidental result of ROMs not being full to the last byte. Nothing creative - not copyrightable.