diff options
| author | B. Watson <urchlay@slackware.uk> | 2026-02-16 21:13:41 -0500 |
|---|---|---|
| committer | B. Watson <urchlay@slackware.uk> | 2026-02-16 21:13:41 -0500 |
| commit | 5ab86143c9d0b0c86411f7067cf9649f7f0d3311 (patch) | |
| tree | 44cc25726ebd6dd8c8e62876be25150a299a6c2f | |
| parent | 126c147638538ce54fc21a3803955b3693a99add (diff) | |
| download | fujinet-chat-5ab86143c9d0b0c86411f7067cf9649f7f0d3311.tar.gz | |
New UI stuff, not yet working.
| -rw-r--r-- | Makefile | 367 | ||||
| -rw-r--r-- | Makefile.client | 350 | ||||
| -rw-r--r-- | font.dat | bin | 0 -> 1024 bytes | |||
| -rw-r--r-- | font_dl.asm | 56 | ||||
| -rw-r--r-- | memsetup.asm | 11 | ||||
| -rw-r--r-- | src/addrs.c | 27 | ||||
| -rw-r--r-- | src/addrs.h | 15 | ||||
| -rw-r--r-- | src/edbox.c | 138 | ||||
| -rw-r--r-- | src/edbox.h | 14 | ||||
| -rw-r--r-- | src/screen.c | 222 | ||||
| -rw-r--r-- | src/screen.h | 103 | ||||
| -rw-r--r-- | uitest/test.c | 65 |
12 files changed, 1021 insertions, 347 deletions
@@ -1,350 +1,23 @@ -############################################################################### -### Generic Makefile for cc65 projects - full version with abstract options ### -### V1.3.0(w) 2010 - 2013 Oliver Schmidt & Patryk "Silver Dream !" Łogiewa ### -############################################################################### - -############################################################################### -### In order to override defaults - values can be assigned to the variables ### -############################################################################### - -# Space or comma separated list of cc65 supported target platforms to build for. -# Default: c64 (lowercase!) -TARGETS := atari - -# Name of the final, single-file executable. -# Default: name of the current dir with target name appended -PROGRAM := fnchat - -# Path(s) to additional libraries required for linking the program -# Use only if you don't want to place copies of the libraries in SRCDIR -# Default: none -LIBS := +PARTS=memsetup.xex font_dl.xex client.xex -# Custom linker configuration file -# Use only if you don't want to place it in SRCDIR -# Default: none -CONFIG := - -# Additional C compiler flags and options. -# Default: none -CFLAGS = -Oris - -# Additional assembler flags and options. -# Default: none -ASFLAGS = - -# Additional linker flags and options. -# Default: none -LDFLAGS = $(LDFLAGS.$(TARGETS)) -LDFLAGS.atari = --mapfile $(PROGRAM).map - -# Path to the directory containing C and ASM sources. -# Default: src -SRCDIR := - -# Path to the directory where object files are to be stored (inside respective target subdirectories). -# Default: obj -OBJDIR := - -# Command used to run the emulator. -# Default: depending on target platform. For default (c64) target: x64 -kernal kernal -VICIIdsize -autoload -EMUCMD := - -# Optional commands used before starting the emulation process, and after finishing it. -# Default: none -#PREEMUCMD := osascript -e "tell application \"System Events\" to set isRunning to (name of processes) contains \"X11.bin\"" -e "if isRunning is true then tell application \"X11\" to activate" -#PREEMUCMD := osascript -e "tell application \"X11\" to activate" -#POSTEMUCMD := osascript -e "tell application \"System Events\" to tell process \"X11\" to set visible to false" -#POSTEMUCMD := osascript -e "tell application \"Terminal\" to activate" -PREEMUCMD := -POSTEMUCMD := - -# On Windows machines VICE emulators may not be available in the PATH by default. -# In such case, please set the variable below to point to directory containing -# VICE emulators. -#VICE_HOME := "C:\Program Files\WinVICE-2.2-x86\" -VICE_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 -STATEFILE := Makefile.options - -################################################################################### -#### DO NOT EDIT BELOW THIS LINE, UNLESS YOU REALLY KNOW WHAT YOU ARE DOING! #### -################################################################################### - -################################################################################### -### Mapping abstract options to the actual compiler, assembler and linker flags ### -### Predefined compiler, assembler and linker flags, used with abstract options ### -### valid for 2.14.x. Consult the documentation of your cc65 version before use ### -################################################################################### - -# Compiler flags used to tell the compiler to optimise for SPEED -define _optspeed_ - CFLAGS += -Oris -endef - -# Compiler flags used to tell the compiler to optimise for SIZE -define _optsize_ - CFLAGS += -Or -endef - -# Compiler and assembler flags for generating listings -define _listing_ - CFLAGS += --listing $$(@:.o=.lst) - ASFLAGS += --listing $$(@:.o=.lst) - REMOVES += $(addsuffix .lst,$(basename $(OBJECTS))) -endef - -# Linker flags for generating map file -define _mapfile_ - LDFLAGS += --mapfile $$@.map - REMOVES += $(PROGRAM).map -endef - -# Linker flags for generating VICE label file -define _labelfile_ - LDFLAGS += -Ln $$@.lbl - REMOVES += $(PROGRAM).lbl -endef - -# Linker flags for generating a debug file -define _debugfile_ - LDFLAGS += -Wl --dbgfile,$$@.dbg - REMOVES += $(PROGRAM).dbg -endef - -############################################################################### -### Defaults to be used if nothing defined in the editable sections above ### -############################################################################### - -# Presume the C64 target like the cl65 compile & link utility does. -# Set TARGETS to override. -ifeq ($(TARGETS),) - TARGETS := c64 -endif - -# Presume we're in a project directory so name the program like the current -# directory. Set PROGRAM to override. -ifeq ($(PROGRAM),) - PROGRAM := $(notdir $(CURDIR)) -endif - -# Presume the C and asm source files to be located in the subdirectory 'src'. -# Set SRCDIR to override. -ifeq ($(SRCDIR),) - SRCDIR := src -endif - -# Presume the object and dependency files to be located in the subdirectory -# 'obj' (which will be created). Set OBJDIR to override. -ifeq ($(OBJDIR),) - OBJDIR := obj -endif -TARGETOBJDIR := $(OBJDIR)/$(TARGETS) - -# On Windows it is mandatory to have CC65_HOME set. So do not unnecessarily -# rely on cl65 being added to the PATH in this scenario. -ifdef CC65_HOME - CC := $(CC65_HOME)/bin/cl65 -else - CC := cl65 -endif - -# Default emulator commands and options for particular targets. -# Set EMUCMD to override. -c64_EMUCMD := $(VICE_HOME)xscpu64 -VICIIdsize -autostart -c128_EMUCMD := $(VICE_HOME)x128 -kernal kernal -VICIIdsize -autoload -vic20_EMUCMD := $(VICE_HOME)xvic -kernal kernal -VICdsize -autoload -pet_EMUCMD := $(VICE_HOME)xpet -Crtcdsize -autoload -plus4_EMUCMD := $(VICE_HOME)xplus4 -TEDdsize -autoload -# So far there is no x16 emulator in VICE (why??) so we have to use xplus4 with -memsize option -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 - -ifeq ($(EMUCMD),) - EMUCMD = $($(CC65TARGET)_EMUCMD) -endif - -############################################################################### -### The magic begins ### -############################################################################### - -# The "Native Win32" GNU Make contains quite some workarounds to get along with -# cmd.exe as shell. However it does not provide means to determine that it does -# actually activate those workarounds. Especially does $(SHELL) NOT contain the -# value 'cmd.exe'. So the usual way to determine if cmd.exe is being used is to -# execute the command 'echo' without any parameters. Only cmd.exe will return a -# non-empy string - saying 'ECHO is on/off'. -# -# Many "Native Win32" prorams accept '/' as directory delimiter just fine. How- -# ever the internal commands of cmd.exe generally require '\' to be used. -# -# cmd.exe has an internal command 'mkdir' that doesn't understand nor require a -# '-p' to create parent directories as needed. -# -# cmd.exe has an internal command 'del' that reports a syntax error if executed -# without any file so make sure to call it only if there's an actual argument. -ifeq ($(shell echo),) - MKDIR = mkdir -p $1 - RMDIR = rmdir $1 - RMFILES = $(RM) $1 -else - MKDIR = mkdir $(subst /,\,$1) - RMDIR = rmdir $(subst /,\,$1) - RMFILES = $(if $1,del /f $(subst /,\,$1)) -endif -COMMA := , -SPACE := $(N/A) $(N/A) -define NEWLINE - - -endef -# Note: Do not remove any of the two empty lines above ! - -TARGETLIST := $(subst $(COMMA),$(SPACE),$(TARGETS)) - -ifeq ($(words $(TARGETLIST)),1) - -# Set PROGRAM to something like 'myprog.c64'. -override PROGRAM := $(PROGRAM).xex - -# Set SOURCES to something like 'src/foo.c src/bar.s'. -# Use of assembler files with names ending differently than .s is deprecated! -SOURCES := $(wildcard $(SRCDIR)/*.c) -SOURCES += $(wildcard $(SRCDIR)/*.s) -SOURCES += $(wildcard $(SRCDIR)/*.asm) -SOURCES += $(wildcard $(SRCDIR)/*.a65) - -# Add to SOURCES something like 'src/c64/me.c src/c64/too.s'. -# Use of assembler files with names ending differently than .s is deprecated! -SOURCES += $(wildcard $(SRCDIR)/$(TARGETLIST)/*.c) -SOURCES += $(wildcard $(SRCDIR)/$(TARGETLIST)/*.s) -SOURCES += $(wildcard $(SRCDIR)/$(TARGETLIST)/*.asm) -SOURCES += $(wildcard $(SRCDIR)/$(TARGETLIST)/*.a65) - -# Set OBJECTS to something like 'obj/c64/foo.o obj/c64/bar.o'. -OBJECTS := $(addsuffix .o,$(basename $(addprefix $(TARGETOBJDIR)/,$(notdir $(SOURCES))))) - -# Set DEPENDS to something like 'obj/c64/foo.d obj/c64/bar.d'. -DEPENDS := $(OBJECTS:.o=.d) - -# Add to LIBS something like 'src/foo.lib src/c64/bar.lib'. -LIBS += $(wildcard $(SRCDIR)/*.lib) -LIBS += $(wildcard $(SRCDIR)/$(TARGETLIST)/*.lib) - -# Add to CONFIG something like 'src/c64/bar.cfg src/foo.cfg'. -CONFIG += $(wildcard $(SRCDIR)/$(TARGETLIST)/*.cfg) -CONFIG += $(wildcard $(SRCDIR)/*.cfg) - -# Select CONFIG file to use. Target specific configs have higher priority. -ifneq ($(word 2,$(CONFIG)),) - CONFIG := $(firstword $(CONFIG)) - $(info Using config file $(CONFIG) for linking) -endif - -.SUFFIXES: -.PHONY: all test clean zap love - -all: $(PROGRAM) - --include $(DEPENDS) --include $(STATEFILE) - -# If OPTIONS are given on the command line then save them to STATEFILE -# if (and only if) they have actually changed. But if OPTIONS are not -# given on the command line then load them from STATEFILE. Have object -# files depend on STATEFILE only if it actually exists. -ifeq ($(origin OPTIONS),command line) - ifneq ($(OPTIONS),$(_OPTIONS_)) - ifeq ($(OPTIONS),) - $(info Removing OPTIONS) - $(shell $(RM) $(STATEFILE)) - $(eval $(STATEFILE):) - else - $(info Saving OPTIONS=$(OPTIONS)) - $(shell echo _OPTIONS_=$(OPTIONS) > $(STATEFILE)) - endif - $(eval $(OBJECTS): $(STATEFILE)) - endif -else - ifeq ($(origin _OPTIONS_),file) - $(info Using saved OPTIONS=$(_OPTIONS_)) - OPTIONS = $(_OPTIONS_) - $(eval $(OBJECTS): $(STATEFILE)) - endif -endif - -# Transform the abstract OPTIONS to the actual cc65 options. -$(foreach o,$(subst $(COMMA),$(SPACE),$(OPTIONS)),$(eval $(_$o_))) - -# Strip potential variant suffix from the actual cc65 target. -CC65TARGET := $(firstword $(subst .,$(SPACE),$(TARGETLIST))) - -# The remaining targets. -$(TARGETOBJDIR): - $(call MKDIR,$@) - -vpath %.c $(SRCDIR)/$(TARGETLIST) $(SRCDIR) - -$(TARGETOBJDIR)/%.o: %.c | $(TARGETOBJDIR) - $(CC) -t $(CC65TARGET) -c --create-dep $(@:.o=.d) $(CFLAGS) -o $@ $< - -vpath %.s $(SRCDIR)/$(TARGETLIST) $(SRCDIR) - -$(TARGETOBJDIR)/%.o: %.s | $(TARGETOBJDIR) - $(CC) -t $(CC65TARGET) -Wa -DDYN_DRV=0 -c --create-dep $(@:.o=.d) $(ASFLAGS) -o $@ $< - -vpath %.asm $(SRCDIR)/$(TARGETLIST) $(SRCDIR) - -$(TARGETOBJDIR)/%.o: %.asm | $(TARGETOBJDIR) - $(CC) -t $(CC65TARGET) -c --create-dep $(@:.o=.d) $(ASFLAGS) -o $@ $< - -vpath %.a65 $(SRCDIR)/$(TARGETLIST) $(SRCDIR) - -$(TARGETOBJDIR)/%.o: %.a65 | $(TARGETOBJDIR) - $(CC) -t $(CC65TARGET) -c --create-dep $(@:.o=.d) $(ASFLAGS) -o $@ $< - -$(PROGRAM): $(CONFIG) $(OBJECTS) $(LIBS) - $(CC) -t $(CC65TARGET) $(LDFLAGS) -o $@ $(patsubst %.cfg,-C %.cfg,$^) +# remove the -a if using older versions of atasm +ATASM=atasm -s -a - -test: $(PROGRAM) - $(PREEMUCMD) - $(EMUCMD) $< - $(POSTEMUCMD) - -clean: - $(call RMFILES,$(OBJECTS)) - $(call RMFILES,$(DEPENDS)) - $(call RMFILES,$(REMOVES)) - $(call RMFILES,$(PROGRAM)) - $(call RMFILES,test.map) - $(call RMFILES,$(PROGRAM).map) - $(call RMFILES,test.atr) - -else # $(words $(TARGETLIST)),1 - -all test clean: - $(foreach t,$(TARGETLIST),$(MAKE) TARGETS=$t $@$(NEWLINE)) - -endif # $(words $(TARGETLIST)),1 - -OBJDIRLIST := $(wildcard $(OBJDIR)/*) - -zap: - $(foreach o,$(OBJDIRLIST),-$(call RMFILES,$o/*.o $o/*.d $o/*.lst)$(NEWLINE)) - $(foreach o,$(OBJDIRLIST),-$(call RMDIR,$o)$(NEWLINE)) - -$(call RMDIR,$(OBJDIR)) - -$(call RMFILES,$(basename $(PROGRAM)).* $(STATEFILE)) - -love: - @echo "Not war, eh?" +all: fnchat.xex -################################################################### -### Place your additional targets in the additional Makefiles ### -### in the same directory - their names have to end with ".mk"! ### -################################################################### --include *.mk +fnchat.xex: $(PARTS) + cat $(PARTS) > fnchat.xex + +client.xex: + $(MAKE) -f Makefile.client + +%.xex: %.asm + $(ATASM) -o$@ $< + +memsetup.xex: memsetup.asm + +font_dl.xex: font_dl.asm font.dat + +test: + cl65 -C src/atari.cfg -t atari -o testmain.xex src/addrs.c src/edbox.c src/screen.c uitest/test.c + cat memsetup.xex font_dl.xex testmain.xex > test.xex diff --git a/Makefile.client b/Makefile.client new file mode 100644 index 0000000..febbae0 --- /dev/null +++ b/Makefile.client @@ -0,0 +1,350 @@ +############################################################################### +### Generic Makefile for cc65 projects - full version with abstract options ### +### V1.3.0(w) 2010 - 2013 Oliver Schmidt & Patryk "Silver Dream !" Łogiewa ### +############################################################################### + +############################################################################### +### In order to override defaults - values can be assigned to the variables ### +############################################################################### + +# Space or comma separated list of cc65 supported target platforms to build for. +# Default: c64 (lowercase!) +TARGETS := atari + +# Name of the final, single-file executable. +# Default: name of the current dir with target name appended +PROGRAM := fnchat + +# Path(s) to additional libraries required for linking the program +# Use only if you don't want to place copies of the libraries in SRCDIR +# Default: none +LIBS := + +# Custom linker configuration file +# Use only if you don't want to place it in SRCDIR +# Default: none +CONFIG := + +# Additional C compiler flags and options. +# Default: none +CFLAGS = -Oris + +# Additional assembler flags and options. +# Default: none +ASFLAGS = + +# Additional linker flags and options. +# Default: none +LDFLAGS = $(LDFLAGS.$(TARGETS)) +LDFLAGS.atari = --mapfile $(PROGRAM).map + +# Path to the directory containing C and ASM sources. +# Default: src +SRCDIR := + +# Path to the directory where object files are to be stored (inside respective target subdirectories). +# Default: obj +OBJDIR := + +# Command used to run the emulator. +# Default: depending on target platform. For default (c64) target: x64 -kernal kernal -VICIIdsize -autoload +EMUCMD := + +# Optional commands used before starting the emulation process, and after finishing it. +# Default: none +#PREEMUCMD := osascript -e "tell application \"System Events\" to set isRunning to (name of processes) contains \"X11.bin\"" -e "if isRunning is true then tell application \"X11\" to activate" +#PREEMUCMD := osascript -e "tell application \"X11\" to activate" +#POSTEMUCMD := osascript -e "tell application \"System Events\" to tell process \"X11\" to set visible to false" +#POSTEMUCMD := osascript -e "tell application \"Terminal\" to activate" +PREEMUCMD := +POSTEMUCMD := + +# On Windows machines VICE emulators may not be available in the PATH by default. +# In such case, please set the variable below to point to directory containing +# VICE emulators. +#VICE_HOME := "C:\Program Files\WinVICE-2.2-x86\" +VICE_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 +STATEFILE := Makefile.options + +################################################################################### +#### DO NOT EDIT BELOW THIS LINE, UNLESS YOU REALLY KNOW WHAT YOU ARE DOING! #### +################################################################################### + +################################################################################### +### Mapping abstract options to the actual compiler, assembler and linker flags ### +### Predefined compiler, assembler and linker flags, used with abstract options ### +### valid for 2.14.x. Consult the documentation of your cc65 version before use ### +################################################################################### + +# Compiler flags used to tell the compiler to optimise for SPEED +define _optspeed_ + CFLAGS += -Oris +endef + +# Compiler flags used to tell the compiler to optimise for SIZE +define _optsize_ + CFLAGS += -Or +endef + +# Compiler and assembler flags for generating listings +define _listing_ + CFLAGS += --listing $$(@:.o=.lst) + ASFLAGS += --listing $$(@:.o=.lst) + REMOVES += $(addsuffix .lst,$(basename $(OBJECTS))) +endef + +# Linker flags for generating map file +define _mapfile_ + LDFLAGS += --mapfile $$@.map + REMOVES += $(PROGRAM).map +endef + +# Linker flags for generating VICE label file +define _labelfile_ + LDFLAGS += -Ln $$@.lbl + REMOVES += $(PROGRAM).lbl +endef + +# Linker flags for generating a debug file +define _debugfile_ + LDFLAGS += -Wl --dbgfile,$$@.dbg + REMOVES += $(PROGRAM).dbg +endef + +############################################################################### +### Defaults to be used if nothing defined in the editable sections above ### +############################################################################### + +# Presume the C64 target like the cl65 compile & link utility does. +# Set TARGETS to override. +ifeq ($(TARGETS),) + TARGETS := c64 +endif + +# Presume we're in a project directory so name the program like the current +# directory. Set PROGRAM to override. +ifeq ($(PROGRAM),) + PROGRAM := $(notdir $(CURDIR)) +endif + +# Presume the C and asm source files to be located in the subdirectory 'src'. +# Set SRCDIR to override. +ifeq ($(SRCDIR),) + SRCDIR := src +endif + +# Presume the object and dependency files to be located in the subdirectory +# 'obj' (which will be created). Set OBJDIR to override. +ifeq ($(OBJDIR),) + OBJDIR := obj +endif +TARGETOBJDIR := $(OBJDIR)/$(TARGETS) + +# On Windows it is mandatory to have CC65_HOME set. So do not unnecessarily +# rely on cl65 being added to the PATH in this scenario. +ifdef CC65_HOME + CC := $(CC65_HOME)/bin/cl65 +else + CC := cl65 +endif + +# Default emulator commands and options for particular targets. +# Set EMUCMD to override. +c64_EMUCMD := $(VICE_HOME)xscpu64 -VICIIdsize -autostart +c128_EMUCMD := $(VICE_HOME)x128 -kernal kernal -VICIIdsize -autoload +vic20_EMUCMD := $(VICE_HOME)xvic -kernal kernal -VICdsize -autoload +pet_EMUCMD := $(VICE_HOME)xpet -Crtcdsize -autoload +plus4_EMUCMD := $(VICE_HOME)xplus4 -TEDdsize -autoload +# So far there is no x16 emulator in VICE (why??) so we have to use xplus4 with -memsize option +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 + +ifeq ($(EMUCMD),) + EMUCMD = $($(CC65TARGET)_EMUCMD) +endif + +############################################################################### +### The magic begins ### +############################################################################### + +# The "Native Win32" GNU Make contains quite some workarounds to get along with +# cmd.exe as shell. However it does not provide means to determine that it does +# actually activate those workarounds. Especially does $(SHELL) NOT contain the +# value 'cmd.exe'. So the usual way to determine if cmd.exe is being used is to +# execute the command 'echo' without any parameters. Only cmd.exe will return a +# non-empy string - saying 'ECHO is on/off'. +# +# Many "Native Win32" prorams accept '/' as directory delimiter just fine. How- +# ever the internal commands of cmd.exe generally require '\' to be used. +# +# cmd.exe has an internal command 'mkdir' that doesn't understand nor require a +# '-p' to create parent directories as needed. +# +# cmd.exe has an internal command 'del' that reports a syntax error if executed +# without any file so make sure to call it only if there's an actual argument. +ifeq ($(shell echo),) + MKDIR = mkdir -p $1 + RMDIR = rmdir $1 + RMFILES = $(RM) $1 +else + MKDIR = mkdir $(subst /,\,$1) + RMDIR = rmdir $(subst /,\,$1) + RMFILES = $(if $1,del /f $(subst /,\,$1)) +endif +COMMA := , +SPACE := $(N/A) $(N/A) +define NEWLINE + + +endef +# Note: Do not remove any of the two empty lines above ! + +TARGETLIST := $(subst $(COMMA),$(SPACE),$(TARGETS)) + +ifeq ($(words $(TARGETLIST)),1) + +# Set PROGRAM to something like 'myprog.c64'. +override PROGRAM := $(PROGRAM).xex + +# Set SOURCES to something like 'src/foo.c src/bar.s'. +# Use of assembler files with names ending differently than .s is deprecated! +SOURCES := $(wildcard $(SRCDIR)/*.c) +SOURCES += $(wildcard $(SRCDIR)/*.s) +SOURCES += $(wildcard $(SRCDIR)/*.asm) +SOURCES += $(wildcard $(SRCDIR)/*.a65) + +# Add to SOURCES something like 'src/c64/me.c src/c64/too.s'. +# Use of assembler files with names ending differently than .s is deprecated! +SOURCES += $(wildcard $(SRCDIR)/$(TARGETLIST)/*.c) +SOURCES += $(wildcard $(SRCDIR)/$(TARGETLIST)/*.s) +SOURCES += $(wildcard $(SRCDIR)/$(TARGETLIST)/*.asm) +SOURCES += $(wildcard $(SRCDIR)/$(TARGETLIST)/*.a65) + +# Set OBJECTS to something like 'obj/c64/foo.o obj/c64/bar.o'. +OBJECTS := $(addsuffix .o,$(basename $(addprefix $(TARGETOBJDIR)/,$(notdir $(SOURCES))))) + +# Set DEPENDS to something like 'obj/c64/foo.d obj/c64/bar.d'. +DEPENDS := $(OBJECTS:.o=.d) + +# Add to LIBS something like 'src/foo.lib src/c64/bar.lib'. +LIBS += $(wildcard $(SRCDIR)/*.lib) +LIBS += $(wildcard $(SRCDIR)/$(TARGETLIST)/*.lib) + +# Add to CONFIG something like 'src/c64/bar.cfg src/foo.cfg'. +CONFIG += $(wildcard $(SRCDIR)/$(TARGETLIST)/*.cfg) +CONFIG += $(wildcard $(SRCDIR)/*.cfg) + +# Select CONFIG file to use. Target specific configs have higher priority. +ifneq ($(word 2,$(CONFIG)),) + CONFIG := $(firstword $(CONFIG)) + $(info Using config file $(CONFIG) for linking) +endif + +.SUFFIXES: +.PHONY: all test clean zap love + +all: $(PROGRAM) + +-include $(DEPENDS) +-include $(STATEFILE) + +# If OPTIONS are given on the command line then save them to STATEFILE +# if (and only if) they have actually changed. But if OPTIONS are not +# given on the command line then load them from STATEFILE. Have object +# files depend on STATEFILE only if it actually exists. +ifeq ($(origin OPTIONS),command line) + ifneq ($(OPTIONS),$(_OPTIONS_)) + ifeq ($(OPTIONS),) + $(info Removing OPTIONS) + $(shell $(RM) $(STATEFILE)) + $(eval $(STATEFILE):) + else + $(info Saving OPTIONS=$(OPTIONS)) + $(shell echo _OPTIONS_=$(OPTIONS) > $(STATEFILE)) + endif + $(eval $(OBJECTS): $(STATEFILE)) + endif +else + ifeq ($(origin _OPTIONS_),file) + $(info Using saved OPTIONS=$(_OPTIONS_)) + OPTIONS = $(_OPTIONS_) + $(eval $(OBJECTS): $(STATEFILE)) + endif +endif + +# Transform the abstract OPTIONS to the actual cc65 options. +$(foreach o,$(subst $(COMMA),$(SPACE),$(OPTIONS)),$(eval $(_$o_))) + +# Strip potential variant suffix from the actual cc65 target. +CC65TARGET := $(firstword $(subst .,$(SPACE),$(TARGETLIST))) + +# The remaining targets. +$(TARGETOBJDIR): + $(call MKDIR,$@) + +vpath %.c $(SRCDIR)/$(TARGETLIST) $(SRCDIR) + +$(TARGETOBJDIR)/%.o: %.c | $(TARGETOBJDIR) + $(CC) -t $(CC65TARGET) -c --create-dep $(@:.o=.d) $(CFLAGS) -o $@ $< + +vpath %.s $(SRCDIR)/$(TARGETLIST) $(SRCDIR) + +$(TARGETOBJDIR)/%.o: %.s | $(TARGETOBJDIR) + $(CC) -t $(CC65TARGET) -Wa -DDYN_DRV=0 -c --create-dep $(@:.o=.d) $(ASFLAGS) -o $@ $< + +vpath %.asm $(SRCDIR)/$(TARGETLIST) $(SRCDIR) + +$(TARGETOBJDIR)/%.o: %.asm | $(TARGETOBJDIR) + $(CC) -t $(CC65TARGET) -c --create-dep $(@:.o=.d) $(ASFLAGS) -o $@ $< + +vpath %.a65 $(SRCDIR)/$(TARGETLIST) $(SRCDIR) + +$(TARGETOBJDIR)/%.o: %.a65 | $(TARGETOBJDIR) + $(CC) -t $(CC65TARGET) -c --create-dep $(@:.o=.d) $(ASFLAGS) -o $@ $< + +$(PROGRAM): $(CONFIG) $(OBJECTS) $(LIBS) + $(CC) -t $(CC65TARGET) $(LDFLAGS) -o $@ $(patsubst %.cfg,-C %.cfg,$^) + + +test: $(PROGRAM) + $(PREEMUCMD) + $(EMUCMD) $< + $(POSTEMUCMD) + +clean: + $(call RMFILES,$(OBJECTS)) + $(call RMFILES,$(DEPENDS)) + $(call RMFILES,$(REMOVES)) + $(call RMFILES,$(PROGRAM)) + $(call RMFILES,test.map) + $(call RMFILES,$(PROGRAM).map) + $(call RMFILES,test.atr) + +else # $(words $(TARGETLIST)),1 + +all test clean: + $(foreach t,$(TARGETLIST),$(MAKE) TARGETS=$t $@$(NEWLINE)) + +endif # $(words $(TARGETLIST)),1 + +OBJDIRLIST := $(wildcard $(OBJDIR)/*) + +zap: + $(foreach o,$(OBJDIRLIST),-$(call RMFILES,$o/*.o $o/*.d $o/*.lst)$(NEWLINE)) + $(foreach o,$(OBJDIRLIST),-$(call RMDIR,$o)$(NEWLINE)) + -$(call RMDIR,$(OBJDIR)) + -$(call RMFILES,$(basename $(PROGRAM)).* $(STATEFILE)) + +love: + @echo "Not war, eh?" + +################################################################### +### Place your additional targets in the additional Makefiles ### +### in the same directory - their names have to end with ".mk"! ### +################################################################### +-include *.mk diff --git a/font.dat b/font.dat Binary files differnew file mode 100644 index 0000000..0527aaf --- /dev/null +++ b/font.dat diff --git a/font_dl.asm b/font_dl.asm new file mode 100644 index 0000000..bbb2b98 --- /dev/null +++ b/font_dl.asm @@ -0,0 +1,56 @@ + *= $a000 + .incbin "font.dat" +dlist + .byte $70, $70, $30 ; 2 8-line blanks, 1 4-line blank + .byte $42 ; LMS GR.0 +dl_top_lms + .word $a500 ; base address of 1st screen + .byte $02, $02, $02, $02, $02, $02, $02, $02 + .byte $02, $02, $02, $02, $02, $02, $02, $02 + .byte $02, $02, $02, $02, $02, $02 ; 22 GR.0 lines + .byte $00 ; 1 blank line + .byte $42 ; another LMS (edit/status box) +dl_bottom_lms + .word $a480 ; edit box base address + .word $02 ; 2nd line of edit box + .byte $41 ; JVB + .word dlist + +status_box + *= * + 80 ; 2 lines + +edit_box + *= * + 160 ; 4 lines + +end_boxes ; currently $a515 + +; screens are 920 bytes each (23 lines * 40), cannot +; cross the 4K boundary at $b000, and must end +; before the ROM (or unwired addresses) at $c000. + +; on a 52K machine (expanded 800 or XL/XE running Translator), +; we'd have another 4K of RAM from $c000-$cfff. With Translator, +; we also could have 2K at $d800-$dfff (the floating point ROM, +; which we don't use)... and we wouldn't have to have the font +; at $a000, it could be plopped right into the OS default location +; at $e000. maybe this will happen someday. meanwhile: + + *= $b000 - (920 * 3) +screen0 + *= * + 920 +screen1 + *= * + 920 +screen2 ; ends 1 byte before $b000 boundary + *= * + 920 +screen3 ; starts at $b000 boundary + *= * + 920 +screen4 + *= * + 920 +screen5 + *= * + 920 +screen6 + *= * + 920 +end_screens ; currently $be60 + +; 7 screens ain't so bad, really. eventually though, we want to +; add scrollback to them, meaning fewer of them. sigh. diff --git a/memsetup.asm b/memsetup.asm new file mode 100644 index 0000000..49d8149 --- /dev/null +++ b/memsetup.asm @@ -0,0 +1,11 @@ + *= $2000 +memsetup + lda #$a0 + sta $6a ; RAMTOP + sta $02e6 ; MEMTOP high + lda #0 + sta $02e5 ; MEMTOP low + rts + + *= $02e2 ; INITAD + .word memsetup diff --git a/src/addrs.c b/src/addrs.c new file mode 100644 index 0000000..8c4ad1b --- /dev/null +++ b/src/addrs.c @@ -0,0 +1,27 @@ +#include "addrs.h" + +u8 *dlist = u8p(DLIST_ADDR); +u16 *dlist_top_lms = u16p(0xa404); +u16 *dlist_bottom_lms = u16p(0xa41e); +u8 *status_box = u8p(0xa425); /* 80 bytes */ +u8 *edit_box = u8p(0xa475); /* 160 bytes */ + +u8 *screen_addrs[7] = { + u8p(0xa538), + u8p(0xa8d0), + u8p(0xac68), + u8p(0xb000), + u8p(0xb398), + u8p(0xb730), + u8p(0xbac8) +}; + +u8 *screen_botlines[7] = { + u8p(0xa8a8), + u8p(0xac40), + u8p(0xafd8), + u8p(0xb370), + u8p(0xb708), + u8p(0xbaa0), + u8p(0xbe38) +}; diff --git a/src/addrs.h b/src/addrs.h new file mode 100644 index 0000000..6d44a68 --- /dev/null +++ b/src/addrs.h @@ -0,0 +1,15 @@ +#define FONT_ADDR_HI 0xa0 +#define DLIST_ADDR 0xa400 + +#define u8 unsigned char +#define u8p(x) ((unsigned char *)x) +#define u16 unsigned int +#define u16p(x) ((unsigned int *)x) + +extern u8 *dlist; +extern u16 *dlist_top_lms; +extern u16 *dlist_bottom_lms; +extern u8 *status_box; +extern u8 *edit_box; +extern u8 *screen_addrs[7]; +extern u8 *screen_botlines[7]; diff --git a/src/edbox.c b/src/edbox.c new file mode 100644 index 0000000..f1c77d1 --- /dev/null +++ b/src/edbox.c @@ -0,0 +1,138 @@ +#include <atari.h> +#include <conio.h> +#include <string.h> +#include "addrs.h" +#include "screen.h" +#include "edbox.h" + +/* TODO: tab completion */ + +// static int edbox_visible = 0; /* don't think we'll ever need it */ +static u16 edbox_pos; /* range 0 to EDBOX_SIZE - 1 */ + +void (*edbox_callback)(void); + +static void hide_cursor(void) { + edit_box[edbox_pos] &= 0x7f; +} + +static void show_cursor(void) { + edit_box[edbox_pos] |= 0x80; +} + +void edbox_clear(void) { + memset(edit_box, 0, EDBOX_SIZE); + edbox_pos = 0; + show_cursor(); +} + +void edbox_show(void) { + u16 addr; + + if(edbox_pos < 80) + addr = (u16)edit_box; + else + addr = (u16)edit_box + edbox_pos - 79; + + scr_waitvcount(116); + + *dlist_bottom_lms = addr; +} + +void edbox_hide(void) { + scr_refresh(); +} + +void edbox_putc(char c) { + if(!c) + return; /* no inserting nulls */ + if((c != CH_EOL) && (edbox_pos == EDBOX_SIZE - 1)) + return; + edit_box[edbox_pos++] = c; + edbox_show(); +} + +static void special_keystroke(char c) { + OS.ch = 0xff; + edbox_putc(c); +} + +static void backspace(void) { + if(!edbox_pos) return; + edit_box[--edbox_pos] = 0; + edbox_show(); +} + +static void del_word(void) { +} + +static void normal_keystroke(void) { + char c; + + c = cgetc(); + + switch(c) { + case CH_EOL: + edbox_putc(c); + if(edbox_callback) + (*edbox_callback)(); + /* fall thru */ + case CH_CLR: + edbox_hide(); + /* fall thru */ + case CH_DELLINE: + case 0x15: /* ^U */ + edbox_clear(); + break; + case CH_DEL: + backspace(); + break; + case 0x17: /* ^W */ + del_word(); + break; + default: + edbox_putc(c); + break; + } +} + +void edbox_keystroke(void) { + char c; + + hide_cursor(); + edbox_show(); + + OS.invflg = c = 0; + + /* XXX: these keys don't click. */ + switch(OS.ch) { + case 0xa0: /* key: ctrl [ */ + c = 0x7b; /* ascii: { */ + break; + case 0xa2: /* key: ctrl ] */ + c = 0x7d; /* ascii: } */ + break; + case 0x1c: /* key: ESC */ + c = 0x60; /* ascii: ` */ + break; + case 0x5c: /* key: shift ESC */ + case 0x9c: /* key: ctrl ESC */ + c = 0x7e; /* ascii: ~ */ + break; + case 0x27: /* atari key */ + case 0x67: /* ...w/shift */ + case 0x97: /* ...w/ctrl */ + return; /* ignore it! */ + break; + default: + break; + } + + if(c) { + special_keystroke(c); + } else { + normal_keystroke(); + } + + show_cursor(); +} diff --git a/src/edbox.h b/src/edbox.h new file mode 100644 index 0000000..ad70cc6 --- /dev/null +++ b/src/edbox.h @@ -0,0 +1,14 @@ +#include "addrs.h" + +/**** public API ****/ + +#define EDBOX_SIZE 160 + +void edbox_clear(void); +void edbox_show(void); +void edbox_hide(void); +void edbox_putc(char c); +void edbox_keystroke(void); + +/* called when the user presses Enter */ +extern void (*edbox_callback)(void); diff --git a/src/screen.c b/src/screen.c new file mode 100644 index 0000000..7f34331 --- /dev/null +++ b/src/screen.c @@ -0,0 +1,222 @@ +#include <atari.h> +#include <string.h> + +#include "addrs.h" +#include "screen.h" + +#define SDLST ((u16 *)0x0230) + +char scr_active[MAX_SCREENS]; + +/* the screen that's currently displaying */ +char scr_current; + +static char scr_names[7][32]; +static char scr_topics[7][40]; + +static char xpos; + +void scr_waitvcount(u8 c) { + while(ANTIC.vcount < c) + /* NOP */; +} + +static void scr_clear(char s) { + memset(screen_addrs[s], 0, SCREEN_SIZE); + memset(scr_names[s], 0, 32); + memset(scr_topics[s], 0, LINE_SIZE); +} + +static void scr_scroll(char s) { + memmove(screen_addrs[s], screen_addrs[s] + 40, 880); + memset(screen_botlines[s], 0, 40); +} + +void scr_init(void) { + int i, old_dma; + + old_dma = OS.sdmctl; + OS.sdmctl = 0; + scr_waitvcount(112); /* after the last GR.0 line */ + *SDLST = DLIST_ADDR; + OS.chbas = FONT_ADDR_HI; + + for(i = 0; i < MAX_SCREENS; i++) { + scr_clear(i); + scr_active[i] = SCR_UNUSED; + } + + strcpy(scr_names[0], "[server]"); + strcpy(scr_names[1], "[private]"); + scr_active[0] = scr_active[1] = SCR_INACTIVE; + + OS.sdmctl = old_dma; + + scr_display(0); +} + +char scr_create(const char *name, char display) { + int i; + + for(i = 0; i < MAX_SCREENS; i++) { + if(scr_active[i] == SCR_UNUSED) { + strcpy(scr_names[i], name); + scr_active[i] = SCR_INACTIVE; + scr_topics[i][0] = '\0'; + if(display) + scr_display(i); + else + scr_display(scr_current); + return i; + } + } + + // scr_print(SCR_CURR, "Can't create window (all in use)\n"); + return 0xff; +} + +void scr_destroy(char s) { + /* <2 because screens 0 and 1 (server and private) cannot be destroyed */ + if(s < 2 || s >= MAX_SCREENS) + return; + + scr_active[s] = SCR_UNUSED; + if(scr_current == s) + scr_display(0); +} + +void scr_set_topic(char s, const char *topic) { + strncpy(scr_topics[s], topic, 40); +} + +void scr_display(char s) { + if(s >= MAX_SCREENS) + return; + + /* leave this out, for testing + if(scr_active[s] == SCR_UNUSED) + return; + */ + + scr_active[s] = SCR_INACTIVE; + scr_current = s; + + scr_waitvcount(112); + *dlist_top_lms = (u16)screen_addrs[s]; + + scr_show_status(s); +} + +void scr_show_status(char s) { + int i; + char *p, sc; + + status_box[0] = s + 177; /* inverse number */ + status_box[1] = ':'; + strncpy(status_box + 2, scr_names[s], 32); + strncpy(status_box + 40, scr_topics[s], 40); + + p = status_box + 33; + for(i = 0; i < MAX_SCREENS; i++) { + switch(scr_active[i]) { + case SCR_ACTIVE: + sc = 128 | ('1' + i); break; + case SCR_INACTIVE: + sc = '1' + i; break; + default: + sc = ' '; + } + *p++ = sc; + } + + scr_waitvcount(112); + *dlist_bottom_lms = (u16)status_box; +} + +void scr_refresh(void) { + scr_display(scr_current); +} + +char scr_getbyname(const char *name) { + char i; + + for(i = 2; i < MAX_SCREENS; i++) { + if(strcasecmp(name, scr_names[i]) == 0) + return i; + } + + return 0; +} + +/* TODO: skip color codes (start with 0x03 or 0x04). + if we're going to ever support utf-8, decode it here... + also, 0x16 is supposed to be reverse video. not widely used/supported. + eventually, this will be rewritten in asm anyway. */ +void scr_putc(char s, char c) { + u8 *dest; + static char bold = 0; + + if(s == SCR_CURR) + s = scr_current; + + if(c == '\n') { + bold = 0; + if(!xpos) + return; + xpos = 40; + return; + } + + if(xpos == 40) { + scr_scroll(s); + xpos = 0; + } + + dest = screen_botlines[s] + xpos; + + if(c & 0x80) { + /* utf-8 (or maybe latin-1), we don't support it yet */ + c = 0xbf; /* inverse ? */ + } else if(c == 0x02) { + bold = !bold; + return; + } else if(c == 0x1d) { + /* italics */ + c = '/'; + } else if(c == 0x1e) { + /* strikethru */ + c = '-'; + } else if(c == 0x1f) { + /* underline */ + c = '_'; + } else if(c == 0x0f) { + /* all formatting off */ + bold = 0; + return; + } else if(c < 0x20) { + /* unsupported control character */ + c += 192; + } + + if(bold) c |= 0x80; + + *dest = c; + xpos++; +} + +void scr_print(char s, const char *text) { + while(*text) { + scr_putc(s, *text); + if(*text == '\n') + break; + text++; + } + scr_activate(s); +} + +void scr_activate(char s) { + if(s != scr_current) { + scr_active[s] = SCR_ACTIVE; + scr_show_status(scr_current); + } +} diff --git a/src/screen.h b/src/screen.h new file mode 100644 index 0000000..5762009 --- /dev/null +++ b/src/screen.h @@ -0,0 +1,103 @@ +#include "addrs.h" + +#define MAX_SCREENS 7 +#define LINE_SIZE 40 +#define SCREEN_SIZE 920 +#define BOTTOM_LINE_OFFS 880 + +#define SCR_UNUSED 0 +#define SCR_INACTIVE 1 +#define SCR_ACTIVE 2 + +#define SCR_CURR 0xff + +/**** public API ****/ + +/* the screen that's currently displaying */ +extern char scr_current; + +/* which screens are "active". the screen being displayed is + never active. any screen that's not visible that's had anything + written to it gets marked active. switching the display to an + active screen clears its active flag. */ +extern char scr_active[MAX_SCREENS]; + +/* call before using any of the other functions. sets up the + display list, clears all screen memory, selects screen 0 + for display. */ +void scr_init(void); + +/* creates a screen, if possible. we only get 7; attempts to create + more that that will return -1. on success, returns the screen + number (0-6). the name gets copied to the 1st line of the screen's + status box. + if display is true, the new screen displays. otherwise it's created + "in the background". + */ +char scr_create(const char *name, char display); + +/* destroys a screen (frees up its slot). */ +void scr_destroy(char s); + +/* sets the topic for a screen (the 2nd line of the status box). + this can't just be another argument to scr_create() because we + don't know the topic yet when we create a screen (also, the + server and msgs windows don't have topics anyway). */ +void scr_set_topic(char s, const char *topic); + +/* switch display to screen s. updates the display list. clears + s's active flag. calls scr_show_status(). */ +void scr_display(char s); + +/* XXX: does this need to be public? */ +void scr_show_status(char s); + +/* calls scr_display() on the currently-visible screen. + called by the edit box code, when closing the edit box (user has + pressed Enter or aborted the message). */ +void scr_refresh(void); + +/* given a channel name, find its screen. if there's no match, + returns 0 (the server messages screen) */ +char scr_getbyname(const char *name); + +/* print one character to a screen. handles scrolling. will not + print an EOL at column 0 (just ignores it). */ +void scr_putc(char s, char c); + +/* print text to a screen. handles scrolling. this + doesn't have to be the screen being displayed, of course; + if it's not, it gets marked as active. */ +void scr_print(char s, const char *text); + +/* set a screen's status to active, if it's not the currently-displayed + one. scr_print() sets it already, but anything that uses scr_putc() + will have to call this. */ +void scr_activate(char s); + +/* XXX: this really should be in a utils.c or common.c... */ +void scr_waitvcount(u8 c); + +/**** end of public API ****/ + +/* notes: + +If a character gets printed to the bottom right corner of a screen, +it *doesn't* scroll yet. It will, the next time a character is printed +to that screen. + +This thing uses a modified font that's in ASCII order rather than +Atari screencode order. So "printing" just means copying... except +for IRC formatting codes. + +scr_print() has to handle formatting: at least it should print inverse +video for either bold or italic. It will print incoming inverse +video as-is; it's the caller's responsibility to replace unprintable +characters (e.g. any char >= 128 might become an inverse question +mark). This has to happen because nick highlighting will use inverse +video. + +Also, scr_print() should eventually be smart enough to strip out color +codes. + +*/ diff --git a/uitest/test.c b/uitest/test.c new file mode 100644 index 0000000..93264dd --- /dev/null +++ b/uitest/test.c @@ -0,0 +1,65 @@ +#include <atari.h> +#include <stdio.h> +#include <conio.h> +#include <string.h> +#include "../src/screen.h" +#include "../src/edbox.h" + +void got_line(void) { + scr_print(SCR_CURR, edit_box); +} + +int main() { + char i, s; + char buf[40]; + + OS.color2 = 0xc2; + OS.color1 = 0x0e; + + scr_init(); + edbox_callback = got_line; + + /* + for(i = 0; i < 4; i++) { + sprintf(buf, "screen%d", i); + s = scr_create(buf, 0); + scr_set_topic(s + 1, "This is screen #%d."); + } + */ + + for(i = 0; i < 19; i++) { + sprintf(buf, "line %d\n", i); + scr_print(0, buf); + } + + scr_print(0, "Hold Start and press:\n"); + scr_print(0, "N: Create new screen, C: Close screen\n"); + scr_print(0, "1-7: Switch to screen (if exists).\n"); + scr_print(0, "To enter text, just start typing.\n"); + + while(1) { + if(OS.ch != 0xff) { + if(GTIA_READ.consol == 6) { /* start pressed */ + i = cgetc(); + if(i >= '1' && i <= '7') { + if(scr_active[i - '1'] != SCR_UNUSED) + scr_display(i - '1'); + } else if(i == 'n') { + s = scr_create("new screen", 1); + if(s != 0xff) { + scr_print(0, "Screen #"); + scr_putc(0, s + '1'); + scr_print(0, " created.\n"); + } else { + scr_print(scr_current, "Can't create screen (all in use)\n"); + } + } else if(i == 'c') { + scr_destroy(scr_current); + } + } else { + edbox_keystroke(); + } + } + } + return 0; +} |
