diff --git a/Source/Apps/Build.cmd b/Source/Apps/Build.cmd index cbcf8a01..675d1f44 100644 --- a/Source/Apps/Build.cmd +++ b/Source/Apps/Build.cmd @@ -4,13 +4,11 @@ setlocal set TOOLS=../../Tools set APPBIN=..\..\Binary\Apps -set PATH=%TOOLS%\tasm32;%TOOLS%\zx;%PATH% +set PATH=%TOOLS%\tasm32;%TOOLS%\zxcc;%PATH% set TASMTABS=%TOOLS%\tasm32 -set ZXBINDIR=%TOOLS%/cpm/bin/ -set ZXLIBDIR=%TOOLS%/cpm/lib/ -set ZXINCDIR=%TOOLS%/cpm/include/ +set CPMDIR80=%TOOLS%/cpm/ call :asm syscopy || exit /b call :asm assign || exit /b @@ -21,10 +19,10 @@ call :asm rtc || exit /b call :asm timer || exit /b call :asm rtchb || exit /b -zx Z80ASM -SYSGEN/F || exit /b +zxcc Z80ASM -SYSGEN/F || exit /b -zx MAC SURVEY.ASM -$PO || exit /b -zx MLOAD25 -SURVEY.COM=SURVEY.HEX || exit /b +zxcc MAC SURVEY.ASM -$PO || exit /b +zxcc MLOAD25 -SURVEY.COM=SURVEY.HEX || exit /b pushd XM && call Build || exit /b & popd pushd FDU && call Build || exit /b & popd diff --git a/Source/Apps/Test/Build.cmd b/Source/Apps/Test/Build.cmd index fb322d6b..ac6e0c2b 100644 --- a/Source/Apps/Test/Build.cmd +++ b/Source/Apps/Test/Build.cmd @@ -4,13 +4,11 @@ setlocal set TOOLS=../../../Tools set APPBIN=..\..\Binary\Apps -set PATH=%TOOLS%\tasm32;%TOOLS%\zx;%PATH% +set PATH=%TOOLS%\tasm32;%TOOLS%\zxcc;%PATH% set TASMTABS=%TOOLS%\tasm32 -set ZXBINDIR=%TOOLS%/cpm/bin/ -set ZXLIBDIR=%TOOLS%/cpm/lib/ -set ZXINCDIR=%TOOLS%/cpm/include/ +set CPMDIR80=%TOOLS%/cpm/ pushd DMAmon && call Build || exit /b & popd pushd tstdskng && call Build || exit /b & popd diff --git a/Source/Apps/XM/Build.cmd b/Source/Apps/XM/Build.cmd index fef70f92..cf07e3cd 100644 --- a/Source/Apps/XM/Build.cmd +++ b/Source/Apps/XM/Build.cmd @@ -3,22 +3,20 @@ setlocal set TOOLS=..\..\..\Tools -set PATH=%TOOLS%\zx;%PATH% +set PATH=%TOOLS%\zxcc;%PATH% -set ZXBINDIR=%TOOLS%\cpm\bin\ -set ZXLIBDIR=%TOOLS%\cpm\lib\ -set ZXINCDIR=%TOOLS%\cpm\include\ +set CPMDIR80=%TOOLS%/cpm/ -zx mac xmdm125.asm $PO || exit /b +zxcc mac xmdm125.asm $PO || exit /b -zx slr180 -xmhb/HF || exit /b -zx mload25 XM=xmdm125,xmhb || exit /b +zxcc slr180 -xmhb/HF || exit /b +zxcc mload25 XM=xmdm125,xmhb || exit /b -rem zx slr180 -xmuf/HF || exit /b -rem zx mload25 XMUF=xmdm125,xmuf || exit /b +rem zxcc slr180 -xmuf/HF || exit /b +rem zxcc mload25 XMUF=xmdm125,xmuf || exit /b -zx slr180 -xmhb_old/HF || exit /b -zx mload25 XMOLD=xmdm125,xmhb_old || exit /b +zxcc slr180 -xmhb_old/HF || exit /b +zxcc mload25 XMOLD=xmdm125,xmhb_old || exit /b rem set PROMPT=[Build] %PROMPT% rem %comspec% diff --git a/Source/Apps/XM/Makefile b/Source/Apps/XM/Makefile index 62c4f1e8..fc9a62e6 100644 --- a/Source/Apps/XM/Makefile +++ b/Source/Apps/XM/Makefile @@ -7,10 +7,10 @@ OTHERS = *.hex include $(TOOLS)/Makefile.inc xm.com: xmdm125.hex xmhb.hex - $(ZXCC) $(CPM)/MLOAD25 XM=xmdm125,xmhb + $(ZXCC) MLOAD25 XM=xmdm125,xmhb xmuf.com: xmdm125.hex xmuf.hex - $(ZXCC) $(CPM)/MLOAD25 XMUF=xmdm125,xmuf + $(ZXCC) MLOAD25 XMUF=xmdm125,xmuf xmold.com: xmdm125.hex xmhb_old.hex - $(ZXCC) $(CPM)/MLOAD25 XMOLD=xmdm125,xmhb_old + $(ZXCC) MLOAD25 XMOLD=xmdm125,xmhb_old diff --git a/Source/Apps/ZMD/Build.cmd b/Source/Apps/ZMD/Build.cmd index cc8d63d5..5d8d700d 100644 --- a/Source/Apps/ZMD/Build.cmd +++ b/Source/Apps/ZMD/Build.cmd @@ -3,35 +3,33 @@ setlocal set TOOLS=..\..\..\Tools -set PATH=%TOOLS%\zx;%PATH% +set PATH=%TOOLS%\zxcc;%PATH% -set ZXBINDIR=%TOOLS%\cpm\bin\ -set ZXLIBDIR=%TOOLS%\cpm\lib\ -set ZXINCDIR=%TOOLS%\cpm\include\ +set CPMDIR80=%TOOLS%/cpm/ -zx z80asm -zmd/fm -zx l80 -zmd,zmd/n/e +zxcc z80asm -zmd/fm +zxcc l80 -zmd,zmd/n/e -zx z80asm -zmap/fm -zx l80 -zmap,zmap/n/e +zxcc z80asm -zmap/fm +zxcc l80 -zmap,zmap/n/e -zx z80asm -znews/fm -zx l80 -znews,znews/n/e +zxcc z80asm -znews/fm +zxcc l80 -znews,znews/n/e -zx z80asm -znewp/fm -zx l80 -znewp,znewp/n/e +zxcc z80asm -znewp/fm +zxcc l80 -znewp,znewp/n/e -zx z80asm -zfors/fm -zx l80 -zfors,zfors/n/e +zxcc z80asm -zfors/fm +zxcc l80 -zfors,zfors/n/e -zx z80asm -zforp/fm -zx l80 -zforp,zforp/n/e +zxcc z80asm -zforp/fm +zxcc l80 -zforp,zforp/n/e -zx z80asm -zmdel/fm -zx l80 -zmdel,zmdel/n/e +zxcc z80asm -zmdel/fm +zxcc l80 -zmdel,zmdel/n/e -zx z80asm -zmdhb/fh -zx mload25 -zmd=zmd.com,zmdhb +zxcc z80asm -zmdhb/fh +zxcc mload25 -zmd=zmd.com,zmdhb copy /Y zmd.com ..\..\..\Binary\Apps\ || exit /b diff --git a/Source/Apps/ZMD/Makefile b/Source/Apps/ZMD/Makefile index 997b4997..70350198 100644 --- a/Source/Apps/ZMD/Makefile +++ b/Source/Apps/ZMD/Makefile @@ -6,5 +6,5 @@ OTHERS = *.hex zmd.rel include $(TOOLS)/Makefile.inc zmd.com: zmd.rel zmdhb.hex - $(ZXCC) $(CPM)/L80 -zmd,zmd/n/e - $(ZXCC) $(CPM)/MLOAD25 -zmd=zmd.com,zmdhb + $(ZXCC) L80 -zmd,zmd/n/e + $(ZXCC) MLOAD25 -zmd=zmd.com,zmdhb diff --git a/Source/Apps/ZMP/Build.cmd b/Source/Apps/ZMP/Build.cmd index 71f79633..8df63e1a 100644 --- a/Source/Apps/ZMP/Build.cmd +++ b/Source/Apps/ZMP/Build.cmd @@ -3,14 +3,12 @@ setlocal set TOOLS=..\..\..\Tools -set PATH=%TOOLS%\zx;%PATH% +set PATH=%TOOLS%\zxcc;%PATH% -set ZXBINDIR=%TOOLS%\cpm\bin\ -set ZXLIBDIR=%TOOLS%\cpm\lib\ -set ZXINCDIR=%TOOLS%\cpm\include\ +set CPMDIR80=%TOOLS%/cpm/ -zx Z80ASM -ZMO-RW01/H || exit /b -zx MLOAD25 -ZMP.COM=ZMPX.COM,ZMO-RW01 || exit /b +zxcc Z80ASM -ZMO-RW01/H || exit /b +zxcc MLOAD25 -ZMP.COM=ZMPX.COM,ZMO-RW01 || exit /b copy /Y zmp.com ..\..\..\Binary\Apps\ || exit /b copy /Y *.ovr ..\..\..\Binary\Apps\ || exit /b diff --git a/Source/Apps/ZMP/Makefile b/Source/Apps/ZMP/Makefile index 09abd053..11574dd6 100644 --- a/Source/Apps/ZMP/Makefile +++ b/Source/Apps/ZMP/Makefile @@ -7,4 +7,4 @@ NODELETE = *.ovr zmp.doc *.hlp include $(TOOLS)/Makefile.inc zmp.com: zmo-rw01.hex - $(ZXCC) $(CPM)/MLOAD25 -ZMP.COM=ZMPX.COM,ZMO-RW01 + $(ZXCC) MLOAD25 -ZMP.COM=ZMPX.COM,ZMO-RW01 diff --git a/Source/BPBIOS/Build.cmd b/Source/BPBIOS/Build.cmd index 90aa684f..184aafec 100644 --- a/Source/BPBIOS/Build.cmd +++ b/Source/BPBIOS/Build.cmd @@ -3,11 +3,9 @@ setlocal pushd ZCPR33 && call Build || exit /b & popd -set PATH=%PATH%;..\..\Tools\zx;..\..\Tools\cpmtools; +set PATH=%PATH%;..\..\Tools\zxcc;..\..\Tools\cpmtools; -set ZXBINDIR=../../tools/cpm/bin/ -set ZXLIBDIR=../../tools/cpm/lib/ -set ZXINCDIR=../../tools/cpm/include/ +set CPMDIR80=%TOOLS%/cpm/ call :makebp 33 call :makebp 33bnk @@ -45,7 +43,7 @@ echo. copy def-ww-z%VER%.lib def-ww.lib || exit /b rem if exist bpbio-ww.rel del bpbio-ww.rel || exit /b -zx ZMAC -BPBIO-WW -/P || exit /b +zxcc ZMAC -BPBIO-WW -/P || exit /b if exist bp%VER%.prn del bp%VER%.prn || exit /b ren bpbio-ww.prn bp%VER%.prn || exit /b if exist bp%VER%.err del bp%VER%.err || exit /b @@ -56,18 +54,18 @@ rem pause rem BPBUILD attempts to rename bpsys.img -> bpsys.bak rem while is is still open. Real CP/M does not care, -rem but zx fails due to host OS. Below, a temp file +rem but zxcc fails due to host OS. Below, a temp file rem is used to avoid the problematic rename. if exist bpsys.img del bpsys.img || exit /b if exist bpsys.tmp del bpsys.tmp || exit /b copy bp%VER%.dat bpsys.tmp || exit /b rem bpsys.tmp -> bpsys.img -zx bpbuild -bpsys.tmp bpsys.img -zx bpbuild -bpsys.tmp $@ diff --git a/Tools/Makefile.inc b/Tools/Makefile.inc index 70820679..59b7e6d5 100644 --- a/Tools/Makefile.inc +++ b/Tools/Makefile.inc @@ -37,7 +37,8 @@ CASEFN = $(TOOLS)/unix/casefn.sh # # compiler/assembler locations and flags # -ZXCC=$(BINDIR)/zx +ZXCC=$(BINDIR)/zxcc +export CPMDIR80=$(TOOLS)/cpm/ TASM=$(BINDIR)/uz80as -t z80 TASMFLAGS= OPENSPIN=$(BINDIR)/openspin @@ -48,7 +49,7 @@ CPMCHATTR=$(BINDIR)/cpmchattr # # directory containing cpm binaries # -CPM=$(TOOLS)/cpm/bin +CPM=$(TOOLS)/cpm/bin80/ # # .ONESHELL uses a single shell instance for all shell scripts. diff --git a/Tools/cpm/bin/ARCV.COM b/Tools/cpm/bin80/ARCV.COM similarity index 100% rename from Tools/cpm/bin/ARCV.COM rename to Tools/cpm/bin80/ARCV.COM diff --git a/Tools/cpm/bin/AS.COM b/Tools/cpm/bin80/AS.COM similarity index 100% rename from Tools/cpm/bin/AS.COM rename to Tools/cpm/bin80/AS.COM diff --git a/Tools/cpm/bin/BASCOM.COM b/Tools/cpm/bin80/BASCOM.COM similarity index 100% rename from Tools/cpm/bin/BASCOM.COM rename to Tools/cpm/bin80/BASCOM.COM diff --git a/Tools/cpm/bin/CC.COM b/Tools/cpm/bin80/CC.COM similarity index 100% rename from Tools/cpm/bin/CC.COM rename to Tools/cpm/bin80/CC.COM diff --git a/Tools/cpm/bin/CNM.COM b/Tools/cpm/bin80/CNM.COM similarity index 100% rename from Tools/cpm/bin/CNM.COM rename to Tools/cpm/bin80/CNM.COM diff --git a/Tools/cpm/bin/CRC.COM b/Tools/cpm/bin80/CRC.COM similarity index 100% rename from Tools/cpm/bin/CRC.COM rename to Tools/cpm/bin80/CRC.COM diff --git a/Tools/cpm/bin/CREF80.COM b/Tools/cpm/bin80/CREF80.COM similarity index 100% rename from Tools/cpm/bin/CREF80.COM rename to Tools/cpm/bin80/CREF80.COM diff --git a/Tools/cpm/bin/CZ.COM b/Tools/cpm/bin80/CZ.COM similarity index 100% rename from Tools/cpm/bin/CZ.COM rename to Tools/cpm/bin80/CZ.COM diff --git a/Tools/cpm/bin/DIRX.COM b/Tools/cpm/bin80/DIRX.COM similarity index 100% rename from Tools/cpm/bin/DIRX.COM rename to Tools/cpm/bin80/DIRX.COM diff --git a/Tools/cpm/bin/DISKINFO.COM b/Tools/cpm/bin80/DISKINFO.COM similarity index 100% rename from Tools/cpm/bin/DISKINFO.COM rename to Tools/cpm/bin80/DISKINFO.COM diff --git a/Tools/cpm/bin/GENCPM.COM b/Tools/cpm/bin80/GENCPM.COM similarity index 100% rename from Tools/cpm/bin/GENCPM.COM rename to Tools/cpm/bin80/GENCPM.COM diff --git a/Tools/cpm/bin/HEX80.COM b/Tools/cpm/bin80/HEX80.COM similarity index 100% rename from Tools/cpm/bin/HEX80.COM rename to Tools/cpm/bin80/HEX80.COM diff --git a/Tools/cpm/bin/HEXCOM.COM b/Tools/cpm/bin80/HEXCOM.COM similarity index 100% rename from Tools/cpm/bin/HEXCOM.COM rename to Tools/cpm/bin80/HEXCOM.COM diff --git a/Tools/cpm/bin/L80.COM b/Tools/cpm/bin80/L80.COM similarity index 100% rename from Tools/cpm/bin/L80.COM rename to Tools/cpm/bin80/L80.COM diff --git a/Tools/cpm/bin/LBREXT.COM b/Tools/cpm/bin80/LBREXT.COM similarity index 100% rename from Tools/cpm/bin/LBREXT.COM rename to Tools/cpm/bin80/LBREXT.COM diff --git a/Tools/cpm/bin/LIB.COM b/Tools/cpm/bin80/LIB.COM similarity index 100% rename from Tools/cpm/bin/LIB.COM rename to Tools/cpm/bin80/LIB.COM diff --git a/Tools/cpm/bin/LIB80.COM b/Tools/cpm/bin80/LIB80.COM similarity index 100% rename from Tools/cpm/bin/LIB80.COM rename to Tools/cpm/bin80/LIB80.COM diff --git a/Tools/cpm/bin/LIBUTIL.COM b/Tools/cpm/bin80/LIBUTIL.COM similarity index 100% rename from Tools/cpm/bin/LIBUTIL.COM rename to Tools/cpm/bin80/LIBUTIL.COM diff --git a/Tools/cpm/bin/LINK.COM b/Tools/cpm/bin80/LINK.COM similarity index 100% rename from Tools/cpm/bin/LINK.COM rename to Tools/cpm/bin80/LINK.COM diff --git a/Tools/cpm/bin/LN.COM b/Tools/cpm/bin80/LN.COM similarity index 100% rename from Tools/cpm/bin/LN.COM rename to Tools/cpm/bin80/LN.COM diff --git a/Tools/cpm/bin/M80.COM b/Tools/cpm/bin80/M80.COM similarity index 100% rename from Tools/cpm/bin/M80.COM rename to Tools/cpm/bin80/M80.COM diff --git a/Tools/cpm/bin/MAC.COM b/Tools/cpm/bin80/MAC.COM similarity index 100% rename from Tools/cpm/bin/MAC.COM rename to Tools/cpm/bin80/MAC.COM diff --git a/Tools/cpm/bin/MLOAD25.COM b/Tools/cpm/bin80/MLOAD25.COM similarity index 100% rename from Tools/cpm/bin/MLOAD25.COM rename to Tools/cpm/bin80/MLOAD25.COM diff --git a/Tools/cpm/bin/NULU.COM b/Tools/cpm/bin80/NULU.COM similarity index 100% rename from Tools/cpm/bin/NULU.COM rename to Tools/cpm/bin80/NULU.COM diff --git a/Tools/cpm/bin/RMAC.COM b/Tools/cpm/bin80/RMAC.COM similarity index 100% rename from Tools/cpm/bin/RMAC.COM rename to Tools/cpm/bin80/RMAC.COM diff --git a/Tools/cpm/bin/SIDSYM.COM b/Tools/cpm/bin80/SIDSYM.COM similarity index 100% rename from Tools/cpm/bin/SIDSYM.COM rename to Tools/cpm/bin80/SIDSYM.COM diff --git a/Tools/cpm/bin/SLR180.COM b/Tools/cpm/bin80/SLR180.COM similarity index 100% rename from Tools/cpm/bin/SLR180.COM rename to Tools/cpm/bin80/SLR180.COM diff --git a/Tools/cpm/bin/SLRMAC.COM b/Tools/cpm/bin80/SLRMAC.COM similarity index 100% rename from Tools/cpm/bin/SLRMAC.COM rename to Tools/cpm/bin80/SLRMAC.COM diff --git a/Tools/cpm/bin/SLRNK.COM b/Tools/cpm/bin80/SLRNK.COM similarity index 100% rename from Tools/cpm/bin/SLRNK.COM rename to Tools/cpm/bin80/SLRNK.COM diff --git a/Tools/cpm/bin/SQZ.COM b/Tools/cpm/bin80/SQZ.COM similarity index 100% rename from Tools/cpm/bin/SQZ.COM rename to Tools/cpm/bin80/SQZ.COM diff --git a/Tools/cpm/bin/TEX21.COM b/Tools/cpm/bin80/TEX21.COM similarity index 100% rename from Tools/cpm/bin/TEX21.COM rename to Tools/cpm/bin80/TEX21.COM diff --git a/Tools/cpm/bin/TEX21A.COM b/Tools/cpm/bin80/TEX21A.COM similarity index 100% rename from Tools/cpm/bin/TEX21A.COM rename to Tools/cpm/bin80/TEX21A.COM diff --git a/Tools/cpm/bin/TEX21B.COM b/Tools/cpm/bin80/TEX21B.COM similarity index 100% rename from Tools/cpm/bin/TEX21B.COM rename to Tools/cpm/bin80/TEX21B.COM diff --git a/Tools/cpm/bin/UCRLZH.COM b/Tools/cpm/bin80/UCRLZH.COM similarity index 100% rename from Tools/cpm/bin/UCRLZH.COM rename to Tools/cpm/bin80/UCRLZH.COM diff --git a/Tools/cpm/bin/UNARC.COM b/Tools/cpm/bin80/UNARC.COM similarity index 100% rename from Tools/cpm/bin/UNARC.COM rename to Tools/cpm/bin80/UNARC.COM diff --git a/Tools/cpm/bin/UNCR.COM b/Tools/cpm/bin80/UNCR.COM similarity index 100% rename from Tools/cpm/bin/UNCR.COM rename to Tools/cpm/bin80/UNCR.COM diff --git a/Tools/cpm/bin/UNZIP.COM b/Tools/cpm/bin80/UNZIP.COM similarity index 100% rename from Tools/cpm/bin/UNZIP.COM rename to Tools/cpm/bin80/UNZIP.COM diff --git a/Tools/cpm/bin/UNZIP154.COM b/Tools/cpm/bin80/UNZIP154.COM similarity index 100% rename from Tools/cpm/bin/UNZIP154.COM rename to Tools/cpm/bin80/UNZIP154.COM diff --git a/Tools/cpm/bin/UNZIP186.COM b/Tools/cpm/bin80/UNZIP186.COM similarity index 100% rename from Tools/cpm/bin/UNZIP186.COM rename to Tools/cpm/bin80/UNZIP186.COM diff --git a/Tools/cpm/bin/USQ.COM b/Tools/cpm/bin80/USQ.COM similarity index 100% rename from Tools/cpm/bin/USQ.COM rename to Tools/cpm/bin80/USQ.COM diff --git a/Tools/cpm/bin/Z80ASM.COM b/Tools/cpm/bin80/Z80ASM.COM similarity index 100% rename from Tools/cpm/bin/Z80ASM.COM rename to Tools/cpm/bin80/Z80ASM.COM diff --git a/Tools/cpm/bin/ZMAC.COM b/Tools/cpm/bin80/ZMAC.COM similarity index 100% rename from Tools/cpm/bin/ZMAC.COM rename to Tools/cpm/bin80/ZMAC.COM diff --git a/Tools/cpm/bin/ZML.COM b/Tools/cpm/bin80/ZML.COM similarity index 100% rename from Tools/cpm/bin/ZML.COM rename to Tools/cpm/bin80/ZML.COM diff --git a/Tools/cpm/bin/ZMLIB.COM b/Tools/cpm/bin80/ZMLIB.COM similarity index 100% rename from Tools/cpm/bin/ZMLIB.COM rename to Tools/cpm/bin80/ZMLIB.COM diff --git a/Tools/cpm/bin/ZSM.COM b/Tools/cpm/bin80/ZSM.COM similarity index 100% rename from Tools/cpm/bin/ZSM.COM rename to Tools/cpm/bin80/ZSM.COM diff --git a/Tools/cpm/include/CTYPE.H b/Tools/cpm/include80/CTYPE.H similarity index 100% rename from Tools/cpm/include/CTYPE.H rename to Tools/cpm/include80/CTYPE.H diff --git a/Tools/cpm/include/ERRNO.H b/Tools/cpm/include80/ERRNO.H similarity index 100% rename from Tools/cpm/include/ERRNO.H rename to Tools/cpm/include80/ERRNO.H diff --git a/Tools/cpm/include/FCNTL.H b/Tools/cpm/include80/FCNTL.H similarity index 100% rename from Tools/cpm/include/FCNTL.H rename to Tools/cpm/include80/FCNTL.H diff --git a/Tools/cpm/include/IO.H b/Tools/cpm/include80/IO.H similarity index 100% rename from Tools/cpm/include/IO.H rename to Tools/cpm/include80/IO.H diff --git a/Tools/cpm/include/LIBC.H b/Tools/cpm/include80/LIBC.H similarity index 100% rename from Tools/cpm/include/LIBC.H rename to Tools/cpm/include80/LIBC.H diff --git a/Tools/cpm/include/MATH.H b/Tools/cpm/include80/MATH.H similarity index 100% rename from Tools/cpm/include/MATH.H rename to Tools/cpm/include80/MATH.H diff --git a/Tools/cpm/include/SETJMP.H b/Tools/cpm/include80/SETJMP.H similarity index 100% rename from Tools/cpm/include/SETJMP.H rename to Tools/cpm/include80/SETJMP.H diff --git a/Tools/cpm/include/SGTTY.H b/Tools/cpm/include80/SGTTY.H similarity index 100% rename from Tools/cpm/include/SGTTY.H rename to Tools/cpm/include80/SGTTY.H diff --git a/Tools/cpm/include/STDIO.H b/Tools/cpm/include80/STDIO.H similarity index 100% rename from Tools/cpm/include/STDIO.H rename to Tools/cpm/include80/STDIO.H diff --git a/Tools/cpm/lib/C.LIB b/Tools/cpm/lib80/C.LIB similarity index 100% rename from Tools/cpm/lib/C.LIB rename to Tools/cpm/lib80/C.LIB diff --git a/Tools/cpm/lib/M.LIB b/Tools/cpm/lib80/M.LIB similarity index 100% rename from Tools/cpm/lib/M.LIB rename to Tools/cpm/lib80/M.LIB diff --git a/Tools/cpm/lib/ROM.LIB b/Tools/cpm/lib80/ROM.LIB similarity index 100% rename from Tools/cpm/lib/ROM.LIB rename to Tools/cpm/lib80/ROM.LIB diff --git a/Tools/cpm/lib/T.LIB b/Tools/cpm/lib80/T.LIB similarity index 100% rename from Tools/cpm/lib/T.LIB rename to Tools/cpm/lib80/T.LIB diff --git a/Tools/unix/Makefile b/Tools/unix/Makefile index cba1782e..571e876d 100644 --- a/Tools/unix/Makefile +++ b/Tools/unix/Makefile @@ -9,7 +9,7 @@ ifeq ($(UNAME), Darwin) SUFFIX=osx endif -SUBDIRS = bst uz80as zx cpmtools bin2asm lzsa +SUBDIRS = bst uz80as zxcc cpmtools bin2asm lzsa all: @chmod +x casefn.sh diff --git a/Tools/unix/zx/Makefile b/Tools/unix/zx/Makefile deleted file mode 100644 index 862ec7a3..00000000 --- a/Tools/unix/zx/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -# -# hacked up brute force makefile for linux and osx -# -UNAME := $(shell uname) -ifeq ($(UNAME), Linux) - SUFFIX=linux -endif -ifeq ($(UNAME), Darwin) - SUFFIX=darwin -endif - -DEST = ../../$(UNAME) -CFLAGS = -g # -DDEBUG - -OBJECTS = zx.o cpmdrv.o cpmglob.o cpmparse.o cpmredir.o \ - drdos.o util.o xlt.o zxbdos.o zxcbdos.o zxdbdos.o z80.o -UNUSED = dirent.o - -all: zx $(DEST) - cp -p bios.bin zx $(DEST) - -$(DEST): - mkdir -p $(DEST) - -clean: - -rm -f $(OBJECTS) config.h zx - -clobber: clean - -rm -f $(DEST)/zx $(DEST)/bios.bin zx - -$(OBJECTS): config.h - -zx: $(OBJECTS) - $(CC) -o zx $(OBJECTS) - -config.h: config.h.$(SUFFIX) - cp config.h.$(SUFFIX) config.h diff --git a/Tools/unix/zx/config.h.darwin b/Tools/unix/zx/config.h.darwin deleted file mode 100644 index cc4b425c..00000000 --- a/Tools/unix/zx/config.h.darwin +++ /dev/null @@ -1,16 +0,0 @@ -//#define HAVE_WINDOWS_H -#define HAVE_DIRENT_H -#define HAVE_UTIME_H -#define HAVE_FCNTL_H -#define HAVE_UNISTD_H -#define BINDIR80 getenv("ZXBINDIR") -#define LIBDIR80 getenv("ZXLIBDIR") -#define INCDIR80 getenv("ZXINCDIR") -#define DARWIN -#include -#include -#define _S_IFDIR S_IFDIR -#define strcmpi(a,b) strcasecmp(a,b) -//#define WIN32 -//#define WINVER 0x0501 // target Windows XP -//#define _WIN32_WINNNT 0x0501 // target Windows XP diff --git a/Tools/unix/zx/config.h.linux b/Tools/unix/zx/config.h.linux deleted file mode 100644 index a015591c..00000000 --- a/Tools/unix/zx/config.h.linux +++ /dev/null @@ -1,17 +0,0 @@ -//#define HAVE_WINDOWS_H -#define HAVE_DIRENT_H -#define HAVE_UTIME_H -#define HAVE_FCNTL_H -#define HAVE_SYS_VFS_H -#define HAVE_UNISTD_H -#define BINDIR80 getenv("ZXBINDIR") -#define LIBDIR80 getenv("ZXLIBDIR") -#define INCDIR80 getenv("ZXINCDIR") -#define LINUX -#include -#include -#define _S_IFDIR S_IFDIR -#define strcmpi(a,b) strcasecmp(a,b) -//#define WIN32 -//#define WINVER 0x0501 // target Windows XP -//#define _WIN32_WINNNT 0x0501 // target Windows XP diff --git a/Tools/unix/zx/config.h.windows b/Tools/unix/zx/config.h.windows deleted file mode 100644 index 8186c485..00000000 --- a/Tools/unix/zx/config.h.windows +++ /dev/null @@ -1,9 +0,0 @@ -#define HAVE_WINDOWS_H -//#define HAVE_DIRENT_H -#define HAVE_FCNTL_H -#define BINDIR80 getenv("ZXBINDIR") -#define LIBDIR80 getenv("ZXLIBDIR") -#define INCDIR80 getenv("ZXINCDIR") -#define WIN32 -#define WINVER 0x0501 // target Windows XP -#define _WIN32_WINNNT 0x0501 // target Windows XP diff --git a/Tools/unix/zx/cpmparse.c b/Tools/unix/zx/cpmparse.c deleted file mode 100644 index 4c709ec1..00000000 --- a/Tools/unix/zx/cpmparse.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - - CPMREDIR: CP/M filesystem redirector - Copyright (C) 1998, John Elliott - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - This file parses filenames to FCBs. -*/ - -#include "cpmint.h" - -#define is_num(c) ((c >= '0') && (c <= '9')) - -static int parse_drive_user(char *txt, cpm_byte *fcb) -{ - char uid[4], drvid[4]; - int up, dp; - - for (up = dp = 0; *txt != ':'; ++txt) - { - if (is_num (*txt)) uid [up++] = *txt; - if (isalpha(*txt)) drvid[dp++] = *txt; - if (!is_num(*txt) && !isalpha(*txt)) return -1; - } - uid[up] = 0; drvid[dp] = 0; - - if (dp > 1) return -1; /* Invalid driveletter */ - if (up > 2) return -1; /* Invalid uid */ - - fcb[0x0d] = atoi(uid) + 1; if (fcb[0x0d] > 16) return -1; - - if (islower(drvid[0])) drvid[0] = toupper(drvid[0]); - - if (drvid[0] < 'A' || drvid[0] > 'P') return -1; - - fcb[0] = drvid[0] - '@'; - return 0; -} - - - -cpm_word fcb_parse(char *txt, cpm_byte *fcb) -{ - int nl = 0, tl = 0, pl = 0, phase = 0; - char *ntxt, ch; - - memset(fcb, 0, 0x24); - - if (txt[1] == ':' || txt[2] == ':' || txt[3] == ':') - { - if (parse_drive_user(txt, fcb)) return 0xFFFF; - /* Move past the colon */ - ntxt = strchr(txt, ':') + 1; - } - else ntxt = txt; - while (phase < 3) - { - ch = *ntxt; - if (islower(ch)) ch = toupper(ch); - - switch(ch) - { - case 0: - case '\r': /* EOL */ - phase = 4; - break; - - case '.': /* file.typ */ - if (!phase) ++phase; - else phase = 3; - break; - - case ';': /* Password */ - if (phase < 2) phase = 2; - else phase = 3; - break; - - case '[': case ']': case '=': case 9: case ' ': - case '>': case '<': case ':': case ',': case '/': - case '|': /* Terminator */ - phase = 3; - - default: - switch(phase) - { - case 0: - if (nl >= 8) return 0xFFFF; - fcb[++nl] = ch; - break; - - case 1: - if (tl >= 3) return 0xFFFF; - fcb[tl + 9] = ch; - ++tl; - break; - - case 2: - if (pl >= 8) return 0xFFFF; - fcb[pl + 0x10] = ch; - ++pl; - break; - } - break; - } - } - if (!nl) return 0xFFFF; - - fcb[0x1A] = pl; - - if (phase == 4) return 0; - - return ntxt - txt; -} diff --git a/Tools/unix/zx/readme.txt b/Tools/unix/zx/readme.txt deleted file mode 100644 index 15feb3e8..00000000 --- a/Tools/unix/zx/readme.txt +++ /dev/null @@ -1,72 +0,0 @@ -ZX Command - -An adaptation of zxcc-0.5.6 by Wayne Warthen - -This directory contains the source files used to build the "zx" tool. This tool -is essentially just John Elliott's zxcc package version zxcc-0.5.6 modified to -build for Windows and simplified down to just a single command (zx) -which is essentially just the zxcc command. - -Please see http://www.seasip.info/Unix/Zxcc/ for more information on zxcc. - -Note that this is a Win32 build. The code has not been updated to build as a 64-bit -binary. However, Win32 binaries run very nicely under 64 bit Windows. - -To build under Open Watcom or Microsoft Visual C++, use the following command: - - cl /Fe"zx.exe" zx.c cpmdrv.c cpmglob.c cpmparse.c cpmredir.c drdos.c util.c xlt.c zxbdos.c zxcbdos.c zxdbdos.c z80.c dirent.c - -To build a debug version, use the following command: - - cl /DDEBUG /Fe"zxdbg.exe" zx.c cpmdrv.c cpmglob.c cpmparse.c cpmredir.c drdos.c util.c xlt.c zxbdos.c zxcbdos.c zxdbdos.c z80.c dirent.c - -WARNING: There seems to be a rare scenario that breaks zx under the Open Watcom build. -CP/M allows a file to be accessed under multiple FCB's without an error. Open Watcom -will see this as an error. At present, the only tool I know of that does this is M80. - -December 5, 2014 - -After struggling to get the entire zxcc package to build nicely using autoconf, -I finally gave up and took a much more direct approach. I have extracted just -the source files needed and created a simple batch file to build the tool. I -realize this could be done much better, but I cheated in the interest of time. - -The one "real" change I made in the source code was that I modified the tool -to look for bios.bin in the same directory as the executable is in. This -just makes it much easier to set up (for me, anyway). - -The GPL status of everything remains in place and carries forward. - -Wayne Warthen -wwarthen@gmail.com - -March 15, 2017 - -- Updated to compile under Open Watcom. -- Implemented BDOS console status function. -- Set stdin and stdout to binary mode at startup. - -August 21, 2021 - -- Incorporated filename case insensitivity changes from Curt Mayer -- Incorporated fixes from Tony Nicholson at https://github.com/agn453/ZXCC - - Emulation of CP/M BDOS function 60 (call resident system extension) - should be disabled and return 0xFF in both the A and L registers. - - Change cpm_bdos_10() to return an unsigned result to avoid buffer - size being interpreted as negative. - - Fix the emulation of Z80 opcodes for IN (HL),(C) and - OUT (C),(HL) - opcodes 0xED,0x70 and 0xED,0x71 respectively. - This is noted in Fred Weigel's AM9511 arithmetic processing unit - emulation from https://github.com/ratboy666/am9511 in the howto.txt - description. NB: I have not included Fred's am9511 support at this - time into ZXCC. -- Fixed parse_to_fcb function in zx.c to handle parsing second automatic - FCB from command line -- I have not been able to reproduce the multiple FCBs referring to a - single file issue with Watcom documented above. Perhaps I fixed it - and don't remember or I found a bug-fixed version of M80. Not sure. - -Wayne Warthen -wwarthen@gmail.com - ---WBW 4:09 PM 8/21/2021 \ No newline at end of file diff --git a/Tools/unix/zx/xlt.c b/Tools/unix/zx/xlt.c deleted file mode 100644 index f0ba1da5..00000000 --- a/Tools/unix/zx/xlt.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - - CPMREDIR: CP/M filesystem redirector - Copyright (C) 1998, John Elliott - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - This file holds functions dealing with name translation; also the - initialisation code. -*/ - -#include "cpmint.h" - -/* Detect DRDOS */ - -#ifdef __MSDOS__ -static void drdos_init(void) -{ - -/* The DJGPP DOS extender won't detect DRDOS using intdos(), so we have - to use __dpmi_int() instead. */ - -#ifdef __GO32__ - __dpmi_regs ir; - - ir.x.ax = 0x4452; /* "DR" */ - - __dpmi_int(0x21, &ir); - if (ir.x.flags & 1) return; /* Not DRDOS */ - - redir_Msg("DRDOS detected.\r\n"); - - redir_drdos = 1; - -#else /* __GO32__ */ - - union REGS ir, or; - - ir.w.ax = 0x4452; /* "DR" */ - - intdos(&ir, &or); - if (or.w.cflag) return; /* Not DRDOS */ - - redir_Msg("DRDOS detected.\r\n"); - - redir_drdos = 1; -#endif /* __GO32__ */ -} -#endif /* __MSDOS__ */ - - - -int fcb_init(void) -{ - int n; - - /* A: to O: free */ - for (n = 0; n < 15; n++) redir_drive_prefix[n][0] = 0; - - strcpy(redir_drive_prefix[15], "./"); /* P: is current directory */ - - /* Log on to P:. It is the only drive at this point which we - * know works. */ - redir_cpmdrive = 15; -#ifdef __MSDOS__ - drdos_init(); -#endif - - return 1; -} - -/* Deinitialise the library. */ - -void fcb_deinit(void) -{ - /* Nothing */ -} - -/* Translate a name from the host FS to a CP/M name. This will (if necessary) - * create a mapping between a CP/M drive and a host directory path. - * - * CP/M drives A: to O: can be mapped in this way. P: is always the current - * drive. - * - */ - -void xlt_name(char *localname, char *cpmname) -{ - char ibuf[CPM_MAXPATH + 1]; - char nbuf[CPM_MAXPATH + 1]; - char *pname; - int n; - - sprintf(ibuf, "%-.*s", CPM_MAXPATH, localname); - pname = strrchr(ibuf, '/'); -#ifdef __MSDOS__ - if (!pname) pname = strrchr(ibuf,'\\'); - if (!pname) pname = strrchr(ibuf,':'); -#endif - if (!pname) /* No path separators in the name. It is therefore a - local filename, so map it to drive P: */ - { - strcpy(cpmname, "p:"); - strcat(cpmname, ibuf); - return; - } - ++pname; - strcpy(nbuf, pname); /* nbuf holds filename component */ - *pname = 0; /* ibuf holds path component */ - - /* See if the path is one of those already mapped to drives */ - - for (n = 0; n < 15; n++) - { - if (redir_drive_prefix[n][0] && !strcmp(ibuf, redir_drive_prefix[n])) - { - sprintf(cpmname,"%c:%s", n + 'a', nbuf); - return; - } - } - - /* It is not, see if another drive can be allocated */ - - for (n = 0; n < 15; n++) if (!redir_drive_prefix[n][0]) - { - strcpy(redir_drive_prefix[n], ibuf); - sprintf(cpmname,"%c:%s", n + 'a', nbuf); - return; - } - - /* No other drive can be allocated */ - - strcpy(cpmname,"p:"); - strcat(cpmname, nbuf); -} - -/* It is sometimes convenient to set some fixed mappings. This will create - * a mapping for a given directory. - * Pass drive = -1 for "first available", or 0-15 for A: to P: - */ - -int xlt_map(int drive, char *localdir) -{ - int n; - - if (drive == -1) - { - for (n = 0; n < 15; n++) if (!redir_drive_prefix[n][0]) - { - drive = n; - break; - } - if (drive == -1) return 0; /* No space for mappings */ - } - if (redir_drive_prefix[drive][0]) return 0; /* Drive taken */ - - sprintf(redir_drive_prefix[drive], "%-.*s", CPM_MAXPATH, localdir); - return 1; -} - - -/* Unmap a drive - */ - -int xlt_umap(int drive) -{ - if (!redir_drive_prefix[drive][0]) return 0; /* Drive not taken */ - redir_drive_prefix[drive][0] = 0; - return 1; -} - - -char *xlt_getcwd(int drive) -{ - if (drive < 0 || drive > 16) return ""; - - return redir_drive_prefix[drive]; -} - diff --git a/Tools/unix/zx/zx.html b/Tools/unix/zx/zx.html deleted file mode 100644 index ff2da790..00000000 --- a/Tools/unix/zx/zx.html +++ /dev/null @@ -1,132 +0,0 @@ -zx CP/M Command Line Emulator - -

zx CP/M Command Line Emulator

- -

zx allows execution of CP/M 2.2 and 3.X application from a -Windows command line. It is compatible with Windows XP and greater (both -32 and 64 bit).

- -

zx is basically a port of a subset of the zxcc program by John Elliott. -The GPLv2 licensing carries forward. Please refer to the - -zxcc web page for more information.

- -

While the original zxcc package was generally intended to allow -execution of the Hi-Tech C CP/M compiler under Unix, zx is slightly -more general and intended to allow running most CP/M tools. Specific -changes were incorporated to improve interactice console operation of -CP/M applications. Additionally, Curt Mayer added case insensitivity -for filenames under Unix variants.

- -

Setup

- -

The zx application (zx.exe) may be copied to any directory for execution. -The bios.bin file must be copied to the same directory. For ease of use, -you will probably want the directory to part of your PATH environment -variable so that you can run the tool from any location.

- -

You will also need the CP/M applications that you want to run. -zx will load files fromthe current directory or one of the following -directories based on file type. Any of the following environment -variables may be defined to determine where zx searches for the -respective file types:

- -
    -
  • ZXBINDIR may contain a single path which will -be searched for executable files (usually *.com)
  • -
  • ZXLIBDIR may contain a single path which will -be search for library files (usually *.lib)
  • -
  • ZXINCDIR may contain a single path which will -be searched for include files (usually *.inc)
  • -
- -

Usage

- -

In general CP/M applications are executed by prefixing the CP/M command -line with "zx". So for example, you could assemble a test.asm using -rmac with a command line like:

- -
zx rmac hello
- -

In this case, rmac.com would need to be in the directory specified by -environment variable ZXBINDIR or in the current directory. Also, -hello.asm would need to be in the current directory.

- -

Filenames

- -

Where you would normally enter a CP/M filename you instead enter -a Windows filename. Note that you will need to use a forward slash -instead of the traditional backslash as a directory separator. The -filename itself (as opposed to any directories in -its path) must obey CP/M 8.3 naming conventions.

- -

Where the documentation requires a CP/M drive letter/user number -you should enter a path complete with trailing slash, for example:

-
-I/usr/src/linux-80/include/
- -

Technical

- -

zx emulates a subset of CP/M 3; hopefully enough to run the -most CP/M tools. It can be used as a limited general-purpose CP/M 3 -emulator provided the emulated program only uses a common subset of -system calls.

- -

Syntax for zx is:

- -
-zx comfile.com arg1 arg2 ... -
- -

The comfile is the program to run; zx searches the current -directory and ZXBINDIR for it.

- -

The arguments are parsed in this way:

- -
    -
  • Any argument starting with a - sign is passed to the CP/M program as-is, -minus the leading - sign. -
  • Any argument starting with a + sign is parsed as a filename (see below) -and then concatenated to the previous argument. -
  • Any argument starting "+-" is concatenated without being parsed. -
  • All other arguments are parsed as filenames. The path is -converted to a CP/M driveletter. -
- -

For example: -

-zx foo.com --Q -A /src/main --I +/src/sub +-, +/foo/bar -
- -

would pass these arguments to foo.com:

- -
--Q A d:main -Id:sub,e:bar -
- -

The other programs are merely wrappers that convert their command lines -into the form required by zx.

- -

Errors

- -

Any errors raised by the zx runtime system will be prefixed -with zx:. Some errors you may encounter are:

- -
-
Unsupported BDOS call
-
Part of CP/M 3 that the program uses has not been emulated. Add the -required functionality to zxbdos.c and recompile.
-
Z80 encountered invalid trap
-
The CP/M program being run attempted to call the zx runtime -system with an unknown call number.
-
- -

Acknowledgements

- -
    -
  • zxcc was written by John Elliott
  • -
  • Hi-Tech C was written by Hi-Tech Software.
  • -
  • The Z80 emulation engine was written by Ian Collier.
  • -
  • Thanks to Jacob Nevins, Andy Parkins and others for bug fix suggestions.
  • -
- - diff --git a/Tools/unix/zxcc/Build-OW.cmd b/Tools/unix/zxcc/Build-OW.cmd new file mode 100644 index 00000000..3be3cdaa --- /dev/null +++ b/Tools/unix/zxcc/Build-OW.cmd @@ -0,0 +1,21 @@ +@echo off +setlocal + +:: +:: Edit WATCOM variable below as needed for your environment +:: +set WATCOM=..\..\Tools\WATCOM2 + +set PATH=%WATCOM%\BINNT;%WATCOM%\BINW;%PATH% +set EDPATH=%WATCOM%\EDDAT +set INCLUDE=%WATCOM%\H;%WATCOM%\H\NT + +copy config.h.windows config.h + +cl /Fe"zxcc.exe" zxcc.c cpmdrv.c cpmglob.c cpmparse.c cpmredir.c drdos.c util.c track.c xlt.c zxbdos.c zxcbdos.c zxdbdos.c z80.c +if errorlevel 1 exit /b 255 + +cl /Fe"zxccdbg.exe" /DDEBUG zxcc.c cpmdrv.c cpmglob.c cpmparse.c cpmredir.c drdos.c util.c track.c xlt.c zxbdos.c zxcbdos.c zxdbdos.c z80.c +if errorlevel 1 exit /b 255 + +copy cpm\bios.bin . \ No newline at end of file diff --git a/Tools/unix/zxcc/Build-VC.cmd b/Tools/unix/zxcc/Build-VC.cmd new file mode 100644 index 00000000..2d199c6d --- /dev/null +++ b/Tools/unix/zxcc/Build-VC.cmd @@ -0,0 +1,25 @@ +@echo off +setlocal + +:: +:: Visual Studio x86 Native Tools Command Prompt is assumed +:: + +:: Below configures VS2012 to target Windows XP and beyond +:: Not sure if it will work in later versions of VS, but seems +:: to do no harm. +set INCLUDE=%ProgramFiles(x86)%\Microsoft SDKs\Windows\7.1A\Include;%INCLUDE% +set PATH=%ProgramFiles(x86)%\Microsoft SDKs\Windows\7.1A\Bin;%PATH% +set LIB=%ProgramFiles(x86)%\Microsoft SDKs\Windows\7.1A\Lib;%LIB% +set CL=/D_USING_V110_SDK71_;%CL% +set LINK=/SUBSYSTEM:CONSOLE,5.01 %LINK% + +copy config.h.windows config.h + +cl zxcc.c cpmdrv.c cpmglob.c cpmparse.c cpmredir.c drdos.c util.c xlt.c zxbdos.c zxcbdos.c zxdbdos.c z80.c dirent.c track.c +if errorlevel 1 exit /b 255 + +cl /DDEBUG /Fe"zxccdbg.exe" zxcc.c cpmdrv.c cpmglob.c cpmparse.c cpmredir.c drdos.c util.c xlt.c zxbdos.c zxcbdos.c zxdbdos.c z80.c dirent.c track.c +if errorlevel 1 exit /b 255 + +copy cpm\bios.bin . \ No newline at end of file diff --git a/Tools/unix/zx/COPYING b/Tools/unix/zxcc/COPYING similarity index 100% rename from Tools/unix/zx/COPYING rename to Tools/unix/zxcc/COPYING diff --git a/Tools/unix/zxcc/Clean.cmd b/Tools/unix/zxcc/Clean.cmd new file mode 100644 index 00000000..eb7fc764 --- /dev/null +++ b/Tools/unix/zxcc/Clean.cmd @@ -0,0 +1,11 @@ +@echo off +setlocal + +if exist *.exe del *.exe +if exist *.obj del *.obj +if exist *.err del *.err +if exist *.o del *.o +if exist *.bin del *.bin +if exist zxcc del zxcc +if exist zxccdbg del zxccdbg +if exist config.h del config.h diff --git a/Tools/unix/zxcc/Makefile b/Tools/unix/zxcc/Makefile new file mode 100644 index 00000000..70420378 --- /dev/null +++ b/Tools/unix/zxcc/Makefile @@ -0,0 +1,40 @@ +# +# hacked up brute force makefile for linux and osx +# +UNAME := $(shell uname) +ifeq ($(UNAME), Linux) + SUFFIX=linux +endif +ifeq ($(UNAME), Darwin) + SUFFIX=darwin +endif + +DEST = ../../$(UNAME) +CFLAGS = -g # -DDEBUG + +OBJECTS = zxcc.o cpmdrv.o cpmglob.o cpmparse.o cpmredir.o \ + drdos.o util.o xlt.o zxbdos.o zxcbdos.o zxdbdos.o z80.o track.o +UNUSED = dirent.o + +all: zxcc $(DEST) + cp -p bios.bin zxcc $(DEST) + +$(DEST): + mkdir -p $(DEST) + +clean: + -rm -f $(OBJECTS) config.h zxcc bios.bin + +clobber: clean + -rm -f $(DEST)/zxcc $(DEST)/bios.bin zxcc + +$(OBJECTS): config.h bios.bin + +zxcc: $(OBJECTS) + $(CC) -o zxcc $(OBJECTS) + +config.h: config.h.$(SUFFIX) + cp config.h.$(SUFFIX) config.h + +bios.bin: cpm/bios.bin + cp cpm/bios.bin . diff --git a/Tools/unix/zx/cbops.h b/Tools/unix/zxcc/cbops.h similarity index 96% rename from Tools/unix/zx/cbops.h rename to Tools/unix/zxcc/cbops.h index 47b69da0..f583e3a8 100644 --- a/Tools/unix/zx/cbops.h +++ b/Tools/unix/zxcc/cbops.h @@ -1,172 +1,172 @@ -/* Emulations of the CB operations of the Z80 instruction set. - * Copyright (C) 1994 Ian Collier. - * - * 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 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#define var_t unsigned char t -#define rlc(x) (x=(x<<1)|(x>>7),rflags(x,x&1)) -#define rrc(x) do{var_t=x&1;x=(x>>1)|(t<<7);rflags(x,t);}while(0) -#define rl(x) do{var_t=x>>7;x=(x<<1)|(f&1);rflags(x,t);}while(0) -#define rr(x) do{var_t=x&1;x=(x>>1)|(f<<7);rflags(x,t);}while(0) -#define sla(x) do{var_t=x>>7;x<<=1;rflags(x,t);}while(0) -#define sra(x) do{var_t=x&1;x=((signed char)x)>>1;rflags(x,t);}while(0) -#define sll(x) do{var_t=x>>7;x=(x<<1)|1;rflags(x,t);}while(0) -#define srl(x) do{var_t=x&1;x>>=1;rflags(x,t);}while(0) - -#define rflags(x,c) (f=(c)|(x&0xa8)|((!x)<<6)|parity(x)) - -#define bit(n,x) (f=(f&1)|((x&(1<>3)&7; - switch(op&0xc7){ - case 0x40: bit(n,b); break; - case 0x41: bit(n,c); break; - case 0x42: bit(n,d); break; - case 0x43: bit(n,e); break; - case 0x44: bit(n,h); break; - case 0x45: bit(n,l); break; - case 0x46: tstates+=4;val=fetch(addr);bit(n,val);store(addr,val);break; - case 0x47: bit(n,a); break; - case 0x80: res(n,b); break; - case 0x81: res(n,c); break; - case 0x82: res(n,d); break; - case 0x83: res(n,e); break; - case 0x84: res(n,h); break; - case 0x85: res(n,l); break; - case 0x86: tstates+=4;val=fetch(addr);res(n,val);store(addr,val);break; - case 0x87: res(n,a); break; - case 0xc0: set(n,b); break; - case 0xc1: set(n,c); break; - case 0xc2: set(n,d); break; - case 0xc3: set(n,e); break; - case 0xc4: set(n,h); break; - case 0xc5: set(n,l); break; - case 0xc6: tstates+=4;val=fetch(addr);set(n,val);store(addr,val);break; - case 0xc7: set(n,a); break; - } - } - if(ixoriy)switch(reg){ - case 0:b=val; break; - case 1:c=val; break; - case 2:d=val; break; - case 3:e=val; break; - case 4:h=val; break; - case 5:l=val; break; - case 7:a=val; break; - } -} - -#undef var_t -#undef rlc -#undef rrc -#undef rl -#undef rr -#undef sla -#undef sra -#undef sll -#undef srl -#undef rflags -#undef bit -#undef set -#undef res +/* Emulations of the CB operations of the Z80 instruction set. + * Copyright (C) 1994 Ian Collier. + * + * 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 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define var_t unsigned char t +#define rlc(x) (x=(x<<1)|(x>>7),rflags(x,x&1)) +#define rrc(x) do{var_t=x&1;x=(x>>1)|(t<<7);rflags(x,t);}while(0) +#define rl(x) do{var_t=x>>7;x=(x<<1)|(f&1);rflags(x,t);}while(0) +#define rr(x) do{var_t=x&1;x=(x>>1)|(f<<7);rflags(x,t);}while(0) +#define sla(x) do{var_t=x>>7;x<<=1;rflags(x,t);}while(0) +#define sra(x) do{var_t=x&1;x=((signed char)x)>>1;rflags(x,t);}while(0) +#define sll(x) do{var_t=x>>7;x=(x<<1)|1;rflags(x,t);}while(0) +#define srl(x) do{var_t=x&1;x>>=1;rflags(x,t);}while(0) + +#define rflags(x,c) (f=(c)|(x&0xa8)|((!x)<<6)|parity(x)) + +#define bit(n,x) (f=(f&1)|((x&(1<>3)&7; + switch(op&0xc7){ + case 0x40: bit(n,b); break; + case 0x41: bit(n,c); break; + case 0x42: bit(n,d); break; + case 0x43: bit(n,e); break; + case 0x44: bit(n,h); break; + case 0x45: bit(n,l); break; + case 0x46: tstates+=4;val=fetch(addr);bit(n,val);store(addr,val);break; + case 0x47: bit(n,a); break; + case 0x80: res(n,b); break; + case 0x81: res(n,c); break; + case 0x82: res(n,d); break; + case 0x83: res(n,e); break; + case 0x84: res(n,h); break; + case 0x85: res(n,l); break; + case 0x86: tstates+=4;val=fetch(addr);res(n,val);store(addr,val);break; + case 0x87: res(n,a); break; + case 0xc0: set(n,b); break; + case 0xc1: set(n,c); break; + case 0xc2: set(n,d); break; + case 0xc3: set(n,e); break; + case 0xc4: set(n,h); break; + case 0xc5: set(n,l); break; + case 0xc6: tstates+=4;val=fetch(addr);set(n,val);store(addr,val);break; + case 0xc7: set(n,a); break; + } + } + if(ixoriy)switch(reg){ + case 0:b=val; break; + case 1:c=val; break; + case 2:d=val; break; + case 3:e=val; break; + case 4:h=val; break; + case 5:l=val; break; + case 7:a=val; break; + } +} + +#undef var_t +#undef rlc +#undef rrc +#undef rl +#undef rr +#undef sla +#undef sra +#undef sll +#undef srl +#undef rflags +#undef bit +#undef set +#undef res diff --git a/Tools/unix/zxcc/config.h.darwin b/Tools/unix/zxcc/config.h.darwin new file mode 100644 index 00000000..b3df1720 --- /dev/null +++ b/Tools/unix/zxcc/config.h.darwin @@ -0,0 +1,6 @@ +#define HAVE_DIRENT_H +#define HAVE_UTIME_H +#define HAVE_FCNTL_H +#define HAVE_UNISTD_H +#define DARWIN +//#define FILETRACKER 1 diff --git a/Tools/unix/zxcc/config.h.linux b/Tools/unix/zxcc/config.h.linux new file mode 100644 index 00000000..86925d43 --- /dev/null +++ b/Tools/unix/zxcc/config.h.linux @@ -0,0 +1,9 @@ +#define HAVE_DIRENT_H +#define HAVE_UTIME_H +#define HAVE_FCNTL_H +#define HAVE_SYS_VFS_H +#define HAVE_UNISTD_H +#define HAVE_STRING_H +#define HAVE_STDLIB_H +#define LINUX +//#define FILETRACKER 1 diff --git a/Tools/unix/zxcc/config.h.windows b/Tools/unix/zxcc/config.h.windows new file mode 100644 index 00000000..1b838310 --- /dev/null +++ b/Tools/unix/zxcc/config.h.windows @@ -0,0 +1,5 @@ +#define HAVE_WINDOWS_H +#define HAVE_FCNTL_H +#define WINVER _WIN32_WINNT_WINXP // target Windows XP +#define _WIN32_WINNT _WIN32_WINNT_WINXP // target Windows XP +//#define FILETRACKER 1 diff --git a/Tools/unix/zx/bios.bin b/Tools/unix/zxcc/cpm/bios.bin similarity index 100% rename from Tools/unix/zx/bios.bin rename to Tools/unix/zxcc/cpm/bios.bin diff --git a/Tools/unix/zx/cpm/bios.com b/Tools/unix/zxcc/cpm/bios.com similarity index 100% rename from Tools/unix/zx/cpm/bios.com rename to Tools/unix/zxcc/cpm/bios.com diff --git a/Tools/unix/zx/cpm/bios.lst b/Tools/unix/zxcc/cpm/bios.lst similarity index 100% rename from Tools/unix/zx/cpm/bios.lst rename to Tools/unix/zxcc/cpm/bios.lst diff --git a/Tools/unix/zx/cpm/bios.z80 b/Tools/unix/zxcc/cpm/bios.z80 similarity index 100% rename from Tools/unix/zx/cpm/bios.z80 rename to Tools/unix/zxcc/cpm/bios.z80 diff --git a/Tools/unix/zx/cpmdrv.c b/Tools/unix/zxcc/cpmdrv.c similarity index 96% rename from Tools/unix/zx/cpmdrv.c rename to Tools/unix/zxcc/cpmdrv.c index 24042e5b..8dcd8889 100644 --- a/Tools/unix/zx/cpmdrv.c +++ b/Tools/unix/zxcc/cpmdrv.c @@ -22,13 +22,12 @@ #include "cpmint.h" -#ifdef WIN32 - +#ifdef _WIN32 static char *drive_to_hostdrive(int cpm_drive) { static char prefix[CPM_MAXPATH]; char *lpfp; - DWORD dw; + dword dw; if (!redir_drive_prefix[cpm_drive]) return NULL; dw = GetFullPathName(redir_drive_prefix[cpm_drive], sizeof(prefix), @@ -37,7 +36,7 @@ static char *drive_to_hostdrive(int cpm_drive) if (!dw) return NULL; if (prefix[1] == ':') /* If path starts with a drive, limit it */ { /* to just that drive */ - prefix[2] = '/'; + prefix[2] = '\\'; /* GetDiskFreeSpace should have trailing backslash */ prefix[3] = 0; } return prefix; @@ -122,7 +121,7 @@ cpm_word fcb_resro(cpm_word bitmap) cpm_word fcb_sync(cpm_byte flag) { -#ifdef WIN32 +#ifdef _WIN32 return 0; #else sync(); return 0; /* Apparently some sync()s are void not int */ @@ -132,7 +131,7 @@ cpm_word fcb_sync(cpm_byte flag) cpm_word fcb_purge() { -#ifdef WIN32 +#ifdef _WIN32 return 0; #else sync(); return 0; /* Apparently some sync()s are void not int */ @@ -182,3 +181,6 @@ cpm_word fcb_dfree (cpm_byte drive, cpm_byte *dma) redir_wr24(dma, 0x8000L); /* 8MB / 128 / 2 */ return 0; } + + + diff --git a/Tools/unix/zx/cpmglob.c b/Tools/unix/zxcc/cpmglob.c similarity index 94% rename from Tools/unix/zx/cpmglob.c rename to Tools/unix/zxcc/cpmglob.c index 5566d8a4..dadae255 100644 --- a/Tools/unix/zx/cpmglob.c +++ b/Tools/unix/zxcc/cpmglob.c @@ -21,6 +21,10 @@ */ #include "cpmint.h" +#ifdef _MSC_VER +#define S_ISDIR(mode) (((mode) & _S_IFDIR) != 0) +#endif + static cpm_byte *find_fcb; static int find_n; @@ -50,7 +54,8 @@ static char upper(char c) static int cpm_match(char *s, cpm_byte *fcb, cpm_byte *pattern) { - int n, m; + int n; + size_t m; char *dotpos; m = strlen(s); @@ -98,10 +103,11 @@ static int cpm_match(char *s, cpm_byte *fcb, cpm_byte *pattern) if (((fcb[0] & 0x7F) == '?') || (fcb[0] & 0x80)) { return 1; } - - for (n = 0; n < 11; n++) { + for (n = 0; n < 11; n++) + { if (fcb[n+1] == '?') continue; - if ((pattern[n] & 0x7F) != (fcb[n+1] & 0x7F)) { + if ((pattern[n] & 0x7F) != (fcb[n+1] & 0x7F)) + { return 0; } } @@ -147,8 +153,7 @@ static struct dirent * next_entry(DIR *dir, cpm_byte *fcb, cpm_byte *pattern, redir_Msg("Can't stat %s so omitting it.\n", target_name); continue; /* Can't stat */ } - //if (S_ISDIR(st->st_mode)) - if ((st->st_mode) & _S_IFDIR) + if (S_ISDIR(st->st_mode)) { /* Searching for files only */ if (fcb[0] != '?' && fcb[0] < 0x80) @@ -291,17 +296,17 @@ cpm_word redir_find(int n, cpm_byte *fcb, cpm_byte *dma) dma[0x0d] = st.st_size & 0x7F; /* Last record byte count */ dma[0x0e] = 0; /* Extent counter, high */ -#ifdef __MSDOS__ - _dos_getfileattr(target_name, (unsigned int *)&attrib); +#ifdef _WIN32 + attrib = GetFileAttributesA(target_name); rights = redir_drdos_get_rights(target_name); if (rights && ((fcb[0] & 0x7F) == '?')) find_xfcb = 1; #else attrib = 0; rights = 0; #endif - if (attrib & 1) dma[9] |= 0x80; - if (attrib & 4) dma[10] |= 0x80; - if (!(attrib & 0x20)) dma[11] |= 0x80; + if (attrib & 1) dma[9] |= 0x80; /* read only */ + if (attrib & 4) dma[10] |= 0x80; /* system */ + if (!(attrib & 0x20)) dma[11] |= 0x80; /* archive */ @@ -310,14 +315,13 @@ cpm_word redir_find(int n, cpm_byte *fcb, cpm_byte *dma) recs = (st.st_size + 127) / 128; dma[0x0f] = (recs > 127) ? 0x80 : (recs & 0x7F); dma[0x10] = 0x80; - //if (S_ISDIR(st.st_mode)) dma[0x10] |= 0x40; - if ((st.st_mode) & _S_IFDIR) {dma[0x10] |= 0x40;} + if (S_ISDIR(st.st_mode)) dma[0x10] |= 0x40; if (attrib & 2) dma[0x10] |= 0x20; dma[0x10] |= ((entryno & 0x1FFF) >> 8); dma[0x11] = dma[0x10]; dma[0x12] = entryno & 0xFF; - redir_wr32(dma + 0x16, st.st_mtime); /* Modification time. */ + redir_wr32(dma + 0x16, (dword)st.st_mtime); /* Modification time. */ /* TODO: It should be in DOS */ /* format */ /* TODO: At 0x1A, 1st cluster */ @@ -483,10 +487,12 @@ cpm_word fcb_unlink(cpm_byte *fcb, cpm_byte *dma) } else { + releaseFile(target_name); handle = unlink(target_name); if (handle && redir_password_error()) { redir_password_append(target_name, dma); + releaseFile(target_name); handle = unlink(target_name); } } @@ -559,7 +565,8 @@ cpm_word redir_get_label(cpm_byte drv, char *pattern) cpm_word redir_get_label(cpm_byte drv, char *pattern) { char *dname; - int l, n; + size_t l; + int n; memset(pattern, ' ', 11); diff --git a/Tools/unix/zx/cpmint.h b/Tools/unix/zxcc/cpmint.h similarity index 76% rename from Tools/unix/zx/cpmint.h rename to Tools/unix/zxcc/cpmint.h index e6878174..65879654 100644 --- a/Tools/unix/zx/cpmint.h +++ b/Tools/unix/zxcc/cpmint.h @@ -20,82 +20,100 @@ This file holds internal declarations for the library. */ -#include "config.h" +#ifndef _WIN32 + #include "config.h" + #define DIRSEP "/" +#else + #include "config.h" + #define DIRSEP "/\\:" +#endif #include -#include +#ifdef HAVE_STDLIB_H + #include +#endif #include -#include +#ifdef HAVE_STRING_H + #include +#endif #include #include -#include +#ifdef _WIN32 + #include +#endif +#ifdef HAVE_SYS_TYPES_H + #include +#endif #include #include #ifdef HAVE_DIRENT_H -# include -#else -#ifdef __WATCOMC__ -# include -# include + #include + #ifdef HAVE_DIRECT_H + #include + #endif #else -# include "dirent.h" -#endif + #ifdef __WATCOMC__ + #include + #include + #else + #include "dirent.h" + #endif #endif #ifdef HAVE_NDIR_H -# include + #include #endif #ifdef HAVE_SYS_DIR_H -# include + #include #endif #ifdef HAVE_SYS_NDIR_H -# include + #include #endif #ifdef HAVE_WINDOWS_H -# include + #include #endif #ifdef HAVE_WINNT_H -# include + #include #endif #ifdef HAVE_SYS_VFS_H -# include + #include #endif #ifdef HAVE_UTIME_H -# include + #include #endif #ifdef HAVE_FCNTL_H -# include + #include #endif #ifdef HAVE_UNISTD_H -# include + #include #endif -#ifdef WIN32 -# define strcasecmp _stricmp +#ifndef _WIN32 + #include + #include + #define _S_IFDIR S_IFDIR #endif +/* MSDOS includes removed */ -#ifdef __MSDOS__ - #include - #include - #include - #ifdef __GO32__ - #include - #include - #include - #endif +#ifdef _WIN32 + #define mkdir(dir, mode) _mkdir(dir) + #define strcasecmp _stricmp + int truncate(const char* path, off_t length); /* see util.c */ + #define ftruncate _chsize + /* note Windows build assumes Windows is configured as a non case sensitive filesystem */ +#else + #define CASE_SENSITIVE_FILESYSTEM 1 #endif -#define CASE_SENSITIVE_FILESYSTEM 0 - - #include "cpmredir.h" typedef unsigned long dword; /* Must be at least 32 bits, and >= sizeof(int) */ + #ifdef CPMDEF - #define EXT - #define INIT(x) =x + #define EXT + #define INIT(x) =x #else - #define EXT extern - #define INIT(x) + #define EXT extern + #define INIT(x) #endif /* The 16 directories to which the 16 CP/M drives are mapped */ @@ -149,9 +167,11 @@ int redir_verify_fcb(cpm_byte *fcb); long zxlseek(int fd, long offset, int wh); #ifdef DEBUG + // long zxlseek(int fd, long offset, int wh); void redir_Msg(char *s, ...); void redir_showfcb(cpm_byte *fcb); #else + // #define zxlseek lseek /* Warning: This is a GCC extension */ #define redir_Msg(x, ...) #define redir_showfcb(x) @@ -224,3 +244,6 @@ cpm_word redir_password_error(void); /* Append password to filename (FILE.TYP -> FILE.TYP;PASSWORD) */ void redir_password_append(char *s, cpm_byte *dma); +void releaseFile(char *fname); +int trackFile(char *fname, void *fcb, int fd); +#define releaseFCB(fcb) trackFile(NULL, fcb, -1) diff --git a/Tools/unix/zxcc/cpmparse.c b/Tools/unix/zxcc/cpmparse.c new file mode 100644 index 00000000..ea0949ed --- /dev/null +++ b/Tools/unix/zxcc/cpmparse.c @@ -0,0 +1,126 @@ +/* + + CPMREDIR: CP/M filesystem redirector + Copyright (C) 1998, John Elliott + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + This file parses filenames to FCBs. +*/ + +#include "cpmint.h" + +#define is_num(c) ((c >= '0') && (c <= '9')) + +static int parse_drive_user(char *txt, cpm_byte *fcb) +{ + char uid[4], drvid[4]; + int up, dp; + + for (up = dp = 0; *txt != ':'; ++txt) + { + if (is_num (*txt)) uid [up++] = *txt; + if (isalpha(*txt)) drvid[dp++] = *txt; + if (!is_num(*txt) && !isalpha(*txt)) return -1; + } + uid[up] = 0; drvid[dp] = 0; + + if (dp > 1) return -1; /* Invalid driveletter */ + if (up > 2) return -1; /* Invalid uid */ + + fcb[0x0d] = atoi(uid) + 1; if (fcb[0x0d] > 16) return -1; + + if (islower(drvid[0])) drvid[0] = toupper(drvid[0]); + + if (drvid[0] < 'A' || drvid[0] > 'P') return -1; + + fcb[0] = drvid[0] - '@'; + return 0; +} + + + +cpm_word fcb_parse(char *txt, cpm_byte *fcb) +{ + int nl = 0, tl = 0, pl = 0, phase = 0; + char *ntxt, ch; + + memset(fcb, 0, 0x24); + + if (txt[1] == ':' || txt[2] == ':' || txt[3] == ':') + { + if (parse_drive_user(txt, fcb)) return 0xFFFF; + /* Move past the colon */ + ntxt = strchr(txt, ':') + 1; + } + else ntxt = txt; + while (phase < 3) + { + ch = *ntxt; + if (islower(ch)) ch = toupper(ch); + + switch(ch) + { + case 0: + case '\r': /* EOL */ + phase = 4; + break; + + case '.': /* file.typ */ + if (!phase) ++phase; + else phase = 3; + break; + + case ';': /* Password */ + if (phase < 2) phase = 2; + else phase = 3; + break; + + case '[': case ']': case '=': case 9: case ' ': + case '>': case '<': case ':': case ',': case '/': + case '|': /* Terminator */ + phase = 3; + + default: + switch(phase) + { + case 0: + if (nl >= 8) return 0xFFFF; + fcb[++nl] = ch; + break; + + case 1: + if (tl >= 3) return 0xFFFF; + fcb[tl + 9] = ch; + ++tl; + break; + + case 2: + if (pl >= 8) return 0xFFFF; + fcb[pl + 0x10] = ch; + ++pl; + break; + } + break; + } + } + if (!nl) return 0xFFFF; + + fcb[0x1A] = pl; + + if (phase == 4) return 0; + + return (cpm_word)(ntxt - txt); +} diff --git a/Tools/unix/zx/cpmredir.c b/Tools/unix/zxcc/cpmredir.c similarity index 87% rename from Tools/unix/zx/cpmredir.c rename to Tools/unix/zxcc/cpmredir.c index d8a5e337..6484608e 100644 --- a/Tools/unix/zx/cpmredir.c +++ b/Tools/unix/zxcc/cpmredir.c @@ -71,7 +71,8 @@ cpm_word fcb_open(cpm_byte *fcb, cpm_byte *dma) { char fname[CPM_MAXPATH]; int handle; - int drv, l; + int drv; + size_t l; char *s; DIR *dir; @@ -95,23 +96,13 @@ cpm_word fcb_open(cpm_byte *fcb, cpm_byte *dma) { l = strlen(redir_drive_prefix[drv]) - 1; s = redir_drive_prefix[drv]; + while (--l > 0 && !strchr(DIRSEP, s[l])) --l; - while (l > 0) - { - if (s[l] == '/') break; -#ifdef __MSDOS__ - if (s[l] == '\\') break; - if (s[l] == ':') break; -#endif - --l; - } -#ifdef __MSDOS__ - if (l < 2) return 0; /* "C:" */ -#else - if (l <= 0) return 0; /* "/" */ + if (l == 0) return 0; /* "/" or "\" */ +#ifdef _WIN32 + if (s[l] == ':' && l < 2) return 0; /* "C:" */ #endif - ++l; - s[l] = 0; + s[l + 1] = 0; return 0; } /* Opening some other directory */ @@ -160,11 +151,11 @@ cpm_word fcb_open(cpm_byte *fcb, cpm_byte *dma) */ /* Get the file length */ - redir_wr32(fcb + 0x1C, zxlseek(handle, 0, SEEK_END)); + redir_wr32(fcb + LENGTH_OFFSET, zxlseek(handle, 0, SEEK_CUR)); zxlseek(handle, 0, SEEK_SET); /* Set the last record byte count */ - if (fcb[0x20] == 0xFF) fcb[0x20] = fcb[0x1C] & 0x7F; + if (fcb[0x20] == 0xFF) fcb[0x20] = fcb[LENGTH_OFFSET] & 0x7F; redir_Msg("Ret: 0\n"); @@ -179,7 +170,7 @@ cpm_word fcb_close(cpm_byte *fcb) SHOWNAME("fcb_close") if ((handle = redir_verify_fcb(fcb)) < 0) return -1; - redir_Msg(" (at %lx)\n", zxlseek(handle, 0, SEEK_CUR)); + redir_Msg(" (at %lx)\n", zxlseek(handle, 0, SEEK_END)); if (fcb[0] & 0x80) /* Close directory */ { @@ -195,13 +186,13 @@ cpm_word fcb_close(cpm_byte *fcb) if (fcb[5] & 0x80) /* CP/M 3: Flush rather than close */ { -#ifndef WIN32 +#ifndef _WIN32 sync(); #endif return 0; } -#ifdef WIN32 +#ifdef _WIN32 { BOOL b; redir_Msg(">CloseHandle() Handle=%lu\n", handle); @@ -290,7 +281,7 @@ cpm_word fcb_read(cpm_byte *fcb, cpm_byte *dma) memset(dma, 0x00, redir_rec_len); -#ifdef WIN32 +#ifdef _WIN32 { BOOL b; redir_Msg(">ReadFile() Handle=%lu, DMA=%lu, Len=%lu\n", handle, dma, redir_rec_len); @@ -324,6 +315,9 @@ cpm_word fcb_read(cpm_byte *fcb, cpm_byte *dma) return redir_xlt_err(); /* unwritten extent */ } + /* if not multiple of 128 bytes, pad sector with 0x1A */ + for (n = rv; n < rd_len; n++) dma[n] = 0x1A; + /* Less was read in than asked for. Report the number of 128-byte * records that _were_ read in. */ @@ -332,16 +326,11 @@ cpm_word fcb_read(cpm_byte *fcb, cpm_byte *dma) { /* Pack from the size actually read up to the size we claim * to have read */ - for (n = rv; n < rd_len; n++) dma[n] = 0x1A; - rd_len = ((rv + 127) / 128) << 8; /* High byte */ + rd_len = rd_len * 2; /* rd_len already sector * 128, so * 2 to move to High byte */ redir_Msg("Ret: 0x%x\n", rd_len | 1); return rd_len | 1; /* eof */ } - /* We have reported that all records were read in. But the last - * record might be less than 128 bytes, so pack it with 0x1A bytes */ - - for (n = rv; n < rd_len; n++) dma[n] = 0x1A; redir_Msg("Ret: 0 (bytes read=%d)\n", rv); return 0; } @@ -366,7 +355,7 @@ cpm_word fcb_write(cpm_byte *fcb, cpm_byte *dma) redir_Msg(" (to %lx)\n", zxlseek(handle, 0, SEEK_CUR)); -#ifdef WIN32 +#ifdef _WIN32 { BOOL b; redir_Msg(">WriteFile() Handle=%lu, DMA=%lu, Len=%lu\n", handle, dma, redir_rec_len); @@ -382,8 +371,8 @@ cpm_word fcb_write(cpm_byte *fcb, cpm_byte *dma) redir_put_fcb_pos(fcb, npos); /* Update the file length */ - len = redir_rd32(fcb + 0x1C); - if (len < npos) redir_wr32(fcb + 0x1C, npos); + len = redir_rd32(fcb + LENGTH_OFFSET); + if (len < npos) redir_wr32(fcb + LENGTH_OFFSET, npos); if (rv < 0) return redir_xlt_err(); /* error */ if (rv < redir_rec_len) return 1; /* disk full */ @@ -397,6 +386,8 @@ cpm_word fcb_creat(cpm_byte *fcb, cpm_byte *dma) char fname[CPM_MAXPATH]; int handle; + releaseFCB(fcb); /* release existing fcb usage */ + /* Don't support ambiguous filenames */ if (redir_fcb2unix(fcb, fname)) return 0x09FF; redir_Msg("fcb_creat(\"%s\")\n", fname); @@ -408,16 +399,13 @@ cpm_word fcb_creat(cpm_byte *fcb, cpm_byte *dma) if (fcb[0] & 0x80) { -#ifdef WIN32 - handle = mkdir(fname); -#else handle = mkdir(fname, 0x777); -#endif if (handle) return redir_xlt_err(); return 0; } + releaseFile(fname); /* purge any open handles for this file */ -#ifdef WIN32 +#ifdef _WIN32 redir_Msg(">CreateFile([CREATE_ALWAYS]) Name='%s'\n", fname); handle = (int)CreateFile(fname, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); redir_Msg("ReadFile() Handle=%lu, DMA=%lu, Len=%lu\n", handle, dma, redir_rec_len); @@ -526,16 +519,20 @@ cpm_word fcb_randrd(cpm_byte *fcb, cpm_byte *dma) redir_put_fcb_pos(fcb, offs); + if (rv < 0) return redir_xlt_err(); /* Error */ + rd_len = ((rv + 127) / 128) * 128; - if (rv < 0) return redir_xlt_err(); /* Error */ + /* PMO: pad partial sector to 128 bytes, even if EOF reached in multi sector read */ + for (n = rv; n < rd_len; n++) dma[n] = 0x1A; /* pad last read to 128 boundary with 0x1A*/ + if (rd_len < redir_rec_len) /* eof */ { - rd_len = ((rv + 127) / 128) << 8; /* High byte */ + rd_len = rd_len * 2; /* rd_len already sector * 128, so * 2 to move to High byte */ redir_Msg("Ret: 0x%x\n", rd_len | 1); return rd_len | 1; /* eof */ } - for (n = rv; n < rd_len; n++) dma[n] = 0x1A; + return 0; } @@ -546,7 +543,7 @@ cpm_word fcb_randwr(cpm_byte *fcb, cpm_byte *dma) int handle; int rv; dword offs = redir_rd24(fcb + 0x21) * 128; - long len; + dword len; SHOWNAME("fcb_randwr") @@ -555,7 +552,8 @@ cpm_word fcb_randwr(cpm_byte *fcb, cpm_byte *dma) if (redir_ro_fcb(fcb)) return 0x02FF; if (zxlseek(handle, offs, SEEK_SET) < 0) return 6; /* bad record no. */ -#ifdef WIN32 + +#ifdef _WIN32 { BOOL b; redir_Msg(">WriteFile() Handle=%lu, DMA=%lu, Len=%lu\n", handle, dma, redir_rec_len); @@ -569,15 +567,38 @@ cpm_word fcb_randwr(cpm_byte *fcb, cpm_byte *dma) zxlseek(handle, offs, SEEK_SET); redir_put_fcb_pos(fcb, offs); + if (rv < 0) return redir_xlt_err(); /* Error */ /* Update the file length */ - len = redir_rd32(fcb + 0x1C); - if (len < offs) redir_wr32(fcb + LENGTH_OFFSET, offs); + len = redir_rd32(fcb + LENGTH_OFFSET); + /* PMO: Bug fix, account for the data just written */ + if (len < offs + rv) { + redir_wr32(fcb + LENGTH_OFFSET, offs + rv); + // fcb[0x20] = (offs + rv) % 256; + } - if (rv < 0) return redir_xlt_err(); /* Error */ if (rv < redir_rec_len) return 1; /* disk full */ return 0; } +#ifndef OLD_RANDWZ +/* PMO: + * Under CP/M for random write with zero fill, the zero fill is only done for a newly allocated + * block and not fill from previous end of file + * to implement this fully would require tracking sparse files and filling to block + * boundaries. + * As the default for POSIX/Windows lseek is to effectively zero fill and for modern hard disks + * the additional space used is small compared to capacity, fcb_randwz is the same as fcb_randwr + * Note zero padding to the end of the block will be done automatically as required when data is + * written to later offsets + */ +/* Write random with 0 fill */ +cpm_word fcb_randwz(cpm_byte* fcb, cpm_byte* dma) +{ + SHOWNAME("fcb_randwz"); + return fcb_randwr(fcb, dma); +} + +#else /* Write random with 0 fill */ cpm_word fcb_randwz(cpm_byte *fcb, cpm_byte *dma) { @@ -588,8 +609,11 @@ cpm_word fcb_randwz(cpm_byte *fcb, cpm_byte *dma) SHOWNAME("fcb_randwz") if ((handle = redir_verify_fcb(fcb)) < 0) return 9; /* Invalid FCB */ + /* Software write-protection */ + if (redir_ro_fcb(fcb)) return 0x02FF; + offs = redir_rd24(fcb + 0x21) * 128; - len = redir_rd32(fcb + 0x1C); + len = redir_rd32(fcb + LENGTH_OFFSET); redir_wr32(fcb + LENGTH_OFFSET, offs); @@ -601,7 +625,7 @@ cpm_word fcb_randwz(cpm_byte *fcb, cpm_byte *dma) rl = sizeof(zerorec); if ((offs - len) < sizeof(zerorec)) rl = offs - len; -#ifdef WIN32 +#ifdef _WIN32 { BOOL b; redir_Msg(">WriteFile() Handle=%lu, DMA=%lu, Len=%lu\n", handle, zerorec, rl); @@ -623,6 +647,8 @@ cpm_word fcb_randwz(cpm_byte *fcb, cpm_byte *dma) return fcb_randwr(fcb, dma); } +#endif + cpm_word fcb_tell(cpm_byte *fcb) { @@ -656,7 +682,7 @@ cpm_word fcb_stat(cpm_byte *fcb) rv = stat(fname, &st); - redir_Msg("fcb_stat(\"%s\") fcb=%x\n", fname, (int)fcb); + redir_Msg("fcb_stat(\"%s\") fcb=%p\n", fname, fcb); if (rv < 0) { redir_Msg("ret: -1\n"); @@ -687,6 +713,10 @@ cpm_word fcb_date(cpm_byte *fcb) struct stat st; int rv; + /* as this function will overwrite the fcb info used by ZXCC + * release any file associated with it + */ + releaseFCB(fcb); /* Don't support ambiguous filenames */ if (redir_fcb2unix(fcb, fname)) return 0x09FF; @@ -703,23 +733,20 @@ cpm_word fcb_date(cpm_byte *fcb) } - cpm_word fcb_trunc(cpm_byte *fcb, cpm_byte *dma) { char fname[CPM_MAXPATH]; dword offs = redir_rd24(fcb + 0x21) * 128; + releaseFCB(fcb); /* CP/M requires truncated files be closed */ /* Don't support ambiguous filenames */ if (redir_fcb2unix(fcb, fname)) return 0x09FF; /* Software write-protection */ if (redir_ro_fcb(fcb)) return 0x02FF; + releaseFile(fname); /* after truncate open files are invalid */ redir_log_fcb(fcb); -#ifdef WIN32 - (void)offs; - return 0x06FF; /* Simply not implemented */ -#else if (truncate(fname, offs)) { if (redir_password_error()) @@ -730,24 +757,13 @@ cpm_word fcb_trunc(cpm_byte *fcb, cpm_byte *dma) return redir_xlt_err(); } return 0; -#endif } cpm_word fcb_sdate(cpm_byte *fcb, cpm_byte *dma) { char fname[CPM_MAXPATH]; -#ifdef WIN32 - /* TODO: Use SetFileTime() here */ - - /* Don't support ambiguous filenames */ - if (redir_fcb2unix(fcb, fname)) return 0x09FF; - - /* Software write-protection */ - if (redir_ro_fcb(fcb)) return 0x02FF; - redir_log_fcb(fcb); -#else struct utimbuf buf; buf.actime = redir_unixtime(dma); @@ -770,7 +786,6 @@ cpm_word fcb_sdate(cpm_byte *fcb, cpm_byte *dma) } return redir_xlt_err(); } -#endif return 0; } @@ -809,7 +824,7 @@ cpm_word fcb_chmod(cpm_byte *fcb, cpm_byte *dma) } return redir_xlt_err(); } -#elif defined (WIN32) +#elif defined (_WIN32) omode = 0; if (fcb[9] & 0x80) omode |= FILE_ATTRIBUTE_READONLY; @@ -838,13 +853,16 @@ cpm_word fcb_chmod(cpm_byte *fcb, cpm_byte *dma) { if (stat(fname, &st)) return redir_xlt_err(); + releaseFCB(fcb); /* cpm required file to be closed so release FCB */ + releaseFile(fname); /* also make sure no other handles open to file */ handle = open(fname, O_RDWR | O_BINARY); if (handle < 0) return redir_xlt_err(); newoffs = offs = ((st.st_size + 127) / 128) * 128; if (fcb[0x20] & 0x7F) { - newoffs -= (0x80 - (fcb[0x20] & 0x7F)); + newoffs -= fcb[0x20] & 0x7f; + //newoffs -= (0x80 - (fcb[0x20] & 0x7F)); } if (newoffs == st.st_size) { @@ -852,13 +870,11 @@ cpm_word fcb_chmod(cpm_byte *fcb, cpm_byte *dma) } else if (newoffs < st.st_size) { -#ifndef WIN32 /* XXX Do this somehow in Win32 */ if (ftruncate(handle, newoffs)) { close(handle); return redir_xlt_err(); } -#endif } else while (newoffs > st.st_size) { diff --git a/Tools/unix/zx/cpmredir.h b/Tools/unix/zxcc/cpmredir.h similarity index 100% rename from Tools/unix/zx/cpmredir.h rename to Tools/unix/zxcc/cpmredir.h diff --git a/Tools/unix/zx/dirent.c b/Tools/unix/zxcc/dirent.c similarity index 100% rename from Tools/unix/zx/dirent.c rename to Tools/unix/zxcc/dirent.c diff --git a/Tools/unix/zx/dirent.h b/Tools/unix/zxcc/dirent.h similarity index 100% rename from Tools/unix/zx/dirent.h rename to Tools/unix/zxcc/dirent.h diff --git a/Tools/unix/zx/drdos.c b/Tools/unix/zxcc/drdos.c similarity index 95% rename from Tools/unix/zx/drdos.c rename to Tools/unix/zxcc/drdos.c index 97bd583c..baf7a00b 100644 --- a/Tools/unix/zx/drdos.c +++ b/Tools/unix/zxcc/drdos.c @@ -1,236 +1,236 @@ -/* - - CPMREDIR: CP/M filesystem redirector - Copyright (C) 1998, John Elliott - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - This file holds DRDOS-specific password code. -*/ - -#include "cpmint.h" - -cpm_word redir_drdos_pwmode(cpm_byte b) -{ - cpm_word mode = 0; - - if (b & 0x80) mode |= 0xddd; - if (b & 0x40) mode |= 0x555; - if (b & 0x20) mode |= 0x111; - - return mode; -} - -cpm_byte redir_cpm_pwmode(cpm_word w) -{ - cpm_byte mode = 0; - - if (w & 0x8) mode |= 0x80; - if (w & 0x4) mode |= 0x40; - if (w & 0x1) mode |= 0x20; - - return mode; -} - -#ifdef __MSDOS__ -#ifdef __GO32__ /* The GO32 extender doesn't understand DRDOS password - * functions, so these are done with __dpmi_int() rather - * than intdos() */ - -cpm_word redir_drdos_get_rights(char *path) -{ - __dpmi_regs r; - - if (!redir_drdos) return 0; - - redir_Msg("Rights for file %s: \n\r", path); - - dosmemput(path, strlen(path) + 1, __tb); - r.x.ax = 0x4302; - r.x.dx = __tb & 0x0F; - r.x.ds = (__tb) >> 4; - - __dpmi_int(0x21, &r); - - redir_Msg(" %04x \n\r", r.x.cx); - - if (r.x.flags & 1) return 0; - return r.x.cx; -} - - -cpm_word redir_drdos_put_rights(char *path, cpm_byte *dma, cpm_word rights) -{ - __dpmi_regs r; - - if (!redir_drdos) return 0; - - redir_Msg("Put rights for file %s: %04x %-8.8s %-8.8s\n\r", path, rights, dma, dma + 8); - - dosmemput(dma+8, 8, __tb); /* Point DTA at password */ - r.x.ax = 0x1A00; - r.x.dx = (__tb & 0x0F); - r.x.ds = (__tb) >> 4; - __dpmi_int(0x21, &r); - - dosmemput(path, strlen(path) + 1, __tb + 0x10); - r.x.ax = 0x4303; /* Set rights */ - r.x.cx = rights; - r.x.dx = (__tb & 0x0F) + 0x10; - r.x.ds = (__tb) >> 4; - - __dpmi_int(0x21, &r); - - if (r.x.flags & 1) - { - redir_Msg(" Try 1 failed. Error %04x\n\r", r.x.ax); - if (redir_password_error()) - { - redir_password_append(path, dma); - - dosmemput(path, strlen(path) + 1, __tb + 0x10); - r.x.ax = 0x4303; /* Set rights */ - r.x.cx = rights; - r.x.dx = (__tb & 0x0F) + 0x10; - r.x.ds = (__tb) >> 4; - - __dpmi_int(0x21, &r); - if (!r.x.flags & 1) return 0; - if (redir_password_error()) return 0x7FF; - } - return 0xFF; - } - return 0; -} - -#else /* __GO32__ */ - -cpm_word redir_drdos_get_rights(char *path) -{ - union REGS r; - struct SREGS s; - - if (!redir_drdos) return 0; - - redir_Msg("Rights for file %s: \n\r", path); - - dosmemput(path, strlen(path) + 1, __tb); - r.w.ax = 0x4302; - r.w.dx = __tb & 0x0F; - s.ds = (__tb) >> 4; - - intdosx(&r, &r, &s); - - redir_Msg(" %04x \n\r", r.w.cx); - - if (r.w.cflag) return 0; - return r.w.cx; -} - - -cpm_word redir_drdos_put_rights(char *path, cpm_byte *dma, cpm_word rights) -{ - union REGS r; - struct SREGS s; - - if (!redir_drdos) return 0; - - redir_Msg("Put rights for file %s: %04x\n\r", path, rights); - - dosmemput(dma, 8, __tb); /* Point DTA at password */ - r.w.ax = 0x1A00; - r.w.dx = (__tb & 0x0F); - s.ds = (__tb) >> 4; - intdosx(&r, &r, &s); - - dosmemput(path, strlen(path) + 1, __tb + 0x10); - r.w.ax = 0x4303; /* Set rights */ - r.w.cx = rights; - r.w.dx = (__tb & 0x0F) + 0x10; - s.ds = (__tb) >> 4; - - intdosx(&r, &r, &s); - - if (r.w.cflag) - { - redir_Msg(" Try 1 failed. Error %04x \n\r", r.w.ax); - if (redir_password_error()) - { - redir_password_append(path, dma); - - dosmemput(path, strlen(path) + 1, __tb + 0x10); - r.w.ax = 0x4303; /* Set rights */ - r.w.cx = rights; - r.w.dx = (__tb & 0x0F) + 0x10; - s.ds = (__tb) >> 4; - - intdosx(&r, &r, &s); - if (!r.w.cflag) return 0; - } - return 0xFF; - } - return 0; -} - -#endif /* __GO32__ */ - - -cpm_word redir_password_error(void) -{ - union REGS r; - - if (!redir_drdos) return 0; - - r.w.ax = 0x5900; - r.w.bx = 0x0000; - - intdos(&r, &r); - - redir_Msg("Last error was: %04x\r\n", r.w.ax); - - if (r.w.ax == 0x56) return 1; /* Bad password */ - return 0; -} - - -void redir_password_append(char *s, cpm_byte *dma) -{ - int n, m; - - if (!redir_drdos) return; - - if (dma[0] == 0 || dma[0] == 0x20) return; - - strcat(s, ";"); - m = strlen(s); - - for (n = 0; n < 8; n++) - { - if (dma[n] == ' ') s[m] = 0; - else s[m] = dma[n]; - ++m; - } - s[m] = 0; - -} -#else /* __MSDOS__ */ -void redir_password_append(char *s, cpm_byte *dma) {} -cpm_word redir_password_error(void) { return 0; } -cpm_word redir_drdos_put_rights(char *path, cpm_byte *dma, cpm_word rights) -{ return 0; } -cpm_word redir_drdos_get_rights(char *path) { return 0; } -#endif /* __MSDOS__ */ - - +/* + + CPMREDIR: CP/M filesystem redirector + Copyright (C) 1998, John Elliott + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + This file holds DRDOS-specific password code. +*/ + +#include "cpmint.h" + +cpm_word redir_drdos_pwmode(cpm_byte b) +{ + cpm_word mode = 0; + + if (b & 0x80) mode |= 0xddd; + if (b & 0x40) mode |= 0x555; + if (b & 0x20) mode |= 0x111; + + return mode; +} + +cpm_byte redir_cpm_pwmode(cpm_word w) +{ + cpm_byte mode = 0; + + if (w & 0x8) mode |= 0x80; + if (w & 0x4) mode |= 0x40; + if (w & 0x1) mode |= 0x20; + + return mode; +} + +#ifdef __MSDOS__ +#ifdef __GO32__ /* The GO32 extender doesn't understand DRDOS password + * functions, so these are done with __dpmi_int() rather + * than intdos() */ + +cpm_word redir_drdos_get_rights(char *path) +{ + __dpmi_regs r; + + if (!redir_drdos) return 0; + + redir_Msg("Rights for file %s: \n\r", path); + + dosmemput(path, strlen(path) + 1, __tb); + r.x.ax = 0x4302; + r.x.dx = __tb & 0x0F; + r.x.ds = (__tb) >> 4; + + __dpmi_int(0x21, &r); + + redir_Msg(" %04x \n\r", r.x.cx); + + if (r.x.flags & 1) return 0; + return r.x.cx; +} + + +cpm_word redir_drdos_put_rights(char *path, cpm_byte *dma, cpm_word rights) +{ + __dpmi_regs r; + + if (!redir_drdos) return 0; + + redir_Msg("Put rights for file %s: %04x %-8.8s %-8.8s\n\r", path, rights, dma, dma + 8); + + dosmemput(dma+8, 8, __tb); /* Point DTA at password */ + r.x.ax = 0x1A00; + r.x.dx = (__tb & 0x0F); + r.x.ds = (__tb) >> 4; + __dpmi_int(0x21, &r); + + dosmemput(path, strlen(path) + 1, __tb + 0x10); + r.x.ax = 0x4303; /* Set rights */ + r.x.cx = rights; + r.x.dx = (__tb & 0x0F) + 0x10; + r.x.ds = (__tb) >> 4; + + __dpmi_int(0x21, &r); + + if (r.x.flags & 1) + { + redir_Msg(" Try 1 failed. Error %04x\n\r", r.x.ax); + if (redir_password_error()) + { + redir_password_append(path, dma); + + dosmemput(path, strlen(path) + 1, __tb + 0x10); + r.x.ax = 0x4303; /* Set rights */ + r.x.cx = rights; + r.x.dx = (__tb & 0x0F) + 0x10; + r.x.ds = (__tb) >> 4; + + __dpmi_int(0x21, &r); + if (!r.x.flags & 1) return 0; + if (redir_password_error()) return 0x7FF; + } + return 0xFF; + } + return 0; +} + +#else /* __GO32__ */ + +cpm_word redir_drdos_get_rights(char *path) +{ + union REGS r; + struct SREGS s; + + if (!redir_drdos) return 0; + + redir_Msg("Rights for file %s: \n\r", path); + + dosmemput(path, strlen(path) + 1, __tb); + r.w.ax = 0x4302; + r.w.dx = __tb & 0x0F; + s.ds = (__tb) >> 4; + + intdosx(&r, &r, &s); + + redir_Msg(" %04x \n\r", r.w.cx); + + if (r.w.cflag) return 0; + return r.w.cx; +} + + +cpm_word redir_drdos_put_rights(char *path, cpm_byte *dma, cpm_word rights) +{ + union REGS r; + struct SREGS s; + + if (!redir_drdos) return 0; + + redir_Msg("Put rights for file %s: %04x\n\r", path, rights); + + dosmemput(dma, 8, __tb); /* Point DTA at password */ + r.w.ax = 0x1A00; + r.w.dx = (__tb & 0x0F); + s.ds = (__tb) >> 4; + intdosx(&r, &r, &s); + + dosmemput(path, strlen(path) + 1, __tb + 0x10); + r.w.ax = 0x4303; /* Set rights */ + r.w.cx = rights; + r.w.dx = (__tb & 0x0F) + 0x10; + s.ds = (__tb) >> 4; + + intdosx(&r, &r, &s); + + if (r.w.cflag) + { + redir_Msg(" Try 1 failed. Error %04x \n\r", r.w.ax); + if (redir_password_error()) + { + redir_password_append(path, dma); + + dosmemput(path, strlen(path) + 1, __tb + 0x10); + r.w.ax = 0x4303; /* Set rights */ + r.w.cx = rights; + r.w.dx = (__tb & 0x0F) + 0x10; + s.ds = (__tb) >> 4; + + intdosx(&r, &r, &s); + if (!r.w.cflag) return 0; + } + return 0xFF; + } + return 0; +} + +#endif /* __GO32__ */ + + +cpm_word redir_password_error(void) +{ + union REGS r; + + if (!redir_drdos) return 0; + + r.w.ax = 0x5900; + r.w.bx = 0x0000; + + intdos(&r, &r); + + redir_Msg("Last error was: %04x\r\n", r.w.ax); + + if (r.w.ax == 0x56) return 1; /* Bad password */ + return 0; +} + + +void redir_password_append(char *s, cpm_byte *dma) +{ + int n, m; + + if (!redir_drdos) return; + + if (dma[0] == 0 || dma[0] == 0x20) return; + + strcat(s, ";"); + m = strlen(s); + + for (n = 0; n < 8; n++) + { + if (dma[n] == ' ') s[m] = 0; + else s[m] = dma[n]; + ++m; + } + s[m] = 0; + +} +#else /* __MSDOS__ */ +void redir_password_append(char *s, cpm_byte *dma) {} +cpm_word redir_password_error(void) { return 0; } +cpm_word redir_drdos_put_rights(char *path, cpm_byte *dma, cpm_word rights) +{ return 0; } +cpm_word redir_drdos_get_rights(char *path) { return 0; } +#endif /* __MSDOS__ */ + + diff --git a/Tools/unix/zx/edops.h b/Tools/unix/zxcc/edops.h similarity index 100% rename from Tools/unix/zx/edops.h rename to Tools/unix/zxcc/edops.h diff --git a/Tools/unix/zxcc/readme.txt b/Tools/unix/zxcc/readme.txt new file mode 100644 index 00000000..ba94bf5d --- /dev/null +++ b/Tools/unix/zxcc/readme.txt @@ -0,0 +1,86 @@ +This is an adaptation of zxcc-0.5.7 for RomWBW by Wayne Warthen. + +In general, this is a stripped down variant of John Elliott's zxcc package that +runs under a Windows command line (32 or 64 bit Windows), Linux, or MacOS. +This adaptation implements only the main "zxcc" command. The other programs +(zxc, zxas, zxlink, and zslibr) are not inluded here because they are fairly +specific to Hi-Tech C. + +Please see http://www.seasip.info/Unix/Zxcc/ for more information on the original +version of zxcc. Also, refer to https://github.com/agn453/ZXCC which has an +updated version of the code. + +The included zxcc.html documentation is from the original version, so it does not +reflect the changes made here. + +To build under Open Watcom, use Build-OW.cmd. To build under Microsoft Visual C, +use Build-VC.cmd. To build under Linux or MacOS, use the Makefile. + +The GPL status of everything remains in place and carries forward. + +December 5, 2014 + +After struggling to get the entire zxcc package to build nicely using autoconf, +I finally gave up and took a much more direct approach. I have extracted just +the source files needed and created a simple batch file to build the tool. I +realize this could be done much better, but I cheated in the interest of time. + +The one "real" change I made in the source code was that I modified the tool +to look for bios.bin in the same directory as the executable is in. This +just makes it much easier to set up (for me, anyway). + +Wayne Warthen +wwarthen@gmail.com + +March 15, 2017 + +- Updated to compile under Open Watcom. +- Implemented BDOS console status function. +- Set stdin and stdout to binary mode at startup. + +August 21, 2021 + +- Incorporated filename case insensitivity changes from Curt Mayer +- Incorporated fixes from Tony Nicholson at https://github.com/agn453/ZXCC + - Emulation of CP/M BDOS function 60 (call resident system extension) + should be disabled and return 0xFF in both the A and L registers. + - Change cpm_bdos_10() to return an unsigned result to avoid buffer + size being interpreted as negative. + - Fix the emulation of Z80 opcodes for IN (HL),(C) and + OUT (C),(HL) - opcodes 0xED,0x70 and 0xED,0x71 respectively. + This is noted in Fred Weigel's AM9511 arithmetic processing unit + emulation from https://github.com/ratboy666/am9511 in the howto.txt + description. NB: I have not included Fred's am9511 support at this + time into ZXCC. +- Fixed parse_to_fcb function in zxcc.c to handle parsing second automatic + FCB from command line + +Wayne Warthen +wwarthen@gmail.com + +--WBW 4:09 PM 8/21/2021 + +January 9, 2022 + +- Running zxcc under WSL (Windows Subsystem for Linux) was gererating output + that was correct but did not match standard Windows or Linux runs. This + turned out to be an assumption in a few places in the code that reading + into a buffer would not modify the area of the buffer that was beyond + the space required by the data being read. Under WSL, this "slack" space + was mangled. I made changes in these locations to clean up the slack + space after such reads. This fixed WSL runs to produce binary identical + output. Although only required by WSL, the changes cause no problems for + other environments and are actually correct per POSIX. + +--WBW 11:56 AM 1/9/2022 + +- I have attempted to sync my code up with the latest code found in Tony + Nicholson's GitHub repo at https://github.com/agn453/ZXCC. The most + significant difference in my code is that I am using the WIN32 API + for all disk I/O. Although the file tracking code is retained, I have + found this mechanism to fail insome scenarios. By using the WIN32 API + I can achieve the same file sharing attributes as Unix which makes the + file tracking mechanism optional. + +--WBW 9:34 AM 2/10/2022 + diff --git a/Tools/unix/zxcc/track.c b/Tools/unix/zxcc/track.c new file mode 100644 index 00000000..20770a8a --- /dev/null +++ b/Tools/unix/zxcc/track.c @@ -0,0 +1,150 @@ +/* + + CPMREDIR: CP/M filesystem redirector + Optional Open file tracker + Copyright (C) 2021, Mark Ogden + + This is an addition to the CPMREDIR + Copyright (C) 1998, John Elliott + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ +//#include "cpmint.h" +#include "zxcc.h" + +/* CP/M does not require that files opened for reading need to be closed, + * this has two impacts + * 1) a lot of file handles can remain opened even when the file is no + * longer used. For modern OS builds this isn't a major problem as + * the system limits are quite high. It is however wasteful + * 2) for windows it can lead to issues when trying to delete / rename a file + * as normally windows will not allow files to be deleted/renamed if the + * file is currently open. Unix variants don't have this restriction. + * + * As an example the build of cgen.com using my decompiled sources + * the linq phase without tracking left 42 open files + * with tracking this was reduced to 2 + * + * This code keeps track of files that are opened until they are explicitly + * closed or the FCB used to open the file is reused, or the file needs to be + * renamed or deleted. + * To do this it keeps track of the expanded filename, fcb location and allocated + * file handle + * + * Two public functions are used to manage the file list, and are called from + * within the bdos emulation + * + * trackFile(char *fname, void *fcb, int fd) + * removes existing tracking with matchin fcb or fd and + * if (fname != NULL) - add the info to the head of the open files list + * it returns fd + * + * the function is called in the following circumstances + * 1) before closing a file (fname is NULL) + * 2) just after the file has been opened/created. + * 3) to remove association with a given fcb trackFile(NULL, fcb, -1) + * + * note a helper macro releaseFCB(fcb) can be used for (3) above + * + * releaseFile(char *fname) + * this scans through the list of open files and for each open file + * with a matching fname, the file is closed + * + * the function is called before deleting a file or renaming a file + * + * + * there is a helper function that removes the info from the list + * + * Notes: + * For most applications the tracker could in principle automatically + * close existing open files at the start of a new executable invocation. + * Unfortunately this does not support the case where there is a scripting + * engine intercepting the warm reboots, as it may need to keep the script + * source file open. + * + * Note in theory it would be possible for a CP/M program to open a file + * with a given fcb, move the fcb internally and then open another file + * with the original fcb. If this happens the FCB tracking could cause + * a problem. I am not aware of any real programs that do this. + * Please let me know if the situation arises. +*/ +/* windows needs to use file tracking, for unix/linux it is optional */ +#ifdef FILETRACKER +typedef struct _track { + struct _track* next; + int handle; + void* fcb; + char* fname; +} track_t; + +track_t* openFiles; + +static track_t* rmHandle(track_t* s) { + track_t* next = s->next; + free(s->fname); + free(s); + return next; +} + +void releaseFile(char* fname) { + track_t* s = (track_t*)&openFiles; + while (s->next) + if (strcmp(s->next->fname, fname) == 0) { + close(s->next->handle); + Msg("releaseFile closed file \"%s\"\n", s->next->fname); + s->next = rmHandle(s->next); + } + else + s = s->next; +} + + +int trackFile(char* fname, void* fcb, int fd) { + track_t* s = (track_t*)&openFiles; + Msg("trackFile: \"%s\", FCB=0x%X, Handle=%i\n", fname, (byte *)fcb - RAM, fd); + while (s->next) { /* find any existing fcb or fd */ + if (s->next->fcb == fcb || s->next->handle == fd) { + if (s->next->handle != fd) { + close(s->next->handle); + Msg(" closed file \"%s\", Handle=%i\n", s->next->fname, s->next->handle); + } + Msg(" released file \"%s\", Handle=%i\n", s->next->fname, s->next->handle); + s->next = rmHandle(s->next); /* release the tracker */ + } + else + s = s->next; + } + if (fname && fd >= 0) { + if ((s = malloc(sizeof(track_t))) == NULL) { + fprintf(stderr, "out of memory\n"); + exit(1); + } + s->next = openFiles; + s->fname = strdup(fname); + s->fcb = fcb; + s->handle = fd; + openFiles = s; + } + return fd; +} + +#else + +void releaseFile(char* fname) {} +int trackFile(char* fname, void* fcb, int fd) { return fd; } + +#endif + diff --git a/Tools/unix/zx/util.c b/Tools/unix/zxcc/util.c similarity index 83% rename from Tools/unix/zx/util.c rename to Tools/unix/zxcc/util.c index cb22e18b..bc3dbb6e 100644 --- a/Tools/unix/zx/util.c +++ b/Tools/unix/zxcc/util.c @@ -22,13 +22,18 @@ #include "cpmint.h" + + + + + /* In debug mode, lseek()s can be traced. */ #ifdef DEBUG long zxlseek(int fd, long offset, int wh) { -#ifdef WIN32 +#ifdef _WIN32 long v; redir_Msg(">SetFilePointer() Handle=%lu, Offset=%lu, Method=%lu\n", fd, offset, wh); v = SetFilePointer((HANDLE)fd, offset, NULL, wh); @@ -49,6 +54,22 @@ long zxlseek(int fd, long offset, int wh) #endif } +#else + +long zxlseek(int fd, long offset, int wh) +{ + #ifdef _WIN32 + return SetFilePointer((HANDLE)fd, offset, NULL, wh); + #else + return lseek(fd, offset, wh); + #endif +} + + +#endif + +#ifdef DEBUG + void redir_showfcb(cpm_byte *fd) { int n; @@ -61,18 +82,6 @@ void redir_showfcb(cpm_byte *fd) printf("\r\n"); } -#else - -long zxlseek(int fd, long offset, int wh) -{ -#ifdef WIN32 - return SetFilePointer((HANDLE)fd, offset, NULL, wh); -#else - return lseek(fd, offset, wh); -#endif -} - - #endif /* Get the "sequential access" file pointer out of an FCB */ @@ -90,9 +99,9 @@ long redir_get_fcb_pos(cpm_byte *fcb) void redir_put_fcb_pos(cpm_byte *fcb, long npos) { - fcb[0x20] = (npos / 128) % 128; - fcb[0x0C] = (npos / 16384) % 32; - fcb[0x0E] = (npos / 524288L) % 64; + fcb[0x20] = (npos / 128) % 128; /* Record */ + fcb[0x0C] = (npos / 16384) % 32; /* Extent */ + fcb[0x0E] = (npos / 524288L) % 64; /* S2 */ } @@ -132,10 +141,8 @@ swizzle(char *fullpath) closedir(dirp); } -/* - * Passed a CP/M FCB, convert it to a unix filename. Turn its drive back into - * a path. - */ +/* Passed a CP/M FCB, convert it to a unix filename. Turn its drive back into + * a path. */ int redir_fcb2unix(cpm_byte *fcb, char *fname) { @@ -178,10 +185,10 @@ int redir_fcb2unix(cpm_byte *fcb, char *fname) int redir_ofile(cpm_byte *fcb, char *s) { - int h, rv; + int h; /* Software write-protection */ -#ifdef WIN32 +#ifdef _WIN32 redir_Msg(">CreateFile([OPEN_EXISTING]) Name='%s'\n", s); h = (int)CreateFile(s, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); redir_Msg("= 0 || (errno != EACCES && errno != EROFS)) return h; + if (h >= 0 || (errno != EACCES && errno != EROFS)) + return trackFile(s, fcb, h); } - redir_Msg("**2**"); h = open(s, O_RDONLY | O_BINARY); if (h < 0) return -1; fcb[9] |= 0x80; #endif #endif - - return h; + return trackFile(s, fcb, h); } @@ -250,10 +257,10 @@ void redir_Msg(char *s, ...) va_list ap; va_start(ap, s); - printf("cpmredir trace: "); - vprintf(s, ap); + fprintf(stderr, "cpmredir trace: "); + vfprintf(stderr, s, ap); va_end(ap); - fflush(stdout); + fflush(stderr); } #endif @@ -263,9 +270,16 @@ void redir_Msg(char *s, ...) /* Convert time_t to CP/M day count/hours/minutes */ dword redir_cpmtime(time_t t) { - long d = (t / 86400) - 2921; /* CP/M day 0 is unix day 2921 */ - long h = (t % 86400) / 3600; /* Hour, 0-23 */ - long m = (t % 3600) / 60; /* Minute, 0-59 */ +/* Microsoft compiler warned around the conversion from time_t to long + * as to support dates beyond 2038 time_t is set as a long long + * and for the Microsoft compiler sizeof(long) == 4 and sizeof(long long) == 8 + * for other compilers both have size 8 + * As the result is a dword (unsigned long), the code below is modified to reflect this + */ + + dword d = (dword)((t / 86400) - 2921); /* CP/M day 0 is unix day 2921 */ + dword h = (t % 86400) / 3600; /* Hour, 0-23 */ + dword m = (t % 3600) / 60; /* Minute, 0-59 */ return (d | (BCD(h) << 16) | (BCD(m) << 24)); } @@ -375,3 +389,20 @@ cpm_word redir_xlt_err(void) } } + +#ifdef _WIN32 +/* minimal implementation of truncate */ +int truncate(const char* path, off_t length) +{ + int result; + int fd = open(path, O_BINARY | O_RDWR); + + if (fd < 0) + return -1; + result = ftruncate(fd, length); + return close(fd) == 0 && result == 0 ? 0 : -1; + +} + + +#endif diff --git a/Tools/unix/zxcc/xlt.c b/Tools/unix/zxcc/xlt.c new file mode 100644 index 00000000..84b76952 --- /dev/null +++ b/Tools/unix/zxcc/xlt.c @@ -0,0 +1,241 @@ +/* + + CPMREDIR: CP/M filesystem redirector + Copyright (C) 1998, John Elliott + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + This file holds functions dealing with name translation; also the + initialisation code. +*/ + +#include "cpmint.h" +static char* skipUser(char* localname); +/* Detect DRDOS */ + +#ifdef __MSDOS__ +static void drdos_init(void) +{ + +/* The DJGPP DOS extender won't detect DRDOS using intdos(), so we have + to use __dpmi_int() instead. */ + +#ifdef __GO32__ + __dpmi_regs ir; + + ir.x.ax = 0x4452; /* "DR" */ + + __dpmi_int(0x21, &ir); + if (ir.x.flags & 1) return; /* Not DRDOS */ + + redir_Msg("DRDOS detected.\r\n"); + + redir_drdos = 1; + +#else /* __GO32__ */ + + union REGS ir, or; + + ir.w.ax = 0x4452; /* "DR" */ + + intdos(&ir, &or); + if (or.w.cflag) return; /* Not DRDOS */ + + redir_Msg("DRDOS detected.\r\n"); + + redir_drdos = 1; +#endif /* __GO32__ */ +} +#endif /* __MSDOS__ */ + + + +int fcb_init(void) +{ + int n; + + /* A: to O: free */ + for (n = 0; n < 15; n++) redir_drive_prefix[n][0] = 0; + + strcpy(redir_drive_prefix[15], "./"); /* P: is current directory */ + + /* Log on to P:. It is the only drive at this point which we + * know works. */ + redir_cpmdrive = 15; +#ifdef __MSDOS__ + drdos_init(); +#endif + + return 1; +} + +/* Deinitialise the library. */ + +void fcb_deinit(void) +{ + /* Nothing */ +} + +/* Translate a name from the host FS to a CP/M name. This will (if necessary) + * create a mapping between a CP/M drive and a host directory path. + * + * CP/M drives A: to O: can be mapped in this way. P: is always the current + * drive. + * + */ + +void xlt_name(char *localname, char *cpmname) +{ + char ibuf[CPM_MAXPATH + 1]; + char nbuf[CPM_MAXPATH + 1]; + char *pname = ibuf; + char *s; + int n; + + sprintf(ibuf, "%-.*s", CPM_MAXPATH, skipUser(localname)); + + while ((s = strpbrk(pname, DIRSEP))) { /* find the last directory separator allows mixed \ and / in windows */ +#ifdef _WIN32 + if (*s == '\\') /* convert separators to common format so directory tracking works more efficiently */ + *s = '/'; +#endif + pname = s + 1; + } + + if (pname == ibuf) { /* No path separators in the name. It is therefore a + local filename, so map it to drive P: */ + strcpy(cpmname, "p:"); + strcat(cpmname, ibuf); + return; + } + + /* catch user specified current drive a,b,c,p or A,B,C,P only, which map to predefined directories */ + if (pname == ibuf + 2 && ibuf[1] == ':' && (s = strchr("aAbBcCpP", ibuf[0]))) { + cpmname[0] = tolower(*s); /* make sure it's lower case */ + strcpy(cpmname + 1, ibuf + 1); + return; + } + + strcpy(nbuf, pname); /* nbuf holds filename component */ + *pname = 0; /* ibuf holds path component */ + + /* See if the path is one of those already mapped to drives */ + + for (n = 0; n < 15; n++) + { + if (redir_drive_prefix[n][0] && !strcmp(ibuf, redir_drive_prefix[n])) + { + sprintf(cpmname,"%c:%s", n + 'a', nbuf); + return; + } + } + + /* It is not, see if another drive can be allocated */ + + for (n = 0; n < 15; n++) if (!redir_drive_prefix[n][0]) + { + strcpy(redir_drive_prefix[n], ibuf); + sprintf(cpmname,"%c:%s", n + 'a', nbuf); + return; + } + + /* No other drive can be allocated */ + + strcpy(cpmname,"p:"); + strcat(cpmname, nbuf); +} + +/* It is sometimes convenient to set some fixed mappings. This will create + * a mapping for a given directory. + * Pass drive = -1 for "first available", or 0-15 for A: to P: + */ + +int xlt_map(int drive, char *localdir) +{ + int n; + + if (drive == -1) + { + for (n = 0; n < 15; n++) if (!redir_drive_prefix[n][0]) + { + drive = n; + break; + } + if (drive == -1) return 0; /* No space for mappings */ + } + if (redir_drive_prefix[drive][0]) return 0; /* Drive taken */ + + sprintf(redir_drive_prefix[drive], "%-.*s", CPM_MAXPATH, localdir); + return 1; +} + + +/* Unmap a drive + */ + +int xlt_umap(int drive) +{ + if (!redir_drive_prefix[drive][0]) return 0; /* Drive not taken */ + redir_drive_prefix[drive][0] = 0; + return 1; +} + + +char *xlt_getcwd(int drive) +{ + if (drive < 0 || drive > 16) return ""; + + return redir_drive_prefix[drive]; +} + +/* as zxcc doesn't really support user spaces, remove any user specification + *hitech c supports + * [[0-9]+[:]][[a-pA-P]:]name[.ext] | [[a-pA-p][[0-9]+]:]name[.ext] + * this function also checks that user is no more than 2 digits and user # <= 31 + * the hitech fcb checks for : as char 2, 3, or 4 which aligns to this + */ +static char* skipUser(char* localname) { + char* s; + int user; + int drive; + + if (!localname || !(s = strchr(localname, ':')) || s > localname + 3) + return localname; + s = localname; + if (isdigit(*s)) { + user = *s++ - '0'; + if (isdigit(*s)) { + user = user * 10 + *s++ - '0'; + if (user > 31) /* check sensible user id */ + return localname; + } + if (*s == ':') /* just strip the user id assume rest is a filename */ + return s + 1; + if ('a' <= (drive = tolower(*s)) && drive <= 'p' && s[1] == ':') + return s; /* was form [0-9]+[a-pA-P] so strip user id */ + else + return localname; /* not vaild so don't change */ + } + if ((drive = tolower(*s++)) < 'a' || 'p' < drive || !isdigit(*s)) + return localname; /* not a valid drive prefix or simple drive spec */ + + user = *s++ - '0'; + if (isdigit(*s)) + user = user * 10 + *s++ - '0'; + if (*s != ':' || user > 31) + return localname; + *--s = drive; /* reinsert the drive just before the : */ + return s; +} diff --git a/Tools/unix/zx/z80.c b/Tools/unix/zxcc/z80.c similarity index 93% rename from Tools/unix/zx/z80.c rename to Tools/unix/zxcc/z80.c index d1d99cd5..1b62994c 100644 --- a/Tools/unix/zx/z80.c +++ b/Tools/unix/zxcc/z80.c @@ -1,270 +1,272 @@ -/* Emulation of the Z80 CPU with hooks into the other parts of xz80. - * Copyright (C) 1994 Ian Collier. - * - * 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 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include "zx.h" - -#define parity(a) (partable[a]) - -unsigned char partable[256]={ - 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, - 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, - 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, - 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, - 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, - 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, - 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, - 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, - 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, - 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, - 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, - 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, - 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, - 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, - 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, - 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4 - }; - -#ifdef DEBUG -static unsigned short breakpoint=0; -static unsigned int breaks=0; - -//static void inline log(fp,name,val) -static void log(fp,name,val) -FILE *fp; -char *name; -unsigned short val; -{ - int i; - fprintf(fp,"%s=%04X ",name,val); - for(i=0;i<8;i++,val++)fprintf(fp," %02X",fetch(val)); - putc('\n',fp); -} -#endif - -void mainloop(word spc, word ssp){ - register unsigned char a, f, b, c, d, e, h, l; - unsigned char r, a1, f1, b1, c1, d1, e1, h1, l1, i, iff1, iff2, im; - register unsigned short pc; - unsigned short ix, iy, sp; - register unsigned long tstates; - register unsigned int radjust; - register unsigned char ixoriy, new_ixoriy; - unsigned char intsample; - register unsigned char op; -#ifdef DEBUG - char flags[9]; - int bit; - FILE *fp=0; - register unsigned short af2=0,bc2=0,de2=0,hl2=0,ix2=0,iy2=0,sp2=0; - register unsigned char i2=0; - //unsigned char *memory=memptr[0]; - struct _next {unsigned char bytes[8];} *next; - unsigned short BC, DE, HL, AF; - - fputs("Press F11 to log\n",stderr); -#endif - a=f=b=c=d=e=h=l=a1=f1=b1=c1=d1=e1=h1=l1=i=r=iff1=iff2=im=0; - ixoriy=new_ixoriy=0; - ix=iy=0; - pc=spc; - sp=ssp; - tstates=radjust=0; - while(1){ - ixoriy=new_ixoriy; - new_ixoriy=0; -#ifdef DEBUG - next=(struct _next *)&fetch(pc); - BC=bc;DE=de;HL=hl;AF=(a<<8)|f; - if(fp && !ixoriy){ - log(fp,"pc",pc); - if(sp!=sp2)log(fp,"sp",sp2=sp); - if(iy!=iy2)log(fp,"iy",iy2=iy); - if(ix!=ix2)log(fp,"ix",ix2=ix); - if(hl!=hl2)log(fp,"hl",hl2=hl); - if(de!=de2)log(fp,"de",de2=de); - if(bc!=bc2)log(fp,"bc",bc2=bc); - if(((a<<8)|f)!=af2){ - af2=(a<<8)|f; - strcpy(flags,"SZ H VNC"); - for(bit=0;bit<8;bit++)if(!(f&(1<<(7-bit))))flags[bit]=' '; - fprintf(fp,"af=%04X %s\n",af2,flags); - } - if(i!=i2)fprintf(fp,"ir=%02X%02X\n",i2=i,r); - putc('\n',fp); - } - if(pc==breakpoint && pc) - breaks++; /* some code at which to set a breakpoint */ - a=AF>>8; f=AF; h=HL>>8; l=HL; d=DE>>8; e=DE; b=BC>>8; c=BC; -#endif -/* -{ - static int tr = 0; - static int id = 0; -// static byte b = 0; -// - if (pc == 0x1177) tr = 1; - if (pc == 0x1185) tr = 0; - if (tr >= 1) ++id; - if (tr >= 1) printf("%d: PC=%04x %02x AF=%02x:%02x BC=%04x DE=%04x HL=%04x IX=%04x IY=%04x\r\n", - id, pc, fetch(pc), a,f, bc, de, hl, ix, iy); -} -*/ - intsample=1; - op=fetch(pc); - pc++; - radjust++; - switch(op){ -#include "z80ops.h" - } -/*** - * ZXCC doesn't do interrupts at all, so all this is commented out - if(tstates>=int_cycles && intsample){ - tstates-=int_cycles; - frames++; - // Carry out X-related tasks (including waiting for timer - // signal if necessary) - switch(interrupt()){ - case Z80_quit: -#ifdef DEBUG - if(fp)fclose(fp); -#endif - return; - case Z80_NMI: - if(fetch(pc)==0x76)pc++; - iff2=iff1; - iff1=0; - // The Z80 performs a machine fetch cycle for 5 Tstates - // but ignores the result. It takes a further 10 Tstates - // to jump to the NMI routine at 0x66. - tstates+=15; - push2(pc); - pc=0x66; - break; - case Z80_reset: - a=f=b=c=d=e=h=l=a1=f1=b1=c1=d1=e1= - h1=l1=i=r=iff1=iff2=im=0; - ix=iy=sp=pc=0; - radjust=0; - break; -#ifdef DEBUG - case Z80_log: - if(fp){ - fclose(fp); - fp=0; - fputs("Logging turned off\n",stderr); - } else { - fp=fopen(config.log,"a"); - if(fp)fprintf(stderr,"Logging to file %s\n",config.log); - else perror(config.log); - } - break; -#endif - - case Z80_load: - stopwatch(); - if(snapload()){ - a=snapa; - f=snapf; - b=snapb; - c=snapc; - d=snapd; - e=snape; - h=snaph; - l=snapl; - a1=snapa1; - f1=snapf1; - b1=snapb1; - c1=snapc1; - d1=snapd1; - e1=snape1; - h1=snaph1; - l1=snapl1; - iff1=snapiff1; - iff2=snapiff2; - i=snapi; - r=snapr; - radjust=r; - im=snapim; - ix=snapix; - iy=snapiy; - sp=snapsp; - pc=snappc; - } - startwatch(1); - break; - case Z80_save: - r=(r&0x80)|(radjust&0x7f); - snapa=a; - snapf=f; - snapb=b; - snapc=c; - snapd=d; - snape=e; - snaph=h; - snapl=l; - snapa1=a1; - snapf1=f1; - snapb1=b1; - snapc1=c1; - snapd1=d1; - snape1=e1; - snaph1=h1; - snapl1=l1; - snapiff1=iff1; - snapiff2=iff2; - snapi=i; - snapr=r; - snapim=im; - snapix=ix; - snapiy=iy; - snapsp=sp; - snappc=pc; - snapsave(); - startwatch(1); - break; - - } - if(iff1){ -#ifdef DEBUG - if(fp)fprintf(fp,"Interrupt (im=%d)\n\n",im); -#endif - if(fetch(pc)==0x76)pc++; - iff1=iff2=0; - tstates+=5; // accompanied by an input from the data bus // - switch(im){ - case 0: // IM 0 // - case 1: // undocumented // - case 2: // IM 1 // - // there is little to distinguish between these cases // - tstates+=8; - push2(pc); - pc=0x38; - break; - case 3: // IM 2 // - tstates+=14; - { - int addr=fetch2((i<<8)|0xff); - push2(pc); - pc=addr; - } - } - } - }*/ - } -} +/* Emulation of the Z80 CPU with hooks into the other parts of xz80. + * Copyright (C) 1994 Ian Collier. + * + * 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 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "zxcc.h" + +#define parity(a) (partable[a]) + +unsigned char partable[256]={ + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4 + }; + +#ifdef DEBUG +// Avoid name conflict with built-in log math function +#define log z80_log + +static unsigned short breakpoint=0; +static unsigned int breaks=0; + +static void inline log(fp,name,val) +FILE *fp; +char *name; +unsigned short val; +{ + int i; + fprintf(fp,"%s=%04X ",name,val); + for(i=0;i<8;i++,val++)fprintf(fp," %02X",fetch(val)); + putc('\n',fp); +} +#endif + +void mainloop(word spc, word ssp){ + register unsigned char a, f, b, c, d, e, h, l; + unsigned char r, a1, f1, b1, c1, d1, e1, h1, l1, i, iff1, iff2, im; + register unsigned short pc; + unsigned short ix, iy, sp; + register unsigned long tstates; + register unsigned int radjust; + register unsigned char ixoriy, new_ixoriy; + unsigned char intsample; + register unsigned char op; +#ifdef DEBUG + char flags[9]; + int bit; + FILE *fp=0; + register unsigned short af2=0,bc2=0,de2=0,hl2=0,ix2=0,iy2=0,sp2=0; + register unsigned char i2=0; + /*unsigned char *memory=memptr[0];*/ + struct _next {unsigned char bytes[8];} *next; + unsigned short BC, DE, HL, AF; + + fputs("Press F11 to log\n",stderr); +#endif + a=f=b=c=d=e=h=l=a1=f1=b1=c1=d1=e1=h1=l1=i=r=iff1=iff2=im=0; + ixoriy=new_ixoriy=0; + ix=iy=0; + pc=spc; + sp=ssp; + tstates=radjust=0; + while(1){ + ixoriy=new_ixoriy; + new_ixoriy=0; +#ifdef DEBUG + next=(struct _next *)&fetch(pc); + BC=bc;DE=de;HL=hl;AF=(a<<8)|f; + if(fp && !ixoriy){ + log(fp,"pc",pc); + if(sp!=sp2)log(fp,"sp",sp2=sp); + if(iy!=iy2)log(fp,"iy",iy2=iy); + if(ix!=ix2)log(fp,"ix",ix2=ix); + if(hl!=hl2)log(fp,"hl",hl2=hl); + if(de!=de2)log(fp,"de",de2=de); + if(bc!=bc2)log(fp,"bc",bc2=bc); + if(((a<<8)|f)!=af2){ + af2=(a<<8)|f; + strcpy(flags,"SZ H VNC"); + for(bit=0;bit<8;bit++)if(!(f&(1<<(7-bit))))flags[bit]=' '; + fprintf(fp,"af=%04X %s\n",af2,flags); + } + if(i!=i2)fprintf(fp,"ir=%02X%02X\n",i2=i,r); + putc('\n',fp); + } + if(pc==breakpoint && pc) + breaks++; /* some code at which to set a breakpoint */ + a=AF>>8; f=AF; h=HL>>8; l=HL; d=DE>>8; e=DE; b=BC>>8; c=BC; +#endif +/* +{ + static int tr = 1; + static int id = 0; +// static byte b = 0; +// +// if (pc == 0x1177) tr = 1; + // if (pc == 0x1185) tr = 0; + if (tr >= 1) ++id; + if (tr >= 1) printf("%d: PC=%04x %02x AF=%02x:%02x BC=%04x DE=%04x HL=%04x IX=%04x IY=%04x\r\n", + id, pc, fetch(pc), a,f, bc, de, hl, ix, iy); +} +*/ + intsample=1; + op=fetch(pc); + pc++; + radjust++; + switch(op){ +#include "z80ops.h" + } +/*** + * ZXCC doesn't do interrupts at all, so all this is commented out + if(tstates>=int_cycles && intsample){ + tstates-=int_cycles; + frames++; + // Carry out X-related tasks (including waiting for timer + // signal if necessary) + switch(interrupt()){ + case Z80_quit: +#ifdef DEBUG + if(fp)fclose(fp); +#endif + return; + case Z80_NMI: + if(fetch(pc)==0x76)pc++; + iff2=iff1; + iff1=0; + // The Z80 performs a machine fetch cycle for 5 Tstates + // but ignores the result. It takes a further 10 Tstates + // to jump to the NMI routine at 0x66. + tstates+=15; + push2(pc); + pc=0x66; + break; + case Z80_reset: + a=f=b=c=d=e=h=l=a1=f1=b1=c1=d1=e1= + h1=l1=i=r=iff1=iff2=im=0; + ix=iy=sp=pc=0; + radjust=0; + break; +#ifdef DEBUG + case Z80_log: + if(fp){ + fclose(fp); + fp=0; + fputs("Logging turned off\n",stderr); + } else { + fp=fopen(config.log,"a"); + if(fp)fprintf(stderr,"Logging to file %s\n",config.log); + else perror(config.log); + } + break; +#endif + + case Z80_load: + stopwatch(); + if(snapload()){ + a=snapa; + f=snapf; + b=snapb; + c=snapc; + d=snapd; + e=snape; + h=snaph; + l=snapl; + a1=snapa1; + f1=snapf1; + b1=snapb1; + c1=snapc1; + d1=snapd1; + e1=snape1; + h1=snaph1; + l1=snapl1; + iff1=snapiff1; + iff2=snapiff2; + i=snapi; + r=snapr; + radjust=r; + im=snapim; + ix=snapix; + iy=snapiy; + sp=snapsp; + pc=snappc; + } + startwatch(1); + break; + case Z80_save: + r=(r&0x80)|(radjust&0x7f); + snapa=a; + snapf=f; + snapb=b; + snapc=c; + snapd=d; + snape=e; + snaph=h; + snapl=l; + snapa1=a1; + snapf1=f1; + snapb1=b1; + snapc1=c1; + snapd1=d1; + snape1=e1; + snaph1=h1; + snapl1=l1; + snapiff1=iff1; + snapiff2=iff2; + snapi=i; + snapr=r; + snapim=im; + snapix=ix; + snapiy=iy; + snapsp=sp; + snappc=pc; + snapsave(); + startwatch(1); + break; + + } + if(iff1){ +#ifdef DEBUG + if(fp)fprintf(fp,"Interrupt (im=%d)\n\n",im); +#endif + if(fetch(pc)==0x76)pc++; + iff1=iff2=0; + tstates+=5; // accompanied by an input from the data bus // + switch(im){ + case 0: // IM 0 // + case 1: // undocumented // + case 2: // IM 1 // + // there is little to distinguish between these cases // + tstates+=8; + push2(pc); + pc=0x38; + break; + case 3: // IM 2 // + tstates+=14; + { + int addr=fetch2((i<<8)|0xff); + push2(pc); + pc=addr; + } + } + } + }*/ + } +} diff --git a/Tools/unix/zx/z80.h b/Tools/unix/zxcc/z80.h similarity index 96% rename from Tools/unix/zx/z80.h rename to Tools/unix/zxcc/z80.h index 89e12a84..d9e3a547 100644 --- a/Tools/unix/zx/z80.h +++ b/Tools/unix/zxcc/z80.h @@ -1,86 +1,86 @@ -/* Miscellaneous definitions for xz80, copyright (C) 1994 Ian Collier. - * - * 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 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* [John Elliott, 15 July 2001] - * Copied this file into ZXCC, a CP/M emulator. - * Since ZXCC's memory is a flat 64k space and will never be bank-switched, - * the bank-switching code is removed. - * Since ZXCC has no memory-mapped screen, all the screen management code - * goes as well. - * Since ZXCC doesn't need its speed regulated, all the speed regulation - * code goes as well. - * Since ZXCC doesn't save or load snapshots... OK, you get the idea. - */ - -#ifdef HAVE_SYS_PARAM_H -#include -#endif - -#define Z80_quit 1 -#define Z80_NMI 2 -#define Z80_reset 3 -#define Z80_load 4 -#define Z80_save 5 -#define Z80_log 6 - -unsigned int in(); -unsigned int out(); -//int interrupt(); -int snapload(); -void snapsave(); -void mainloop(word xpc, word xsp); -void eachframe(); -void itimeron(); -void itimeroff(); -void startwatch(); -unsigned long stopwatch(); -void requester(); -int loader(); -int saver(); -void multiloader(); -void usage(); -void version(); -void drawborder(); - -#define fetch(x) (RAM[x]) -#define fetch2(x) ((fetch((x)+1)<<8)|fetch(x)) - -#define store(x,y) do { RAM[(x)] = (y); } while(0) - -#define store2b(x,hi,lo) do {\ - RAM[(x)]=(lo); \ - RAM[((x+1) & 0xFFFF)]=(hi); } while(0) - -#define store2(x,y) store2b(x,(y)>>8,y) - -#ifdef __GNUC__ -static void inline storefunc(unsigned short ad,unsigned char b){ - store(ad,b); -} -#undef store -#define store(x,y) storefunc(x,y) - -static void inline store2func(unsigned short ad,unsigned char b1,unsigned char b2){ - store2b(ad,b1,b2); -} -#undef store2b -#define store2b(x,hi,lo) store2func(x,hi,lo) -#endif - -#define bc ((b<<8)|c) -#define de ((d<<8)|e) -#define hl ((h<<8)|l) +/* Miscellaneous definitions for xz80, copyright (C) 1994 Ian Collier. + * + * 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 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* [John Elliott, 15 July 2001] + * Copied this file into ZXCC, a CP/M emulator. + * Since ZXCC's memory is a flat 64k space and will never be bank-switched, + * the bank-switching code is removed. + * Since ZXCC has no memory-mapped screen, all the screen management code + * goes as well. + * Since ZXCC doesn't need its speed regulated, all the speed regulation + * code goes as well. + * Since ZXCC doesn't save or load snapshots... OK, you get the idea. + */ + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#define Z80_quit 1 +#define Z80_NMI 2 +#define Z80_reset 3 +#define Z80_load 4 +#define Z80_save 5 +#define Z80_log 6 + +unsigned int in(); +unsigned int out(); +//int interrupt(); +int snapload(); +void snapsave(); +void mainloop(word xpc, word xsp); +void eachframe(); +void itimeron(); +void itimeroff(); +void startwatch(); +unsigned long stopwatch(); +void requester(); +int loader(); +int saver(); +void multiloader(); +void usage(); +void version(); +void drawborder(); + +#define fetch(x) (RAM[x]) +#define fetch2(x) ((fetch((x)+1)<<8)|fetch(x)) + +#define store(x,y) do { RAM[(x)] = (y); } while(0) + +#define store2b(x,hi,lo) do {\ + RAM[(x)]=(lo); \ + RAM[((x+1) & 0xFFFF)]=(hi); } while(0) + +#define store2(x,y) store2b(x,(y)>>8,y) + +#ifdef __GNUC__ +static void inline storefunc(unsigned short ad,unsigned char b){ + store(ad,b); +} +#undef store +#define store(x,y) storefunc(x,y) + +static void inline store2func(unsigned short ad,unsigned char b1,unsigned char b2){ + store2b(ad,b1,b2); +} +#undef store2b +#define store2b(x,hi,lo) store2func(x,hi,lo) +#endif + +#define bc ((b<<8)|c) +#define de ((d<<8)|e) +#define hl ((h<<8)|l) diff --git a/Tools/unix/zx/z80ops.h b/Tools/unix/zxcc/z80ops.h similarity index 93% rename from Tools/unix/zx/z80ops.h rename to Tools/unix/zxcc/z80ops.h index aac5d548..a07cfe5e 100644 --- a/Tools/unix/zx/z80ops.h +++ b/Tools/unix/zxcc/z80ops.h @@ -1,1332 +1,1332 @@ -/* Emulations of the Z80 CPU instruction set - part of xz80. - * Copyright (C) 1994 Ian Collier. - * - * 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 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#define instr(opcode,cycles) case opcode: {tstates+=cycles -#define HLinstr(opcode,cycles,morecycles) \ - case opcode: {unsigned short addr; \ - tstates+=cycles; \ - if(ixoriy==0)addr=hl; \ - else tstates+=morecycles, \ - addr=(ixoriy==1?ix:iy)+ \ - (signed char)fetch(pc),\ - pc++ -#define endinstr }; break - -#define cy (f&1) - -#define xh (ixoriy==0?h:ixoriy==1?(ix>>8):(iy>>8)) -#define xl (ixoriy==0?l:ixoriy==1?(ix&0xff):(iy&0xff)) - -#define setxh(x) (ixoriy==0?(h=(x)):ixoriy==1?(ix=(ix&0xff)|((x)<<8)):\ - (iy=(iy&0xff)|((x)<<8))) -#define setxl(x) (ixoriy==0?(l=(x)):ixoriy==1?(ix=(ix&0xff00)|(x)):\ - (iy=(iy&0xff00)|(x))) - -#define inc(var) /* 8-bit increment */ ( var++,\ - f=(f&1)|(var&0xa8)|\ - ((!(var&15))<<4)|((!var)<<6)|\ - ((var==128)<<2)\ - ) -#define dec(var) /* 8-bit decrement */ ( f=(f&1)|((!(var&15))<<4)|2,\ - --var,\ - f|=(var&0xa8)|((var==127)<<2)|\ - ((!var)<<6)\ - ) -#define swap(x,y) {unsigned char t=x; x=y; y=t;} -#define addhl(hi,lo) /* 16-bit add */ if(!ixoriy){\ - unsigned short t;\ - l=t=l+(lo);\ - f=(f&0xc4)|(((t>>=8)+(h&0x0f)+((hi)&0x0f)>15)<<4);\ - h=t+=h+(hi);\ - f|=(h&0x28)|(t>>8);\ - }\ - else do{unsigned long t=(ixoriy==1?ix:iy);\ - f=(f&0xc4)|(((t&0xfff)+((hi<<8)|lo)>0xfff)<<4);\ - t+=(hi<<8)|lo;\ - if(ixoriy==1)ix=t; else iy=t;\ - f|=((t>>8)&0x28)|(t>>16);\ - } while(0) -#define adda(x,c) /* 8-bit add */ do{unsigned short y;\ - unsigned char z=(x);\ - y=a+z+(c);\ - f=(y&0xa8)|(y>>8)|(((a&0x0f)+(z&0x0f)+(c)>15)<<4)|\ - (((~a^z)&0x80&(y^a))>>5);\ - f|=(!(a=y))<<6;\ - } while(0) -#define suba(x,c) /* 8-bit subtract */ do{unsigned short y;\ - unsigned char z=(x);\ - y=(a-z-(c))&0x1ff;\ - f=(y&0xa8)|(y>>8)|(((a&0x0f)<(z&0x0f)+(c))<<4)|\ - (((a^z)&0x80&(y^a))>>5)|2;\ - f|=(!(a=y))<<6;\ - } while(0) -#define cpa(x) /* 8-bit compare */ do{unsigned short y;\ - unsigned char z=(x);\ - y=(a-z)&0x1ff;\ - f=(y&0xa8)|(y>>8)|(((a&0x0f)<(z&0x0f))<<4)|\ - (((a^z)&0x80&(y^a))>>5)|2|((!y)<<6);\ - } while(0) -#define anda(x) /* logical and */ do{\ - a&=(x);\ - f=(a&0xa8)|((!a)<<6)|0x10|parity(a);\ - } while(0) -#define xora(x) /* logical xor */ do{\ - a^=(x);\ - f=(a&0xa8)|((!a)<<6)|parity(a);\ - } while(0) -#define ora(x) /* logical or */ do{\ - a|=(x);\ - f=(a&0xa8)|((!a)<<6)|parity(a);\ - } while(0) - -#define jr /* execute relative jump */ do{int j=(signed char)fetch(pc);\ - pc+=j+1;\ - tstates+=5;\ - } while(0) -#define jp /* execute jump */ (pc=fetch2(pc)) -#define call /* execute call */ do{\ - tstates+=7;\ - push2(pc+2);\ - jp;\ - } while(0) -#define ret /* execute return */ do{\ - tstates+=6;\ - pop2(pc);\ - } while(0) -#define pop2(var) /* pop 16-bit register */ (var=fetch2(sp),sp+=2) -#define pop1(v1,v2) /* pop register pair */ (v2=fetch(sp),\ - v1=fetch(sp+1),sp+=2) -#define push2(val) /* push 16-bit register */ do{sp-=2;store2(sp,(val));}\ - while(0) -#define push1(v1,v2) /* push register pair */ do{sp-=2;\ - store2b(sp,v1,v2);\ - }while(0) - -instr(0,4); - /* nop */ -endinstr; - -instr(1,10); - c=fetch(pc),pc++; - b=fetch(pc),pc++; -endinstr; - -instr(2,7); - store(bc,a); -endinstr; - -instr(3,6); - if(!++c)b++; -endinstr; - -instr(4,4); - inc(b); -endinstr; - -instr(5,4); - dec(b); -endinstr; - -instr(6,7); - b=fetch(pc),pc++; -endinstr; - -instr(7,4); - a=(a<<1)|(a>>7); - f=(f&0xc4)|(a&0x29); -endinstr; - -instr(8,4); - swap(a,a1); - swap(f,f1); -endinstr; - -instr(9,11); - addhl(b,c); -endinstr; - -instr(10,7); - a=fetch(bc); -endinstr; - -instr(11,6); - if(!c--)b--; -endinstr; - -instr(12,4); - inc(c); -endinstr; - -instr(13,4); - dec(c); -endinstr; - -instr(14,7); - c=fetch(pc),pc++; -endinstr; - -instr(15,4); - f=(f&0xc4)|(a&1); - a=(a>>1)|(a<<7); - f|=a&0x28; -endinstr; - -instr(16,8); - if(!--b)pc++; - else jr; -endinstr; - -instr(17,10); - e=fetch(pc),pc++; - d=fetch(pc),pc++; -endinstr; - -instr(18,7); - store(de,a); -endinstr; - -instr(19,6); - if(!++e)d++; -endinstr; - -instr(20,4); - inc(d); -endinstr; - -instr(21,4); - dec(d); -endinstr; - -instr(22,7); - d=fetch(pc),pc++; -endinstr; - -instr(23,4); - {int t=a>>7; - a=(a<<1)|(f&1); - f=(f&0xc4)|(a&0x28)|t; - } -endinstr; - -instr(24,7); - jr; -endinstr; - -instr(25,11); - addhl(d,e); -endinstr; - -instr(26,7); - a=fetch(de); -endinstr; - -instr(27,6); - if(!e--)d--; -endinstr; - -instr(28,4); - inc(e); -endinstr; - -instr(29,4); - dec(e); -endinstr; - -instr(30,7); - e=fetch(pc),pc++; -endinstr; - -instr(31,4); - {int t=a&1; - a=(a>>1)|(f<<7); - f=(f&0xc4)|(a&0x28)|t; - } -endinstr; - -instr(32,7); - if(f&0x40)pc++; - else jr; -endinstr; - -instr(33,10); - if(!ixoriy){ - l=fetch(pc),pc++; - h=fetch(pc),pc++; - } - else { - if(ixoriy==1)ix=fetch2(pc); - else iy=fetch2(pc); - pc+=2; - } -endinstr; - -instr(34,16); - {unsigned short addr=fetch2(pc); - pc+=2; - if(!ixoriy)store2b(addr,h,l); - else if(ixoriy==1)store2(addr,ix); - else store2(addr,iy); - } -endinstr; - -instr(35,6); - if(!ixoriy){if(!++l)h++;} - else if(ixoriy==1)ix++; - else iy++; -endinstr; - -instr(36,4); - if(ixoriy==0)inc(h); - else{unsigned char t; - t=(ixoriy==1?ix:iy)>>8; - inc(t); - if(ixoriy==1)ix=(ix&0xff)|(t<<8); - else iy=(iy&0xff)|(t<<8); - } -endinstr; - -instr(37,4); - if(ixoriy==0)dec(h); - else{unsigned char t; - t=(ixoriy==1?ix:iy)>>8; - dec(t); - if(ixoriy==1)ix=(ix&0xff)|(t<<8); - else iy=(iy&0xff)|(t<<8); - } -endinstr; - -instr(38,7); - setxh(fetch(pc)); - pc++; -endinstr; - -instr(39,4); - { - /* Frank D. Cringle's DAA implementation, converted from yaze 1.10 */ - unsigned int acu,temp,cbits; - - acu=a; - temp=(acu&15); - cbits=(f&1); - if(f&2) /* if N */ - { - /* last operation was a subtract */ - int hd=(cbits || (acu>0x99)); - if((f&16) || (temp>9)) - { /* adjust low digit */ - if(temp>5) f&=~16; - acu-=6; - acu&=0xff; - } - /* adjust high digit */ - if(hd) - acu-=0x160; - } - else - { - /* last operation was an add */ - if((f&16) || (temp>9)) - { - /* adjust low digit */ - if(temp>9) f|=16; else f&=~16; - acu+=6; - } - /* adjust high digit */ - if(cbits || ((acu&0x1f0)>0x90)) - acu+=0x60; - } - cbits|=((acu>>8)&1); - acu&=0xff; - a=acu; - f=((acu&0xa8)|((acu==0)<<6)|(f&0x12)|parity(a)|cbits); - } -endinstr; - -instr(40,7); - if(f&0x40)jr; - else pc++; -endinstr; - -instr(41,11); - if(!ixoriy)addhl(h,l); - else if(ixoriy==1)addhl((ix>>8),(ix&0xff)); - else addhl((iy>>8),(iy&0xff)); -endinstr; - -instr(42,16); - {unsigned short addr=fetch2(pc); - pc+=2; - if(!ixoriy){ - l=fetch(addr); - h=fetch(addr+1); - } - else if(ixoriy==1)ix=fetch2(addr); - else iy=fetch2(addr); - } -endinstr; - -instr(43,6); - if(!ixoriy){if(!l--)h--;} - else if(ixoriy==1)ix--; - else iy--; -endinstr; - -instr(44,4); - if(!ixoriy)inc(l); - else {unsigned char t; - t=(ixoriy==1?ix:iy); - inc(t); - if(ixoriy==1)ix=(ix&0xff00)|t; - else iy=(iy&0xff00)|t; - } -endinstr; - -instr(45,4); - if(!ixoriy)dec(l); - else {unsigned char t; - t=(ixoriy==1?ix:iy); - dec(t); - if(ixoriy==1)ix=(ix&0xff00)|t; - else iy=(iy&0xff00)|t; - } -endinstr; - -instr(46,7); - setxl(fetch(pc)); - pc++; -endinstr; - -instr(47,4); - a=~a; - f=(f&0xc5)|(a&0x28)|0x12; -endinstr; - -instr(48,7); - if(f&1)pc++; - else jr; -endinstr; - -instr(49,10); - sp=fetch2(pc); - pc+=2; -endinstr; - -instr(50,13); - {unsigned short addr=fetch2(pc); - pc+=2; - store(addr,a); - } -endinstr; - -instr(51,6); - sp++; -endinstr; - -HLinstr(52,11,8); - {unsigned char t=fetch(addr); - inc(t); - store(addr,t); - } -endinstr; - -HLinstr(53,11,8); - {unsigned char t=fetch(addr); - dec(t); - store(addr,t); - } -endinstr; - -HLinstr(54,10,5); - store(addr,fetch(pc)); - pc++; -endinstr; - -instr(55,4); - f=(f&0xc4)|1|(a&0x28); -endinstr; - -instr(56,7); - if(f&1)jr; - else pc++; -endinstr; - -instr(57,11); - addhl((sp>>8),(sp&0xff)); -endinstr; - -instr(58,13); - {unsigned short addr=fetch2(pc); - pc+=2; - a=fetch(addr); - } -endinstr; - -instr(59,6); - sp--; -endinstr; - -instr(60,4); - inc(a); -endinstr; - -instr(61,4); - dec(a); -endinstr; - -instr(62,7); - a=fetch(pc),pc++; -endinstr; - -instr(63,4); - f=(f&0xc4)|(cy^1)|(cy<<4)|(a&0x28); -endinstr; - -instr(0x40,4); - /* ld b,b */ -endinstr; - -instr(0x41,4); - b=c; -endinstr; - -instr(0x42,4); - b=d; -endinstr; - -instr(0x43,4); - b=e; -endinstr; - -instr(0x44,4); - b=xh; -endinstr; - -instr(0x45,4); - b=xl; -endinstr; - -HLinstr(0x46,7,8); - b=fetch(addr); -endinstr; - -instr(0x47,4); - b=a; -endinstr; - -instr(0x48,4); - c=b; -endinstr; - -instr(0x49,4); - /* ld c,c */ -endinstr; - -instr(0x4a,4); - c=d; -endinstr; - -instr(0x4b,4); - c=e; -endinstr; - -instr(0x4c,4); - c=xh; -endinstr; - -instr(0x4d,4); - c=xl; -endinstr; - -HLinstr(0x4e,7,8); - c=fetch(addr); -endinstr; - -instr(0x4f,4); - c=a; -endinstr; - -instr(0x50,4); - d=b; -endinstr; - -instr(0x51,4); - d=c; -endinstr; - -instr(0x52,4); - /* ld d,d */ -endinstr; - -instr(0x53,4); - d=e; -endinstr; - -instr(0x54,4); - d=xh; -endinstr; - -instr(0x55,4); - d=xl; -endinstr; - -HLinstr(0x56,7,8); - d=fetch(addr); -endinstr; - -instr(0x57,4); - d=a; -endinstr; - -instr(0x58,4); - e=b; -endinstr; - -instr(0x59,4); - e=c; -endinstr; - -instr(0x5a,4); - e=d; -endinstr; - -instr(0x5b,4); - /* ld e,e */ -endinstr; - -instr(0x5c,4); - e=xh; -endinstr; - -instr(0x5d,4); - e=xl; -endinstr; - -HLinstr(0x5e,7,8); - e=fetch(addr); -endinstr; - -instr(0x5f,4); - e=a; -endinstr; - -instr(0x60,4); - setxh(b); -endinstr; - -instr(0x61,4); - setxh(c); -endinstr; - -instr(0x62,4); - setxh(d); -endinstr; - -instr(0x63,4); - setxh(e); -endinstr; - -instr(0x64,4); - /* ld h,h */ -endinstr; - -instr(0x65,4); - setxh(xl); -endinstr; - -HLinstr(0x66,7,8); - h=fetch(addr); -endinstr; - -instr(0x67,4); - setxh(a); -endinstr; - -instr(0x68,4); - setxl(b); -endinstr; - -instr(0x69,4); - setxl(c); -endinstr; - -instr(0x6a,4); - setxl(d); -endinstr; - -instr(0x6b,4); - setxl(e); -endinstr; - -instr(0x6c,4); - setxl(xh); -endinstr; - -instr(0x6d,4); - /* ld l,l */ -endinstr; - -HLinstr(0x6e,7,8); - l=fetch(addr); -endinstr; - -instr(0x6f,4); - setxl(a); -endinstr; - -HLinstr(0x70,7,8); - store(addr,b); -endinstr; - -HLinstr(0x71,7,8); - store(addr,c); -endinstr; - -HLinstr(0x72,7,8); - store(addr,d); -endinstr; - -HLinstr(0x73,7,8); - store(addr,e); -endinstr; - -HLinstr(0x74,7,8); - store(addr,h); -endinstr; - -HLinstr(0x75,7,8); - store(addr,l); -endinstr; - -instr(0x76,4); - /* Was HALT - ZXCC ignores HALT */ -endinstr; - -HLinstr(0x77,7,8); - store(addr,a); -endinstr; - -instr(0x78,4); - a=b; -endinstr; - -instr(0x79,4); - a=c; -endinstr; - -instr(0x7a,4); - a=d; -endinstr; - -instr(0x7b,4); - a=e; -endinstr; - -instr(0x7c,4); - a=xh; -endinstr; - -instr(0x7d,4); - a=xl; -endinstr; - -HLinstr(0x7e,7,8); - a=fetch(addr); -endinstr; - -instr(0x7f,4); - /* ld a,a */ -endinstr; - -instr(0x80,4); - adda(b,0); -endinstr; - -instr(0x81,4); - adda(c,0); -endinstr; - -instr(0x82,4); - adda(d,0); -endinstr; - -instr(0x83,4); - adda(e,0); -endinstr; - -instr(0x84,4); - adda(xh,0); -endinstr; - -instr(0x85,4); - adda(xl,0); -endinstr; - -HLinstr(0x86,7,8); - adda(fetch(addr),0); -endinstr; - -instr(0x87,4); - adda(a,0); -endinstr; - -instr(0x88,4); - adda(b,cy); -endinstr; - -instr(0x89,4); - adda(c,cy); -endinstr; - -instr(0x8a,4); - adda(d,cy); -endinstr; - -instr(0x8b,4); - adda(e,cy); -endinstr; - -instr(0x8c,4); - adda(xh,cy); -endinstr; - -instr(0x8d,4); - adda(xl,cy); -endinstr; - -HLinstr(0x8e,7,8); - adda(fetch(addr),cy); -endinstr; - -instr(0x8f,4); - adda(a,cy); -endinstr; - -instr(0x90,4); - suba(b,0); -endinstr; - -instr(0x91,4); - suba(c,0); -endinstr; - -instr(0x92,4); - suba(d,0); -endinstr; - -instr(0x93,4); - suba(e,0); -endinstr; - -instr(0x94,4); - suba(xh,0); -endinstr; - -instr(0x95,4); - suba(xl,0); -endinstr; - -HLinstr(0x96,7,8); - suba(fetch(addr),0); -endinstr; - -instr(0x97,4); - suba(a,0); -endinstr; - -instr(0x98,4); - suba(b,cy); -endinstr; - -instr(0x99,4); - suba(c,cy); -endinstr; - -instr(0x9a,4); - suba(d,cy); -endinstr; - -instr(0x9b,4); - suba(e,cy); -endinstr; - -instr(0x9c,4); - suba(xh,cy); -endinstr; - -instr(0x9d,4); - suba(xl,cy); -endinstr; - -HLinstr(0x9e,7,8); - suba(fetch(addr),cy); -endinstr; - -instr(0x9f,4); - suba(a,cy); -endinstr; - -instr(0xa0,4); - anda(b); -endinstr; - -instr(0xa1,4); - anda(c); -endinstr; - -instr(0xa2,4); - anda(d); -endinstr; - -instr(0xa3,4); - anda(e); -endinstr; - -instr(0xa4,4); - anda(xh); -endinstr; - -instr(0xa5,4); - anda(xl); -endinstr; - -HLinstr(0xa6,7,8); - anda(fetch(addr)); -endinstr; - -instr(0xa7,4); - anda(a); -endinstr; - -instr(0xa8,4); - xora(b); -endinstr; - -instr(0xa9,4); - xora(c); -endinstr; - -instr(0xaa,4); - xora(d); -endinstr; - -instr(0xab,4); - xora(e); -endinstr; - -instr(0xac,4); - xora(xh); -endinstr; - -instr(0xad,4); - xora(xl); -endinstr; - -HLinstr(0xae,7,8); - xora(fetch(addr)); -endinstr; - -instr(0xaf,4); - xora(a); -endinstr; - -instr(0xb0,4); - ora(b); -endinstr; - -instr(0xb1,4); - ora(c); -endinstr; - -instr(0xb2,4); - ora(d); -endinstr; - -instr(0xb3,4); - ora(e); -endinstr; - -instr(0xb4,4); - ora(xh); -endinstr; - -instr(0xb5,4); - ora(xl); -endinstr; - -HLinstr(0xb6,7,8); - ora(fetch(addr)); -endinstr; - -instr(0xb7,4); - ora(a); -endinstr; - -instr(0xb8,4); - cpa(b); -endinstr; - -instr(0xb9,4); - cpa(c); -endinstr; - -instr(0xba,4); - cpa(d); -endinstr; - -instr(0xbb,4); - cpa(e); -endinstr; - -instr(0xbc,4); - cpa(xh); -endinstr; - -instr(0xbd,4); - cpa(xl); -endinstr; - -HLinstr(0xbe,7,8); - cpa(fetch(addr)); -endinstr; - -instr(0xbf,4); - cpa(a); -endinstr; - -instr(0xc0,5); - if(!(f&0x40))ret; -endinstr; - -instr(0xc1,10); - pop1(b,c); -endinstr; - -instr(0xc2,10); - if(!(f&0x40))jp; - else pc+=2; -endinstr; - -instr(0xc3,10); - jp; -endinstr; - -instr(0xc4,10); - if(!(f&0x40))call; - else pc+=2; -endinstr; - -instr(0xc5,11); - push1(b,c); -endinstr; - -instr(0xc6,7); - adda(fetch(pc),0); - pc++; -endinstr; - -instr(0xc7,11); - push2(pc); - pc=0; -endinstr; - -instr(0xc8,5); - if(f&0x40)ret; -endinstr; - -instr(0xc9,4); - ret; -endinstr; - -instr(0xca,10); - if(f&0x40)jp; - else pc+=2; -endinstr; - -instr(0xcb,4); -#include "cbops.h" -endinstr; - -instr(0xcc,10); - if(f&0x40)call; - else pc+=2; -endinstr; - -instr(0xcd,10); - call; -endinstr; - -instr(0xce,7); - adda(fetch(pc),cy); - pc++; -endinstr; - -instr(0xcf,11); - push2(pc); - pc=8; -endinstr; - -instr(0xd0,5); - if(!cy)ret; -endinstr; - -instr(0xd1,10); - pop1(d,e); -endinstr; - -instr(0xd2,10); - if(!cy)jp; - else pc+=2; -endinstr; - -instr(0xd3,11); - tstates+=out(tstates,a,fetch(pc),a); - pc++; -endinstr; - -instr(0xd4,10); - if(!cy)call; - else pc+=2; -endinstr; - -instr(0xd5,11); - push1(d,e); -endinstr; - -instr(0xd6,7); - suba(fetch(pc),0); - pc++; -endinstr; - -instr(0xd7,11); - push2(pc); - pc=16; -endinstr; - -instr(0xd8,5); - if(cy)ret; -endinstr; - -instr(0xd9,4); - swap(b,b1); - swap(c,c1); - swap(d,d1); - swap(e,e1); - swap(h,h1); - swap(l,l1); -endinstr; - -instr(0xda,10); - if(cy)jp; - else pc+=2; -endinstr; - -instr(0xdb,11); - {unsigned short t; - a=t=in(tstates,a,fetch(pc)); - tstates+=t>>8; - pc++; - } -endinstr; - -instr(0xdc,10); - if(cy)call; - else pc+=2; -endinstr; - -instr(0xdd,4); - new_ixoriy=1; - intsample=0; -endinstr; - -instr(0xde,7); - suba(fetch(pc),cy); - pc++; -endinstr; - -instr(0xdf,11); - push2(pc); - pc=24; -endinstr; - -instr(0xe0,5); - if(!(f&4))ret; -endinstr; - -instr(0xe1,10); - if(!ixoriy)pop1(h,l); - else if(ixoriy==1)pop2(ix); - else pop2(iy); -endinstr; - -instr(0xe2,10); - if(!(f&4))jp; - else pc+=2; -endinstr; - -instr(0xe3,19); - if(!ixoriy){ - unsigned short t=fetch2(sp); - store2b(sp,h,l); - l=t; - h=t>>8; - } - else if(ixoriy==1){ - unsigned short t=fetch2(sp); - store2(sp,ix); - ix=t; - } - else{ - unsigned short t=fetch2(sp); - store2(sp,iy); - iy=t; - } -endinstr; - -instr(0xe4,10); - if(!(f&4))call; - else pc+=2; -endinstr; - -instr(0xe5,11); - if(!ixoriy)push1(h,l); - else if(ixoriy==1)push2(ix); - else push2(iy); -endinstr; - -instr(0xe6,7); - anda(fetch(pc)); - pc++; -endinstr; - -instr(0xe7,11); - push2(pc); - pc=32; -endinstr; - -instr(0xe8,5); - if(f&4)ret; -endinstr; - -instr(0xe9,4); - pc=!ixoriy?hl:ixoriy==1?ix:iy; -endinstr; - -instr(0xea,10); - if(f&4)jp; - else pc+=2; -endinstr; - -instr(0xeb,4); - swap(h,d); - swap(e,l); -endinstr; - -instr(0xec,10); - if(f&4)call; - else pc+=2; -endinstr; - -instr(0xed,4); -#include"edops.h" -endinstr; - -instr(0xee,7); - xora(fetch(pc)); - pc++; -endinstr; - -instr(0xef,11); - push2(pc); - pc=40; -endinstr; - -instr(0xf0,5); - if(!(f&0x80))ret; -endinstr; - -instr(0xf1,10); - pop1(a,f); -endinstr; - -instr(0xf2,10); - if(!(f&0x80))jp; - else pc+=2; -endinstr; - -instr(0xf3,4); - iff1=iff2=0; - intsample=0; -endinstr; - -instr(0xf4,10); - if(!(f&0x80))call; - else pc+=2; -endinstr; - -instr(0xf5,11); - push1(a,f); -endinstr; - -instr(0xf6,7); - ora(fetch(pc)); - pc++; -endinstr; - -instr(0xf7,11); - push2(pc); - pc=48; -endinstr; - -instr(0xf8,5); - if(f&0x80)ret; -endinstr; - -instr(0xf9,6); - sp=!ixoriy?hl:ixoriy==1?ix:iy; -endinstr; - -instr(0xfa,10); - if(f&0x80)jp; - else pc+=2; -endinstr; - -instr(0xfb,4); - iff1=iff2=1; - intsample=0; -endinstr; - -instr(0xfc,10); - if(f&0x80)call; - else pc+=2; -endinstr; - -instr(0xfd,4); - new_ixoriy=2; - intsample=0; -endinstr; - -instr(0xfe,7); - cpa(fetch(pc)); - pc++; -endinstr; - -instr(0xff,11); - push2(pc); - pc=56; -endinstr; - +/* Emulations of the Z80 CPU instruction set - part of xz80. + * Copyright (C) 1994 Ian Collier. + * + * 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 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define instr(opcode,cycles) case opcode: {tstates+=cycles +#define HLinstr(opcode,cycles,morecycles) \ + case opcode: {unsigned short addr; \ + tstates+=cycles; \ + if(ixoriy==0)addr=hl; \ + else tstates+=morecycles, \ + addr=(ixoriy==1?ix:iy)+ \ + (signed char)fetch(pc),\ + pc++ +#define endinstr }; break + +#define cy (f&1) + +#define xh (ixoriy==0?h:ixoriy==1?(ix>>8):(iy>>8)) +#define xl (ixoriy==0?l:ixoriy==1?(ix&0xff):(iy&0xff)) + +#define setxh(x) (ixoriy==0?(h=(x)):ixoriy==1?(ix=(ix&0xff)|((x)<<8)):\ + (iy=(iy&0xff)|((x)<<8))) +#define setxl(x) (ixoriy==0?(l=(x)):ixoriy==1?(ix=(ix&0xff00)|(x)):\ + (iy=(iy&0xff00)|(x))) + +#define inc(var) /* 8-bit increment */ ( var++,\ + f=(f&1)|(var&0xa8)|\ + ((!(var&15))<<4)|((!var)<<6)|\ + ((var==128)<<2)\ + ) +#define dec(var) /* 8-bit decrement */ ( f=(f&1)|((!(var&15))<<4)|2,\ + --var,\ + f|=(var&0xa8)|((var==127)<<2)|\ + ((!var)<<6)\ + ) +#define swap(x,y) {unsigned char t=x; x=y; y=t;} +#define addhl(hi,lo) /* 16-bit add */ if(!ixoriy){\ + unsigned short t;\ + l=t=l+(lo);\ + f=(f&0xc4)|(((t>>=8)+(h&0x0f)+((hi)&0x0f)>15)<<4);\ + h=t+=h+(hi);\ + f|=(h&0x28)|(t>>8);\ + }\ + else do{unsigned long t=(ixoriy==1?ix:iy);\ + f=(f&0xc4)|(((t&0xfff)+((hi<<8)|lo)>0xfff)<<4);\ + t+=(hi<<8)|lo;\ + if(ixoriy==1)ix=t; else iy=t;\ + f|=((t>>8)&0x28)|(t>>16);\ + } while(0) +#define adda(x,c) /* 8-bit add */ do{unsigned short y;\ + unsigned char z=(x);\ + y=a+z+(c);\ + f=(y&0xa8)|(y>>8)|(((a&0x0f)+(z&0x0f)+(c)>15)<<4)|\ + (((~a^z)&0x80&(y^a))>>5);\ + f|=(!(a=y))<<6;\ + } while(0) +#define suba(x,c) /* 8-bit subtract */ do{unsigned short y;\ + unsigned char z=(x);\ + y=(a-z-(c))&0x1ff;\ + f=(y&0xa8)|(y>>8)|(((a&0x0f)<(z&0x0f)+(c))<<4)|\ + (((a^z)&0x80&(y^a))>>5)|2;\ + f|=(!(a=y))<<6;\ + } while(0) +#define cpa(x) /* 8-bit compare */ do{unsigned short y;\ + unsigned char z=(x);\ + y=(a-z)&0x1ff;\ + f=(y&0xa8)|(y>>8)|(((a&0x0f)<(z&0x0f))<<4)|\ + (((a^z)&0x80&(y^a))>>5)|2|((!y)<<6);\ + } while(0) +#define anda(x) /* logical and */ do{\ + a&=(x);\ + f=(a&0xa8)|((!a)<<6)|0x10|parity(a);\ + } while(0) +#define xora(x) /* logical xor */ do{\ + a^=(x);\ + f=(a&0xa8)|((!a)<<6)|parity(a);\ + } while(0) +#define ora(x) /* logical or */ do{\ + a|=(x);\ + f=(a&0xa8)|((!a)<<6)|parity(a);\ + } while(0) + +#define jr /* execute relative jump */ do{int j=(signed char)fetch(pc);\ + pc+=j+1;\ + tstates+=5;\ + } while(0) +#define jp /* execute jump */ (pc=fetch2(pc)) +#define call /* execute call */ do{\ + tstates+=7;\ + push2(pc+2);\ + jp;\ + } while(0) +#define ret /* execute return */ do{\ + tstates+=6;\ + pop2(pc);\ + } while(0) +#define pop2(var) /* pop 16-bit register */ (var=fetch2(sp),sp+=2) +#define pop1(v1,v2) /* pop register pair */ (v2=fetch(sp),\ + v1=fetch(sp+1),sp+=2) +#define push2(val) /* push 16-bit register */ do{sp-=2;store2(sp,(val));}\ + while(0) +#define push1(v1,v2) /* push register pair */ do{sp-=2;\ + store2b(sp,v1,v2);\ + }while(0) + +instr(0,4); + /* nop */ +endinstr; + +instr(1,10); + c=fetch(pc),pc++; + b=fetch(pc),pc++; +endinstr; + +instr(2,7); + store(bc,a); +endinstr; + +instr(3,6); + if(!++c)b++; +endinstr; + +instr(4,4); + inc(b); +endinstr; + +instr(5,4); + dec(b); +endinstr; + +instr(6,7); + b=fetch(pc),pc++; +endinstr; + +instr(7,4); + a=(a<<1)|(a>>7); + f=(f&0xc4)|(a&0x29); +endinstr; + +instr(8,4); + swap(a,a1); + swap(f,f1); +endinstr; + +instr(9,11); + addhl(b,c); +endinstr; + +instr(10,7); + a=fetch(bc); +endinstr; + +instr(11,6); + if(!c--)b--; +endinstr; + +instr(12,4); + inc(c); +endinstr; + +instr(13,4); + dec(c); +endinstr; + +instr(14,7); + c=fetch(pc),pc++; +endinstr; + +instr(15,4); + f=(f&0xc4)|(a&1); + a=(a>>1)|(a<<7); + f|=a&0x28; +endinstr; + +instr(16,8); + if(!--b)pc++; + else jr; +endinstr; + +instr(17,10); + e=fetch(pc),pc++; + d=fetch(pc),pc++; +endinstr; + +instr(18,7); + store(de,a); +endinstr; + +instr(19,6); + if(!++e)d++; +endinstr; + +instr(20,4); + inc(d); +endinstr; + +instr(21,4); + dec(d); +endinstr; + +instr(22,7); + d=fetch(pc),pc++; +endinstr; + +instr(23,4); + {int t=a>>7; + a=(a<<1)|(f&1); + f=(f&0xc4)|(a&0x28)|t; + } +endinstr; + +instr(24,7); + jr; +endinstr; + +instr(25,11); + addhl(d,e); +endinstr; + +instr(26,7); + a=fetch(de); +endinstr; + +instr(27,6); + if(!e--)d--; +endinstr; + +instr(28,4); + inc(e); +endinstr; + +instr(29,4); + dec(e); +endinstr; + +instr(30,7); + e=fetch(pc),pc++; +endinstr; + +instr(31,4); + {int t=a&1; + a=(a>>1)|(f<<7); + f=(f&0xc4)|(a&0x28)|t; + } +endinstr; + +instr(32,7); + if(f&0x40)pc++; + else jr; +endinstr; + +instr(33,10); + if(!ixoriy){ + l=fetch(pc),pc++; + h=fetch(pc),pc++; + } + else { + if(ixoriy==1)ix=fetch2(pc); + else iy=fetch2(pc); + pc+=2; + } +endinstr; + +instr(34,16); + {unsigned short addr=fetch2(pc); + pc+=2; + if(!ixoriy)store2b(addr,h,l); + else if(ixoriy==1)store2(addr,ix); + else store2(addr,iy); + } +endinstr; + +instr(35,6); + if(!ixoriy){if(!++l)h++;} + else if(ixoriy==1)ix++; + else iy++; +endinstr; + +instr(36,4); + if(ixoriy==0)inc(h); + else{unsigned char t; + t=(ixoriy==1?ix:iy)>>8; + inc(t); + if(ixoriy==1)ix=(ix&0xff)|(t<<8); + else iy=(iy&0xff)|(t<<8); + } +endinstr; + +instr(37,4); + if(ixoriy==0)dec(h); + else{unsigned char t; + t=(ixoriy==1?ix:iy)>>8; + dec(t); + if(ixoriy==1)ix=(ix&0xff)|(t<<8); + else iy=(iy&0xff)|(t<<8); + } +endinstr; + +instr(38,7); + setxh(fetch(pc)); + pc++; +endinstr; + +instr(39,4); + { + /* Frank D. Cringle's DAA implementation, converted from yaze 1.10 */ + unsigned int acu,temp,cbits; + + acu=a; + temp=(acu&15); + cbits=(f&1); + if(f&2) /* if N */ + { + /* last operation was a subtract */ + int hd=(cbits || (acu>0x99)); + if((f&16) || (temp>9)) + { /* adjust low digit */ + if(temp>5) f&=~16; + acu-=6; + acu&=0xff; + } + /* adjust high digit */ + if(hd) + acu-=0x160; + } + else + { + /* last operation was an add */ + if((f&16) || (temp>9)) + { + /* adjust low digit */ + if(temp>9) f|=16; else f&=~16; + acu+=6; + } + /* adjust high digit */ + if(cbits || ((acu&0x1f0)>0x90)) + acu+=0x60; + } + cbits|=((acu>>8)&1); + acu&=0xff; + a=acu; + f=((acu&0xa8)|((acu==0)<<6)|(f&0x12)|parity(a)|cbits); + } +endinstr; + +instr(40,7); + if(f&0x40)jr; + else pc++; +endinstr; + +instr(41,11); + if(!ixoriy)addhl(h,l); + else if(ixoriy==1)addhl((ix>>8),(ix&0xff)); + else addhl((iy>>8),(iy&0xff)); +endinstr; + +instr(42,16); + {unsigned short addr=fetch2(pc); + pc+=2; + if(!ixoriy){ + l=fetch(addr); + h=fetch(addr+1); + } + else if(ixoriy==1)ix=fetch2(addr); + else iy=fetch2(addr); + } +endinstr; + +instr(43,6); + if(!ixoriy){if(!l--)h--;} + else if(ixoriy==1)ix--; + else iy--; +endinstr; + +instr(44,4); + if(!ixoriy)inc(l); + else {unsigned char t; + t=(ixoriy==1?ix:iy); + inc(t); + if(ixoriy==1)ix=(ix&0xff00)|t; + else iy=(iy&0xff00)|t; + } +endinstr; + +instr(45,4); + if(!ixoriy)dec(l); + else {unsigned char t; + t=(ixoriy==1?ix:iy); + dec(t); + if(ixoriy==1)ix=(ix&0xff00)|t; + else iy=(iy&0xff00)|t; + } +endinstr; + +instr(46,7); + setxl(fetch(pc)); + pc++; +endinstr; + +instr(47,4); + a=~a; + f=(f&0xc5)|(a&0x28)|0x12; +endinstr; + +instr(48,7); + if(f&1)pc++; + else jr; +endinstr; + +instr(49,10); + sp=fetch2(pc); + pc+=2; +endinstr; + +instr(50,13); + {unsigned short addr=fetch2(pc); + pc+=2; + store(addr,a); + } +endinstr; + +instr(51,6); + sp++; +endinstr; + +HLinstr(52,11,8); + {unsigned char t=fetch(addr); + inc(t); + store(addr,t); + } +endinstr; + +HLinstr(53,11,8); + {unsigned char t=fetch(addr); + dec(t); + store(addr,t); + } +endinstr; + +HLinstr(54,10,5); + store(addr,fetch(pc)); + pc++; +endinstr; + +instr(55,4); + f=(f&0xc4)|1|(a&0x28); +endinstr; + +instr(56,7); + if(f&1)jr; + else pc++; +endinstr; + +instr(57,11); + addhl((sp>>8),(sp&0xff)); +endinstr; + +instr(58,13); + {unsigned short addr=fetch2(pc); + pc+=2; + a=fetch(addr); + } +endinstr; + +instr(59,6); + sp--; +endinstr; + +instr(60,4); + inc(a); +endinstr; + +instr(61,4); + dec(a); +endinstr; + +instr(62,7); + a=fetch(pc),pc++; +endinstr; + +instr(63,4); + f=(f&0xc4)|(cy^1)|(cy<<4)|(a&0x28); +endinstr; + +instr(0x40,4); + /* ld b,b */ +endinstr; + +instr(0x41,4); + b=c; +endinstr; + +instr(0x42,4); + b=d; +endinstr; + +instr(0x43,4); + b=e; +endinstr; + +instr(0x44,4); + b=xh; +endinstr; + +instr(0x45,4); + b=xl; +endinstr; + +HLinstr(0x46,7,8); + b=fetch(addr); +endinstr; + +instr(0x47,4); + b=a; +endinstr; + +instr(0x48,4); + c=b; +endinstr; + +instr(0x49,4); + /* ld c,c */ +endinstr; + +instr(0x4a,4); + c=d; +endinstr; + +instr(0x4b,4); + c=e; +endinstr; + +instr(0x4c,4); + c=xh; +endinstr; + +instr(0x4d,4); + c=xl; +endinstr; + +HLinstr(0x4e,7,8); + c=fetch(addr); +endinstr; + +instr(0x4f,4); + c=a; +endinstr; + +instr(0x50,4); + d=b; +endinstr; + +instr(0x51,4); + d=c; +endinstr; + +instr(0x52,4); + /* ld d,d */ +endinstr; + +instr(0x53,4); + d=e; +endinstr; + +instr(0x54,4); + d=xh; +endinstr; + +instr(0x55,4); + d=xl; +endinstr; + +HLinstr(0x56,7,8); + d=fetch(addr); +endinstr; + +instr(0x57,4); + d=a; +endinstr; + +instr(0x58,4); + e=b; +endinstr; + +instr(0x59,4); + e=c; +endinstr; + +instr(0x5a,4); + e=d; +endinstr; + +instr(0x5b,4); + /* ld e,e */ +endinstr; + +instr(0x5c,4); + e=xh; +endinstr; + +instr(0x5d,4); + e=xl; +endinstr; + +HLinstr(0x5e,7,8); + e=fetch(addr); +endinstr; + +instr(0x5f,4); + e=a; +endinstr; + +instr(0x60,4); + setxh(b); +endinstr; + +instr(0x61,4); + setxh(c); +endinstr; + +instr(0x62,4); + setxh(d); +endinstr; + +instr(0x63,4); + setxh(e); +endinstr; + +instr(0x64,4); + /* ld h,h */ +endinstr; + +instr(0x65,4); + setxh(xl); +endinstr; + +HLinstr(0x66,7,8); + h=fetch(addr); +endinstr; + +instr(0x67,4); + setxh(a); +endinstr; + +instr(0x68,4); + setxl(b); +endinstr; + +instr(0x69,4); + setxl(c); +endinstr; + +instr(0x6a,4); + setxl(d); +endinstr; + +instr(0x6b,4); + setxl(e); +endinstr; + +instr(0x6c,4); + setxl(xh); +endinstr; + +instr(0x6d,4); + /* ld l,l */ +endinstr; + +HLinstr(0x6e,7,8); + l=fetch(addr); +endinstr; + +instr(0x6f,4); + setxl(a); +endinstr; + +HLinstr(0x70,7,8); + store(addr,b); +endinstr; + +HLinstr(0x71,7,8); + store(addr,c); +endinstr; + +HLinstr(0x72,7,8); + store(addr,d); +endinstr; + +HLinstr(0x73,7,8); + store(addr,e); +endinstr; + +HLinstr(0x74,7,8); + store(addr,h); +endinstr; + +HLinstr(0x75,7,8); + store(addr,l); +endinstr; + +instr(0x76,4); + /* Was HALT - ZXCC ignores HALT */ +endinstr; + +HLinstr(0x77,7,8); + store(addr,a); +endinstr; + +instr(0x78,4); + a=b; +endinstr; + +instr(0x79,4); + a=c; +endinstr; + +instr(0x7a,4); + a=d; +endinstr; + +instr(0x7b,4); + a=e; +endinstr; + +instr(0x7c,4); + a=xh; +endinstr; + +instr(0x7d,4); + a=xl; +endinstr; + +HLinstr(0x7e,7,8); + a=fetch(addr); +endinstr; + +instr(0x7f,4); + /* ld a,a */ +endinstr; + +instr(0x80,4); + adda(b,0); +endinstr; + +instr(0x81,4); + adda(c,0); +endinstr; + +instr(0x82,4); + adda(d,0); +endinstr; + +instr(0x83,4); + adda(e,0); +endinstr; + +instr(0x84,4); + adda(xh,0); +endinstr; + +instr(0x85,4); + adda(xl,0); +endinstr; + +HLinstr(0x86,7,8); + adda(fetch(addr),0); +endinstr; + +instr(0x87,4); + adda(a,0); +endinstr; + +instr(0x88,4); + adda(b,cy); +endinstr; + +instr(0x89,4); + adda(c,cy); +endinstr; + +instr(0x8a,4); + adda(d,cy); +endinstr; + +instr(0x8b,4); + adda(e,cy); +endinstr; + +instr(0x8c,4); + adda(xh,cy); +endinstr; + +instr(0x8d,4); + adda(xl,cy); +endinstr; + +HLinstr(0x8e,7,8); + adda(fetch(addr),cy); +endinstr; + +instr(0x8f,4); + adda(a,cy); +endinstr; + +instr(0x90,4); + suba(b,0); +endinstr; + +instr(0x91,4); + suba(c,0); +endinstr; + +instr(0x92,4); + suba(d,0); +endinstr; + +instr(0x93,4); + suba(e,0); +endinstr; + +instr(0x94,4); + suba(xh,0); +endinstr; + +instr(0x95,4); + suba(xl,0); +endinstr; + +HLinstr(0x96,7,8); + suba(fetch(addr),0); +endinstr; + +instr(0x97,4); + suba(a,0); +endinstr; + +instr(0x98,4); + suba(b,cy); +endinstr; + +instr(0x99,4); + suba(c,cy); +endinstr; + +instr(0x9a,4); + suba(d,cy); +endinstr; + +instr(0x9b,4); + suba(e,cy); +endinstr; + +instr(0x9c,4); + suba(xh,cy); +endinstr; + +instr(0x9d,4); + suba(xl,cy); +endinstr; + +HLinstr(0x9e,7,8); + suba(fetch(addr),cy); +endinstr; + +instr(0x9f,4); + suba(a,cy); +endinstr; + +instr(0xa0,4); + anda(b); +endinstr; + +instr(0xa1,4); + anda(c); +endinstr; + +instr(0xa2,4); + anda(d); +endinstr; + +instr(0xa3,4); + anda(e); +endinstr; + +instr(0xa4,4); + anda(xh); +endinstr; + +instr(0xa5,4); + anda(xl); +endinstr; + +HLinstr(0xa6,7,8); + anda(fetch(addr)); +endinstr; + +instr(0xa7,4); + anda(a); +endinstr; + +instr(0xa8,4); + xora(b); +endinstr; + +instr(0xa9,4); + xora(c); +endinstr; + +instr(0xaa,4); + xora(d); +endinstr; + +instr(0xab,4); + xora(e); +endinstr; + +instr(0xac,4); + xora(xh); +endinstr; + +instr(0xad,4); + xora(xl); +endinstr; + +HLinstr(0xae,7,8); + xora(fetch(addr)); +endinstr; + +instr(0xaf,4); + xora(a); +endinstr; + +instr(0xb0,4); + ora(b); +endinstr; + +instr(0xb1,4); + ora(c); +endinstr; + +instr(0xb2,4); + ora(d); +endinstr; + +instr(0xb3,4); + ora(e); +endinstr; + +instr(0xb4,4); + ora(xh); +endinstr; + +instr(0xb5,4); + ora(xl); +endinstr; + +HLinstr(0xb6,7,8); + ora(fetch(addr)); +endinstr; + +instr(0xb7,4); + ora(a); +endinstr; + +instr(0xb8,4); + cpa(b); +endinstr; + +instr(0xb9,4); + cpa(c); +endinstr; + +instr(0xba,4); + cpa(d); +endinstr; + +instr(0xbb,4); + cpa(e); +endinstr; + +instr(0xbc,4); + cpa(xh); +endinstr; + +instr(0xbd,4); + cpa(xl); +endinstr; + +HLinstr(0xbe,7,8); + cpa(fetch(addr)); +endinstr; + +instr(0xbf,4); + cpa(a); +endinstr; + +instr(0xc0,5); + if(!(f&0x40))ret; +endinstr; + +instr(0xc1,10); + pop1(b,c); +endinstr; + +instr(0xc2,10); + if(!(f&0x40))jp; + else pc+=2; +endinstr; + +instr(0xc3,10); + jp; +endinstr; + +instr(0xc4,10); + if(!(f&0x40))call; + else pc+=2; +endinstr; + +instr(0xc5,11); + push1(b,c); +endinstr; + +instr(0xc6,7); + adda(fetch(pc),0); + pc++; +endinstr; + +instr(0xc7,11); + push2(pc); + pc=0; +endinstr; + +instr(0xc8,5); + if(f&0x40)ret; +endinstr; + +instr(0xc9,4); + ret; +endinstr; + +instr(0xca,10); + if(f&0x40)jp; + else pc+=2; +endinstr; + +instr(0xcb,4); +#include "cbops.h" +endinstr; + +instr(0xcc,10); + if(f&0x40)call; + else pc+=2; +endinstr; + +instr(0xcd,10); + call; +endinstr; + +instr(0xce,7); + adda(fetch(pc),cy); + pc++; +endinstr; + +instr(0xcf,11); + push2(pc); + pc=8; +endinstr; + +instr(0xd0,5); + if(!cy)ret; +endinstr; + +instr(0xd1,10); + pop1(d,e); +endinstr; + +instr(0xd2,10); + if(!cy)jp; + else pc+=2; +endinstr; + +instr(0xd3,11); + tstates+=out(tstates,a,fetch(pc),a); + pc++; +endinstr; + +instr(0xd4,10); + if(!cy)call; + else pc+=2; +endinstr; + +instr(0xd5,11); + push1(d,e); +endinstr; + +instr(0xd6,7); + suba(fetch(pc),0); + pc++; +endinstr; + +instr(0xd7,11); + push2(pc); + pc=16; +endinstr; + +instr(0xd8,5); + if(cy)ret; +endinstr; + +instr(0xd9,4); + swap(b,b1); + swap(c,c1); + swap(d,d1); + swap(e,e1); + swap(h,h1); + swap(l,l1); +endinstr; + +instr(0xda,10); + if(cy)jp; + else pc+=2; +endinstr; + +instr(0xdb,11); + {unsigned short t; + a=t=in(tstates,a,fetch(pc)); + tstates+=t>>8; + pc++; + } +endinstr; + +instr(0xdc,10); + if(cy)call; + else pc+=2; +endinstr; + +instr(0xdd,4); + new_ixoriy=1; + intsample=0; +endinstr; + +instr(0xde,7); + suba(fetch(pc),cy); + pc++; +endinstr; + +instr(0xdf,11); + push2(pc); + pc=24; +endinstr; + +instr(0xe0,5); + if(!(f&4))ret; +endinstr; + +instr(0xe1,10); + if(!ixoriy)pop1(h,l); + else if(ixoriy==1)pop2(ix); + else pop2(iy); +endinstr; + +instr(0xe2,10); + if(!(f&4))jp; + else pc+=2; +endinstr; + +instr(0xe3,19); + if(!ixoriy){ + unsigned short t=fetch2(sp); + store2b(sp,h,l); + l=t; + h=t>>8; + } + else if(ixoriy==1){ + unsigned short t=fetch2(sp); + store2(sp,ix); + ix=t; + } + else{ + unsigned short t=fetch2(sp); + store2(sp,iy); + iy=t; + } +endinstr; + +instr(0xe4,10); + if(!(f&4))call; + else pc+=2; +endinstr; + +instr(0xe5,11); + if(!ixoriy)push1(h,l); + else if(ixoriy==1)push2(ix); + else push2(iy); +endinstr; + +instr(0xe6,7); + anda(fetch(pc)); + pc++; +endinstr; + +instr(0xe7,11); + push2(pc); + pc=32; +endinstr; + +instr(0xe8,5); + if(f&4)ret; +endinstr; + +instr(0xe9,4); + pc=!ixoriy?hl:ixoriy==1?ix:iy; +endinstr; + +instr(0xea,10); + if(f&4)jp; + else pc+=2; +endinstr; + +instr(0xeb,4); + swap(h,d); + swap(e,l); +endinstr; + +instr(0xec,10); + if(f&4)call; + else pc+=2; +endinstr; + +instr(0xed,4); +#include"edops.h" +endinstr; + +instr(0xee,7); + xora(fetch(pc)); + pc++; +endinstr; + +instr(0xef,11); + push2(pc); + pc=40; +endinstr; + +instr(0xf0,5); + if(!(f&0x80))ret; +endinstr; + +instr(0xf1,10); + pop1(a,f); +endinstr; + +instr(0xf2,10); + if(!(f&0x80))jp; + else pc+=2; +endinstr; + +instr(0xf3,4); + iff1=iff2=0; + intsample=0; +endinstr; + +instr(0xf4,10); + if(!(f&0x80))call; + else pc+=2; +endinstr; + +instr(0xf5,11); + push1(a,f); +endinstr; + +instr(0xf6,7); + ora(fetch(pc)); + pc++; +endinstr; + +instr(0xf7,11); + push2(pc); + pc=48; +endinstr; + +instr(0xf8,5); + if(f&0x80)ret; +endinstr; + +instr(0xf9,6); + sp=!ixoriy?hl:ixoriy==1?ix:iy; +endinstr; + +instr(0xfa,10); + if(f&0x80)jp; + else pc+=2; +endinstr; + +instr(0xfb,4); + iff1=iff2=1; + intsample=0; +endinstr; + +instr(0xfc,10); + if(f&0x80)call; + else pc+=2; +endinstr; + +instr(0xfd,4); + new_ixoriy=2; + intsample=0; +endinstr; + +instr(0xfe,7); + cpa(fetch(pc)); + pc++; +endinstr; + +instr(0xff,11); + push2(pc); + pc=56; +endinstr; + diff --git a/Tools/unix/zx/zxbdos.c b/Tools/unix/zxcc/zxbdos.c similarity index 95% rename from Tools/unix/zx/zxbdos.c rename to Tools/unix/zxcc/zxbdos.c index 3c4dd931..811dcd6d 100644 --- a/Tools/unix/zx/zxbdos.c +++ b/Tools/unix/zxcc/zxbdos.c @@ -1,4 +1,4 @@ -#include "zx.h" +#include "zxcc.h" #define BDOS_DEF #include "zxbdos.h" @@ -12,11 +12,14 @@ #define BCD(x) (((x % 10)+16*(x/10)) & 0xFF) /* Convert time_t to CP/M day count/hours/minutes */ +/* there is a duplicate of this code in util.c. +* same modification applied here +*/ dword cpmtime(time_t t) { - long d = (t / 86400) - 2921; /* CP/M day 0 is unix day 2921 */ - long h = (t % 86400) / 3600; /* Hour, 0-23 */ - long m = (t % 3600) / 60; /* Minute, 0-59 */ + dword d = (dword)((t / 86400) - 2921); /* CP/M day 0 is unix day 2921 */ + dword h = (t % 86400) / 3600; /* Hour, 0-23 */ + dword m = (t % 3600) / 60; /* Minute, 0-59 */ return (d | (BCD(h) << 16) | (BCD(m) << 24)); } @@ -203,7 +206,7 @@ void cpmbdos(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f, /* For GENCOM's benefit, claim to be v3.1 */ *l = 0x31; /* v3.1 */ - //*l = 0x22; /* v2.2 */ + /* *l = 0x22; * v2.2 */ *h = 0; /* CP/M, no network */ break; @@ -237,9 +240,6 @@ void cpmbdos(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f, case 0x14: /* Sequential read using FCB */ setw(l, h, fcb_read(pde, pdma)); - - //Msg("fcb_read L=%02x H=%02x\n", *l, *h); - break; case 0x15: /* Sequential write using FCB */ @@ -470,14 +470,12 @@ void cpmbdos(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f, fprintf(stderr,"%s: Unsupported BDOS call %d\n", progname, (int)(*c)); dump_regs(stderr,*a,*b,*c,*d,*e,*f,*h,*l,*pc,*ix,*iy); - zx_exit(1); + zxcc_exit(1); break; } *a = *l; *b = *h; - - Msg("BDOS service completion.\n"); } @@ -492,7 +490,7 @@ void cpmbios(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f, switch(func) /* BIOS function */ { case 1: - zx_exit(zx_term()); /* Program termination */ + zxcc_exit(zxcc_term()); /* Program termination */ break; case 2: /* CONST */ @@ -540,8 +538,8 @@ void cpmbios(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f, printf("This program has attempted to call USERF, which " "is not implemented.\n"); #endif - zx_term(); - zx_exit(1); + zxcc_term(); + zxcc_exit(1); break; default: @@ -554,8 +552,6 @@ void cpmbios(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f, fprintf(stderr,"%s: Unsupported BIOS call %d\n", progname, func); dump_regs(stderr,*a,*b,*c,*d,*e,*f,*h,*l,*pc,*ix,*iy); - zx_exit(1); + zxcc_exit(1); } - - Msg("BIOS service completion.\n"); } diff --git a/Tools/unix/zx/zxbdos.h b/Tools/unix/zxcc/zxbdos.h similarity index 100% rename from Tools/unix/zx/zxbdos.h rename to Tools/unix/zxcc/zxbdos.h diff --git a/Tools/unix/zx/zxcbdos.c b/Tools/unix/zxcc/zxcbdos.c similarity index 77% rename from Tools/unix/zx/zxcbdos.c rename to Tools/unix/zxcc/zxcbdos.c index 355dd687..e3eb1f2f 100644 --- a/Tools/unix/zx/zxcbdos.c +++ b/Tools/unix/zxcc/zxcbdos.c @@ -1,10 +1,8 @@ -#include "zx.h" +#include "zxcc.h" #include "zxbdos.h" #include "zxcbdos.h" -#if !(defined(__MINGW32__) || defined(_MSC_BUILD) || defined(__WATCOMC__)) -#include -#endif -#ifdef WIN32 + +#ifdef _WIN32 #include #endif @@ -76,7 +74,6 @@ void bdos_rdline(word line, word *PC) #ifndef USE_CPMIO - int cpm_bdos_6(byte e) { int c; @@ -100,11 +97,10 @@ int cpm_bdos_6(byte e) } #endif -#if defined(__MINGW32__) || defined(_MSC_BUILD) || defined(__WATCOMC__) - +#ifdef _WIN32 byte cin() { - if (_isatty(_fileno(stdin))) + if (_isatty(STDIN_FILENO)) return getch(); else return getchar(); @@ -112,7 +108,7 @@ byte cin() void cout(byte c) { - if (_isatty(_fileno(stdout))) + if (_isatty(STDOUT_FILENO)) putch(c); else putchar(c); @@ -120,30 +116,34 @@ void cout(byte c) int cstat() { - if (_isatty(_fileno(stdin))) + if (_isatty(STDIN_FILENO)) return _kbhit() ? 0xFF : 0; else return 0xFF; } -#else /* defined(__MINGW32__) || defined(_MSC_BUILD) || defined(__WATCOMC__) */ +#else /* def _WIN32 */ byte cin() { - return getchar(); + char c = 0; + + read(STDIN_FILENO, &c, 1); + return c; } void cout(byte c) { - putchar(c); + write(STDOUT_FILENO, &c, 1); + return; } int cstat() { int i; - ioctl(_fileno(stdin), FIONREAD, &i); - if (i > 0) return 0xff; + ioctl(STDIN_FILENO, FIONREAD, &i); + if (i > 0) return 0xFF; return 0; } diff --git a/Tools/unix/zx/zxcbdos.h b/Tools/unix/zxcc/zxcbdos.h similarity index 100% rename from Tools/unix/zx/zxcbdos.h rename to Tools/unix/zxcc/zxcbdos.h diff --git a/Tools/unix/zx/zx.c b/Tools/unix/zxcc/zxcc.c similarity index 61% rename from Tools/unix/zx/zx.c rename to Tools/unix/zxcc/zxcc.c index 88b20cb3..9668243b 100644 --- a/Tools/unix/zx/zx.c +++ b/Tools/unix/zxcc/zxcc.c @@ -1,8 +1,4 @@ -#include "zx.h" - -#ifdef WIN32 -#include "windows.h" -#endif +#include "zxcc.h" /* Global variables */ @@ -11,16 +7,26 @@ char **argv; int argc; byte cpm_drive; -char *mypath; - byte cpm_user; extern byte cpm_error; +char bindir80[CPM_MAXPATH] = ""; +char libdir80[CPM_MAXPATH] = ""; +char incdir80[CPM_MAXPATH] = ""; + byte RAM[65536]; /* The Z80's address space */ void load_comfile(void); /* Forward declaration */ static int deinit_term, deinit_gsx; +static void mkpath(char* fullpath, char* path, char* subdir); + +#ifndef _WIN32 +struct termios tc_orig; + +void raw_init(void); +void deinit_raw(void); +#endif void dump_regs(FILE *fp, byte a, byte b, byte c, byte d, byte e, byte f, byte h, byte l, word pc, word ix, word iy) @@ -39,8 +45,10 @@ char *parse_to_fcb(char *s, int afcb) RAM[afcb] = 0; memset(fcb, ' ', 11); - while (*s == ' ') ++s; - + while (s[0]==' ') /* skip leading spaces */ + { + s++; + } while (1) { if (s[0] == 0) break; @@ -73,10 +81,9 @@ void Msg(char *s, ...) va_list ap; va_start(ap, s); - printf("%s trace: ", progname); - vprintf(s, ap); - fflush(stdout); - if (s[strlen(s) - 1] == '\n') putchar('\r'); + fprintf(stderr, "%s trace: ", progname); + vfprintf(stderr, s, ap); + fflush(stderr); va_end(ap); #endif } @@ -97,8 +104,8 @@ void ed_fe(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f, case 0xC2: fprintf(stderr,"%s: Incompatible BIOS.BIN\n", progname); - zx_term(); - zx_exit(1); + zxcc_term(); + zxcc_exit(1); case 0xC3: cpmbios(a,b,c,d,e,f,h,l,pc,ix,iy); @@ -107,8 +114,8 @@ void ed_fe(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f, default: fprintf(stderr, "%s: Z80 encountered invalid trap\n", progname); dump_regs(stderr,*a,*b,*c,*d,*e,*f,*h,*l,*pc,*ix,*iy); - zx_term(); - zx_exit(1); + zxcc_term(); + zxcc_exit(1); } } @@ -121,54 +128,52 @@ void ed_fe(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f, void load_bios(void) { - int bios_len; - - FILE * fp = NULL; - char biospath[CPM_MAXPATH + 1] = ""; + char dir[CPM_MAXPATH + 1], fname[CPM_MAXPATH + 1]; + char* q; + size_t bios_len; -#ifdef WIN32 + FILE* fp = fopen("bios.bin", "rb"); if (!fp) { - GetModuleFileName(NULL, biospath, sizeof(biospath)); - strcpy(strrchr(biospath, '\\'), "\\bios.bin"); - fp = fopen(biospath, "rb"); + strcpy(fname, bindir80); + strcat(fname, "bios.bin"); + fp = fopen(fname, "rb"); } + if (!fp) + { +#ifdef _WIN32 + dir[0] = 0; /* use strncat in case the path is very long */ + strncat(dir, _pgmptr, CPM_MAXPATH - 8); /* copy the executable path */ +#elif defined(__APPLE__) + uint32_t size = CPM_MAXPATH - 8; + _NSGetExecutablePath(dir, &size); #else - if (!fp) { - strcpy(biospath, mypath); - strcpy(strrchr(biospath, '/'), "/bios.bin"); - fp = fopen(biospath, "rb"); - } + readlink("/proc/self/exe", dir, CPM_MAXPATH - 8); /* allow room for bios.bin */ #endif - - if (!fp && BINDIR80) - { - strcpy(biospath, BINDIR80); - strcat(biospath, "bios.bin"); - fp = fopen(biospath, "rb"); + q = strrchr(dir, DIRSEPCH); + *++q = 0; + strcpy(fname, dir); + strcat(fname, "bios.bin"); + fp = fopen(fname, "rb"); } - - if (!fp) fp = fopen("bios.bin", "rb"); - if (!fp) { fprintf(stderr,"%s: Cannot locate bios.bin\n", progname); - zx_term(); - zx_exit(1); + zxcc_term(); + zxcc_exit(1); } bios_len = fread(RAM + 0xFE00, 1, 512, fp); if (bios_len < 1 || ferror(fp)) { fclose(fp); fprintf(stderr,"%s: Cannot load bios.bin\n", progname); - zx_term(); - zx_exit(1); + zxcc_term(); + zxcc_exit(1); } fclose(fp); Msg("Loaded %d bytes of BIOS\n", bios_len); } - /* * try_com() attempts to open file, file.com, file.COM, file.cpm and file.CPM * @@ -198,32 +203,33 @@ FILE *try_com(char *s) void load_comfile(void) { - int com_len; - char fname[CPM_MAXPATH + 1] = ""; + size_t com_len; + char fname[CPM_MAXPATH + 1]; FILE *fp; - if (BINDIR80) strcpy(fname, BINDIR80); - strcat(fname, argv[1]); + /* Look in current directory first */ + strcpy(fname, argv[1]); fp = try_com(fname); if (!fp) { - strcpy(fname, argv[1]); + strcpy(fname, bindir80); + strcat(fname, argv[1]); fp = try_com(fname); } if (!fp) { fprintf(stderr,"%s: Cannot locate %s, %s.com, %s.COM, %s.cpm _or_ %s.CPM\r\n", progname, argv[1], argv[1], argv[1], argv[1], argv[1]); - zx_term(); - zx_exit(1); + zxcc_term(); + zxcc_exit(1); } com_len = fread(RAM + 0x0100, 1, 0xFD00, fp); if (com_len < 1 || ferror(fp)) { fclose(fp); fprintf(stderr,"%s: Cannot load %s\n", progname, fname); - zx_term(); - zx_exit(1); + zxcc_term(); + zxcc_exit(1); } fclose(fp); @@ -245,7 +251,7 @@ unsigned int out() { return 0; } * the result to the command line. */ -void zx_xltname(char *name, char *pcmd) +void zxcc_xltname(char *name, char *pcmd) { char nbuf[CPM_MAXPATH + 1]; @@ -265,23 +271,31 @@ int main(int ac, char **av) { int n; char *pCmd, *str; + char* tmpenv; + argc = ac; argv = av; #ifdef __PACIFIC__ /* Pacific C doesn't support argv[0] */ - progname="ZX"; + progname="ZXCC"; #endif progname = argv[0]; - mypath = strdup(argv[0]); /* DJGPP includes the whole path in the program name, which looks * untidy... */ - str = strrchr(progname, '/'); - if (!str) str = strrchr(progname, '\\'); - if (str) progname = str + 1; + while ((str = strpbrk(progname, DIRSEP))) + progname = str + 1; + +#ifdef DEBUG + fprintf(stderr, "\n\n"); + Msg("Start of execution: "); + for (n = 0; n < argc; n++) + fprintf(stderr, " %s", argv[n]); + fprintf(stderr, "\n"); +#endif - if (_isatty(_fileno(stdin))) + if (_isatty(STDIN_FILENO)) Msg("Using interactive console mode\n"); else Msg("Using standard input/ouput mode\n"); @@ -290,18 +304,22 @@ int main(int ac, char **av) { fprintf(stderr,"%s: type lengths incorrect; edit typedefs " "and recompile.\n", progname); - zx_exit(1); + zxcc_exit(1); } if (argc < 2) { fprintf(stderr,"%s: No CP/M program name provided.\n",progname); - zx_exit(1); + zxcc_exit(1); } - - setmode(_fileno(stdin), O_BINARY ); - setmode(_fileno(stdout), O_BINARY ); +#ifdef _WIN32 + setmode(STDIN_FILENO, O_BINARY ); + setmode(STDOUT_FILENO, O_BINARY ); +#else + if (_isatty(STDIN_FILENO)) + raw_init(); +#endif /* Parse arguments. An argument can be either: @@ -319,12 +337,37 @@ int main(int ac, char **av) if (!fcb_init()) { fprintf(stderr, "Could not initialise CPMREDIR library\n"); - zx_exit(1); + zxcc_exit(1); } - xlt_map(0, BINDIR80); /* Establish the 3 fixed mappings */ - xlt_map(1, LIBDIR80); - xlt_map(2, INCDIR80); + /* allow environment variables to override default locations */ + /* two options are supported, explicit overrides for each directory + * (BINDIR80, LIBDIR80, INCDIR80) + * or a common directory prefix override (CPMDIR80) + * the explict override takes precedence + */ + if ((tmpenv = getenv("CPMDIR80"))) { + mkpath(bindir80, tmpenv, BIN80); /* use CPMDIR80 & std subdirs */ + mkpath(libdir80, tmpenv, LIB80); + mkpath(incdir80, tmpenv, INC80); + } + if ((tmpenv = getenv("BINDIR80"))) + mkpath(bindir80, tmpenv, ""); + + if ((tmpenv = getenv("LIBDIR80"))) + mkpath(libdir80, tmpenv, ""); + + if ((tmpenv = getenv("INCDIR80"))) + mkpath(incdir80, tmpenv, ""); + + Msg("BINDIR80=\"%s\"\n", bindir80); + Msg("LIBDIR80=\"%s\"\n", libdir80); + Msg("INCDIR80=\"%s\"\n", incdir80); + + xlt_map(0, bindir80); /* Establish the 3 fixed mappings */ + xlt_map(1, libdir80); + xlt_map(2, incdir80); + pCmd = (char *)RAM + 0x81; for (n = 2; n < argc; n++) @@ -342,17 +385,17 @@ int main(int ac, char **av) } else if (argv[n][0] == '+') { - zx_xltname(pCmd, argv[n]+1); + zxcc_xltname(pCmd, argv[n]+1); } else /* Translate a filename */ { strcat(pCmd, " "); - zx_xltname(pCmd, argv[n]); + zxcc_xltname(pCmd, argv[n]); } } pCmd[0x7F] = 0; /* Truncate to fit the buffer */ - RAM[0x80] = strlen(pCmd); + RAM[0x80] = (byte)strlen(pCmd); str = parse_to_fcb(pCmd, 0x5C); parse_to_fcb(str, 0x6C); @@ -401,10 +444,10 @@ int main(int ac, char **av) /* Start the Z80 at 0xFF00, with stack at 0xFE00 */ mainloop(0xFF00, 0xFE00); - return zx_term(); + return zxcc_term(); } -void zx_exit(int code) +void zxcc_exit(int code) { #ifdef USE_CPMIO if (deinit_term) cpm_scr_unit(); @@ -415,10 +458,13 @@ void zx_exit(int code) exit(code); } -int zx_term(void) +int zxcc_term(void) { word n; +#ifndef _WIN32 + deinit_raw(); +#endif //n = RAM[0x81]; /* Get the return code. This is Hi-Tech C */ //n = (n << 8) | RAM[0x80]; /* specific and fails with other COM files */ @@ -438,4 +484,69 @@ int zx_term(void) else return 0; } +/* helper function to build full path */ +/* make sure that a / or \ is present at the end of path + * before appending the subdir + */ +static void mkpath(char* fullpath, char* path, char* subdir) { + char* s; + strcpy(fullpath, path); + s = strchr(fullpath, '\0'); + if (*fullpath && !ISDIRSEP(s[-1])) /* make sure we have dir sep */ + *s++ = '/'; + strcpy(s, subdir); +} + +#ifndef _WIN32 +void raw_init(void) +{ + struct termios tc_raw; + + Msg("Enabling RAW Terminal IO\n"); + + if (tcgetattr(STDIN_FILENO, &tc_orig) == -1) + { + Msg("Failed to enable RAW Terminal IO - tcgetattr() failed\n"); + zxcc_exit(1);; + } + + //tc_raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + //tc_raw.c_oflag &= ~(OPOST); + //tc_raw.c_cflag |= (CS8); + //tc_raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); + //tc_raw.c_cc[VMIN] = 1; + //tc_raw.c_cc[VTIME] = 0; + + tc_raw.c_iflag &= ~(ICRNL | INPCK | ISTRIP | IXON); + tc_raw.c_oflag &= ~(OPOST); + tc_raw.c_cflag |= (CS8); + tc_raw.c_lflag &= ~(ECHO | ICANON | IEXTEN); + tc_raw.c_cc[VMIN] = 1; + tc_raw.c_cc[VTIME] = 0; + + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tc_raw) == -1) + { + Msg("Failed to enable RAW Terminal IO - tcsetattr() failed\n"); + zxcc_exit(1); + } + + Msg("Enabled RAW Terminal IO\n"); + + return; +} + +void deinit_raw(void) +{ + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tc_orig) == -1) + { + Msg("Failed to disable RAW Terminal IO - tcsetattr() failed\n"); + return; + } + + Msg("Disabled RAW Terminal IO\n"); + + return; +} + +#endif diff --git a/Tools/unix/zxcc/zxcc.doc b/Tools/unix/zxcc/zxcc.doc new file mode 100644 index 00000000..2f30a1ac --- /dev/null +++ b/Tools/unix/zxcc/zxcc.doc @@ -0,0 +1,207 @@ + zxcc v0.5.7 + + zxcc is a wrapper for the Hi-Tech C CP/M compiler, allowing it to be + used as a cross-compiler under UNIX. Version 0.5.0 also works with the + build tools necessary to assemble CP/M 3 (MAC, RMAC, LINK, GENCOM). + + New in this version: + * Compiles on boxes where sync() does not return int (reported by + multiple users). + * BDOS function 10 takes a pointer to unsigned char, thus allowing + input buffers longer than 128 bytes (Andy Parkins) + +Setting up + + Firstly, build the compiler. It should not be necessary to rebuild + bios.bin; but if you have to, it assembles using the z80asm assembler + (part of the z80pack emulation package which can be found on the Walnut + Creek CP/M CDROM) or the [1]ZMAC assembler (downloadable from + ). + + Previous versions of ZXCC could be compiled under DOS using DJGPP; this + may still be possible, but has not been tested since the build system + was changed to use the GNU autotools. + + This version of zxcc contains copies of the CPMIO and CPMREDIR + libraries, so you won't need to obtain them separately. + + You will need the tools you want to use; either the Hi-Tech C compiler + for CP/M <[2]http://www.hitech.com.au> or Digital Research's tools at + <[3]http://www.cpm.z80.de> Once you have obtained the tools, + documentation and possibly the library source, you need to decide where + to put the files. zxcc uses three directories: + * BINDIR80 (by default, /usr/local/lib/cpm/bin80) holds the compiler + itself. You should copy the compiler .com files (or MAC, RMAC etc.) + and bios.bin to this directory. + * LIBDIR80 (by default, /usr/local/lib/cpm/lib80) holds the C + libraries libc.lib, libf.lib, crtcpm.obj and rrtcpm.obj. + * INCDIR80 (by default, /usr/local/lib/cpm/include80) holds the + compiler .h files. + + The locations of these directories are normally set by the configure + script; you can override them by editing zxcc.h and uncommenting the + lines that redefine them. + + Once you have installed zxcc and the build tools, try building Hello + World: + + #include + void main() + { + printf("Hello World\n"); + } + + or for RMAC: + + CSEG + LXI D,HELLO + MVI C,9 + CALL 5 + RST 0 + HELLO: DB 'Hello World',13,10,'$' + + To compile the first example, type + + zxc hello.c + + ; if all goes well, you should end up with a file called hello.com. You + can test the resulting file by typing + + zxcc hello.com + + . + + To assemble the second example, type + + zxcc rmac.com hello + zxcc link.com hello + + and run it as above. NOTE: RMAC requires that lines be terminated with + CR/LF. You may need to put a unix2dos command in your makefile before + you invoke RMAC. + +Using zxcc + + For detailed instructions, see the documentation for Hi-Tech C or the + CP/M tools. zxcc behaves in the same way, but note the following + points: + + Program names + + The names of the programs have been changed between CP/M and UNIX; for + example, you would type + + zxc hello.c + + instead of + + c hello.c + + . The programs to use are: + + zxc + The equivalent of C.COM. + + zxas + The equivalent of ZAS.COM. + + zxlink + The equivalent of LINK.COM. + + zxlibr + The equivalent of LIBR.COM. + + All these programs work by converting their arguments to a form + suitable for zxcc, and then invoking zxcc. + + There are no front-end programs for the CP/M build tools; you will have + to enter arguments to these in the zxcc format given below. + + Filenames + + Where the documentation allows you to enter a CP/M filename, you should + instead enter a UNIX one. The filename itself (as opposed to any + directories in its path) must obey CP/M 8.3 naming conventions and be + all lowercase. + + Where the documentation requires a CP/M driveletter / user number + + -I2:C: + + you should enter a path complete with trailing slash: + + -I/usr/src/linux-80/include/ + +Technical + + zxcc emulates a subset of CP/M 3; hopefully enough to run the Hi-Tech C + compiler. It can be used as a limited general-purpose CP/M 3 emulator + provided the emulated program only uses a restricted subset of system + calls. + + zxcc behaves like the emulator com, allowing CP/M programs to be used + transparently from a UNIX prompt. However com: + * Emulates all of CP/M 2, rather than a subset of CP/M 3; + * Is designed for general use, not tailored to Hi-Tech C; + * Is written partly in assembly language and will only run on + 68000-based computers; + * Cannot map UNIX directories to CP/M drives; + * Contains some bugs connected with command parsing and file I/O. + + Syntax for zxcc is: + + zxcc comfile.com arg1 arg2 ... + + The comfile is the program to run; zxcc searches the current directory + and BINDIR80 for it. + + The arguments are parsed in this way: + * Any argument starting with a - sign is passed to the CP/M program + as-is, minus the leading - sign. + * Any argument starting with a + sign is parsed as a filename (see + below) and then concatenated to the previous argument. + * Any argument starting "+-" is concatenated without being parsed. + * All other arguments are parsed as filenames. The UNIX pathname is + converted to a CP/M driveletter. + + For example: + + zxcc foo.com --Q -A /dev/null --I +/dev/zero +-, +/foo/bar + + would pass these arguments to foo.com: + + -Q A d:null -Id:zero,e:bar + + The other programs are merely wrappers that convert their command lines + into the form required by zxcc. + +Errors + + Any errors raised by the zxcc runtime system will be prefixed with + zxcc:. Some errors you may encounter are: + + Unsupported BDOS call + Part of CP/M 3 that the program uses has not been emulated. Add + the required functionality to zxbdos.c and recompile. + + Z80 encountered invalid trap + The CP/M program being run attempted to call the zxcc runtime + system with an unknown call number. This will happen if the + program was written for my emulator "Joyce". + +Acknowledgements + + * Hi-Tech C was written by Hi-Tech Software. + * The Z80 emulation engine was written by Ian Collier. + * Thanks to Jacob Nevins, Andy Parkins and others for bug fix + suggestions. + __________________________________________________________________ + + + John Elliott, 28 March 2003 + +References + + 1. http://www.nenie.org/cpcip/index.html#zmac + 2. http://www.hitech.com.au/ + 3. http://www.cpm.z80.de/ diff --git a/Tools/unix/zx/zx.h b/Tools/unix/zxcc/zxcc.h similarity index 51% rename from Tools/unix/zx/zx.h rename to Tools/unix/zxcc/zxcc.h index dac69ce0..4d08949a 100644 --- a/Tools/unix/zx/zx.h +++ b/Tools/unix/zxcc/zxcc.h @@ -1,23 +1,44 @@ /* * Change the directories in these #defines if necessary. Note trailing slash. */ +#ifndef _WIN32 + #include "config.h" + #define ISDIRSEP(c) ((c) == '/') + #define DIRSEPCH '/' + #define DIRSEP "/" +#else + #include "config.h" + #define ISDIRSEP(c) ((c) == '/' || (c) == '\\') + #define DIRSEPCH '\\' + #define DIRSEP "/\\:" +#endif + +#ifndef CPMDIR80 + #ifdef _WIN32 + #define CPMDIR80 "d:/local/lib/cpm/" + #else + #define CPMDIR80 "/usr/local/lib/cpm/" + #endif +#endif -#include "config.h" +/* the default sub directories trailing / is required */ +#define BIN80 "bin80/" +#define LIB80 "lib80/" +#define INC80 "include80/" -#ifdef __MSDOS__ - #define BINDIR80 "d:/tools/cpm/bin80/" - #define LIBDIR80 "d:/tools/cpm/lib80/" - #define INCDIR80 "d:/tools/cpm/include/" -#else -/* Unless overridden, these are defined by autoconf. Note trailing slash. - #undef BINDIR80 - #undef LIBDIR80 - #undef INCDIR80 - #define BINDIR80 "/usr/local/lib/cpm/bin80/" - #define LIBDIR80 "/usr/local/lib/cpm/lib80/" - #define INCDIR80 "/usr/local/lib/cpm/include80/" -*/ +#ifndef BINDIR80 + #define BINDIR80 CPMDIR80 BIN80 +#endif +#ifndef LIBDIR80 + #define LIBDIR80 CPMDIR80 LIB80 #endif +#ifndef INCDIR80 + #define INCDIR80 CPMDIR80 INC80 +#endif + +extern char bindir80[]; +extern char libdir80[]; +extern char incdir80[]; #define SERIAL "ZXCC05" @@ -31,30 +52,42 @@ #include #include #include -#if defined(LINUX) || defined(DARWIN) -#include -#define _isatty(a) isatty(a) -#define _fileno(a) fileno(a) -#define setmode(a,b) -#define O_BINARY 0 +#ifdef HAVE_UNISTD_H + #include #endif -#ifdef WIN32 -#include +#ifdef _WIN32 + #include + #include + #define strcasecmp _stricmp + #ifndef STDIN_FILENO + #define STDIN_FILENO _fileno(stdin) + #define STDOUT_FILENO _fileno(stdout) + #define STDERR_FILENO _fileno(stderr) + #endif +#else + #include + #define _isatty(a) isatty(a) + #define _fileno(a) fileno(a) #endif #include #include #ifdef __MSDOS -#include + #include +#endif +#ifndef _WIN32 + #include + #include + #define _S_IFDIR S_IFDIR #endif /* Library includes */ #ifdef USE_CPMIO -#include "cpmio.h" + #include "cpmio.h" #endif #ifdef USE_CPMGSX -#include "cpmgsx.h" + #include "cpmgsx.h" #endif #include "cpmredir.h" /* BDOS disc simulation */ @@ -73,8 +106,8 @@ void cpmbios(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f, void dump_regs(FILE *fp, byte a, byte b, byte c, byte d, byte e, byte f, byte h, byte l, word pc, word ix, word iy); void Msg(char *s, ...); -int zx_term(void); -void zx_exit(int code); +int zxcc_term(void); +void zxcc_exit(int code); byte cin(void); void cout(byte); @@ -87,8 +120,6 @@ extern char **argv; extern int argc; extern byte RAM[65536]; /* The Z80's address space */ -extern int usestdio; - /* Z80 CPU emulation */ #include "z80.h" diff --git a/Tools/unix/zxcc/zxcc.html b/Tools/unix/zxcc/zxcc.html new file mode 100644 index 00000000..502d8777 --- /dev/null +++ b/Tools/unix/zxcc/zxcc.html @@ -0,0 +1,200 @@ +zxcc v0.5.7 + +

zxcc v0.5.7

+ +

zxcc is a wrapper for the Hi-Tech C CP/M compiler, allowing it to +be used as a cross-compiler under UNIX. Version 0.5.0 also works with the build +tools necessary to assemble CP/M 3 (MAC, RMAC, LINK, GENCOM). + +

New in this version: +

    +
  • Compiles on boxes where sync() does not return int (reported by multiple +users). +
  • BDOS function 10 takes a pointer to unsigned char, thus allowing input +buffers longer than 128 bytes (Andy Parkins) +
+ +

Setting up

+ +

Firstly, build the compiler. It should not be necessary to rebuild bios.bin; +but if you have to, it assembles using the z80asm assembler (part of +the z80pack emulation package which can be found on the Walnut Creek +CP/M CDROM) or the +ZMAC assembler +(downloadable from <http://www.nenie.org/cpcip/index.html#zmac>). +

Previous versions of ZXCC could be compiled under DOS using +DJGPP; this may still be possible, but has not been tested since the build +system was changed to use the GNU autotools. + +

This version of zxcc contains copies of the CPMIO and CPMREDIR libraries, +so you won't need to obtain them separately. + +

You will need the tools you want to use; either the Hi-Tech C compiler for +CP/M <http://www.hitech.com.au> + +or Digital Research's tools at + +<http://www.cpm.z80.de> + +Once you have obtained the tools, documentation and possibly the library +source, you need to decide where to put the files. zxcc uses +three directories: + +

    +
  • BINDIR80 (by default, /usr/local/lib/cpm/bin80) + holds the compiler itself. You should copy the compiler .com files + (or MAC, RMAC etc.) and bios.bin to this directory. +
  • LIBDIR80 (by default, /usr/local/lib/cpm/lib80) + holds the C libraries libc.lib, libf.lib, crtcpm.obj and rrtcpm.obj. +
  • INCDIR80 (by default, /usr/local/lib/cpm/include80) + holds the compiler .h files. +
+ +

The locations of these directories are normally set by the configure +script; you can override them by editing zxcc.h and uncommenting the lines +that redefine them. + +

Once you have installed zxcc and the build tools, try +building Hello World: + +

+#include <stdio.h>
+void main()
+{
+ printf("Hello World\n");
+}
+
+ +or for RMAC: + +
+ CSEG
+
+ LXI D,HELLO
+ MVI C,9
+ CALL 5
+ RST 0
+
+HELLO: DB 'Hello World',13,10,'$' + +
+ +

To compile the first example, type

zxc hello.c
; if +all goes well, you should end up with a file called hello.com. You can +test the resulting file by typing
zxcc hello.com
. + +

To assemble the second example, type +

+ zxcc rmac.com hello
+ zxcc link.com hello +
+and run it as above. NOTE: RMAC requires that lines be terminated with CR/LF. +You may need to put a unix2dos command in your makefile before you invoke RMAC. + +

Using zxcc

+ +

For detailed instructions, see the documentation for Hi-Tech C or +the CP/M tools. zxcc behaves in the same way, but note the +following points: + +

Program names

+ +

The names of the programs have been changed between CP/M and UNIX; for +example, you would type

zxc hello.c
instead of +
c hello.c
. The programs to use are: + +
+
zxc
The equivalent of C.COM. +
zxas
The equivalent of ZAS.COM. +
zxlink
The equivalent of LINK.COM. +
zxlibr
The equivalent of LIBR.COM. +
+ +

All these programs work by converting their arguments to a form suitable +for zxcc, and then invoking zxcc. + +

There are no front-end programs for the CP/M build tools; you will have to +enter arguments to these in the zxcc format given below. + +

Filenames

+ +

Where the documentation allows you to enter a CP/M filename, you should +instead enter a UNIX one. The filename itself (as opposed to any directories in +its path) must obey CP/M 8.3 naming conventions and be all lowercase. +

Where the documentation requires a CP/M driveletter / user number +

-I2:C:
you should enter a path complete with + trailing slash:
-I/usr/src/linux-80/include/
+ +

Technical

+ +

zxcc emulates a subset of CP/M 3; hopefully enough to run the +Hi-Tech C compiler. It can be used as a limited general-purpose CP/M 3 +emulator provided the emulated program only uses a restricted subset of +system calls. +

zxcc behaves like the emulator com, allowing CP/M +programs to be used transparently from a UNIX prompt. However com: +

    +
  • Emulates all of CP/M 2, rather than a subset of CP/M 3; +
  • Is designed for general use, not tailored to Hi-Tech C; +
  • Is written partly in assembly language and will only run on 68000-based +computers; +
  • Cannot map UNIX directories to CP/M drives; +
  • Contains some bugs connected with command parsing and file I/O. +
+ +

Syntax for zxcc is: + +

+ zxcc comfile.com arg1 arg2 ... +
+ +

The comfile is the program to run; zxcc searches the current +directory and BINDIR80 for it. +

The arguments are parsed in this way: + +

    +
  • Any argument starting with a - sign is passed to the CP/M program as-is, + minus the leading - sign. +
  • Any argument starting with a + sign is parsed as a filename (see below) + and then concatenated to the previous argument. +
  • Any argument starting "+-" is concatenated without being parsed. +
  • All other arguments are parsed as filenames. The UNIX pathname is + converted to a CP/M driveletter. +
+

For example: +

+ zxcc foo.com --Q -A /dev/null --I +/dev/zero +-, +/foo/bar +
+would pass these arguments to foo.com: +
+ -Q A d:null -Id:zero,e:bar +
+ +

The other programs are merely wrappers that convert their command lines +into the form required by zxcc. + +

Errors

+ +

Any errors raised by the zxcc runtime system will be prefixed +with zxcc:. Some errors you may encounter are: + +

+
Unsupported BDOS call +
Part of CP/M 3 that the program uses has not been emulated. Add the +required functionality to zxbdos.c and recompile. +
Z80 encountered invalid trap +
The CP/M program being run attempted to call the zxcc runtime +system with an unknown call number. This will happen if the program was +written for my emulator "Joyce". +
+

Acknowledgements

+ +
    +
  • Hi-Tech C was written by Hi-Tech Software. +
  • The Z80 emulation engine was written by Ian Collier. +
  • Thanks to Jacob Nevins, Andy Parkins and others for bug fix suggestions. +
+
+
John Elliott, 28 March 2003
+ + diff --git a/Tools/unix/zx/zxdbdos.c b/Tools/unix/zxcc/zxdbdos.c similarity index 64% rename from Tools/unix/zx/zxdbdos.c rename to Tools/unix/zxcc/zxdbdos.c index f5f21f3b..36cbe532 100644 --- a/Tools/unix/zx/zxdbdos.c +++ b/Tools/unix/zxcc/zxdbdos.c @@ -1,88 +1,97 @@ -#include "zx.h" -#include "zxbdos.h" -#include "zxdbdos.h" - -/* This file used to deal with all disc-based BDOS calls. - Now the calls have been moved into libcpmredir, it's a bit empty round - here. - - ZXCC does a few odd things when searching, to make Hi-Tech C behave - properly. -*/ - - -/* If a file could not be found on the default drive, try again on a "search" - drive (A: for .COM files, B: for .LIB and .OBJ files) */ - -int fcbforce(byte *fcb, byte *odrv) -{ - byte drive; - char typ[4]; - int n; - - for (n = 0; n < 3; n++) typ[n] = fcb[n+9] & 0x7F; - typ[3] = 0; - - Msg("fcbforce: typ=%s, fcb=%hhx\r\n", typ, *fcb); - - drive = 0; - if (*fcb) return 0; /* not using default drive */ - //if ((*fcb) != 16) return 0; /* not using default drive */ - if (!strcmpi(typ, "COM")) drive = 1; - if (!strcmpi(typ, "LIB")) drive = 2; - if (!strcmpi(typ, "OBJ")) drive = 2; - if (!strcmpi(typ, "H ")) drive = 3; - - Msg("fcbforce: drive=%i\r\n", drive); - - if (!drive) return 0; - - *odrv = *fcb; - *fcb = drive; - return 1; -} - -/* zxcc has a trick with some filenames: If it can't find them where they - should be, and a drive wasn't specified, it searches BINDIR80, - LIBDIR80 or INCDIR80 (depending on the type of the file). - */ - -word x_fcb_open(byte *fcb, byte *dma) -{ - word rv = fcb_open(fcb, dma); - byte odrv; - - Msg("x_fcb_open: rv=%X\r\n", rv); - - if (rv == 0xFF) - { - if (fcbforce(fcb, &odrv)) - { - rv = fcb_open(fcb, dma); - Msg("x_fcb_open: rv=%X\r\n", rv); - *fcb = odrv; - } - } - return rv; -} - - - -word x_fcb_stat(byte *fcb) -{ - word rv = fcb_stat(fcb); - byte odrv; - - if (rv == 0xFF) - { - if (fcbforce(fcb, &odrv)) - { - rv = fcb_stat(fcb); - *fcb = odrv; - } - } - return rv; -} - - - +#include "zxcc.h" +#include "zxbdos.h" +#include "zxdbdos.h" + +/* This file used to deal with all disc-based BDOS calls. + Now the calls have been moved into libcpmredir, it's a bit empty round + here. + + ZXCC does a few odd things when searching, to make Hi-Tech C behave + properly. +*/ + + +/* If a file could not be found on the default drive, try again on a "search" + drive (A: for .COM files, B: for .LIB and .OBJ files) */ + +int fcbforce(byte *fcb, byte *odrv) +{ + byte drive; + char nam[9]; + char typ[4]; + int n; + + for (n = 0; n < 8; n++) nam[n] = fcb[n+1] & 0x7F; + nam[8] = 0; + for (n = 0; n < 3; n++) typ[n] = fcb[n+9] & 0x7F; + typ[3] = 0; + + drive = 0; + if (*fcb) return 0; /* not using default drive */ + + /* Microsoft BASIC compiler run-time */ + if (!strcmp(nam,"BCLOAD ") && !strcmp(typ, " ")) drive = 2; + + /* HI-TECH C options help file */ + if (!strcmp(nam,"OPTIONS ") && !strcmp(typ, " ")) drive = 1; + + /* binaries, libraries and object files */ + if (!strcmp(typ, "COM")) drive = 1; + if (!strcmp(typ, "LIB")) drive = 2; + if (!strcmp(typ, "OBJ")) drive = 2; + + /* some extras for messages, overlays, includes */ + if (!strcmp(typ, "HLP")) drive = 1; + if (!strcmp(typ, "MSG")) drive = 1; + if (!strcmp(typ, "OVR")) drive = 1; + if (!strcmp(typ, "REL")) drive = 2; + if (!strcmp(typ, "H ")) drive = 3; + + if (!drive) return 0; + + *odrv = *fcb; + *fcb = drive; + return 1; +} + +/* zxcc has a trick with some filenames: If it can't find them where they + should be, and a drive wasn't specified, it searches BINDIR80, + LIBDIR80 or INCDIR80 (depending on the type of the file). + */ + +word x_fcb_open(byte *fcb, byte *dma) +{ + word rv = fcb_open(fcb, dma); + byte odrv; + + if (rv == 0xFF) + { + if (fcbforce(fcb, &odrv)) + { + rv = fcb_open(fcb, dma); + *fcb = odrv; + } + } + return rv; +} + + + +word x_fcb_stat(byte *fcb) +{ + word rv = fcb_stat(fcb); + byte odrv; + + if (rv == 0xFF) + { + if (fcbforce(fcb, &odrv)) + { + rv = fcb_stat(fcb); + *fcb = odrv; + } + } + return rv; +} + + + diff --git a/Tools/unix/zx/zxdbdos.h b/Tools/unix/zxcc/zxdbdos.h similarity index 100% rename from Tools/unix/zx/zxdbdos.h rename to Tools/unix/zxcc/zxdbdos.h diff --git a/Tools/zx/ReadMe.txt b/Tools/zx/ReadMe.txt deleted file mode 100644 index 90a7b1c3..00000000 --- a/Tools/zx/ReadMe.txt +++ /dev/null @@ -1,12 +0,0 @@ -ZX Command - -An adaptation of zxcc-0.5.6 by Wayne Warthen - -This is simply a stripped down variant of John Elliott's zxcc package that -runs under a Windows command line (32 or 64 bit Windows). It contains -only one command, "zx", which is generally equivalent to the original -zxcc command. - -Please see http://www.seasip.info/Unix/Zxcc/ for more information on zxcc. - -Refer to the zx.html document for usage information. diff --git a/Tools/zx/bios.bin b/Tools/zx/bios.bin deleted file mode 100644 index b20e62d9..00000000 Binary files a/Tools/zx/bios.bin and /dev/null differ diff --git a/Tools/zx/zx-src.zip b/Tools/zx/zx-src.zip deleted file mode 100644 index 7158ac73..00000000 Binary files a/Tools/zx/zx-src.zip and /dev/null differ diff --git a/Tools/zx/zx.exe b/Tools/zx/zx.exe deleted file mode 100644 index f33c7a19..00000000 Binary files a/Tools/zx/zx.exe and /dev/null differ diff --git a/Tools/zx/zx.html b/Tools/zx/zx.html deleted file mode 100644 index ff2da790..00000000 --- a/Tools/zx/zx.html +++ /dev/null @@ -1,132 +0,0 @@ -zx CP/M Command Line Emulator - -

zx CP/M Command Line Emulator

- -

zx allows execution of CP/M 2.2 and 3.X application from a -Windows command line. It is compatible with Windows XP and greater (both -32 and 64 bit).

- -

zx is basically a port of a subset of the zxcc program by John Elliott. -The GPLv2 licensing carries forward. Please refer to the - -zxcc web page for more information.

- -

While the original zxcc package was generally intended to allow -execution of the Hi-Tech C CP/M compiler under Unix, zx is slightly -more general and intended to allow running most CP/M tools. Specific -changes were incorporated to improve interactice console operation of -CP/M applications. Additionally, Curt Mayer added case insensitivity -for filenames under Unix variants.

- -

Setup

- -

The zx application (zx.exe) may be copied to any directory for execution. -The bios.bin file must be copied to the same directory. For ease of use, -you will probably want the directory to part of your PATH environment -variable so that you can run the tool from any location.

- -

You will also need the CP/M applications that you want to run. -zx will load files fromthe current directory or one of the following -directories based on file type. Any of the following environment -variables may be defined to determine where zx searches for the -respective file types:

- -
    -
  • ZXBINDIR may contain a single path which will -be searched for executable files (usually *.com)
  • -
  • ZXLIBDIR may contain a single path which will -be search for library files (usually *.lib)
  • -
  • ZXINCDIR may contain a single path which will -be searched for include files (usually *.inc)
  • -
- -

Usage

- -

In general CP/M applications are executed by prefixing the CP/M command -line with "zx". So for example, you could assemble a test.asm using -rmac with a command line like:

- -
zx rmac hello
- -

In this case, rmac.com would need to be in the directory specified by -environment variable ZXBINDIR or in the current directory. Also, -hello.asm would need to be in the current directory.

- -

Filenames

- -

Where you would normally enter a CP/M filename you instead enter -a Windows filename. Note that you will need to use a forward slash -instead of the traditional backslash as a directory separator. The -filename itself (as opposed to any directories in -its path) must obey CP/M 8.3 naming conventions.

- -

Where the documentation requires a CP/M drive letter/user number -you should enter a path complete with trailing slash, for example:

-
-I/usr/src/linux-80/include/
- -

Technical

- -

zx emulates a subset of CP/M 3; hopefully enough to run the -most CP/M tools. It can be used as a limited general-purpose CP/M 3 -emulator provided the emulated program only uses a common subset of -system calls.

- -

Syntax for zx is:

- -
-zx comfile.com arg1 arg2 ... -
- -

The comfile is the program to run; zx searches the current -directory and ZXBINDIR for it.

- -

The arguments are parsed in this way:

- -
    -
  • Any argument starting with a - sign is passed to the CP/M program as-is, -minus the leading - sign. -
  • Any argument starting with a + sign is parsed as a filename (see below) -and then concatenated to the previous argument. -
  • Any argument starting "+-" is concatenated without being parsed. -
  • All other arguments are parsed as filenames. The path is -converted to a CP/M driveletter. -
- -

For example: -

-zx foo.com --Q -A /src/main --I +/src/sub +-, +/foo/bar -
- -

would pass these arguments to foo.com:

- -
--Q A d:main -Id:sub,e:bar -
- -

The other programs are merely wrappers that convert their command lines -into the form required by zx.

- -

Errors

- -

Any errors raised by the zx runtime system will be prefixed -with zx:. Some errors you may encounter are:

- -
-
Unsupported BDOS call
-
Part of CP/M 3 that the program uses has not been emulated. Add the -required functionality to zxbdos.c and recompile.
-
Z80 encountered invalid trap
-
The CP/M program being run attempted to call the zx runtime -system with an unknown call number.
-
- -

Acknowledgements

- -
    -
  • zxcc was written by John Elliott
  • -
  • Hi-Tech C was written by Hi-Tech Software.
  • -
  • The Z80 emulation engine was written by Ian Collier.
  • -
  • Thanks to Jacob Nevins, Andy Parkins and others for bug fix suggestions.
  • -
- - diff --git a/Tools/zx/zxdbg.exe b/Tools/zx/zxdbg.exe deleted file mode 100644 index 598ace60..00000000 Binary files a/Tools/zx/zxdbg.exe and /dev/null differ diff --git a/Tools/zx/COPYING b/Tools/zxcc/COPYING similarity index 100% rename from Tools/zx/COPYING rename to Tools/zxcc/COPYING diff --git a/Tools/zxcc/ReadMe.txt b/Tools/zxcc/ReadMe.txt new file mode 100644 index 00000000..ba94bf5d --- /dev/null +++ b/Tools/zxcc/ReadMe.txt @@ -0,0 +1,86 @@ +This is an adaptation of zxcc-0.5.7 for RomWBW by Wayne Warthen. + +In general, this is a stripped down variant of John Elliott's zxcc package that +runs under a Windows command line (32 or 64 bit Windows), Linux, or MacOS. +This adaptation implements only the main "zxcc" command. The other programs +(zxc, zxas, zxlink, and zslibr) are not inluded here because they are fairly +specific to Hi-Tech C. + +Please see http://www.seasip.info/Unix/Zxcc/ for more information on the original +version of zxcc. Also, refer to https://github.com/agn453/ZXCC which has an +updated version of the code. + +The included zxcc.html documentation is from the original version, so it does not +reflect the changes made here. + +To build under Open Watcom, use Build-OW.cmd. To build under Microsoft Visual C, +use Build-VC.cmd. To build under Linux or MacOS, use the Makefile. + +The GPL status of everything remains in place and carries forward. + +December 5, 2014 + +After struggling to get the entire zxcc package to build nicely using autoconf, +I finally gave up and took a much more direct approach. I have extracted just +the source files needed and created a simple batch file to build the tool. I +realize this could be done much better, but I cheated in the interest of time. + +The one "real" change I made in the source code was that I modified the tool +to look for bios.bin in the same directory as the executable is in. This +just makes it much easier to set up (for me, anyway). + +Wayne Warthen +wwarthen@gmail.com + +March 15, 2017 + +- Updated to compile under Open Watcom. +- Implemented BDOS console status function. +- Set stdin and stdout to binary mode at startup. + +August 21, 2021 + +- Incorporated filename case insensitivity changes from Curt Mayer +- Incorporated fixes from Tony Nicholson at https://github.com/agn453/ZXCC + - Emulation of CP/M BDOS function 60 (call resident system extension) + should be disabled and return 0xFF in both the A and L registers. + - Change cpm_bdos_10() to return an unsigned result to avoid buffer + size being interpreted as negative. + - Fix the emulation of Z80 opcodes for IN (HL),(C) and + OUT (C),(HL) - opcodes 0xED,0x70 and 0xED,0x71 respectively. + This is noted in Fred Weigel's AM9511 arithmetic processing unit + emulation from https://github.com/ratboy666/am9511 in the howto.txt + description. NB: I have not included Fred's am9511 support at this + time into ZXCC. +- Fixed parse_to_fcb function in zxcc.c to handle parsing second automatic + FCB from command line + +Wayne Warthen +wwarthen@gmail.com + +--WBW 4:09 PM 8/21/2021 + +January 9, 2022 + +- Running zxcc under WSL (Windows Subsystem for Linux) was gererating output + that was correct but did not match standard Windows or Linux runs. This + turned out to be an assumption in a few places in the code that reading + into a buffer would not modify the area of the buffer that was beyond + the space required by the data being read. Under WSL, this "slack" space + was mangled. I made changes in these locations to clean up the slack + space after such reads. This fixed WSL runs to produce binary identical + output. Although only required by WSL, the changes cause no problems for + other environments and are actually correct per POSIX. + +--WBW 11:56 AM 1/9/2022 + +- I have attempted to sync my code up with the latest code found in Tony + Nicholson's GitHub repo at https://github.com/agn453/ZXCC. The most + significant difference in my code is that I am using the WIN32 API + for all disk I/O. Although the file tracking code is retained, I have + found this mechanism to fail insome scenarios. By using the WIN32 API + I can achieve the same file sharing attributes as Unix which makes the + file tracking mechanism optional. + +--WBW 9:34 AM 2/10/2022 + diff --git a/Tools/unix/zx/cpm/bios.bin b/Tools/zxcc/bios.bin similarity index 100% rename from Tools/unix/zx/cpm/bios.bin rename to Tools/zxcc/bios.bin diff --git a/Tools/zxcc/zxcc-src.zip b/Tools/zxcc/zxcc-src.zip new file mode 100644 index 00000000..16bedad5 Binary files /dev/null and b/Tools/zxcc/zxcc-src.zip differ diff --git a/Tools/zxcc/zxcc.exe b/Tools/zxcc/zxcc.exe new file mode 100644 index 00000000..54681729 Binary files /dev/null and b/Tools/zxcc/zxcc.exe differ diff --git a/Tools/zxcc/zxcc.html b/Tools/zxcc/zxcc.html new file mode 100644 index 00000000..502d8777 --- /dev/null +++ b/Tools/zxcc/zxcc.html @@ -0,0 +1,200 @@ +zxcc v0.5.7 + +

zxcc v0.5.7

+ +

zxcc is a wrapper for the Hi-Tech C CP/M compiler, allowing it to +be used as a cross-compiler under UNIX. Version 0.5.0 also works with the build +tools necessary to assemble CP/M 3 (MAC, RMAC, LINK, GENCOM). + +

New in this version: +

    +
  • Compiles on boxes where sync() does not return int (reported by multiple +users). +
  • BDOS function 10 takes a pointer to unsigned char, thus allowing input +buffers longer than 128 bytes (Andy Parkins) +
+ +

Setting up

+ +

Firstly, build the compiler. It should not be necessary to rebuild bios.bin; +but if you have to, it assembles using the z80asm assembler (part of +the z80pack emulation package which can be found on the Walnut Creek +CP/M CDROM) or the +ZMAC assembler +(downloadable from <http://www.nenie.org/cpcip/index.html#zmac>). +

Previous versions of ZXCC could be compiled under DOS using +DJGPP; this may still be possible, but has not been tested since the build +system was changed to use the GNU autotools. + +

This version of zxcc contains copies of the CPMIO and CPMREDIR libraries, +so you won't need to obtain them separately. + +

You will need the tools you want to use; either the Hi-Tech C compiler for +CP/M <http://www.hitech.com.au> + +or Digital Research's tools at + +<http://www.cpm.z80.de> + +Once you have obtained the tools, documentation and possibly the library +source, you need to decide where to put the files. zxcc uses +three directories: + +

    +
  • BINDIR80 (by default, /usr/local/lib/cpm/bin80) + holds the compiler itself. You should copy the compiler .com files + (or MAC, RMAC etc.) and bios.bin to this directory. +
  • LIBDIR80 (by default, /usr/local/lib/cpm/lib80) + holds the C libraries libc.lib, libf.lib, crtcpm.obj and rrtcpm.obj. +
  • INCDIR80 (by default, /usr/local/lib/cpm/include80) + holds the compiler .h files. +
+ +

The locations of these directories are normally set by the configure +script; you can override them by editing zxcc.h and uncommenting the lines +that redefine them. + +

Once you have installed zxcc and the build tools, try +building Hello World: + +

+#include <stdio.h>
+void main()
+{
+ printf("Hello World\n");
+}
+
+ +or for RMAC: + +
+ CSEG
+
+ LXI D,HELLO
+ MVI C,9
+ CALL 5
+ RST 0
+
+HELLO: DB 'Hello World',13,10,'$' + +
+ +

To compile the first example, type

zxc hello.c
; if +all goes well, you should end up with a file called hello.com. You can +test the resulting file by typing
zxcc hello.com
. + +

To assemble the second example, type +

+ zxcc rmac.com hello
+ zxcc link.com hello +
+and run it as above. NOTE: RMAC requires that lines be terminated with CR/LF. +You may need to put a unix2dos command in your makefile before you invoke RMAC. + +

Using zxcc

+ +

For detailed instructions, see the documentation for Hi-Tech C or +the CP/M tools. zxcc behaves in the same way, but note the +following points: + +

Program names

+ +

The names of the programs have been changed between CP/M and UNIX; for +example, you would type

zxc hello.c
instead of +
c hello.c
. The programs to use are: + +
+
zxc
The equivalent of C.COM. +
zxas
The equivalent of ZAS.COM. +
zxlink
The equivalent of LINK.COM. +
zxlibr
The equivalent of LIBR.COM. +
+ +

All these programs work by converting their arguments to a form suitable +for zxcc, and then invoking zxcc. + +

There are no front-end programs for the CP/M build tools; you will have to +enter arguments to these in the zxcc format given below. + +

Filenames

+ +

Where the documentation allows you to enter a CP/M filename, you should +instead enter a UNIX one. The filename itself (as opposed to any directories in +its path) must obey CP/M 8.3 naming conventions and be all lowercase. +

Where the documentation requires a CP/M driveletter / user number +

-I2:C:
you should enter a path complete with + trailing slash:
-I/usr/src/linux-80/include/
+ +

Technical

+ +

zxcc emulates a subset of CP/M 3; hopefully enough to run the +Hi-Tech C compiler. It can be used as a limited general-purpose CP/M 3 +emulator provided the emulated program only uses a restricted subset of +system calls. +

zxcc behaves like the emulator com, allowing CP/M +programs to be used transparently from a UNIX prompt. However com: +

    +
  • Emulates all of CP/M 2, rather than a subset of CP/M 3; +
  • Is designed for general use, not tailored to Hi-Tech C; +
  • Is written partly in assembly language and will only run on 68000-based +computers; +
  • Cannot map UNIX directories to CP/M drives; +
  • Contains some bugs connected with command parsing and file I/O. +
+ +

Syntax for zxcc is: + +

+ zxcc comfile.com arg1 arg2 ... +
+ +

The comfile is the program to run; zxcc searches the current +directory and BINDIR80 for it. +

The arguments are parsed in this way: + +

    +
  • Any argument starting with a - sign is passed to the CP/M program as-is, + minus the leading - sign. +
  • Any argument starting with a + sign is parsed as a filename (see below) + and then concatenated to the previous argument. +
  • Any argument starting "+-" is concatenated without being parsed. +
  • All other arguments are parsed as filenames. The UNIX pathname is + converted to a CP/M driveletter. +
+

For example: +

+ zxcc foo.com --Q -A /dev/null --I +/dev/zero +-, +/foo/bar +
+would pass these arguments to foo.com: +
+ -Q A d:null -Id:zero,e:bar +
+ +

The other programs are merely wrappers that convert their command lines +into the form required by zxcc. + +

Errors

+ +

Any errors raised by the zxcc runtime system will be prefixed +with zxcc:. Some errors you may encounter are: + +

+
Unsupported BDOS call +
Part of CP/M 3 that the program uses has not been emulated. Add the +required functionality to zxbdos.c and recompile. +
Z80 encountered invalid trap +
The CP/M program being run attempted to call the zxcc runtime +system with an unknown call number. This will happen if the program was +written for my emulator "Joyce". +
+

Acknowledgements

+ +
    +
  • Hi-Tech C was written by Hi-Tech Software. +
  • The Z80 emulation engine was written by Ian Collier. +
  • Thanks to Jacob Nevins, Andy Parkins and others for bug fix suggestions. +
+
+
John Elliott, 28 March 2003
+ + diff --git a/Tools/zxcc/zxccdbg.exe b/Tools/zxcc/zxccdbg.exe new file mode 100644 index 00000000..543aac00 Binary files /dev/null and b/Tools/zxcc/zxccdbg.exe differ