From 3766cbc90265f3cd665fc12dcd86587fd3439c1c Mon Sep 17 00:00:00 2001 From: StewBC Date: Thu, 9 Jul 2020 15:46:25 -0700 Subject: [PATCH] Atari Version added Added the Atari platform (tested on 48K Atari 800 - NTSC artifacting used for color) --- Makefile | 5 +- Makefile-atr.mk | 44 ++++ readme.txt | 39 ++-- src/atari/chessAtari.cfg | 62 ++++++ src/atari/dataAtari.c | 318 ++++++++++++++++++++++++++ src/atari/dataAtari.h | 14 ++ src/atari/genpieces.cpp | 319 ++++++++++++++++++++++++++ src/atari/hiresAtari.s | 228 +++++++++++++++++++ src/atari/platAtari.c | 467 +++++++++++++++++++++++++++++++++++++++ 9 files changed, 1478 insertions(+), 18 deletions(-) create mode 100644 Makefile-atr.mk create mode 100644 src/atari/chessAtari.cfg create mode 100644 src/atari/dataAtari.c create mode 100644 src/atari/dataAtari.h create mode 100644 src/atari/genpieces.cpp create mode 100644 src/atari/hiresAtari.s create mode 100644 src/atari/platAtari.c diff --git a/Makefile b/Makefile index 7b9bc0a..c91d8fa 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ # Space or comma separated list of cc65 supported target platforms to build for. # Default: c64 (lowercase!) -TARGETS := apple2 atmos c64 c64.chr cx16 +TARGETS := apple2 atari atmos c64 c64.chr cx16 # Name of the final, single-file executable. # Default: name of the current dir with target name appended @@ -67,6 +67,7 @@ VICE_HOME := CX16_HOME := AWIN_HOME := ORIC_HOME := +ATARI_HOME := # Options state file name. You should not need to change this, but for those # rare cases when you feel you really need to name it differently - here you are @@ -157,7 +158,7 @@ plus4_EMUCMD := $(VICE_HOME)xplus4 -TEDdsize -autoload c16_EMUCMD := $(VICE_HOME)xplus4 -ramsize 16 -TEDdsize -autoload cbm510_EMUCMD := $(VICE_HOME)xcbm2 -model 510 -VICIIdsize -autoload cbm610_EMUCMD := $(VICE_HOME)xcbm2 -model 610 -Crtcdsize -autoload -atari_EMUCMD := atari800 -windowed -xl -pal -nopatchall -run +atari_EMUCMD := $(ATARI_HOME)Altirra64 /defprofile:800 /disk cc65-Chess.atr cx16_EMUCMD := $(CX16_HOME)x16emu -run -prg apple2_EMUCMD := $(AWIN_HOME)AppleWin.exe -d1 atmos_EMUCMD := $(ORIC_HOME)Oricutron.exe -t diff --git a/Makefile-atr.mk b/Makefile-atr.mk new file mode 100644 index 0000000..984927a --- /dev/null +++ b/Makefile-atr.mk @@ -0,0 +1,44 @@ +# If ATARIDOS is commented out, the disk will be MyPicodos 4.05 +# if ATARIDOS is not commented out, set ATARIDOSTYPE to the +# desired type (say Dos25 for Dos 2.5) and put the +# sys files for the correct version in the ataridos folder +# (i.e. dos.sys and dup.sys). Only tested with Dos25 and MyPicodos + +ATR = cc65-Chess.atr +# ATARIDOS = ataridos +ATARIDOSTYPE = Dos25 +ATARIDSK = atari.atr +DIR2ATR ?= dir2atr.exe + +# Unix or Windows +ifeq ($(shell echo),) + CP = cp $1 +else + CP = copy $(subst /,\,$1) +endif + +# Just the files, not the atari.atr folder. Don't know how to extend the zap: in the Makefile +REMOVES += $(ATR) $(ATARIDSK)/cc65-Chess $(ATRDOSOBJS) + +.PHONY: ATR +atr: $(ATR) + +$(ATARIDSK): + $(call MKDIR,$@) + +$(ATARIDSK)/%.sys: + $(call CP,$(ATARIDOS)/$(notdir $(@)) $@) + +# Different based on ATARIDOS or MyPicoDos +ifeq ($(ATARIDOS),) +ATARIDOSTYPE = MyPicoDOS405 +ATRDOSOBJS := +else +# I don't know of a better way to "copy if needed" the .sys files from one folder to another +ATRDOSSRCS += $(wildcard $(ATARIDOS)/*.sys) +ATRDOSOBJS := $(addsuffix .sys,$(basename $(addprefix $(ATARIDSK)/,$(notdir $(ATRDOSSRCS))))) +endif + +$(ATR): cc65-Chess.atari $(ATARIDSK) $(ATRDOSOBJS) + $(call CP,$< $(ATARIDSK)/cc65-Chess) + $(DIR2ATR) -b $(ATARIDOSTYPE) cc65-Chess.atr $(ATARIDSK) diff --git a/readme.txt b/readme.txt index b61efe8..f0454a8 100644 --- a/readme.txt +++ b/readme.txt @@ -1,5 +1,6 @@ 0. Updates +* Jul 2020 - Added a version for the Atari. * May 2020 - Advanced Build instructions at XI. * May 2020 - I created a version for the Commander X16 (R37). * May 2020 - I created a graphics version for the C64. @@ -257,9 +258,11 @@ XI. Build Instructions All of the 8-Bit versions of cc65 Chess can be built using make. -I recommend the game be built for speed, which also results in smaller file and -is essential for all targets. This is done by using the OPTIONS=optspeed -command line to make. See examples below. +I recommend the game be built for speed on almost all targets, which also +results in smaller file and is essential for all targets. This is done by +using the OPTIONS=optspeed command line to make. For the Atari, it is +essential to use OPTIONS=optsize as the 48K Atari really needs the extra +1K of memory. When you type make (using GNU Make) the default behaviour is to make all of the versions. Currently, that means the following (cc65 target name in brackets): @@ -269,50 +272,54 @@ versions. Currently, that means the following (cc65 target name in brackets): * Apple 2 (apple2) * Oric-1/Atmos/Telestrat (atmos) * Commander X16 (cx16) +* Atari (atari - Needs at least 48K, tested on Atari 800 48K) Most platforms have an additional step that can be performed, which is to make a -program (prg), disk (dsk) or tape (tap) file. Do make again, but with dsk -(Apple 2 dsk), tap (Oric tape), prg (C64 prg), cprg (c64.chr prg) or cxprg (cX16 -prg) on the command line. +program (prg), disk (dsk, atr) or tape (tap) file. Do make again, but with dsk +(Apple 2 dsk), atr (Atari disk), tap (Oric tape), prg (C64 prg), cprg (c64.chr +prg) or cxprg (cX16 prg) on the command line. The two steps can be combined into a single make command, by using "all" as the first target, i.e: -make OPTIONS=optspeed all dsk tap prg cprg cxprg +make OPTIONS=optsize all dsk atr tap prg cprg cxprg -Makeing a terminal version (using curses) - See IV (b) above. +Making a terminal version (using curses) - See IV (b) above. Examples: -1) Make everything, and then make the dsk and tap files for the Apple and Oric. +1) Make everything, and then make the images for all platforms. -make OPTIONS=optspeed +make OPTIONS=optsize This will make the following files: cc65-Chess.apple2 +cc65-Chess.atari cc65-Chess.atmos cc65-Chess.c64 cc65-Chess.c64.chr cc65-Chess.cx16 -make dsk tap prg cprg cxprg +make dsk atr tap prg cprg cxprg This will make the following files: cc65-Chess.tap +cc65-Chess.atr cc65-Chess.dsk cc65-Chess-c64.prg cc65-Chess-chr.prg cc65-Chess-cx16.prg -Once you have used the OPTIONS=optspeed on the command-line, you do not have to -use it again since the options are saved in a file called Makefile.options. +Once you have used the OPTIONS=optsize (or OPTIONS=optspeed) on the +command-line, you do not have to use it again since the options are +saved in a file called Makefile.options. 2) Build just one version (let's say the Oric) -make OPTIONS=optspeed TARGETS=atmos tap +make OPTIONS=optsize TARGETS=atmos tap This will create a ready to run TAP file named cc65-Chess.tap 3) You can also start an emulator directly from make with the test command-line. -make OPTIONS=optspeed atmos test +make OPTIONS=optsize atmos test This last command example is a good way of callimg make to build and test any of the targets by itself, provided you have configured an emulator in the Makefile. @@ -325,6 +332,6 @@ example, to run AppleWin I removed the $< from $(EMUCMD) $< in the test: section, because AppleWin did not like the extra (cc64-Chess.apple2) file being passed, and I had to give it the full path to cc64-Chess.dsk as part of apple2_EMUCMD. -Lastly - the CX16 and C64 versions use the same piece defenitions that Oliver +Lastly - the Atari, CX16 and C64 versions use the same piece defenitions that Oliver Schmidt added for the Apple II, and kindly agreed to let me use for these versions as well. See genPieces.cpp in the specific src folder for more details. diff --git a/src/atari/chessAtari.cfg b/src/atari/chessAtari.cfg new file mode 100644 index 0000000..6aebecd --- /dev/null +++ b/src/atari/chessAtari.cfg @@ -0,0 +1,62 @@ +FEATURES { + STARTADDRESS: default = $2000; +} +SYMBOLS { + __EXEHDR__: type = import; + __SYSTEM_CHECK__: type = import; # force inclusion of "system check" load chunk + __AUTOSTART__: type = import; # force inclusion of autostart "trailer" + __STACKSIZE__: type = weak, value = $0800; # 2k stack + __STARTADDRESS__: type = export, value = %S; + __RESERVED_MEMORY__: type = weak, value = $0000; +} +MEMORY { + ZP: file = "", define = yes, start = $0082, size = $007E; + +# file header, just $FFFF + HEADER: file = %O, start = $0000, size = $0002; + +# "system check" load chunk + SYSCHKHDR: file = %O, start = $0000, size = $0004; + SYSCHKCHNK: file = %O, start = $2E00, size = $0300; + SYSCHKTRL: file = %O, start = $0000, size = $0006; + +# "main program" load chunk + MAINHDR: file = %O, start = $0000, size = $0004; + MAIN: file = %O, define = yes, start = %S, size = $BC20 - __STACKSIZE__ - __RESERVED_MEMORY__ - %S; + TRAILER: file = %O, start = $0000, size = $0006; +} +SEGMENTS { + ZEROPAGE: load = ZP, type = zp; + EXTZP: load = ZP, type = zp, optional = yes; + EXEHDR: load = HEADER, type = ro; + SYSCHKHDR: load = SYSCHKHDR, type = ro, optional = yes; + SYSCHK: load = SYSCHKCHNK, type = rw, define = yes, optional = yes; + SYSCHKTRL: load = SYSCHKTRL, type = ro, optional = yes; + MAINHDR: load = MAINHDR, type = ro; + STARTUP: load = MAIN, type = ro, define = yes; + LOWBSS: load = MAIN, type = rw, optional = yes; # not zero initialized + LOWCODE: load = MAIN, type = ro, define = yes, optional = yes; + ONCE: load = MAIN, type = ro, optional = yes; + CODE: load = MAIN, type = ro, define = yes; + RODATA: load = MAIN, type = ro; + DATA: load = MAIN, type = rw; + DLIST: load = MAIN, type = rw, define = yes, optional = yes, align = $0100; + INIT: load = MAIN, type = rw, optional = yes; + BSS: load = MAIN, type = bss, define = yes; + AUTOSTRT: load = TRAILER, type = ro; +} +FEATURES { + CONDES: type = constructor, + label = __CONSTRUCTOR_TABLE__, + count = __CONSTRUCTOR_COUNT__, + segment = ONCE; + CONDES: type = destructor, + label = __DESTRUCTOR_TABLE__, + count = __DESTRUCTOR_COUNT__, + segment = RODATA; + CONDES: type = interruptor, + label = __INTERRUPTOR_TABLE__, + count = __INTERRUPTOR_COUNT__, + segment = RODATA, + import = __CALLIRQ__; +} diff --git a/src/atari/dataAtari.c b/src/atari/dataAtari.c new file mode 100644 index 0000000..185c167 --- /dev/null +++ b/src/atari/dataAtari.c @@ -0,0 +1,318 @@ +/* + * dataAtari.c + * cc65 Chess + * + * Created by Stefan Wessels, July 2020. + * + */ + +#include "../types.h" +#include "dataAtari.h" + +/*-----------------------------------------------------------------------*/ +// Atari specific graphics for the chess pieces + +// 66 = 3 cols * 22 rows, 2 per side, PAWN # pieces +const char gfxTiles[PAWN][2][66] = +{ + { + { + 0x00, 0x00, 0x00, + 0x3C, 0x7C, 0x78, + 0x24, 0x44, 0x48, + 0x24, 0x44, 0x48, + 0x27, 0xC7, 0xC8, + 0x20, 0x00, 0x08, + 0x10, 0x00, 0x10, + 0x08, 0x00, 0x20, + 0x05, 0xFF, 0x40, + 0x06, 0x00, 0xC0, + 0x02, 0x00, 0x80, + 0x02, 0x00, 0x80, + 0x02, 0x00, 0x80, + 0x02, 0x00, 0x80, + 0x02, 0x00, 0x80, + 0x04, 0x00, 0x40, + 0x08, 0x00, 0x20, + 0x0B, 0xFF, 0xA0, + 0x10, 0x00, 0x10, + 0x3F, 0xFF, 0xF8, + 0x3F, 0xFF, 0xF8, + 0x00, 0x00, 0x00, + }, + { + 0x00, 0x00, 0x00, + 0x3C, 0x7C, 0x78, + 0x3C, 0x7C, 0x78, + 0x3C, 0x7C, 0x78, + 0x3F, 0xFF, 0xF8, + 0x3F, 0xFF, 0xF8, + 0x1F, 0xFF, 0xF0, + 0x0F, 0xFF, 0xE0, + 0x07, 0xFF, 0xC0, + 0x04, 0x00, 0x40, + 0x03, 0xFF, 0x80, + 0x03, 0xFF, 0x80, + 0x03, 0xFF, 0x80, + 0x03, 0xFF, 0x80, + 0x03, 0xFF, 0x80, + 0x07, 0xFF, 0xC0, + 0x0F, 0xFF, 0xE0, + 0x0F, 0xFF, 0xE0, + 0x10, 0x00, 0x10, + 0x3F, 0xFF, 0xF8, + 0x3F, 0xFF, 0xF8, + 0x00, 0x00, 0x00, + }, + }, + { + { + 0x00, 0x00, 0x00, + 0x00, 0x88, 0x00, + 0x01, 0x54, 0x00, + 0x02, 0x12, 0x00, + 0x02, 0x01, 0x00, + 0x04, 0x00, 0x80, + 0x04, 0x42, 0x80, + 0x04, 0x02, 0x80, + 0x08, 0x03, 0x40, + 0x10, 0x01, 0x40, + 0x20, 0x00, 0x40, + 0x21, 0xE0, 0x40, + 0x12, 0x11, 0x60, + 0x0C, 0x21, 0xA0, + 0x00, 0x40, 0x90, + 0x00, 0x80, 0x50, + 0x01, 0x00, 0x18, + 0x02, 0x00, 0x08, + 0x05, 0xFF, 0xE8, + 0x04, 0x00, 0x08, + 0x07, 0xFF, 0xF8, + 0x00, 0x00, 0x00, + }, + { + 0x00, 0x00, 0x00, + 0x00, 0x88, 0x00, + 0x01, 0x54, 0x00, + 0x03, 0xEE, 0x00, + 0x03, 0xFF, 0x00, + 0x07, 0xFF, 0x80, + 0x07, 0xBD, 0x80, + 0x07, 0xFD, 0x80, + 0x0F, 0xFC, 0xC0, + 0x1F, 0xFE, 0xC0, + 0x3F, 0xFF, 0xC0, + 0x3F, 0xFF, 0xC0, + 0x1E, 0x1E, 0xE0, + 0x0C, 0x3E, 0x60, + 0x00, 0x7F, 0x70, + 0x00, 0xFF, 0xB0, + 0x01, 0xFF, 0xF8, + 0x03, 0xFF, 0xF8, + 0x04, 0x00, 0x08, + 0x07, 0xFF, 0xF8, + 0x07, 0xFF, 0xF8, + 0x00, 0x00, 0x00, + }, + }, + { + { + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x38, 0x00, + 0x00, 0x44, 0x00, + 0x00, 0x82, 0x00, + 0x01, 0x11, 0x00, + 0x02, 0x10, 0x80, + 0x02, 0xFE, 0x80, + 0x04, 0x10, 0x40, + 0x04, 0x10, 0x40, + 0x04, 0x10, 0x40, + 0x02, 0x10, 0x80, + 0x02, 0x00, 0x80, + 0x01, 0x01, 0x00, + 0x00, 0xFE, 0x00, + 0x00, 0x82, 0x00, + 0x00, 0x82, 0x00, + 0x00, 0x7C, 0x00, + 0x02, 0x00, 0x80, + 0x0F, 0xFF, 0xE0, + 0x1F, 0xFF, 0xF0, + 0x00, 0x00, 0x00, + }, + { + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x38, 0x00, + 0x00, 0x7C, 0x00, + 0x00, 0xFE, 0x00, + 0x01, 0xEF, 0x00, + 0x03, 0xEF, 0x80, + 0x03, 0x01, 0x80, + 0x07, 0xEF, 0xC0, + 0x07, 0xEF, 0xC0, + 0x07, 0xEF, 0xC0, + 0x03, 0xEF, 0x80, + 0x03, 0xFF, 0x80, + 0x01, 0xFF, 0x00, + 0x00, 0x82, 0x00, + 0x00, 0xFE, 0x00, + 0x00, 0xFE, 0x00, + 0x00, 0x7C, 0x00, + 0x03, 0xFF, 0x80, + 0x08, 0x00, 0x20, + 0x1F, 0xFF, 0xF0, + 0x00, 0x00, 0x00, + }, + }, + { + { + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x38, 0x00, + 0x00, 0x44, 0x00, + 0x0E, 0x44, 0xE0, + 0x11, 0x29, 0x10, + 0x21, 0x45, 0x08, + 0x22, 0x82, 0x88, + 0x20, 0x00, 0x08, + 0x22, 0x10, 0x88, + 0x23, 0x39, 0x88, + 0x11, 0xFF, 0x10, + 0x10, 0xFE, 0x10, + 0x08, 0x00, 0x20, + 0x08, 0x00, 0x20, + 0x0B, 0xFF, 0xA0, + 0x04, 0x00, 0x40, + 0x04, 0x00, 0x40, + 0x04, 0x00, 0x40, + 0x06, 0x00, 0xC0, + 0x03, 0xFF, 0x80, + 0x00, 0x00, 0x00, + }, + { + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x38, 0x00, + 0x00, 0x7C, 0x00, + 0x0E, 0x7C, 0xE0, + 0x1F, 0x39, 0xF0, + 0x3F, 0x7D, 0xF8, + 0x3E, 0xFE, 0xF8, + 0x3F, 0xFF, 0xF8, + 0x3D, 0xEF, 0x78, + 0x3C, 0xC6, 0x78, + 0x1E, 0x00, 0xF0, + 0x1F, 0x01, 0xF0, + 0x0F, 0xFF, 0xE0, + 0x0F, 0xFF, 0xE0, + 0x0C, 0x00, 0x60, + 0x07, 0xFF, 0xC0, + 0x07, 0xFF, 0xC0, + 0x07, 0xFF, 0xC0, + 0x07, 0xFF, 0xC0, + 0x03, 0xFF, 0x80, + 0x00, 0x00, 0x00, + }, + }, + { + { + 0x00, 0x00, 0x00, + 0x00, 0x38, 0x00, + 0x00, 0x28, 0x00, + 0x00, 0xEE, 0x00, + 0x00, 0xC6, 0x00, + 0x03, 0x29, 0x80, + 0x04, 0xAA, 0x40, + 0x08, 0x6C, 0x20, + 0x10, 0x28, 0x10, + 0x12, 0x44, 0x90, + 0x24, 0x28, 0x48, + 0x24, 0x10, 0x48, + 0x22, 0x10, 0x88, + 0x11, 0x01, 0x10, + 0x10, 0x82, 0x10, + 0x08, 0x00, 0x20, + 0x09, 0xFF, 0x20, + 0x04, 0x00, 0x40, + 0x04, 0x00, 0x40, + 0x06, 0x00, 0xC0, + 0x03, 0xFF, 0x80, + 0x00, 0x00, 0x00, + }, + { + 0x00, 0x00, 0x00, + 0x00, 0x38, 0x00, + 0x00, 0x28, 0x00, + 0x00, 0xEE, 0x00, + 0x00, 0xC6, 0x00, + 0x03, 0x29, 0x80, + 0x07, 0xAB, 0xC0, + 0x0F, 0xEF, 0xE0, + 0x1F, 0xC7, 0xF0, + 0x1D, 0xAB, 0x70, + 0x3B, 0xC7, 0xB8, + 0x3B, 0xEF, 0xB8, + 0x3D, 0xFF, 0x78, + 0x1E, 0xFE, 0xF0, + 0x1F, 0x7D, 0xF0, + 0x0F, 0xFF, 0xE0, + 0x0C, 0x00, 0x60, + 0x07, 0xFF, 0xC0, + 0x07, 0xFF, 0xC0, + 0x07, 0xFF, 0xC0, + 0x03, 0xFF, 0x80, + 0x00, 0x00, 0x00, + }, + }, + { + { + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x38, 0x00, + 0x00, 0x44, 0x00, + 0x00, 0x82, 0x00, + 0x00, 0x82, 0x00, + 0x00, 0x82, 0x00, + 0x00, 0x44, 0x00, + 0x00, 0x38, 0x00, + 0x00, 0x44, 0x00, + 0x00, 0x44, 0x00, + 0x00, 0xC6, 0x00, + 0x00, 0x44, 0x00, + 0x00, 0x44, 0x00, + 0x00, 0xFE, 0x00, + 0x01, 0x01, 0x00, + 0x03, 0xFF, 0x80, + 0x03, 0xFF, 0x80, + 0x00, 0x00, 0x00, + }, + { + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x38, 0x00, + 0x00, 0x7C, 0x00, + 0x00, 0xFE, 0x00, + 0x00, 0xFE, 0x00, + 0x00, 0xFE, 0x00, + 0x00, 0x7C, 0x00, + 0x00, 0x38, 0x00, + 0x00, 0x7C, 0x00, + 0x00, 0x7C, 0x00, + 0x00, 0xFE, 0x00, + 0x00, 0x7C, 0x00, + 0x00, 0x7C, 0x00, + 0x00, 0xFE, 0x00, + 0x01, 0x01, 0x00, + 0x03, 0xFF, 0x80, + 0x03, 0xFF, 0x80, + 0x00, 0x00, 0x00, + }, + }, +}; diff --git a/src/atari/dataAtari.h b/src/atari/dataAtari.h new file mode 100644 index 0000000..a74c0eb --- /dev/null +++ b/src/atari/dataAtari.h @@ -0,0 +1,14 @@ +/* + * dataAtari.h + * cc65 Chess + * + * Created by Stefan Wessels, July 2020. + * + */ + +#ifndef _DATA_H_ +#define _DATA_H_ + +extern const char gfxTiles[PAWN][2][66]; + +#endif //_DATA_H_ diff --git a/src/atari/genpieces.cpp b/src/atari/genpieces.cpp new file mode 100644 index 0000000..a2d8d24 --- /dev/null +++ b/src/atari/genpieces.cpp @@ -0,0 +1,319 @@ +/* + * genPieces.cpp + * cc65 Chess + * + * Created by Oliver Schmidt, January 2020. + * Pieces designed by Frank Gebhart, 1980s. + * Modified for Atari by S. Wessels, Jul 2020. + * + */ + +#include + +char pieces[]= +" " +" **** ***** **** " +" * * * * * * " +" * * * * * * " +" * ***** ***** * " +" * * " +" * * " +" * * " +" * ********* * " +" ** ** " +" * * " +" * * " +" * * " +" * * " +" * * " +" * * " +" * * " +" * *********** * " +" * * " +" ******************* " +" ******************* " +" " +" " +" **** ***** **** " +" **** ***** **** " +" **** ***** **** " +" ******************* " +" ******************* " +" ***************** " +" *************** " +" ************* " +" * * " +" *********** " +" *********** " +" *********** " +" *********** " +" *********** " +" ************* " +" *************** " +" *************** " +" * * " +" ******************* " +" ******************* " +" " +" " +" * * " +" * * * * " +" * * * " +" * * " +" * * " +" * * * * " +" * * * " +" * ** * " +" * * * " +" * * " +" * **** * " +" * * * * ** " +" ** * ** * " +" * * * " +" * * * " +" * ** " +" * * " +" * ************ * " +" * * " +" **************** " +" " +" " +" * * " +" * * * * " +" ***** *** " +" ********** " +" ************ " +" **** **** ** " +" ********* ** " +" ********** ** " +" ************ ** " +" **************** " +" **************** " +" **** **** *** " +" ** ***** ** " +" ******* *** " +" ********* ** " +" ************** " +" *************** " +" * * " +" **************** " +" **************** " +" " +" " +" " +" *** " +" * * " +" * * " +" * * * " +" * * * " +" * ******* * " +" * * * " +" * * * " +" * * * " +" * * * " +" * * " +" * * " +" ******* " +" * * " +" * * " +" ***** " +" * * " +" *************** " +" ***************** " +" " +" " +" " +" *** " +" ***** " +" ******* " +" **** **** " +" ***** ***** " +" ** ** " +" ****** ****** " +" ****** ****** " +" ****** ****** " +" ***** ***** " +" *********** " +" ********* " +" * * " +" ******* " +" ******* " +" ***** " +" *********** " +" * * " +" ***************** " +" " +" " +" " +" *** " +" * * " +" *** * * *** " +" * * * * * * " +" * * * * * * " +" * * * * * * " +" * * " +" * * * * * " +" * ** *** ** * " +" * ********* * " +" * ******* * " +" * * " +" * * " +" * *********** * " +" * * " +" * * " +" * * " +" ** ** " +" *********** " +" " +" " +" " +" *** " +" ***** " +" *** ***** *** " +" ***** *** ***** " +" ****** ***** ****** " +" ***** ******* ***** " +" ******************* " +" **** **** **** **** " +" **** ** ** **** " +" **** **** " +" ***** ***** " +" *************** " +" *************** " +" ** ** " +" ************* " +" ************* " +" ************* " +" ************* " +" *********** " +" " +" " +" *** " +" * * " +" *** *** " +" ** ** " +" ** * * ** " +" * * * * * * " +" * ** ** * " +" * * * * " +" * * * * * * " +" * * * * * * " +" * * * * * " +" * * * * * " +" * * * * " +" * * * * " +" * * " +" * ********* * " +" * * " +" * * " +" ** ** " +" *********** " +" " +" " +" *** " +" * * " +" *** *** " +" ** ** " +" ** * * ** " +" **** * * **** " +" ******* ******* " +" ******* ******* " +" *** ** * * ** *** " +" *** **** **** *** " +" *** ***** ***** *** " +" **** ********* **** " +" **** ******* **** " +" ***** ***** ***** " +" *************** " +" ** ** " +" ************* " +" ************* " +" ************* " +" *********** " +" " +" " +" " +" " +" " +" " +" *** " +" * * " +" * * " +" * * " +" * * " +" * * " +" *** " +" * * " +" * * " +" ** ** " +" * * " +" * * " +" ******* " +" * * " +" *********** " +" *********** " +" " +" " +" " +" " +" " +" " +" *** " +" ***** " +" ******* " +" ******* " +" ******* " +" ***** " +" *** " +" ***** " +" ***** " +" ******* " +" ***** " +" ***** " +" ******* " +" * * " +" *********** " +" *********** " +" " +; + +int main(void) +{ + int i, j, k; + unsigned char c = 0; + + printf("const char gfxTiles[PAWN][2][66] = \n{\n\t{\n\t\t{\n\t\t\t"); + for(i=0, j=7, k=0; iscrn ; Mode $0x + LMS, setting screen memory to $9000 + .repeat top-1 ; 102 lines of mode $0x (incl LMS row above) + .byte mode + .endrep + .byte $40 +mode, <(scnd), >(scnd) ; clear the 4k boundry and start another row of mode $0x + .repeat bot-1 ; another 90 lines of mode $0x (incl. LMS row above) + .byte mode + .endrep + .byte $41,displayList ; Vertical Blank jump to start of displayList + +;----------------------------------------------------------------------- +; lookup to the start of a graphics row +rowL: + .repeat top, I ; $66 rows at $9000 + .byte <(scrn + I *40) + .endrep + .repeat bot, I ; $5a rows at $a000 + .byte <(scnd + I *40) + .endrep + +rowH: + .repeat top, I + .byte >(scrn + I *40) + .endrep + .repeat bot, I + .byte >(scnd + I *40) + .endrep + +;----------------------------------------------------------------------- +; The code to draw in hires +.code + +;----------------------------------------------------------------------- +.import popa + +;----------------------------------------------------------------------- +; the functions exported to "C" +.export _plat_atariInit +.export _plat_gfxFill +.export _plat_showPiece +.export _plat_showStrXY + +;----------------------------------------------------------------------- +; Init the hires screen with teh display list +.proc _plat_atariInit + + lda #0 ; stop the dma + sta DMACTL + lda #displayList + sta SDLSTH + lda #$22 ; resume the DMA + sta DMACTL + + rts + +.endproc + +;----------------------------------------------------------------------- +; void plat_gfxFill(char fill, char x, char y, char w, char h) +.proc _plat_gfxFill + + sta ptr2 + 1 ; h was in acc + jsr popa ; w + sta ptr2 + jsr popa ; y + sta tmp1 + jsr popa ; x + sta tmp2 + jsr popa ; fill + sta tmp3 + +rowStart: + ldy tmp1 ; get the row top + lda rowL, y ; get the address where the row starts + sta ptr1 + lda rowH, y + sta ptr1 + 1 + lda tmp3 ; get the fill byte + ldx ptr2 ; width in x + ldy tmp2 ; and col x in y register +: + sta (ptr1), y ; write the fill byte + iny ; memory is linear + dex ; one less column to do + bne :- ; do for all columns + inc tmp1 ; go down one row + dec ptr2 + 1 ; one less row to do in height + bne rowStart ; repeat till all height rows done + rts + +.endproc + +;----------------------------------------------------------------------- +; void plat_showPiece(char x, char Y, const char *src) +.proc _plat_showPiece + + sta read + 1 ; store the pointer to the piece + stx read + 2 + jsr popa ; y + sta tmp1 + jsr popa ; x + sta tmp2 + + lda #22 ; pieces are 22 heigh + sta tmp4 + + ldx #0 ; start at the 1st byte of the piece +loop: + ldy tmp1 ; get the current piece row + lda rowL, y ; look up teh row start address in memory + sta ptr1 + lda rowH, y + sta ptr1 + 1 + lda #3 ; a piece is 3 bytes wide + sta tmp3 ; col counter + ldy tmp2 ; the col x goes into y register + +read: + lda $ffff, x ; read a byte from the piece + eor (ptr1), y ; eor with teh screen + sta (ptr1), y ; and save back to the screen + inx ; next byte in piece + iny ; next byte on screen + dec tmp3 ; one less col byte to do + bne read ; if not all done, do the rest of the cols on this row + inc tmp1 ; next row + dec tmp4 ; one less row to do of the 22 + bne loop ; if not all done, do the next row + + rts + +.endproc + +;----------------------------------------------------------------------- +; void plat_showStrXY(char x, char Y, char *str) +.proc _plat_showStrXY + + sta strRead + 1 ; pointer to the strin comes in as a, x regsiters + stx strRead + 2 + + jsr popa ; get the y + asl ; mult it by 8 + asl + asl + sta tmp1 ; y * 8 + jsr popa + sta tmp2 ; x + +loop: + lda #0 + sta fontRead + 2 ; prep the hi byte + +strRead: + lda $ffff ; get the character + bne :+ ; if not 0, not at end of string + rts ; end of string, all done +: + cmp #96 ; if lowercase + bcs :+ ; then all is well + sec ; uppercase and numbers need to shift + sbc #32 ; down by 32 to be aligned with the ROM font +: + inc strRead + 1 ; next char in string + bne :+ + inc strRead + 2 +: + asl ; ROM char is 8 wide so mult string char * 8 + rol fontRead + 2 + asl + rol fontRead + 2 + asl + rol fontRead + 2 + sta fontRead + 1 + clc + lda CHBAS ; add the character rom hi + adc fontRead + 2 ; to the character pointer + sta fontRead + 2 + + ldx #0 ; start at first row of 8 rows in a char + ldy tmp1 ; y reg is the piwel row to draw at + +charPlot: + sty tmp3 ; copy the pixel row + lda rowL, y ; look up the screen address of the row + sta ptr1 + lda rowH, y + sta ptr1 + 1 + ldy tmp2 ; put the col into the y reg + +fontRead: + lda $ffff, x ; read the font defenition for this char row (char row in x) + sta (ptr1), y ; store to the screen + ldy tmp3 ; get the screen pixel row in y + iny ; go down a row + inx ; one more of the 8 character rows done + cpx #8 ; all 8 done + bne charPlot ; if not, keep going + inc tmp2 ; next column on screeen + jmp loop ; do the next character in the string + +.endproc diff --git a/src/atari/platAtari.c b/src/atari/platAtari.c new file mode 100644 index 0000000..ee093db --- /dev/null +++ b/src/atari/platAtari.c @@ -0,0 +1,467 @@ +/* + * platAtari.c + * cc65 Chess + * + * Created by Stefan Wessels, July 2020. + * + */ + +#include +#include +#include +#include "../types.h" +#include "../globals.h" +#include "../undo.h" +#include "../frontend.h" +#include "../plat.h" +#include "dataAtari.h" + + +/*-----------------------------------------------------------------------*/ +#define SCROLL_SPEED 10 +#define BOARD_PIECE_WIDTH 3 +#define BOARD_PIECE_HEIGHT 22 +#define SCREEN_WIDTH 40 +#define SCREEN_HEIGHT 24 +#define LOG_WINDOW_HEIGHT (SCREEN_HEIGHT - 2) + +/*-----------------------------------------------------------------------*/ +// Internal function Prototype +char plat_TimeExpired(unsigned char aTime); + +/*-----------------------------------------------------------------------*/ +// Function Prototype for functions in hiresAtari.s +extern void plat_atariInit(void); +extern void plat_gfxFill(char fill, char x, char y, char w, char h); +extern void plat_showPiece(char x, char Y, const char *src); +extern void plat_showStrXY(char x, char y, char *str); + +/*-----------------------------------------------------------------------*/ +// Local storage +char textStr[41]; +static char subMenu; + +/*-----------------------------------------------------------------------*/ +void plat_Init() +{ + // Setting this to 0 will not show the "Quit" option in the main menu + gReturnToOS = 1; + + plat_gfxFill(0,0,0,40,191); + plat_atariInit(); + + _setcolor(1,0xc,0xf); // Pixel %1 color + _setcolor(2,0xc,0x7); // Pixel %0 color + _setcolor(4,0xC,0x7); // border color + + // Show the welcome text + strcpy(textStr, "Atari graphics version, July 2020."); + plat_showStrXY(2,SCREEN_HEIGHT/2-1, gszAbout); + plat_showStrXY(3,SCREEN_HEIGHT/2+1,textStr); + + // Show the welcome kings (black and white, solid versions) + plat_showPiece(SCREEN_WIDTH/2 - 1, 8*(SCREEN_HEIGHT/2 - 6), gfxTiles[KING-1][1]); + plat_showPiece(SCREEN_WIDTH/2 - 1, 8*(SCREEN_HEIGHT/2 + 4), gfxTiles[KING-1][0]); + + // Hold the welcome screen + plat_ReadKeys(1); + + // Set game colors + _setcolor(2,0x0,0x0); // Pixel %0 color + plat_gfxFill(0,0,0,40,191); + + // Not in a menu + subMenu = 0; +} + +/*-----------------------------------------------------------------------*/ +void plat_UpdateScreen() +{ +} + +/*-----------------------------------------------------------------------*/ +// Very simple menu with a heading and a scrolling banner as a footer +char plat_Menu(char **menuItems, char height, char *scroller) +{ + static char *prevScroller, *pScroller, *pEnd; + int keyMask; + char i, sx, sy, numMenuItems, timerInit = 0, maxLen = 0; + + subMenu++; + + // If the scroller message chages, cache the new one + if(prevScroller != scroller) + { + prevScroller = scroller; + pScroller = scroller; + pEnd = scroller + strlen(scroller); + } + + // Find the longest entry + for(numMenuItems=0; menuItems[numMenuItems]; ++numMenuItems) + { + char len = strlen(menuItems[numMenuItems]); + if(len > maxLen) + maxLen = len; + } + + // Centre on the screen + sy = MAX_SIZE(0, (SCREEN_HEIGHT / 2) - (height / 2) - 1); + sx = MAX_SIZE(0, (SCREEN_WIDTH / 2) - (maxLen / 2) - 1); + maxLen = MIN_SIZE(SCREEN_WIDTH-2, maxLen); + + // Draw and color a frame + plat_gfxFill(0xAA , sx-1 , 8*(sy-1 ), maxLen+4 , 8*(1 )); + plat_gfxFill(0xAA , sx-1 , 8*(sy ), 1 , 8*(height+3)); + plat_gfxFill(0xAA , sx+maxLen+2, 8*(sy ), 1 , 8*(height+3)); + plat_gfxFill(0xAA , sx , 8*(sy+height+2), maxLen+2 , 8*(1 )); + + // Show the title + sprintf(textStr, " %.*s ",38, menuItems[0]); + plat_showStrXY(sx, sy, textStr); + + // Leave a blank line + sprintf(textStr, "%-*s", maxLen+2," "); + plat_showStrXY(sx, ++sy, textStr); + + // Show all the menu items + for(i=1; i%.*s<",maxLen, menuItems[i]); + plat_showStrXY(sx, sy+i, textStr); + + // Look for user input + keyMask = plat_ReadKeys(0); + + if(keyMask & INPUT_MOTION) + { + // selection changes so de-highlight the selected item + sprintf(textStr, " %.*s ",maxLen, menuItems[i]); + plat_showStrXY(sx, sy+i, textStr); + + // see if the selection goes up or down + switch(keyMask & INPUT_MOTION) + { + case INPUT_UP: + if(!--i) + i = numMenuItems-1; + break; + + case INPUT_DOWN: + if(numMenuItems == ++i) + i = 1; + break; + } + } + keyMask &= (INPUT_SELECT | INPUT_BACKUP); + + // Show the scroller + sprintf(textStr, " %.*s ",maxLen, pScroller); + plat_showStrXY(sx, sy+height, textStr); + + // Wrap the message if needed + if((pEnd - pScroller) < maxLen-1) + { + sprintf(textStr, " %.*s ",maxLen-(pEnd - pScroller)-1, scroller); + plat_showStrXY(sx+(pEnd-pScroller)+1, sy+height, textStr); + } + + // Only update the scrolling when needed + if(plat_TimeExpired(SCROLL_SPEED)) + { + ++pScroller; + if(!*pScroller) + pScroller = scroller; + } + } while(keyMask != INPUT_SELECT && keyMask != INPUT_BACKUP); + + // if backing out of the menu, return 0 + if(keyMask & INPUT_BACKUP) + return 0; + + // return the selection + return i; +} + +/*-----------------------------------------------------------------------*/ +void plat_DrawBoard(char clearLog) +{ + char i; + + // Not in a menu when drawBoard is called + if(subMenu) + { + clearLog = 1; + subMenu = 0; + } + + if(clearLog) + { + // Clear the log area pixels and color to green + plat_gfxFill(0, 25, 0, 15, 24*8); + } + + // redraw all tiles + for(i=0; i<64; ++i) + { + plat_DrawSquare(i); + } + + // Add the A..H and 1..8 tile-keys + for(i=0; i<8; ++i) + { + // Print the letters and numbers in Black on Green + sprintf(textStr, "%c",'A'+i); + plat_showStrXY(2+i*BOARD_PIECE_WIDTH, 0, textStr); + + sprintf(textStr, "%d",8-i); + plat_showStrXY(0, 1+i*3, textStr); + } +} + +/*-----------------------------------------------------------------------*/ +void plat_DrawSquare(char position) +{ + char index; + char piece, color; + char y = position / 8, x = position & 7; + char blackWhite = !((x & 1) ^ (y & 1)); + + // Draw the board square + plat_gfxFill(blackWhite ? 0xff : 0x0, 1 + x * BOARD_PIECE_WIDTH, 8 + y * BOARD_PIECE_HEIGHT, BOARD_PIECE_WIDTH, BOARD_PIECE_HEIGHT); + + // Get the piece data to draw the piece over the tile + piece = gChessBoard[y][x]; + color = piece & PIECE_WHITE; + piece &= PIECE_DATA; + + if(piece) + { + index = 1; + if((color && blackWhite) || (!color && !blackWhite)) + index = 0; + plat_showPiece(1 + x * BOARD_PIECE_WIDTH, 8 + y * BOARD_PIECE_HEIGHT, gfxTiles[piece-1][index]); + } + + // Show the attack numbers + if(gShowAttackBoard) + { + char piece_value = (gChessBoard[y][x] & 0x0f); + char piece_color = (gChessBoard[y][x] & PIECE_WHITE) >> 7; + + // Attackers (bottom left) + sprintf(textStr, "%d",(gpAttackBoard[giAttackBoardOffset[position][0]])); + plat_showStrXY(1+x*BOARD_PIECE_WIDTH,(y+1)*3, textStr); + + // Defenders (bottom right) + sprintf(textStr, "%d",(gpAttackBoard[giAttackBoardOffset[position][1]])); + plat_showStrXY(1+x*BOARD_PIECE_WIDTH+3,(y+1)*3, textStr); + + // Color (0 is black, 128 is white) and piece value (1=ROOK, 2=KNIGHT, 3=BISHOP, 4=QUEEN, 5=KING, 6=PAWN) + sprintf(textStr, "%0d",piece_value); + plat_showStrXY(1+x*BOARD_PIECE_WIDTH,1+y*3, textStr); + + // Color + sprintf(textStr, "%d",piece_color); + plat_showStrXY(1+x*BOARD_PIECE_WIDTH+3,1+y*3, textStr); + } +} + +/*-----------------------------------------------------------------------*/ +void plat_ShowSideToGoLabel(char side) +{ + // Show Black or White + sprintf(textStr, "%s",gszSideLabel[side]); + plat_showStrXY(2+8*BOARD_PIECE_WIDTH, 0, textStr); +} + +/*-----------------------------------------------------------------------*/ +void plat_Highlight(char position, char color, char cursor) +{ + char colSelect[6] = {0x55, 0xaa, 0x55, 0xaa, 0x55}; + char y = position / 8, x = position & 7; + + // get a pattern for the cursor + color = colSelect[color-2]; + + // If an attacker/defender cursor, swap the colors + if(!cursor) + color ^= 0xff; + + // for my real Atari 800 on a Commodore 1802 monitor, this is + // what I want. On Altirra 3.20 with an NTSC 800 and NTSC + // artifacting, the colors are inverted from what I want. + // A little odd, but I am going with the real hardware. + color ^= 0xff; + + // turn position into a board based offset + x *= BOARD_PIECE_WIDTH; + y *= BOARD_PIECE_HEIGHT; + + // The board is 1 line down from the top + y += 8; + + // Draw the two vertical bars - the "cursor" + plat_gfxFill(color, x + 1 , y, 1, BOARD_PIECE_HEIGHT); + plat_gfxFill(color, x + BOARD_PIECE_WIDTH, y, 1, BOARD_PIECE_HEIGHT); +} + +/*-----------------------------------------------------------------------*/ +void plat_ShowMessage(char *str, char ) +{ + sprintf(textStr, "%.*s",SCREEN_WIDTH-1-(8*BOARD_PIECE_WIDTH),str); + plat_showStrXY(1+(8*BOARD_PIECE_WIDTH), (SCREEN_HEIGHT-1), textStr); +} + +/*-----------------------------------------------------------------------*/ +void plat_ClearMessage() +{ + // Erase the message from ShowMessage + sprintf(textStr, "%-*s",SCREEN_WIDTH-1-(8*BOARD_PIECE_WIDTH)," "); + plat_showStrXY(1+(8*BOARD_PIECE_WIDTH), (SCREEN_HEIGHT-1), textStr); +} + +/*-----------------------------------------------------------------------*/ +// This function can/will change the gTile and related global variables so +// caution is needed +void plat_AddToLogWin() +{ + char bot = SCREEN_HEIGHT-2, y = 1, x = 2+(8*BOARD_PIECE_WIDTH); + char i = 0; + + // Show a log of the moves that have been played + for(; y<=bot; ++y) + { + if(undo_FindUndoLine(bot-y)) + { + frontend_FormatLogString(); + sprintf(textStr, "%-6s",gLogStrBuffer); + plat_showStrXY(x, y, textStr); + } + else + { + sprintf(textStr, "%-*s",SCREEN_WIDTH-x," "); + plat_showStrXY(x, y, textStr); + } + } +} + +/*-----------------------------------------------------------------------*/ +void plat_AddToLogWinTop() +{ + plat_AddToLogWin(); +} + +/*-----------------------------------------------------------------------*/ +char plat_TimeExpired(unsigned char aTime) +{ + if(OS.rtclok[2] > aTime) + { + OS.rtclok[2] = 0; + return 1; + } + return 0; +} + +/*-----------------------------------------------------------------------*/ +int plat_ReadKeys(char blocking) +{ + char key = 0; + int keyMask = 0; + + if(blocking) + { + while(KEY_NONE == (key = OS.ch)); + } + else + { + if(KEY_NONE == (key = OS.ch)) + return 0; + } + + switch(key) + { + case KEY_DASH | KEY_CTRL: //KEY_UP: // Up + keyMask |= INPUT_UP; + break; + + case KEY_RIGHT: // Right + keyMask |= INPUT_RIGHT; + break; + + case KEY_DOWN: // Down + keyMask |= INPUT_DOWN; + break; + + case KEY_LEFT: // Left + keyMask |= INPUT_LEFT; + break; + + case KEY_ESC: // Esc + keyMask |= INPUT_BACKUP; + break; + + case KEY_A: // 'a' - Show Attackers + keyMask |= INPUT_TOGGLE_A; + break; + + case KEY_B: // 'b' - Board attacks - Show all attacks + keyMask |= INPUT_TOGGLE_B; + break; + + case KEY_D: // 'd' - Show Defenders + keyMask |= INPUT_TOGGLE_D; + break; + + case KEY_M: // 'm' - Menu + keyMask |= INPUT_MENU; + break; + + case KEY_RETURN: // Enter + keyMask |= INPUT_SELECT; + break; + + case KEY_R: + keyMask |= INPUT_REDO; + break; + + case KEY_U: + keyMask |= INPUT_UNDO; + break; + + // default: // Debug - show key code + // { + // char s[] = "Key:000"; + // s[4] = (key/100)+'0'; + // key -= (s[4] - '0') * 100; + // s[5] = (key/10)+'0'; + // s[6] = (key%10)+'0'; + // plat_ShowMessage(s,COLOR_RED); + // } + // break; + } + + OS.ch = KEY_NONE; + return keyMask; +} + +/*-----------------------------------------------------------------------*/ +void plat_Shutdown() +{ +}