diff --git a/Makefile b/Makefile index 73811a4a..8b65ee95 100644 --- a/Makefile +++ b/Makefile @@ -26,14 +26,16 @@ TARGETSTRIP = $(TOOLSPREFIX)strip TARGETCXXFLAGS = # Directory containing the source to sdcc -SDCCDIR = $(TOPDIR)/sdcc -#SDCCDIR = $(ZGB_PATH)/../env/SDCC +#SDCCDIR = $(TOPDIR)/sdcc +SDCCDIR = $(ZGB_PATH)/../env/SDCC # Directory containing the source to gbdk-lib GBDKLIBDIR = $(TOPDIR)/gbdk-lib # Directory containing the source to gbdk-support GBDKSUPPORTDIR = $(TOPDIR)/gbdk-support # Directory containing the source to maccer MACCERDIR = $(TOPDIR)/maccer +# Directory containing the source to linker +LINKERDIR = $(TOPDIR)/link # Base setup # Extension to add to executables @@ -53,7 +55,7 @@ NOISELOG = $(TOPDIR)/noise.log all: native-build -clean: maccer-clean gbdk-support-clean gbdk-lib-clean +clean: maccer-clean linker-clean gbdk-support-clean gbdk-lib-clean distclean: clean build-dir-clean @@ -95,9 +97,9 @@ src: clean tar czf gbdk-$(VER).tar.gz gbdk # Base rules -gbdk-build: maccer-build gbdk-support-build gbdk-lib-build +gbdk-build: maccer-build linker-build gbdk-support-build gbdk-lib-build -gbdk-install: gbdk-support-install gbdk-lib-install +gbdk-install: build-bin-dir linker-install gbdk-support-install gbdk-lib-install # Directories build-bin-dir: @@ -121,36 +123,7 @@ setup-from-cvs: cvs -d :pserver:anonymous@cvs.gbdk.sourceforge.net:/cvsroot/gbdk -q co $(CVSFLAGS) gbdk-support # Rules for sdcc -SDCCCONFIGUREFLAGS = \ - --disable-mcs51-port \ - --disable-avr-port \ - --disable-ds390-port \ - --disable-pic-port \ - --disable-i186-port \ - --disable-tlcs900h-port \ - --disable-ucsim \ - --disable-device-lib-build \ - --disable-packihx -SDCCCONFIGUREFLAGS += \ - --prefix=$(TARGETDIR) \ - --program-suffix=$(EXEEXTENSION) - -sdcc-build: $(SDCCDIR)/sdccconf.h - $(MAKE) -C $(SDCCDIR) SDCC_SUB_VERSION=$(PKG)-$(VER) - -$(SDCCDIR)/sdccconf.h: - cd $(SDCCDIR); CC=$(TARGETCC) CXX=$(TARGETCXX) STRIP=$(TARGETSTRIP) RANLIB=$(TARGETRANLIB) CXXFLAGS=$(TARGETCXXFLAGS) ./configure $(SDCCCONFIGUREFLAGS) --host=$(HOSTOS) - -sdcc-install: sdcc-build build-bin-dir - rm -fr tmp - $(MAKE) -C $(SDCCDIR) install prefix=$(TOPDIR)/tmp - cp tmp/bin/sdcc* tmp/bin/sdcpp* tmp/bin/link-* tmp/bin/as-* $(BUILDDIR)/bin - -# PENDING: Hack below -sdcc-clean: - -$(MAKE) -C $(SDCCDIR) distclean - touch $(SDCCDIR)/doc/holder.pdf # Rules for gbdk-support gbdk-support-build: @@ -184,10 +157,21 @@ gbdk-lib-examples-makefile: # Rules for maccer maccer-build: - $(MAKE) -C $(MACCERDIR) + $(MAKE) -C $(MACCERDIR) BUILDDIR=$(BUILDDIR) maccer-clean: $(MAKE) -C $(MACCERDIR) clean + +#rules for linker +linker-build: + $(MAKE) -C $(LINKERDIR) + +linker-install: + $(MAKE) -C $(LINKERDIR) install BUILDDIR=$(BUILDDIR) + +linker-clean: + $(MAKE) -C $(LINKERDIR) clean + # Final binary binary: binary-tidyup diff --git a/link/Makefile b/link/Makefile new file mode 100644 index 00000000..6eb0096e --- /dev/null +++ b/link/Makefile @@ -0,0 +1,16 @@ +PRJDIR = ./ + +LINK_DIR = $(shell pwd) + +include Makefile.common + +PORTS = gbz80 + +all: + $(MAKE) -C z80 _link-gbz80 E=$(E) BUILDDIR=../bin/ + +install: all + $(INSTALL) $(PRJDIR)/bin/link-gbz80 `echo $(BUILDDIR)/bin/link-gbz80|sed '$(transform)'` + $(STRIP) `echo $(BUILDDIR)/bin/link-gbz80.exe|sed '$(transform)'` + +include clean.mk diff --git a/link/Makefile.common b/link/Makefile.common new file mode 100644 index 00000000..fb0bcaab --- /dev/null +++ b/link/Makefile.common @@ -0,0 +1,65 @@ +# Generated automatically from Makefile.common.in by configure. +# +# +# + +# HACK +PORT = mcs51 + +# Version +VERSION = 2.3.1 +VERSIONHI = 2 +VERSIONLO = 3 +VERSIONP = 1 + +# Programs +SHELL = /bin/sh +CC = gcc +CPP = gcc -E +RANLIB = ranlib +INSTALL = install -c +YACC = bison -y +LEX = flex +AWK = gawk +STRIP = strip +prefix = /opt/gbdk +exec_prefix = ${prefix} +bindir = ${exec_prefix}/bin +libdir = ${exec_prefix}/lib +datadir = ${prefix}/share +includedir = ${prefix}/include +mandir = ${prefix}/man +man1dir = $(mandir)/man1 +man2dir = $(mandir)/man2 +infodir = ${prefix}/info +srcdir = . +docdir = ${prefix}/share/doc/sdcc + +# Modules to enable/disable +OPT_ENABLE_UCSIM = no +OPT_ENABLE_DEVICE_LIB_BUILD = no +OPT_ENABLE_PACKIHX = no + +SLIB = $(PRJDIR)/support/Util + +transform = s,$$,,; + +# Flags + +DEFS = $(subs -DHAVE_CONFIG_H,,-DHAVE_CONFIG_H) +CPPFLAGS = $(INCLUDEFLAGS) -I. -I$(PRJDIR) -I$(SLIB) +CFLAGS = -ggdb -O2 -pipe -Wall +M_OR_MM = -MM + +EXTRALIBS = + +# Shared settings between all the sub Makefiles +# Done here so that we don't have to start a Make from the top levelport +# directory. + +# Library compilation options +SCC = $(PRJDIR)/src/sdcc +SAS = $(PRJDIR)/as/$(PORT)/as +CLEANSPEC = *.lst *.asm *.sym *~ *.cdb *.dep *.rul + +OBJ = $(SOURCES:.c=.o) diff --git a/link/README b/link/README new file mode 100644 index 00000000..5aba86d3 --- /dev/null +++ b/link/README @@ -0,0 +1,8 @@ +sdcc/link +--------- + +In gbdk the linker and assembler were split into seperate packages. + +For now I'm keeping that split, and leaving the mcs51 version as is. + +-- Michael diff --git a/link/as/Makefile b/link/as/Makefile new file mode 100644 index 00000000..65ec6658 --- /dev/null +++ b/link/as/Makefile @@ -0,0 +1,20 @@ +PRJDIR = .. +include $(PRJDIR)/Makefile.common + +PORTS = z80 gbz80 +DOCS = README abstra.doc appendk.txt asmlnk.doc asxhtm.html format.txt + +all: + $(MAKE) -C z80 _as-z80 _as-gbz80 E=$(E) BUILDDIR=../../bin/ + +install: all install-doc + $(INSTALL) $(PRJDIR)/bin/as-z80 `echo $(bindir)/as-z80|sed '$(transform)'` + $(STRIP) `echo $(bindir)/as-z80|sed '$(transform)'` + $(INSTALL) $(PRJDIR)/bin/as-gbz80 `echo $(bindir)/as-gbz80|sed '$(transform)'` + $(STRIP) `echo $(bindir)/as-gbz80|sed '$(transform)'` + +install-doc: + $(INSTALL) -d $(docdir)/aslink + cp -f `find doc -maxdepth 1 -not -type d` $(docdir)/aslink + +include clean.mk diff --git a/link/as/README b/link/as/README new file mode 100644 index 00000000..b0f405ed --- /dev/null +++ b/link/as/README @@ -0,0 +1,5 @@ +sdcc/as +------- + +Both the z80 and mcs51 assemblers are derrived from the same tree. One +day they may be re-combined. diff --git a/link/as/as_z80.dsp b/link/as/as_z80.dsp new file mode 100644 index 00000000..204c1372 --- /dev/null +++ b/link/as/as_z80.dsp @@ -0,0 +1,131 @@ +# Microsoft Developer Studio Project File - Name="as_z80" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=as_z80 - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "as_z80.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "as_z80.mak" CFG="as_z80 - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "as_z80 - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "as_z80___Win32_Debug" +# PROP BASE Intermediate_Dir "as_z80___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "z80" +# PROP Intermediate_Dir "z80" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /G3 /ML /W3 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "INDEXLIB" /D "MLH_MAP" /D "SDK" /FR /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:console /debug /machine:I386 /out:"..\bin\as-z80.exe" /pdbtype:sept +# SUBTRACT LINK32 /incremental:no +# Begin Target + +# Name "as_z80 - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\z80\asdata.c +# End Source File +# Begin Source File + +SOURCE=.\z80\asexpr.c +# End Source File +# Begin Source File + +SOURCE=.\z80\aslex.c +# End Source File +# Begin Source File + +SOURCE=.\z80\aslist.c +# End Source File +# Begin Source File + +SOURCE=.\z80\asmain.c +# End Source File +# Begin Source File + +SOURCE=.\z80\asout.c +# End Source File +# Begin Source File + +SOURCE=.\z80\assubr.c +# End Source File +# Begin Source File + +SOURCE=.\z80\assym.c +# End Source File +# Begin Source File + +SOURCE=.\z80\z80adr.c +# End Source File +# Begin Source File + +SOURCE=.\z80\z80ext.c +# End Source File +# Begin Source File + +SOURCE=.\z80\z80mch.c +# End Source File +# Begin Source File + +SOURCE=.\z80\z80pst.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\z80\alloc.h +# End Source File +# Begin Source File + +SOURCE=.\z80\asm.h +# End Source File +# Begin Source File + +SOURCE=.\z80\string.h +# End Source File +# Begin Source File + +SOURCE=.\z80\z80.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/link/as/aslink.dsp b/link/as/aslink.dsp new file mode 100644 index 00000000..1be9cbba --- /dev/null +++ b/link/as/aslink.dsp @@ -0,0 +1,143 @@ +# Microsoft Developer Studio Project File - Name="aslink" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=aslink - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "aslink.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "aslink.mak" CFG="aslink - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "aslink - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "aslink___Win32_Debug" +# PROP BASE Intermediate_Dir "aslink___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "mcs51" +# PROP Intermediate_Dir "mcs51" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /G3 /ML /W3 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "INDEXLIB" /D "MLH_MAP" /D "SDK" /FR /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:console /debug /machine:I386 /out:"..\bin\aslink.exe" /pdbtype:sept +# SUBTRACT LINK32 /incremental:no /nodefaultlib +# Begin Target + +# Name "aslink - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=mcs51\lkarea.c +# End Source File +# Begin Source File + +SOURCE=mcs51\lkdata.c +# End Source File +# Begin Source File + +SOURCE=mcs51\lkeval.c +# End Source File +# Begin Source File + +SOURCE=mcs51\lkhead.c +# End Source File +# Begin Source File + +SOURCE=mcs51\lkihx.c +# End Source File +# Begin Source File + +SOURCE=mcs51\lklex.c +# End Source File +# Begin Source File + +SOURCE=mcs51\lklibr.c +# End Source File +# Begin Source File + +SOURCE=mcs51\lklist.c +# End Source File +# Begin Source File + +SOURCE=mcs51\lkmain.c +# End Source File +# Begin Source File + +SOURCE=mcs51\lknoice.c +# End Source File +# Begin Source File + +SOURCE=mcs51\lkrloc.c +# End Source File +# Begin Source File + +SOURCE=mcs51\lks19.c +# End Source File +# Begin Source File + +SOURCE=mcs51\lkstore.c +# End Source File +# Begin Source File + +SOURCE=mcs51\lksym.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\mcs51\alloc.h +# End Source File +# Begin Source File + +SOURCE=.\mcs51\aslink.h +# End Source File +# Begin Source File + +SOURCE=.\mcs51\asm.h +# End Source File +# Begin Source File + +SOURCE=.\mcs51\i8051.h +# End Source File +# Begin Source File + +SOURCE=.\mcs51\string.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/link/as/asx8051.dsp b/link/as/asx8051.dsp new file mode 100644 index 00000000..22e1cb25 --- /dev/null +++ b/link/as/asx8051.dsp @@ -0,0 +1,131 @@ +# Microsoft Developer Studio Project File - Name="asx8051" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=asx8051 - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "asx8051.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "asx8051.mak" CFG="asx8051 - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "asx8051 - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "mcs51" +# PROP Intermediate_Dir "mcs51" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /G3 /ML /W3 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "INDEXLIB" /D "MLH_MAP" /D "SDK" /FR /J /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:console /debug /machine:I386 /out:"\sdcc\bin\asx8051.exe" /pdbtype:sept +# SUBTRACT LINK32 /incremental:no +# Begin Target + +# Name "asx8051 - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=mcs51\asdata.c +# End Source File +# Begin Source File + +SOURCE=mcs51\asexpr.c +# End Source File +# Begin Source File + +SOURCE=mcs51\aslex.c +# End Source File +# Begin Source File + +SOURCE=mcs51\aslist.c +# End Source File +# Begin Source File + +SOURCE=mcs51\asmain.c +# End Source File +# Begin Source File + +SOURCE=mcs51\asnoice.c +# End Source File +# Begin Source File + +SOURCE=mcs51\asout.c +# End Source File +# Begin Source File + +SOURCE=mcs51\asstore.c +# End Source File +# Begin Source File + +SOURCE=mcs51\assubr.c +# End Source File +# Begin Source File + +SOURCE=mcs51\assym.c +# End Source File +# Begin Source File + +SOURCE=mcs51\i51adr.c +# End Source File +# Begin Source File + +SOURCE=mcs51\i51ext.c +# End Source File +# Begin Source File + +SOURCE=mcs51\i51mch.c +# End Source File +# Begin Source File + +SOURCE=mcs51\i51pst.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\mcs51\asm.h +# End Source File +# Begin Source File + +SOURCE=.\mcs51\i8051.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/link/as/clean.mk b/link/as/clean.mk new file mode 100644 index 00000000..93bc4b0a --- /dev/null +++ b/link/as/clean.mk @@ -0,0 +1,6 @@ +clean: + $(MAKE) -C z80 -f clean.mk clean + +distclean: + $(MAKE) -C z80 -f clean.mk distclean + diff --git a/link/as/z80/Makefile b/link/as/z80/Makefile new file mode 100644 index 00000000..9ea2069d --- /dev/null +++ b/link/as/z80/Makefile @@ -0,0 +1,53 @@ +PRJDIR = ../.. + +include $(PRJDIR)/Makefile.common + +OBJDIR = obj/$(EXT) + +SDC = . + +SLIBSRC = NewAlloc.c + +SRC = asdata.c asexpr.c aslex.c aslist.c asmain.c asout.c \ + assubr.c assym.c z80adr.c z80ext.c z80mch.c z80pst.c + +OBJS = $(SRC:%.c=$(OBJDIR)/%.o) +SLIBOBJS = $(SLIBSRC:%.c=$(OBJDIR)/%.o) + +BINS = $(BUILDDIR)as$(EXT) + +CFLAGS += $(CPPFLAGS) $(OPTS) -I. -DINDEXLIB -DMLH_MAP -DUNIX -DSDK +CFLAGS += -funsigned-char +CFLAGS += -I$(SLIB) + +LDFLAGS += -lm $(EXTRALIBS) + +all: $(OBJDIR) dep $(BINS) + +dep: Makefile.dep + +Makefile.dep: $(SRC) *.h + $(CPP) $(CPPFLAGS) $(M_OR_MM) $(SRC) > Makefile.dep + +include Makefile.dep + +$(OBJDIR): + mkdir -p $(OBJDIR) + +$(BINS): $(OBJS) $(SLIBOBJS) + $(CC) -o $(BINS) $(OBJS) $(SLIBOBJS) $(LDFLAGS) + + +$(OBJDIR)/%.o: %.c + $(CC) -c $(CFLAGS) -o $@ $< + +$(OBJDIR)/%.o: $(SLIB)/%.c + $(CC) -c $(CFLAGS) -o $@ $< + +_as-z80: + $(MAKE) EXT=-z80$(E) + +_as-gbz80: + $(MAKE) EXT=-gbz80$(E) OPTS=-DGAMEBOY + +include clean.mk diff --git a/link/as/z80/Makefile.in b/link/as/z80/Makefile.in new file mode 100644 index 00000000..5ae5e07d --- /dev/null +++ b/link/as/z80/Makefile.in @@ -0,0 +1,97 @@ +# +# +# + +VERSION = @VERSION@ +VERSIONHI = @VERSIONHI@ +VERSIONLO = @VERSIONLO@ +VERSIONP = @VERSIONP@ + +SHELL = /bin/sh +CC = @CC@ +CPP = @CPP@ +INSTALL = @INSTALL@ + +PRJDIR = ../.. + +srcdir = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +libdir = @libdir@ +datadir = @datadir@ +includedir = @include@ +mandir = @mandir@ +man1dir = $(mandir)/man1 +man2dir = $(mandir)/man2 +infodir = @infodir@ + +CPPFLAGS = @CPPFLAGS@ -I. -I$(PRJDIR) +CFLAGS = @CFLAGS@ -Wall -DINDEXLIB -DMLH_MAP -DUNIX -DSDK -funsigned-char -ggdb +M_OR_MM = @M_OR_MM@ +LDFLAGS = @LDFLAGS@ -lm + +ASOBJECTS = asdata.o asexpr.o aslex.o aslist.o asmain.o asout.o \ + assubr.o assym.o z80adr.o z80ext.o z80mch.o z80pst.o +ASSOURCES = $(patsubst %.o,%.c,$(ASOBJECTS)) + +ASXZ80 = $(PRJDIR)/bin/as-z80 + +# Compiling entire program or any subproject +# ------------------------------------------ +all: checkconf $(ASXZ80) + +$(ASXZ80): $(ASOBJECTS) + $(CC) $(CFLAGS) -o $@ $(ASOBJECTS) $(LDFLAGS) + +# Compiling and installing everything and runing test +# --------------------------------------------------- +install: all installdirs + $(INSTALL) $(ASXZ80) $(bindir)/as-z80 + +# Deleting all the installed files +# -------------------------------- +uninstall: + rm -f $(bindir)/as-z80 + + +# Performing self-test +# -------------------- +check: + + +# Performing installation test +# ---------------------------- +installcheck: + + +# Creating installation directories +# --------------------------------- +installdirs: + $(INSTALL) -d $(bindir) + + +# Creating dependencies +# --------------------- +dep: Makefile.dep + +Makefile.dep: $(ASSOURCES) *.h $(PRJDIR)/*.h + $(CPP) $(CPPFLAGS) $(M_OR_MM) $(ASSOURCES) >Makefile.dep + +include Makefile.dep +include clean.mk + +# My rules +# -------- +.c.o: + $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< + + +# Remaking configuration +# ---------------------- +checkconf: + @if [ -f $(PRJDIR)/devel ]; then\ + $(MAKE) -f conf.mk srcdir="$(srcdir)" PRJDIR="$(PRJDIR)" freshconf;\ + fi + +# End of Makefile diff --git a/link/as/z80/alloc.h b/link/as/z80/alloc.h new file mode 100644 index 00000000..f4ee1b95 --- /dev/null +++ b/link/as/z80/alloc.h @@ -0,0 +1,10 @@ +/* alloc.h */ +/* DECUS C */ + +#ifndef SDK +//extern char *alloc(); +//extern char *malloc(); +//extern char *calloc(); +//extern char *realloc(); +#endif + diff --git a/link/as/z80/asdata.c b/link/as/z80/asdata.c new file mode 100644 index 00000000..189be0b2 --- /dev/null +++ b/link/as/z80/asdata.c @@ -0,0 +1,279 @@ +/* asdata.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +#include +#include +#include + +#include "asm.h" + +/*)Module asdata.c + * + * The module asdata.c contains the global constants, + * structures, and variables used in the assembler. + */ + +int aserr; /* ASxxxx error counter + */ +jmp_buf jump_env; /* compiler dependent structure + * used by setjmp() and longjmp() + */ +int inpfil; /* count of assembler + * input files specified + */ +int incfil; /* current file handle index + * for include files + */ +int cfile; /* current file handle index + * of input assembly files + */ +int flevel; /* IF-ELSE-ENDIF flag will be non + * zero for false conditional case + */ +int tlevel; /* current conditional level + */ +int ifcnd[MAXIF+1]; /* array of IF statement condition + * values (0 = FALSE) indexed by tlevel + */ +int iflvl[MAXIF+1]; /* array of IF-ELSE-ENDIF flevel + * values indexed by tlevel + */ + +char afn[FILSPC]; /* afile temporary file name + */ +char srcfn[MAXFIL][FILSPC]; /* array of source file names + */ +int srcline[MAXFIL]; /* source line number + */ +char incfn[MAXINC][FILSPC]; /* array of include file names + */ +int incline[MAXINC]; /* include line number + */ + +int radix; /* current number conversion radix: + * 2 (binary), 8 (octal), 10 (decimal), + * 16 (hexadecimal) + */ +int line; /* current assembler source + * line number + */ +int page; /* current page number + */ +int lop; /* current line number on page + */ +int pass; /* assembler pass number + */ +int lflag; /* -l, generate listing flag + */ +int gflag; /* -g, make undefined symbols global flag + */ +int aflag; /* -a, make all symbols global flag + */ +int oflag; /* -o, generate relocatable output flag + */ +int sflag; /* -s, generate symbol table flag + */ +int pflag; /* -p, enable listing pagination + */ +int xflag; /* -x, listing radix flag + */ +int fflag; /* -f(f), relocations flagged flag + */ +Addr_T laddr; /* address of current assembler line + * or value of .if argument + */ +Addr_T fuzz; /* tracks pass to pass changes in the + * address of symbols caused by + * variable length instruction formats + */ +int lmode; /* listing mode + */ +char *ep; /* pointer into error list + * array eb[NERR] + */ +char eb[NERR]; /* array of generated error codes + */ +char *ip; /* pointer into the assembler-source + * text line in ib[] + */ +char ib[NINPUT]; /* assembler-source text line + */ +char *cp; /* pointer to assembler output + * array cb[] + */ +char cb[NCODE]; /* array of assembler output values + */ +int *cpt; /* pointer to assembler relocation type + * output array cbt[] + */ +int cbt[NCODE]; /* array of assembler relocation types + * describing the data in cb[] + */ +char tb[NTITL]; /* Title string buffer + */ +char stb[NSBTL]; /* Subtitle string buffer + */ + +char symtbl[] = { "Symbol Table" }; +char aretbl[] = { "Area Table" }; + +char module[NCPS]; /* module name string + */ + +/* + * The mne structure is a linked list of the assembler + * mnemonics and directives. The list of mnemonics and + * directives contained in the device dependent file + * xxxpst.c are hashed and linked into NHASH lists in + * module assym.c by syminit(). The structure contains + * the mnemonic/directive name, a subtype which directs + * the evaluation of this mnemonic/directive, a flag which + * is used to detect the end of the mnemonic/directive + * list in xxxpst.c, and a value which is normally + * associated with the assembler mnemonic base instruction + * value. + * + * struct mne + * { + * struct mne *m_mp; Hash link + * char m_id[NCPS]; Mnemonic + * char m_type; Mnemonic subtype + * char m_flag; Mnemonic flags + * Addr_T m_valu; Value + * }; + */ +struct mne *mnehash[NHASH]; + +/* + * The sym structure is a linked list of symbols defined + * in the assembler source files. The first symbol is "." + * defined here. The entry 'struct tsym *s_tsym' + * links any temporary symbols following this symbol and + * preceeding the next normal symbol. The structure also + * contains the symbol's name, type (USER or NEW), flag + * (global, assigned, and multiply defined), a pointer + * to the area structure defining where the symbol is + * located, a reference number assigned by outgsd() in + * asout.c, and the symbols address relative to the base + * address of the area where the symbol is located. + * + * struct sym + * { + * struct sym *s_sp; Hash link + * struct tsym *s_tsym; Temporary symbol link + * char s_id[NCPS]; Symbol + * char s_type; Symbol subtype + * char s_flag; Symbol flags + * struct area *s_area; Area line, 0 if absolute + * int s_ref; Ref. number + * Addr_T s_addr; Address + * }; + */ +struct sym sym[] = { + { NULL, NULL, ".", S_USER, S_END, NULL, 0, } +}; + +struct sym *symp; /* pointer to a symbol structure + */ +struct sym *symhash[NHASH]; /* array of pointers to NHASH + * linked symbol lists + */ + +/* + * The area structure contains the parameter values for a + * specific program or data section. The area structure + * is a linked list of areas. The initial default area + * is "_CODE" defined here, the next area structure + * will be linked to this structure through the structure + * element 'struct area *a_ep'. The structure contains the + * area name, area reference number ("_CODE" is 0) determined + * by the order of .area directives, area size determined + * from the total code and/or data in an area, area fuzz is + * an variable used to track pass to pass changes in the + * area size caused by variable length instruction formats, + * and area flags which specify the area's relocation type. + * + * struct area + * { + * struct area *a_ap; Area link + * char a_id[NCPS]; Area Name + * int a_ref; Reference number + * Addr_T a_size; Area size + * Addr_T a_fuzz; Area fuzz + * int a_flag; Area flags + * }; + */ +struct area area[] = { + { NULL, "_CODE", 0, 0, 0, A_CON|A_REL } +}; + +struct area *areap; /* pointer to an area structure + */ + +FILE *lfp; /* list output file handle + */ +FILE *ofp; /* relocation output file handle + */ +FILE *tfp; /* symbol table output file handle + */ +FILE *sfp[MAXFIL]; /* array of assembler-source file handles + */ +FILE *ifp[MAXINC]; /* array of include-file file handles + */ + +/* + * array of character types, one per + * ASCII character + */ +char ctype[128] = { +/*NUL*/ ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, +/*BS*/ ILL, SPACE, ILL, ILL, SPACE, ILL, ILL, ILL, +/*DLE*/ ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, +/*CAN*/ ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, +/*SPC*/ SPACE, ETC, ETC, ETC, LETTER, BINOP, BINOP, ETC, +/*(*/ ETC, ETC, BINOP, BINOP, ETC, BINOP, LETTER, BINOP, +/*0*/ DGT2, DGT2, DGT8, DGT8, DGT8, DGT8, DGT8, DGT8, +/*8*/ DGT10, DGT10, ETC, ETC, BINOP, ETC, BINOP, ETC, +/*@*/ ETC, LTR16, LTR16, LTR16, LTR16, LTR16, LTR16, LETTER, +/*H*/ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/*P*/ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/*X*/ LETTER, LETTER, LETTER, ETC, ETC, ETC, BINOP, LETTER, +/*`*/ ETC, LTR16, LTR16, LTR16, LTR16, LTR16, LTR16, LETTER, +/*h*/ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/*p*/ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/*x*/ LETTER, LETTER, LETTER, ETC, BINOP, ETC, ETC, ETC +}; + +/* + * an array of characters which + * perform the case translation function + */ +#if CASE_SENSITIVE +#else +char ccase[128] = { +/*NUL*/ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', +/*BS*/ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', +/*DLE*/ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', +/*CAN*/ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', +/*SPC*/ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047', +/*(*/ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057', +/*0*/ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067', +/*8*/ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077', +/*@*/ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', +/*H*/ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', +/*P*/ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', +/*X*/ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137', +/*`*/ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147', +/*h*/ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', +/*p*/ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', +/*x*/ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177' +}; +#endif diff --git a/link/as/z80/asexpr.c b/link/as/z80/asexpr.c new file mode 100644 index 00000000..2664550d --- /dev/null +++ b/link/as/z80/asexpr.c @@ -0,0 +1,667 @@ +/* asexpr.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +#include +#include +#include + +#include "asm.h" + +/*)Module asexpr.c + * + * The module asexpr.c contains the routines to evaluate + * arithmetic/numerical expressions. The functions in + * asexpr.c perform a recursive evaluation of the arithmetic + * expression read from the assembler-source text line. + * The expression may include binary/unary operators, brackets, + * symbols, labels, and constants in hexadecimal, decimal, octal + * and binary. Arithmetic operations are prioritized and + * evaluated by normal arithmetic conventions. + * + * asexpr.c contains the following functions: + * VOID abscheck() + * Addr_T absexpr() + * VOID clrexpr() + * int digit() + * VOID expr() + * int oprio() + * VOID term() + * + * asexpr.c contains no local/static variables + */ + +/*)Function VOID expr(esp, n) + * + * expr * esp pointer to an expr structure + * int n a firewall priority; all top + * level calls (from the user) + * should be made with n set to 0. + * + * The function expr() evaluates an expression and + * stores its value and relocation information into + * the expr structure supplied by the user. + * + * local variables: + * int c current assembler-source + * text character + * int p current operator priority + * area * ap pointer to an area structure + * exp re internal expr structure + * + * global variables: + * char ctype[] array of character types, one per + * ASCII character + * + * functions called: + * VOID abscheck() asexpr.c + * VOID clrexpr() asexpr.c + * VOID expr() asexpr.c + * int getnb() aslex.c + * int oprio() asexpr.c + * VOID qerr() assubr.c + * VOID rerr() assubr.c + * VOID term() asexpr.c + * VOID unget() aslex.c + * + * + * side effects: + * An expression is evaluated modifying the user supplied + * expr structure, a sym structure maybe created for an + * undefined symbol, and the parse of the expression may + * terminate if a 'q' error occurs. + */ + +VOID +expr(esp, n) +register struct expr *esp; +int n; +{ + register int c, p; + struct area *ap; + struct expr re; + + term(esp); + while (ctype[c = getnb()] & BINOP) { + /* + * Handle binary operators + - * / & | % ^ << >> + */ + if ((p = oprio(c)) <= n) + break; + if ((c == '>' || c == '<') && c != get()) + qerr(); + clrexpr(&re); + expr(&re, p); + esp->e_rlcf |= re.e_rlcf; + if (c == '+') { + /* + * esp + re, at least one must be absolute + */ + if (esp->e_base.e_ap == NULL) { + /* + * esp is absolute (constant), + * use area from re + */ + esp->e_base.e_ap = re.e_base.e_ap; + } else + if (re.e_base.e_ap) { + /* + * re should be absolute (constant) + */ + rerr(); + } + if (esp->e_flag && re.e_flag) + rerr(); + if (re.e_flag) + esp->e_flag = 1; + esp->e_addr += re.e_addr; + } else + if (c == '-') { + /* + * esp - re + */ + if ((ap = re.e_base.e_ap) != NULL) { + if (esp->e_base.e_ap == ap) { + esp->e_base.e_ap = NULL; + } else { + rerr(); + } + } + if (re.e_flag) + rerr(); + esp->e_addr -= re.e_addr; + } else { + /* + * Both operands (esp and re) must be constants + */ + abscheck(esp); + abscheck(&re); + switch (c) { + + case '*': + esp->e_addr *= re.e_addr; + break; + + case '/': + esp->e_addr /= re.e_addr; + break; + + case '&': + esp->e_addr &= re.e_addr; + break; + + case '|': + esp->e_addr |= re.e_addr; + break; + + case '%': + esp->e_addr %= re.e_addr; + break; + + case '^': + esp->e_addr ^= re.e_addr; + break; + + case '<': + esp->e_addr <<= re.e_addr; + break; + + case '>': + esp->e_addr >>= re.e_addr; + break; + + default: + qerr(); + break; + } + } + } + unget(c); +} + +/*)Function Addr_T absexpr() + * + * The function absexpr() evaluates an expression, verifies it + * is absolute (i.e. not position dependent or relocatable), and + * returns its value. + * + * local variables: + * expr e expr structure + * + * global variables: + * none + * + * functions called: + * VOID abscheck() asexpr.c + * VOID clrexpr() asexpr.c + * VOID expr() asexpr.c + * + * side effects: + * If the expression is not absolute then + * a 'r' error is reported. + */ + +Addr_T +absexpr() +{ + struct expr e; + + clrexpr(&e); + expr(&e, 0); + abscheck(&e); + return (e.e_addr); +} + +/*)Function VOID term(esp) + * + * expr * esp pointer to an expr structure + * + * The function term() evaluates a single constant + * or symbol value prefaced by any unary operator + * ( +, -, ~, ', ", >, or < ). This routine is also + * responsible for setting the relocation type to symbol + * based (e.flag != 0) on global references. + * + * local variables: + * int c current character + * char id[] symbol name + * char * jp pointer to assembler-source text + * int n constant evaluation running sum + * int r current evaluation radix + * sym * sp pointer to a sym structure + * tsym * tp pointer to a tsym structure + * int v current digit evaluation + * + * global variables: + * char ctype[] array of character types, one per + * ASCII character + * sym * symp pointer to a symbol structure + * + * functions called: + * VOID abscheck() asexpr.c + * int digit() asexpr.c + * VOID err() assubr.c + * VOID expr() asexpr.c + * int is_abs() asexpr.c + * int get() aslex.c + * VOID getid() aslex.c + * int getmap() aslex.c + * int getnb() aslex.c + * sym * lookup() assym.c + * VOID qerr() assubr.c + * VOID unget() aslex.c + * + * side effects: + * An arithmetic term is evaluated, a symbol structure + * may be created, term evaluation may be terminated + * by a 'q' error. + */ + +VOID +term(esp) +register struct expr *esp; +{ + register int c, n; + register char *jp; + char id[NCPS]; + struct sym *sp; + struct tsym *tp; + int r = 0, v; + + c = getnb(); + /* + * Discard the unary '+' at this point and + * also any reference to numerical arguments + * associated with the '#' prefix. + */ + while (c == '+' || c == '#') { c = getnb(); } + /* + * Evaluate all binary operators + * by recursively calling expr(). + */ + if (c == LFTERM) { + expr(esp, 0); + if (getnb() != RTTERM) + qerr(); + return; + } + if (c == '-') { + expr(esp, 100); + abscheck(esp); + esp->e_addr = 0 - esp->e_addr; + return; + } + if (c == '~') { + expr(esp, 100); + abscheck(esp); + esp->e_addr = ~esp->e_addr; + return; + } + if (c == '\'') { + esp->e_mode = S_USER; + esp->e_addr = getmap(-1)&0377; + return; + } + if (c == '\"') { + esp->e_mode = S_USER; + if (hilo) { + esp->e_addr = (getmap(-1)&0377)<<8; + esp->e_addr |= (getmap(-1)&0377); + } else { + esp->e_addr = (getmap(-1)&0377); + esp->e_addr |= (getmap(-1)&0377)<<8; + } + return; + } + if (c == '>' || c == '<') { + expr(esp, 100); + if (is_abs (esp)) { + /* + * evaluate msb/lsb directly + */ + if (c == '>') + esp->e_addr >>= 8; + esp->e_addr &= 0377; + return; + } else { + /* + * let linker perform msb/lsb, lsb is default + */ + esp->e_rlcf |= R_BYT2; + if (c == '>') + esp->e_rlcf |= R_MSB; + return; + } + } + /* + * Evaluate digit sequences as local symbols + * if followed by a '$' or as constants. + */ + if (ctype[c] & DIGIT) { + esp->e_mode = S_USER; + jp = ip; + while (ctype[(unsigned char)(*jp)] & RAD10) { + jp++; + } + if (*jp == '$') { + n = 0; + while ((v = digit(c, 10)) >= 0) { + n = 10*n + v; + c = get(); + } + tp = symp->s_tsym; + while (tp) { + if (n == tp->t_num) { + esp->e_base.e_ap = tp->t_area; + esp->e_addr = tp->t_addr; + return; + } + tp = tp->t_lnk; + } + err('u'); + return; + } + r = radix; + if (c == '0') { + c = get(); + switch (c) { + case 'b': + case 'B': + r = 2; + c = get(); + break; + case 'o': + case 'O': + case 'q': + case 'Q': + r = 8; + c = get(); + break; + case 'd': + case 'D': + r = 10; + c = get(); + break; + case 'h': + case 'H': + case 'x': + case 'X': + r = 16; + c = get(); + break; + default: + break; + } + } + n = 0; + while ((v = digit(c, r)) >= 0) { + n = r*n + v; + c = get(); + } + unget(c); + esp->e_addr = n; + return; + } + /* + * Evaluate '$' sequences as a temporary radix + * if followed by a '%', '&', '#', or '$'. + */ + if (c == '$') { + c = get(); + if (c == '%' || c == '&' || c == '#' || c == '$') { + switch (c) { + case '%': + r = 2; + break; + case '&': + r = 8; + break; + case '#': + r = 10; + break; + case '$': + r = 16; + break; + default: + break; + } + c = get(); + n = 0; + while ((v = digit(c, r)) >= 0) { + n = r*n + v; + c = get(); + } + unget(c); + esp->e_mode = S_USER; + esp->e_addr = n; + return; + } + unget(c); + c = '$'; + } + /* + * Evaluate symbols and labels + */ + if (ctype[c] & LETTER) { + esp->e_mode = S_USER; + getid(id, c); + sp = lookup(id); + if (sp->s_type == S_NEW) { + if (sp->s_flag&S_GBL) { + esp->e_flag = 1; + esp->e_base.e_sp = sp; + return; + } + err('u'); + } else { + esp->e_mode = sp->s_type; + esp->e_addr = sp->s_addr; + esp->e_base.e_ap = sp->s_area; + } + return; + } + /* + * Else not a term. + */ + qerr(); +} + +/*)Function int digit(c, r) + * + * int c digit character + * int r current radix + * + * The function digit() returns the value of c + * in the current radix r. If the c value is not + * a number of the current radix then a -1 is returned. + * + * local variables: + * none + * + * global variables: + * char ctype[] array of character types, one per + * ASCII character + * + * functions called: + * none + * + * side effects: + * none + */ + +int +digit(c, r) +register int c, r; +{ + if (r == 16) { + if (ctype[c] & RAD16) { + if (c >= 'A' && c <= 'F') + return (c - 'A' + 10); + if (c >= 'a' && c <= 'f') + return (c - 'a' + 10); + return (c - '0'); + } + } else + if (r == 10) { + if (ctype[c] & RAD10) + return (c - '0'); + } else + if (r == 8) { + if (ctype[c] & RAD8) + return (c - '0'); + } else + if (r == 2) { + if (ctype[c] & RAD2) + return (c - '0'); + } + return (-1); +} + +/*)Function VOID abscheck(esp) + * + * expr * esp pointer to an expr structure + * + * The function abscheck() tests the evaluation of an + * expression to verify it is absolute. If the evaluation + * is relocatable then an 'r' error is noted and the expression + * made absolute. + * + * Note: The area type (i.e. ABS) is not checked because + * the linker can be told to explicitly relocate an + * absolute area. + * + * local variables: + * none + * + * global variables: + * none + * + * functions called: + * VOID rerr() assubr.c + * + * side effects: + * The expression may be changed to absolute and the + * 'r' error invoked. + */ + +VOID +abscheck(esp) +register struct expr *esp; +{ + if (esp->e_flag || esp->e_base.e_ap) { + esp->e_flag = 0; + esp->e_base.e_ap = NULL; + rerr(); + } +} + +/*)Function int is_abs(esp) + * + * expr * esp pointer to an expr structure + * + * The function is_abs() tests the evaluation of an + * expression to verify it is absolute. If the evaluation + * is absolute then 1 is returned, else 0 is returned. + * + * Note: The area type (i.e. ABS) is not checked because + * the linker can be told to explicitly relocate an + * absolute area. + * + * local variables: + * none + * + * global variables: + * none + * + * functions called: + * none + * + * side effects: + * none + */ + +int +is_abs (esp) +register struct expr *esp; +{ + if (esp->e_flag || esp->e_base.e_ap) { + return(0); + } + return(1); +} + +/*)Function int oprio(c) + * + * int c operator character + * + * The function oprio() returns a relative priority + * for all valid unary and binary operators. + * + * local variables: + * none + * + * global variables: + * none + * + * functions called: + * none + * + * side effects: + * none + */ + +int +oprio(c) +register int c; +{ + if (c == '*' || c == '/' || c == '%') + return (10); + if (c == '+' || c == '-') + return (7); + if (c == '<' || c == '>') + return (5); + if (c == '^') + return (4); + if (c == '&') + return (3); + if (c == '|') + return (1); + return (0); +} + +/*)Function VOID clrexpr(esp) + * + * expr * esp pointer to expression structure + * + * The function clrexpr() clears the expression structure. + * + * local variables: + * none + * + * global variables: + * none + * + * functions called: + * none + * + * side effects: + * expression structure cleared. + */ + +VOID +clrexpr(esp) +register struct expr *esp; +{ + esp->e_mode = 0; + esp->e_flag = 0; + esp->e_addr = 0; + esp->e_base.e_ap = NULL; + esp->e_rlcf = 0; +} diff --git a/link/as/z80/aslex.c b/link/as/z80/aslex.c new file mode 100644 index 00000000..7f90d2b6 --- /dev/null +++ b/link/as/z80/aslex.c @@ -0,0 +1,502 @@ +/* aslex.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +/* + * Extensions: P. Felber, M. Hope + */ + +#include +#include +#include + +#include "asm.h" + +/*)Module aslex.c + * + * The module aslex.c includes the general lexical + * analysis routines for the assembler. + * + * aslex.c contains the following functions: + * char endline() + * char get() + * VOID getid(id,c) + * int getLine_() + * int getmap() + * char getnb() + * VOID getst() + * int more() + * VOID unget(c) + * + * aslex.c contains no local/static variables + */ + +/*)Function VOID getid(id,c) + * + * char * id a pointer to a string of + * maximum length NCPS + * int c mode flag + * >=0 this is first character to + * copy to the string buffer + * <0 skip white space, first + * character must be a LETTER + * + * The function getid() scans the current assembler-source text line + * from the current position copying the next LETTER | DIGIT string + * into the external string buffer (id). The string ends when a non + * LETTER or DIGIT character is found. The maximum number of + * characters copied is NCPS. If the input string is larger than + * NCPS characters then the string is truncated, if the input string + * is shorter than NCPS characters then the string is NULL filled. + * If the mode argument (c) is >=0 then (c) is the first character + * copied to the string buffer, if (c) is <0 then intervening white + * space (SPACES and TABS) are skipped and the first character found + * must be a LETTER else a 'q' error terminates the parse of this + * assembler-source text line. + * + * local variables: + * char * p pointer to external string buffer + * int c current character value + * + * global variables: + * char ctype[] a character array which defines the + * type of character being processed. + * This index is the character + * being processed. + * + * called functions: + * char get() aslex.c + * char getnb() aslex.c + * VOID unget() aslex.c + * + * side effects: + * use of getnb(), get(), and unget() updates the + * global pointer ip, the position in the current + * assembler-source text line. + */ + +VOID +getid(id, c) +register int c; +char *id; +{ + register char *p; + + if (c < 0) { + c = getnb(); + if ((ctype[c] & LETTER) == 0) + qerr(); + } + p = id; + do { + if (p < &id[NCPS]) + *p++ = c; + } while (ctype[c=get()] & (LETTER|DIGIT)); + unget(c); + while (p < &id[NCPS]) + *p++ = 0; +} + +/*)Function VOID getst(id,c) + * + * char * id a pointer to a string of + * maximum length NCPS + * int c mode flag + * >=0 this is first character to + * copy to the string buffer + * <0 skip white space, first + * character must be a LETTER + * + * The function getnbid() scans the current assembler-source text line + * from the current position copying the next character string into + * the external string buffer (id). The string ends when a SPACE or + * ILL character is found. The maximum number of + * characters copied is NCPS. If the input string is larger than + * NCPS characters then the string is truncated, if the input string + * is shorter than NCPS characters then the string is NULL filled. + * If the mode argument (c) is >=0 then (c) is the first character + * copied to the string buffer, if (c) is <0 then intervening white + * space (SPACES and TABS) are skipped and the first character found + * must be a LETTER else a 'q' error terminates the parse of this + * assembler-source text line. + * + * local variables: + * char * p pointer to external string buffer + * int c current character value + * + * global variables: + * char ctype[] a character array which defines the + * type of character being processed. + * This index is the character + * being processed. + * + * called functions: + * char get() aslex.c + * char getnb() aslex.c + * VOID unget() aslex.c + * + * side effects: + * use of getnb(), get(), and unget() updates the + * global pointer ip, the position in the current + * assembler-source text line. + */ + +VOID +getst(id, c) +register int c; +char *id; +{ + register char *p; + + if (c < 0) { + c = getnb(); + if ((ctype[c] & LETTER) == 0) + qerr(); + } + p = id; + do { + if (p < &id[NCPS]) + *p++ = c; + } while (ctype[c=get()] & ~(SPACE|ILL)); + unget(c); + while (p < &id[NCPS]) + *p++ = 0; +} + +/*)Function char getnb() + * + * The function getnb() scans the current assembler-source + * text line returning the first character not a SPACE or TAB. + * + * local variables: + * int c current character from + * assembler-source text line + * + * global variables: + * none + * + * called functions: + * char get() aslex.c + * + * side effects: + * use of get() updates the global pointer ip, the position + * in the current assembler-source text line + */ + +char +getnb() +{ + register int c; + + while ((c=get()) == ' ' || c == '\t') + ; + return (c); +} + +/*)Function char get() + * + * The function get() returns the next character in the + * assembler-source text line, at the end of the line a + * NULL character is returned. + * + * local variables: + * int c current character from + * assembler-source text line + * + * global variables: + * char * ip pointer into the current + * assembler-source text line + * + * called functions: + * none + * + * side effects: + * updates ip to the next character position in the + * assembler-source text line. If ip is at the end of the + * line, ip is not updated. + */ + +char +get() +{ + register int c; + + if ((c = *ip) != 0) + ++ip; + return (c); +} + +/*)Function VOID unget(c) + * + * int c value of last character read from + * assembler-source text line + * + * If (c) is not a NULL character then the global pointer ip + * is updated to point to the preceeding character in the + * assembler-source text line. + * + * NOTE: This function does not push the character (c) + * back into the assembler-source text line, only + * the pointer ip is changed. + * + * local variables: + * int c last character read from + * assembler-source text line + * + * global variables: + * char * ip position into the current + * assembler-source text line + * + * called functions: + * none + * + * side effects: + * ip decremented by 1 character position + */ + +VOID +unget(c) +{ + if (c) + if (ip != ib) + --ip; +} + +/*)Function int getmap(d) + * + * int d value to compare with the + * assembler-source text line character + * + * The function getmap() converts the 'C' style characters \b, \f, + * \n, \r, and \t to their equivalent ascii values and also + * converts 'C' style octal constants '\123' to their equivalent + * numeric values. If the first character is equivalent to (d) then + * a (-1) is returned, if the end of the line is detected then + * a 'q' error terminates the parse for this line, or if the first + * character is not a \ then the character value is returned. + * + * local variables: + * int c value of character from the + * assembler-source text line + * int n looping counter + * int v current value of numeric conversion + * + * global variables: + * none + * + * called functions: + * char get() aslex.c + * + * side effects: + * use of get() updates the global pointer ip the position + * in the current assembler-source text line + */ + +int +getmap(d) +{ + register int c, n, v; + + if ((c=get()) == '\0') + qerr(); + if (c == d) + return (-1); + if (c == '\\') { + c = get(); + switch (c) { + + case 'b': + c = '\b'; + break; + + case 'f': + c = '\f'; + break; + + case 'n': + c = '\n'; + break; + + case 'r': + c = '\r'; + break; + + case 't': + c = '\t'; + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + n = 0; + v = 0; + while (++n<=3 && c>='0' && c<='7') { + v = (v<<3) + c - '0'; + c = get(); + } + unget(c); + c = v; + break; + } + } + return (c); +} + +/*)Function int getLine_() + * + * The function getLine_() reads a line of assembler-source text + * from an assembly source text file or an include file. + * Lines of text are processed from assembler-source files until + * all files have been read. If an include file is opened then + * lines of text are read from the include file (or nested + * include file) until the end of the include file is found. + * The input text line is copied into the global string ib[] + * and converted to a NULL terminated string. The function + * getLine_() returns a (1) after succesfully reading a line + * or a (0) if all files have been read. + * + * local variables: + * int i string length + * + * global variables: + * char ib[] string buffer containing + * assembler-source text line + * char ifp[] array of file handles for + * include files + * int incfil index for ifp[] specifies + * active include file + * int incline[] array of include file + * line numbers + * char sfp[] array of file handles for + * assembler source files + * int cfile index for sfp[] specifies + * active source file + * int srcline[] array of source file + * line numbers + * int inpfil maximum input file index + * + * called functions: + * int fclose() c-library + * char * fgets() c-library + * int strlen() c-library + * + * side effects: + * include file will be closed at detection of end of file. + * the next sequential source file may be selected. + * the global file indexes incfil or cfile may be changed. + * The respective source line or include line counter + * will be updated. + */ + +int +getLine_() +{ +register int i; + +loop: if (incfil >= 0) { + if (fgets(ib, sizeof ib, ifp[incfil]) == NULL) { +#ifdef SDK + fclose(ifp[incfil]); + ifp[incfil--] = NULL; +#else /* SDK */ + fclose(ifp[incfil--]); +#endif /* SDK */ + lop = NLPP; + goto loop; + } else { + ++incline[incfil]; + } + } else { + if (fgets(ib, sizeof ib, sfp[cfile]) == NULL) { + if (++cfile <= inpfil) { + srcline[cfile] = 0; + goto loop; + } + return (0); + } else { + ++srcline[cfile]; + } + } + i = strlen(ib) - 1; + if (ib[i] == '\n') + ib[i] = 0; + if (i >= 1 && ib[i-1] == '\r') + ib[i-1] = 0; + return (1); +} + +/*)Function int more() + * + * The function more() scans the assembler-source text line + * skipping white space (SPACES and TABS) and returns a (0) + * if the end of the line or a comment delimeter (;) is found, + * or a (1) if their are additional characters in the line. + * + * local variables: + * int c next character from the + * assembler-source text line + * + * global variables: + * none + * + * called functions: + * char getnb() aslex.c + * VOID unget() aslex.c + * + * side effects: + * use of getnb() and unget() updates the global pointer ip + * the position in the current assembler-source text line + */ + +int +more() +{ + register int c; + + c = getnb(); + unget(c); + return( (c == '\0' || c == ';') ? 0 : 1 ); +} + +/*)Function char endline() + * + * The function endline() scans the assembler-source text line + * skipping white space (SPACES and TABS) and returns the next + * character or a (0) if the end of the line is found or a + * comment delimiter (;) is found. + * + * local variables: + * int c next character from the + * assembler-source text line + * + * global variables: + * none + * + * called functions: + * char getnb() aslex.c + * + * side effects: + * use of getnb() updates the global pointer ip the + * position in the current assembler-source text line + */ + +char +endline() +{ + register int c; + + c = getnb(); + return( (c == '\0' || c == ';') ? 0 : c ); +} diff --git a/link/as/z80/aslist.c b/link/as/z80/aslist.c new file mode 100644 index 00000000..e5344899 --- /dev/null +++ b/link/as/z80/aslist.c @@ -0,0 +1,810 @@ +/* aslist.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +/* + * Extensions: P. Felber + */ + +#include +#include +#include +#if defined(__APPLE__) && defined(__MACH__) +#include +#include +#else +#include +#endif + +#include "asm.h" + +/*)Module aslist.c + * + * The module aslist.c contains all the functions used + * to generate the assembler list and symbol output files. + * + * aslist.c contains the following functions: + * VOID list() + * VOID list1() + * VOID list2() + * VOID slew() + * VOID lstsym() + * + * The module aslist.c contains no local/static variables + */ + +/*)Function VOID list() + * + * The function list() generates the listing output + * which includes the input source, line numbers, + * and generated code. Numerical output may be selected + * as hexadecimal, decimal, or octal. + * + * local variables: + * int * wp pointer to the assembled data bytes + * int * wpt pointer to the data byte mode + * int nb computed number of assembled bytes + * + * global variables: + * int cb[] array of assembler output values + * int cbt[] array of assembler relocation types + * describing the data in cb[] + * int * cp pointer to assembler output array cb[] + * int * cpt pointer to assembler relocation type + * output array cbt[] + * char eb[] array of generated error codes + * char * ep pointer into error list + * array eb[] + * char ib[] assembler-source text line + * FILE * lfp list output file handle + * int line current assembler source line number + * int lmode listing mode + * int xflag -x, listing radix flag + * + * functions called: + * int fprintf() c_library + * VOID list1() aslist.c + * int putc() c_library + * VOID slew() asslist.c + * + * side effects: + * Listing or symbol output updated. + */ + +#ifndef MLH_LST +VOID +list() +{ + register char *wp; + register int *wpt; + register int nb; + + if (lfp == NULL || lmode == NLIST) + return; + + /* + * Get Correct Line Number + */ + if (incfil >= 0) { + line = incline[incfil]; + if (line == 0) { + if (incfil > 0) { + line = incline[incfil-1]; + } else { + line = srcline[cfile]; + } + } + } else { + line = srcline[cfile]; + } + + /* + * Move to next line. + */ + slew(lfp, pflag); + + /* + * Output a maximum of NERR error codes with listing. + */ + while (ep < &eb[NERR]) + *ep++ = ' '; + fprintf(lfp, "%.2s", eb); + + /* + * Source listing only option. + */ + if (lmode == SLIST) { + fprintf(lfp, "%24s%5u %s\n", "", line, ib); + return; + } +#ifndef SDK + if (lmode == ALIST) { + outchk(HUGE,HUGE); + } +#endif + + /* + * HEX output Option. + */ + if (xflag == 0) { /* HEX */ + /* + * Equate only + */ + if (lmode == ELIST) { + fprintf(lfp, "%18s%04X", "", laddr); + fprintf(lfp, " %5u %s\n", line, ib); + return; + } + + /* + * Address (with allocation) + */ + fprintf(lfp, " %04X", laddr); + if (lmode == ALIST || lmode == BLIST) { + fprintf(lfp, "%19s%5u %s\n", "", line, ib); +#ifndef SDK + outdot(); +#endif + return; + } + wp = cb; + wpt = cbt; + nb = (int) (cp - cb); + + /* + * First line of output for this source line with data. + */ + list1(wp, wpt, nb, 1); + fprintf(lfp, " %5u %s\n", line, ib); + + /* + * Subsequent lines of output if more data. + */ + while ((nb -= 6) > 0) { + wp += 6; + wpt += 6; + slew(lfp, 0); + fprintf(lfp, "%7s", ""); + list1(wp, wpt, nb, 0); + putc('\n', lfp); + } + } else + /* + * OCTAL output Option. + */ + if (xflag == 1) { /* OCTAL */ + /* + * Equate only + */ + if (lmode == ELIST) { + fprintf(lfp, "%16s%06o", "", laddr); + fprintf(lfp, " %5u %s\n", line, ib); + return; + } + + /* + * Address (with allocation) + */ + fprintf(lfp, " %06o", laddr); + if (lmode == ALIST || lmode == BLIST) { + fprintf(lfp, "%17s%5u %s\n", "", line, ib); +#ifndef SDK + outdot(); +#endif + return; + } + wp = cb; + wpt = cbt; + nb = (int) (cp - cb); + + /* + * First line of output for this source line with data. + */ + list1(wp, wpt, nb, 1); + fprintf(lfp, " %5u %s\n", line, ib); + + /* + * Subsequent lines of output if more data. + */ + while ((nb -= 4) > 0) { + wp += 4; + wpt += 4; + slew(lfp, 0); + fprintf(lfp, "%9s", ""); + list1(wp, wpt, nb, 0); + putc('\n', lfp); + } + } else + /* + * DECIMAL output Option. + */ + if (xflag == 2) { /* DECIMAL */ + /* + * Equate only + */ + if (lmode == ELIST) { + fprintf(lfp, "%16s%05u", "", laddr); + fprintf(lfp, " %5u %s\n", line, ib); + return; + } + + /* + * Address (with allocation) + */ + fprintf(lfp, " %05u", laddr); + if (lmode == ALIST || lmode == BLIST) { + fprintf(lfp, "%17s%5u %s\n", "", line, ib); +#ifndef SDK + outdot(); +#endif + return; + } + wp = cb; + wpt = cbt; + nb = (int) (cp - cb); + + /* + * First line of output for this source line with data. + */ + list1(wp, wpt, nb, 1); + fprintf(lfp, " %5u %s\n", line, ib); + + /* + * Subsequent lines of output if more data. + */ + while ((nb -= 4) > 0) { + wp += 4; + wpt += 4; + slew(lfp, 0); + fprintf(lfp, "%9s", ""); + list1(wp, wpt, nb, 0); + putc('\n', lfp); + } + } +} +#else +VOID +list() +{ + register char *wp; + register int *wpt; + register nb; + + if (lfp == NULL || lmode == NLIST) + return; + + /* + * Get Correct Line Number + */ + if (incfil >= 0) { + line = incline[incfil]; + if (line == 0) { + if (incfil > 0) { + line = incline[incfil-1]; + } else { + line = srcline[cfile]; + } + } + } else { + line = srcline[cfile]; + } + + /* + * HEX output Option. + */ + /* Output filename relative_address line_number */ + + if (incfil >= 0) { + fprintf(lfp, "%s ", incfn[incfil]); + } + else { + fprintf(lfp, "%s ", srcfn[cfile]); + } + fprintf(lfp, "%u %04X\n", line, laddr); +#if 0 + wp = cb; + wpt = cbt; + nb = (int) (cp - cb); + + /* + * First line of output for this source line with data. + */ + list1(wp, wpt, nb, 1); + fprintf(lfp, " %5u %s\n", line, ib); + + /* + * Subsequent lines of output if more data. + */ + while ((nb -= 6) > 0) { + wp += 6; + wpt += 6; + slew(lfp, 0); + fprintf(lfp, "%7s", ""); + list1(wp, wpt, nb, 0); + putc('\n', lfp); + } +#endif +} +#endif /* MLH_LST */ + +/*)Function VOID list1(wp, wpt, nw, f) + * + * int f fill blank fields (1) + * int nb number of data bytes + * int * wp pointer to data bytes + * int * wpt pointer to data byte mode + * + * local variables: + * int i loop counter + * + * global variables: + * int xflag -x, listing radix flag + * + * functions called: + * VOID list2() asslist.c + * int fprintf() c_library + * + * side effects: + * Data formatted and output to listing. + */ + +VOID +list1(wp, wpt, nb, f) +register char *wp; +register int *wpt, nb, f; +{ + register int i; + + /* + * HEX output Option. + */ + if (xflag == 0) { /* HEX */ + /* + * Bound number of words to HEX maximum per line. + */ + if (nb > 6) + nb = 6; + + /* + * Output bytes. + */ + for (i=0; i 4) + nb = 4; + + /* + * Output bytes. + */ + for (i=0; i 4) + nb = 4; + + /* + * Output bytes. + */ + for (i=0; i= 2) { + if (t & R_RELOC) { + if (t & (R_PAG0|R_PAG)) { + c = '*'; + } else if (t & R_USGN) { + c = 'u'; + } else if (t & R_PCR) { + c = 'p'; + } else { + c = 'r'; + } + if (t & R_HIGH) c += 1; + } + } + + /* + * Output the selected mode. + */ + putc(c, lfp); +} + +/*)Function VOID slew(fp, flag) + * + * FILE * fp file handle for listing + * int flag enable pagination + * + * The function slew() increments the page line count. + * If the page overflows and pagination is enabled: + * 1) put out a page skip, + * 2) a title, + * 3) a subtitle, + * 4) and reset the line count. + * + * local variables: + * none + * + * global variables: + * char cpu[] cpu type string + * int lop current line number on page + * int page current page number + * char stb[] Subtitle string buffer + * char tb[] Title string buffer + * + * functions called: + * int fprintf() c_library + * + * side effects: + * Increments page line counter, on overflow + * a new page header is output to the listing file. + */ + +VOID +slew(fp,flag) +FILE *fp; +int flag; +{ + if ((lop++ >= NLPP) && flag) { + fprintf(fp, "\fASxxxx Assembler %s (%s), page %u.\n", + VERSION, cpu, ++page); + fprintf(fp, "%s\n", tb); + fprintf(fp, "%s\n\n", stb); + lop = 5; + } +} + +/*)Function VOID lstsym(fp) + * + * FILE * fp file handle for output + * + * The function lstsym() outputs alphabetically + * sorted symbol and area tables. + * + * local variables: + * int c temporary + * int i loop counter + * int j temporary + * int k temporary + * char * ptr pointer to an id string + * int nmsym number of symbols + * int narea number of areas + * sym * sp pointer to symbol structure + * sym ** p pointer to an array of + * pointers to symbol structures + * area * ap pointer to an area structure + * + * global variables: + * area * areap pointer to an area structure + * char aretbl[] string "Area Table" + * sym dot defined as sym[0] + * char stb[] Subtitle string buffer + * sym * symhash[] array of pointers to NHASH + * linked symbol lists + * char symtbl[] string "Symbol Table" + * FILE * tfp symbol table output file handle + * int xflag -x, listing radix flag + * + * functions called: + * int fprintf() c_library + * int putc() c_library + * VOID slew() aslist.c + * int strcmp() c_library + * char * strcpy() c_library + * + * side effects: + * Symbol and area tables output. + */ + +VOID +lstsym(fp) +FILE *fp; +{ + register int c, i, j, k; + register char *ptr; + int nmsym, narea; + struct sym *sp; + struct sym **p; + struct area *ap; + + /* + * Symbol Table Header + */ + strcpy(stb, &symtbl[0]); + lop = NLPP; + if (fp == tfp) + page = 0; + slew(fp, 1); + + /* + * Find number of symbols + */ + nmsym = 0; + for (i=0; is_sp; + } + } + if (nmsym == 0) + goto atable; + + /* + * Allocate space for an array of pointers to symbols + * and load array. + */ + if ((p = (struct sym **) malloc(sizeof((struct sym *) sp)*nmsym)) + == NULL) { + fprintf(fp, "Insufficient space to build Symbol Table.\n"); + return; + } + nmsym = 0; + for (i=0; is_sp; + } + } + + /* + * Bubble Sort on Symbol Table Array + */ + j = 1; + c = nmsym - 1; + while (j) { + j = 0; + for (i=0; is_id[0],&p[i+1]->s_id[0]) > 0) { + j = 1; + sp = p[i+1]; + p[i+1] = p[i]; + p[i] = sp; + } + } + } + + /* + * Symbol Table Output + */ + for (i=0; is_area) { + j = sp->s_area->a_ref; + if (xflag == 0) { + fprintf(fp, " %2X ", j); + } else + if (xflag == 1) { + fprintf(fp, "%3o ", j); + } else + if (xflag == 2) { + fprintf(fp, "%3u ", j); + } + } else { + fprintf(fp, " "); + } + ptr = &sp->s_id[0]; + while (ptr < &sp->s_id[NCPS]) { + if ((c = *ptr++) != 0) { + putc(c, fp); + } else { + putc(' ', fp); + } + } + if (sp->s_flag & S_ASG) { + putc('=', fp); + } else { + putc(' ', fp); + } + if (sp->s_type == S_NEW) { + if (xflag == 0) { + fprintf(fp, " **** "); + } else + if (xflag == 1) { + fprintf(fp, "****** "); + } else + if (xflag == 2) { + fprintf(fp, " ***** "); + } + } else { + j = sp->s_addr; + if (xflag == 0) { + fprintf(fp, " %04X ", j); + } else + if (xflag == 1) { + fprintf(fp, "%06o ", j); + } else + if (xflag == 2) { + fprintf(fp, " %05u ", j); + } + } + j = 0; + if (sp->s_flag & S_GBL) { + putc('G', fp); + ++j; + } + if (sp->s_area != NULL) { + putc('R', fp); + ++j; + } + if (sp->s_type == S_NEW) { + putc('X', fp); + ++j; + } +#if NCPS-8 + putc('\n', fp); + slew(fp, 0); + ++i; +#else + if (++i % 3 == 0) { + putc('\n', fp); + slew(fp, pflag); + } else + if (i < nmsym) { + while (j++ < 4) + putc(' ', fp); + fprintf(fp, "| "); + } +#endif + } + putc('\n', fp); + + /* + * Area Table Header + */ + +atable: + strcpy(stb, &aretbl[0]); + lop = NLPP; + slew(fp, 1); + + /* + * Area Table Output + */ + narea = 0; + ap = areap; + while (ap) { + ++narea; + ap = ap->a_ap; + } + for (i=0; ia_ap; + j = ap->a_ref; + if (xflag == 0) { + fprintf(fp, " %2X ", j); + } else + if (xflag == 1) { + fprintf(fp, " %3o ", j); + } else + if (xflag == 2) { + fprintf(fp, " %3u ", j); + } + ptr = &ap->a_id[0]; + while (ptr < &ap->a_id[NCPS]) { + if ((c = *ptr++) != 0) { + putc(c, fp); + } else { + putc(' ', fp); + } + } + j = ap->a_size; + k = ap->a_flag; + if (xflag==0) { + fprintf(fp, " size %4X flags %X\n", j, k); + } else + if (xflag==1) { + fprintf(fp, " size %6o flags %o\n", j, k); + } else + if (xflag==2) { + fprintf(fp, " size %5u flags %u\n", j, k); + } + } +} diff --git a/link/as/z80/asm.h b/link/as/z80/asm.h new file mode 100644 index 00000000..d911b21f --- /dev/null +++ b/link/as/z80/asm.h @@ -0,0 +1,598 @@ +/* asm.h */ + +/* + * (C) Copyright 1989-1996 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +/* + * Extensions: P. Felber + */ + +#define VERSION "V01.75" + +/* + * Case Sensitivity Flag + */ +#define CASE_SENSITIVE 0 + +/*)Module asm.h + * + * The module asm.h contains the definitions for constants, + * structures, global variables, and ASxxxx functions + * contained in the ASxxxx.c files. The two functions + * and three global variables from the machine dependent + * files are also defined. + */ + +/* + * compiler/operating system specific definitions + */ + +/* DECUS C void definition */ +/* File/extension seperator */ + +#ifdef decus +#define VOID char +#define FSEPX '.' +#endif + +/* PDOS C void definition */ +/* File/extension seperator */ + +#ifdef PDOS +#define VOID char +#define FSEPX ':' +#endif + +/* Default void definition */ +/* File/extension seperator */ + +#ifndef VOID +#define VOID void +#define FSEPX '.' +#define OTHERSYSTEM +#endif + +/* + * Assembler definitions. + */ +#define LFTERM '(' /* Left expression delimeter */ +#define RTTERM ')' /* Right expression delimeter */ + +#ifdef SDK +#define NCPS 32 /* characters per symbol */ +#else /* SDK */ +#define NCPS 8 /* Chars. per symbol */ +#endif /* SDK */ +/* #define NCPS 32 */ /* Chars. per symbol */ +#define HUGE 1000 /* A huge number */ +#define NERR 3 /* Errors per line */ +#define NINPUT 128 /* Input buffer size */ +#define NCODE 128 /* Listing code buffer size */ +#define NTITL 64 /* Title buffer size */ +#define NSBTL 64 /* SubTitle buffer size */ +#define NHASH 64 /* Buckets in hash table */ +#define HMASK 077 /* Hash mask */ +#define NLPP 60 /* Lines per page */ +#define MAXFIL 6 /* Maximum command line input files */ +#define MAXINC 6 /* Maximum nesting of include files */ +#define MAXIF 10 /* Maximum nesting of if/else/endif */ +#define FILSPC 256 /* Chars. in filespec */ + +#define NLIST 0 /* No listing */ +#define SLIST 1 /* Source only */ +#define ALIST 2 /* Address only */ +#define BLIST 3 /* Address only with allocation */ +#define CLIST 4 /* Code */ +#define ELIST 5 /* Equate only */ + +#define dot sym[0] /* Dot, current loc */ +#define dca area[0] /* Dca, default code area */ + + +typedef unsigned int Addr_T; + +/* + * The area structure contains the parameter values for a + * specific program or data section. The area structure + * is a linked list of areas. The initial default area + * is "_CODE" defined in asdata.c, the next area structure + * will be linked to this structure through the structure + * element 'struct area *a_ap'. The structure contains the + * area name, area reference number ("_CODE" is 0) determined + * by the order of .area directives, area size determined + * from the total code and/or data in an area, area fuzz is + * a variable used to track pass to pass changes in the + * area size caused by variable length instruction formats, + * and area flags which specify the area's relocation type. + */ +struct area +{ + struct area *a_ap; /* Area link */ + char a_id[NCPS]; /* Area Name */ + int a_ref; /* Ref. number */ + Addr_T a_size; /* Area size */ + Addr_T a_fuzz; /* Area fuzz */ + int a_flag; /* Area flags */ +}; + +/* + * The "A_" area constants define values used in + * generating the assembler area output data. + * + * Area flags + * + * 7 6 5 4 3 2 1 0 + * +-----+-----+-----+-----+-----+-----+-----+-----+ + * | | | | PAG | ABS | OVR | | | + * +-----+-----+-----+-----+-----+-----+-----+-----+ + */ + +#define A_CON 000 /* Concatenating */ +#define A_OVR 004 /* Overlaying */ +#define A_REL 000 /* Relocatable */ +#define A_ABS 010 /* absolute */ +#define A_NOPAG 000 /* Non-Paged */ +#define A_PAG 020 /* Paged */ + +/* + * The "R_" relocation constants define values used in + * generating the assembler relocation output data for + * areas, symbols, and code. + * + * Relocation flags + * + * 7 6 5 4 3 2 1 0 + * +-----+-----+-----+-----+-----+-----+-----+-----+ + * | MSB | PAGn| PAG0| USGN| BYT2| PCR | SYM | BYT | + * +-----+-----+-----+-----+-----+-----+-----+-----+ + */ + +#define R_WORD 0000 /* 16 bit */ +#define R_BYTE 0001 /* 8 bit */ + +#define R_AREA 0000 /* Base type */ +#define R_SYM 0002 + +#define R_NORM 0000 /* PC adjust */ +#define R_PCR 0004 + +#define R_BYT1 0000 /* Byte count for R_BYTE = 1 */ +#define R_BYT2 0010 /* Byte count for R_BYTE = 2 */ + +#define R_SGND 0000 /* Signed Byte */ +#define R_USGN 0020 /* Unsigned Byte */ + +#define R_NOPAG 0000 /* Page Mode */ +#define R_PAG0 0040 /* Page '0' */ +#define R_PAG 0100 /* Page 'nnn' */ + +#define R_LSB 0000 /* low byte */ +#define R_MSB 0200 /* high byte */ + +/* + * Listing Control Flags + */ + +#define R_HIGH 0040000 /* High Byte */ +#define R_RELOC 0100000 /* Relocation */ + +#define R_DEF 00 /* Global def. */ +#define R_REF 01 /* Global ref. */ +#define R_REL 00 /* Relocatable */ +#define R_ABS 02 /* Absolute */ +#define R_GBL 00 /* Global */ +#define R_LCL 04 /* Local */ + +/* + * The mne structure is a linked list of the assembler + * mnemonics and directives. The list of mnemonics and + * directives contained in the device dependent file + * xxxpst.c are hashed and linked into NHASH lists in + * module assym.c by syminit(). The structure contains + * the mnemonic/directive name, a subtype which directs + * the evaluation of this mnemonic/directive, a flag which + * is used to detect the end of the mnemonic/directive + * list in xxxpst.c, and a value which is normally + * associated with the assembler mnemonic base instruction + * value. + */ +struct mne +{ + struct mne *m_mp; /* Hash link */ + char m_id[NCPS]; /* Mnemonic */ + char m_type; /* Mnemonic subtype */ + char m_flag; /* Mnemonic flags */ + Addr_T m_valu; /* Value */ +}; + +/* + * The sym structure is a linked list of symbols defined + * in the assembler source files. The first symbol is "." + * defined in asdata.c. The entry 'struct tsym *s_tsym' + * links any temporary symbols following this symbol and + * preceeding the next normal symbol. The structure also + * contains the symbol's name, type (USER or NEW), flag + * (global, assigned, and multiply defined), a pointer + * to the area structure defining where the symbol is + * located, a reference number assigned by outgsd() in + * asout.c, and the symbols address relative to the base + * address of the area where the symbol is located. + */ +struct sym +{ + struct sym *s_sp; /* Hash link */ + struct tsym *s_tsym; /* Temporary symbol link */ + char s_id[NCPS]; /* Symbol */ + char s_type; /* Symbol subtype */ + char s_flag; /* Symbol flags */ + struct area *s_area; /* Area line, 0 if absolute */ + int s_ref; /* Ref. number */ + Addr_T s_addr; /* Address */ +}; + +#define S_GBL 01 /* Global */ +#define S_ASG 02 /* Assigned */ +#define S_MDF 04 /* Mult. def */ +#define S_END 010 /* End mark for pst. */ + +#define S_NEW 0 /* New name */ +#define S_USER 1 /* User name */ + /* unused slot */ + /* unused slot */ + /* unused slot */ + +#define S_BYTE 5 /* .byte */ +#define S_WORD 6 /* .word */ +#define S_ASCII 7 /* .ascii */ +#define S_ASCIZ 8 /* .asciz */ +#define S_BLK 9 /* .blkb or .blkw */ +#define S_INCL 10 /* .include */ +#define S_DAREA 11 /* .area */ +#define S_ATYP 12 /* .area type */ +#define S_AREA 13 /* .area name */ +#define S_GLOBL 14 /* .globl */ +#define S_PAGE 15 /* .page */ +#define S_TITLE 16 /* .title */ +#define S_SBTL 17 /* .sbttl */ +#define S_IF 18 /* .if */ +#define S_ELSE 19 /* .else */ +#define S_ENDIF 20 /* .endif */ +#define S_EVEN 21 /* .even */ +#define S_ODD 22 /* .odd */ +#define S_RADIX 23 /* .radix */ +#define S_ORG 24 /* .org */ +#define S_MODUL 25 /* .module */ +#define S_ASCIS 26 /* .ascis */ +#ifdef SDK +# define S_FLOAT 27 /* .df */ +#endif + +/* + * The tsym structure is a linked list of temporary + * symbols defined in the assembler source files following + * a normal symbol. The structure contains the temporary + * symbols number, a flag (multiply defined), a pointer to the + * area structure defining where the temporary structure + * is located, and the temporary symbol's address relative + * to the base address of the area where the symbol + * is located. + */ +struct tsym +{ + struct tsym *t_lnk; /* Link to next */ + int t_num; /* 0-lots$ */ + char t_flg; /* flags */ + struct area *t_area; /* Area */ + Addr_T t_addr; /* Address */ +}; + +/* + * External Definitions for all Global Variables + */ + +extern int aserr; /* ASxxxx error counter + */ +extern jmp_buf jump_env; /* compiler dependent structure + * used by setjmp() and longjmp() + */ +extern int inpfil; /* count of assembler + * input files specified + */ +extern int incfil; /* current file handle index + * for include files + */ +extern int cfile; /* current file handle index + * of input assembly files + */ +extern int flevel; /* IF-ELSE-ENDIF flag will be non + * zero for false conditional case + */ +extern int tlevel; /* current conditional level + */ +extern int ifcnd[MAXIF+1]; /* array of IF statement condition + * values (0 = FALSE) indexed by tlevel + */ +extern int iflvl[MAXIF+1]; /* array of IF-ELSE-ENDIF flevel + * values indexed by tlevel + */ +extern char + afn[FILSPC]; /* afile() temporary filespec + */ +extern char + srcfn[MAXFIL][FILSPC]; /* array of source file names + */ +extern int + srcline[MAXFIL]; /* current source file line + */ +extern char + incfn[MAXINC][FILSPC]; /* array of include file names + */ +extern int + incline[MAXINC]; /* current include file line + */ +extern int radix; /* current number conversion radix: + * 2 (binary), 8 (octal), 10 (decimal), + * 16 (hexadecimal) + */ +extern int line; /* current assembler source + * line number + */ +extern int page; /* current page number + */ +extern int lop; /* current line number on page + */ +extern int pass; /* assembler pass number + */ +extern int lflag; /* -l, generate listing flag + */ +extern int gflag; /* -g, make undefined symbols global flag + */ +extern int aflag; /* -a, make all symbols global flag + */ +extern int oflag; /* -o, generate relocatable output flag + */ +extern int sflag; /* -s, generate symbol table flag + */ +extern int pflag; /* -p, enable listing pagination + */ +extern int xflag; /* -x, listing radix flag + */ +extern int fflag; /* -f(f), relocations flagged flag + */ +extern Addr_T laddr; /* address of current assembler line + * or value of .if argument + */ +extern Addr_T fuzz; /* tracks pass to pass changes in the + * address of symbols caused by + * variable length instruction formats + */ +extern int lmode; /* listing mode + */ +extern struct area area[]; /* array of 1 area + */ +extern struct area *areap; /* pointer to an area structure + */ +extern struct sym sym[]; /* array of 1 symbol + */ +extern struct sym *symp; /* pointer to a symbol structure + */ +extern struct sym *symhash[NHASH]; /* array of pointers to NHASH + * linked symbol lists + */ +extern struct mne *mnehash[NHASH]; /* array of pointers to NHASH + * linked mnemonic/directive lists + */ +extern char *ep; /* pointer into error list + * array eb[NERR] + */ +extern char eb[NERR]; /* array of generated error codes + */ +extern char *ip; /* pointer into the assembler-source + * text line in ib[] + */ +extern char ib[NINPUT]; /* assembler-source text line + */ +extern char *cp; /* pointer to assembler output + * array cb[] + */ +extern char cb[NCODE]; /* array of assembler output values + */ +extern int *cpt; /* pointer to assembler relocation type + * output array cbt[] + */ +extern int cbt[NCODE]; /* array of assembler relocation types + * describing the data in cb[] + */ +extern char tb[NTITL]; /* Title string buffer + */ +extern char stb[NSBTL]; /* Subtitle string buffer + */ +extern char symtbl[]; /* string "Symbol Table" + */ +extern char aretbl[]; /* string "Area Table" + */ +extern char module[NCPS]; /* module name string + */ +extern FILE *lfp; /* list output file handle + */ +extern FILE *ofp; /* relocation output file handle + */ +extern FILE *tfp; /* symbol table output file handle + */ +extern FILE *sfp[MAXFIL]; /* array of assembler-source file handles + */ +extern FILE *ifp[MAXINC]; /* array of include-file file handles + */ +extern char ctype[128]; /* array of character types, one per + * ASCII character + */ + +#if CASE_SENSITIVE +#else +extern char ccase[128]; /* an array of characters which + * perform the case translation function + */ +#endif + +/* + * Definitions for Character Types + */ +#define SPACE 0000 +#define ETC 0000 +#define LETTER 0001 +#define DIGIT 0002 +#define BINOP 0004 +#define RAD2 0010 +#define RAD8 0020 +#define RAD10 0040 +#define RAD16 0100 +#define ILL 0200 + +#define DGT2 DIGIT|RAD16|RAD10|RAD8|RAD2 +#define DGT8 DIGIT|RAD16|RAD10|RAD8 +#define DGT10 DIGIT|RAD16|RAD10 +#define LTR16 LETTER|RAD16 + +/* + * The exp structure is used to return the evaluation + * of an expression. The structure supports three valid + * cases: + * (1) The expression evaluates to a constant, + * mode = S_USER, flag = 0, addr contains the + * constant, and base = NULL. + * (2) The expression evaluates to a defined symbol + * plus or minus a constant, mode = S_USER, + * flag = 0, addr contains the constant, and + * base = pointer to area symbol. + * (3) The expression evaluates to a external + * global symbol plus or minus a constant, + * mode = S_NEW, flag = 1, addr contains the + * constant, and base = pointer to symbol. + */ +struct expr +{ + char e_mode; /* Address mode */ + char e_flag; /* Symbol flag */ + Addr_T e_addr; /* Address */ + union { + struct area *e_ap; + struct sym *e_sp; + } e_base; /* Rel. base */ + char e_rlcf; /* Rel. flags */ +}; + +/* C Library functions */ +/* for reference only +extern VOID exit(); +extern int fclose(); +extern char * fgets(); +extern FILE * fopen(); +extern int fprintf(); +extern VOID longjmp(); +extern VOID * malloc(); +extern int printf(); +extern char putc(); +extern int rewind(); +extern int setjmp(); +extern int strcmp(); +extern char * strcpy(); +extern int strlen(); +extern char * strncpy(); +*/ + +/* Machine independent functions */ + +/* asmain.c */ +extern FILE * afile(); +extern VOID asexit(); +extern VOID asmbl(); +extern int main(); +extern VOID newdot(); +extern VOID phase(); +extern VOID usage(); + +/* aslex.c */ +extern char endline(); +extern char get(); +extern VOID getid(); +extern int getLine_(); +extern int getmap(); +extern char getnb(); +extern VOID getst(); +extern int more(); +extern VOID unget(); + +/* assym.c */ +extern struct area * alookup(); +extern struct mne * mlookup(); +extern int hash(); +extern struct sym * lookup(); +extern VOID * new(); +extern int symeq(); +extern VOID syminit(); +extern VOID symglob(); +extern VOID allglob(); + +/* assubr.c */ +extern VOID aerr(); +extern VOID diag(); +extern VOID err(); +extern char * geterr(); +extern VOID qerr(); +extern VOID rerr(); + +/* asexpr.c */ +extern VOID abscheck(); +extern Addr_T absexpr(); +extern VOID clrexpr(); +extern int digit(); +extern int is_abs(); +extern VOID expr(); +extern int oprio(); +extern VOID term(); + +/* aslist.c */ +extern VOID list(); +extern VOID list1(); +extern VOID list2(); +extern VOID lstsym(); +extern VOID slew(); + +/* asout.c */ +extern int hibyte(); +extern int lobyte(); +extern VOID out(); +extern VOID outab(); +extern VOID outarea(); +extern VOID outaw(); +extern VOID outall(); +extern VOID outdot(); +extern VOID outbuf(); +extern VOID outchk(); +extern VOID outgsd(); +extern VOID outrb(); +extern VOID outrw(); +extern VOID outsym(); +extern VOID out_lb(); +extern VOID out_lw(); +extern VOID out_rw(); +extern VOID out_tw(); + + +/* Machine dependent variables */ + +extern char * cpu; +extern char * dsft; +extern int hilo; +extern struct mne mne[]; + +/* Machine dependent functions */ + +extern VOID minit(); + diff --git a/link/as/z80/asmain.c b/link/as/z80/asmain.c new file mode 100644 index 00000000..24f12132 --- /dev/null +++ b/link/as/z80/asmain.c @@ -0,0 +1,1197 @@ +/* asmain.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +/* + * Extensions: P. Felber + */ + +#include +#include +#include + +#ifdef SDK +#include +#include +#undef HUGE +#endif +#include "asm.h" +#include "z80.h" + +/*)Module asmain.c + * + * The module asmain.c includes the command argument parser, + * the three pass sequencer, and the machine independent + * assembler parsing code. + * + * asmain.c contains the following functions: + * VOID main(argc, argv) + * VOID asexit() + * VOID asmbl() + * FILE * afile(fn, ft, wf) + * VOID newdot(nap) + * VOID phase(ap, a) + * VOID usage() + * + * asmain.c contains the array char *usetxt[] which + * references the usage text strings printed by usage(). + */ + +/*)Function VOID main(argc, argv) + * + * int argc argument count + * char * argv array of pointers to argument strings + * + * The function main() is the entry point to the assembler. + * The purpose of main() is to (1) parse the command line + * arguments for options and source file specifications and + * (2) to process the source files through the 3 pass assembler. + * Before each assembler pass various variables are initialized + * and source files are rewound to their beginning. During each + * assembler pass each assembler-source text line is processed. + * After each assembler pass the assembler information is flushed + * to any opened output files and the if-else-endif processing + * is checked for proper termination. + * + * The function main() is also responsible for opening all + * output files (REL, LST, and SYM), sequencing the global (-g) + * and all-global (-a) variable definitions, and dumping the + * REL file header information. + * + * local variables: + * char * p pointer to argument string + * int c character from argument string + * int i argument loop counter + * area * ap pointer to area structure + * + * global variables: + * int aflag -a, make all symbols global flag + * char afn[] afile() constructed filespec + * area * areap pointer to an area structure + * int cb[] array of assembler output values + * int cbt[] array of assembler relocation types + * describing the data in cb[] + * int cfile current file handle index + * of input assembly files + * int * cp pointer to assembler output array cb[] + * int * cpt pointer to assembler relocation type + * output array cbt[] + * char eb[] array of generated error codes + * char * ep pointer into error list array eb[] + * int fflag -f(f), relocations flagged flag + * int flevel IF-ELSE-ENDIF flag will be non + * zero for false conditional case + * Addr_T fuzz tracks pass to pass changes in the + * address of symbols caused by + * variable length instruction formats + * int gflag -g, make undefined symbols global flag + * char ib[] assembler-source text line + * int inpfil count of assembler + * input files specified + * int ifcnd[] array of IF statement condition + * values (0 = FALSE) indexed by tlevel + * int iflvl[] array of IF-ELSE-ENDIF flevel + * values indexed by tlevel + * int incfil current file handle index + * for include files + * char * ip pointer into the assembler-source + * text line in ib[] + * jmp_buf jump_env compiler dependent structure + * used by setjmp() and longjmp() + * int lflag -l, generate listing flag + * int line current assembler source + * line number + * int lop current line number on page + * int oflag -o, generate relocatable output flag + * int page current page number + * int pflag enable listing pagination + * int pass assembler pass number + * int radix current number conversion radix: + * 2 (binary), 8 (octal), 10 (decimal), + * 16 (hexadecimal) + * int sflag -s, generate symbol table flag + * char srcfn[][] array of source file names + * int srcline[] current source file line + * char stb[] Subtitle string buffer + * sym * symp pointer to a symbol structure + * int tlevel current conditional level + * int xflag -x, listing radix flag + * FILE * lfp list output file handle + * FILE * ofp relocation output file handle + * FILE * tfp symbol table output file handle + * FILE * sfp[] array of assembler-source file handles + * + * called functions: + * FILE * afile() asmain.c + * VOID allglob() assym.c + * VOID asexit() asmain.c + * VOID diag() assubr.c + * VOID err() assubr.c + * int fprintf() c-library + * int getLine_() aslex.c + * VOID list() aslist.c + * VOID lstsym() aslist.c + * VOID minit() ___mch.c + * VOID newdot() asmain.c + * VOID outchk() asout.c + * VOID outgsd() asout.c + * int rewind() c-library + * int setjmp() c-library + * VOID symglob() assym.c + * VOID syminit() assym.c + * VOID usage() asmain.c + * + * side effects: + * Completion of main() completes the assembly process. + * REL, LST, and/or SYM files may be generated. + */ + +int +main(int argc, char **argv) +{ + register char *p; + register int c, i; + struct area *ap; + +#ifdef SDK + inpfil = -2; +#else /* SDK */ + fprintf(stdout, "\n"); + inpfil = -1; +#endif /* SDK */ + pflag = 1; + for (i=1; i= 0) + usage(); + ++p; + while ((c = *p++) != 0) + switch(c) { + + case 'a': + case 'A': + ++aflag; + break; + + case 'g': + case 'G': + ++gflag; + break; + + case 'l': + case 'L': + ++lflag; + break; + + case 'o': + case 'O': + ++oflag; + break; + + case 's': + case 'S': + ++sflag; + break; + + case 'p': + case 'P': + pflag = 0; + break; + + case 'x': + case 'X': + xflag = 0; + break; + + case 'q': + case 'Q': + xflag = 1; + break; + + case 'd': + case 'D': + xflag = 2; + break; + + case 'f': + case 'F': + ++fflag; + break; + + default: + usage(); + } + } else { +#ifdef SDK + if(inpfil != -2) { +#endif /* SDK */ + if (++inpfil == MAXFIL) { + fprintf(stderr, "too many input files\n"); + asexit(1); + } + sfp[inpfil] = afile(p, "", 0); + strcpy(srcfn[inpfil],afn); +#ifdef SDK + } else + inpfil++; + if (inpfil == -1) { + if (lflag) + lfp = afile(p, "lst", 1); + if (oflag) + ofp = afile(p, "", 1); + if (sflag) + tfp = afile(p, "sym", 1); + } +#else /* SDK */ + if (inpfil == 0) { + if (lflag) + lfp = afile(p, "LST", 1); + if (oflag) + ofp = afile(p, "REL", 1); + if (sflag) + tfp = afile(p, "SYM", 1); + } +#endif /* SDK */ + } + } + if (inpfil < 0) + usage(); + syminit(); + for (pass=0; pass<3; ++pass) { + if (gflag && pass == 1) + symglob(); + if (aflag && pass == 1) + allglob(); + if (oflag && pass == 2) + outgsd(); + flevel = 0; + tlevel = 0; + ifcnd[0] = 0; + iflvl[0] = 0; + radix = 10; + srcline[0] = 0; + page = 0; + stb[0] = 0; + lop = NLPP; + cfile = 0; + incfil = -1; + for (i = 0; i <= inpfil; i++) + rewind(sfp[i]); + ap = areap; + while (ap) { + ap->a_fuzz = 0; + ap->a_size = 0; + ap = ap->a_ap; + } + fuzz = 0; + dot.s_addr = 0; + dot.s_area = &dca; + symp = ˙ + minit(); + while (getLine_()) { + cp = cb; + cpt = cbt; + ep = eb; + ip = ib; + if (setjmp(jump_env) == 0) + asmbl(); + if (pass == 2) { + diag(); + list(); + } + } + newdot(dot.s_area); /* Flush area info */ + if (flevel || tlevel) + err('i'); + } + if (oflag) + outchk(HUGE, HUGE); /* Flush */ + if (sflag) { + lstsym(tfp); + } else + if (lflag) { + lstsym(lfp); + } + asexit(aserr != 0); + /* Never reached */ + return 0; +} + +/*)Function VOID asexit(i) + * + * int i exit code + * + * The function asexit() explicitly closes all open + * files and then terminates the program. + * + * local variables: + * int j loop counter + * + * global variables: + * FILE * ifp[] array of include-file file handles + * FILE * lfp list output file handle + * FILE * ofp relocation output file handle + * FILE * tfp symbol table output file handle + * FILE * sfp[] array of assembler-source file handles + * + * functions called: + * int fclose() c-library + * VOID exit() c-library + * + * side effects: + * All files closed. Program terminates. + */ + +VOID +asexit(i) +int i; +{ + int j; + + if (lfp != NULL) fclose(lfp); + if (ofp != NULL) fclose(ofp); + if (tfp != NULL) fclose(tfp); + + for (j=0; j= 0) { + n = 10*n + d; + c = get(); + } + if (c != '$' || get() != ':') + qerr(); + tp = symp->s_tsym; + if (pass == 0) { + while (tp) { + if (n == tp->t_num) { + tp->t_flg |= S_MDF; + break; + } + tp = tp->t_lnk; + } + if (tp == NULL) { + tp=(struct tsym *) new (sizeof(struct tsym)); + tp->t_lnk = symp->s_tsym; + tp->t_num = n; + tp->t_flg = 0; + tp->t_area = dot.s_area; + tp->t_addr = dot.s_addr; + symp->s_tsym = tp; + } + } else { + while (tp) { + if (n == tp->t_num) { + break; + } + tp = tp->t_lnk; + } + if (tp) { + if (pass == 1) { + fuzz = tp->t_addr - dot.s_addr; + tp->t_area = dot.s_area; + tp->t_addr = dot.s_addr; + } else { + phase(tp->t_area, tp->t_addr); + if (tp->t_flg & S_MDF) + err('m'); + } + } else { + err('u'); + } + } + lmode = ALIST; + goto loop; + } + /* + * If the first character is a letter then assume a lable, + * symbol, assembler directive, or assembler mnemonic is + * being processed. + */ + if ((ctype[c] & LETTER) == 0) { + if (flevel) { + return; + } else { + qerr(); + } + } + getid(id, c); + c = getnb(); + /* + * If the next character is a : then a label is being processed. + * A double :: defines a global label. If this is new label + * then create a symbol structure. + * pass 0: + * Flag multiply defined labels. + * pass 1: + * Load area, address, and fuzz values + * into structure symp. + * pass 2: + * Check for assembler phase error and + * multiply defined error. + */ + if (c == ':') { + if (flevel) + return; + if ((c = get()) != ':') { + unget(c); + c = 0; + } + symp = lookup(id); + if (symp == &dot) + err('.'); + if (pass == 0) + if ((symp->s_type != S_NEW) && + ((symp->s_flag & S_ASG) == 0)) + symp->s_flag |= S_MDF; + if (pass != 2) { + fuzz = symp->s_addr - dot.s_addr; + symp->s_type = S_USER; + symp->s_area = dot.s_area; + symp->s_addr = dot.s_addr; + } else { + if (symp->s_flag & S_MDF) + err('m'); + phase(symp->s_area, symp->s_addr); + } + if (c) { + symp->s_flag |= S_GBL; + } + lmode = ALIST; + goto loop; + } + /* + * If the next character is a = then an equate is being processed. + * A double == defines a global equate. If this is new variable + * then create a symbol structure. + */ + if (c == '=') { + if (flevel) + return; + if ((c = get()) != '=') { + unget(c); + c = 0; + } + clrexpr(&e1); + expr(&e1, 0); + sp = lookup(id); + if (sp == &dot) { + outall(); + if (e1.e_flag || e1.e_base.e_ap != dot.s_area) + err('.'); + } else + if (sp->s_type != S_NEW && (sp->s_flag & S_ASG) == 0) { + err('m'); + } + sp->s_type = S_USER; + sp->s_area = e1.e_base.e_ap; + sp->s_addr = laddr = e1.e_addr; + sp->s_flag |= S_ASG; + if (c) { + sp->s_flag |= S_GBL; + } + lmode = ELIST; + goto loop; + } + unget(c); + lmode = flevel ? SLIST : CLIST; + if ((mp = mlookup(id)) == NULL) { + if (!flevel) + err('o'); + return; + } + /* + * If we have gotten this far then we have found an + * assembler directive or an assembler mnemonic. + * + * Check for .if, .else, .endif, and .page directives + * which are not controlled by the conditional flags + */ + switch (mp->m_type) { + + case S_IF: + n = absexpr(); + if (tlevel < MAXIF) { + ++tlevel; + ifcnd[tlevel] = n; + iflvl[tlevel] = flevel; + if (n == 0) { + ++flevel; + } + } else { + err('i'); + } + lmode = ELIST; + laddr = n; + return; + + case S_ELSE: + if (ifcnd[tlevel]) { + if (++flevel > (iflvl[tlevel]+1)) { + err('i'); + } + } else { + if (--flevel < iflvl[tlevel]) { + err('i'); + } + } + lmode = SLIST; + return; + + case S_ENDIF: + if (tlevel) { + flevel = iflvl[tlevel--]; + } else { + err('i'); + } + lmode = SLIST; + return; + + case S_PAGE: + lop = NLPP; + lmode = NLIST; + return; + + default: + break; + } + if (flevel) + return; + /* + * If we are not in a false state for .if/.else then + * process the assembler directives here. + */ + switch (mp->m_type) { + + case S_EVEN: + outall(); + laddr = dot.s_addr = (dot.s_addr + 1) & ~1; + lmode = ALIST; + break; + + case S_ODD: + outall(); + laddr = dot.s_addr |= 1; + lmode = ALIST; + break; + + case S_BYTE: + case S_WORD: + do { + clrexpr(&e1); + expr(&e1, 0); + if (mp->m_type == S_BYTE) { + outrb(&e1, R_NORM); + } else { + outrw(&e1, R_NORM); + } + } while ((c = getnb()) == ','); + unget(c); + break; + +#ifdef SDK + case S_FLOAT: + do { + getid( readbuffer, ' ' ); /* Hack :) */ + if ((c=getnb())=='.') + { + getid(&readbuffer[strlen(readbuffer)],'.'); + } + else + unget(c); + + f1 = strtod( readbuffer, (char **)NULL ); + /* Convert f1 to a gb-lib type fp + * 24 bit mantissa followed by 7 bit exp and 1 bit sign + */ + + if (f1!=0) + { + + f2 = floor(log(fabs(f1))/log(2))+1; + mantissa = (unsigned int) ((0x1000000*fabs(f1))/exp(f2*log(2))) ; + mantissa &=0xffffff; + exponent = (unsigned int) (f2 + 0x40) ; + if (f1<0) + exponent |=0x80; + } + + else + { + mantissa=0; + exponent=0; + } + + outab(mantissa&0xff); + outab((mantissa>>8)&0xff); + outab((mantissa>>16)&0xff); + outab(exponent&0xff); + + } while ((c = getnb()) == ','); + unget(c); + break; +#endif + + case S_ASCII: + case S_ASCIZ: + if ((d = getnb()) == '\0') + qerr(); + while ((c = getmap(d)) >= 0) + outab(c); + if (mp->m_type == S_ASCIZ) + outab(0); + break; + + case S_ASCIS: + if ((d = getnb()) == '\0') + qerr(); + c = getmap(d); + while (c >= 0) { + if ((n = getmap(d)) >= 0) { + outab(c); + } else { + outab(c | 0x80); + } + c = n; + } + break; + + case S_BLK: + clrexpr(&e1); + expr(&e1, 0); + dot.s_addr += e1.e_addr*mp->m_valu; + outchk(HUGE,HUGE); + lmode = BLIST; + break; + + case S_TITLE: + p = tb; + if ((c = getnb()) != 0) { + do { + if (p < &tb[NTITL-1]) + *p++ = c; + } while ((c = get()) != 0); + } + *p = 0; + unget(c); + lmode = SLIST; + break; + + case S_SBTL: + p = stb; + if ((c = getnb()) != 0) { + do { + if (p < &stb[NSBTL-1]) + *p++ = c; + } while ((c = get()) != 0); + } + *p = 0; + unget(c); + lmode = SLIST; + break; + + case S_MODUL: + getst(id, -1); + if (pass == 0) { + if (module[0]) { + err('m'); + } else { + strncpy(module, id, NCPS); + } + } + lmode = SLIST; + break; + + case S_GLOBL: + do { + getid(id, -1); + sp = lookup(id); + sp->s_flag |= S_GBL; + } while ((c = getnb()) == ','); + unget(c); + lmode = SLIST; + break; + + case S_DAREA: + getid(id, -1); + uaf = 0; + uf = A_CON|A_REL; + if ((c = getnb()) == '(') { + do { + getid(opt, -1); + mp = mlookup(opt); + if (mp && mp->m_type == S_ATYP) { + ++uaf; + uf |= mp->m_valu; + } else { + err('u'); + } + } while ((c = getnb()) == ','); + if (c != ')') + qerr(); + } else { + unget(c); + } + if ((ap = alookup(id)) != NULL) { + if (uaf && uf != ap->a_flag) + err('m'); + } else { + ap = (struct area *) new (sizeof(struct area)); + ap->a_ap = areap; + strncpy(ap->a_id, id, NCPS); + ap->a_ref = areap->a_ref + 1; + ap->a_size = 0; + ap->a_fuzz = 0; + ap->a_flag = uaf ? uf : (A_CON|A_REL); + areap = ap; + } + newdot(ap); + lmode = SLIST; + break; + + case S_ORG: + if (dot.s_area->a_flag & A_ABS) { + outall(); + laddr = dot.s_addr = absexpr(); + } else { + err('o'); + } + outall(); + lmode = ALIST; + break; + + case S_RADIX: + if (more()) { + switch (getnb()) { + case 'b': + case 'B': + radix = 2; + break; + case '@': + case 'o': + case 'O': + case 'q': + case 'Q': + radix = 8; + break; + case 'd': + case 'D': + radix = 10; + break; + case 'h': + case 'H': + case 'x': + case 'X': + radix = 16; + break; + default: + radix = 10; + qerr(); + break; + } + } else { + radix = 10; + } + lmode = SLIST; + break; + + case S_INCL: + d = getnb(); + p = fn; + while ((c = get()) != d) { + if (p < &fn[FILSPC-1]) { + *p++ = c; + } else { + break; + } + } + *p = 0; + if (++incfil == MAXINC || + (ifp[incfil] = fopen(fn, "r")) == NULL) { + --incfil; + err('i'); + } else { + lop = NLPP; + incline[incfil] = 0; + strcpy(incfn[incfil],fn); + } + lmode = SLIST; + break; + + /* + * If not an assembler directive then go to + * the machine dependent function which handles + * all the assembler mnemonics. + */ + default: + machine(mp); + } + goto loop; +} + +/*)Function FILE * afile(fn, ft, wf) + * + * char * fn file specification string + * char * ft file type string + * int wf read(0)/write(1) flag + * + * The function afile() opens a file for reading or writing. + * (1) If the file type specification string ft + * is not NULL then a file specification is + * constructed with the file path\name in fn + * and the extension in ft. + * (2) If the file type specification string ft + * is NULL then the file specification is + * constructed from fn. If fn does not have + * a file type then the default source file + * type dsft is appended to the file specification. + * + * afile() returns a file handle for the opened file or aborts + * the assembler on an open error. + * + * local variables: + * int c character value + * FILE * fp filehandle for opened file + * char * p1 pointer to filespec string fn + * char * p2 pointer to filespec string fb + * char * p3 pointer to filetype string ft + * + * global variables: + * char afn[] afile() constructed filespec + * char dsft[] default assembler file type string + * char afn[] constructed file specification string + * + * functions called: + * VOID asexit() asmain.c + * FILE * fopen() c_library + * int fprintf() c_library + * + * side effects: + * File is opened for read or write. + */ + +FILE * +afile(fn, ft, wf) +char *fn; +char *ft; +int wf; +{ + register char *p2, *p3; + register int c; + FILE *fp; + + p2 = afn; + p3 = ft; + + strcpy (afn, fn); + p2 = strrchr (afn, FSEPX); // search last '.' + if (!p2) + p2 = afn + strlen (afn); + if (p2 > &afn[FILSPC-4]) // truncate filename, if it's too long + p2 = &afn[FILSPC-4]; + *p2++ = FSEPX; + + // choose a file-extension + if (*p3 == 0) { // extension supplied? + p3 = strrchr (fn, FSEPX); // no: extension in fn? + if (p3) + ++p3; + else + p3 = dsft; // no: default extension + } + + while ((c = *p3++) != 0) { // strncpy + if (p2 < &afn[FILSPC-1]) + *p2++ = c; + } + *p2++ = 0; + + if ((fp = fopen(afn, wf?"w":"r")) == NULL) { + fprintf(stderr, "%s: cannot %s.\n", afn, wf?"create":"open"); + asexit(1); + } + return (fp); +} + +/*)Function VOID newdot(nap) + * + * area * nap pointer to the new area structure + * + * The function newdot(): + * (1) copies the current values of fuzz and the last + * address into the current area referenced by dot + * (2) loads dot with the pointer to the new area and + * loads the fuzz and last address parameters + * (3) outall() is called to flush any remaining + * bufferred code from the old area to the output + * + * local variables: + * area * oap pointer to old area + * + * global variables: + * sym dot defined as sym[0] + * Addr_T fuzz tracks pass to pass changes in the + * address of symbols caused by + * variable length instruction formats + * + * functions called: + * none + * + * side effects: + * Current area saved, new area loaded, buffers flushed. + */ + +VOID +newdot(nap) +register struct area *nap; +{ + register struct area *oap; + + oap = dot.s_area; + oap->a_fuzz = fuzz; + oap->a_size = dot.s_addr; + fuzz = nap->a_fuzz; + dot.s_area = nap; + dot.s_addr = nap->a_size; + outall(); +} + +/*)Function VOID phase(ap, a) + * + * area * ap pointer to area + * Addr_T a address in area + * + * Function phase() compares the area ap and address a + * with the current area dot.s_area and address dot.s_addr + * to determine if the position of the symbol has changed + * between assembler passes. + * + * local variables: + * none + * + * global varaibles: + * sym * dot defined as sym[0] + * + * functions called: + * none + * + * side effects: + * The p error is invoked if the area and/or address + * has changed. + */ + +VOID +phase(ap, a) +struct area *ap; +Addr_T a; +{ + if (ap != dot.s_area || a != dot.s_addr) + err('p'); +} + +char *usetxt[] = { +#ifdef SDK + "Usage: [-dqxgalopsf] outfile file1 [file2 file3 ...]", +#else /* SDK */ + "Usage: [-dqxgalopsf] file1 [file2 file3 ...]", +#endif /* SDK */ + " d decimal listing", + " q octal listing", + " x hex listing (default)", + " g undefined symbols made global", + " a all user symbols made global", +#ifdef SDK + " l create list output outfile[LST]", + " o create object output outfile[o]", + " s create symbol output outfile[SYM]", +#else /* SDK */ + " l create list output file1[LST]", + " o create object output file1[REL]", + " s create symbol output file1[SYM]", +#endif /* SDK */ + " p disable listing pagination", + " f flag relocatable references by ` in listing file", + " ff flag relocatable references by mode in listing file", + "", + 0 +}; + +/*)Function VOID usage() + * + * The function usage() outputs to the stderr device the + * assembler name and version and a list of valid assembler options. + * + * local variables: + * char ** dp pointer to an array of + * text string pointers. + * + * global variables: + * char cpu[] assembler type string + * char * usetxt[] array of string pointers + * + * functions called: + * VOID asexit() asmain.c + * int fprintf() c_library + * + * side effects: + * program is terminated + */ + +VOID +usage() +{ + register char **dp; + + fprintf(stderr, "\nASxxxx Assembler %s (%s)\n\n", VERSION, cpu); + for (dp = usetxt; *dp; dp++) + fprintf(stderr, "%s\n", *dp); + asexit(1); +} diff --git a/link/as/z80/asout.c b/link/as/z80/asout.c new file mode 100644 index 00000000..5396de3e --- /dev/null +++ b/link/as/z80/asout.c @@ -0,0 +1,1084 @@ +/* asout.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +#include +#include +#include +#include "asm.h" + + +/*)Module asout.c + * + * The module asout.c contains all the functions used to + * generate the .REL assembler output file. + * + * + * The assemblers' output object file is an ascii file containing + * the information needed by the linker to bind multiple object + * modules into a complete loadable memory image. + * + * The object module contains the following designators: + * + * [XDQ][HL] + * X Hexidecimal radix + * D Decimal radix + * Q Octal radix + * + * H Most significant byte first + * L Least significant byte first + * + * H Header + * M Module + * A Area + * S Symbol + * T Object code + * R Relocation information + * P Paging information + * + * + * (1) Radix Line + * + * The first line of an object module contains the [XDQ][HL] + * format specifier (i.e. XH indicates a hexidecimal file with + * most significant byte first) for the following designators. + * + * + * (2) Header Line + * + * H aa areas gg global symbols + * + * The header line specifies the number of areas(aa) and the + * number of global symbols(gg) defined or referenced in this ob- + * ject module segment. + * + * + * (3) Module Line + * + * M name + * + * The module line specifies the module name from which this + * header segment was assembled. The module line will not appear + * if the .module directive was not used in the source program. + * + * + * (4) Symbol Line + * + * S string Defnnnn + * + * or + * + * S string Refnnnn + * + * The symbol line defines (Def) or references (Ref) the symbol + * 'string' with the value nnnn. The defined value is relative to + * the current area base address. References to constants and ex- + * ternal global symbols will always appear before the first area + * definition. References to external symbols will have a value of + * zero. + * + * + * (5) Area Line + * + * A label size ss flags ff + * + * The area line defines the area label, the size (ss) of the + * area in bytes, and the area flags (ff). The area flags specify + * the ABS, REL, CON, OVR, and PAG parameters: + * + * OVR/CON (0x04/0x00 i.e. bit position 2) + * + * ABS/REL (0x08/0x00 i.e. bit position 3) + * + * PAG (0x10 i.e. bit position 4) + * + * + * (6) T Line + * + * T xx xx nn nn nn nn nn ... + * + * The T line contains the assembled code output by the assem- + * bler with xx xx being the offset address from the current area + * base address and nn being the assembled instructions and data in + * byte format. + * + * + * (7) R Line + * + * R 0 0 nn nn n1 n2 xx xx ... + * + * The R line provides the relocation information to the linker. + * The nn nn value is the current area index, i.e. which area the + * current values were assembled. Relocation information is en- + * coded in groups of 4 bytes: + * + * 1. n1 is the relocation mode and object format + * 1. bit 0 word(0x00)/byte(0x01) + * 2. bit 1 relocatable area(0x00)/symbol(0x02) + * 3. bit 2 normal(0x00)/PC relative(0x04) relocation + * 4. bit 3 1-byte(0x00)/2-byte(0x08) object format for + * byte data + * 5. bit 4 signed(0x00)/unsigned(0x10) byte data + * 6. bit 5 normal(0x00)/page '0'(0x20) reference + * 7. bit 6 normal(0x00)/page 'nnn'(0x40) reference + * 8. bit 7 normal(0x00)/MSB of value + * + * 2. n2 is a byte index into the corresponding (i.e. pre- + * ceeding) T line data (i.e. a pointer to the data to be + * updated by the relocation). The T line data may be + * 1-byte or 2-byte byte data format or 2-byte word + * format. + * + * 3. xx xx is the area/symbol index for the area/symbol be- + * ing referenced. the corresponding area/symbol is found + * in the header area/symbol lists. + * + * + * The groups of 4 bytes are repeated for each item requiring relo- + * cation in the preceeding T line. + * + * + * (8) P Line + * + * P 0 0 nn nn n1 n2 xx xx + * + * The P line provides the paging information to the linker as + * specified by a .setdp directive. The format of the relocation + * information is identical to that of the R line. The correspond- + * ing T line has the following information: + * T xx xx aa aa bb bb + * + * Where aa aa is the area reference number which specifies the + * selected page area and bb bb is the base address of the page. + * bb bb will require relocation processing if the 'n1 n2 xx xx' is + * specified in the P line. The linker will verify that the base + * address is on a 256 byte boundary and that the page length of an + * area defined with the PAG type is not larger than 256 bytes. + * + * The linker defaults any direct page references to the first + * area defined in the input REL file. All ASxxxx assemblers will + * specify the _CODE area first, making this the default page area. + * + * + * asout.c contains the following functions: + * int lobyte() + * int hibyte() + * VOID out() + * VOID outab() + * VOID outall() + * VOID outarea() + * VOID outaw() + * VOID outbuf() + * VOID outchk() + * VOID outdot() + * VOID outdp() + * VOID outgsd() + * VOID outrb() + * VOID outrw() + * VOID outsym() + * VOID out_lb() + * VOID out_lw() + * VOID out_rw() + * VOID out_tw() + * + * The module asout.c contains the following local variables: + * int rel[] relocation data for code/data array + * int * relp pointer to rel array + * int txt[] assembled code/data array + * int * txtp pointer to txt array + */ + +#define NTXT 16 +#define NREL 16 + +char txt[NTXT]; +char rel[NREL]; + +char *txtp = { &txt[0] }; +char *relp = { &rel[0] }; + +/*)Function VOID outab(b) + * + * int b assembler data word + * + * The function outab() processes a single word of + * assembled data in absolute format. + * + * local variables: + * int * txtp pointer to data word + * + * global variables: + * int oflag -o, generate relocatable output flag + * int pass assembler pass number + * + * functions called: + * VOID outchk() asout.c + * VOID out_lb() asout.c + * + * side effects: + * The current assembly address is incremented by 1. + */ + +VOID +outab(b) +{ + if (pass == 2) { + out_lb(b,0); + if (oflag) { + outchk(1, 0); + *txtp++ = lobyte(b); + } + } + ++dot.s_addr; +} + +/*)Function VOID outaw(w) + * + * int w assembler data word + * + * The function outaw() processes a single word of + * assembled data in absolute format. + * + * local variables: + * int * txtp pointer to data word + * + * global variables: + * int oflag -o, generate relocatable output flag + * int pass assembler pass number + * + * functions called: + * VOID outchk() asout.c + * VOID out_lw() asout.c + * + * side effects: + * The current assembly address is incremented by 2. + */ + +VOID +outaw(w) +{ + if (pass == 2) { + out_lw(w,0); + if (oflag) { + outchk(2, 0); + out_tw(w); + } + } + dot.s_addr += 2; +} + +/*)Function VOID outrb(esp, r) + * + * expr * esp pointer to expr structure + * int r relocation mode + * + * The function outrb() processes a byte of generated code + * in either absolute or relocatable format dependent upon + * the data contained in the expr structure esp. If the + * .REL output is enabled then the appropriate information + * is loaded into the txt and rel buffers. + * + * local variables: + * int n symbol/area reference number + * int * relp pointer to rel array + * int * txtp pointer to txt array + * + * global variables: + * sym dot defined as sym[0] + * int oflag -o, generate relocatable output flag + * int pass assembler pass number + * + * functions called: + * VOID aerr() assubr.c + * VOID outchk() asout.c + * VOID out_lb() asout.c + * VOID out_rb() asout.c + * VOID out_tb() asout.c + * + * side effects: + * The current assembly address is incremented by 1. + */ + +VOID +outrb(esp, r) +register struct expr *esp; +int r; +{ + register int n; + + if (pass == 2) { + if (esp->e_flag==0 && esp->e_base.e_ap==NULL) { + out_lb(lobyte(esp->e_addr),0); + if (oflag) { + outchk(1, 0); + *txtp++ = lobyte(esp->e_addr); + } + } else { + r |= R_BYTE | R_BYT2 | esp->e_rlcf; + if (r & R_MSB) { + out_lb(hibyte(esp->e_addr),r|R_RELOC|R_HIGH); + } else { + out_lb(lobyte(esp->e_addr),r|R_RELOC); + } + if (oflag) { + outchk(2, 4); + out_tw(esp->e_addr); + if (esp->e_flag) { + n = esp->e_base.e_sp->s_ref; + r |= R_SYM; + } else { + n = esp->e_base.e_ap->a_ref; + } + *relp++ = r; + *relp++ = txtp - txt - 2; + out_rw(n); + } + } + } + ++dot.s_addr; +} + +/*)Function VOID outrw(esp, r) + * + * expr * esp pointer to expr structure + * int r relocation mode + * + * The function outrw() processes a word of generated code + * in either absolute or relocatable format dependent upon + * the data contained in the expr structure esp. If the + * .REL output is enabled then the appropriate information + * is loaded into the txt and rel buffers. + * + * local variables: + * int n symbol/area reference number + * int * relp pointer to rel array + * int * txtp pointer to txt array + * + * global variables: + * sym dot defined as sym[0] + * int oflag -o, generate relocatable output flag + * int pass assembler pass number + * + * functions called: + * VOID aerr() assubr.c + * VOID outchk() asout.c + * VOID out_lw() asout.c + * VOID out_rw() asout.c + * VOID out_tw() asout.c + * + * side effects: + * The current assembly address is incremented by 2. + */ + +VOID +outrw(esp, r) +register struct expr *esp; +int r; +{ + register int n; + + if (pass == 2) { + if (esp->e_flag==0 && esp->e_base.e_ap==NULL) { + out_lw(esp->e_addr,0); + if (oflag) { + outchk(2, 0); + out_tw(esp->e_addr); + } + } else { + r |= R_WORD | esp->e_rlcf; + if (r & R_BYT2) { + rerr(); + if (r & R_MSB) { + out_lw(hibyte(esp->e_addr),r|R_RELOC); + } else { + out_lw(lobyte(esp->e_addr),r|R_RELOC); + } + } else { + out_lw(esp->e_addr,r|R_RELOC); + } + if (oflag) { + outchk(2, 4); + out_tw(esp->e_addr); + if (esp->e_flag) { + n = esp->e_base.e_sp->s_ref; + r |= R_SYM; + } else { + n = esp->e_base.e_ap->a_ref; + } + *relp++ = r; + *relp++ = txtp - txt - 2; + out_rw(n); + } + } + } + dot.s_addr += 2; +} + +/*)Function VOID outdp(carea, esp) + * + * area * carea pointer to current area strcuture + * expr * esp pointer to expr structure + * + * The function outdp() flushes the output buffer and + * outputs paging information to the .REL file. + * + * local variables: + * int n symbol/area reference number + * int r relocation mode + * int * relp pointer to rel array + * int * txtp pointer to txt array + * + * global variables: + * int oflag -o, generate relocatable output flag + * int pass assembler pass number + * + * functions called: + * VOID outbuf() asout.c + * VOID outchk() asout.c + * VOID out_rw() asout.c + * VOID out_tw() asout.c + * + * side effects: + * Output buffer flushed to .REL fiel. + * Paging information dumped to .REL file. + */ + +VOID +outdp(carea, esp) +register struct area *carea; +register struct expr *esp; +{ + register int n, r; + + if (oflag && pass==2) { + outchk(HUGE,HUGE); + out_tw(carea->a_ref); + out_tw(esp->e_addr); + if (esp->e_flag || esp->e_base.e_ap!=NULL) { + r = R_WORD; + if (esp->e_flag) { + n = esp->e_base.e_sp->s_ref; + r |= R_SYM; + } else { + n = esp->e_base.e_ap->a_ref; + } + *relp++ = r; + *relp++ = txtp - txt - 2; + out_rw(n); + } + outbuf("P"); + } +} + +/*)Function VOID outall() + * + * The function outall() will output any bufferred assembled + * data and relocation information (during pass 2 if the .REL + * output has been enabled). + * + * local variables: + * none + * + * global variables: + * int oflag -o, generate relocatable output flag + * int pass assembler pass number + * + * functions called: + * VOID outbuf() asout.c + * + * side effects: + * assembled data and relocation buffers will be cleared. + */ + +VOID +outall() +{ + if (oflag && pass==2) + outbuf("R"); +} + +/*)Function VOID outdot() + * + * The function outdot() outputs information about the + * current program counter value (during pass 2 if the .REL + * output has been enabled). + * + * local variables: + * none + * + * global variables: + * int oflag -o, generate relocatable output flag + * int pass assembler pass number + * + * functions called: + * int fprintf() c_library + * VOID out() asout.c + * + * side effects: + * assembled data and relocation buffers will be cleared. + */ + +VOID +outdot() +{ + if (oflag && pass==2) { + fprintf(ofp, "T"); + out(txt,(int) (txtp-txt)); + fprintf(ofp, "\n"); + fprintf(ofp, "R"); + out(rel,(int) (relp-rel)); + fprintf(ofp, "\n"); + txtp = txt; + relp = rel; + } +} + +/*)Function outchk(nt, nr) + * + * int nr number of additional relocation words + * int nt number of additional data words + * + * The function outchk() checks the data and relocation buffers + * for space to insert the nt data words and nr relocation words. + * If space is not available then output the current data and + * initialize the data buffers to receive the new data. + * + * local variables: + * area * ap pointer to an area structure + * int * relp pointer to rel array + * int * txtp pointer to txt array + * + * global variables: + * sym dot defined as sym[0] + * + * functions called: + * VOID outbuf() asout.c + * + * side effects: + * Data and relocation buffers may be emptied and initialized. + */ + +VOID +outchk(nt, nr) +{ + register struct area *ap; + + if (txtp+nt > &txt[NTXT] || relp+nr > &rel[NREL]) { + outbuf("R"); + } + if (txtp == txt) { + out_tw(dot.s_addr); + if ((ap = dot.s_area) != NULL) { + *relp++ = R_WORD|R_AREA; + *relp++ = 0; + out_rw(ap->a_ref); + } + } +} + +/*)Function VOID outbuf() + * + * The function outbuf() will output any bufferred data + * and relocation information to the .REL file. The output + * buffer pointers and counters are initialized. + * + * local variables: + * int rel[] relocation data for code/data array + * int * relp pointer to rel array + * int txt[] assembled code/data array + * int * txtp pointer to txt array + * + * global variables: + * FILE * ofp relocation output file handle + * + * functions called: + * VOID out() asout.c + * + * side effects: + * All bufferred data written to .REL file and + * buffer pointers and counters initialized. + */ + +VOID +outbuf(s) +char *s; +{ + if (txtp > &txt[2]) { + fprintf(ofp, "T"); + out(txt,(int) (txtp-txt)); + fprintf(ofp, "\n"); + fprintf(ofp, s); + out(rel,(int) (relp-rel)); + fprintf(ofp, "\n"); + } + txtp = txt; + relp = rel; +} + +/*)Function VOID outgsd() + * + * The function outgsd() performs the following: + * (1) outputs the .REL file radix + * (2) outputs the header specifying the number + * of areas and global symbols + * (3) outputs the module name + * (4) set the reference number and output a symbol line + * for all external global variables and absolutes + * (5) output an area name, set reference number and output + * a symbol line for all global relocatables in the area. + * Repeat this proceedure for all areas. + * + * local variables: + * area * ap pointer to an area structure + * sym * sp pointer to a sym structure + * int i loop counter + * int j loop counter + * int c string character value + * int narea number of code areas + * char * ptr string pointer + * int nglob number of global symbols + * int rn symbol reference number + * + * global variables: + * area * areap pointer to an area structure + * char module[] module name string + * sym * symhash[] array of pointers to NHASH + * linked symbol lists + * int xflag -x, listing radix flag + * + * functions called: + * int fprintf() c_library + * VOID outarea() asout.c + * VOID outsym() asout.c + * int putc() c_library + * + * side effects: + * All symbols are given reference numbers, all symbol + * and area information is output to the .REL file. + */ + +VOID +outgsd() +{ + register struct area *ap; + register struct sym *sp; + register int i, j; + char *ptr; + int c, narea, nglob, rn; + + /* + * Number of areas + */ + narea = areap->a_ref + 1; + + /* + * Number of global references/absolutes + */ + nglob = 0; + for (i = 0; i < NHASH; ++i) { + sp = symhash[i]; + while (sp) { + if (sp->s_flag&S_GBL) + ++nglob; + sp = sp->s_sp; + } + } + + /* + * Output Radix and number of areas and symbols + */ + if (xflag == 0) { + fprintf(ofp, "X%c\n", hilo ? 'H' : 'L'); + fprintf(ofp, "H %X areas %X global symbols\n", narea, nglob); + } else + if (xflag == 1) { + fprintf(ofp, "Q%c\n", hilo ? 'H' : 'L'); + fprintf(ofp, "H %o areas %o global symbols\n", narea, nglob); + } else + if (xflag == 2) { + fprintf(ofp, "D%c\n", hilo ? 'H' : 'L'); + fprintf(ofp, "H %u areas %u global symbols\n", narea, nglob); + } + + /* + * Module name + */ + if (module[0]) { + fprintf(ofp, "M "); + ptr = &module[0]; + while (ptr < &module[NCPS]) { + if ((c = *ptr++) != 0) + putc(c, ofp); + } + putc('\n', ofp); + } + + /* + * Global references and absolutes. + */ + rn = 0; + for (i=0; is_area==NULL && sp->s_flag&S_GBL) { + sp->s_ref = rn++; + outsym(sp); + } + sp = sp->s_sp; + } + } + + /* + * Global relocatables. + */ + for (i=0; ia_ref != i) + ap = ap->a_ap; + outarea(ap); + for (j=0; js_area==ap && sp->s_flag&S_GBL) { + sp->s_ref = rn++; + outsym(sp); + } + sp = sp->s_sp; + } + } + } +} + +/*)Function VOID outarea(ap) + * + * area * ap pointer to an area structure + * + * The function outarea() outputs the A line to the .REL + * file. The A line contains the area's name, size, and + * attributes. + * + * local variables: + * char * ptr pointer to area id string + * int c character value + * + * global variables: + * FILE * ofp relocation output file handle + * int xflag -x, listing radix flag + * + * functions called: + * int fprintf() c_library + * int putc() c_library + * + * side effects: + * The A line is sent to the .REL file. + */ + +VOID +outarea(ap) +register struct area *ap; +{ + register char *ptr; + register int c; + + fprintf(ofp, "A "); + ptr = &ap->a_id[0]; + while (ptr < &ap->a_id[NCPS]) { + if ((c = *ptr++) != 0) + putc(c, ofp); + } + if (xflag == 0) { + fprintf(ofp, " size %X flags %X\n", ap->a_size, ap->a_flag); + } else + if (xflag == 1) { + fprintf(ofp, " size %o flags %o\n", ap->a_size, ap->a_flag); + } else + if (xflag == 2) { + fprintf(ofp, " size %u flags %u\n", ap->a_size, ap->a_flag); + } +} + +/*)Function VOID outsym(sp) + * + * sym * sp pointer to a sym structure + * + * The function outsym() outputs the S line to the .REL + * file. The S line contains the symbols name and whether the + * the symbol is defined or referenced. + * + * local variables: + * char * ptr pointer to symbol id string + * int c character value + * + * global variables: + * FILE * ofp relocation output file handle + * int xflag -x, listing radix flag + * + * functions called: + * int fprintf() c_library + * int putc() c_library + * + * side effects: + * The S line is sent to the .REL file. + */ + +VOID +outsym(sp) +register struct sym *sp; +{ + register char *ptr; + register int c; + + fprintf(ofp, "S "); + ptr = &sp->s_id[0]; + while (ptr < &sp->s_id[NCPS]) { + if ((c = *ptr++) != 0) + putc(c, ofp); + } + fprintf(ofp, " %s", sp->s_type==S_NEW ? "Ref" : "Def"); + if (xflag == 0) { + fprintf(ofp, "%04X\n", sp->s_addr); + } else + if (xflag == 1) { + fprintf(ofp, "%06o\n", sp->s_addr); + } else + if (xflag == 2) { + fprintf(ofp, "%05u\n", sp->s_addr); + } +} + +/*)Function VOID out(p, n) + * + * int n number of words to output + * int * p pointer to data words + * + * The function out() outputs the data words to the .REL file + * int the specified radix. + * + * local variables: + * none + * + * global variables: + * FILE * ofp relocation output file handle + * int xflag -x, listing radix flag + * + * functions called: + * int fprintf() c_library + * + * side effects: + * Data is sent to the .REL file. + */ + +VOID +out(p, n) +register char *p; +register int n; +{ + while (n--) { + if (xflag == 0) { + fprintf(ofp, " %02X", (*p++)&0377); + } else + if (xflag == 1) { + fprintf(ofp, " %03o", (*p++)&0377); + } else + if (xflag == 2) { + fprintf(ofp, " %03u", (*p++)&0377); + } + } +} + +/*)Function VOID out_lb(b, t) + * + * int b assembled data + * int t relocation type + * + * The function out_lb() copies the assembled data and + * its relocation type to the list data buffers. + * + * local variables: + * none + * + * global variables: + * int * cp pointer to assembler output array cb[] + * int * cpt pointer to assembler relocation type + * output array cbt[] + * + * functions called: + * none + * + * side effects: + * Pointers to data and relocation buffers incremented by 1. + */ + +VOID +out_lb(b,t) +register int b,t; +{ + if (cp < &cb[NCODE]) { + *cp++ = b; + *cpt++ = t; + } +} + +/*)Function VOID out_lw(n, t) + * + * int n assembled data + * int t relocation type + * + * The function out_lw() copies the assembled data and + * its relocation type to the list data buffers. + * + * local variables: + * none + * + * global variables: + * int * cp pointer to assembler output array cb[] + * int * cpt pointer to assembler relocation type + * output array cbt[] + * + * functions called: + * none + * + * side effects: + * Pointers to data and relocation buffers incremented by 2. + */ + +VOID +out_lw(n,t) +register int n,t; +{ + if (hilo) { + out_lb(hibyte(n),t ? t|R_HIGH : 0); + out_lb(lobyte(n),t); + } else { + out_lb(lobyte(n),t); + out_lb(hibyte(n),t ? t|R_HIGH : 0); + } +} + +/*)Function VOID out_rw(n) + * + * int n data word + * + * The function out_rw() outputs the relocation (R) + * data word as two bytes ordered according to hilo. + * + * local variables: + * int * relp pointer to rel array + * + * global variables: + * none + * + * functions called: + * int lobyte() asout.c + * int hibyte() asout.c + * + * side effects: + * Pointer to relocation buffer incremented by 2. + */ + +VOID +out_rw(n) +register int n; +{ + if (hilo) { + *relp++ = hibyte(n); + *relp++ = lobyte(n); + } else { + *relp++ = lobyte(n); + *relp++ = hibyte(n); + } +} + +/*)Function VOID out_tw(n) + * + * int n data word + * + * The function out_tw() outputs the text (T) + * data word as two bytes ordered according to hilo. + * + * local variables: + * int * txtp pointer to txt array + * + * global variables: + * none + * + * functions called: + * int lobyte() asout.c + * int hibyte() asout.c + * + * side effects: + * Pointer to relocation buffer incremented by 2. + */ + +VOID +out_tw(n) +register int n; +{ + if (hilo) { + *txtp++ = hibyte(n); + *txtp++ = lobyte(n); + } else { + *txtp++ = lobyte(n); + *txtp++ = hibyte(n); + } +} + +/*)Function int lobyte(n) + * + * int n data word + * + * The function lobyte() returns the lower byte of + * integer n. + * + * local variables: + * none + * + * global variables: + * none + * + * functions called: + * none + * + * side effects: + * none + */ + +int +lobyte(n) +{ + return (n&0377); +} + +/*)Function int hibyte(n) + * + * int n data word + * + * The function hibyte() returns the higher byte of + * integer n. + * + * local variables: + * none + * + * global variables: + * none + * + * functions called: + * none + * + * side effects: + * none + */ + +int +hibyte(n) +{ + return ((n>>8)&0377); +} + diff --git a/link/as/z80/assubr.c b/link/as/z80/assubr.c new file mode 100644 index 00000000..6423d9fd --- /dev/null +++ b/link/as/z80/assubr.c @@ -0,0 +1,254 @@ +/* assubr.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +/* + * Extensions: P. Felber, M. Hope + */ + +#include +#include +#include +#include "asm.h" + +/*)Module assubr.c + * + * The module assubr.c contains the error + * processing routines. + * + * assubr.c contains the following functions: + * VOID aerr() + * VOID diag() + * VOID err() + * VOID qerr() + * VOID rerr() + * + * assubr.c contains the local array of *error[] + */ + +/*)Function VOID err(c) + * + * int c error type character + * + * The function err() logs the error code character + * suppressing duplicate errors. If the error code + * is 'q' then the parse of the current assembler-source + * text line is terminated. + * + * local variables: + * char * p pointer to the error array + * + * global variables: + * char eb[] array of generated error codes + * + * functions called: + * VOID longjmp() c_library + * + * side effects: + * The error code may be inserted into the + * error code array eb[] or the parse terminated. + */ + +VOID +err(c) +register int c; +{ + register char *p; + +#ifndef SDK + aserr++; +#endif /* SDK */ + p = eb; + while (p < ep) + if (*p++ == c) + return; + if (p < &eb[NERR]) { + *p++ = c; + ep = p; + } + if (c == 'q') + longjmp(jump_env, -1); +} + +/*)Function VOID diag() + * + * The function diag() prints any error codes and + * the source line number to the stderr output device. + * + * local variables: + * char * p pointer to error code array eb[] + * + * global variables: + * int cfile current source file index + * char eb[] array of generated error codes + * char * ep pointer into error list + * int incfile current include file index + * char incfn[] array of include file names + * int incline[] array of include line numbers + * char srcfn[] array of source file names + * int srcline[] array of source line numbers + * FILE * stderr c_library + * + * functions called: + * int fprintf() c_library + * char * geterr() assubr.c + * + * side effects: + * none + */ + +VOID +diag() +{ + register char *p,*errstr; + + if (eb != ep) { + p = eb; +#ifndef SDK + fprintf(stderr, "?ASxxxx-Error-<"); + while (p < ep) { + fprintf(stderr, "%c", *p++); + } + fprintf(stderr, "> in line "); + if (incfil >= 0) { + fprintf(stderr, "%d", incline[incfil]); + fprintf(stderr, " of %s\n", incfn[incfil]); + } else { + fprintf(stderr, "%d", srcline[cfile]); + fprintf(stderr, " of %s\n", srcfn[cfile]); + } + p = eb; +#endif /* SDK */ + while (p < ep) { + if ((errstr = geterr(*p++)) != NULL) { +#ifdef SDK + /* Modified to conform to gcc error standard, M. Hope, 7 Feb 98. */ + if (incfil >= 0) { + fprintf(stderr, "%s:", incfn[incfil]); + fprintf(stderr, "%d: Error:", incline[incfil]); + } + else { + fprintf(stderr, "%s:", srcfn[cfile]); + fprintf(stderr, "%d: Error:", srcline[cfile]); + } + fprintf(stderr, " %s\n", errstr); +#else + fprintf(stderr, " %s\n", errstr); +#endif /* SDK */ + } + } +#ifdef SDK + aserr++; +#endif /* SDK */ + } +} + +/*)Functions: VOID aerr() + * VOID qerr() + * VOID rerr() + * + * The functions aerr(), qerr(), and rerr() report their + * respective error type. These are included only for + * convenience. + * + * local variables: + * none + * + * global variables: + * none + * + * functions called: + * VOID err() assubr.c + * + * side effects: + * The appropriate error code is inserted into the + * error array and the parse may be terminated. + */ + +/* + * Note an 'r' error. + */ +VOID +rerr() +{ + err('r'); +} + +/* + * Note an 'a' error. + */ +VOID +aerr() +{ + err('a'); +} + +/* + * Note a 'q' error. + */ +VOID +qerr() +{ + err('q'); +} + +/* + * ASxxxx assembler errors + */ +char *errors[] = { + "<.> use \". = . + \" not \". = \"", + " machine specific addressing or addressing mode error", + " direct page boundary error", + " direct page addressing error", + " .include file error or an .if/.endif mismatch", + " multiple definitions error", + " .org in REL area or directive / mnemonic error", + "

phase error: label location changing between passes 2 and 3", + " missing or improper operators, terminators, or delimiters", + " relocation error", + " undefined symbol encountered during assembly", + NULL +}; + +/*)Function: char *getarr(c) + * + * int c the error code character + * + * The function geterr() scans the list of errors returning the + * error string corresponding to the input error character. + * + * local variables: + * int i error index counter + * + * global variables: + * char *errors[] array of pointers to the + * error strings + * + * functions called: + * none + * + * side effects: + * A pointer to the appropriate + * error code string is returned. + */ +char * +geterr(c) +int c; +{ + int i; + + for (i=0; errors[i]!=NULL; i++) { + if (c == errors[i][1]) { + return(errors[i]); + } + } + return(NULL); +} + diff --git a/link/as/z80/assym.c b/link/as/z80/assym.c new file mode 100644 index 00000000..db88a08a --- /dev/null +++ b/link/as/z80/assym.c @@ -0,0 +1,446 @@ +/* assym.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +#include +#include +#include +#if defined(__APPLE__) && defined(__MACH__) +#include +#include +#else +#include +#endif +#include "asm.h" + +/*)Module assym.c + * + * The module assym.c contains the functions that operate + * on the mnemonic/directive and symbol structures. + * + * assym.c contains the following functions: + * VOID allglob() + * area * alookup() + * int hash() + * sym * lookup() + * mne * mlookup() + * VOID * new() + * int symeq() + * VOID syminit() + * VOID symglob() + * + * assym.c contains no local/static variables. + */ + +/*)Function VOID syminit() + * + * The function syminit() is called early in the game + * to set up the hashtables. First all buckets in a + * table are cleared. Then a pass is made through + * the respective symbol lists, linking them into + * their hash buckets. Finally the base area pointer + * is set to 'dca'. + * + * local variables: + * int h computed hash value + * mne * mp pointer to a mne structure + * mne ** mpp pointer to an array of + * mne structure pointers + * sym * sp pointer to a sym structure + * sym ** spp pointer to an array of + * sym structure pointers + * + * global variables: + * area area[] single elememt area array + * area dca defined as area[0] + * mne * mnehash[] array of pointers to NHASH + * linked mnemonic/directive lists + * sym * symhash[] array of pointers to NHASH + * linked symbol lists + * + * functions called: + * none + * + * side effects: + * (1) The symbol hash tables are initialized, + * the only defined symbol is '.'. + * (2) The mnemonic/directive hash tables are + * initialized with the assembler directives + * and mnemonics found in the machine dependent + * file ___pst.c. + * (3) The area pointer is initialized to dca (area[0]). + */ + +VOID +syminit() +{ + register struct mne *mp; + struct mne **mpp; + register struct sym *sp; + struct sym **spp; + register int h; + + mpp = &mnehash[0]; + while (mpp < &mnehash[NHASH]) + *mpp++ = NULL; + mp = &mne[0]; + for (;;) { + h = hash(mp->m_id); + mp->m_mp = mnehash[h]; + mnehash[h] = mp; + if (mp->m_flag&S_END) + break; + ++mp; + } + + spp = &symhash[0]; + while (spp < &symhash[NHASH]) + *spp++ = NULL; + sp = &sym[0]; + for (;;) { + h = hash(sp->s_id); + sp->s_sp = symhash[h]; + symhash[h] = sp; + if (sp->s_flag&S_END) + break; + ++sp; + } + + areap = &dca; +} + +/*)Function area * alookup(id) + * + * char * id area name string + * + * The function alookup() searches the area list for a + * match with id. If the area is defined then a pointer + * to this area is returned else a NULL is returned. + * + * local variables: + * area * ap pointer to area structure + * + * global variables: + * area * areap pointer to an area structure + * + * functions called: + * int symeq() assym.c + * + * side effects: + * none + */ + +struct area * +alookup(id) +char *id; +{ + register struct area *ap; + + ap = areap; + while (ap) { + if (symeq(id, ap->a_id)) { + return (ap); + } + ap = ap->a_ap; + } + return(NULL); +} + +/*)Function mne * mlookup(id) + * + * char * id mnemonic/directive name string + * + * The function mlookup() searches the mnemonic/directive + * hash tables for a match returning a pointer to the + * mne structure else it returns a NULL. + * + * local variables: + * mne * mp pointer to mne structure + * int h calculated hash value + * + * global variables: + * mne * mnehash[] array of pointers to NHASH + * linked mnemonic/directive lists + * + * functions called: + * none + * + * side effects: + * none + */ + +struct mne * +mlookup(id) +char *id; +{ + register struct mne *mp; + register int h; + + h = hash(id); + mp = mnehash[h]; + while (mp) { + if (symeq(id, mp->m_id)) + return (mp); + mp = mp->m_mp; + } + return (NULL); +} + +/*)Function sym * lookup(id) + * + * char * id symbol name string + * + * The function lookup() searches the symbol hash tables for + * a symbol name match returning a pointer to the sym structure. + * If the symbol is not found then a sym structure is created, + * initialized, and linked to the appropriate hash table. + * A pointer to this new sym structure is returned. + * + * local variables: + * int h computed hash value + * sym * sp pointer to a sym structure + * + * global varaibles: + * sym * symhash[] array of pointers to NHASH + * linked symbol lists + * + * functions called: + * int hash() assym.c + * VOID * new() assym.c + * int symeq() assym.c + * + * side effects: + * If the function new() fails to allocate space + * for the new sym structure the assembly terminates. + */ + +struct sym * +lookup(id) +char *id; +{ + register struct sym *sp; + register int h; + + h = hash(id); + sp = symhash[h]; + while (sp) { + if (symeq(id, sp->s_id)) + return (sp); + sp = sp->s_sp; + } + sp = (struct sym *) new (sizeof(struct sym)); + sp->s_sp = symhash[h]; + symhash[h] = sp; + sp->s_tsym = NULL; + strncpy(sp->s_id, id, NCPS); + sp->s_type = S_NEW; + sp->s_flag = 0; + sp->s_area = NULL; + sp->s_ref = 0; + sp->s_addr = 0; + return (sp); +} + +/*)Function VOID symglob() + * + * The function symglob() will mark all symbols of + * type S_NEW as global. Called at the beginning of pass 1 + * if the assembly option -g was specified. + * + * local variables: + * sym * sp pointer to a sym structure + * int i loop index + * + * global variables: + * sym * symhash[] array of pointers to NHASH + * linked symbol lists + * + * functions called: + * none + * + * side effects: + * Symbol types changed. + */ + +VOID +symglob() +{ + register struct sym *sp; + register int i; + + for (i=0; is_type == S_NEW) + sp->s_flag |= S_GBL; + sp = sp->s_sp; + } + } +} + +/*)Function VOID allglob() + * + * The function allglob() will mark all symbols of + * type S_USER as global. Called at the beginning of pass 1 + * if the assembly option -a was specified. + * + * local variables: + * sym * sp pointer to a sym structure + * int i loop index + * + * global variables: + * sym * symhash[] array of pointers to NHASH + * linked symbol lists + * + * functions called: + * none + * + * side effects: + * Symbol types changed. + */ + +VOID +allglob() +{ + register struct sym *sp; + register int i; + + for (i=0; is_type == S_USER) + sp->s_flag |= S_GBL; + sp = sp->s_sp; + } + } +} + +/*)Function int symeq(p1, p2) + * + * char * p1 name string + * char * p2 name string + * + * The function symeq() compares the two name strings for a match. + * The return value is 1 for a match and 0 for no match. + * + * local variables: + * int h loop counter + * + * global variables: + * char ccase[] an array of characters which + * perform the case translation function + * + * functions called: + * none + * + * side effects: + * none + * + */ + +int +symeq(p1, p2) +register char *p1, *p2; +{ + register int n; + + n = NCPS; + do { + +#if CASE_SENSITIVE + if (*p1++ != *p2++) + return (0); +#else + if (ccase[(unsigned char)(*p1++)] != ccase[(unsigned char)(*p2++)]) + return (0); +#endif + + } while (--n); + return (1); +} + +/*)Function int hash(p) + * + * char * p pointer to string to hash + * + * The function hash() computes a hash code using the sum + * of all characters mod table size algorithm. + * + * local variables: + * int h accumulated character sum + * int n loop counter + * + * global variables: + * char ccase[] an array of characters which + * perform the case translation function + * + * functions called: + * none + * + * side effects: + * none + */ + +int +hash(p) +register char *p; +{ + register int h, n; + + h = 0; + n = NCPS; + do { + +#if CASE_SENSITIVE + h += *p++; +#else + h += ccase[(unsigned char)(*p++)]; +#endif + + } while (--n); + return (h&HMASK); +} + +/*)Function VOID * new(n) + * + * unsigned int n allocation size in bytes + * + * The function new() allocates n bytes of space and returns + * a pointer to this memory. If no space is available the + * assembly is terminated. + * + * local variables: + * VOID * p a general pointer + * + * global variables: + * none + * + * functions called: + * VOID asexit() asmain.c + * int fprintf() c_library + * VOID * malloc() c_library + * + * side effects: + * Memory is allocated, if allocation fails + * the assembly is terminated. + */ + +VOID * +new(n) +unsigned int n; +{ + register VOID *p; + + if ((p = (VOID *) malloc(n)) == NULL) { + fprintf(stderr, "Out of space!\n"); + asexit(1); + } + return (p); +} diff --git a/link/as/z80/clean.mk b/link/as/z80/clean.mk new file mode 100644 index 00000000..5c2a9007 --- /dev/null +++ b/link/as/z80/clean.mk @@ -0,0 +1,23 @@ +# Deleting all files created by building the program +# -------------------------------------------------- +clean: + rm -rf obj + rm -f *core *[%~] *.[oa] + rm -f .[a-z]*~ + rm -f $(PRJDIR)/as-z80 as-z80 + +# Deleting all files created by configuring or building the program +# ----------------------------------------------------------------- +distclean: clean + rm -f *.dep + + +# Like clean but some files may still exist +# ----------------------------------------- +mostlyclean: clean + + +# Deleting everything that can reconstructed by this Makefile. It deletes +# everything deleted by distclean plus files created by bison, etc. +# ----------------------------------------------------------------------- +realclean: distclean diff --git a/link/as/z80/conf.mk b/link/as/z80/conf.mk new file mode 100644 index 00000000..524efe65 --- /dev/null +++ b/link/as/z80/conf.mk @@ -0,0 +1,23 @@ +# Deleting all files created by building the program +# -------------------------------------------------- +clean: + rm -f *core *[%~] *.[oa] + rm -f .[a-z]*~ + rm -f $(PRJDIR)/as-z80 as-z80 + + +# Deleting all files created by configuring or building the program +# ----------------------------------------------------------------- +distclean: clean + rm -f Makefile *.dep + + +# Like clean but some files may still exist +# ----------------------------------------- +mostlyclean: clean + + +# Deleting everything that can reconstructed by this Makefile. It deletes +# everything deleted by distclean plus files created by bison, etc. +# ----------------------------------------------------------------------- +realclean: distclean diff --git a/link/as/z80/incld1.asm b/link/as/z80/incld1.asm new file mode 100644 index 00000000..6994f274 --- /dev/null +++ b/link/as/z80/incld1.asm @@ -0,0 +1,10 @@ + xxx ;1 + .include "incld2.asm" ;2 + ;3 + ;4 + ;5 + xxx ;6 + ;7 + ;8 + ;9 + ;10 diff --git a/link/as/z80/incld2.asm b/link/as/z80/incld2.asm new file mode 100644 index 00000000..2c33ce88 --- /dev/null +++ b/link/as/z80/incld2.asm @@ -0,0 +1,10 @@ + ;1 + xxx ;2 + .include "incld3.asm" ;3 + ;4 + ;5 + ;6 + xxx ;7 + ;8 + ;9 + ;10 diff --git a/link/as/z80/incld3.asm b/link/as/z80/incld3.asm new file mode 100644 index 00000000..0c66f55a --- /dev/null +++ b/link/as/z80/incld3.asm @@ -0,0 +1,10 @@ + ;1 + ;2 + xxx ;3 + .include "incld4.asm" ;4 + ;5 + ;6 + ;7 + xxx ;8 + ;9 + ;10 diff --git a/link/as/z80/incld4.asm b/link/as/z80/incld4.asm new file mode 100644 index 00000000..0fc64c54 --- /dev/null +++ b/link/as/z80/incld4.asm @@ -0,0 +1,10 @@ + ;1 + ;2 + ;3 + xxx ;4 + .include "incld5.asm" ;5 + ;6 + ;7 + ;8 + xxx ;9 + ;10 diff --git a/link/as/z80/incld5.asm b/link/as/z80/incld5.asm new file mode 100644 index 00000000..9392a007 --- /dev/null +++ b/link/as/z80/incld5.asm @@ -0,0 +1,10 @@ + ;1 + ;2 + ;3 + ;4 + xxx ;5 + .include "incldx.asm" ;6 + ;7 + ;8 + ;9 + xxx ;10 diff --git a/link/as/z80/itsta.asm b/link/as/z80/itsta.asm new file mode 100644 index 00000000..c87c4fc2 --- /dev/null +++ b/link/as/z80/itsta.asm @@ -0,0 +1,42 @@ + .include "incld1.asm" ;1 + ;2 + ;3 + ;4 + ;5 + ;6 + ;7 + ;8 + ;9 + ;10 + xxx ;11 +; +; This is a simple test of the error reporting +; for source and include files. +; +; assemble inctst: +; asxxxx itsta itstb +; +; ?ASxxxx-E- in line 1 of incld1.asm +; ?ASxxxx-E- in line 2 of incld2.asm +; ?ASxxxx-E- in line 3 of incld3.asm +; ?ASxxxx-E- in line 4 of incld4.asm +; ?ASxxxx-E- in line 5 of incld5.asm +; ?ASxxxx-E- in line 6 of incld5.asm +; ?ASxxxx-E- in line 10 of incld5.asm +; ?ASxxxx-E- in line 9 of incld4.asm +; ?ASxxxx-E- in line 8 of incld3.asm +; ?ASxxxx-E- in line 7 of incld2.asm +; ?ASxxxx-E- in line 6 of incld1.asm +; ?ASxxxx-E- in line 11 of itsta.asm +; ?ASxxxx-E- in line 1 of incld1.asm +; ?ASxxxx-E- in line 2 of incld2.asm +; ?ASxxxx-E- in line 3 of incld3.asm +; ?ASxxxx-E- in line 4 of incld4.asm +; ?ASxxxx-E- in line 5 of incld5.asm +; ?ASxxxx-E- in line 6 of incld5.asm +; ?ASxxxx-E- in line 10 of incld5.asm +; ?ASxxxx-E- in line 9 of incld4.asm +; ?ASxxxx-E- in line 8 of incld3.asm +; ?ASxxxx-E- in line 7 of incld2.asm +; ?ASxxxx-E- in line 6 of incld1.asm +; ?ASxxxx-E- in line 11 of itstb.asm diff --git a/link/as/z80/itstb.asm b/link/as/z80/itstb.asm new file mode 100644 index 00000000..c87c4fc2 --- /dev/null +++ b/link/as/z80/itstb.asm @@ -0,0 +1,42 @@ + .include "incld1.asm" ;1 + ;2 + ;3 + ;4 + ;5 + ;6 + ;7 + ;8 + ;9 + ;10 + xxx ;11 +; +; This is a simple test of the error reporting +; for source and include files. +; +; assemble inctst: +; asxxxx itsta itstb +; +; ?ASxxxx-E- in line 1 of incld1.asm +; ?ASxxxx-E- in line 2 of incld2.asm +; ?ASxxxx-E- in line 3 of incld3.asm +; ?ASxxxx-E- in line 4 of incld4.asm +; ?ASxxxx-E- in line 5 of incld5.asm +; ?ASxxxx-E- in line 6 of incld5.asm +; ?ASxxxx-E- in line 10 of incld5.asm +; ?ASxxxx-E- in line 9 of incld4.asm +; ?ASxxxx-E- in line 8 of incld3.asm +; ?ASxxxx-E- in line 7 of incld2.asm +; ?ASxxxx-E- in line 6 of incld1.asm +; ?ASxxxx-E- in line 11 of itsta.asm +; ?ASxxxx-E- in line 1 of incld1.asm +; ?ASxxxx-E- in line 2 of incld2.asm +; ?ASxxxx-E- in line 3 of incld3.asm +; ?ASxxxx-E- in line 4 of incld4.asm +; ?ASxxxx-E- in line 5 of incld5.asm +; ?ASxxxx-E- in line 6 of incld5.asm +; ?ASxxxx-E- in line 10 of incld5.asm +; ?ASxxxx-E- in line 9 of incld4.asm +; ?ASxxxx-E- in line 8 of incld3.asm +; ?ASxxxx-E- in line 7 of incld2.asm +; ?ASxxxx-E- in line 6 of incld1.asm +; ?ASxxxx-E- in line 11 of itstb.asm diff --git a/link/as/z80/string.h b/link/as/z80/string.h new file mode 100644 index 00000000..fdcd2116 --- /dev/null +++ b/link/as/z80/string.h @@ -0,0 +1,15 @@ +/* STRING.H */ +/* DECUC C */ + +extern char * strcat(); +extern char * strchr(); +extern int strcmp(); +extern char * strcpy(); +extern int streq(); +extern int strlen(); +extern char * strncat(); +extern int strncmp(); +extern char * strncpy(); +extern int strneq(); +extern char * strrchr(); + diff --git a/link/as/z80/tconst.asm b/link/as/z80/tconst.asm new file mode 100644 index 00000000..c8f254bc --- /dev/null +++ b/link/as/z80/tconst.asm @@ -0,0 +1,68 @@ + .title Assembler Link Test Constants + + .module tconst + + .area TEST (ABS,OVR) + + bra1 == 0 ; branching constants + bra2 == 0x80 + bra3 == 0x182 + bra4 == 0x204 + + .blkb 0x7E ;bra1: + .blkb 0x02 + .blkb 0x7F ;bra2: + .blkb 0x02 + .blkb 0x02 + .blkb 0x7F + .blkb 0x00 ;bra3: + .blkb 0x02 + .blkb 0x80 + .blkb 0x00 ;bra4: + + .globl bra5,bra6,bra7,bra8 + + ; branching labels +bra5: .blkb 0x7E ;bra5: + .blkb 0x02 +bra6: .blkb 0x7F ;bra6: + .blkb 0x02 + .blkb 0x02 + .blkb 0x7F +bra7: .blkb 0x00 ;bra7: + .blkb 0x02 + .blkb 0x80 +bra8: .blkb 0x00 ;bra8: + + + ; 12-Bit numbers are considered valid if: + ; 1) the most significant 4 bits of the 16-bit number are zero + ; 2) the most significant 4 bits of the 16-bit number are all ones + + n0FFF == 0x0FFF ;largest positive + n1000 == 0x1000 ;+1 + + nF000 == 0xF000 ;largest negative + nEFFF == 0xEFFF ;-1 + + + .area DIRECT (ABS,OVR) + .setdp + + boundary == 0x101 + + minus1 == -1 ; paging / indexing constants + zero == 0 + two55 == 0d255 + two56 == 0d256 + five11 == 0d511 + five12 == 0d512 + + + .globl lzero,ltwo55,ltwo56,lminus1 + +lzero: .blkb 0x00FF ; paging labels +ltwo55: .blkb 0x0001 +ltwo56: .blkb 0xFEFF +lminus1:.blkb 0d0000 + diff --git a/link/as/z80/tz80.asm b/link/as/z80/tz80.asm new file mode 100644 index 00000000..a33edc21 --- /dev/null +++ b/link/as/z80/tz80.asm @@ -0,0 +1,1013 @@ + .title Test of Z80 / HD64180 assembler + + offset = 0x55 ;arbitrary constants + n = 0x20 + nn = 0x0584 + + ; notes: + ; Leading 'a' operand is optional. + ; If offset is ommitted 0 is assumed. + + ;*********************************************************** + ; add with carry to 'a' + adc a,(hl) ;8E + adc a,offset(ix) ;DD 8E 55 + adc a,offset(iy) ;FD 8E 55 + adc a,a ;8F + adc a,b ;88 + adc a,c ;89 + adc a,d ;8A + adc a,e ;8B + adc a,h ;8C + adc a,l ;8D + adc a,#n ;CE 20 + ;*********************************************************** + adc (hl) ;8E + adc offset(ix) ;DD 8E 55 + adc offset(iy) ;FD 8E 55 + adc a ;8F + adc b ;88 + adc c ;89 + adc d ;8A + adc e ;8B + adc h ;8C + adc l ;8D + adc #n ;CE 20 + ;*********************************************************** + ; add with carry register pair to 'hl' + adc hl,bc ;ED 4A + adc hl,de ;ED 5A + adc hl,hl ;ED 6A + adc hl,sp ;ED 7A + ;*********************************************************** + ; add operand to 'a' + add a,(hl) ;86 + add a,offset(ix) ;DD 86 55 + add a,offset(iy) ;FD 86 55 + add a,a ;87 + add a,b ;80 + add a,c ;81 + add a,d ;82 + add a,e ;83 + add a,h ;84 + add a,l ;85 + add a,#n ;C6 20 + ;*********************************************************** + ; add register pair to 'hl' + add hl,bc ;09 + add hl,de ;19 + add hl,hl ;29 + add hl,sp ;39 + ;*********************************************************** + ; add register pair to 'ix' + add ix,bc ;DD 09 + add ix,de ;DD 19 + add ix,ix ;DD 29 + add ix,sp ;DD 39 + ;*********************************************************** + ; add register pair to 'iy' + add iy,bc ;FD 09 + add iy,de ;FD 19 + add iy,iy ;FD 29 + add iy,sp ;FD 39 + ;*********************************************************** + ; logical 'and' operand with 'a' + and a,(hl) ;A6 + and a,offset(ix) ;DD A6 55 + and a,offset(iy) ;FD A6 55 + and a,a ;A7 + and a,b ;A0 + and a,c ;A1 + and a,d ;A2 + and a,e ;A3 + and a,h ;A4 + and a,l ;A5 + and a,#n ;E6 20 + ;*********************************************************** + ; test bit of location or register + bit 0,(hl) ;CB 46 + bit 0,offset(ix) ;DD CB 55 46 + bit 0,offset(iy) ;FD CB 55 46 + bit 0,a ;CB 47 + bit 0,b ;CB 40 + bit 0,c ;CB 41 + bit 0,d ;CB 42 + bit 0,e ;CB 43 + bit 0,h ;CB 44 + bit 0,l ;CB 45 + bit 1,(hl) ;CB 4E + bit 1,offset(ix) ;DD CB 55 4E + bit 1,offset(iy) ;FD CB 55 4E + bit 1,a ;CB 4F + bit 1,b ;CB 48 + bit 1,c ;CB 49 + bit 1,d ;CB 4A + bit 1,e ;CB 4B + bit 1,h ;CB 4C + bit 1,l ;CB 4D + bit 2,(hl) ;CB 56 + bit 2,offset(ix) ;DD CB 55 56 + bit 2,offset(iy) ;FD CB 55 56 + bit 2,a ;CB 57 + bit 2,b ;CB 50 + bit 2,c ;CB 51 + bit 2,d ;CB 52 + bit 2,e ;CB 53 + bit 2,h ;CB 54 + bit 2,l ;CB 55 + bit 3,(hl) ;CB 5E + bit 3,offset(ix) ;DD CB 55 5E + bit 3,offset(iy) ;FD CB 55 5E + bit 3,a ;CB 5F + bit 3,b ;CB 58 + bit 3,c ;CB 59 + bit 3,d ;CB 5A + bit 3,e ;CB 5B + bit 3,h ;CB 5C + bit 3,l ;CB 5D + bit 4,(hl) ;CB 66 + bit 4,offset(ix) ;DD CB 55 66 + bit 4,offset(iy) ;FD CB 55 66 + bit 4,a ;CB 67 + bit 4,b ;CB 60 + bit 4,c ;CB 61 + bit 4,d ;CB 62 + bit 4,e ;CB 63 + bit 4,h ;CB 64 + bit 4,l ;CB 65 + bit 5,(hl) ;CB 6E + bit 5,offset(ix) ;DD CB 55 6E + bit 5,offset(iy) ;FD CB 55 6E + bit 5,a ;CB 6F + bit 5,b ;CB 68 + bit 5,c ;CB 69 + bit 5,d ;CB 6A + bit 5,e ;CB 6B + bit 5,h ;CB 6C + bit 5,l ;CB 6D + bit 6,(hl) ;CB 76 + bit 6,offset(ix) ;DD CB 55 76 + bit 6,offset(iy) ;FD CB 55 76 + bit 6,a ;CB 77 + bit 6,b ;CB 70 + bit 6,c ;CB 71 + bit 6,d ;CB 72 + bit 6,e ;CB 73 + bit 6,h ;CB 74 + bit 6,l ;CB 75 + bit 7,(hl) ;CB 7E + bit 7,offset(ix) ;DD CB 55 7E + bit 7,offset(iy) ;FD CB 55 7E + bit 7,a ;CB 7F + bit 7,b ;CB 78 + bit 7,c ;CB 79 + bit 7,d ;CB 7A + bit 7,e ;CB 7B + bit 7,h ;CB 7C + bit 7,l ;CB 7D + ;*********************************************************** + ; call subroutine at nn if condition is true + call C,nn ;DC 84 05 + call M,nn ;FC 84 05 + call NC,nn ;D4 84 05 + call NZ,nn ;C4 84 05 + call P,nn ;F4 84 05 + call PE,nn ;EC 84 05 + call PO,nn ;E4 84 05 + call Z,nn ;CC 84 05 + ;*********************************************************** + ; unconditional call to subroutine at nn + call nn ;CD 84 05 + ;*********************************************************** + ; complement carry flag + ccf ;3F + ;*********************************************************** + ; compare operand with 'a' + cp a,(hl) ;BE + cp a,offset(ix) ;DD BE 55 + cp a,offset(iy) ;FD BE 55 + cp a,a ;BF + cp a,b ;B8 + cp a,c ;B9 + cp a,d ;BA + cp a,e ;BB + cp a,h ;BC + cp a,l ;BD + cp a,#n ;FE 20 + ;*********************************************************** + ; compare location (hl) and 'a' + ; decrement 'hl' and 'bc' + cpd ;ED A9 + ;*********************************************************** + ; compare location (hl) and 'a' + ; decrement 'hl' and 'bc' + ; repeat until 'bc' = 0 + cpdr ;ED B9 + ;*********************************************************** + ; compare location (hl) and 'a' + ; increment 'hl' and decrement 'bc' + cpi ;ED A1 + ;*********************************************************** + ; compare location (hl) and 'a' + ; increment 'hl' and decrement 'bc' + ; repeat until 'bc' = 0 + cpir ;ED B1 + ;*********************************************************** + ; 1's complement of 'a' + cpl ;2F + ;*********************************************************** + ; decimal adjust 'a' + daa ;27 + ;*********************************************************** + ; decrement operand + dec (hl) ;35 + dec offset(ix) ;DD 35 55 + dec offset(iy) ;FD 35 55 + dec a ;3D + dec b ;05 + dec bc ;0B + dec c ;0D + dec d ;15 + dec de ;1B + dec e ;1D + dec h ;25 + dec hl ;2B + dec ix ;DD 2B + dec iy ;FD 2B + dec l ;2D + dec sp ;3B + ;*********************************************************** + ; disable interrupts + di ;F3 + ;*********************************************************** + ; decrement b and jump relative if b # 0 + djnz .+0x12 ;10 10 + ;*********************************************************** + ; enable interrupts + ei ;FB + ;*********************************************************** + ; exchange location and (sp) + ex (sp),hl ;E3 + ex (sp),ix ;DD E3 + ex (sp),iy ;FD E3 + ;*********************************************************** + ; exchange af and af' + ex af,af' ;08 + ;*********************************************************** + ; exchange de and hl + ex de,hl ;EB + ;*********************************************************** + ; exchange: + ; bc <-> bc' + ; de <-> de' + ; hl <-> hl' + exx ;D9 + ;*********************************************************** + ; halt (wait for interrupt or reset) + halt ;76 + ;*********************************************************** + ; set interrupt mode + im 0 ;ED 46 + im 1 ;ED 56 + im 2 ;ED 5E + ;*********************************************************** + ; load 'a' with input from device n + in a,(n) ;DB 20 + ;*********************************************************** + ; load register with input from (c) + in a,(c) ;ED 78 + in b,(c) ;ED 40 + in c,(c) ;ED 48 + in d,(c) ;ED 50 + in e,(c) ;ED 58 + in h,(c) ;ED 60 + in l,(c) ;ED 68 + ;*********************************************************** + ; increment operand + inc (hl) ;34 + inc offset(ix) ;DD 34 55 + inc offset(iy) ;FD 34 55 + inc a ;3C + inc b ;04 + inc bc ;03 + inc c ;0C + inc d ;14 + inc de ;13 + inc e ;1C + inc h ;24 + inc hl ;23 + inc ix ;DD 23 + inc iy ;FD 23 + inc l ;2C + inc sp ;33 + ;*********************************************************** + ; load location (hl) with input + ; from port (c) + ; decrement 'hl' and 'b' + ind ;ED AA + ;*********************************************************** + ; load location (hl) with input + ; from port (c) + ; decrement 'hl' and 'b' + ; repeat until 'b' = 0 + indr ;ED BA + ;*********************************************************** + ; load location (hl) with input + ; from port (c) + ; increment 'hl' and decrement 'b' + ini ;ED A2 + ;*********************************************************** + ; load location (hl) with input + ; from port (c) + ; increment 'hl' and decrement 'b' + ; repeat until 'b' = 0 + inir ;ED B2 + ;*********************************************************** + ; unconditional jump to location nn + jp nn ;C3 84 05 + jp (hl) ;E9 + jp (ix) ;DD E9 + jp (iy) ;FD E9 + ;*********************************************************** + ; jump to location if condition is true + jp C,nn ;DA 84 05 + jp M,nn ;FA 84 05 + jp NC,nn ;D2 84 05 + jp NZ,nn ;C2 84 05 + jp P,nn ;F2 84 05 + jp PE,nn ;EA 84 05 + jp PO,nn ;E2 84 05 + jp Z,nn ;CA 84 05 + ;*********************************************************** + ; unconditional jump relative to PC+e + jr jr1+0x10 ;18 10 + ;*********************************************************** + ; jump relative to PC+e if condition is true +jr1: jr C,jr2+0x10 ;38 10 +jr2: jr NC,jr3+0x10 ;30 10 +jr3: jr NZ,jr4+0x10 ;20 10 +jr4: jr Z,jr5+0x10 ;28 10 +jr5: + ;*********************************************************** + ; load source to destination + ld a,(hl) ;7E + ld a,offset(ix) ;DD 7E 55 + ld a,offset(iy) ;FD 7E 55 + ld a,a ;7F + ld a,b ;78 + ld a,c ;79 + ld a,d ;7A + ld a,e ;7B + ld a,h ;7C + ld a,l ;7D + ld a,#n ;3E 20 + ld b,(hl) ;46 + ld b,offset(ix) ;DD 46 55 + ld b,offset(iy) ;FD 46 55 + ld b,a ;47 + ld b,b ;40 + ld b,c ;41 + ld b,d ;42 + ld b,e ;43 + ld b,h ;44 + ld b,l ;45 + ld b,#n ;06 20 + ld c,(hl) ;4E + ld c,offset(ix) ;DD 4E 55 + ld c,offset(iy) ;FD 4E 55 + ld c,a ;4F + ld c,b ;48 + ld c,c ;49 + ld c,d ;4A + ld c,e ;4B + ld c,h ;4C + ld c,l ;4D + ld c,#n ;0E 20 + ld d,(hl) ;56 + ld d,offset(ix) ;DD 56 55 + ld d,offset(iy) ;FD 56 55 + ld d,a ;57 + ld d,b ;50 + ld d,c ;51 + ld d,d ;52 + ld d,e ;53 + ld d,h ;54 + ld d,l ;55 + ld d,#n ;16 20 + ld e,(hl) ;5E + ld e,offset(ix) ;DD 5E 55 + ld e,offset(iy) ;FD 5E 55 + ld e,a ;5F + ld e,b ;58 + ld e,c ;59 + ld e,d ;5A + ld e,e ;5B + ld e,h ;5C + ld e,l ;5D + ld e,#n ;1E 20 + ld h,(hl) ;66 + ld h,offset(ix) ;DD 66 55 + ld h,offset(iy) ;FD 66 55 + ld h,a ;67 + ld h,b ;60 + ld h,c ;61 + ld h,d ;62 + ld h,e ;63 + ld h,h ;64 + ld h,l ;65 + ld h,#n ;26 20 + ld l,(hl) ;6E + ld l,offset(ix) ;DD 6E 55 + ld l,offset(iy) ;FD 6E 55 + ld l,a ;6F + ld l,b ;68 + ld l,c ;69 + ld l,d ;6A + ld l,e ;6B + ld l,h ;6C + ld l,l ;6D + ld l,#n ;2E 20 + ;*********************************************************** + ld i,a ;ED 47 + ld r,a ;ED 4F + ld a,i ;ED 57 + ld a,r ;ED 5F + ;*********************************************************** + ld (bc),a ;02 + ld (de),a ;12 + ld a,(bc) ;0A + ld a,(de) ;1A + ;*********************************************************** + ld (hl),a ;77 + ld (hl),b ;70 + ld (hl),c ;71 + ld (hl),d ;72 + ld (hl),e ;73 + ld (hl),h ;74 + ld (hl),l ;75 + ld (hl),#n ;36 20 + ;*********************************************************** + ld offset(ix),a ;DD 77 55 + ld offset(ix),b ;DD 70 55 + ld offset(ix),c ;DD 71 55 + ld offset(ix),d ;DD 72 55 + ld offset(ix),e ;DD 73 55 + ld offset(ix),h ;DD 74 55 + ld offset(ix),l ;DD 75 55 + ld offset(ix),#n ;DD 36 55 20 + ;*********************************************************** + ld offset(iy),a ;FD 77 55 + ld offset(iy),b ;FD 70 55 + ld offset(iy),c ;FD 71 55 + ld offset(iy),d ;FD 72 55 + ld offset(iy),e ;FD 73 55 + ld offset(iy),h ;FD 74 55 + ld offset(iy),l ;FD 75 55 + ld offset(iy),#n ;FD 36 55 20 + ;*********************************************************** + ld (nn),a ;32 84 05 + ld (nn),bc ;ED 43 84 05 + ld (nn),de ;ED 53 84 05 + ld (nn),hl ;22 84 05 + ld (nn),sp ;ED 73 84 05 + ld (nn),ix ;DD 22 84 05 + ld (nn),iy ;FD 22 84 05 + ;*********************************************************** + ld a,(nn) ;3A 84 05 + ld bc,(nn) ;ED 4B 84 05 + ld de,(nn) ;ED 5B 84 05 + ld hl,(nn) ;2A 84 05 + ld sp,(nn) ;ED 7B 84 05 + ld ix,(nn) ;DD 2A 84 05 + ld iy,(nn) ;FD 2A 84 05 + ;*********************************************************** + ld bc,#nn ;01 84 05 + ld de,#nn ;11 84 05 + ld hl,#nn ;21 84 05 + ld sp,#nn ;31 84 05 + ld ix,#nn ;DD 21 84 05 + ld iy,#nn ;FD 21 84 05 + ;*********************************************************** + ld sp,hl ;F9 + ld sp,ix ;DD F9 + ld sp,iy ;FD F9 + ;*********************************************************** + ; load location (hl) + ; with location (de) + ; decrement de, hl + ; decrement bc + ldd ;ED A8 + ;*********************************************************** + ; load location (hl) + ; with location (de) + ; decrement de, hl + ; decrement bc + ; repeat until bc = 0 + lddr ;ED B8 + ;*********************************************************** + ; load location (hl) + ; with location (de) + ; increment de, hl + ; decrement bc + ldi ;ED A0 + ;*********************************************************** + ; load location (hl) + ; with location (de) + ; increment de, hl + ; decrement bc + ; repeat until bc = 0 + ldir ;ED B0 + ;*********************************************************** + ; 2's complement of 'a' + neg ;ED 44 + ;*********************************************************** + ; no operation + nop ;00 + ;*********************************************************** + ; logical 'or' operand with 'a' + or a,(hl) ;B6 + or a,offset(ix) ;DD B6 55 + or a,offset(iy) ;FD B6 55 + or a,a ;B7 + or a,b ;B0 + or a,c ;B1 + or a,d ;B2 + or a,e ;B3 + or a,h ;B4 + or a,l ;B5 + or a,#n ;F6 20 + ;*********************************************************** + ; load output port (c) + ; with location (hl) + ; decrement hl and decrement b + ; repeat until b = 0 + otdr ;ED BB + ;*********************************************************** + ; load output port (c) + ; with location (hl) + ; increment hl and decrement b + ; repeat until b = 0 + otir ;ED B3 + ;*********************************************************** + ; load output port (c) with reg + out (c),a ;ED 79 + out (c),b ;ED 41 + out (c),c ;ED 49 + out (c),d ;ED 51 + out (c),e ;ED 59 + out (c),h ;ED 61 + out (c),l ;ED 69 + ;*********************************************************** + ; load output port (n) with 'a' + out (n),a ;D3 20 + ;*********************************************************** + ; load output port (c) + ; with location (hl) + ; decrement hl and decrement b + outd ;ED AB + ;*********************************************************** + ; load output port (c) + ; with location (hl) + ; increment hl and decrement b + outi ;ED A3 + ;*********************************************************** + ; load destination with top of stack + pop af ;F1 + pop bc ;C1 + pop de ;D1 + pop hl ;E1 + pop ix ;DD E1 + pop iy ;FD E1 + ;*********************************************************** + ; put source on stack + push af ;F5 + push bc ;C5 + push de ;D5 + push hl ;E5 + push ix ;DD E5 + push iy ;FD E5 + ;*********************************************************** + ; reset bit of location or register + res 0,(hl) ;CB 86 + res 0,offset(ix) ;DD CB 55 86 + res 0,offset(iy) ;FD CB 55 86 + res 0,a ;CB 87 + res 0,b ;CB 80 + res 0,c ;CB 81 + res 0,d ;CB 82 + res 0,e ;CB 83 + res 0,h ;CB 84 + res 0,l ;CB 85 + res 1,(hl) ;CB 8E + res 1,offset(ix) ;DD CB 55 8E + res 1,offset(iy) ;FD CB 55 8E + res 1,a ;CB 8F + res 1,b ;CB 88 + res 1,c ;CB 89 + res 1,d ;CB 8A + res 1,e ;CB 8B + res 1,h ;CB 8C + res 1,l ;CB 8D + res 2,(hl) ;CB 96 + res 2,offset(ix) ;DD CB 55 96 + res 2,offset(iy) ;FD CB 55 96 + res 2,a ;CB 97 + res 2,b ;CB 90 + res 2,c ;CB 91 + res 2,d ;CB 92 + res 2,e ;CB 93 + res 2,h ;CB 94 + res 2,l ;CB 95 + res 3,(hl) ;CB 9E + res 3,offset(ix) ;DD CB 55 9E + res 3,offset(iy) ;FD CB 55 9E + res 3,a ;CB 9F + res 3,b ;CB 98 + res 3,c ;CB 99 + res 3,d ;CB 9A + res 3,e ;CB 9B + res 3,h ;CB 9C + res 3,l ;CB 9D + res 4,(hl) ;CB A6 + res 4,offset(ix) ;DD CB 55 A6 + res 4,offset(iy) ;FD CB 55 A6 + res 4,a ;CB A7 + res 4,b ;CB A0 + res 4,c ;CB A1 + res 4,d ;CB A2 + res 4,e ;CB A3 + res 4,h ;CB A4 + res 4,l ;CB A5 + res 5,(hl) ;CB AE + res 5,offset(ix) ;DD CB 55 AE + res 5,offset(iy) ;FD CB 55 AE + res 5,a ;CB AF + res 5,b ;CB A8 + res 5,c ;CB A9 + res 5,d ;CB AA + res 5,e ;CB AB + res 5,h ;CB AC + res 5,l ;CB AD + res 6,(hl) ;CB B6 + res 6,offset(ix) ;DD CB 55 B6 + res 6,offset(iy) ;FD CB 55 B6 + res 6,a ;CB B7 + res 6,b ;CB B0 + res 6,c ;CB B1 + res 6,d ;CB B2 + res 6,e ;CB B3 + res 6,h ;CB B4 + res 6,l ;CB B5 + res 7,(hl) ;CB BE + res 7,offset(ix) ;DD CB 55 BE + res 7,offset(iy) ;FD CB 55 BE + res 7,a ;CB BF + res 7,b ;CB B8 + res 7,c ;CB B9 + res 7,d ;CB BA + res 7,e ;CB BB + res 7,h ;CB BC + res 7,l ;CB BD + ;*********************************************************** + ; return from subroutine + ret ;C9 + ;*********************************************************** + ; return from subroutine if condition is true + ret C ;D8 + ret M ;F8 + ret NC ;D0 + ret NZ ;C0 + ret P ;F0 + ret PE ;E8 + ret PO ;E0 + ret Z ;C8 + ;*********************************************************** + ; return from interrupt + reti ;ED 4D + ;*********************************************************** + ; return from non-maskable interrupt + retn ;ED 45 + ;*********************************************************** + ; rotate left through carry + rl a,(hl) ;CB 16 + rl a,offset(ix) ;DD CB 55 16 + rl a,offset(iy) ;FD CB 55 16 + rl a,a ;CB 17 + rl a,b ;CB 10 + rl a,c ;CB 11 + rl a,d ;CB 12 + rl a,e ;CB 13 + rl a,h ;CB 14 + rl a,l ;CB 15 + ;*********************************************************** + ; rotate left 'a' with carry + rla ;17 + ;*********************************************************** + ; rotate left circular + rlc a,(hl) ;CB 06 + rlc a,offset(ix) ;DD CB 55 06 + rlc a,offset(iy) ;FD CB 55 06 + rlc a,a ;CB 07 + rlc a,b ;CB 00 + rlc a,c ;CB 01 + rlc a,d ;CB 02 + rlc a,e ;CB 03 + rlc a,h ;CB 04 + rlc a,l ;CB 05 + ;*********************************************************** + ; rotate left 'a' circular + rlca ;07 + ;*********************************************************** + ; rotate digit left and right + ; between 'a' and location (hl) + rld ;ED 6F + ;*********************************************************** + ; rotate right through carry + rr a,(hl) ;CB 1E + rr a,offset(ix) ;DD CB 55 1E + rr a,offset(iy) ;FD CB 55 1E + rr a,a ;CB 1F + rr a,b ;CB 18 + rr a,c ;CB 19 + rr a,d ;CB 1A + rr a,e ;CB 1B + rr a,h ;CB 1C + rr a,l ;CB 1D + ;*********************************************************** + ; rotate 'a' right with carry + rra ;1F + ;*********************************************************** + ; rotate right circular + rrc a,(hl) ;CB 0E + rrc a,offset(ix) ;DD CB 55 0E + rrc a,offset(iy) ;FD CB 55 0E + rrc a,a ;CB 0F + rrc a,b ;CB 08 + rrc a,c ;CB 09 + rrc a,d ;CB 0A + rrc a,e ;CB 0B + rrc a,h ;CB 0C + rrc a,l ;CB 0D + ;*********************************************************** + ; rotate 'a' right circular + rrca ;0F + ;*********************************************************** + ; rotate digit right and left + ; between 'a' and location (hl) + rrd ;ED 67 + ;*********************************************************** + ; restart location + rst 0x00 ;C7 + rst 0x08 ;CF + rst 0x10 ;D7 + rst 0x18 ;DF + rst 0x20 ;E7 + rst 0x28 ;EF + rst 0x30 ;F7 + rst 0x38 ;FF + ;*********************************************************** + ; subtract with carry to 'a' + sbc a,(hl) ;9E + sbc a,offset(ix) ;DD 9E 55 + sbc a,offset(iy) ;FD 9E 55 + sbc a,a ;9F + sbc a,b ;98 + sbc a,c ;99 + sbc a,d ;9A + sbc a,e ;9B + sbc a,h ;9C + sbc a,l ;9D + sbc a,#n ;DE 20 + ;*********************************************************** + ; add with carry register pair to 'hl' + sbc hl,bc ;ED 42 + sbc hl,de ;ED 52 + sbc hl,hl ;ED 62 + sbc hl,sp ;ED 72 + ;*********************************************************** + ; set carry flag (C=1) + scf ;37 + ;*********************************************************** + ; set bit of location or register + set 0,(hl) ;CB C6 + set 0,offset(ix) ;DD CB 55 C6 + set 0,offset(iy) ;FD CB 55 C6 + set 0,a ;CB C7 + set 0,b ;CB C0 + set 0,c ;CB C1 + set 0,d ;CB C2 + set 0,e ;CB C3 + set 0,h ;CB C4 + set 0,l ;CB C5 + set 1,(hl) ;CB CE + set 1,offset(ix) ;DD CB 55 CE + set 1,offset(iy) ;FD CB 55 CE + set 1,a ;CB CF + set 1,b ;CB C8 + set 1,c ;CB C9 + set 1,d ;CB CA + set 1,e ;CB CB + set 1,h ;CB CC + set 1,l ;CB CD + set 2,(hl) ;CB D6 + set 2,offset(ix) ;DD CB 55 D6 + set 2,offset(iy) ;FD CB 55 D6 + set 2,a ;CB D7 + set 2,b ;CB D0 + set 2,c ;CB D1 + set 2,d ;CB D2 + set 2,e ;CB D3 + set 2,h ;CB D4 + set 2,l ;CB D5 + set 3,(hl) ;CB DE + set 3,offset(ix) ;DD CB 55 DE + set 3,offset(iy) ;FD CB 55 DE + set 3,a ;CB DF + set 3,b ;CB D8 + set 3,c ;CB D9 + set 3,d ;CB DA + set 3,e ;CB DB + set 3,h ;CB DC + set 3,l ;CB DD + set 4,(hl) ;CB E6 + set 4,offset(ix) ;DD CB 55 E6 + set 4,offset(iy) ;FD CB 55 E6 + set 4,a ;CB E7 + set 4,b ;CB E0 + set 4,c ;CB E1 + set 4,d ;CB E2 + set 4,e ;CB E3 + set 4,h ;CB E4 + set 4,l ;CB E5 + set 5,(hl) ;CB EE + set 5,offset(ix) ;DD CB 55 EE + set 5,offset(iy) ;FD CB 55 EE + set 5,a ;CB EF + set 5,b ;CB E8 + set 5,c ;CB E9 + set 5,d ;CB EA + set 5,e ;CB EB + set 5,h ;CB EC + set 5,l ;CB ED + set 6,(hl) ;CB F6 + set 6,offset(ix) ;DD CB 55 F6 + set 6,offset(iy) ;FD CB 55 F6 + set 6,a ;CB F7 + set 6,b ;CB F0 + set 6,c ;CB F1 + set 6,d ;CB F2 + set 6,e ;CB F3 + set 6,h ;CB F4 + set 6,l ;CB F5 + set 7,(hl) ;CB FE + set 7,offset(ix) ;DD CB 55 FE + set 7,offset(iy) ;FD CB 55 FE + set 7,a ;CB FF + set 7,b ;CB F8 + set 7,c ;CB F9 + set 7,d ;CB FA + set 7,e ;CB FB + set 7,h ;CB FC + set 7,l ;CB FD + ;*********************************************************** + ; shift operand left arithmetic + sla a,(hl) ;CB 26 + sla a,offset(ix) ;DD CB 55 26 + sla a,offset(iy) ;FD CB 55 26 + sla a,a ;CB 27 + sla a,b ;CB 20 + sla a,c ;CB 21 + sla a,d ;CB 22 + sla a,e ;CB 23 + sla a,h ;CB 24 + sla a,l ;CB 25 + ;*********************************************************** + ; shift operand right arithmetic + sra a,(hl) ;CB 2E + sra a,offset(ix) ;DD CB 55 2E + sra a,offset(iy) ;FD CB 55 2E + sra a,a ;CB 2F + sra a,b ;CB 28 + sra a,c ;CB 29 + sra a,d ;CB 2A + sra a,e ;CB 2B + sra a,h ;CB 2C + sra a,l ;CB 2D + ;*********************************************************** + ; shift operand right logical + srl a,(hl) ;CB 3E + srl a,offset(ix) ;DD CB 55 3E + srl a,offset(iy) ;FD CB 55 3E + srl a,a ;CB 3F + srl a,b ;CB 38 + srl a,c ;CB 39 + srl a,d ;CB 3A + srl a,e ;CB 3B + srl a,h ;CB 3C + srl a,l ;CB 3D + ;*********************************************************** + ; subtract operand from 'a' + sub a,(hl) ;96 + sub a,offset(ix) ;DD 96 55 + sub a,offset(iy) ;FD 96 55 + sub a,a ;97 + sub a,b ;90 + sub a,c ;91 + sub a,d ;92 + sub a,e ;93 + sub a,h ;94 + sub a,l ;95 + sub a,#n ;D6 20 + ;*********************************************************** + ; logical 'xor' operand with 'a' + xor a,(hl) ;AE + xor a,offset(ix) ;DD AE 55 + xor a,offset(iy) ;FD AE 55 + xor a,a ;AF + xor a,b ;A8 + xor a,c ;A9 + xor a,d ;AA + xor a,e ;AB + xor a,h ;AC + xor a,l ;AD + xor a,#n ;EE 20 + + .page + ;*********************************************************** + ; Hitachi HD64180 Codes + ;*********************************************************** + + .hd64 + + ;*********************************************************** + ; load register with input from port (n) + in0 a,(n) ;ED 38 20 + in0 b,(n) ;ED 00 20 + in0 c,(n) ;ED 08 20 + in0 d,(n) ;ED 10 20 + in0 e,(n) ;ED 18 20 + in0 h,(n) ;ED 20 20 + in0 l,(n) ;ED 28 20 + ;*********************************************************** + ; multiplication of each half + ; of the specified register pair + ; with the 16-bit result going to + ; the specified register pair + mlt bc ;ED 4C + mlt de ;ED 5C + mlt hl ;ED 6C + mlt sp ;ED 7C + ;*********************************************************** + ; load output port (c) with + ; location (hl), + ; decrement hl and b + ; decrement c + otdm ;ED 8B + ;*********************************************************** + ; load output port (c) with + ; location (hl), + ; decrement hl and c + ; decrement b + ; repeat until b = 0 + otdmr ;ED 9B + ;*********************************************************** + ; load output port (c) with + ; location (hl), + ; increment hl and b + ; decrement c + otim ;ED 83 + ;*********************************************************** + ; load output port (c) with + ; location (hl), + ; increment hl and c + ; decrement b + ; repeat until b = 0 + otimr ;ED 93 + ;*********************************************************** + ; load output port (n) from register + out0 (n),a ;ED 39 20 + out0 (n),b ;ED 01 20 + out0 (n),c ;ED 09 20 + out0 (n),d ;ED 11 20 + out0 (n),e ;ED 19 20 + out0 (n),h ;ED 21 20 + out0 (n),l ;ED 29 20 + ;*********************************************************** + ; enter sleep mode + slp ;ED 76 + ;*********************************************************** + ; non-destructive'and' with accumulator and specified operand + tst a ;ED 3C + tst b ;ED 04 + tst c ;ED 0C + tst d ;ED 14 + tst e ;ED 1C + tst h ;ED 24 + tst l ;ED 2C + tst #n ;ED 64 20 + tst (hl) ;ED 34 + ;*********************************************************** + ; non-destructive 'and' of n and the contents of port (c) + tstio #n ;ED 74 20 + ;*********************************************************** + diff --git a/link/as/z80/tz80l.asm b/link/as/z80/tz80l.asm new file mode 100644 index 00000000..aec2ba2f --- /dev/null +++ b/link/as/z80/tz80l.asm @@ -0,0 +1,47 @@ + .sbttl Assembler Link Tests + + .module tz80l + + ; This file and TCONST.ASM should be assembled and linked. + ; + ; ASZ80 -XGOL TZ80L + ; ASZ80 -XGOL TCONST + ; + ; ASLINK -C + ; -XMS + ; TZ80L + ; TCONST + ; -E + ; + ; The following tests verify the correct processing of + ; external references for the branches. + ; + ; *L signifies an error will be reported at link time. + + ; branch test must be first + + .area TEST (ABS,OVR) + + .blkb 0x7E ;bra1: + jr C,bra1 ; 38 00 [38 80] + .blkb 0x7F ;bra2: + jr C,bra2 ;*L 38 00 [38 7F] + jr C,bra3 ; 38 00 [38 7F] + .blkb 0x7F + .blkb 0x00 ;bra3: + jr C,bra4 ;*L 38 00 [38 [80] + .blkb 0x80 + .blkb 0x00 ;bra4: + + .blkb 0x7E ;bra5: + jr C,bra5 ; 38 00 [38 80] + .blkb 0x7F ;bra6: + jr C,bra6 ;*L 38 00 [38 7F] + jr C,bra7 ; 38 00 [38 7F] + .blkb 0x7F + .blkb 0x00 ;bra7: + jr C,bra8 ;*L 38 00 [38 [80] + .blkb 0x80 + .blkb 0x00 ;bra8: + + diff --git a/link/as/z80/z80.h b/link/as/z80/z80.h new file mode 100644 index 00000000..82cf3177 --- /dev/null +++ b/link/as/z80/z80.h @@ -0,0 +1,191 @@ +/* z80.h */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +/* + * Extensions: P. Felber + */ + +/*)BUILD + $(PROGRAM) = ASZ80 + $(INCLUDE) = { + ASM.H + Z80.H + } + $(FILES) = { + Z80EXT.C + Z80MCH.C + Z80ADR.C + Z80PST.C + ASMAIN.C + ASLEX.C + ASSYM.C + ASSUBR.C + ASEXPR.C + ASDATA.C + ASLIST.C + ASOUT.C + } + $(STACK) = 2000 +*/ + +/* + * Indirect Addressing delimeters + */ +#define LFIND '(' +#define RTIND ')' + +/* + * Registers + */ +#define B 0 +#define C 1 +#define D 2 +#define E 3 +#define H 4 +#define L 5 +#define A 7 + +#define I 0107 +#define R 0117 + +#define BC 0 +#define DE 1 +#define HL 2 +#define SP 3 +#define AF 4 +#ifndef GAMEBOY +#define IX 5 +#define IY 6 +#else /* GAMEBOY */ +#define HLD 5 +#define HLI 6 +#endif /* GAMEBOY */ + +/* + * Conditional definitions + */ +#define NZ 0 +#define Z 1 +#define NC 2 +#define CS 3 +#ifndef GAMEBOY +#define PO 4 +#define PE 5 +#define P 6 +#define M 7 +#endif /* GAMEBOY */ + +/* + * Symbol types + */ +#define S_IMMED 30 +#define S_R8 31 +#define S_R8X 32 +#define S_R16 33 +#define S_R16X 34 +#define S_CND 35 +#define S_FLAG 36 + +/* + * Indexing modes + */ +#define S_INDB 40 +#define S_IDC 41 +#define S_INDR 50 +#define S_IDBC 50 +#define S_IDDE 51 +#define S_IDHL 52 +#define S_IDSP 53 +#ifndef GAMEBOY +#define S_IDIX 55 +#define S_IDIY 56 +#else /* GAMEBOY */ +#define S_IDHLD 55 +#define S_IDHLI 56 +#endif /* GAMEBOY */ +#define S_INDM 57 + +/* + * Instruction types + */ +#define S_LD 60 +#define S_CALL 61 +#define S_JP 62 +#define S_JR 63 +#define S_RET 64 +#define S_BIT 65 +#define S_INC 66 +#define S_DEC 67 +#define S_ADD 68 +#define S_ADC 69 +#define S_AND 70 +#ifndef GAMEBOY +#define S_EX 71 +#endif /* GAMEBOY */ +#define S_PUSH 72 +#ifndef GAMEBOY +#define S_IN 73 +#define S_OUT 74 +#endif /* GAMEBOY */ +#define S_RL 75 +#define S_RST 76 +#define S_IM 77 +#define S_INH1 78 +#ifndef GAMEBOY +#define S_INH2 79 +#define S_DJNZ 80 +#endif /* GAMEBOY */ +#define S_SUB 81 +#define S_SBC 82 +#ifdef GAMEBOY +#define S_STOP 83 +#define S_LDH 84 +#define S_LDA 85 +#define S_LDHL 86 +#endif /* GAMEBOY */ + +/* + * HD64180 Instructions + */ +#define X_HD64 90 +#define X_INH2 91 +#define X_IN 92 +#define X_OUT 93 +#define X_MLT 94 +#define X_TST 95 +#define X_TSTIO 96 + +struct adsym +{ + char a_str[4]; /* addressing string */ + int a_val; /* addressing mode value */ +}; + +extern struct adsym R8[]; +extern struct adsym R8X[]; +extern struct adsym R16[]; +extern struct adsym R16X[]; +extern struct adsym CND[]; + + /* machine dependent functions */ + + /* z80adr.c */ +extern int addr(); +extern int admode(); +extern int any(); +extern int srch(); + + /* z80mch.c */ +extern int comma(); +extern int genop(); +extern int gixiy(); +extern VOID minit(); +extern VOID machine(struct mne *mp) ; diff --git a/link/as/z80/z80adr.c b/link/as/z80/z80adr.c new file mode 100644 index 00000000..d47b8eba --- /dev/null +++ b/link/as/z80/z80adr.c @@ -0,0 +1,256 @@ +/* z80adr.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +/* + * Extensions: P. Felber + */ + +#include +#include +#include "asm.h" +#include "z80.h" + +/* + * Read an address specifier. Pack the + * address information into the supplied + * `expr' structure. Return the mode of + * the address. + * + * This addr(esp) routine performs the following addressing decoding: + * + * address mode flag addr base + * #n S_IMMED 0 n NULL + * label s_type ---- s_addr s_area + * [REG] S_IND+icode 0 0 NULL + * [label] S_INDM ---- s_addr s_area + * offset[REG] S_IND+icode ---- offset ---- + */ +int +addr(esp) +register struct expr *esp; +{ + register int c, mode = 0, indx; + + if ((c = getnb()) == '#') { + expr(esp, 0); + esp->e_mode = S_IMMED; + } else + if (c == LFIND) { + if ((indx = admode(R8)) != 0) { + mode = S_INDB; + } else + if ((indx = admode(R16)) != 0) { + mode = S_INDR; + } else + if ((indx = admode(R8X)) != 0) { + mode = S_R8X; + aerr(); + } else + if ((indx = admode(R16X)) != 0) { + mode = S_R16X; + aerr(); + } else { + expr(esp, 0); + esp->e_mode = S_INDM; + } + if (indx) { + esp->e_mode = (mode + indx)&0xFF; + esp->e_base.e_ap = NULL; + } + if ((c = getnb()) != RTIND) + qerr(); + } else { + unget(c); + if ((indx = admode(R8)) != 0) { + mode = S_R8; + } else + if ((indx = admode(R16)) != 0) { + mode = S_R16; + } else + if ((indx = admode(R8X)) != 0) { + mode = S_R8X; + } else + if ((indx = admode(R16X)) != 0) { + mode = S_R16X; + } else { + expr(esp, 0); + esp->e_mode = S_USER; + } + if (indx) { + esp->e_addr = indx&0xFF; + esp->e_mode = mode; + esp->e_base.e_ap = NULL; + } + if ((c = getnb()) == LFIND) { +#ifndef GAMEBOY + if ((indx=admode(R16))!=0 + && ((indx&0xFF)==IX || (indx&0xFF)==IY)) { +#else /* GAMEBOY */ + if ((indx=admode(R16))!=0) { +#endif /* GAMEBOY */ + esp->e_mode = S_INDR + (indx&0xFF); + } else { + aerr(); + } + if ((c = getnb()) != RTIND) + qerr(); + } else { + unget(c); + } + } + return (esp->e_mode); +} + +/* + * Enter admode() to search a specific addressing mode table + * for a match. Return the addressing value on a match or + * zero for no match. + */ +int +admode(sp) +register struct adsym *sp; +{ + register char *ptr; + register int i; + register char *ips; + + ips = ip; + unget(getnb()); + + i = 0; + while ( *(ptr = (char *) &sp[i]) ) { + if (srch(ptr)) { + return(sp[i].a_val); + } + i++; + } + ip = ips; + return(0); +} + +/* + * srch --- does string match ? + */ +int +srch(str) +register char *str; +{ + register char *ptr; + ptr = ip; + +#if CASE_SENSITIVE + while (*ptr && *str) { + if (*ptr != *str) + break; + ptr++; + str++; + } + if (*ptr == *str) { + ip = ptr; + return(1); + } +#else + while (*ptr && *str) { + if (ccase[(unsigned char)(*ptr)] != ccase[(unsigned char)(*str)]) + break; + ptr++; + str++; + } + if (ccase[(unsigned char)(*ptr)] == ccase[(unsigned char)(*str)]) { + ip = ptr; + return(1); + } +#endif + + if (!*str) + if (any(*ptr," \t\n,);")) { + ip = ptr; + return(1); + } + return(0); +} + +/* + * any --- does str contain c? + */ +int +any(c,str) +char c, *str; +{ + while (*str) + if(*str++ == c) + return(1); + return(0); +} + +/* + * Registers + */ + +struct adsym R8[] = { + { "b", B|0400 }, + { "c", C|0400 }, + { "d", D|0400 }, + { "e", E|0400 }, + { "h", H|0400 }, + { "l", L|0400 }, + { "a", A|0400 }, + { "", 000 } +}; + +struct adsym R8X[] = { + { "i", I|0400 }, + { "r", R|0400 }, + { "", 000 } +}; + +struct adsym R16[] = { + { "bc", BC|0400 }, + { "de", DE|0400 }, + { "hl", HL|0400 }, + { "sp", SP|0400 }, +#ifndef GAMEBOY + { "ix", IX|0400 }, + { "iy", IY|0400 }, +#else /* GAMEBOY */ + { "hl-", HLD|0400 }, + { "hl+", HLI|0400 }, + { "hld", HLD|0400 }, + { "hli", HLI|0400 }, +#endif /* GAMEBOY */ + { "", 000 } +}; + +struct adsym R16X[] = { + { "af", AF|0400 }, +#ifndef GAMEBOY + { "af'", AF|0400 }, +#endif /* GAMEBOY */ + { "", 000 } +}; + +/* + * Conditional definitions + */ + +struct adsym CND[] = { + { "NZ", NZ|0400 }, + { "Z", Z |0400 }, + { "NC", NC|0400 }, + { "C", CS|0400 }, +#ifndef GAMEBOY + { "PO", PO|0400 }, + { "PE", PE|0400 }, + { "P", P |0400 }, + { "M", M |0400 }, +#endif /* GAMEBOY */ + { "", 000 } +}; diff --git a/link/as/z80/z80ext.c b/link/as/z80/z80ext.c new file mode 100644 index 00000000..4ae945a9 --- /dev/null +++ b/link/as/z80/z80ext.c @@ -0,0 +1,27 @@ +/* z80ext.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +/* + * Extensions: P. Felber + */ + +#include +#include +#include "asm.h" +#include "z80.h" + +#ifndef GAMEBOY +char *cpu = "Zilog Z80 / Hitachi HD64180"; +#else /* GAMEBOY */ +char *cpu = "GameBoy Z80-like CPU"; +#endif /* GAMEBOY */ +int hilo = 0; +char *dsft = "ASM"; diff --git a/link/as/z80/z80mch.c b/link/as/z80/z80mch.c new file mode 100644 index 00000000..7ee7c746 --- /dev/null +++ b/link/as/z80/z80mch.c @@ -0,0 +1,773 @@ +/* z80mch.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +/* + * Extensions: P. Felber + */ + +#include +#include +#include "asm.h" +#include "z80.h" + +char imtab[3] = { 0x46, 0x56, 0x5E }; +#ifndef GAMEBOY +int hd64; +#endif /* GAMEBOY */ + +/* + * Process a machine op. + */ +VOID +machine(mp) +struct mne *mp; +{ + register int op, t1, t2; + struct expr e1, e2; + int rf, v1, v2; + + clrexpr(&e1); + clrexpr(&e2); + op = mp->m_valu; + rf = mp->m_type; +#ifndef GAMEBOY + if (!hd64 && rf>X_HD64) + rf = 0; +#endif /* GAMEBOY */ + switch (rf) { + + case S_INH1: + outab(op); + break; + +#ifndef GAMEBOY + case S_INH2: + outab(0xED); + outab(op); + break; +#endif /* GAMEBOY */ + + case S_RET: + if (more()) { + if ((v1 = admode(CND)) != 0) { + outab(op | v1<<3); + } else { + qerr(); + } + } else { + outab(0xC9); + } + break; + + case S_PUSH: + if (admode(R16X)) { + outab(op+0x30); + break; + } else + if ((v1 = admode(R16)) != 0 && (v1 &= 0xFF) != SP) { + if (v1 != gixiy(v1)) { + outab(op+0x20); + break; + } + outab(op | v1<<4); + break; + } + aerr(); + break; + + case S_RST: + v1 = absexpr(); + if (v1 & ~0x38) { + aerr(); + v1 = 0; + } + outab(op|v1); + break; + + case S_IM: + expr(&e1, 0); + abscheck(&e1); + if (e1.e_addr > 2) { + aerr(); + e1.e_addr = 0; + } + outab(op); + outab(imtab[e1.e_addr]); + break; + + case S_BIT: + expr(&e1, 0); + t1 = 0; + v1 = e1.e_addr; + if (v1 > 7) { + ++t1; + v1 &= 0x07; + } + op |= (v1<<3); + comma(); + addr(&e2); + abscheck(&e1); + if (genop(0xCB, op, &e2, 0) || t1) + aerr(); + break; + + case S_RL: + t1 = 0; + t2 = addr(&e2); + if (more()) { + if ((t2 != S_R8) || (e2.e_addr != A)) + ++t1; + comma(); + t2 = addr(&e2); + } + if (genop(0xCB, op, &e2, 0) || t1) + aerr(); + break; + + case S_AND: + case S_SUB: + t1 = 0; + t2 = addr(&e2); + if (more()) { + if ((t2 != S_R8) || (e2.e_addr != A)) + ++t1; + comma(); + t2 = addr(&e2); + } + if (genop(0, op, &e2, 1) || t1) + aerr(); + break; + + case S_ADD: + case S_ADC: + case S_SBC: + t1 = addr(&e1); + t2 = 0; + if (more()) { + comma(); + t2 = addr(&e2); + } + if (t2 == 0) { + if (genop(0, op, &e1, 1)) + aerr(); + break; + } + if ((t1 == S_R8) && (e1.e_addr == A)) { + if (genop(0, op, &e2, 1)) + aerr(); + break; + } + if ((t1 == S_R16) && (t2 == S_R16)) { +#ifndef GAMEBOY + if (rf == S_ADD) + op = 0x09; + if (rf == S_ADC) + op = 0x4A; + if (rf == S_SBC) + op = 0x42; + v1 = e1.e_addr; + v2 = e2.e_addr; + if ((v1 == HL) && (v2 <= SP)) { + if (rf != S_ADD) + outab(0xED); + outab(op | (v2<<4)); + break; + } + if (rf != S_ADD) { + aerr(); + break; + } + if ((v1 == IX) && (v2 != HL) && (v2 != IY)) { + if (v2 == IX) + v2 = HL; + outab(0xDD); + outab(op | (v2<<4)); + break; + } + if ((v1 == IY) && (v2 != HL) && (v2 != IX)) { + if (v2 == IY) + v2 = HL; + outab(0xFD); + outab(op | (v2<<4)); + break; + } + } +#else /* GAMEBOY */ + v1 = e1.e_addr; + v2 = e2.e_addr; + if ((v1 == HL) && (v2 <= SP) && (rf == S_ADD)) { + outab(0x09 | (v2<<4)); + break; + } + } + /* + * 0xE8 : ADD SP,#n + */ + if ((rf == S_ADD) && (t1 == S_R16) && (e1.e_addr == SP) && (t2 == S_IMMED)) { + outab(0xE8); + outrb(&e2,0); + break; + } +#endif /* GAMEBOY */ + aerr(); + break; + + case S_LD: + t1 = addr(&e1); + comma(); + t2 = addr(&e2); + if (t1 == S_R8) { + v1 = op | e1.e_addr<<3; + if (genop(0, v1, &e2, 0) == 0) + break; + if (t2 == S_IMMED) { + outab(e1.e_addr<<3 | 0x06); + outrb(&e2,0); + break; + } + } + v1 = e1.e_addr; + v2 = e2.e_addr; + if ((t1 == S_R16) && (t2 == S_IMMED)) { + v1 = gixiy(v1); + outab(0x01|v1<<4); + outrw(&e2, 0); + break; + } +#ifndef GAMEBOY + if ((t1 == S_R16) && (t2 == S_INDM)) { + if (gixiy(v1) == HL) { + outab(0x2A); + } else { + outab(0xED); + outab(0x4B | v1<<4); + } + outrw(&e2, 0); + break; + } + if ((t1 == S_INDM) && (t2 == S_R16)) { + if (gixiy(v2) == HL) { + outab(0x22); + } else { + outab(0xED); + outab(0x43 | v2<<4); + } + outrw(&e1, 0); + break; + } + if ((t1 == S_R8) && (v1 == A) && (t2 == S_INDM)) { + outab(0x3A); + outrw(&e2, 0); + break; + } + if ((t1 == S_INDM) && (t2 == S_R8) && (v2 == A)) { + outab(0x32); + outrw(&e1, 0); + break; + } +#endif /* GAMEBOY */ + if ((t2 == S_R8) && (gixiy(t1) == S_IDHL)) { + outab(0x70|v2); + if (t1 != S_IDHL) + outrb(&e1, 0); + break; + } + if ((t2 == S_IMMED) && (gixiy(t1) == S_IDHL)) { + outab(0x36); + if (t1 != S_IDHL) + outrb(&e1, 0); + outrb(&e2, 0); + break; + } +#ifndef GAMEBOY + if ((t1 == S_R8X) && (t2 == S_R8) && (v2 == A)) { + outab(0xED); + outab(v1); + break; + } + if ((t1 == S_R8) && (v1 == A) && (t2 == S_R8X)) { + outab(0xED); + outab(v2|0x10); + break; + } +#endif /* GAMEBOY */ + if ((t1 == S_R16) && (v1 == SP)) { + if ((t2 == S_R16) && (gixiy(v2) == HL)) { + outab(0xF9); + break; + } + } + if ((t1 == S_R8) && (v1 == A)) { + if ((t2 == S_IDBC) || (t2 == S_IDDE)) { + outab(0x0A | (t2-S_INDR)<<4); + break; + } + } + if ((t2 == S_R8) && (v2 == A)) { + if ((t1 == S_IDBC) || (t1 == S_IDDE)) { + outab(0x02 | (t1-S_INDR)<<4); + break; + } + } +#ifdef GAMEBOY + /* + * 0x08 : LD (nn),SP + */ + if ((t1 == S_INDM) && (t2 == S_R16) && (v2 == SP)) { + outab(0x08); + outrw(&e1, 0); + break; + } + /* + * 0xEA : LD (nn),A + * 0xFA : LD A,(nn) + */ + if ((t1 == S_INDM) && (t2 == S_R8) && (v2 == A)) { + outab(0xEA); + outrw(&e1, 0); + break; + } + if ((t2 == S_INDM) && (t1 == S_R8) && (v1 == A)) { + outab(0xFA); + outrw(&e2, 0); + break; + } + /* + * 0x32 : LD (HL-),A + * 0x3A : LD A,(HL-) + */ + if ((t1 == S_R8) && (v1 == A) && (t2 == S_IDHLD)) { + outab(0x3A); + break; + } + if ((t2 == S_R8) && (v2 == A) && (t1 == S_IDHLD)) { + outab(0x32); + break; + } + /* + * 0x22 : LD (HL+),A + * 0x2A : LD A,(HL+) + */ + if ((t1 == S_R8) && (v1 == A) && (t2 == S_IDHLI)) { + outab(0x2A); + break; + } + if ((t2 == S_R8) && (v2 == A) && (t1 == S_IDHLI)) { + outab(0x22); + break; + } +#endif /* GAMEBOY */ + aerr(); + break; + + +#ifdef GAMEBOY + case S_STOP: /* 0x10 */ + /* + * 0x10 : STOP + */ + outab(op); + outab(0x00); + break; + + + case S_LDH: /* 0xE0 */ + /* + * 0xE0 : LDH (n),A = LD ($FF00+n),A + * 0xE2 : LDH (C),A = LD ($FF00+C),A + * 0xF0 : LDH A,(n) = LD A,($FF00+n) + * 0xF2 : LDH A,(C) = LD A,($FF00+C) + */ + t1 = addr(&e1); + comma(); + t2 = addr(&e2); + if ((t1 == S_INDM) && (t2 == S_R8) && (e2.e_addr == A)) { + outab(0xE0); + outrb(&e1, 0); + break; + } + if ((t1 == S_IDC) && (t2 == S_R8) && (e2.e_addr == A)) { + outab(0xE2); + break; + } + if ((t2 == S_INDM) && (t1 == S_R8) && (e1.e_addr == A)) { + outab(0xF0); + outrb(&e2, 0); + break; + } + if ((t2 == S_IDC) && (t1 == S_R8) && (e1.e_addr == A)) { + outab(0xF2); + break; + } + aerr(); + break; + + + case S_LDA: /* 0xE8 */ + /* + * 0xE8 : LDA SP,#n(SP) + * 0xF8 : LDA HL,#n(SP) + */ + t1 = addr(&e1); + comma(); + t2 = addr(&e2); + if ((t1 == S_R16) && (e1.e_addr == SP) && (t2 == S_INDR+SP)) { + outab(0xE8); + outrb(&e2,0); + break; + } + if ((t1 == S_R16) && (e1.e_addr == HL) && (t2 == S_INDR+SP)) { + outab(0xF8); + outrb(&e2,0); + break; + } + aerr(); + break; + + + case S_LDHL: /* 0xF8 */ + /* + * 0xF8 : LDHL SP,#n + */ + t1 = addr(&e1); + comma(); + t2 = addr(&e2); + if ((t1 == S_R16) && (e1.e_addr == SP) && (t2 == S_IMMED)) { + outab(0xF8); + outrb(&e2,0); + break; + } + aerr(); + break; +#endif /* GAMEBOY */ + + +#ifndef GAMEBOY + case S_EX: + t1 = addr(&e1); + comma(); + t2 = addr(&e2); + if (t2 == S_R16) { + v1 = e1.e_addr; + v2 = e2.e_addr; + if ((t1 == S_IDSP) && (v1 == 0)) { + if (gixiy(v2) == HL) { + outab(op); + break; + } + } + if (t1 == S_R16) { + if ((v1 == DE) && (v2 == HL)) { + outab(0xEB); + break; + } + } + } + if ((t1 == S_R16X) && (t2 == S_R16X)) { + outab(0x08); + break; + } + aerr(); + break; + + case S_IN: + case S_OUT: + if (rf == S_IN) { + t1 = addr(&e1); + comma(); + t2 = addr(&e2); + } else { + t2 = addr(&e2); + comma(); + t1 = addr(&e1); + } + v1 = e1.e_addr; + v2 = e2.e_addr; + if (t1 == S_R8) { + if ((v1 == A) && (t2 == S_INDM)) { + outab(op); + outab(v2); + break; + } + if (t2 == S_IDC) { + outab(0xED); + outab(((rf == S_IN) ? 0x40 : 0x41) + (v1<<3)); + break; + } + } + aerr(); + break; +#endif /* GAMEBOY */ + + case S_DEC: + case S_INC: + t1 = addr(&e1); + v1 = e1.e_addr; + if (t1 == S_R8) { + outab(op|(v1<<3)); + break; + } + if (t1 == S_IDHL) { + outab(op|0x30); + break; + } + if (t1 != gixiy(t1)) { + outab(op|0x30); + outrb(&e1,0); + break; + } + if (t1 == S_R16) { + v1 = gixiy(v1); + if (rf == S_INC) { + outab(0x03|(v1<<4)); + break; + } + if (rf == S_DEC) { + outab(0x0B|(v1<<4)); + break; + } + } + aerr(); + break; + +#ifndef GAMEBOY + case S_DJNZ: + case S_JR: + if ((v1 = admode(CND)) != 0 && rf != S_DJNZ) { +#else /* GAMEBOY */ + case S_JR: + if ((v1 = admode(CND)) != 0) { +#endif /* GAMEBOY */ + if ((v1 &= 0xFF) <= 0x18) { + op += (v1+1)<<3; + } else { + aerr(); + } + comma(); + } + expr(&e2, 0); + outab(op); + if (e2.e_base.e_ap == NULL || e2.e_base.e_ap == dot.s_area) { + v2 = e2.e_addr - dot.s_addr - 1; + if (pass == 2 && ((v2 < -128) || (v2 > 127))) + aerr(); + outab(v2); + } else { + outrb(&e2, R_PCR); + } + if (e2.e_mode != S_USER) + rerr(); + break; + + case S_CALL: + if ((v1 = admode(CND)) != 0) { + op |= (v1&0xFF)<<3; + comma(); + } else { + op = 0xCD; + } + expr(&e1, 0); + outab(op); + outrw(&e1, 0); + break; + + case S_JP: + if ((v1 = admode(CND)) != 0) { + op |= (v1&0xFF)<<3; + comma(); + expr(&e1, 0); + outab(op); + outrw(&e1, 0); + break; + } + t1 = addr(&e1); + if (t1 == S_USER) { + outab(0xC3); + outrw(&e1, 0); + break; + } + if ((e1.e_addr == 0) && (gixiy(t1) == S_IDHL)) { + outab(0xE9); + break; + } + aerr(); + break; + +#ifndef GAMEBOY + case X_HD64: + ++hd64; + break; + + case X_INH2: + outab(0xED); + outab(op); + break; + + case X_IN: + case X_OUT: + if (rf == X_IN) { + t1 = addr(&e1); + comma(); + t2 = addr(&e2); + } else { + t2 = addr(&e2); + comma(); + t1 = addr(&e1); + } + if ((t1 == S_R8) && (t2 == S_INDM)) { + outab(0xED); + outab(op | e1.e_addr<<3); + outrb(&e2, 0); + break; + } + aerr(); + break; + + case X_MLT: + t1 = addr(&e1); + if ((t1 == S_R16) && ((v1 = e1.e_addr) <= SP)) { + outab(0xED); + outab(op | v1<<4); + break; + } + aerr(); + break; + + case X_TST: + t1 = addr(&e1); + if (t1 == S_R8) { + outab(0xED); + outab(op | e1.e_addr<<3); + break; + } + if (t1 == S_IDHL) { + outab(0xED); + outab(0x34); + break; + } + if (t1 == S_IMMED) { + outab(0xED); + outab(0x64); + outrb(&e1, 0); + break; + } + aerr(); + break; + + case X_TSTIO: + t1 = addr(&e1); + if (t1 == S_IMMED) { + outab(0xED); + outab(op); + outrb(&e1, 0); + break; + } + aerr(); + break; +#endif /* GAMEBOY */ + + default: + err('o'); + } +} + +/* + * general addressing evaluation + * return(0) if general addressing mode output, else + * return(esp->e_mode) + */ +int +genop(pop, op, esp, f) +register int pop, op; +register struct expr *esp; +int f; +{ + register int t1; + if ((t1 = esp->e_mode) == S_R8) { + if (pop) + outab(pop); + outab(op|esp->e_addr); + return(0); + } + if (t1 == S_IDHL) { + if (pop) + outab(pop); + outab(op|0x06); + return(0); + } + if (gixiy(t1) == S_IDHL) { + if (pop) { + outab(pop); + outrb(esp,0); + outab(op|0x06); + } else { + outab(op|0x06); + outrb(esp,0); + } + return(0); + } + if ((t1 == S_IMMED) && (f)) { + if (pop) + outab(pop); + outab(op|0x46); + outrb(esp,0); + return(0); + } + return(t1); +} + +/* + * IX and IY prebyte check + */ +int +gixiy(v) +int v; +{ +#ifndef GAMEBOY + if (v == IX) { + v = HL; + outab(0xDD); + } else if (v == IY) { + v = HL; + outab(0xFD); + } else if (v == S_IDIX) { + v = S_IDHL; + outab(0xDD); + } else if (v == S_IDIY) { + v = S_IDHL; + outab(0xFD); + } +#endif /* GAMEBOY */ + return(v); +} + +/* + * The next character must be a + * comma. + */ +int +comma() +{ + if (getnb() != ',') + qerr(); + return(1); +} + +/* + * Machine dependent initialization + */ +VOID +minit() +{ +#ifndef GAMEBOY + hd64 = 0; +#endif /* GAMEBOY */ +} diff --git a/link/as/z80/z80pst.c b/link/as/z80/z80pst.c new file mode 100644 index 00000000..7e6dc807 --- /dev/null +++ b/link/as/z80/z80pst.c @@ -0,0 +1,179 @@ +/* z80pst.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +/* + * Extensions: P. Felber + */ + +#include +#include +#include "asm.h" +#include "z80.h" + +struct mne mne[] = { + + /* machine */ + + /* system */ + + { NULL, "CON", S_ATYP, 0, A_CON }, + { NULL, "OVR", S_ATYP, 0, A_OVR }, + { NULL, "REL", S_ATYP, 0, A_REL }, + { NULL, "ABS", S_ATYP, 0, A_ABS|A_OVR }, + { NULL, "NOPAG", S_ATYP, 0, A_NOPAG }, + { NULL, "PAG", S_ATYP, 0, A_PAG }, + + { NULL, ".byte", S_BYTE, 0, 0 }, + { NULL, ".db", S_BYTE, 0, 0 }, + { NULL, ".word", S_WORD, 0, 0 }, + { NULL, ".dw", S_WORD, 0, 0 }, + { NULL, ".df", S_FLOAT, 0, 0 }, + { NULL, ".ascii", S_ASCII, 0, 0 }, + { NULL, ".asciz", S_ASCIZ, 0, 0 }, + { NULL, ".blkb", S_BLK, 0, 1 }, + { NULL, ".ds", S_BLK, 0, 1 }, + { NULL, ".blkw", S_BLK, 0, 2 }, + { NULL, ".page", S_PAGE, 0, 0 }, + { NULL, ".title", S_TITLE, 0, 0 }, + { NULL, ".sbttl", S_SBTL, 0, 0 }, + { NULL, ".globl", S_GLOBL, 0, 0 }, + { NULL, ".area", S_DAREA, 0, 0 }, + { NULL, ".even", S_EVEN, 0, 0 }, + { NULL, ".odd", S_ODD, 0, 0 }, + { NULL, ".if", S_IF, 0, 0 }, + { NULL, ".else", S_ELSE, 0, 0 }, + { NULL, ".endif", S_ENDIF, 0, 0 }, + { NULL, ".include", S_INCL, 0, 0 }, + { NULL, ".radix", S_RADIX, 0, 0 }, + { NULL, ".org", S_ORG, 0, 0 }, + { NULL, ".module", S_MODUL, 0, 0 }, + { NULL, ".ascis", S_ASCIS, 0, 0 }, + + /* z80 / hd64180 */ + + { NULL, "ld", S_LD, 0, 0x40 }, + + { NULL, "call", S_CALL, 0, 0xC4 }, + { NULL, "jp", S_JP, 0, 0xC2 }, + { NULL, "jr", S_JR, 0, 0x18 }, +#ifndef GAMEBOY + { NULL, "djnz", S_DJNZ, 0, 0x10 }, +#endif /* GAMEBOY */ + { NULL, "ret", S_RET, 0, 0xC0 }, + + { NULL, "bit", S_BIT, 0, 0x40 }, + { NULL, "res", S_BIT, 0, 0x80 }, + { NULL, "set", S_BIT, 0, 0xC0 }, + + { NULL, "inc", S_INC, 0, 0x04 }, + { NULL, "dec", S_DEC, 0, 0x05 }, + + { NULL, "add", S_ADD, 0, 0x80 }, + { NULL, "adc", S_ADC, 0, 0x88 }, + { NULL, "sub", S_SUB, 0, 0x90 }, + { NULL, "sbc", S_SBC, 0, 0x98 }, + + { NULL, "and", S_AND, 0, 0xA0 }, + { NULL, "cp", S_AND, 0, 0xB8 }, + { NULL, "or", S_AND, 0, 0xB0 }, + { NULL, "xor", S_AND, 0, 0xA8 }, + +#ifndef GAMEBOY + { NULL, "ex", S_EX, 0, 0xE3 }, +#endif /* GAMEBOY */ + + { NULL, "push", S_PUSH, 0, 0xC5 }, + { NULL, "pop", S_PUSH, 0, 0xC1 }, + +#ifndef GAMEBOY + { NULL, "in", S_IN, 0, 0xDB }, + { NULL, "out", S_OUT, 0, 0xD3 }, +#endif /* GAMEBOY */ + + { NULL, "rl", S_RL, 0, 0x10 }, + { NULL, "rlc", S_RL, 0, 0x00 }, + { NULL, "rr", S_RL, 0, 0x18 }, + { NULL, "rrc", S_RL, 0, 0x08 }, + { NULL, "sla", S_RL, 0, 0x20 }, + { NULL, "sra", S_RL, 0, 0x28 }, + { NULL, "srl", S_RL, 0, 0x38 }, + + { NULL, "rst", S_RST, 0, 0xC7 }, + +#ifndef GAMEBOY + { NULL, "im", S_IM, 0, 0xED }, +#endif /* GAMEBOY */ + + { NULL, "ccf", S_INH1, 0, 0x3F }, + { NULL, "cpl", S_INH1, 0, 0x2F }, + { NULL, "daa", S_INH1, 0, 0x27 }, + { NULL, "di", S_INH1, 0, 0xF3 }, + { NULL, "ei", S_INH1, 0, 0xFB }, +#ifndef GAMEBOY + { NULL, "exx", S_INH1, 0, 0xD9 }, +#endif /* GAMEBOY */ + { NULL, "nop", S_INH1, 0, 0x00 }, + { NULL, "halt", S_INH1, 0, 0x76 }, + { NULL, "rla", S_INH1, 0, 0x17 }, + { NULL, "rlca", S_INH1, 0, 0x07 }, + { NULL, "rra", S_INH1, 0, 0x1F }, + { NULL, "rrca", S_INH1, 0, 0x0F }, + { NULL, "scf", S_INH1, 0, 0x37 }, + +#ifndef GAMEBOY + { NULL, "cpd", S_INH2, 0, 0xA9 }, + { NULL, "cpdr", S_INH2, 0, 0xB9 }, + { NULL, "cpi", S_INH2, 0, 0xA1 }, + { NULL, "cpir", S_INH2, 0, 0xB1 }, + { NULL, "ind", S_INH2, 0, 0xAA }, + { NULL, "indr", S_INH2, 0, 0xBA }, + { NULL, "ini", S_INH2, 0, 0xA2 }, + { NULL, "inir", S_INH2, 0, 0xB2 }, + { NULL, "ldd", S_INH2, 0, 0xA8 }, + { NULL, "lddr", S_INH2, 0, 0xB8 }, + { NULL, "ldi", S_INH2, 0, 0xA0 }, + { NULL, "ldir", S_INH2, 0, 0xB0 }, + { NULL, "neg", S_INH2, 0, 0x44 }, + { NULL, "otdr", S_INH2, 0, 0xBB }, + { NULL, "otir", S_INH2, 0, 0xB3 }, + { NULL, "outd", S_INH2, 0, 0xAB }, + { NULL, "outi", S_INH2, 0, 0xA3 }, + { NULL, "reti", S_INH2, 0, 0x4D }, + { NULL, "retn", S_INH2, 0, 0x45 }, + { NULL, "rld", S_INH2, 0, 0x6F }, + { NULL, "rrd", S_INH2, 0, 0x67 }, + + /* 64180 */ + + { NULL, ".hd64", X_HD64, 0, 0 }, + + { NULL, "otdm", X_INH2, 0, 0x8B }, + { NULL, "otdmr", X_INH2, 0, 0x9B }, + { NULL, "otim", X_INH2, 0, 0x83 }, + { NULL, "otimr", X_INH2, 0, 0x93 }, + { NULL, "slp", X_INH2, 0, 0x76 }, + + { NULL, "in0", X_IN, 0, 0x00 }, + { NULL, "out0", X_OUT, 0, 0x01 }, + + { NULL, "mlt", X_MLT, 0, 0x4C }, + + { NULL, "tst", X_TST, 0, 0x04 }, + { NULL, "tstio", X_TSTIO, S_END, 0x7 } +#else /* GAMEBOY */ + { NULL, "stop", S_STOP, 0, 0x10 }, + { NULL, "swap", S_RL, 0, 0x30 }, + { NULL, "reti", S_INH1, 0, 0xD9 }, + { NULL, "ldh", S_LDH, 0, 0xE0 }, + { NULL, "lda", S_LDA, 0, 0xE8 }, + { NULL, "ldhl", S_LDHL, S_END, 0xF } +#endif /* GAMEBOY */ +}; diff --git a/link/clean.mk b/link/clean.mk new file mode 100644 index 00000000..27351ebf --- /dev/null +++ b/link/clean.mk @@ -0,0 +1,4 @@ +clean: + $(MAKE) -C z80 -f clean.mk clean + +distclean: clean diff --git a/link/sdccconf.h b/link/sdccconf.h new file mode 100644 index 00000000..8caf75b7 --- /dev/null +++ b/link/sdccconf.h @@ -0,0 +1,46 @@ +/* sdccconf.h. Generated automatically by configure. */ +/* + */ + +#ifndef SDCCCONF_HEADER +#define SDCCCONF_HEADER + + +#define SDCC_VERSION_HI 2 +#define SDCC_VERSION_LO 3 +#define SDCC_VERSION_P 1 +#define SDCC_VERSION_STR "2.3.1" + +#define PREFIX "/opt/gbdk" +#define DATADIR "/opt/gbdk/share/sdcc" +#define SRCDIR "/home/Zalo/Desktop/gb/gbdk-2020/sdcc" + +#define STANDARD_INCLUDE_DIR "/opt/gbdk/share/sdcc/include" +#define SDCC_INCLUDE_DIR "/opt/gbdk/share/sdcc/include" +#define SDCC_LIB_DIR "/opt/gbdk/share/sdcc/lib" +#define STD_LIB "libsdcc" +#define STD_INT_LIB "libint" +#define STD_LONG_LIB "liblong" +#define STD_FP_LIB "libfloat" +#define STD_DS390_LIB "libds390" +/* #undef HAVE_SYS_SOCKET_H */ +/* #undef HAVE_SYS_ISA_DEFS_H */ +/* #undef HAVE_ENDIAN_H */ +/* #undef HAVE_MACHINE_ENDIAN_H */ + +#define HAVE_STRERROR 1 + +#define OPT_DISABLE_MCS51 1 +#define OPT_DISABLE_GBZ80 0 +#define OPT_DISABLE_Z80 0 +#define OPT_DISABLE_AVR 1 +#define OPT_DISABLE_DS390 1 +#define OPT_DISABLE_PIC 1 +#define OPT_DISABLE_I186 1 +#define OPT_DISABLE_TLCS900H 1 + +#define OPT_ENABLE_LIBGC 0 + +#endif + +/* End of config.h */ diff --git a/link/support/Util/BuildCmd.c b/link/support/Util/BuildCmd.c new file mode 100644 index 00000000..2d0b051f --- /dev/null +++ b/link/support/Util/BuildCmd.c @@ -0,0 +1,90 @@ +/*------------------------------------------------------------------------- + BuildCmd - SDCC Support function + + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1999) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ + +/*! Build a command line with parameter substitution +*/ + +#include +#include + +void +buildCmdLine (char *into, const char **cmds, + const char *p1, const char *p2, + const char *p3, const char **list) +{ + const char *p, *from; + + *into = '\0'; + + while (*cmds) + { + from = *cmds; + cmds++; + + /* See if it has a '$' anywhere - if not, just copy */ + if ((p = strchr (from, '$'))) + { + strncat (into, from, p - from); + /* seperate it */ + strcat (into, " "); + from = p + 2; + p++; + switch (*p) + { + case '1': + if (p1) + strcat (into, p1); + break; + case '2': + if (p2) + strcat (into, p2); + break; + case '3': + if (p3) + strcat (into, p3); + break; + case 'l': + { + const char **tmp = list; + if (tmp) + { + while (*tmp) + { + strcat (into, *tmp); + strcat (into, " "); + tmp++; + } + } + break; + } + default: + assert (0); + } + } + strcat (into, from); // this includes the ".asm" from "$1.asm" + + strcat (into, " "); + } +} + diff --git a/link/support/Util/BuildCmd.h b/link/support/Util/BuildCmd.h new file mode 100644 index 00000000..0dc403e0 --- /dev/null +++ b/link/support/Util/BuildCmd.h @@ -0,0 +1,34 @@ +/*------------------------------------------------------------------------- + BuildCmd - SDCC Support function + + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1999) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ + +#if !defined(__BUILDCMD_H) + +#define __BUILDCMD_H + +void +buildCmdLine (char *into, const char **cmds, + const char *p1, const char *p2, + const char *p3, const char **list) ; + +#endif diff --git a/link/support/Util/MySystem.c b/link/support/Util/MySystem.c new file mode 100644 index 00000000..e18646b2 --- /dev/null +++ b/link/support/Util/MySystem.c @@ -0,0 +1,99 @@ +/*------------------------------------------------------------------------- + MySystem - SDCC Support function + + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1999) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ + +#include "common.h" +#include "newalloc.h" +#if defined(_MSC_VER) +#include +#else +#include +#endif + + +#if !defined(__BORLANDC__) && !defined(_MSC_VER) +#include +#else +// No unistd.h in Borland C++ +extern int access (const char *, int); +#define X_OK 1 +#endif + +/*! +Call an external program with arguements +*/ + +//char *ExePathList[]= {SRCDIR "/bin",PREFIX "/bin", NULL}; +char *ExePathList[] = {NULL, NULL}; /* First entry may be overwritten, so use two. */ + +int +my_system (const char *cmd) +{ + int argsStart, e, i = 0; + char *cmdLine = NULL; + + argsStart = strstr (cmd, " ") - cmd; + + // try to find the command in predefined path's + while (ExePathList[i]) + { + cmdLine = (char *) Safe_alloc (strlen (ExePathList[i]) + strlen (cmd) + 10); + strcpy (cmdLine, ExePathList[i]); // the path + + strcat (cmdLine, DIR_SEPARATOR_STRING); + strncat (cmdLine, cmd, argsStart); // the command + +#if NATIVE_WIN32 + strcat (cmdLine, ".exe"); +#endif + + if (access (cmdLine, X_OK) == 0) + { + // the arguments + strcat (cmdLine, cmd + argsStart); + break; + } + Safe_free (cmdLine); + cmdLine = NULL; + i++; + } + + if (verboseExec) + { + printf ("+ %s\n", cmdLine ? cmdLine : cmd); + } + + if (cmdLine) + { + // command found in predefined path + e = system (cmdLine); + Safe_free (cmdLine); + } + else + { + // trust on $PATH + e = system (cmd); + } + return e; +} + diff --git a/link/support/Util/MySystem.h b/link/support/Util/MySystem.h new file mode 100644 index 00000000..93eb07f2 --- /dev/null +++ b/link/support/Util/MySystem.h @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- + MySystem - SDCC Support function + + Written By - Sandeep Dutta . sandeep.dutta@usa.net (1999) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ + +#if !defined(__MYSYSTEM_H) +#define __MYSYSTEM_H + +int my_system (const char *cmd) ; + +extern char *ExePathList[] ; // List of paths to try to locate exeucatbles + +#endif diff --git a/link/support/Util/NewAlloc.c b/link/support/Util/NewAlloc.c new file mode 100644 index 00000000..d049260a --- /dev/null +++ b/link/support/Util/NewAlloc.c @@ -0,0 +1,275 @@ +/* +=============================================================================== +NEWALLOC - SDCC Memory allocation functions + +These functions are wrappers for the standard malloc, realloc and free +functions. + + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! + +=============================================================================== +*/ + +#include +#if defined(__APPLE__) && defined(__MACH__) +#include +#else +#include +#endif +#include +#include +#include +#include +#include "newalloc.h" +#include "sdccconf.h" + +#if OPT_ENABLE_LIBGC +#include + +#define MALLOC GC_malloc +#define REALLOC GC_realloc +/* PENDING: This is a mild hack. If we try to GC_free something + allocated with malloc() then the program will segfault. Might as + well drop it and let the garbase collector take care of things. +*/ +#define FREE(_a) + +#else + +#define MALLOC malloc +#define REALLOC realloc +#define FREE free + +#endif + +#define TRACEMALLOC 0 + +#if TRACEMALLOC +enum + { + TRACESIZE = 4096 + }; + +static int _allocs[TRACESIZE]; +static int _above; + +static void +_dumpTrace(int code, void *parg) +{ + int i; + for (i = 0; i < TRACESIZE; i++) + { + if (_allocs[i]) + { + printf("%u %u\n", _allocs[i], i); + } + } + printf("%u above\n", _above); +} + +static void +_log(int size) +{ + static int registered; + + if (registered == 0) + { + on_exit(_dumpTrace, NULL); + registered = 1; + } + if (size == 12) + { + _above++; + } + + if (size >= TRACESIZE) + { + _above++; + } + else + { + _allocs[size]++; + } +} +#endif + +/* +------------------------------------------------------------------------------- +Clear_realloc - Reallocate a memory block and clear any memory added with +out of memory error detection + +------------------------------------------------------------------------------- +*/ + +void *Clear_realloc(void *OldPtr,size_t OldSize,size_t NewSize) + +{ +void *NewPtr ; + +NewPtr = REALLOC(OldPtr,NewSize) ; + +if (!NewPtr) + { + printf("ERROR - No more memory\n") ; +/* werror(E_OUT_OF_MEM,__FILE__,NewSize);*/ + exit (1); + } + +if (NewPtr) + if (NewSize > OldSize) + memset((char *) NewPtr + OldSize,0x00,NewSize - OldSize) ; + +return NewPtr ; +} +/* +------------------------------------------------------------------------------- +Safe_realloc - Reallocate a memory block with out of memory error detection + +------------------------------------------------------------------------------- +*/ + +void *Safe_realloc(void *OldPtr,size_t NewSize) + +{ +void *NewPtr ; + +NewPtr = REALLOC(OldPtr,NewSize) ; + +if (!NewPtr) + { + printf("ERROR - No more memory\n") ; +/* werror(E_OUT_OF_MEM,__FILE__,NewSize);*/ + exit (1); + } + +return NewPtr ; +} +/* +------------------------------------------------------------------------------- +Safe_calloc - Allocate a block of memory from the application heap, clearing +all data to zero and checking for out of memory errors. + +------------------------------------------------------------------------------- +*/ + +void *Safe_calloc(size_t Elements,size_t Size) + +{ +void *NewPtr ; + +NewPtr = MALLOC(Elements*Size) ; +#if TRACEMALLOC + _log(Elements*Size); +#endif + +if (!NewPtr) + { + printf("ERROR - No more memory\n") ; +/* werror(E_OUT_OF_MEM,__FILE__,Size);*/ + exit (1); + } + + memset(NewPtr, 0, Elements*Size); + +return NewPtr ; +} +/* +------------------------------------------------------------------------------- +Safe_malloc - Allocate a block of memory from the application heap +and checking for out of memory errors. + +------------------------------------------------------------------------------- +*/ + +void *Safe_malloc(size_t Size) + +{ +void *NewPtr ; + +NewPtr = MALLOC(Size) ; + +#if TRACEMALLOC + _log(Size); +#endif + +if (!NewPtr) + { + printf("ERROR - No more memory\n") ; +/* werror(E_OUT_OF_MEM,__FILE__,Size);*/ + exit (1); + } + +return NewPtr ; +} + +void *Safe_alloc(size_t Size) +{ + return Safe_calloc(1, Size); +} + +void Safe_free(void *p) +{ + FREE(p); +} + +char *Safe_strdup(const char *sz) +{ + char *pret; + assert(sz); + + pret = Safe_alloc(strlen(sz) +1); + strcpy(pret, sz); + + return pret; +} + +void *traceAlloc(allocTrace *ptrace, void *p) +{ + assert(ptrace); + assert(p); + + /* Also handles where max == 0 */ + if (ptrace->num == ptrace->max) + { + /* Add an offset to handle max == 0 */ + ptrace->max = (ptrace->max+2)*2; + ptrace->palloced = Safe_realloc(ptrace->palloced, ptrace->max * sizeof(*ptrace->palloced)); + } + ptrace->palloced[ptrace->num++] = p; + + return p; +} + +void freeTrace(allocTrace *ptrace) +{ + int i; + assert(ptrace); + + for (i = 0; i < ptrace->num; i++) + { + Safe_free(ptrace->palloced[i]); + } + ptrace->num = 0; + + Safe_free(ptrace->palloced); + ptrace->palloced = NULL; + ptrace->max = 0; +} + diff --git a/link/support/Util/SDCCerr.c b/link/support/Util/SDCCerr.c new file mode 100644 index 00000000..605de30b --- /dev/null +++ b/link/support/Util/SDCCerr.c @@ -0,0 +1,463 @@ +/* + * SDCCerr - Standard error handler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include + +#include "SDCCerr.h" + + +#define USE_STDOUT_FOR_ERRORS 0 + +#if USE_STDOUT_FOR_ERRORS +#define DEFAULT_ERROR_OUT stdout +#else +#define DEFAULT_ERROR_OUT stderr +#endif + +static struct { + ERROR_LOG_LEVEL logLevel; + FILE *out; +} _SDCCERRG; + +extern char *filename ; +extern int lineno ; +extern int fatalError ; + +/* Currently the errIndex field must match the position of the + * entry in the array. It is only included in order to make + * human error lookup easier. + */ +struct +{ + int errIndex; + ERROR_LOG_LEVEL errType; + const char *errText; +} ErrTab [] = +{ +{ E_DUPLICATE, ERROR_LEVEL_ERROR, + "Duplicate symbol '%s', symbol IGNORED" }, +{ E_SYNTAX_ERROR, ERROR_LEVEL_ERROR, + "Syntax error, declaration ignored at '%s'" }, +{ E_CONST_EXPECTED, ERROR_LEVEL_ERROR, + "Constant Expected Found Variable" }, +{ E_OUT_OF_MEM, ERROR_LEVEL_ERROR, + "'malloc' failed file '%s' for size %ld" }, +{ E_FILE_OPEN_ERR, ERROR_LEVEL_ERROR, + "'fopen' failed on file '%s'" }, +{ E_INVALID_OCLASS, ERROR_LEVEL_ERROR, + "Internal Error Oclass invalid '%s'" }, +{ E_CANNOT_ALLOC, ERROR_LEVEL_ERROR, + "Cannot allocate variable '%s'." }, +{ E_OLD_STYLE, ERROR_LEVEL_ERROR, + "Old style C declaration. IGNORED '%s'" }, +{ E_STACK_OUT, ERROR_LEVEL_ERROR, + "Out of stack Space. '%s' not allocated" }, +{ E_INTERNAL_ERROR, ERROR_LEVEL_ERROR, + "FATAL Compiler Internal Error in file '%s' line number '%d' : %s \n" + "Contact Author with source code" }, +{ E_LVALUE_REQUIRED, ERROR_LEVEL_ERROR, + "'lvalue' required for '%s' operation ." }, +{ E_TMPFILE_FAILED, ERROR_LEVEL_ERROR, + "Creation of temp file failed" }, +{ E_FUNCTION_EXPECTED, ERROR_LEVEL_ERROR, + "called object is not a function" }, +{ E_USING_ERROR, ERROR_LEVEL_ERROR, + "'using', 'interrupt' or 'reentrant' must follow a function definiton .'%s'" }, +{ E_SFR_INIT, ERROR_LEVEL_ERROR, + "Absolute address & initial value both cannot be specified for\n" + " a 'sfr','sbit' storage class, initial value ignored '%s'" }, +{ W_INIT_IGNORED, ERROR_LEVEL_WARNING, + "Variable in the storage class cannot be initialized.'%s'" }, +{ E_AUTO_ASSUMED, ERROR_LEVEL_ERROR, + "storage class not allowed for automatic variable '%s' in reentrant function unless static" }, +{ E_AUTO_ABSA, ERROR_LEVEL_ERROR, + "absolute address not allowed for automatic var '%s' in reentrant function " }, +{ W_INIT_WRONG, ERROR_LEVEL_WARNING, + "Initializer different levels of indirections" }, +{ E_FUNC_REDEF, ERROR_LEVEL_ERROR, + "Function name '%s' redefined " }, +{ E_ID_UNDEF, ERROR_LEVEL_ERROR, + "Undefined identifier '%s'" }, +{ W_STACK_OVERFLOW, ERROR_LEVEL_WARNING, + "stack exceeds 256 bytes for function '%s'" }, +{ E_NEED_ARRAY_PTR, ERROR_LEVEL_ERROR, + "Array or pointer required for '%s' operation " }, +{ E_IDX_NOT_INT, ERROR_LEVEL_ERROR, + "Array index not an integer" }, +{ E_ARRAY_BOUND, ERROR_LEVEL_ERROR, + "Array bound Exceeded, assuming zero" }, +{ E_STRUCT_UNION, ERROR_LEVEL_ERROR, + "Structure/Union expected left of '.%s'" }, +{ E_NOT_MEMBER, ERROR_LEVEL_ERROR, + "'%s' not a structure/union member" }, +{ E_PTR_REQD, ERROR_LEVEL_ERROR, + "Pointer required" }, +{ E_UNARY_OP, ERROR_LEVEL_ERROR, + "'unary %c': illegal operand" }, +{ E_CONV_ERR, ERROR_LEVEL_ERROR, + "convertion error: integral promotion failed" }, +{ E_INT_REQD, ERROR_LEVEL_ERROR, + "type must be INT for bit field definition" }, +{ E_BITFLD_SIZE, ERROR_LEVEL_ERROR, + "bit field size greater than 16 . assuming 16" }, +{ W_TRUNCATION, ERROR_LEVEL_WARNING, + "high order truncation might occur" }, +{ E_CODE_WRITE, ERROR_LEVEL_ERROR, + "Attempt to assign value to a constant variable %s" }, +{ E_LVALUE_CONST, ERROR_LEVEL_ERROR, + "Lvalue specifies constant object" }, +{ E_ILLEGAL_ADDR, ERROR_LEVEL_ERROR, + "'&' illegal operand , %s" }, +{ E_CAST_ILLEGAL, ERROR_LEVEL_ERROR, + "illegal cast (cast cannot be aggregate)" }, +{ E_MULT_INTEGRAL, ERROR_LEVEL_ERROR, + "'*' bad operand" }, +{ E_ARG_ERROR, ERROR_LEVEL_ERROR, + "Argument count error, argument ignored" }, +{ E_ARG_COUNT, ERROR_LEVEL_ERROR, + "Function was expecting more arguments" }, +{ E_FUNC_EXPECTED, ERROR_LEVEL_ERROR, + "Function name expected '%s'.ANSI style declaration REQUIRED" }, +{ E_PLUS_INVALID, ERROR_LEVEL_ERROR, + "invalid operand '%s'" }, +{ E_PTR_PLUS_PTR, ERROR_LEVEL_ERROR, + "pointer + pointer invalid" }, +{ E_SHIFT_OP_INVALID, ERROR_LEVEL_ERROR, + "invalid operand for shift operator" }, +{ E_COMPARE_OP, ERROR_LEVEL_ERROR, + "compare operand cannot be struct/union" }, +{ E_BITWISE_OP, ERROR_LEVEL_ERROR, + "operand invalid for bitwise operation" }, +{ E_ANDOR_OP, ERROR_LEVEL_ERROR, + "Invalid operand for '&&' or '||'" }, +{ E_TYPE_MISMATCH, ERROR_LEVEL_ERROR, + "indirections to different types %s %s " }, +{ E_AGGR_ASSIGN, ERROR_LEVEL_ERROR, + "cannot assign values to aggregates" }, +{ E_ARRAY_DIRECT, ERROR_LEVEL_ERROR, + "bit Arrays can be accessed by literal index only" }, +{ E_BIT_ARRAY, ERROR_LEVEL_ERROR, + "Array or Pointer to bit|sbit|sfr not allowed.'%s'" }, +{ E_DUPLICATE_TYPEDEF, ERROR_LEVEL_ERROR, + "typedef/enum '%s' duplicate.Previous definiton Ignored" }, +{ E_ARG_TYPE, ERROR_LEVEL_ERROR, + "Actual Argument type different from declaration %d" }, +{ E_RET_VALUE, ERROR_LEVEL_ERROR, + "Function return value mismatch" }, +{ E_FUNC_AGGR, ERROR_LEVEL_ERROR, + "Function cannot return aggregate. Func body ignored" }, +{ E_FUNC_DEF, ERROR_LEVEL_ERROR, + "ANSI Style declaration needed" }, +{ E_DUPLICATE_LABEL, ERROR_LEVEL_ERROR, + "Label name redefined '%s'" }, +{ E_LABEL_UNDEF, ERROR_LEVEL_ERROR, + "Label undefined '%s'" }, +{ E_FUNC_VOID, ERROR_LEVEL_ERROR, + "void function returning value" }, +{ E_VOID_FUNC, ERROR_LEVEL_ERROR, + "function '%s' must return value" }, +{ W_RETURN_MISMATCH, ERROR_LEVEL_WARNING, + "function return value mismatch" }, +{ E_CASE_CONTEXT, ERROR_LEVEL_ERROR, + "'case/default' found without 'switch'.statement ignored" }, +{ E_CASE_CONSTANT, ERROR_LEVEL_ERROR, + "'case' expression not constant. statement ignored" }, +{ E_BREAK_CONTEXT, ERROR_LEVEL_ERROR, + "'break/continue' statement out of context" }, +{ E_SWITCH_AGGR, ERROR_LEVEL_ERROR, + "nonintegral used in switch expression" }, +{ E_FUNC_BODY, ERROR_LEVEL_ERROR, + "function '%s' already has body" }, +{ E_UNKNOWN_SIZE, ERROR_LEVEL_ERROR, + "attempt to allocate variable of unknown size '%s'" }, +{ E_AUTO_AGGR_INIT, ERROR_LEVEL_ERROR, + "aggregate 'auto' variable '%s' cannot be initialized" }, +{ E_INIT_COUNT, ERROR_LEVEL_ERROR, + "too many initializers" }, +{ E_INIT_STRUCT, ERROR_LEVEL_ERROR, + "struct/union/array '%s' :initialization needs curly braces" }, +{ E_INIT_NON_ADDR, ERROR_LEVEL_ERROR, + "non-address initialization expression" }, +{ E_INT_DEFINED, ERROR_LEVEL_ERROR, + "interrupt no '%d' already has a service routine '%s'" }, +{ E_INT_ARGS, ERROR_LEVEL_ERROR, + "interrupt routine cannot have arguments, arguments ingored" }, +{ E_INCLUDE_MISSING, ERROR_LEVEL_ERROR, + "critical compiler #include file missing. " }, +{ E_NO_MAIN, ERROR_LEVEL_ERROR, + "function 'main' undefined" }, +{ E_EXTERN_INIT, ERROR_LEVEL_ERROR, + "'extern' variable '%s' cannot be initialised " }, +{ E_PRE_PROC_FAILED, ERROR_LEVEL_ERROR, + "Pre-Processor %s" }, +{ E_DUP_FAILED, ERROR_LEVEL_ERROR, + "_dup call failed" }, +{ E_INCOMPAT_TYPES, ERROR_LEVEL_ERROR, + "incompatible types" }, +{ W_LOOP_ELIMINATE, ERROR_LEVEL_WARNING, + "'while' loop with 'zero' constant.loop eliminated" }, +{ W_NO_SIDE_EFFECTS, ERROR_LEVEL_WARNING, + "%s expression has NO side effects.expr eliminated" }, +{ W_CONST_TOO_LARGE, ERROR_LEVEL_PEDANTIC, + "constant value '%s', out of range." }, +{ W_BAD_COMPARE, ERROR_LEVEL_WARNING, + "comparison will either, ALWAYs succeed or ALWAYs fail" }, +{ E_TERMINATING, ERROR_LEVEL_ERROR, + "Compiler Terminating , contact author with source" }, +{ W_LOCAL_NOINIT, ERROR_LEVEL_WARNING, + "'auto' variable '%s' may be used before initialization at %s(%d)" }, +{ W_NO_REFERENCE, ERROR_LEVEL_WARNING, + "in function %s unreferenced %s : '%s'" }, +{ E_OP_UNKNOWN_SIZE, ERROR_LEVEL_ERROR, + "unknown size for operand" }, +{ W_LONG_UNSUPPORTED, ERROR_LEVEL_WARNING, + "'%s' 'long' not supported , declared as 'int' ." }, +{ E_LITERAL_GENERIC, ERROR_LEVEL_ERROR, + //"illegal cast of LITERAL value to 'generic' pointer: assuming 'xdata' pointer" }, + "illegal cast of LITERAL value to 'generic' pointer" }, +{ E_SFR_ADDR_RANGE, ERROR_LEVEL_ERROR, + "%s '%s' address out of range" }, +{ E_BITVAR_STORAGE, ERROR_LEVEL_ERROR, + "storage class CANNOT be specified for bit variable '%s'" }, +{ E_EXTERN_MISMATCH, ERROR_LEVEL_ERROR, + "extern definition for '%s' mismatches with declaration." }, +{ W_NONRENT_ARGS, ERROR_LEVEL_WARNING, + "Functions called via pointers must be 'reentrant' to take arguments" }, +{ W_DOUBLE_UNSUPPORTED, ERROR_LEVEL_WARNING, + "type 'double' not supported assuming 'float'" }, +{ W_IF_NEVER_TRUE, ERROR_LEVEL_WARNING, + "if-statement condition always false.if-statement not generated" }, +{ W_FUNC_NO_RETURN, ERROR_LEVEL_WARNING, + "no 'return' statement found for function '%s'" }, +{ W_PRE_PROC_WARNING, ERROR_LEVEL_WARNING, + "Pre-Processor %s" }, +{ W_STRUCT_AS_ARG, ERROR_LEVEL_WARNING, + "structure '%s' passed as function argument changed to pointer" }, +{ E_PREV_DEF_CONFLICT, ERROR_LEVEL_ERROR, + "conflict with previous definition of '%s' for attribute '%s'" }, +{ E_CODE_NO_INIT, ERROR_LEVEL_ERROR, + "variable '%s' declared in code space must have initialiser" }, +{ E_OPS_INTEGRAL, ERROR_LEVEL_ERROR, + "operands not integral for assignment operation" }, +{ E_TOO_MANY_PARMS, ERROR_LEVEL_ERROR, + "too many parameters " }, +{ E_TOO_FEW_PARMS, ERROR_LEVEL_ERROR, + "too few parameters" }, +{ E_FUNC_NO_CODE, ERROR_LEVEL_ERROR, + "code not generated for '%s' due to previous errors" }, +{ E_TYPE_MISMATCH_PARM, ERROR_LEVEL_ERROR, + "type mismatch for parameter number %d" }, +{ E_INVALID_FLOAT_CONST, ERROR_LEVEL_ERROR, + "invalid float constant '%s'" }, +{ E_INVALID_OP, ERROR_LEVEL_ERROR, + "invalid operand for '%s' operation" }, +{ E_SWITCH_NON_INTEGER, ERROR_LEVEL_ERROR, + "switch value not an integer" }, +{ E_CASE_NON_INTEGER, ERROR_LEVEL_ERROR, + "case label not an integer" }, +{ W_FUNC_TOO_LARGE, ERROR_LEVEL_WARNING, + "function '%s' too large for global optimization" }, +{ W_CONTROL_FLOW, ERROR_LEVEL_PEDANTIC, + "conditional flow changed by optimizer '%s(%d)':so said EVELYN the modified DOG" }, +{ W_PTR_TYPE_INVALID, ERROR_LEVEL_WARNING, + "invalid type specifier for pointer type specifier ignored" }, +{ W_IMPLICIT_FUNC, ERROR_LEVEL_WARNING, + "function '%s' implicit declaration" }, +{ W_CONTINUE, ERROR_LEVEL_WARNING, + "%s" }, +{ I_TOOMANY_SPILS, ERROR_LEVEL_INFO, + "extended by %d bytes for compiler temp(s) :in function '%s': %s " }, +{ W_UNKNOWN_PRAGMA, ERROR_LEVEL_WARNING, + "unknown or unsupported #pragma directive '%s'" }, +{ W_SHIFT_CHANGED, ERROR_LEVEL_PEDANTIC, + "%s shifting more than size of object changed to zero" }, +{ W_UNKNOWN_OPTION, ERROR_LEVEL_WARNING, + "unknown compiler option '%s' ignored" }, +{ W_UNSUPP_OPTION, ERROR_LEVEL_WARNING, + "option '%s' no longer supported '%s' " }, +{ W_UNKNOWN_FEXT, ERROR_LEVEL_WARNING, + "don't know what to do with file '%s'. file extension unsupported" }, +{ W_TOO_MANY_SRC, ERROR_LEVEL_WARNING, + "cannot compile more than one source file . file '%s' ignored" }, +{ I_CYCLOMATIC, ERROR_LEVEL_INFO, + "function '%s', # edges %d , # nodes %d , cyclomatic complexity %d" }, +{ E_DIVIDE_BY_ZERO, ERROR_LEVEL_ERROR, + "dividing by ZERO" }, +{ E_FUNC_BIT, ERROR_LEVEL_ERROR, + "function cannot return 'bit'" }, +{ E_CAST_ZERO, ERROR_LEVEL_ERROR, + "casting from to type 'void' is illegal" }, +{ W_CONST_RANGE, ERROR_LEVEL_WARNING, + "constant is out of range %s" }, +{ W_CODE_UNREACH, ERROR_LEVEL_PEDANTIC, + "unreachable code %s(%d)" }, +{ E_NONPTR2_GENPTR, ERROR_LEVEL_ERROR, + "non-pointer type cast to generic pointer" }, +{ W_POSSBUG, ERROR_LEVEL_WARNING, + "possible code generation error at line %d,\n" + " send source to sandeep.dutta@usa.net" }, +{ E_INCOMPAT_PTYPES, ERROR_LEVEL_WARNING, + "pointer types incompatible " }, +{ W_UNKNOWN_MODEL, ERROR_LEVEL_WARNING, + "unknown memory model at %s : %d" }, +{ E_UNKNOWN_TARGET, ERROR_LEVEL_ERROR, + "cannot generate code for target '%s'" }, +{ W_INDIR_BANKED, ERROR_LEVEL_WARNING, + "Indirect call to a banked function not implemented." }, +{ W_UNSUPPORTED_MODEL, ERROR_LEVEL_WARNING, + "Model '%s' not supported for %s, ignored." }, +{ W_BANKED_WITH_NONBANKED, ERROR_LEVEL_WARNING, + "Both banked and nonbanked attributes used. nonbanked wins." }, +{ W_BANKED_WITH_STATIC, ERROR_LEVEL_WARNING, + "Both banked and static used. static wins." }, +{ W_INT_TO_GEN_PTR_CAST, ERROR_LEVEL_WARNING, + "converting integer type to generic pointer: assuming XDATA" }, +{ W_ESC_SEQ_OOR_FOR_CHAR, ERROR_LEVEL_WARNING, + "escape sequence out of range for char." }, +{ E_INVALID_HEX, ERROR_LEVEL_ERROR, + "\\x used with no following hex digits." }, +{ W_FUNCPTR_IN_USING_ISR, ERROR_LEVEL_WARNING, + "call via function pointer in ISR using non-zero register bank.\n" + " Cannot determine which register bank to save." }, +{ E_NO_SUCH_BANK, ERROR_LEVEL_ERROR, + "called function uses unknown register bank %d." }, +{ E_TWO_OR_MORE_DATA_TYPES, ERROR_LEVEL_ERROR, + "two or more data types in declaration for '%s'" }, +{ E_LONG_OR_SHORT_INVALID, ERROR_LEVEL_ERROR, + "long or short specified for %s '%s'" }, +{ E_SIGNED_OR_UNSIGNED_INVALID, ERROR_LEVEL_ERROR, + "signed or unsigned specified for %s '%s'" }, +{ E_LONG_AND_SHORT_INVALID, ERROR_LEVEL_ERROR, + "both long and short specified for %s '%s'" }, +{ E_SIGNED_AND_UNSIGNED_INVALID, ERROR_LEVEL_ERROR, + "both signed and unsigned specified for %s '%s'" }, +{ E_TWO_OR_MORE_STORAGE_CLASSES, ERROR_LEVEL_ERROR, + "two or more storage classes in declaration for '%s'" }, +{ W_EXESS_ARRAY_INITIALIZERS, ERROR_LEVEL_WARNING, + "excess elements in array initializer after `%s' at line %d" }, +{ E_ARGUMENT_MISSING, ERROR_LEVEL_ERROR, + "Option %s requires an argument." }, +{ W_STRAY_BACKSLASH, ERROR_LEVEL_WARNING, + "stray '\\' at column %d" }, +{ W_NEWLINE_IN_STRING, ERROR_LEVEL_WARNING, + "newline in string constant" }, +{ E_CANNOT_USE_GENERIC_POINTER, ERROR_LEVEL_ERROR, + "cannot use generic pointer %s to initialize %s" }, +{ W_EXCESS_SHORT_OPTIONS, ERROR_LEVEL_WARNING, + "Only one short option can be specified at a time. Rest of %s ignored." }, +{ E_VOID_VALUE_USED, ERROR_LEVEL_ERROR, + "void value not ignored as it ought to be" }, +{ W_INTEGRAL2PTR_NOCAST, ERROR_LEVEL_WARNING, + "converting integral to pointer without a cast" }, +{ W_PTR2INTEGRAL_NOCAST, ERROR_LEVEL_WARNING, + "converting pointer to integral without a cast" }, +{ W_SYMBOL_NAME_TOO_LONG, ERROR_LEVEL_WARNING, + "symbol name too long, truncated to %d chars" }, +{ W_CAST_STRUCT_PTR,ERROR_LEVEL_WARNING, + "cast of struct %s * to struct %s * " } +}; + +/* +------------------------------------------------------------------------------- +SetErrorOut - Set the error output file + +------------------------------------------------------------------------------- +*/ + +FILE *SetErrorOut(FILE *NewErrorOut) + +{ + _SDCCERRG.out = NewErrorOut ; + +return NewErrorOut ; +} + +void +setErrorLogLevel (ERROR_LOG_LEVEL level) +{ + _SDCCERRG.logLevel = level; +} + +/* +------------------------------------------------------------------------------- +vwerror - Output a standard eror message with variable number of arguements + +------------------------------------------------------------------------------- +*/ + +void vwerror (int errNum, va_list marker) +{ + if (_SDCCERRG.out == NULL) { + _SDCCERRG.out = DEFAULT_ERROR_OUT; + } + + if (ErrTab[errNum].errIndex != errNum) + { + fprintf(_SDCCERRG.out, + "*** Internal error: error table entry for %d inconsistent.", errNum); + } + + + if (ErrTab[errNum].errType >= _SDCCERRG.logLevel) { + if ( ErrTab[errNum].errType == ERROR_LEVEL_ERROR ) + fatalError++ ; + + if ( filename && lineno ) { + fprintf(_SDCCERRG.out, "%s(%d):",filename,lineno); + } else if (lineno) { + fprintf(_SDCCERRG.out, "at %d:", lineno); + } + + switch(ErrTab[errNum].errType) + { + case ERROR_LEVEL_ERROR: + fprintf(_SDCCERRG.out, "error *** "); + break; + case ERROR_LEVEL_WARNING: + case ERROR_LEVEL_PEDANTIC: + fprintf(_SDCCERRG.out, "warning *** "); + break; + case ERROR_LEVEL_INFO: + fprintf(_SDCCERRG.out, "info *** "); + break; + default: + break; + } + + vfprintf(_SDCCERRG.out, ErrTab[errNum].errText,marker); + fprintf(_SDCCERRG.out, "\n"); + } + else { + // Below the logging level, drop. + } +} +/* +------------------------------------------------------------------------------- +werror - Output a standard eror message with variable number of arguements + +------------------------------------------------------------------------------- +*/ + +void werror (int errNum, ... ) +{ + va_list marker; + va_start(marker,errNum); + vwerror(errNum, marker); + va_end( marker ); +} + diff --git a/link/support/Util/SDCCerr.h b/link/support/Util/SDCCerr.h new file mode 100644 index 00000000..b9e3c22d --- /dev/null +++ b/link/support/Util/SDCCerr.h @@ -0,0 +1,231 @@ +/* +=============================================================================== +SDCCERR - SDCC Standard error handler + + +=============================================================================== +*/ + +#if !defined(__SDCCERR_H) + +#define __SDCCERR_H + +#include +#include + +/* ERROR Message Definition */ + +#define E_DUPLICATE 0 /* Duplicate variable */ +#define E_SYNTAX_ERROR 1 /* Syntax Error */ +#define E_CONST_EXPECTED 2 /* constant expected */ +#define E_OUT_OF_MEM 3 /* malloc failed */ +#define E_FILE_OPEN_ERR 4 /* File open failed */ +#define E_INVALID_OCLASS 5 /* output class invalid */ +#define E_CANNOT_ALLOC 6 /* cannot allocate space*/ +#define E_OLD_STYLE 7 /* old style C ! allowed*/ +#define E_STACK_OUT 8 /* v r out of stack */ +#define E_INTERNAL_ERROR 9 /* unable to alloc tvar */ +#define E_LVALUE_REQUIRED 10 /* lvalue required */ +#define E_TMPFILE_FAILED 11 /* tmpfile creation failed */ +#define E_FUNCTION_EXPECTED 12 /* function expected */ +#define E_USING_ERROR 13 /* using in error */ +#define E_SFR_INIT 14 /* init error for sbit */ +#define W_INIT_IGNORED 15 /* initialiser ignored */ +#define E_AUTO_ASSUMED 16 /* sclass auto assumed */ +#define E_AUTO_ABSA 17 /* abs addr for auto var*/ +#define W_INIT_WRONG 18 /* initializer type != */ +#define E_FUNC_REDEF 19 /* func name redefined */ +#define E_ID_UNDEF 20 /* identifer undefined */ +#define W_STACK_OVERFLOW 21 /* stack overflow */ +#define E_NEED_ARRAY_PTR 22 /* array or pointer reqd*/ +#define E_IDX_NOT_INT 23 /* index not an integer */ +#define E_ARRAY_BOUND 24 /* array limit exceeded */ +#define E_STRUCT_UNION 25 /* struct,union expected*/ +#define E_NOT_MEMBER 26 /* !struct/union member */ +#define E_PTR_REQD 27 /* pointer required */ +#define E_UNARY_OP 28 /* unary operator bad op*/ +#define E_CONV_ERR 29 /* conversion error */ +#define E_INT_REQD 30 /* bit field must be int*/ +#define E_BITFLD_SIZE 31 /* bit field size > 16 */ +#define W_TRUNCATION 32 /* high order trucation */ +#define E_CODE_WRITE 33 /* trying 2 write to code */ +#define E_LVALUE_CONST 34 /* lvalue is a const */ +#define E_ILLEGAL_ADDR 35 /* address of bit */ +#define E_CAST_ILLEGAL 36 /* cast illegal */ +#define E_MULT_INTEGRAL 37 /* mult opernd must b integral */ +#define E_ARG_ERROR 38 /* argument count error*/ +#define E_ARG_COUNT 39 /* func expecting more */ +#define E_FUNC_EXPECTED 40 /* func name expected */ +#define E_PLUS_INVALID 41 /* plus invalid */ +#define E_PTR_PLUS_PTR 42 /* pointer + pointer */ +#define E_SHIFT_OP_INVALID 43 /* shft op op invalid */ +#define E_COMPARE_OP 44 /* compare operand */ +#define E_BITWISE_OP 45 /* bit op invalid op */ +#define E_ANDOR_OP 46 /* && || op invalid */ +#define E_TYPE_MISMATCH 47 /* type mismatch */ +#define E_AGGR_ASSIGN 48 /* aggr assign */ +#define E_ARRAY_DIRECT 49 /* array indexing in */ +#define E_BIT_ARRAY 50 /* bit array not allowed */ +#define E_DUPLICATE_TYPEDEF 51 /* typedef name duplicate */ +#define E_ARG_TYPE 52 /* arg type mismatch */ +#define E_RET_VALUE 53 /* return value mismatch */ +#define E_FUNC_AGGR 54 /* function returing aggr */ +#define E_FUNC_DEF 55 /* ANSI Style def neede */ +#define E_DUPLICATE_LABEL 56 /* duplicate label name */ +#define E_LABEL_UNDEF 57 /* undefined label used */ +#define E_FUNC_VOID 58 /* void func ret value */ +#define E_VOID_FUNC 59 /* func must return value */ +#define W_RETURN_MISMATCH 60 /* return value mismatch */ +#define E_CASE_CONTEXT 61 /* case stmnt without switch */ +#define E_CASE_CONSTANT 62 /* case expression ! const*/ +#define E_BREAK_CONTEXT 63 /* break statement invalid*/ +#define E_SWITCH_AGGR 64 /* non integral for switch*/ +#define E_FUNC_BODY 65 /* func has body already */ +#define E_UNKNOWN_SIZE 66 /* variable has unknown size */ +#define E_AUTO_AGGR_INIT 67 /* auto aggregates no init */ +#define E_INIT_COUNT 68 /* too many initializers */ +#define E_INIT_STRUCT 69 /* struct init wrong */ +#define E_INIT_NON_ADDR 70 /* non address xpr for init */ +#define E_INT_DEFINED 71 /* interrupt already over */ +#define E_INT_ARGS 72 /* interrupt rtn cannot have args */ +#define E_INCLUDE_MISSING 73 /* compiler include missing */ +#define E_NO_MAIN 74 /* main function undefined */ +#define E_EXTERN_INIT 75 /* extern variable initialised */ +#define E_PRE_PROC_FAILED 76 /* preprocessor failed */ +#define E_DUP_FAILED 77 /* file DUP failed */ +#define E_INCOMPAT_TYPES 78 /* incompatible types casting */ +#define W_LOOP_ELIMINATE 79 /* loop eliminated */ +#define W_NO_SIDE_EFFECTS 80 /* expression has no side effects */ +#define W_CONST_TOO_LARGE 81 /* constant out of range */ +#define W_BAD_COMPARE 82 /* bad comparison */ +#define E_TERMINATING 83 /* compiler terminating */ +#define W_LOCAL_NOINIT 84 /* local reference before assignment */ +#define W_NO_REFERENCE 85 /* no reference to local variable */ +#define E_OP_UNKNOWN_SIZE 86 /* unknown size for operand */ +#define W_LONG_UNSUPPORTED 87 /* 'long' not supported yet */ +#define E_LITERAL_GENERIC 88 /* literal being cast to generic pointer */ +#define E_SFR_ADDR_RANGE 89 /* sfr address out of range */ +#define E_BITVAR_STORAGE 90 /* storage given for 'bit' variable */ +#define E_EXTERN_MISMATCH 91 /* extern declaration mismatches */ +#define W_NONRENT_ARGS 92 /* fptr non reentrant has args */ +#define W_DOUBLE_UNSUPPORTED 93 /* 'double' not supported yet */ +#define W_IF_NEVER_TRUE 94 /* if always false */ +#define W_FUNC_NO_RETURN 95 /* no return statement found */ +#define W_PRE_PROC_WARNING 96 /* preprocessor generated warning */ +#define W_STRUCT_AS_ARG 97 /* structure passed as argument */ +#define E_PREV_DEF_CONFLICT 98 /* previous definition conflicts with current */ +#define E_CODE_NO_INIT 99 /* vars in code space must have initializer */ +#define E_OPS_INTEGRAL 100 /* operans must be integral for certian assignments */ +#define E_TOO_MANY_PARMS 101 /* too many parameters */ +#define E_TOO_FEW_PARMS 102 /* to few parameters */ +#define E_FUNC_NO_CODE 103 /* fatalError */ +#define E_TYPE_MISMATCH_PARM 104 /* type mismatch for parameter */ +#define E_INVALID_FLOAT_CONST 105 /* invalid floating point literal string */ +#define E_INVALID_OP 106 /* invalid operand for some operation */ +#define E_SWITCH_NON_INTEGER 107 /* switch value not integer */ +#define E_CASE_NON_INTEGER 108 /* case value not integer */ +#define W_FUNC_TOO_LARGE 109 /* function too large */ +#define W_CONTROL_FLOW 110 /* control flow changed due to optimization */ +#define W_PTR_TYPE_INVALID 111 /* invalid type specifier for pointer */ +#define W_IMPLICIT_FUNC 112 /* function declared implicitly */ +#define W_CONTINUE 113 /* more than one line */ +#define I_TOOMANY_SPILS 114 /* too many spils occured */ +#define W_UNKNOWN_PRAGMA 115 /* #pragma directive unsupported */ +#define W_SHIFT_CHANGED 116 /* shift changed to zero */ +#define W_UNKNOWN_OPTION 117 /* don't know the option */ +#define W_UNSUPP_OPTION 118 /* processor reset has been redifned */ +#define W_UNKNOWN_FEXT 119 /* unknown file extension */ +#define W_TOO_MANY_SRC 120 /* can only compile one .c file at a time */ +#define I_CYCLOMATIC 121 /* information message */ +#define E_DIVIDE_BY_ZERO 122 /* / 0 */ +#define E_FUNC_BIT 123 /* function cannot return bit */ +#define E_CAST_ZERO 124 /* casting to from size zero */ +#define W_CONST_RANGE 125 /* constant too large */ +#define W_CODE_UNREACH 126 /* unreachable code */ +#define E_NONPTR2_GENPTR 127 /* non pointer cast to generic pointer */ +#define W_POSSBUG 128 /* possible code generation error */ +#define E_INCOMPAT_PTYPES 129 /* incampatible pointer assignment */ +#define W_UNKNOWN_MODEL 130 /* Unknown memory model */ +#define E_UNKNOWN_TARGET 131 /* target not defined */ +#define W_INDIR_BANKED 132 /* Indirect call to a banked fun */ +#define W_UNSUPPORTED_MODEL 133 /* Unsupported model, ignored */ +#define W_BANKED_WITH_NONBANKED 134 /* banked and nonbanked attributes mixed */ +#define W_BANKED_WITH_STATIC 135 /* banked and static mixed */ +#define W_INT_TO_GEN_PTR_CAST 136 /* Converting integer type to generic pointer. */ +#define W_ESC_SEQ_OOR_FOR_CHAR 137 /* Escape sequence of of range for char */ +#define E_INVALID_HEX 138 /* \x used with no following hex digits */ +#define W_FUNCPTR_IN_USING_ISR 139 /* Call via function pointer in ISR with using attribute. */ +#define E_NO_SUCH_BANK 140 /* 'using' attribute specifies non-existant register bank. */ +#define E_TWO_OR_MORE_DATA_TYPES 141 +#define E_LONG_OR_SHORT_INVALID 142 /* long or short invalid for .. */ +#define E_SIGNED_OR_UNSIGNED_INVALID 143 /* signed or unsigned invalid for .. */ +#define E_LONG_AND_SHORT_INVALID 144 /* long and short invalid for .. */ +#define E_SIGNED_AND_UNSIGNED_INVALID 145 /* signed and unsigned invalid for .. */ +#define E_TWO_OR_MORE_STORAGE_CLASSES 146 +#define W_EXESS_ARRAY_INITIALIZERS 147 /* too much initializers for array */ +#define E_ARGUMENT_MISSING 148 /* Option requires an argument. */ +#define W_STRAY_BACKSLASH 149 +#define W_NEWLINE_IN_STRING 150 +#define E_CANNOT_USE_GENERIC_POINTER 151 +#define W_EXCESS_SHORT_OPTIONS 152 +#define E_VOID_VALUE_USED 153 +#define W_INTEGRAL2PTR_NOCAST 154 +#define W_PTR2INTEGRAL_NOCAST 155 +#define W_SYMBOL_NAME_TOO_LONG 156 +#define W_CAST_STRUCT_PTR 157 /* pointer to different structure types */ + +/** Describes the maximum error level that will be logged. Any level + * includes all of the levels listed after it. + * + * + */ +enum _ERROR_LOG_LEVEL { + /** Everything. Currently the same as PEDANTIC. */ + ERROR_LEVEL_ALL, + /** All warnings, including those considered 'reasonable to use, + on occasion, in clean programs' (man 3 gcc). */ + ERROR_LEVEL_PEDANTIC, + /** 'informational' warnings */ + ERROR_LEVEL_INFO, + /** Most warnings. */ + ERROR_LEVEL_WARNING, + /** Errors only. */ + ERROR_LEVEL_ERROR +}; + +typedef enum _ERROR_LOG_LEVEL ERROR_LOG_LEVEL; + +/** Sets the maximum error level to log. + See MAX_ERROR_LEVEL. The default is ERROR_LEVEL_ALL. +*/ +void +setErrorLogLevel (ERROR_LOG_LEVEL level); + +/* +------------------------------------------------------------------------------- +SetErrorOut - Set the error output file + +------------------------------------------------------------------------------- +*/ + +FILE * SetErrorOut(FILE *NewErrorOut) ; + +/* +------------------------------------------------------------------------------- +vwerror - Output a standard eror message with variable number of arguements + +------------------------------------------------------------------------------- +*/ + +void vwerror (int errNum, va_list marker) ; + +/* +------------------------------------------------------------------------------- +werror - Output a standard eror message with variable number of arguements + +------------------------------------------------------------------------------- +*/ + +void werror (int errNum, ... ) ; + +#endif diff --git a/link/support/Util/newalloc.h b/link/support/Util/newalloc.h new file mode 100644 index 00000000..9e583c9d --- /dev/null +++ b/link/support/Util/newalloc.h @@ -0,0 +1,103 @@ +/* +=============================================================================== +NEWALLOC - SDCC Memory allocation functions + +These functions are wrappers for the standard malloc, realloc and free +functions. + + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! + +=============================================================================== +*/ + +#if !defined(_NewAlloc_H) + +#define _NewAlloc_H + +#include + +typedef struct _allocTrace +{ + int num; + int max; + void **palloced; +} allocTrace; + +/* +------------------------------------------------------------------------------- +Clear_realloc - Reallocate a memory block and clear any memory added with +out of memory error detection + +------------------------------------------------------------------------------- +*/ + +void *Clear_realloc(void *OldPtr,size_t OldSize,size_t NewSize) ; + +/* +------------------------------------------------------------------------------- +Safe_realloc - Reallocate a memory block with out of memory error detection + +------------------------------------------------------------------------------- +*/ + +void *Safe_realloc(void *OldPtr,size_t NewSize) ; + +/* +------------------------------------------------------------------------------- +Safe_calloc - Allocate a block of memory from the application heap, clearing +all data to zero and checking for out or memory errors. + +------------------------------------------------------------------------------- +*/ + +void *Safe_calloc(size_t Elements,size_t Size) ; + +/* +------------------------------------------------------------------------------- +Safe_malloc - Allocate a block of memory from the application heap +and checking for out or memory errors. + +------------------------------------------------------------------------------- +*/ + +void *Safe_malloc(size_t Size) ; + +/** Replacement for Safe_malloc that also zeros memory. To make it interchangable. + */ +void *Safe_alloc(size_t Size) ; + +/** Function to make the replacements complete. + */ +void Safe_free(void *p); + +/** Creates a copy of a string in a safe way. + */ +char *Safe_strdup(const char *sz); + +/** Logs the allocated memory 'p' in the given trace for batch freeing + later using freeTrace. +*/ +void *traceAlloc(allocTrace *ptrace, void *p); + +/** Frees all the memory logged in the trace and resets the trace. + */ +void freeTrace(allocTrace *ptrace); + +#endif diff --git a/link/z80/Makefile b/link/z80/Makefile new file mode 100644 index 00000000..cfa45115 --- /dev/null +++ b/link/z80/Makefile @@ -0,0 +1,47 @@ +PRJDIR = .. + +include $(PRJDIR)/Makefile.common + +OBJDIR = obj/$(EXT) + +SLIBSRC = NewAlloc.c + +SRC = lkarea.c lkdata.c lkeval.c lkhead.c lkihx.c lklex.c \ + lklibr.c lklist.c lkmain.c lkrloc.c lks19.c lksym.c \ + lkgb.c lkgg.c + +OBJS = $(SRC:%.c=$(OBJDIR)/%.o) +SLIBOBJS = $(SLIBSRC:%.c=$(OBJDIR)/%.o) + +BINS = $(BUILDDIR)link$(EXT) + +CFLAGS += $(CPPFLAGS) $(OPTS) -DINDEXLIB -DMLH_MAP -DUNIX -DSDK +CFLAGS += -funsigned-char -DUNIX +CFLAGS += -I$(PRJDIR)/as/$(PORT) -I$(SLIB) + +LDFLAGS += -lm $(EXTRALIBS) + +all: $(BINS) + +$(BINS): $(OBJDIR) $(BUILDDIR) $(OBJS) $(SLIBOBJS) + $(CC) -g -o $(BINS) $(OBJS) $(SLIBOBJS) $(LDFLAGS) + +$(OBJDIR): + mkdir -p $(OBJDIR) + +$(BUILDDIR): + mkdir -p $(BUILDDIR) + +$(OBJDIR)/%.o: %.c + $(CC) -c $(CFLAGS) -o $@ $< + +$(OBJDIR)/%.o: $(SLIB)/%.c + $(CC) -c $(CFLAGS) -o $@ $< + +_link-z80: + $(MAKE) EXT=-z80$(E) PORT=z80 + +_link-gbz80: + $(MAKE) EXT=-gbz80$(E) OPTS=-DGAMEBOY PORT=z80 + +include clean.mk diff --git a/link/z80/Makefile.in b/link/z80/Makefile.in new file mode 100644 index 00000000..ed966a28 --- /dev/null +++ b/link/z80/Makefile.in @@ -0,0 +1,104 @@ +# +# +# + +VERSION = @VERSION@ +VERSIONHI = @VERSIONHI@ +VERSIONLO = @VERSIONLO@ +VERSIONP = @VERSIONP@ + +SHELL = /bin/sh +CC = @CC@ +CPP = @CPP@ +INSTALL = @INSTALL@ + +PRJDIR = ../.. + +srcdir = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +libdir = @libdir@ +datadir = @datadir@ +includedir = @includedir@ +mandir = @mandir@ +man1dir = $(mandir)/man1 +man2dir = $(mandir)/man2 +infodir = @infodir@ + +SLIB =$(PRJDIR)/support/Util + +CPPFLAGS = @CPPFLAGS@ -I. -I$(PRJDIR) -I$(PRJDIR)/as/z80 -I$(SLIB) +CFLAGS = @CFLAGS@ -Wall -DINDEXLIB -DMLH_MAP -DUNIX -DSDK -DSDK_VERSION_STRING="\"3.0.0\"" -DTARGET_STRING="\"gbz80\"" -funsigned-char +M_OR_MM = @M_OR_MM@ +LDFLAGS = @LDFLAGS@ -lm + +SLIBOBJS = NewAlloc.o + +LKOBJECTS = lkarea.o lkdata.o lkeval.o lkhead.o lkihx.o lklex.o \ + lklibr.o lklist.o lkmain.o lkrloc.o lks19.o lksym.o \ + lkgb.o lkgg.o +LKSOURCES = $(patsubst %.o,%.c,$(LKOBJECTS)) + +LKZ80 = $(PRJDIR)/bin/link-z80 + +# Compiling entire program or any subproject +# ------------------------------------------ +all: checkconf $(LKZ80) + +$(LKZ80): $(SLIBOBJS) $(LKOBJECTS) + $(CC) $(CFLAGS) -o $@ $(SLIBOBJS) $(LKOBJECTS) $(LDFLAGS) + +# Compiling and installing everything and runing test +# --------------------------------------------------- +install: all installdirs + $(INSTALL) $(LKZ80) $(bindir)/link-z80 + +# Deleting all the installed files +# -------------------------------- +uninstall: + rm -f $(bindir)/link-z80 + + +# Performing self-test +# -------------------- +check: + + +# Performing installation test +# ---------------------------- +installcheck: + + +# Creating installation directories +# --------------------------------- +installdirs: + $(INSTALL) -d $(bindir) + + +# Creating dependencies +# --------------------- +dep: Makefile.dep + +Makefile.dep: $(LKSOURCES) *.h $(PRJDIR)/*.h + $(CPP) $(CPPFLAGS) $(M_OR_MM) $(LKSOURCES) >Makefile.dep + +include Makefile.dep +include clean.mk + +# My rules +# -------- +.c.o: + $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< + +$(SLIBOBJS):%.o:$(SLIB)/%.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ + +# Remaking configuration +# ---------------------- +checkconf: + @if [ -f $(PRJDIR)/devel ]; then\ + $(MAKE) -f conf.mk srcdir="$(srcdir)" PRJDIR="$(PRJDIR)" freshconf;\ + fi + +# End of Makefile diff --git a/link/z80/aslink.h b/link/z80/aslink.h new file mode 100644 index 00000000..da89f684 --- /dev/null +++ b/link/z80/aslink.h @@ -0,0 +1,720 @@ +/* aslink.h */ + +/* + * (C) Copyright 1989-1996 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +/* + * Extensions: P. Felber + */ +#include + +#define VERSION "V01.75" + +/* + * Case Sensitivity Flag + */ +#define CASE_SENSITIVE 0 + +/*)Module asmlnk.h + * + * The module asmlnk.h contains the definitions for constants, + * structures, global variables, and LKxxxx functions + * contained in the LKxxxx.c files. + */ + +/*)BUILD + $(PROGRAM) = ASLINK + $(INCLUDE) = ASLINK.H + $(FILES) = { + LKMAIN.C + LKLEX.C + LKAREA.C + LKHEAD.C + LKSYM.C + LKEVAL.C + LKDATA.C + LKLIST.C + LKRLOC.C + LKLIBR.C + LKS19.C + LKIHX.C + } + $(STACK) = 2000 +*/ + +/* DECUS C void definition */ +/* File/extension seperator */ + +#ifdef decus +#define VOID char +#define FSEPX '.' +#endif + +/* PDOS C void definition */ +/* File/extension seperator */ + +#ifdef PDOS +#define VOID char +#define FSEPX ':' +#endif + +/* Default void definition */ +/* File/extension seperator */ + +#ifndef VOID +#define VOID void +#define FSEPX '.' +#define OTHERSYSTEM +#endif + +/* + * This file defines the format of the + * relocatable binary file. + */ + +#ifdef SDK +#define NCPS 32 /* characters per symbol */ +#else /* SDK */ +#define NCPS 8 /* characters per symbol */ +#endif /* SDK */ +/* #define NCPS 32 */ /* characters per symbol */ +#define NDATA 16 /* actual data */ +#define NINPUT PATH_MAX /* Input buffer size */ +#define NHASH 64 /* Buckets in hash table */ +#define HMASK 077 /* Hash mask */ +#define NLPP 60 /* Lines per page */ +#define NTXT 16 /* T values */ +#define FILSPC PATH_MAX /* File spec length */ + +/* + * The "R_" relocation constants define values used in + * generating the assembler relocation output data for + * areas, symbols, and code. + * + * + * Relocation types. + * + * 7 6 5 4 3 2 1 0 + * +-----+-----+-----+-----+-----+-----+-----+-----+ + * | MSB | PAGn| PAG0| USGN| BYT2| PCR | SYM | BYT | + * +-----+-----+-----+-----+-----+-----+-----+-----+ + */ + +#define R_WORD 0x00 /* 16 bit */ +#define R_BYTE 0x01 /* 8 bit */ + +#define R_AREA 0x00 /* Base type */ +#define R_SYM 0x02 + +#define R_NORM 0x00 /* PC adjust */ +#define R_PCR 0x04 + +#define R_BYT1 0x00 /* Byte count for R_BYTE = 1 */ +#define R_BYT2 0x08 /* Byte count for R_BYTE = 2 */ + +#define R_SGND 0x00 /* Signed value */ +#define R_USGN 0x10 /* Unsigned value */ + +#define R_NOPAG 0x00 /* Page Mode */ +#define R_PAG0 0x20 /* Page '0' */ +#define R_PAG 0x40 /* Page 'nnn' */ + +/* + * Valid for R_BYT2: + */ +#define R_LSB 0x00 /* output low byte */ +#define R_MSB 0x80 /* output high byte */ + +/* + * Global symbol types. + */ +#define S_REF 1 /* referenced */ +#define S_DEF 2 /* defined */ + +/* + * Area types + */ +#define A_CON 000 /* concatenate */ +#define A_OVR 004 /* overlay */ +#define A_REL 000 /* relocatable */ +#define A_ABS 010 /* absolute */ +#define A_NOPAG 000 /* non-paged */ +#define A_PAG 020 /* paged */ + +/* + * File types + */ +#define F_INV 0 /* invalid */ +#define F_STD 1 /* stdin */ +#define F_LNK 2 /* File.lnk */ +#define F_REL 3 /* File.rel */ +#ifdef SDK +#define F_CMD 4 /* Command line */ +#endif /* SDK */ + +#ifdef GAMEBOY +/* + * Multiple banks support + */ +extern int nb_rom_banks; +extern int nb_ram_banks; +extern int current_rom_bank; +extern int mbc_type; +extern char cart_name[]; +/* + * ROM patching support + */ +typedef struct _patch { + unsigned int addr; + unsigned char value; + struct _patch *next; +} patch; +extern patch* patches; +#endif /* GAMEBOY */ +/* + * General assembler address type + */ +typedef unsigned int Addr_T; + +/* + * The structures of head, area, areax, and sym are created + * as the REL files are read during the first pass of the + * linker. The struct head is created upon encountering a + * H directive in the REL file. The structure contains a + * link to a link file structure (struct lfile) which describes + * the file containing the H directive, the number of data/code + * areas contained in this header segment, the number of + * symbols referenced/defined in this header segment, a pointer + * to an array of pointers to areax structures (struct areax) + * created as each A directive is read, and a pointer to an + * array of pointers to symbol structures (struct sym) for + * all referenced/defined symbols. As H directives are read + * from the REL files a linked list of head structures is + * created by placing a link to the new head structure + * in the previous head structure. + */ +struct head +{ + struct head *h_hp; /* Header link */ + struct lfile *h_lfile;/* Associated file */ + int h_narea; /* # of areas */ + struct areax **a_list; /* Area list */ + int h_nglob; /* # of global symbols */ + struct sym **s_list; /* Globle symbol list */ + char m_id[NCPS]; /* Module name */ +}; + +/* + * A structure area is created for each 'unique' data/code + * area definition found as the REL files are read. The + * struct area contains the name of the area, a flag byte + * which contains the area attributes (REL/CON/OVR/ABS), + * an area subtype (not used in this assembler), and the + * area base address and total size which will be filled + * in at the end of the first pass through the REL files. + * As A directives are read from the REL files a linked + * list of unique area structures is created by placing a + * link to the new area structure in the previous area structure. + */ +struct area +{ + struct area *a_ap; /* Area link */ + struct areax *a_axp; /* Area extension link */ + Addr_T a_addr; /* Beginning address of area */ + Addr_T a_size; /* Total size of the area */ + char a_type; /* Area subtype */ + char a_flag; /* Flag byte */ + char a_id[NCPS]; /* Name */ +}; + +/* + * An areax structure is created for every A directive found + * while reading the REL files. The struct areax contains a + * link to the 'unique' area structure referenced by the A + * directive and to the head structure this area segment is + * a part of. The size of this area segment as read from the + * A directive is placed in the areax structure. The beginning + * address of this segment will be filled in at the end of the + * first pass through the REL files. As A directives are read + * from the REL files a linked list of areax structures is + * created for each unique area. The final areax linked + * list has at its head the 'unique' area structure linked + * to the linked areax structures (one areax structure for + * each A directive for this area). + */ +struct areax +{ + struct areax *a_axp; /* Area extension link */ + struct area *a_bap; /* Base area link */ + struct head *a_bhp; /* Base header link */ + Addr_T a_addr; /* Beginning address of section */ + Addr_T a_size; /* Size of the area in section */ +}; + +/* + * A sym structure is created for every unique symbol + * referenced/defined while reading the REL files. The + * struct sym contains the symbol's name, a flag value + * (not used in this linker), a symbol type denoting + * referenced/defined, and an address which is loaded + * with the relative address within the area in which + * the symbol was defined. The sym structure also + * contains a link to the area where the symbol was defined. + * The sym structures are linked into linked lists using + * the symbol link element. + */ +struct sym +{ + struct sym *s_sp; /* Symbol link */ + struct areax *s_axp; /* Symbol area link */ + char s_type; /* Symbol subtype */ + char s_flag; /* Flag byte */ + Addr_T s_addr; /* Address */ + char s_id[NCPS]; /* Name */ +}; + +/* + * The structure lfile contains a pointer to a + * file specification string, the file type, and + * a link to the next lfile structure. + */ +struct lfile +{ + struct lfile *f_flp; /* lfile link */ + int f_type; /* File type */ + char *f_idp; /* Pointer to file spec */ +}; + +/* + * The struct base contains a pointer to a + * base definition string and a link to the next + * base structure. + */ +struct base +{ + struct base *b_base; /* Base link */ + char *b_strp; /* String pointer */ +}; + +/* + * The struct globl contains a pointer to a + * global definition string and a link to the next + * global structure. + */ +struct globl +{ + struct globl *g_globl; /* Global link */ + char *g_strp; /* String pointer */ +}; + +/* + * A structure sdp is created for each 'unique' paged + * area definition found as the REL files are read. + * As P directives are read from the REL files a linked + * list of unique sdp structures is created by placing a + * link to the new sdp structure in the previous area structure. + */ +struct sdp +{ + struct area *s_area; /* Paged Area link */ + struct areax *s_areax; /* Paged Area Extension Link */ + Addr_T s_addr; /* Page address offset */ +}; + +/* + * The structure rerr is loaded with the information + * required to report an error during the linking + * process. The structure contains an index value + * which selects the areax structure from the header + * areax structure list, a mode value which selects + * symbol or area relocation, the base address in the + * area section, an area/symbol list index value, and + * an area/symbol offset value. + */ +struct rerr +{ + int aindex; /* Linking area */ + int mode; /* Relocation mode */ + Addr_T rtbase; /* Base address in section */ + int rindex; /* Area/Symbol reloaction index */ + Addr_T rval; /* Area/Symbol offset value */ +}; + +/* + * The structure lbpath is created for each library + * path specification input by the -k option. The + * lbpath structures are linked into a list using + * the next link element. + */ +struct lbpath { + struct lbpath *next; + char *path; +}; + +/* + * The structure lbname is created for all combinations of the + * library path specifications (input by the -k option) and the + * library file specifications (input by the -l option) that + * lead to an existing file. The element path points to + * the path string, element libfil points to the library + * file string, and the element libspc is the concatenation + * of the valid path and libfil strings. + * + * The lbpath structures are linked into a list + * using the next link element. + * + * Each library file contains a list of object files + * that are contained in the particular library. e.g.: + * + * \iolib\termio + * \inilib\termio + * + * Only one specification per line is allowed. + */ +struct lbname { + struct lbname *next; + char *path; + char *libfil; + char *libspc; +}; + +/* + * The function fndsym() searches through all combinations of the + * library path specifications (input by the -k option) and the + * library file specifications (input by the -l option) that + * lead to an existing file for a symbol definition. + * + * The structure lbfile is created for the first library + * object file which contains the definition for the + * specified undefined symbol. + * + * The element libspc points to the library file path specification + * and element relfil points to the object file specification string. + * The element filspc is the complete path/file specification for + * the library file to be imported into the linker. The + * file specicifation may be formed in one of two ways: + * + * (1) If the library file contained an absolute + * path/file specification then this becomes filspc. + * (i.e. C:\...) + * + * (2) If the library file contains a relative path/file + * specification then the concatenation of the path + * and this file specification becomes filspc. + * (i.e. \...) + * + * The lbpath structures are linked into a list + * using the next link element. + */ +struct lbfile { + struct lbfile *next; + char *libspc; + char *relfil; + char *filspc; +}; + +/* + * External Definitions for all Global Variables + */ + +extern char *_abs_; /* = { ". .ABS." }; + */ +extern int lkerr; /* ASLink error flag + */ +extern char *ip; /* pointer into the REL file + * text line in ib[] + */ +extern char ib[NINPUT]; /* REL file text line + */ +extern char *rp; /* pointer into the LST file + * text line in rb[] + */ +extern char rb[NINPUT]; /* LST file text line being + * address relocated + */ +extern char ctype[]; /* array of character types, one per + * ASCII character + */ + +/* + * Character Type Definitions + */ +#define SPACE 0000 +#define ETC 0000 +#define LETTER 0001 +#define DIGIT 0002 +#define BINOP 0004 +#define RAD2 0010 +#define RAD8 0020 +#define RAD10 0040 +#define RAD16 0100 +#define ILL 0200 + +#define DGT2 DIGIT|RAD16|RAD10|RAD8|RAD2 +#define DGT8 DIGIT|RAD16|RAD10|RAD8 +#define DGT10 DIGIT|RAD16|RAD10 +#define LTR16 LETTER|RAD16 + +#if CASE_SENSITIVE +#else +extern char ccase[]; /* an array of characters which + * perform the case translation function + */ +#endif + +extern struct lfile *filep; /* The pointers (lfile *) filep, + * (lfile *) cfp, and (FILE *) sfp + * are used in conjunction with + * the routine getLine_() to read + * asmlnk commands from + * (1) the standard input or + * (2) or a command file + * and to read the REL files + * sequentially as defined by the + * asmlnk input commands. + * + * The pointer *filep points to the + * beginning of a linked list of + * lfile structures. + */ +extern struct lfile *cfp; /* The pointer *cfp points to the + * current lfile structure + */ +extern struct lfile *startp;/* asmlnk startup file structure + */ +extern struct lfile *linkp; /* pointer to first lfile structure + * containing an input REL file + * specification + */ +extern struct lfile *lfp; /* pointer to current lfile structure + * being processed by parse() + */ +extern struct head *headp; /* The pointer to the first + * head structure of a linked list + */ +extern struct head *hp; /* Pointer to the current + * head structure + */ +extern struct area *areap; /* The pointer to the first + * area structure of a linked list + */ +extern struct area *ap; /* Pointer to the current + * area structure + */ +extern struct areax *axp; /* Pointer to the current + * areax structure + */ +extern struct sym *symhash[NHASH]; /* array of pointers to NHASH + * linked symbol lists + */ +extern struct base *basep; /* The pointer to the first + * base structure + */ +extern struct base *bsp; /* Pointer to the current + * base structure + */ +extern struct globl *globlp;/* The pointer to the first + * globl structure + */ +extern struct globl *gsp; /* Pointer to the current + * globl structure + */ +extern struct sdp sdp; /* Base Paged structure + */ +extern struct rerr rerr; /* Structure containing the + * linker error information + */ +extern FILE *ofp; /* Linker Output file handle + */ +extern FILE *mfp; /* Map output file handle + */ +extern FILE *rfp; /* File handle for output + * address relocated ASxxxx + * listing file + */ +extern FILE *sfp; /* The file handle sfp points to the + * currently open file + */ +extern FILE *tfp; /* File handle for input + * ASxxxx listing file + */ +extern int oflag; /* Output file type flag + */ +extern int mflag; /* Map output flag + */ +#ifdef SDK +extern int symflag; /* no$gmb .sym output flag + */ +#endif +extern int xflag; /* Map file radix type flag + */ +extern int pflag; /* print linker command file flag + */ +extern int uflag; /* Listing relocation flag + */ +extern int radix; /* current number conversion radix: + * 2 (binary), 8 (octal), 10 (decimal), + * 16 (hexadecimal) + */ +extern int line; /* current line number + */ +extern int page; /* current page number + */ +extern int lop; /* current line number on page + */ +extern int pass; /* linker pass number + */ +extern int rtcnt; /* count of elements in the + * rtval[] and rtflg[] arrays + */ +extern Addr_T rtval[]; /* data associated with relocation + */ +extern int rtflg[]; /* indicates if rtval[] value is + * to be sent to the output file. + * (always set in this linker) + */ +extern int hilo; /* REL file byte ordering + */ +extern int gline; /* LST file relocation active + * for current line + */ +extern int gcntr; /* LST file relocation active + * counter + */ +extern struct lbpath *lbphead; /* pointer to the first + * library path structure + */ +extern struct lbname *lbnhead; /* pointer to the first + * library name structure + */ +extern struct lbfile *lbfhead; /* pointer to the first + * library file structure + */ + +/* C Library function definitions */ +/* for reference only +extern VOID exit(); +extern int fclose(); +extern char * fgets(); +extern FILE * fopen(); +extern int fprintf(); +extern VOID free(); +extern VOID * malloc(); +extern char putc(); +extern char * strcpy(); +extern int strlen(); +extern char * strncpy(); +*/ + +/* Program function definitions */ + +/* lkmain.c */ +extern FILE * afile(); +extern VOID bassav(); +extern VOID gblsav(); +extern VOID link(); +extern VOID lkexit(); +extern int main(); +extern VOID map(); +#ifdef SDK +extern VOID sym(); +#endif +extern int parse(); +extern VOID setbas(); +extern VOID setgbl(); +extern VOID usage(); + +/* lklex.c */ +extern char endline(); +extern char get(); +extern VOID getfid(); +extern VOID getid(); +extern int getLine_(); +extern int getmap(); +extern char getnb(); +extern int more(); +extern VOID skip(); +extern VOID unget(); + +/* lkarea.c */ +extern VOID lkparea(); +extern VOID lnkarea(); +extern VOID lnksect(); +extern VOID newarea(); + +/* lkhead.c */ +extern VOID module(); +extern VOID newhead(); + +/* lksym.c */ +extern int hash(); +extern struct sym * lkpsym(); +extern VOID * new(); +extern struct sym * newsym(); +extern VOID symdef(); +extern int symeq(); +extern VOID syminit(); +extern VOID symmod(); +extern Addr_T symval(); + +/* lkeval.c */ +extern int digit(); +extern Addr_T eval(); +extern Addr_T expr(); +extern int oprio(); +extern Addr_T term(); + +/* lklist.c */ +extern int dgt(); +extern VOID lkulist(); +extern VOID lkalist(); +extern VOID lkglist(); +extern VOID lstarea(); +extern VOID newpag(); +extern VOID slew(); + +/* lkrloc.c */ +extern Addr_T adb_b(); +extern Addr_T adb_hi(); +extern Addr_T adb_lo(); +extern Addr_T adw_w(); +extern Addr_T adw_hi(); +extern Addr_T adw_lo(); +extern Addr_T evword(); +extern VOID rele(); +extern VOID reloc(); +extern VOID relt(); +extern VOID relr(); +extern VOID relp(); +extern VOID relerr(); +extern char * errmsg[]; +extern VOID errdmp(); +extern VOID relerp(); +extern VOID erpdmp(); +extern VOID prntval(); + +/* lklibr.c */ +extern VOID addfile(); +extern VOID addlib(); +extern VOID addpath(); +extern int fndsym(); +extern VOID library(); +extern VOID loadfile(); +extern VOID search(); + +/* lks19.c */ +extern VOID s19(); + +/* lkihx.c */ +extern VOID ihx(); + +/* lkgb.h */ +VOID gb(int in); +VOID gg(int in); + diff --git a/link/z80/clean.mk b/link/z80/clean.mk new file mode 100644 index 00000000..8394c52a --- /dev/null +++ b/link/z80/clean.mk @@ -0,0 +1,22 @@ +# Deleting all files created by building the program +# -------------------------------------------------- +clean: + rm -f *core *[%~] *.[oa] + rm -f .[a-z]*~ + rm -f $(PRJDIR)/link-z80 link-z80 + rm -f *.dep + rm -rf obj + +# Deleting all files created by configuring or building the program +# ----------------------------------------------------------------- +distclean: clean + + +# Like clean but some files may still exist +# ----------------------------------------- +mostlyclean: clean + +# Deleting everything that can reconstructed by this Makefile. It deletes +# everything deleted by distclean plus files created by bison, etc. +# ----------------------------------------------------------------------- +realclean: distclean diff --git a/link/z80/conf.mk b/link/z80/conf.mk new file mode 100644 index 00000000..1ce49560 --- /dev/null +++ b/link/z80/conf.mk @@ -0,0 +1,23 @@ +# Deleting all files created by building the program +# -------------------------------------------------- +clean: + rm -f *core *[%~] *.[oa] + rm -f .[a-z]*~ + rm -f $(PRJDIR)/link-z80 link-z80 + + +# Deleting all files created by configuring or building the program +# ----------------------------------------------------------------- +distclean: clean + rm -f Makefile *.dep + + +# Like clean but some files may still exist +# ----------------------------------------- +mostlyclean: clean + + +# Deleting everything that can reconstructed by this Makefile. It deletes +# everything deleted by distclean plus files created by bison, etc. +# ----------------------------------------------------------------------- +realclean: distclean diff --git a/link/z80/lkarea.c b/link/z80/lkarea.c new file mode 100644 index 00000000..deb61c99 --- /dev/null +++ b/link/z80/lkarea.c @@ -0,0 +1,430 @@ +/* lkarea.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +#include +#include +#include "aslink.h" + +/*)Module lkarea.c + * + * The module lkarea.c contains the functions which + * create and link together all area definitions read + * from the .rel file(s). + * + * lkarea.c contains the following functions: + * VOID lnkarea() + * VOID lnksect() + * VOID lkparea() + * VOID newarea() + * + * lkarea.c contains no global variables. + */ + +/*)Function VOID newarea() + * + * The function newarea() creates and/or modifies area + * and areax structures for each A directive read from + * the .rel file(s). The function lkparea() is called + * to find tha area structure associated with this name. + * If the area does not yet exist then a new area + * structure is created and linked to any existing + * linked area structures. The area flags are copied + * into the area flag variable. For each occurence of + * an A directive an areax structure is created and + * linked to the areax structures associated with this + * area. The size of this area section is placed into + * the areax structure. The flag value for all subsequent + * area definitions for the same area are compared and + * flagged as an error if they are not identical. + * The areax structure created for every occurence of + * an A directive is loaded with a pointer to the base + * area structure and a pointer to the associated + * head structure. And finally, a pointer to this + * areax structure is loaded into the list of areax + * structures in the head structure. Refer to lkdata.c + * for details of the structures and their linkage. + * + * local variables: + * areax **halp pointer to an array of pointers + * int i counter, loop variable, value + * char id[] id string + * int narea number of areas in this head structure + * areax * taxp pointer to an areax structure + * to areax structures + * + * global variables: + * area *ap Pointer to the current + * area structure + * areax *axp Pointer to the current + * areax structure + * head *hp Pointer to the current + * head structure + * int lkerr error flag + * + * functions called: + * Addr_T eval() lkeval.c + * VOID exit() c_library + * int fprintf() c_library + * VOID getid() lklex.c + * VOID lkparea() lkarea.c + * VOID skip() lklex.c + * + * side effects: + * The area and areax structures are created and + * linked with the appropriate head structures. + * Failure to allocate area or areax structure + * space will terminate the linker. Other internal + * errors most likely caused by corrupted .rel + * files will also terminate the linker. + */ + +/* + * Create an area entry. + * + * A xxxxxx size nnnn flags mm + * | | | + * | | `-- ap->a_flag + * | `------------- axp->a_size + * `------------------------- ap->a_id + * + */ +VOID +newarea() +{ + register int i, narea; + struct areax *taxp; + struct areax **halp; + char id[NCPS]; + + /* + * Create Area entry + */ + getid(id, -1); + lkparea(id); + /* + * Evaluate area size + */ + skip(-1); + axp->a_size = eval(); + /* + * Evaluate flags + */ + skip(-1); + i = 0; + taxp = ap->a_axp; + while (taxp->a_axp) { + ++i; + taxp = taxp->a_axp; + } + if (i == 0) { + ap->a_flag = eval(); + } else { + i = eval(); + if (i && (ap->a_flag != i)) { + fprintf(stderr, "Conflicting flags in area %.8s\n", id); + lkerr++; + } + } + /* + * Place pointer in header area list + */ + if (headp == NULL) { + fprintf(stderr, "No header defined\n"); + lkexit(1); + } + narea = hp->h_narea; + halp = hp->a_list; + for (i=0; i < narea ;++i) { + if (halp[i] == NULL) { + halp[i] = taxp; + return; + } + } + fprintf(stderr, "Header area list overflow\n"); + lkexit(1); +} + +/*)Function VOID lkparea(id) + * + * char * id pointer to the area name string + * + * The function lkparea() searches the linked area structures + * for a name match. If the name is not found then an area + * structure is created. An areax structure is created and + * appended to the areax structures linked to the area structure. + * The associated base area and head structure pointers are + * loaded into the areax structure. + * + * local variables: + * area * tap pointer to an area structure + * areax * taxp pointer to an areax structure + * + * global variables: + * area *ap Pointer to the current + * area structure + * area *areap The pointer to the first + * area structure of a linked list + * areax *axp Pointer to the current + * areax structure + * + * functions called: + * VOID * new() lksym() + * char * strcpy() c_library + * int symeq() lksym.c + * + * side effects: + * Area and/or areax structures are created. + * Failure to allocate space for created structures + * will terminate the linker. + */ + +VOID +lkparea(id) +char *id; +{ + register struct area *tap; + register struct areax *taxp; + + ap = areap; + axp = (struct areax *) new (sizeof(struct areax)); + while (ap) { + if (symeq(id, ap->a_id)) { + taxp = ap->a_axp; + while (taxp->a_axp) + taxp = taxp->a_axp; + taxp->a_axp = axp; + axp->a_bap = ap; + axp->a_bhp = hp; + return; + } + ap = ap->a_ap; + } + ap = (struct area *) new (sizeof(struct area)); + if (areap == NULL) { + areap = ap; + } else { + tap = areap; + while (tap->a_ap) + tap = tap->a_ap; + tap->a_ap = ap; + } + ap->a_axp = axp; + axp->a_bap = ap; + axp->a_bhp = hp; + strncpy(ap->a_id, id, NCPS); +} + +/*)Function VOID lnkarea() + * + * The function lnkarea() resolves all area addresses. + * The function evaluates each area structure (and all + * the associated areax structures) in sequence. The + * linking process supports four (4) possible area types: + * + * ABS/OVR - All sections (each individual areax + * section) starts at the identical base + * area address overlaying all other + * areax sections for this area. The + * size of the area is largest of the area + * sections. + * + * ABS/CON - All sections (each individual areax + * section) are concatenated with the + * first section starting at the base + * area address. The size of the area + * is the sum of the section sizes. + * + * NOTE: Multiple absolute (ABS) areas are + * never concatenated with each other, + * thus absolute area A and absolute area + * B will overlay each other if they begin + * at the same location (the default is + * always address 0 for absolute areas). + * + * REL/OVR - All sections (each individual areax + * section) starts at the identical base + * area address overlaying all other + * areax sections for this area. The + * size of the area is largest of the area + * sections. + * + * REL/CON - All sections (each individual areax + * section) are concatenated with the + * first section starting at the base + * area address. The size of the area + * is the sum of the section sizes. + * + * NOTE: Relocatable (REL) areas ae always concatenated + * with each other, thus relocatable area B + * (defined after area A) will follow + * relocatable area A independent of the + * starting address of area A. Within a + * specific area each areax section may be + * overlayed or concatenated with other + * areax sections. + * + * + * If a base address for an area is specified then the + * area will start at that address. Any relocatable + * areas defined subsequently will be concatenated to the + * previous relocatable area if it does not have a base + * address specified. + * + * The names s_ and l_ are created to + * define the starting address and length of each area. + * + * local variables: + * Addr_T rloc ;current relocation address + * char temp[] ;temporary string + * struct symbol *sp ;symbol structure + * + * global variables: + * area *ap Pointer to the current + * area structure + * area *areap The pointer to the first + * area structure of a linked list + * + * functions called: + * int fprintf() c_library + * VOID lnksect() lkarea.c + * symbol *lkpsym() lksysm.c + * char * strncpy() c_library + * int symeq() lksysm.c + * + * side effects: + * All area and areax addresses and sizes are + * determined and saved in their respective + * structures. + */ + +/* + * Resolve all area addresses. + */ +VOID +lnkarea() +{ + register int rloc; + char temp[NCPS]; + struct sym *sp; + + rloc = 0; + ap = areap; + while (ap) { + if (ap->a_flag&A_ABS) { + /* + * Absolute sections + */ + lnksect(ap); + } else { + /* + * Relocatable sections + */ + if (ap->a_addr == 0) + ap->a_addr = rloc; + lnksect(ap); + rloc = ap->a_addr + ap->a_size; + } + + /* + * Create symbols called: + * s_ the start address of the area + * l_ the length of the area + */ + + if (! symeq(ap->a_id, _abs_)) { + strncpy(temp+2,ap->a_id,NCPS-2); + *(temp+1) = '_'; + + *temp = 's'; + sp = lkpsym(temp, 1); + sp->s_addr = ap->a_addr; + sp->s_axp = NULL; + sp->s_type |= S_DEF; + + *temp = 'l'; + sp = lkpsym(temp, 1); + sp->s_addr = ap->a_size; + sp->s_axp = NULL; + sp->s_type |= S_DEF; + } + ap = ap->a_ap; + } +} + +/*)Function VOID lnksect() + * + * area * tap pointer to an area structure + * + * The function lnksect() is the function called by + * lnkarea() to resolve the areax addresses. Refer + * to the function lnkarea() for more detail. Pageing + * boundary and length errors will be reported by this + * function. + * + * local variables: + * Addr_T size size of area + * Addr_T addr address of area + * areax * taxp pointer to an areax structure + * + * global variables: + * int lkerr error flag + * + * functions called: + * none + * + * side effects: + * All area and areax addresses and sizes area determined + * and linked into the structures. + */ + +VOID +lnksect(tap) +register struct area *tap; +{ + register Addr_T size, addr; + register struct areax *taxp; + + size = 0; + addr = tap->a_addr; + if ((tap->a_flag&A_PAG) && (addr & 0xFF)) { + fprintf(stderr, + "\n?ASlink-Warning-Paged Area %.8s Boundary Error\n", tap->a_id); + lkerr++; + } + taxp = tap->a_axp; + if (tap->a_flag&A_OVR) { + /* + * Overlayed sections + */ + while (taxp) { + taxp->a_addr = addr; + if (taxp->a_size > size) + size = taxp->a_size; + taxp = taxp->a_axp; + } + } else { + /* + * Concatenated sections + */ + while (taxp) { + taxp->a_addr = addr; + addr += taxp->a_size; + size += taxp->a_size; + taxp = taxp->a_axp; + } + } + tap->a_size = size; + if ((tap->a_flag&A_PAG) && (size > 256)) { + fprintf(stderr, + "\n?ASlink-Warning-Paged Area %.8s Length Error\n", tap->a_id); + lkerr++; + } +} diff --git a/link/z80/lkdata.c b/link/z80/lkdata.c new file mode 100644 index 00000000..5dc6369d --- /dev/null +++ b/link/z80/lkdata.c @@ -0,0 +1,465 @@ +/* lkdata.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +#include +#include +//#include +#include "aslink.h" + +/*)Module lkdata.c + * + * The module lkdata contains the global variables + * and structures used in the linker aslink. + */ + +/* + * Definitions for all Global Variables + */ + +char *_abs_ = { ". .ABS." }; + +int lkerr; /* Linker error flag + */ +char *ip; /* Pointer into the REL file text line in ib[] + */ +char ib[NINPUT]; /* REL file text line + */ +char *rp; /* pointer into the LST file + * text line in rb[] + */ +char rb[NINPUT]; /* LST file text line being + * address relocated + */ +int oflag; /* Output file type flag + */ +int mflag; /* Map output flag + */ +#ifdef SDK +int symflag; /* no$gmb .sym output flag + */ +#endif +int xflag; /* Map file radix type flag + */ +int pflag; /* print linker command file flag + */ +int uflag; /* Listing relocation flag + */ +int radix; /* current number conversion radix: + * 2 (binary), 8 (octal), 10 (decimal), + * 16 (hexadecimal) + */ +int line; /* current line number + */ +int page; /* current page number + */ +int lop; /* current line number on page + */ +int pass; /* linker pass number + */ +int rtcnt; /* count of elements in the + * rtval[] and rtflg[] arrays + */ +Addr_T rtval[NTXT]; /* data associated with relocation + */ +int rtflg[NTXT]; /* indicates if rtval[] value is + * to be sent to the output file. + * (always set in this linker) + */ +int hilo; /* REL file byte ordering + */ +int gline; /* LST file relocation active + * for current line + */ +int gcntr; /* LST file relocation active + * counter + */ + +/* + * The structure lfile contains a pointer to a + * file specification string, the file type, and + * a link to the next lfile structure. + * + * struct lfile + * { + * struct lfile *f_flp; lfile link + * int f_type; File type + * char *f_idp; Pointer to file spec + * }; + */ +struct lfile *filep; /* The pointers (lfile *) filep, + * (lfile *) cfp, and (FILE *) sfp + * are used in conjunction with + * the routine getLine_() to read + * asmlnk commands from + * (1) the standard input or + * (2) or a command file + * and to read the REL files + * sequentially as defined by the + * asmlnk input commands. + * + * The pointer *filep points to the + * beginning of a linked list of + * lfile structures. + */ +struct lfile *cfp; /* The pointer *cfp points to the + * current lfile structure + */ +struct lfile *startp;/* asmlnk startup file structure + */ +struct lfile *linkp; /* pointer to first lfile structure + * containing an input REL file + * specification + */ +struct lfile *lfp; /* pointer to current lfile structure + * being processed by parse() + */ +FILE *ofp; /* Output file handle + * for word formats + */ +FILE *mfp; /* Map output file handle + */ +FILE *rfp; /* File handle for output + * address relocated ASxxxx + * listing file + */ +FILE *sfp; /* The file handle sfp points to the + * currently open file + */ +FILE *tfp; /* File handle for input + * ASxxxx listing file + */ + +/* + * The structures of head, area, areax, and sym are created + * as the REL files are read during the first pass of the + * linker. The struct head is created upon encountering a + * H directive in the REL file. The structure contains a + * link to a link file structure (struct lfile) which describes + * the file containing the H directive, the number of data/code + * areas contained in this header segment, the number of + * symbols referenced/defined in this header segment, a pointer + * to an array of pointers to areax structures (struct areax) + * created as each A directive is read, and a pointer to an + * array of pointers to symbol structures (struct sym) for + * all referenced/defined symbols. As H directives are read + * from the REL files a linked list of head structures is + * created by placing a link to the new head structure + * in the previous head structure. + * + * struct head + * { + * struct head *h_hp; Header link + * struct lfile *h_lfile; Associated file + * int h_narea; # of areas + * struct areax **a_list; Area list + * int h_nglob; # of global symbols + * struct sym **s_list; Global symbol list + * char m_id[NCPS]; Module name + * }; + */ +struct head *headp; /* The pointer to the first + * head structure of a linked list + */ +struct head *hp; /* Pointer to the current + * head structure + */ + +/* + * A structure area is created for each 'unique' data/code + * area definition found as the REL files are read. The + * struct area contains the name of the area, a flag byte + * which contains the area attributes (REL/CON/OVR/ABS), + * an area subtype (not used in this assembler), and the + * area base address and total size which will be filled + * in at the end of the first pass through the REL files. + * As A directives are read from the REL files a linked + * list of unique area structures is created by placing a + * link to the new area structure in the previous area structure. + * + * struct area + * { + * struct area *a_ap; Area link + * struct areax *a_axp; Area extension link + * Addr_T a_addr; Beginning address of area + * Addr_T a_size; Total size of the area + * char a_type; Area subtype + * char a_flag; Flag byte + * char a_id[NCPS]; Name + * }; + */ +struct area *areap; /* The pointer to the first + * area structure of a linked list + */ +struct area *ap; /* Pointer to the current + * area structure + */ + +/* + * An areax structure is created for every A directive found + * while reading the REL files. The struct areax contains a + * link to the 'unique' area structure referenced by the A + * directive and to the head structure this area segment is + * a part of. The size of this area segment as read from the + * A directive is placed in the areax structure. The beginning + * address of this segment will be filled in at the end of the + * first pass through the REL files. As A directives are read + * from the REL files a linked list of areax structures is + * created for each unique area. The final areax linked + * list has at its head the 'unique' area structure linked + * to the linked areax structures (one areax structure for + * each A directive for this area). + * + * struct areax + * { + * struct areax *a_axp; Area extension link + * struct area *a_bap; Base area link + * struct head *a_bhp; Base header link + * Addr_T a_addr; Beginning address of section + * Addr_T a_size; Size of the area in section + * }; + */ +struct areax *axp; /* Pointer to the current + * areax structure + */ + +/* + * A sym structure is created for every unique symbol + * referenced/defined while reading the REL files. The + * struct sym contains the symbol's name, a flag value + * (not used in this linker), a symbol type denoting + * referenced/defined, and an address which is loaded + * with the relative address within the area in which + * the symbol was defined. The sym structure also + * contains a link to the area where the symbol was defined. + * The sym structures are linked into linked lists using + * the symbol link element. + * + * struct sym + * { + * struct sym *s_sp; Symbol link + * struct areax *s_axp; Symbol area link + * char s_type; Symbol subtype + * char s_flag; Flag byte + * Addr_T s_addr; Address + * char s_id[NCPS]; Name + * }; + */ +struct sym *symhash[NHASH]; /* array of pointers to NHASH + * linked symbol lists + */ +/* + * The struct base contains a pointer to a + * base definition string and a link to the next + * base structure. + * + * struct base + * { + * struct base *b_base; Base link + * char *b_strp; String pointer + * }; + */ +struct base *basep; /* The pointer to the first + * base structure + */ +struct base *bsp; /* Pointer to the current + * base structure + */ + +/* + * The struct globl contains a pointer to a + * global definition string and a link to the next + * global structure. + * + * struct globl + * { + * struct globl *g_globl; Global link + * char *g_strp; String pointer + * }; + */ +struct globl *globlp;/* The pointer to the first + * globl structure + */ +struct globl *gsp; /* Pointer to the current + * globl structure + */ + +/* + * A structure sdp is created for each 'unique' paged + * area definition found as the REL files are read. + * As P directives are read from the REL files a linked + * list of unique sdp structures is created by placing a + * link to the new sdp structure in the previous area structure. + * + * struct sdp + * { + * struct area *s_area; Paged Area link + * struct areax *s_areax; Paged Area Extension Link + * Addr_T s_addr; Page address offset + * }; + */ +struct sdp sdp; /* Base Page Structure */ + +/* + * The structure rerr is loaded with the information + * required to report an error during the linking + * process. The structure contains an index value + * which selects the areax structure from the header + * areax structure list, a mode value which selects + * symbol or area relocation, the base address in the + * area section, an area/symbol list index value, and + * an area/symbol offset value. + * + * struct rerr + * { + * int aindex; Linking area + * int mode; Relocation mode + * Addr_T rtbase; Base address in section + * int rindex; Area/Symbol reloaction index + * Addr_T rval; Area/Symbol offset value + * }; + */ +struct rerr rerr; /* Structure containing the + * linker error information + */ + +/* + * The structure lbpath is created for each library + * path specification input by the -k option. The + * lbpath structures are linked into a list using + * the next link element. + * + * struct lbpath { + * struct lbpath *next; + * char *path; + * }; + */ +struct lbpath *lbphead; /* pointer to the first + * library path structure + */ + +/* + * The structure lbname is created for all combinations of the + * library path specifications (input by the -k option) and the + * library file specifications (input by the -l option) that + * lead to an existing file. The element path points to + * the path string, element libfil points to the library + * file string, and the element libspc is the concatenation + * of the valid path and libfil strings. + * + * The lbpath structures are linked into a list + * using the next link element. + * + * Each library file contains a list of object files + * that are contained in the particular library. e.g.: + * + * \iolib\termio + * \inilib\termio + * + * Only one specification per line is allowed. + * + * struct lbname { + * struct lbname *next; + * char *path; + * char *libfil; + * char *libspc; + * }; + */ +struct lbname *lbnhead; /* pointer to the first + * library name structure + */ + +/* + * The function fndsym() searches through all combinations of the + * library path specifications (input by the -k option) and the + * library file specifications (input by the -l option) that + * lead to an existing file for a symbol definition. + * + * The structure lbfile is created for the first library + * object file which contains the definition for the + * specified undefined symbol. + * + * The element libspc points to the library file path specification + * and element relfil points to the object file specification string. + * The element filspc is the complete path/file specification for + * the library file to be imported into the linker. The + * file specicifation may be formed in one of two ways: + * + * (1) If the library file contained an absolute + * path/file specification then this becomes filspc. + * (i.e. C:\...) + * + * (2) If the library file contains a relative path/file + * specification then the concatenation of the path + * and this file specification becomes filspc. + * (i.e. \...) + * + * The lbpath structures are linked into a list + * using the next link element. + * + * struct lbfile { + * struct lbfile *next; + * char *libspc; + * char *relfil; + * char *filspc; + * }; + */ +struct lbfile *lbfhead; /* pointer to the first + * library file structure + */ + +/* + * array of character types, one per + * ASCII character + */ +char ctype[128] = { +/*NUL*/ ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, +/*BS*/ ILL, SPACE, ILL, ILL, SPACE, ILL, ILL, ILL, +/*DLE*/ ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, +/*CAN*/ ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, +/*SPC*/ SPACE, ETC, ETC, ETC, LETTER, BINOP, BINOP, ETC, +/*(*/ ETC, ETC, BINOP, BINOP, ETC, BINOP, LETTER, BINOP, +/*0*/ DGT2, DGT2, DGT8, DGT8, DGT8, DGT8, DGT8, DGT8, +/*8*/ DGT10, DGT10, ETC, ETC, BINOP, ETC, BINOP, ETC, +/*@*/ ETC, LTR16, LTR16, LTR16, LTR16, LTR16, LTR16, LETTER, +/*H*/ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/*P*/ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/*X*/ LETTER, LETTER, LETTER, ETC, ETC, ETC, BINOP, LETTER, +/*`*/ ETC, LTR16, LTR16, LTR16, LTR16, LTR16, LTR16, LETTER, +/*h*/ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/*p*/ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/*x*/ LETTER, LETTER, LETTER, ETC, BINOP, ETC, ETC, ETC +}; + +/* + * an array of characters which + * perform the case translation function + */ +#if CASE_SENSITIVE +#else +char ccase[128] = { +/*NUL*/ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', +/*BS*/ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', +/*DLE*/ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', +/*CAN*/ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', +/*SPC*/ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047', +/*(*/ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057', +/*0*/ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067', +/*8*/ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077', +/*@*/ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', +/*H*/ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', +/*P*/ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', +/*X*/ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137', +/*`*/ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147', +/*h*/ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', +/*p*/ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', +/*x*/ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177' +}; +#endif diff --git a/link/z80/lkeval.c b/link/z80/lkeval.c new file mode 100644 index 00000000..2dff89be --- /dev/null +++ b/link/z80/lkeval.c @@ -0,0 +1,398 @@ +/* lkeval.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +#include +#include +//#include +#include "aslink.h" + +/*)Module lkeval.c + * + * The module lkeval.c contains the routines to evaluate + * arithmetic/numerical expressions. The functions in + * lkeval.c perform a recursive evaluation of the arithmetic + * expression read from the input text line. + * The expression may include binary/unary operators, brackets, + * symbols, labels, and constants in hexadecimal, decimal, octal + * and binary. Arithmetic operations are prioritized and + * evaluated by normal arithmetic conventions. + * + * lkeval.c contains the following functions: + * int digit() + * Addr_T eval() + * Addr_T expr() + * int oprio() + * Addr_T term() + * + * lkeval.c contains no local/static variables + */ + +/*)Function Addr_T eval() + * + * The function eval() evaluates a character string to a + * numerical value. + * + * local variables: + * int c character from input string + * int v value of character in current radix + * Addr_T n evaluation value + * + * global variables: + * int radix current number conversion radix + * + * functions called: + * int digit() lkeval.c + * char get() lklex.c + * char getnb() lklex.c + * VOID unget() lklex.c + * + * side effects: + * Input test is scanned and evaluated to a + * numerical value. + */ + +Addr_T +eval() +{ + register int c, v; + register Addr_T n; + + c = getnb(); + n = 0; + while ((v = digit(c, radix)) >= 0) { + n = n*radix + v; + c = get(); + } + unget(c); + return(n); +} + +/*)Function Addr_T expr(n) + * + * int n a firewall priority; all top + * level calls (from the user) + * should be made with n set to 0. + * + * The function expr() evaluates an expression and + * returns the value. + * + * local variables: + * int c current input text character + * int p current operator priority + * Addr_T v value returned by term() + * Addr_T ve value returned by a + * recursive call to expr() + * + * global variables: + * char ctype[] array of character types, one per + * ASCII character + * int lkerr error flag + * FILE * stderr c_library + * + * functions called: + * VOID expr() lkeval.c + * int fprintf() c_library + * int getnb() lklex.c + * int oprio() lkeval.c + * VOID term() lkeval.c + * VOID unget() lklex.c + * + * + * side effects: + * An expression is evaluated by scanning the input + * text string. + */ + +Addr_T +expr (n) +{ + register int c, p; + register Addr_T v, ve; + + v = term(); + while (ctype[c = getnb()] & BINOP) { + if ((p = oprio(c)) <= n) + break; + if ((c == '>' || c == '<') && c != get()) { + fprintf(stderr, "Invalid expression"); + lkerr++; + return(v); + } + ve = expr(p); + if (c == '+') { + v += ve; + } else + if (c == '-') { + v -= ve; + } else { + switch (c) { + + case '*': + v *= ve; + break; + + case '/': + v /= ve; + break; + + case '&': + v &= ve; + break; + + case '|': + v |= ve; + break; + + case '%': + v %= ve; + break; + + case '^': + v ^= ve; + break; + + case '<': + v <<= ve; + break; + + case '>': + v >>= ve; + break; + } + } + } + unget(c); + return(v); +} + +/*)Function Addr_T term() + * + * The function term() evaluates a single constant + * or symbol value prefaced by any unary operator + * ( +, -, ~, ', ", >, or < ). + * + * local variables: + * int c current character + * char id[] symbol name + * int n value of digit in current radix + * int r current evaluation radix + * sym * sp pointer to a sym structure + * Addr_T v evaluation value + * + * global variables: + * char ctype[] array of character types, one per + * ASCII character + * int lkerr error flag + * + * functions called: + * int digit() lkeval.c + * VOID expr() lkeval.c + * int fprintf() c_library + * int get() lklex.c + * VOID getid() lklex.c + * int getmap() lklex.c + * int getnb() lklex.c + * sym * lkpsym() lksym.c + * Addr_T symval() lksym.c + * VOID unget() lklex.c + * + * side effects: + * An arithmetic term is evaluated by scanning input text. + */ + +Addr_T +term() +{ + register int c, r, n; + register Addr_T v; + struct sym *sp; + char id[NCPS]; + + c = getnb(); + if (c == '#') { c = getnb(); } + if (c == '(') { + v = expr(0); + if (getnb() != ')') { + fprintf(stderr, "Missing delimiter"); + lkerr++; + } + return(v); + } + if (c == '-') { + return(-expr(100)); + } + if (c == '~') { + return(~expr(100)); + } + if (c == '\'') { + return(getmap(-1)&0377); + } + if (c == '\"') { + if (hilo) { + v = (getmap(-1)&0377)<<8; + v |= getmap(-1)&0377; + } else { + v = getmap(-1)&0377; + v |= (getmap(-1)&0377)<<8; + } + return(v); + } + if (c == '>' || c == '<') { + v = expr(100); + if (c == '>') + v >>= 8; + return(v&0377); + } + if (ctype[c] & DIGIT) { + r = 10; + if (c == '0') { + c = get(); + switch (c) { + case 'b': + case 'B': + r = 2; + c = get(); + break; + case '@': + case 'o': + case 'O': + case 'q': + case 'Q': + r = 8; + c = get(); + break; + case 'd': + case 'D': + r = 10; + c = get(); + break; + case 'h': + case 'H': + case 'x': + case 'X': + r = 16; + c = get(); + break; + default: + break; + } + } + v = 0; + while ((n = digit(c, r)) >= 0) { + v = r*v + n; + c = get(); + } + unget(c); + return(v); + } + if (ctype[c] & LETTER) { + getid(id, c); + if ((sp = lkpsym(id, 0)) == NULL) { + fprintf(stderr, "Undefined symbol %8s\n", id); + lkerr++; + return(0); + } else { + return(symval(sp)); + } + } + /* Shouldn't get here. */ + return 0; +} + +/*)Function int digit(c, r) + * + * int c digit character + * int r current radix + * + * The function digit() returns the value of c + * in the current radix r. If the c value is not + * a number of the current radix then a -1 is returned. + * + * local variables: + * none + * + * global variables: + * char ctype[] array of character types, one per + * ASCII character + * + * functions called: + * none + * + * side effects: + * none + */ + +int +digit(c, r) +register int c, r; +{ + if (r == 16) { + if (ctype[c] & RAD16) { + if (c >= 'A' && c <= 'F') + return (c - 'A' + 10); + if (c >= 'a' && c <= 'f') + return (c - 'a' + 10); + return (c - '0'); + } + } else + if (r == 10) { + if (ctype[c] & RAD10) + return (c - '0'); + } else + if (r == 8) { + if (ctype[c] & RAD8) + return (c - '0'); + } else + if (r == 2) { + if (ctype[c] & RAD2) + return (c - '0'); + } + return (-1); +} + +/*)Function int oprio(c) + * + * int c operator character + * + * The function oprio() returns a relative priority + * for all valid unary and binary operators. + * + * local variables: + * none + * + * global variables: + * none + * + * functions called: + * none + * + * side effects: + * none + */ + +int +oprio(c) +register int c; +{ + if (c == '*' || c == '/' || c == '%') + return (10); + if (c == '+' || c == '-') + return (7); + if (c == '<' || c == '>') + return (5); + if (c == '^') + return (4); + if (c == '&') + return (3); + if (c == '|') + return (1); + return (0); +} diff --git a/link/z80/lkgb.c b/link/z80/lkgb.c new file mode 100644 index 00000000..9ecac07b --- /dev/null +++ b/link/z80/lkgb.c @@ -0,0 +1,190 @@ +/* lkgb.c */ + +/* + * P. Felber + */ + +#ifdef GAMEBOY + +#include +#include +#include +#include +#include "aslink.h" + +/* Value used to fill the unused portions of the image */ +/* FFh puts less stress on a EPROM/Flash */ +#define FILLVALUE 0xFF + +#define CARTSIZE ((unsigned long)nb_rom_banks*16UL*1024UL) +#define NBSEG 8UL +#define SEGSIZE (CARTSIZE/NBSEG) + +#define ROMSIZE 0x8000UL +#define BANKSTART 0x4000UL +#define BANKSIZE 0x4000UL + +unsigned char *cart[NBSEG]; + +int nb_rom_banks; +int nb_ram_banks; +int current_rom_bank; +int mbc_type; +char cart_name[16] = ""; + +patch* patches = NULL; + +VOID gb(int in) +{ + static int first = 1; + unsigned long pos, chk; + int i; + patch *p; + + if(first) { + for(i = 0; i < NBSEG; i++) { + if((cart[i] = malloc(SEGSIZE)) == NULL) { + fprintf(stderr, "ERROR: can't allocate %dth segment of memory (%d bytes)\n", i, (int)SEGSIZE); + exit(-1); + } + memset(cart[i], FILLVALUE, SEGSIZE); + } + first = 0; + } + if(in) { + if(rtcnt > 2) { + if(hilo == 0) + pos = rtval[0] | (rtval[1]<<8); + else + pos = rtval[1] | (rtval[0]<<8); + + /* Perform some validity checks */ + if(pos >= ROMSIZE) { + fprintf(stderr, "ERROR: address overflow (addr %lx >= %lx)\n", pos, ROMSIZE); + exit(-1); + } + if(current_rom_bank >= nb_rom_banks) { + fprintf(stderr, "ERROR: bank overflow (addr %x > %x)\n", current_rom_bank, nb_rom_banks); + exit(-1); + } + if(current_rom_bank > 0 && pos < BANKSTART) { + fprintf(stderr, "ERROR: address underflow (addr %lx < %lx)\n", pos, BANKSTART); + exit(-1); + } + if(nb_rom_banks == 2 && current_rom_bank > 0) { + fprintf(stderr, "ERROR: only 1 32kB segment with 2 bank\n"); + exit(-1); + } + if(current_rom_bank > 1) + pos += (current_rom_bank-1)*BANKSIZE; + for(i = 2; i < rtcnt; i++) { + if(rtflg[i]) { + if(pos < CARTSIZE) { + if(cart[pos/SEGSIZE][pos%SEGSIZE] != FILLVALUE) + fprintf(stderr, "WARNING: possibly wrote twice at addr %lx (%02X->%02X)\n", pos, rtval[i], cart[pos/SEGSIZE][pos%SEGSIZE]); + cart[pos/SEGSIZE][pos%SEGSIZE] = rtval[i]; + } else { + fprintf(stderr, "ERROR: cartridge size overflow (addr %lx >= %lx)\n", pos, CARTSIZE); + exit(-1); + } + pos++; + } + } + } + } else { + /* EOF */ + if(cart_name[0] == 0 && linkp->f_idp != NULL) { + for(i = strlen(linkp->f_idp); + i > 0 && (isalnum(linkp->f_idp[i-1]) || linkp->f_idp[i-1] == '.'); + i--) + ; + for(pos = 0; pos < 16 && linkp->f_idp[i] != '.'; pos++, i++) + cart_name[pos] = toupper(linkp->f_idp[i]); + if(pos < 16) + cart_name[pos] = 0; + } + for(pos = 0x0134, i = 0; + pos < 0x0144 && cart_name[i]; + pos++, i++) + cart[pos/SEGSIZE][pos%SEGSIZE] = cart_name[i]; + for(; pos < 0x0144; pos++) + cart[pos/SEGSIZE][pos%SEGSIZE] = 0; + cart[0x147/SEGSIZE][0x147%SEGSIZE] = mbc_type; + switch(nb_rom_banks) { + case 2: + cart[0x148/SEGSIZE][0x148%SEGSIZE] = 0; + break; + case 4: + cart[0x148/SEGSIZE][0x148%SEGSIZE] = 1; + break; + case 8: + cart[0x148/SEGSIZE][0x148%SEGSIZE] = 2; + break; + case 16: + cart[0x148/SEGSIZE][0x148%SEGSIZE] = 3; + break; + case 32: + cart[0x148/SEGSIZE][0x148%SEGSIZE] = 4; + break; + case 64: + cart[0x148/SEGSIZE][0x148%SEGSIZE] = 5; + break; + case 128: + cart[0x148/SEGSIZE][0x148%SEGSIZE] = 6; + break; + case 256: + cart[0x148/SEGSIZE][0x148%SEGSIZE] = 7; + break; + case 512: + cart[0x148/SEGSIZE][0x148%SEGSIZE] = 8; + break; + default: + fprintf(stderr, "WARNING: unsupported number of ROM banks (%d)\n", nb_rom_banks); + cart[0x148/SEGSIZE][0x148%SEGSIZE] = 0; + break; + } + switch(nb_ram_banks) { + case 0: + cart[0x149/SEGSIZE][0x149%SEGSIZE] = 0; + break; + case 1: + cart[0x149/SEGSIZE][0x149%SEGSIZE] = 2; + break; + case 4: + cart[0x149/SEGSIZE][0x149%SEGSIZE] = 3; + break; + case 16: + cart[0x149/SEGSIZE][0x149%SEGSIZE] = 4; + break; + default: + fprintf(stderr, "WARNING: unsupported number of RAM banks (%d)\n", nb_ram_banks); + cart[0x149/SEGSIZE][0x149%SEGSIZE] = 0; + break; + } + + /* Patch before calculating the checksum */ + if(patches) + for(p = patches; p; p = p->next) + cart[p->addr/SEGSIZE][p->addr%SEGSIZE] = p->value; + + /* Update complement checksum */ + chk = 0; + for(pos = 0x0134; pos < 0x014D; pos++) + chk += cart[pos/SEGSIZE][pos%SEGSIZE]; + cart[0x014D/SEGSIZE][0x014D%SEGSIZE] = 0xE7 - (chk&0xFF); + /* Update checksum */ + chk = 0; + cart[0x014E/SEGSIZE][0x014E%SEGSIZE] = 0; + cart[0x014F/SEGSIZE][0x014F%SEGSIZE] = 0; + for(i = 0; i < NBSEG; i++) + for(pos = 0; pos < SEGSIZE; pos++) + chk += cart[i][pos]; + cart[0x014E/SEGSIZE][0x014E%SEGSIZE] = (chk>>8)&0xFF; + cart[0x014F/SEGSIZE][0x014F%SEGSIZE] = chk&0xFF; + + for(i = 0; i < NBSEG; i++) + fwrite(cart[i], 1, SEGSIZE, ofp); + } +} + +#endif /* GAMEBOY */ diff --git a/link/z80/lkgg.c b/link/z80/lkgg.c new file mode 100644 index 00000000..d8248d6e --- /dev/null +++ b/link/z80/lkgg.c @@ -0,0 +1,79 @@ +/* lkgg.c */ + +/* + * P. Felber + */ + +#ifdef GAMEGEAR + +#include +#include +#include +#include +#include +#include "aslink.h" + +#define CARTSIZE ((unsigned long)4*16UL*1024UL) +#define NBSEG 8UL +#define SEGSIZE (CARTSIZE/NBSEG) + +unsigned char *cart[NBSEG]; + +#define ROMSIZE 0x10000UL +#define BANKSIZE 0x4000UL + +int current_rom_bank; + +VOID gg(int in) +{ + static int first = 1; + unsigned long pos; + int i; + + if(first) { + for(i = 0; i < NBSEG; i++) { + if((cart[i] = malloc(SEGSIZE)) == NULL) { + fprintf(stderr, "ERROR: can't allocate %dth segment of memory (%d bytes)\n", i, (int)SEGSIZE); + exit(-1); + } + memset(cart[i], 0, SEGSIZE); + } + first = 0; + } + if(in) { + if(rtcnt > 2) { + if(hilo == 0) + pos = rtval[0] | (rtval[1]<<8); + else + pos = rtval[1] | (rtval[0]<<8); + + /* Perform some validity checks */ + if(pos >= ROMSIZE) { + fprintf(stderr, "ERROR: address overflow (addr %lx >= %lx)\n", pos, ROMSIZE); + exit(-1); + } + if(current_rom_bank > 1) + pos += (current_rom_bank-1)*BANKSIZE; + for(i = 2; i < rtcnt; i++) { + if(rtflg[i]) { + if(pos < CARTSIZE) { + if(cart[pos/SEGSIZE][pos%SEGSIZE] != 0) + fprintf(stderr, "WARNING: wrote twice at addr %lx (%02X->%02X)\n", pos, rtval[i], cart[pos/SEGSIZE][pos%SEGSIZE]); + cart[pos/SEGSIZE][pos%SEGSIZE] = rtval[i]; + } else { + fprintf(stderr, "ERROR: cartridge size overflow (addr %lx >= %lx)\n", pos, CARTSIZE); + exit(-1); + } + pos++; + } + } + } + } else { + /* EOF */ + /* Patch before calculating the checksum */ + for(i = 0; i < NBSEG; i++) + fwrite(cart[i], 1, SEGSIZE, ofp); + } +} + +#endif /* GAMEGEAR */ diff --git a/link/z80/lkhead.c b/link/z80/lkhead.c new file mode 100644 index 00000000..3eb127d9 --- /dev/null +++ b/link/z80/lkhead.c @@ -0,0 +1,154 @@ +/* lkhead.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +#include +#include +//#include +#include "aslink.h" + +/*Module lkhead.c + * + * The module lkhead.c contains the function newhead() which + * creates a head structure and the function module() which + * loads the module name into the current head structure. + * + * lkhead.c contains the following functions: + * VOID newhead() + * VOID module() + * + * lkhead.c contains no local variables. + */ + +/*)Function VOID newhead() + * + * The function newhead() creates a head structure. All head + * structures are linked to form a linked list of head structures + * with the current head structure at the tail of the list. + * + * local variables: + * int i evaluation value + * head * thp temporary pointer + * to a header structure + * + * global variables: + * area *ap Pointer to the current + * area structure + * lfile *cfp The pointer *cfp points to the + * current lfile structure + * head *headp The pointer to the first + * head structure of a linked list + * head *hp Pointer to the current + * head structure + * + * functions called: + * Addr_T expr() lkeval.c + * VOID * new() lksym.c + * VOID lkparea() lkarea.c + * + * side effects: + * A new head structure is created and linked to any + * existing linked head structure. The head structure + * parameters of file handle, number of areas, and number + * of global symbols are loaded into the structure. + * The default area "_abs_" is created when the first + * head structure is created and an areax structure is + * created for every head structure called. + */ + +/* + * Create a new header entry. + * + * H n areas n global symbols + * | | + * | `---- hp->h_nglob + * `------------ hp->h_narea + * + */ +VOID +newhead() +{ + register int i; + struct head *thp; + + hp = (struct head *) new (sizeof(struct head)); + if (headp == NULL) { + headp = hp; + } else { + thp = headp; + while (thp->h_hp) + thp = thp->h_hp; + thp->h_hp = hp; + } + /* + * Set file pointer + */ + hp->h_lfile = cfp; + /* + * Evaluate and build Area pointer list + */ + i = hp->h_narea = eval(); + if (i) + hp->a_list = (struct areax **) new (i*sizeof(struct areax *)); + /* + * Evaluate and build Global symbol pointer list + */ + skip(-1); + i = hp->h_nglob = eval(); + if (i) + hp->s_list = (struct sym **) new (i*sizeof(struct sym *)); + /* + * Setup Absolute DEF linkage. + */ + lkparea(_abs_); + ap->a_flag = A_ABS|A_OVR; +} + +/*)Function VOID module() + * + * The function module() copies the module name into + * the current head structure. + * + * local variables: + * char id[] module id string + * + * global variables: + * head *headp The pointer to the first + * head structure of a linked list + * head *hp Pointer to the current + * head structure + * int lkerr error flag + * FILE * stderr c_library + * + * functions called: + * int fprintf() c_library + * VOID getid() lklex.c + * char * strncpy() c_library + * + * side effects: + * The module name is copied into the head structure. + */ + +/* + * Module Name + */ +VOID +module() +{ + char id[NCPS]; + + if (headp) { + getid(id, -1); + strncpy(hp->m_id, id, NCPS); + } else { + fprintf(stderr, "No header defined\n"); + lkerr++; + } +} diff --git a/link/z80/lkihx.c b/link/z80/lkihx.c new file mode 100644 index 00000000..a0e35d99 --- /dev/null +++ b/link/z80/lkihx.c @@ -0,0 +1,134 @@ +/* lkihx.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +#include +#include +//#include +#include "aslink.h" + +/*)Module lkihx.c + * + * The module lkihx.c contains the function to + * output the relocated object code in the + * Intel Hex format. + * + * lkihx.c contains the following function: + * VOID ihx(i) + * + * lkihx.c contains no local variables. + */ + +/*Intel Hex Format + * Record Mark Field - This field signifies the start of a + * record, and consists of an ascii colon + * (:). + * + * Record Length Field - This field consists of two ascii + * characters which indicate the number of + * data bytes in this record. The + * characters are the result of converting + * the number of bytes in binary to two + * ascii characters, high digit first. An + * End of File record contains two ascii + * zeros in this field. + * + * Load Address Field - This field consists of the four ascii + * characters which result from converting + * the the binary value of the address in + * which to begin loading this record. The + * order is as follows: + * + * High digit of high byte of address. + * Low digit of high byte of address. + * High digit of low byte of address. + * Low digit of low byte of address. + * + * In an End of File record this field con- + * sists of either four ascii zeros or the + * program entry address. Currently the + * entry address option is not supported. + * + * Record Type Field - This field identifies the record type, + * which is either 0 for data records or 1 + * for an End of File record. It consists + * of two ascii characters, with the high + * digit of the record type first, followed + * by the low digit of the record type. + * + * Data Field - This field consists of the actual data, + * converted to two ascii characters, high + * digit first. There are no data bytes in + * the End of File record. + * + * Checksum Field - The checksum field is the 8 bit binary + * sum of the record length field, the load + * address field, the record type field, + * and the data field. This sum is then + * negated (2's complement) and converted + * to two ascii characters, high digit + * first. + */ + +/*)Function ihx(i) + * + * int i 0 - process data + * 1 - end of data + * + * The function ihx() outputs the relocated data + * in the standard Intel Hex format. + * + * local variables: + * Addr_T chksum byte checksum + * + * global variables: + * int hilo byte order + * FILE * ofp output file handle + * int rtcnt count of data words + * int rtflg[] output the data flag + * Addr_T rtval[] relocated data + * + * functions called: + * int fprintf() c_library + * + * side effects: + * The data is output to the file defined by ofp. + */ + +VOID +ihx(i) +{ + register Addr_T chksum; + + if (i) { + if (hilo == 0) { + chksum = rtval[0]; + rtval[0] = rtval[1]; + rtval[1] = chksum; + } + for (i = 0, chksum = -2; i < rtcnt; i++) { + if (rtflg[i]) + chksum++; + } + fprintf(ofp, ":%02X", chksum); + for (i = 0; i < rtcnt ; i++) { + if (rtflg[i]) { + fprintf(ofp, "%02X", rtval[i]); + chksum += rtval[i]; + } + if (i == 1) { + fprintf(ofp, "00"); + } + } + fprintf(ofp, "%02X\n", (-chksum) & 0xff); + } else { + fprintf(ofp, ":00000001FF\n"); + } +} diff --git a/link/z80/lklex.c b/link/z80/lklex.c new file mode 100644 index 00000000..2939b3d7 --- /dev/null +++ b/link/z80/lklex.c @@ -0,0 +1,569 @@ +/* lklex.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +/* + * Extensions: P. Felber, M. Hope + */ + +#include +#include +//#include +#include "aslink.h" + +/*)Module lklex.c + * + * The module lklex.c contains the general lexical analysis + * functions used to scan the text lines from the .rel files. + * + * lklex.c contains the fllowing functions: + * char endline() + * char get() + * VOID getfid() + * VOID getid() + * int getLine_() + * int getmap() + * char getnb() + * int more() + * VOID skip() + * VOID unget() + * + * lklex.c contains no local variables. + */ + +/*)Function VOID getid(id,c) + * + * char * id a pointer to a string of + * maximum length NCPS + * int c mode flag + * >=0 this is first character to + * copy to the string buffer + * <0 skip white space + * + * The function getid() scans the current input text line + * from the current position copying the next LETTER | DIGIT string + * into the external string buffer (id). The string ends when a non + * LETTER or DIGIT character is found. The maximum number of + * characters copied is NCPS. If the input string is larger than + * NCPS characters then the string is truncated, if the input string + * is shorter than NCPS characters then the string is NULL filled. + * If the mode argument (c) is >=0 then (c) is the first character + * copied to the string buffer, if (c) is <0 then intervening white + * space (SPACES and TABS) are skipped. + * + * local variables: + * char * p pointer to external string buffer + * int c current character value + * + * global variables: + * char ctype[] a character array which defines the + * type of character being processed. + * This index is the character + * being processed. + * + * called functions: + * char get() lklex.c + * char getnb() lklex.c + * VOID unget() lklex.c + * + * side effects: + * use of getnb(), get(), and unget() updates the + * global pointer ip the position in the current + * input text line. + */ + +VOID +getid(id, c) +register int c; +char *id; +{ + register char *p; + + if (c < 0) { + c = getnb(); + } + p = id; + do { + if (p < &id[NCPS]) + *p++ = c; + } while (ctype[c=get()] & (LETTER|DIGIT)); + unget(c); + while (p < &id[NCPS]) + *p++ = 0; +} + +/*)Function VOID getfid(fid,c) + * + * char * str a pointer to a string of + * maximum length FILSPC + * int c this is first character to + * copy to the string buffer + * + * The function getfid() scans the current input text line + * from the current position copying the next string + * into the external string buffer (str). The string ends when a + * non SPACE type character is found. The maximum number of + * characters copied is FILSPC. If the input string is larger than + * FILSPC characters then the string is truncated, if the input string + * is shorter than FILSPC characters then the string is NULL filled. + * + * local variables: + * char * p pointer to external string buffer + * int c current character value + * + * global variables: + * char ctype[] a character array which defines the + * type of character being processed. + * This index is the character + * being processed. + * + * called functions: + * char get() lklex.c + * + * side effects: + * use of get() updates the global pointer ip + * the position in the current input text line. + */ + +VOID +getfid(str, c) +register int c; +char *str; +{ + register char *p; + + p = str; + do { + if (p < &str[FILSPC-1]) + *p++ = c; + c = get(); +#ifdef SDK + } while (c); +#else /* SDK */ + } while (c && (ctype[c] != SPACE)); +#endif /* SDK */ + while (p < &str[FILSPC]) + *p++ = 0; +} + +/*)Function char getnb() + * + * The function getnb() scans the current input text + * line returning the first character not a SPACE or TAB. + * + * local variables: + * int c current character from input + * + * global variables: + * none + * + * called functions: + * char get() lklex.c + * + * side effects: + * use of get() updates the global pointer ip, the position + * in the current input text line + */ + +char +getnb() +{ + register int c; + + while ((c=get())==' ' || c=='\t') + ; + return (c); +} + +/*)Function VOID skip() + * + * The function skip() scans the input text skipping all + * letters and digits. + * + * local variables: + * none + * + * global variables: + * char ctype[] array of character types, one per + * ASCII character + * + * functions called: + * char get() lklex.c + * char getnb() lklex.c + * VOID unget() lklex.c + * + * side effects: + * Input letters and digits are skipped. + */ + +VOID +skip(c) +register int c; +{ + if (c < 0) + c = getnb(); + while (ctype[c=get()] & (LETTER|DIGIT)) { ; } + unget(c); +} + +/*)Function char get() + * + * The function get() returns the next character in the + * input text line, at the end of the line a + * NULL character is returned. + * + * local variables: + * int c current character from + * input text line + * + * global variables: + * char * ip pointer into the current + * input text line + * + * called functions: + * none + * + * side effects: + * updates ip to the next character position in the + * input text line. If ip is at the end of the + * line, ip is not updated. + */ + +char +get() +{ + register int c; + + if ((c = *ip) != 0) + ++ip; + return (c); +} + +/*)Function VOID unget(c) + * + * int c value of last character + * read from input text line + * + * If (c) is not a NULL character then the global pointer ip + * is updated to point to the preceeding character in the + * input text line. + * + * NOTE: This function does not push the character (c) + * back into the input text line, only + * the pointer ip is changed. + * + * local variables: + * int c last character read + * from input text line + * + * global variables: + * char * ip position into the current + * input text line + * + * called functions: + * none + * + * side effects: + * ip decremented by 1 character position + */ + +VOID +unget(c) +{ + if (c != 0) + --ip; +} + +/*)Function int getmap(d) + * + * int d value to compare with the + * input text line character + * + * The function getmap() converts the 'C' style characters \b, \f, + * \n, \r, and \t to their equivalent ascii values and also + * converts 'C' style octal constants '\123' to their equivalent + * numeric values. If the first character is equivalent to (d) then + * a (-1) is returned, if the end of the line is detected then + * a 'q' error terminates the parse for this line, or if the first + * character is not a \ then the character value is returned. + * + * local variables: + * int c value of character + * from input text line + * int n looping counter + * int v current value of numeric conversion + * + * global variables: + * none + * + * called functions: + * char get() lklex.c + * VOID unget() lklex.c + * + * side effects: + * use of get() updates the global pointer ip the position + * in the current input text line + */ + +int +getmap(d) +{ + register int c, n, v; + + if ((c = get()) == '\0') + return (-1); + if (c == d) + return (-1); + if (c == '\\') { + c = get(); + switch (c) { + + case 'b': + c = '\b'; + break; + + case 'f': + c = '\f'; + break; + + case 'n': + c = '\n'; + break; + + case 'r': + c = '\r'; + break; + + case 't': + c = '\t'; + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + n = 0; + v = 0; + while (++n<=3 && c>='0' && c<='7') { + v = (v<<3) + c - '0'; + c = get(); + } + unget(c); + c = v; + break; + } + } + return (c); +} + +/*)Function int getLine_() + * + * The function getLine_() reads a line of input text from a + * .rel source text file, a .lnk command file or from stdin. + * Lines of text are processed from a single .lnk file or + * multiple .rel files until all files have been read. + * The input text line is copied into the global string ib[] + * and converted to a NULL terminated string. The function + * getLine_() returns a (1) after succesfully reading a line + * or a (0) if all files have been read. + * This function also opens each input .lst file and output + * .rst file as each .rel file is processed. + * + * local variables: + * int i string length + * int ftype file type + * char * fid file name + * + * global variables: + * lfile *cfp The pointer *cfp points to the + * current lfile structure + * lfile *filep The pointer *filep points to the + * beginning of a linked list of + * lfile structures. + * int gline get a line from the LST file + * to translate for the RST file + * char ib[NINPUT] REL file text line + * int pass linker pass number + * int pflag print linker command file flag + * FILE *rfp The file handle to the current + * output RST file + * FILE *sfp The file handle sfp points to the + * currently open file + * FILE * stdin c_library + * FILE * stdout c_library + * FILE *tfp The file handle to the current + * LST file being scanned + * int uflag update listing flag + * + * called functions: + * FILE * afile() lkmain.c + * int fclose() c_library + * char * fgets() c_library + * int fprintf() c_library + * VOID lkulist() lklist.c + * VOID lkexit() lkmain.c + * int strlen() c_library + * + * side effects: + * The input stream is scanned. The .rel files will be + * opened and closed sequentially scanning each in turn. + */ + +int +getLine_() +{ + register int i, ftype; + register char *fid; + +loop: if (pflag && cfp && cfp->f_type == F_STD) + fprintf(stdout, "ASlink >> "); + +#ifdef SDK + if(cfp == NULL && filep != NULL && filep->f_type == F_CMD) { + char **argv = (char **)filep->f_idp; + if(argv[0] != NULL && strlen(argv[0]) < sizeof ib) { + strcpy(ib, argv[0]); + filep->f_idp = (char *)&argv[1]; + } else { + filep = NULL; + return(0); + } + } else +#endif /* SDK */ + if (sfp == NULL || fgets(ib, sizeof ib, sfp) == NULL) { + if (sfp) { + fclose(sfp); +#ifdef SDK + sfp = NULL; +#endif /* SDK */ + lkulist(0); + } + if (cfp == NULL) { + cfp = filep; + } else { + cfp = cfp->f_flp; + } + if (cfp) { + ftype = cfp->f_type; + fid = cfp->f_idp; + if (ftype == F_STD) { + sfp = stdin; + } else + if (ftype == F_LNK) { +#ifdef SDK + sfp = afile(fid, "lnk", 0); +#else /* SDK */ + sfp = afile(fid, "LNK", 0); +#endif /* SDK */ + } else + if (ftype == F_REL) { +#ifdef SDK + sfp = afile(fid, "", 0); + if (uflag && pass != 0) { + if ((tfp = afile(fid, "lst", 0)) != NULL) { + if ((rfp = afile(fid, "rst", 1)) == NULL) { +#else /* SDK */ + sfp = afile(fid, "REL", 0); + if (uflag && pass != 0) { + if ((tfp = afile(fid, "LST", 0)) != NULL) { + if ((rfp = afile(fid, "RST", 1)) == NULL) { +#endif /* SDK */ + fclose(tfp); + tfp = NULL; + } + } + } + gline = 1; + } else { + fprintf(stderr, "Invalid file type\n"); + lkexit(1); + } + if (sfp == NULL) { + lkexit(1); + } + goto loop; + } else { + filep = NULL; + return(0); + } + } + i = strlen(ib) - 1; + if (ib[i] == '\n') + ib[i] = 0; + return (1); +} + +/*)Function int more() + * + * The function more() scans the input text line + * skipping white space (SPACES and TABS) and returns a (0) + * if the end of the line or a comment delimeter (;) is found, + * or a (1) if their are additional characters in the line. + * + * local variables: + * int c next character from + * the input text line + * + * global variables: + * none + * + * called functions: + * char getnb() lklex.c + * VOID unget() lklex.c + * + * side effects: + * use of getnb() and unget() updates the global pointer ip + * the position in the current input text line + */ + +int +more() +{ + register int c; + + c = getnb(); + unget(c); + return( (c == '\0' || c == ';') ? 0 : 1 ); +} + +/*)Function char endline() + * + * The function endline() scans the input text line + * skipping white space (SPACES and TABS) and returns the next + * character or a (0) if the end of the line is found or a + * comment delimiter (;) is found. + * + * local variables: + * int c next character from + * the input text line + * + * global variables: + * none + * + * called functions: + * char getnb() lklex.c + * + * side effects: + * Use of getnb() updates the global pointer ip the + * position in the current input text line. + */ + +char +endline() +{ + register int c; + + c = getnb(); + return( (c == '\0' || c == ';') ? 0 : c ); +} diff --git a/link/z80/lklibr.c b/link/z80/lklibr.c new file mode 100644 index 00000000..7fd9f3de --- /dev/null +++ b/link/z80/lklibr.c @@ -0,0 +1,810 @@ +/* lklibr.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + * + * With contributions for the + * object libraries from + * Ken Hornstein + * kenh@cmf.nrl.navy.mil + * + */ + +/* + * Extensions: P. Felber + */ + +#include +#include +#include +#include "aslink.h" + +/*)Module lklibr.c + * + * The module lklibr.c contains the functions which + * (1) specify the path(s) to library files [.LIB] + * (2) specify the library file(s) [.LIB] to search + * (3) search the library files for specific symbols + * and link the module containing this symbol + * + * lklibr.c contains the following functions: + * VOID addpath() + * VOID addlib() + * VOID addfile() + * VOID search() + * VOID fndsym() + * VOID library() + * VOID loadfile() + * + */ + +#ifdef INDEXLIB +typedef struct slibrarysymbol mlibrarysymbol; +typedef struct slibrarysymbol *pmlibrarysymbol; + +struct slibrarysymbol { + char name[40]; + pmlibrarysymbol next; +}; + +typedef struct slibraryfile mlibraryfile; +typedef struct slibraryfile *pmlibraryfile; + +struct slibraryfile { + int loaded; + char *libspc; + char *str; + char relfil[FILSPC]; + char filename[FILSPC]; + pmlibrarysymbol symbols; + pmlibraryfile next; +}; + +int buildlibraryindex(); +#endif /* INDEXLIB */ + +/*)Function VOID addpath() + * + * The function addpath() creates a linked structure containing + * the paths to various object module library files. + * + * local variables: + * lbpath *lbph pointer to new path structure + * lbpath *lbp temporary pointer + * + * global variables: + * lbpath *lbphead The pointer to the first + * path structure + * + * functions called: + * char getnb() lklex.c + * VOID * new() lksym.c + * int strlen() c_library + * char * strcpy() c_library + * VOID unget() lklex.c + * + * side effects: + * An lbpath structure may be created. + */ + +VOID +addpath() +{ + struct lbpath *lbph, *lbp; + + lbph = (struct lbpath *) new (sizeof(struct lbpath)); + if (lbphead == NULL) { + lbphead = lbph; + } else { + lbp = lbphead; + while (lbp->next) + lbp = lbp->next; + lbp->next = lbph; + } + unget(getnb()); + lbph->path = (char *) new (strlen(ip)+1); + strcpy(lbph->path, ip); +} + +/*)Function VOID addlib() + * + * The function addlib() tests for the existance of a + * library path structure to determine the method of + * adding this library file to the library search structure. + * + * This function calls the function addfile() to actually + * add the library file to the search list. + * + * local variables: + * lbpath *lbph pointer to path structure + * + * global variables: + * lbpath *lbphead The pointer to the first + * path structure + * + * functions called: + * VOID addfile() lklibr.c + * char getnb() lklex.c + * VOID unget() lklex.c + * + * side effects: + * The function addfile() may add the file to + * the library search list. + */ + +VOID +addlib() +{ + struct lbpath *lbph; + + unget(getnb()); + + if (lbphead == NULL) { + addfile(NULL,ip); + return; + } + for (lbph=lbphead; lbph; lbph=lbph->next) { + addfile(lbph->path,ip); + } +} + +/*)Function VOID addfile(path,libfil) + * + * char *path library path specification + * char *libfil library file specification + * + * The function addfile() searches for the library file + * by concatenating the path and libfil specifications. + * if the library is found, an lbname structure is created + * and linked to any previously defined structures. This + * linked list is used by the function fndsym() to attempt + * to find any undefined symbols. + * + * The function does not give report an error on invalid + * path / file specifications or if the file is not found. + * + * local variables: + * lbname *lbnh pointer to new name structure + * lbname *lbn temporary pointer + * + * global variables: + * lbname *lbnhead The pointer to the first + * path structure + * + * functions called: + * char getnb() lklex.c + * VOID * new() lksym.c + * int strlen() c_library + * char * strcpy() c_library + * VOID unget() lklex.c + * + * side effects: + * An lbname structure may be created. + */ + +VOID +addfile(path,libfil) +char *path; +char *libfil; +{ + FILE *fp; + char *str; + struct lbname *lbnh, *lbn; + + if ((path != NULL) && (strchr(libfil,':') == NULL)){ + str = (char *) new (strlen(path) + strlen(libfil) + 6); + strcpy(str,path); +#ifdef OTHERSYSTEM +#ifdef SDK +#ifdef UNIX + if (str[strlen(str)-1] != '/') { + strcat(str,"/"); +#else /* UNIX */ + if (str[strlen(str)-1] != '\\') { + strcat(str,"\\"); +#endif /* UNIX */ +#else /* SDK */ + if (str[strlen(str)-1] != '\\') { + strcat(str,"\\"); +#endif /* SDK */ + } +#endif + } else { + str = (char *) new (strlen(libfil) + 5); + } +#ifdef OTHERSYSTEM +#ifdef SDK +#ifdef UNIX + if (libfil[0] == '/') { libfil++; } +#else /* UNIX */ + if (libfil[0] == '\\') { libfil++; } +#endif /* UNIX */ +#else /* SDK */ + if (libfil[0] == '\\') { libfil++; } +#endif /* SDK */ +#endif + strcat(str,libfil); + if(strchr(str,FSEPX) == NULL) { + sprintf(&str[strlen(str)], "%clib", FSEPX); + } + if ((fp = fopen(str, "r")) != NULL) { + fclose(fp); + lbnh = (struct lbname *) new (sizeof(struct lbname)); + if (lbnhead == NULL) { + lbnhead = lbnh; + } else { + lbn = lbnhead; + while (lbn->next) + lbn = lbn->next; + lbn->next = lbnh; + } + if ((path != NULL) && (strchr(libfil,':') == NULL)){ + lbnh->path = path; + } + lbnh->libfil = (char *) new (strlen(libfil) + 1); + strcpy(lbnh->libfil,libfil); + lbnh->libspc = str; + } else { + free(str); + } +} + +/*)Function VOID search() + * + * The function search() looks through all the symbol tables + * at the end of pass 1. If any undefined symbols are found + * then the function fndsym() is called. Function fndsym() + * searches any specified library files to automagically + * import the object modules containing the needed symbol. + * + * After a symbol is found and imported by the function + * fndsym() the symbol tables are again searched. The + * symbol tables are search until no more symbols can be + * resolved within the library files. This ensures that + * back references from one library module to another are + * also resolved. + * + * local variables: + * int i temporary counter + * sym *sp pointer to a symbol structure + * int symfnd found a symbol flag + * + * global variables: + * sym *symhash[] array of pointers to symbol tables + * + * functions called: + * int fndsym() lklibr.c + * + * side effects: + * If a symbol is found then the library object module + * containing the symbol will be imported and linked. + */ + +VOID +search() +{ + register struct sym *sp; + register int i, symfnd; + + /* + * Look for undefined symbols. Keep + * searching until no more symbols are resolved. + */ + symfnd = 1; + while (symfnd) { + symfnd = 0; + /* + * Look through all the symbols + */ + for (i=0; is_type & S_DEF) == 0) { + if (fndsym(sp->s_id)) { + symfnd++; + } + } + sp = sp->s_sp; + } + } + } +} + + +/*)Function VOID fndsym(name) + * + * char *name symbol name to find + * + * The function fndsym() searches through all combinations of the + * library path specifications (input by the -k option) and the + * library file specifications (input by the -l option) that + * lead to an existing file. + * + * The file specicifation may be formed in one of two ways: + * + * (1) If the library file contained an absolute + * path/file specification then this becomes filspc. + * (i.e. C:\...) + * + * (2) If the library file contains a relative path/file + * specification then the concatenation of the path + * and this file specification becomes filspc. + * (i.e. \...) + * + * The structure lbfile is created for the first library + * object file which contains the definition for the + * specified undefined symbol. + * + * If the library file [.LIB] contains file specifications for + * non existant files, no errors are returned. + * + * local variables: + * char buf[] [.REL] file input line + * char c [.REL] file input character + * FILE *fp file handle for object file + * lbfile *lbf temporary pointer + * lbfile *lbfh pointer to lbfile structure + * FILE *libfp file handle for library file + * lbname *lbnh pointer to lbname structure + * char *path file specification path + * char relfil[] [.REL] file specification + * char *str combined path and file specification + * char symname[] [.REL] file symbol string + * + * global variables: + * lbname *lbnhead The pointer to the first + * name structure + * lbfile *lbfhead The pointer to the first + * file structure + * + * functions called: + * int fclose() c_library + * int fgets() c_library + * FILE *fopen() c_library + * VOID free() c_library + * char getnb() lklex.c + * VOID lkexit() lkmain.c + * VOID loadfile() lklibr.c + * VOID * new() lksym.c + * char * sprintf() c_library + * int sscanf() c_library + * char * strcat() c_library + * char * strchr() c_library + * char * strcpy() c_library + * int strlen() c_library + * int strncmp() c_library + * VOID unget() lklex.c + * + * side effects: + * If the symbol is found then a new lbfile structure + * is created and added to the linked list of lbfile + * structures. The file containing the found symbol + * is linked. + */ + +#ifdef INDEXLIB + +/* First entry in the library object symbol cache */ +mlibraryfile libr; + +int fndsym( char *name ) +{ + struct lbfile *lbfh, *lbf; + pmlibraryfile ThisLibr; + pmlibrarysymbol ThisSym = NULL; + + /* Build the index if this is the first call to fndsym */ + if (libr.next==NULL) + buildlibraryindex(); + + /* Iterate through all library object files */ + ThisLibr = libr.next; + while (ThisLibr) { + + /* Iterate through all symbols in an object file */ + ThisSym = ThisLibr->symbols->next; + + while (ThisSym) { + if (!strcmp(ThisSym->name, name)) { + if (!ThisLibr->loaded) { + /* Object file is not loaded - add it to the list */ + lbfh = (struct lbfile *) new (sizeof(struct lbfile)); + if (lbfhead == NULL) { + lbfhead = lbfh; + } else { + lbf = lbfhead; + while (lbf->next) + lbf = lbf->next; + lbf->next = lbfh; + } + lbfh->libspc = ThisLibr->libspc; + lbfh->filspc = ThisLibr->str; + lbfh->relfil = (char *) new (strlen(ThisLibr->relfil) + 1); + strcpy(lbfh->relfil,ThisLibr->relfil); + loadfile(lbfh->filspc); + ThisLibr->loaded=1; + } + return (1); /* Found the symbol, return */ + } + ThisSym=ThisSym->next; /* Next sym in library */ + } + ThisLibr=ThisLibr->next; /* Next library in list */ + } + return 0; /* Failure - symbol not found in any library */ +}; + +/* buildlibraryindex - build an in-memory cache of the symbols contained in + * the libraries + */ + +int buildlibraryindex() +{ + FILE *libfp, *fp; + struct lbname *lbnh; + char relfil[NINPUT+2], *str, *path; + char buf[NINPUT+2], c; + char symname[NINPUT+2]; + pmlibraryfile This; + pmlibrarysymbol ThisSym; + + This=&libr; + + /* Iterate through all library files */ +/*1*/ for (lbnh=lbnhead; lbnh; lbnh=lbnh->next) { + libfp = fopen( lbnh->libspc, "r" ); + if (libfp) { + path=lbnh->path; + + /* + * Read in a line from the library file. + * This is the relative file specification + * for a .REL file in this library. + */ + +/*2*/ while (fgets(relfil, NINPUT, libfp) != NULL) { + relfil[NINPUT+1] = '\0'; + relfil[strlen(relfil) - 1] = '\0'; + if (path != NULL) { + str = (char *)new(strlen(path)+strlen(relfil)+6); + strcpy(str,path); +#ifdef OTHERSYSTEM +#ifdef SDK +#ifdef UNIX + if (str[strlen(str)-1] != '/') { + strcat(str,"/"); +#else /* UNIX */ + if (str[strlen(str)-1] != '\\') { + strcat(str,"\\"); +#endif /* UNIX */ +#else /* SDK */ + if (str[strlen(str)-1] != '\\') { + strcat(str,"\\"); +#endif /* SDK */ + } +#endif + } else { + str = (char *)new(strlen(relfil) + 5); + } +#ifdef SDK +#ifdef UNIX + if (relfil[0] == '/') { +#else /* UNIX */ + if (relfil[0] == '\\') { +#endif /* UNIX */ +#else /* SDK */ + if (relfil[0] == '\\') { +#endif /* SDK */ + strcat(str,relfil+1); + } else { + strcat(str,relfil); + } + if(strchr(str,FSEPX) == NULL) { +#ifdef SDK + sprintf(&str[strlen(str)], "%co", FSEPX); +#else /* SDK */ + sprintf(&str[strlen(str)], "%crel", FSEPX); +#endif /* SDK */ + } +/*3*/ if ((fp = fopen(str, "r")) != NULL) { + + /* Opened OK - create a new libraryfile object for it */ + This->next = (pmlibraryfile)new( sizeof( mlibraryfile )); + if (This->next == NULL) { + printf("panic: cant allocate memory.\n"); + exit(-1); + } + + This=This->next; + This->next = NULL; + This->loaded=-1; + + strcpy( This->filename, str ); + + ThisSym = This->symbols = (pmlibrarysymbol)malloc( sizeof(mlibrarysymbol)); + ThisSym->next = NULL; + + /* + * Read in the object file. Look for lines that + * begin with "S" and end with "D". These are + * symbol table definitions. If we find one, see + * if it is our symbol. Make sure we only read in + * our object file and don't go into the next one. + */ + +/*4*/ while (fgets(buf, NINPUT, fp) != NULL) { + + buf[NINPUT+1] = '\0'; + buf[strlen(buf) - 1] = '\0'; + + /* + * Skip everything that's not a symbol record. + */ + if (buf[0] != 'S') + continue; + + /* + * When a 'T line' is found terminate file scan. + * All 'S line's preceed 'T line's in .REL files. + */ + if (buf[0] == 'T') + break; + + sscanf(buf, "S %s %c", symname, &c); + + /* If it's an actual symbol, record it */ +/*5*/ if (c == 'D') { + ThisSym->next = (pmlibrarysymbol)malloc(sizeof(mlibrarysymbol)); + ThisSym=ThisSym->next; + if (ThisSym == NULL) { + printf("panic: cant allocate memory.\n"); + exit(-2); + } + This->loaded=0; + ThisSym->next=NULL; + This->str = str; + strcpy(This->relfil,relfil); + strcpy(ThisSym->name, symname); + This->libspc = lbnh->libspc; + } + } /* Closes while - read object file */ + fclose(fp); + } /* Closes if object file opened OK */ + } /* Ends while - processing all in libr */ + fclose(libfp); + } /* Ends good open of libr file */ + } + return 0; +} +#else /* INDEXLIB */ + +int +fndsym(name) +char *name; +{ + FILE *libfp, *fp; + struct lbname *lbnh; + struct lbfile *lbfh, *lbf; + char relfil[NINPUT+2]; + char buf[NINPUT+2]; + char symname[NINPUT]; + char *path,*str; + char c; + + /* + * Search through every library in the linked list "lbnhead". + */ + +/*1*/ for (lbnh=lbnhead; lbnh; lbnh=lbnh->next) { + if ((libfp = fopen(lbnh->libspc, "r")) == NULL) { + fprintf(stderr, "Cannot open library file %s\n", + lbnh->libspc); + lkexit(1); + } + path = lbnh->path; + + /* + * Read in a line from the library file. + * This is the relative file specification + * for a .REL file in this library. + */ + +/*2*/ while (fgets(relfil, NINPUT, libfp) != NULL) { + relfil[NINPUT+1] = '\0'; + relfil[strlen(relfil) - 1] = '\0'; + if (path != NULL) { + str = (char *) new (strlen(path)+strlen(relfil)+6); + strcpy(str,path); +#ifdef OTHERSYSTEM +#ifdef SDK +#ifdef UNIX + if (str[strlen(str)-1] != '/') { + strcat(str,"/"); +#else /* UNIX */ + if (str[strlen(str)-1] != '\\') { + strcat(str,"\\"); +#endif /* UNIX */ +#else /* SDK */ + if (str[strlen(str)-1] != '\\') { + strcat(str,"\\"); +#endif /* SDK */ + } +#endif + } else { + str = (char *) new (strlen(relfil) + 5); + } +#ifdef SDK +#ifdef UNIX + if (relfil[0] == '/') { +#else /* UNIX */ + if (relfil[0] == '\\') { +#endif /* UNIX */ +#else /* SDK */ + if (relfil[0] == '\\') { +#endif /* SDK */ + strcat(str,relfil+1); + } else { + strcat(str,relfil); + } + if(strchr(str,FSEPX) == NULL) { +#ifdef SDK + sprintf(&str[strlen(str)], "%co", FSEPX); +#else /* SDK */ + sprintf(&str[strlen(str)], "%crel", FSEPX); +#endif /* SDK */ + } +/*3*/ if ((fp = fopen(str, "r")) != NULL) { + + /* + * Read in the object file. Look for lines that + * begin with "S" and end with "D". These are + * symbol table definitions. If we find one, see + * if it is our symbol. Make sure we only read in + * our object file and don't go into the next one. + */ + +/*4*/ while (fgets(buf, NINPUT, fp) != NULL) { + + buf[NINPUT+1] = '\0'; + buf[strlen(buf) - 1] = '\0'; + + /* + * Skip everything that's not a symbol record. + */ + if (buf[0] != 'S') + continue; + + /* + * When a 'T line' is found terminate file scan. + * All 'S line's preceed 'T line's in .REL files. + */ + if (buf[0] == 'T') + break; + + sscanf(buf, "S %s %c", symname, &c); + + /* + * If we find a symbol definition for the + * symbol we're looking for, load in the + * file and add it to lbfhead so it gets + * loaded on pass number 2. + */ +/*5*/ if (strncmp(symname, name, NCPS) == 0 && c == 'D') { + + lbfh = (struct lbfile *) new (sizeof(struct lbfile)); + if (lbfhead == NULL) { + lbfhead = lbfh; + } else { + lbf = lbfhead; + while (lbf->next) + lbf = lbf->next; + lbf->next = lbfh; + } + lbfh->libspc = lbnh->libspc; + lbfh->filspc = str; + lbfh->relfil = (char *) new (strlen(relfil) + 1); + strcpy(lbfh->relfil,relfil); + fclose(fp); + fclose(libfp); + loadfile(str); + return (1); + +/*5*/ } + +/*4*/ } + fclose(fp); +/*3*/ } + + free(str); +/*2*/ } + fclose(libfp); +/*1*/ } + return(0); +} +#endif /* INDEXLIB */ + +/*)Function VOID library() + * + * The function library() links all the library object files + * contained in the lbfile structures. + * + * local variables: + * lbfile *lbfh pointer to lbfile structure + * + * global variables: + * lbfile *lbfhead pointer to first lbfile structure + * + * functions called: + * VOID loadfile lklibr.c + * + * side effects: + * Links all files contained in the lbfile structures. + */ + +VOID +library() +{ + struct lbfile *lbfh; + + for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) { + loadfile(lbfh->filspc); + } +} + +/*)Function VOID loadfile(filspc) + * + * char *filspc library object file specification + * + * The function loadfile() links the library object module. + * + * local variables: + * FILE *fp file handle + * int i input line length + * char str[] file input line + * + * global variables: + * char *ip pointer to linker input string + * + * functions called: + * int fclose() c_library + * int fgets() c_library + * FILE * fopen() c_library + * VOID link() lkmain.c + * int strlen() c_library + * + * side effects: + * If file exists it is linked. + */ + +VOID +loadfile(filspc) +char *filspc; +{ + FILE *fp; + char str[NINPUT+2]; + int i; + + if ((fp = fopen(filspc,"r")) != NULL) { + while (fgets(str, NINPUT, fp) != NULL) { + str[NINPUT+1] = '\0'; + i = strlen(str) - 1; + if (str[i] == '\n') + str[i] = '\0'; + ip = str; + link(); + } + fclose(fp); + } +} diff --git a/link/z80/lklist.c b/link/z80/lklist.c new file mode 100644 index 00000000..6b9b1c58 --- /dev/null +++ b/link/z80/lklist.c @@ -0,0 +1,1270 @@ +/* lklist.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +#include +#include +#include +#include "aslink.h" + +/*)Module lklist.c + * + * The module lklist.c contains the functions which + * output the linker .map file and produce a relocated + * listing .rst file. + * + * lklist.c contains the following functions: + * int dgt() + * VOID lstarea() + * VOID lkulist() + * VOID lkalist() + * VOID lkglist() + * VOID newpag() + * VOID slew() + * + * lklist.c contains no local variables. + */ + +/*)Function VOID slew(fp) + * + * FILE * fp output file handle + * + * The function slew() increments the page line counter. + * If the number of lines exceeds the maximum number of + * lines per page then a page skip and a page header are + * output. + * + * local variables: + * int i loop counter + * + * global variables: + * int lop current line number on page + * int xflag Map file radix type flag + * + * functions called: + * int fprintf() c_library + * VOID newpag() lklist.c + * + * side effects: + * The page line and the page count may be updated. + */ + +VOID +slew(fp) +FILE *fp; +{ + register int i; + + if (lop++ >= NLPP) { + newpag(fp); + if (xflag == 0) { + fprintf(fp, "Hexidecimal\n\n"); + } else + if (xflag == 1) { + fprintf(fp, "Octal\n\n"); + } else + if (xflag == 2) { + fprintf(fp, "Decimal\n\n"); + } + fprintf(fp, "Area Addr Size"); + fprintf(fp, " Decimal Bytes (Attributes)\n"); + for(i=0;i<4;++i) + fprintf(fp, " Value--Global"); + fprintf(fp, "\n\n"); + lop += 6; + } +} + +/*)Function VOID newpag() + * + * The function newpag() outputs a page skip, writes the + * first page header line, sets the line count to 1, and + * increments the page counter. + * + * local variables: + * none + * + * global variables: + * int lop current line number on page + * int page current page number + * + * functions called: + * int fprintf() c_library + * + * side effects: + * The page and line counters are updated. + */ + +VOID +newpag(fp) +FILE *fp; +{ + fprintf(fp, "\fASxxxx Linker %s, page %u.\n", VERSION, ++page); + lop = 1; +} + +#if NCPS-8 + +/* NCPS != 8 */ +/*)Function VOID lstarea(xp) + * + * area * xp pointer to an area structure + * + * The function lstarea() creates the linker map output for + * the area specified by pointer xp. The generated output + * area header includes the area name, starting address, + * size of area, number of words (in decimal), and the + * area attributes. The symbols defined in this area are + * sorted by ascending address and output one per line + * in the selected radix. + * + * local variables: + * areax * oxp pointer to an area extension structure + * int c character value + * int i loop counter + * int j bubble sort update status + * char * ptr pointer to an id string + * int nmsym number of symbols in area + * Addr_T a0 temporary + * Addr_T ai temporary + * Addr_T aj temporary + * sym * sp pointer to a symbol structure + * sym ** p pointer to an array of + * pointers to symbol structures + * + * global variables: + * FILE *mfp Map output file handle + * sym *symhash[NHASH] array of pointers to NHASH + * linked symbol lists + * int xflag Map file radix type flag + * + * functions called: + * int fprintf() c_library + * VOID free() c_library + * char * malloc() c_library + * char putc() c_library + * VOID slew() lklist.c + * + * side effects: + * Map output generated. + */ + +#ifndef MLH_MAP +VOID +lstarea(xp) +struct area *xp; +{ + register struct area *op; + register struct areax *oxp; + register c, i, j; + register char *ptr; + int nmsym; + Addr_T a0, ai, aj; + struct sym *sp; + struct sym **p; + + putc('\n', mfp); + if (xflag == 0) { + fprintf(mfp, "Hexidecimal\n\n"); + } else + if (xflag == 1) { + fprintf(mfp, "Octal\n\n"); + } else + if (xflag == 2) { + fprintf(mfp, "Decimal\n\n"); + } + fprintf(mfp, "Area "); + fprintf(mfp, "Addr Size Decimal Bytes (Attributes)\n"); + fprintf(mfp, "-------------------------------- "); + fprintf(mfp, "---- ---- ------- ----- ------------\n"); + /* + * Output Area Header + */ + ptr = &xp->a_id[0]; + while (ptr < &xp->a_id[NCPS]) { + if ((c = *ptr++) != 0) { + putc(c, mfp); + } else { + putc(' ', mfp); + } + } + ai = xp->a_addr; + aj = xp->a_size; + if (xflag == 0) { + fprintf(mfp, " %04X %04X", ai, aj); + } else + if (xflag == 1) { + fprintf(mfp, " %06o %06o", ai, aj); + } else + if (xflag == 2) { + fprintf(mfp, " %05u %05u", ai, aj); + } + fprintf(mfp, " = %6u. bytes ", aj); + if (xp->a_flag & A_ABS) { + fprintf(mfp, "(ABS"); + } else { + fprintf(mfp, "(REL"); + } + if (xp->a_flag & A_OVR) { + fprintf(mfp, ",OVR"); + } else { + fprintf(mfp, ",CON"); + } + if (xp->a_flag & A_PAG) { + fprintf(mfp, ",PAG"); + } + fprintf(mfp, ")"); + if (xp->a_flag & A_PAG) { + ai = (ai & 0xFF); + aj = (aj > 256); + if (ai || aj) { fprintf(mfp, " "); } + if (ai) { fprintf(mfp, " Boundary"); } + if (ai & aj) { fprintf(mfp, " /"); } + if (aj) { fprintf(mfp, " Length"); } + if (ai || aj) { fprintf(mfp, " Error"); } + } + + /* + * Find number of symbols in area + */ + nmsym = 0; + oxp = xp->a_axp; + while (oxp) { + for (i=0; is_axp) + ++nmsym; + sp = sp->s_sp; + } + } + oxp = oxp->a_axp; + } + if (nmsym == 0) { + putc('\n', mfp); + return; + } + + /* + * Allocate space for an array of pointers to symbols + * and load array. + */ + if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *))) + == NULL) { + fprintf(mfp, "\nInsufficient space to build Map Segment.\n"); + return; + } + nmsym = 0; + oxp = xp->a_axp; + while (oxp) { + for (i=0; is_axp) { + p[nmsym++] = sp; + } + sp = sp->s_sp; + } + } + oxp = oxp->a_axp; + } + + /* + * Bubble Sort of Addresses in Symbol Table Array + */ + j = 1; + while (j) { + j = 0; + sp = p[0]; + a0 = sp->s_addr + sp->s_axp->a_addr; + for (i=1; is_addr + sp->s_axp->a_addr; + if (a0 > ai) { + j = 1; + p[i] = p[i-1]; + p[i-1] = sp; + } + a0 = ai; + } + } + + /* + * Symbol Table Output + */ + i = 0; + fprintf(mfp, "\n\n"); + fprintf(mfp, " Value Global\n"); + fprintf(mfp, " ----- --------------------------------"); + while (i < nmsym) { + fprintf(mfp, "\n"); + fprintf(mfp, " "); + + sp = p[i]; + aj = sp->s_addr + sp->s_axp->a_addr; + if (xflag == 0) { + fprintf(mfp, " %04X ", aj); + } else + if (xflag == 1) { + fprintf(mfp, "%06o ", aj); + } else + if (xflag == 2) { + fprintf(mfp, " %05u ", aj); + } + ptr = &sp->s_id[0]; + while (ptr < &sp->s_id[NCPS]) { + if ((c = *ptr++) != 0) { + putc(c, mfp); + } else { + putc(' ', mfp); + } + } + i++; + } + putc('\n', mfp); + free(p); +} +#else +VOID lstarea(struct area *xp) +{ + register struct areax *oxp; + register int i, j; + int nmsym; + Addr_T a0, ai = 0, aj = 0; + struct sym *sp; + struct sym **p; + + /* + * Find number of symbols in area + */ + nmsym = 0; + oxp = xp->a_axp; + while (oxp) { + for (i=0; is_axp) + ++nmsym; + sp = sp->s_sp; + } + } + oxp = oxp->a_axp; + } + + /* + * Symbol Table Output + */ + if (!((xp->a_size==0)&&(xp->a_addr==0)&&(nmsym==0))) { + fprintf(mfp, "AREA %s\n", xp->a_id ); + switch (xflag) { + case 1: + fprintf(mfp, "\tRADIX OCTAL\n" ); + break; + case 2: + fprintf(mfp, "\tRADIX DEC\n" ); + break; + default: + fprintf(mfp, "\tRADIX HEX\n" ); + break; + } + fprintf( mfp, "\tBASE %04X\n" + "\tSIZE %04X\n" + "\tATTRIB " + , xp->a_addr, xp->a_size ); + if (xp->a_flag & A_ABS) { + fprintf(mfp, "ABS"); + } else { + fprintf(mfp, "REL"); + } + if (xp->a_flag & A_OVR) { + fprintf(mfp, " OVR"); + } else { + fprintf(mfp, " CON"); + } + if (xp->a_flag & A_PAG) { + fprintf(mfp, " PAG"); + } + if (xp->a_flag & A_PAG) { + ai = (ai & 0xFF); + aj = (aj > 256); + if (ai || aj) { fprintf(mfp, " "); } + if (ai) { fprintf(mfp, " Boundary"); } + if (ai & aj) { fprintf(mfp, " /"); } + if (aj) { fprintf(mfp, " Length"); } + if (ai || aj) { fprintf(mfp, " Error"); } + } + + fprintf( mfp,"\n"); + if (nmsym>0) { + /* + * Allocate space for an array of pointers to symbols + * and load array. + */ + if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *))) + == NULL) { + fprintf(mfp, "\nInsufficient space to build Map Segment.\n"); + return; + } + nmsym = 0; + oxp = xp->a_axp; + while (oxp) { + for (i=0; is_axp) { + p[nmsym++] = sp; + } + sp = sp->s_sp; + } + } + oxp = oxp->a_axp; + } + + /* + * Bubble Sort of Addresses in Symbol Table Array + */ + j = 1; + while (j) { + j = 0; + sp = p[0]; + a0 = sp->s_addr + sp->s_axp->a_addr; + for (i=1; is_addr + sp->s_axp->a_addr; + if (a0 > ai) { + j = 1; + p[i] = p[i-1]; + p[i-1] = sp; + } + a0 = ai; + } + } + + fprintf( mfp, "\tGLOBALS\n"); + i = 0; + while (i < nmsym) { + fprintf(mfp, "\t\t%s\t%04X\n", p[i]->s_id, p[i]->s_addr + p[i]->s_axp->a_addr ); + i++; + } + free(p); + } + } +} +#endif /* MLH_MAP */ +#else + +/* NCPS == 8 */ +/*)Function VOID lstarea(xp) + * + * area * xp pointer to an area structure + * + * The function lstarea() creates the linker map output for + * the area specified by pointer xp. The generated output + * area header includes the area name, starting address, + * size of area, number of words (in decimal), and the + * area attributes. The symbols defined in this area are + * sorted by ascending address and output four per line + * in the selected radix. + * + * local variables: + * areax * oxp pointer to an area extension structure + * int c character value + * int i loop counter + * int j bubble sort update status + * char * ptr pointer to an id string + * int nmsym number of symbols in area + * Addr_T a0 temporary + * Addr_T ai temporary + * Addr_T aj temporary + * sym * sp pointer to a symbol structure + * sym ** p pointer to an array of + * pointers to symbol structures + * + * global variables: + * FILE *mfp Map output file handle + * sym *symhash[NHASH] array of pointers to NHASH + * linked symbol lists + * int xflag Map file radix type flag + * + * functions called: + * int fprintf() c_library + * VOID free() c_library + * char * malloc() c_library + * char putc() c_library + * VOID slew() lklist.c + * + * side effects: + * Map output generated. + */ + +VOID +lstarea(xp) +struct area *xp; +{ + register struct areax *oxp; + register c, i, j; + register char *ptr; + int nmsym; + Addr_T a0, ai, aj; + struct sym *sp; + struct sym **p; + + putc('\n', mfp); + slew(mfp); + /* + * Output Area Header + */ + ptr = &xp->a_id[0]; + while (ptr < &xp->a_id[NCPS]) { + if ((c = *ptr++) != 0) { + putc(c, mfp); + } else { + putc(' ', mfp); + } + } + ai = xp->a_addr; + aj = xp->a_size; + if (xflag == 0) { + fprintf(mfp, " %04X %04X", ai, aj); + } else + if (xflag == 1) { + fprintf(mfp, " %06o %06o", ai, aj); + } else + if (xflag == 2) { + fprintf(mfp, " %05u %05u", ai, aj); + } + fprintf(mfp, " = %6u. bytes ", aj); + if (xp->a_flag & A_ABS) { + fprintf(mfp, "(ABS"); + } else { + fprintf(mfp, "(REL"); + } + if (xp->a_flag & A_OVR) { + fprintf(mfp, ",OVR"); + } else { + fprintf(mfp, ",CON"); + } + if (xp->a_flag & A_PAG) { + fprintf(mfp, ",PAG"); + } + fprintf(mfp, ")"); + if (xp->a_flag & A_PAG) { + ai = (ai & 0xFF); + aj = (aj > 256); + if (ai || aj) { fprintf(mfp, " "); } + if (ai) { fprintf(mfp, " Boundary"); } + if (ai & aj) { fprintf(mfp, " /"); } + if (aj) { fprintf(mfp, " Length"); } + if (ai || aj) { fprintf(mfp, " Error"); } + } + + /* + * Find number of symbols in area + */ + nmsym = 0; + oxp = xp->a_axp; + while (oxp) { + for (i=0; is_axp) + ++nmsym; + sp = sp->s_sp; + } + } + oxp = oxp->a_axp; + } + if (nmsym == 0) { + putc('\n', mfp); + slew(mfp); + return; + } + + /* + * Allocate space for an array of pointers to symbols + * and load array. + */ + if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *))) + == NULL) { + fprintf(mfp, "\nInsufficient space to build Map Segment.\n"); + slew(mfp); + return; + } + nmsym = 0; + oxp = xp->a_axp; + while (oxp) { + for (i=0; is_axp) { + p[nmsym++] = sp; + } + sp = sp->s_sp; + } + } + oxp = oxp->a_axp; + } + + /* + * Bubble Sort of Addresses in Symbol Table Array + */ + j = 1; + while (j) { + j = 0; + sp = p[0]; + a0 = sp->s_addr + sp->s_axp->a_addr; + for (i=1; is_addr + sp->s_axp->a_addr; + if (a0 > ai) { + j = 1; + p[i] = p[i-1]; + p[i-1] = sp; + } + a0 = ai; + } + } + + /* + * Symbol Table Output + */ + i = 0; + while (i < nmsym) { + if (i % 4 == 0) { + fprintf(mfp, "\n"); + slew(mfp); + fprintf(mfp, " "); + } + sp = p[i]; + aj = sp->s_addr + sp->s_axp->a_addr; + if (xflag == 0) { + fprintf(mfp, " %04X ", aj); + } else + if (xflag == 1) { + fprintf(mfp, "%06o ", aj); + } else + if (xflag == 2) { + fprintf(mfp, " %05u ", aj); + } + ptr = &sp->s_id[0]; + while (ptr < &sp->s_id[NCPS]) { + if ((c = *ptr++) != 0) { + putc(c, mfp); + } else { + putc(' ', mfp); + } + } + if (++i < nmsym) + if (i % 4 != 0) + fprintf(mfp, " | "); + } + putc('\n', mfp); + free(p); + slew(mfp); +} +#endif + +#ifdef SDK +VOID lstareatosym(struct area *xp) +{ + /* Output the current area symbols to a NO$GMB .sym file */ + register struct areax *oxp; + register int i, j; + int nmsym; + Addr_T a0, ai; + struct sym *sp; + struct sym **p; + + /* + * Find number of symbols in area + */ + nmsym = 0; + oxp = xp->a_axp; + while (oxp) { + for (i=0; is_axp) + ++nmsym; + sp = sp->s_sp; + } + } + oxp = oxp->a_axp; + } + + /* + * Symbol Table Output + */ + if (!((xp->a_size==0)&&(xp->a_addr==0)&&(nmsym==0))) { + /* Dont worry about any area information */ + fprintf(mfp, "; Area: %s\n", xp->a_id ); + if (nmsym>0) { + /* + * Allocate space for an array of pointers to symbols + * and load array. + */ + if ( (p = (struct sym **) malloc(nmsym*sizeof(struct sym *))) + == NULL) { + fprintf(mfp, "\nInsufficient space to build Map Segment.\n"); + return; + } + nmsym = 0; + oxp = xp->a_axp; + while (oxp) { + for (i=0; is_axp) { + p[nmsym++] = sp; + } + sp = sp->s_sp; + } + } + oxp = oxp->a_axp; + } + + /* + * Bubble Sort of Addresses in Symbol Table Array + */ + j = 1; + while (j) { + j = 0; + sp = p[0]; + a0 = sp->s_addr + sp->s_axp->a_addr; + for (i=1; is_addr + sp->s_axp->a_addr; + if (a0 > ai) { + j = 1; + p[i] = p[i-1]; + p[i-1] = sp; + } + a0 = ai; + } + } + i = 0; + while (i < nmsym) { + /* no$gmb requires the symbol names to be less than 32 chars long. Truncate. */ + char name[32]; + strncpy(name, p[i]->s_id, 31); + name[31] = '\0'; + if ((strncmp("l__", name, 3)!=0)&&(strchr(name,' ')==NULL)) { + a0=p[i]->s_addr + p[i]->s_axp->a_addr; + if (a0>0x7FFFU) { + /* Not inside the ROM, so treat as being in bank zero */ + fprintf(mfp, "00:%04X %s\n", a0, name); + } + else { + fprintf(mfp, "%02X:%04X %s\n", a0/16384, a0, name); + } + } + i++; + } + free(p); + } + } +} +#endif + +/*)Function VOID lkulist(i) + * + * int i i # 0 process LST to RST file + * i = 0 copy remainder of LST file + * to RST file and close files + * + * The function lkulist() creates a relocated listing (.rst) + * output file from the ASxxxx assembler listing (.lst) + * files. The .lst file's program address and code bytes + * are changed to reflect the changes made by ASlink as + * the .rel files are combined into a single relocated + * output file. + * + * local variables: + * Addr_T pc current program counter address + * + * global variables: + * int hilo byte order + * int gline get a line from the LST file + * to translate for the RST file + * char rb[] read listing file text line + * FILE *rfp The file handle to the current + * output RST file + * int rtcnt count of data words + * int rtflg[] output the data flag + * Addr_T rtval[] relocated data + * FILE *tfp The file handle to the current + * LST file being scanned + * + * functions called: + * int fclose() c_library + * int fgets() c_library + * int fprintf() c_library + * VOID lkalist() lklist.c + * VOID lkglist() lklist.c + * + * side effects: + * A .rst file is created for each available .lst + * file associated with a .rel file. + */ + +VOID +lkulist(i) +int i; +{ + Addr_T pc; + + /* + * Exit if listing file is not open + */ + if (tfp == NULL) + return; + + /* + * Normal processing of LST to RST + */ + if (i) { + /* + * Evaluate current code address + */ + if (hilo == 0) { + pc = ((rtval[1] & 0xFF) << 8) + (rtval[0] & 0xFF); + } else { + pc = ((rtval[0] & 0xFF) << 8) + (rtval[1] & 0xFF); + } + + /* + * Line with only address + */ + if (rtcnt == 2) { + lkalist(pc); + + /* + * Line with address and code + */ + } else { + for (i=2; i < rtcnt; i++) { + if (rtflg[i]) { + lkglist(pc++, rtval[i] & 0xFF); + } + } + } + + /* + * Copy remainder of LST to RST + */ + } else { + if (gline == 0) + fprintf(rfp, rb); + + while (fgets(rb, sizeof(rb), tfp) != 0) { + fprintf(rfp, rb); + } + fclose(tfp); + tfp = NULL; + fclose(rfp); + rfp = NULL; + } +} + +/*)Function VOID lkalist(pc) + * + * int pc current program counter value + * + * The function lkalist() performs the following functions: + * + * (1) if the value of gline = 0 then the current listing + * file line is copied to the relocated listing file output. + * + * (2) the listing file is read line by line and copied to + * the relocated listing file until a valid source + * line number and a program counter value of the correct + * radix is found. The new relocated pc value is substituted + * and the line is written to the RST file. + * + * local variables: + * int i loop counter + * char str[] temporary string + * + * global variables: + * int gcntr data byte counter + * int gline get a line from the LST file + * to translate for the RST file + * char rb[] read listing file text line + * char *rp pointer to listing file text line + * FILE *rfp The file handle to the current + * output RST file + * FILE *tfp The file handle to the current + * LST file being scanned + * + * functions called: + * int dgt() lklist.c + * int fclose() c_library + * int fgets() c_library + * int fprintf() c_library + * int sprintf() c_library + * char * strncpy() c_library + * + * side effects: + * Lines of the LST file are copied to the RST file, + * the last line copied has the code address + * updated to reflect the program relocation. + */ + +VOID +lkalist(pc) +Addr_T pc; +{ + char str[8]; + int i; + + /* + * Exit if listing file is not open + */ +loop: if (tfp == NULL) + return; + + /* + * Copy current LST to RST + */ + if (gline == 0) { + fprintf(rfp, rb); + gline = 1; + } + + /* + * Clear text line buffer + */ + for (i=0,rp=rb; i +#include +//#include +#include "aslink.h" +#include + +#ifndef SDK_VERSION_STRING +#define SDK_VERSION_STRING "3.0.0" +#endif +#ifndef TARGET_STRING +#define TARGET_STRING "gbz80" +#endif + +/*)Module lkmain.c + * + * The module lkmain.c contains the functions which + * (1) input the linker options, parameters, and specifications + * (2) perform a two pass link + * (3) produce the appropriate linked data output and/or + * link map file and/or relocated listing files. + * + * lkmain.c contains the following functions: + * FILE * afile(fn,ft,wf) + * VOID bassav() + * VOID gblsav() + * VOID link() + * VOID lkexit() + * VOID main(argc,argv) + * VOID map() + * int parse() + * VOID setbas() + * VOID setgbl() + * VOID usage() + * + * lkmain.c contains the following local variables: + * char * usetext[] array of pointers to the + * command option tect lines + * + */ + +/*)Function VOID main(argc,argv) + * + * int argc number of command line arguments + 1 + * char * argv[] array of pointers to the command line + * arguments + * + * The function main() evaluates the command line arguments to + * determine if the linker parameters are to input through 'stdin' + * or read from a command file. The functiond getLine_() and parse() + * are to input and evaluate the linker parameters. The linking process + * proceeds by making the first pass through each .rel file in the order + * presented to the linker. At the end of the first pass the setbase(), + * lnkarea(), setgbl(), and symdef() functions are called to evaluate + * the base address terms, link all areas, define global variables, + * and look for undefined symbols. Following these routines a linker + * map file may be produced and the linker output files may be opened. + * The second pass through the .rel files will output the linked data + * in one of the four supported formats. + * + * local variables: + * char * p pointer to an argument string + * int c character from argument string + * int i loop counter + * + * global variables: + * text line in ib[] + * lfile *cfp The pointer *cfp points to the + * current lfile structure + * char ctype[] array of character types, one per + * ASCII character + * lfile *filep The pointer *filep points to the + * beginning of a linked list of + * lfile structures. + * head *hp Pointer to the current + * head structure + * char ib[NINPUT] .rel file text line + * char *ip pointer into the .rel file + * lfile *linkp pointer to first lfile structure + * containing an input .rel file + * specification + * int lkerr error flag + * int mflag Map output flag + * int oflag Output file type flag + * FILE *ofp Output file handle + * for word formats + * FILE *ofph Output file handle + * for high byte format + * FILE *ofpl Output file handle + * for low byte format + * int pass linker pass number + * int pflag print linker command file flag + * int radix current number conversion radix + * FILE *sfp The file handle sfp points to the + * currently open file + * lfile *startp asmlnk startup file structure + * FILE * stdin c_library + * FILE * stdout c_library + * + * functions called: + * FILE * afile() lkmain.c + * int fclose() c_library + * int fprintf() c_library + * int getLine_() lklex.c + * VOID library() lklibr.c + * VOID link() lkmain.c + * VOID lkexit() lkmain.c + * VOID lnkarea() lkarea.c + * VOID map() lkmain.c + * VOID new() lksym.c + * int parse() lkmain.c + * VOID reloc() lkreloc.c + * VOID search() lklibr.c + * VOID setbas() lkmain.c + * VOID setgbl() lkmain.c + * VOID symdef() lksym.c + * VOID usage() lkmain.c + * + * side effects: + * Completion of main() completes the linking process + * and may produce a map file (.map) and/or a linked + * data files (.ihx or .s19) and/or one or more + * relocated listing files (.rst). + */ + +#ifdef SDK +int binary = 0; +#endif /* SDK */ +#ifdef GAMEBOY +char *default_basep[] = { + "_CODE=0x0200", + "_DATA=0xC0A0", + NULL +}; + +char *default_globlp[] = { + /* DMA transfer must start at multiples of 0x100 */ + ".OAM=0xC000", + ".STACK=0xE000", + ".refresh_OAM=0xFF80", + + ".init=0x0000", + + NULL +}; +#endif /* GAMEBOY */ + +int +main(argc, argv) +char *argv[]; +{ + register char *p; + register int c, i; + +#ifdef GAMEBOY + nb_rom_banks = 2; + nb_ram_banks = 0; + mbc_type = 0; + symflag=0; + + for(i = 0; default_basep[i] != NULL; i++) { + if(basep == NULL) { + basep = (struct base *)new(sizeof(struct base)); + bsp = basep; + } else { + bsp->b_base = (struct base *)new(sizeof(struct base)); + bsp = bsp->b_base; + } + bsp->b_strp = default_basep[i]; + } + for(i = 0; default_globlp[i] != NULL; i++) { + if(globlp == NULL) { + globlp = (struct globl *)new(sizeof(struct globl)); + gsp = globlp; + } else { + gsp->g_globl = (struct globl *)new(sizeof(struct globl)); + gsp = gsp->g_globl; + } + gsp->g_strp = default_globlp[i]; + } +#endif /* GAMEBOY */ +#ifndef SDK + fprintf(stdout, "\n"); +#endif /* SDK */ + + startp = (struct lfile *) new (sizeof (struct lfile)); + + pflag = 1; + for (i=1; if_type = F_STD; + break; + + case 'f': + case 'F': + startp->f_type = F_LNK; + break; + + case 'n': + case 'N': + pflag = 0; + break; + + case 'p': + case 'P': + pflag = 1; + break; + + default: + usage(); + } + } + +#ifdef SDK + if(c == '-') { + startp->f_type = F_CMD; + startp->f_idp = (char *)&argv[i+1]; + break; + } +#endif /* SDK */ + + } else { + if (startp->f_type == F_LNK) { + startp->f_idp = p; + } + } + } + if (startp->f_type == F_INV) + usage(); + if (startp->f_type == F_LNK && startp->f_idp == NULL) + usage(); +#ifdef SDK + if (startp->f_type == F_CMD && startp->f_idp == NULL) + usage(); +#endif /* SDK */ + + cfp = NULL; + sfp = NULL; + filep = startp; + while (1) { + ip = ib; + if (getLine_() == 0) + break; + if (pflag && sfp != stdin) + fprintf(stdout, "%s\n", ip); + if (*ip == '\0' || parse()) + break; + } + if (sfp) + fclose(sfp); + if (linkp == NULL) + usage(); +#ifdef SDK + if (linkp->f_flp == NULL) + usage(); +#endif /* SDK */ + +#ifdef GAMEBOY + for(i = 1; i < nb_rom_banks; i++) { + bsp->b_base = (struct base *)new(sizeof(struct base)); + bsp = bsp->b_base; + bsp->b_strp = (char *)malloc(18); + sprintf(bsp->b_strp, "_CODE_%d=0x4000", i); + } + for(i = 0; i < nb_ram_banks; i++) { + bsp->b_base = (struct base *)new(sizeof(struct base)); + bsp = bsp->b_base; + bsp->b_strp = (char *)malloc(18); + sprintf(bsp->b_strp, "_DATA_%d=0xA000", i); + } +#endif /* GAMEBOY */ + + syminit(); + for (pass=0; pass<2; ++pass) { + cfp = NULL; + sfp = NULL; +#ifdef SDK + filep = linkp->f_flp; +#else /* SDK */ + filep = linkp; +#endif /* SDK */ + hp = NULL; + radix = 10; + + while (getLine_()) { + ip = ib; + link(); + } + if (pass == 0) { + /* + * Search libraries for global symbols + */ + search(); + /* + * Set area base addresses. + */ + setbas(); + /* + * Link all area addresses. + */ + lnkarea(); + /* + * Process global definitions. + */ + setgbl(); + /* + * Check for undefined globals. + */ + symdef(stderr); +#ifdef SDK + if (symflag) + sym(); +#endif + /* + * Output Link Map. + */ + if (mflag) + map(); + /* + * Open output file + */ + if (oflag == 1) { +#ifdef SDK + ofp = afile(linkp->f_idp, "ihx", 1); +#else /* SDK */ + ofp = afile(linkp->f_idp, "IHX", 1); +#endif /* SDK */ + if (ofp == NULL) { + lkexit(1); + } + } else + if (oflag == 2) { +#ifdef SDK + ofp = afile(linkp->f_idp, "s19", 1); +#else /* SDK */ + ofp = afile(linkp->f_idp, "S19", 1); +#endif /* SDK */ + if (ofp == NULL) { + lkexit(1); + } +#ifdef SDK + } else + if (oflag == 3) { + binary = 1; + ofp = afile(linkp->f_idp, "", 1); + binary = 0; + if (ofp == NULL) { + lkexit(1); + } +#endif /* SDK */ + } + } else { + /* + * Link in library files + */ + library(); + reloc('E'); + } + } + lkexit(lkerr); + + /* Never get here. */ + return 0; +} + +/*)Function VOID lkexit(i) + * + * int i exit code + * + * The function lkexit() explicitly closes all open + * files and then terminates the program. + * + * local variables: + * none + * + * global variables: + * FILE * mfp file handle for .map + * FILE * ofp file handle for .ihx/.s19 + * FILE * rfp file hanlde for .rst + * FILE * sfp file handle for .rel + * FILE * tfp file handle for .lst + * + * functions called: + * int fclose() c_library + * VOID exit() c_library + * + * side effects: + * All files closed. Program terminates. + */ + +VOID +lkexit(i) +int i; +{ + if (mfp != NULL) fclose(mfp); + if (ofp != NULL) fclose(ofp); + if (rfp != NULL) fclose(rfp); + if (sfp != NULL) fclose(sfp); + if (tfp != NULL) fclose(tfp); + exit(i); +} + +/*)Function link() + * + * The function link() evaluates the directives for each line of + * text read from the .rel file(s). The valid directives processed + * are: + * X, D, Q, H, M, A, S, T, R, and P. + * + * local variables: + * int c first non blank character of a line + * + * global variables: + * head *headp The pointer to the first + * head structure of a linked list + * head *hp Pointer to the current + * head structure + * int pass linker pass number + * int radix current number conversion radix + * + * functions called: + * char endline() lklex.c + * VOID module() lkhead.c + * VOID newarea() lkarea.c + * VOID newhead() lkhead.c + * sym * newsym() lksym.c + * VOID reloc() lkreloc.c + * + * side effects: + * Head, area, and symbol structures are created and + * the radix is set as the .rel file(s) are read. + */ + +VOID +link() +{ + register int c; + + if ((c=endline()) == 0) { return; } + switch (c) { + + case 'X': + radix = 16; + break; + + case 'D': + radix = 10; + break; + + case 'Q': + radix = 8; + break; + + case 'H': + if (pass == 0) { + newhead(); + } else { + if (hp == 0) { + hp = headp; + } else { + hp = hp->h_hp; + } + } + sdp.s_area = NULL; + sdp.s_areax = NULL; + sdp.s_addr = 0; + break; + + case 'M': + if (pass == 0) + module(); + break; + + case 'A': + if (pass == 0) + newarea(); + if (sdp.s_area == NULL) { + sdp.s_area = areap; + sdp.s_areax = areap->a_axp; + sdp.s_addr = 0; + } + break; + + case 'S': + if (pass == 0) + newsym(); + break; + + case 'T': + case 'R': + case 'P': + if (pass == 0) + break; + reloc(c); + break; + + default: + break; + } + if (c == 'X' || c == 'D' || c == 'Q') { + if ((c = get()) == 'H') { + hilo = 1; + } else + if (c == 'L') { + hilo = 0; + } + } +} + +/*)Function VOID map() + * + * The function map() opens the output map file and calls the various + * routines to + * (1) output the variables in each area, + * (2) list the files processed with module names, + * (3) list the libraries file processed, + * (4) list base address definitions, + * (5) list global variable definitions, and + * (6) list any undefined variables. + * + * local variables: + * int i counter + * head * hdp pointer to head structure + * lbfile *lbfh pointer to library file structure + * + * global variables: + * area *ap Pointer to the current + * area structure + * area *areap The pointer to the first + * area structure of a linked list + * base *basep The pointer to the first + * base structure + * base *bsp Pointer to the current + * base structure + * lfile *filep The pointer *filep points to the + * beginning of a linked list of + * lfile structures. + * globl *globlp The pointer to the first + * globl structure + * globl *gsp Pointer to the current + * globl structure + * head *headp The pointer to the first + * head structure of a linked list + * lbfile *lbfhead The pointer to the first + * lbfile structure of a linked list + * lfile *linkp pointer to first lfile structure + * containing an input REL file + * specification + * int lop current line number on page + * FILE *mfp Map output file handle + * int page current page number + * + * functions called: + * FILE * afile() lkmain.c + * int fprintf() c_library + * VOID lkexit() lkmain.c + * VOID lstarea() lklist.c + * VOID newpag() lklist.c + * VOID symdef() lksym.c + * + * side effects: + * The map file is created. + */ + +#ifndef MLH_MAP +VOID +map() +{ + register i; + register struct head *hdp; + register struct lbfile *lbfh; + + /* + * Open Map File + */ +#ifdef SDK + mfp = afile(linkp->f_idp, "map", 1); +#else /* SDK */ + mfp = afile(linkp->f_idp, "MAP", 1); +#endif /* SDK */ + if (mfp == NULL) { + lkexit(1); + } + + /* + * Output Map Area Lists + */ + page = 0; + lop = NLPP; + ap = areap; + while (ap) { + lstarea(ap); + ap = ap->a_ap; + } + /* + * List Linked Files + */ + newpag(mfp); + fprintf(mfp, "\nFiles Linked [ module(s) ]\n\n"); + hdp = headp; +#ifdef SDK + filep = linkp->f_flp; +#else /* SDK */ + filep = linkp; +#endif /* SDK */ + while (filep) { + fprintf(mfp, "%-16s", filep->f_idp); + i = 0; + while ((hdp != NULL) && (hdp->h_lfile == filep)) { + if (i % 5) { + fprintf(mfp, ", %8.8s", hdp->m_id); + } else { + if (i) { + fprintf(mfp, ",\n%20s%8.8s", "", hdp->m_id); + } else { + fprintf(mfp, " [ %8.8s", hdp->m_id); + } + } + hdp = hdp->h_hp; + i++; + } + if (i) + fprintf(mfp, " ]"); + fprintf(mfp, "\n"); + filep = filep->f_flp; + } + /* + * List Linked Libraries + */ + if (lbfhead != NULL) { + fprintf(mfp, + "\nLibraries Linked [ object file ]\n\n"); + for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) { + fprintf(mfp, "%-32s [ %16.16s ]\n", + lbfh->libspc, lbfh->relfil); + } + fprintf(mfp, "\n"); + } + /* + * List Base Address Definitions + */ + if (basep) { + newpag(mfp); + fprintf(mfp, "\nUser Base Address Definitions\n\n"); + bsp = basep; + while (bsp) { + fprintf(mfp, "%s\n", bsp->b_strp); + bsp = bsp->b_base; + } + } + /* + * List Global Definitions + */ + if (globlp) { + newpag(mfp); + fprintf(mfp, "\nUser Global Definitions\n\n"); + gsp = globlp; + while (gsp) { + fprintf(mfp, "%s\n", gsp->g_strp); + gsp = gsp->g_globl; + } + } + fprintf(mfp, "\n\f"); + symdef(mfp); +} +#else +VOID map() +{ + register struct head *hdp; + register struct lbfile *lbfh; + + /* + * Open Map File + */ +#ifdef SDK + mfp = afile(linkp->f_idp, "map", 1); +#else /* SDK */ + mfp = afile(linkp->f_idp, "MAP", 1); +#endif /* SDK */ + if (mfp == NULL) { + lkexit(1); + } + + /* + *Output Map Area Lists + */ + page = 0; + lop = NLPP; + ap = areap; + while (ap) { + lstarea(ap); + ap = ap->a_ap; + } + /* + * List Linked Files + */ + hdp = headp; +#ifdef SDK + filep = linkp->f_flp; +#else /* SDK */ + filep = linkp; +#endif /* SDK */ + if (filep) { + fprintf( mfp, "MODULES\n"); + } + while (filep) { + fprintf(mfp, "\tFILE %s\n", filep->f_idp); + while ((hdp != NULL) && (hdp->h_lfile == filep)) { + if (strlen(hdp->m_id)>0) + fprintf(mfp, "\t\tNAME %s\n", hdp->m_id); + hdp = hdp->h_hp; + } + filep = filep->f_flp; + } + /* + * List Linked Libraries + */ + if (lbfhead != NULL) { + fprintf(mfp, "LIBRARIES\n"); + for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) { + fprintf(mfp, "\tLIBRARY %s\n" + "\t\tMODULE %s\n", + lbfh->libspc, lbfh->relfil); + } + } + /* + * List Base Address Definitions + */ + if (basep) { + fprintf(mfp, "USERBASEDEF\n"); + bsp = basep; + while (bsp) { + fprintf(mfp, "\t%s\n", bsp->b_strp); + bsp = bsp->b_base; + } + } + /* + * List Global Definitions + */ + if (globlp) { + fprintf(mfp, "USERGLOBALDEF\n"); + gsp = globlp; + while (gsp) { + fprintf(mfp, "\t%s\n", gsp->g_strp); + gsp = gsp->g_globl; + } + } + symdef(mfp); +#ifdef SDK + if (mfp!=NULL) { + fclose(mfp); + mfp = NULL; + } +#endif +} +#endif /* MLH_MAP */ + +#ifdef SDK +/* PENDING */ +VOID lstareatosym(struct area *xp); + +VOID sym() +{ + /* + * Open sym File + */ + mfp = afile(linkp->f_idp, "sym", 1); + if (mfp == NULL) { + lkexit(1); + } + fprintf( mfp, "; no$gmb format .sym file\n" + "; Generated automagically by ASxxxx linker %s (SDK " SDK_VERSION_STRING ")\n" + , VERSION ); + /* + * Output sym Area Lists + */ + page = 0; + lop = NLPP; + ap = areap; + while (ap) { + lstareatosym(ap); + ap = ap->a_ap; + } + if (mfp!=NULL) { + fclose(mfp); + mfp = NULL; + } +} +#endif /* SDK */ + +/*)Function int parse() + * + * The function parse() evaluates all command line or file input + * linker directives and updates the appropriate variables. + * + * local variables: + * int c character value + * char fid[] file id string + * + * global variables: + * char ctype[] array of character types, one per + * ASCII character + * lfile *lfp pointer to current lfile structure + * being processed by parse() + * lfile *linkp pointer to first lfile structure + * containing an input REL file + * specification + * int mflag Map output flag + * int oflag Output file type flag + * int pflag print linker command file flag + * FILE * stderr c_library + * int uflag Relocated listing flag + * int xflag Map file radix type flag + * + * Functions called: + * VOID addlib() lklibr.c + * VOID addpath() lklibr.c + * VOID bassav() lkmain.c + * int fprintf() c_library + * VOID gblsav() lkmain.c + * VOID getfid() lklex.c + * char getnb() lklex.c + * VOID lkexit() lkmain.c + * char * strcpy() c_library + * int strlen() c_library + * + * side effects: + * Various linker flags are updated and the linked + * structure lfile is created. + */ + +int +parse() +{ + register int c; + char fid[NINPUT]; + + while ((c = getnb()) != 0) { + if ( c == '-') { + while (ctype[c=get()] & LETTER) { + switch(c) { + + case 'i': + case 'I': + oflag = 1; + break; + + case 's': + case 'S': + oflag = 2; + break; +#ifdef GAMEBOY + case 'y': + case 'Y': + c = get(); + if(c == 'O' || c == 'o') + nb_rom_banks = expr(0); + else if(c == 'A' || c == 'a') + nb_ram_banks = expr(0); + else if(c == 'T' || c == 't') + mbc_type = expr(0); + else if(c == 'N' || c == 'n') { + int i = 0; + if(getnb() != '=' || getnb() != '"') { + fprintf(stderr, "Syntax error in -YN=\"name\" flag\n"); + lkexit(1); + } + while((c = get()) != '"' && i < 16) { + cart_name[i++] = c; + } + if(i < 16) + cart_name[i] = 0; + else + while(get() != '"') + ; + } else if(c == 'P' || c == 'p') { + patch *p = patches; + + patches = (patch *)malloc(sizeof(patch)); + patches->next = p; + patches->addr = expr(0); + if(getnb() != '=') { + fprintf(stderr, "Syntax error in -YHaddr=val flag\n"); + lkexit(1); + } + patches->value = expr(0); + } else { + fprintf(stderr, "Invalid option\n"); + lkexit(1); + } + break; + +#endif /* GAMEBOY */ +#ifdef SDK + case 'j': + case 'J': + ++symflag; + break; + case 'z': + case 'Z': + oflag = 3; + break; +#endif /* SDK */ + case 'm': + case 'M': + ++mflag; + break; + + case 'u': + case 'U': + uflag = 1; + break; + + case 'x': + case 'X': + xflag = 0; + break; + + case 'q': + case 'Q': + xflag = 1; + break; + + case 'd': + case 'D': + xflag = 2; + break; + + case 'e': + case 'E': + return(1); + + case 'n': + case 'N': + pflag = 0; + break; + + case 'p': + case 'P': + pflag = 1; + break; + + case 'b': + case 'B': + bassav(); + return(0); + + case 'g': + case 'G': + gblsav(); + return(0); + + case 'k': + case 'K': + addpath(); + return(0); + + case 'l': + case 'L': + addlib(); + return(0); + + default: + fprintf(stderr, "Invalid option\n"); + lkexit(1); + } + } + } else + if (ctype[c] != ILL) { + if (linkp == NULL) { + linkp = (struct lfile *) + new (sizeof (struct lfile)); + lfp = linkp; + } else { + lfp->f_flp = (struct lfile *) + new (sizeof (struct lfile)); + lfp = lfp->f_flp; + } + getfid(fid, c); + lfp->f_idp = (char *) new (strlen(fid)+1); + strcpy(lfp->f_idp, fid); + lfp->f_type = F_REL; + } else { + fprintf(stderr, "Invalid input"); + lkexit(1); + } + } + return(0); +} + +/*)Function VOID bassav() + * + * The function bassav() creates a linked structure containing + * the base address strings input to the linker. + * + * local variables: + * none + * + * global variables: + * base *basep The pointer to the first + * base structure + * base *bsp Pointer to the current + * base structure + * char *ip pointer into the REL file + * text line in ib[] + * + * functions called: + * char getnb() lklex.c + * VOID * new() lksym.c + * int strlen() c_library + * char * strcpy() c_library + * VOID unget() lklex.c + * + * side effects: + * The basep structure is created. + */ + +VOID +bassav() +{ + if (basep == NULL) { + basep = (struct base *) + new (sizeof (struct base)); + bsp = basep; + } else { + bsp->b_base = (struct base *) + new (sizeof (struct base)); + bsp = bsp->b_base; + } + unget(getnb()); + bsp->b_strp = (char *) new (strlen(ip)+1); + strcpy(bsp->b_strp, ip); +} + +/*)Function VOID setbas() + * + * The function setbas() scans the base address lines in hte + * basep structure, evaluates the arguments, and sets beginning + * address of the specified areas. + * + * local variables: + * int v expression value + * char id[] base id string + * + * global variables: + * area *ap Pointer to the current + * area structure + * area *areap The pointer to the first + * area structure of a linked list + * base *basep The pointer to the first + * base structure + * base *bsp Pointer to the current + * base structure + * char *ip pointer into the REL file + * text line in ib[] + * int lkerr error flag + * + * functions called: + * Addr_T expr() lkeval.c + * int fprintf() c_library + * VOID getid() lklex.c + * char getnb() lklex.c + * int symeq() lksym.c + * + * side effects: + * The base address of an area is set. + */ + +VOID +setbas() +{ + register int v; + char id[NCPS]; + + bsp = basep; + while (bsp) { + ip = bsp->b_strp; + getid(id, -1); + if (getnb() == '=') { + v = expr(0); + for (ap = areap; ap != NULL; ap = ap->a_ap) { + if (symeq(id, ap->a_id)) + break; + } + if (ap == NULL) { +#ifndef SDK + fprintf(stderr, + "No definition of area %s\n", id); + lkerr++; +#endif /* SDK */ + } else { + ap->a_addr = v; + } + } else { + fprintf(stderr, "No '=' in base expression"); + lkerr++; + } + bsp = bsp->b_base; + } +} + +/*)Function VOID gblsav() + * + * The function gblsav() creates a linked structure containing + * the global variable strings input to the linker. + * + * local variable: + * none + * + * global variables: + * globl *globlp The pointer to the first + * globl structure + * globl *gsp Pointer to the current + * globl structure + * char *ip pointer into the REL file + * text line in ib[] + * int lkerr error flag + * + * functions called: + * char getnb() lklex.c + * VOID * new() lksym.c + * int strlen() c_library + * char * strcpy() c_library + * VOID unget() lklex.c + * + * side effects: + * The globlp structure is created. + */ + +VOID +gblsav() +{ + if (globlp == NULL) { + globlp = (struct globl *) + new (sizeof (struct globl)); + gsp = globlp; + } else { + gsp->g_globl = (struct globl *) + new (sizeof (struct globl)); + gsp = gsp->g_globl; + } + unget(getnb()); + gsp->g_strp = (char *) new (strlen(ip)+1); + strcpy(gsp->g_strp, ip); +} + +/*)Function VOID setgbl() + * + * The function setgbl() scans the global variable lines in hte + * globlp structure, evaluates the arguments, and sets a variable + * to this value. + * + * local variables: + * int v expression value + * char id[] base id string + * sym * sp pointer to a symbol structure + * + * global variables: + * char *ip pointer into the REL file + * text line in ib[] + * globl *globlp The pointer to the first + * globl structure + * globl *gsp Pointer to the current + * globl structure + * FILE * stderr c_library + * int lkerr error flag + * + * functions called: + * Addr_T expr() lkeval.c + * int fprintf() c_library + * VOID getid() lklex.c + * char getnb() lklex.c + * sym * lkpsym() lksym.c + * + * side effects: + * The value of a variable is set. + */ + +VOID +setgbl() +{ + register int v; + register struct sym *sp; + char id[NCPS]; + + gsp = globlp; + while (gsp) { + ip = gsp->g_strp; + getid(id, -1); + if (getnb() == '=') { + v = expr(0); + sp = lkpsym(id, 0); + if (sp == NULL) { +#ifndef SDK + fprintf(stderr, + "No definition of symbol %s\n", id); + lkerr++; +#endif /* SDK */ + } else { +#ifndef SDK + if (sp->s_flag & S_DEF) { + fprintf(stderr, + "Redefinition of symbol %s\n", id); + lkerr++; + sp->s_axp = NULL; + } +#endif /* SDK */ + sp->s_addr = v; + sp->s_type |= S_DEF; + } + } else { + fprintf(stderr, "No '=' in global expression"); + lkerr++; + } + gsp = gsp->g_globl; + } +} + +/*)Function FILE * afile(fn,, ft, wf) + * + * char * fn file specification string + * char * ft file type string + * int wf read(0)/write(1) flag + * + * The function afile() opens a file for reading or writing. + * (1) If the file type specification string ft + * is not NULL then a file specification is + * constructed with the file path\name in fn + * and the extension in ft. + * (2) If the file type specification string ft + * is NULL then the file specification is + * constructed from fn. If fn does not have + * a file type then the default .rel file + * type is appended to the file specification. + * + * afile() returns a file handle for the opened file or aborts + * the assembler on an open error. + * + * local variables: + * int c character value + * char fb[] constructed file specification string + * FILE * fp filehandle for opened file + * char * p1 pointer to filespec string fn + * char * p2 pointer to filespec string fb + * char * p3 pointer to filetype string ft + * + * global variables: + * int lkerr error flag + * + * functions called: + * FILE * fopen() c_library + * int fprintf() c_library + * + * side effects: + * File is opened for read or write. + */ + +FILE * +afile(fn, ft, wf) +char *fn; +char *ft; +{ + register char *p1, *p2, *p3; + register int c; + FILE *fp; + char fb[FILSPC]; + + p1 = fn; + p2 = fb; + p3 = ft; + while ((c = *p1++) != 0 && c != FSEPX) { + if (p2 < &fb[FILSPC-4]) + *p2++ = c; + } + *p2++ = FSEPX; + if (*p3 == 0) { + if (c == FSEPX) { + p3 = p1; + } else { +#ifdef SDK + p3 = "rel"; +#else /* SDK */ + p3 = "REL"; +#endif /* SDK */ + } + } + while ((c = *p3++) != 0) { + if (p2 < &fb[FILSPC-1]) + *p2++ = c; + } + *p2++ = 0; +#ifdef SDK + if ((fp = fopen(fb, wf?(binary?"wb":"w"):(binary?"rb":"r"))) == NULL) { +#else /* SDK */ + if ((fp = fopen(fb, wf?"w":"r")) == NULL) { +#endif /* SDK */ + fprintf(stderr, "%s: cannot %s.\n", fb, wf?"create":"open"); + lkerr++; + } + return (fp); +} + +char *usetxt[] = { +#ifdef SDK + "Distributed with SDK " SDK_VERSION_STRING ", built on " __DATE__ " " __TIME__, + "Compile options: SDK Target " TARGET_STRING +#ifdef INDEXLIB + " INDEXLIB" +#endif + "\n", +#endif + "Startup:", +#ifdef SDK + " -- [Commands] Non-interactive command line input", +#endif /* SDK */ + " -c Command line input", + " -f file[LNK] File input", + " -p Prompt and echo of file[LNK] to stdout (default)", + " -n No echo of file[LNK] to stdout", +#ifdef SDK + "Usage: [-Options] outfile file [file ...]", +#else /* SDK */ + "Usage: [-Options] file [file ...]", +#endif /* SDK */ + "Librarys:", + " -k Library path specification, one per -k", + " -l Library file specification, one per -l", + "Relocation:", + " -b area base address = expression", + " -g global symbol = expression", +#ifdef GAMEBOY + " -yo Number of rom banks (default: 2)", + " -ya Number of ram banks (default: 0)", + " -yt MBC type (default: no MBC)", + " -yn Name of program (default: name of output file)", + " -yp# Patch one byte in the output GB file (# is: addr=byte)", +#endif /* GAMEBOY */ + "Map format:", + " -m Map output generated as file[MAP]", +#ifdef SDK + " -j no$gmb symbol file generated as file[SYM]", +#endif /* SDK */ + " -x Hexidecimal (default)", + " -d Decimal", + " -q Octal", + "Output:", + " -i Intel Hex as file[IHX]", + " -s Motorola S19 as file[S19]", +#ifdef SDK +#ifdef GAMEGEAR + " -z Gamegear image as file[GG]", +#else + " -z Gameboy image as file[GB]", +#endif /* GAMEGEAR */ +#endif /* SDK */ + "List:", + " -u Update listing file(s) with link data as file(s)[.RST]", + "End:", + " -e or null line terminates input", + "", + 0 +}; + +/*)Function VOID usage() + * + * The function usage() outputs to the stderr device the + * assembler name and version and a list of valid assembler options. + * + * local variables: + * char ** dp pointer to an array of + * text string pointers. + * + * global variables: + * FILE * stderr c_library + * + * functions called: + * int fprintf() c_library + * + * side effects: + * none + */ + +VOID +usage() +{ + register char **dp; + + fprintf(stderr, "\nASxxxx Linker %s\n\n", VERSION); + for (dp = usetxt; *dp; dp++) + fprintf(stderr, "%s\n", *dp); + lkexit(1); +} diff --git a/link/z80/lkrloc.c b/link/z80/lkrloc.c new file mode 100644 index 00000000..0746dbbe --- /dev/null +++ b/link/z80/lkrloc.c @@ -0,0 +1,1171 @@ +/* lkrloc.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +/* + * Extensions: P. Felber + */ + +#include +#include +#include +//#include +#include +#include "aslink.h" + +/*)Module lkrloc.c + * + * The module lkrloc.c contains the functions which + * perform the relocation calculations. + * + * lkrloc.c contains the following functions: + * Addr_T adb_b() + * Addr_T adb_lo() + * Addr_T adb_hi() + * Addr_T adw_w() + * Addr_T adw_lo() + * Addr_T adw_hi() + * VOID erpdmp() + * VOID errdmp() + * Addr_T evword() + * VOID prntval() + * VOID rele() + * VOID relerr() + * VOID relerp() + * VOID reloc() + * VOID relp() + * VOID relr() + * VOID relt() + * + * lkrloc.c the local variable errmsg[]. + * + */ + +/*)Function VOID reloc(c) + * + * char c process code + * + * The function reloc() calls a particular relocation + * function determined by the process code. + * + * local variable: + * none + * + * global variables: + * int lkerr error flag + * + * called functions: + * int fprintf() c_library + * VOID rele() lkrloc.c + * VOID relp() lkrloc.c + * VOID relr() lkrloc.c + * VOId relt() lkrloc.c + * + * side effects: + * Refer to the called relocation functions. + * + */ + +VOID +reloc(c) +char c; +{ + switch(c) { + + case 'T': + relt(); + break; + + case 'R': + relr(); + break; + + case 'P': + relp(); + break; + + case 'E': + rele(); + break; + + default: + fprintf(stderr, "Undefined Relocation Operation\n"); + lkerr++; + break; + + } +} + + +/*)Function VOID relt() + * + * The function relt() evaluates a T line read by + * the linker. Each byte value read is saved in the + * rtval[] array, rtflg[] is set, and the number of + * evaluations is maintained in rtcnt. + * + * T Line + * + * T xx xx nn nn nn nn nn ... + * + * + * In: "T n0 n1 n2 n3 ... nn" + * + * Out: 0 1 2 .. rtcnt + * +----+----+----+----+----+ + * rtval | n0 | n1 | n2 | .. | nn | + * +----+----+----+----+----+ + * rtflag| 1 | 1 | 1 | 1 | 1 | + * +----+----+----+----+----+ + * + * The T line contains the assembled code output by the assem- + * bler with xx xx being the offset address from the current area + * base address and nn being the assembled instructions and data in + * byte format. + * + * local variable: + * none + * + * global variables: + * int rtcnt number of values evaluated + * int rtflg[] array of evaluation flags + * int rtval[] array of evaluation values + * + * called functions: + * int eval() lkeval.c + * int more() lklex.c + * + * side effects: + * Linker input T line evaluated. + * + */ + +VOID +relt() +{ + rtcnt = 0; + while (more()) { + if (rtcnt < NTXT) { + rtval[rtcnt] = eval(); + rtflg[rtcnt] = 1; + rtcnt++; + } + } +} + +/*)Function VOID relr() + * + * The function relr() evaluates a R line read by + * the linker. The R line data is combined with the + * previous T line data to perform the relocation of + * code and data bytes. The S19 / IHX output and + * translation of the LST files to RST files may be + * performed. + * + * R Line + * + * R 0 0 nn nn n1 n2 xx xx ... + * + * The R line provides the relocation information to the linker. + * The nn nn value is the current area index, i.e. which area the + * current values were assembled. Relocation information is en- + * coded in groups of 4 bytes: + * + * 1. n1 is the relocation mode and object format + * 1. bit 0 word(0x00)/byte(0x01) + * 2. bit 1 relocatable area(0x00)/symbol(0x02) + * 3. bit 2 normal(0x00)/PC relative(0x04) relocation + * 4. bit 3 1-byte(0x00)/2-byte(0x08) object format for + * byte data + * 5. bit 4 signed(0x00)/unsigned(0x10) byte data + * 6. bit 5 normal(0x00)/page '0'(0x20) reference + * 7. bit 6 normal(0x00)/page 'nnn'(0x40) reference + * + * 2. n2 is a byte index into the corresponding (i.e. pre- + * ceeding) T line data (i.e. a pointer to the data to be + * updated by the relocation). The T line data may be + * 1-byte or 2-byte byte data format or 2-byte word + * format. + * + * 3. xx xx is the area/symbol index for the area/symbol be- + * ing referenced. the corresponding area/symbol is found + * in the header area/symbol lists. + * + * The groups of 4 bytes are repeated for each item requiring relo- + * cation in the preceeding T line. + * + * local variable: + * areax **a pointer to array of area pointers + * int aindex area index + * char *errmsg[] array of pointers to error strings + * int error error code + * int lkerr error flag + * int mode relocation mode + * adrr_t paga paging base area address + * Addr_T pags paging symbol address + * Addr_T pc relocated base address + * Addr_T r PCR relocation value + * Addr_T reli relocation initial value + * Addr_T relv relocation final value + * int rindex symbol / area index + * Addr_T rtbase base code address + * Addr_T rtofst rtval[] index offset + * int rtp index into T data + * sym **s pointer to array of symbol pointers + * + * global variables: + * head *hp pointer to the head structure + * rerr rerr linker error structure + * FILE *stderr standard error device + * + * called functions: + * Addr_T adb_b() lkrloc.c + * Addr_T adb_lo() lkrloc.c + * Addr_T adb_hi() lkrloc.c + * Addr_T adw_w() lkrloc.c + * Addr_T evword() lkrloc.c + * int eval() lkeval.c + * int fprintf() c_library + * VOID ihx() lkihx.c + * int lkulist lklist.c + * int more() lklex.c + * VOID relerr() lkrloc.c + * VOID s19() lks19.c + * int symval() lksym.c + * + * side effects: + * The R and T lines are combined to produce + * relocated code and data. Output S19 / IHX + * and relocated listing files may be produced. + * + */ + +VOID +relr() +{ + register int mode; + register Addr_T reli, relv; + int aindex, rindex, rtp, error; + Addr_T r, rtbase, rtofst, paga = 0, pags = 0, pc; + struct areax **a; + struct sym **s; + + /* + * Get area and symbol lists + */ + a = hp->a_list; + s = hp->s_list; + + /* + * Verify Area Mode + */ + if (eval() != (R_WORD | R_AREA) || eval()) { + fprintf(stderr, "R input error\n"); + lkerr++; + } + + /* + * Get area pointer + */ + aindex = evword(); + if (aindex >= hp->h_narea) { + fprintf(stderr, "R area error\n"); + lkerr++; + return; + } + + /* + * Base values + */ + rtbase = adw_w(0, 0); + rtofst = 2; + + /* + * Relocate address + */ + pc = adw_w(a[aindex]->a_addr, 0); + +#ifdef GAMEBOY + { + char *s = strrchr(a[aindex]->a_bap->a_id, '_'); + if(s != NULL && isdigit(s[1])) + current_rom_bank = atoi(s+1); + else + current_rom_bank = 0; + } +#endif /* GAMEBOY */ + /* + * Do remaining relocations + */ + while (more()) { + error = 0; + mode = eval(); + rtp = eval(); + rindex = evword(); + + /* + * R_SYM or R_AREA references + */ + if (mode & R_SYM) { + if (rindex >= hp->h_nglob) { + fprintf(stderr, "R symbol error\n"); + lkerr++; + return; + } + reli = symval(s[rindex]); + } else { + if (rindex >= hp->h_narea) { + fprintf(stderr, "R area error\n"); + lkerr++; + return; + } + reli = a[rindex]->a_addr; + } + + /* + * R_PCR addressing + */ + if (mode & R_PCR) { + if (mode & R_BYTE) { + reli -= (pc + (rtp-rtofst) + 1); + } else { + reli -= (pc + (rtp-rtofst) + 2); + } + } + + /* + * R_PAG0 or R_PAG addressing + */ + if (mode & (R_PAG0|R_PAG)) { + paga = sdp.s_area->a_addr; + pags = sdp.s_addr; + reli -= paga + pags; + } + + /* + * R_BYTE or R_WORD operation + */ + if (mode & R_BYTE) { + if (mode & R_BYT2) { + if (mode & R_MSB) { + relv = adb_hi(reli, rtp); + } else { + relv = adb_lo(reli, rtp); + } + } else { + relv = adb_b(reli, rtp); + } + } else { + /* + * R_WORD with the R_BYT2 mode is flagged + * as an 'r' error by the assembler, + * but it is processed here anyway. + */ + if (mode & R_BYT2) { + if (mode & R_MSB) { + relv = adw_hi(reli, rtp); + } else { + relv = adw_lo(reli, rtp); + } + } else { + relv = adw_w(reli, rtp); + } + } + + /* + * R_BYTE with R_BYT2 offset adjust + */ + if (mode & R_BYTE) { + if (mode & R_BYT2) { + rtofst += 1; + } + } + + /* + * Unsigned Byte Checking + */ + if (mode & R_USGN && mode & R_BYTE && relv & ~0xFF) + error = 1; + + /* + * PCR Relocation Error Checking + */ + if (mode & R_PCR && mode & R_BYTE) { + r = relv & ~0x7F; + if (r != (Addr_T) ~0x7F && r != 0) + error = 2; + } + + /* + * Page Relocation Error Checking + */ + if (mode & R_PAG0 && (relv & ~0xFF || paga || pags)) + error = 3; + if (mode & R_PAG && (relv & ~0xFF)) + error = 4; + + /* + * Error Processing + */ + if (error) { + rerr.aindex = aindex; + rerr.mode = mode; + rerr.rtbase = rtbase + rtp - rtofst - 1; + rerr.rindex = rindex; + rerr.rval = relv - reli; + relerr(errmsg[error-1]); + } + } + if (uflag != 0) { + lkulist(1); + } + if (oflag == 1) { + ihx(1); + } else + if (oflag == 2) { + s19(1); +#ifdef SDK + } else + if (oflag == 3) { +#ifdef GAMEGEAR + gg(1); +#endif /* GAMEGEAR */ +#ifdef GAMEBOY + gb(1); +#endif /* GAMEBOY */ +#endif /* SDK */ + } +} + +char *errmsg[] = { + "Unsigned Byte error", + "Byte PCR relocation error", + "Page0 relocation error", + "Page Mode relocation error" +}; + + +/*)Function VOID relp() + * + * The function relp() evaluates a P line read by + * the linker. The P line data is combined with the + * previous T line data to set the base page address + * and test the paging boundary and length. + * + * P Line + * + * P 0 0 nn nn n1 n2 xx xx + * + * The P line provides the paging information to the linker as + * specified by a .setdp directive. The format of the relocation + * information is identical to that of the R line. The correspond- + * ing T line has the following information: + * T xx xx aa aa bb bb + * + * Where aa aa is the area reference number which specifies the + * selected page area and bb bb is the base address of the page. + * bb bb will require relocation processing if the 'n1 n2 xx xx' is + * specified in the P line. The linker will verify that the base + * address is on a 256 byte boundary and that the page length of an + * area defined with the PAG type is not larger than 256 bytes. + * + * local variable: + * areax **a pointer to array of area pointers + * int aindex area index + * int mode relocation mode + * Addr_T relv relocation value + * int rindex symbol / area index + * int rtp index into T data + * sym **s pointer to array of symbol pointers + * + * global variables: + * head *hp pointer to the head structure + * int lkerr error flag + * sdp sdp base page structure + * FILE *stderr standard error device + * + * called functions: + * Addr_T adw_w() lkrloc.c + * Addr_T evword() lkrloc.c + * int eval() lkeval.c + * int fprintf() c_library + * int more() lklex.c + * int symval() lksym.c + * + * side effects: + * The P and T lines are combined to set + * the base page address and report any + * paging errors. + * + */ + +VOID +relp() +{ + register int aindex, rindex; + int mode, rtp; + Addr_T relv; + struct areax **a; + struct sym **s; + + /* + * Get area and symbol lists + */ + a = hp->a_list; + s = hp->s_list; + + /* + * Verify Area Mode + */ + if (eval() != (R_WORD | R_AREA) || eval()) { + fprintf(stderr, "P input error\n"); + lkerr++; + } + + /* + * Get area pointer + */ + aindex = evword(); + if (aindex >= hp->h_narea) { + fprintf(stderr, "P area error\n"); + lkerr++; + return; + } + + /* + * Do remaining relocations + */ + while (more()) { + mode = eval(); + rtp = eval(); + rindex = evword(); + + /* + * R_SYM or R_AREA references + */ + if (mode & R_SYM) { + if (rindex >= hp->h_nglob) { + fprintf(stderr, "P symbol error\n"); + lkerr++; + return; + } + relv = symval(s[rindex]); + } else { + if (rindex >= hp->h_narea) { + fprintf(stderr, "P area error\n"); + lkerr++; + return; + } + relv = a[rindex]->a_addr; + } + adw_w(relv, rtp); + } + + /* + * Paged values + */ + aindex = adw_w(0,2); + if (aindex >= hp->h_narea) { + fprintf(stderr, "P area error\n"); + lkerr++; + return; + } + sdp.s_areax = a[aindex]; + sdp.s_area = sdp.s_areax->a_bap; + sdp.s_addr = adw_w(0,4); + if (sdp.s_area->a_addr & 0xFF || sdp.s_addr & 0xFF) + relerp("Page Definition Boundary Error"); +} + +/*)Function VOID rele() + * + * The function rele() closes all open output files + * at the end of the linking process. + * + * local variable: + * none + * + * global variables: + * int oflag output type flag + * int uflag relocation listing flag + * + * called functions: + * VOID ihx() lkihx.c + * VOID lkulist() lklist.c + * VOID s19() lks19.c + * + * side effects: + * All open output files are closed. + * + */ + +VOID +rele() +{ + if (uflag != 0) { + lkulist(0); + } + if (oflag == 1) { + ihx(0); + } else + if (oflag == 2) { + s19(0); +#ifdef SDK + } else + if (oflag == 3) { +#ifdef GAMEGEAR + gg(0); +#endif /* GAMEGEAR */ +#ifdef GAMEBOY + gb(0); +#endif /* GAMEBOY */ +#endif /* SDK */ + } +} + +/*)Function Addr_T evword() + * + * The function evword() combines two byte values + * into a single word value. + * + * local variable: + * Addr_T v temporary evaluation variable + * + * global variables: + * hilo byte ordering parameter + * + * called functions: + * int eval() lkeval.c + * + * side effects: + * Relocation text line is scanned to combine + * two byte values into a single word value. + * + */ + +Addr_T +evword() +{ + register Addr_T v; + + if (hilo) { + v = (eval() << 8); + v += eval(); + } else { + v = eval(); + v += (eval() << 8); + } + return(v); +} + +/*)Function Addr_T adb_b(v, i) + * + * int v value to add to byte + * int i rtval[] index + * + * The function adb_b() adds the value of v to + * the single byte value contained in rtval[i]. + * The new value of rtval[i] is returned. + * + * local variable: + * none + * + * global variables: + * none + * + * called functions: + * none + * + * side effects: + * The value of rtval[] is changed. + * + */ + +Addr_T +adb_b(v, i) +register Addr_T v; +register int i; +{ + return(rtval[i] += v); +} + +/*)Function Addr_T adb_lo(v, i) + * + * int v value to add to byte + * int i rtval[] index + * + * The function adb_lo() adds the value of v to the + * double byte value contained in rtval[i] and rtval[i+1]. + * The new value of rtval[i] / rtval[i+1] is returned. + * The MSB rtflg[] is cleared. + * + * local variable: + * Addr_T j temporary evaluation variable + * + * global variables: + * hilo byte ordering parameter + * + * called functions: + * none + * + * side effects: + * The value of rtval[] is changed. + * The rtflg[] value corresponding to the + * MSB of the word value is cleared to reflect + * the fact that the LSB is the selected byte. + * + */ + +Addr_T +adb_lo(v, i) +Addr_T v; +int i; +{ + register Addr_T j; + + j = adw_w(v, i); + /* + * Remove Hi byte + */ + if (hilo) { + rtflg[i] = 0; + } else { + rtflg[i+1] = 0; + } + return (j); +} + +/*)Function Addr_T adb_hi(v, i) + * + * int v value to add to byte + * int i rtval[] index + * + * The function adb_hi() adds the value of v to the + * double byte value contained in rtval[i] and rtval[i+1]. + * The new value of rtval[i] / rtval[i+1] is returned. + * The LSB rtflg[] is cleared. + * + * local variable: + * Addr_T j temporary evaluation variable + * + * global variables: + * hilo byte ordering parameter + * + * called functions: + * none + * + * side effects: + * The value of rtval[] is changed. + * The rtflg[] value corresponding to the + * LSB of the word value is cleared to reflect + * the fact that the MSB is the selected byte. + * + */ + +Addr_T +adb_hi(v, i) +Addr_T v; +int i; +{ + register Addr_T j; + + j = adw_w(v, i); + /* + * Remove Lo byte + */ + if (hilo) { + rtflg[i+1] = 0; + } else { + rtflg[i] = 0; + } + return (j); +} + +/*)Function Addr_T adw_w(v, i) + * + * int v value to add to word + * int i rtval[] index + * + * The function adw_w() adds the value of v to the + * word value contained in rtval[i] and rtval[i+1]. + * The new value of rtval[i] / rtval[i+1] is returned. + * + * local variable: + * Addr_T j temporary evaluation variable + * + * global variables: + * hilo byte ordering parameter + * + * called functions: + * none + * + * side effects: + * The word value of rtval[] is changed. + * + */ + +Addr_T +adw_w(v, i) +register Addr_T v; +register int i; +{ + register Addr_T j; + + if (hilo) { + j = v + (rtval[i] << 8) + (rtval[i+1] & 0xff); + rtval[i] = (j >> 8) & 0xff; + rtval[i+1] = j & 0xff; + } else { + j = v + (rtval[i] & 0xff) + (rtval[i+1] << 8); + rtval[i] = j & 0xff; + rtval[i+1] = (j >> 8) & 0xff; + } + return(j); +} + +/*)Function Addr_T adw_lo(v, i) + * + * int v value to add to byte + * int i rtval[] index + * + * The function adw_lo() adds the value of v to the + * double byte value contained in rtval[i] and rtval[i+1]. + * The new value of rtval[i] / rtval[i+1] is returned. + * The MSB rtval[] is zeroed. + * + * local variable: + * Addr_T j temporary evaluation variable + * + * global variables: + * hilo byte ordering parameter + * + * called functions: + * none + * + * side effects: + * The value of rtval[] is changed. + * The MSB of the word value is cleared to reflect + * the fact that the LSB is the selected byte. + * + */ + +Addr_T +adw_lo(v, i) +Addr_T v; +int i; +{ + register Addr_T j; + + j = adw_w(v, i); + /* + * Clear Hi byte + */ + if (hilo) { + rtval[i] = 0; + } else { + rtval[i+1] = 0; + } + return (j); +} + +/*)Function Addr_T adw_hi(v, i) + * + * int v value to add to byte + * int i rtval[] index + * + * The function adw_hi() adds the value of v to the + * double byte value contained in rtval[i] and rtval[i+1]. + * The new value of rtval[i] / rtval[i+1] is returned. + * The MSB and LSB values are interchanged. + * The MSB rtval[] is zeroed. + * + * local variable: + * Addr_T j temporary evaluation variable + * + * global variables: + * hilo byte ordering parameter + * + * called functions: + * none + * + * side effects: + * The value of rtval[] is changed. + * The MSB and LSB values are interchanged and + * then the MSB cleared. + * + */ + +Addr_T +adw_hi(v, i) +Addr_T v; +int i; +{ + register Addr_T j; + + j = adw_w(v, i); + /* + * LSB = MSB, Clear MSB + */ + if (hilo) { + rtval[i+1] = rtval[i]; + rtval[i] = 0; + } else { + rtval[i] = rtval[i+1]; + rtval[i+1] = 0; + } + return (j); +} + +/*)Function VOID relerr(str) + * + * char *str error string + * + * The function relerr() outputs the error string to + * stderr and to the map file (if it is open). + * + * local variable: + * none + * + * global variables: + * FILE *mfp handle for the map file + * + * called functions: + * VOID errdmp() lkrloc.c + * + * side effects: + * Error message inserted into map file. + * + */ + +VOID +relerr(str) +char *str; +{ + errdmp(stderr, str); + if (mfp) + errdmp(mfp, str); +} + +/*)Function VOID errdmp(fptr, str) + * + * FILE *fptr output file handle + * char *str error string + * + * The function errdmp() outputs the error string str + * to the device specified by fptr. Additional information + * is output about the definition and referencing of + * the symbol / area error. + * + * local variable: + * int mode error mode + * int aindex area index + * int lkerr error flag + * int rindex error index + * sym **s pointer to array of symbol pointers + * areax **a pointer to array of area pointers + * areax *raxp error area extension pointer + * + * global variables: + * sdp sdp base page structure + * + * called functions: + * int fprintf() c_library + * VOID prntval() lkrloc.c + * + * side effects: + * Error reported. + * + */ + +VOID +errdmp(fptr, str) +FILE *fptr; +char *str; +{ + int mode, aindex, rindex; + struct sym **s; + struct areax **a; + struct areax *raxp; + + a = hp->a_list; + s = hp->s_list; + + mode = rerr.mode; + aindex = rerr.aindex; + rindex = rerr.rindex; + + /* + * Print Error + */ + fprintf(fptr, "\n?ASlink-Warning-%s", str); + lkerr++; + + /* + * Print symbol if symbol based + */ + if (mode & R_SYM) { + fprintf(fptr, " for symbol %.*s\n", + NCPS, &s[rindex]->s_id[0]); + } else { + fprintf(fptr, "\n"); + } + + /* + * Print Ref Info + */ + fprintf(fptr, + " file module area offset\n"); + fprintf(fptr, + " Refby %-8.8s %-8.8s %-8.8s ", + hp->h_lfile->f_idp, + &hp->m_id[0], + &a[aindex]->a_bap->a_id[0]); + prntval(fptr, rerr.rtbase); + + /* + * Print Def Info + */ + if (mode & R_SYM) { + raxp = s[rindex]->s_axp; + } else { + raxp = a[rindex]; + } + fprintf(fptr, + " Defin %-8.8s %-8.8s %-8.8s ", + raxp->a_bhp->h_lfile->f_idp, + &raxp->a_bhp->m_id[0], + &raxp->a_bap->a_id[0]); + if (mode & R_SYM) { + prntval(fptr, s[rindex]->s_addr); + } else { + prntval(fptr, rerr.rval); + } +} + +/*)Function VOID prntval(fptr, v) + * + * FILE *fptr output file handle + * Addr_T v value to output + * + * The function prntval() outputs the value v, in the + * currently selected radix, to the device specified + * by fptr. + * + * local variable: + * none + * + * global variables: + * int xflag current radix + * + * called functions: + * int fprintf() c_library + * + * side effects: + * none + * + */ + +VOID +prntval(fptr, v) +FILE *fptr; +Addr_T v; +{ + if (xflag == 0) { + fprintf(fptr, "%04X\n", v); + } else + if (xflag == 1) { + fprintf(fptr, "%06o\n", v); + } else + if (xflag == 2) { + fprintf(fptr, "%05u\n", v); + } +} + +/*)Function VOID relerp(str) + * + * char *str error string + * + * The function relerp() outputs the paging error string to + * stderr and to the map file (if it is open). + * + * local variable: + * none + * + * global variables: + * FILE *mfp handle for the map file + * + * called functions: + * VOID erpdmp() lkrloc.c + * + * side effects: + * Error message inserted into map file. + * + */ + +VOID +relerp(str) +char *str; +{ + erpdmp(stderr, str); + if (mfp) + erpdmp(mfp, str); +} + +/*)Function VOID erpdmp(fptr, str) + * + * FILE *fptr output file handle + * char *str error string + * + * The function erpdmp() outputs the error string str + * to the device specified by fptr. + * + * local variable: + * head *thp pointer to head structure + * + * global variables: + * int lkerr error flag + * sdp sdp base page structure + * + * called functions: + * int fprintf() c_library + * VOID prntval() lkrloc.c + * + * side effects: + * Error reported. + * + */ + +VOID +erpdmp(fptr, str) +FILE *fptr; +char *str; +{ + register struct head *thp; + + thp = sdp.s_areax->a_bhp; + + /* + * Print Error + */ + fprintf(fptr, "\n?ASlink-Warning-%s\n", str); + lkerr++; + + /* + * Print PgDef Info + */ + fprintf(fptr, + " file module pgarea pgoffset\n"); + fprintf(fptr, + " PgDef %-8.8s %-8.8s %-8.8s ", + thp->h_lfile->f_idp, + &thp->m_id[0], + &sdp.s_area->a_id[0]); + prntval(fptr, sdp.s_area->a_addr + sdp.s_addr); +} diff --git a/link/z80/lks19.c b/link/z80/lks19.c new file mode 100644 index 00000000..905e7e74 --- /dev/null +++ b/link/z80/lks19.c @@ -0,0 +1,123 @@ +/* lks19.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +#include +#include +//#include +#include "aslink.h" + +/*)Module lks19.c + * + * The module lks19.c contains the function to + * output the relocated object code in the + * Motorola S19 format. + * + * lks19.c contains the following function: + * VOID s19(i) + * + * lks19.c contains no local variables. + */ + +/*)S19 Format + * Record Type Field - This field signifies the start of a + * record and identifies the the record + * type as follows: + * + * Ascii S1 - Data Record + * Ascii S9 - End of File Record + * + * Record Length Field - This field specifies the record length + * which includes the address, data, and + * checksum fields. The 8 bit record + * length value is converted to two ascii + * characters, high digit first. + * + * Load Address Field - This field consists of the four ascii + * characters which result from converting + * the the binary value of the address in + * which to begin loading this record. The + * order is as follows: + * + * High digit of high byte of address. + * Low digit of high byte of address. + * High digit of low byte of address. + * Low digit of low byte of address. + * + * In an End of File record this field con- + * sists of either four ascii zeros or the + * program entry address. Currently the + * entry address option is not supported. + * + * Data Field - This field consists of the actual data, + * converted to two ascii characters, high + * digit first. There are no data bytes in + * the End of File record. + * + * Checksum Field - The checksum field is the 8 bit binary + * sum of the record length field, the load + * address field, and the data field. This + * sum is then complemented (1's comple- + * ment) and converted to two ascii + * characters, high digit first. + */ + +/*)Function s19(i) + * + * int i 0 - process data + * 1 - end of data + * + * The function s19() outputs the relocated data + * in the standard Motorola S19 format. + * + * local variables: + * Addr_T chksum byte checksum + * + * global variables: + * int hilo byte order + * FILE * ofp output file handle + * int rtcnt count of data words + * int rtflg[] output the data flag + * Addr_T rtval[] relocated data + * + * functions called: + * int fprintf() c_library + * + * side effects: + * The data is output to the file defined by ofp. + */ + +VOID +s19(i) +{ + register Addr_T chksum; + + if (i) { + if (hilo == 0) { + chksum = rtval[0]; + rtval[0] = rtval[1]; + rtval[1] = chksum; + } + for (i = 0, chksum = 1; i < rtcnt; i++) { + if (rtflg[i]) + chksum++; + } + fprintf(ofp, "S1%02X", chksum); + for (i = 0; i < rtcnt ; i++) { + if (rtflg[i]) { + fprintf(ofp, "%02X", rtval[i]); + chksum += rtval[i]; + } + } + fprintf(ofp, "%02X\n", (-chksum-1) & 0xff); + } else { + fprintf(ofp, "S9030000FC\n"); + } +} diff --git a/link/z80/lksym.c b/link/z80/lksym.c new file mode 100644 index 00000000..8699da8e --- /dev/null +++ b/link/z80/lksym.c @@ -0,0 +1,496 @@ +/* lksym.c */ + +/* + * (C) Copyright 1989-1995 + * All Rights Reserved + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + */ + +#include +#include +#include +#include "aslink.h" + +/*)Module lksym.c + * + * The module lksym.c contains the functions that operate + * on the symbol structures. + * + * lksym.c contains the following functions: + * int hash() + * sym * lkpsym() + * VOID * new() + * sym * newsym() + * VOID symdef() + * int symeq() + * VOID syminit() + * VOID symmod() + * Addr_T symval() + * + * lksym.c contains no local/static variables. + */ + +/*)Function VOID syminit() + * + * The function syminit() is called to clear the hashtable. + * + * local variables: + * int h computed hash value + * sym ** spp pointer to an array of + * sym structure pointers + * + * global variables: + * sym * symhash[] array of pointers to NHASH + * linked symbol lists + * + * functions called: + * none + * + * side effects: + * (1) The symbol hash tables are cleared + */ + +VOID +syminit() +{ + struct sym **spp; + + spp = &symhash[0]; + while (spp < &symhash[NHASH]) + *spp++ = NULL; +} + +/*)Function sym * newsym() + * + * The function newsym() is called to evaluate the symbol + * definition/reference directive from the .rel file(s). + * If the symbol is not found in the symbol table a new + * symbol structure is created. Evaluation of the + * directive determines if this is a reference or a definition. + * Multiple definitions of the same variable will be flagged + * as an error if the values are not identical. A symbol + * definition places the symbol value and area extension + * into the symbols data structure. And finally, a pointer + * to the symbol structure is placed into the head structure + * symbol list. Refer to the description of the header, symbol, + * area, and areax structures in lkdata.c for structure and + * linkage details. + * + * local variables: + * int c character from input text + * int i evaluation value + * char id[] symbol name + * int nglob number of symbols in this header + * sym * tsp pointer to symbol structure + * sym ** s list of pointers to symbol structures + * + * global variables: + * areax *axp Pointer to the current + * areax structure + * head *headp The pointer to the first + * head structure of a linked list + * int lkerr error flag + * + * functions called: + * Addr_T eval() lkeval.c + * VOID exit() c_library + * int fprintf() c_library + * char get() lklex.c + * char getnb() lklex.c + * sym * lkpsym() lksym.c + * + * side effects: + * A symbol structure is created and/or modified. + * If structure space allocation fails linker will abort. + * Several severe errors (these are internal errors + * indicating a corrupted .rel file or corrupted + * assembler or linker) will terminated the linker. + */ + +/* + * Find/Create a global symbol entry. + * + * S xxxxxx Defnnnn + * | | | + * | | `-- sp->s_addr + * | `----- sp->s_type + * `------------ sp->s_id + * + */ +struct sym * +newsym() +{ + register int c, i, nglob; + struct sym *tsp; + struct sym **s; + char id[NCPS]; + + getid(id, -1); + tsp = lkpsym(id, 1); + c = getnb();get();get(); + if (c == 'R') { + tsp->s_type |= S_REF; + if (eval()) { + fprintf(stderr, "Non zero S_REF\n"); + lkerr++; + } + } else + if (c == 'D') { + i = eval(); + if (tsp->s_type & S_DEF && tsp->s_addr != i) { +#ifdef SDK + fprintf(stderr, "Multiple definition of %s\n", id); +#else + fprintf(stderr, "Multiple definition of %.8s\n", id); +#endif + lkerr++; + } + tsp->s_type |= S_DEF; + /* + * Set value and area extension link. + */ + tsp->s_addr = i; + tsp->s_axp = axp; + } else { + fprintf(stderr, "Invalid symbol type %c for %.8s\n", c, id); + lkexit(1); + } + /* + * Place pointer in header symbol list + */ + if (headp == NULL) { + fprintf(stderr, "No header defined\n"); + lkexit(1); + } + nglob = hp->h_nglob; + s = hp->s_list; + for (i=0; i < nglob ;++i) { + if (s[i] == NULL) { + s[i] = tsp; + return(tsp); + } + } + fprintf(stderr, "Header symbol list overflow\n"); + lkexit(1); + + /* Never reached */ + return 0; +} + +/*)Function sym * lkpsym(id,f) + * + * char * id symbol name string + * int f f == 0, lookup only + * f != 0, create if not found + * + * The function lookup() searches the symbol hash tables for + * a symbol name match returning a pointer to the sym structure. + * If the symbol is not found then a sym structure is created, + * initialized, and linked to the appropriate hash table if f != 0. + * A pointer to this new sym structure is returned or a NULL + * pointer is returned if f == 0. + * + * local variables: + * int h computed hash value + * sym * sp pointer to a sym structure + * + * global varaibles: + * sym * symhash[] array of pointers to NHASH + * linked symbol lists + * + * functions called: + * int hash() lksym.c + * VOID * new() lksym.c + * int symeq() lksym.c + * + * side effects: + * If the function new() fails to allocate space + * for the new sym structure the linker terminates. + */ + +struct sym * +lkpsym(id, f) +char *id; +{ + register struct sym *sp; + register int h; + + h = hash(id); + sp = symhash[h]; + while (sp != NULL) { + if (symeq(id, sp->s_id)) + return (sp); + sp = sp->s_sp; + } + if (f == 0) + return (NULL); + sp = (struct sym *) new (sizeof(struct sym)); + sp->s_sp = symhash[h]; + symhash[h] = sp; + strncpy(sp->s_id, id, NCPS); + return (sp); +} + +/*)Function Addr_T symval(tsp) + * + * sym * tsp pointer to a symbol structure + * + * The function symval() returns the value of the + * relocated symbol by adding the variable definition + * value to the areax base address. + * + * local variables: + * Addr_T val relocated address value + * + * global variables: + * none + * + * functions called: + * none + * + * side effects: + * none + */ + +Addr_T +symval(tsp) +register struct sym *tsp; +{ + register Addr_T val; + + val = tsp->s_addr; + if (tsp->s_axp) { + val += tsp->s_axp->a_addr; + } + return(val); +} + +/*)Function VOID symdef(fp) + * + * FILE * fp file handle for output + * + * The function symdef() scans the hashed symbol table + * searching for variables referenced but not defined. + * Undefined variables are linked to the default + * area "_CODE" and reported as referenced by the + * appropriate module. + * + * local variables: + * int i hash table index loop variable + * sym * sp pointer to linked symbol structure + * + * global variables: + * area *areap The pointer to the first + * area structure of a linked list + * sym *symhash[NHASH] array of pointers to NHASH + * linked symbol lists + * + * functions called: + * symmod() lksym.c + * + * side effects: + * Undefined variables have their areas set to "_CODE". + */ + +VOID +symdef(fp) +FILE *fp; +{ + register struct sym *sp; + register int i; + + for (i=0; is_axp == NULL) + sp->s_axp = areap->a_axp; + if ((sp->s_type & S_DEF) == 0) + symmod(fp, sp); + sp = sp->s_sp; + } + } +} + +/*)Function VOID symmod(fp,tsp) + * + * FILE * fp output file handle + * sym * tsp pointer to a symbol structure + * + * The function symmod() scans the header structures + * searching for a reference to the symbol structure + * pointer to by tsp. The function then generates an error + * message whichs names the module having referenced the + * undefined variable. + * + * local variables: + * int i loop counter + * sym ** p pointer to a list of pointers + * to symbol structures + * + * global variables: + * head *headp The pointer to the first + * head structure of a linked list + * head *hp Pointer to the current + * head structure + * int lkerr error flag + * + * functions called: + * int fprintf() c_library + * + * side effects: + * Error output generated. + */ + +VOID +symmod(fp, tsp) +FILE *fp; +struct sym *tsp; +{ + register int i; + struct sym **p; + + if ((hp = headp) != NULL) { + while(hp) { + p = hp->s_list; + for (i=0; ih_nglob; ++i) { + if (p[i] == tsp) { + fprintf(fp, "\n?ASlink-Warning-Undefined Global %s ", tsp->s_id); + fprintf(fp, "referenced by module %s\n", hp->m_id); + lkerr++; + } + } + hp = hp->h_hp; + } + } +} + +/*)Function int symeq(p1, p2) + * + * char * p1 name string + * char * p2 name string + * + * The function symeq() compares the two name strings for a match. + * The return value is 1 for a match and 0 for no match. + * + * local variables: + * int h loop counter + * + * global variables: + * char ccase[] an array of characters which + * perform the case translation function + * + * functions called: + * none + * + * side effects: + * none + * + */ + +int +symeq(p1, p2) +register char *p1, *p2; +{ + register int n; + + n = NCPS; + do { + +#if CASE_SENSITIVE + if (*p1++ != *p2++) + return (0); +#else + if (ccase[(unsigned char)(*p1++)] != ccase[(unsigned char)(*p2++)]) + return (0); +#endif + + } while (--n); + return (1); +} + +/*)Function int hash(p) + * + * char * p pointer to string to hash + * + * The function hash() computes a hash code using the sum + * of all characters mod table size algorithm. + * + * local variables: + * int h accumulated character sum + * int n loop counter + * + * global variables: + * char ccase[] an array of characters which + * perform the case translation function + * + * functions called: + * none + * + * side effects: + * none + * + */ + +int +hash(p) +register char *p; +{ + register int h, n; + + h = 0; + n = NCPS; + do { + +#if CASE_SENSITIVE + h += *p++; +#else + h += ccase[(unsigned char)(*p++)]; +#endif + + } while (--n); + return (h&HMASK); +} + +/*)Function VOID * new(n) + * + * unsigned int n allocation size in bytes + * + * The function new() allocates n bytes of space and returns + * a pointer to this memory. If no space is available the + * linker is terminated. + * + * local variables: + * char * p a general pointer + * char * q a general pointer + * + * global variables: + * none + * + * functions called: + * int fprintf() c_library + * VOID * malloc() c_library + * + * side effects: + * Memory is allocated, if allocation fails + * the linker is terminated. + */ + +VOID * +new(n) +unsigned int n; +{ + register char *p,*q; + register unsigned int i; + + if ((p = (char *) malloc(n)) == NULL) { + fprintf(stderr, "Out of space!\n"); + lkexit(1); + } + for (i=0,q=p; i