diff --git a/Binary/Apps/Makefile b/Binary/Apps/Makefile index 20ebfc63..0b913750 100644 --- a/Binary/Apps/Makefile +++ b/Binary/Apps/Makefile @@ -8,4 +8,4 @@ all:: mkdir -p Tunes clobber:: - @rm -f *.bin *.com *.img *.rom *.pdf *.log *.eeprom *.ovr *.hlp *.doc *.COM *.BIN Tunes/*.mym Tunes/*.pt? + @rm -f *.bin *.com *.img *.rom *.pdf *.log *.eeprom *.ovr *.hlp *.doc *.COM *.BIN Tunes/*.mym Tunes/*.pt? Tunes/*.vgm diff --git a/Doc/ChangeLog.txt b/Doc/ChangeLog.txt index 7a3861a1..2afffb6e 100644 --- a/Doc/ChangeLog.txt +++ b/Doc/ChangeLog.txt @@ -60,6 +60,8 @@ Version 3.1.1 - D?T: Substantial update to TastyBasic incuding a .COM executable - PMS: Added VGM audio file player - WBW: ZPMLDR and ZPM3 fixes, credit to Lars Nelson for finding ZPM3 source! +- DDW: Add support for MBC sound card +- WBW: Add support for "romless" booting Version 3.1 ----------- diff --git a/Doc/ROM Applications.pdf b/Doc/ROM Applications.pdf index bdf95a31..cabcf55c 100644 Binary files a/Doc/ROM Applications.pdf and b/Doc/ROM Applications.pdf differ diff --git a/Doc/RomWBW Applications.pdf b/Doc/RomWBW Applications.pdf index b1611059..2f03b23c 100644 Binary files a/Doc/RomWBW Applications.pdf and b/Doc/RomWBW Applications.pdf differ diff --git a/Doc/RomWBW Architecture.pdf b/Doc/RomWBW Architecture.pdf index 7e5baed7..56c5def4 100644 Binary files a/Doc/RomWBW Architecture.pdf and b/Doc/RomWBW Architecture.pdf differ diff --git a/Doc/RomWBW Disk Catalog.pdf b/Doc/RomWBW Disk Catalog.pdf index 93265d75..16622fc9 100644 Binary files a/Doc/RomWBW Disk Catalog.pdf and b/Doc/RomWBW Disk Catalog.pdf differ diff --git a/Doc/RomWBW Getting Started.pdf b/Doc/RomWBW Getting Started.pdf index ac015941..56aff8a3 100644 Binary files a/Doc/RomWBW Getting Started.pdf and b/Doc/RomWBW Getting Started.pdf differ diff --git a/ReadMe.md b/ReadMe.md index 897958ea..8f8bbc8e 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -1,50 +1,9 @@ ---- -author: "Wayne Warthen (mailto:wwarthen@gmail.com)" -classoption: -- oneside -colorlinks: true -date: 08 Dec 2021 -documentclass: book -fontfamily: helvet -fontsize: 12pt -geometry: -- top=1.5in -- bottom=1.5in -- left=1.5in -- right=1.5in -graphics: true -header-includes: -- -- -include-before: -- -- -institution: RetroBrew Computers Group -linestretch: 1.25 -numbersections: true -papersize: letter -secnumdepth: 1 -title: RomWBW Getting Started -toc: true -toc-depth: 1 ---- - - - - - - - - - - - # RomWBW ## Z80/Z180 System Software Version 3.1 Pre-release -08 Dec 2021 +21 Mar 2022 Wayne Warthen @@ -455,7 +414,7 @@ therefore, globally available. | TALK | Direct console I/O to a specified character device. | | RTC | Manage and test the Real Time Clock hardware. | | TIMER | Display value of running periodic system timer. | -| INTTEST | Test interrupt vector hooking. | +| CPUSPD | Change the running CPU speed and wait states of the system. | Some custom applications do not fit on the ROM disk. They are found on the disk image files or the individual files can be found in the @@ -465,6 +424,7 @@ Binary\\Apps directory of the distribution. |-------------|-------------------------------------------------------------| | TUNE | Play .PT2, .PT3, .MYM audio files. | | FAT | Access MS-DOS FAT filesystems from RomWBW (based on FatFs). | +| INTTEST | Test interrupt vector hooking. | Additional documentation on all of these applications can be found in “RomWBW Applications.pdf” in the Doc directory of the distribution. @@ -1100,7 +1060,7 @@ through the normal startup process just like it was started from ROM. However, your ROM has not been updated and the next time you boot your system, it will revert to the system image contained in ROM. -# Upgrading via Flash Utility +## Upgrading via Flash Utility If you do not have easy access to a ROM programmer, it is usually possible to reprogram your system ROM using the FLASH utility from Will @@ -1142,7 +1102,7 @@ To confirm your ROM chip has been successfully updated, restart your system and boot an operating system from ROM. Do not boot from a disk device yet. Review the boot messages to see if any issues have occurred. -# Upgrading via XModem Flash Updater +## Upgrading via XModem Flash Updater Similar to using the Flash utility, the system ROM can be updated or upgraded through the ROM based updater utility. This works by by @@ -1157,7 +1117,7 @@ file. More information can be found in the ROM Applications document. -# Post Update System Image and Application update process +## Post Upgrade System Image and Application Update Process Once you are satisfied that the ROM is working well, you will need to update the system images and RomWBW custom applications on your disk @@ -1226,21 +1186,20 @@ system on your disk. After this is done, you will need to use `SYSCOPY` to place the ZPM3 loader image on the boot tracks of all ZPM3 boot disks/slices. The - loader image is called `CPMLDR.SYS`. You must then copy (at a + loader image is called `ZPMLDR.SYS`. You must then copy (at a minimum) `CPM3.SYS`, `ZCCP.COM`, `ZINSTAL.ZPM`, and `STARTZPM.COM` onto the disk/slice. Assuming you copied the ZPM3 boot files onto your RAM disk at A:, you would use: - A>B:SYSCOPY C:=CPMLDR.SYS + A>B:SYSCOPY C:=ZPMLDR.SYS A>B:COPY CPM3.SYS C: A>B:COPY ZCCP.COM C: A>B:COPY ZINSTAL.ZPM C: A>B:COPY STARTZPM.COM C: - You may be wondering if the references to `CPMLDR.SYS` and - `CPM3.SYS` are typos. They are not. ZPM3 uses the same loader image - as CPM3. The ZPM3 main system code file is called `CPM3.SYS` which - is the same name as CP/M 3 uses, but the file contents are not the + You may be wondering if the reference to `CPM3.SYS` is a typo. It is + not. The ZPM3 main system code file is called `CPM3.SYS` which is + the same name as CP/M 3 uses, but the file contents are not the same. Finally, if you have copies of any of the RomWBW custom applications on @@ -1272,7 +1231,7 @@ images. - FAT.COM - TUNE.COM -# System Update +## System Update If the system running ROMWBW utilizes the SST39SF040 Flash chip then it is possible to do a System Update in place of a System Upgrade in some @@ -1298,9 +1257,9 @@ extension “.rom” and be 512Kb or 1024Kb in size. Transferring and flashing the System Update is accomplished in the same manner as described above in *Upgrading* with the required difference being that the flash application needs to be directed to complete a -partial flash using the /p command line switch. +partial flash using the /P command line switch. -`E>flash write rom.upd /p` +`E>FLASH WRITE ROM.UPD /P` # RomWBW Distribution @@ -1317,12 +1276,12 @@ set of directories. Each of these directories has it’s own ReadMe.txt file describing the contents in detail. In summary, these directories are: -| Application | Description | -|-------------|-----------------------------------------------------------------------------------------------------------------------------------------| -| Binary | The final output files of the build process are placed here. Most importantly, are the ROM images with the file names ending in “.rom”. | -| Doc | Contains various detailed documentation including the operating systems, RomWBW architecture, etc. | -| Source | Contains the source code files used to build the software and ROM images. | -| Tools | Contains the MS Windows programs that are used by the build process or that may be useful in setting up your system. | +| Application | Description | +|-------------|-------------------------------------------------------------------------------------------------------------------------------------| +| Binary | The final output files of the build process are placed here. Most importantly, the ROM images with the file names ending in “.rom”. | +| Doc | Contains various detailed documentation including the operating systems, RomWBW architecture, etc. | +| Source | Contains the source code files used to build the software and ROM images. | +| Tools | Contains the MS Windows programs that are used by the build process or that may be useful in setting up your system. | # Acknowledgments @@ -1343,10 +1302,11 @@ applications are no longer provided. driver. - Ed Brindley contributed some of the code that supports the RC2014 platform. -- Phil Summers contributed Forth and BASIC in ROM, the AY-3-8910 sound - driver as well as a long list of general code enhancements. +- Phil Summers contributed the Forth and BASIC adaptations in ROM, the + AY-3-8910 sound driver as well as a long list of general code + enhancements. - Phillip Stevens contributed support for FreeRTOS. -- Curt Mayer contributed the Linux / MacOS build process. +- Curt Mayer contributed the original Linux / MacOS build process. - UNA BIOS and FDISK80 are the products of John Coffman. - FLASH4 is a product of Will Sowerbutts. - CLRDIR is a product of Max Scane. @@ -1357,6 +1317,48 @@ applications are no longer provided. Contributions of all kinds to RomWBW are very welcome. +# Licensing + +RomWBW 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 3 of the License, or (at your +option) any later version. + +RomWBW 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 RomWBW. If not, see . + +Portions of RomWBW were created by, contributed by, or derived from the +work of others. It is believed that these works are being used in +accordance with the intentions and/or licensing of their creators. + +If anyone feels their work is being used outside of it’s intended +licensing, please notify: + +> Wayne Warthen +> wwarthen@gmail.com + +RomWBW is an aggregate work. It is composed of many individual, +standalone programs that are distributed as a whole to function as a +cohesive system. Each program may have it’s own licensing which may be +different from other programs within the aggregate. + +In some cases, a single program (e.g., CP/M Operating System) is +composed of multiple components with different licenses. It is believed +that in all such cases the licenses are compatible with GPL version 3. + +RomWBW encourages code contributions from others. Contributors may +assert their own copyright in their contributions by annotating the +contributed source code appropriately. Contributors are further +encouraged to submit their contributions via the RomWBW source code +control system to ensure their contributions are clearly documented. + +All contributions to RomWBW are subject to this license. + # Getting Assistance The best way to get assistance with RomWBW or any aspect of the diff --git a/ReadMe.txt b/ReadMe.txt index 2bc55874..70410157 100644 --- a/ReadMe.txt +++ b/ReadMe.txt @@ -1,6 +1,6 @@ RomWBW Getting Started Wayne Warthen (mailto:wwarthen@gmail.com) -08 Dec 2021 +21 Mar 2022 @@ -17,7 +17,7 @@ RomWBW Z80/Z180 System Software Version 3.1 Pre-release -08 Dec 2021 +21 Mar 2022 Wayne Warthen wwarthen@gmail.com @@ -460,7 +460,7 @@ therefore, globally available. TIMER Display value of running periodic system timer. - INTTEST Test interrupt vector hooking. + CPUSPD Change the running CPU speed and wait states of the system. ----------------------------------------------------------------------------- Some custom applications do not fit on the ROM disk. They are found on @@ -471,6 +471,7 @@ Binary\Apps directory of the distribution. ------------- ------------------------------------------------------------- TUNE Play .PT2, .PT3, .MYM audio files. FAT Access MS-DOS FAT filesystems from RomWBW (based on FatFs). + INTTEST Test interrupt vector hooking. Additional documentation on all of these applications can be found in “RomWBW Applications.pdf” in the Doc directory of the distribution. @@ -1154,7 +1155,7 @@ file. More information can be found in the ROM Applications document. -Post Update System Image and Application update process +Post Upgrade System Image and Application Update Process Once you are satisfied that the ROM is working well, you will need to update the system images and RomWBW custom applications on your disk @@ -1222,21 +1223,20 @@ system on your disk. After this is done, you will need to use SYSCOPY to place the ZPM3 loader image on the boot tracks of all ZPM3 boot disks/slices. The - loader image is called CPMLDR.SYS. You must then copy (at a minimum) + loader image is called ZPMLDR.SYS. You must then copy (at a minimum) CPM3.SYS, ZCCP.COM, ZINSTAL.ZPM, and STARTZPM.COM onto the disk/slice. Assuming you copied the ZPM3 boot files onto your RAM disk at A:, you would use: - A>B:SYSCOPY C:=CPMLDR.SYS + A>B:SYSCOPY C:=ZPMLDR.SYS A>B:COPY CPM3.SYS C: A>B:COPY ZCCP.COM C: A>B:COPY ZINSTAL.ZPM C: A>B:COPY STARTZPM.COM C: - You may be wondering if the references to CPMLDR.SYS and CPM3.SYS - are typos. They are not. ZPM3 uses the same loader image as CPM3. - The ZPM3 main system code file is called CPM3.SYS which is the same - name as CP/M 3 uses, but the file contents are not the same. + You may be wondering if the reference to CPM3.SYS is a typo. It is + not. The ZPM3 main system code file is called CPM3.SYS which is the + same name as CP/M 3 uses, but the file contents are not the same. Finally, if you have copies of any of the RomWBW custom applications on your hard disk, you need to update them with the latest copies. The @@ -1292,9 +1292,9 @@ extension “.rom” and be 512Kb or 1024Kb in size. Transferring and flashing the System Update is accomplished in the same manner as described above in Upgrading with the required difference being that the flash application needs to be directed to complete a -partial flash using the /p command line switch. +partial flash using the /P command line switch. -E>flash write rom.upd /p +E>FLASH WRITE ROM.UPD /P RomWBW Distribution @@ -1314,8 +1314,8 @@ are: Application Description ------------- ------------------------------------------------------------ Binary The final output files of the build process are placed here. - Most importantly, are the ROM images with the file names - ending in “.rom”. + Most importantly, the ROM images with the file names ending + in “.rom”. Doc Contains various detailed documentation including the operating systems, RomWBW architecture, etc. @@ -1346,10 +1346,11 @@ applications are no longer provided. driver. - Ed Brindley contributed some of the code that supports the RC2014 platform. -- Phil Summers contributed Forth and BASIC in ROM, the AY-3-8910 sound - driver as well as a long list of general code enhancements. +- Phil Summers contributed the Forth and BASIC adaptations in ROM, the + AY-3-8910 sound driver as well as a long list of general code + enhancements. - Phillip Stevens contributed support for FreeRTOS. -- Curt Mayer contributed the Linux / MacOS build process. +- Curt Mayer contributed the original Linux / MacOS build process. - UNA BIOS and FDISK80 are the products of John Coffman. - FLASH4 is a product of Will Sowerbutts. - CLRDIR is a product of Max Scane. @@ -1360,6 +1361,48 @@ applications are no longer provided. Contributions of all kinds to RomWBW are very welcome. +Licensing + +RomWBW 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 3 of the License, or (at your +option) any later version. + +RomWBW 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 RomWBW. If not, see https://www.gnu.org/licenses/. + +Portions of RomWBW were created by, contributed by, or derived from the +work of others. It is believed that these works are being used in +accordance with the intentions and/or licensing of their creators. + +If anyone feels their work is being used outside of it’s intended +licensing, please notify: + + Wayne Warthen + wwarthen@gmail.com + +RomWBW is an aggregate work. It is composed of many individual, +standalone programs that are distributed as a whole to function as a +cohesive system. Each program may have it’s own licensing which may be +different from other programs within the aggregate. + +In some cases, a single program (e.g., CP/M Operating System) is +composed of multiple components with different licenses. It is believed +that in all such cases the licenses are compatible with GPL version 3. + +RomWBW encourages code contributions from others. Contributors may +assert their own copyright in their contributions by annotating the +contributed source code appropriately. Contributors are further +encouraged to submit their contributions via the RomWBW source code +control system to ensure their contributions are clearly documented. + +All contributions to RomWBW are subject to this license. + Getting Assistance The best way to get assistance with RomWBW or any aspect of the diff --git a/Readme.unix b/Readme.unix index 62d6aca2..8814e28c 100644 --- a/Readme.unix +++ b/Readme.unix @@ -19,10 +19,14 @@ with respect to the .DS directive. it's usually a bad idea to mix It assumes that you have some standard system tools and libraries installed, specifically: gcc, gnu make, libncurses, and srecord. Typically, something like this will take care of adding all -required packages: +required packages in Linux: sudo apt install build-essential libncurses-dev srecord +For MacOS, you will need: + + brew install srecord + To build: cd to the top directory and type "make". @@ -40,16 +44,20 @@ the "SCZ180" platform: make ROM_PLATFORM=SCZ180 ROM_CONFIG=126 -Please be aware that the make-based build does have a couple of -deficiencies. +Please be aware that the make-based build does have a few deficiencies. + +First and most important, the Makefiles do not handle reruns very well. +To ensure a full buld, use "make clobber" from the top level directory +before running the actual build. For those used to using "make clean", +you can do that but it is not as thorough as "make clobber". -First, there are some build failures that will not stop the make -process. Some of this is because real CP/M 2.2 tools are used in +Second, there are some build failures that will not stop the make +process. Most of this is because real CP/M 2.2 tools are used in places and CP/M 2.2 does not allow programs to return a result code. -Second, not all dependencies are properly handled. So, changes to some +Third, not all dependencies are properly handled. So, changes to some files will not cause things to rebuild as appropriate. In general, I -recommend doing a "make clean" before running "make" to ensure that +recommend doing a "make clobber" before running "make" to ensure that everything is fully rebuilt. For macOS users, you may encounter a failure reading or writing files. diff --git a/Source/Apps/Build.cmd b/Source/Apps/Build.cmd index 0e27703a..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 @@ -35,6 +33,7 @@ pushd ZMP && call Build || exit /b & popd pushd ZMD && call Build || exit /b & popd pushd Dev && call Build || exit /b & popd pushd VGM && call Build || exit /b & popd +pushd cpuspd && call Build || exit /b & popd copy *.com %APPBIN%\ || exit /b diff --git a/Source/Apps/Clean.cmd b/Source/Apps/Clean.cmd index 0ee31190..198f461d 100644 --- a/Source/Apps/Clean.cmd +++ b/Source/Apps/Clean.cmd @@ -16,3 +16,4 @@ pushd ZMP && call Clean || exit /b 1 & popd pushd ZMD && call Clean || exit /b 1 & popd pushd Dev && call Clean || exit /b 1 & popd pushd VGM && call Clean || exit /b 1 & popd +pushd cpuspd && call Clean || exit /b 1 & popd diff --git a/Source/Apps/Makefile b/Source/Apps/Makefile index 51060be0..96d2411c 100644 --- a/Source/Apps/Makefile +++ b/Source/Apps/Makefile @@ -1,7 +1,7 @@ OBJECTS = sysgen.com survey.com \ syscopy.com assign.com format.com talk.com mode.com rtc.com \ timer.com rtchb.com -SUBDIRS = XM FDU FAT Tune Test ZMP ZMD Dev VGM +SUBDIRS = XM FDU FAT Tune Test ZMP ZMD Dev VGM cpuspd DEST = ../../Binary/Apps TOOLS =../../Tools diff --git a/Source/Apps/Test/2piotst/2piotst.mac b/Source/Apps/Test/2piotst/2piotst.mac new file mode 100644 index 00000000..027dcddf --- /dev/null +++ b/Source/Apps/Test/2piotst/2piotst.mac @@ -0,0 +1,567 @@ +; 24.9.2018 PMS (b1ackmai1er) +; Modified version for ECB-ZILOG PERIPHERALS BOARD - TEST 2 PIO's +; 01.11.2011 WKA +; Assembler M80 +; ECB-4PIO +; Testprogramm fr die I/O-Karte ECB-4PIO in Z80-Mnemonics + + PAGE 72 + .Z80 + ASEG + ORG 100H +; +;CP/M-ADDRESSES +;* * * * * * * +; +BOOT EQU 0 ;WARMBOOT CP/M +BDOS EQU 5 ;ENTRY BDOS +NMI EQU 66H ;Error-ROUTINE +; +;CONSOLE-CODES +;* * * * * * * +; +EOT EQU 4 ;END OF TEXT +BS EQU 8 ;BACKSPACE +TAB EQU 9 ;TABULATOR +LF EQU 0AH ;LINE-FEED +CR EQU 0DH ;CARRIAGE-RETURN +FF EQU 0CH ;FORM-FEED +ESC EQU 1BH ;ESCAPE +CTRLC EQU 'C'-40H ;CONTROL-C +CTRLW EQU 'W'-40H ;CONTROL-W +CTRLX EQU 'X'-40H ;CONTROL-X +CTRLY EQU 'Y'-40H ;CONTROL-Y +CTRLZ EQU 'Z'-40H ;CONTROL-Z +; +BASE EQU 0B8H ; 4 DIL-SCHALTER +; +PIO0AD EQU BASE+0 ; PIO 0 A DATEN +PIO0AC EQU BASE+2 ; PIO 0 A CONTROL +PIO0BD EQU BASE+1 ; PIO 0 B DATEN +PIO0BC EQU BASE+3 ; PIO 0 B CONTROL +; +PIO1AD EQU BASE+4 ; PIO 1 A DATEN +PIO1AC EQU BASE+6 ; PIO 1 A CONTROL +PIO1BD EQU BASE+5 ; PIO 1 B DATEN +PIO1BC EQU BASE+7 ; PIO 1 B CONTROL +; +MAIN: LD DE,PIO_SRTMSG + CALL PSTRIN +; + LD DE,INI_MSG + CALL PSTRIN + CALL INIT +; + LD DE,PIO0ADW ;PIO0 A + CALL PSTRIN + LD A,55H + PUSH AF + CALL OUTB + LD DE,LINE_E + CALL PSTRIN + POP AF + OUT (PIO0AD),A + IN A,(PIO0AD) + PUSH AF +; + LD DE,PIO0ADR + CALL PSTRIN + POP AF + CALL OUTB + LD DE,LINE_E + CALL PSTRIN +; + LD DE,PIO0ADW + CALL PSTRIN + LD A,0AAH + PUSH AF + CALL OUTB + LD DE,LINE_E + CALL PSTRIN + POP AF + OUT (PIO0AD),A + IN A,(PIO0AD) + PUSH AF +; + LD DE,PIO0ADR + CALL PSTRIN + POP AF + CALL OUTB + LD DE,LINE_E + CALL PSTRIN +; + LD DE,PIO0BDW ;PIO0 B + CALL PSTRIN + LD A,55H + PUSH AF + CALL OUTB + LD DE,LINE_E + CALL PSTRIN + POP AF + OUT (PIO0BD),A + IN A,(PIO0BD) + PUSH AF +; + LD DE,PIO0BDR + CALL PSTRIN + POP AF + CALL OUTB + LD DE,LINE_E + CALL PSTRIN +; + LD DE,PIO0BDW + CALL PSTRIN + LD A,0AAH + PUSH AF + CALL OUTB + LD DE,LINE_E + CALL PSTRIN + POP AF + OUT (PIO0BD),A + IN A,(PIO0BD) + PUSH AF +; + LD DE,PIO0BDR + CALL PSTRIN + POP AF + CALL OUTB + LD DE,LINE_E + CALL PSTRIN +; + LD DE,PIO1ADW ;PIO1 A + CALL PSTRIN + LD A,55H + PUSH AF + CALL OUTB + LD DE,LINE_E + CALL PSTRIN + POP AF + OUT (PIO1AD),A + IN A,(PIO1AD) + PUSH AF +; + LD DE,PIO1ADR + CALL PSTRIN + POP AF + CALL OUTB + LD DE,LINE_E + CALL PSTRIN +; + LD DE,PIO1ADW + CALL PSTRIN + LD A,0AAH + PUSH AF + CALL OUTB + LD DE,LINE_E + CALL PSTRIN + POP AF + OUT (PIO1AD),A + IN A,(PIO1AD) + PUSH AF +; + LD DE,PIO1ADR + CALL PSTRIN + POP AF + CALL OUTB + LD DE,LINE_E + CALL PSTRIN +; + LD DE,PIO1BDW ;PIO1 B + CALL PSTRIN + LD A,55H + PUSH AF + CALL OUTB + LD DE,LINE_E + CALL PSTRIN + POP AF + OUT (PIO1BD),A + IN A,(PIO1BD) + PUSH AF +; + LD DE,PIO1BDR + CALL PSTRIN + POP AF + CALL OUTB + LD DE,LINE_E + CALL PSTRIN +; + LD DE,PIO1BDW + CALL PSTRIN + LD A,0AAH + PUSH AF + CALL OUTB + LD DE,LINE_E + CALL PSTRIN + POP AF + OUT (PIO1BD),A + IN A,(PIO1BD) + PUSH AF +; + LD DE,PIO1BDR + CALL PSTRIN + POP AF + CALL OUTB + LD DE,LINE_E + CALL PSTRIN +; + LD DE,PIO_ENDMSG + CALL PSTRIN + JP BOOT +; +;========================================================================== +INIT: LD HL,PIO0T ; PIO0 INITITALISIEREN + CALL INITX + LD HL,PIO1T ; PIO1 INITITALISIEREN + CALL INITX + RET +; +INITX: LD A,(HL) ; BYTE-ANZAHL + OR A + RET Z + LD B,A ; Port-Adresse nach C + INC HL + LD C,(HL) + INC HL + OTIR + JR INITX +; +PIO0T: DEFB 05 ; 5 BYTE ZUM PIO 0 A CONTROL + DEFB PIO0AC + DEFB 00000011B ; DIS-INT + DEFB 01001111B ; BETR.ART BYTE EINGABE + DEFB 01001111B ; BETR.ART BYTE EINGABE + DEFB 11001111B ; BETR.ART BIT EIN/AUSG. + DEFB 00000000B ; ALLES AUSG. + DEFB 01 ; 1 BYTE ZUM PIO 0 A DATEN + DEFB PIO0AD + DEFB 00000000B ; DATEN "LOW" +; + DEFB 05 ; 5 BYTE ZUM PIO 0 B CONTROL + DEFB PIO0BC + DEFB 00000011B ; DIS-INT + DEFB 01001111B ; BETR.ART BYTE EINGABE + DEFB 01001111B ; BETR.ART BYTE EINGABE + DEFB 11001111B ; BETR.ART BIT EIN/AUSG. + DEFB 00000000B ; ALLES AUSG. + DEFB 01 ; 1 BYTE ZUM PIO 0 B DATEN + DEFB PIO0BD + DEFB 00000000B ; DATEN "LOW" + DEFB 0 ; ENDE PIO 0 B -TABELLE +; +PIO1T: DEFB 05 ; 5 BYTE ZUM PIO 1 A CONTROL + DEFB PIO1AC + DEFB 00000011B ; DIS-INT + DEFB 01001111B ; BETR.ART BYTE EINGABE + DEFB 01001111B ; BETR.ART BYTE EINGABE + DEFB 11001111B ; BETR.ART BIT EIN/AUSG. + DEFB 00000000B ; ALLES AUSG. + DEFB 01 ; 1 BYTE ZUM PIO 1 A DATEN + DEFB PIO1AD + DEFB 00000000B ; DATEN "LOW" +; + DEFB 05 ; 5 BYTE ZUM PIO 1 B CONTROL + DEFB PIO1BC + DEFB 00000011B ; DIS-INT + DEFB 01001111B ; BETR.ART BYTE EINGABE + DEFB 01001111B ; BETR.ART BYTE EINGABE + DEFB 11001111B ; BETR.ART BIT EIN/AUSG. + DEFB 00000000B ; ALLES AUSG. + DEFB 01 ; 1 BYTE ZUM PIO 1 B DATEN + DEFB PIO1BD + DEFB 00000000B ; DATEN "LOW" + DEFB 0 ; ENDE PIO 1 B -TABELLE +; +;========================================================================== +; +;Output on Screen +;**************** +; +PRBS: LD E,BS + CALL PCHAR + RET +; +;Output CR+LF on Screen +;********************** +; +CRLF: LD E,CR + CALL PCHAR + LD E,LF + CALL PCHAR + RET +; +;Output ASCII-Character +;********************** +; +PRINP: PUSH AF + LD E,A + CALL PCHAR + POP AF + RET; +; +;CALL BDOS with Register Save +;**************************** +; +INCHA: LD C,1 ;INPUT CHARACTER TO A + JR BDO +PCHAR: LD C,2 ;PRINT CHARACTER IN E + JR BDO +PSTRIN: LD C,9 ;PRINT STRING + JR BDO +INBUFF: LD C,10 ;READ CONSOLE-BUFFER + JR BDO +CSTS: LD C,11 ;CONSOLE-STATUS + JR BDO +OPEN: LD C,15 ;OPEN FILE + JR BDO +CLOSE: LD C,16 ;CLOSE FILE + JR BDO +DELETE: LD C,19 ;DELETE FILE + JR BDO +READS: LD C,20 ;READ SEEK + JR BDO +WRITES: LD C,21 ;WRITE SEEK + JR BDO +MAKE: LD C,22 ;MAKE FILE + JR BDO +SETDMA: LD C,26 ;SET DMA-ADDRESS +BDO: PUSH HL + PUSH DE + PUSH BC + PUSH IX + PUSH IY + CALL BDOS + POP IY + POP IX + POP BC + POP DE + POP HL + RET +; +;DIRECT CONSOLE INPUT +;******************** +; +INDCON: CALL INDCOX + CP 0 + JR Z,INDCON + RET +; +INDCOX: LD C,6 ;Code for Direct Console Input + LD E,0FFH ;Code for Input + PUSH HL + PUSH DE + PUSH BC + PUSH IX + PUSH IY + CALL BDOS + POP IY + POP IX + POP BC + POP DE + POP HL + RET +; +; +;Output WORD +;*********** +; +;PARAMETER: Entry WORD IN HL +;********* +; +OUTW: LD A,H + CALL OUTB + LD A,L + CALL OUTB + RET +; +;Output BYTE +;*********** +; +;PARAMETER: Entry BYTE IN A +;********* +; +OUTB: PUSH AF + RRCA + RRCA + RRCA + RRCA + AND 0FH + CALL HBTHE ;Change Half-BYTE + POP AF + AND 0FH + CALL HBTHE + RET +; +;Output HALF-BYTE +;**************** +; +;PARAMETER: Entry Half-BYTE IN A (BIT 0 - 3) +;********* +; +HBTHE: CP 0AH + JR C,HBTHE1 + ADD A,7 ;Character to Letter +HBTHE1: ADD A,30H + LD E,A + CALL PCHAR + RET +; +;Input ADDRESS +;************* +; +;PARAMETER: Exit with ADDRESS IN HL +;********* +; +INADR: LD HL,0 +INADR1: CALL INCHAR ;Input TETRADE + LD D,A + CALL INBYT1 ;IN HEXA + RET C ;END OF Input + ADD HL,HL + ADD HL,HL + ADD HL,HL + ADD HL,HL + OR L + LD L,A + JR INADR1 ;New Key +; +; +;Input BYTE +;********** +; +;PARAMTER: Exit with BYTE IN A +;******** +; +INBYT: CALL INADR + LD A,L + RET +; +;Input of one TETRADE to A (BIT 0-3) +;************************************ +; +INBYT1: SUB '0' + RET C + CP 'G'-30H + JR NC,INBYT3 ;Error + CP ':'-30H + JR C,INBYT2 + CP 'A'-30H + JR C,INBYT3 ;Error + SUB 7 +INBYT2: OR A + RET +; +INBYT3: SCF + RET +; +;Input ASCII-Character to A +;************************** +; +INCON: CALL INDCON ;Input ASCII-Character to A + CP CTRLC ;TEST CONTROL-C + JP Z,QUIT + CP CTRLX ;TEST CONTROL-X + JR Z,INCHA1 + CP CTRLW ;TEST CONTROL-W + JR Z,INCHA3 + CP CTRLY ;TEST CONTROL-Y + JR Z,INCHA2 + CP BS + RET Z + CP CR + RET Z + CP ' ' + JR C,INCON + JR INCH1 +; +INCHAR: CALL INCHA ;Input ASCII-Character to A + CP CTRLC ;TEST CONTROL-C + JR Z,QUIT + CP CTRLX ;TEST CONTROL-X + JR Z,INCHA1 + CP CTRLW ;TEST CONTROL-W + JR Z,INCHA3 + CP CTRLY ;TEST CONTROL-Y + JR Z,INCHA2 + CP BS + RET Z + CP CR + RET Z + CP ' ' + JR C,INCHAR ;Input invalied +; +INCH1: CP 'A' + RET C ;Character ok +; + RES 5,A ;lower case -> upper case + RET +INCHA1: POP HL + LD E,FF + CALL PCHAR ;Clear screen + JP GOON +INCHA2: POP HL + LD E,FF + CALL PCHAR ;Clear screen + JP GOON +INCHA3: LD E,FF + CALL PCHAR + RET +; +;ABBRUCH DER BEARBEITUNG +;*********************** +; +COMPLT: LD DE,TCOMP + CALL PSTRIN + JP GOON +QUIT: CALL CRLF + LD DE,TQUIT + JR FINIS +INTTIM: POP DE ;STACK OK +; CALL DESAK + LD DE,TNMIAB + CALL PSTRIN + LD DE,MAIN ;NEW ADDRESS + PUSH DE + RETN +FINIS: CALL PSTRIN ;AT BDOS-ERROR +GOON: + JP BOOT +; +; +;TEXT-Messages +;************* +; +TCOMP: DEFB ESC,21,0,14H,ESC,23,0 + DEFM 'Function complete !!$' +TQUIT: DEFB ESC,23,0,14H,7 + DEFM 'End Run RAMFTEST$' +TNMIAB: DEFB ESC,23,0,14H + DEFM 'Time Out !!$' +; +; +INI_MSG:DEFM 'ECB-4PIO Init all PIO Bit-Mode ',CR,LF,'$' +PIO0ADW:DEFM 'ECB-4PIO Write to PIO0AD ','$' +PIO0ADR:DEFM 'ECB-4PIO Read from PIO0AD ','$' +PIO0BDW:DEFM 'ECB-4PIO Write to PIO0BD ','$' +PIO0BDR:DEFM 'ECB-4PIO Read from PIO0BD ','$' +PIO1ADW:DEFM 'ECB-4PIO Write to PIO1AD ','$' +PIO1ADR:DEFM 'ECB-4PIO Read from PIO1AD ','$' +PIO1BDW:DEFM 'ECB-4PIO Write to PIO1BD ','$' +PIO1BDR:DEFM 'ECB-4PIO Read from PIO1BD ','$' + +PIO_SRTMSG: + DEFM 'ECB-ZILOG PERIPHERALS start test 1.0',CR,LF,'$' +PIO_ENDMSG: + DEFM 'ECB-ZILOG PERIPHERALS end test 1.0',CR,LF,'$' +LINE_E: DEFM 'H',CR,LF,'$' +; + IF1 + .PRINTX 'Pass 1 complete' + ENDIF +; + IF2 + .PRINTX 'Pass 2 complete' + .PRINTX 'Assembly complete' + ENDIF +; + END + diff --git a/Source/Apps/Test/2piotst/Build.cmd b/Source/Apps/Test/2piotst/Build.cmd new file mode 100644 index 00000000..8d719eab --- /dev/null +++ b/Source/Apps/Test/2piotst/Build.cmd @@ -0,0 +1,13 @@ +@echo off +setlocal + +set TOOLS=..\..\..\..\Tools + +set PATH=%TOOLS%\zxcc;%PATH% + +set CPMDIR80=%TOOLS%/cpm/ + +zxcc M80 -=2piotst/l || exit /b +zxcc L80 -2piotst,2piotst.com/n/e || exit /b + +copy /Y 2piotst.com ..\..\..\..\Binary\Apps\Test\ || exit /b diff --git a/Source/Apps/Test/2piotst/Clean.cmd b/Source/Apps/Test/2piotst/Clean.cmd new file mode 100644 index 00000000..a9c92a7d --- /dev/null +++ b/Source/Apps/Test/2piotst/Clean.cmd @@ -0,0 +1,8 @@ +@echo off +setlocal + +if exist *.com del *.com +if exist *.lst del *.lst +if exist *.bin del *.bin +if exist *.rel del *.rel +if exist *.prn del *.prn diff --git a/Source/Apps/Test/2piotst/Makefile b/Source/Apps/Test/2piotst/Makefile new file mode 100644 index 00000000..6dde1f3a --- /dev/null +++ b/Source/Apps/Test/2piotst/Makefile @@ -0,0 +1,8 @@ +OBJECTS = 2piotst.com +DEST = ../../../../Binary/Apps/Test +TOOLS =../../../../Tools +OTHERS = *.rel + +include $(TOOLS)/Makefile.inc + +2piotst.com : 2piotst.rel \ No newline at end of file diff --git a/Source/Apps/Test/Build.cmd b/Source/Apps/Test/Build.cmd index 139ea0c9..e68dee33 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 @@ -21,7 +19,9 @@ pushd I2C && call Build || exit /b & popd pushd rzsz && call Build || exit /b & popd pushd vdctest && call Build || exit /b & popd pushd kbdtest && call Build || exit /b & popd -pushd kbdinfo && call Build || exit /b & popd +pushd ps2info && call Build || exit /b & popd +pushd 2piotst && call Build || exit /b & popd +pushd piomon && call Build || exit /b & popd goto :eof diff --git a/Source/Apps/Test/Clean.cmd b/Source/Apps/Test/Clean.cmd index 3cb2cdfa..243c2a5c 100644 --- a/Source/Apps/Test/Clean.cmd +++ b/Source/Apps/Test/Clean.cmd @@ -16,4 +16,6 @@ pushd I2C && call Clean || exit /b 1 & popd pushd rzsz && call Clean || exit /b 1 & popd pushd vdctest && call Clean || exit /b 1 & popd pushd kbdtest && call Clean || exit /b 1 & popd -pushd kbdinfo && call Clean || exit /b 1 & popd +pushd ps2info && call Clean || exit /b 1 & popd +pushd 2piotst && call Clean || exit /b 1 & popd +pushd piomon && call Clean || exit /b 1 & popd diff --git a/Source/Apps/Test/DMAmon/Readme.txt b/Source/Apps/Test/DMAmon/Readme.txt index 1d6ab543..24ca0401 100644 --- a/Source/Apps/Test/DMAmon/Readme.txt +++ b/Source/Apps/Test/DMAmon/Readme.txt @@ -1 +1,8 @@ DMAmon is a program to verify operation of the Z80 MBC DMA board + +Version 2 has been hacked to include testing for interrupts. This +requires running the application under RomWBW using IM2. There +is an equate in the source file to disable interrupt testing +if needed. + +--WBW 10:36 AM 3/14/2022 \ No newline at end of file diff --git a/Source/Apps/Test/DMAmon/dmamon.asm b/Source/Apps/Test/DMAmon/dmamon.asm index 5baa6be3..9cfc0441 100644 --- a/Source/Apps/Test/DMAmon/dmamon.asm +++ b/Source/Apps/Test/DMAmon/dmamon.asm @@ -16,6 +16,14 @@ TRUE .EQU ~FALSE SPD_FIXED .EQU 0 ; PLATFORM SPEED FIXED AND CANNOT CHANGE SPEEDS SPD_HILO .EQU 1 ; PLATFORM CAN CHANGE BETWEEN TWO SPEEDS ; +; INTERRUPT TESTING CONFIGURATION +; N.B., INTERRUPT TESTING REQUIRES ROMWBW!!! +; ASSUMES SYSTEM IS ALREADY CONFIGURED FOR IM2 OPERATION +; INTIDX MUST BE SET TO AN UNUSED INTERRUPT SLOT +; +INTENABLE .EQU TRUE ; ENABLE INT TESTING +INTIDX .EQU 1 ; INT VECTOR INDEX +; ; SYSTEM SPEED CHARACTERISTICS ; SPD_UNSUP .EQU 0 ; PLATFORM CAN CHANGE SPEEDS BUT IS UNSUPPORTED @@ -56,14 +64,20 @@ DMA_RESET .equ $c3 ;DMA_RESET_PORT_B_TIMING .equ $cb ;DMA_CONTINUE .equ $d3 ;DMA_DISABLE_INTERUPTS .equ $af -;DMA_ENABLE_INTERUPTS .equ $ab +DMA_ENABLE_INTERUPTS .equ $ab ;DMA_RESET_DISABLE_INTERUPTS .equ $a3 ;DMA_ENABLE_AFTER_RETI .equ $b7 -;DMA_REINIT_STATUS_BYTE .equ $8b +DMA_REINIT_STATUS_BYTE .equ $8b ; DMA_RDY .EQU %00001000 DMA_FORCE .EQU 0 - +; +bf_sysint .equ $FC ; INT function +; +bf_sysintinfo .equ $00 ; INT INFO subfunction +bf_sysintget .equ $10 ; INT GET subfunction +bf_sysintset .equ $20 ; INT SET subfunction +; #IF (DMA_USEHS & (DMAMODE=DMAMODE_MBC)) #IF (CPUSPDDEF=SPD_HIGH) #DEFINE DMAIOSLO LD A,(HB_RTCVAL) \ AND %11110111 \ OUT (RTCIO),A @@ -100,66 +114,128 @@ MAIN: LD SP,STACK ; STACK ; call PRTSTRD ; WELCOME - .db "DMA MONITOR\n\r$" + .db "\n\rDMA Monitor V2\n\r$" +; +#IF (INTENABLE) +; + ; Install interrupt handler in upper mem + ld hl,reladr + ld de,$A000 + ld bc,hsiz + ldir +; + ; Install interrupt vector (RomWBW specific!!!) + ld hl,int ; pointer to my interrupt handler + ld b,bf_sysint + ld c,bf_sysintset ; set new vector + ld e,INTIDX ; vector idx + di + rst 08 ; do it + ld (orgvec),hl ; save the original vector + ei ; interrupts back on +; +#ENDIF ; MENULP: CALL DISPM ; DISPLAY MENU CALL CIN ; GET SELECTION -; + ; Force upper case + CP 'a' ; < 'a' + JR C,MENULP1 ; IF SO, JUST CONTINUE + CP 'z'+1 ; > 'z' + JR NC,MENULP1 ; IS SO, JUST CONTINUE + SUB 'a'-'A' ; CONVERT TO UPPER +; +MENULP1: + CALL NEWLINE CP 'D' JP Z,DMATST_D ; DUMP REGISTERS CP 'I' JP Z,DMATST_I ; INITIALIZE +#IF (INTENABLE) + CP 'T' + JP Z,DMATST_T ; TOGGLE INT USAGE +#ENDIF CP 'M' - JP Z,DMATST_M ; MEMORY MOVE + JP Z,DMATST_M ; MEMORY COPY + CP 'N' + JP Z,DMATST_N ; MEMORY COPY ITER CP '0' JP Z,DMATST_01 CP '1' - JR Z,DMATST_01 + JP Z,DMATST_01 CP 'R' JP Z,DMATST_R ; TOGGLE RESET CP 'Y' JP Z,DMATST_Y ; TOGGLE READY CP 'X' - JR Z,DMABYE ; EXIT + JP Z,DMABYE ; EXIT ; JR MENULP ; -DMABYE: LD SP,(SAVSTK) ; RESTORE CP/M STACK +DMABYE: +#IF (INTENABLE) + ; Deinstall interrupt vector + ld hl,(orgvec) ; original vector + ld b,bf_sysint + ld c,bf_sysintset ; set new vector + ld e,INTIDX ; vector idx + di + rst 08 ; do it + ei ; interrupts back on +#ENDIF +; + LD SP,(SAVSTK) ; RESTORE CP/M STACK RET ; DMATST_I: call PRTSTRD - .db "\n\rSTART DMA_INIT\n\r$" + .db "\n\rStart Initialization\n\r$" CALL DMA_INIT JP MENULP ; +#IF (INTENABLE) +; +DMATST_T: + LD A,(USEINT) + XOR $FF + LD (USEINT),A + JP MENULP +; +#ENDIF +; DMATST_M: call PRTSTRD - .db "\n\rSTART DMAMemMove\n\r$" - CALL DMAMemMove + .db "\n\rPerforming Memory-Memory Copy Test\n\r$" + CALL DMAMemTest + JP MENULP +; +DMATST_N: + call PRTSTRD + .db "\n\rPerforming Iterative Memory-Memory Copy Test\n\r$" + CALL DMAMemTestIter JP MENULP ; DMATST_01: call PRTSTRD - .db "\n\rTOGGLE PORT\n\r$" + .db "\n\rPerforming Port Selection Test\n\r$" CALL DMA_Port01 JP MENULP ; DMATST_D: call PRTSTRD - .db "\n\rSTART DMARegDump\n\r$" + .db "\n\rDump Registers\n\r$" CALL DMARegDump JP MENULP ; DMATST_Y: call PRTSTRD - .db "\n\rTEST READY\n\r$" + .db "\n\rPerforming Ready Bit Test\n\r$" CALL DMA_ReadyT JP MENULP ; DMATST_R: call PRTSTRD - .db "\n\rRESET\n\r$" + .db "\n\rPerforming Reset\n\r$" ; CALL JP MENULP ;================================================================================================== @@ -167,19 +243,39 @@ DMATST_R: ;================================================================================================== ; DISPM: call PRTSTRD - .db "\n\rDMA DEVICE: $" + .db "\n\rDMA Device: $" LD C,DMAMODE ; DISPLAY LD A,00000111B ; TARGET LD DE,DMA_DEV_STR ; DEVICE CALL PRTIDXMSK - CALL NEWLINE ; call PRTSTRD - .db "DMA PORT: $" + .db ", Port=0x$" LD A,DMABASE ; DISPLAY CALL PRTHEXBYTE ; DMA PORT - CALL NEWLINE ; +#IF (INTENABLE) +; + call PRTSTRD + .db "\n\rInterrupts=$" + LD A,(USEINT) + OR A + LD A,'Y' + JR NZ,DISPM_INT + LD A,'N' + JR DISPM_INT +; +DISPM_INT: + CALL COUT +; + call PRTSTRD + .db ", Interrupt Count=$" + ld hl,(counter) + call PRTDEC +; +#ENDIF +; + call NEWLINE LD HL,MENU_OPT ; DISPLAY CALL PRTSTR ; MENU OPTIONS ; @@ -206,7 +302,7 @@ DMA_INIT: jr nz,DMA_NOTFOUND ; call PRTSTRD - .db " DMA FOUND\n\r$" + .db " DMA Found\n\r$" ; ld hl,DMACode ; program the ld b,DMACode_Len ; dma command @@ -224,7 +320,7 @@ DMA_EXIT: DMA_NOTFOUND: push af call PRTSTRD - .db " NOT PRESENT$" + .db " NOT Present$" pop af jr DMA_EXIT ; @@ -242,38 +338,41 @@ DMA_DEV_STR: MENU_OPT: .TEXT "\n\r" .TEXT "I) Initialize DMA\n\r" - .TEXT "M) Memory to Memory test\n\r" - .TEXT "0) DMA Port select test\n\r" - .TEXT "1) DMA Latch Port select test\n\r" - .TEXT "Y) Ready bit test\n\r" + .TEXT "T) Toggle Interrupt Usage\n\r" + .TEXT "M) Test Memory-Memory Copy\n\r" + .TEXT "N) Test Memory-Memory Copy Iteratively\n\r" + .TEXT "0) Test DMA Port Selection\n\r" + .TEXT "1) Test DMA Latch Port Selection\n\r" + .TEXT "Y) Test Ready Bit\n\r" .TEXT "X) Exit\n\r" .TEXT ">$" ; ;================================================================================================== -; TOGGLE A PORT ON AND OFF +; PULSE PORT ;================================================================================================== ; DMA_Port01: + call PRTSTRD + .db "\r\nPulsing port 0x$" sub '0' ; Calculate add a,DMABASE ; Port to + call PRTHEXBYTE + call NEWLINE ld c,a ; toggle - ld b,0 + ld b,$20 ; loop counter portlp: push bc - call PRTSTRD - .db "\n\rON ...$" - call PRTHEXWORD + call PC_PERIOD push bc ld b,0 ld a,0 portlp1:out (c),a djnz portlp1 pop bc - call PRTSTRD - .db " OFF$" call delay pop bc djnz portlp + call NEWLINE JP MENULP ; delay: push bc @@ -290,18 +389,23 @@ dlylp: dec bc ;================================================================================================== ; DMA_ReadyT: + call NEWLINE ld c,DMABASE+1 ; toggle - ld b,0 + ld b,$20 ; loop counter portlp2:push bc + ld a,b + call PRTDECB call PRTSTRD - .db "\n\rON ...$" - call PRTHEXWORD + .db ": ON$" + call delay ld a,$FF ld c,DMABASE+1 out (c),a call PRTSTRD - .db " OFF$" + .db " -> OFF$" call delay + call PRTSTRD + .db "\r \r$" ld c,DMABASE+1 ld a,0 out (c),a @@ -332,8 +436,16 @@ DMAMemMove: LD HL,PROEND ; DMA COPY LD DE,$8000 LD BC,4096-1 - CALL DMALDIR - + LD A,(USEINT) ; USE INTS? + OR A ; TEST VALUE + JR NZ,DMAMemMove1 ; IF SO, DO SO + CALL DMALDIR ; ELSE NORMAL DMA + JR DMAMemMove2 +; +DMAMemMove1: + CALL DMALDIRINT ; DMA W/ INTERRUPTS +; +DMAMemMove2: ; ; LD HL,$8400 ; PLANT ; LD A,$00 ; BAD @@ -345,15 +457,57 @@ DMAMemMove: NXTCMP: CPI JP PO,CMPOK JR Z,NXTCMP - - call PRTHEXWORD + RET ; RET W/ ZF CLEAR +; +CMPOK: + RET ; RET W/ ZF SET +; +;================================================================================================== +; DMA MEMORY TEST +;================================================================================================== +; +DMAMemTest: + call DMAMemMove ; do a single memory copy + jr z,DMAMemTestOK + jr DMAMemTestFail +; +DMAMemTestOK: call PRTSTRD - .db " TEST MEMORY MOVE FAILED\n\r$" - RET - -CMPOK: call PRTSTRD - .db "TEST MEMORY MOVE SUCCEEDED\n\r$" - RET + .db "\n\rMemory-Memory Test Passed\n\r$" + ret +; +DMAMemTestFail: + call PRTSTRD + .db "\n\rMemory-Memory Test Failed\n\r$" + ret +; +;================================================================================================== +; DMA MEMORY MOVE ITERATIVE +;================================================================================================== +; +DMAMemTestIter: + ld b,$20 ; loop counter + call PRTSTRD + .db "\n\rPerforming $" + ld a,b + call PRTDECB + call PRTSTRD + .db " iterations, '.'=OK, '*'=Fail\n\r$" +DMAMemTestIterLoop: + push bc ; save loop control + call DMAMemMove ; do an iteration + jr z,DMAMemTestIterOK + call PC_ASTERISK ; signal failure + jr DMAMemTestIterCont ; continue +; +DMAMemTestIterOK: + call PC_PERIOD ; signal pass +; +DMAMemTestIterCont: + pop bc + djnz DMAMemTestIterLoop + call NEWLINE + ret ; ;================================================================================================== ; DMA PROBE - WRITE TO ADDRESS REGISTER AND READ BACK @@ -455,6 +609,62 @@ DMADest .dw 0 ; R4-Port B, Destination address DMACopy_Len .equ $-DMACopy ; ;================================================================================================== +; DMA COPY BLOCK CODE - ASSUMES DMA PREINITIALIZED +; INTERRUPT VERSION! +;================================================================================================== +; +DMALDIRINT: +; +#IF (INTENABLE) +; + ld (DMASourceInt),hl ; populate the dma + ld (DMADestInt),de ; register template + ld (DMALengthInt),bc +; + ld hl,DMACopyInt ; program the + ld b,DMACopyInt_Len ; dma command + ld c,DMABASE ; block +; + DMAIOSLO + di + otir ; load and execute dma + ei +; + ld a,DMA_READ_STATUS_BYTE ; check status + out (DMABASE),a ; of transfer + in a,(DMABASE) ; set non-zero + and %00111011 ; if failed + sub %00011011 + DMAIONOR +; +#ENDIF +; + ret +; +#IF (INTENABLE) +; +DMACopyInt ;.db DMA_DISABLE ; R6-Command Disable DMA + .db %01111101 ; R0-Transfer mode, A -> B, start address, block length follow +DMASourceInt .dw 0 ; R0-Port A, Start address +DMALengthInt .dw 0 ; R0-Block length + .db %00010100 ; R1-No timing bytes follow, address increments, is memory + .db %00010000 ; R2-No timing bytes follow, address increments, is memory + .db %10100000 ; R3-DMA, interrupt, stop on match disabled + .db DMA_CONTINUOUS ; R4-Continuous mode, destination address, interrupt and control byte follow +DMADestInt .dw 0 ; R4-Port B, Destination address + .db %00011110 ; R4-Interrupt control byte: Pulse byte follows, Pulse generated + .db 0 ; R4-Pulse control byte + .db INTIDX*2 ; R4-Interrupt vector +; .db %10010010+DMA_RDY;R5-Stop on end of block, ce/wait multiplexed, READY active config + .db %10011010 + .db DMA_LOAD ; R6-Command Load + .db DMA_FORCE_READY ; R6-Command Force ready + .db DMA_ENABLE ; R6-Command Enable DMA +DMACopyInt_Len .equ $-DMACopyInt +; +#ENDIF +; +;================================================================================================== ; DMA I/O OUT BLOCK CODE - ADDRESS TO I/O PORT ;================================================================================================== ; @@ -552,8 +762,6 @@ DMAIn_Len .equ $-DMAInCode ; DEBUG - READ START, DESTINATION AND COUNT REGISTERS ;================================================================================================== ; -;#IF (0) -; DMARegDump: ld a,DMA_READ_MASK_FOLLOWS out (DMABASE),a @@ -586,7 +794,6 @@ DMARegDump: ; call NEWLINE ret -;#ENDIF ; CIO_CONSOLE .EQU $80 ; CONSOLE UNIT TO C BF_CIOOUT .EQU $01 ; HBIOS FUNC: OUTPUT CHAR @@ -662,10 +869,52 @@ CST: POP DE POP BC RET - +; +USEINT .DB FALSE ; USE INTERRUPTS FLAG +; SAVSTK: .DW 2 .FILL 64 STACK: .EQU $ +; +orgvec .dw 0 ; saved interrupt vector +; +;=============================================================================== +; Interrupt Handler +;=============================================================================== +; +reladr .equ $ ; relocation start adr +; + .org $A000 ; code will run here +; +int: + ; According to the DMA doc, you must issue + ; a DMA_DISABLE command prior to a + ; DMA_REINIT_STATUS_BYTE command to avoid a + ; potential race condition. + ld a,DMA_DISABLE + out (DMABASE),a +; + ; The doc confuses me, but apparently it is + ; necessary to reinitialize the status byte + ; when an end-of-block interrupt occurs. Otherwise, + ; the end-of-block condition remains set and + ; causes the interrupt to fire continuously. + ld a,DMA_REINIT_STATUS_BYTE + out (DMABASE),a +; + ld hl,(counter) + inc hl + ld (counter),hl +; + or $ff ; signal int handled + ret +; +counter .dw 0 +; +hsiz .equ $ - $A000 ; size of handler to relocate +; + .org reladr + hsiz +; PROEND: .EQU $ ; .END diff --git a/Source/Apps/Test/DMAmon/dmamon.sh b/Source/Apps/Test/DMAmon/dmamon.sh deleted file mode 100644 index 2d738d47..00000000 --- a/Source/Apps/Test/DMAmon/dmamon.sh +++ /dev/null @@ -1,3 +0,0 @@ -~/RomWBW-dev/Tools/unix/uz80as/uz80as -t z80 dmamon.asm dmamon.bin -#srec_cat dmamon.bin -binary -offset 0x0100 --address-length=2 -o dmamon.hex -Intel -cat dmamon.bin > dmamon.com \ No newline at end of file diff --git a/Source/Apps/Test/Makefile b/Source/Apps/Test/Makefile index 3c844c01..8f14cfa7 100644 --- a/Source/Apps/Test/Makefile +++ b/Source/Apps/Test/Makefile @@ -1,5 +1,5 @@ OBJECTS = -SUBDIRS = DMAmon I2C inttest ppidetst ramtest tstdskng rzsz vdctest kbdtest kbdinfo +SUBDIRS = DMAmon I2C inttest ppidetst ramtest tstdskng rzsz vdctest kbdtest ps2info 2piotst piomon DEST = ../../../Binary/Apps/Test TOOLS =../../../Tools diff --git a/Source/Apps/Test/kbdinfo/Build.cmd b/Source/Apps/Test/kbdinfo/Build.cmd deleted file mode 100644 index 1f9866d6..00000000 --- a/Source/Apps/Test/kbdinfo/Build.cmd +++ /dev/null @@ -1,10 +0,0 @@ -@echo off -setlocal - -set TOOLS=../../../../Tools -set PATH=%TOOLS%\tasm32;%PATH% -set TASMTABS=%TOOLS%\tasm32 - -tasm -t180 -g3 -fFF kbdinfo.asm kbdinfo.com kbdinfo.lst || exit /b - -copy /Y kbdinfo.com ..\..\..\..\Binary\Apps\Test\ || exit /b diff --git a/Source/Apps/Test/kbdinfo/mseinfo.asm b/Source/Apps/Test/kbdinfo/mseinfo.asm deleted file mode 100644 index 506aeacf..00000000 --- a/Source/Apps/Test/kbdinfo/mseinfo.asm +++ /dev/null @@ -1,896 +0,0 @@ -; -;======================================================================= -; Mouse Information Utility (MSEINFO) -;======================================================================= -; -; Simple utility that attempts to determine the status of the mouse you -; have attached to an 8242 keyboard controller. -; -; Based on Wayne Warthen's KBDINFO program, Thanks to his great work -; on RomWBW and support to the Retrobrewcomputers community at large -; -; Additional help from these websites -; https://isdaman.com/alsos/hardware/mouse/ps2interface.htm -; -; Second PS/2 write data port info from -; https://wiki.osdev.org/%228042%22_PS/2_Controller#Second_PS.2F2_Port -; -; PS/2 Mouse initialization code in C -; http://bos.asmhackers.net/docs/mouse/snippet_2/mouse.inc -; -;======================================================================= -; -; Mouse controller port addresses (adjust as needed) -; -iocmd .equ $E3 ; keyboard controller command port address -iodat .equ $E2 ; keyboard controller data port address -; -; General operational equates (should not requre adjustment) -; -stksiz .equ $40 ; Working stack size -; -timeout .equ $00 ; Controller timeout constant -; -restart .equ $0000 ; CP/M restart vector -bdos .equ $0005 ; BDOS invocation vector -; -;======================================================================= -; - .org $100 ; standard CP/M executable -; -; - ; setup stack (save old value) - ld (stksav),sp ; save stack - ld sp,stack ; set new stack -; - call crlf - ld de,str_banner ; banner - call prtstr -; - call main ; do the real work -; -exit: - call crlf2 - ld de,str_exit - call prtstr - ;call crlf - - ; clean up and return to command processor - call crlf ; formatting - ld sp,(stksav) ; restore stack - jp restart ; return to CP/M via restart -; -; -;======================================================================= -; Main Program -;======================================================================= -; -main: -; -; Display active mouse controller port addresses -; - call crlf2 - ld de,str_cmdport - call prtstr - ld a,iocmd - call prthex - call crlf - ld de,str_dataport - call prtstr - ld a,iodat - call prthex -; -; Attempt self-test command on mouse controller -; -; Mouse controller should respond with an 0x55 on data port -; after being sent a 0xAA on the command port. -; - call crlf2 - ld de,str_ctrl_test - call prtstr - ld a,$aa ; self-test command - call put_cmd_dbg - jp c,err_ctlr_io ; handle controller error - call get_data_dbg - jp c,err_ctlr_io ; handle controller error - cp $55 ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - ld de,str_ctrl_test_ok - call prtstr -; -; Send 0xA8 Mouse Enable command to 8242 controller -; - call crlf2 - ld de,str_enable_mouse - call prtstr - - ld a,$a8 ; Send Mouse Enable command to 8242 - call put_cmd_dbg - jp c,err_ctlr_io ; handle controller error - - call get_data_dbg ; Read Mouse for self-test status - jp c,err_ctlr_io ; handle controller error - cp $AA ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - - call get_data_dbg ; Read Mouse for Mouse ID - jp c,err_ctlr_io ; handle controller error - cp $00 ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - - - -; -; Disable translation on keyboard controller to get raw scan codes! Enable Mouse -; -; call crlf2 -; ld de,str_trans_off -; call prtstr -; ld a,$60 ; write to command register 0 -; call put_cmd_dbg -; jp c,err_ctlr_io ; handle controller error -; ld a,$00 ; xlat disabled, mouse enabled, no ints -; call put_cmd_dbg -; jp c,err_ctlr_io ; handle controller error - -; Attempt four reset commands on mouse controller -; - call crlf2 - ld de,str_mse_init - call prtstr - -; Reset Pass #1 - ld a,$ff ; Send Mouse Reset command - call put_data_dbg - jp c,err_ctlr_io ; handle controller error - - call get_data_dbg ; Read Mouse for Acknowledge - jp c,err_ctlr_io ; handle controller error - cp $fa ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - ld de,str_ctrl_test_ok - call prtstr - - call get_data_dbg ; Read Mouse for self-test status - jp c,err_ctlr_io ; handle controller error - cp $AA ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - - call get_data_dbg ; Read Mouse for Mouse ID - jp c,err_ctlr_io ; handle controller error - cp $00 ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - -; Reset Pass #2 - ld a,$ff ; Send Mouse Reset command - call put_data_dbg - jp c,err_ctlr_io ; handle controller error - - call get_data_dbg ; Read Mouse for Acknowledge - jp c,err_ctlr_io ; handle controller error - cp $fa ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - ld de,str_ctrl_test_ok - call prtstr - - call get_data_dbg ; Read Mouse for self-test status - jp c,err_ctlr_io ; handle controller error - cp $AA ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - - call get_data_dbg ; Read Mouse for Mouse ID - jp c,err_ctlr_io ; handle controller error - cp $00 ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - -; Reset Pass #3 - ld a,$ff ; Send Mouse Reset command - call put_data_dbg - jp c,err_ctlr_io ; handle controller error - - call get_data_dbg ; Read Mouse for Acknowledge - jp c,err_ctlr_io ; handle controller error - cp $fa ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - ld de,str_ctrl_test_ok - call prtstr - - call get_data_dbg ; Read Mouse for self-test status - jp c,err_ctlr_io ; handle controller error - cp $AA ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - - call get_data_dbg ; Read Mouse for Mouse ID - jp c,err_ctlr_io ; handle controller error - cp $00 ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - -; Reset Pass #4 - ld a,$ff ; Send Mouse Reset command - call put_data_dbg - jp c,err_ctlr_io ; handle controller error - - call get_data_dbg ; Read Mouse for Acknowledge - jp c,err_ctlr_io ; handle controller error - cp $fa ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - ld de,str_ctrl_test_ok - call prtstr - - call get_data_dbg ; Read Mouse for self-test status - jp c,err_ctlr_io ; handle controller error - cp $AA ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - - call get_data_dbg ; Read Mouse for Mouse ID - jp c,err_ctlr_io ; handle controller error - cp $00 ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - -; Begin setting mouse parameters, Request Microsoft Scrolling Mouse Mode - - ld a,$f3 ; Send Set Sample Rate command - call put_data_dbg - jp c,err_ctlr_io ; handle controller error - - call get_data_dbg ; Read Mouse for Acknowledge - jp c,err_ctlr_io ; handle controller error - cp $fa ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - ld de,str_ctrl_test_ok - call prtstr - - ld a,$c8 ; Send Decimal 200 command - call put_data_dbg - jp c,err_ctlr_io ; handle controller error - - call get_data_dbg ; Read Mouse for Acknowledge - jp c,err_ctlr_io ; handle controller error - cp $fa ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - ld de,str_ctrl_test_ok - call prtstr - - ld a,$f3 ; Send Set Sample Rate command - call put_data_dbg - jp c,err_ctlr_io ; handle controller error - - call get_data_dbg ; Read Mouse for Acknowledge - jp c,err_ctlr_io ; handle controller error - cp $fa ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - ld de,str_ctrl_test_ok - call prtstr - - ld a,$64 ; Send Decimal 100 command - call put_data_dbg - jp c,err_ctlr_io ; handle controller error - - call get_data_dbg ; Read Mouse for Acknowledge - jp c,err_ctlr_io ; handle controller error - cp $fa ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - ld de,str_ctrl_test_ok - call prtstr - - ld a,$f3 ; Send Set Sample Rate command - call put_data_dbg - jp c,err_ctlr_io ; handle controller error - - call get_data_dbg ; Read Mouse for Acknowledge - jp c,err_ctlr_io ; handle controller error - cp $fa ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - ld de,str_ctrl_test_ok - call prtstr - - ld a,$50 ; Send Decimal 80 command - call put_data_dbg - jp c,err_ctlr_io ; handle controller error - - call get_data_dbg ; Read Mouse for Acknowledge - jp c,err_ctlr_io ; handle controller error - cp $fa ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - ld de,str_ctrl_test_ok - call prtstr - - ld a,$f2 ; Send Read Device Type command - call put_data_dbg - jp c,err_ctlr_io ; handle controller error - - call get_data_dbg ; Read Mouse for Acknowledge - jp c,err_ctlr_io ; handle controller error - cp $fa ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - ld de,str_ctrl_test_ok - call prtstr - - call get_data_dbg ; Read Mouse for Mouse ID - jp c,err_ctlr_io ; handle controller error - cp $03 ; detect MS Intellimouse/Microsoft Scrolling Mouse - jp z,Intellimouse - cp $00 ; expected value? ($00 if Regular PS/2 Mouse) - jp z,ReadMouseID -Intellimouse: - call crlf - ld de,str_intellimouse_ok - call prtstr -ReadMouseID: - jp nz,err_ctlr_test ; handle self-test error - call crlf - - ld a,$f3 ; Send Set Sample Rate command - call put_data_dbg - jp c,err_ctlr_io ; handle controller error - - call get_data_dbg ; Read Mouse for Acknowledge - jp c,err_ctlr_io ; handle controller error - cp $fa ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - ld de,str_ctrl_test_ok - call prtstr - - ld a,$0a ; Send Decimal 10 command - call put_data_dbg - jp c,err_ctlr_io ; handle controller error - - call get_data_dbg ; Read Mouse for Acknowledge - jp c,err_ctlr_io ; handle controller error - cp $fa ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - ld de,str_ctrl_test_ok - call prtstr - - ld a,$f2 ; Send Read Device Type command - call put_data_dbg - jp c,err_ctlr_io ; handle controller error - - call get_data_dbg ; Read Mouse for Acknowledge - jp c,err_ctlr_io ; handle controller error - cp $fa ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - ld de,str_ctrl_test_ok - call prtstr - - call get_data_dbg ; Read Mouse for Mouse ID - jp c,err_ctlr_io ; handle controller error - cp $03 ; detect MS Intellimouse/Microsoft Scrolling Mouse - jp z,Intellimouse2 - cp $00 ; expected value? ($00 if Regular PS/2 Mouse) - jp z,ReadMouseID2 -Intellimouse2: - call crlf - ld de,str_intellimouse_ok - call prtstr -ReadMouseID2: - jp nz,err_ctlr_test ; handle self-test error - call crlf - - ld a,$e8 ; Send Set Resolution command - call put_data_dbg - jp c,err_ctlr_io ; handle controller error - - call get_data_dbg ; Read Mouse for Acknowledge - jp c,err_ctlr_io ; handle controller error - cp $fa ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - ld de,str_ctrl_test_ok - call prtstr - - ld a,$03 ; Send 8 Counts/mm command - call put_data_dbg - jp c,err_ctlr_io ; handle controller error - - call get_data_dbg ; Read Mouse for Acknowledge - jp c,err_ctlr_io ; handle controller error - cp $fa ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - ld de,str_ctrl_test_ok - call prtstr - - ld a,$e6 ; Send Set Scaling 1:1 command - call put_data_dbg - jp c,err_ctlr_io ; handle controller error - - call get_data_dbg ; Read Mouse for Acknowledge - jp c,err_ctlr_io ; handle controller error - cp $fa ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - ld de,str_ctrl_test_ok - call prtstr - - ld a,$f3 ; Send Set Sample Rate command - call put_data_dbg - jp c,err_ctlr_io ; handle controller error - - call get_data_dbg ; Read Mouse for Acknowledge - jp c,err_ctlr_io ; handle controller error - cp $fa ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - ld de,str_ctrl_test_ok - call prtstr - - ld a,$28 ; Send Decimal 40 command - call put_data_dbg - jp c,err_ctlr_io ; handle controller error - - call get_data_dbg ; Read Mouse for Acknowledge - jp c,err_ctlr_io ; handle controller error - cp $fa ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - ld de,str_ctrl_test_ok - call prtstr - - ld a,$f4 ; Send Enable command - call put_data_dbg - jp c,err_ctlr_io ; handle controller error - - call get_data_dbg ; Read Mouse for Acknowledge - jp c,err_ctlr_io ; handle controller error - cp $fa ; expected value? - jp nz,err_ctlr_test ; handle self-test error - call crlf - ld de,str_ctrl_test_ok - call prtstr - -; Initialization Complete - -ReadMousePackets: - -; call check_read -; jp nz, ReadMousePackets - - call get_data_dbg ; Read Mouse for self-test status - jp c,err_ctlr_io ; handle controller error - call crlf - - call get_data_dbg ; Read Mouse for Mouse ID - jp c,err_ctlr_io ; handle controller error - call crlf - - call get_data_dbg ; Read Mouse for Mouse ID - jp c,err_ctlr_io ; handle controller error - call crlf - - call crlf - - jp ReadMousePackets - -; -done: - ret - -; -;======================================================================= -; Mouse Controller I/O Routines -;======================================================================= -; -wait_write: -; -; Wait for mouse controller to be ready for a write -; A=0 indicates success (ZF set) -; - ld b,timeout ; setup timeout constant -wait_write1: - in a,(iocmd) ; get status - ld c,a ; save status - and $02 ; isolate input buf status bit - ret z ; 0 means ready, all done - call delay ; wait a bit - djnz wait_write1 ; loop until counter exhausted - ld de,str_timeout_write ; write timeout message - call crlf - call prtstr - ld a,c ; recover last status value - call prthex - or $ff ; signal error - ret -; -wait_read: -; -; Wait for mouse controller to be ready to read a byte -; A=0 indicates success (ZF set) -; - ld b,timeout ; setup timeout constant -wait_read1: - in a,(iocmd) ; get status - ld c,a ; save status - and $01 ; isolate input buf status bit - xor $01 ; invert so 0 means ready - ret z ; if 0, all done - call delay ; wait a bit - djnz wait_read1 ; loop until counter exhausted - ld de,str_timeout_read ; write timeout message - call crlf - call prtstr - ld a,c ; recover last status value - call prthex - or $ff ; signal error - ret -; -check_read: -; -; Check for data ready to read -; A=0 indicates data available (ZF set) -; - in a,(iocmd) ; get status - and $01 ; isolate input buf status bit - xor $01 ; invert so 0 means ready - ret -; -put_cmd: -; -; Put a cmd byte from A to the mouse interface with timeout -; CF set indicates timeout error -; - ld e,a ; save incoming value - call wait_write ; wait for controller ready - jr z,put_cmd1 ; if ready, move on - scf ; else, signal timeout error - ret ; and bail out -put_cmd1: - ld a,e ; recover value to write - out (iocmd),a ; write it - or a ; clear CF for success - ret -; -put_cmd_dbg: - call put_cmd - ret c - push af - call crlf - ld de,str_put_cmd - call prtstr - call prthex - pop af - ret -; -put_data: -; -; Put a data byte from A to the mouse interface with timeout -; CF set indicates timeout error -; -; note: direct data to second PS/2 port, send $d4 to 8242 command register -; different than keyboard which uses first PS/2 port - - push af ; save contents of a - ld e,a ; save incoming value - call wait_write ; wait for controller ready - jr z,put_data0 ; if ready, move on - scf ; else, signal timeout error - ret ; and bail out -put_data0: - ld a,$d4 ; direct to second PS/2 port for mouse - out (iocmd),a ; send second port command to 8242 - pop af - -; rest of put_data is the same as for PS/2 keyboard - - ld e,a ; save incoming value - call wait_write ; wait for controller ready - jr z,put_data1 ; if ready, move on - scf ; else, signal timeout error - ret ; and bail out -put_data1: - ld a,e ; recover value to write - out (iodat),a ; write it - or a ; clear CF for success - ret -; -put_data_dbg: - call put_data - ret c - push af - call crlf - ld de,str_put_data - call prtstr - call prthex - pop af - ret - -; -; Get a data byte from the mouse interface to A with timeout -; CF set indicates timeout error -; -get_data: -; - call wait_read ; wait for byte to be ready - jr z,get_data1 ; if ready, move on - scf ; else signal timeout error - ret ; and bail out -get_data1: - in a,(iodat) ; get data byte - or a ; clear CF for success - ret -; -get_data_dbg: - call get_data - ret c - push af - call crlf - ld de,str_get_data - call prtstr - call prthex - pop af - ret -; -; Error Handlers -; -err_ctlr_io: - ld de,str_err_ctrl_io - jr err_ret -; -err_ctlr_test: - ld de,str_err_ctrl_test - jr err_ret -; -err_mse_reset: - ld de,str_err_mse_reset - jr err_ret -; -err_ret: - call crlf2 - call prtstr - or $ff ; signal error - ret -; -;======================================================================= -; Utility Routines -;======================================================================= -; -; -; Print character in A without destroying any registers -; -prtchr: - push bc ; save registers - push de - push hl - ld e,a ; character to print in E - ld c,$02 ; BDOS function to output a character - call bdos ; do it - pop hl ; restore registers - pop de - pop bc - ret -; -prtdot: -; - ; shortcut to print a dot preserving all regs - push af ; save af - ld a,'.' ; load dot char - call prtchr ; print it - pop af ; restore af - ret ; done -; -; Print a zero terminated string at (de) without destroying any registers -; -prtstr: - push af - push de -; -prtstr1: - ld a,(de) ; get next char - or a - jr z,prtstr2 - call prtchr - inc de - jr prtstr1 -; -prtstr2: - pop de ; restore registers - pop af - ret -; -; Print the value in A in hex without destroying any registers -; -prthex: - push af ; save AF - push de ; save DE - call hexascii ; convert value in A to hex chars in DE - ld a,d ; get the high order hex char - call prtchr ; print it - ld a,e ; get the low order hex char - call prtchr ; print it - pop de ; restore DE - pop af ; restore AF - ret ; done -; -; print the hex word value in hl -; -prthexword: - push af - ld a,h - call prthex - ld a,l - call prthex - pop af - ret -; -; print the hex dword value in de:hl -; -prthex32: - push bc - push de - pop bc - call prthexword - push hl - pop bc - call prthexword - pop bc - ret -; -; Convert binary value in A to ascii hex characters in DE -; -hexascii: - ld d,a ; save A in D - call hexconv ; convert low nibble of A to hex - ld e,a ; save it in E - ld a,d ; get original value back - rlca ; rotate high order nibble to low bits - rlca - rlca - rlca - call hexconv ; convert nibble - ld d,a ; save it in D - ret ; done -; -; Convert low nibble of A to ascii hex -; -hexconv: - and $0F ; low nibble only - add a,$90 - daa - adc a,$40 - daa - ret -; -; Print value of A or HL in decimal with leading zero suppression -; Use prtdecb for A or prtdecw for HL -; -prtdecb: - push hl - ld h,0 - ld l,a - call prtdecw ; print it - pop hl - ret -; -prtdecw: - push af - push bc - push de - push hl - call prtdec0 - pop hl - pop de - pop bc - pop af - ret -; -prtdec0: - ld e,'0' - ld bc,-10000 - call prtdec1 - ld bc,-1000 - call prtdec1 - ld bc,-100 - call prtdec1 - ld c,-10 - call prtdec1 - ld e,0 - ld c,-1 -prtdec1: - ld a,'0' - 1 -prtdec2: - inc a - add hl,bc - jr c,prtdec2 - sbc hl,bc - cp e - ret z - ld e,0 - call prtchr - ret -; -; Start a new line -; -crlf2: - call crlf ; two of them -crlf: - push af ; preserve AF - ld a,13 ; - call prtchr ; print it - ld a,10 ; - call prtchr ; print it - pop af ; restore AF - ret -; -; Brief delay -; -delay: - push bc - ld b,0 -delay1: - ex (sp),hl - ex (sp),hl - ex (sp),hl - ex (sp),hl - ex (sp),hl - ex (sp),hl - ex (sp),hl - ex (sp),hl - djnz delay1 - pop bc - ret -; -;======================================================================= -; Constants -;======================================================================= -; -str_banner .db "Mouse Information, v0.1",0 -str_exit .db "Done, Thank you for using MSEINFO!",0 -str_cmdport .db "Mouse Controller Command Port: 0x",0 -str_dataport .db "Mouse Controller Data Port: 0x",0 -str_timeout_write .db "Mouse Controller Write Timeout, Status: 0x",0 -str_timeout_read .db "Mouse Controller Read Timeout, Status: 0x",0 -str_err_ctrl_io .db "Mouse Controller I/O Failure",0 -str_err_ctrl_test .db "Mouse Controller Self-Test Failed",0 -str_put_cmd .db "Sent Command 0x",0 -str_put_data .db "Sent Data 0x",0 -str_get_data .db "Got Data 0x",0 -str_ctrl_test .db "Attempting Controller Self-Test",0 -str_mse_init .db "Attempting Mouse Initialization",0 -str_enable_mouse .db "Enabling Mouse in 8242 Controller",0 -str_ctrl_test_ok .db "Controller Self-Test OK",0 -str_intellimouse_ok .db "MS Intellimouse OK",0 -str_trans_off .db "Disabling Controller Translation",0 -str_mse_reset .db "Attempting Mouse Reset",0 -str_mse_reset_ok .db "Mouse Reset OK",0 -str_err_mse_reset .db "Mouse Reset Failed",0 -; -;======================================================================= -; Working data -;======================================================================= -; -stksav .dw 0 ; stack pointer saved at start - .fill stksiz,0 ; stack -stack .equ $ ; stack top -; -workbuf .fill 8 -workbuf_len .db 0 -; -;======================================================================= -; - .end - diff --git a/Source/Apps/Test/piomon/Build.cmd b/Source/Apps/Test/piomon/Build.cmd new file mode 100644 index 00000000..f0e405e1 --- /dev/null +++ b/Source/Apps/Test/piomon/Build.cmd @@ -0,0 +1,10 @@ +@echo off +setlocal + +set TOOLS=../../../../Tools +set PATH=%TOOLS%\tasm32;%PATH% +set TASMTABS=%TOOLS%\tasm32 + +tasm -t180 -g3 -fFF piomon.asm piomon.com piomon.lst || exit /b + +copy /Y piomon.com ..\..\..\..\Binary\Apps\Test\ || exit /b diff --git a/Source/Apps/Test/kbdinfo/Clean.cmd b/Source/Apps/Test/piomon/Clean.cmd similarity index 100% rename from Source/Apps/Test/kbdinfo/Clean.cmd rename to Source/Apps/Test/piomon/Clean.cmd diff --git a/Source/Apps/Test/kbdinfo/Makefile b/Source/Apps/Test/piomon/Makefile similarity index 56% rename from Source/Apps/Test/kbdinfo/Makefile rename to Source/Apps/Test/piomon/Makefile index 3525056d..d3054352 100644 --- a/Source/Apps/Test/kbdinfo/Makefile +++ b/Source/Apps/Test/piomon/Makefile @@ -1,4 +1,4 @@ -OBJECTS = kbdinfo.com +OBJECTS = piomon.com DEST = ../../../../Binary/Apps/Test TOOLS =../../../../Tools diff --git a/Source/Apps/Test/piomon/Readme.txt b/Source/Apps/Test/piomon/Readme.txt new file mode 100644 index 00000000..ddf13f7a --- /dev/null +++ b/Source/Apps/Test/piomon/Readme.txt @@ -0,0 +1,36 @@ +PIOMON is a program to verify operation of the Z80 MBC DUALPIO board + +Most testing requires the use of loopback hardware constructed as: + +Channel A RDY STB D0 D1 D2 D3 D4 D5 D6 D7 + \ / | | | | | | | | + \ / | | | | | | | | + X | | | | | | | | + / \ | | | | | | | | + / \ | | | | | | | | +Channel B RDY STB D0 D1 D2 D3 D4 D5 D6 D7 + +The DUALPIO has, well, 2 PIO chips. Only one chip +is tested at a time. At startup, PIOMON will ask +you for the port of the chip to test. It defaults +to the standard port number for the primary PIO chip +on an MBC DUALPIO board. + +The port number specified is the base I/O port. Each +chip has two channels which are addressed in the +menu by specifying A or B. + +MBC DUALPIO Primary PIO = 0xB8 +MBC DUALPIO Secondary PIO = 0xBC + +If you try to use PIOMON without the RDY and STB +cross connected, you may have interrupt issues +because STB will be floating. + +N.B., V1 and V2 of the DUALPIO lack a hardware reset. The +PIO chips will reset at power-on, but they do not reset +when the reset button is pushed. + +Happy St. Patrick's Day!!! + +--WBW 7:42 PM 3/17/2022 \ No newline at end of file diff --git a/Source/Apps/Test/piomon/piomon.asm b/Source/Apps/Test/piomon/piomon.asm new file mode 100644 index 00000000..d7cdb71f --- /dev/null +++ b/Source/Apps/Test/piomon/piomon.asm @@ -0,0 +1,1361 @@ +; +;======================================================================= +; Zilog PIO Monitor & Hardware Testing Application +;======================================================================= +; +iodef .equ $B8 ; Default base I/O port address +; +; +; +; Port address offsets from base address +iodata .equ 0 ; Channel A Data +iodatb .equ 1 ; Channel B Data +ioctla .equ 2 ; Channel A Control +ioctlb .equ 3 ; Channel B Control +; +intveca .equ 0 ; Channel A interrupt vector +intvecb .equ 1 ; Channel B interrupt vector +; +iocmd .equ $E3 ; PS/2 controller command port address +iodat .equ $E2 ; PS/2 controller data port address +; +cpumhz .equ 8 ; for time delay calculations (not critical) +; +; General operational equates (should not requre adjustment) +; +stksiz .equ $40 ; Working stack size +buflen .equ $80 ; Command buffer length +; +ltimout .equ 0 ; 256*10ms = 2.56s +stimout .equ 10 ; 10*10ms = 100ms +; +restart .equ $0000 ; CP/M restart vector +bdos .equ $0005 ; BDOS invocation vector +; +bf_sysint .equ $FC ; INT function +; +bf_sysintinfo .equ $00 ; INT INFO subfunction +bf_sysintget .equ $10 ; INT GET subfunction +bf_sysintset .equ $20 ; INT SET subfunction +; +bel .equ 7 ; ASCII bell +bs .equ 8 ; ASCII backspace +lf .equ 10 ; ASCII linefeed +cr .equ 13 ; ASCII carriage return +; +;======================================================================= +; + .org $100 ; standard CP/M executable +; +; + ; setup stack (save old value) + ld (stksav),sp ; save stack + ld sp,stack ; set new stack +; + call nl + ld hl,str_banner ; banner + call pstr +; +getport1: + ld hl,str_port1 + call pstr + ld a,(iobase) + call prthexbyte + ld hl,str_port2 + call pstr + call rdln + ld ix,cmdbuf + call skipws + or a + jr z,getport2 + call ishex + jr nz,getport1 + call gethex ; get port value + jp c,getport1 ; handle overflow + ld (iobase),a ; save value +; +getport2: + call init +; + call main ; do the real work +; +exit: + call deinit +; + call nl2 + ld hl,str_exit + call pstr +; + ; clean up and return to command processor + call nl ; formatting + ld sp,(stksav) ; restore stack + jp restart ; return to CP/M via restart +; +;======================================================================= +; Initialize +;======================================================================= +; +init: + ; Install interrupt handler in upper mem + ld hl,reladr + ld de,$A000 + ld bc,hsiz + ldir +; + ; Install interrupt vectors (RomWBW specific!!!) + ld hl,inta ; pointer to my interrupt handler + ld b,bf_sysint + ld c,bf_sysintset ; set new vector + ld e,intveca ; vector idx + di + rst 08 ; do it + ld (orgveca),hl ; save the original vector + ei ; interrupts back on + ld hl,intb ; pointer to my interrupt handler + ld b,bf_sysint + ld c,bf_sysintset ; set new vector + ld e,intvecb ; vector idx + di + rst 08 ; do it + ld (orgvecb),hl ; save the original vector + ei ; interrupts back on +; + ; Load the interrupt vectors + ld a,(iobase) + add a,ioctla + ld c,a + ld a,intveca * 2 + out (c),a + ld a,(iobase) + add a,ioctlb + ld c,a + ld a,intvecb * 2 + out (c),a +; + ; Set the interrupt control words + ld a,(iobase) + add a,ioctla + ld c,a + ld a,%10000111 + out (c),a ; int enab, no mask follows + ;ld a,%11111111 + ;out (ioctla),a ; no ints in control mode + ld a,(iobase) + add a,ioctlb + ld c,a + ld a,%10000111 + out (c),a ; int enab, no mask follows + ;ld a,%11111111 + ;out (ioctlb),a ; no ints in control mode +; + ret +; +deinit: + call reset +; + ld a,(iobase) + add a,ioctla + ld c,a + ld a,%00010111 ; clear interrupt ctl word + out (c),a + ld a,%11111111 ; clear mask + out (c),a + ld a,%00000000 ; clear interrupt vector + out (c),a +; + ld a,(iobase) + add a,ioctlb + ld c,a + ld a,%00010111 ; clear interrupt ctl word + out (c),a + ld a,%11111111 ; clear mask + out (c),a + ld a,%00000000 ; clear interrupt vector + out (c),a +; + ; Deinstall interrupt vectors + ld hl,(orgveca) ; original vector + ld b,bf_sysint + ld c,bf_sysintset ; set new vector + ld e,intveca ; vector idx + di + rst 08 ; do it + ei ; interrupts back on + ld hl,(orgvecb) ; original vector + ld b,bf_sysint + ld c,bf_sysintset ; set new vector + ld e,intvecb ; vector idx + di + rst 08 ; do it + ei ; interrupts back on + ret +; +;======================================================================= +; Main Program +;======================================================================= +; +main: + ; Prompt + call nl2 + ld hl,str_pre + call pstr + ld a,(iobase) + call prthexbyte +; + ld hl,str_int1 + call pstr + ld hl,(intcnta) + call prtdec + ld hl,str_int2 + call pstr + ld hl,(intcntb) + call prtdec +; + ld hl,str_pre2 + call pstr +; + ; Read command line + call rdln + ld ix,cmdbuf +; +main1: + ;;;; Upper case the entire command line + ;;;ld a,(ix) + ;;;or a + ;;;jr z,main2 + ;;;call upcase + ;;;ld (ix),a + ;;;inc ix + ;;;jr main1 +; +main2: + ld ix,cmdbuf + call skipws + or a ; check for eol + call nz,runcmd ; run command if not eol + jr main ; loop +; +; Run the command line pointed to by IX +; +runcmd: + ld ix,cmdbuf ; point to cmd line + call skipws + or a ; check for eol + ret z ; return if nothing there +; + ld a,(ix) ; get character +; + ; Dispatch + cp '?' ; Help + jp z,help + cp 'H' ; Help + jp z,help + cp 'X' ; Exit + jp z,exit + cp 'P' ; PIO Base Port + jp z,setport + cp 'Z' ; Reset Chip + jp z,reschip + cp 'W' ; Watch pins + jp z,watch + cp 'I' ; Input pins on channel + jp z,input + cp 'O' ; Output pins on channel + jp z,output + cp 'S' ; Send strobed byte to channel + jp z,send + cp 'R' ; Read strobed byte from channel + jp z,receive + cp 'T' ; Test + jp z,test + jp err_invcmd ; Invalid command +; +help: + ld hl,str_usage + call pstr + ret +; +setport: + call findws ; skip command + call skipws ; skip white space + call ishex ; do we have a number + jp nz,err_invcmd ; handle invalid command + call gethex + jp c,err_invcmd ; handle overflow error + push af + call deinit + pop af + ld (iobase),a ; set new port value + call init + ret ; and done +; +reschip: + ld hl,str_reschip1 + call pstr + call reset + ld hl,str_reschip2 + call pstr + ret +; +watch: + inc ix ; skip command byte + call getchan ; get channel + jp nz,err_invcmd ; handle invalid channel +; + ld hl,str_watch1 + call pstr + ld a,(channel) + add a,'A' + call cout + ld hl,str_watch2 + call pstr + call nl2 ; formatting + call ctlport ; set c to ctl port of channel + ld a,%11001111 ; bit control mode + out (c),a ; do it + ld a,%11111111 ; set all pins to input + out (c),a ; do it + call dataport ; set c to data port + ld a,0 + ld b,0 + jr watch2 +watch1: + call keychk ; key pressed? + ret nz ; return if so + in a,(c) ; read data port + cp b ; same as before + jr z,watch1 ; loop +watch2: + ld b,a ; save in B + ld hl,str_watchtag + call pstr + ld a,b ; restore value read + call prthexbyte ; print new value + jr watch1 +; +input: + inc ix ; skip command byte + call getchan ; get channel + jp nz,err_invcmd ; handle invalid channel +; + ld hl,str_input1 + call pstr + ld a,(channel) + add a,'A' + call cout + ld hl,str_input2 + call pstr + call ctlport ; set c to ctl port of channel + ld a,%11001111 ; bit control mode + out (c),a ; do it + ld a,%11111111 ; set all pins to input + out (c),a ; do it + call dataport ; set c to data port + in a,(c) + call prthexbyte + ret +; +output: + inc ix ; skip command byte + call getchan ; get channel + jp nz,err_invcmd ; handle invalid channel +; + call findws ; skip command + call skipws ; skip white space + call ishex ; do we have a number + jp nz,err_invcmd ; handle invalid command + call gethex + jp c,err_invcmd ; handle overflow error + push af +; + ld hl,str_output1 + call pstr + ld a,(channel) + add a,'A' + call cout + ld hl,str_output2 + call pstr + call ctlport ; set c to ctl port of channel + ld a,%11001111 ; bit control mode + out (c),a ; do it + ld a,%00000000 ; set all pins to output + out (c),a ; do it + call dataport ; set c to data port + pop af + out (c),a + call prthexbyte + ret +; +send: + inc ix ; skip command byte + call getchan ; get channel + jp nz,err_invcmd ; handle invalid channel +; + call findws ; skip command + call skipws ; skip white space + call ishex ; do we have a number + jp nz,err_invcmd ; handle invalid command + call gethex + jp c,err_invcmd ; handle overflow error + push af +; + ld hl,str_send1 + call pstr + ld a,(channel) + add a,'A' + call cout + ld hl,str_send2 + call pstr + call ctlport ; set c to ctl port of channel + ld a,%00001111 ; strobed output mode + out (c),a ; do it + call dataport ; set c to data port + pop af + out (c),a + call prthexbyte + ret +; +receive: + inc ix ; skip command byte + call getchan ; get channel + jp nz,err_invcmd ; handle invalid channel +; + ld hl,str_receive1 + call pstr + ld a,(channel) + add a,'A' + call cout + ld hl,str_receive2 + call pstr + call ctlport ; set c to ctl port of channel + ld a,%01001111 ; strobed input mode + out (c),a ; do it + call dataport ; set c to data port + in a,(c) + call prthexbyte + ret +; +test: + inc ix ; skip command byte + ld a,(ix) ; get character +; + ; Dispatch + cp 'R' + jp z,test_rdbk ; Readback Test + cp 'L' + jp z,test_lpbk ; Loopback Test + cp 'S' + jp z,test_stlp ; Strobed Loopback Test + jp err_invcmd + ret +; +test_rdbk: + inc ix ; skip command byte + call getchan ; get channel + jp nz,err_invcmd ; handle invalid channel +; + ld hl,str_rdbk + call pstr + ld a,(channel) + add a,'A' + call cout + call nl ; formatting + call ctlport ; set c to ctl port of channel + ld a,%00001111 ; mode 0 (output mode) + out (c),a ; do it + call dataport ; set c to data port +; + ld hl,vallist + ld b,vallen +test_rdbk0: + push hl + push bc + ld a,(hl) + call test_rdbk1 + pop bc + pop hl + jp nz,err_fail + inc hl + djnz test_rdbk0 + ret +; +test_rdbk1: + ld b,a + call nl + ld a,b + call prthexbyte + out (c),a + ld hl,str_arrow + call pstr + in a,(c) + call prthexbyte + cp b + ret +; +test_lpbk: + ld hl,str_lpbkAB + call pstr + ld a,(iobase) ; Test from A + add a,ioctla + ld d,a + ld a,(iobase) ; ... to B + add a,ioctlb + ld e,a + push de + call reset + call test_lpbk1 ; avoid output on both channels + pop de + jp nz,err_fail + ld hl,str_lpbkBA + call pstr + ld a,d ; switch direction + ld d,e + ld e,a + call reset ; avoid output on both channels + call test_lpbk1 + jp nz,err_fail + ret +; +test_lpbk1: + ; Setup output channel + ld c,d + ld a,%11001111 ; bit control mode + out (c),a ; do it + ld a,%00000000 ; set all pins to output + out (c),a ; do it +; + ; Setup input channel + ld c,e + ld a,%11001111 ; bit control mode + out (c),a ; do it + ld a,%11111111 ; set all pins to input + out (c),a ; do it +; + ; Loop through test values + dec d ; point to data port (output) + dec d + dec e ; point to data port (input) + dec e + ld hl,vallist + ld b,vallen +; +test_lpbk2: + call test_lpbk3 + ret nz + inc hl + djnz test_lpbk2 + ret +; +test_lpbk3: + call nl + ld c,d + ld a,(hl) + call prthexbyte + out (c),a + push hl + ld hl,str_arrow + call pstr + pop hl + ld c,e + in a,(c) + call prthexbyte + cp (hl) + ret +; +test_stlp: + ld hl,str_stlpAB + call pstr + ld a,(iobase) ; Test from A + add a,ioctla + ld d,a + ld a,(iobase) ; ... to B + add a,ioctlb + ld e,a + push de + call reset + call test_stlp1 ; avoid output on both channels + pop de + jp nz,err_fail + ld hl,str_stlpBA + call pstr + ld a,d ; switch direction + ld d,e + ld e,a + call reset ; avoid output on both channels + call test_stlp1 + jp nz,err_fail + ret +; +test_stlp1: + ; Setup output channel + ld c,d + ld a,%00001111 ; strobed output mode + out (c),a ; do it +; + ; Setup input channel + ld c,e + ld a,%01001111 ; strobed input mode + out (c),a ; do it +; + ; Loop through test values + dec d ; point to data port (output) + dec d + dec e ; point to data port (input) + dec e + ld hl,vallist + ld b,vallen +; +test_stlp2: + call test_stlp3 + ret nz + inc hl + djnz test_stlp2 + ret +; +test_stlp3: + call nl + ld c,d + ld a,(hl) + call prthexbyte + out (c),a + push hl + ld hl,str_arrow + call pstr + pop hl + ld c,e + in a,(c) + call prthexbyte + cp (hl) + ret +; +; +; +getchan: + ld a,(ix) ; get byte + sub 'A' ; convert to binary + cp 2 ; check for max value + ret nc ; return with NZ if too high + ld (channel),a ; save new value + cp a ; set ZF + ret ; done +; +; +; +reset: + ld a,(iobase) + add a,ioctla + ld c,a + call reset1 + ld a,(iobase) + add a,ioctlb + ld c,a + jr reset1 +; +reset1: + ld a,%01001111 ; set mode 1 (input) + out (c),a + ;ld a,%00010111 ; clear interrupt ctl word + ;out (c),a + ;ld a,%11111111 ; clear mask + ;out (c),a + ;ld a,%00000000 ; clear interrupt vector + ;out (c),a + ret +; +; +; +ctlport: + ld a,(iobase) ; base port + add a,ioctla ; offset to control ports + ld c,a ; put in c + ld a,(channel) ; get channel + add a,c ; combine + ld c,a + ret +; +; +; +dataport: + ld a,(iobase) ; base port + add a,iodata ; offset to data ports + ld c,a ; put in c + ld a,(channel) ; get channel + add a,c ; combine + ld c,a + ret +; +; Error Handlers +; +err_abort: + ld hl,str_err_abort + jr err_ret +err_invcmd: + ld hl,str_err_invcmd + jr err_ret +err_fail: + ld hl,str_err_fail + jr err_ret +; +err_ret: + push hl + ld hl,str_err_prefix + call pstr + pop hl + jp pstr +; +str_err_prefix .db bel,"\r\n\r\n*** ",0 +str_err_abort .db "User Aborted",0 +str_err_invcmd .db "Invalid command, press '?' for help",0 +str_err_fail .db "Test failed!",0 +; +;======================================================================= +; Utility functions +;======================================================================= +; +; Print string at HL on console, null terminated +; +pstr: + push af + push hl +pstr1: + ld a,(hl) ; get next character + or a ; set flags + inc hl ; bump pointer regardless + jr z,pstr2 ; done if null + call cout ; display character + jr pstr1 ; loop till done +pstr2: + pop hl + pop af + ret +; +; Print volume label string at HL, '$' terminated, 16 chars max +; +pvol: + ld b,16 ; init max char downcounter +pvol1: + ld a,(hl) ; get next character + cp '$' ; set flags + inc hl ; bump pointer regardless + ret z ; done if null + call cout ; display character + djnz pvol1 ; loop till done + ret ; hit max of 16 chars +; +; Start a newline on console (cr/lf) +; +nl2: + call nl ; double newline +nl: + ld a,cr ; cr + call cout ; send it + ld a,lf ; lf + jp cout ; send it and return +; +; Print a dot on console +; +pdot: + push af + ld a,'.' + call cout + pop af + ret +; +; +; +keychk: + call cst + or a + ret z + call cin + or $FF + ret +; +; Read a string on the console to cmdbuf +; +; Input is zero terminated +; +rdln: + ld de,cmdbuf ; init buffer address ptr +rdln_nxt: + call cin ; get a character + cp bs ; backspace? + jr z,rdln_bs ; handle it if so + cp cr ; return? + jr z,rdln_cr ; handle it if so +; + ; check for non-printing characters + cp ' ' ; first printable is space char + jr c,rdln_bel ; too low, beep and loop + cp '~'+1 ; last printable char + jr nc,rdln_bel ; too high, beep and loop +; + ; need to check for buffer overflow here!!! + ld hl,cmdbuf+buflen ; max cmd length + or a ; clear carry + sbc hl,de ; test for max + jr z,rdln_bel ; at max, beep and loop +; + ; good to go, echo and store character + call upcase + call cout ; echo character input + ld (de),a ; save in buffer + inc de ; inc buffer ptr + jr rdln_nxt ; loop till done +; +rdln_bs: + ld hl,cmdbuf ; start of buffer + or a ; clear carry + sbc hl,de ; subtract from cur buf ptr + jr z,rdln_bel ; at buf start, just beep + ld hl,str_bs ; backspace sequence + call pstr ; send it + dec de ; backup buffer pointer + jr rdln_nxt ; and loop +; +rdln_bel: + ld a,bel ; Bell characters + call cout ; send it + jr rdln_nxt ; and loop +; +rdln_cr: + xor a ; null to A + ld (de),a ; store terminator + ret ; and return +; +; Find next whitespace character at buffer adr in DE, returns with first +; whitespace character in A. +; +findws: + ld a,(ix) ; get next char + or a ; check for eol + ret z ; done if so + cp ' ' ; blank? + ret z ; nope, done + inc ix ; bump buffer pointer + jr findws ; and loop +; +; Skip whitespace at buffer adr in DE, returns with first +; non-whitespace character in A. +; +skipws: + ld a,(ix) ; get next char + or a ; check for eol + ret z ; done if so + cp ' ' ; blank? + ret nz ; nope, done + inc ix ; bump buffer pointer + jr skipws ; and loop +; +; Uppercase character in A +; +upcase: + cp 'a' ; below 'a'? + ret c ; if so, nothing to do + cp 'z'+1 ; above 'z'? + ret nc ; if so, nothing to do + and ~$20 ; convert character to lower + ret ; done +; +; Get numeric chars at IX and convert to number returned in A +; Carry flag set on overflow +; +getnum: + ld c,0 ; C is working register +getnum1: + ld a,(ix) ; get the active char + cp '0' ; compare to ascii '0' + jr c,getnum2 ; abort if below + cp '9' + 1 ; compare to ascii '9' + jr nc,getnum2 ; abort if above +; + ; valid digit, add new digit to C + ld a,c ; get working value to A + rlca ; multiply by 10 + ret c ; overflow, return with carry set + rlca ; ... + ret c ; overflow, return with carry set + add a,c ; ... + ret c ; overflow, return with carry set + rlca ; ... + ret c ; overflow, return with carry set + ld c,a ; back to C + ld a,(ix) ; get new digit + sub '0' ; make binary + add a,c ; add in working value + ret c ; overflow, return with carry set + ld c,a ; back to C +; + inc ix ; bump to next char + jr getnum1 ; loop +; +getnum2: ; return result + ld a,c ; return result in A + or a ; with flags set, CF is cleared + ret +; +; Get hex chars at IX and convert to binary number returned in A +; Carry flag set on overflow +; +gethex: + ld c,0 ; C is working register +gethex1: + ld a,(ix) ; get the active char + call ishex ; is it a hex char? + jr nz,gethex9 ; abort if not +; + ; valid digit, add new digit to C + ld a,c ; get working value to A + rlca ; multiply by 16 + ret c ; overflow, return with carry set + rlca ; ... + ret c ; overflow, return with carry set + rlca ; ... + ret c ; overflow, return with carry set + rlca ; ... + ret c ; overflow, return with carry set + ld c,a ; back to C + ld a,(ix) ; get new hex digit + call isnum ; regular number? + jr z,gethex2 ; if so, handle it, else hex char + sub 'A'-10 ; convert to binary + jr gethex3 ; and continue +gethex2: + sub '0' ; convert to binary +gethex3: + add a,c ; add in working value + ret c ; overflow, return with carry set + ld c,a ; back to C +; + inc ix ; bump to next char + jr gethex1 ; loop +; +gethex9: ; return result + ld a,c ; return result in A + or a ; with flags set, CF is cleared + ret +; +; Is character in A numberic? NZ if not +; +isnum: + cp '0' ; compare to ascii '0' + jr c,isnum1 ; abort if below + cp '9' + 1 ; compare to ascii '9' + jr nc,isnum1 ; abort if above + cp a ; set Z + ret +isnum1: + cp '0' ; set NZ w/o changing value + ret ; and done +; +; Is character in A hex? NZ if not +; +ishex: + call isnum ; is it a numeric? + ret z ; if so, all done + cp 'A' ; first hex char + jr c,ishex1 ; abort if below + cp 'F' + 1 ; last hex char + jr nc,ishex1 ; abort if above + cp a ; set Z + ret ; done +ishex1: + cp '0' ; set NZ w/o changing value + ret ; done +; +; Delay 16us (cpu speed compensated) incuding call/ret invocation +; Register A and flags destroyed +; No compensation for z180 memory wait states +; There is an overhead of 3ts per invocation +; Impact of overhead diminishes as cpu speed increases +; +; cpu scaler (cpuscl) = (cpuhmz - 2) for 16us + 3ts delay +; note: cpuscl must be >= 1! +; +; example: 8mhz cpu (delay goal is 16us) +; loop = ((6 * 16) - 5) = 91ts +; total cost = (91 + 40) = 131ts +; actual delay = (131 / 8) = 16.375us +; + ; --- total cost = (loop cost + 40) ts -----------------+ +delay: ; 17ts (from invoking call) | + ld a,(cpuscl) ; 13ts | +; | +delay1: ; | + ; --- loop = ((cpuscl * 16) - 5) ts ------------+ | + dec a ; 4ts | | + jr nz,delay1 ; 12ts (nz) / 7ts (z) | | + ; ----------------------------------------------+ | +; | + ret ; 10ts (return) | + ;-------------------------------------------------------+ +; +; Delay 16us * DE (cpu speed compensated) +; Register DE, A, and flags destroyed +; No compensation for z180 memory wait states +; There is a 27ts overhead for call/ret per invocation +; Impact of overhead diminishes as DE and/or cpu speed increases +; +; cpu scaler (cpuscl) = (cpuhmz - 2) for 16us outer loop cost +; note: cpuscl must be > 0! +; +; Example: 8MHz cpu, DE=6250 (delay goal is .1 sec or 100,000us) +; inner loop = ((16 * 6) - 5) = 91ts +; outer loop = ((91 + 37) * 6250) = 800,000ts +; actual delay = ((800,000 + 27) / 8) = 100,003us +; + ; --- total cost = (outer loop + 27) ts ------------------------+ +vdelay: ; 17ts (from invoking call) | +; | + ; --- outer loop = ((inner loop + 37) * de) ts ---------+ | + ld a,(cpuscl) ; 13ts | | +; | | +vdelay1: ; | | + ; --- inner loop = ((cpuscl * 16) - 5) ts ------+ | | + dec a ; 4ts | | | + jr nz,vdelay1 ; 12ts (nz) / 7ts (z) | | | + ; ----------------------------------------------+ | | +; | | + dec de ; 6ts | | + ld a,d ; 4ts | | + or e ; 4ts | | + jp nz,vdelay ; 10ts | | + ;-------------------------------------------------------+ | +; | + ret ; 10ts (final return) | + ;---------------------------------------------------------------+ +; +; Delay about 0.5 seconds +; 500000us / 16us = 31250 +; +ldelay: + push af + push de + ld de,31250 + call vdelay + pop de + pop af + ret +; +#if (cpumhz < 3) +cpuscl .db 1 ; cpu scaler must be > 0 +#else +cpuscl .db cpumhz - 2 ; otherwise 2 less than phi mhz +#endif +; +; Print value of a in decimal with leading zero suppression +; +prtdecb: + push hl + push af + ld l,a + ld h,0 + call prtdec + pop af + pop hl + ret +; +; Print value of HL in decimal with leading zero suppression +; +prtdec: + push bc + push de + push hl + ld e,'0' + ld bc,-10000 + call prtdec1 + ld bc,-1000 + call prtdec1 + ld bc,-100 + call prtdec1 + ld c,-10 + call prtdec1 + ld e,0 + ld c,-1 + call prtdec1 + pop hl + pop de + pop bc + ret +prtdec1: + ld a,'0' - 1 +prtdec2: + inc a + add hl,bc + jr c,prtdec2 + sbc hl,bc + cp e + jr z,prtdec3 + ld e,0 + call cout +prtdec3: + ret +; +; Short delay functions. No clock speed compensation, so they +; will run longer on slower systems. The number indicates the +; number of call/ret invocations. A single call/ret is +; 27 t-states on a z80, 25 t-states on a z180. +; +; ; z80 z180 +; ; ---- ---- +dly64: call dly32 ; 1728 1600 +dly32: call dly16 ; 864 800 +dly16: call dly8 ; 432 400 +dly8: call dly4 ; 216 200 +dly4: call dly2 ; 108 100 +dly2: call dly1 ; 54 50 +dly1: ret ; 27 25 +; +; Add hl,a +; +; A register is destroyed! +; +addhla: + add a,l + ld l,a + ret nc + inc h + ret +; +; +; +prtdot: + push af + ld a,'.' + call cout + pop af + ret +; +; Print the hex byte value in A +; +prthexbyte: + push af + push de + call hexascii + ld a,d + call cout + ld a,e + call cout + pop de + pop af + ret +; +; Print the hex word value in BC +; +prthexword: + push af + ld a,b + call prthexbyte + ld a,c + call prthexbyte + pop af + ret +; +; Print the hex dword value in DE:HL +; +prthex32: + push bc + push de + pop bc + call prthexword + push hl + pop bc + call prthexword + pop bc + ret +; +; Convert binary value in A to ASCII hex characters in DE +; +hexascii: + ld d,a + call hexconv + ld e,a + ld a,d + rlca + rlca + rlca + rlca + call hexconv + ld d,a + ret +; +; Convert low nibble of A to ASCII hex +; +hexconv: + and 0Fh ; low nibble only + add a,90h + daa + adc a,40h + daa + ret +; +; Output character from A +; +cout: + ; Save all incoming registers + push af + push bc + push de + push hl +; + ; Output character to console via BDOS + ld e,a ; output char to E + ld c,6 ; BDOS direct console I/O + call bdos ; output character +; + ; Restore all registers + pop hl + pop de + pop bc + pop af + ret +; +; Input character to A +; +cin: + ; Save incoming registers (AF is output) + push bc + push de + push hl +; + ; Input character from console via BDOS +cin1: + ld e,$FF ; input request + ld c,6 ; BDOS direct console I/O + call bdos ; input character to A + or a ; test for zero (no input) + jr z,cin1 ; loop till we have a char +; + ; Restore registers (AF is output) + pop hl + pop de + pop bc + ret +; +; Return input status in A (0 = no char, != 0 char waiting) +; +cst: + ; Save incoming registers (AF is output) + push bc + push de + push hl +; + ; Get console input status via BDOS + ld e,$FE ; status + ld c,6 ; BDOS direct console I/O + call bdos ; input status to A +; + ; Restore registers (AF is output) + pop hl + pop de + pop bc + ret +; +; +; +;======================================================================= +; Constants +;======================================================================= +; +str_banner .db "Zilog PIO Monitor v0.1, 14-Mar-2022\r\n" + .db "Press ? for help$" +str_bs .db bs,' ',bs,0 +str_port1 .db "\r\n\r\nEnter PIO port in hex [",0 +str_port2 .db "]:",0 +str_pre .db "Zilog PIO @ Port 0x",0 +str_pre2 .db "\r\n\r\n>",0 +str_exit .db "Done, Thank you for using Zilog PIO Monitor!",0 +str_reschip1 .db "\r\n\r\nFull Reset of PIO Chip... ",0 +str_reschip2 .db "Done",0 +str_int1 .db "\r\nChannel A Interrupts=",0 +str_int2 .db ", Channel B Interrupts=",0 +str_watch1 .db "\r\n\r\nWatching Channel ",0 +str_watch2 .db ", press any to end...",0 +str_watchtag .db "\rPort Value=0x",0 +str_input1 .db "\r\n\r\nValue of Pins on Channel ",0 +str_input2 .db " = 0x",0 +str_output1 .db "\r\n\r\nSetting Value of Pins on Channel ",0 +str_output2 .db " = 0x",0 +str_receive1 .db "\r\n\r\nReceived from Channel ",0 +str_receive2 .db " = 0x",0 +str_send1 .db "\r\n\r\nSent to Channel ",0 +str_send2 .db " = 0x",0 +str_rdbk .db "\r\n\r\nReadback Test on Channel ",0 +str_arrow .db " --> ",0 +str_lpbkAB .db "\r\n\r\nLoopback Test in Bit Control Mode A->B...\r\n",0 +str_lpbkBA .db "\r\n\r\nLoopback Test in Bit Control Mode B->A...\r\n",0 +str_stlpAB .db "\r\n\r\nLoopback Test in Strobed Mode A->B...\r\n",0 +str_stlpBA .db "\r\n\r\nLoopback Test in Strobed Mode B->A...\r\n",0 +str_usage .db "\r\n" + .db "\r\n P n - Set Current PIO Base Port" + .db "\r\n Z - Reset PIO (both channels)" + .db "\r\n Wc - Watch Channel c Pin Values (bit control)" + .db "\r\n Oc n - Output Channel c Pin Values (bit control)" + .db "\r\n Ic - Input Channel c Pin Values (bit control)" + .db "\r\n Sc n - Send Value to Channel c (strobed)" + .db "\r\n Rc - Receive Value from Channel c (strobed)" + .db "\r\n TRc - Test Readback on Channel c (bit control)" + .db "\r\n TL - Test Loopback (bit control)" + .db "\r\n TS - Test Loopback (strobed)" + .db "\r\n H,? - Help" + .db "\r\n X - Exit" + .db "\r\n " + .db "\r\n Loopback tests require hardware loopback (see readme.txt)" + .db 0 +; +;======================================================================= +; Working data +;======================================================================= +; +stksav .dw 0 ; stack pointer saved at start + .fill stksiz,0 ; stack +stack .equ $ ; stack top +; +iobase .db iodef ; current I/O base address +channel .db 0 ; current channel +wrkval .db 0 +; +cmdbuf .fill buflen+1,0 +; +vallist: + .db $00,$FF,$AA,$55,$A5,$5A,$FF,$00 +vallen .equ $ - vallist +; +orgveca .dw 0 ; saved int vector, channel A +orgvecb .dw 0 ; saved int vector, channel B +; +;=============================================================================== +; Interrupt Handler +;=============================================================================== +; +reladr .equ $ ; relocation start adr +; + .org $A000 ; code will run here +; +inta: +; + ld hl,(intcnta) + inc hl + ld (intcnta),hl +; + or $ff ; signal int handled + ret +; +intb: +; + ld hl,(intcntb) + inc hl + ld (intcntb),hl +; + or $ff ; signal int handled + ret +; +intcnta .dw 0 +intcntb .dw 0 +; +hsiz .equ $ - $A000 ; size of handler to relocate +; + .org reladr + hsiz +; + .end + \ No newline at end of file diff --git a/Source/Apps/Test/ps2info/Build.cmd b/Source/Apps/Test/ps2info/Build.cmd new file mode 100644 index 00000000..965883ce --- /dev/null +++ b/Source/Apps/Test/ps2info/Build.cmd @@ -0,0 +1,10 @@ +@echo off +setlocal + +set TOOLS=../../../../Tools +set PATH=%TOOLS%\tasm32;%PATH% +set TASMTABS=%TOOLS%\tasm32 + +tasm -t180 -g3 -fFF ps2info.asm ps2info.com ps2info.lst || exit /b + +copy /Y ps2info.com ..\..\..\..\Binary\Apps\Test\ || exit /b diff --git a/Source/Apps/Test/ps2info/Clean.cmd b/Source/Apps/Test/ps2info/Clean.cmd new file mode 100644 index 00000000..9ecb428f --- /dev/null +++ b/Source/Apps/Test/ps2info/Clean.cmd @@ -0,0 +1,6 @@ +@echo off +setlocal + +if exist *.com del *.com +if exist *.lst del *.lst +if exist *.bin del *.bin diff --git a/Source/Apps/Test/ps2info/Makefile b/Source/Apps/Test/ps2info/Makefile new file mode 100644 index 00000000..33330b47 --- /dev/null +++ b/Source/Apps/Test/ps2info/Makefile @@ -0,0 +1,7 @@ +OBJECTS = ps2info.com +DEST = ../../../../Binary/Apps/Test +TOOLS =../../../../Tools + +USETASM=1 + +include $(TOOLS)/Makefile.inc \ No newline at end of file diff --git a/Source/Apps/Test/kbdinfo/kbdinfo.asm b/Source/Apps/Test/ps2info/ps2info.asm similarity index 53% rename from Source/Apps/Test/kbdinfo/kbdinfo.asm rename to Source/Apps/Test/ps2info/ps2info.asm index 151db818..8a517a22 100644 --- a/Source/Apps/Test/kbdinfo/kbdinfo.asm +++ b/Source/Apps/Test/ps2info/ps2info.asm @@ -1,17 +1,17 @@ ; ;======================================================================= -; Keyboard Information Utility (KBDINFO) +; PS/2 Keyboard/Mouse Information Utility (PS2INFO) ;======================================================================= ; -; Simple utility that attempts to determine the type of keyboard you -; have attached to an 8242 keyboard controller. +; Simple utility that performs simple tests of an 8242 PS/2 controller, +; keyboard, and mouse. ; ;======================================================================= ; -; Keyboard controller port addresses (adjust as needed) +; PS/2 Keyboard/Mouse controller port addresses (adjust as needed) ; -iocmd .equ $E3 ; keyboard controller command port address -iodat .equ $E2 ; keyboard controller data port address +iocmd .equ $E3 ; PS/2 controller command port address +iodat .equ $E2 ; PS/2 controller data port address ; cpumhz .equ 8 ; for time delay calculations (not critical) ; @@ -39,10 +39,6 @@ bdos .equ $0005 ; BDOS invocation vector call prtstr ; call main ; do the real work - jr z,exit ; completed all tests - ld de,str_run_failed - call crlf2 - call prtstr ; exit: call crlf2 @@ -61,7 +57,7 @@ exit: ; main: ; -; Display active keyboard controller port addresses +; Display active controller port addresses ; call crlf2 ld de,str_cmdport @@ -73,16 +69,66 @@ main: call prtstr ld a,iodat call prthex +; + call test_ctlr + jr z,main0 ; continue if ctlr OK + ld de,str_kbd_failed + call crlf2 + call prtstr + jr mainz ; bail out if ctlr fails +; +main0: + call test_kbd + jr z,main1 ; completed all tests, continue + ld de,str_kbd_failed + call crlf2 + call prtstr +; +main1: + call test_mse + jr z,main2 ; completed all tests, continue + ld de,str_mse_failed + call crlf2 + call prtstr +; +main2: + call test_kbdmse +; +mainz: + xor a + ret +; +; Test 8242 PS/2 Controller +; +test_ctlr: + call crlf2 + ld de,str_ctlr + call prtstr +; + call ctlr_test + ret nz +; + call ctlr_test_p1 + ;ret nz +; + call ctlr_test_p2 + ;ret nz +; + ret +; +; Test Keyboard +; +test_kbd: ; ; First, we attempt to contact the controller and keyboard, then -; print the keyboard identity and scan codes scupported +; print the keyboard identity and scan codes supported ; ; Run test series with translation off call crlf2 ld de,str_basic call prtstr ; - call do_basic + call test_kbd_basic ret nz ; ; We make two passes through the test series with different controller @@ -94,29 +140,78 @@ main: ld de,str_trans_off call prtstr ; - ld a,$20 ; xlat disabled, mouse disabled, no ints + ld a,$20 ; kbd enabled, xlat disabled, mouse disabled, no ints ld (ctlr_cfgval),a - call do_tests + call test_kbd_keys ; ; Run test series with translation on call crlf2 ld de,str_trans_on call prtstr ; - ld a,$60 ; xlat enabled, mouse disabled, no ints + ld a,$60 ; kbd enabled, xlat enabled, mouse disabled, no ints ld (ctlr_cfgval),a - call do_tests - + call test_kbd_keys +; + ret +; +; Test Mouse +; +test_mse: + call crlf2 + ld de,str_basic_mse + call prtstr +; + ld a,$10 ; kbd disabled, mse enabled, no ints + call ctlr_setup + ret nz +; + call mse_reset + ret nz +; + call mse_ident + ret nz +; + call mse_stream + ret nz +; + call mse_echo +; xor a ; signal success ret ; -; Perform basic keyboard tests, display keyboard identity, and -; inventory the supported scan code sets. +; Test Everything ; -do_basic: - call ctlr_test +test_kbdmse: + call crlf2 + ld de,str_kbdmse + call prtstr +; + ld a,$00 ; kbd enabled, mse enabled, no ints + call ctlr_setup ret nz ; + call kbd_reset + ret nz +; + ld a,2 + call kbd_setsc +; + call mse_reset + ret nz +; + call mse_stream + ret nz +; + call kbdmse_echo +; + xor a ; signal success + ret +; +; Perform basic keyboard tests, display keyboard identity, and +; inventory the supported scan code sets. +; +test_kbd_basic: ld a,$20 ; Xlat off for this checking call ctlr_setup ret nz @@ -129,7 +224,7 @@ do_basic: ; ld b,3 ; Loop control, 3 scan code sets ld c,1 ; Current scan code number -do_basic1: +test_kbd_basic1: ld a,c ; Scan code set to A push bc call kbd_setsc ; Attempt to set it @@ -142,12 +237,12 @@ do_basic1: call prtdecb pop af ; restore result ld de,str_sc_ok - jr z,do_basic2 + jr z,test_kbd_basic2 ld de,str_sc_fail -do_basic2: +test_kbd_basic2: call prtstr inc c - djnz do_basic1 + djnz test_kbd_basic1 ; xor a ; signal success ret @@ -156,10 +251,7 @@ do_basic2: ; desired controller setup value should be placed in ctlr_cfgval ; prior to invoking this routine. ; -do_tests: - call ctlr_test - ret nz -; +test_kbd_keys: ld a,(ctlr_cfgval) call ctlr_setup ret nz @@ -177,19 +269,19 @@ do_tests: call kbd_dispsc ;ret nz ; - call kbd_showkeys + call kbd_echo ;ret nz ; xor a ; signal success ret ; ;======================================================================= -; Keyboard/Controller Test Routines +; Controller/Keyboard/Mouse Test Routines ;======================================================================= ; -; Attempt self-test command on keyboard controller +; Attempt self-test command on PS/2 controller ; -; Keyboard controller should respond with an 0x55 on data port +; PS/2 controller should respond with an 0x55 on data port ; after being sent a 0xAA on the command port. ; ctlr_test: @@ -209,9 +301,47 @@ ctlr_test: xor a ret ; -; Keyboard controller setup +; Attempt self-test of first port of controller +; +ctlr_test_p1: + call crlf2 + ld de,str_ctlr_test_p1 + call prtstr + ld a,$ab ; self-test first port + call put_cmd_dbg + jp c,err_ctlr_to ; handle controller error + call get_data_dbg + jp c,err_ctlr_to ; handle controller error + cp $00 ; expected value? + jp nz,err_ctlr_test_p1 ; handle self-test error + call crlf + ld de,str_ctlr_test_p1_ok + call prtstr + xor a + ret +; +; Attempt self-test of second port of controller ; -; Set keyboard controller command register to value in A +ctlr_test_p2: + call crlf2 + ld de,str_ctlr_test_p2 + call prtstr + ld a,$a9 ; self-test second port + call put_cmd_dbg + jp c,err_ctlr_to ; handle controller error + call get_data_dbg + jp c,err_ctlr_to ; handle controller error + cp $00 ; expected value? + jp nz,err_ctlr_test_p2 ; handle self-test error + call crlf + ld de,str_ctlr_test_p2_ok + call prtstr + xor a + ret +; +; PS/2 controller setup +; +; Set controller command register to value in A ; ctlr_setup: push af ; save incoming value @@ -243,7 +373,7 @@ kbd_reset: jp nz,err_kbd_reset call get_data_dbg jp c,err_ctlr_to ; handle controller error - cp $AA ; Success? + cp $aa ; Success? jp nz,err_kbd_reset call crlf ld de,str_kbd_reset_ok @@ -313,7 +443,7 @@ kbd_ident4: xor a ret ; -; Display active scan code set being used +; Display keyboard active scan code set being used ; kbd_dispsc: call crlf2 @@ -344,7 +474,7 @@ kbd_dispsc: xor a ret ; -; Set active scan code set to value in A +; Set keyboard active scan code set to value in A ; kbd_setsc: ld (kbd_setsc_val),a ; Save incoming value @@ -371,10 +501,9 @@ kbd_setsc: ; kbd_setsc_val .db 0 ; -; ; Read and display raw scan codes ; -kbd_showkeys: +kbd_echo: call crlf2 ld de,str_disp_scan_codes call prtstr @@ -384,7 +513,7 @@ read_loop: call bdos cp $1B ; Escape key? ret z - call check_read + call check_read_kbd jr nz,read_loop call get_data jp c,err_ctlr_to ; handle controller error @@ -399,13 +528,255 @@ read_loop: call prtchr jr read_loop ; +; Reset Mouse +; +mse_reset: + call crlf2 + ld de,str_mse_reset + call prtstr + ld a,$f2 ; Identify mouse command + call put_data_mse_dbg + jp c,err_ctlr_to ; handle controller error + call get_data_dbg + jp c,err_ctlr_to ; handle controller error + cp $fa ; Is it an ack as expected? + jp nz,err_mse_reset + call crlf + ld de,str_mse_reset_ok + call prtstr + xor a + ret +; +; Identify Mouse +; +mse_ident: + call crlf2 + ld de,str_mse_ident + call prtstr + ld a,$f2 ; Identify mouse command + call put_data_mse_dbg + jp c,err_ctlr_to ; handle controller error + call get_data_dbg + jp c,err_ctlr_to ; handle controller error + cp $fa ; Is it an ack as expected? + jp nz,err_mse_ident + call get_data_dbg + jp c,err_ctlr_to ; handle controller error + push af + call crlf + ld de,str_mse_ident_disp + call prtstr + pop af + call prtdecb + xor a + ret +; +; Enable mouse packet streaming +; +mse_stream: + call crlf2 + ld de,str_mse_stream + call prtstr + ld a,$f4 ; Stream packets cmd + call put_data_mse_dbg + jp c,err_ctlr_to ; handle controller error + call get_data_dbg + jp c,err_ctlr_to ; handle controller error + cp $FA ; Is it an ack as expected? + jp nz,err_mse_stream + xor a + ret +; +; Read and display raw mouse packets +; +mse_echo: + call crlf2 + ld de,str_disp_mse_pkts + call prtstr + call mse_track_disp ; show mouse status + xor a + ld (msebuflen),a +mse_echo1: + ld c,$06 ; BDOS direct console I/O + ld e,$FF ; Subfunction = read + call bdos + cp $1B ; Escape key? + ret z + call check_read_mse + jr nz,mse_echo1 + call get_data + jp c,err_ctlr_to ; handle controller error + push af + ld a,(msebuflen) ; current bytes in buf + ld hl,msebuf ; start of buf + call addhla ; point to next buf pos + pop af + ld (hl),a ; save byte in buf + ld a,(msebuflen) + inc a + ld (msebuflen),a ; inc buf len + cp 3 ; got 3 bytes? + jr nz,mse_echo1 ; if not, get some more + call mse_track + call mse_track_disp + jr mse_echo1 ; and loop +; +; Read and display data from keyboard and mouse +; +kbdmse_echo: + call crlf2 + ld de,str_disp_kbdmse + call prtstr + xor a + ld (msebuflen),a + call kbdmse_track_disp +; +kbdmse_echo1: + ; Check for user abort + ld c,$06 ; BDOS direct console I/O + ld e,$FF ; Subfunction = read + call bdos + cp $1B ; Escape key? + ret z +; + call kbdmse_echo2 + call kbdmse_echo3 + jr kbdmse_echo1 +; +kbdmse_echo2: + ; Check & handle keyboard data + call check_read_kbd + ret nz + call get_data + ld (kbd_byte),a + call kbdmse_track_disp + ret +; +kbdmse_echo3: + ; Check & handle mouse data + call check_read_mse + ret nz + call get_data + jp c,err_ctlr_to ; handle controller error + push af + ld a,(msebuflen) ; current bytes in buf + ld hl,msebuf ; start of buf + call addhla ; point to next buf pos + pop af + ld (hl),a ; save byte in buf + ld a,(msebuflen) + inc a + ld (msebuflen),a ; inc buf len + cp 3 ; full packet? + ret nz ; if not, loop + call mse_track + call kbdmse_track_disp + ret +; +; Update mouse tracking stuff +; This routine assumes that msebuf has been filled with a complete +; 3 byte mouse packet. +; +mse_track: + ; Buttons... + ld a,(msebuf) + ld (mse_stat),a +; + ; X Coordinate + ld a,(msebuf+1) + ld e,a + ld d,0 + ld a,(msebuf) + and %00010000 ; sign bit + jr z,mse_track_x + ld d,$ff ; sign extend +mse_track_x: + ld hl,(mse_x) + add hl,de + ld (mse_x),hl ; save result +; + ; Y Coordinate + ld a,(msebuf+2) + ld e,a + ld d,0 + ld a,(msebuf) + and %00100000 ; sign bit + jr z,mse_track_y + ld d,$ff ; sign extend +mse_track_y: + ld hl,(mse_y) + add hl,de + ld (mse_y),hl ; save result +; + ; Reset mouse buffer + xor a + ld (msebuflen),a + ret +; +; Display current mouse tracking info (buttons and coordinates) +; +mse_track_disp: + ld a,13 ; CR only + call prtchr + ld de,str_msestat1 ; "L=" + call prtstr + ld a,(mse_stat) + and %00000001 + call updown + ld de,str_msestat2 ; ", M=" + call prtstr + ld a,(mse_stat) + and %00000100 + call updown + ld de,str_msestat3 ; ", R=" + call prtstr + ld a,(mse_stat) + and %00000010 + call updown +; + ld de,str_msestat4 ; ", X=" + call prtstr + ld hl,(mse_x) ; save result + call prthexword +; + ld de,str_msestat5 ; ", Y=" + call prtstr + ld hl,(mse_y) ; save result + call prthexword +; + ret +; +updown: + jr nz,updown1 + ld de,str_up + jr updown2 +updown1: + ld de,str_down +updown2: + call prtstr + ret +; +; Display all keyboard and mouse tracking +; +kbdmse_track_disp: + call mse_track_disp + ld a,' ' + call prtchr + ld a,'[' + call prtchr + ld a,(kbd_byte) + call prthex + ld a,']' + call prtchr + ret +; ;======================================================================= -; Keyboard Controller I/O Routines +; PS/2 Controller I/O Routines ;======================================================================= ; wait_write: ; -; Wait for keyboard controller to be ready for a write +; Wait for controller to be ready for a write ; A=0 indicates success (ZF set) ; ld a,(timeout) ; setup timeout constant @@ -427,7 +798,7 @@ wait_write1: ; wait_read: ; -; Wait for keyboard controller to be ready to read a byte +; Wait for controller to be ready to read a byte ; A=0 indicates success (ZF set) ; ld a,(timeout) ; setup timeout constant @@ -458,9 +829,29 @@ check_read: xor $01 ; invert so 0 means ready ret ; +check_read_kbd: +; +; Check for keyboard data ready to read +; A=0 indicates data available (ZF set) +; + in a,(iocmd) ; get status + and %00100001 ; isolate input buf status bit + cp %00000001 ; data ready, not mouse + ret +; +check_read_mse: +; +; Check for mouse data ready to read +; A=0 indicates data available (ZF set) +; + in a,(iocmd) ; get status + and %00100001 ; isolate input buf status bit + cp %00100001 ; data ready, is mouse + ret +; put_cmd: ; -; Put a cmd byte from A to the keyboard interface with timeout +; Put a cmd byte from A to the controller with timeout ; CF set indicates timeout error ; ld e,a ; save incoming value @@ -484,18 +875,12 @@ put_cmd_dbg: call prtstr call prthex -; ld de,str_prefix ; " " -; call prtstr -; call prthex -; ld de,str_cmdout ; "->(CMD)" -; call prtstr - pop af ret ; put_data: ; -; Put a data byte from A to the keyboard interface with timeout +; Put a data byte from A to the controller interface with timeout ; CF set indicates timeout error ; ld e,a ; save incoming value @@ -519,17 +904,41 @@ put_data_dbg: call prtstr call prthex -; ld de,str_prefix ; " " -; call prtstr -; call prthex -; ld de,str_dataout ; "->(DATA)" -; call prtstr - pop af ret +; +put_data_mse: +; +; Put a data byte from A to the mouse interface with timeout +; CF set indicates timeout error +; + ld e,a ; save incoming value + push de + + ld a,$d4 ; mouse channel prefix + call put_cmd + pop de + ret c + + ld a,e ; recover value + call put_data + ret +; +put_data_mse_dbg: + ld e,a ; save incoming value + push de + + ld a,$d4 ; mouse channel prefix + call put_cmd_dbg + pop de + ret c + + ld a,e ; recover value + call put_data_dbg + ret ; -; Get a data byte from the keyboard interface to A with timeout +; Get a data byte from the controller interface to A with timeout ; CF set indicates timeout error ; get_data: @@ -552,10 +961,6 @@ get_data_dbg: call prtstr call prthex -; ld de,str_datain ; " (DATA)->" -; call prtstr -; call prthex - pop af ret ; @@ -569,6 +974,14 @@ err_ctlr_test: ld de,str_err_ctlr_test jr err_ret ; +err_ctlr_test_p1: + ld de,str_err_ctlr_test_p1 + jr err_ret +; +err_ctlr_test_p2: + ld de,str_err_ctlr_test_p2 + jr err_ret +; err_kbd_reset: ld de,str_err_kbd_reset jr err_ret @@ -585,6 +998,18 @@ err_kbd_ident: ld de,str_err_kbd_ident jr err_ret ; +err_mse_reset: + ld de,str_err_mse_reset + jr err_ret +; +err_mse_ident: + ld de,str_err_mse_ident + jr err_ret +; +err_mse_stream: + ld de,str_err_mse_stream + jr err_ret +; err_ret: call crlf2 call prtstr @@ -648,7 +1073,6 @@ prthexpre: call prtchr pop af ret - ; ; Print the value in A in hex without destroying any registers ; @@ -779,6 +1203,17 @@ crlf: pop af ; restore AF ret ; +; Add hl,a +; +; A register is destroyed! +; +addhla: + add a,l + ld l,a + ret nc + inc h + ret +; ; Delay ~10ms ; delay: @@ -804,30 +1239,36 @@ delay1: ; Constants ;======================================================================= ; -str_banner .db "Keyboard Information v0.2, 23-Dec-2021",0 -str_exit .db "Done, Thank you for using Keyboard Information!",0 -str_cmdport .db "Keyboard Controller Command Port: ",0 -str_dataport .db "Keyboard Controller Data Port: ",0 -;str_prefix .db " ",0 -;str_cmdout .db "->(CMD)",0 -;str_dataout .db "->(DATA)",0 -;str_datain .db " (DATA)->",0 -;str_timeout_write .db "Keyboard Controller Write Timeout, Status: ",0 -;str_timeout_read .db "Keyboard Controller Read Timeout, Status: ",0 -str_err_ctlr_to .db "Keyboard Controller I/O Timeout",0 -str_err_ctlr_test .db "Keyboard Controller Self-Test Failed",0 +str_banner .db "PS/2 Keyboard/Mouse Information v0.4, 7-Jan-2022",0 +str_exit .db "Done, Thank you for using PS/2 Keyboard/Mouse Information!",0 +str_cmdport .db "Controller Command Port: ",0 +str_dataport .db "Controller Data Port: ",0 +str_err_ctlr_to .db "Controller I/O Timeout",0 +str_err_ctlr_test .db "Controller Self-Test Failed",0 str_put_cmd .db " Sent Command ",0 str_put_data .db " Sent Data ",0 str_get_data .db " Got Data ",0 str_ctlr_test .db "Attempting Controller Self-Test",0 str_ctlr_test_ok .db "Controller Self-Test OK",0 +str_ctlr_test_p1 .db "Attempting Self-Test of First Controller Port",0 +str_ctlr_test_p1_ok .db "Controller First Port Self-Test OK",0 +str_err_ctlr_test_p1 .db "Controller First Port Self-Test Failed",0 +str_ctlr_test_p2 .db "Attempting Self-Test of Second Controller Port",0 +str_ctlr_test_p2_ok .db "Controller Second Port Self-Test OK",0 +str_err_ctlr_test_p2 .db "Controller Second Port Self-Test Failed",0 str_ctlr_setup .db "Performing Controller Setup",0 +str_ctlr .db "***** Basic 8242 PS/2 Controller Tests *****",0 str_basic .db "***** Basic Keyboard Checks and Scan Code Inventory *****",0 -str_trans_off .db "***** Testing with Scan Code Translation DISABLED *****",0 -str_trans_on .db "***** Testing with Scan Code Translation ENABLED *****",0 +str_trans_off .db "***** Testing Keyboard with Scan Code Translation DISABLED *****",0 +str_trans_on .db "***** Testing Keyboard with Scan Code Translation ENABLED *****",0 +str_basic_mse .db "***** Basic Mouse Tests *****",0 +str_kbdmse .db "***** Test All Devices Combined *****",0 str_kbd_reset .db "Attempting Keyboard Reset",0 str_kbd_reset_ok .db "Keyboard Reset OK",0 str_err_kbd_reset .db "Keyboard Reset Failed",0 +str_mse_reset .db "Attempting Mouse Reset",0 +str_mse_reset_ok .db "Mouse Reset OK",0 +str_err_mse_reset .db "Mouse Reset Failed",0 str_kbd_getsc .db "Requesting Active Scan Code Set from Keyboard",0 str_kbd_dispsc .db "Active Keyboard Scan Code Set is #",0 str_err_kbd_getsc .db "Error getting Active Keyboard Scan Code Set",0 @@ -835,18 +1276,42 @@ str_kbd_setsc .db "Setting Active Keyboard Scan Code Set to #",0 str_err_kbd_setsc .db "Error setting Active Keyboard Scan Code Set",0 str_kbd_ident .db "Keyboard Identification",0 str_kbd_ident_disp .db "Keyboard Identity: ",0 +str_mse_ident .db "Mouse Identification",0 +str_mse_ident_disp .db "Mouse Identity: ",0 +str_mse_stream .db "Enable Mouse Packet Streaming",0 +str_err_mse_stream .db "Error enabling Mouse Packet Streaming",0 +str_msestat1 .db "L=",0 +str_msestat2 .db ", M=",0 +str_msestat3 .db ", R=",0 +str_msestat4 .db ", X=",0 +str_msestat5 .db ", Y=",0 +str_up .db "UP",0 +str_down .db "DN",0 str_sc_tag .db "Scan Code Set #",0 str_sc_ok .db " IS supported",0 str_sc_fail .db " IS NOT supported",0 str_err_kbd_ident .db "Error performing Keyboard Identification",0 +str_err_mse_ident .db "Error performing Mouse Identification",0 str_disp_scan_codes .db "Displaying Raw Scan Codes",13,10 .db " Press keys on test keyboard to display scan codes",13,10 .db " Press on CP/M console to end",13,10,13,10,0 -str_run_failed .db "***** HARDWARE ERROR *****",13,10,13,10 +str_disp_mse_pkts .db "Displaying Mouse Packets",13,10 + .db " Move mouse and click mouse buttons",13,10 + .db " Press on CP/M console to end",13,10,13,10,0 +str_disp_kbdmse .db "Displaying Keyboard & Mouse Activity",13,10 + .db " Press keys on test keyboard to display scan codes",13,10 + .db " Move mouse and click mouse buttons",13,10 + .db " Press on CP/M console to end",13,10,13,10,0 +str_kbd_failed .db "***** KEYBOARD HARDWARE ERROR *****",13,10,13,10 .db "A basic hardware or configuration issue prevented",13,10 - .db "Keyboard Information from completing the full set",13,10 - .db "of tests. Check your hardware and verify the port",13,10 - .db "addresses being used for the keyboard controller",0 + .db "the completion of the full set of keyboard tests.",13,10 + .db "Check your hardware and verify the port",13,10 + .db "addresses being used for the controller",0 +str_mse_failed .db "***** MOUSE HARDWARE ERROR *****",13,10,13,10 + .db "A basic hardware or configuration issue prevented",13,10 + .db "the completion of the full set of mouse tests.",13,10 + .db "Check your hardware and verify the port",13,10 + .db "addresses being used for the controller",0 ; ;======================================================================= ; Working data @@ -859,6 +1324,15 @@ stack .equ $ ; stack top workbuf .fill 8 workbuf_len .db 0 ; +msebuf .fill 5,0 +msebuflen .db 0 +; +mse_stat .db 0 +mse_x .dw 0 +mse_y .dw 0 +; +kbd_byte .db 0 +; ctlr_cfgval .db 0 ; Value for controller cmd reg 0 ; cpuscl .db cpumhz - 2 diff --git a/Source/Apps/Tune/tune.asm b/Source/Apps/Tune/tune.asm index 513c21d4..4659f556 100644 --- a/Source/Apps/Tune/tune.asm +++ b/Source/Apps/Tune/tune.asm @@ -622,6 +622,9 @@ CFGTBL: ; PLT RSEL RDAT RIN Z180 ACR ; .DB $0B, $33, $32, $32, $FF, $FF ; RCZ280 W/ LINC SOUND MODULE .DW HWSTR_LINC +; + .DB 13, $A0, $A1, $A0, $FF, $A2 ; MBC + .DW HWSTR_MBC ; .DB $FF ; END OF TABLE MARKER ; @@ -674,6 +677,7 @@ HWSTR_RCEB .DB "RC2014 Sound Module (EB)",0 HWSTR_RCEB6 .DB "RC2014 Sound Module (EBv6)",0 HWSTR_RCMF .DB "RC2014 Sound Module (MF)",0 HWSTR_LINC .DB "Z50 LiNC Sound Module",0 +HWSTR_MBC .DB "NHYODYNE Sound Module",0 MSGUNSUP .db "MYM files not supported with HBIOS yet!\r\n", 0 @@ -2649,4 +2653,3 @@ data: ; ;=============================================================================== .END - diff --git a/Source/Apps/VGM/Tunes/filthy01.vgm b/Source/Apps/VGM/Tunes/filthy01.vgm new file mode 100644 index 00000000..c161e1f3 Binary files /dev/null and b/Source/Apps/VGM/Tunes/filthy01.vgm differ 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/XM/xmhb.180 b/Source/Apps/XM/xmhb.z80 similarity index 100% rename from Source/Apps/XM/xmhb.180 rename to Source/Apps/XM/xmhb.z80 diff --git a/Source/Apps/XM/xmhb_old.180 b/Source/Apps/XM/xmhb_old.z80 similarity index 100% rename from Source/Apps/XM/xmhb_old.180 rename to Source/Apps/XM/xmhb_old.z80 diff --git a/Source/Apps/XM/xmuf.180 b/Source/Apps/XM/xmuf.z80 similarity index 100% rename from Source/Apps/XM/xmuf.180 rename to Source/Apps/XM/xmuf.z80 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/Apps/assign.asm b/Source/Apps/assign.asm index a3ed2981..258573e8 100644 --- a/Source/Apps/assign.asm +++ b/Source/Apps/assign.asm @@ -22,12 +22,14 @@ ; 2016-04-08 [WBW] Determine key memory addresses dynamically ; 2019-08-07 [WBW] Fixed DPB selection error ; 2019-11-17 [WBW] Added preliminary CP/M 3 support -; 2019-12-24 [WBW] Fixed location of BIOS save area\ +; 2019-12-24 [WBW] Fixed location of BIOS save area ; 2020-04-29 [WBW] Updated for larger DPH (16 -> 20 bytes) ; 2020-05-06 [WBW] Add patch level to version compare ; 2020-05-10 [WBW] Set media change flag in XDPH for CP/M 3 ; 2020-05-12 [WBW] Back out media change flag ; 2021-12-06 [WBW] Fix inverted ROM/RAM DPB mapping in buffer alloc +; 2022-02-28 [WBW] Use HBIOS to swap banks under CP/M 3 +; Use CPM3 BDOS direct BIOS call to get DRVTBL adr ;_______________________________________________________________________________ ; ; ToDo: @@ -43,6 +45,7 @@ stksiz .equ $40 ; Working stack size ; restart .equ $0000 ; CP/M restart vector bdos .equ $0005 ; BDOS invocation vector +bnksel .equ $FFF3 ; HBIOS bank select vector ; stamp .equ $40 ; loc of RomWBW CBIOS zero page stamp ; @@ -108,8 +111,11 @@ init: ld c,$0C ; function number call bdos ; do it, HL := version ld (cpmver),hl ; save it - ld a,l ; low byte - cp $30 ; CP/M 3.0? + ;push hl ; *debug* + ;pop bc ; *debug* + ;call prthexword ; *debug* + ;ld a,l ; low byte + ;cp $30 ; CP/M 3.0? ; ; get location of config data and verify integrity ld hl,stamp ; HL := adr or RomWBW zero page stamp @@ -231,18 +237,24 @@ initx: ; CP/M 3 initialization ; initcpm3: - ld hl,(bioloc) - ld de,22*3 ; offset of DRVTBL func - add hl,de ; HL := DRVTBL func - call jphl ; do it, HL := DRVTBL adr - ld (drvtbl),hl ; save it + ld a,22 ; XBIOS DRVTBL function + call xbios ; Invoke XBIOS + ld (drvtbl),hl ; save DRVTBL address +; +; The CP/M 3 drvtbl is in common memory, but the XDPHs are not. +; So, here we temporarily swap the bank to the CP/M 3 system +; bank. We cannot use the CP/M Direct BIOS call because it +; explicitly blocks use of SELMEM, so we are foreced to use +; HBIOS call. The CP/M 3 system bank is always the HBIOS +; user bank. ; ; switch to sysbnk - ld hl,(bioloc) - ld de,27*3 ; offset of SELMEM func - add hl,de ; HL := SELMEM func - ld a,0 ; bank 0 is system bank - call jphl + ld a,($FFE0) ; get current bank + push af ; save it + ld bc,$F8F2 ; HBIOS Get Bank Info + rst 08 ; call HBIOS, E=User Bank + ld a,e ; HBIOS User Bank + call bnksel ; HBIOS BNKSEL ; ; copy CP/M 3 drvtbl to drvmap working copy ld hl,(drvtbl) ; get drive table in HL @@ -278,11 +290,8 @@ initc4: djnz initc2 ; ; switch back to tpabnk - ld hl,(bioloc) - ld de,27*3 ; offset of SELMEM func - add hl,de ; HL := SELMEM func - ld a,1 ; bank 1 is tpa bank - call jphl + pop af ; recover prev bank + call bnksel ; HBIOS BNKSEL ; ; return success xor a ; signal success @@ -397,6 +406,15 @@ usage: call crlf ; formatting ld de,msgban1 ; point to version message part 1 call prtstr ; print it + ld de,msg22 ; assume CP/M 2.2 + ld a,(cpmver) ; low byte of ver + cp $30 ; CP/M 3.0? + jp c,usage1 ; if not, jump ahead + ld de,msg3 ; CP/M 3 +usage1: + call prtstr + ld de,msbban2 ; next portion of banner + call prtstr ld a,(unamod) ; get UNA flag or a ; set flags ld de,msghb ; point to HBIOS mode message @@ -404,7 +422,7 @@ usage: ld de,msgub ; point to UBIOS mode message call nz,prtstr ; if UNA, say so call crlf ; formatting - ld de,msgban2 ; point to version message part 2 + ld de,msgban3 ; point to version message part 2 call prtstr ; print it call crlf2 ; blank line ld de,msguse ; point to usage message @@ -728,13 +746,13 @@ makdph3: ; ; instcpm3: -; - ; switch to sysbnk - ld hl,(bioloc) - ld de,27*3 ; offset of SELMEM func - add hl,de ; HL := SELMEM func - ld a,0 ; bank 0 is system bank - call jphl + ; swicth to sysbnk + ld a,($FFE0) ; get current bank + push af ; save it + ld bc,$F8F2 ; HBIOS Get Bank Info + rst 08 ; call HBIOS, E=User Bank + ld a,e ; HBIOS User Bank + call $FFF3 ; HBIOS BNKSEL ; ; copy drvmap working copy to CP/M 3 drvtbl ld hl,(drvtbl) ; get drvtbl address @@ -802,11 +820,8 @@ instc3: djnz instc1 ; ; switch back to tpabnk - ld hl,(bioloc) - ld de,27*3 ; offset of SELMEM func - add hl,de ; HL := SELMEM func - ld a,1 ; bank 1 is tpa bank - call jphl + pop af ; recover prev bank + call $FFF3 ; HBIOS BNKSEL ; ; set SCB drive door open flag ld a,$54 ; SCB drive door opened flag @@ -1733,6 +1748,23 @@ cbios: call addhl ; determine specific function address jp (hl) ; invoke CBIOS ; +; Routine to call CPM3 BIOS routines via BDOS +; function 50. +; +xbios: + ld (biofnc),a ; set BIOS function + ld c,50 ; direct BIOS call function + ld (dereg),de ; set DE parm + ld de,biospb ; BIOS parameter block + jp bdos ; invoke BDOS +; +biospb: +biofnc .db 0 ; BIOS function +areg .db 0 ; A register +bcreg .dw 0 ; BC register +dereg .dw 0 ; DE register +hlreg .dw 0 ; HL register +; ; Add the value in A to HL (HL := HL + A) ; addhl: @@ -1911,10 +1943,13 @@ stack .equ $ ; stack top ; Messages ; indent .db " ",0 -msgban1 .db "ASSIGN v1.4a for RomWBW CP/M, 6-Dec-2021",0 +msgban1 .db "ASSIGN v1.5 for RomWBW CP/M ",0 +msg22 .db "2.2",0 +msg3 .db "3",0 +msbban2 .db ", 28-Feb-2022",0 msghb .db " (HBIOS Mode)",0 msgub .db " (UBIOS Mode)",0 -msgban2 .db "Copyright 2021, Wayne Warthen, GNU GPL v3",0 +msgban3 .db "Copyright 2021, Wayne Warthen, GNU GPL v3",0 msguse .db "Usage: ASSIGN D:[=[{D:|[]:[]}]][,...]",13,10 .db " ex. ASSIGN (display all active assignments)",13,10 .db " ASSIGN /? (display version and usage)",13,10 diff --git a/Source/Apps/cpuspd/Build.cmd b/Source/Apps/cpuspd/Build.cmd new file mode 100644 index 00000000..1e3fe0a5 --- /dev/null +++ b/Source/Apps/cpuspd/Build.cmd @@ -0,0 +1,10 @@ +@echo off +setlocal + +set TOOLS=../../../Tools +set PATH=%TOOLS%\tasm32;%PATH% +set TASMTABS=%TOOLS%\tasm32 + +tasm -t180 -g3 -fFF cpuspd.asm cpuspd.com cpuspd.lst || exit /b + +copy /Y cpuspd.com ..\..\..\Binary\Apps\ || exit /b diff --git a/Source/Apps/cpuspd/Clean.cmd b/Source/Apps/cpuspd/Clean.cmd new file mode 100644 index 00000000..9ecb428f --- /dev/null +++ b/Source/Apps/cpuspd/Clean.cmd @@ -0,0 +1,6 @@ +@echo off +setlocal + +if exist *.com del *.com +if exist *.lst del *.lst +if exist *.bin del *.bin diff --git a/Source/Apps/cpuspd/Makefile b/Source/Apps/cpuspd/Makefile new file mode 100644 index 00000000..c8025816 --- /dev/null +++ b/Source/Apps/cpuspd/Makefile @@ -0,0 +1,7 @@ +OBJECTS = cpuspd.com +DEST = ../../../Binary/Apps +TOOLS =../../../Tools + +USETASM=1 + +include $(TOOLS)/Makefile.inc \ No newline at end of file diff --git a/Source/Apps/cpuspd/cpuspd.asm b/Source/Apps/cpuspd/cpuspd.asm new file mode 100644 index 00000000..363c4e75 --- /dev/null +++ b/Source/Apps/cpuspd/cpuspd.asm @@ -0,0 +1,707 @@ +; +;======================================================================= +; HBIOS CPU Speed Selection Tool +;======================================================================= +; +; Simple utility that sets CPU speed on RomWBW systems that support +; software speed selection. +; +;======================================================================= +; +#include "../../HBIOS/hbios.inc" +; +; General operational equates (should not requre adjustment) +; +stksiz .equ $40 ; Working stack size +; +cpumhz .equ 30 ; for time delay calculations (not critical) +; +rtc_port .equ $70 ; RTC latch port adr +; +restart .equ $0000 ; CP/M restart vector +bdos .equ $0005 ; BDOS invocation vector +; +ident .equ $FFFE ; loc of RomWBW HBIOS ident ptr +; +rmj .equ 3 ; intended CBIOS version - major +rmn .equ 1 ; intended CBIOS version - minor +; +;======================================================================= +; + .org $100 ; standard CP/M executable +; +; + ; setup stack (save old value) + ld (stksav),sp ; save stack + ld sp,stack ; set new stack +; + call crlf + ld de,str_banner ; banner + call prtstr +; + ; initialization + call init ; initialize + jr nz,exit ; abort if init fails +; + call main ; do the real work +; +exit: + ; clean up and return to command processor + call crlf ; formatting + ld sp,(stksav) ; restore stack + jp restart ; return to CP/M via restart +; +; +;======================================================================= +; Main Program +;======================================================================= +; +; +; Initialization +; +init: + ; check for UNA (UBIOS) + ld a,($FFFD) ; fixed location of UNA API vector + cp $C3 ; jp instruction? + jr nz,initwbw ; if not, not UNA + ld hl,($FFFE) ; get jp address + ld a,(hl) ; get byte at target address + cp $FD ; first byte of UNA push ix instruction + jr nz,initwbw ; if not, not UNA + inc hl ; point to next byte + ld a,(hl) ; get next byte + cp $E5 ; second byte of UNA push ix instruction + jr nz,initwbw ; if not, not UNA + jp err_una ; UNA not supported +; +initwbw: + ; get location of config data and verify integrity + ld hl,(ident) ; HL := adr or RomWBW HBIOS ident + ld a,(hl) ; get first byte of RomWBW marker + cp 'W' ; match? + jp nz,err_inv ; abort with invalid config block + inc hl ; next byte (marker byte 2) + ld a,(hl) ; load it + cp ~'W' ; match? + jp nz,err_inv ; abort with invalid config block + inc hl ; next byte (major/minor version) + ld a,(hl) ; load it + cp rmj << 4 | rmn ; match? + jp nz,err_ver ; abort with invalid os version +; +initz: + ; initialization complete + xor a ; signal success + ret ; return +; +; +; +main: + ; skip to start of first parm + ld ix,$81 ; point to start of parm area (past len byte) + call nonblank ; skip to next non-blank char + jp z,show_spd ; no parms, show current settings +; +main1: + ; process options (if any) + cp '/' ; option prefix? + jr nz,main2 ; not an option, continue + call option ; process option + ret nz ; some options mean we are done (e.g., "/?") + inc ix ; skip option character + call nonblank ; skip whitespace + jr main1 ; continue option checking +; +main2: + ret z ; if end, nothing to do + cp ',' ; no new speed? + jr z,main2a ; go to wait states + ; parse speed string (half, full, double) + call getalpha ; extract speed ("HALF", "FULL", "DOUBLE") + call parse_spd ; parse to numeric + jp c,err_parm ; if invalid, abort + ld (new_cpu_spd),a ; save it + call nonblank ; skip whitespace + jp z,set_spd ; if nothing else, set new speed + cp ',' ; parm separator + jp nz,err_parm ; invalid format, show usage and abort +main2a: + inc ix ; pass separator + call nonblank ; skip whitespace + jp z,set_spd ; if nothing else, set new speed + call isnum ; start of parm? + jr c,main3 ; nope, try skipping this parm + call getnum ; get memory wait states + jp c,err_parm ; if overflow, show usage and abort + ld (new_ws_mem),a ; save memory wait states +; +main3: + call nonblank ; skip whitespace + jp z,set_spd ; if nothing else, set new speed + cp ',' ; parm separator + jp nz,err_parm ; invalid format, show usage and abort + inc ix ; pass separator + call nonblank ; skip whitespace + jp z,set_spd ; if nothing else, set new speed + call getnum ; get I/O wait states + jp c,err_parm ; if overflow, show usage and abort + ld (new_ws_io),a ; save memory wait states +; + call nonblank ; skip whitespace + jp nz,err_parm ; invalid format, show usage and abort + jp set_spd ; set new speed and return +; +parse_spd: + ld a,(tmpstr) ; first byte of string + ld c,0 ; assume half speed + cp 'H' ; check it + jr z,parse_spd1 ; if equal, done + ld c,1 ; assume full speed + cp 'F' ; check it + jr z,parse_spd1 ; if equal, done + ld c,2 ; assume double speed + cp 'D' ; check it + jr z,parse_spd1 ; if equal, done + or a ; clear CF + ccf ; set CF to indicate error + ret +parse_spd1: + ld a,c ; result to a + or a ; clear CF + ret +; +set_spd: + call delay + ld b,BF_SYSSET + ld c,BF_SYSSET_CPUSPD + ld a,(new_cpu_spd) + ld l,a + ld a,(new_ws_mem) + ld d,a + ld a,(new_ws_io) + ld e,a + rst 08 + jp nz,err_not_sup + call show_spd + xor a + ret +; +show_spd: + ld b,BF_SYSGET + ld c,BF_SYSGET_CPUINFO + rst 08 + jp nz,err_not_sup + call crlf2 + push de ; save CPU speed for now + push bc ; Oscillator speed to HL + pop hl + ld de,str_spacer + call prtstr + call prtd3m ; print it + ld de,str_oscspd + call prtstr + ld b,BF_SYSGET + ld c,BF_SYSGET_CPUSPD + rst 08 + jp nz,err_not_sup + push de + ld a,l + ld de,str_slow + cp 0 + jr z,show_spd1 + ld de,str_full + cp 1 + jr z,show_spd1 + ld de,str_dbl + cp 2 + jr z,show_spd1 + jp err_invalid +show_spd1: + call crlf + call prtstr + pop bc ; recover wait states + pop hl ; recover CPU speed + push bc ; resave wait states + call prtd3m + ld de,str_cpuspd + call prtstr + pop hl + ld a,h ; memory wait states + cp $FF + jr z,show_spd2 + call crlf + ld de,str_spacer + call prtstr + call prtdecb + ld de,str_memws + call prtstr +; +show_spd2: + ld a,l + cp $FF + jr z,show_spd3 + call crlf + ld de,str_spacer + call prtstr + call prtdecb + ld de,str_iows + call prtstr +; +show_spd3: + ret +; +; Handle special options +; +option: +; + inc ix ; next char + ld a,(ix) ; get it + cp '?' ; is it a '?' as expected? + jp z,usage ; yes, display usage + jp err_parm ; anything else is an error + +usage: + call crlf2 + ld de,str_usage + call prtstr + or $FF + ret +; +; Error Handlers +; +err_una: + ld de,str_err_una + jr err_ret +err_inv: + ld de,str_err_inv + jr err_ret +err_ver: + ld de,str_err_ver + jr err_ret +err_parm: + ld de,str_err_parm + jr err_ret +err_not_sup: + ld de,str_err_not_sup + jr err_ret +err_invalid: + ld de,str_err_invalid + jr err_ret +; +err_ret: + call crlf2 + call prtstr + or $FF ; signal error + ret +; +;======================================================================= +; Utility Routines +;======================================================================= +; +; +; Print character in A without destroying any registers +; +prtchr: + push af + push bc ; save registers + push de + push hl + ld e,a ; character to print in E + ld c,$02 ; BDOS function to output a character + call bdos ; do it + pop hl ; restore registers + pop de + pop bc + pop af + ret +; +; Print a dot character without destroying any registers +; +prtdot: + ; shortcut to print a dot preserving all regs + push af ; save af + ld a,'.' ; load dot char + call prtchr ; print it + pop af ; restore af + ret ; done +; +; Print a zero terminated string at (de) without destroying any registers +; +prtstr: + push af + push de +; +prtstr1: + ld a,(de) ; get next char + or a + jr z,prtstr2 + call prtchr + inc de + jr prtstr1 +; +prtstr2: + pop de ; restore registers + pop af + ret +; +; Print a hex value prefix "0x" +; +prthexpre: + push af + ld a,'0' + call prtchr + ld a,'x' + call prtchr + pop af + ret +; +; Print the value in A in hex without destroying any registers +; +prthex: + call prthexpre +prthex1: + push af ; save AF + push de ; save DE + call hexascii ; convert value in A to hex chars in DE + ld a,d ; get the high order hex char + call prtchr ; print it + ld a,e ; get the low order hex char + call prtchr ; print it + pop de ; restore DE + pop af ; restore AF + ret ; done +; +; print the hex word value in hl +; +prthexword: + call prthexpre +prthexword1: + push af + ld a,h + call prthex1 + ld a,l + call prthex1 + pop af + ret +; +; print the hex dword value in de:hl +; +prthex32: + call prthexpre + push bc + push de + pop bc + call prthexword1 + push hl + pop bc + call prthexword1 + pop bc + ret +; +; Convert binary value in A to ascii hex characters in DE +; +hexascii: + ld d,a ; save A in D + call hexconv ; convert low nibble of A to hex + ld e,a ; save it in E + ld a,d ; get original value back + rlca ; rotate high order nibble to low bits + rlca + rlca + rlca + call hexconv ; convert nibble + ld d,a ; save it in D + ret ; done +; +; Convert low nibble of A to ascii hex +; +hexconv: + and $0F ; low nibble only + add a,$90 + daa + adc a,$40 + daa + ret +; +; Print value of A or HL in decimal with leading zero suppression +; Use prtdecb for A or prtdecw for HL +; +prtdecb: + push hl + ld h,0 + ld l,a + call prtdecw ; print it + pop hl + ret +; +prtdecw: + push af + push bc + push de + push hl + call prtdec0 + pop hl + pop de + pop bc + pop af + ret +; +prtdec0: + ld e,'0' + ld bc,-10000 + call prtdec1 + ld bc,-1000 + call prtdec1 + ld bc,-100 + call prtdec1 + ld c,-10 + call prtdec1 + ld e,0 + ld c,-1 +prtdec1: + ld a,'0' - 1 +prtdec2: + inc a + add hl,bc + jr c,prtdec2 + sbc hl,bc + cp e + ret z + ld e,0 + call prtchr + ret +; +; Print value of HL as thousandths, ie. 0.000 +; +prtd3m: + push bc + push de + push hl + ld e,'0' + ld bc,-10000 + call prtd3m1 + ld e,0 + ld bc,-1000 + call prtd3m1 + call prtdot + ld bc,-100 + call prtd3m1 + ld c,-10 + call prtd3m1 + ld c,-1 + call prtd3m1 + pop hl + pop de + pop bc + ret +prtd3m1: + ld a,'0' - 1 +prtd3m2: + inc a + add hl,bc + jr c,prtd3m2 + sbc hl,bc + cp e + jr z,prtd3m3 + ld e,0 + call prtchr +prtd3m3: + ret + + + +; +; Get the next non-blank character from (HL). +; +nonblank: + ld a,(ix) ; load next character + or a ; string ends with a null + ret z ; if null, return pointing to null + cp ' ' ; check for blank + ret nz ; return if not blank + inc ix ; if blank, increment character pointer + jr nonblank ; and loop +; +; Get alpha chars and save in tmpstr +; Length of string returned in A +; +getalpha: +; + ld hl,tmpstr ; location to save chars + ld b,8 ; length counter (tmpstr max chars) + ld c,0 ; init character counter +; +getalpha1: + ld a,(ix) ; get active char + call ucase ; lower case -> uppper case, if needed + cp 'A' ; check for start of alpha range + jr c,getalpha2 ; not alpha, get out + cp 'Z' + 1 ; check for end of alpha range + jr nc,getalpha2 ; not alpha, get out + ; handle alpha char + ld (hl),a ; save it + inc c ; bump char count + inc hl ; inc string pointer + inc ix ; increment buffer ptr + djnz getalpha1 ; if space, loop for more chars +; +getalpha2: ; non-alpha, clean up and return + ld (hl),0 ; terminate string + ld a,c ; string length to A + or a ; set flags + ret ; and return +; +; Determine if byte in A is a numeric '0'-'9' +; Return with CF clear if it is numeric +; +isnum: + cp '0' + jr c,isnum1 ; too low + cp '9' + 1 + jr nc,isnum1 ; too high + or a ; clear CF + ret +isnum1: + or a ; clear CF + ccf ; set CF + ret + +; +; Get numeric chars and convert to number returned in A +; Carry flag set on overflow +; +getnum: + ld c,0 ; C is working register +getnum1: + ld a,(ix) ; get the active char + cp '0' ; compare to ascii '0' + jr c,getnum2 ; abort if below + cp '9' + 1 ; compare to ascii '9' + jr nc,getnum2 ; abort if above +; + ; valid digit, add new digit to C + ld a,c ; get working value to A + rlca ; multiply by 10 + ret c ; overflow, return with carry set + rlca ; ... + ret c ; overflow, return with carry set + add a,c ; ... + ret c ; overflow, return with carry set + rlca ; ... + ret c ; overflow, return with carry set + ld c,a ; back to C + ld a,(ix) ; get new digit + sub '0' ; make binary + add a,c ; add in working value + ret c ; overflow, return with carry set + ld c,a ; back to C +; + inc ix ; bump to next char + jr getnum1 ; loop +; +getnum2: ; return result + ld a,c ; return result in A + or a ; with flags set, CF is cleared + ret +; +; Start a new line +; +crlf2: + call crlf ; two of them +crlf: + push af ; preserve AF + ld a,13 ; + call prtchr ; print it + ld a,10 ; + call prtchr ; print it + pop af ; restore AF + ret +; +; Convert character in A to uppercase +; +ucase: + cp 'a' ; if below 'a' + ret c ; ... do nothing and return + cp 'z' + 1 ; if above 'z' + ret nc ; ... do nothing and return + res 5,a ; clear bit 5 to make lower case -> upper case + ret ; and return +; +; Add hl,a +; +; A register is destroyed! +; +addhla: + add a,l + ld l,a + ret nc + inc h + ret +; +; Delay ~10ms +; +delay: + push af + push de + ld de,625 ; 10000us/16us +delay0: + ld a,cpumhz - 2 +delay1: + dec a + jr nz,delay1 + dec de + ld a,d + or e + jp nz,delay0 + pop de + pop af + ret +; +; +;======================================================================= +; Constants +;======================================================================= +; +str_banner .db "RomWBW CPU Speed Selector v0.5, 2-Feb-2022",0 +str_spacer .db " ",0 +str_oscspd .db " MHz Oscillator",0 +str_slow .db " CPU speed is HALF (",0 +str_full .db " CPU speed is FULL (",0 +str_dbl .db " CPU speed is DOUBLE (",0 +str_cpuspd .db " MHz)",0 +str_memws .db " Memory Wait State(s)",0 +str_iows .db " I/O Wait State(s)",0 +str_err_una .db " ERROR: UNA not supported by application",0 +str_err_inv .db " ERROR: Invalid BIOS (signature missing)",0 +str_err_ver .db " ERROR: Unexpected HBIOS version",0 +str_err_parm .db " ERROR: Parameter error (CPUSPD /? for usage)",0 +str_err_not_sup .db " ERROR: Platform or configuration not supported!",0 +str_err_invalid .db " ERROR: Invalid configuration!",0 +str_usage .db " Usage: CPUSPD ,,\r\n" + .db "\r\n" + .db " : \"Half\", \"Full\", or \"Double\"\r\n" + .db " : Memory wait states\r\n" + .db " : I/O wait states\r\n" + .db "\r\n" + .db " Any parameter may be omitted\r\n" + .db " Ability to set values varies by system\r\n",0 +; +;======================================================================= +; Working data +;======================================================================= +; +stksav .dw 0 ; stack pointer saved at start + .fill stksiz,0 ; stack +stack .equ $ ; stack top +; +; +tmpstr .fill 9,0 ; temp string (8 chars, 0 term) +new_cpu_spd .db $FF ; new CPU speed +new_ws_mem .db $FF ; new memory wait states +new_ws_io .db $FF ; new I/O wait states + + +; +;======================================================================= +; + .end \ No newline at end of file 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 . The source code is provided in the RomWBW distribution. + +# CPUSPD + +The `CPUSPD` application is used to change the running speed and wait +states of a RomWBW system. + + The functionality is highly dependent on +the capabilities of your system. + +At present, all Z180 systems can change their CPU speed and their +wait states. SBC and MBC systems may be able to change their CPU +speed if the hardware supports it and it is enabled in the HBIOS +configuration. + +## Syntax + +| `CPUSPD [`*``*`[,[`*``*`][,[`*``*`]]]` + +*``* is one of HALF, FULL, or DOUBLE. +*``* is a number specifying the desired memory wait states. +*``* is a number specifying the desired I/O wait states. + +## Usage + +Entering `CPUSPD` with no parameters will display the current CPU speed +and wait state information of the running system. Wait state +information is not available for all systems. + +To modify the running speed of a system, you can specify the +`*``*` parameter. To modify either or both of the wait +states, you can enter the desired number. Either or both of the wait +state parameters may be omitted and the current wait state settings +will remain in effect. + +## Notes + +The ability to modify the running speed and wait states of a system +varies widely depending on the hardware capabilities and the HBIOS +configuration settings. + +Note that it is frequently impossible to tell if a system is capable +of dynamic speed changes. This function makes the changes blindly. +If an attempt is made to change the speed of a system +that is definitely incapable of doing so, then an error result is +returned. + +The `CPUSPD` command makes no attempt to ensure that the new CPU +speed will actually work on the current hardware. Setting a CPU +speed that exceeds the capabilities of the system will result in +unstable operation or a system stall. + +Some peripherals are dependant on the CPU speed. For example, the Z180 +ASCI baud rate and system timer are derived from the CPU speed. The +CPUSPD applicastion will attempt to adjust these peripherals for +correct operation after modifying the CPU speed. However, in some +cases this may not be possible. The baud rate of ASCI ports have a +limited set of divisors. If there is no satisfactory divisor to +retain the existing baud rate under the new CPU speed, then the baud +rate of the ASCI port(s) will be affected. + +## Etymology + +The `CPUSPD` application was custom written for RomWBW. All of the +hardware interface code is specific to RomWBW and the application will +not operate correctly on non-RomWBW systems. + +The source code is provided in the RomWBW distribution. diff --git a/Source/Doc/Architecture.md b/Source/Doc/Architecture.md index 859c712a..ed9a33e5 100644 --- a/Source/Doc/Architecture.md +++ b/Source/Doc/Architecture.md @@ -223,6 +223,18 @@ initialization routine. At this point, the prior HBIOS code has been discarded and overwritten. Finally, the Boot Loader is invoked just like a ROM Boot. +ROM-less Boot +------------- + +Some hardware supported by RomWBW has a special mechanism for loading +the initial code. These systems have no ROM chips. However, they +have a small hardware bootstrap that loads a chunk of code from a +disk device directlly into RAM at system startup. + +The startup then proceeds very much like the Application Boot +process described above. HBIOS is installed in it's operating bank +and control is passed to the loader. + Notes ----- @@ -1938,6 +1950,7 @@ lookup. | H: Z80 CPU Variant | L: CPU Speed in MHz | DE: CPU Speed in KHz +| BC: Oscillator Speed in KHz #### SYSGET Subfunction 0xF1 -- Get Memory Information (MEMINFO) @@ -1959,6 +1972,23 @@ lookup. | D: BIOS Bank ID | E: User Bank ID +#### SYSGET Subfunction 0xF3 -- Get CPU Speed (CPUSPD) + +| _Entry Parameters_ +| BC: 0xF8F3 + +| _Returned Values_ +| A: Status (0=OK, else error) +| L: Clock Mult (0:Half, 1:Full, 2: Double) +| D: Memory Wait States +| E: I/O Wait States + +This function will return the running CPU speed attributes of a system. +Note that it is frequently impossible to tell if a system is capable +of dynamic speed changes. This function returns it's best guess. +If either of the wait state settings is unknown, the function will +return 0xFF. + ### Function 0xF9 -- System Set (SYSSET) | _Entry Parameters_ @@ -2002,6 +2032,34 @@ available along with the registers/information used as input. | _Returned Values_ | A: Status (0=OK, else error) +#### SYSSET Subfunction 0xF3 -- Set CPU Speed (CPUSPD) + +| _Entry Parameters_ +| BC: 0xF9F3 +| L: Clock Mult (0:Half, 1:Full, 2: Double) +| D: Memory Wait States +| E: I/O Wait States + +| _Returned Values_ +| A: Status (0=OK, else error) + +This function will modify the running CPU speed attributes of a system. +Note that it is frequently impossible to tell if a system is capable +of dynamic speed changes. This function makes the changes blindly. +You can specify 0xFF for either of the wait state settings to have them +left alone. If an attempt is made to change the speed of a system +that is definitely incapable of doing so, then an error result is +returned. + +Some peripherals are dependant on the CPU speed. For example, the Z180 +ASCI baud rate and system timer are derived from the CPU speed. The +Set CPU Speed function will attempt to adjust these peripherals for +correct operation after modifying the CPU speed. However, in some +cases this may not be possible. The baud rate of ASCI ports have a +limited set of divisors. If there is no satisfactory divisor to +retain the existing baud rate under the new CPU speed, then the baud +rate of the ASCI port(s) will be affected. + ### Function 0xFA -- System Peek (SYSPEEK) | _Entry Parameters_ diff --git a/Source/Doc/Build.cmd b/Source/Doc/Build.cmd index 34316376..dad1f07f 100644 --- a/Source/Doc/Build.cmd +++ b/Source/Doc/Build.cmd @@ -51,7 +51,7 @@ gpp -o %1.tmp -U "$" "$" "{" "}{" "}$" "{" "}" "@@@" "" -M "$" "$" "{" "}{" "}$" pandoc %1.tmp -f markdown -t pdf -s -o %1.pdf --default-image-extension=pdf || exit /b pandoc %1.tmp -f markdown -t html -s -o %1.html --default-image-extension=png || exit /b pandoc %1.tmp -f markdown -t dokuwiki -s -o %1.dw --default-image-extension=png || exit /b -pandoc %1.tmp -f markdown -t gfm -s -o %1.gfm --default-image-extension=png || exit /b +pandoc %1.tmp -f markdown -t gfm -o %1.gfm --default-image-extension=png || exit /b pandoc %1.tmp -f markdown -t plain -s -o %1.txt --default-image-extension=png || exit /b goto :eof \ No newline at end of file diff --git a/Source/Doc/GettingStarted.md b/Source/Doc/GettingStarted.md index 92ccc134..899b8c34 100644 --- a/Source/Doc/GettingStarted.md +++ b/Source/Doc/GettingStarted.md @@ -424,7 +424,7 @@ therefore, globally available. | TALK | Direct console I/O to a specified character device. | | RTC | Manage and test the Real Time Clock hardware. | | TIMER | Display value of running periodic system timer. | -| INTTEST | Test interrupt vector hooking. | +| CPUSPD | Change the running CPU speed and wait states of the system. | Some custom applications do not fit on the ROM disk. They are found on the disk image files or the individual files can be found in the Binary\\Apps @@ -434,6 +434,7 @@ directory of the distribution. | ----------- | -------------------------------------------------------------- | | TUNE | Play .PT2, .PT3, .MYM audio files. | | FAT | Access MS-DOS FAT filesystems from RomWBW (based on FatFs). | +| INTTEST | Test interrupt vector hooking. | Additional documentation on all of these applications can be found in "RomWBW Applications.pdf" in the Doc directory of the distribution. @@ -1083,7 +1084,7 @@ through the normal startup process just like it was started from ROM. However, your ROM has not been updated and the next time you boot your system, it will revert to the system image contained in ROM. -# Upgrading via Flash Utility +## Upgrading via Flash Utility If you do not have easy access to a ROM programmer, it is usually possible to reprogram your system ROM using the FLASH utility from @@ -1128,7 +1129,7 @@ system and boot an operating system from ROM. Do not boot from a disk device yet. Review the boot messages to see if any issues have occurred. -# Upgrading via XModem Flash Updater +## Upgrading via XModem Flash Updater Similar to using the Flash utility, the system ROM can be updated or upgraded through the ROM based updater utility. This works by @@ -1143,7 +1144,7 @@ U (Begin Update). Then initiate the Xmodem transfer of the .img or More information can be found in the ROM Applications document. -# Post Update System Image and Application update process +## Post Upgrade System Image and Application Update Process Once you are satisfied that the ROM is working well, you will need to update the system images and RomWBW custom applications on your disk @@ -1214,23 +1215,22 @@ operating system on your disk. After this is done, you will need to use `SYSCOPY` to place the ZPM3 loader image on the boot tracks of all ZPM3 - boot disks/slices. The loader image is called `CPMLDR.SYS`. + boot disks/slices. The loader image is called `ZPMLDR.SYS`. You must then copy (at a minimum) `CPM3.SYS`, `ZCCP.COM`, `ZINSTAL.ZPM`, and `STARTZPM.COM` onto the disk/slice. Assuming you copied the ZPM3 boot files onto your RAM disk at A:, you would use: ``` - A>B:SYSCOPY C:=CPMLDR.SYS + A>B:SYSCOPY C:=ZPMLDR.SYS A>B:COPY CPM3.SYS C: A>B:COPY ZCCP.COM C: A>B:COPY ZINSTAL.ZPM C: A>B:COPY STARTZPM.COM C: ``` - You may be wondering if the references to `CPMLDR.SYS` and - `CPM3.SYS` are typos. They are not. ZPM3 uses the same loader - image as CPM3. The ZPM3 main system code file is called `CPM3.SYS` + You may be wondering if the reference to `CPM3.SYS` is a typo. + It is not. The ZPM3 main system code file is called `CPM3.SYS` which is the same name as CP/M 3 uses, but the file contents are not the same. @@ -1263,29 +1263,34 @@ images. * FAT.COM * TUNE.COM -# System Update +## System Update -If the system running ROMWBW utilizes the SST39SF040 Flash chip then it is possible to do a System Update in place of -a System Upgrade in some cases. +If the system running ROMWBW utilizes the SST39SF040 Flash chip then it +is possible to do a System Update in place of a System Upgrade in some +cases. -A System Update would involve only updating the BIOS, ROM applications and CP/M system. +A System Update would involve only updating the BIOS, ROM applications +and CP/M system. -A System Update may be more favorable than a System Upgrade in cases such as: +A System Update may be more favorable than a System Upgrade in cases +such as: - Overwriting of the ROM drive is not desired. - Space is unavailable to hold a full ROMWBW ROM. - To mimimize time taken to transfer and flash a full ROM. - Configuration changes are only minor and do not impact disk applications. -The ROMWBW build process generates a system upgrade file along with the normal ROM image and can be identified by the -extension ".upd". It will be 128Kb in size. In comparison the normal ROM image will have the extension ".rom" and be -512Kb or 1024Kb in size. +The ROMWBW build process generates a system upgrade file along with +the normal ROM image and can be identified by the extension ".upd". It +will be 128Kb in size. In comparison the normal ROM image will have +the extension ".rom" and be 512Kb or 1024Kb in size. -Transferring and flashing the System Update is accomplished in the same manner as described above in *Upgrading* with -the required difference being that the flash application needs to be directed to complete a partial flash using the -/p command line switch. +Transferring and flashing the System Update is accomplished in the +same manner as described above in *Upgrading* with the required +difference being that the flash application needs to be directed to +complete a partial flash using the /P command line switch. -`E>flash write rom.upd /p` +`E>FLASH WRITE ROM.UPD /P` # RomWBW Distribution @@ -1303,7 +1308,7 @@ directories are: | Application | Description | | ----------- | -------------------------------------------------------------- | -| Binary | The final output files of the build process are placed here. Most importantly, are the ROM images with the file names ending in ".rom". | +| Binary | The final output files of the build process are placed here. Most importantly, the ROM images with the file names ending in ".rom". | | Doc | Contains various detailed documentation including the operating systems, RomWBW architecture, etc. | | Source | Contains the source code files used to build the software and ROM images. | | Tools | Contains the MS Windows programs that are used by the build process or that may be useful in setting up your system. | @@ -1327,10 +1332,11 @@ these applications are no longer provided. driver. * Ed Brindley contributed some of the code that supports the RC2014 platform. -* Phil Summers contributed Forth and BASIC in ROM, the AY-3-8910 sound -driver as well as a long list of general code enhancements. +* Phil Summers contributed the Forth and BASIC adaptations in ROM, the +AY-3-8910 sound driver as well as a long list of general code +enhancements. * Phillip Stevens contributed support for FreeRTOS. -* Curt Mayer contributed the Linux / MacOS build process. +* Curt Mayer contributed the original Linux / MacOS build process. * UNA BIOS and FDISK80 are the products of John Coffman. * FLASH4 is a product of Will Sowerbutts. * CLRDIR is a product of Max Scane. @@ -1341,6 +1347,50 @@ the SN76489 sound driver. Contributions of all kinds to RomWBW are very welcome. +# Licensing + +RomWBW 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 3 of the License, or +(at your option) any later version. + +RomWBW 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 RomWBW. If not, see . + +Portions of RomWBW were created by, contributed by, or derived from +the work of others. It is believed that these works are being used +in accordance with the intentions and/or licensing of their creators. + +If anyone feels their work is being used outside of it's intended +licensing, please notify: + +> Wayne Warthen +> wwarthen@gmail.com + +RomWBW is an aggregate work. It is composed of many individual, +standalone programs that are distributed as a whole to function as +a cohesive system. Each program may have it's own licensing which +may be different from other programs within the aggregate. + +In some cases, a single program (e.g., CP/M Operating System) is +composed of multiple components with different licenses. It is +believed that in all such cases the licenses are compatible with +GPL version 3. + +RomWBW encourages code contributions from others. Contributors +may assert their own copyright in their contributions by +annotating the contributed source code appropriately. Contributors +are further encouraged to submit their contributions via the RomWBW +source code control system to ensure their contributions are clearly +documented. + +All contributions to RomWBW are subject to this license. + # Getting Assistance The best way to get assistance with RomWBW or any aspect of the diff --git a/Source/Forth/Build.cmd b/Source/Forth/Build.cmd index 1d93e79f..59f19957 100644 --- a/Source/Forth/Build.cmd +++ b/Source/Forth/Build.cmd @@ -3,15 +3,13 @@ setlocal set TOOLS=../../Tools -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/ -zx zsm =camel80.azm -/l || exit /b -zx link -CAMEL80.BIN[L200]=CAMEL80 || exit /b +zxcc zsm =camel80.azm -/l || exit /b +zxcc link -CAMEL80.BIN[L200]=CAMEL80 || exit /b diff --git a/Source/HBIOS/API.txt b/Source/HBIOS/API.txt index 013ec895..af68ecfe 100644 --- a/Source/HBIOS/API.txt +++ b/Source/HBIOS/API.txt @@ -100,9 +100,10 @@ GET ($F8): H=Z80 CPU Variant L=CPU Speed in MHz DE=CPU Speed in KHz + BC=Oscillator Freq in KHz MEMINFO ($F1): - BC=Function/Subfunction A=Result + BC=FuSnction/Subfunction A=Result D=# ROM Banks E=# RAM Banks @@ -111,6 +112,13 @@ GET ($F8): D=BIOS Bank Id E=User Bank Id + CPUSPD ($F3): + BC=Function/Subfunction A=Result + L=Clock Mult (0:Half, 1:Full, 2: Double) + D=Memory Wait States + E=I/O Wait States + + SET ($F9): BC=Function/Subfunction A=Result @@ -127,6 +135,13 @@ SET ($F9): DE=Boot Volume (Disk Unit/Slice) L=Boot Bank Id + CPUSPD ($F3): + BC=Function/Subfunction A=Result + L=Clock Mult (0:Half, 1:Full, 2: Double) + D=Memory Wait States + E=I/O Wait States + + PEEK ($FA): B=Function A=Result D=Bank E=Byte Value diff --git a/Source/HBIOS/Build.cmd b/Source/HBIOS/Build.cmd index c0a9fe0f..04dad21d 100644 --- a/Source/HBIOS/Build.cmd +++ b/Source/HBIOS/Build.cmd @@ -9,13 +9,11 @@ if "%1" == "dist" goto :dist set TOOLS=../../Tools -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/ :: :: This PowerShell script validates the build variables passed in. If @@ -95,8 +93,10 @@ copy /b romldr.bin + dbgmon.bin + ..\zsdos\zsys_wbw.bin osimg_small.bin || exit :: should yield a result of zero. :: -for %%f in (hbios_rom.bin osimg.bin osimg1.bin osimg2.bin) do ( - "%TOOLS%\srecord\srec_cat.exe" %%f -Binary -Crop 0 0x7FFF -Checksum_Negative_Big_Endian 0x7FFF 1 1 -o %%f -Binary || exit /b +if %ROMSize% gtr 0 ( + for %%f in (hbios_rom.bin osimg.bin osimg1.bin osimg2.bin) do ( + "%TOOLS%\srecord\srec_cat.exe" %%f -Binary -Crop 0 0x7FFF -Checksum_Negative_Big_Endian 0x7FFF 1 1 -o %%f -Binary || exit /b + ) ) :: @@ -115,17 +115,23 @@ for %%f in (hbios_rom.bin osimg.bin osimg1.bin osimg2.bin) do ( :: HBIOS on the fly for testing purposes. :: -copy /b hbios_rom.bin + osimg.bin + osimg1.bin + osimg2.bin + ..\RomDsk\rom%ROMSize%_wbw.dat %ROMName%.rom || exit /b -copy /b hbios_rom.bin + osimg.bin + osimg1.bin + osimg2.bin %ROMName%.upd || exit /b -copy /b hbios_app.bin + osimg_small.bin %ROMName%.com || exit /b +if %ROMSize% gtr 0 ( + copy /b hbios_rom.bin + osimg.bin + osimg1.bin + osimg2.bin + ..\RomDsk\rom%ROMSize%_wbw.dat %ROMName%.rom || exit /b + copy /b hbios_rom.bin + osimg.bin + osimg1.bin + osimg2.bin %ROMName%.upd || exit /b + copy /b hbios_app.bin + osimg_small.bin %ROMName%.com || exit /b +) else ( + copy /b hbios_rom.bin + osimg_small.bin %ROMName%.rom || exit /b + copy /b hbios_rom.bin + osimg_small.bin %ROMName%.upd || exit /b + copy /b hbios_app.bin + osimg_small.bin %ROMName%.com || exit /b +) :: :: Copy results to output directory :: -copy %ROMName%.rom ..\..\Binary || exit /b -copy %ROMName%.upd ..\..\Binary || exit /b -copy %ROMName%.com ..\..\Binary || exit /b +if exist %ROMName%.rom copy %ROMName%.rom ..\..\Binary || exit /b +if exist %ROMName%.upd copy %ROMName%.upd ..\..\Binary || exit /b +if exist %ROMName%.com copy %ROMName%.com ..\..\Binary || exit /b goto :eof @@ -190,6 +196,7 @@ call Build RCZ80 kio 512 || exit /b call Build RCZ80 mt 512 || exit /b call Build RCZ80 duart 512 || exit /b call Build RCZ80 zrc 512 || exit /b +call Build RCZ80 zrc_ram 0 || exit /b call Build RCZ180 ext 512 || exit /b call Build RCZ180 nat 512 || exit /b call Build RCZ280 ext 512 || exit /b diff --git a/Source/HBIOS/Build.ps1 b/Source/HBIOS/Build.ps1 index e6b62fec..a5606716 100644 --- a/Source/HBIOS/Build.ps1 +++ b/Source/HBIOS/Build.ps1 @@ -76,8 +76,8 @@ while ($true) while ($true) { - if (($RomSize -eq 128) -or ($RomSize -eq 256) -or ($RomSize -eq 512) -or ($RomSize -eq 1024)) {break} - $RomSize = (Read-Host -prompt "ROM Size [128|256|512|1024]").Trim() + if (($RomSize -eq 0) -or ($RomSize -eq 128) -or ($RomSize -eq 256) -or ($RomSize -eq 512) -or ($RomSize -eq 1024)) {break} + $RomSize = (Read-Host -prompt "ROM Size [0|128|256|512|1024]").Trim() } # diff --git a/Source/HBIOS/Build.sh b/Source/HBIOS/Build.sh index cc4d5304..818b45fa 100755 --- a/Source/HBIOS/Build.sh +++ b/Source/HBIOS/Build.sh @@ -26,6 +26,7 @@ if [ "${ROM_PLATFORM}" == "dist" ] ; then ROM_PLATFORM="RCZ80"; ROM_CONFIG="std"; ROMSIZE="512"; bash Build.sh ROM_PLATFORM="RCZ80"; ROM_CONFIG="skz"; ROMSIZE="512"; bash Build.sh ROM_PLATFORM="RCZ80"; ROM_CONFIG="zrc"; ROMSIZE="512"; bash Build.sh + ROM_PLATFORM="RCZ80"; ROM_CONFIG="zrc_ram"; ROMSIZE="0"; bash Build.sh ROM_PLATFORM="SBC"; ROM_CONFIG="std"; ROMSIZE="512"; bash Build.sh ROM_PLATFORM="SBC"; ROM_CONFIG="simh"; ROMSIZE="512"; bash Build.sh ROM_PLATFORM="MBC"; ROM_CONFIG="std"; ROMSIZE="512"; bash Build.sh @@ -71,7 +72,7 @@ if [ -z "${ROMSIZE}" ] ; then ROMSIZE="512" fi -while [ ! '(' "${ROMSIZE}" = 1024 -o "${ROMSIZE}" = 512 -o "${ROMSIZE}" = 256 -o "${ROMSIZE}" = 128 ')' ] ; do +while [ ! '(' "${ROMSIZE}" = 1024 -o "${ROMSIZE}" = 512 -o "${ROMSIZE}" = 256 -o "${ROMSIZE}" = 128 -o "${ROMSIZE}" = 0 ')' ] ; do echo -n "Romsize :" read ROMSIZE done diff --git a/Source/HBIOS/Config/RCZ280_nat.asm b/Source/HBIOS/Config/RCZ280_nat.asm index 8fe12ab4..2f0797cf 100644 --- a/Source/HBIOS/Config/RCZ280_nat.asm +++ b/Source/HBIOS/Config/RCZ280_nat.asm @@ -28,7 +28,7 @@ ; CRTACT .SET FALSE ; ACTIVATE CRT (VDU,CVDU,PROPIO,ETC) AT STARTUP ; -CPUOSC .SET 24000000 ; CPU OSC FREQ IN MHZ +CPUOSC .SET 12000000 ; CPU OSC FREQ IN MHZ ; MEMMGR .SET MM_Z280 ; MEMORY MANAGER: MM_[SBC|Z2|N8|Z180|Z280] ; diff --git a/Source/HBIOS/Config/RCZ280_nat_zzr.asm b/Source/HBIOS/Config/RCZ280_nat_zzr.asm index 71b08a4b..4439f45d 100644 --- a/Source/HBIOS/Config/RCZ280_nat_zzr.asm +++ b/Source/HBIOS/Config/RCZ280_nat_zzr.asm @@ -28,16 +28,17 @@ ; #include "Config/RCZ280_nat.asm" ; -CPUOSC .SET 29491200 ; CPU OSC FREQ IN MHZ +CPUOSC .SET 14745600 ; CPU OSC FREQ IN MHZ ; -RAMSIZE .SET 384 ; SIZE OF RAM IN KB (MUST MATCH YOUR HARDWARE!!!) -PLT_RAM_R .SET 128 ; RESERVE FIRST N KB OF RAM (USUALLY 0) -PLT_ROM_R .SET 0 ; RESERVE FIRST N KB OR ROM (USUALLY 0) +RAMSIZE .SET 256 ; SIZE OF RAM IN KB (MUST MATCH YOUR HARDWARE!!!) +ROMSIZE_CHK .SET 256 ; ROMSIZE VALUE VEREIFICATION (0=DISABLED) ; -RAMLOC .SET 23 ; START OF RAM AS POWER OF 2 (2^N) IN PHYSICAL ADDRESS SPACE +RAMLOC .SET 18 ; START OF RAM AS POWER OF 2 (2^N) IN PHYSICAL ADDRESS SPACE RAMBIAS .SET (1 << (RAMLOC - 10)) ; OFFSET OF START OF RAM IN PHYSICAL ADDRESS SPACE ; -MDROM .SET FALSE ; MD: ENABLE ROM DISK -MDRAM .SET TRUE ; MD: ENABLE RAM DISK +MDROM .SET TRUE ; MD: ENABLE ROM DISK +MDRAM .SET FALSE ; MD: ENABLE RAM DISK ; -Z2U0HFC .SET TRUE ; Z2U 0: ENABLE HARDWARE FLOW CONTROL +; +Z2UOSC .SET (CPUOSC / 8) ; Z2U: OSC FREQUENCY IN MHZ +Z2U0HFC .SET TRUE ; Z2U0: ENABLE HARDWARE FLOW CONTROL diff --git a/Source/HBIOS/Config/RCZ80_zrc.asm b/Source/HBIOS/Config/RCZ80_zrc.asm index e03cebba..44997489 100644 --- a/Source/HBIOS/Config/RCZ80_zrc.asm +++ b/Source/HBIOS/Config/RCZ80_zrc.asm @@ -30,6 +30,7 @@ CRTACT .SET FALSE ; ACTIVATE CRT (VDU,CVDU,PROPIO,ETC) AT STARTUP ; CPUOSC .SET 7372800 ; CPU OSC FREQ IN MHZ ; +RAMSIZE .SET 1536 ; SIZE OF RAM IN KB (MUST MATCH YOUR HARDWARE!!!) MEMMGR .SET MM_ZRC ; MEMORY MANAGER: MM_[SBC|Z2|N8|Z180] ; UARTENABLE .SET TRUE ; UART: ENABLE 8250/16550-LIKE SERIAL DRIVER (UART.ASM) diff --git a/Source/HBIOS/Config/RCZ80_zrc_ram.asm b/Source/HBIOS/Config/RCZ80_zrc_ram.asm new file mode 100644 index 00000000..cd68248d --- /dev/null +++ b/Source/HBIOS/Config/RCZ80_zrc_ram.asm @@ -0,0 +1,54 @@ +; +;================================================================================================== +; RC2014 Z80 ZRC CONFIGURATION +;================================================================================================== +; +; THE COMPLETE SET OF DEFAULT CONFIGURATION SETTINGS FOR THIS PLATFORM ARE FOUND IN THE +; CFG_.ASM INCLUDED FILE WHICH IS FOUND IN THE PARENT DIRECTORY. THIS FILE CONTAINS +; COMMON CONFIGURATION SETTINGS THAT OVERRIDE THE DEFAULTS. IT IS INTENDED THAT YOU MAKE +; YOUR CUSTOMIZATIONS IN THIS FILE AND JUST INHERIT ALL OTHER SETTINGS FROM THE DEFAULTS. +; EVEN BETTER, YOU CAN MAKE A COPY OF THIS FILE WITH A NAME LIKE _XXX.ASM AND SPECIFY +; YOUR FILE IN THE BUILD PROCESS. +; +; THE SETTINGS BELOW ARE THE SETTINGS THAT ARE MOST COMMONLY MODIFIED FOR THIS PLATFORM. +; MANY OF THEM ARE EQUAL TO THE SETTINGS IN THE INCLUDED FILE, SO THEY DON'T REALLY DO +; ANYTHING AS IS. THEY ARE LISTED HERE TO MAKE IT EASY FOR YOU TO ADJUST THE MOST COMMON +; SETTINGS. +; +; N.B., SINCE THE SETTINGS BELOW ARE REDEFINING VALUES ALREADY SET IN THE INCLUDED FILE, +; TASM INSISTS THAT YOU USE THE .SET OPERATOR AND NOT THE .EQU OPERATOR BELOW. ATTEMPTING +; TO REDEFINE A VALUE WITH .EQU BELOW WILL CAUSE TASM ERRORS! +; +; PLEASE REFER TO THE CUSTOM BUILD INSTRUCTIONS (README.TXT) IN THE SOURCE DIRECTORY (TWO +; DIRECTORIES ABOVE THIS ONE). +; +#DEFINE BOOT_DEFAULT "H" ; DEFAULT BOOT LOADER CMD ON OR AUTO BOOT +; +#include "cfg_rcz80.asm" +; +CRTACT .SET FALSE ; ACTIVATE CRT (VDU,CVDU,PROPIO,ETC) AT STARTUP +; +CPUOSC .SET 7372800 ; CPU OSC FREQ IN MHZ +; +RAMSIZE .SET 2048 ; SIZE OF RAM IN KB (MUST MATCH YOUR HARDWARE!!!) +MEMMGR .SET MM_ZRC ; MEMORY MANAGER: MM_[SBC|Z2|N8|Z180] +; +MDROM .SET FALSE ; MD: ENABLE ROM DISK +; +UARTENABLE .SET TRUE ; UART: ENABLE 8250/16550-LIKE SERIAL DRIVER (UART.ASM) +ACIAENABLE .SET TRUE ; ACIA: ENABLE MOTOROLA 6850 ACIA DRIVER (ACIA.ASM) +SIOENABLE .SET TRUE ; SIO: ENABLE ZILOG SIO SERIAL DRIVER (SIO.ASM) +; +TMSENABLE .SET FALSE ; TMS: ENABLE TMS9918 VIDEO/KBD DRIVER (TMS.ASM) +TMSTIMENABLE .SET FALSE ; TMS: ENABLE TIMER INTERRUPTS (REQUIRES IM1) +; +AY38910ENABLE .SET TRUE ; AY: AY-3-8910 / YM2149 SOUND DRIVER +; +FDENABLE .SET TRUE ; FD: ENABLE FLOPPY DISK DRIVER (FD.ASM) +FDMODE .SET FDMODE_RCWDC ; FD: DRIVER MODE: FDMODE_[DIO|ZETA|ZETA2|DIDE|N8|DIO3|RCSMC|RCWDC|DYNO|EPWDC] +; +IDEENABLE .SET TRUE ; IDE: ENABLE IDE DISK DRIVER (IDE.ASM) +; +PPIDEENABLE .SET TRUE ; PPIDE: ENABLE PARALLEL PORT IDE DISK DRIVER (PPIDE.ASM) +; +PRPENABLE .SET FALSE ; PRP: ENABLE ECB PROPELLER IO BOARD DRIVER (PRP.ASM) diff --git a/Source/HBIOS/Makefile b/Source/HBIOS/Makefile index f1c5ef01..371f24d2 100644 --- a/Source/HBIOS/Makefile +++ b/Source/HBIOS/Makefile @@ -56,18 +56,26 @@ $(ROMNAME).rom $(ROMNAME).com $(ROMNAME).img &: $(ROMDEPS) if [ $(ROM_PLATFORM) != UNA ] ; then \ cat camel80.bin nascom.bin tastybasic.bin game.bin eastaegg.bin netboot.mod updater.bin usrrom.bin >osimg1.bin ; \ cat imgpad2.bin >osimg2.bin ; \ - for f in hbios_rom.bin osimg.bin osimg1.bin osimg2.bin ; do \ - srec_cat $$f -Binary -Crop 0 0x7FFF -Checksum_Negative_Big_Endian 0x7FFF 1 1 -o $$f -Binary ; \ - done \ + if [ $(ROMSIZE) -gt 0 ] ; then \ + for f in hbios_rom.bin osimg.bin osimg1.bin osimg2.bin ; do \ + srec_cat $$f -Binary -Crop 0 0x7FFF -Checksum_Negative_Big_Endian 0x7FFF 1 1 -o $$f -Binary ; \ + done \ + fi \ fi if [ $(ROM_PLATFORM) = UNA ] ; then \ cp osimg.bin $(DEST)/UNA_WBW_SYS.bin ; \ cp ../RomDsk/rom$(ROMSIZE)_una.dat $(DEST)/UNA_WBW_ROM$(ROMSIZE).bin ; \ cat ../UBIOS/UNA-BIOS.BIN osimg.bin ../UBIOS/FSFAT.BIN ../RomDsk/rom$(ROMSIZE)_una.dat >$(ROMNAME).rom ; \ else \ - cat hbios_rom.bin osimg.bin osimg1.bin osimg2.bin ../RomDsk/rom$(ROMSIZE)_wbw.dat >$(ROMNAME).rom ; \ - cat hbios_rom.bin osimg.bin osimg1.bin osimg2.bin >$(ROMNAME).upd ; \ - cat hbios_app.bin osimg_small.bin > $(ROMNAME).com ; \ + if [ $(ROMSIZE) -gt 0 ] ; then \ + cat hbios_rom.bin osimg.bin osimg1.bin osimg2.bin ../RomDsk/rom$(ROMSIZE)_wbw.dat >$(ROMNAME).rom ; \ + cat hbios_rom.bin osimg.bin osimg1.bin osimg2.bin >$(ROMNAME).upd ; \ + cat hbios_app.bin osimg_small.bin > $(ROMNAME).com ; \ + else \ + cat hbios_rom.bin osimg_small.bin > $(ROMNAME).rom ; \ + cat hbios_rom.bin osimg_small.bin > $(ROMNAME).upd ; \ + cat hbios_app.bin osimg_small.bin > $(ROMNAME).com ; \ + fi \ fi prereq: $(FONTS) camel80.bin tastybasic.bin diff --git a/Source/HBIOS/ay38910.asm b/Source/HBIOS/ay38910.asm index 3a196605..2dde8d29 100644 --- a/Source/HBIOS/ay38910.asm +++ b/Source/HBIOS/ay38910.asm @@ -48,6 +48,14 @@ AY_RDAT .EQU $32 AY_RIN .EQU $32 #ENDIF ; +#IF (AYMODE == AYMODE_MBC) +AY_RSEL .EQU $A0 +AY_RDAT .EQU $A1 +AY_RIN .EQU AY_RSEL +AY_ACR .EQU $A2 +AY_CLK .SET 3579545 ; MSX NTSC COLOUR BURST FREQ = 315/88 +#ENDIF +; ;====================================================================== ; ; REGISTERS @@ -128,6 +136,10 @@ AY38910_INIT: PRTS(" MODE=MSX$") #ENDIF ; +#IF (AYMODE == AYMODE_MBC) + PRTS(" MODE=MBC$") +#ENDIF +; #IF (AYMODE == AYMODE_LINC) PRTS(" MODE=LINC$") #ENDIF @@ -136,7 +148,7 @@ AY38910_INIT: LD A,AY_RSEL CALL PRTHEXBYTE ; -#IF ((AYMODE == AYMODE_SCG) | (AYMODE == AYMODE_N8)) +#IF ((AYMODE == AYMODE_SCG) | (AYMODE == AYMODE_N8) | (AYMODE == AYMODE_MBC)) LD A,$FF ; ACTIVATE DEVICE BIT 4 IS AY RESET CONTROL, BIT 3 IS ACTIVE LED OUT (AY_ACR),A ; SET INIT AUX CONTROL REG #ENDIF diff --git a/Source/HBIOS/cfg_dyno.asm b/Source/HBIOS/cfg_dyno.asm index 5a4ce268..7be37bcb 100644 --- a/Source/HBIOS/cfg_dyno.asm +++ b/Source/HBIOS/cfg_dyno.asm @@ -13,6 +13,8 @@ ; #DEFINE PLATFORM_NAME "DYNO" ; +#INCLUDE "hbios.inc" +; PLATFORM .EQU PLT_DYNO ; PLT_[SBC|ZETA|ZETA2|N8|MK4|UNA|RCZ80|RCZ180|EZZ80|SCZ180|DYNO|RCZ280|MBC] CPUFAM .EQU CPU_Z180 ; CPU FAMILY: CPU_[Z80|Z180|Z280] BIOS .EQU BIOS_WBW ; HARDWARE BIOS: BIOS_[WBW|UNA] @@ -30,8 +32,7 @@ INTMODE .EQU 2 ; INTERRUPTS: 0=NONE, 1=MODE 1, 2=MODE 2, 3=MODE 3 (Z280) DEFSERCFG .EQU SER_38400_8N1 ; DEFAULT SERIAL LINE CONFIG (SEE STD.ASM) ; RAMSIZE .EQU 512 ; SIZE OF RAM IN KB (MUST MATCH YOUR HARDWARE!!!) -PLT_RAM_R .EQU 0 ; RESERVE FIRST N KB OF RAM (USUALLY 0) -PLT_ROM_R .EQU 0 ; RESERVE FIRST N KB OR ROM (USUALLY 0) +ROMSIZE_CHK .EQU 0 ; ROMSIZE VALUE VEREIFICATION (0=DISABLED) MEMMGR .EQU MM_Z180 ; MEMORY MANAGER: MM_[SBC|Z2|N8|Z180|Z280|MBC] RAMLOC .EQU 19 ; START OF RAM AS POWER OF 2 (2^N) IN PHYSICAL ADDRESS SPACE RAMBIAS .EQU (1 << (RAMLOC - 10)) ; OFFSET OF START OF RAM IN PHYSICAL ADDRESS SPACE @@ -124,7 +125,7 @@ MDENABLE .EQU TRUE ; MD: ENABLE MEMORY (ROM/RAM) DISK DRIVER (MD.ASM) MDROM .EQU TRUE ; MD: ENABLE ROM DISK MDRAM .EQU TRUE ; MD: ENABLE RAM DISK MDTRACE .EQU 1 ; MD: TRACE LEVEL (0=NO,1=ERRORS,2=ALL) -MDFFENABLE .EQU FALSE ; MD: ENABLE FLASH FILE SYSTEM +MDFFENABLE .EQU FALSE ; MD: ENABLE FLASH FILE SYSTEM ; FDENABLE .EQU FALSE ; FD: ENABLE FLOPPY DISK DRIVER (FD.ASM) FDMODE .EQU FDMODE_DYNO ; FD: DRIVER MODE: FDMODE_[DIO|ZETA|ZETA2|DIDE|N8|DIO3|RCSMC|RCWDC|DYNO|EPFDC|MBC] @@ -178,6 +179,8 @@ PPPENABLE .EQU FALSE ; PPP: ENABLE ZETA PARALLEL PORT PROPELLER BOARD DRIVER (P ; HDSKENABLE .EQU FALSE ; HDSK: ENABLE SIMH HDSK DISK DRIVER (HDSK.ASM) ; +PIOENABLE .EQU FALSE ; PIO: ENABLE ZILOG PIO DRIVER (PIO.ASM) +; PIO_4P .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB 4P BOARD PIO_ZP .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB ZILOG PERIPHERALS BOARD (PIO.ASM) PIO_SBC .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR 8255 CHIP @@ -191,7 +194,7 @@ SNMODE .EQU SNMODE_NONE ; DRIVER MODE: SNMODE_[NONE|RC2014|VGM] ; AY38910ENABLE .EQU FALSE ; AY: AY-3-8910 / YM2149 SOUND DRIVER AY_CLK .EQU CPUOSC / 4 ; DEFAULT TO CPUOSC / 4 -AYMODE .EQU AYMODE_NONE ; AY: DRIVER MODE: AYMODE_[SCG|N8|RCZ80|RCZ180|MSX|LINC] +AYMODE .EQU AYMODE_NONE ; AY: DRIVER MODE: AYMODE_[SCG|N8|RCZ80|RCZ180|MSX|LINC|MBC] ; SPKENABLE .EQU FALSE ; SPK: ENABLE RTC LATCH IOBIT SOUND DRIVER (SPK.ASM) ; diff --git a/Source/HBIOS/cfg_ezz80.asm b/Source/HBIOS/cfg_ezz80.asm index 24713e83..59ee6c98 100644 --- a/Source/HBIOS/cfg_ezz80.asm +++ b/Source/HBIOS/cfg_ezz80.asm @@ -13,6 +13,8 @@ ; #DEFINE PLATFORM_NAME "EASYZ80" ; +#INCLUDE "hbios.inc" +; PLATFORM .EQU PLT_EZZ80 ; PLT_[SBC|ZETA|ZETA2|N8|MK4|UNA|RCZ80|RCZ180|EZZ80|SCZ180|DYNO|RCZ280|MBC] CPUFAM .EQU CPU_Z80 ; CPU FAMILY: CPU_[Z80|Z180|Z280] BIOS .EQU BIOS_WBW ; HARDWARE BIOS: BIOS_[WBW|UNA] @@ -30,8 +32,7 @@ INTMODE .EQU 2 ; INTERRUPTS: 0=NONE, 1=MODE 1, 2=MODE 2, 3=MODE 3 (Z280) DEFSERCFG .EQU SER_115200_8N1 ; DEFAULT SERIAL LINE CONFIG (SEE STD.ASM) ; RAMSIZE .EQU 512 ; SIZE OF RAM IN KB (MUST MATCH YOUR HARDWARE!!!) -PLT_RAM_R .EQU 0 ; RESERVE FIRST N KB OF RAM (USUALLY 0) -PLT_ROM_R .EQU 0 ; RESERVE FIRST N KB OR ROM (USUALLY 0) +ROMSIZE_CHK .EQU 0 ; ROMSIZE VALUE VEREIFICATION (0=DISABLED) MEMMGR .EQU MM_Z2 ; MEMORY MANAGER: MM_[SBC|Z2|N8|Z180|Z280|MBC] MPGSEL_0 .EQU $78 ; Z2 MEM MGR BANK 0 PAGE SELECT REG (WRITE ONLY) MPGSEL_1 .EQU $79 ; Z2 MEM MGR BANK 1 PAGE SELECT REG (WRITE ONLY) @@ -162,7 +163,7 @@ MDENABLE .EQU TRUE ; MD: ENABLE MEMORY (ROM/RAM) DISK DRIVER (MD.ASM) MDROM .EQU TRUE ; MD: ENABLE ROM DISK MDRAM .EQU TRUE ; MD: ENABLE RAM DISK MDTRACE .EQU 1 ; MD: TRACE LEVEL (0=NO,1=ERRORS,2=ALL) -MDFFENABLE .EQU FALSE ; MD: ENABLE FLASH FILE SYSTEM +MDFFENABLE .EQU FALSE ; MD: ENABLE FLASH FILE SYSTEM ; FDENABLE .EQU FALSE ; FD: ENABLE FLOPPY DISK DRIVER (FD.ASM) FDMODE .EQU FDMODE_RCWDC ; FD: DRIVER MODE: FDMODE_[DIO|ZETA|ZETA2|DIDE|N8|DIO3|RCSMC|RCWDC|DYNO|EPFDC|MBC] @@ -220,6 +221,8 @@ PPPENABLE .EQU FALSE ; PPP: ENABLE ZETA PARALLEL PORT PROPELLER BOARD DRIVER (P ; HDSKENABLE .EQU FALSE ; HDSK: ENABLE SIMH HDSK DISK DRIVER (HDSK.ASM) ; +PIOENABLE .EQU FALSE ; PIO: ENABLE ZILOG PIO DRIVER (PIO.ASM) +; PIO_4P .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB 4P BOARD PIO_ZP .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB ZILOG PERIPHERALS BOARD (PIO.ASM) PIO_SBC .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR 8255 CHIP @@ -233,7 +236,7 @@ SNMODE .EQU SNMODE_NONE ; DRIVER MODE: SNMODE_[NONE|RC2014|VGM] ; AY38910ENABLE .EQU FALSE ; AY: AY-3-8910 / YM2149 SOUND DRIVER AY_CLK .EQU CPUOSC / 4 ; DEFAULT TO CPUOSC / 4 -AYMODE .EQU AYMODE_RCZ80 ; AY: DRIVER MODE: AYMODE_[SCG|N8|RCZ80|RCZ180|MSX|LINC] +AYMODE .EQU AYMODE_RCZ80 ; AY: DRIVER MODE: AYMODE_[SCG|N8|RCZ80|RCZ180|MSX|LINC|MBC] ; SPKENABLE .EQU FALSE ; SPK: ENABLE RTC LATCH IOBIT SOUND DRIVER (SPK.ASM) ; diff --git a/Source/HBIOS/cfg_master.asm b/Source/HBIOS/cfg_master.asm index f527e76f..42a39766 100644 --- a/Source/HBIOS/cfg_master.asm +++ b/Source/HBIOS/cfg_master.asm @@ -10,6 +10,8 @@ ; #DEFINE PLATFORM_NAME "ROMWBW" ; +#INCLUDE "hbios.inc" +; PLATFORM .EQU PLT_SBC ; PLT_[SBC|ZETA|ZETA2|N8|MK4|UNA|RCZ80|RCZ180|EZZ80|SCZ180|DYNO|RCZ280|MBC] CPUFAM .EQU CPU_Z80 ; CPU FAMILY: CPU_[Z80|Z180|Z280] BIOS .EQU BIOS_WBW ; HARDWARE BIOS: BIOS_[WBW|UNA] @@ -27,8 +29,7 @@ INTMODE .EQU 0 ; INTERRUPTS: 0=NONE, 1=MODE 1, 2=MODE 2, 3=MODE 3 (Z280) DEFSERCFG .EQU SER_38400_8N1 ; DEFAULT SERIAL LINE CONFIG (SEE STD.ASM) ; RAMSIZE .EQU 512 ; SIZE OF RAM IN KB (MUST MATCH YOUR HARDWARE!!!) -PLT_RAM_R .EQU 0 ; RESERVE FIRST N KB OF RAM (USUALLY 0) -PLT_ROM_R .EQU 0 ; RESERVE FIRST N KB OR ROM (USUALLY 0) +ROMSIZE_CHK .EQU 0 ; ROMSIZE VALUE VEREIFICATION (0=DISABLED) MEMMGR .EQU MM_NONE ; MEMORY MANAGER: MM_[SBC|Z2|N8|Z180|Z280|MBC] RAMLOC .EQU 19 ; START OF RAM AS POWER OF 2 (2^N) IN PHYSICAL ADDRESS SPACE RAMBIAS .EQU (1 << (RAMLOC - 10)) ; OFFSET OF START OF RAM IN PHYSICAL ADDRESS SPACE @@ -285,6 +286,11 @@ PPPCONENABLE .EQU TRUE ; PPP: ENABLE PPP DRIVER VIDEO/KBD SUPPORT HDSKENABLE .EQU FALSE ; HDSK: ENABLE SIMH HDSK DISK DRIVER (HDSK.ASM) HDSKTRACE .EQU 1 ; HDSK: TRACE LEVEL (0=NO,1=ERRORS,2=ALL) ; +PIOENABLE .EQU FALSE ; PIO: ENABLE ZILOG PIO DRIVER (PIO.ASM) +PIOCNT .EQU 2 ; PIO: NUMBER OF CHIPS TO DETECT (1-2), 2 CHANNELS PER CHIP +PIO0BASE .EQU $B8 ; PIO 0: REGISTERS BASE ADR +PIO1BASE .EQU $BC ; PIO 1: REGISTERS BASE ADR +; PIO_4P .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB 4P BOARD PIO4BASE .EQU $90 ; PIO: PIO REGISTERS BASE ADR FOR ECB 4P BOARD PIO_ZP .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB ZILOG PERIPHERALS BOARD (PIO.ASM) @@ -302,7 +308,7 @@ SNMODE .EQU SNMODE_NONE ; DRIVER MODE: SNMODE_[NONE|RC2014|VGM] ; AY38910ENABLE .EQU FALSE ; AY: AY-3-8910 / YM2149 SOUND DRIVER AY_CLK .EQU CPUOSC / 4 ; DEFAULT TO CPUOSC / 4 -AYMODE .EQU AYMODE_NONE ; AY: DRIVER MODE: AYMODE_[SCG|N8|RCZ80|RCZ180|MSX|LINC] +AYMODE .EQU AYMODE_NONE ; AY: DRIVER MODE: AYMODE_[SCG|N8|RCZ80|RCZ180|MSX|LINC|MBC] ; SPKENABLE .EQU FALSE ; SPK: ENABLE RTC LATCH IOBIT SOUND DRIVER (SPK.ASM) ; diff --git a/Source/HBIOS/cfg_mbc.asm b/Source/HBIOS/cfg_mbc.asm index ec23472c..a5cae23b 100644 --- a/Source/HBIOS/cfg_mbc.asm +++ b/Source/HBIOS/cfg_mbc.asm @@ -13,6 +13,8 @@ ; #DEFINE PLATFORM_NAME "Multi Board Computer" ; +#INCLUDE "hbios.inc" +; PLATFORM .EQU PLT_MBC ; PLT_[SBC|ZETA|ZETA2|N8|MK4|UNA|RCZ80|RCZ180|EZZ80|SCZ180|DYNO|RCZ280|MBC] CPUFAM .EQU CPU_Z80 ; CPU FAMILY: CPU_[Z80|Z180|Z280] BIOS .EQU BIOS_WBW ; HARDWARE BIOS: BIOS_[WBW|UNA] @@ -30,8 +32,7 @@ INTMODE .EQU 0 ; INTERRUPTS: 0=NONE, 1=MODE 1, 2=MODE 2, 3=MODE 3 (Z280) DEFSERCFG .EQU SER_38400_8N1 ; DEFAULT SERIAL LINE CONFIG (SEE STD.ASM) ; RAMSIZE .EQU 512 ; SIZE OF RAM IN KB (MUST MATCH YOUR HARDWARE!!!) -PLT_RAM_R .EQU 0 ; RESERVE FIRST N KB OF RAM (USUALLY 0) -PLT_ROM_R .EQU 0 ; RESERVE FIRST N KB OR ROM (USUALLY 0) +ROMSIZE_CHK .EQU 0 ; ROMSIZE VALUE VEREIFICATION (0=DISABLED) MEMMGR .EQU MM_MBC ; MEMORY MANAGER: MM_[SBC|Z2|N8|Z180|Z280|MBC] MPCL_RAM .EQU $78 ; SBC MEM MGR RAM PAGE SELECT REG (WRITE ONLY) MPCL_ROM .EQU $7C ; SBC MEM MGR ROM PAGE SELECT REG (WRITE ONLY) @@ -41,7 +42,7 @@ RTCIO .EQU $70 ; RTC LATCH REGISTER ADR KIOENABLE .EQU FALSE ; ENABLE ZILOG KIO SUPPORT KIOBASE .EQU $80 ; KIO BASE I/O ADDRESS ; -CTCENABLE .EQU FALSE ; ENABLE ZILOG CTC SUPPORT +CTCENABLE .EQU TRUE ; ENABLE ZILOG CTC SUPPORT CTCDEBUG .EQU FALSE ; ENABLE CTC DRIVER DEBUG OUTPUT CTCBASE .EQU $B0 ; CTC BASE I/O ADDRESS CTCTIMER .EQU TRUE ; ENABLE CTC PERIODIC TIMER @@ -49,7 +50,7 @@ CTCMODE .EQU CTCMODE_CTR ; CTC MODE: CTCMODE_[NONE|CTR|TIM16|TIM256] CTCPRE .EQU 256 ; PRESCALE CONSTANT (1-256) CTCPRECH .EQU 2 ; PRESCALE CHANNEL (0-3) CTCTIMCH .EQU 3 ; TIMER CHANNEL (0-3) -CTCOSC .EQU 614400 ; CTC CLOCK FREQUENCY +CTCOSC .EQU (4915200/8) ; CTC CLOCK FREQUENCY ; EIPCENABLE .EQU FALSE ; EIPC: ENABLE Z80 EIPC (Z84C15) INITIALIZATION ; @@ -120,7 +121,7 @@ Z2UENABLE .EQU FALSE ; Z2U: ENABLE Z280 UART SERIAL DRIVER (Z2U.ASM) ; ACIAENABLE .EQU FALSE ; ACIA: ENABLE MOTOROLA 6850 ACIA DRIVER (ACIA.ASM) ; -SIOENABLE .EQU FALSE ; SIO: ENABLE ZILOG SIO SERIAL DRIVER (SIO.ASM) +SIOENABLE .EQU TRUE ; SIO: ENABLE ZILOG SIO SERIAL DRIVER (SIO.ASM) SIODEBUG .EQU FALSE ; SIO: ENABLE DEBUG OUTPUT SIOBOOT .EQU 0 ; SIO: REBOOT ON RCV CHAR (0=DISABLED) SIOCNT .EQU 1 ; SIO: NUMBER OF CHIPS TO DETECT (1-2), 2 CHANNELS PER CHIP @@ -151,7 +152,7 @@ MDENABLE .EQU TRUE ; MD: ENABLE MEMORY (ROM/RAM) DISK DRIVER (MD.ASM) MDROM .EQU TRUE ; MD: ENABLE ROM DISK MDRAM .EQU TRUE ; MD: ENABLE RAM DISK MDTRACE .EQU 1 ; MD: TRACE LEVEL (0=NO,1=ERRORS,2=ALL) -MDFFENABLE .EQU FALSE ; MD: ENABLE FLASH FILE SYSTEM +MDFFENABLE .EQU FALSE ; MD: ENABLE FLASH FILE SYSTEM ; ; FDENABLE .EQU FALSE ; FD: ENABLE FLOPPY DISK DRIVER (FD.ASM) @@ -217,6 +218,11 @@ PPPENABLE .EQU FALSE ; PPP: ENABLE ZETA PARALLEL PORT PROPELLER BOARD DRIVER (P HDSKENABLE .EQU FALSE ; HDSK: ENABLE SIMH HDSK DISK DRIVER (HDSK.ASM) HDSKTRACE .EQU 1 ; HDSK: TRACE LEVEL (0=NO,1=ERRORS,2=ALL) ; +PIOENABLE .EQU TRUE ; PIO: ENABLE ZILOG PIO DRIVER (PIO.ASM) +PIOCNT .EQU 2 ; PIO: NUMBER OF CHIPS TO DETECT (1-2), 2 CHANNELS PER CHIP +PIO0BASE .EQU $B8 ; PIO 0: REGISTERS BASE ADR +PIO1BASE .EQU $BC ; PIO 1: REGISTERS BASE ADR +; PIO_4P .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB 4P BOARD PIO4BASE .EQU $90 ; PIO: PIO REGISTERS BASE ADR FOR ECB 4P BOARD PIO_ZP .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB ZILOG PERIPHERALS BOARD (PIO.ASM) @@ -234,7 +240,7 @@ SNMODE .EQU SNMODE_NONE ; DRIVER MODE: SNMODE_[NONE|RC2014|VGM] ; AY38910ENABLE .EQU FALSE ; AY: AY-3-8910 / YM2149 SOUND DRIVER AY_CLK .EQU CPUOSC / 4 ; DEFAULT TO CPUOSC / 4 -AYMODE .EQU AYMODE_NONE ; AY: DRIVER MODE: AYMODE_[SCG|N8|RCZ80|RCZ180|MSX|LINC] +AYMODE .EQU AYMODE_NONE ; AY: DRIVER MODE: AYMODE_[SCG|N8|RCZ80|RCZ180|MSX|LINC|MBC] ; SPKENABLE .EQU TRUE ; SPK: ENABLE RTC LATCH IOBIT SOUND DRIVER (SPK.ASM) ; diff --git a/Source/HBIOS/cfg_mk4.asm b/Source/HBIOS/cfg_mk4.asm index 157e1134..2732bd39 100644 --- a/Source/HBIOS/cfg_mk4.asm +++ b/Source/HBIOS/cfg_mk4.asm @@ -13,6 +13,8 @@ ; #DEFINE PLATFORM_NAME "MARK IV" ; +#INCLUDE "hbios.inc" +; PLATFORM .EQU PLT_MK4 ; PLT_[SBC|ZETA|ZETA2|N8|MK4|UNA|RCZ80|RCZ180|EZZ80|SCZ180|DYNO|RCZ280|MBC] CPUFAM .EQU CPU_Z180 ; CPU FAMILY: CPU_[Z80|Z180|Z280] BIOS .EQU BIOS_WBW ; HARDWARE BIOS: BIOS_[WBW|UNA] @@ -30,8 +32,7 @@ INTMODE .EQU 2 ; INTERRUPTS: 0=NONE, 1=MODE 1, 2=MODE 2, 3=MODE 3 (Z280) DEFSERCFG .EQU SER_38400_8N1 ; DEFAULT SERIAL LINE CONFIG (SEE STD.ASM) ; RAMSIZE .EQU 512 ; SIZE OF RAM IN KB (MUST MATCH YOUR HARDWARE!!!) -PLT_RAM_R .EQU 0 ; RESERVE FIRST N KB OF RAM (USUALLY 0) -PLT_ROM_R .EQU 0 ; RESERVE FIRST N KB OR ROM (USUALLY 0) +ROMSIZE_CHK .EQU 0 ; ROMSIZE VALUE VEREIFICATION (0=DISABLED) MEMMGR .EQU MM_Z180 ; MEMORY MANAGER: MM_[SBC|Z2|N8|Z180|Z280|MBC] RAMLOC .EQU 19 ; START OF RAM AS POWER OF 2 (2^N) IN PHYSICAL ADDRESS SPACE RAMBIAS .EQU (1 << (RAMLOC - 10)) ; OFFSET OF START OF RAM IN PHYSICAL ADDRESS SPACE @@ -150,7 +151,7 @@ MDENABLE .EQU TRUE ; MD: ENABLE MEMORY (ROM/RAM) DISK DRIVER (MD.ASM) MDROM .EQU TRUE ; MD: ENABLE ROM DISK MDRAM .EQU TRUE ; MD: ENABLE RAM DISK MDTRACE .EQU 1 ; MD: TRACE LEVEL (0=NO,1=ERRORS,2=ALL) -MDFFENABLE .EQU FALSE ; MD: ENABLE FLASH FILE SYSTEM +MDFFENABLE .EQU FALSE ; MD: ENABLE FLASH FILE SYSTEM ; FDENABLE .EQU FALSE ; FD: ENABLE FLOPPY DISK DRIVER (FD.ASM) FDMODE .EQU FDMODE_DIDE ; FD: DRIVER MODE: FDMODE_[DIO|ZETA|ZETA2|DIDE|N8|DIO3|RCSMC|RCWDC|DYNO|EPFDC|MBC] @@ -218,6 +219,11 @@ PPPCONENABLE .EQU TRUE ; PPP: ENABLE PPP DRIVER VIDEO/KBD SUPPORT ; HDSKENABLE .EQU FALSE ; HDSK: ENABLE SIMH HDSK DISK DRIVER (HDSK.ASM) ; +PIOENABLE .EQU FALSE ; PIO: ENABLE ZILOG PIO DRIVER (PIO.ASM) +PIOCNT .EQU 2 ; PIO: NUMBER OF CHIPS TO DETECT (1-2), 2 CHANNELS PER CHIP +PIO0BASE .EQU $B8 ; PIO 0: REGISTERS BASE ADR +PIO1BASE .EQU $BC ; PIO 1: REGISTERS BASE ADR +; PIO_4P .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB 4P BOARD PIO4BASE .EQU $90 ; PIO: PIO REGISTERS BASE ADR FOR ECB 4P BOARD PIO_ZP .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB ZILOG PERIPHERALS BOARD (PIO.ASM) @@ -235,7 +241,7 @@ SNMODE .EQU SNMODE_NONE ; DRIVER MODE: SNMODE_[NONE|RC2014|VGM] ; AY38910ENABLE .EQU FALSE ; AY: AY-3-8910 / YM2149 SOUND DRIVER AY_CLK .EQU CPUOSC / 4 ; DEFAULT TO CPUOSC / 4 -AYMODE .EQU AYMODE_SCG ; AY: DRIVER MODE: AYMODE_[SCG|N8|RCZ80|RCZ180|MSX|LINC] +AYMODE .EQU AYMODE_SCG ; AY: DRIVER MODE: AYMODE_[SCG|N8|RCZ80|RCZ180|MSX|LINC|MBC] ; SPKENABLE .EQU FALSE ; SPK: ENABLE RTC LATCH IOBIT SOUND DRIVER (SPK.ASM) ; diff --git a/Source/HBIOS/cfg_n8.asm b/Source/HBIOS/cfg_n8.asm index d9aa64c6..47dab164 100644 --- a/Source/HBIOS/cfg_n8.asm +++ b/Source/HBIOS/cfg_n8.asm @@ -13,6 +13,8 @@ ; #DEFINE PLATFORM_NAME "N8" ; +#INCLUDE "hbios.inc" +; PLATFORM .EQU PLT_N8 ; PLT_[SBC|ZETA|ZETA2|N8|MK4|UNA|RCZ80|RCZ180|EZZ80|SCZ180|DYNO|RCZ280|MBC] CPUFAM .EQU CPU_Z180 ; CPU FAMILY: CPU_[Z80|Z180|Z280] BIOS .EQU BIOS_WBW ; HARDWARE BIOS: BIOS_[WBW|UNA] @@ -30,8 +32,7 @@ INTMODE .EQU 2 ; INTERRUPTS: 0=NONE, 1=MODE 1, 2=MODE 2, 3=MODE 3 (Z280) DEFSERCFG .EQU SER_38400_8N1 ; DEFAULT SERIAL LINE CONFIG (SEE STD.ASM) ; RAMSIZE .EQU 512 ; SIZE OF RAM IN KB (MUST MATCH YOUR HARDWARE!!!) -PLT_RAM_R .EQU 0 ; RESERVE FIRST N KB OF RAM (USUALLY 0) -PLT_ROM_R .EQU 0 ; RESERVE FIRST N KB OR ROM (USUALLY 0) +ROMSIZE_CHK .EQU 0 ; ROMSIZE VALUE VEREIFICATION (0=DISABLED) MEMMGR .EQU MM_N8 ; MEMORY MANAGER: MM_[SBC|Z2|N8|Z180|Z280|MBC] RAMBIAS .EQU 0 ; OFFSET OF START OF RAM IN PHYSICAL ADDRESS SPACE RAMLOC .EQU 0 ; START OF RAM AS POWER OF 2 (2^N) IN PHYSICAL ADDRESS SPACE @@ -152,7 +153,7 @@ MDENABLE .EQU TRUE ; MD: ENABLE MEMORY (ROM/RAM) DISK DRIVER (MD.ASM) MDROM .EQU TRUE ; MD: ENABLE ROM DISK MDRAM .EQU TRUE ; MD: ENABLE RAM DISK MDTRACE .EQU 1 ; MD: TRACE LEVEL (0=NO,1=ERRORS,2=ALL) -MDFFENABLE .EQU FALSE ; MD: ENABLE FLASH FILE SYSTEM +MDFFENABLE .EQU FALSE ; MD: ENABLE FLASH FILE SYSTEM ; FDENABLE .EQU TRUE ; FD: ENABLE FLOPPY DISK DRIVER (FD.ASM) FDMODE .EQU FDMODE_N8 ; FD: DRIVER MODE: FDMODE_[DIO|ZETA|ZETA2|DIDE|N8|DIO3|RCSMC|RCWDC|DYNO|EPFDC|MBC] @@ -216,6 +217,11 @@ PPPENABLE .EQU FALSE ; PPP: ENABLE ZETA PARALLEL PORT PROPELLER BOARD DRIVER (P ; HDSKENABLE .EQU FALSE ; HDSK: ENABLE SIMH HDSK DISK DRIVER (HDSK.ASM) ; +PIOENABLE .EQU FALSE ; PIO: ENABLE ZILOG PIO DRIVER (PIO.ASM) +PIOCNT .EQU 2 ; PIO: NUMBER OF CHIPS TO DETECT (1-2), 2 CHANNELS PER CHIP +PIO0BASE .EQU $B8 ; PIO 0: REGISTERS BASE ADR +PIO1BASE .EQU $BC ; PIO 1: REGISTERS BASE ADR +; PIO_4P .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB 4P BOARD PIO4BASE .EQU $90 ; PIO: PIO REGISTERS BASE ADR FOR ECB 4P BOARD PIO_ZP .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB ZILOG PERIPHERALS BOARD (PIO.ASM) @@ -233,7 +239,7 @@ SNMODE .EQU SNMODE_NONE ; DRIVER MODE: SNMODE_[NONE|RC2014|VGM] ; AY38910ENABLE .EQU FALSE ; AY: AY-3-8910 / YM2149 SOUND DRIVER AY_CLK .EQU CPUOSC / 4 ; DEFAULT TO CPUOSC / 4 -AYMODE .EQU AYMODE_N8 ; AY: DRIVER MODE: AYMODE_[SCG|N8|RCZ80|RCZ180|MSX|LINC] +AYMODE .EQU AYMODE_N8 ; AY: DRIVER MODE: AYMODE_[SCG|N8|RCZ80|RCZ180|MSX|LINC|MBC] ; SPKENABLE .EQU FALSE ; SPK: ENABLE RTC LATCH IOBIT SOUND DRIVER (SPK.ASM) ; diff --git a/Source/HBIOS/cfg_rcz180.asm b/Source/HBIOS/cfg_rcz180.asm index eaf2141d..63000248 100644 --- a/Source/HBIOS/cfg_rcz180.asm +++ b/Source/HBIOS/cfg_rcz180.asm @@ -13,6 +13,8 @@ ; #DEFINE PLATFORM_NAME "RC2014" ; +#INCLUDE "hbios.inc" +; PLATFORM .EQU PLT_RCZ180 ; PLT_[SBC|ZETA|ZETA2|N8|MK4|UNA|RCZ80|RCZ180|EZZ80|SCZ180|DYNO|RCZ280|MBC] CPUFAM .EQU CPU_Z180 ; CPU FAMILY: CPU_[Z80|Z180|Z280] BIOS .EQU BIOS_WBW ; HARDWARE BIOS: BIOS_[WBW|UNA] @@ -30,8 +32,7 @@ INTMODE .EQU 2 ; INTERRUPTS: 0=NONE, 1=MODE 1, 2=MODE 2, 3=MODE 3 (Z280) DEFSERCFG .EQU SER_115200_8N1 ; DEFAULT SERIAL LINE CONFIG (SEE STD.ASM) ; RAMSIZE .EQU 512 ; SIZE OF RAM IN KB (MUST MATCH YOUR HARDWARE!!!) -PLT_RAM_R .EQU 0 ; RESERVE FIRST N KB OF RAM (USUALLY 0) -PLT_ROM_R .EQU 0 ; RESERVE FIRST N KB OR ROM (USUALLY 0) +ROMSIZE_CHK .EQU 0 ; ROMSIZE VALUE VEREIFICATION (0=DISABLED) MEMMGR .EQU MM_Z180 ; MEMORY MANAGER: MM_[SBC|Z2|N8|Z180|Z280|MBC] RAMLOC .EQU 19 ; START OF RAM AS POWER OF 2 (2^N) IN PHYSICAL ADDRESS SPACE RAMBIAS .EQU (1 << (RAMLOC - 10)) ; OFFSET OF START OF RAM IN PHYSICAL ADDRESS SPACE @@ -168,7 +169,7 @@ MDENABLE .EQU TRUE ; MD: ENABLE MEMORY (ROM/RAM) DISK DRIVER (MD.ASM) MDROM .EQU TRUE ; MD: ENABLE ROM DISK MDRAM .EQU TRUE ; MD: ENABLE RAM DISK MDTRACE .EQU 1 ; MD: TRACE LEVEL (0=NO,1=ERRORS,2=ALL) -MDFFENABLE .EQU FALSE ; MD: ENABLE FLASH FILE SYSTEM +MDFFENABLE .EQU FALSE ; MD: ENABLE FLASH FILE SYSTEM ; FDENABLE .EQU FALSE ; FD: ENABLE FLOPPY DISK DRIVER (FD.ASM) FDMODE .EQU FDMODE_RCWDC ; FD: DRIVER MODE: FDMODE_[DIO|ZETA|ZETA2|DIDE|N8|DIO3|RCSMC|RCWDC|DYNO|EPFDC|MBC] @@ -232,6 +233,11 @@ PPPENABLE .EQU FALSE ; PPP: ENABLE ZETA PARALLEL PORT PROPELLER BOARD DRIVER (P ; HDSKENABLE .EQU FALSE ; HDSK: ENABLE SIMH HDSK DISK DRIVER (HDSK.ASM) ; +PIOENABLE .EQU FALSE ; PIO: ENABLE ZILOG PIO DRIVER (PIO.ASM) +PIOCNT .EQU 2 ; PIO: NUMBER OF CHIPS TO DETECT (1-2), 2 CHANNELS PER CHIP +PIO0BASE .EQU $B8 ; PIO 0: REGISTERS BASE ADR +PIO1BASE .EQU $BC ; PIO 1: REGISTERS BASE ADR +; PIO_4P .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB 4P BOARD PIO_ZP .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB ZILOG PERIPHERALS BOARD (PIO.ASM) PIO_SBC .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR 8255 CHIP @@ -245,7 +251,7 @@ SNMODE .EQU SNMODE_NONE ; DRIVER MODE: SNMODE_[NONE|RC2014|VGM] ; AY38910ENABLE .EQU FALSE ; AY: AY-3-8910 / YM2149 SOUND DRIVER AY_CLK .EQU CPUOSC / 4 ; DEFAULT TO CPUOSC / 4 -AYMODE .EQU AYMODE_RCZ180 ; AY: DRIVER MODE: AYMODE_[SCG|N8|RCZ80|RCZ180|MSX|LINC] +AYMODE .EQU AYMODE_RCZ180 ; AY: DRIVER MODE: AYMODE_[SCG|N8|RCZ80|RCZ180|MSX|LINC|MBC] ; SPKENABLE .EQU FALSE ; SPK: ENABLE RTC LATCH IOBIT SOUND DRIVER (SPK.ASM) ; diff --git a/Source/HBIOS/cfg_rcz280.asm b/Source/HBIOS/cfg_rcz280.asm index 625f5e32..e79d56c7 100644 --- a/Source/HBIOS/cfg_rcz280.asm +++ b/Source/HBIOS/cfg_rcz280.asm @@ -13,6 +13,8 @@ ; #DEFINE PLATFORM_NAME "RC2014" ; +#INCLUDE "hbios.inc" +; PLATFORM .EQU PLT_RCZ280 ; PLT_[SBC|ZETA|ZETA2|N8|MK4|UNA|RCZ80|RCZ180|EZZ80|SCZ180|DYNO|RCZ280|MBC] CPUFAM .EQU CPU_Z280 ; CPU FAMILY: CPU_[Z80|Z180|Z280] BIOS .EQU BIOS_WBW ; HARDWARE BIOS: BIOS_[WBW|UNA] @@ -25,13 +27,12 @@ BOOT_TIMEOUT .EQU -1 ; AUTO BOOT TIMEOUT IN SECONDS, -1 TO DISABLE, 0 FOR IMMED ; CPUSPDCAP .EQU SPD_FIXED ; CPU SPEED CHANGE CAPABILITY SPD_FIXED|SPD_HILO CPUSPDDEF .EQU SPD_HIGH ; CPU SPEED DEFAULT SPD_UNSUP|SPD_HIGH|SPD_LOW -CPUOSC .EQU 24000000 ; CPU OSC FREQ IN MHZ +CPUOSC .EQU 12000000 ; CPU OSC FREQ IN MHZ INTMODE .EQU 0 ; INTERRUPTS: 0=NONE, 1=MODE 1, 2=MODE 2, 3=MODE 3 (Z280) DEFSERCFG .EQU SER_115200_8N1 ; DEFAULT SERIAL LINE CONFIG (SEE STD.ASM) ; RAMSIZE .EQU 512 ; SIZE OF RAM IN KB (MUST MATCH YOUR HARDWARE!!!) -PLT_RAM_R .EQU 0 ; RESERVE FIRST N KB OF RAM (USUALLY 0) -PLT_ROM_R .EQU 0 ; RESERVE FIRST N KB OR ROM (USUALLY 0) +ROMSIZE_CHK .EQU 0 ; ROMSIZE VALUE VEREIFICATION (0=DISABLED) MEMMGR .EQU MM_Z2 ; MEMORY MANAGER: MM_[SBC|Z2|N8|Z180|Z280|MBC] RAMLOC .EQU 19 ; START OF RAM AS POWER OF 2 (2^N) IN PHYSICAL ADDRESS SPACE RAMBIAS .EQU (1 << (RAMLOC - 10)) ; OFFSET OF START OF RAM IN PHYSICAL ADDRESS SPACE @@ -184,7 +185,7 @@ MDENABLE .EQU TRUE ; MD: ENABLE MEMORY (ROM/RAM) DISK DRIVER (MD.ASM) MDROM .EQU TRUE ; MD: ENABLE ROM DISK MDRAM .EQU TRUE ; MD: ENABLE RAM DISK MDTRACE .EQU 1 ; MD: TRACE LEVEL (0=NO,1=ERRORS,2=ALL) -MDFFENABLE .EQU FALSE ; MD: ENABLE FLASH FILE SYSTEM +MDFFENABLE .EQU FALSE ; MD: ENABLE FLASH FILE SYSTEM ; FDENABLE .EQU FALSE ; FD: ENABLE FLOPPY DISK DRIVER (FD.ASM) FDMODE .EQU FDMODE_RCWDC ; FD: DRIVER MODE: FDMODE_[DIO|ZETA|ZETA2|DIDE|N8|DIO3|RCSMC|RCWDC|DYNO|EPFDC|MBC] @@ -248,6 +249,11 @@ PPPENABLE .EQU FALSE ; PPP: ENABLE ZETA PARALLEL PORT PROPELLER BOARD DRIVER (P ; HDSKENABLE .EQU FALSE ; HDSK: ENABLE SIMH HDSK DISK DRIVER (HDSK.ASM) ; +PIOENABLE .EQU FALSE ; PIO: ENABLE ZILOG PIO DRIVER (PIO.ASM) +PIOCNT .EQU 2 ; PIO: NUMBER OF CHIPS TO DETECT (1-2), 2 CHANNELS PER CHIP +PIO0BASE .EQU $B8 ; PIO 0: REGISTERS BASE ADR +PIO1BASE .EQU $BC ; PIO 1: REGISTERS BASE ADR +; PIO_4P .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB 4P BOARD PIO_ZP .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB ZILOG PERIPHERALS BOARD (PIO.ASM) PIO_SBC .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR 8255 CHIP @@ -261,7 +267,7 @@ SNMODE .EQU SNMODE_NONE ; DRIVER MODE: SNMODE_[NONE|RC2014|VGM] ; AY38910ENABLE .EQU FALSE ; AY: AY-3-8910 / YM2149 SOUND DRIVER AY_CLK .EQU CPUOSC / 4 ; DEFAULT TO CPUOSC / 4 -AYMODE .EQU AYMODE_RCZ80 ; AY: DRIVER MODE: AYMODE_[SCG|N8|RCZ80|RCZ180|MSX|LINC] +AYMODE .EQU AYMODE_RCZ80 ; AY: DRIVER MODE: AYMODE_[SCG|N8|RCZ80|RCZ180|MSX|LINC|MBC] ; SPKENABLE .EQU FALSE ; SPK: ENABLE RTC LATCH IOBIT SOUND DRIVER (SPK.ASM) ; diff --git a/Source/HBIOS/cfg_rcz80.asm b/Source/HBIOS/cfg_rcz80.asm index 4fbb3501..8c4e8454 100644 --- a/Source/HBIOS/cfg_rcz80.asm +++ b/Source/HBIOS/cfg_rcz80.asm @@ -13,6 +13,8 @@ ; #DEFINE PLATFORM_NAME "RC2014" ; +#INCLUDE "hbios.inc" +; PLATFORM .EQU PLT_RCZ80 ; PLT_[SBC|ZETA|ZETA2|N8|MK4|UNA|RCZ80|RCZ180|EZZ80|SCZ180|DYNO|RCZ280|MBC] CPUFAM .EQU CPU_Z80 ; CPU FAMILY: CPU_[Z80|Z180|Z280] BIOS .EQU BIOS_WBW ; HARDWARE BIOS: BIOS_[WBW|UNA] @@ -30,8 +32,7 @@ INTMODE .EQU 1 ; INTERRUPTS: 0=NONE, 1=MODE 1, 2=MODE 2, 3=MODE 3 (Z280) DEFSERCFG .EQU SER_115200_8N1 ; DEFAULT SERIAL LINE CONFIG (SEE STD.ASM) ; RAMSIZE .EQU 512 ; SIZE OF RAM IN KB (MUST MATCH YOUR HARDWARE!!!) -PLT_RAM_R .EQU 0 ; RESERVE FIRST N KB OF RAM (USUALLY 0) -PLT_ROM_R .EQU 0 ; RESERVE FIRST N KB OR ROM (USUALLY 0) +ROMSIZE_CHK .EQU 0 ; ROMSIZE VALUE VEREIFICATION (0=DISABLED) MEMMGR .EQU MM_Z2 ; MEMORY MANAGER: MM_[SBC|Z2|N8|Z180|Z280|MBC] MPGSEL_0 .EQU $78 ; Z2 MEM MGR BANK 0 PAGE SELECT REG (WRITE ONLY) MPGSEL_1 .EQU $79 ; Z2 MEM MGR BANK 1 PAGE SELECT REG (WRITE ONLY) @@ -173,7 +174,7 @@ MDENABLE .EQU TRUE ; MD: ENABLE MEMORY (ROM/RAM) DISK DRIVER (MD.ASM) MDROM .EQU TRUE ; MD: ENABLE ROM DISK MDRAM .EQU TRUE ; MD: ENABLE RAM DISK MDTRACE .EQU 1 ; MD: TRACE LEVEL (0=NO,1=ERRORS,2=ALL) -MDFFENABLE .EQU FALSE ; MD: ENABLE FLASH FILE SYSTEM +MDFFENABLE .EQU FALSE ; MD: ENABLE FLASH FILE SYSTEM ; FDENABLE .EQU FALSE ; FD: ENABLE FLOPPY DISK DRIVER (FD.ASM) FDMODE .EQU FDMODE_RCWDC ; FD: DRIVER MODE: FDMODE_[DIO|ZETA|ZETA2|DIDE|N8|DIO3|RCSMC|RCWDC|DYNO|EPFDC|MBC] @@ -237,6 +238,11 @@ PPPENABLE .EQU FALSE ; PPP: ENABLE ZETA PARALLEL PORT PROPELLER BOARD DRIVER (P ; HDSKENABLE .EQU FALSE ; HDSK: ENABLE SIMH HDSK DISK DRIVER (HDSK.ASM) ; +PIOENABLE .EQU FALSE ; PIO: ENABLE ZILOG PIO DRIVER (PIO.ASM) +PIOCNT .EQU 2 ; PIO: NUMBER OF CHIPS TO DETECT (1-2), 2 CHANNELS PER CHIP +PIO0BASE .EQU $B8 ; PIO 0: REGISTERS BASE ADR +PIO1BASE .EQU $BC ; PIO 1: REGISTERS BASE ADR +; PIO_4P .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB 4P BOARD PIO_ZP .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB ZILOG PERIPHERALS BOARD (PIO.ASM) PIO_SBC .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR 8255 CHIP @@ -250,7 +256,7 @@ SNMODE .EQU SNMODE_RCZ80 ; DRIVER MODE: SNMODE_[NONE|RC2014|VGM] ; AY38910ENABLE .EQU FALSE ; AY: AY-3-8910 / YM2149 SOUND DRIVER AY_CLK .EQU CPUOSC / 4 ; DEFAULT TO CPUOSC / 4 -AYMODE .EQU AYMODE_RCZ80 ; AY: DRIVER MODE: AYMODE_[SCG|N8|RCZ80|RCZ180|MSX|LINC] +AYMODE .EQU AYMODE_RCZ80 ; AY: DRIVER MODE: AYMODE_[SCG|N8|RCZ80|RCZ180|MSX|LINC|MBC] ; SPKENABLE .EQU FALSE ; SPK: ENABLE RTC LATCH IOBIT SOUND DRIVER (SPK.ASM) ; diff --git a/Source/HBIOS/cfg_sbc.asm b/Source/HBIOS/cfg_sbc.asm index 1fe35342..2f7bedff 100644 --- a/Source/HBIOS/cfg_sbc.asm +++ b/Source/HBIOS/cfg_sbc.asm @@ -13,6 +13,8 @@ ; #DEFINE PLATFORM_NAME "SBC" ; +#INCLUDE "hbios.inc" +; PLATFORM .EQU PLT_SBC ; PLT_[SBC|ZETA|ZETA2|N8|MK4|UNA|RCZ80|RCZ180|EZZ80|SCZ180|DYNO|RCZ280|MBC] CPUFAM .EQU CPU_Z80 ; CPU FAMILY: CPU_[Z80|Z180|Z280] BIOS .EQU BIOS_WBW ; HARDWARE BIOS: BIOS_[WBW|UNA] @@ -30,8 +32,7 @@ INTMODE .EQU 0 ; INTERRUPTS: 0=NONE, 1=MODE 1, 2=MODE 2, 3=MODE 3 (Z280) DEFSERCFG .EQU SER_38400_8N1 ; DEFAULT SERIAL LINE CONFIG (SEE STD.ASM) ; RAMSIZE .EQU 512 ; SIZE OF RAM IN KB (MUST MATCH YOUR HARDWARE!!!) -PLT_RAM_R .EQU 0 ; RESERVE FIRST N KB OF RAM (USUALLY 0) -PLT_ROM_R .EQU 0 ; RESERVE FIRST N KB OR ROM (USUALLY 0) +ROMSIZE_CHK .EQU 0 ; ROMSIZE VALUE VEREIFICATION (0=DISABLED) MEMMGR .EQU MM_SBC ; MEMORY MANAGER: MM_[SBC|Z2|N8|Z180|Z280|MBC] MPCL_RAM .EQU $78 ; SBC MEM MGR RAM PAGE SELECT REG (WRITE ONLY) MPCL_ROM .EQU $7C ; SBC MEM MGR ROM PAGE SELECT REG (WRITE ONLY) @@ -151,7 +152,7 @@ MDENABLE .EQU TRUE ; MD: ENABLE MEMORY (ROM/RAM) DISK DRIVER (MD.ASM) MDROM .EQU TRUE ; MD: ENABLE ROM DISK MDRAM .EQU TRUE ; MD: ENABLE RAM DISK MDTRACE .EQU 1 ; MD: TRACE LEVEL (0=NO,1=ERRORS,2=ALL) -MDFFENABLE .EQU FALSE ; MD: ENABLE FLASH FILE SYSTEM +MDFFENABLE .EQU FALSE ; MD: ENABLE FLASH FILE SYSTEM ; ; FDENABLE .EQU FALSE ; FD: ENABLE FLOPPY DISK DRIVER (FD.ASM) @@ -217,6 +218,11 @@ PPPENABLE .EQU FALSE ; PPP: ENABLE ZETA PARALLEL PORT PROPELLER BOARD DRIVER (P HDSKENABLE .EQU FALSE ; HDSK: ENABLE SIMH HDSK DISK DRIVER (HDSK.ASM) HDSKTRACE .EQU 1 ; HDSK: TRACE LEVEL (0=NO,1=ERRORS,2=ALL) ; +PIOENABLE .EQU FALSE ; PIO: ENABLE ZILOG PIO DRIVER (PIO.ASM) +PIOCNT .EQU 2 ; PIO: NUMBER OF CHIPS TO DETECT (1-2), 2 CHANNELS PER CHIP +PIO0BASE .EQU $B8 ; PIO 0: REGISTERS BASE ADR +PIO1BASE .EQU $BC ; PIO 1: REGISTERS BASE ADR +; PIO_4P .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB 4P BOARD PIO4BASE .EQU $90 ; PIO: PIO REGISTERS BASE ADR FOR ECB 4P BOARD PIO_ZP .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB ZILOG PERIPHERALS BOARD (PIO.ASM) @@ -234,7 +240,7 @@ SNMODE .EQU SNMODE_VGM ; DRIVER MODE: SNMODE_[NONE|RC2014|VGM] ; AY38910ENABLE .EQU FALSE ; AY: AY-3-8910 / YM2149 SOUND DRIVER AY_CLK .EQU CPUOSC / 4 ; DEFAULT TO CPUOSC / 4 -AYMODE .EQU AYMODE_SCG ; AY: DRIVER MODE: AYMODE_[SCG|N8|RCZ80|RCZ180|MSX|LINC] +AYMODE .EQU AYMODE_SCG ; AY: DRIVER MODE: AYMODE_[SCG|N8|RCZ80|RCZ180|MSX|LINC|MBC] ; SPKENABLE .EQU FALSE ; SPK: ENABLE RTC LATCH IOBIT SOUND DRIVER (SPK.ASM) ; diff --git a/Source/HBIOS/cfg_scz180.asm b/Source/HBIOS/cfg_scz180.asm index 82daba78..3fc39a3d 100644 --- a/Source/HBIOS/cfg_scz180.asm +++ b/Source/HBIOS/cfg_scz180.asm @@ -13,6 +13,8 @@ ; #DEFINE PLATFORM_NAME "SCZ180" ; +#INCLUDE "hbios.inc" +; PLATFORM .EQU PLT_SCZ180 ; PLT_[SBC|ZETA|ZETA2|N8|MK4|UNA|RCZ80|RCZ180|EZZ80|SCZ180|DYNO|RCZ280|MBC] CPUFAM .EQU CPU_Z180 ; CPU FAMILY: CPU_[Z80|Z180|Z280] BIOS .EQU BIOS_WBW ; HARDWARE BIOS: BIOS_[WBW|UNA] @@ -30,8 +32,7 @@ INTMODE .EQU 2 ; INTERRUPTS: 0=NONE, 1=MODE 1, 2=MODE 2, 3=MODE 3 (Z280) DEFSERCFG .EQU SER_115200_8N1 ; DEFAULT SERIAL LINE CONFIG (SEE STD.ASM) ; RAMSIZE .EQU 512 ; SIZE OF RAM IN KB (MUST MATCH YOUR HARDWARE!!!) -PLT_RAM_R .EQU 0 ; RESERVE FIRST N KB OF RAM (USUALLY 0) -PLT_ROM_R .EQU 0 ; RESERVE FIRST N KB OR ROM (USUALLY 0) +ROMSIZE_CHK .EQU 0 ; ROMSIZE VALUE VEREIFICATION (0=DISABLED) MEMMGR .EQU MM_Z180 ; MEMORY MANAGER: MM_[SBC|Z2|N8|Z180|Z280|MBC] RAMLOC .EQU 19 ; START OF RAM AS POWER OF 2 (2^N) IN PHYSICAL ADDRESS SPACE RAMBIAS .EQU (1 << (RAMLOC - 10)) ; OFFSET OF START OF RAM IN PHYSICAL ADDRESS SPACE @@ -163,7 +164,7 @@ MDENABLE .EQU TRUE ; MD: ENABLE MEMORY (ROM/RAM) DISK DRIVER (MD.ASM) MDROM .EQU TRUE ; MD: ENABLE ROM DISK MDRAM .EQU TRUE ; MD: ENABLE RAM DISK MDTRACE .EQU 1 ; MD: TRACE LEVEL (0=NO,1=ERRORS,2=ALL) -MDFFENABLE .EQU FALSE ; MD: ENABLE FLASH FILE SYSTEM +MDFFENABLE .EQU FALSE ; MD: ENABLE FLASH FILE SYSTEM ; FDENABLE .EQU FALSE ; FD: ENABLE FLOPPY DISK DRIVER (FD.ASM) FDMODE .EQU FDMODE_RCWDC ; FD: DRIVER MODE: FDMODE_[DIO|ZETA|ZETA2|DIDE|N8|DIO3|RCSMC|RCWDC|DYNO|EPFDC|MBC] @@ -227,6 +228,11 @@ PPPENABLE .EQU FALSE ; PPP: ENABLE ZETA PARALLEL PORT PROPELLER BOARD DRIVER (P ; HDSKENABLE .EQU FALSE ; HDSK: ENABLE SIMH HDSK DISK DRIVER (HDSK.ASM) ; +PIOENABLE .EQU FALSE ; PIO: ENABLE ZILOG PIO DRIVER (PIO.ASM) +PIOCNT .EQU 2 ; PIO: NUMBER OF CHIPS TO DETECT (1-2), 2 CHANNELS PER CHIP +PIO0BASE .EQU $B8 ; PIO 0: REGISTERS BASE ADR +PIO1BASE .EQU $BC ; PIO 1: REGISTERS BASE ADR +; PIO_4P .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB 4P BOARD PIO_ZP .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB ZILOG PERIPHERALS BOARD (PIO.ASM) PIO_SBC .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR 8255 CHIP @@ -240,7 +246,7 @@ SNMODE .EQU SNMODE_NONE ; DRIVER MODE: SNMODE_[NONE|RC2014|VGM] ; AY38910ENABLE .EQU FALSE ; AY: AY-3-8910 / YM2149 SOUND DRIVER AY_CLK .EQU CPUOSC / 4 ; DEFAULT TO CPUOSC / 4 -AYMODE .EQU AYMODE_RCZ180 ; AY: DRIVER MODE: AYMODE_[SCG|N8|RCZ80|RCZ180|MSX|LINC] +AYMODE .EQU AYMODE_RCZ180 ; AY: DRIVER MODE: AYMODE_[SCG|N8|RCZ80|RCZ180|MSX|LINC|MBC] ; SPKENABLE .EQU FALSE ; SPK: ENABLE RTC LATCH IOBIT SOUND DRIVER (SPK.ASM) ; diff --git a/Source/HBIOS/cfg_una.asm b/Source/HBIOS/cfg_una.asm index 33528538..9d0e2af5 100644 --- a/Source/HBIOS/cfg_una.asm +++ b/Source/HBIOS/cfg_una.asm @@ -13,7 +13,9 @@ ; #DEFINE PLATFORM_NAME "UNA" ; -PLATFORM .EQU PLT_UNA ; PLT_[SBC|ZETA|ZETA2|N8|MK4|UNA|RCZ80|RCZ180|EZZ80|SCZ180|DYNO|RCZ280|MBC] +#INCLUDE "../UBIOS/ubios.inc" +; +;PLATFORM .EQU PLT_UNA ; PLT_[SBC|ZETA|ZETA2|N8|MK4|UNA|RCZ80|RCZ180|EZZ80|SCZ180|DYNO|RCZ280|MBC] BIOS .EQU BIOS_UNA ; HARDWARE BIOS: BIOS_[WBW|UNA] ; BOOT_TIMEOUT .EQU -1 ; AUTO BOOT TIMEOUT IN SECONDS, -1 TO DISABLE, 0 FOR IMMEDIATE @@ -24,8 +26,6 @@ CPUOSC .EQU 18432000 ; CPU OSC FREQ IN MHZ INTMODE .EQU 0 ; INTERRUPTS: 0=NONE, 1=MODE 1, 2=MODE 2, 3=MODE 3 (Z280) ; RAMSIZE .EQU 512 ; SIZE OF RAM IN KB (MUST MATCH YOUR HARDWARE!!!) -PLT_RAM_R .EQU 0 ; RESERVE FIRST N KB OF RAM (USUALLY 0) -PLT_ROM_R .EQU 0 ; RESERVE FIRST N KB OR ROM (USUALLY 0) ; RTCIO .EQU $70 ; RTC LATCH REGISTER ADR ; diff --git a/Source/HBIOS/cfg_zeta.asm b/Source/HBIOS/cfg_zeta.asm index 8a2bb725..198a5985 100644 --- a/Source/HBIOS/cfg_zeta.asm +++ b/Source/HBIOS/cfg_zeta.asm @@ -13,6 +13,8 @@ ; #DEFINE PLATFORM_NAME "ZETA" ; +#INCLUDE "hbios.inc" +; PLATFORM .EQU PLT_ZETA ; PLT_[SBC|ZETA|ZETA2|N8|MK4|UNA|RCZ80|RCZ180|EZZ80|SCZ180|DYNO|RCZ280|MBC] CPUFAM .EQU CPU_Z80 ; CPU FAMILY: CPU_[Z80|Z180|Z280] BIOS .EQU BIOS_WBW ; BIOS_[WBW|UNA]: HARDWARE BIOS @@ -30,8 +32,7 @@ INTMODE .EQU 0 ; INTERRUPTS: 0=NONE, 1=MODE 1, 2=MODE 2, 3=MODE 3 (Z280) DEFSERCFG .EQU SER_38400_8N1 ; DEFAULT SERIAL LINE CONFIG (SEE STD.ASM) ; RAMSIZE .EQU 512 ; SIZE OF RAM IN KB (MUST MATCH YOUR HARDWARE!!!) -PLT_RAM_R .EQU 0 ; RESERVE FIRST N KB OF RAM (USUALLY 0) -PLT_ROM_R .EQU 0 ; RESERVE FIRST N KB OR ROM (USUALLY 0) +ROMSIZE_CHK .EQU 0 ; ROMSIZE VALUE VEREIFICATION (0=DISABLED) MEMMGR .EQU MM_SBC ; MEMORY MANAGER: MM_[SBC|Z2|N8|Z180|Z280|MBC] MPCL_RAM .EQU $78 ; SBC MEM MGR RAM PAGE SELECT REG (WRITE ONLY) MPCL_ROM .EQU $7C ; SBC MEM MGR ROM PAGE SELECT REG (WRITE ONLY) @@ -161,6 +162,11 @@ PPPCONENABLE .EQU TRUE ; PPP: ENABLE PPP DRIVER VIDEO/KBD SUPPORT ; HDSKENABLE .EQU FALSE ; HDSK: ENABLE SIMH HDSK DISK DRIVER (HDSK.ASM) ; +PIOENABLE .EQU FALSE ; PIO: ENABLE ZILOG PIO DRIVER (PIO.ASM) +PIOCNT .EQU 2 ; PIO: NUMBER OF CHIPS TO DETECT (1-2), 2 CHANNELS PER CHIP +PIO0BASE .EQU $B8 ; PIO 0: REGISTERS BASE ADR +PIO1BASE .EQU $BC ; PIO 1: REGISTERS BASE ADR +; PIO_4P .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB 4P BOARD PIO_ZP .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB ZILOG PERIPHERALS BOARD (PIO.ASM) PIO_SBC .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR 8255 CHIP diff --git a/Source/HBIOS/cfg_zeta2.asm b/Source/HBIOS/cfg_zeta2.asm index 30983347..da495739 100644 --- a/Source/HBIOS/cfg_zeta2.asm +++ b/Source/HBIOS/cfg_zeta2.asm @@ -13,6 +13,8 @@ ; #DEFINE PLATFORM_NAME "ZETA V2" ; +#INCLUDE "hbios.inc" +; PLATFORM .EQU PLT_ZETA2 ; PLT_[SBC|ZETA|ZETA2|N8|MK4|UNA|RCZ80|RCZ180|EZZ80|SCZ180|DYNO|RCZ280|MBC] CPUFAM .EQU CPU_Z80 ; CPU FAMILY: CPU_[Z80|Z180|Z280] BIOS .EQU BIOS_WBW ; HARDWARE BIOS: BIOS_[WBW|UNA] @@ -30,8 +32,7 @@ INTMODE .EQU 2 ; INTERRUPTS: 0=NONE, 1=MODE 1, 2=MODE 2, 3=MODE 3 (Z280) DEFSERCFG .EQU SER_38400_8N1 ; DEFAULT SERIAL LINE CONFIG (SEE STD.ASM) ; RAMSIZE .EQU 512 ; SIZE OF RAM IN KB (MUST MATCH YOUR HARDWARE!!!) -PLT_RAM_R .EQU 0 ; RESERVE FIRST N KB OF RAM (USUALLY 0) -PLT_ROM_R .EQU 0 ; RESERVE FIRST N KB OR ROM (USUALLY 0) +ROMSIZE_CHK .EQU 0 ; ROMSIZE VALUE VEREIFICATION (0=DISABLED) MEMMGR .EQU MM_Z2 ; MEMORY MANAGER: MM_[SBC|Z2|N8|Z180|Z280|MBC] MPGSEL_0 .EQU $78 ; Z2 MEM MGR BANK 0 PAGE SELECT REG (WRITE ONLY) MPGSEL_1 .EQU $79 ; Z2 MEM MGR BANK 1 PAGE SELECT REG (WRITE ONLY) @@ -134,7 +135,7 @@ MDENABLE .EQU TRUE ; MD: ENABLE MEMORY (ROM/RAM) DISK DRIVER (MD.ASM) MDROM .EQU TRUE ; MD: ENABLE ROM DISK MDRAM .EQU TRUE ; MD: ENABLE RAM DISK MDTRACE .EQU 1 ; MD: TRACE LEVEL (0=NO,1=ERRORS,2=ALL) -MDFFENABLE .EQU FALSE ; MD: ENABLE FLASH FILE SYSTEM +MDFFENABLE .EQU FALSE ; MD: ENABLE FLASH FILE SYSTEM ; FDENABLE .EQU TRUE ; FD: ENABLE FLOPPY DISK DRIVER (FD.ASM) FDMODE .EQU FDMODE_ZETA2 ; FD: DRIVER MODE: FDMODE_[DIO|ZETA|ZETA2|DIDE|N8|DIO3|RCSMC|RCWDC|DYNO|EPFDC|MBC] @@ -172,6 +173,8 @@ PPPCONENABLE .EQU TRUE ; PPP: ENABLE PPP DRIVER VIDEO/KBD SUPPORT ; HDSKENABLE .EQU FALSE ; HDSK: ENABLE SIMH HDSK DISK DRIVER (HDSK.ASM) ; +PIOENABLE .EQU FALSE ; PIO: ENABLE ZILOG PIO DRIVER (PIO.ASM) +; PIO_4P .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB 4P BOARD PIO_ZP .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR ECB ZILOG PERIPHERALS BOARD (PIO.ASM) PIO_SBC .EQU FALSE ; PIO: ENABLE PARALLEL PORT DRIVER FOR 8255 CHIP diff --git a/Source/HBIOS/ctc.asm b/Source/HBIOS/ctc.asm index d4c6b156..b1698699 100644 --- a/Source/HBIOS/ctc.asm +++ b/Source/HBIOS/ctc.asm @@ -19,17 +19,27 @@ CTC_TIMCFG .EQU %11010111 ; CTC TIMER CHANNEL CONFIG ; |+-------- COUNTER MODE ; +--------- INTERRUPT ENABLE ; -#IF (CTCTIMER) +#IF (INTMODE != 2) + .ECHO "*** WARNING: CTC TIMER DISABLED -- INTMODE 2 REQUIRED!!!\n" +#ENDIF +; +#IF (CTCTIMER & (INTMODE == 2)) +; + #IF (INT_CTC0A % 4) + + .ECHO INT_CTC0A + .ECHO "\n" + .ECHO (INT_CTC0A % 4) + .ECHO "\n" + + .ECHO "*** ERROR: CTC BASE VECTOR NOT /4 ALIGNED!!!\n" + !!! ; FORCE AN ASSEMBLY ERROR + #ENDIF ; ; ONLY IM2 IMPLEMENTED BELOW. I DON'T SEE ANY REASONABLE WAY TO ; IMPLEMENT AN IM1 TIMER BECAUSE THE CTC PROVIDES NO WAY TO ; DETERMINE IF IT WAS THE CAUSE OF AN INTERRUPT OR A WAY TO ; DETERMINE WHICH CHANNEL CAUSED AN INTERRUPT. -; - #IF (INTMODE != 2) - .ECHO "*** ERROR: CTC REQUIRES INTMODE 2!!!\n" - !!! ; FORCE AN ASSEMBLY ERROR - #ENDIF ; CTC_PREIO .EQU CTCBASE + CTCPRECH CTC_SCLIO .EQU CTCBASE + CTCTIMCH @@ -82,6 +92,9 @@ CTCTIVT .EQU INT_CTC0A + CTCTIMCH ; ; CTC_PREINIT: + CALL CTC_DETECT ; DO WE HAVE ONE? + LD (CTC_EXIST),A ; SAVE IT + RET NZ ; ABORT IF NONE ; ; RESET ALL CTC CHANNELS LD B,4 ; 4 CHANNELS @@ -92,7 +105,7 @@ CTC_PREINIT1: INC C ; NEXT CHANNEL PORT DJNZ CTC_PREINIT1 ; -#IF (CTCTIMER) +#IF (CTCTIMER & (INTMODE == 2)) ; SETUP TIMER INTERRUPT IVT SLOT LD HL,HB_TIMINT ; TIMER INT HANDLER ADR LD (IVT(CTCTIVT)),HL ; IVT ENTRY FOR TIMER CHANNEL @@ -101,7 +114,7 @@ CTC_PREINIT1: ; EACH CHANNEL. BELOW WE SET THE BASE VECTOR TO THE ; START OF THE IVT, SO THE FIRST FOUR ENTIRES OF THE ; IVT CORRESPOND TO CTC CHANNELS A-D. - LD A,0 + LD A,INT_CTC0A * 2 OUT (CTCBASE),A ; SETUP CTC BASE INT VECTOR ; ; IN ORDER TO DIVIDE THE CTC INPUT CLOCK DOWN TO THE @@ -136,9 +149,20 @@ CTC_PRTCFG: LD A,CTCBASE ; GET BASE PORT CALL PRTHEXBYTE ; PRINT BASE PORT ; -#IF (CTCTIMER) + LD A,(CTC_EXIST) ; IS IT THERE? + OR A ; 0 MEANS YES + JR Z,CTC_PRTCFG1 ; IF SO, CONTINUE +; + ; NOTIFY NO CTC HARDWARE + PRTS(" NOT PRESENT$") + OR $FF + RET +; +CTC_PRTCFG1: +; +#IF (CTCTIMER & (INTMODE == 2)) ; - PRTS(" MODE=$") ; FORMATTING + PRTS(" TIMER MODE=$") ; FORMATTING #IF (CTCMODE == CTCMODE_CTR) PRTS("CTR$") #ENDIF @@ -149,6 +173,7 @@ CTC_PRTCFG: PRTS("TIM256$") #ENDIF ; + #IF (CTCDEBUG) PRTS(" DIVHI=$") LD A,CTC_DIVHI & $FF CALL PRTHEXBYTE @@ -157,7 +182,6 @@ CTC_PRTCFG: LD A,CTC_DIVLO & $FF CALL PRTHEXBYTE ; - #IF (CTCDEBUG) PRTS(" PREIO=$") LD A,CTC_PREIO CALL PRTHEXBYTE @@ -175,3 +199,31 @@ CTC_PRTCFG: ; XOR A RET +; +; +; +CTC_DETECT: + LD A,CTC_TIM256CFG + OUT (CTCBASE),A + XOR A + OUT (CTCBASE),A + ; CTC SHOULD NOW BE RUNNING WITH TIME CONSTANT 0 + LD A,CTC_TIM256CFG ; RESET + OUT (CTCBASE),A + IN A,(CTCBASE) ; SHOULD READ 0 NOW + CP 0 + JR NZ,CTC_NO + LD A,$FF ; TIME CONSTANT $FF + OUT (CTCBASE),A + IN A,(CTCBASE) ; SHOULD NOT BE 0 NOW + CP 0 + JR Z,CTC_NO + XOR A + RET +CTC_NO: + OR $FF + RET +; +; +; +CTC_EXIST .DB $FF diff --git a/Source/HBIOS/hbios.asm b/Source/HBIOS/hbios.asm index 7ed0e96e..4382b343 100644 --- a/Source/HBIOS/hbios.asm +++ b/Source/HBIOS/hbios.asm @@ -87,6 +87,20 @@ MODCNT .SET MODCNT + 1 !!! ; FORCE AN ASSEMBLY ERROR #ENDIF ; +; SOME HARDWARE REQUIRES A SPECIFIC ROMSIZE (NOTABLY ZZRCC) OR THE +; RESULTING BUILD IMAGES WILL BE CORRUPT. ROMSIZE_CHK IS SPECIFIED +; IN THE CONFIG FILE AND IS VERIFIED AGAINST THE ROMSIZE BEING USED +; BY THE BUILD. A ROMSIZE_CHK VALUE OF 0 INDICATES THE VERFICATION +; IS DISABLED (WHICH IT USUALLY IS). +; +#IF (ROMSIZE_CHK != 0) & (ROMSIZE != ROMSIZE_CHK) + .ECHO "*** ERROR: ROMSIZE VALUE VERIFICATION FAILURE.\n" + .ECHO "THIS CONFIGURATION REQUIRES A ROMSIZE OF " \ .ECHO ROMSIZE_CHK \ .ECHO ".\n" + .ECHO "BUILD IS USING A ROMSIZE OF " \ .ECHO ROMSIZE \ .ECHO ".\n" + .ECHO "SEE COMMENTS IN HBIOS.ASM.\n" + !!! ; FORCE AN ASSEMBLY ERROR +#ENDIF +; ; ; #IF (DIAGENABLE) @@ -129,7 +143,7 @@ MODCNT .SET MODCNT + 1 #IF (INTMODE == 3) ; Z280 MODE 3 INTERRUPT HANDLING (INTA, C/T 0, & UART RCVR ENABLED) #DEFINE HB_DI DI -#DEFINE HB_EI .DB $ED,$7F,$0B +#DEFINE HB_EI EI $0B #ELSE ; Z280 MODE 1/2 INTERRUPT HANDLING #DEFINE HB_DI DI @@ -170,16 +184,14 @@ MODCNT .SET MODCNT + 1 ; ; ; -#IF (CTCENABLE) -CTCA .EQU CTCBASE + 0 ; CTC: CHANNEL A REGISTER ADR -CTCB .EQU CTCBASE + 1 ; CTC: CHANNEL B REGISTER ADR -CTCC .EQU CTCBASE + 2 ; CTC: CHANNEL C REGISTER ADR -CTCD .EQU CTCBASE + 3 ; CTC: CHANNEL D REGISTER ADR -#ENDIF -; -; THIS EQUATE IS UPDATED BY DRIVER INCLUDES THAT SHARE THE RTC LATCH. -; AS DRIVER IS INCLUDED, IT WILL USE .SET TO SET ANY BITS THEY OWN -; AND WANT TO SET AS DEFAULT. +; THE RTCDEF EQUATE IS INITIALIZED HERE AND UPDATED BY DRIVER INCLUDES +; THAT SHARE THE RTC LATCH. AS EACH DRIVER FILE IS INCLUDED, IT CAN +; USE .SET TO SET ANY BITS THEY OWN WITHIN THE RTC LATCH BYTE. +; SINCE RTCDEF IS CHANGED AFTER IT NEEDS TO BE USED BY THE CODE, IT +; CANNOT BE USED DIRECTLY TO SET THE LATCH. INSTEAD, THE FINAL VALUE +; OF RTCDEF IS USED TO INITIALIZE A STORAGE BYTE CALLED RTCDEFVAL AT +; THE END OF HBIOS.ASM. SO (RTCDEFVAL) CAN BE USED ANYWHERE IN +; HBIOS.ASM TO ACCESS THE FINAL RTCDEF VALUE. ; RTCDEF .EQU 0 ; ALLOWS DRIVERS TO SET BITS ; @@ -188,19 +200,11 @@ RTCDEF .SET RTCDEF | %00000001 ; SC128 I2C SCL BIT #ENDIF ; #IF ((CPUSPDCAP==SPD_HILO) & (PLATFORM==PLT_MBC)) -#IF (CPUSPDDEF==SPD_HIGH) -RTCDEF .SET RTCDEF | %00001000 ; DEFAULT SPEED HIGH -#ELSE -RTCDEF .SET RTCDEF & ~%00001000 ; DEFAULT SPEED LOW -#ENDIF +RTCDEF .SET RTCDEF & ~%00001000 ; INITIAL SPEED LOW #ENDIF ; #IF ((CPUSPDCAP==SPD_HILO) & (PLATFORM==PLT_SBC)) -#IF (CPUSPDDEF==SPD_HIGH) -RTCDEF .SET RTCDEF & ~%00001000 ; DEFAULT SPEED HIGH -#ELSE -RTCDEF .SET RTCDEF | %00001000 ; DEFAULT SPEED LOW -#ENDIF +RTCDEF .SET RTCDEF | %00001000 ; INITIAL SPEED LOW #ENDIF ; ; @@ -362,8 +366,7 @@ HBX_INVOKE: LD A,BID_BIOS ; HBIOS BANK LD (HB_CURBNK),A ; SET AS CURRENT BANK ; - .DB $ED,$71 ; SC - .DW HB_DISPATCH ; SC PARAMETER + SC HB_DISPATCH ; PUSH AF LD A,(HB_INVBNK) @@ -466,7 +469,7 @@ HBX_ROM: JR Z,HBX_ROM ; IF NOT SET, SELECT ROM PAGE ; HBX_RAM: - RES 7,A ; CLEAR BIT 7 FROM ABOVE + AND %00011111 ; AVOID WRAPPING BITS RLCA ; SCALE SELECTOR TO RLCA ; ... GO FROM Z180 4K PAGE SIZE RLCA ; ... TO DESIRED 32K PAGE SIZE @@ -489,6 +492,7 @@ HBX_ROM: JR NC,HBX_BNKSEL1 ; IF NC, WANT ROM PAGE, SKIP AHEAD XOR %00100001 ; SET BIT FOR HI 512K, CLR BIT 0 HBX_BNKSEL1: + AND %00111111 ; AVOID WRAPPING BITS RLCA ; CONTINUE SHIFTING TO SCALE SELECTOR RLCA ; FOR Z180 4K PAGE -> DESIRED 32K PAGE OUT0 (Z180_BBR),A ; WRITE TO BANK BASE @@ -499,8 +503,7 @@ HBX_BNKSEL1: PUSH BC ; SAVE BC PUSH HL ; SAVE HL LD B,$00 ; FIRST USER PDR - .DB $ED,$71 ; SC - .DW Z280_BNKSEL ; SC PARAMETER + SC Z280_BNKSEL ; SYSCALL POP HL ; RESTORE HL POP BC ; RESTORE BC RET ; DONE @@ -510,7 +513,7 @@ HBX_BNKSEL1: BIT 7,A ; BIT 7 SET REQUESTS RAM PAGE JR Z,HBX_ROM ; NOT SET, SELECT ROM PAGE RES 7,A ; RAM PAGE REQUESTED: CLEAR ROM BIT - ADD A,$10 ; ADD 16 x 32K - RAM STARTS FROM 512K + ADD A,ROMSIZE / 32 ; STARTING RAM BANK NUMBER OFFSET ; HBX_ROM: OUT ($1F),A ; HCS WRITE TO THE BANK CONTROL REGISTER @@ -569,9 +572,11 @@ HBX_MMA .DB 0 ; TEMPORARY STORAGE FOR REG A ; HBX_BNKCPY: #IF (MEMMGR == MM_Z280) - .DB $ED,$71 ; SC - .DW Z280_BNKCPY ; SC PARAMETER + SC Z280_BNKCPYX ; SYSCALL TO BNKCPYX RET +; +IOPRSAV .DW 0 ; TEMP STORAGE FOR IOPR +; #ELSE #IF (CPUFAM == CPU_Z280) PUSH HL @@ -660,8 +665,7 @@ HBX_BNKCALL: #IF (MEMMGR == MM_Z280) CP BID_BIOS ; CALLING HBIOS? JR NZ,HBX_BNKCALL3 ; NOPE, DO NORMAL PROCESSING - .DB $ED,$71 ; SC - .DW HBX_BNKCALL2 ; CALL HERE IN SYSTEM MODE + SC HBX_BNKCALL2 ; SYSCALL TO BNKCALL2 RET ; THEN RETURN ; HBX_BNKCALL2: @@ -962,7 +966,7 @@ HBX_BUF_END .EQU $ .DB BID_USR ; HB_DSTBNK: BNKCPY DESTINATION BANK ID .DW 0 ; HB_CPYLEN: BNKCPY LENGTH .FILL 4,0 ; FILLER, RESERVED FOR FUTURE HBIOS USE - .DB RTCDEF ; SHADOW VALUE FOR RTC LATCH PORT + .DB 0 ; SHADOW VALUE FOR RTC LATCH PORT .DB $FE ; HB_LOCK: HBIOS MUTEX LOCK JP HBX_INVOKE ; HB_INVOKE: FIXED ADR ENTRY FOR HBX_INVOKE (ALT FOR RST 08) JP HBX_BNKSEL ; HB_BNKSEL: FIXED ADR ENTRY FOR HBX_BNKSEL @@ -1085,9 +1089,16 @@ Z280_BOOTERR .TEXT "\r\n\r\n*** Application mode boot not supported under Z280 n DI ; NO INTERRUPTS IM 1 ; INTERRUPT MODE 1 -#IF ((PLATFORM=PLT_MBC) | (PLATFORM=PLT_SBC)) - LD A,(HB_RTCVAL) ; SET DEFAULT - OUT (RTCIO),A ; SPEED +;#IF ((PLATFORM == PLT_MBC) | (PLATFORM == PLT_SBC)) + ; INITIALIZE RTC LATCH BYTE + ; FOR SOME PLATFORMS THIS CONTROLS HI/LO SPEED CIRCUIT + LD A,(RTCDEFVAL) ; GET DEFAULT VALUE + OUT (RTCIO),A ; SET IT +;#ENDIF +; +#IF (PLATFORM == PLT_N8) + LD A,N8_DEFACR ; ENSURE N8 ACR + OUT0 (N8_ACR),A ; ... REGISTER IS INITIALIZED #ENDIF ; #IF (DIAGENABLE) @@ -1099,13 +1110,15 @@ Z280_BOOTERR .TEXT "\r\n\r\n*** Application mode boot not supported under Z280 n XOR A ; LED IS INVERTED, TURN IT ON #ENDIF #IF (LEDMODE == LEDMODE_RTC) - LD A,(HB_RTCVAL) - OR %00000001 ; LED 0 - LD (HB_RTCVAL),A ; SAVE TO SHADOW REGISTER + LD A,(RTCDEFVAL) ; DEFAULT LATCH VALUE + OR %00000001 ; LED 0 ON #ENDIF OUT (LEDPORT),A #ENDIF ; + ; WARNING: ALTHOUGH WE ARE INITIALIZING SP HERE, IT IS NOT YET + ; SAFE TO PUSH VALUES TO THE STACK BECAUSE SOME PLATFORMS WILL + ; NOT YET HAVE RAM MAPPED TO THE UPPER 32K YET! LD SP,HBX_LOC ; SETUP INITIAL STACK JUST BELOW HBIOS PROXY ; #IF (CPUFAM == CPU_Z280) @@ -1127,7 +1140,7 @@ Z280_BOOTERR .TEXT "\r\n\r\n*** Application mode boot not supported under Z280 n LD HL,Z280_BOOTPDRTBL ; START OF PDR VALUES TABLE LD C,Z280_MMUBLKMOV ; PDR BLOCK MOVE PORT LD B,16 ; PROGRAM 16 PDRS - .DB $ED,$93 ; OTIRW + OTIRW ; OTIRW ; ; INITIALIZE ALL OF THE USER PAGE DESCRIPTORS WITH BLOCK MOVE LD A,$10 ; FIRST SYSTEM PDR @@ -1135,7 +1148,7 @@ Z280_BOOTERR .TEXT "\r\n\r\n*** Application mode boot not supported under Z280 n LD HL,Z280_BOOTPDRTBL ; START OF PDR VALUES TABLE LD C,Z280_MMUBLKMOV ; PDR BLOCK MOVE PORT LD B,16 ; PROGRAM 16 PDRS - .DB $ED,$93 ; OTIRW + OTIRW ; OTIRW ; ; ENABLE MMU (SYSTEM AND USER TRANSLATION) LD C,Z280_MMUMCR ; MMU MASTER CONTROL REGISTER @@ -1288,25 +1301,54 @@ Z280_INITZ: ; AT THIS POINT, RAM SHOULD BE AVAILABLE IN THE COMMON BANK ; (TOP 32K). ; - DIAG(%00000011) +; NOTIFICATION THAT WE HAVE MADE THE JUMP TO RAM BANK! +; THE DIAG() MACRO IS NOT USED BECAUSE IT USES THE STACK AND WE DO +; NOT WANT TO EFFECT RAM UNTIL AFTER THE BACKUP BATTERY STATUS CHECK +; IS PERFORMED NEXT. ; -; CHECK BATTERY BACKUP STATUS BEFORE WE COPY PROXY TO UPPER MEMORY + LD A,%00000011 + OUT (DIAGPORT),A +; +; WE USE THE TWO BYTES IMMEDIATELY BELOW THE PROXY TO STORE A COUPLE +; VALUES TEMPORARILY BECAUSE WE MAY BE OPERATING IN ROM AT THIS POINT. +; (HBX_LOC - 1) = BATCOND, (HBX_LOC - 2) = APPBANK +; THERE IS NOTHING ON THE STACK AT THIS POINT SO, HERE, WE JUST RESET +; THE STACK TO HBX_LOC - 2. +; + LD SP,HBX_LOC - 2 +; +; CHECK BATTERY BACKUP STATUS BEFORE WE TOUCH RAM (UPPER MEMORY) ; ; IF A DS1210 POWER CONTROLLER IS INSTALLED AND BATTERY BACKUP IS NOT INSTALLED ; OR IS LESS THAN 2V THEN THE DS1210 WILL BLOCK THE SECOND RAM ACCESS. ; FAILURE TO COMPLETE TWO RAM ACCESSES BEFORE INSTALLING PROXY WILL RESULT ; IN THE ROM ID BYTES NOT BEING COPIED CORRECTLY AND CP/M APPLICATIONS ; WILL NOT START CORRECTLY WHEN THEY CHECK THE ROM ID VERSION BYTES. -; THE BATTERY CONDITION VALUE IS TEMPORARILY STORED AT HBX_LOC - 1. +; THE BATTERY CONDITION VALUE IS TEMPORARILY STORED AT HBX_LOC - 1 +; BECAUSE WE ARE CURRENTLY RUNNING IN ROM. AFTER WE TRANSITION HBIOS +; TO RAM, THE VALUE IS MOVED TO IT'S REAL LCOATION AT HB_BATCOND. ; IF THERE IS NO DS1210 IN THE SYSTEM, THE CODE BELOW DOES NO HARM. ; - DEC SP ; RESERVE A STACK BYTE + LD HL,HBX_LOC - 1 ; POINT TO BYTE XOR A ; ZERO MEANS LOW BAT - LD (HBX_LOC - 1),A ; WRITE IT (SHOULD ALWAYS WORK) + LD (HL),A INC A ; 1 MEANS BAT OK - LD (HBX_LOC - 1),A ; OVERWRITE IF NVC ALLOWS IT + LD (HL),A +; +; INSTALL PROXY IN UPPER MEMORY +; THE HB_CURBNK MUST BE PRESERVED IF THIS IS AN APPBOOT. +; + LD A,(HB_CURBNK) ; SAVE EXISTING HB_CURBNK + LD DE,HBX_LOC ; AS PER ABOVE + LD HL,HBX_IMG + LD BC,HBX_SIZ + LDIR +; +#IFDEF APPBOOT + LD (HB_CURBNK),A ; RESTORE HB_CURBNK +#ENDIF ; -; IF APPBOOT, SAVE CURRENT BANKID +; SAVE CURRENT BANKID ; ; THIS IS NOT GOING TO WORK IF THE APP BOOT IMAGE IS LOADED ; USING THE UNA FAT32 LOADER. SHOULD PROBABLY CHECK THAT THERE @@ -1314,23 +1356,108 @@ Z280_INITZ: ; THIS USE CASE IS PROBABLY NON-EXISTENT. THE IMG BOOT IMAGE ; SHOULD WORK FINE WITH THE UNA FAT32 LOADER. ; -#IFDEF APPBOOT - LD A,(HB_CURBNK) - DEC SP ; RESERVE A STACK BYTE - LD (HBX_LOC - 2),A ; SAVE BANK - PUSH AF ; ALSO ON STACK -#ENDIF +; THIS VALUE IS TEMPORARILY STORED AT HBX_LOC - 2 +; BECAUSE WE ARE CURRENTLY RUNNING IN ROM. AFTER WE TRANSITION HBIOS +; TO RAM, THE VALUE IS MOVED TO IT'S REAL LCOATION AT HB_APPBNK. ; -; INSTALL PROXY IN UPPER MEMORY + LD A,(HB_CURBNK) ; GET HB_CURBNK + LD (HBX_LOC - 2),A ; ... AND SAVE TEMP FOR APPBNK ; - LD DE,HBX_LOC ; AS PER ABOVE - LD HL,HBX_IMG - LD BC,HBX_SIZ - LDIR +; THE RTCVAL FIELD OF THE PROXY DATA NEEDS TO BE INITIALIZED HERE +; BECAUSE IT CANNOT BE PRE-INITIALIZED (SEE COMMENTS ABOVE WHERE +; RTCVAL EQUATE IS DEFINED). +; + LD A,(RTCDEFVAL) + LD (HB_RTCVAL),A ; -; THIS IS WHERE WE SHOULD PROBE FOR THE ACTUAL NUMBER OF RAM -; BANKS AVAILABLE IN THE SYSTEM. THE PROBE CODE WOULD NEED +#IFDEF TESTING +; +; THIS IS WHERE WE PROBE FOR THE ACTUAL NUMBER OF RAM +; BANKS AVAILABLE IN THE SYSTEM. THE PROBE CODE NEEDS ; TO BE COPIED TO AND RUN FROM THE COMMON RAM BANK. +; + LD DE,$F000 + LD HL,RS_IMAGE + LD BC,RS_LEN + LDIR + CALL RS_START + JP RS_IMAGE + RS_LEN +; +; CODE THAT IS COPIED TO $F000 TO PERFORM RAM SIZE DETECTION +; +RS_IMAGE: + .ORG $F000 +RS_START: + LD A,(HB_CURBNK) ; GET CURRENT BANK + PUSH AF ; SAVE IT + + LD C,0 ; RUNNING BANK COUNT + LD HL,$7FFF ; BYTE TEST ADDRESS + LD IX,RS_ARY ; ORIG BYTE STORAGE ARRAY PTR +RS_LOOP1: + LD A,C + ADD A,$80 ; OFFSET BY START OF RAM BANKS + CALL HBX_BNKSEL ; SELECT THE BANK + + LD A,(HL) ; GET ORIGINAL VALUE + LD (IX),A ; SAVE IT TO RESTORE LATER + INC IX ; BUMP IX + + LD A,$AA ; TEST LOC WITH $AA + LD (HL),A ; AVOID PROBLEMS WITH + LD (HL),A ; ... DS1210 + LD (HL),A + LD A,(HL) + CP $AA + JR NZ,RS_DONE + + LD A,$55 ; TEST LOC WITH $55 + LD (HL),A + LD A,(HL) + CP $55 + JR NZ,RS_DONE + + ; STORE A UNIQUE VALUE + LD A,C + LD (HL),A + OR A ; ZERO? + JR Z,RS_NEXT ; SKIP STORED VALUE CHECK + + ; VERIFY ALL STORED VALUES + LD B,C ; INIT LOOP COUNTER + LD E,0 ; INIT BANK ID +RS_LOOP3: + LD A,E + ADD A,$80 + CALL HBX_BNKSEL + LD A,(HL) + CP E ; VERIFY + JR NZ,RS_DONE ; ABORT IF MISCOMPARE + INC E ; NEXT BANK + DJNZ RS_LOOP3 +; +RS_NEXT: + INC C ; ADD 1 TO RAM BANK COUNT + JR RS_LOOP1 ; AND LOOP TILL DONE +; +RS_DONE: + LD E,C ; FINAL BANK COUNT TO E + LD A,C + OR A + JR Z,RS_LOOPZ + ; RESTORE SAVED VALUES + LD IX,RS_ARY + LD B,C ; LOOP COUNT + LD C,$80 ; BANK ID +RS_LOOP2: + LD A,C + CALL HBX_BNKSEL + INC C + LD A,(IX) ; GET VALUE + LD (HL),A ; RESTORE IT + INC IX + DJNZ RS_LOOP2 ; ALL BANKS +RS_LOOPZ: ; ; MBC RUNTIME MEMORY SIZE ADJUSTMENT ; @@ -1348,21 +1475,114 @@ Z280_INITZ: ; AND THEN POKES THE MASK INTO AN XOR INSTRUCTION IN THE MBC ; MEMORY MANAGER. ; -#IF (MEMMGR == MM_MBC) - LD HL,CB_RAMBANKS ; IN NUMBER OF RAMBANKS DETECTED FOR MBC + #IF (MEMMGR == MM_MBC) +; + ;LD HL,CB_RAMBANKS ; IN NUMBER OF RAMBANKS DETECTED FOR MBC + LD A,%11101011 ; IS 4 (128KB) OR 16 (512KB) THEN + ;AND (HL) ; ZERO THE LAST BANK MASK OTHERWISE + AND E ; ZERO THE LAST BANK MASK OTHERWISE + JR Z,MBC_SINGLE ; CALCULATE THE LAST BANK MASK (BANKS/2) + RRA ; 256K = %00000100, 1024K = %00010000 +MBC_SINGLE: + LD (HBX_MBCMSK),A +; + #ENDIF +; + ; RETURN TO ORIGINAL BANK + POP AF + CALL HBX_BNKSEL + LD A,E ; RETURN BANK COUNT + LD ($FFEA),A ; STASH HERE FOR A BIT + RET +; +RS_ARY .EQU $ +; +RS_LEN .EQU $ - RS_START + .ORG RS_IMAGE + RS_LEN +; +#ELSE +; +; MBC RUNTIME MEMORY SIZE ADJUSTMENT +; +; THE MBC RAM BOARD CAN CONTAIN 1 OR 2 RAM CHIPS. THEY CAN BE +; EITHER 128K OR 512K EACH. SO THE MBC RAM BOARD CAN HAVE A +; TOTAL OF 128K, 256K, 512K, OR 1024K. THE COMMON (HIMEM) RAM +; IS ALWAYS MAPPED TO THE LAST 32K OF THE FIRST CHIP ON THE BOARD. +; IF THERE ARE TWO CHIPS ON THE BOARD, THIS MEANS THE COMMON +; BANK WILL APPEAR IN THE "MIDDLE" OF THE PHYSICAL RAM BANKS. +; ROMWBW NEEDS THE COMMON BANK TO BE AT THE LAST BANK OF PHYSICAL +; RAM IN ORDER TO HAVE SEQUENTIAL RAM BANKS AVAILABLE FOR THE +; RAM DISK. TO WORK AROUND THIS, WE FLIP THE HIGH BIT OF THE +; BANK ID FOR AN MBC SYSTEM IFF IT HAS 2 CHIPS (256K OR 1024K). +; THE CODE BELOW GENERATES THE CORRECT MASK TO ACCOMPLISH THIS +; AND THEN POKES THE MASK INTO AN XOR INSTRUCTION IN THE MBC +; MEMORY MANAGER. +; + #IF (MEMMGR == MM_MBC) + LD HL,CB_RAMBANKS ; IF NUMBER OF RAMBANKS DETECTED FOR MBC LD A,%11101011 ; IS 4 (128KB) OR 16 (512KB) THEN AND (HL) ; ZERO THE LAST BANK MASK OTHERWISE JR Z,MBC_SINGLE ; CALCULATE THE LAST BANK MASK (BANKS/2) RRA ; 256K = %00000100, 1024K = %00010000 MBC_SINGLE: LD (HBX_MBCMSK),A + #ENDIF +; #ENDIF ; -; IF APPBOOT, RESTORE CURRENT BANK ID +; IF THIS IS A ROM-LESS SYSTEM, THEN WE NEED TO COPY THE PAYLOAD +; (LOADER, MONITOR, ZSDOS) THAT HAS BEEN LOADED TO PHYSICAL RAM +; BANKS 0 AND 1 TO THE USER TPA BANK TO RUN AFTER BOOT. +; IT IS DONE PRIOR TO COPYING HBIOS TO IT'S FINAL BANK BECAUSE +; THE PAYLOAD MAY EXTEND INTO THE HBIOS OPERATING BANK. THIS +; HAPPENS PRIMARILY IN THE CASE WHERE THE +; SYSTEM HAS THE MINIMUM 128KB OF RAM. +; +#IFDEF ROMBOOT + #IF (ROMSIZE == 0) + ; + ; THE PAYLOAD IS LIKELY TO CROSS OVER THE RAM BANK 0/1 + ; BOUNDARY. BNKCPY DOES NOT HANDLE THIS BECAUSE IT ASSUMES + ; THE COMMON BANK IS USED AFTER PASSING OVER THE BANK + ; BOUNDARY. WE WORK AROUND THAT HERE BY DOING TWO COPIES. + ; THE FIRST ONE HANDLES THE PORTION OF THE PAYLOAD FROM THE + ; END OF HBIOS TO THE BANK BOUNDARY ($8000). THE SECOND + ; ONE HANDLES THE PORTION THAT EXTENDS INTO THE SECOND + ; PHYSICAL RAM BANK. +; + ; COPY PORTION OF PAYLOAD FOLLOWING HBIOS TO THE BANK + ; BOUNDARY AT $8000 INTO START OF TPA. + LD A,BID_RAM0 + LD (HB_SRCBNK),A + LD A,BID_USR + LD (HB_DSTBNK),A + LD HL,HB_END + LD DE,0 + LD BC,$8000-HB_END +; + #IF (MEMMGR == MM_Z280) + CALL Z280_BNKCPY + #ELSE + CALL HBX_BNKCPY + #ENDIF +; + ; COPY REMAINDER OF PAYLOAD EXTENDING INTO THE SECOND PHYSICAL + ; RAM BANK. NOTE THAT THE DESTINATION ADDRESS (DE) IS + ; ALREADY CORRECT FROM THE PRIOR COPY. + LD A,BID_RAM0+1 + LD (HB_SRCBNK),A + LD HL,$0000 + ; DE IS ALREADY CORRECT + LD BC,$8000-($8000-HB_END) +; + #IF (MEMMGR == MM_Z280) + CALL Z280_BNKCPY + #ELSE + CALL HBX_BNKCPY + #ENDIF +; + #ENDIF ; -#IFDEF APPBOOT - POP AF - LD (HB_CURBNK),A #ENDIF ; ; IF ALREADY EXECUTING IN RAM, BYPASS RAM BANK INSTALLATION @@ -1380,39 +1600,10 @@ MBC_SINGLE: LD HL,0 LD DE,0 LD BC,$8000 +#IF (MEMMGR == MM_Z280) + CALL Z280_BNKCPY +#ELSE CALL HBX_BNKCPY -; -#IF (1) -; -; POPULATE THE CRITICAL RAM BANK NUMBERS. -; -; ASSUME THAT CB_RAMBANKS IS THE NUMBER OF 32K RAM BANKS THAT HAS BEEN SET EITHER -; AT ASSEMBLY TIME OR BY PROBING THE ACTUAL AVAILABLE MEMORY (NOT IMPLEMENTED YET). -; - LD A,(CB_RAMBANKS) ; CALCULATE START - DEC A ; RAMBANK AFTER - ADD A,($80 + (PLT_RAM_R / 32)) ; RESERVED BANKS -; - LD HL,CB_BIDCOM - LD B,4 -CB_IDS: LD (HL),A ; POPULATE CB_BIDCOM - INC HL ; POPULATE CB_BIDUSR - DEC A ; POPULATE CB_BIDBIOS - DJNZ CB_IDS ; POPULATE CB_BIDAUX - - LD A,(CB_BIDUSR) - LD (HB_SRCBNK),A ; POPULATE HB_SRCBNK - LD (HB_DSTBNK),A ; POPULATE HB_DSTBNK -; - LD A,+($80 + (PLT_RAM_R / 32)) ; POPULATE CB_BIDRAMD0 ; START RAMBANK - LD (HL),A - INC HL -; - LD A,(CB_RAMBANKS) ; POPULATE CB_BIDRAMDN ; END RAMBANK - DEC A - SUB TOT_RAM_RB - LD (HL),A -; #ENDIF ; ; TRANSITION TO HBIOS IN RAM BANK @@ -1435,15 +1626,30 @@ HB_RAMFLAG .DB FALSE ; INITIALLY FALSE, SET TO TRUE BELOW AFTER RAM TRANSITION ; HB_START1: ; BNKCALL ARRIVES HERE, BUT NOW RUNNING IN RAM BANK ; + ; WE RESET THE STACK HERE BECAUSE WE ARE NOT GOING TO RETURN + ; FROM THE BNKCALL. REMEMBER THAT WE STORED A COUPLE BYTES + ; RIGHT BELOW HBX_LOC, SO THE STACK IS SET TO START JUST BELOW + ; THAT. + LD SP,HBX_LOC - 2 ; RESET STACK +; + ; NOTIFY THAT WE MADE THE TRANSTION! DIAG(%00000111) LED(%00000010) ; - LD A,(HBX_LOC - 1) ; RECALL BATTERY STATE AND SAVE - LD (HB_BATCOND),A ; FOR FUTURE REFERENCE -; - LD SP,HBX_LOC ; RESET STACK SINCE WE DO NOT RETURN + ; SET THE IN-RAM FLAG LD A,TRUE ; ACCUM := TRUE LD (HB_RAMFLAG),A ; SET RAMFLAG +; + ; RECOVER DATA PASSED PRIOR TO RAM TRANSITION + ; (HBX_LOC - 1) = BATCOND, (HBX_LOC - 2) = APPBNK + POP HL ; POP 2 BYTES + LD A,H ; GET FIRST BYTE PUSHED + LD (HB_BATCOND),A ; ... AND SAVE AS BAT COND +; +#IFDEF APPBOOT + LD A,L ; GET SECOND BYTE PUSHED + LD (HB_APPBNK),A ; ... AND SAVE AS APPBNK +#ENDIF ; #IF (MEMMGR == MM_Z280) ; NOW POINT TO RAM COPY OF Z280 INT/TRAP TABLE @@ -1457,10 +1663,6 @@ HB_START1: ; BNKCALL ARRIVES HERE, BUT NOW RUNNING IN RAM BANK ; IF APPBOOT, WE NEED TO FIX UP A FEW THINGS IN PAGE ZERO ; #IFDEF APPBOOT -; - ; GET AND SAVE APP BOOT BANK ID - LD A,(HBX_LOC - 2) - LD (HB_APPBNK),A ; ; MAKE SURE RST 08 VECTOR IS RIGHT LD A,$C3 @@ -1484,6 +1686,39 @@ HB_START1: ; BNKCALL ARRIVES HERE, BUT NOW RUNNING IN RAM BANK #ENDIF #ENDIF ; +#IF FALSE +; +; POPULATE THE CRITICAL RAM BANK NUMBERS. +; +; ASSUME THAT CB_RAMBANKS IS THE NUMBER OF 32K RAM BANKS THAT HAS BEEN SET EITHER +; AT ASSEMBLY TIME OR BY PROBING THE ACTUAL AVAILABLE MEMORY (NOT IMPLEMENTED YET). +; + LD A,(CB_RAMBANKS) ; CALCULATE TOP RAMBANK + ADD A,BID_RAM0 ; AS FIRST RAMBANK + + DEC A ; #RAMBANKS - 1 +; + LD HL,CB_BIDCOM + LD B,4 +CB_IDS: LD (HL),A ; POPULATE CB_BIDCOM + INC HL ; POPULATE CB_BIDUSR + DEC A ; POPULATE CB_BIDBIOS + DJNZ CB_IDS ; POPULATE CB_BIDAUX +; + LD A,(CB_BIDUSR) + LD (HB_SRCBNK),A ; POPULATE HB_SRCBNK + LD (HB_DSTBNK),A ; POPULATE HB_DSTBNK +; + LD A,BID_RAM0 ; POPULATE CB_BIDRAMD0 ; START RAMBANK + LD (HL),A + INC HL +; + LD A,(CB_RAMBANKS) ; POPULATE CB_BIDRAMDN ; END RAMBANK + DEC A + SUB TOT_RAM_RB + LD (HL),A +; +#ENDIF +; ;================================================================================================== ; RECOVERY MODE ;================================================================================================== @@ -1613,56 +1848,123 @@ HB_CPU1: OUT ($6D),A ; IMPLEMENT IT ; #ENDIF +; + DIAG(%00011111) +; +; INIT OSCILLATOR SPEED FROM CONFIG +; + LD HL,CPUOSC / 1000 + LD (HB_CPUOSC),HL +; +; ATTEMPT DYNAMIC CPU SPEED DERIVATION +; NOTE THAT FOR PLATFORMS WITH SOFTWARE SELECTABLE CPU SPEED, +; THIS IS BEING DONE WITH THE CPU SPEED SET TO THE LOWEST +; POSSIBLE SETTING. THE FINAL CPU SPEED WILL BE ADJUSTED +; LATER. +; + CALL HB_CPUSPD ; CPU SPEED DETECTION + JR NZ,HB_CPUSPD2 ; SKIP IF FAILED +; +; RECORD THE UPDATED CPU OSCILLATOR SPEED +; +#IF ((CPUFAM == CPU_Z180) | (CPUSPDCAP == SPD_HILO)) + ; SPEED MEASURED WILL BE HALF OSCILLATOR SPEED + ; SO RECORD DOUBLE THE MEASURED VALUE + SLA L + RL H + LD (HB_CPUOSC),HL +#ENDIF +; +HB_CPUSPD2: +; +; INIT CPUKHZ BASED ON OSCILLATOR SPEED +; + LD HL,(HB_CPUOSC) +; +; TRANSITION TO FINAL DESIRED CPU SPEED FOR THOSE PLATFORMS +; THAT SUPPORT SOFTWARE SELECTABLE CPU SPEED. UPDATE CB_CPUKHZ +; IN HCB AS WE DO THIS. +; +#IF ((CPUSPDCAP==SPD_HILO) & (PLATFORM==PLT_MBC)) + #IF (CPUSPDDEF==SPD_HIGH) + ; SET HIGH SPEED VIA RTC LATCH + LD A,(HB_RTCVAL) + OR %00001000 ; SET HI SPEED BIT + LD (HB_RTCVAL),A ; SAVE SHADOW + OUT (RTCIO),A ; IMPLEMENT + ; HL IS ALREADY CORRECT FOR FULL SPEED OPERATION + #ELSE + ; ADJUST HL TO REFLECT HALF SPEED OPERATION + SRL H ; ADJUST HL ASSUMING + RR L ; HALF SPEED OPERATION + #ENDIF +#ENDIF +; +#IF ((CPUSPDCAP==SPD_HILO) & (PLATFORM==PLT_SBC)) + #IF (CPUSPDDEF==SPD_HIGH) + ; SET HIGH SPEED VIA RTC LATCH + LD A,(HB_RTCVAL) + AND ~%00001000 ; CLEAR HI SPEED BIT + LD (HB_RTCVAL),A ; SAVE SHADOW + OUT (RTCIO),A ; IMPLEMENT + ; HL IS ALREADY CORRECT FOR FULL SPEED OPERATION + #ELSE + ; ADJUST HL TO REFLECT HALF SPEED OPERATION + SRL H ; ADJUST HL ASSUMING + RR L ; HALF SPEED OPERATION + #ENDIF +#ENDIF ; #IF (CPUFAM == CPU_Z180) ; - ; AT BOOT, Z180 PHI IS OSC / 2 - LD C,(CPUOSC / 2) / 1000000 - LD DE,(CPUOSC / 2) / 1000 + LD HL,(HB_CPUOSC) ; INIT HL TO CPU OSC FREQ (KHZ) ; - #IF (Z180_CLKDIV >= 1) + #IF (Z180_CLKDIV == 0) + ; ADJUST HL TO REFLECT HALF SPEED OPERATION + SRL H ; ADJUST HL ASSUMING + RR L ; HALF SPEED OPERATION + #ENDIF +; + #IF (Z180_CLKDIV == 1) LD A,(HB_CPUTYPE) ; GET CPU TYPE CP 2 ; Z8S180 REV K OR BETTER? - JR C,HB_CPU2 ; IF NOT, NOT POSSIBLE! + JR C,HB_CPU3 ; IF NOT, NOT POSSIBLE! ; SET CLOCK DIVIDE TO 1 RESULTING IN FULL XTAL SPEED LD A,$80 OUT0 (Z180_CCR),A - ; REFLECT SPEED CHANGE - LD C,CPUOSC / 1000000 - LD DE,CPUOSC / 1000 + ; HL ALREADY REFLECTS FULL SPEED OPERATION #ENDIF - +; #IF (Z180_CLKDIV >= 2) LD A,(HB_CPUTYPE) ; GET CPU TYPE CP 3 ; Z8S180 REV N OR BETTER? - JR C,HB_CPU2 ; IF NOT, NOT POSSIBLE! + JR C,HB_CPU3 ; IF NOT, NOT POSSIBLE! ; SET CPU MULTIPLIER TO 1 RESULTING IN XTAL * 2 SPEED ; ALSO SET CCR AGAIN BECAUSE OF REPORTS THAT CCR ; *MUST* BE SET AFTER CMR. LD A,$80 OUT0 (Z180_CMR),A ; CPU MULTIPLIER OUT0 (Z180_CCR),A ; CLOCK DIVIDE - ; REFLECT SPEED CHANGE - LD C,(CPUOSC * 2) / 1000000 - LD DE,(CPUOSC * 2) / 1000 + ; ADJUST HL TO REFLECT DOUBLE SPEED OPERATION + SLA L + RL H #ENDIF ; -HB_CPU2: - ; SAVE CPU SPEED IN CONFIG BLOCK - LD A,C - LD (CB_CPUMHZ),A - LD (CB_CPUKHZ),DE -; +HB_CPU3: #ENDIF ; - DIAG(%00011111) -; -; PERFORM DYNAMIC CPU SPEED DERIVATION -; - CALL HB_CPUSPD ; CPU SPEED DETECTION +; HL SHOULD NOW HAVE FINAL CPU RUNNING SPEED IN KHZ. +; UPDATE CB_CPUMHZ/CB_CPUKHZ WITH THIS VALUE. ; - LD A,(CB_CPUMHZ) ; CPU SPEED TO ACCUM AND INIT - CALL DELAY_INIT ; .. SPEED COMPENSATED DELAY + LD (CB_CPUKHZ),HL ; UPDATE CPUKHZ + LD DE,1000 ; SET UP TO DIV BY 1000 FOR MHZ + CALL DIV16 ; BC=CPU MHZ, HL=REMAINDER + LD DE,500 ; SET UP TO ROUND UP + XOR A ; IF WITHIN 500 KHZ + SBC HL,DE ; REMAINDER - 500 + CCF ; COMPLEMENT CF + ADC A,C ; C -> A; ADD CF FOR ROUNDING + LD (CB_CPUMHZ),A ; SAVE IT ; #IF (CPUFAM == CPU_Z180) ; @@ -1693,6 +1995,9 @@ HB_CPU2: LDCTL (C),HL ; #ENDIF +; + LD A,(CB_CPUMHZ) ; CPU SPEED TO ACCUM AND INIT + CALL DELAY_INIT ; .. SPEED COMPENSATED DELAY ; #IF (INTMODE == 2) ; SETUP Z80 IVT AND INT MODE 2 @@ -1769,6 +2074,8 @@ HB_CPU2: ; NOW IF DIVIDE BOTH SIDES BY 1000, WE CAN USE ; CPUKHZ VALUE AND SIMPLIFY TO ; RLDR = CPUKHZ + XOR A ; ALL BITS ZERO + OUT0 (Z180_TCR),A ; ... INHIBITS TIMER OPERATION LD HL,(CB_CPUKHZ) ; 50HZ = 18432000 / 20 / 50 / X, SO X = CPU KHZ OUT0 (Z180_TMDR0L),L ; INITIALIZE TIMER 0 DATA REGISTER OUT0 (Z180_TMDR0H),H @@ -1835,6 +2142,7 @@ Z280_TC .EQU CPUOSC / 4 / 50 / 2 ; TIME CONSTANT CALL FILL ; DO IT ; DIAG(%00111111) +; #IF FALSE ; ; TEST DEBUG *************************************************************************************** @@ -1863,8 +2171,6 @@ NOT_REC_M0: CALL CALLLIST ; PROCESS THE PRE-INIT CALL TABLE ; #IF (DSKYENABLE) - ;CALL DSKY_PREINIT - LD HL,MSG_HBVER + 5 LD A,(DSKY_HEXMAP + RMJ) OR $80 @@ -2137,6 +2443,20 @@ HB_Z280BUS1: CALL PRTSTRD .TEXT "KB RAM$" ; +#IFDEF TESTING +; + CALL PRTSTRD + .TEXT ", RAMBANKS=0x$" + LD A,($FFEA) + CALL PRTHEXBYTE +; + CALL PRTSTRD + .TEXT ", RTCDEF=0x$" + LD A,(RTCDEFVAL) + CALL PRTHEXBYTE +; +#ENDIF +; #IF 0 ; ; DIAGNOSTIC DISPLAY OF BANK IDS IN HCB @@ -2174,6 +2494,7 @@ HB_Z280BUS1: #ENDIF ; #IFDEF ROMBOOT + #IF (ROMSIZE > 0) ; ; ROM CHECKSUM VERIFICATION ; EACH OF THE FIRST 4 ROM BANKS HAS A CHECKSUM INJECTED SUCH THAT @@ -2223,7 +2544,13 @@ HB_CKBNK: LD BC,1 ; DECREMENT VALUE XOR A ; ZERO ACCUM HB_CKBNK1: +#IF (MEMMGR == MM_Z280) + LD D,A ; WORKING VALUE TO D + LDUD A,(HL) ; GRAB NEXT BYTE FROM USER SPACE + ADD A,D ; ADD NEXT BYTE +#ELSE ADD A,(HL) ; ADD NEXT BYTE +#ENDIF OR A ; CLEAR CARRY SBC HL,BC ; DECREMENT JR NC,HB_CKBNK1 ; LOOP TILL DONE @@ -2238,6 +2565,7 @@ HB_CKBNKSIZ .EQU $-HB_CKBNK ; SIZE OF ROUTINE ; HB_ROMCKZ: ; + #ENDIF #ENDIF ; ; LOW BATTERY DIAGNOSTIC MESSAGE @@ -2352,6 +2680,71 @@ HB_WDZ: INITSYS3: CALL PRTSUM ; PRINT UNIT/DEVICE SUMMARY TABLE ; +#IF 0 + CALL NEWLINE + CALL NEWLINE + CALL NEWLINE + + ; SRC & DEST BELOW BND + CALL NEWLINE + LD HL,$4000 + LD DE,$5000 + LD BC,$3000 + CALL NEWLINE + CALL REGDMP + CALL Z280_BNKCPYX + + ; SRC & DEST ABOVE BND + CALL NEWLINE + LD HL,$8000 + LD DE,$9000 + LD BC,$1000 + CALL NEWLINE + CALL REGDMP + CALL Z280_BNKCPYX + + ; SRC CROSSOVER + CALL NEWLINE + LD HL,$7000 + LD DE,$9000 + LD BC,$2000 + CALL NEWLINE + CALL REGDMP + CALL Z280_BNKCPYX + + ; DEST CROSSOVER + CALL NEWLINE + LD HL,$9000 + LD DE,$7000 + LD BC,$2000 + CALL NEWLINE + CALL REGDMP + CALL Z280_BNKCPYX + + ; DOUBLE CROSSOVER + CALL NEWLINE + LD HL,$7800 + LD DE,$7000 + LD BC,$2000 + CALL NEWLINE + CALL REGDMP + CALL Z280_BNKCPYX + + ; DOUBLE CROSSOVER SINGLE BYTES + CALL NEWLINE + LD HL,$7FFE + LD DE,$7FFF + LD BC,$0500 + CALL NEWLINE + CALL REGDMP + CALL Z280_BNKCPYX + + CALL NEWLINE + CALL NEWLINE + CALL NEWLINE +; +#ENDIF +; INITSYS4: ; #IF (MEMMGR == MM_Z280) @@ -2376,15 +2769,8 @@ INITSYS4: LDCTL (C),HL #ENDIF ; -; CHAIN TO OS LOADER +#IFNDEF ROMBOOT ; -#IFDEF ROMBOOT - ; PERFORM BANK CALL TO OS IMAGES BANK IN ROM - LD A,BID_IMG0 ; CHAIN TO OS IMAGES BANK - LD IX,0 ; ENTER AT ADDRESS 0 - CALL HBX_BNKCALL ; GO THERE - HALT ; WE SHOULD NEVER COME BACK! -#ELSE ; COPY OS IMAGE: BID_USR: --> BID_USR:0 LD B,BF_SYSSETCPY ; HBIOS FUNC: SETUP BANK COPY LD D,BID_USR ; D = DEST BANK = USER BANK @@ -2398,16 +2784,23 @@ INITSYS4: LD DE,0 ; TO USER ADDRESS 0 RST 08 ; DO IT ; - ; PERFORM BANK CALL TO USER BANK - LD A,BID_USR ; CHAIN TO OS IMAGES BANK +#ENDIF +; +; CHAIN TO LOADER +; +#IFDEF ROMBOOT + #IF (ROMSIZE > 0) + LD A,BID_IMG0 ; CHAIN TO OS IMAGES BANK + #ELSE + LD A,BID_USR ; CHAIN TO USER BANK + #ENDIF +#ELSE + LD A,BID_USR ; CHAIN TO USER BANK +#ENDIF LD IX,0 ; ENTER AT ADDRESS 0 CALL HBX_BNKCALL ; GO THERE HALT ; WE SHOULD NEVER COME BACK! ; -#ENDIF -; - RET -; ; CALL A LIST OF ROUTINES POINTED TO BY DE OF LENGTH B. ; CALLLIST: @@ -2478,6 +2871,9 @@ HB_PCINITTBL: #IF (ACIAENABLE) .DW ACIA_PREINIT #ENDIF +#IF (PIOENABLE) + .DW PIO_PREINIT +#ENDIF #IF (PIO_4P | PIO_ZP) .DW PIO_PREINIT #ENDIF @@ -2597,6 +2993,9 @@ HB_INITTBL: #IF (PPPENABLE) .DW PPP_INIT #ENDIF +#IF (PIOENABLE) + .DW PIO_INIT +#ENDIF #IF (PIO_4P | PIO_ZP) .DW PIO_INIT #ENDIF @@ -3328,6 +3727,11 @@ SYS_RESINT: ; GO BACK TO ROM BOOT LOADER ; SYS_RESWARM: +; +#IF (ROMSIZE == 0) + JR SYS_RESCOLD +#ENDIF +; CALL SYS_RESINT ; #IF (MEMMGR == MM_Z280) @@ -3344,6 +3748,14 @@ SYS_RESWARM: ; RESTART SYSTEM AS THOUGH POWER HAD JUST BEEN TURNED ON ; SYS_RESCOLD: +; +#IF (ROMSIZE == 0) + LD DE,STR_RESTART + CALL Z,WRITESTR + DI + HALT +#ENDIF +; #IF (MEMMGR == MM_Z280) JP Z280_RESTART #ELSE @@ -3538,6 +3950,8 @@ SYS_GET: JP Z,SYS_GETMEMINFO CP BF_SYSGET_BNKINFO JP Z,SYS_GETBNKINFO + CP BF_SYSGET_CPUSPD + JP Z,SYS_GETCPUSPD CALL SYSCHK LD A,ERR_NOFUNC ; SIGNAL ERROR OR A ; SET FLAGS @@ -3597,6 +4011,7 @@ SYS_GETCPUINFO: LD A,(CB_CPUMHZ) LD L,A LD DE,(CB_CPUKHZ) + LD BC,(HB_CPUOSC) XOR A RET ; @@ -3626,6 +4041,65 @@ SYS_GETBNKINFO: XOR A RET ; +; GET SYSTEM CPU SPEED ORMANCE ATTRIBUTES +; RETURNS: +; L: CLOCK MULT (0:HALF, 1:FULL, 2: DOUBLE) +; D: MEMORY WAIT STATES +; E: I/O WAIT STATES +; +SYS_GETCPUSPD: +; +#IF (((PLATFORM == PLT_SBC) | (PLATFORM == PLT_MBC)) & (CPUSPDCAP==SPD_HILO)) + LD A,(HB_RTCVAL) + BIT 3,A +#IF (PLATFORM == PLT_SBC) + XOR %00001000 ; SBC SPEED BIT IS INVERTED +#ENDIF + LD L,0 ; ASSUME HALF SPEED + JR Z,SYS_GETCPUSPD1 + LD L,1 +SYS_GETCPUSPD1: + LD DE,$FFFF ; UNKNOWN WAIT STATES +; + XOR A + RET +#ENDIF +; +#IF (CPUFAM == CPU_Z180) + IN0 A,(Z180_CMR) ; GET CLOCK MULTIPLIER + RLCA ; ROTATE BIT TO BIT 0 + AND %00000001 ; ISOLATE IT + LD H,A ; SAVE IN H + IN0 A,(Z180_CCR) ; GET CLOCK CONTROL + RLCA ; ROTATE BIT TO BIT 0 + AND %00000001 ; ISOLATE IT + LD L,A ; SAVE IN L + XOR A ; CLEAR ACCUM + ADD A,H ; ADD IN CMR BIT + ADD A,L ; ADD IN CCR BIT + LD L,A ; SAVE RESULT IN L +; + ; DCNTL = MMII???? + IN0 A,(Z180_DCNTL) ; GET WAIT STATES + RLCA ; ROTATE MEM WS BITS + RLCA ; ... TO LOW BITS + PUSH AF ; SAVE FOR NOW + AND %00000011 ; ISOLATE BITS + LD D,A ; PUT IN D + POP AF ; RECOVER A + RLCA ; ROTATE I/O WS BITS + RLCA ; ... TO LOW BITS + AND %00000011 ; ISOLATE BITS + INC A ; ADD 1 FOR BUILT-IN WS + LD E,A ; PUT IN E +; + XOR A + RET +#ENDIF +; + OR $FF + RET +; ; GET SERIAL UNIT COUNT ; SYS_GETCIOCNT: @@ -3756,6 +4230,8 @@ SYS_SET: JR Z,SYS_SETSECS CP BF_SYSSET_BOOTINFO JR Z,SYS_SETBOOTINFO + CP BF_SYSSET_CPUSPD + JR Z,SYS_SETCPUSPD CALL SYSCHK LD A,ERR_NOFUNC ; SIGNAL ERROR OR A ; SET FLAGS @@ -3797,6 +4273,219 @@ SYS_SETSECS: XOR A RET ; +; SET SYSTEM CPU SPEED ATTRIBUTES +; ON ENTRY: +; L: CLOCK MULT (0:HALF, 1:FULL, 2: DOUBLE) +; D: MEMORY WAIT STATES +; E: I/O WAIT STATES +; +SYS_SETCPUSPD: +; +#IF (((PLATFORM == PLT_SBC) | (PLATFORM == PLT_MBC)) & (CPUSPDCAP==SPD_HILO)) +; +; NOTE: WAIT STATE SETTINGS ARE IGNORED FOR Z80 +; + LD A,L ; CLK SPD TO ACCUM + CP $FF ; NO CHANGE? + JR Z,SYS_SETCPUSPD3 ; DONE IF SO + LD C,%00000000 ; HALF SPEED + CP 0 + JR Z,SYS_SETCPUSPD1 + LD C,%00001000 ; FULL SPEED + CP 1 + JR Z,SYS_SETCPUSPD1 + JR SYS_SETCPUSPD_ERR ; SPD NOT SUPPORTED +SYS_SETCPUSPD1: + LD A,(HB_RTCVAL) + AND ~%00001000 ; CLEAR SPEED BIT + OR C ; IMPLEMENT NEW SPEED BIT +#IF (PLATFORM == PLT_SBC) + ; SBC SPEED BIT IS INVERTED, ADJUST IT + LD A,C + XOR %00001000 + LD C,A +#ENDIF + LD (HB_RTCVAL),A ; SAVE IN SHADOW REGISTER + OUT (RTCIO),A ; UPDATE HARDWARE REGISTER +; + ; UPDATE THE CURRENT CPU SPEED IN HCB! + LD A,L + LD HL,(HB_CPUOSC) ; ASSUME FULL SPEED + CP 1 ; CHECK FOR 1 (FULL SPEED) + JR Z,SYS_SETCPUSPD2 ; IF SO, ALL DONE + ; ADJUST HL TO REFLECT HALF SPEED OPERATION + SRL H ; ADJUST HL ASSUMING + RR L ; HALF SPEED OPERATION +; +SYS_SETCPUSPD2: +; +; HL SHOULD NOW HAVE FINAL CPU RUNNING SPEED IN KHZ. +; UPDATE CB_CPUMHZ/CB_CPUKHZ WITH THIS VALUE. +; + LD (CB_CPUKHZ),HL ; UPDATE CPUKHZ + LD DE,1000 ; SET UP TO DIV BY 1000 FOR MHZ + CALL DIV16 ; BC=CPU MHZ, HL=REMAINDER + LD DE,500 ; SET UP TO ROUND UP + XOR A ; IF WITHIN 500 KHZ + SBC HL,DE ; REMAINDER - 500 + CCF ; COMPLEMENT CF + ADC A,C ; C -> A; ADD CF FOR ROUNDING + LD (CB_CPUMHZ),A ; SAVE IT +; + ; REINIT DELAY ROUTINE + LD A,(CB_CPUMHZ) ; CPU SPEED TO ACCUM AND INIT + CALL DELAY_INIT ; .. SPEED COMPENSATED DELAY +; +SYS_SETCPUSPD3: + XOR A + RET +#ENDIF +; +#IF (CPUFAM == CPU_Z180) + PUSH DE ; SAVE WAIT STATES FOR NOW + ; BEFORE IMPLEMENTING THE NEW CPU SPEED, WE SWITCH THE + ; WAIT STATES TO MAXIMUM BECAUSE WE MAY BE IMPLEMENTING + ; SLOWER WAIT STATES REQUIRED BY THE NEW SPEED. WE SAVE + ; THE ORIGINAL WAIT STATES REGISTER VALUE ON STACK + IN0 A,(Z180_DCNTL) ; GET CURRENT REGISTER VALUE + LD E,A ; PUT IN E + PUSH DE ; SAVE FOR LATER + OR %11110000 ; MAX WAIT STATES + OUT0 (Z180_DCNTL),A ; DO IT +; + LD A,L ; NEW CLK SPD TO ACCUM + CP $FF ; NO CHANGE? + JR Z,SYS_SETCPUSPD2B ; IF SO, SKIP TO WAIT STATES +; + LD B,0 ; B HAS BIT FOR CMR + LD C,0 ; C HAS BIT FOR CCR + CP 2 ; DOUBLE SPEED? + JR C,SYS_SETCPUSPD1 ; <2?, SKIP AHEAD + LD B,%10000000 ; SET CMR BIT +SYS_SETCPUSPD1: + CP 1 ; FULL SPEED? + JR C,SYS_SETCPUSPD2 ; <1?, SKIP AHEAD + LD C,%10000000 ; SET CCR BIT +SYS_SETCPUSPD2: +; + IN0 A,(Z180_CMR) + AND ~%10000000 + OR B + OUT0 (Z180_CMR),A +; + IN0 A,(Z180_CCR) + AND ~%10000000 + OR C + OUT0 (Z180_CCR),A +; + ; UPDATE THE CURRENT CPU SPEED IN HCB! + LD A,L ; SETTING TO A + LD HL,(HB_CPUOSC) ; START WITH CPU OSC VALUE + ; ADJUST HL TO REFLECT HALF SPEED OPERATION + SRL H ; ADJUST HL ASSUMING + RR L ; HALF SPEED OPERATION + OR A ; CHECK FOR HALF SPEED + JR Z,SETCPUSPD2A ; IF SO, DONE + ; ADJUST HL TO REFLECT FULL SPEED OPERATION + SLA L + RL H + CP 1 ; CHECK FOR FULL SPEED + JR Z,SETCPUSPD2A ; IF SO DONE + ; ADJUST HL TO REFLECT DOUBLE SPEED OPERATION + SLA L + RL H +; +SETCPUSPD2A: +; +; HL SHOULD NOW HAVE FINAL CPU RUNNING SPEED IN KHZ. +; UPDATE CB_CPUMHZ/CB_CPUKHZ WITH THIS VALUE. +; + LD (CB_CPUKHZ),HL ; UPDATE CPUKHZ + LD DE,1000 ; SET UP TO DIV BY 1000 FOR MHZ + CALL DIV16 ; BC=CPU MHZ, HL=REMAINDER + LD DE,500 ; SET UP TO ROUND UP + XOR A ; IF WITHIN 500 KHZ + SBC HL,DE ; REMAINDER - 500 + CCF ; COMPLEMENT CF + ADC A,C ; C -> A; ADD CF FOR ROUNDING + LD (CB_CPUMHZ),A ; SAVE IT +; +SYS_SETCPUSPD2B: + ; NOW IMPLEMENT ANY WAIT STATE CHANGES. + POP HL ; INIT L WITH ORIG DCNTL VALUE + POP DE ; RECOVER WAIT STATES + LD A,D ; GET MEM WS + CP $FF ; SKIP? + JR Z,SYS_SETCPUSPD3 ; IF SO, GO AHEAD + AND %00000011 ; JUST TWO BITS + RRCA ; MEM WS IS TOP TWO BITS + RRCA + LD H,A ; MOVE WS BITS TO H + LD A,L ; CUR VALUE TO A + AND %00111111 ; MASK OFF MEM WS BITS + OR H ; SET NEW MEM WS BITS + LD L,A ; BACK TO L +; +SYS_SETCPUSPD3: +; + LD A,E ; GET I/O WS + CP $FF ; SKIP? + JR Z,SYS_SETCPUSPD4 ; IF SO, GO AHEAD + DEC A ; ADJUST FOR BUILT-IN I/O WS + AND %00000011 ; JUST TWO BITS + RRCA ; I/O WS IS BITS 5-4 + RRCA + RRCA + RRCA + LD H,A ; MOVE WS BITS TO H + LD A,L ; CUR VALUE TO A + AND %11001111 ; MASK OFF I/O WS BITS + OR H ; SET NEW I/O WS BITS + LD L,A ; BACK TO L +; +SYS_SETCPUSPD4: + LD A,L ; WORKING VALUE TO A + OUT0 (Z180_DCNTL),A ; IMPLEMENT NEW VALUE +; + ; REINIT DELAY ROUTINE + LD A,(CB_CPUMHZ) ; CPU SPEED TO ACCUM AND INIT + CALL DELAY_INIT ; .. SPEED COMPENSATED DELAY +; + #IF ((INTMODE == 2) & (Z180_TIMER)) + ; THE Z180 TIMER IS BASED ON CPU SPEED. SO HERE + ; WE RECOMPUTE THE TIMER CONSTANTS BASED ON THE NEW SPEED. + XOR A ; ALL BITS ZERO + OUT0 (Z180_TCR),A ; ... INHIBITS TIMER OPERATION + LD HL,(CB_CPUKHZ) ; 50HZ = 18432000 / 20 / 50 / X, SO X = CPU KHZ + OUT0 (Z180_TMDR0L),L ; INITIALIZE TIMER 0 DATA REGISTER + OUT0 (Z180_TMDR0H),H + DEC HL ; RELOAD OCCURS *AFTER* ZERO + OUT0 (Z180_RLDR0L),L ; INITIALIZE TIMER 0 RELOAD REGISTER + OUT0 (Z180_RLDR0H),H + LD A,%00010001 ; ENABLE TIMER0 INT AND DOWN COUNTING + OUT0 (Z180_TCR),A + #ENDIF +; + #IF (ASCIENABLE) + ; RESET THE ASCI PORTS IN CASE SPEED CHANGED! + ; N.B., THIS WILL FAIL IF THE CURRENT BAUD RATE + ; IS IMPOSSIBLE TO IMPLEMENT AT THE NEW CPU SPEED!!! + LD DE,-1 + LD IY,ASCI0_CFG + CALL ASCI_INITDEV + LD DE,-1 + LD IY,ASCI1_CFG + CALL ASCI_INITDEV + #ENDIF +; + XOR A + RET +#ENDIF +; +SYS_SETCPUSPD_ERR: + OR $FF ; NOT SUPPORTED + RET +; ; RETURN A BYTE OF MEMORY FROM SPECIFIED BANK ; ENTRY: D=BANK ID, HL=ADDRESS ; RETURN: E=BYTE VALUE @@ -4192,7 +4881,7 @@ Z280_BADINT: CALL PRTHEXWORDHL ; DUMP MSR EX (SP),HL ; MSR TO STK, RECOVER HL ; - .DB $ED,$55 ; RETIL + RETIL ; RETURN FROM INT ; Z280_SSTEP: ; SAVE HL AND MSR FOR POSSIBLE RETURN VIA RETIL @@ -4286,7 +4975,7 @@ Z280_PRIVINST: PUSH BC PUSH DE ; - .DB $ED,$96 ; LDUP A,(HL) + LDUP A,(HL) ; BYTE FROM USER SPACE ; ; HANDLE DI CP $F3 ; DI? @@ -4314,7 +5003,7 @@ Z280_PRIVINST3: CALL PC_LBKT LD B,$10 Z280_PRIVINST4: - .DB $ED,$96 ; LDUP A,(HL) + LDUP A,(HL) ; BYTE FROM USER SPACE CALL PRTHEXBYTE INC HL DJNZ Z280_PRIVINST4 @@ -4335,7 +5024,7 @@ Z280_PRIVINSTX: PUSH HL ; SAVE HL LD HL,(HB_MSRSAV) ; GET SAVED MSR EX (SP),HL ; MSR TO STK, RECOVER HL - .DB $ED,$55 ; RETIL + RETIL ; RETURN FROM INT ; HB_MSRSAV .DW 0 ; SAVED MSR HB_RCSAV .DW 0 ; SAVED REASON CODE @@ -4640,7 +5329,7 @@ Z280_BNKSEL2: ; ; SET LOW NIBBLE LD A,$0A ; VALUE FOR LOW NIBBLE - .DB $ED,$6D ; ADD HL,A ; HL=0000 RBBB B000 1010 + ADD HL,A ; ADD HL,A ; HL=0000 RBBB B000 1010 ; ; POINT TO FIRST PDR TO PROGRAM LD A,B ; INITIAL PDR TO PROG @@ -4684,8 +5373,115 @@ Z280_BNKSEL_LEN .EQU $ - Z280_BNKSEL ; ; Z280 BANK COPY (CALLED FROM PROXY) ; +; USE Z280 PHYSICAL MEMORY DMA COPY TO PERFORM AN INTERBANK COPY. +; COPY FROM (HB_SRCBNK):(HL) TO (HB_DSTBNK):(DE) FOR BC BYTES. BOTH +; HB_SRCBNK AND HB_DSTBNK MUST BE INITIALIZED PRIOR TO CALLING THIS +; ROUTINE. +; +; ADDRESSES ARE TRANSLATED FROM LOGICAL (Z80) TO PHYSICAL (Z280) TO +; SETUP THE DMA COPY PARAMETERS. IF THE SOURCE OR DESTINATION RANGE +; CROSSES OVER THE BANKED/COMMON BOUNDARY AT $8000, THEN SPECIAL STEPS +; MUST BE TAKEN BECAUSE THE BANKED AND COMMON AEAS ARE PROBABLY NOT +; SEQUENTIALLY LOCATED IN PHYSICAL MEMORY. TWO ENTRY POINTS ARE +; PROVIDED. Z280_BNKCPY IS MUCH FASTER, BUT DOES NOT ACCOUNT FOR THE +; COPY RANGES CROSSING OVER THE BANKED/COMMON BOUNDARY (WORKS GREAT +; FOR ANY COPY KNOWN TO STAY WITHIN IT'S OWN AREA). Z280_BNKCPYX +; WILL HANDLE COPIES WHERE THE SOURCE AND/OR DESTINATION RANGES +; CROSS OVER THE BANKED/COMMON MEMORY BOUNDARY. IT DOES THIS BY +; BREAKING UP THE COPY REQUESTS INTO MULTIPLE REQUESTS THAT ALL FIT +; WITHIN A SINGLE BANKED/COMMON MEMORY SEGMENT AND CALLING Z280_BNKCPY +; ITERATIVELY UNTIL THE COPY IS COMPLETE. +; +; THERE IS ESSENTIALLY NO PROTECTION FOR CALLING THESE ROUTINES WITH +; INVALID PARAMETERS. FOR EXAMPLE, A REQUEST TO COPY $2000 BYTES +; STARTING AT $F000 EXCEEDS THE SIZE OF THE Z80 MEMORY SPACES AND +; RESULTS IN UNDEFINED BEHAVIOR. +; +; THE COPY IS ALWAYS DONE FROM START TO END. IF THE SOURCE AND +; DESTINATION RANGES OVERLAP, THEN YOU MUST TAKE THIS INTO ACCOUNT. +; +; THE ROUTINE FUNCTIONS LOGICALLY LIKE THE Z80 LDIR INSTRUCTION. ON +; RETURN THE SOURCE (HL) AND DESTINATION (DE) REGISTERS WILL BE LEFT +; POINTING TO THE NEXT BYTE THAT WOULD BE COPIED IF THE COPY ROUTINE +; CONTINUED. BC WILL BE 0. AF IS UNDEFINED. +; #IF (MEMMGR == MM_Z280) ; +; ADJUST THE LENGTH OF THE COPY SUCH THAT BOTH THE SOURCE AND +; DESTINATION RANGES DO NOT CROSS OVER THE BANKED/COMMON MEMORY +; BOUNDARY. CALL Z280_BNKCPY TO DO AS MANY ITERATIONS AS NEEDED TO +; COMPLETE THE COPY. +; +; +Z280_BNKCPYX: + LD (Z280_BNKCPY_LEN),BC ; SAVE LENGTH +; + CALL Z280_BNKCPY_XOVER ; ADJUST FOR XOVER AS NEEDED + EX DE,HL ; SWAP SOURCE/DEST + CALL Z280_BNKCPY_XOVER ; ADJUST FOR XOVER AS NEEDED + EX DE,HL ; SWAP BACK +; + ; DO THE WORK, SAVE THE LEN OF THIS ITERATION + PUSH BC ; SAVE ITER LENGTH + CALL Z280_BNKCPY ; DO THE WORK +; + ;;; *DEBUG* SIMULATE CALL TO Z280_BNKCPY + ;;CALL NEWLINE + ;;CALL REGDMP ; *DEBUG* + ;;ADD HL,BC ; INCREMENT SRC ADR BY COUNT + ;;EX DE,HL ; SWAP + ;;ADD HL,BC ; INCREMENT DST ADR BY COUNT + ;;EX DE,HL ; SWAP BACK + ;;LD BC,0 ; COUNT IS NOW ZERO + ;;; END *DEBUG* +; + POP BC ; RECOVER ITER LENGTH +; + ; ACCUNT FOR WORK ACTUALLY PERFORMED + PUSH HL ; SAVE SOURCE ADR + LD HL,(Z280_BNKCPY_LEN) ; GET PENDING LENGTH + OR A ; CLEAR CARRY + SBC HL,BC ; SUBTRACT WHAT WE DID + PUSH HL ; MOVE NEW PENDING LEN + POP BC ; TO BC + POP HL ; RECOVER SOURCE ADR +; + ; SEE IF WE NEED TO ITERATE + LD A,B ; IS LENGTH + OR C ; ... NOW ZERO? + RET Z ; IF SO, ALL DONE + JR Z280_BNKCPYX ; ELSE ITERATE UNTIL DONE +; +Z280_BNKCPY_LEN .DW 0 ; TEMP STORAGE FOR BC +; +Z280_BNKCPY_XOVER: + ; DETECT XOVER IN RANGE AND ADJUST COPY LEN IF SO + ; HL=START, BC=LEN + ; BC IS REDUCED AS NEEDED TO AVOID XOVER + BIT 7,H ; START ABOVE 32K? + RET NZ ; YES, NO XOVER + PUSH HL ; SAVE START ADR + ADD HL,BC ; ADD COPY LEN + DEC HL ; CONVERT TO "LAST" BYTE OF RANGE + BIT 7,H ; ABOVE 32K? + POP HL ; RESTORE HL + RET Z ; IF NOT, NO XOVER +; + ; START IS BELOW 32K, END IS OVER 32K, XOVER IN SOURCE! + ; REDUCE LENGTH TO AVOID IT + ; COMPUTE (32K - START) FOR NEW LEN + PUSH DE ; SAVE DEST (DE) + PUSH HL ; SAVE START (HL) + LD DE,$8000 + EX DE,HL ; DE=START, HL=32K + OR A ; CLEAR CARRY + SBC HL,DE ; HL = NEW LEN + PUSH HL ; MOVE NEW LEN + POP BC ; ... TO BC + POP HL ; RECOVER START + POP DE ; RECOVER DEST + RET ; RETURN +; Z280_BNKCPY: ; Z280 MEMORY TO MEMORY DMA ; USE FLOW THROUGH MODE @@ -4708,7 +5504,7 @@ Z280_BNKCPY: ; SELECT I/O PAGE $FF LD C,Z280_IOPR ; I/O PAGE REGISTER LDCTL HL,(C) ; GET CURRENT I/O PAGE - LD (IOPRVAL),HL ; SAVE IT + LD (IOPRSAV),HL ; SAVE IT LD L,$FF ; I/O PAGE $FF LDCTL (C),HL ; @@ -4730,13 +5526,13 @@ Z280_BNKCPY: ; ; WAIT FOR XFER TO COMPLETE Z2DMALOOP: - .DB $ED,$B7 ; INW HL,(C) + INW HL,(C) ; WORD INPUT BIT 7,H ; CHECK EN BIT OF TDR JR NZ,Z2DMALOOP ; LOOP WHILE ACTIVE ; ; RESTORE I/O PAGE LD C,Z280_IOPR ; I/O PAGE REGISTER - LD HL,(IOPRVAL) ; RESTORE I/O PAGE + LD HL,(IOPRSAV) ; RESTORE I/O PAGE LDCTL (C),HL ; ; SETUP RETURN VALUES @@ -4799,6 +5595,7 @@ Z2DMAADR2: INC C ; BUMP TO NEXT REG ; RET +; #ENDIF ; ; Z280 SYSCALL VECTOR ENTRY POINT. TAKES STACK PARAMETER AS A BRANCH @@ -4812,7 +5609,7 @@ Z280_SYSCALL: POP HL Z280_SYSCALL_GO: CALL $FFFF ; PARM SET ABOVE - .DB $ED,$55 ; RETIL + RETIL ; RETURN FROM INT #ENDIF ; ;================================================================================================== @@ -5165,6 +5962,15 @@ SIZ_SPK .EQU $ - ORG_SPK .ECHO " bytes.\n" #ENDIF ; +#IF (PIOENABLE) +ORG_PIO .EQU $ + #INCLUDE "pio.asm" +SIZ_PIO .EQU $ - ORG_PIO + .ECHO "PIO occupies " + .ECHO SIZ_PIO + .ECHO " bytes.\n" +#ENDIF +; #IF (PIO_4P | PIO_ZP | PIO_SBC) ORG_PIO .EQU $ #INCLUDE "pio.asm" @@ -5299,16 +6105,8 @@ HB_CPUSPD1: SLA L RL H ; - LD (CB_CPUKHZ),HL ; HL=CPU SPEED IN KHZ - LD DE,1000 ; SET UP TO DIV BY 1000 FOR MHZ - CALL DIV16 ; BC=CPU MHZ, HL=REMAINDER - LD DE,500 ; SET UP TO ROUND UP - XOR A ; IF WITHIN 500 KHZ - SBC HL,DE ; REMAINDER - 500 - CCF ; COMPLEMENT CF - ADC A,C ; C -> A; ADD CF FOR ROUNDING - LD (CB_CPUMHZ),A ; SAVE IT -; + ; RETURN CURRENT CPU SPD (KHZ) IN HL + XOR A ; SIGNAL SUCCESS RET ; HB_WAITSEC: @@ -5361,6 +6159,7 @@ HB_RDSEC: ; #ELSE ; + OR $FF ; SIGNAL ERROR RET ; NO RTC, ABORT ; #ENDIF @@ -5597,7 +6396,7 @@ PS_PRTDC: RET ; DONE ; PS_PRTDC1: - ; PRINT ROM/ROM DISK CAPACITY IN KB + ; PRINT ROM/RAM DISK CAPACITY IN KB LD B,BF_DIOCAP ; HBIOS FUNC: GET CAPACTIY RST 08 ; DE:HL := BLOCKS JP NZ,PS_PRTNUL ; MEDIA PROBLEM @@ -6022,7 +6821,7 @@ PS_SDPRPCON .TEXT "PRPCON$" PS_SDPPPCON .TEXT "PPPCON$" PS_SDSIO .TEXT "SIO$" PS_SDACIA .TEXT "ACIA$" -PS_SDPIO .TEXT "PORT$" +PS_SDPIO .TEXT "PIO$" PS_SDUF .TEXT "UF$" PS_SDDUART .TEXT "DUART$" PS_SDZ2U .TEXT "Z2U$" @@ -6240,11 +7039,12 @@ HB_SECTCK .DB TICKFREQ ; TICK COUNTER FOR FRACTIONAL SECONDS HB_SECS .FILL 4,0 ; 32 BIT SECONDS COUNTER ; HB_CPUTYPE .DB 0 ; 0=Z80, 1=80180, 2=SL1960, 3=ASCI BRG -; -IOPRVAL .DW 0 ; TEMP STORAGE FOR IOPR +HB_CPUOSC .DW CPUOSC ; ACTUAL CPU HARDWARE OSC FREQ IN KHZ ; HB_BATCOND .DB 0 ; BATTERY CONDITION (0=LOW, 1=OK) ; +RTCDEFVAL .DB RTCDEF ; STORAGE FOR RTC DEFAULT VALUE +; #IF (BT_REC_TYPE != BT_REC_NONE) HB_BOOT_REC .DB 0 ; BOOT MODE (0=NORMAL, 1=RECOVERY MODE) #ENDIF @@ -6258,6 +7058,7 @@ STR_LOWBAT .DB "\r\n\r\n+++ LOW BATTERY +++$" STR_PANIC .TEXT "\r\n>>> PANIC: $" STR_SYSCHK .TEXT "\r\n>>> SYSCHK: $" STR_CONTINUE .TEXT "\r\nContinue (Y/N)? $" +STR_RESTART .TEXT "\r\n\r\n>>> Press hardware reset button to restart system\r\n\r\n$" ; #IF (DSKYENABLE) ; 'H','B','I','O',' ',' ',' ',' ' #IF (DSKYMODE == DSKYMODE_V1) @@ -6284,7 +7085,9 @@ SLACK .EQU BNKTOP - $ .ECHO " bytes.\n" ; #IFDEF ROMBOOT + #IF (ROMSIZE > 0) .FILL SLACK + #ENDIF #ENDIF ; .END diff --git a/Source/HBIOS/hbios.inc b/Source/HBIOS/hbios.inc index 498d51c7..cd25559a 100644 --- a/Source/HBIOS/hbios.inc +++ b/Source/HBIOS/hbios.inc @@ -108,10 +108,12 @@ BF_SYSGET_BOOTINFO .EQU $E0 ; GET BOOT INFORMATION BF_SYSGET_CPUINFO .EQU $F0 ; GET CPU INFORMATION BF_SYSGET_MEMINFO .EQU $F1 ; GET MEMORY CAPACTITY INFO BF_SYSGET_BNKINFO .EQU $F2 ; GET BANK ASSIGNMENT INFO +BF_SYSGET_CPUSPD .EQU $F3 ; GET CLOCK SPEED & WAIT STATES ; BF_SYSSET_TIMER .EQU $D0 ; SET TIMER VALUE BF_SYSSET_SECS .EQU $D1 ; SET SECONDS VALUE BF_SYSSET_BOOTINFO .EQU $E0 ; SET BOOT INFORMATION +BF_SYSSET_CPUSPD .EQU $F3 ; SET CLOCK SPEED & WAIT STATES ; BF_SYSINT_INFO .EQU $00 ; GET INTERRUPT SYSTEM INFO BF_SYSINT_GET .EQU $10 ; GET INT VECTOR ADDRESS @@ -119,6 +121,22 @@ BF_SYSINT_SET .EQU $20 ; SET INT VECTOR ADDRESS ; CIO_CONSOLE .EQU $80 ; CIO UNIT NUM FOR CUR CON ; +; PRIMARY HARDWARE PLATFORMS +; +PLT_SBC .EQU 1 ; SBC ECB Z80 SBC +PLT_ZETA .EQU 2 ; ZETA Z80 SBC +PLT_ZETA2 .EQU 3 ; ZETA Z80 V2 SBC +PLT_N8 .EQU 4 ; N8 (HOME COMPUTER) Z180 SBC +PLT_MK4 .EQU 5 ; MARK IV +PLT_UNA .EQU 6 ; UNA BIOS +PLT_RCZ80 .EQU 7 ; RC2014 W/ Z80 +PLT_RCZ180 .EQU 8 ; RC2014 W/ Z180 +PLT_EZZ80 .EQU 9 ; EASY Z80 +PLT_SCZ180 .EQU 10 ; SCZ180 +PLT_DYNO .EQU 11 ; DYNO MICRO-ATX MOTHERBOARD +PLT_RCZ280 .EQU 12 ; RC2014 W/ Z280 +PLT_MBC .EQU 13 ; MULTI BOARD COMPUTER +; ; HBIOS GLOBAL ERROR RETURN VALUES ; ERR_NONE .EQU 0 ; SUCCESS diff --git a/Source/HBIOS/pio.asm b/Source/HBIOS/pio.asm index f198f25a..90a27864 100644 --- a/Source/HBIOS/pio.asm +++ b/Source/HBIOS/pio.asm @@ -1,776 +1,254 @@ -; PIO driver sets up the parallel port as a subtype of Serial/Char device. ; +;================================================================================================== +; PIO DRIVER (SERIAL PORT) +;================================================================================================== ; -; HBIOS initializes driver by: +; SETUP PARAMETER WORD: +; +-------+---+-------------------+ +---+---+-----------+---+-------+ +; | |RTS| ENCODED BAUD RATE | |DTR|XON| PARITY |STP| 8/7/6 | +; +-------+---+---+---------------+ ----+---+-----------+---+-------+ +; F E D C B A 9 8 7 6 5 4 3 2 1 0 +; -- MSB (D REGISTER) -- -- LSB (E REGISTER) -- ; -; 1) Calling Pre-initialization +; THIS DRIVER IS JUST A STUB TO DETECT AND INITIALIZE PIO HARDWARE +; IF IT EXISTS. FOR NOW, IT DOES NOT REGISTER ANY OF THE PIO CHANNELS +; AS CHARCTER DEVICE UNITS. ; -; This involves setting up all the data structures describing the devices. -; If possible, do a hardware test to verify it is available for adding to available devices. -; -; 2) Calling device initialization. -; -; Hardware initialization. -; Configure to initial state or to a new state. -; -; Implementation limitations: -; -; The fully functionality of the Z80 PIO can only be realized by using Z80 interrupt mode 2. -; Registers cannot be interrogated for interrupts status and the originating interrupt -; device cannot be determine. -; -; Full implementation of IM2 functionality for an ECB-ZP and ECB-4P board would require the -; allocation of an interrupt handler for each chip channel. Thus, 12 interrupt handlers -; would be required to support this configuration. As the HBIOS only has an allocation of -; 16, a full implmentation is impractical. -; -; The compromise solution is to allow 4 interrupts for the PIO driver. All remaining PIO's -; are limited to Bit mode or blind read and write to the input/output ports. -; -; Zilog PIO reset state: -; -; Both port mask registers are reset to inhibit All port data bits. -; Port data bus lines are set to a high-impedance state and the Ready "handshake" -; Mode 1 (output) is automatically selected. -; The vector address registers are not reset. -; Both port interrupt enable flip-flops are reset. -; Both port output registers are reset. -; -; Register addressing example for ECB-ZP and ECB-4P assuming base address 90h and 88h respectively. +PIO_NONE .EQU 0 +PIO_PIO .EQU 1 ; -; PIO ----ZP---- ----4P---- -; 0 DATA 0 90h DATA 0 B8h -; 0 DATA 1 91h DATA 1 B9h -; 0 CMD 0 92h CMD 0 BAh -; 0 CMD 1 93h CMD 1 BBh -; 1 DATA 0 94h DATA 0 BCh -; 1 DATA 1 95h DATA 1 BDh -; 1 CMD 0 96h CMD 0 BEh -; 1 CMD 1 97h CMD 1 BFh -; 2 DATA 0 C0h -; 2 DATA 1 C1h -; 2 CMD 0 C2h -; 2 CMD 1 C3h -; 3 DATA 0 C4h -; 3 DATA 1 C5h -; 3 CMD 0 C6h -; 3 CMD 1 C7h +PIO0A_CTL .EQU PIO0BASE + $02 +PIO0A_DAT .EQU PIO0BASE + $00 +PIO0B_CTL .EQU PIO0BASE + $03 +PIO0B_DAT .EQU PIO0BASE + $01 ; -PIODEBUG .EQU 1 +#IF (PIOCNT >= 2) ; -M_Output .EQU $00 << 6 -M_Input .EQU $01 << 6 -M_Bidir .EQU $02 << 6 -M_BitCtrl .EQU $03 << 6 -M_BitAllIn .EQU $FF -M_BitAllOut .EQU $00 +PIO1A_CTL .EQU PIO1BASE + $02 +PIO1A_DAT .EQU PIO1BASE + $00 +PIO1B_CTL .EQU PIO1BASE + $03 +PIO1B_DAT .EQU PIO1BASE + $01 ; -PIO_NONE .EQU 0 -PIO_ZPIO .EQU 1 -PIO_8255 .EQU 2 -PIO_PORT .EQU 3 - -; SET MAXIMUM NUMBER OF INTERRUPTS AVAILABLE FOR ALL -; ENSURE INTERRUPTS ARE NOT TURNED ON IF IM2 IS NOT SET. - -INT_ALLOC .DB 0 -INT_N .EQU 00000000B -#IF (INTMODE == 2) -INT_Y .EQU 00000100B -INT_ALLOW .EQU 4 -#ELSE -INT_Y .EQU INT_N -INT_ALLOW .EQU 0 #ENDIF ; -INT0 .EQU 00000000B -INT1 .EQU 00000001B -INT2 .EQU 00000010B -INT3 .EQU 00000011B - +PIO_PREINIT: ; ; SETUP THE DISPATCH TABLE ENTRIES +; NOTE: INTS WILL BE DISABLED WHEN PREINIT IS CALLED AND THEY MUST REMIAIN +; DISABLED. ; -; PIO_CNT HOLDS THE NUMBER OF DEVICED CALCULATED FROM THE NUMBER OF DEFPIO MACROS -; PIO_CNT SHOULD INCREASE BY 2 FOR EVERY PIO CHIP ADDED. + CALL PIO_PROBE ; PROBE FOR CHIPS ; -; PIO_PREINIT WILL READ THROUGH ALL PIOCFG TABLES AND CONFIGURE EACH TABLE. -; IT WITH THEN CALL PIO_INITUNIT TO INITIALIZE EACH DEVICE TO ITS DEFAULT STATE -; -; EXPECTS NOTHING ON ENTRY -; -PIO_PREINIT: - CALL NEWLINE ;D - LD B,PIO_CNT ; LOOP CONTROL - LD C,0 ; PHYSICAL UNIT INDEX + LD B,PIO_CFGCNT ; LOOP CONTROL XOR A ; ZERO TO ACCUM -; LD (PIO_DEV),A ; CURRENT DEVICE NUMBER - LD (INT_ALLOC),A ; START WITH NO INTERRUPTS ALLOCATED + LD (PIO_DEV),A ; CURRENT DEVICE NUMBER + LD IY,PIO_CFG ; POINT TO START OF CFG TABLE PIO_PREINIT0: PUSH BC ; SAVE LOOP CONTROL -; LD A,C ; INITIALIZE THE UNIT - -; PUSH AF ;D -; LD A,'u' ;D -; CALL COUT ;D -; POP AF ;D -; CALL PRTHEXBYTE ;D UNIT -; CALL PC_SPACE ;D - -; RLCA ; MULTIPLY BY CFG TABLE ENTRY SIZE (32 BYTES) -; RLCA ; ... -; RLCA ; ... TO GET OFFSET INTO CFG TABLE -; RLCA -;; RLCA -; LD HL,PIO_CFG ; POINT TO START OF CFG TABLE -; PUSH AF -; CALL ADDHLA ; HL := ENTRY ADDRESS -; POP AF -; CALL ADDHLA ; HL := ENTRY ADDRESS -; PUSH HL ; SAVE IT -; POP IY ; ... TO IY - - CALL IDXCFG - - LD (HL),C - - PUSH AF ;D - LD A,'c' ;D - CALL COUT ;D - POP AF ;D - PUSH BC ;D - PUSH HL ;D - POP BC ;D - CALL PRTHEXWORD ;D CONFIG TABLE - CALL PC_SPACE ;D - POP BC ;D - + CALL PIO_INITUNIT ; HAND OFF TO GENERIC INIT CODE + POP BC ; RESTORE LOOP CONTROL +; LD A,(IY+1) ; GET THE PIO TYPE DETECTED - CP PIO_PORT ; SET FLAGS - - PUSH AF ;D - LD A,'t' ;D - CALL COUT ;D - POP AF ;D - CALL PRTHEXBYTE ;D TYPE - CALL PC_SPACE ;D - -; JR Z,BADINIT - -; PUSH BC ; SAVE LOOP CONTROL -; LD BC,PIO_FNTBL ; BC := FUNCTION TABLE ADDRESS -; DEC A -; JR Z,TYPFND ; SKIP IT IF NOTHING FOUND -; LD BC,PPI_FNTBL ; BC := FUNCTION TABLE ADDRESS -; DEC A -; JR Z,TYPFND ; ADD ENTRY IF PIO FOUND, BC:DE -; LD BC,PRT_FNTBL -; DEC A -; JR Z,TYPFND -; POP BC -; JR BADINIT - - PUSH HL - LD DE,-1 ; INITIALIZE THIS DEVICE WITH - CALL PIO_INITDEV ; DEFAULT VALUES - POP HL - -; JR NZ,SKPINIT - - ; AT THIS POINT WE KNOW WE - ; HAVE A VALID DEVICE SO ADD IT - - LD A,8 ; CALCULATE THE FUNCTION TABLE - CALL ADDHLA ; POSITION WHICH FOLLOWS THE - PUSH HL ; CONFIGURATION TABLE OF EACH - POP BC ; DEVICE - -TYPFND: PUSH AF ;D - LD A,'f' ;D - CALL COUT ;D - POP AF ;D - PUSH BC ;D - CALL PRTHEXWORD ;D FUNCTION TABLE - POP BC ;D - CALL NEWLINE ;D - - PUSH IY ; ADD ENTRY IF PIO FOUND, BC:DE - POP DE ; BC: DRIVER FUNCTION TABLE - CALL CIO_ADDENT ; DE: ADDRESS OF UNIT INSTANCE DATA - -BADINIT:POP BC ; RESTORE LOOP CONTROL - - INC C ; NEXT PHYSICAL UNIT -SKPINIT:DJNZ PIO_PREINIT0 ; LOOP UNTIL DONE - - PUSH AF ;D - PRTS("INTS=$") ;D - LD A,(INT_ALLOC) ;D - CALL PRTHEXBYTE ;D - POP AF ;D - PUSH DE ;D - LD DE,CIO_TBL-3 ;D - CALL DUMP_BUFFER ;D - POP DE ;D + OR A ; SET FLAGS + JR Z,PIO_PREINIT2 ; SKIP IT IF NOTHING FOUND +; + PUSH BC ; SAVE LOOP CONTROL + PUSH IY ; CFG ENTRY ADDRESS + POP DE ; ... TO DE + LD BC,PIO_FNTBL ; BC := FUNCTION TABLE ADDRESS + ; REGISTRATION OF CHARACTER UNIT IN HBIOS IS BYPASSED + ; FOR NOW. NOT SURE WHAT TO DO WITH THIS HARDWARE YET. + ;CALL NZ,CIO_ADDENT ; ADD ENTRY IF PIO FOUND, BC:DE + POP BC ; RESTORE LOOP CONTROL +; +PIO_PREINIT2: + LD DE,PIO_CFGSIZ ; SIZE OF CFG ENTRY + ADD IY,DE ; BUMP IY TO NEXT ENTRY + DJNZ PIO_PREINIT0 ; LOOP UNTIL DONE +; XOR A ; SIGNAL SUCCESS RET ; AND RETURN ; -; INDEX INTO THE CONFIG TABLE -; ON ENTRY C = UNIT NUMBER -; ON EXIT IY = CONFIG DATA POINTER -; ON EXIT DE = CONFIG TABLE START -; -; EACH CONFIG TABLE IS 24 BYTES LONG -; -CFG_SIZ .EQU 24 -; -IDXCFG: LD A,C - RLCA ; X 2 - RLCA ; X 4 - RLCA ; X 8 - LD H,0 - LD L,A ; HL = X 8 - PUSH HL - ADD HL,HL ; HL = X 16 - POP DE - ADD HL,DE ; HL = X 24 - LD DE,PIO_CFG - ADD HL,DE - PUSH HL ; COPY CFG DATA PTR - POP IY ; ... TO IY - RET - -; PIO_INITDEV - INITIALIZE DEVICE +; PIO INITIALIZATION ROUTINE ; -; IF DE = FFFF THEN THE SETUP PARAMETER WORD WILL BE READ FROM THE DEVICE CONFIGURATION -; TABLE POINTED TO BY IY AND THE PIO PORT WILL BE PROGRAMMED BASED ON THAT CONFIGURATION. +PIO_INITUNIT: + CALL PIO_DETECT ; DETERMINE PIO TYPE + LD (IY+1),A ; SAVE IN CONFIG TABLE + OR A ; SET FLAGS + RET Z ; ABORT IF NOTHING THERE ; -; OTHERWISE THE PIO PORT WILL BE PROGRAMMED BY THE SETUP PARAMETER WORD IN DE AND THIS -; WILL BE SAVED IN THE DEVICE CONFIGURATION TABLE POINTED TO BY IY. + ; UPDATE WORKING PIO DEVICE NUM + LD HL,PIO_DEV ; POINT TO CURRENT UART DEVICE NUM + LD A,(HL) ; PUT IN ACCUM + INC (HL) ; INCREMENT IT (FOR NEXT LOOP) + LD (IY),A ; UPDATE UNIT NUM +; + ; SET DEFAULT CONFIG + LD DE,-1 ; LEAVE CONFIG ALONE + ; CALL INITDEVX TO IMPLEMENT CONFIG, BUT NOTE THAT WE CALL + ; THE INITDEVX ENTRY POINT THAT DOES NOT ENABLE/DISABLE INTS! + JP PIO_INITDEVX ; IMPLEMENT IT AND RETURN ; -; ALL OTHER CONFIGURATION OF THE DEVICE CONFIGURATION TABLE IS DONE UPSTEAM BY PIO_PREINIT - -PIO_INITDEV: - ; TEST FOR -1 (FFFF) WHICH MEANS USE CURRENT CONFIG (JUST REINIT) - LD A,D ; TEST DE FOR - AND E ; ... VALUE OF -1 - INC A ; ... SO Z SET IF -1 - JR NZ,PIO_INITDEV1 ; IF DE == -1, REINIT CURRENT CONFIG -PIO_INITDEV0: - ; LOAD EXISTING CONFIG (DCW) TO REINIT - LD E,(IY+4) ; LOW BYTE - LD D,(IY+5) ; HIGH BYTE -; -PIO_INITDEV1: ; WHICH DEVICE TYPE? - LD A,(IY+1) - CP PIO_ZPIO - JR Z,SETPIO0 - CP PIO_8255 - JP Z,SET_8255 - CP PIO_PORT - JP Z,SET_PORT -BAD_SET:OR $FF ; UNKNOWN DEVICE - RET - -SETPIO0:LD A,E ; GET MODE - AND 11000000B ; BITS (B7B6) - CP 10000000B ; IS IT BIDIR? - JR NZ,SETPIO1 - LD A,(IY+2) ; GET CHANNEL - OR A - JR NZ,BAD_SET ; CAN'T DO ON CH1 - - ; VALIDATE INTERRUPT REQUEST - ; GRANT INTERRUPT IF THERE IS A FREE INTERRUPT - ; GRANT INTERRUPT IF AN INTERRUPT IS ALREADY ALLOCATED TO THIS UNIT - -SETPIO1:PUSH AF ;D - LD A,'[' ;D - CALL COUT ;D - LD A,(IY) ;D - CALL PRTHEXBYTE ;D - LD A,']' ;D - CALL COUT ;D - POP AF ;D - - BIT 2,E ; SKIP IF WE ARE NOT REQUESTING - JP Z,SETPIO2 ; AN INTERRUPT - - PRTS("[INTREQ]$") ;D - -; LD A,(IY+4) ; GET CURRENT INTERRUPT SETTING -; BIT 2,A ; SKIP IF IT IS ALREADY -; JP NZ,SETPIO2 ; ALLOCATED TO THIS UNIT - - LD A,(INT_ALLOC) ; WE NEED TO ALLOCATE AN - CP INT_ALLOW ; INTERRUPT. DO WE HAVE - JR NC,BAD_SET ; ONE FREE? - - PRTS("[ALLOCINT]$") ;D - - ; WHICH INTERRUPT IS FREE ? - ; SCAN THROUGH THE CFG TABLES - ; AND FIND A FREE ONE - - PUSH AF ; NESTED LOOP - LD DE,CFG_SIZ ; OUTSIDE LOOP IS INTERRUPT - LD B,INT_ALLOW ; INSIDE LOOP IS DEVICE -SETPIOP: LD C,B - DEC C - PUSH BC - LD B,PIO_CNT - LD HL,PIO_CFG+4 -SETPIOX: LD A,(HL) - BIT 2,A ; JUMP TO NEXT DEVICE - JR Z,SETPIOY ; IF NO INTERRUPT ON - AND 00000011B ; THIS DEVICE - - CP C ; IF WE MATCH AN INTERRUPT HERE THEN IT IS NOT FREE. - JR NZ,SETPIOY ; SO EXIT INSIDE LOOP AND TRY NEXT INTERRUPT - - XOR A ; WE MATCH INT 0 - IF WE ARE CHECKING FOR IT THEN - OR C ; WE REGARD IS AS FREE. - JR NZ,SETPIOZ - -SETPIOY: ADD HL,DE - DJNZ SETPIOX - - JR SETPIOQ ; WE GET HERE IF THE CURRENT INTERRUPT - ; WAS NOT MATCHED SO IT IS FREE -SETPIOZ: POP BC - DJNZ SETPIOP - POP AF - - PRTS("[NONEFREE]$") - RET - -SETPIOQ:PUSH AF ; AVAILABLE INTERRUPT IS IN C - PRTS("[FREE]=$") - LD A,C - CALL PRTHEXBYTE - POP AF - - POP AF - POP AF - -SETPIOR:LD HL,INT_ALLOC ; INCREASE THE COUNT - INC (HL) ; OF USED INTERRUPTS - LD A,(HL) - -; LD A,(IY) ; IS THIS UNIT -; INC A ; UNITIALIZED? -; JR Z,SETPIO6 - - LD A,(IY+4) ; IT IS UNITIALIZED SO - OR C ; SAVE THE ALLOCATES - LD (IY+4),A ; INTERRUPT -; -; FOR THIS DEVICE AND INTERRUPT, UPDATE THE CONFIG TABLE FOR THIS DEVICE. -; PIO_IN, PIO_OUT, PIO_IST, PIO_OST ENTRIES NEED TO BE REDIRECTED. -; INTERRUPT VECTOR NEEDS TO BE UPDATED -; - LD A,(IY+0) - LD HL,0 - ; SETUP PIO INTERRUPT VECTOR IN IVT - LD HL,HBX_IV09+1 - -; CALL SPK_BEEP ; -SETPIO6:RET - - ; EXIT WITH FREE INTERRUPT IN C - - LD A,C - LD (INT_ALLOC),A - - LD A,E - AND 11000000B - OR 00000100B - OR C - LD E,A - LD (IY+5),A ; - ; TODO: DEALLOCATE AN INTERRUPT +PIO_INIT: + LD B,PIO_CFGCNT ; COUNT OF POSSIBLE PIO UNITS + LD IY,PIO_CFG ; POINT TO START OF CFG TABLE +PIO_INIT1: + PUSH BC ; SAVE LOOP CONTROL + LD A,(IY+1) ; GET PIO TYPE + OR A ; SET FLAGS + CALL NZ,PIO_PRTCFG ; PRINT IF NOT ZERO + POP BC ; RESTORE LOOP CONTROL + LD DE,PIO_CFGSIZ ; SIZE OF CFG ENTRY + ADD IY,DE ; BUMP IY TO NEXT ENTRY + DJNZ PIO_INIT1 ; LOOP TILL DONE ; -; LD A,(INT_ALLOC) -; DEC A -; LD (INT_ALLOC),A + XOR A ; SIGNAL SUCCESS + RET ; DONE ; -SETPIO2: - -; DE CONTAINS THE MODE IF INTERRUPT ROUTINE SKIPPED - - PRTS("[NOINTREQ]$") ;D - -; LD A,(IY+4) - LD A,E ; GET MODE AND CREATE COMMAND - AND 11000000B ; $B0 - OR 00001111B ; $0F - - LD C,(IY+3) ; GET DATA PORT - INC C ; POINT TO CMD - INC C ; PORT - OUT (C),A ; SET MODE - CP (M_BitCtrl | $0F) ; IF MODE 3 - JR NZ,SETPIO3 - LD A,(IY+5) ; SET I/O DIRECTION - OUT (C),A ; FOR MODE 3 - -SETPIO3:; INTERUPT HANDLING - - JP SETPIO4 - - ; SETUP THE INTERRUPT VECTOR - - LD A,E - AND 00000011B -; DEC A ; INDEX INTO THE - ADD A,A ; THE VECTOR TABLE - ADD A,A ; - LD C,A - LD B,0 - LD HL,HBX_IV09+1 - ADD HL,BC ; GET THE ADDRESS OF - PUSH DE - LD D,(HL) ; THAT INTERRUPT - INC HL ; HANDLER - LD E,(HL) - LD HL,0 ;HBX_IVT+IVT_PIO0 ; POPULATE THE - LD A,L ; GET LOW BYTE OF IVT ADDRESS - ADD HL,BC ; INTERRUPT TABLE - LD (HL),D ; WITH THE INTERRUPT - INC HL ; HANDLER ADDRESS FOR - LD (HL),E ; THIS UNIT - POP DE - LD HL,INT_ALLOC - LD C,(HL) - LD B,0 - LD HL,PRTTAB-1 ; SAVE THE DATA - ADD HL,BC ; PORT FOR EACH INTERRUPT - LD C,(IY+3) - LD (HL),C - - INC C ; POINT TO CMD PORT - INC C - DI ; SET THE VECTOR ADDRESS - OUT (C),A - -; LD A,10000011B ; ENABLE INTERRUPTS ON - OUT (C),A ; THIS UNIT - EI -; JR GUD_SET +; DRIVER FUNCTION TABLE +; +PIO_FNTBL: + .DW PIO_IN + .DW PIO_OUT + .DW PIO_IST + .DW PIO_OST + .DW PIO_INITDEV + .DW PIO_QUERY + .DW PIO_DEVICE +#IF (($ - PIO_FNTBL) != (CIO_FNCNT * 2)) + .ECHO "*** INVALID PIO FUNCTION TABLE ***\n" +#ENDIF ; -SETPIO4:LD A,00000111B ; $07 - OUT (C),A ; NO INTERRUPTS ; -; SUCCESSFULL SO SAVE DEVICE CONFIGURATION WORD (DCW) ; -GUD_SET:LD (IY+4),E ; LOW BYTE - LD (IY+5),D ; HIGH BYTE +PIO_IN: + LD E,0 ; DUMMY VALUE + XOR A ; SIGNAL SUCCESS + RET ; -; UPDATE THE DEVICE TABLE WITH THE ADDRESSES FOR THE CORRECT ROUTINE. ; - LD A,E - AND 00000111B - LD HL,INTMATRIX ; POINT TO EITHER THE INTERRUPT - JR NZ, USEIM - LD HL,POLMATRIX ; MATRIX OR THE POLLED MATRIX -USEIM: PUSH HL - - PUSH IY ; CALCULATE THE DESTINATION - POP HL ; ADDRESS IN THE PIO_CFG TABLE - LD BC,8 ; FOR THE FOUR ADDESSES TO BE - ADD HL,BC ; COPIED TO - -; LD B,0 ; 00000000 CALCULATE THE SOURCE ADDRESS - LD C,E ; XX?????? FROM THE MATRIX. EACH ENTRY - SRL C ; 0XX????? IN THE MATRIX IS 8 BYTES SO - SRL C ; 00XX???? SOURCE = MATRIX BASE + (8 * MODE) - SRL C ; 000XX??? - POP DE ; LOAD THE MATRIX BASE -; LD DE,POLMATRIX - EX DE,HL - ADD HL,BC ; HL = SOURCE - - LD C,8 ; COPY 8 BYTES - LDIR - -; PUSH IY -; POP DE -; CALL DUMP_BUFFER - - XOR A - RET - -PRTTAB: .DB 0 - .DB 0 - .DB 0 - .DB 0 -; -;----------------------------------------------------------------------------- -; -; INPUT INTERRUPT VECTOR MACRO AND DEFINITION FOR FOUR PORTS -; -#DEFINE PIOMIVT(PIOIN,PIOIST,PIOPRT) \ -#DEFCONT ;\ -#DEFCONT ; RETURN WITH ERROR IF THERE IS \ -#DEFCONT ; ALREADY A CHARACTER IN BUFFER \ -#DEFCONT ;\ -#DEFCONT ; OTHERWISE CHANGE THE STATUS TO \ -#DEFCONT ; SHOW THERE IS ONE CHARACTER IN \ -#DEFCONT ; THE BUFFER AND READ IT IN AND \ -#DEFCONT ; AND STORE IT.RETURN GOOD STATUS.\ -#DEFCONT ;\ -#DEFCONT \ LD A,(_CIST) -#DEFCONT \ OR A -#DEFCONT \ JR NZ,_OVFL -#DEFCONT \ LD A,(PIOPRT) -#DEFCONT \ LD C,A -#DEFCONT \ LD A,1 -#DEFCONT \ LD (_CIST),A -#DEFCONT \ IN A,(C) -#DEFCONT \ LD (_CICH),A -#DEFCONT \ OR $FF -#DEFCONT \ RET -#DEFCONT \_OVFL:XOR A -#DEFCONT \ RET -#DEFCONT ;\ -#DEFCONT ;\ -#DEFCONT ;\ -#DEFCONT ;\ -#DEFCONT ;\ -#DEFCONT ;\ -#DEFCONT \PIOIN:CALL PIOIST -#DEFCONT \ JR Z,PIOIN -#DEFCONT \ LD A,(_CICH) -#DEFCONT \ LD E,A -#DEFCONT \ XOR A -#DEFCONT \ LD (_CIST),A -#DEFCONT \ RET -#DEFCONT ;\ -#DEFCONT ; If THERE A CHARACTER \ -#DEFCONT ; AVAILABLE? RETURN NUMBER \ -#DEFCONT ; IN A - 0 OR 1 \ -#DEFCONT ;\ -#DEFCONT \PIOIST:LD A,(_CIST) -#DEFCONT \ AND 00000001B -#DEFCONT \ RET -#DEFCONT ;\ -#DEFCONT ; CIST : 01 = CHARACTER READY ELSE NOT READY \ -#DEFCONT ; CISH : CHARACTER STORED BY INTERRUPT \ -#DEFCONT ;\ -#DEFCONT \_CIST .DB 00 -#DEFCONT \_CICH .DB 00 -; -PIOIVT0:.MODULE PIOIVT0 -PIOMIVT(PIO0IN,PI0_IST,PRTTAB+0) -PIOIVT1:.MODULE PIOIVT1 -PIOMIVT(PIO1IN,PI1_IST,PRTTAB+1) -PIOIVT2:.MODULE PIOIVT2 -PIOMIVT(PIO2IN,PI2_IST,PRTTAB+2) -PIOIVT3:.MODULE PIOIVT3 -PIOMIVT(PIO3IN,PI3_IST,PRTTAB+3) -; -;----------------------------------------------------------------------------- -; -; OUTPUT INTERRUPT VECTOR MACRO AND DEFINITION FOR FOUR PORTS -; -; AN INTERRUPT IS GENERATED WHEN THE RECEIVING DEVICE CAN ACCEPT A CHARACTER -; -#DEFINE PIOMOVT(PIOOUT,PIOOST,PIOPRT) \ -#DEFCONT ;\ -#DEFCONT ; RETURN IF WE ARE WAITING FOR A \ -#DEFCONT ; CHARACTER (COST = 00) \ -#DEFCONT ;\ -#DEFCONT ; IF ZERO CHARACTERS READY -#DEFCONT ; (COST = 01) CHANGE STATUS TO \ -#DEFCONT ; WAITING FOR CHARACTER (COST 00) \ -#DEFCONT ;\ -#DEFCONT ; IF A CHARACTER IS READY THEN \ -#DEFCONT ; OUTPUT AND CHANGE STATUS TO \ -#DEFCONT ; ZERO CHARACTERS READY \ -#DEFCONT ;\ -#DEFCONT \ LD A,(_COST) -#DEFCONT \ DEC A -#DEFCONT \ RET M -#DEFCONT \ JR Z,_WFC -#DEFCONT \ LD A,(_COCH) -#DEFCONT \ LD E,A -#DEFCONT \_ONOW:LD A,(PIOPRT) -#DEFCONT \ LD C,A -#DEFCONT \ OUT (C),E -#DEFCONT \ LD A,1 -#DEFCONT \_WFC: LD (_COST),A -#DEFCONT \ RET -#DEFCONT ;\ -#DEFCONT ; WAIT FOR SPACE FOR THE CHARACTER\ -#DEFCONT ; IF WE ARE WAITING FOR A \ -#DEFCONT ; CHARACTRE THEN OUTPUT IT NOW \ -#DEFCONT ; OTHERWISE STORE IT UNTIL THE \ -#DEFCONT ; INTERRUPT CALLS FOR IT \ -#DEFCONT ;\ -#DEFCONT \PIOOUT:LD A,(_COST) -#DEFCONT \ CP 2 -#DEFCONT \ JR C,_ONOW -#DEFCONT \ LD A,E -#DEFCONT \ LD (_COCH),A -#DEFCONT \ LD A,2 -#DEFCONT \ LD (_COST),A -#DEFCONT \ JR PIOOUT -#DEFCONT ;\ -#DEFCONT ; RETURN WITH NUMBER OF \ -#DEFCONT ; CHARACTERS AVAILABLE 0 or 1 \ -#DEFCONT ;\ -#DEFCONT \PIOOST:LD A,(_COST) -#DEFCONT \ DEC A -#DEFCONT \ DEC A -#DEFCONT \ RET Z -#DEFCONT \ LD A,1 -#DEFCONT \ RET -#DEFCONT ;\ -#DEFCONT ; COST : 00 WAITING FOR CHARACTER\ -#DEFCONT ; 01 ZERO CHARACTERS READY\ -#DEFCONT ; 02 ONE CHARACTER READY \ -#DEFCONT ; COCH : CHARACTER TO OUTPUT \ -#DEFCONT ;\ -#DEFCONT \_COST .DB 01 -#DEFCONT \_COCH .DB 00 -; -PIOOVT0:.MODULE PIOOVT0 -PIOMOVT(PIO0OUT,PI0_OST,PRTTAB+0) -PIOOVT1:.MODULE PIOOVT1 -PIOMOVT(PIO1OUT,PI1_OST,PRTTAB+1) -PIOOVT2:.MODULE PIOOVT2 -PIOMOVT(PIO2OUT,PI2_OST,PRTTAB+2) -PIOOVT3:.MODULE PIOOVT3 -PIOMOVT(PIO3OUT,PI3_OST,PRTTAB+3) -; -;----------------------------------------------------------------------------- -; -; NON INTERRUPT OUTPUT ROUTINE - SHARED -; -; INPUT WILL ALWAYS RETURN ERROR, CHARACTER RETURNED IS UNDEFINED. -; OUTPUT WILL ALWAYS RETURN SUCCESS -; INPUT-STATUS WILL ALWAYS RETURN 0 CHARACTERS IN BUFFER. -; OUTPUT-STATUS WILL ALWAYS RETURN 1 CHARACTER SPACE IN BUFFER. - -PIOSHO_IN: - LD A,1 - RET ; -PIOSHO_OUT: - LD C,(IY+3) - OUT (C),E - XOR A +PIO_OUT: + XOR A ; SIGNAL SUCCESS RET ; -PIOSHO_IST: XOR A - RET ; -PIOSH_OST: - LD A,1 - RET ; -;----------------------------------------------------------------------------- +PIO_IST: + XOR A ; NO CHARS WAITING + RET ; -; NON INTERRUPT INPUT ROUTINE - SHARED ; -; INPUT WILL ALWAYS A CHARACTER AND SUCCESS. -; OUTPUT WILL ALWAYS RETURN FAILURE -; INPUT STATUS WILL ALWAYS RETURN 1 CHARACTER IN BUFFER. -;OUTPUT-STATUS WILL ALWAYS RETURN 0 CHARACTER SPACE IN BUFFER. ; -PIOSHI_IN: - LD C,(IY+3) - IN A,(C) - LD E,A - XOR A +PIO_OST: + XOR A ; NO BUFFER SPACE AVAIL RET ; -PIOSHI_OUT: - LD A,1 - RET +; NOTE THAT THERE ARE TWO ENTRY POINTS. INITDEV WILL DISABLE/ENABLE INTS +; AND INITDEVX WILL NOT. THIS IS DONE SO THAT THE PREINIT ROUTINE ABOVE +; CAN AVOID ENABLING/DISABLING INTS. ; -PIOSH_IST: - LD A,1 - RET +PIO_INITDEV: + HB_DI ; DISABLE INTS + CALL PIO_INITDEVX ; DO THE WORK + HB_EI ; INTS BACK ON + RET ; DONE ; -PIOSHI_OST: - XOR A +PIO_INITDEVX: +; +; THIS ENTRY POINT BYPASSES DISABLING/ENABLING INTS WHICH IS REQUIRED BY +; PREINIT ABOVE. PREINIT IS NOT ALLOWED TO ENABLE INTS! +; + LD C,(IY+3) ; CONTROL PORT + LD A,%00010111 ; CLEAR INTERRUPT CTL WORD + OUT (C),A + LD A,%11111111 ; CLEAR MASK + OUT (C),A + LD A,%00000000 ; CLEAR INTERRUPT VECTOR + OUT (C),A + LD A,%01001111 ; SET MODE 1 (INPUT) + OUT (C),A RET ; -;----------------------------------------------------------------------------- ; -; ON ENTRY IY POINTS TO THE DEVICE RECORD. GET AND RETURN THE CONFIGURATION WORD IN DE ; PIO_QUERY: -PPI_QUERY: - LD E,(IY+4) ; FIRST CONFIG BYTE TO E - LD D,(IY+5) ; SECOND CONFIG BYTE TO D + LD E,(IY+5) ; FIRST CONFIG BYTE TO E + LD D,(IY+6) ; SECOND CONFIG BYTE TO D XOR A ; SIGNAL SUCCESS - RET + RET ; DONE ; -;----------------------------------------------------------------------------- ; -; ON ENTRY IY POINTS TO THE DEVICE RECORD. FOR CHARACTER DEVICES BIT 6 OF ATTRIBUTE -; INDICATES PARALLEL PORT IF 1 SO WE SET IT. COMMON TO ALL PORTS ; PIO_DEVICE: -PPI_DEVICE: LD D,CIODEV_PIO ; D := DEVICE TYPE LD E,(IY) ; E := PHYSICAL UNIT - LD C,$40 ; C := ATTRIBUTE - LD H,0 ; H := 0, DRIVER HAS NO MODES + LD C,$40 ; C := DEVICE TYPE, 0x40 IS PIO + LD H,(IY+1) ; H := MODE LD L,(IY+3) ; L := BASE I/O ADDRESS XOR A ; SIGNAL SUCCESS RET ; -INTMATRIX: - .DW PIO0IN, PIO0OUT, PI0_IST, PI0_OST - .DW PIO1IN, PIO1OUT, PI1_IST, PI1_OST - .DW PIO2IN, PIO2OUT, PI2_IST, PI2_OST - .DW PIO3IN, PIO3OUT, PI3_IST, PI3_OST -POLMATRIX: - .DW PIOSHO_IN, PIOSHO_OUT, PIOSHO_IST, PIOSH_OST ; OUTPUT - .DW PIOSHI_IN, PIOSHI_OUT, PIOSH_IST, PIOSHI_OST ; INPUT - .DW 0,0,0,0 ; BIDIR - .DW 0,0,0,0 ; BIT MODE - -SET_8255: - RET +; PIO CHIP PROBE +; CHECK FOR PRESENCE OF PIO CHIPS AND POPULATE THE +; PIO_MAP BITMAP (ONE BIT PER CHIP). THIS DETECTS +; CHIPS, NOT CHANNELS. EACH CHIP HAS 2 CHANNELS. +; MAX OF TWO CHIPS CURRENTLY. INT VEC VALUE IS TRASHED! +; +PIO_PROBE: + ; CLEAR THE PRESENCE BITMAP + LD HL,PIO_MAP ; HL POINTS TO BITMAP + XOR A ; ZERO + LD (PIO_MAP),A ; CLEAR CHIP PRESENT BITMAP +; + ; FIRST POSSIBLE CHIP + LD C,PIO0A_CTL ; FIRST CHIP CMD/STAT PORT + CALL PIO_PROBECHIP ; PROBE IT + JR NZ,PIO_PROBE1 ; IF NOT ZERO, NOT FOUND + SET 0,(HL) ; SET BIT FOR FIRST CARD +PIO_PROBE1: +; +#IF (PIOCNT >= 2) + LD C,PIO1A_CTL ; SECOND CHIP CMD/STAT PORT + CALL PIO_PROBECHIP ; PROBE IT + JR NZ,PIO_PROBE2 ; IF NOT ZERO, NOT FOUND + SET 1,(HL) ; SET BIT FOR SECOND CARD +PIO_PROBE2: +#ENDIF ; -SET_BYE: - XOR A ; SIGNAL SUCCESS RET ; -; ------------------------------------ -; i8255 FUNCTION TABLE ROUTINES -;------------------------------------- - -PPI_IN: - XOR A ; SIGNAL SUCCESS - RET -; -PPI_OUT: - XOR A ; SIGNAL SUCCESS - RET -; -PPI_IST: - RET -; -PPI_OST: +PIO_PROBECHIP: + ; PIO IS HRD TO DETECT DEFINITIVELY. BEST I CAN THINK + ; OF IS TO CHECK THE VALUE READ FROM THE CONTROL PORT. + ; IT APPEARS TO BE ZERO CONSISTENTLY IF CHIP EXISTS. + IN A,(C) ; GET VALUE + OR A ; COMPARE TO ZERO RET ; -; PIO_INITDEV - Configure device. -; If DE = FFFF then extract the configuration information from the table of devices and program the device using those settings. -; Otherwise use the configuration information in DE to program those settings and save them in the device table - -PPI_INITDEV: - XOR A ; SIGNAL SUCCESS - RET -PPI_INT:OR $FF ; NZ SET TO INDICATE INT HANDLED - RET -; +; PIO DETECTION ROUTINE +; THERE IS ONLY ONE VARIATION OF PIO CHIP, SO HERE WE JUST CHECK THE +; CHIP PRESENCE BITMAP TO SET THE CHIP TYPE OF EITHER NONE OR PIO. +; +PIO_DETECT: + LD B,(IY+2) ; GET CHIP/CHANNEL + SRL B ; SHIFT AWAY THE CHANNEL BIT + INC B ; NUMBER OF TIMES TO ROTATE BITS + LD A,(PIO_MAP) ; BIT MAP IN A +PIO_DETECT1: + ; ROTATE DESIRED CHIP BIT INTO CF + RRA ; ROTATE NEXT BIT INTO CF + DJNZ PIO_DETECT1 ; DO THIS UNTIL WE HAVE DESIRED BIT + ; RETURN CHIP TYPE + LD A,PIO_NONE ; ASSUME NOTHING HERE + RET NC ; IF CF NOT SET, RETURN + LD A,PIO_PIO ; CHIP TYPE IS PIO + RET ; DONE +; +; +; PIO_PRTCFG: ; ANNOUNCE PORT CALL NEWLINE ; FORMATTING @@ -780,220 +258,90 @@ PIO_PRTCFG: PRTS(": IO=0x$") ; FORMATTING LD A,(IY+3) ; GET BASE PORT CALL PRTHEXBYTE ; PRINT BASE PORT -; + ; PRINT THE PIO TYPE CALL PC_SPACE ; FORMATTING LD A,(IY+1) ; GET PIO TYPE BYTE - LD DE,PIO_TYPE_STR ; POINT HL TO TYPE MAP TABLE - CALL PRTIDXDEA - - ; ALL DONE IF NO PIO WAS DETECTED - LD A,(IY+1) ; GET PIO TYPE BYTE - OR A ; SET FLAGS - RET Z ; IF ZERO, NOT PRESENT -; - PRTS(" MODE=$") ; FORMATTING - LD E,(IY+4) ; LOAD CONFIG - LD D,(IY+5) ; ... WORD TO DE - CALL PS_PRTPC0 ; PRINT CONFIG -; - LD A,(IY+4) ; PRINT - BIT 2,A ; ALLOCATED - JR Z,NOINT ; INTERRUPT - PRTS("/i$") - LD A,(IY+4) - AND 00000011B - CALL PRTDECB -NOINT: XOR A + RLCA ; MAKE IT A WORD OFFSET + LD HL,PIO_TYPE_MAP ; POINT HL TO TYPE MAP TABLE + CALL ADDHLA ; HL := ENTRY + LD E,(HL) ; DEREFERENCE + INC HL ; ... + LD D,(HL) ; ... TO GET STRING POINTER + CALL WRITESTR ; PRINT IT +; + XOR A RET ; -; WORKING VARIABLES ; -PIO_DEV .DB 0 ; DEVICE NUM USED DURING INIT -; -; DESCRIPTION OF DIFFERENT PORT TYPES -; -PIO_TYPE_STR: - .TEXT "$" ; IDX 0 - .TEXT "Zilog PIO$" ; IDX 1 - .TEXT "i8255 PPI$" ; IDX 2 - .TEXT "IO Port$" ; IDX 3 -; -; Z80 PIO PORT TABLE - EACH ENTRY IS FOR 1 CHIP I.E. TWO PORTS -; -; 32 BYTE DATA STRUCTURE FOR EACH PORT -; -; .DB 0 ; IY+0 CIO DEVICE NUMBER (SET DURING PRE-INIT, THEN FIXED) -; .DB 0 ; IY+1 PIO TYPE (SET AT ASSEMBLY, FIXED) -; .DB 0 ; IY+2 PIO CHANNEL (SET AT ASSEMBLY, FIXED) -; .DB PIOBASE+2 ; IY+3 BASE DATA PORT (SET AT ASSEMBLY, FIXED) -; .DB 0 ; IY+4 SPW - MODE 3 I/O DIRECTION BYTE (SET AT ASSEMBLE, SET WITH INIT) -; .DB 0 ; IY+5 SPW - MODE, INTERRUPT (SET AT ASSEMBLY, SET WITH INIT) -; .DW 0 ; IY+6/7 FUNCTION TABLE (SET AT ASSEMBLY, SET DURING PRE-INIT AND AT INIT) -; .DW PIO_IN ; IY+8 ADDR FOR DEVICE INPUT (SET WITH INIT) -; .DW PIO_OUT ; IY+10 ADDR FOR DEVICE OUTPUT (SET WITH INIT) -; .DW PIO_IST ; IY+12 ADDR FOR DEVICE INPUT STATUS (SET WITH INIT) -; .DW PIO_OST ; IY+14 ADDR FOR DEVICE OUTPUT STATUS (SET WITH INIT) -; .DW PIO_INITDEV ; IY+16 ADDR FOR INITIALIZE DEVICE ROUTINE (SET AT ASSEMBLY, FIXED) -; .DW PIO_QUERY ; IY+18 ADDR FOR QUERY DEVICE RECORD ROUTINE (SET AT ASSEMBLY, FIXED) -; .DW PIO_DEVICE ; IY+20 ADDR FOR DEVICE TYPE ROUTINE (SET AT ASSEMBLY, FIXED) -; .FILL 10 -; -; SETUP PARAMETER WORD: -; -; +-------------------------------+ +-------+-----------+---+-------+ -; | BIT CONTROL | | MODE | | A | INT | -; +-------------------------------+ --------------------+-----------+ -; F E D C B A 9 8 7 6 5 4 3 2 1 0 -; -- MSB (D REGISTER) -- -- LSB (E REGISTER) -- -; -; -; MSB = BIT CONTROL MAP USE IN MODE 3 -; -; MODE B7 B6 = 00 Mode 0 Output -; 01 Mode 1 Input -; 10 Mode 2 Bidir -; 11 Mode 3 Bit Mode -; -; INTERRUPT ALLOCATED B2 = 0 NOT ALLOCATED -; = 1 IS ALLOCATED -; -; WHICH IVT IS ALLOCATES B1 B0 00 IVT_PIO0 -; 01 IVT_PIO1 -; 10 IVT_PIO2 -; 11 IVT_PIO3 -; -#DEFINE DEFPIO(MPIOBASE,MPIOCH0,MPIOCH1,MPIOCH0X,MPIOCH1X,MPIOIN0,MPIOIN1) \ -#DEFCONT \ .DB 0 -#DEFCONT \ .DB PIO_ZPIO -#DEFCONT \ .DB 0 -#DEFCONT \ .DB MPIOBASE -#DEFCONT \ .DB (MPIOCH0|MPIOIN0) -#DEFCONT \ .DB MPIOCH0X -#DEFCONT \ .DW 0 -#DEFCONT \ .DW 0,0,0,0, PIO_INITDEV,PIO_QUERY,PIO_DEVICE -#DEFCONT \ .FILL 2 -#DEFCONT \ .DB 0 -#DEFCONT \ .DB PIO_ZPIO -#DEFCONT \ .DB 1 -#DEFCONT \ .DB MPIOBASE+1 -#DEFCONT \ .DB (MPIOCH1|MPIOIN1) -#DEFCONT \ .DB MPIOCH1X -#DEFCONT \ .DW 0 -#DEFCONT \ .DW 0,0,0,0, PIO_INITDEV,PIO_QUERY,PIO_DEVICE -#DEFCONT \ .FILL 2 -; -; i8255 PORT TABLE - EACH ENTRY IS FOR 1 CHIP I.E. THREE PORTS -; -#DEFINE DEFPPI(MPPIBASE,MPPICH1,MPPICH2,MPPICH3,MPPICH1X,MPPICH2X,MPPICH3X) \ -#DEFCONT \ .DB 0 -#DEFCONT \ .DB PIO_8255 -#DEFCONT \ .DB 0 -#DEFCONT \ .DB MPPIBASE -#DEFCONT \ .DB (MPPICH1|00001000B) -#DEFCONT \ .DB MPPICH1X -#DEFCONT \ .DW 0 -#DEFCONT \ .DW PPI_IN,PPI_OUT,PPI_IST,PPI_OST,PPI_INITDEV,PPI_QUERY,PPI_DEVICE -#DEFCONT \ .FILL 2 -#DEFCONT \ .DB 0 -#DEFCONT \ .DB PIO_8255 -#DEFCONT \ .DB 1 -#DEFCONT \ .DB MPPIBASE+2 -#DEFCONT \ .DB (MPPICH2|00010000B) -#DEFCONT \ .DB MPPICH2X -#DEFCONT \ .DW 0 -#DEFCONT \ .DW PPI_IN,PPI_OUT,PPI_IST,PPI_OST,PPI_INITDEV,PPI_QUERY,PPI_DEVICE -#DEFCONT \ .FILL 2 -#DEFCONT \ .DB 0 -#DEFCONT \ .DB PIO_8255 -#DEFCONT \ .DB 2 -#DEFCONT \ .DB MPPIBASE+4 -#DEFCONT \ .DB (MPPICH3|00100000B) -#DEFCONT \ .DB MPPICH3X -#DEFCONT \ .DW 0 -#DEFCONT \ .DW PPI_IN,PPI_OUT,PPI_IST,PPI_OST,PPI_INITDEV,PPI_QUERY,PPI_DEVICE -#DEFCONT \ .FILL 2 -; -; HERE WE ACTUALLY DEFINE THE HARDWARE THAT THE HBIOS CAN ACCESS -; THE INIT ROUTINES READ AND SET THE INITIAL MODES FROM THIS INFO ; -PIO_CFG: -; -#IF PIO_4P -DEFPIO(PIO4BASE+0,M_Output,M_Input,M_BitAllOut,M_BitAllOut,INT_N,INT_N) -DEFPIO(PIO4BASE+4,M_Input,M_Input,M_BitAllOut,M_BitAllOut,INT_N,INT_N) -DEFPIO(PIO4BASE+8,M_Output,M_Output,M_BitAllOut,M_BitAllOut,INT_N,INT_N) -DEFPIO(PIO4BASE+12,M_Output,M_Output,M_BitAllOut,M_Output,INT_N,INT_N) -#ENDIF -#IF PIO_ZP -DEFPIO(PIOZBASE+0,M_Input,M_Input,M_BitAllOut,M_BitAllOut,INT_N,INT_N) -DEFPIO(PIOZBASE+4,M_Output,M_Output,M_BitAllOut,M_BitAllOut,INT_N,INT_N) -#ENDIF -; PIO_SBC & (PLATFORM == PLT_SBC) & (PPIDEMODE != PPIDEMODE_SBC)) +PIO_TYPE_MAP: + .DW PIO_STR_NONE + .DW PIO_STR_PIO -#IF PIO_SBC -DEFPPI(PIOSBASE,M_Output,M_Output,M_Output,M_BitAllOut,M_BitAllOut,M_BitAllOut) -#ENDIF +PIO_STR_NONE .DB "$" +PIO_STR_PIO .DB "PIO$" ; -PIO_CNT .EQU ($ - PIO_CFG) / CFG_SIZ +; WORKING VARIABLES ; -;------------------------------------------------------------------- -; WHEN WE GET HERE IY POINTS TO THE PIO_CFG TABLE WE ARE WORKING ON. -; C IS THE UNIT NUMBER -;------------------------------------------------------------------- +PIO_DEV .DB 0 ; DEVICE NUM USED DURING INIT +PIO_MAP .DB 0 ; CHIP PRESENCE BITMAP ; -;PIO_INITUNIT: -; LD A,C ; SET THE UNIT NUMBER -; LD (IY),A +PIO0A_RCVBUF .EQU 0 +PIO0B_RCVBUF .EQU 0 ; -; LD DE,-1 ; LEAVE CONFIG ALONE -; CALL PIO_INITDEV ; IMPLEMENT IT AND RETURN -; XOR A ; SIGNAL SUCCESS -; RET ; AND RETURN +#IF (PIOCNT >= 2) +PIO1A_RCVBUF .EQU 0 +PIO1B_RCVBUF .EQU 0 +#ENDIF ; -PIO_INIT: -; CALL SPK_BEEP - LD B,PIO_CNT ; COUNT OF POSSIBLE PIO UNITS - LD C,0 ; INDEX INTO PIO CONFIG TABLE -PIO_INIT1: - PUSH BC ; SAVE LOOP CONTROL - -; LD A,C ; PHYSICAL UNIT TO A -; RLCA ; MULTIPLY BY CFG TABLE ENTRY SIZE (32 BYTES) -; RLCA ; ... -; RLCA ; ... TO GET OFFSET INTO CFG TABLE -; RLCA -;; RLCA -; LD HL,PIO_CFG ; POINT TO START OF CFG TABLE -; PUSH AF -; CALL ADDHLA ; HL := ENTRY ADDRESS -; POP AF -; CALL ADDHLA ; HL := ENTRY ADDRESS -; PUSH HL ; COPY CFG DATA PTR -; POP IY ; ... TO IY -; POP IY ; ... TO IY - - CALL IDXCFG - - LD A,(IY+1) ; GET PIO TYPE - OR A ; SET FLAGS - CALL NZ,PIO_PRTCFG ; PRINT IF NOT ZERO - -; PUSH DE -; LD DE,$FFFF ; INITIALIZE DEVICE/CHANNEL -; CALL PIO_INITDEV ; BASED ON DPW -; POP DE - - POP BC ; RESTORE LOOP CONTROL - INC C ; NEXT UNIT - DJNZ PIO_INIT1 ; LOOP TILL DONE +; PIO PORT TABLE ; - XOR A ; SIGNAL SUCCESS - RET ; DONE +PIO_CFG: + ; PIO0 CHANNEL A +PIO0A_CFG: + .DB 0 ; DEVICE NUMBER (SET DURING INIT) + .DB 0 ; PIO TYPE (SET DURING INIT) + .DB $00 ; CHIP 0 / CHANNEL A (LOW BIT IS CHANNEL) + .DB PIO0A_CTL ; CMD/STATUS PORT + .DB PIO0A_DAT ; DATA PORT + .DW DEFSERCFG ; LINE CONFIGURATION + .DW PIO0A_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; +PIO_CFGSIZ .EQU $ - PIO_CFG ; SIZE OF ONE CFG TABLE ENTRY +; + ; PIO0 CHANNEL B +PIO0B_CFG: + .DB 0 ; DEVICE NUMBER (SET DURING INIT) + .DB 0 ; PIO TYPE (SET DURING INIT) + .DB $01 ; CHIP 0 / CHANNEL B (LOW BIT IS CHANNEL) + .DB PIO0B_CTL ; CMD/STATUS PORT + .DB PIO0B_DAT ; DATA PORT + .DW DEFSERCFG ; LINE CONFIGURATION + .DW PIO0B_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; +#IF (PIOCNT >= 2) +; + ; PIO1 CHANNEL A +PIO1A_CFG: + .DB 0 ; DEVICE NUMBER (SET DURING INIT) + .DB 0 ; PIO TYPE (SET DURING INIT) + .DB $02 ; CHIP 1 / CHANNEL A (LOW BIT IS CHANNEL) + .DB PIO1A_CTL ; CMD/STATUS PORT + .DB PIO1A_DAT ; DATA PORT + .DW DEFSERCFG ; LINE CONFIGURATION + .DW PIO1A_RCVBUF ; POINTER TO RCV BUFFER STRUCT +; + ; PIO1 CHANNEL B +PIO1B_CFG: + .DB 0 ; DEVICE NUMBER (SET DURING INIT) + .DB 0 ; PIO TYPE (SET DURING INIT) + .DB $03 ; CHIP 1 / CHANNEL B (LOW BIT IS CHANNEL) + .DB PIO1B_CTL ; CMD/STATUS PORT + .DB PIO1B_DAT ; DATA PORT + .DW DEFSERCFG ; LINE CONFIGURATION + .DW PIO1B_RCVBUF ; POINTER TO RCV BUFFER STRUCT ; -SET_PORT: - ; DEVICE TYPE IS I/O PORT SO JUST WRITE $00 TO IT - LD C,(IY+3) - OUT (C),A - XOR A - RET +#ENDIF +; +PIO_CFGCNT .EQU ($ - PIO_CFG) / PIO_CFGSIZ diff --git a/Source/HBIOS/pio_ps.asm b/Source/HBIOS/pio_ps.asm new file mode 100644 index 00000000..f198f25a --- /dev/null +++ b/Source/HBIOS/pio_ps.asm @@ -0,0 +1,999 @@ +; PIO driver sets up the parallel port as a subtype of Serial/Char device. +; +; +; HBIOS initializes driver by: +; +; 1) Calling Pre-initialization +; +; This involves setting up all the data structures describing the devices. +; If possible, do a hardware test to verify it is available for adding to available devices. +; +; 2) Calling device initialization. +; +; Hardware initialization. +; Configure to initial state or to a new state. +; +; Implementation limitations: +; +; The fully functionality of the Z80 PIO can only be realized by using Z80 interrupt mode 2. +; Registers cannot be interrogated for interrupts status and the originating interrupt +; device cannot be determine. +; +; Full implementation of IM2 functionality for an ECB-ZP and ECB-4P board would require the +; allocation of an interrupt handler for each chip channel. Thus, 12 interrupt handlers +; would be required to support this configuration. As the HBIOS only has an allocation of +; 16, a full implmentation is impractical. +; +; The compromise solution is to allow 4 interrupts for the PIO driver. All remaining PIO's +; are limited to Bit mode or blind read and write to the input/output ports. +; +; Zilog PIO reset state: +; +; Both port mask registers are reset to inhibit All port data bits. +; Port data bus lines are set to a high-impedance state and the Ready "handshake" +; Mode 1 (output) is automatically selected. +; The vector address registers are not reset. +; Both port interrupt enable flip-flops are reset. +; Both port output registers are reset. +; +; Register addressing example for ECB-ZP and ECB-4P assuming base address 90h and 88h respectively. +; +; PIO ----ZP---- ----4P---- +; 0 DATA 0 90h DATA 0 B8h +; 0 DATA 1 91h DATA 1 B9h +; 0 CMD 0 92h CMD 0 BAh +; 0 CMD 1 93h CMD 1 BBh +; 1 DATA 0 94h DATA 0 BCh +; 1 DATA 1 95h DATA 1 BDh +; 1 CMD 0 96h CMD 0 BEh +; 1 CMD 1 97h CMD 1 BFh +; 2 DATA 0 C0h +; 2 DATA 1 C1h +; 2 CMD 0 C2h +; 2 CMD 1 C3h +; 3 DATA 0 C4h +; 3 DATA 1 C5h +; 3 CMD 0 C6h +; 3 CMD 1 C7h +; +PIODEBUG .EQU 1 +; +M_Output .EQU $00 << 6 +M_Input .EQU $01 << 6 +M_Bidir .EQU $02 << 6 +M_BitCtrl .EQU $03 << 6 +M_BitAllIn .EQU $FF +M_BitAllOut .EQU $00 +; +PIO_NONE .EQU 0 +PIO_ZPIO .EQU 1 +PIO_8255 .EQU 2 +PIO_PORT .EQU 3 + +; SET MAXIMUM NUMBER OF INTERRUPTS AVAILABLE FOR ALL +; ENSURE INTERRUPTS ARE NOT TURNED ON IF IM2 IS NOT SET. + +INT_ALLOC .DB 0 +INT_N .EQU 00000000B +#IF (INTMODE == 2) +INT_Y .EQU 00000100B +INT_ALLOW .EQU 4 +#ELSE +INT_Y .EQU INT_N +INT_ALLOW .EQU 0 +#ENDIF +; +INT0 .EQU 00000000B +INT1 .EQU 00000001B +INT2 .EQU 00000010B +INT3 .EQU 00000011B + +; +; SETUP THE DISPATCH TABLE ENTRIES +; +; PIO_CNT HOLDS THE NUMBER OF DEVICED CALCULATED FROM THE NUMBER OF DEFPIO MACROS +; PIO_CNT SHOULD INCREASE BY 2 FOR EVERY PIO CHIP ADDED. +; +; PIO_PREINIT WILL READ THROUGH ALL PIOCFG TABLES AND CONFIGURE EACH TABLE. +; IT WITH THEN CALL PIO_INITUNIT TO INITIALIZE EACH DEVICE TO ITS DEFAULT STATE +; +; EXPECTS NOTHING ON ENTRY +; +PIO_PREINIT: + CALL NEWLINE ;D + LD B,PIO_CNT ; LOOP CONTROL + LD C,0 ; PHYSICAL UNIT INDEX + XOR A ; ZERO TO ACCUM +; LD (PIO_DEV),A ; CURRENT DEVICE NUMBER + LD (INT_ALLOC),A ; START WITH NO INTERRUPTS ALLOCATED +PIO_PREINIT0: + PUSH BC ; SAVE LOOP CONTROL +; LD A,C ; INITIALIZE THE UNIT + +; PUSH AF ;D +; LD A,'u' ;D +; CALL COUT ;D +; POP AF ;D +; CALL PRTHEXBYTE ;D UNIT +; CALL PC_SPACE ;D + +; RLCA ; MULTIPLY BY CFG TABLE ENTRY SIZE (32 BYTES) +; RLCA ; ... +; RLCA ; ... TO GET OFFSET INTO CFG TABLE +; RLCA +;; RLCA +; LD HL,PIO_CFG ; POINT TO START OF CFG TABLE +; PUSH AF +; CALL ADDHLA ; HL := ENTRY ADDRESS +; POP AF +; CALL ADDHLA ; HL := ENTRY ADDRESS +; PUSH HL ; SAVE IT +; POP IY ; ... TO IY + + CALL IDXCFG + + LD (HL),C + + PUSH AF ;D + LD A,'c' ;D + CALL COUT ;D + POP AF ;D + PUSH BC ;D + PUSH HL ;D + POP BC ;D + CALL PRTHEXWORD ;D CONFIG TABLE + CALL PC_SPACE ;D + POP BC ;D + + LD A,(IY+1) ; GET THE PIO TYPE DETECTED + CP PIO_PORT ; SET FLAGS + + PUSH AF ;D + LD A,'t' ;D + CALL COUT ;D + POP AF ;D + CALL PRTHEXBYTE ;D TYPE + CALL PC_SPACE ;D + +; JR Z,BADINIT + +; PUSH BC ; SAVE LOOP CONTROL +; LD BC,PIO_FNTBL ; BC := FUNCTION TABLE ADDRESS +; DEC A +; JR Z,TYPFND ; SKIP IT IF NOTHING FOUND +; LD BC,PPI_FNTBL ; BC := FUNCTION TABLE ADDRESS +; DEC A +; JR Z,TYPFND ; ADD ENTRY IF PIO FOUND, BC:DE +; LD BC,PRT_FNTBL +; DEC A +; JR Z,TYPFND +; POP BC +; JR BADINIT + + PUSH HL + LD DE,-1 ; INITIALIZE THIS DEVICE WITH + CALL PIO_INITDEV ; DEFAULT VALUES + POP HL + +; JR NZ,SKPINIT + + ; AT THIS POINT WE KNOW WE + ; HAVE A VALID DEVICE SO ADD IT + + LD A,8 ; CALCULATE THE FUNCTION TABLE + CALL ADDHLA ; POSITION WHICH FOLLOWS THE + PUSH HL ; CONFIGURATION TABLE OF EACH + POP BC ; DEVICE + +TYPFND: PUSH AF ;D + LD A,'f' ;D + CALL COUT ;D + POP AF ;D + PUSH BC ;D + CALL PRTHEXWORD ;D FUNCTION TABLE + POP BC ;D + CALL NEWLINE ;D + + PUSH IY ; ADD ENTRY IF PIO FOUND, BC:DE + POP DE ; BC: DRIVER FUNCTION TABLE + CALL CIO_ADDENT ; DE: ADDRESS OF UNIT INSTANCE DATA + +BADINIT:POP BC ; RESTORE LOOP CONTROL + + INC C ; NEXT PHYSICAL UNIT +SKPINIT:DJNZ PIO_PREINIT0 ; LOOP UNTIL DONE + + PUSH AF ;D + PRTS("INTS=$") ;D + LD A,(INT_ALLOC) ;D + CALL PRTHEXBYTE ;D + POP AF ;D + PUSH DE ;D + LD DE,CIO_TBL-3 ;D + CALL DUMP_BUFFER ;D + POP DE ;D + XOR A ; SIGNAL SUCCESS + RET ; AND RETURN +; +; INDEX INTO THE CONFIG TABLE +; ON ENTRY C = UNIT NUMBER +; ON EXIT IY = CONFIG DATA POINTER +; ON EXIT DE = CONFIG TABLE START +; +; EACH CONFIG TABLE IS 24 BYTES LONG +; +CFG_SIZ .EQU 24 +; +IDXCFG: LD A,C + RLCA ; X 2 + RLCA ; X 4 + RLCA ; X 8 + LD H,0 + LD L,A ; HL = X 8 + PUSH HL + ADD HL,HL ; HL = X 16 + POP DE + ADD HL,DE ; HL = X 24 + LD DE,PIO_CFG + ADD HL,DE + PUSH HL ; COPY CFG DATA PTR + POP IY ; ... TO IY + RET + +; PIO_INITDEV - INITIALIZE DEVICE +; +; IF DE = FFFF THEN THE SETUP PARAMETER WORD WILL BE READ FROM THE DEVICE CONFIGURATION +; TABLE POINTED TO BY IY AND THE PIO PORT WILL BE PROGRAMMED BASED ON THAT CONFIGURATION. +; +; OTHERWISE THE PIO PORT WILL BE PROGRAMMED BY THE SETUP PARAMETER WORD IN DE AND THIS +; WILL BE SAVED IN THE DEVICE CONFIGURATION TABLE POINTED TO BY IY. +; +; ALL OTHER CONFIGURATION OF THE DEVICE CONFIGURATION TABLE IS DONE UPSTEAM BY PIO_PREINIT + +PIO_INITDEV: + ; TEST FOR -1 (FFFF) WHICH MEANS USE CURRENT CONFIG (JUST REINIT) + LD A,D ; TEST DE FOR + AND E ; ... VALUE OF -1 + INC A ; ... SO Z SET IF -1 + JR NZ,PIO_INITDEV1 ; IF DE == -1, REINIT CURRENT CONFIG +PIO_INITDEV0: + ; LOAD EXISTING CONFIG (DCW) TO REINIT + LD E,(IY+4) ; LOW BYTE + LD D,(IY+5) ; HIGH BYTE +; +PIO_INITDEV1: ; WHICH DEVICE TYPE? + LD A,(IY+1) + CP PIO_ZPIO + JR Z,SETPIO0 + CP PIO_8255 + JP Z,SET_8255 + CP PIO_PORT + JP Z,SET_PORT +BAD_SET:OR $FF ; UNKNOWN DEVICE + RET + +SETPIO0:LD A,E ; GET MODE + AND 11000000B ; BITS (B7B6) + CP 10000000B ; IS IT BIDIR? + JR NZ,SETPIO1 + LD A,(IY+2) ; GET CHANNEL + OR A + JR NZ,BAD_SET ; CAN'T DO ON CH1 + + ; VALIDATE INTERRUPT REQUEST + ; GRANT INTERRUPT IF THERE IS A FREE INTERRUPT + ; GRANT INTERRUPT IF AN INTERRUPT IS ALREADY ALLOCATED TO THIS UNIT + +SETPIO1:PUSH AF ;D + LD A,'[' ;D + CALL COUT ;D + LD A,(IY) ;D + CALL PRTHEXBYTE ;D + LD A,']' ;D + CALL COUT ;D + POP AF ;D + + BIT 2,E ; SKIP IF WE ARE NOT REQUESTING + JP Z,SETPIO2 ; AN INTERRUPT + + PRTS("[INTREQ]$") ;D + +; LD A,(IY+4) ; GET CURRENT INTERRUPT SETTING +; BIT 2,A ; SKIP IF IT IS ALREADY +; JP NZ,SETPIO2 ; ALLOCATED TO THIS UNIT + + LD A,(INT_ALLOC) ; WE NEED TO ALLOCATE AN + CP INT_ALLOW ; INTERRUPT. DO WE HAVE + JR NC,BAD_SET ; ONE FREE? + + PRTS("[ALLOCINT]$") ;D + + ; WHICH INTERRUPT IS FREE ? + ; SCAN THROUGH THE CFG TABLES + ; AND FIND A FREE ONE + + PUSH AF ; NESTED LOOP + LD DE,CFG_SIZ ; OUTSIDE LOOP IS INTERRUPT + LD B,INT_ALLOW ; INSIDE LOOP IS DEVICE +SETPIOP: LD C,B + DEC C + PUSH BC + LD B,PIO_CNT + LD HL,PIO_CFG+4 +SETPIOX: LD A,(HL) + BIT 2,A ; JUMP TO NEXT DEVICE + JR Z,SETPIOY ; IF NO INTERRUPT ON + AND 00000011B ; THIS DEVICE + + CP C ; IF WE MATCH AN INTERRUPT HERE THEN IT IS NOT FREE. + JR NZ,SETPIOY ; SO EXIT INSIDE LOOP AND TRY NEXT INTERRUPT + + XOR A ; WE MATCH INT 0 - IF WE ARE CHECKING FOR IT THEN + OR C ; WE REGARD IS AS FREE. + JR NZ,SETPIOZ + +SETPIOY: ADD HL,DE + DJNZ SETPIOX + + JR SETPIOQ ; WE GET HERE IF THE CURRENT INTERRUPT + ; WAS NOT MATCHED SO IT IS FREE +SETPIOZ: POP BC + DJNZ SETPIOP + POP AF + + PRTS("[NONEFREE]$") + RET + +SETPIOQ:PUSH AF ; AVAILABLE INTERRUPT IS IN C + PRTS("[FREE]=$") + LD A,C + CALL PRTHEXBYTE + POP AF + + POP AF + POP AF + +SETPIOR:LD HL,INT_ALLOC ; INCREASE THE COUNT + INC (HL) ; OF USED INTERRUPTS + LD A,(HL) + +; LD A,(IY) ; IS THIS UNIT +; INC A ; UNITIALIZED? +; JR Z,SETPIO6 + + LD A,(IY+4) ; IT IS UNITIALIZED SO + OR C ; SAVE THE ALLOCATES + LD (IY+4),A ; INTERRUPT +; +; FOR THIS DEVICE AND INTERRUPT, UPDATE THE CONFIG TABLE FOR THIS DEVICE. +; PIO_IN, PIO_OUT, PIO_IST, PIO_OST ENTRIES NEED TO BE REDIRECTED. +; INTERRUPT VECTOR NEEDS TO BE UPDATED +; + LD A,(IY+0) + LD HL,0 + ; SETUP PIO INTERRUPT VECTOR IN IVT + LD HL,HBX_IV09+1 + +; CALL SPK_BEEP +; +SETPIO6:RET + + ; EXIT WITH FREE INTERRUPT IN C + + LD A,C + LD (INT_ALLOC),A + + LD A,E + AND 11000000B + OR 00000100B + OR C + LD E,A + LD (IY+5),A +; + ; TODO: DEALLOCATE AN INTERRUPT +; +; LD A,(INT_ALLOC) +; DEC A +; LD (INT_ALLOC),A +; +SETPIO2: + +; DE CONTAINS THE MODE IF INTERRUPT ROUTINE SKIPPED + + PRTS("[NOINTREQ]$") ;D + +; LD A,(IY+4) + LD A,E ; GET MODE AND CREATE COMMAND + AND 11000000B ; $B0 + OR 00001111B ; $0F + + LD C,(IY+3) ; GET DATA PORT + INC C ; POINT TO CMD + INC C ; PORT + OUT (C),A ; SET MODE + CP (M_BitCtrl | $0F) ; IF MODE 3 + JR NZ,SETPIO3 + LD A,(IY+5) ; SET I/O DIRECTION + OUT (C),A ; FOR MODE 3 + +SETPIO3:; INTERUPT HANDLING + + JP SETPIO4 + + ; SETUP THE INTERRUPT VECTOR + + LD A,E + AND 00000011B +; DEC A ; INDEX INTO THE + ADD A,A ; THE VECTOR TABLE + ADD A,A ; + LD C,A + LD B,0 + LD HL,HBX_IV09+1 + ADD HL,BC ; GET THE ADDRESS OF + PUSH DE + LD D,(HL) ; THAT INTERRUPT + INC HL ; HANDLER + LD E,(HL) + LD HL,0 ;HBX_IVT+IVT_PIO0 ; POPULATE THE + LD A,L ; GET LOW BYTE OF IVT ADDRESS + ADD HL,BC ; INTERRUPT TABLE + LD (HL),D ; WITH THE INTERRUPT + INC HL ; HANDLER ADDRESS FOR + LD (HL),E ; THIS UNIT + POP DE + LD HL,INT_ALLOC + LD C,(HL) + LD B,0 + LD HL,PRTTAB-1 ; SAVE THE DATA + ADD HL,BC ; PORT FOR EACH INTERRUPT + LD C,(IY+3) + LD (HL),C + + INC C ; POINT TO CMD PORT + INC C + DI ; SET THE VECTOR ADDRESS + OUT (C),A + +; LD A,10000011B ; ENABLE INTERRUPTS ON + OUT (C),A ; THIS UNIT + EI +; JR GUD_SET +; +SETPIO4:LD A,00000111B ; $07 + OUT (C),A ; NO INTERRUPTS +; +; SUCCESSFULL SO SAVE DEVICE CONFIGURATION WORD (DCW) +; +GUD_SET:LD (IY+4),E ; LOW BYTE + LD (IY+5),D ; HIGH BYTE +; +; UPDATE THE DEVICE TABLE WITH THE ADDRESSES FOR THE CORRECT ROUTINE. +; + LD A,E + AND 00000111B + LD HL,INTMATRIX ; POINT TO EITHER THE INTERRUPT + JR NZ, USEIM + LD HL,POLMATRIX ; MATRIX OR THE POLLED MATRIX +USEIM: PUSH HL + + PUSH IY ; CALCULATE THE DESTINATION + POP HL ; ADDRESS IN THE PIO_CFG TABLE + LD BC,8 ; FOR THE FOUR ADDESSES TO BE + ADD HL,BC ; COPIED TO + +; LD B,0 ; 00000000 CALCULATE THE SOURCE ADDRESS + LD C,E ; XX?????? FROM THE MATRIX. EACH ENTRY + SRL C ; 0XX????? IN THE MATRIX IS 8 BYTES SO + SRL C ; 00XX???? SOURCE = MATRIX BASE + (8 * MODE) + SRL C ; 000XX??? + POP DE ; LOAD THE MATRIX BASE +; LD DE,POLMATRIX + EX DE,HL + ADD HL,BC ; HL = SOURCE + + LD C,8 ; COPY 8 BYTES + LDIR + +; PUSH IY +; POP DE +; CALL DUMP_BUFFER + + XOR A + RET + +PRTTAB: .DB 0 + .DB 0 + .DB 0 + .DB 0 +; +;----------------------------------------------------------------------------- +; +; INPUT INTERRUPT VECTOR MACRO AND DEFINITION FOR FOUR PORTS +; +#DEFINE PIOMIVT(PIOIN,PIOIST,PIOPRT) \ +#DEFCONT ;\ +#DEFCONT ; RETURN WITH ERROR IF THERE IS \ +#DEFCONT ; ALREADY A CHARACTER IN BUFFER \ +#DEFCONT ;\ +#DEFCONT ; OTHERWISE CHANGE THE STATUS TO \ +#DEFCONT ; SHOW THERE IS ONE CHARACTER IN \ +#DEFCONT ; THE BUFFER AND READ IT IN AND \ +#DEFCONT ; AND STORE IT.RETURN GOOD STATUS.\ +#DEFCONT ;\ +#DEFCONT \ LD A,(_CIST) +#DEFCONT \ OR A +#DEFCONT \ JR NZ,_OVFL +#DEFCONT \ LD A,(PIOPRT) +#DEFCONT \ LD C,A +#DEFCONT \ LD A,1 +#DEFCONT \ LD (_CIST),A +#DEFCONT \ IN A,(C) +#DEFCONT \ LD (_CICH),A +#DEFCONT \ OR $FF +#DEFCONT \ RET +#DEFCONT \_OVFL:XOR A +#DEFCONT \ RET +#DEFCONT ;\ +#DEFCONT ;\ +#DEFCONT ;\ +#DEFCONT ;\ +#DEFCONT ;\ +#DEFCONT ;\ +#DEFCONT \PIOIN:CALL PIOIST +#DEFCONT \ JR Z,PIOIN +#DEFCONT \ LD A,(_CICH) +#DEFCONT \ LD E,A +#DEFCONT \ XOR A +#DEFCONT \ LD (_CIST),A +#DEFCONT \ RET +#DEFCONT ;\ +#DEFCONT ; If THERE A CHARACTER \ +#DEFCONT ; AVAILABLE? RETURN NUMBER \ +#DEFCONT ; IN A - 0 OR 1 \ +#DEFCONT ;\ +#DEFCONT \PIOIST:LD A,(_CIST) +#DEFCONT \ AND 00000001B +#DEFCONT \ RET +#DEFCONT ;\ +#DEFCONT ; CIST : 01 = CHARACTER READY ELSE NOT READY \ +#DEFCONT ; CISH : CHARACTER STORED BY INTERRUPT \ +#DEFCONT ;\ +#DEFCONT \_CIST .DB 00 +#DEFCONT \_CICH .DB 00 +; +PIOIVT0:.MODULE PIOIVT0 +PIOMIVT(PIO0IN,PI0_IST,PRTTAB+0) +PIOIVT1:.MODULE PIOIVT1 +PIOMIVT(PIO1IN,PI1_IST,PRTTAB+1) +PIOIVT2:.MODULE PIOIVT2 +PIOMIVT(PIO2IN,PI2_IST,PRTTAB+2) +PIOIVT3:.MODULE PIOIVT3 +PIOMIVT(PIO3IN,PI3_IST,PRTTAB+3) +; +;----------------------------------------------------------------------------- +; +; OUTPUT INTERRUPT VECTOR MACRO AND DEFINITION FOR FOUR PORTS +; +; AN INTERRUPT IS GENERATED WHEN THE RECEIVING DEVICE CAN ACCEPT A CHARACTER +; +#DEFINE PIOMOVT(PIOOUT,PIOOST,PIOPRT) \ +#DEFCONT ;\ +#DEFCONT ; RETURN IF WE ARE WAITING FOR A \ +#DEFCONT ; CHARACTER (COST = 00) \ +#DEFCONT ;\ +#DEFCONT ; IF ZERO CHARACTERS READY +#DEFCONT ; (COST = 01) CHANGE STATUS TO \ +#DEFCONT ; WAITING FOR CHARACTER (COST 00) \ +#DEFCONT ;\ +#DEFCONT ; IF A CHARACTER IS READY THEN \ +#DEFCONT ; OUTPUT AND CHANGE STATUS TO \ +#DEFCONT ; ZERO CHARACTERS READY \ +#DEFCONT ;\ +#DEFCONT \ LD A,(_COST) +#DEFCONT \ DEC A +#DEFCONT \ RET M +#DEFCONT \ JR Z,_WFC +#DEFCONT \ LD A,(_COCH) +#DEFCONT \ LD E,A +#DEFCONT \_ONOW:LD A,(PIOPRT) +#DEFCONT \ LD C,A +#DEFCONT \ OUT (C),E +#DEFCONT \ LD A,1 +#DEFCONT \_WFC: LD (_COST),A +#DEFCONT \ RET +#DEFCONT ;\ +#DEFCONT ; WAIT FOR SPACE FOR THE CHARACTER\ +#DEFCONT ; IF WE ARE WAITING FOR A \ +#DEFCONT ; CHARACTRE THEN OUTPUT IT NOW \ +#DEFCONT ; OTHERWISE STORE IT UNTIL THE \ +#DEFCONT ; INTERRUPT CALLS FOR IT \ +#DEFCONT ;\ +#DEFCONT \PIOOUT:LD A,(_COST) +#DEFCONT \ CP 2 +#DEFCONT \ JR C,_ONOW +#DEFCONT \ LD A,E +#DEFCONT \ LD (_COCH),A +#DEFCONT \ LD A,2 +#DEFCONT \ LD (_COST),A +#DEFCONT \ JR PIOOUT +#DEFCONT ;\ +#DEFCONT ; RETURN WITH NUMBER OF \ +#DEFCONT ; CHARACTERS AVAILABLE 0 or 1 \ +#DEFCONT ;\ +#DEFCONT \PIOOST:LD A,(_COST) +#DEFCONT \ DEC A +#DEFCONT \ DEC A +#DEFCONT \ RET Z +#DEFCONT \ LD A,1 +#DEFCONT \ RET +#DEFCONT ;\ +#DEFCONT ; COST : 00 WAITING FOR CHARACTER\ +#DEFCONT ; 01 ZERO CHARACTERS READY\ +#DEFCONT ; 02 ONE CHARACTER READY \ +#DEFCONT ; COCH : CHARACTER TO OUTPUT \ +#DEFCONT ;\ +#DEFCONT \_COST .DB 01 +#DEFCONT \_COCH .DB 00 +; +PIOOVT0:.MODULE PIOOVT0 +PIOMOVT(PIO0OUT,PI0_OST,PRTTAB+0) +PIOOVT1:.MODULE PIOOVT1 +PIOMOVT(PIO1OUT,PI1_OST,PRTTAB+1) +PIOOVT2:.MODULE PIOOVT2 +PIOMOVT(PIO2OUT,PI2_OST,PRTTAB+2) +PIOOVT3:.MODULE PIOOVT3 +PIOMOVT(PIO3OUT,PI3_OST,PRTTAB+3) +; +;----------------------------------------------------------------------------- +; +; NON INTERRUPT OUTPUT ROUTINE - SHARED +; +; INPUT WILL ALWAYS RETURN ERROR, CHARACTER RETURNED IS UNDEFINED. +; OUTPUT WILL ALWAYS RETURN SUCCESS +; INPUT-STATUS WILL ALWAYS RETURN 0 CHARACTERS IN BUFFER. +; OUTPUT-STATUS WILL ALWAYS RETURN 1 CHARACTER SPACE IN BUFFER. + +PIOSHO_IN: + LD A,1 + RET +; +PIOSHO_OUT: + LD C,(IY+3) + OUT (C),E + XOR A + RET +; +PIOSHO_IST: XOR A + RET +; +PIOSH_OST: + LD A,1 + RET +; +;----------------------------------------------------------------------------- +; +; NON INTERRUPT INPUT ROUTINE - SHARED +; +; INPUT WILL ALWAYS A CHARACTER AND SUCCESS. +; OUTPUT WILL ALWAYS RETURN FAILURE +; INPUT STATUS WILL ALWAYS RETURN 1 CHARACTER IN BUFFER. +;OUTPUT-STATUS WILL ALWAYS RETURN 0 CHARACTER SPACE IN BUFFER. +; +PIOSHI_IN: + LD C,(IY+3) + IN A,(C) + LD E,A + XOR A + RET +; +PIOSHI_OUT: + LD A,1 + RET +; +PIOSH_IST: + LD A,1 + RET +; +PIOSHI_OST: + XOR A + RET +; +;----------------------------------------------------------------------------- +; +; ON ENTRY IY POINTS TO THE DEVICE RECORD. GET AND RETURN THE CONFIGURATION WORD IN DE +; +PIO_QUERY: +PPI_QUERY: + LD E,(IY+4) ; FIRST CONFIG BYTE TO E + LD D,(IY+5) ; SECOND CONFIG BYTE TO D + XOR A ; SIGNAL SUCCESS + RET +; +;----------------------------------------------------------------------------- +; +; ON ENTRY IY POINTS TO THE DEVICE RECORD. FOR CHARACTER DEVICES BIT 6 OF ATTRIBUTE +; INDICATES PARALLEL PORT IF 1 SO WE SET IT. COMMON TO ALL PORTS +; +PIO_DEVICE: +PPI_DEVICE: + LD D,CIODEV_PIO ; D := DEVICE TYPE + LD E,(IY) ; E := PHYSICAL UNIT + LD C,$40 ; C := ATTRIBUTE + LD H,0 ; H := 0, DRIVER HAS NO MODES + LD L,(IY+3) ; L := BASE I/O ADDRESS + XOR A ; SIGNAL SUCCESS + RET +; +INTMATRIX: + .DW PIO0IN, PIO0OUT, PI0_IST, PI0_OST + .DW PIO1IN, PIO1OUT, PI1_IST, PI1_OST + .DW PIO2IN, PIO2OUT, PI2_IST, PI2_OST + .DW PIO3IN, PIO3OUT, PI3_IST, PI3_OST +POLMATRIX: + .DW PIOSHO_IN, PIOSHO_OUT, PIOSHO_IST, PIOSH_OST ; OUTPUT + .DW PIOSHI_IN, PIOSHI_OUT, PIOSH_IST, PIOSHI_OST ; INPUT + .DW 0,0,0,0 ; BIDIR + .DW 0,0,0,0 ; BIT MODE + +SET_8255: + RET +; +SET_BYE: + XOR A ; SIGNAL SUCCESS + RET +; +; ------------------------------------ +; i8255 FUNCTION TABLE ROUTINES +;------------------------------------- + +PPI_IN: + XOR A ; SIGNAL SUCCESS + RET +; +PPI_OUT: + XOR A ; SIGNAL SUCCESS + RET +; +PPI_IST: + RET +; +PPI_OST: + RET +; +; PIO_INITDEV - Configure device. +; If DE = FFFF then extract the configuration information from the table of devices and program the device using those settings. +; Otherwise use the configuration information in DE to program those settings and save them in the device table + +PPI_INITDEV: + XOR A ; SIGNAL SUCCESS + RET +PPI_INT:OR $FF ; NZ SET TO INDICATE INT HANDLED + RET +; +PIO_PRTCFG: + ; ANNOUNCE PORT + CALL NEWLINE ; FORMATTING + PRTS("PIO$") ; FORMATTING + LD A,(IY) ; DEVICE NUM + CALL PRTDECB ; PRINT DEVICE NUM + PRTS(": IO=0x$") ; FORMATTING + LD A,(IY+3) ; GET BASE PORT + CALL PRTHEXBYTE ; PRINT BASE PORT +; + ; PRINT THE PIO TYPE + CALL PC_SPACE ; FORMATTING + LD A,(IY+1) ; GET PIO TYPE BYTE + LD DE,PIO_TYPE_STR ; POINT HL TO TYPE MAP TABLE + CALL PRTIDXDEA + + ; ALL DONE IF NO PIO WAS DETECTED + LD A,(IY+1) ; GET PIO TYPE BYTE + OR A ; SET FLAGS + RET Z ; IF ZERO, NOT PRESENT +; + PRTS(" MODE=$") ; FORMATTING + LD E,(IY+4) ; LOAD CONFIG + LD D,(IY+5) ; ... WORD TO DE + CALL PS_PRTPC0 ; PRINT CONFIG +; + LD A,(IY+4) ; PRINT + BIT 2,A ; ALLOCATED + JR Z,NOINT ; INTERRUPT + PRTS("/i$") + LD A,(IY+4) + AND 00000011B + CALL PRTDECB +NOINT: XOR A + RET +; +; WORKING VARIABLES +; +PIO_DEV .DB 0 ; DEVICE NUM USED DURING INIT +; +; DESCRIPTION OF DIFFERENT PORT TYPES +; +PIO_TYPE_STR: + .TEXT "$" ; IDX 0 + .TEXT "Zilog PIO$" ; IDX 1 + .TEXT "i8255 PPI$" ; IDX 2 + .TEXT "IO Port$" ; IDX 3 +; +; Z80 PIO PORT TABLE - EACH ENTRY IS FOR 1 CHIP I.E. TWO PORTS +; +; 32 BYTE DATA STRUCTURE FOR EACH PORT +; +; .DB 0 ; IY+0 CIO DEVICE NUMBER (SET DURING PRE-INIT, THEN FIXED) +; .DB 0 ; IY+1 PIO TYPE (SET AT ASSEMBLY, FIXED) +; .DB 0 ; IY+2 PIO CHANNEL (SET AT ASSEMBLY, FIXED) +; .DB PIOBASE+2 ; IY+3 BASE DATA PORT (SET AT ASSEMBLY, FIXED) +; .DB 0 ; IY+4 SPW - MODE 3 I/O DIRECTION BYTE (SET AT ASSEMBLE, SET WITH INIT) +; .DB 0 ; IY+5 SPW - MODE, INTERRUPT (SET AT ASSEMBLY, SET WITH INIT) +; .DW 0 ; IY+6/7 FUNCTION TABLE (SET AT ASSEMBLY, SET DURING PRE-INIT AND AT INIT) +; .DW PIO_IN ; IY+8 ADDR FOR DEVICE INPUT (SET WITH INIT) +; .DW PIO_OUT ; IY+10 ADDR FOR DEVICE OUTPUT (SET WITH INIT) +; .DW PIO_IST ; IY+12 ADDR FOR DEVICE INPUT STATUS (SET WITH INIT) +; .DW PIO_OST ; IY+14 ADDR FOR DEVICE OUTPUT STATUS (SET WITH INIT) +; .DW PIO_INITDEV ; IY+16 ADDR FOR INITIALIZE DEVICE ROUTINE (SET AT ASSEMBLY, FIXED) +; .DW PIO_QUERY ; IY+18 ADDR FOR QUERY DEVICE RECORD ROUTINE (SET AT ASSEMBLY, FIXED) +; .DW PIO_DEVICE ; IY+20 ADDR FOR DEVICE TYPE ROUTINE (SET AT ASSEMBLY, FIXED) +; .FILL 10 +; +; SETUP PARAMETER WORD: +; +; +-------------------------------+ +-------+-----------+---+-------+ +; | BIT CONTROL | | MODE | | A | INT | +; +-------------------------------+ --------------------+-----------+ +; F E D C B A 9 8 7 6 5 4 3 2 1 0 +; -- MSB (D REGISTER) -- -- LSB (E REGISTER) -- +; +; +; MSB = BIT CONTROL MAP USE IN MODE 3 +; +; MODE B7 B6 = 00 Mode 0 Output +; 01 Mode 1 Input +; 10 Mode 2 Bidir +; 11 Mode 3 Bit Mode +; +; INTERRUPT ALLOCATED B2 = 0 NOT ALLOCATED +; = 1 IS ALLOCATED +; +; WHICH IVT IS ALLOCATES B1 B0 00 IVT_PIO0 +; 01 IVT_PIO1 +; 10 IVT_PIO2 +; 11 IVT_PIO3 +; +#DEFINE DEFPIO(MPIOBASE,MPIOCH0,MPIOCH1,MPIOCH0X,MPIOCH1X,MPIOIN0,MPIOIN1) \ +#DEFCONT \ .DB 0 +#DEFCONT \ .DB PIO_ZPIO +#DEFCONT \ .DB 0 +#DEFCONT \ .DB MPIOBASE +#DEFCONT \ .DB (MPIOCH0|MPIOIN0) +#DEFCONT \ .DB MPIOCH0X +#DEFCONT \ .DW 0 +#DEFCONT \ .DW 0,0,0,0, PIO_INITDEV,PIO_QUERY,PIO_DEVICE +#DEFCONT \ .FILL 2 +#DEFCONT \ .DB 0 +#DEFCONT \ .DB PIO_ZPIO +#DEFCONT \ .DB 1 +#DEFCONT \ .DB MPIOBASE+1 +#DEFCONT \ .DB (MPIOCH1|MPIOIN1) +#DEFCONT \ .DB MPIOCH1X +#DEFCONT \ .DW 0 +#DEFCONT \ .DW 0,0,0,0, PIO_INITDEV,PIO_QUERY,PIO_DEVICE +#DEFCONT \ .FILL 2 +; +; i8255 PORT TABLE - EACH ENTRY IS FOR 1 CHIP I.E. THREE PORTS +; +#DEFINE DEFPPI(MPPIBASE,MPPICH1,MPPICH2,MPPICH3,MPPICH1X,MPPICH2X,MPPICH3X) \ +#DEFCONT \ .DB 0 +#DEFCONT \ .DB PIO_8255 +#DEFCONT \ .DB 0 +#DEFCONT \ .DB MPPIBASE +#DEFCONT \ .DB (MPPICH1|00001000B) +#DEFCONT \ .DB MPPICH1X +#DEFCONT \ .DW 0 +#DEFCONT \ .DW PPI_IN,PPI_OUT,PPI_IST,PPI_OST,PPI_INITDEV,PPI_QUERY,PPI_DEVICE +#DEFCONT \ .FILL 2 +#DEFCONT \ .DB 0 +#DEFCONT \ .DB PIO_8255 +#DEFCONT \ .DB 1 +#DEFCONT \ .DB MPPIBASE+2 +#DEFCONT \ .DB (MPPICH2|00010000B) +#DEFCONT \ .DB MPPICH2X +#DEFCONT \ .DW 0 +#DEFCONT \ .DW PPI_IN,PPI_OUT,PPI_IST,PPI_OST,PPI_INITDEV,PPI_QUERY,PPI_DEVICE +#DEFCONT \ .FILL 2 +#DEFCONT \ .DB 0 +#DEFCONT \ .DB PIO_8255 +#DEFCONT \ .DB 2 +#DEFCONT \ .DB MPPIBASE+4 +#DEFCONT \ .DB (MPPICH3|00100000B) +#DEFCONT \ .DB MPPICH3X +#DEFCONT \ .DW 0 +#DEFCONT \ .DW PPI_IN,PPI_OUT,PPI_IST,PPI_OST,PPI_INITDEV,PPI_QUERY,PPI_DEVICE +#DEFCONT \ .FILL 2 +; +; HERE WE ACTUALLY DEFINE THE HARDWARE THAT THE HBIOS CAN ACCESS +; THE INIT ROUTINES READ AND SET THE INITIAL MODES FROM THIS INFO +; +PIO_CFG: +; +#IF PIO_4P +DEFPIO(PIO4BASE+0,M_Output,M_Input,M_BitAllOut,M_BitAllOut,INT_N,INT_N) +DEFPIO(PIO4BASE+4,M_Input,M_Input,M_BitAllOut,M_BitAllOut,INT_N,INT_N) +DEFPIO(PIO4BASE+8,M_Output,M_Output,M_BitAllOut,M_BitAllOut,INT_N,INT_N) +DEFPIO(PIO4BASE+12,M_Output,M_Output,M_BitAllOut,M_Output,INT_N,INT_N) +#ENDIF +#IF PIO_ZP +DEFPIO(PIOZBASE+0,M_Input,M_Input,M_BitAllOut,M_BitAllOut,INT_N,INT_N) +DEFPIO(PIOZBASE+4,M_Output,M_Output,M_BitAllOut,M_BitAllOut,INT_N,INT_N) +#ENDIF +; PIO_SBC & (PLATFORM == PLT_SBC) & (PPIDEMODE != PPIDEMODE_SBC)) + +#IF PIO_SBC +DEFPPI(PIOSBASE,M_Output,M_Output,M_Output,M_BitAllOut,M_BitAllOut,M_BitAllOut) +#ENDIF +; +PIO_CNT .EQU ($ - PIO_CFG) / CFG_SIZ +; +;------------------------------------------------------------------- +; WHEN WE GET HERE IY POINTS TO THE PIO_CFG TABLE WE ARE WORKING ON. +; C IS THE UNIT NUMBER +;------------------------------------------------------------------- +; +;PIO_INITUNIT: +; LD A,C ; SET THE UNIT NUMBER +; LD (IY),A +; +; LD DE,-1 ; LEAVE CONFIG ALONE +; CALL PIO_INITDEV ; IMPLEMENT IT AND RETURN +; XOR A ; SIGNAL SUCCESS +; RET ; AND RETURN +; +PIO_INIT: +; CALL SPK_BEEP + LD B,PIO_CNT ; COUNT OF POSSIBLE PIO UNITS + LD C,0 ; INDEX INTO PIO CONFIG TABLE +PIO_INIT1: + PUSH BC ; SAVE LOOP CONTROL + +; LD A,C ; PHYSICAL UNIT TO A +; RLCA ; MULTIPLY BY CFG TABLE ENTRY SIZE (32 BYTES) +; RLCA ; ... +; RLCA ; ... TO GET OFFSET INTO CFG TABLE +; RLCA +;; RLCA +; LD HL,PIO_CFG ; POINT TO START OF CFG TABLE +; PUSH AF +; CALL ADDHLA ; HL := ENTRY ADDRESS +; POP AF +; CALL ADDHLA ; HL := ENTRY ADDRESS +; PUSH HL ; COPY CFG DATA PTR +; POP IY ; ... TO IY +; POP IY ; ... TO IY + + CALL IDXCFG + + LD A,(IY+1) ; GET PIO TYPE + OR A ; SET FLAGS + CALL NZ,PIO_PRTCFG ; PRINT IF NOT ZERO + +; PUSH DE +; LD DE,$FFFF ; INITIALIZE DEVICE/CHANNEL +; CALL PIO_INITDEV ; BASED ON DPW +; POP DE + + POP BC ; RESTORE LOOP CONTROL + INC C ; NEXT UNIT + DJNZ PIO_INIT1 ; LOOP TILL DONE +; + XOR A ; SIGNAL SUCCESS + RET ; DONE +; +SET_PORT: + ; DEVICE TYPE IS I/O PORT SO JUST WRITE $00 TO IT + LD C,(IY+3) + OUT (C),A + XOR A + RET diff --git a/Source/HBIOS/sio.asm b/Source/HBIOS/sio.asm index 8e7e323a..f1de029c 100644 --- a/Source/HBIOS/sio.asm +++ b/Source/HBIOS/sio.asm @@ -716,7 +716,7 @@ SIO_INITDEV4: ; ; ALL GOOD. PROGRAM THE CTC CHANNEL LD A,(IY+13) ; GET CTC CHANNEL - ADD A,CTCA ; ADD TO CTC BASE PORT ADR + ADD A,CTCBASE ; ADD TO CTC BASE PORT ADR #IF (SIODEBUG) PRTS(" CTC=$") CALL PRTHEXBYTE @@ -815,7 +815,7 @@ SIO_INITSAFE: ; IF A CTC CHANNEL IS CONFIGURED, PROGRAM IT FOR ; SIMPLE 1:1 SCALING. LD A,(IY+13) ; GET CTC CHANNEL - ADD A,CTCA ; ADD TO CTC BASE PORT ADR + ADD A,CTCBASE ; ADD TO CTC BASE PORT ADR LD C,A ; AND PUT IN C FOR I/O LD A,%01010111 ; CTCC CONTROL WORD VALUE OUT (C),A ; PREP CTC CHANNEL diff --git a/Source/HBIOS/std.asm b/Source/HBIOS/std.asm index 500c4fea..aa9b12b4 100644 --- a/Source/HBIOS/std.asm +++ b/Source/HBIOS/std.asm @@ -42,22 +42,6 @@ DL_INFO .EQU 16 ; HBIOS DISPLAYS INFORMATIONAL MESSAGES DL_DETAIL .EQU 20 ; HBIOS DISPLAYS DETAILED DIAGNOSTIC MESSAGES DL_VERBOSE .EQU 24 ; HBIOS DISPLAYS ANYTHING IT KNOWS HOW TO ; -; PRIMARY HARDWARE PLATFORMS -; -PLT_SBC .EQU 1 ; SBC ECB Z80 SBC -PLT_ZETA .EQU 2 ; ZETA Z80 SBC -PLT_ZETA2 .EQU 3 ; ZETA Z80 V2 SBC -PLT_N8 .EQU 4 ; N8 (HOME COMPUTER) Z180 SBC -PLT_MK4 .EQU 5 ; MARK IV -PLT_UNA .EQU 6 ; UNA BIOS -PLT_RCZ80 .EQU 7 ; RC2014 W/ Z80 -PLT_RCZ180 .EQU 8 ; RC2014 W/ Z180 -PLT_EZZ80 .EQU 9 ; EASY Z80 -PLT_SCZ180 .EQU 10 ; SCZ180 -PLT_DYNO .EQU 11 ; DYNO MICRO-ATX MOTHERBOARD -PLT_RCZ280 .EQU 12 ; RC2014 W/ Z280 -PLT_MBC .EQU 13 ; MULTI BOARD COMPUTER -; ; CPU TYPES ; CPU_NONE .EQU 0 ; NO CPU TYPE DEFINED @@ -209,6 +193,7 @@ AYMODE_RCZ80 .EQU 3 ; RC2014 SOUND MODULE BY ED BRINDLEY ON Z80 AYMODE_RCZ180 .EQU 4 ; RC2014 SOUND MODULE BY ED BRINDLEY ON Z180 AYMODE_MSX .EQU 5 ; RC2014 SOUND MODULE REV6 BY ED BRINDLEY ON Z80/Z180 AT MSX PORTS AYMODE_LINC .EQU 6 ; LINC Z50 AY SOUND CARD +AYMODE_MBC .EQU 7 ; MBC SOUND BOARD ; ; SN SOUND CHIP MODE SELECTIONS ; @@ -416,15 +401,6 @@ SPD_LOW .EQU 2 ; PLATFORM CAN CHANGE SPEED, STARTS LOW ; #INCLUDE "build.inc" ; INCLUDE USER CONFIG, ADD VARIANT, TIMESTAMP, & ROMSIZE ; -#IF (BIOS == BIOS_WBW) -#INCLUDE "hbios.inc" -#ENDIF -; -#IF (BIOS == BIOS_UNA) -#INCLUDE "../UBIOS/ubios.inc" -#ENDIF -; -; ; INCLUDE Z180 REGISTER DEFINITIONS ; #IF (BIOS == BIOS_WBW) @@ -520,17 +496,17 @@ SYSTIM .SET TM_Z280 ; WBW_ROM_R .EQU 128 ; 128K ; RESERVED ROM REQUIRED FOR ROMWBW WBW_RAM_R .EQU 256 ; 256K ; RESERVED RAM REQUIRED FOR ROMWBW -TOT_ROM_RB .EQU (PLT_ROM_R + WBW_ROM_R)/32 ; TOTAL ROM BANKS RESERVED -TOT_RAM_RB .EQU (PLT_RAM_R + WBW_RAM_R)/32 ; TOTAL RAM BANKS RESERVED +TOT_ROM_RB .EQU (WBW_ROM_R / 32) ; TOTAL ROM BANKS RESERVED +TOT_RAM_RB .EQU (WBW_RAM_R / 32) ; TOTAL RAM BANKS RESERVED ; #IF (BIOS == BIOS_UNA) -BID_ROM0 .EQU $0000 + (PLT_ROM_R / 32) -BID_RAM0 .EQU $8000 + (PLT_RAM_R / 32) +BID_ROM0 .EQU $0000 +BID_RAM0 .EQU $8000 #ENDIF ; #IF (BIOS == BIOS_WBW) -BID_ROM0 .EQU $00 + (PLT_ROM_R / 32) -BID_RAM0 .EQU $80 + (PLT_RAM_R / 32) +BID_ROM0 .EQU $00 +BID_RAM0 .EQU $80 #ENDIF BID_ROMN .EQU (BID_ROM0 + ((ROMSIZE / 32) - 1)) @@ -538,13 +514,13 @@ BID_RAMN .EQU (BID_RAM0 + ((RAMSIZE / 32) - 1)) ; BID_RAMD0 .EQU BID_RAM0 ; FIRST RAM DRIVE BANK ^ RAM BID_RAMDN .EQU BID_RAMN - TOT_RAM_RB ; LAST RAM DRIVE BANK | DRIVE -; ; OS BUFFERS CP/M3? -+ THESE -; ; OS BUFFERS CP/M3? | MAKE -; ; OS BUFFERS CP/M3? | UP -; ; OS BUFFERS CP/M3? | THE -BID_AUX .EQU BID_RAMN - 3 ; AUX BANK (BPBIOS, ETC.) | 256KB +; ; OS BUFFERS CP/M3? -+ THESE CPM3 BNK 5 (BUF) +; ; OS BUFFERS CP/M3? | MAKE CPM3 BNK 4 (BUF) +; ; OS BUFFERS CP/M3? | UP CPM3 BNK 3 (BUF) +; ; OS BUFFERS CP/M3? | THE CPM3 BNK 2 (BUF) +BID_AUX .EQU BID_RAMN - 3 ; AUX BANK (BPBIOS, ETC.) | 256KB CPM3 BNK 1 (TPA) BID_BIOS .EQU BID_RAMN - 2 ; BIOS BANK | RESERVED -BID_USR .EQU BID_RAMN - 1 ; USER BANK (CP/M TPA, ETC.) | RAM +BID_USR .EQU BID_RAMN - 1 ; USER BANK (CP/M TPA, ETC.) | RAM CPM3 BNK 0 (OS) BID_COM .EQU BID_RAMN - 0 ; COMMON BANK, UPPER 32K -+ BANKS BID_BOOT .EQU BID_ROM0 + 0 ; BOOT BANK -+ THESE MAKE BID_IMG0 .EQU BID_ROM0 + 1 ; ROM LOADER AND FIRST IMAGES BANK | UP THE 128KB @@ -553,6 +529,46 @@ BID_IMG2 .EQU BID_ROM0 + 3 ; NETWORK BOOT -+ ROM BANKS BID_ROMD0 .EQU BID_ROM0 + 4 ; FIRST ROM DRIVE BANK | ROM BID_ROMDN .EQU BID_ROMN ; LAST ROM DRIVE BANK V DRIVE ; +#IF (ROMSIZE == 0) +BID_BOOT .SET BID_RAM0 ; SPECIAL CASE ROM-LESS SYSTEM +#ENDIF +; +#IF (BIOS == BIOS_WBW) +; + #IF (!MDRAM) +BID_RAMD0 .SET $FF ; RAM DRIVE DISABLED +BID_RAMDN .SET $FF ; RAM DRIVE DISABLED + #ENDIF +; + #IF (!MDROM) +BID_ROMD0 .SET $FF ; ROM DRIVE DISABLED +BID_ROMDN .SET $FF ; ROM DRIVE DISABLED + #ENDIF +; +#ENDIF +; +#IF FALSE + .ECHO "BID_AUX: " \ .ECHO BID_AUX \ .ECHO "\n" + .ECHO "BID_BIOS: " \ .ECHO BID_BIOS \ .ECHO "\n" + .ECHO "BID_USR: " \ .ECHO BID_USR \ .ECHO "\n" + .ECHO "BID_COM: " \ .ECHO BID_COM \ .ECHO "\n" + + .ECHO "BID_BOOT: " \ .ECHO BID_BOOT \ .ECHO "\n" + .ECHO "BID_IMG0: " \ .ECHO BID_IMG0 \ .ECHO "\n" + .ECHO "BID_IMG1: " \ .ECHO BID_IMG1 \ .ECHO "\n" + .ECHO "BID_IMG2: " \ .ECHO BID_IMG2 \ .ECHO "\n" + + .ECHO "BID_ROMD0: " \ .ECHO BID_ROMD0 \ .ECHO "\n" + .ECHO "BID_ROMDN: " \ .ECHO BID_ROMDN \ .ECHO "\n" + .ECHO "BID_RAMD0: " \ .ECHO BID_RAMD0 \ .ECHO "\n" + .ECHO "BID_RAMDN: " \ .ECHO BID_RAMDN \ .ECHO "\n" + + .ECHO "BID_ROM0: " \ .ECHO BID_ROM0 \ .ECHO "\n" + .ECHO "BID_ROMN: " \ .ECHO BID_ROMN \ .ECHO "\n" + .ECHO "BID_RAM0: " \ .ECHO BID_RAM0 \ .ECHO "\n" + .ECHO "BID_RAMN: " \ .ECHO BID_RAMN \ .ECHO "\n" +#ENDIF +; ; MEMORY LAYOUT ; SYS_SIZ .EQU $3000 ; COMBINED SIZE OF SYSTEM AREA (OS + HBIOS PROXY) @@ -670,6 +686,28 @@ INT_SIO1 .EQU 14 ; ZILOG SIO 1, CHANNEL A & B ; Z80-BASED SYSTEMS + + #IF (PLATFORM == PLT_MBC) + +;INT_CTC0A .EQU 0 ; ZILOG CTC 0, CHANNEL A +;INT_CTC0B .EQU 1 ; ZILOG CTC 0, CHANNEL B +;INT_CTC0C .EQU 2 ; ZILOG CTC 0, CHANNEL C +;INT_CTC0D .EQU 3 ; ZILOG CTC 0, CHANNEL D +INT_UART0 .EQU 4 ; MBC UART 0 +INT_UART1 .EQU 5 ; MBC UART 1 +INT_SIO0 .EQU 8 ; ZILOG SIO 0, CHANNEL A & B +INT_SIO1 .EQU 9 ; ZILOG SIO 1, CHANNEL A & B +INT_CTC0A .EQU 12 ; ZILOG CTC 0, CHANNEL A +INT_CTC0B .EQU 13 ; ZILOG CTC 0, CHANNEL B +INT_CTC0C .EQU 14 ; ZILOG CTC 0, CHANNEL C +INT_CTC0D .EQU 15 ; ZILOG CTC 0, CHANNEL D +;INT_PIO0A .EQU 9 ; ZILOG PIO 0, CHANNEL A +;INT_PIO0B .EQU 10 ; ZILOG PIO 0, CHANNEL B +;INT_PIO1A .EQU 11 ; ZILOG PIO 1, CHANNEL A +;INT_PIO1B .EQU 12 ; ZILOG PIO 1, CHANNEL B + + #ELSE + INT_CTC0A .EQU 0 ; ZILOG CTC 0, CHANNEL A INT_CTC0B .EQU 1 ; ZILOG CTC 0, CHANNEL B INT_CTC0C .EQU 2 ; ZILOG CTC 0, CHANNEL C @@ -683,22 +721,23 @@ INT_PIO0B .EQU 10 ; ZILOG PIO 0, CHANNEL B INT_PIO1A .EQU 11 ; ZILOG PIO 1, CHANNEL A INT_PIO1B .EQU 12 ; ZILOG PIO 1, CHANNEL B + #ENDIF + #ENDIF #DEFINE IVT(INTX) HB_IVT+(INTX * 4)+1 #DEFINE VEC(INTX) INTX*2 #ENDIF - +; ; SET DEFAULT CSIO SPEED (INTERNAL CLOCK, SLOW AS POSSIBLE) ; DIV 1280, 14KHZ @ 18MHZ CLK - +; #IF (BIOS == BIOS_WBW) #IF (CPUFAM == CPU_Z180) Z180_CNTR_DEF .EQU $06 ; DEFAULT VALUE FOR Z180 CSIO CONFIG #ENDIF #ENDIF - ; ; HELPER MACROS ; diff --git a/Source/HDIAG/Build.cmd b/Source/HDIAG/Build.cmd index a3d35a56..62ffe922 100644 --- a/Source/HDIAG/Build.cmd +++ b/Source/HDIAG/Build.cmd @@ -8,10 +8,6 @@ set PATH=%TOOLS%\tasm32;%PATH% set TASMTABS=%TOOLS%\tasm32 -set ZXBINDIR=%TOOLS%/cpm/bin/ -set ZXLIBDIR=%TOOLS%/cpm/lib/ -set ZXINCDIR=%TOOLS%/cpm/include/ - tasm -t180 -g3 -fFF -DAPPBOOT hdiag.asm hdiag.com hdiag_com.lst || exit /b tasm -t180 -g3 -fFF -DROMBOOT hdiag.asm hdiag.rom hdiag_rom.lst || exit /b diff --git a/Source/Images/Build.cmd b/Source/Images/Build.cmd index 63c6572d..b9b264e3 100644 --- a/Source/Images/Build.cmd +++ b/Source/Images/Build.cmd @@ -23,6 +23,7 @@ call BuildDisk.cmd nzcom hd wbw_hd512 ..\zsdos\zsys_wbw.sys || exit /b call BuildDisk.cmd cpm3 hd wbw_hd512 ..\cpm3\cpmldr.sys || exit /b call BuildDisk.cmd zpm3 hd wbw_hd512 ..\zpm3\zpmldr.sys || exit /b call BuildDisk.cmd ws4 hd wbw_hd512 || exit /b +call BuildDisk.cmd dos65 hd wbw_hd512 ..\zsdos\zsys_wbw.sys || exit /b if exist ..\BPBIOS\bpbio-ww.rel call BuildDisk.cmd bp hd wbw_hd512 || exit /b diff --git a/Source/Images/Common/All/FIND.COM b/Source/Images/Common/All/FIND.COM index 2ed5c52b..163dcc91 100644 Binary files a/Source/Images/Common/All/FIND.COM and b/Source/Images/Common/All/FIND.COM differ diff --git a/Source/Images/Common/All/ZMRX.COM b/Source/Images/Common/All/ZMRX.COM index 6a5286af..19f317b1 100644 Binary files a/Source/Images/Common/All/ZMRX.COM and b/Source/Images/Common/All/ZMRX.COM differ diff --git a/Source/Images/Common/All/ZMTX.COM b/Source/Images/Common/All/ZMTX.COM index 8d6d85bb..d512481a 100644 Binary files a/Source/Images/Common/All/ZMTX.COM and b/Source/Images/Common/All/ZMTX.COM differ diff --git a/Source/Images/Makefile b/Source/Images/Makefile index bda9e88b..4a6a5f50 100644 --- a/Source/Images/Makefile +++ b/Source/Images/Makefile @@ -16,7 +16,7 @@ HD512PREFIX = HD1024PREFIX = hd1024_prefix.dat OBJECTS = $(FDIMGS) -OBJECTS += $(HD512IMGS) hd512_combo.img $(HD512PREFIX) +OBJECTS += $(HD512IMGS) hd512_dos65.img hd512_combo.img $(HD512PREFIX) OBJECTS += $(HD1024IMGS) hd1024_combo.img $(HD1024PREFIX) OTHERS = blank144 blankhd512 blankhd1024 @@ -71,7 +71,7 @@ blankhd1024: @sys= ; \ case $@ in \ (*cpm22*) sys=../CPM22/cpm_wbw.sys;; \ - (*zsdos* | *nzcom*) sys=../ZSDOS/zsys_wbw.sys;; \ + (*zsdos* | *nzcom* | *dos65*) sys=../ZSDOS/zsys_wbw.sys;; \ (*cpm3*) sys=../CPM3/cpmldr.sys;; \ (*zpm3*) sys=../ZPM3/zpmldr.sys;; \ esac ; \ diff --git a/Source/Images/d_dos65/u0/alloc.co6 b/Source/Images/d_dos65/u0/alloc.co6 new file mode 100644 index 00000000..bf0fda84 Binary files /dev/null and b/Source/Images/d_dos65/u0/alloc.co6 differ diff --git a/Source/Images/d_dos65/u0/asm.co6 b/Source/Images/d_dos65/u0/asm.co6 new file mode 100644 index 00000000..95766085 Binary files /dev/null and b/Source/Images/d_dos65/u0/asm.co6 differ diff --git a/Source/Images/d_dos65/u0/assign.co6 b/Source/Images/d_dos65/u0/assign.co6 new file mode 100644 index 00000000..b84a4efc Binary files /dev/null and b/Source/Images/d_dos65/u0/assign.co6 differ diff --git a/Source/Images/d_dos65/u0/bcompile.co6 b/Source/Images/d_dos65/u0/bcompile.co6 new file mode 100644 index 00000000..bed7b51c Binary files /dev/null and b/Source/Images/d_dos65/u0/bcompile.co6 differ diff --git a/Source/Images/d_dos65/u0/compare.co6 b/Source/Images/d_dos65/u0/compare.co6 new file mode 100644 index 00000000..486a48f3 Binary files /dev/null and b/Source/Images/d_dos65/u0/compare.co6 differ diff --git a/Source/Images/d_dos65/u0/copy.co6 b/Source/Images/d_dos65/u0/copy.co6 new file mode 100644 index 00000000..4bcaaab2 Binary files /dev/null and b/Source/Images/d_dos65/u0/copy.co6 differ diff --git a/Source/Images/d_dos65/u0/cpm.co6 b/Source/Images/d_dos65/u0/cpm.co6 new file mode 100644 index 00000000..d74ddf4a Binary files /dev/null and b/Source/Images/d_dos65/u0/cpm.co6 differ diff --git a/Source/Images/d_dos65/u0/dbasic.co6 b/Source/Images/d_dos65/u0/dbasic.co6 new file mode 100644 index 00000000..b5c19c73 Binary files /dev/null and b/Source/Images/d_dos65/u0/dbasic.co6 differ diff --git a/Source/Images/d_dos65/u0/debug.co6 b/Source/Images/d_dos65/u0/debug.co6 new file mode 100644 index 00000000..612ffeda Binary files /dev/null and b/Source/Images/d_dos65/u0/debug.co6 differ diff --git a/Source/Images/d_dos65/u0/dos65.com b/Source/Images/d_dos65/u0/dos65.com new file mode 100644 index 00000000..207003d6 Binary files /dev/null and b/Source/Images/d_dos65/u0/dos65.com differ diff --git a/Source/Images/d_dos65/u0/dos65.hex b/Source/Images/d_dos65/u0/dos65.hex new file mode 100644 index 00000000..393d60db --- /dev/null +++ b/Source/Images/d_dos65/u0/dos65.hex @@ -0,0 +1,321 @@ +:203800004C21CED84820FCBB682000BCAD92CC4A4A4A4A8DF6BFAD43BFD03CA2FF9AD8A946 +:203820001120F0BB2069BCA93E20F0BBAD8BBEAC8CBE20F4BBA000AE43BFF0DFB944BFC956 +:20384000619009C97BB005295F9944BFC8CAD0EC8A9944BF8DE7BF20A4BD202BBC8DE8BFEE +:2038600020A5BCD064ADE9BFF004A915D02EA900AA8DECBFA001BD1DBFF01AD9C3BFD00490 +:20388000E8C8D0F2E8BD1DBFD0FAE8EEECBFADECBFC907D0DFADECBF0A6DECBFAAE8BD96B4 +:2038A000BEBC97BE8DEABF8CEBBFAD8FBE48AD8EBE486CEABF2034BC20A5BCADC4BF38E953 +:2038C000200DE9BFD0034C1BB820E1BBACEDBFB944BFF00AC920F0062072BCC8D0F1A93FB9 +:2038E00020F0BB4C1BB820A5BC20ABBDA920CDC4BFD00FCDCCBFD00AA93FA00B99C3BF8875 +:20390000D0FA205FBC3058ADF6BF8DF5BF20E1BB206CBCA93A20F0BBADEEBF0A0A0A0A0A39 +:203920002960A8C8A201B92801297F2072BCC8E8E00CF00CE009D0EEA92E2072BC4C26B984 +:2039400020F8BBD0192097BC2010BC8DEEBF300ECEF5BFF0B220EEBB20EEBB4C10B960A009 +:20396000344CC0BD20A5BCD057209EBC20ABBD205FBC304F20E0BDACE7BFB944BFC920D062 +:203980003C20A5BCD037ADE9BFF012CDF2BFF00D38E901CDE8BFD025ADF2BFD020ADF2BF5A +:2039A0008DE9BFA9008DD3BF20ABBD205FBC100920E0BD2097BC4C27BCA03ED0082034BC09 +:2039C0004CC9B8A0344CC0BDA900A0088DFCBF8CFDBF2005BED07A8DF1BF0DF1BFF07220F3 +:2039E000A5BCD06D20E0BD209EBC2005BEAEC4BFE020F00A8DFCBF8CFDBFC002905320F39C +:203A0000BD20ABBD2014BC2097BC2023BC3045204ABC304418ADFDBF6DF1BF8DF1BFADFC6C +:203A2000BFACFDBF8DF3BF8CF4BF20CACA2097BC201FBCD02718ADF3BFACF4BF6980900376 +:203A4000C8F005CCF1BFD0DC2097BC2008BC3010604CC9B8A001D00AA055D006A062D002A3 +:203A6000A00A4CC0BD20A5BCC90BD013A01820C0BD20EABB4820E1BB68295FC959D0D120AA +:203A8000ABBD4C14BC20A5BCD0302047BC303220E1BB2059BCF00410203022A200BD2801AD +:203AA000C91AF0152072BC20F8BBD008AEEFBFE810EB30DEA206200301604CC9B8A029D046 +:203AC00002A0344CC0BD20D5BD20A5BCD0EC20E0BD209EBC2005BEAEC4BFE020F00320D921 +:203AE000BD20F3BD2047BC30D8ADF3BFACF4BF202FBC2059BCD00620B7CA4CEFBA30BE4C6A +:203B0000A4BD2005BEAEC4BFE020F0034C76BB4C72BBADC4BFC920D011ADE9BFF00938E9DE +:203B2000018DE8BF2000BC4CB8B8ADCCBFC920F0034CD9BBA202BDE4BF9DCCBFCA10F720A7 +:203B400047BC10034CD6BB20D5BD202FBC2059BCD01E20B7CACD91BE9007CC92BE90EBB0F7 +:203B600007CC92BE90E4F0E220A4BD2059BCF06C306AA900A0088DCBBB8CCCBB2034BC2089 +:203B8000A5BCADE9BF8DC3BFA21020A7BCADE9BF8DD3BFA0008CE3BFA220BDC3BF9D070143 +:203BA000CA10F7E8B944BFF007C920F003C8D0F4A9008D2801B944BF9D2901F007E8C8EEBA +:203BC0002801D0F120E1BB20A4BD200008ADE8BF2000BC4C1BB82034BC4CC9B8A04A4CC074 +:203BE000BDA90D20F0BBA90AD006A201D043A920A202D03DA20AD039A20BD035A20DD031B7 +:203C0000A20ED02DA20FD029A210D025A211D021A212D01D2097BCA213D016A214D012A219 +:203C200015D00EA216D00AA217D006A219D002A21A4C0301ADE9BFF01F38E901CDE8BFF0ED +:203C400017ADE8BF4C00BC20ABBDA9008DE3BF2097BC2004BC8DEEBF602097BC4C1BBC20EE +:203C600097BC200CBC8DEEBF6020E1BB202BBC1869418EEFBF8CF0BF20C1C8B01048AD9085 +:203C8000CC20F0BB68094020F0BBAD8FCC20F0BBACF0BFAEEFBF60AD94BEAC95BE60ADE933 +:203CA000BF8DF2BF60A2008A48A9008DE9BFACE7BF2072BD8CEDBFF00D290F48C8B944BF7B +:203CC000C93AF00A6888ADE8BF9DC3BF1008688DE9BF9DC3BFC8A9088DECBF207FBDF01D96 +:203CE000E8C92AD007A93F9DC3BFD0049DC3BFC8CEECBFD0E6207FBDF011C8D0F8E8A92083 +:203D00009DC3BFCEECBFD0F5B944BF48A9038DECBF68C92ED023C8207FBDF01DE8C92AD030 +:203D200007A93F9DC3BFD0049DC3BFC8CEECBFD0E6207FBDF00EC8D0F8E8A9209DC3BFCE03 +:203D4000ECBFD0F5A9038DECBFE8A9009DC3BFCEECBFD0F58CE7BFA9008DECBF68A8A20B51 +:203D6000C8B9C3BFC93FD003EEECBFCAD0F2ADECBF60B944BFF007C920D003C8D0F460B974 +:203D800044BFF01CC9209019F016C93DF012C92EF00EC93AF00AC93BF006C93CF002C93E8A +:203DA000604CC9B8A928A0014C2FBCA9008DC3BFADE9BFF01F38E901CDE8BFF0174C00BC6C +:203DC0008CF0BF20E1BBACF0BFB9AFBEF0062072BCC8D0F560A900A0088DF3BF8CF4BF600B +:203DE000A20FBDC3BFBCD3BF9DD3BF989DC3BFCA10F060A20FBDD3BF9DC3BFCA10F7ADF2E6 +:203E0000BF8DE9BF60A9098DF7BF20A5BCADE9BFD0678DF8BF8DF9BFA8B9C4BFC924D0061C +:203E2000A90F8DF7BFC8C8B9C3BFC920F04E20A1CA900E20ABCAB041E906A20FECF7BFD0D4 +:203E400038290F48ADF8BF8DFABFADF9BF8DFBBFAEF7BF18ADF8BF6DFABF8DF8BFADF9BFA5 +:203E60006DFBBF8DF9BFB011CAD0E9686DF8BF8DF8BF90B2EEF9BFD0AD4CC9B8ADCCBFC98F +:203E800020D0F6ADF8BFACF9BF604C42BF4CB4B84C03B84CC3BF4CE6B84CC8B94C65BA4CCC +:203EA00085BA4C64B94C02BB4CC6BA4C12BBFF004E4F2053504143450043414E204E4F5461 +:203EC00020434C4F534500414C4C2046494C45532028592F4E293F00524541442045525235 +:203EE0004F52004E4F5420464F554E440046494C4520455849535453004C4F41442045529D +:203F0000524F520043414E204E4F54204F50454E005752495445204552524F520044495265 +:203F20002000534156452000455241200054595045200052454E2000474F20004C4F4144DD +:203F400020007F0000000000000000000000000000000000000000000000000000000000C2 +:203F6000000000000000000000000000000000000000000000000000000000000000000041 +:203F8000000000000000000000000000000000000000000000000000000000000000000021 +:203FA000000000000000000000000000000000000000000000000000000000000000000001 +:203FC0000000000000000000000000000000000000000000000000000000000000000000E1 +:203FE00000000000434F360000000000000000000000000008000009000000000008D88D7B +:2040000098CB8DDCCB8C99CB8CDDCB8E9ACBE024B050BD54CBF008A9FF8D97CB20E9C2A90F +:20402000008D9FCBAD9ACB0A6D9ACBAAE8BD76C0BC77C08DA0CB8CA1CBADE4CA48ADE3CA36 +:2040400048AD98CBAC99CB6CA0CB8D9BCB8C9CCBAD9FCBF00DA0009102ADA9CB8D98CB20C3 +:2040600004C32C97CB100820E9C2A9008D97CBAC9CCBAD9BCB604CEAC04CDBC24C19C94C91 +:204080006BCC4C68CC4C65CC4C8BC84C1FC14C2AC14CD0C84C85C94C9BC84C83CC4C32C3E1 +:2040A0004C04C34CAFC54CEAC54C0EC64C3AC14CA2C14C42C14CC7C14CB7C64C80C14C3225 +:2040C000C14C2EC14CF9C24C23C14C6DC54C36C14CE2C04CE6C04CFAC04C0EC14C18C14C7A +:2040E00089CC8D95CB60AD95CB602C97CB100820E9C2A9008D97CB4C59CC2086CC8DC5CBA8 +:204100008CC6CB8EC7CB8A2980A8ADC5CB60ADC7CB297FA8ADC6CB60AD6CC3AC6DC360ADF8 +:20412000060160ADD4CBACD5CB608D060160ADAACB60ADABCB60ADACCB602012C3A90D4CAC +:204140001BC62012C3208FC5ADB5CBCDB6CB9013C980F003A90160A20120F3C6C900D0F4A8 +:204160008DB5CB2084C7ADB0CB0DB1CBD003A902602066C620ACC4203DC8209EC5A90060AB +:204180002012C3201AC8A90C2013C63014A900A0109102A90CA2102086C6A90C201BC610B1 +:2041A000EC602012C3201AC8A90C2013C63017A20020EAC7ACAFCBAD53CB91042043C8A9FA +:2041C0000C201BC610E9602012C3201AC8208FC5ADB5CBC9809003A901602084C7A9008D5A +:2041E000D9CBADB0CB0DB1CBF0034CAAC2A9028DD9CBAD91CB48C910F01AA8882CC0CB10B8 +:204200000188B1028DB0CBC8A9002CC0CB1002B1028DB1CBADB0CB8DA5CB8DA7CBADB1CB17 +:204220008DA6CB8DA8CBADA7CBCDCBCBD008ACA8CBCCCCCBF012EEA7CBD003EEA8CBADA5BC +:20424000CB0DA6CBF018D00BADA5CB0DA6CBD003A8F030ADA5CBD003CEA6CBCEA5CBADA53D +:20426000CBACA6CB2051C5D009ADA5CBACA6CB4C83C2ADA7CBACA8CB2051C5D0A9ADA7CB70 +:20428000ACA8CB8DB0CB8CB1CB0DB1CBD00468A90260ADB0CB2065C568A8ADB0CB9102AD35 +:2042A000B1CBC82CC0CB100291022066C620ACC42049C8AEB5CBECB6CB9005E88EB6CBCA60 +:2042C000E07FD011209EC5A20020F3C6C900D00AA9FF8DB5CB209EC5A90060208BC820C168 +:2042E000C89005482019C96860A207B502BCDCCB9DDCCB9402CA10F360A502A4038504842A +:20430000054C7ACCAD98CBCDAACBF0EC8DAACB4C45C3A000B102F01938E90129078D98CBE4 +:20432000ADAACB8DA9CBB1028D9FCB9891022004C360A9028DAACB8DABCBA928A001850295 +:20434000840320F9C2ADAACBC908900F206CC8ADE6CAACE7CA20D0C84CEAC02071CC8D6C57 +:20436000C38C6DC30D6DC3F0E3A00DB9FFFF99CBCB8810F7ADD1CBA81869038DC4CBB98BB7 +:20438000CB8DC3CBADD2CB8DC1CBADD3CB4A6EC1CB4A6EC1CB8DC2CBA9008DC0CBADCCCBE2 +:2043A000F00588386EC0CBB988CB8DDACB38A91FF988CB8DDBCBAEAACBBD80CB2DABCBD0F4 +:2043C0000CBD80CB0DABCB8DABCB4CCEC360202EC8ADCBCB8DC8CBADCCCBA2034A6EC8CB59 +:2043E000CAD0F98DC9CBEEC8CBD003EEC9CBADD4CBACD5CB85068407A000A9009106E606B9 +:20440000D002E607ADC8CBD003CEC9CBCEC8CBADC8CB0DC9CBD0E3ADC1CB8DC8CBADC2CBE0 +:20442000AEC4CB4A6EC8CBCAD0F98DC9CBEEC8CBD003EEC9CB8EB0CB8EB1CBADB0CBACB1D2 +:20444000CB2065C5EEB0CBD003EEB1CBADC8CBD003CEC9CBCEC8CBADC8CB0DC9CBD0DC201E +:204460007EC420DEC7A2012026C73011ACAFCBB104C9E5F0F0A20120EAC74C65C460206E04 +:20448000CCADCFCBACD0CB4C74CCADAECB8DB1CBADADCB4EB1CB6A4EB1CB6A8DB7CB8DB02E +:2044A000CBADB1CB8DB8CBA9008DB2CBA2008ECACB8EA2CB8EA3CB8EA4CBADB0CBCDA2CB2A +:2044C000ADB1CBEDA3CBADB2CBEDA4CB902118ADA2CB6DCDCB8DA2CBADA3CB6DCECB8DA39F +:2044E000CB9003EEA4CBE8D0D1EECACB4CBAC4CAE0FFD003CECACB8A186DCFCBAAADCACBB7 +:204500006DD0CBA88A2074CC38ADA2CBEDCDCB8DA2CBADA3CBEDCECB8DA3CB38ADB0CBED47 +:20452000A2CBAAADB1CBEDA3CBA88A2089CC4C77CC488407A00346076A88D0FA186DD4CB07 +:204540008506A5076DD5CB8507682907AABD78CB602031C5310660E001F00A2031C549FF03 +:2045600031069106602031C51106910660AEAACBBD80CB0DACCB8DACCB60A900A07F187185 +:20458000048810FA60AEAACBBD80CB2DACCB60A020B1028DB5CBA00FB1028DB6CB60AEB543 +:2045A000CBE88AA0209102ADB6CBA00F9102602012C32011C63032A90C0DAFCBA8B104AA0A +:2045C00098291FA88A9102980DAFCBA8C898291FD0EBA00CAD92CBD102F00B9102A980903C +:2045E000010AA00F9102ADB9CB602012C32011C6301B2085C5D013A00CB10248980DAFCB93 +:20460000A868D1046E90CB2082C6ADB9CB602012C3A90D4820DEC7207EC4688DB3CBA200C4 +:204620008EB4CB2026C7303DAEB3CBACB4CBEEB4CBB102C00CD0138D92CB48980DAFCBA8D4 +:204640006851042DDBCBF017D0D4C93FF01148980DAFCBA868851CB104297FC51CD0BFCA67 +:20466000D0C9ADB9CB60AEC4CB0EB0CB2EB1CB2EB2CBCAD0F4ADC3CB2DB5CB0DB0CB8DB0BA +:20468000CB60A920A2008DB3CBCEB3CB188A6DB3CBA8C00CF004C00FD0052C90CB100DB13F +:2046A0000248ADB3CB0DAFCBA8689104CEB3CB10DB208AC44C43C82012C3201AC8A5024877 +:2046C000A50348ADE9CAACEACA85028403A9012013C6688503688502ADB9CB3015A00DA9CE +:2046E000009102C8C021D0F9386E90CB2082C6ADB9CB608E9ECB20EDC5302AA00CB1021821 +:204700006901291FF01791022011C6100BAD9ECBD01320BAC64C1BC720B2C51003A90160C0 +:20472000208FC5A900608A48EEADCBD003EEAECBADD2CBCDADCBADD3CBEDAECBB00568AA83 +:204740004CDEC7ADADCB29038DB9CB0A0A0A0A0A8DAFCBF00568AA4C62C7208AC4203DC8BE +:2047600068AAADB9CB602CD6CB30FACAD009207AC520C8C7910860207AC520C8C7D108F01E +:20478000E44C6DC5AEC4CBADB5CB4ACAD0FC8DB0CB38A908EDC4CBAAA00CB1022DDACB4ADB +:2047A0002ACAD0FC186DB0CB2CC0CB10010A1869108D91CBA8B1028DB0CBC8A9002CC0CB62 +:2047C0001002B1028DB1CB604818ADB7CB6DD7CB8508ADB8CB6DD8CB8509A0006860A9FFA2 +:2047E0008DADCB8DAECB8DB9CB6018ADAFCB6910A88CBECB8A48B1048DBFCBC8207EC80DEF +:20480000BFCBF00A207EC8A8ADBFCB2057C568AAACBECBC898290FD0D8602085C5F01D2015 +:204820006CC8ADECCAACEDCA20D0C84CEAC0AEAACBBD80CB49FF2DACCB8DACCB60207DCCEC +:204840004C4FC8A201A901D003ADD9CB2080CCC900F0E9206CC8ADEFCAACF0CA20D0C8207E +:204860008BC8C90DF0034CEAC04C67CAADF2CAACF3CA20D0C8ADAACB1869414C19C9A90064 +:204880002CC0CB1005B1048CBECB60AD94CB48A9008D94CB68D003205FCC60AD94CBD02057 +:2048A000205CCCC900F019205FCCC913D00D205FCCC903D0034CEAC0A900608D94CBA9FF5D +:2048C00060C90DF00AC90AF006C909F002C920608DD9C88CDAC8A000B9FFFFC924F00CC86E +:2048E0008CBACB2019C9ACBACBD0ED602C95CB100A2CBCCB3005482065CC686020C1C8B00F +:204900001848AD90CC2032C9A95E20ECC8680940202AC9AD8FCC4C32C9C909D00DA920208D +:204920002AC9AD96CB2907D0F46048209BC86820ECC8482CBCCB30032062CC68EE96CBC91F +:2049400020B026CD8ECCF021CE96CBCD8CCCD006CE96CB300F60C90DF00ACD93CCF005CD73 +:2049600094CCD005A9008D96CB60A90D202AC9A90A20ECC8AD93CBCD96CBF0EDAD8ECC207E +:2049800032C94C74C9A900A00191028C9DCBAD96CB8D93CB208BC8AC9DCBC90DD0034C64E9 +:2049A000CAC908D05EC001F0EBB10248A00138B102E901910268CE9DCBC920B040C909D075 +:2049C00030386EBCCBAD96CB8DBDCB206AC92071CAAD96CB4838ADBDCBED96CB8DBDCB0E75 +:2049E000BCCB2091CACEBDCBD0F8688D96CB4C94C9AD8FCC208DCAAD90CC208DCA2091CA1E +:204A00004C94C9C910D00BAD95CB49FF8D95CB4C94C9C918D00C206AC9AD8DCC2032C94CD1 +:204A200085C9C912D009206AC92071CA4C94C9C89102488C9DCBA0019818710291026820A7 +:204A4000FCC8AC9DCBB102C903D00BA001B102C901D0034CEAC0A001B10288D102B0034C8F +:204A600094C9A90D4C2AC9A90D202AC9A90A4C2AC9AD9DCB8DBBCBA9014868CEBBCBD00182 +:204A800060A8C89848B10220FCC84C7ACAC9209019AD8CCC482032C9A9202032C9684C327B +:204AA000C9C9309004C93A9001386020A1CA90FAC94190F5C94760ADF3BFACF4BF186980A1 +:204AC0008DF3BF9004C88CF4BF60ADF3BFACF4BF8DD9CA8CDACAA200BDFFFF9D2801E81063 +:204AE000F7604C49C04C42CB4C53CB4CF8CA4CFFCA4C32CB4CCBCBFF202D20522F4F242079 +:204B00002D2042414420534543544F520D0A3C5245543E20544F2049474E4F5245202D2DF4 +:204B2000203C4F544845523E20544F2041424F5254240D0A50454D204552524F52204F4E7A +:204B40002024202D20494E56414C494420445249564524E5000000000000000000000100F9 +:204B600000010101010101010101010100000100000000000000000080402010080402012A +:204B80000102040810204080000103070F1F3F7F000000000000000000000000000000001F +:204BA0000000000000000000000000000000000000000000000000000000000000000000F5 +:204BC0000000000000000000000000000000000000000000000000000000000000000000D5 +:204BE0000000000048DA5AAA4A4A4A4A1820F8CB8A20F8CB7AFA6860290F0930C93A30031C +:204C00001869074CB5CE48DA5AA90D20B5CEA90A20B5CE7AFA68605ADA48A000A2FF38E8F9 +:204C2000E964B0FB69642040CCA2FF38E8E90AB0FB690A2040CCAAA0012040CC68FA7A60D2 +:204C400048C000D0098AA8C000D0034C54CC8A093020B5CE68604CAECD4C21CE4CAFCE4CFD +:204C6000B2CE4CB5CE4CB8CE4CB9CE4CBACE4C5ACE4C29CE4C5ECE4C66CE4CAACE4C6DCE72 +:204C80004C8BCEA901604CBBCE4CBCCE08010C005E18500C1E020D0A6438383838622E20A8 +:204CA000202E643838622E20202E64383838382E20202020644420202020206F6F6F6F6F6F +:204CC0000D0A38382020603844202E3850202059382E2038382020205950202020643820A7 +:204CE0002020202038507E7E7E7E0D0A3838202020383820383820202020383820603862C3 +:204D00006F2E202020206438202020202064500D0A383820202038382038382020202038E7 +:204D200038202020605938622E206438383838622E205638383838622E0D0A0038382020B9 +:204D40002E384420603862202064382720646220202038442038382020603844202020209E +:204D6000206038440D0A593838383844202020605938385020202060383838385920206031 +:204D80003838383850202038386F6F62590D0A11444F532F3635204F4E20544845204E487E +:204DA000594F44594E4520332E30300D0A0078A2FF9AD8A996A0CC20BDCEA93CA0CD20BD13 +:204DC000CE2006CC2075D820AFD0201ED5207DD7546E5C5E6E54794020B9D7A9448530A98E +:204DE000BF8531A94A852EA9CE852F2037CF20B9D8A2008E88DA8E89DABD1BCE9D0001E8E7 +:204E0000E006D0F5A928A00120AACEAD82DAA9022029CE205ACEA9024C03B84C59CC4CFE5D +:204E2000BF78A2FF9AD84CEECD29078D82DAAD82DA0AAABD3ACEBC3BCE6012DA20DA2EDA73 +:204E40003CDA4ADA58DA66DA74DA00000100300030013002300330043006A900A000188D39 +:204E60008ADA8C8BDA608D8CDA8C8DDA60201BCF29F0C900D004202CD960C920D003A9FF8E +:204E800060C930D0034C70D2A9FF60201BCF29F0C900D0042060D960C920D003A9FF60C94A +:204EA00030D00420C4D260A9FF6085F484F5604C9DD04C8ED04C6FD0606060606085F084B7 +:204EC000F1A000B1F0C900F00720B5CEC84CC3CE6048AD8CDA2903182AAABDF2CE85EEE8ED +:204EE000BDF2CE85EFA5F485ECA5F585ED2028CF686009E389E309E489E448AD8CDA290393 +:204F0000182AAABDF2CE85ECE8BDF2CE85EDA5F485EEA5F585EF2028CF6860DAAD82DA29DB +:204F2000070AAABD4ACEFA605AA000B1EE91ECC898C980D0F67A602006CC48DA5AA200BD5B +:204F400053CFE8C924F00620B5CE4C3FCF7AFA684C67CF4469736B20436F6E666967757221 +:204F60006174696F6E3A242006CCA20048DA5AA200BD85CFE8C924F00620B5CE4C71CF7A81 +:204F8000FA684C8ACF20202020248A4A18694120B5CEA93A20B5CEA93D20B5CE20B4CFA9D2 +:204FA0003A20B5CEE8BD4ACE2017CCE82006CCE010D0B960BD4ACE4829F0C900D01F48DA91 +:204FC0005AA200BDD7CFE8C924F00620B5CE4CC3CF7AFA684CDACF4D44244C67D0C910D074 +:204FE0002048DA5AA200BDFACFE8C924F00620B5CE4CE6CF7AFA684CFECF554E4B244C67C4 +:20500000D0C920D01F48DA5AA200BD1ED0E8C924F00620B5CE4C0AD07AFA684C21D04644E8 +:20502000244C67D0C930D02248DA5AA200BD41D0E8C924F00620B5CE4C2DD07AFA684C47CC +:20504000D05050494445244C67D048DA5AA200BD63D0E8C924F00620B5CE4C4FD07AFA68A4 +:205060004C67D0554E4B2468290F2017CC606048AD6D032920C900F0F7688D680360AD6D00 +:20508000032901C900F004AD680360A90060AD6D032901C900F0F7AD6803297F60AD6D0371 +:2050A0002901C900F003A9FF60A9006000000048DA5AA200BDC8D0E8C924F00620B5CE4CCC +:2050C000B4D07AFA684CD0D05050494445203A242006CC2062D2D03548DA5AA200BDF1D0AD +:2050E000E8C924F00620B5CE4CDDD07AFA684CF8D020494F3D307824A90320E4CBA96020F4 +:20510000E4CB20F7D2209BD1B0034C36D148DA5AA200BD26D1E8C924F00620B5CE4C12D1F6 +:205120007AFA684C33D1204E4F542050524553454E54244C97D12006CC48DA5AA200BD52FA +:20514000D1E8C924F00620B5CE4C3ED17AFA684C63D1205050494445303A20426C6F636B52 +:20516000733D24A90020DBD148DA5AA200BD81D1E8C924F00620B5CE4C6DD17AFA684C9207 +:20518000D1205050494445313A20426C6F636B733D24A90120DBD12006CC60A9008D600301 +:2051A0002022D3B034A90F20D4D48A2940C900F028A90A20D4D4E001D01FA90B20D4D4E0FB +:2051C00001D016A90C20D4D4E000D00DA90D20D4D4E000D004184CDAD1386029010A0A0A8D +:2051E0000A09E0AAA000A90E20F2D42022D3B048A90FA2EC20F2D4204AD3B03C207AD348BE +:20520000DA5AA200BD18D2E8C924F00620B5CE4C04D27AFA684C1BD2307824AD84E320E488 +:20522000CBAD83E320E4CBAD82E320E4CBAD81E320E4CB2006CC186048DA5AA200BD51D298 +:20524000E8C924F00620B5CE4C3DD27AFA684C5DD24E4F542050524553454E54242006CCE6 +:2052600038602016D5A9008D6003AD6003C900602077D220D1CE602019D4AD90DACD95DAD1 +:20528000D013AD8FDACD94DAD00BAD8EDACD93DAD003A900602022D3B02720E6D3A90FA2B5 +:2052A0002020F2D4204AD3B018207AD3AD90DA8D95DAAD8EDA8D93DAAD8FDA8D94DAA9009A +:2052C00060A9FF602077D220FACE2022D3B02520E6D3A90FA23020F2D4204AD3B01620AF10 +:2052E000D32022D3B00EA9FF8D95DA8D93DA8D94DAA90060A9FF60A9008D90DA8D8EDA8D3C +:205300008FDAA9FF8D95DA8D93DA8D94DAA9808D6203A200CAE000D0FBA9008D6203200A94 +:20532000D660DA5A48A9008DADD08DAED0A90F20D4D48A2980F00EEEADD0D0F1EEAED0D0E4 +:20534000EC384C46D318687AFA60DA5A48A9008DADD08DAED0A90F20D4D48A2988C908F0BA +:20536000142901C901F00AEEADD0D0E9EEAED0D0E4384C76D318687AFA60A2008EACD0A971 +:205380000820D4D48AAEACD09D09E3E8989D09E3E8E000D0E78EACD0A90820D4D48AAEAC11 +:2053A000D09D09E4E8989D09E4E8E000D0E760A2008EACD0BD0AE3A8BD09E3AAA90820F296 +:2053C000D4AEACD0E8E8E000D0E7A2008EACD0BD0AE4A8BD09E4AAA90820F2D4AEACD0E86C +:2053E000E8E000D0E760201BCF29010A0A0A0A09E0AAA000A90E20F2D4AE8FDAA90D20F2C3 +:20540000D4AE8EDAA90C20F2D4AE90DAA90B20F2D4A201A90A20F2D460AD8ADA290F0A0A5C +:205420000A0AAAAD8CDA4A4A290F8D90DA8A0D90DA8D90DAAD8ADA8D8EDAAD8BDA8D8FDAD2 +:20544000AD8FDA4A8D8FDAAD8EDA6A8D8EDAAD8FDA4A8D8FDAAD8EDA6A8D8EDAAD8FDA4A58 +:205460008D8FDAAD8EDA6A8D8EDAAD8FDA4A8D8FDAAD8EDA6A8D8EDAAD82DA29070AAAE823 +:20548000BD4ACE8D98DAA9008D97DA186E98DA6E97DA6E98DA6E97DABD4ACE186D97DA8DA3 +:2054A00097DA18AD97DA6D8EDA8D8EDAAD98DA6D8FDA8D8FDAAD82DA8D71D8AD8FDA8D729C +:2054C000D8AD8EDA8D73D8AD90DA8D74D82090D620C5D660200ED58D620309408D620348FE +:2054E000AE6003AC61036849408D6203A9008D6203602016D58E60038C61038D62030920A6 +:205500008D620349208D6203A9008D62036048A9928D6303686048A9808D6303686020DADF +:20552000D548DA5AA200BD3AD5E8C924F00620B5CE4C26D57AFA684C40D544534B593A2421 +:205540002006CC48DA5AA200BD5CD5E8C924F00620B5CE4C48D57AFA684C63D520494F3D21 +:20556000307824A90320E4CBA96020E4CB48DA5AA200BD86D5E8C924F00620B5CE4C72D5D5 +:205580007AFA684C8DD5204D4F44453D2448DA5AA200BDA6D5E8C924F00620B5CE4C92D564 +:2055A0007AFA684CA9D54E4724AD68D8C9FFF02648DA5AA200BDC9D5E8C924F00620B5CEDA +:2055C0004CB5D57AFA684CD6D5204E4F542050524553454E54242006CC60201FD6D02A202B +:2055E00041D8A9068D620309808D6203297F8D6203200AD6A9A5A000205BD7A000206FD796 +:20560000C9A5D005A9FF8D68D8602053D8A92120DBD6A9DF20DBD6A200DAFACAD0FB6020A8 +:205620002AD8A9008D6003AD6003C90060AD68D8C9FFD0052014D7290F60AD68D8C9FFD0E4 +:2056400024202DD6F0F4A94020DBD62019D749C048293F8D66D8A200BD74D6CD66D8F00924 +:20566000E8E01CD0F368A9FF606825C08D66D88A0D66D8600D040C14030B13020A1201094C +:205680001100081005151D1C1B1A191823222120A200BD71D84A4A4A4ADAAABD56D8FADA8F +:2056A000488A0AAA689D69D8FABD71D8290FDAAABD56D8FADA488A0AAAE8689D69D8FAE80D +:2056C000E004D0CE6048DA5AA200BD69D8DA7A205BD7E8E008D0F37AFA686048A9014CE435 +:2056E000D648A900202AD809068D620309188D62038D66D8688D6003AD66D829FD8D620387 +:20570000EA09028D620329E78D620329E68D62032053D860A9014C1BD7A9002041D809061B +:205720008D620309188D6203297B8D62038D66D8AD600348AD66D809048D620329E78D62C2 +:205740000329E68D62032053D86860A99020DBD6A210A9FF20E1D6CAD0F8605A484818986B +:205760006990A820DBD66849FF20E1D6687A6018986970A820DBD62019D749FF608E66D868 +:20578000BA6885146885159AAE66D8DA5A4818E6149002E615A000B114205BD7C8C008D094 +:2057A000F6687AFA8D66D81868690885149003681A48A51448AD66D8605ADA48A00F206F5F +:2057C000D70920A920A00F205BD7A28FA0FF88D0FDCAD0FAA00F206FD729DFA9DFA00F20D2 +:2057E0005BD768FA7A605A48A00D206FD70920A00D205BD7687A605A48A00E206FD709203D +:20580000A00E205BD7687A605A48A00D206FD729DFA00D205BD7687A605A48A00E206FD792 +:2058200029DFA00E205BD7687A6048AD67D8C982F00DA9828D63038D67D8A9068D620368AF +:205840006048AD67D8C992F008A9928D63038D67D868604C41D83F065B4F666D7D077F670E +:20586000777C395E797100000000000000000000000000000048DA5AA200BD8ED8E8C9249E +:20588000F00620B5CE4C7AD87AFA684CB6D84D443A20554E4954533D322052414D4449534E +:2058A0004B3D3235364B4220524F4D4449534B3D3338344B42242006CCA200BDC7D89D00E3 +:2058C00002E8E000D0F560488415A00084148A2980C900D0388A2940C900D00DA9808D7CF1 +:2058E000036809808D7803D00BA9008D780368297F8D7C03A200DA7AB1149D0004E8E000E0 +:20590000D0F4A9808D7C03A98E8D7803606809808D7803A200DA7ABD00049114E8E000D002 +:20592000F4A9808D7C03A98E8D7803602035D920C6D9A90060201BCF29010A0A0A0A0A0A39 +:20594000297FAA2083D9E000F00CEE8EDAEE8EDAEE8EDAEE8EDAAD8EDAAC90DA2000026098 +:20596000201BCF2901C900F003A9FF602035D92083D920ECD9AD8EDAAC90DAA28020000231 +:20598000A90060DAAD8CDA4A291F8D90DAAD8ADA29030A0A0A0A0A09800D90DA8D90DAAD75 +:2059A0008ADA4A4A8D8EDAAD82DA8D71D8A9008D72D8AD8EDA8D73D8AD90DA8D74D820900E +:2059C000D620C5D6FA6048AD8CDA2901C900D007A90085EE4CDBD9A98085EEA90485EFA539 +:2059E000F485ECA5F585ED2028CF686048AD8CDA2901C900D007A90085EC4C01DAA9808543 +:205A0000ECA90485EDA5F485EEA5F585EF2028CF68607F004000000001FF0099DA0089E2E5 +:205A2000BF0040000000019B0097DB0089E2FF074000100002FF0195DC0089E2FF07400074 +:205A4000100002FF0193DD0089E2FF074000100002FF0191DE0089E2FF074000100002FFD0 +:205A6000018FDF0089E2FF074000100002FF018DE00089E2FF074000100002FF018BE10058 +:205A800089E202000000000000000000000000000000000000000000000000000000000099 +:205AA0000000000000000000000000000000000000000000000000000000000000000000E6 +:205AC0000000000000000000000000000000000000000000000000000000000000000000C6 +:205AE0000000000000000000000000000000000000000000000000000000000000000000A6 +:205B0000000000000000000000000000000000000000000000000000000000000000000085 +:205B2000000000000000000000000000000000000000000000000000000000000000000065 +:205B4000000000000000000000000000000000000000000000000000000000000000000045 +:205B6000000000000000000000000000000000000000000000000000000000000000000025 +:205B8000000000000000000000000000000000000000000000000000000000000000000005 +:205BA0000000000000000000000000000000000000000000000000000000000000000000E5 +:205BC0000000000000000000000000000000000000000000000000000000000000000000C5 +:205BE0000000000000000000000000000000000000000000000000000000000000000000A5 +:205C0000000000000000000000000000000000000000000000000000000000000000000084 +:205C2000000000000000000000000000000000000000000000000000000000000000000064 +:205C4000000000000000000000000000000000000000000000000000000000000000000044 +:205C6000000000000000000000000000000000000000000000000000000000000000000024 +:205C8000000000000000000000000000000000000000000000000000000000000000000004 +:205CA0000000000000000000000000000000000000000000000000000000000000000000E4 +:205CC0000000000000000000000000000000000000000000000000000000000000000000C4 +:205CE0000000000000000000000000000000000000000000000000000000000000000000A4 +:205D0000000000000000000000000000000000000000000000000000000000000000000083 +:205D2000000000000000000000000000000000000000000000000000000000000000000063 +:205D4000000000000000000000000000000000000000000000000000000000000000000043 +:205D6000000000000000000000000000000000000000000000000000000000000000000023 +:205D8000000000000000000000000000000000000000000000000000000000000000000003 +:205DA0000000000000000000000000000000000000000000000000000000000000000000E3 +:205DC0000000000000000000000000000000000000000000000000000000000000000000C3 +:205DE0000000000000000000000000000000000000000000000000000000000000000000A3 +:205E0000000000000000000000000000000000000000000000000000000000000000000082 +:205E2000000000000000000000000000000000000000000000000000000000000000000062 +:205E4000000000000000000000000000000000000000000000000000000000000000000042 +:205E6000000000000000000000000000000000000000000000000000000000000000000022 +:205E8000000000000000000000000000000000000000000000000000000000000000000002 +:205EA0000000000000000000000000000000000000000000000000000000000000000000E2 +:205EC0000000000000000000000000000000000000000000000000000000000000000000C2 +:205EE0000000000000000000000000000000000000000000000000000000000000000000A2 +:205F0000000000000000000000000000000000000000000000000000000000000000000081 +:205F2000000000000000000000000000000000000000000000000000000000000000000061 +:205F4000000000000000000000000000000000000000000000000000000000000000000041 +:205F6000000000000000000000000000000000000000000000000000000000000000000021 +:205F8000000000000000000000000000000000000000000000000000000000000000000001 +:205FA0000000000000000000000000000000000000000000000000000000000000000000E1 +:205FC0000000000000000000000000000000000000000000000000000000000000000000C1 +:205FE0000000000000000000000000000000000000000000000000000000000000000000A1 +:00000001FF diff --git a/Source/Images/d_dos65/u0/dos65.s19 b/Source/Images/d_dos65/u0/dos65.s19 new file mode 100644 index 00000000..8a5da23f --- /dev/null +++ b/Source/Images/d_dos65/u0/dos65.s19 @@ -0,0 +1,361 @@ +S123B7F3FD7F3ECD77DBFF0000000000004C21CED84820FCBB682000BCAD92CC4A4A4A4AB1 +S123B8138DF6BFAD43BFD03CA2FF9AD8A91120F0BB2069BCA93E20F0BBAD8BBEAC8CBE2079 +S123B833F4BBA000AE43BFF0DFB944BFC9619009C97BB005295F9944BFC8CAD0EC8A9944D2 +S123B853BF8DE7BF20A4BD202BBC8DE8BF20A5BCD064ADE9BFF004A915D02EA900AA8DEC9D +S123B873BFA001BD1DBFF01AD9C3BFD004E8C8D0F2E8BD1DBFD0FAE8EEECBFADECBFC90719 +S123B893D0DFADECBF0A6DECBFAAE8BD96BEBC97BE8DEABF8CEBBFAD8FBE48AD8EBE486C59 +S123B8B3EABF2034BC20A5BCADC4BF38E9200DE9BFD0034C1BB820E1BBACEDBFB944BFF05F +S123B8D30AC920F0062072BCC8D0F1A93F20F0BB4C1BB820A5BC20ABBDA920CDC4BFD00FBE +S123B8F3CDCCBFD00AA93FA00B99C3BF88D0FA205FBC3058ADF6BF8DF5BF20E1BB206CBC95 +S123B913A93A20F0BBADEEBF0A0A0A0A0A2960A8C8A201B92801297F2072BCC8E8E00CF0D6 +S123B9330CE009D0EEA92E2072BC4C26B920F8BBD0192097BC2010BC8DEEBF300ECEF5BFD8 +S123B953F0B220EEBB20EEBB4C10B960A0344CC0BD20A5BCD057209EBC20ABBD205FBC3075 +S123B9734F20E0BDACE7BFB944BFC920D03C20A5BCD037ADE9BFF012CDF2BFF00D38E90125 +S123B993CDE8BFD025ADF2BFD020ADF2BF8DE9BFA9008DD3BF20ABBD205FBC100920E0BDE5 +S123B9B32097BC4C27BCA03ED0082034BC4CC9B8A0344CC0BDA900A0088DFCBF8CFDBF209D +S123B9D305BED07A8DF1BF0DF1BFF07220A5BCD06D20E0BD209EBC2005BEAEC4BFE020F0EE +S123B9F30A8DFCBF8CFDBFC002905320F3BD20ABBD2014BC2097BC2023BC3045204ABC306C +S123BA134418ADFDBF6DF1BF8DF1BFADFCBFACFDBF8DF3BF8CF4BF20CACA2097BC201FBC80 +S123BA33D02718ADF3BFACF4BF69809003C8F005CCF1BFD0DC2097BC2008BC3010604CC9B5 +S123BA53B8A001D00AA055D006A062D002A00A4CC0BD20A5BCC90BD013A01820C0BD20EAF3 +S123BA73BB4820E1BB68295FC959D0D120ABBD4C14BC20A5BCD0302047BC303220E1BB20B7 +S123BA9359BCF00410203022A200BD2801C91AF0152072BC20F8BBD008AEEFBFE810EB302C +S123BAB3DEA206200301604CC9B8A029D002A0344CC0BD20D5BD20A5BCD0EC20E0BD209EF6 +S123BAD3BC2005BEAEC4BFE020F00320D9BD20F3BD2047BC30D8ADF3BFACF4BF202FBC20F2 +S123BAF359BCD00620B7CA4CEFBA30BE4CA4BD2005BEAEC4BFE020F0034C76BB4C72BBAD69 +S123BB13C4BFC920D011ADE9BFF00938E9018DE8BF2000BC4CB8B8ADCCBFC920F0034CD94C +S123BB33BBA202BDE4BF9DCCBFCA10F72047BC10034CD6BB20D5BD202FBC2059BCD01E2023 +S123BB53B7CACD91BE9007CC92BE90EBB007CC92BE90E4F0E220A4BD2059BCF06C306AA995 +S123BB7300A0088DCBBB8CCCBB2034BC20A5BCADE9BF8DC3BFA21020A7BCADE9BF8DD3BF42 +S123BB93A0008CE3BFA220BDC3BF9D0701CA10F7E8B944BFF007C920F003C8D0F4A9008D10 +S123BBB32801B944BF9D2901F007E8C8EE2801D0F120E1BB20A4BD200008ADE8BF2000BCAE +S123BBD34C1BB82034BC4CC9B8A04A4CC0BDA90D20F0BBA90AD006A201D043A920A202D0A2 +S123BBF33DA20AD039A20BD035A20DD031A20ED02DA20FD029A210D025A211D021A212D0B4 +S123BC131D2097BCA213D016A214D012A215D00EA216D00AA217D006A219D002A21A4C03FC +S123BC3301ADE9BFF01F38E901CDE8BFF017ADE8BF4C00BC20ABBDA9008DE3BF2097BC209C +S123BC5304BC8DEEBF602097BC4C1BBC2097BC200CBC8DEEBF6020E1BB202BBC1869418ED5 +S123BC73EFBF8CF0BF20C1C8B01048AD90CC20F0BB68094020F0BBAD8FCC20F0BBACF0BF95 +S123BC93AEEFBF60AD94BEAC95BE60ADE9BF8DF2BF60A2008A48A9008DE9BFACE7BF20724A +S123BCB3BD8CEDBFF00D290F48C8B944BFC93AF00A6888ADE8BF9DC3BF1008688DE9BF9DC5 +S123BCD3C3BFC8A9088DECBF207FBDF01DE8C92AD007A93F9DC3BFD0049DC3BFC8CEECBFC4 +S110BCF3D0E6207FBDF011C8D0F8E8A920EC +S123BD009DC3BFCEECBFD0F5B944BF48A9038DECBF68C92ED023C8207FBDF01DE8C92AD0AC +S123BD2007A93F9DC3BFD0049DC3BFC8CEECBFD0E6207FBDF00EC8D0F8E8A9209DC3BFCE7F +S123BD40ECBFD0F5A9038DECBFE8A9009DC3BFCEECBFD0F58CE7BFA9008DECBF68A8A20BCD +S123BD60C8B9C3BFC93FD003EEECBFCAD0F2ADECBF60B944BFF007C920D003C8D0F460B9F0 +S123BD8044BFF01CC9209019F016C93DF012C92EF00EC93AF00AC93BF006C93CF002C93E06 +S123BDA0604CC9B8A928A0014C2FBCA9008DC3BFADE9BFF01F38E901CDE8BFF0174C00BCE8 +S123BDC08CF0BF20E1BBACF0BFB9AFBEF0062072BCC8D0F560A900A0088DF3BF8CF4BF6087 +S123BDE0A20FBDC3BFBCD3BF9DD3BF989DC3BFCA10F060A20FBDD3BF9DC3BFCA10F7ADF262 +S123BE00BF8DE9BF60A9098DF7BF20A5BCADE9BFD0678DF8BF8DF9BFA8B9C4BFC924D00698 +S123BE20A90F8DF7BFC8C8B9C3BFC920F04E20A1CA900E20ABCAB041E906A20FECF7BFD050 +S123BE4038290F48ADF8BF8DFABFADF9BF8DFBBFAEF7BF18ADF8BF6DFABF8DF8BFADF9BF21 +S123BE606DFBBF8DF9BFB011CAD0E9686DF8BF8DF8BF90B2EEF9BFD0AD4CC9B8ADCCBFC90B +S123BE8020D0F6ADF8BFACF9BF604C42BF4CB4B84C03B84CC3BF4CE6B84CC8B94C65BA4C48 +S123BEA085BA4C64B94C02BB4CC6BA4C12BBFF004E4F2053504143450043414E204E4F54DD +S123BEC020434C4F534500414C4C2046494C45532028592F4E293F005245414420455252B1 +S123BEE04F52004E4F5420464F554E440046494C4520455849535453004C4F414420455219 +S123BF00524F520043414E204E4F54204F50454E005752495445204552524F5200444952E1 +S123BF202000534156452000455241200054595045200052454E2000474F20004C4F414459 +S123BF4020007F00000000000000000000000000000000000000000000000000000000003E +S123BF600000000000000000000000000000000000000000000000000000000000000000BD +S123BF8000000000000000000000000000000000000000000000000000000000000000009D +S123BFA000000000000000000000000000000000000000000000000000000000000000007D +S123BFC000000000000000000000000000000000000000000000000000000000000000005D +S123BFE000000000434F360000000000000000000000000008000009000000000008D88DF7 +S123C00098CB8DDCCB8C99CB8CDDCB8E9ACBE024B050BD54CBF008A9FF8D97CB20E9C2A98B +S123C020008D9FCBAD9ACB0A6D9ACBAAE8BD76C0BC77C08DA0CB8CA1CBADE4CA48ADE3CAB2 +S123C04048AD98CBAC99CB6CA0CB8D9BCB8C9CCBAD9FCBF00DA0009102ADA9CB8D98CB203F +S123C06004C32C97CB100820E9C2A9008D97CBAC9CCBAD9BCB604CEAC04CDBC24C19C94C0D +S123C0806BCC4C68CC4C65CC4C8BC84C1FC14C2AC14CD0C84C85C94C9BC84C83CC4C32C35D +S123C0A04C04C34CAFC54CEAC54C0EC64C3AC14CA2C14C42C14CC7C14CB7C64C80C14C32A1 +S123C0C0C14C2EC14CF9C24C23C14C6DC54C36C14CE2C04CE6C04CFAC04C0EC14C18C14CF6 +S123C0E089CC8D95CB60AD95CB602C97CB100820E9C2A9008D97CB4C59CC2086CC8DC5CB24 +S123C1008CC6CB8EC7CB8A2980A8ADC5CB60ADC7CB297FA8ADC6CB60AD6CC3AC6DC360AD74 +S123C120060160ADD4CBACD5CB608D060160ADAACB60ADABCB60ADACCB602012C3A90D4C28 +S123C1401BC62012C3208FC5ADB5CBCDB6CB9013C980F003A90160A20120F3C6C900D0F424 +S123C1608DB5CB2084C7ADB0CB0DB1CBD003A902602066C620ACC4203DC8209EC5A9006027 +S123C1802012C3201AC8A90C2013C63014A900A0109102A90CA2102086C6A90C201BC6102D +S123C1A0EC602012C3201AC8A90C2013C63017A20020EAC7ACAFCBAD53CB91042043C8A976 +S123C1C00C201BC610E9602012C3201AC8208FC5ADB5CBC9809003A901602084C7A9008DD6 +S123C1E0D9CBADB0CB0DB1CBF0034CAAC2A9028DD9CBAD91CB48C910F01AA8882CC0CB1034 +S123C2000188B1028DB0CBC8A9002CC0CB1002B1028DB1CBADB0CB8DA5CB8DA7CBADB1CB93 +S123C2208DA6CB8DA8CBADA7CBCDCBCBD008ACA8CBCCCCCBF012EEA7CBD003EEA8CBADA538 +S123C240CB0DA6CBF018D00BADA5CB0DA6CBD003A8F030ADA5CBD003CEA6CBCEA5CBADA5B9 +S123C260CBACA6CB2051C5D009ADA5CBACA6CB4C83C2ADA7CBACA8CB2051C5D0A9ADA7CBEC +S123C280ACA8CB8DB0CB8CB1CB0DB1CBD00468A90260ADB0CB2065C568A8ADB0CB9102ADB1 +S123C2A0B1CBC82CC0CB100291022066C620ACC42049C8AEB5CBECB6CB9005E88EB6CBCADC +S123C2C0E07FD011209EC5A20020F3C6C900D00AA9FF8DB5CB209EC5A90060208BC820C1E4 +S123C2E0C89005482019C96860A207B502BCDCCB9DDCCB9402CA10F360A502A403850484A6 +S123C300054C7ACCAD98CBCDAACBF0EC8DAACB4C45C3A000B102F01938E90129078D98CB60 +S123C320ADAACB8DA9CBB1028D9FCB9891022004C360A9028DAACB8DABCBA928A001850211 +S123C340840320F9C2ADAACBC908900F206CC8ADE6CAACE7CA20D0C84CEAC02071CC8D6CD3 +S123C360C38C6DC30D6DC3F0E3A00DB9FFFF99CBCB8810F7ADD1CBA81869038DC4CBB98B33 +S123C380CB8DC3CBADD2CB8DC1CBADD3CB4A6EC1CB4A6EC1CB8DC2CBA9008DC0CBADCCCB5E +S123C3A0F00588386EC0CBB988CB8DDACB38A91FF988CB8DDBCBAEAACBBD80CB2DABCBD070 +S123C3C00CBD80CB0DABCB8DABCB4CCEC360202EC8ADCBCB8DC8CBADCCCBA2034A6EC8CBD5 +S123C3E0CAD0F98DC9CBEEC8CBD003EEC9CBADD4CBACD5CB85068407A000A9009106E60635 +S123C400D002E607ADC8CBD003CEC9CBCEC8CBADC8CB0DC9CBD0E3ADC1CB8DC8CBADC2CB5C +S123C420AEC4CB4A6EC8CBCAD0F98DC9CBEEC8CBD003EEC9CB8EB0CB8EB1CBADB0CBACB14E +S123C440CB2065C5EEB0CBD003EEB1CBADC8CBD003CEC9CBCEC8CBADC8CB0DC9CBD0DC209A +S123C4607EC420DEC7A2012026C73011ACAFCBB104C9E5F0F0A20120EAC74C65C460206E80 +S123C480CCADCFCBACD0CB4C74CCADAECB8DB1CBADADCB4EB1CB6A4EB1CB6A8DB7CB8DB0AA +S123C4A0CBADB1CB8DB8CBA9008DB2CBA2008ECACB8EA2CB8EA3CB8EA4CBADB0CBCDA2CBA6 +S123C4C0ADB1CBEDA3CBADB2CBEDA4CB902118ADA2CB6DCDCB8DA2CBADA3CB6DCECB8DA31B +S123C4E0CB9003EEA4CBE8D0D1EECACB4CBAC4CAE0FFD003CECACB8A186DCFCBAAADCACB33 +S123C5006DD0CBA88A2074CC38ADA2CBEDCDCB8DA2CBADA3CBEDCECB8DA3CB38ADB0CBEDC3 +S123C520A2CBAAADB1CBEDA3CBA88A2089CC4C77CC488407A00346076A88D0FA186DD4CB83 +S123C5408506A5076DD5CB8507682907AABD78CB602031C5310660E001F00A2031C549FF7F +S123C56031069106602031C51106910660AEAACBBD80CB0DACCB8DACCB60A900A07F187101 +S123C580048810FA60AEAACBBD80CB2DACCB60A020B1028DB5CBA00FB1028DB6CB60AEB5BF +S123C5A0CBE88AA0209102ADB6CBA00F9102602012C32011C63032A90C0DAFCBA8B104AA86 +S123C5C098291FA88A9102980DAFCBA8C898291FD0EBA00CAD92CBD102F00B9102A98090B8 +S123C5E0010AA00F9102ADB9CB602012C32011C6301B2085C5D013A00CB10248980DAFCB0F +S123C600A868D1046E90CB2082C6ADB9CB602012C3A90D4820DEC7207EC4688DB3CBA20040 +S123C6208EB4CB2026C7303DAEB3CBACB4CBEEB4CBB102C00CD0138D92CB48980DAFCBA850 +S123C6406851042DDBCBF017D0D4C93FF01148980DAFCBA868851CB104297FC51CD0BFCAE3 +S123C660D0C9ADB9CB60AEC4CB0EB0CB2EB1CB2EB2CBCAD0F4ADC3CB2DB5CB0DB0CB8DB036 +S123C680CB60A920A2008DB3CBCEB3CB188A6DB3CBA8C00CF004C00FD0052C90CB100DB1BB +S123C6A00248ADB3CB0DAFCBA8689104CEB3CB10DB208AC44C43C82012C3201AC8A50248F3 +S123C6C0A50348ADE9CAACEACA85028403A9012013C6688503688502ADB9CB3015A00DA94A +S123C6E0009102C8C021D0F9386E90CB2082C6ADB9CB608E9ECB20EDC5302AA00CB102189D +S123C7006901291FF01791022011C6100BAD9ECBD01320BAC64C1BC720B2C51003A901603C +S123C720208FC5A900608A48EEADCBD003EEAECBADD2CBCDADCBADD3CBEDAECBB00568AAFF +S123C7404CDEC7ADADCB29038DB9CB0A0A0A0A0A8DAFCBF00568AA4C62C7208AC4203DC83A +S123C76068AAADB9CB602CD6CB30FACAD009207AC520C8C7910860207AC520C8C7D108F09A +S123C780E44C6DC5AEC4CBADB5CB4ACAD0FC8DB0CB38A908EDC4CBAAA00CB1022DDACB4A57 +S123C7A02ACAD0FC186DB0CB2CC0CB10010A1869108D91CBA8B1028DB0CBC8A9002CC0CBDE +S123C7C01002B1028DB1CB604818ADB7CB6DD7CB8508ADB8CB6DD8CB8509A0006860A9FF1E +S123C7E08DADCB8DAECB8DB9CB6018ADAFCB6910A88CBECB8A48B1048DBFCBC8207EC80D6B +S123C800BFCBF00A207EC8A8ADBFCB2057C568AAACBECBC898290FD0D8602085C5F01D2091 +S123C8206CC8ADECCAACEDCA20D0C84CEAC0AEAACBBD80CB49FF2DACCB8DACCB60207DCC68 +S123C8404C4FC8A201A901D003ADD9CB2080CCC900F0E9206CC8ADEFCAACF0CA20D0C820FA +S123C8608BC8C90DF0034CEAC04C67CAADF2CAACF3CA20D0C8ADAACB1869414C19C9A900E0 +S123C8802CC0CB1005B1048CBECB60AD94CB48A9008D94CB68D003205FCC60AD94CBD020D3 +S123C8A0205CCCC900F019205FCCC913D00D205FCCC903D0034CEAC0A900608D94CBA9FFD9 +S123C8C060C90DF00AC90AF006C909F002C920608DD9C88CDAC8A000B9FFFFC924F00CC8EA +S123C8E08CBACB2019C9ACBACBD0ED602C95CB100A2CBCCB3005482065CC686020C1C8B08B +S123C9001848AD90CC2032C9A95E20ECC8680940202AC9AD8FCC4C32C9C909D00DA9202009 +S123C9202AC9AD96CB2907D0F46048209BC86820ECC8482CBCCB30032062CC68EE96CBC99B +S123C94020B026CD8ECCF021CE96CBCD8CCCD006CE96CB300F60C90DF00ACD93CCF005CDEF +S123C96094CCD005A9008D96CB60A90D202AC9A90A20ECC8AD93CBCD96CBF0EDAD8ECC20FA +S123C98032C94C74C9A900A00191028C9DCBAD96CB8D93CB208BC8AC9DCBC90DD0034C6465 +S123C9A0CAC908D05EC001F0EBB10248A00138B102E901910268CE9DCBC920B040C909D0F1 +S123C9C030386EBCCBAD96CB8DBDCB206AC92071CAAD96CB4838ADBDCBED96CB8DBDCB0EF1 +S123C9E0BCCB2091CACEBDCBD0F8688D96CB4C94C9AD8FCC208DCAAD90CC208DCA2091CA9A +S123CA004C94C9C910D00BAD95CB49FF8D95CB4C94C9C918D00C206AC9AD8DCC2032C94C4D +S123CA2085C9C912D009206AC92071CA4C94C9C89102488C9DCBA001981871029102682023 +S123CA40FCC8AC9DCBB102C903D00BA001B102C901D0034CEAC0A001B10288D102B0034C0B +S123CA6094C9A90D4C2AC9A90D202AC9A90A4C2AC9AD9DCB8DBBCBA9014868CEBBCBD001FE +S123CA8060A8C89848B10220FCC84C7ACAC9209019AD8CCC482032C9A9202032C9684C32F7 +S123CAA0C9C9309004C93A9001386020A1CA90FAC94190F5C94760ADF3BFACF4BF1869801D +S123CAC08DF3BF9004C88CF4BF60ADF3BFACF4BF8DD9CA8CDACAA200BDFFFF9D2801E810DF +S123CAE0F7604C49C04C42CB4C53CB4CF8CA4CFFCA4C32CB4CCBCBFF202D20522F4F2420F5 +S123CB002D2042414420534543544F520D0A3C5245543E20544F2049474E4F5245202D2D70 +S123CB20203C4F544845523E20544F2041424F5254240D0A50454D204552524F52204F4EF6 +S123CB402024202D20494E56414C494420445249564524E500000000000000000000010075 +S123CB600001010101010101010101010000010000000000000000008040201008040201A6 +S123CB800102040810204080000103070F1F3F7F000000000000000000000000000000009B +S123CBA0000000000000000000000000000000000000000000000000000000000000000071 +S123CBC0000000000000000000000000000000000000000000000000000000000000000051 +S123CBE00000000048DA5AAA4A4A4A4A1820F8CB8A20F8CB7AFA6860290F0930C93A300398 +S123CC001869074CB5CE48DA5AA90D20B5CEA90A20B5CE7AFA68605ADA48A000A2FF38E875 +S123CC20E964B0FB69642040CCA2FF38E8E90AB0FB690A2040CCAAA0012040CC68FA7A604E +S123CC4048C000D0098AA8C000D0034C54CC8A093020B5CE68604CAECD4C21CE4CAFCE4C79 +S123CC60B2CE4CB5CE4CB8CE4CB9CE4CBACE4C5ACE4C29CE4C5ECE4C66CE4CAACE4C6DCEEE +S123CC804C8BCEA901604CBBCE4CBCCE08010C005E18500C1E020D0A6438383838622E2024 +S123CCA0202E643838622E20202E64383838382E20202020644420202020206F6F6F6F6FEB +S123CCC00D0A38382020603844202E3850202059382E203838202020595020202064382023 +S123CCE02020202038507E7E7E7E0D0A38382020203838203838202020203838206038623F +S123CD006F2E202020206438202020202064500D0A38382020203838203838202020203863 +S123CD2038202020605938622E206438383838622E205638383838622E0D0A003838202035 +S123CD402E384420603862202064382720646220202038442038382020603844202020201A +S123CD60206038440D0A5938383838442020206059383850202020603838383859202060AD +S123CD803838383850202038386F6F62590D0A11444F532F3635204F4E20544845204E48FA +S123CDA0594F44594E4520332E30300D0A0078A2FF9AD8A996A0CC20BDCEA93CA0CD20BD8F +S123CDC0CE2006CC2075D820AFD0201ED5207DD7546E5C5E6E54794020B9D7A9448530A90A +S123CDE0BF8531A94A852EA9CE852F2037CF20B9D8A2008E88DA8E89DABD1BCE9D0001E863 +S123CE00E006D0F5A928A00120AACEAD82DAA9022029CE205ACEA9024C03B84C59CC4CFED9 +S123CE20BF78A2FF9AD84CEECD29078D82DAAD82DA0AAABD3ACEBC3BCE6012DA20DA2EDAEF +S123CE403CDA4ADA58DA66DA74DA00000100300030013002300330043006A900A000188DB5 +S123CE608ADA8C8BDA608D8CDA8C8DDA60201BCF29F0C900D004202CD960C920D003A9FF0A +S123CE8060C930D0034C70D2A9FF60201BCF29F0C900D0042060D960C920D003A9FF60C9C6 +S123CEA030D00420C4D260A9FF6085F484F5604C9DD04C8ED04C6FD0606060606085F08433 +S123CEC0F1A000B1F0C900F00720B5CEC84CC3CE6048AD8CDA2903182AAABDF2CE85EEE869 +S123CEE0BDF2CE85EFA5F485ECA5F585ED2028CF686009E389E309E489E448AD8CDA29030F +S123CF00182AAABDF2CE85ECE8BDF2CE85EDA5F485EEA5F585EF2028CF6860DAAD82DA2957 +S123CF20070AAABD4ACEFA605AA000B1EE91ECC898C980D0F67A602006CC48DA5AA200BDD7 +S123CF4053CFE8C924F00620B5CE4C3FCF7AFA684C67CF4469736B20436F6E66696775729D +S123CF606174696F6E3A242006CCA20048DA5AA200BD85CFE8C924F00620B5CE4C71CF7AFD +S123CF80FA684C8ACF20202020248A4A18694120B5CEA93A20B5CEA93D20B5CE20B4CFA94E +S123CFA03A20B5CEE8BD4ACE2017CCE82006CCE010D0B960BD4ACE4829F0C900D01F48DA0D +S123CFC05AA200BDD7CFE8C924F00620B5CE4CC3CF7AFA684CDACF4D44244C67D0C910D0F0 +S123CFE02048DA5AA200BDFACFE8C924F00620B5CE4CE6CF7AFA684CFECF554E4B244C6740 +S123D000D0C920D01F48DA5AA200BD1ED0E8C924F00620B5CE4C0AD07AFA684C21D0464464 +S123D020244C67D0C930D02248DA5AA200BD41D0E8C924F00620B5CE4C2DD07AFA684C4748 +S123D040D05050494445244C67D048DA5AA200BD63D0E8C924F00620B5CE4C4FD07AFA6820 +S123D0604C67D0554E4B2468290F2017CC606048AD6D032920C900F0F7688D680360AD6D7C +S123D080032901C900F004AD680360A90060AD6D032901C900F0F7AD6803297F60AD6D03ED +S123D0A02901C900F003A9FF60A9006000000048DA5AA200BDC8D0E8C924F00620B5CE4C48 +S123D0C0B4D07AFA684CD0D05050494445203A242006CC2062D2D03548DA5AA200BDF1D029 +S123D0E0E8C924F00620B5CE4CDDD07AFA684CF8D020494F3D307824A90320E4CBA9602070 +S123D100E4CB20F7D2209BD1B0034C36D148DA5AA200BD26D1E8C924F00620B5CE4C12D172 +S123D1207AFA684C33D1204E4F542050524553454E54244C97D12006CC48DA5AA200BD5276 +S123D140D1E8C924F00620B5CE4C3ED17AFA684C63D1205050494445303A20426C6F636BCE +S123D160733D24A90020DBD148DA5AA200BD81D1E8C924F00620B5CE4C6DD17AFA684C9283 +S123D180D1205050494445313A20426C6F636B733D24A90120DBD12006CC60A9008D60037D +S123D1A02022D3B034A90F20D4D48A2940C900F028A90A20D4D4E001D01FA90B20D4D4E077 +S123D1C001D016A90C20D4D4E000D00DA90D20D4D4E000D004184CDAD1386029010A0A0A09 +S123D1E00A09E0AAA000A90E20F2D42022D3B048A90FA2EC20F2D4204AD3B03C207AD3483A +S123D200DA5AA200BD18D2E8C924F00620B5CE4C04D27AFA684C1BD2307824AD84E320E404 +S123D220CBAD83E320E4CBAD82E320E4CBAD81E320E4CB2006CC186048DA5AA200BD51D214 +S123D240E8C924F00620B5CE4C3DD27AFA684C5DD24E4F542050524553454E54242006CC62 +S123D26038602016D5A9008D6003AD6003C900602077D220D1CE602019D4AD90DACD95DA4D +S123D280D013AD8FDACD94DAD00BAD8EDACD93DAD003A900602022D3B02720E6D3A90FA231 +S123D2A02020F2D4204AD3B018207AD3AD90DA8D95DAAD8EDA8D93DAAD8FDA8D94DAA90016 +S123D2C060A9FF602077D220FACE2022D3B02520E6D3A90FA23020F2D4204AD3B01620AF8C +S123D2E0D32022D3B00EA9FF8D95DA8D93DA8D94DAA90060A9FF60A9008D90DA8D8EDA8DB8 +S123D3008FDAA9FF8D95DA8D93DA8D94DAA9808D6203A200CAE000D0FBA9008D6203200A10 +S123D320D660DA5A48A9008DADD08DAED0A90F20D4D48A2980F00EEEADD0D0F1EEAED0D060 +S123D340EC384C46D318687AFA60DA5A48A9008DADD08DAED0A90F20D4D48A2988C908F036 +S123D360142901C901F00AEEADD0D0E9EEAED0D0E4384C76D318687AFA60A2008EACD0A9ED +S123D3800820D4D48AAEACD09D09E3E8989D09E3E8E000D0E78EACD0A90820D4D48AAEAC8D +S123D3A0D09D09E4E8989D09E4E8E000D0E760A2008EACD0BD0AE3A8BD09E3AAA90820F212 +S123D3C0D4AEACD0E8E8E000D0E7A2008EACD0BD0AE4A8BD09E4AAA90820F2D4AEACD0E8E8 +S123D3E0E8E000D0E760201BCF29010A0A0A0A09E0AAA000A90E20F2D4AE8FDAA90D20F23F +S123D400D4AE8EDAA90C20F2D4AE90DAA90B20F2D4A201A90A20F2D460AD8ADA290F0A0AD8 +S123D4200A0AAAAD8CDA4A4A290F8D90DA8A0D90DA8D90DAAD8ADA8D8EDAAD8BDA8D8FDA4E +S123D440AD8FDA4A8D8FDAAD8EDA6A8D8EDAAD8FDA4A8D8FDAAD8EDA6A8D8EDAAD8FDA4AD4 +S123D4608D8FDAAD8EDA6A8D8EDAAD8FDA4A8D8FDAAD8EDA6A8D8EDAAD82DA29070AAAE89F +S123D480BD4ACE8D98DAA9008D97DA186E98DA6E97DA6E98DA6E97DABD4ACE186D97DA8D1F +S123D4A097DA18AD97DA6D8EDA8D8EDAAD98DA6D8FDA8D8FDAAD82DA8D71D8AD8FDA8D7218 +S123D4C0D8AD8EDA8D73D8AD90DA8D74D82090D620C5D660200ED58D620309408D6203487A +S123D4E0AE6003AC61036849408D6203A9008D6203602016D58E60038C61038D6203092022 +S123D5008D620349208D6203A9008D62036048A9928D6303686048A9808D6303686020DA5B +S123D520D548DA5AA200BD3AD5E8C924F00620B5CE4C26D57AFA684C40D544534B593A249D +S123D5402006CC48DA5AA200BD5CD5E8C924F00620B5CE4C48D57AFA684C63D520494F3D9D +S123D560307824A90320E4CBA96020E4CB48DA5AA200BD86D5E8C924F00620B5CE4C72D551 +S123D5807AFA684C8DD5204D4F44453D2448DA5AA200BDA6D5E8C924F00620B5CE4C92D5E0 +S123D5A07AFA684CA9D54E4724AD68D8C9FFF02648DA5AA200BDC9D5E8C924F00620B5CE56 +S123D5C04CB5D57AFA684CD6D5204E4F542050524553454E54242006CC60201FD6D02A20A7 +S123D5E041D8A9068D620309808D6203297F8D6203200AD6A9A5A000205BD7A000206FD712 +S123D600C9A5D005A9FF8D68D8602053D8A92120DBD6A9DF20DBD6A200DAFACAD0FB602024 +S123D6202AD8A9008D6003AD6003C90060AD68D8C9FFD0052014D7290F60AD68D8C9FFD060 +S123D64024202DD6F0F4A94020DBD62019D749C048293F8D66D8A200BD74D6CD66D8F009A0 +S123D660E8E01CD0F368A9FF606825C08D66D88A0D66D8600D040C14030B13020A120109C8 +S123D6801100081005151D1C1B1A191823222120A200BD71D84A4A4A4ADAAABD56D8FADA0B +S123D6A0488A0AAA689D69D8FABD71D8290FDAAABD56D8FADA488A0AAAE8689D69D8FAE889 +S123D6C0E004D0CE6048DA5AA200BD69D8DA7A205BD7E8E008D0F37AFA686048A9014CE4B1 +S123D6E0D648A900202AD809068D620309188D62038D66D8688D6003AD66D829FD8D620303 +S123D700EA09028D620329E78D620329E68D62032053D860A9014C1BD7A9002041D8090697 +S123D7208D620309188D6203297B8D62038D66D8AD600348AD66D809048D620329E78D623E +S123D7400329E68D62032053D86860A99020DBD6A210A9FF20E1D6CAD0F8605A48481898E7 +S123D7606990A820DBD66849FF20E1D6687A6018986970A820DBD62019D749FF608E66D8E4 +S123D780BA6885146885159AAE66D8DA5A4818E6149002E615A000B114205BD7C8C008D010 +S123D7A0F6687AFA8D66D81868690885149003681A48A51448AD66D8605ADA48A00F206FDB +S123D7C0D70920A920A00F205BD7A28FA0FF88D0FDCAD0FAA00F206FD729DFA9DFA00F204E +S123D7E05BD768FA7A605A48A00D206FD70920A00D205BD7687A605A48A00E206FD70920B9 +S123D800A00E205BD7687A605A48A00D206FD729DFA00D205BD7687A605A48A00E206FD70E +S123D82029DFA00E205BD7687A6048AD67D8C982F00DA9828D63038D67D8A9068D6203682B +S123D8406048AD67D8C992F008A9928D63038D67D868604C41D83F065B4F666D7D077F678A +S123D860777C395E797100000000000000000000000000000048DA5AA200BD8ED8E8C9241A +S123D880F00620B5CE4C7AD87AFA684CB6D84D443A20554E4954533D322052414D444953CA +S123D8A04B3D3235364B4220524F4D4449534B3D3338344B42242006CCA200BDC7D89D005F +S123D8C002E8E000D0F560488415A00084148A2980C900D0388A2940C900D00DA9808D7C6D +S123D8E0036809808D7803D00BA9008D780368297F8D7C03A200DA7AB1149D0004E8E0005C +S123D900D0F4A9808D7C03A98E8D7803606809808D7803A200DA7ABD00049114E8E000D07E +S123D920F4A9808D7C03A98E8D7803602035D920C6D9A90060201BCF29010A0A0A0A0A0AB5 +S123D940297FAA2083D9E000F00CEE8EDAEE8EDAEE8EDAEE8EDAAD8EDAAC90DA2000026014 +S123D960201BCF2901C900F003A9FF602035D92083D920ECD9AD8EDAAC90DAA280200002AD +S123D980A90060DAAD8CDA4A291F8D90DAAD8ADA29030A0A0A0A0A09800D90DA8D90DAADF1 +S123D9A08ADA4A4A8D8EDAAD82DA8D71D8A9008D72D8AD8EDA8D73D8AD90DA8D74D820908A +S123D9C0D620C5D6FA6048AD8CDA2901C900D007A90085EE4CDBD9A98085EEA90485EFA5B5 +S123D9E0F485ECA5F585ED2028CF686048AD8CDA2901C900D007A90085EC4C01DAA98085BF +S123DA00ECA90485EDA5F485EEA5F585EF2028CF68607F004000000001FF0099DA0089E261 +S123DA20BF0040000000019B0097DB0089E2FF074000100002FF0195DC0089E2FF074000F0 +S123DA40100002FF0193DD0089E2FF074000100002FF0191DE0089E2FF074000100002FF4C +S123DA60018FDF0089E2FF074000100002FF018DE00089E2FF074000100002FF018BE100D4 +S123DA8089E202000000000000000000000000000000000000000000000000000000000015 +S123DAA0000000000000000000000000000000000000000000000000000000000000000062 +S123DAC0000000000000000000000000000000000000000000000000000000000000000042 +S123DAE0000000000000000000000000000000000000000000000000000000000000000022 +S123DB00000000000000000000000000000000000000000000000000000000000000000001 +S123DB200000000000000000000000000000000000000000000000000000000000000000E1 +S123DB400000000000000000000000000000000000000000000000000000000000000000C1 +S123DB600000000000000000000000000000000000000000000000000000000000000000A1 +S123DB80000000000000000000000000000000000000000000000000000000000000000081 +S123DBA0000000000000000000000000000000000000000000000000000000000000000061 +S123DBC0000000000000000000000000000000000000000000000000000000000000000041 +S123DBE0000000000000000000000000000000000000000000000000000000000000000021 +S123DC00000000000000000000000000000000000000000000000000000000000000000000 +S123DC200000000000000000000000000000000000000000000000000000000000000000E0 +S123DC400000000000000000000000000000000000000000000000000000000000000000C0 +S123DC600000000000000000000000000000000000000000000000000000000000000000A0 +S123DC80000000000000000000000000000000000000000000000000000000000000000080 +S123DCA0000000000000000000000000000000000000000000000000000000000000000060 +S123DCC0000000000000000000000000000000000000000000000000000000000000000040 +S123DCE0000000000000000000000000000000000000000000000000000000000000000020 +S123DD000000000000000000000000000000000000000000000000000000000000000000FF +S123DD200000000000000000000000000000000000000000000000000000000000000000DF +S123DD400000000000000000000000000000000000000000000000000000000000000000BF +S123DD6000000000000000000000000000000000000000000000000000000000000000009F +S123DD8000000000000000000000000000000000000000000000000000000000000000007F +S123DDA000000000000000000000000000000000000000000000000000000000000000005F +S123DDC000000000000000000000000000000000000000000000000000000000000000003F +S123DDE000000000000000000000000000000000000000000000000000000000000000001F +S123DE000000000000000000000000000000000000000000000000000000000000000000FE +S123DE200000000000000000000000000000000000000000000000000000000000000000DE +S123DE400000000000000000000000000000000000000000000000000000000000000000BE +S123DE6000000000000000000000000000000000000000000000000000000000000000009E +S123DE8000000000000000000000000000000000000000000000000000000000000000007E +S123DEA000000000000000000000000000000000000000000000000000000000000000005E +S123DEC000000000000000000000000000000000000000000000000000000000000000003E +S123DEE000000000000000000000000000000000000000000000000000000000000000001E +S123DF000000000000000000000000000000000000000000000000000000000000000000FD +S123DF200000000000000000000000000000000000000000000000000000000000000000DD +S123DF400000000000000000000000000000000000000000000000000000000000000000BD +S123DF6000000000000000000000000000000000000000000000000000000000000000009D +S123DF8000000000000000000000000000000000000000000000000000000000000000007D +S123DFA000000000000000000000000000000000000000000000000000000000000000005D +S123DFC000000000000000000000000000000000000000000000000000000000000000003D +S123DFE000000000000000000000000000000000000000000000000000000000000000001D +S123E0000000000000000000000000000000000000000000000000000000000000000000FC +S123E0200000000000000000000000000000000000000000000000000000000000000000DC +S123E0400000000000000000000000000000000000000000000000000000000000000000BC +S123E06000000000000000000000000000000000000000000000000000000000000000009C +S123E08000000000000000000000000000000000000000000000000000000000000000007C +S123E0A000000000000000000000000000000000000000000000000000000000000000005C +S123E0C000000000000000000000000000000000000000000000000000000000000000003C +S123E0E000000000000000000000000000000000000000000000000000000000000000001C +S123E1000000000000000000000000000000000000000000000000000000000000000000FB +S123E1200000000000000000000000000000000000000000000000000000000000000000DB +S123E1400000000000000000000000000000000000000000000000000000000000000000BB +S123E16000000000000000000000000000000000000000000000000000000000000000009B +S123E18000000000000000000000000000000000000000000000000000000000000000007B +S123E1A000000000000000000000000000000000000000000000000000000000000000005B +S123E1C000000000000000000000000000000000000000000000000000000000000000003B +S123E1E000000000000000000000000000000000000000000000000000000000000000001B +S123E2000000000000000000000000000000000000000000000000000000000000000000FA +S123E2200000000000000000000000000000000000000000000000000000000000000000DA +S123E2400000000000000000000000000000000000000000000000000000000000000000BA +S123E26000000000000000000000000000000000000000000000000000000000000000009A +S123E28000000000000000000000000000000000000000000000000000000000000000007A +S123E2A000000000000000000000000000000000000000000000000000000000000000005A +S123E2C000000000000000000000000000000000000000000000000000000000000000003A +S123E2E000000000000000000000000000000000000000000000000000000000000000001A +S123E3000000000000000000000000000000000000000000000000000000000000000000F9 +S123E3200000000000000000000000000000000000000000000000000000000000000000D9 +S123E3400000000000000000000000000000000000000000000000000000000000000000B9 +S123E360000000000000000000000000000000000000000000000000000000000000000099 +S123E380000000000000000000000000000000000000000000000000000000000000000079 +S123E3A0000000000000000000000000000000000000000000000000000000000000000059 +S123E3C0000000000000000000000000000000000000000000000000000000000000000039 +S123E3E0000000000000000000000000000000000000000000000000000000000000000019 +S123E4000000000000000000000000000000000000000000000000000000000000000000F8 +S123E4200000000000000000000000000000000000000000000000000000000000000000D8 +S123E4400000000000000000000000000000000000000000000000000000000000000000B8 +S123E460000000000000000000000000000000000000000000000000000000000000000098 +S123E480000000000000000000000000000000000000000000000000000000000000000078 +S123E4A0000000000000000000000000000000000000000000000000000000000000000058 +S123E4C0000000000000000000000000000000000000000000000000000000000000000038 +S123E4E0000000000000000000000000000000000000000000000000000000000000000018 diff --git a/Source/Images/d_dos65/u0/edit.co6 b/Source/Images/d_dos65/u0/edit.co6 new file mode 100644 index 00000000..e685410c Binary files /dev/null and b/Source/Images/d_dos65/u0/edit.co6 differ diff --git a/Source/Images/d_dos65/u0/run.co6 b/Source/Images/d_dos65/u0/run.co6 new file mode 100644 index 00000000..cd6edb24 Binary files /dev/null and b/Source/Images/d_dos65/u0/run.co6 differ diff --git a/Source/Images/d_dos65/u0/sedit.co6 b/Source/Images/d_dos65/u0/sedit.co6 new file mode 100644 index 00000000..c130e67d Binary files /dev/null and b/Source/Images/d_dos65/u0/sedit.co6 differ diff --git a/Source/Images/fd_bp.txt b/Source/Images/fd_bp.txt index fa97b717..6b251b2a 100644 --- a/Source/Images/fd_bp.txt +++ b/Source/Images/fd_bp.txt @@ -11,6 +11,7 @@ # #../../Binary/Apps/*.com 15: ../../Binary/Apps/assign.com 15: +../../Binary/Apps/cpuspd.com 15: ../../Binary/Apps/fat.com 15: ../../Binary/Apps/fdu.com 15: ../../Binary/Apps/fdu.doc 15: diff --git a/Source/Images/fd_cpm22.txt b/Source/Images/fd_cpm22.txt index 525717c8..859b7e30 100644 --- a/Source/Images/fd_cpm22.txt +++ b/Source/Images/fd_cpm22.txt @@ -7,6 +7,7 @@ d_cpm22/ReadMe.txt 0: # #../../Binary/Apps/*.com 0: ../../Binary/Apps/assign.com 0: +../../Binary/Apps/cpuspd.com 0: ../../Binary/Apps/fat.com 0: ../../Binary/Apps/fdu.com 0: ../../Binary/Apps/fdu.doc 0: diff --git a/Source/Images/fd_cpm3.txt b/Source/Images/fd_cpm3.txt index 92eb3860..43c3e8ba 100644 --- a/Source/Images/fd_cpm3.txt +++ b/Source/Images/fd_cpm3.txt @@ -23,6 +23,7 @@ # #../../Binary/Apps/*.com 0: ../../Binary/Apps/assign.com 0: +../../Binary/Apps/cpuspd.com 0: ../../Binary/Apps/fat.com 0: ../../Binary/Apps/fdu.com 0: ../../Binary/Apps/fdu.doc 0: diff --git a/Source/Images/fd_nzcom.txt b/Source/Images/fd_nzcom.txt index 5a4dfb46..a569b365 100644 --- a/Source/Images/fd_nzcom.txt +++ b/Source/Images/fd_nzcom.txt @@ -7,6 +7,7 @@ d_nzcom/ReadMe.txt 0: # #../../Binary/Apps/*.com 0: ../../Binary/Apps/assign.com 0: +../../Binary/Apps/cpuspd.com 0: ../../Binary/Apps/fat.com 0: ../../Binary/Apps/fdu.com 0: ../../Binary/Apps/rtc.com 0: diff --git a/Source/Images/fd_zpm3.txt b/Source/Images/fd_zpm3.txt index dcec6bfa..a7077906 100644 --- a/Source/Images/fd_zpm3.txt +++ b/Source/Images/fd_zpm3.txt @@ -22,6 +22,7 @@ # #../../Binary/Apps/*.com 15: ../../Binary/Apps/assign.com 15: +../../Binary/Apps/cpuspd.com 15: ../../Binary/Apps/fat.com 15: ../../Binary/Apps/fdu.com 15: ../../Binary/Apps/fdu.doc 15: diff --git a/Source/Images/fd_zsdos.txt b/Source/Images/fd_zsdos.txt index 0d7c71ae..1b7acc71 100644 --- a/Source/Images/fd_zsdos.txt +++ b/Source/Images/fd_zsdos.txt @@ -20,6 +20,7 @@ d_cpm22/u0/XSUB.COM 0: # #../../Binary/Apps/*.com 0: ../../Binary/Apps/assign.com 0: +../../Binary/Apps/cpuspd.com 0: ../../Binary/Apps/fat.com 0: ../../Binary/Apps/fdu.com 0: ../../Binary/Apps/fdu.doc 0: @@ -47,7 +48,7 @@ d_cpm22/u0/XSUB.COM 0: # Add Tune sample files # ../../Binary/Apps/Tunes/*.pt? 3: -../../Binary/Apps/Tunes/*.mym 3: +#../../Binary/Apps/Tunes/*.mym 3: ../../Binary/Apps/Tunes/*.vgm 3: # # Add OS image diff --git a/Source/Images/hd_bp.txt b/Source/Images/hd_bp.txt index 7449e46d..340f07d3 100644 --- a/Source/Images/hd_bp.txt +++ b/Source/Images/hd_bp.txt @@ -11,6 +11,7 @@ # #../../Binary/Apps/*.com 15: ../../Binary/Apps/assign.com 15: +../../Binary/Apps/cpuspd.com 15: ../../Binary/Apps/fat.com 15: ../../Binary/Apps/fdu.com 15: ../../Binary/Apps/fdu.doc 15: diff --git a/Source/Images/hd_cpm22.txt b/Source/Images/hd_cpm22.txt index e98400cc..a57d2283 100644 --- a/Source/Images/hd_cpm22.txt +++ b/Source/Images/hd_cpm22.txt @@ -7,6 +7,7 @@ d_cpm22/ReadMe.txt 0: # #../../Binary/Apps/*.com 0: ../../Binary/Apps/assign.com 0: +../../Binary/Apps/cpuspd.com 0: ../../Binary/Apps/fat.com 0: ../../Binary/Apps/fdu.com 0: ../../Binary/Apps/fdu.doc 0: diff --git a/Source/Images/hd_cpm3.txt b/Source/Images/hd_cpm3.txt index 40feb417..2cc80492 100644 --- a/Source/Images/hd_cpm3.txt +++ b/Source/Images/hd_cpm3.txt @@ -23,6 +23,7 @@ # #../../Binary/Apps/*.com 0: ../../Binary/Apps/assign.com 0: +../../Binary/Apps/cpuspd.com 0: ../../Binary/Apps/fat.com 0: ../../Binary/Apps/fdu.com 0: ../../Binary/Apps/fdu.doc 0: diff --git a/Source/Images/hd_dos65.txt b/Source/Images/hd_dos65.txt new file mode 100644 index 00000000..7d6b7d12 --- /dev/null +++ b/Source/Images/hd_dos65.txt @@ -0,0 +1,3 @@ +# +# Nothing to add for now +# diff --git a/Source/Images/hd_nzcom.txt b/Source/Images/hd_nzcom.txt index 2f561e07..95968469 100644 --- a/Source/Images/hd_nzcom.txt +++ b/Source/Images/hd_nzcom.txt @@ -24,6 +24,7 @@ d_zsdos/u0/*.* 0: # #../../Binary/Apps/*.com 0: ../../Binary/Apps/assign.com 0: +../../Binary/Apps/cpuspd.com 0: ../../Binary/Apps/fat.com 0: ../../Binary/Apps/fdu.com 0: ../../Binary/Apps/fdu.doc 0: diff --git a/Source/Images/hd_zpm3.txt b/Source/Images/hd_zpm3.txt index 3d52e4b7..55853d5b 100644 --- a/Source/Images/hd_zpm3.txt +++ b/Source/Images/hd_zpm3.txt @@ -22,6 +22,7 @@ # #../../Binary/Apps/*.com 15: ../../Binary/Apps/assign.com 15: +../../Binary/Apps/cpuspd.com 15: ../../Binary/Apps/fat.com 15: ../../Binary/Apps/fdu.com 15: ../../Binary/Apps/fdu.doc 15: diff --git a/Source/Images/hd_zsdos.txt b/Source/Images/hd_zsdos.txt index 4d8c8e06..e23d5c4a 100644 --- a/Source/Images/hd_zsdos.txt +++ b/Source/Images/hd_zsdos.txt @@ -20,6 +20,7 @@ d_cpm22/u0/XSUB.COM 0: # #../../Binary/Apps/*.com 0: ../../Binary/Apps/assign.com 0: +../../Binary/Apps/cpuspd.com 0: ../../Binary/Apps/fat.com 0: ../../Binary/Apps/fdu.com 0: ../../Binary/Apps/fdu.doc 0: diff --git a/Source/RomDsk/Build.cmd b/Source/RomDsk/Build.cmd index 1a5295b9..a13f1a2f 100644 --- a/Source/RomDsk/Build.cmd +++ b/Source/RomDsk/Build.cmd @@ -3,16 +3,14 @@ setlocal set TOOLS=../../Tools -set PATH=%TOOLS%\tasm32;%TOOLS%\zx;%TOOLS%\srecord;%TOOLS%\cpmtools;%PATH% +set PATH=%TOOLS%\tasm32;%TOOLS%\zxcc;%TOOLS%\srecord;%TOOLS%\cpmtools;%PATH% set TASMTABS=%TOOLS%\tasm32 -set ZXBINDIR=%TOOLS%/cpm/bin/ -set ZXLIBDIR=%TOOLS%/cpm/lib/ -set ZXINCDIR=%TOOLS%/cpm/include/ +set CPMDIR80=%TOOLS%/cpm/ set RomApps1=assign mode rtc syscopy xm -set RomApps2=fdu format survey sysgen talk timer +set RomApps2=fdu format survey sysgen talk timer cpuspd :: :: Make all variants of the ROM Disk contents image. Three sizes are diff --git a/Source/RomDsk/Makefile b/Source/RomDsk/Makefile index 4f899321..c94e9ab7 100644 --- a/Source/RomDsk/Makefile +++ b/Source/RomDsk/Makefile @@ -7,7 +7,7 @@ include $(TOOLS)/Makefile.inc .SHELLFLAGS = -ce ROMAPPS1 := assign mode rtc syscopy xm -ROMAPPS2 := fdu format survey sysgen talk timer +ROMAPPS2 := fdu format survey sysgen talk timer cpuspd rom256_%.dat: ROMSIZ=256 rom512_%.dat: ROMSIZ=512 diff --git a/Source/RomDsk/ROM_1024KB/UNZIP.COM b/Source/RomDsk/ROM_1024KB/UNZIP.COM index afde7204..9da369ff 100644 Binary files a/Source/RomDsk/ROM_1024KB/UNZIP.COM and b/Source/RomDsk/ROM_1024KB/UNZIP.COM differ diff --git a/Source/RomDsk/ROM_1024KB/UNZIP154.COM b/Source/RomDsk/ROM_1024KB/UNZIP154.COM deleted file mode 100644 index f0572630..00000000 Binary files a/Source/RomDsk/ROM_1024KB/UNZIP154.COM and /dev/null differ diff --git a/Source/RomDsk/ROM_1024KB/UNZIP186.COM b/Source/RomDsk/ROM_1024KB/UNZIP186.COM deleted file mode 100644 index c750ff52..00000000 Binary files a/Source/RomDsk/ROM_1024KB/UNZIP186.COM and /dev/null differ diff --git a/Source/ZCPR-DJ/Build.cmd b/Source/ZCPR-DJ/Build.cmd index 403a01e1..16de441d 100644 --- a/Source/ZCPR-DJ/Build.cmd +++ b/Source/ZCPR-DJ/Build.cmd @@ -3,13 +3,11 @@ setlocal set TOOLS=../../Tools -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/ -zx M80 -=zcpr/l || exit /b -zx L80 -zcpr,zcpr.bin/n/e || exit /b \ No newline at end of file +zxcc M80 -=zcpr/l || exit /b +zxcc L80 -zcpr,zcpr.bin/n/e || exit /b \ No newline at end of file diff --git a/Source/ZCPR-DJ/Makefile b/Source/ZCPR-DJ/Makefile index 47584a38..aff0ac20 100644 --- a/Source/ZCPR-DJ/Makefile +++ b/Source/ZCPR-DJ/Makefile @@ -7,4 +7,4 @@ TOOLS = ../../Tools include $(TOOLS)/Makefile.inc zcpr.bin: zcpr.rel - $(ZXCC) $(TOOLS)/cpm/bin/L80 -zcpr,zcpr.bin/n/e + $(ZXCC) L80 -zcpr,zcpr.bin/n/e diff --git a/Source/ZCPR/Build.cmd b/Source/ZCPR/Build.cmd index b6b9d764..35655a20 100644 --- a/Source/ZCPR/Build.cmd +++ b/Source/ZCPR/Build.cmd @@ -3,16 +3,14 @@ setlocal set TOOLS=../../Tools -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/ -zx MAC -ZCPR.ASM -$PO || exit /b -zx MLOAD25 -ZCPR.BIN=ZCPR.HEX || exit /b +zxcc MAC -ZCPR.ASM -$PO || exit /b +zxcc MLOAD25 -ZCPR.BIN=ZCPR.HEX || exit /b -zx MAC -BDLOC.ASM -$PO || exit /b -zx MLOAD25 -BDLOC.COM=BDLOC.HEX || exit /b +zxcc MAC -BDLOC.ASM -$PO || exit /b +zxcc MLOAD25 -BDLOC.COM=BDLOC.HEX || exit /b diff --git a/Source/ZCPR/Makefile b/Source/ZCPR/Makefile index 4e35f6d1..b3abd231 100644 --- a/Source/ZCPR/Makefile +++ b/Source/ZCPR/Makefile @@ -7,6 +7,6 @@ TOOLS = ../../Tools include $(TOOLS)/Makefile.inc zcpr.bin: zcpr.asm - $(ZXCC) $(CPM)/MAC -$< -$$PO - $(ZXCC) $(CPM)/MLOAD25 -$@=zcpr.hex + $(ZXCC) MAC -$< -$$PO + $(ZXCC) MLOAD25 -$@=zcpr.hex diff --git a/Source/ZPM3/Build.cmd b/Source/ZPM3/Build.cmd index f0f5a3c6..05707ed9 100644 --- a/Source/ZPM3/Build.cmd +++ b/Source/ZPM3/Build.cmd @@ -3,13 +3,11 @@ setlocal set TOOLS=../../Tools -set PATH=%TOOLS%\tasm32;%TOOLS%\zx;%TOOLS%\cpmtools;%PATH% +set PATH=%TOOLS%\tasm32;%TOOLS%\zxcc;%TOOLS%\cpmtools;%PATH% set TASMTABS=%TOOLS%\tasm32 -set ZXBINDIR=%TOOLS%/cpm/bin/ -set ZXLIBDIR=%TOOLS%/cpm/lib/ -set ZXINCDIR=%TOOLS%/cpm/include/ +set CPMDIR80=%TOOLS%/cpm/ copy ..\ZCCP\ccp.com zccp.com || exit /b copy ..\ZCCP\zinstal.zpm . || exit /b @@ -28,11 +26,11 @@ echo. echo. echo *** ZPM Loader *** echo. -zx LINK -ZPMLDRD[L100]=ZPM3LDR,BIOSLDRD,UTIL || exit /b -:: zx SLRNK -ZPM3LDR,BIOSLDRD,UTIL,ZPMLDRD/N/E +zxcc LINK -ZPMLDRD[L100]=ZPM3LDR,BIOSLDRD,UTIL || exit /b +:: zxcc SLRNK -ZPM3LDR,BIOSLDRD,UTIL,ZPMLDRD/N/E move /Y zpmldrd.com zpmldr.bin || exit /b -zx LINK -ZPMLDRC[L100]=ZPM3LDR,BIOSLDRC,UTIL || exit /b -:: zx SLRNK -ZPM3LDR,BIOSLDRC,UTIL,ZPMLDRC/N/E +zxcc LINK -ZPMLDRC[L100]=ZPM3LDR,BIOSLDRC,UTIL || exit /b +:: zxcc SLRNK -ZPM3LDR,BIOSLDRC,UTIL,ZPMLDRC/N/E move /Y zpmldrc.com zpmldr.com || exit /b rem pause @@ -42,13 +40,13 @@ echo. echo *** Banked ZPM3 *** echo. copy genbnk.dat gencpm.dat || exit /b -zx gencpm -auto -display || exit /b +zxcc gencpm -auto -display || exit /b rem pause rem ZPM3 Tools -zx Z80ASM -clrhist/F || exit /b -zx Z80ASM -setz3/F || exit /b -zx Z80ASM -autotog/F || exit /b +zxcc Z80ASM -clrhist/F || exit /b +zxcc Z80ASM -setz3/F || exit /b +zxcc Z80ASM -autotog/F || exit /b rem Loader diff --git a/Source/ZPM3/Makefile b/Source/ZPM3/Makefile index 46d98359..47158132 100644 --- a/Source/ZPM3/Makefile +++ b/Source/ZPM3/Makefile @@ -9,11 +9,11 @@ TOOLS =../../Tools include $(TOOLS)/Makefile.inc zpmldr.bin: zpm3ldr.rel biosldrd.rel util.rel - $(ZXCC) $(CPM)/LINK -ZPMLDRD[L100]=ZPM3LDR,BIOSLDRD,UTIL + $(ZXCC) LINK -ZPMLDRD[L100]=ZPM3LDR,BIOSLDRD,UTIL mv zpmldrd.com zpmldr.bin zpmldr.com: zpm3ldr.rel biosldrc.rel util.rel - $(ZXCC) $(CPM)/LINK -ZPMLDRC[L100]=ZPM3LDR,BIOSLDRC,UTIL + $(ZXCC) LINK -ZPMLDRC[L100]=ZPM3LDR,BIOSLDRC,UTIL mv zpmldrc.com zpmldr.com zpmldr.sys: zpmldr.bin loader.bin diff --git a/Source/ZRC/Build.cmd b/Source/ZRC/Build.cmd index d303209d..99b9b522 100644 --- a/Source/ZRC/Build.cmd +++ b/Source/ZRC/Build.cmd @@ -1,8 +1,38 @@ @echo off setlocal -if not exist ..\..\Binary\RCZ80_zrc.rom goto :eof +set TOOLS=../../Tools -copy /b zrc_cfldr.bin + zrc_ptbl.bin + zrc_fill_1.bin + zrc_mon.bin + zrc_fill_2.bin + ..\..\Binary\RCZ80_zrc.rom + zrc_fill_3.bin ..\..\Binary\hd1024_zrc_prefix.dat || exit /b +set PATH=%TOOLS%\srecord;%PATH% -copy /b ..\..\Binary\hd1024_zrc_prefix.dat + ..\..\Binary\hd1024_cpm22.img + ..\..\Binary\hd1024_zsdos.img + ..\..\Binary\hd1024_nzcom.img + ..\..\Binary\hd1024_cpm3.img + ..\..\Binary\hd1024_zpm3.img + ..\..\Binary\hd1024_ws4.img ..\..\Binary\hd1024_zrc_combo.img || exit /b \ No newline at end of file +if exist ..\..\Binary\RCZ80_zrc.rom call :build_zrc + +if exist ..\..\Binary\RCZ80_zrc_ram.rom call :build_zrc_ram + +goto :eof + +:build_zrc + +srec_cat -generate 0x0 0x100000 --constant 0x00 -o temp.dat -binary +srec_cat temp.dat -binary -exclude 0x0 0x100 zrc_cfldr.bin -binary -o temp.dat -binary +srec_cat temp.dat -binary -exclude 0x100 0x200 zrc_ptbl.bin -binary -offset 0x100 -o temp.dat -binary +srec_cat temp.dat -binary -exclude 0x1F000 0x20000 zrc_mon.bin -binary -offset 0x1F000 -o temp.dat -binary +srec_cat temp.dat -binary -exclude 0x24000 0xA4000 ..\..\Binary\RCZ80_zrc.rom -binary -offset 0x24000 -o temp.dat -binary +move temp.dat ..\..\Binary\hd1024_zrc_prefix.dat + +copy /b ..\..\Binary\hd1024_zrc_prefix.dat + ..\..\Binary\hd1024_cpm22.img + ..\..\Binary\hd1024_zsdos.img + ..\..\Binary\hd1024_nzcom.img + ..\..\Binary\hd1024_cpm3.img + ..\..\Binary\hd1024_zpm3.img + ..\..\Binary\hd1024_ws4.img ..\..\Binary\hd1024_zrc_combo.img || exit /b + +goto :eof + +:build_zrc_ram + +srec_cat -generate 0x0 0x100000 --constant 0x00 -o temp.dat -binary +srec_cat temp.dat -binary -exclude 0x0 0x100 zrc_cfldr.bin -binary -o temp.dat -binary +srec_cat temp.dat -binary -exclude 0x100 0x200 zrc_ptbl.bin -binary -offset 0x100 -o temp.dat -binary +srec_cat temp.dat -binary -exclude 0x1F000 0x20000 zrc_mon.bin -binary -offset 0x1F000 -o temp.dat -binary +srec_cat temp.dat -binary -exclude 0x24000 0xA4000 ..\..\Binary\RCZ80_zrc_ram.rom -binary -offset 0x24000 -o temp.dat -binary +move temp.dat ..\..\Binary\hd1024_zrc_ram_prefix.dat + +copy /b ..\..\Binary\hd1024_zrc_ram_prefix.dat + ..\..\Binary\hd1024_cpm22.img + ..\..\Binary\hd1024_zsdos.img + ..\..\Binary\hd1024_nzcom.img + ..\..\Binary\hd1024_cpm3.img + ..\..\Binary\hd1024_zpm3.img + ..\..\Binary\hd1024_ws4.img ..\..\Binary\hd1024_zrc_ram_combo.img || exit /b + +goto :eof diff --git a/Source/ZRC/Makefile b/Source/ZRC/Makefile index 3c582211..b2248ad1 100644 --- a/Source/ZRC/Makefile +++ b/Source/ZRC/Makefile @@ -1,6 +1,9 @@ HD1024ZRCPREFIX = hd1024_zrc_prefix.dat HD1024ZRCCOMBOIMG = hd1024_zrc_combo.img +HD1024ZRCRAMPREFIX = hd1024_zrc_ram_prefix.dat +HD1024ZRCRAMCOMBOIMG = hd1024_zrc_ram_combo.img ZRCROM = ../../Binary/RCZ80_zrc.rom +ZRCRAMROM = ../../Binary/RCZ80_zrc_ram.rom HD1024IMGS = ../../Binary/hd1024_cpm22.img ../../Binary/hd1024_zsdos.img ../../Binary/hd1024_nzcom.img \ ../../Binary/hd1024_cpm3.img ../../Binary/hd1024_zpm3.img ../../Binary/hd1024_ws4.img @@ -10,6 +13,10 @@ ifneq ($(wildcard $(ZRCROM)),) OBJECTS += $(HD1024ZRCPREFIX) $(HD1024ZRCCOMBOIMG) endif +ifneq ($(wildcard $(ZRCRAMROM)),) + OBJECTS += $(HD1024ZRCRAMPREFIX) $(HD1024ZRCRAMCOMBOIMG) +endif + DEST=../../Binary TOOLS = ../../Tools @@ -19,7 +26,23 @@ include $(TOOLS)/Makefile.inc DIFFPATH = $(DIFFTO)/Binary $(HD1024ZRCPREFIX): - cat zrc_cfldr.bin zrc_ptbl.bin zrc_fill_1.bin zrc_mon.bin zrc_fill_2.bin $(ZRCROM) zrc_fill_3.bin >$@ + srec_cat -generate 0x0 0x100000 --constant 0x00 -o temp.dat -binary + srec_cat temp.dat -binary -exclude 0x0 0x100 zrc_cfldr.bin -binary -o temp.dat -binary + srec_cat temp.dat -binary -exclude 0x100 0x200 zrc_ptbl.bin -binary -offset 0x100 -o temp.dat -binary + srec_cat temp.dat -binary -exclude 0x1F000 0x20000 zrc_mon.bin -binary -offset 0x1F000 -o temp.dat -binary + srec_cat temp.dat -binary -exclude 0x24000 0xA4000 $(ZRCROM) -binary -offset 0x24000 -o temp.dat -binary + mv temp.dat $@ + +$(HD1024ZRCRAMPREFIX): + srec_cat -generate 0x0 0x100000 --constant 0x00 -o temp.dat -binary + srec_cat temp.dat -binary -exclude 0x0 0x100 zrc_cfldr.bin -binary -o temp.dat -binary + srec_cat temp.dat -binary -exclude 0x100 0x200 zrc_ptbl.bin -binary -offset 0x100 -o temp.dat -binary + srec_cat temp.dat -binary -exclude 0x1F000 0x20000 zrc_mon.bin -binary -offset 0x1F000 -o temp.dat -binary + srec_cat temp.dat -binary -exclude 0x24000 0xA4000 $(ZRCRAMROM) -binary -offset 0x24000 -o temp.dat -binary + mv temp.dat $@ $(HD1024ZRCCOMBOIMG): $(HD1024ZRCPREFIX) $(HD1024IMGS) - cat $^ > $@ \ No newline at end of file + cat $^ > $@ + +$(HD1024ZRCRAMCOMBOIMG): $(HD1024ZRCRAMPREFIX) $(HD1024IMGS) + cat $^ > $@ diff --git a/Source/ZRC/zrc_fill_1.bin b/Source/ZRC/zrc_fill_1.bin deleted file mode 100644 index 705bedcd..00000000 Binary files a/Source/ZRC/zrc_fill_1.bin and /dev/null differ diff --git a/Source/ZRC/zrc_fill_2.bin b/Source/ZRC/zrc_fill_2.bin deleted file mode 100644 index 294f4016..00000000 Binary files a/Source/ZRC/zrc_fill_2.bin and /dev/null differ diff --git a/Source/ZRC/zrc_fill_3.bin b/Source/ZRC/zrc_fill_3.bin deleted file mode 100644 index a461d083..00000000 Binary files a/Source/ZRC/zrc_fill_3.bin and /dev/null differ diff --git a/Source/ZSDOS/Build.cmd b/Source/ZSDOS/Build.cmd index fd4cf213..554a8dbb 100644 --- a/Source/ZSDOS/Build.cmd +++ b/Source/ZSDOS/Build.cmd @@ -3,16 +3,14 @@ setlocal set TOOLS=../../Tools -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/ -zx ZMAC -ZSDOS -/P || exit /b -zx LINK -ZSDOS.BIN=ZSDOS[LD800] || exit /b +zxcc ZMAC -ZSDOS -/P || exit /b +zxcc LINK -ZSDOS.BIN=ZSDOS[LD800] || exit /b tasm -t80 -g3 -fFF loader.asm loader.bin loader.lst || exit /b diff --git a/Source/ZSDOS/Clock/Build.cmd b/Source/ZSDOS/Clock/Build.cmd index d676aae2..2a02d1e1 100644 --- a/Source/ZSDOS/Clock/Build.cmd +++ b/Source/ZSDOS/Clock/Build.cmd @@ -3,12 +3,10 @@ setlocal set TOOLS=../../../Tools -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/ -zx ZMAC -WBWCLK -/P || exit /b +zxcc ZMAC -WBWCLK -/P || exit /b diff --git a/Source/ZSDOS/Makefile b/Source/ZSDOS/Makefile index 90963e9d..55731ea4 100644 --- a/Source/ZSDOS/Makefile +++ b/Source/ZSDOS/Makefile @@ -8,10 +8,10 @@ CCP = ../ZCPR-DJ/zcpr.bin include $(TOOLS)/Makefile.inc zsdos.rel: zsdos.z80 - $(ZXCC) $(CPM)/ZMAC -$< -/P + $(ZXCC) ZMAC -$< -/P zsdos.bin: zsdos.rel - $(ZXCC) $(CPM)/LINK -$@=$<[LD800] + $(ZXCC) LINK -$@=$<[LD800] %.sys: %.bin loader.bin cat loader.bin $*.bin > $@ diff --git a/Source/ZZR/Bank Layout.txt b/Source/ZZR/Bank Layout.txt index d7b4bc64..9e2d951e 100644 --- a/Source/ZZR/Bank Layout.txt +++ b/Source/ZZR/Bank Layout.txt @@ -1,19 +1,32 @@ +ZZRCC has no real ROM. It has a single 512K RAM chip. The first +256K of the RAM chip is loaded from the CF card. This 256K is +treated like ROM by RomWBW. The remainder of the RAM (256K) is +treated like RAM by RomWBW. + +Because of the memory constraints, notice that there is no RAM Disk, +only a ROM disk. If you perform a ROM boot to an OS, the A: drive +will be the ROM disk and will not be writable. Booting a ROM OS +on this system is not typical since the system has a CF card by +definition. + Bank ROM RAM RAM ---- --- --- --- -0 HBIOS (IMG) RAMDISK RAMDISK -1 ROMLDR+MON+CP/M2+ZSYS RAMDISK RAMDISK -2 FTH+BAS+TBAS+PLAY+USR RAMDISK RAMDISK -3 RESERVED RAMDISK RAMDISK -4 ROMDISK RAMDISK RAMDISK -5 ROMDISK RAMDISK RAMDISK -6 ROMDISK RAMDISK RAMDISK -7 ROMDISK RAMDISK RAMDISK +0 HBIOS (IMG) +1 ROMLDR+MON+CP/M2+ZSYS +2 FTH+BAS+TBAS+PLAY+USR +3 RESERVED +4 ROMDISK +5 ROMDISK +6 ROMDISK +7 ROMDISK -8 ROMDISK BUF (CPM3) BUF (CPM3) -9 ROMDISK BUF (CPM3) BUF (CPM3) -A ROMDISK BUF (CPM3) BUF (CPM3) -B ROMDISK BUF (CPM3) BUF (CPM3) -C ROMDISK AUX (CPM3) TPA (CPM3) -D ROMDISK HBIOS (EXEC) HBIOS (EXEC) -E ROMDISK TPA-LO OS (CPM3) -F ROMDISK COMMON (TPA-HI) COMMON (TPA-HI) \ No newline at end of file +8 BUF (CPM3) BUF (CPM3) +9 BUF (CPM3) BUF (CPM3) +A BUF (CPM3) BUF (CPM3) +B BUF (CPM3) BUF (CPM3) +C AUX (CPM3) TPA (CPM3) +D HBIOS (EXEC) HBIOS (EXEC) +E TPA-LO OS (CPM3) +F COMMON (TPA-HI) COMMON (TPA-HI) + +--WBW 6:40 PM 2/16/2022 \ No newline at end of file diff --git a/Source/ZZR/Build.cmd b/Source/ZZR/Build.cmd index 3d6b0872..4dea5d8e 100644 --- a/Source/ZZR/Build.cmd +++ b/Source/ZZR/Build.cmd @@ -1,7 +1,27 @@ @echo off setlocal -if not exist ..\..\Binary\RCZ280_nat_zzr.rom goto :eof +set ROMFILE=..\..\Binary\RCZ280_nat_zzr.rom +set ROMSIZE=262144 + +if not exist %ROMFILE% goto :eof + +:: +:: The ROM image *must* be exactly 256K or the resulting disk +:: image produced below will be invalid. Check for the proper size. +:: + +call :filesize %ROMFILE% + +if "%FILESIZE%" neq "%ROMSIZE%" ( + echo. + echo. + echo ERROR: "%ROMFILE%" is not exactly %ROMSIZE% bytes as required!!! + echo You must specify a ROMSIZE of "256" when building the ZZRCC ROM image. + echo. + echo. + exit /b 1 +) rem ..\..\Tools\srecord\srec_cat.exe ..\..\Binary\RCZ280_nat_zzr.rom -Binary -Exclude 0x5000 0x7000 zzr_romldr.hex -Intel -Output ..\..\Binary\RCZ280_nat_zzr.hex -Intel || exit /b @@ -13,4 +33,10 @@ rem copy /b zzr_cfldr.bin + zzr_ptbl.bin + zzr_fill_1.bin + zzr_mon.bin + zzr_fi copy /b zzr_cfldr.bin + zzr_ptbl.bin + zzr_fill_1.bin + zzr_mon.bin + zzr_fill_2.bin + ..\..\Binary\RCZ280_nat_zzr.rom + zzr_fill_3.bin ..\..\Binary\hd1024_zzr_prefix.dat || exit /b -copy /b ..\..\Binary\hd1024_zzr_prefix.dat + ..\..\Binary\hd1024_cpm22.img + ..\..\Binary\hd1024_zsdos.img + ..\..\Binary\hd1024_nzcom.img + ..\..\Binary\hd1024_cpm3.img + ..\..\Binary\hd1024_zpm3.img + ..\..\Binary\hd1024_ws4.img ..\..\Binary\hd1024_zzr_combo.img || exit /b \ No newline at end of file +copy /b ..\..\Binary\hd1024_zzr_prefix.dat + ..\..\Binary\hd1024_cpm22.img + ..\..\Binary\hd1024_zsdos.img + ..\..\Binary\hd1024_nzcom.img + ..\..\Binary\hd1024_cpm3.img + ..\..\Binary\hd1024_zpm3.img + ..\..\Binary\hd1024_ws4.img ..\..\Binary\hd1024_zzr_combo.img || exit /b + +goto :eof + +:filesize +set FILESIZE=%~z1 +goto :eof \ No newline at end of file diff --git a/Source/ZZR/Makefile b/Source/ZZR/Makefile index 36b67930..03d78ad3 100644 --- a/Source/ZZR/Makefile +++ b/Source/ZZR/Makefile @@ -1,17 +1,15 @@ HD1024ZZRPREFIX = hd1024_zzr_prefix.dat HD1024ZZZROMBOIMG = hd1024_zzr_combo.img ZZRROM = ../../Binary/RCZ280_nat_zzr.rom -ZZRLDRROM = RCZ280_nat_zzr_ldr.rom ZZRROMHEX = RCZ280_nat_zzr.hex HD1024IMGS = ../../Binary/hd1024_cpm22.img ../../Binary/hd1024_zsdos.img ../../Binary/hd1024_nzcom.img \ ../../Binary/hd1024_cpm3.img ../../Binary/hd1024_zpm3.img ../../Binary/hd1024_ws4.img - +ZZRROMSIZE = 262144 OBJECTS := ifneq ($(wildcard $(ZZRROM)),) -# OBJECTS += $(ZZRROMHEX) $(ZZRLDRROM) $(HD1024ZZRPREFIX) $(HD1024ZZZROMBOIMG) - OBJECTS += $(ZZRROMHEX) $(HD1024ZZRPREFIX) $(HD1024ZZZROMBOIMG) + OBJECTS += $(ZZRROMHEX) $(HD1024ZZRPREFIX) $(HD1024ZZZROMBOIMG) endif DEST=../../Binary @@ -22,16 +20,14 @@ include $(TOOLS)/Makefile.inc DIFFPATH = $(DIFFTO)/Binary -$(HD1024ZZRPREFIX): -# cat zzr_cfldr.bin zzr_ptbl.bin zzr_fill_1.bin zzr_mon.bin zzr_fill_2.bin $(ZZRLDRROM) zzr_fill_3.bin >$@ +zzrromchk: + [ `wc -c $(ZZRROM) | awk '{print $$1}'` = $(ZZRROMSIZE) ] + +$(HD1024ZZRPREFIX): zzrromchk cat zzr_cfldr.bin zzr_ptbl.bin zzr_fill_1.bin zzr_mon.bin zzr_fill_2.bin $(ZZRROM) zzr_fill_3.bin >$@ -$(HD1024ZZZROMBOIMG): $(HD1024ZZRPREFIX) $(HD1024IMGS) - cat $^ > $@ +$(HD1024ZZZROMBOIMG): zzrromchk $(HD1024ZZRPREFIX) $(HD1024IMGS) + cat $(HD1024ZZRPREFIX) $(HD1024IMGS) > $@ -$(ZZRROMHEX): $(ZZRROM) -# srec_cat $(ZZRROM) -Binary -Exclude 0x5000 0x7000 zzr_romldr.hex -Intel -Output $(ZZRROMHEX) -Intel +$(ZZRROMHEX): zzrromchk $(ZZRROM) srec_cat $(ZZRROM) -Binary -Output $(ZZRROMHEX) -Intel -CRLF - -$(ZZRLDRROM): $(ZZRROMHEX) - srec_cat $(ZZRROMHEX) -Intel -Output $(ZZRLDRROM) -Binary diff --git a/Source/ver.inc b/Source/ver.inc index f14ca9b3..d011272e 100644 --- a/Source/ver.inc +++ b/Source/ver.inc @@ -2,4 +2,4 @@ #DEFINE RMN 1 #DEFINE RUP 1 #DEFINE RTP 0 -#DEFINE BIOSVER "3.1.1-pre.146" +#DEFINE BIOSVER "3.1.1-pre.162" diff --git a/Source/ver.lib b/Source/ver.lib index a22e049f..5fc0acbd 100644 --- a/Source/ver.lib +++ b/Source/ver.lib @@ -3,5 +3,5 @@ rmn equ 1 rup equ 1 rtp equ 0 biosver macro - db "3.1.1-pre.146" + db "3.1.1-pre.162" endm diff --git a/Tools/Makefile.inc b/Tools/Makefile.inc index 70820679..1a579e50 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. @@ -96,10 +97,10 @@ CPM=$(TOOLS)/cpm/bin %.rel: %.z80 $(ZXCC) $(CPM)/Z80ASM -$(basename $<)/MF -%.hex: %.z80 - $(ZXCC) $(CPM)/Z80ASM -$(basename $<)/HF +#%.hex: %.z80 +# $(ZXCC) $(CPM)/Z80ASM -$(basename $<)/HF -%.hex: %.180 +%.hex: %.z80 $(ZXCC) $(CPM)/SLR180 -$(basename $<)/HF %.rel: %.azm @@ -111,6 +112,9 @@ CPM=$(TOOLS)/cpm/bin %.rel: %.mac $(ZXCC) $(CPM)/M80 -=$(basename $<) +%.com: %.rel + $(ZXCC) $(CPM)/L80 -$(basename $<),$(basename $<).com/n/e + ifeq ($(UNAME), Linux) %.eeprom: %.spin $(BSTC) -e -l $< diff --git a/Tools/cpm/bin/SLR180.COM b/Tools/cpm/bin/SLR180.COM deleted file mode 100644 index 0360a7d5..00000000 Binary files a/Tools/cpm/bin/SLR180.COM and /dev/null differ diff --git a/Tools/cpm/bin/TEX21B.COM b/Tools/cpm/bin/TEX21B.COM deleted file mode 100644 index aa72b287..00000000 Binary files a/Tools/cpm/bin/TEX21B.COM and /dev/null differ diff --git a/Tools/cpm/bin/UNZIP.COM b/Tools/cpm/bin/UNZIP.COM deleted file mode 100644 index b231bf47..00000000 Binary files a/Tools/cpm/bin/UNZIP.COM and /dev/null differ diff --git a/Tools/cpm/bin/UNZIP154.COM b/Tools/cpm/bin/UNZIP154.COM deleted file mode 100644 index f0572630..00000000 Binary files a/Tools/cpm/bin/UNZIP154.COM and /dev/null differ diff --git a/Tools/cpm/bin/UNZIP186.COM b/Tools/cpm/bin/UNZIP186.COM deleted file mode 100644 index c750ff52..00000000 Binary files a/Tools/cpm/bin/UNZIP186.COM and /dev/null differ 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/bin80/SLR180.COM b/Tools/cpm/bin80/SLR180.COM new file mode 100644 index 00000000..91255eed Binary files /dev/null and b/Tools/cpm/bin80/SLR180.COM differ 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/bin80/TEX21B.COM b/Tools/cpm/bin80/TEX21B.COM new file mode 100644 index 00000000..68326c1f Binary files /dev/null and b/Tools/cpm/bin80/TEX21B.COM differ 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/bin80/UNZIP.COM b/Tools/cpm/bin80/UNZIP.COM new file mode 100644 index 00000000..9da369ff Binary files /dev/null and b/Tools/cpm/bin80/UNZIP.COM differ 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/tasm32/TASM280.TAB b/Tools/tasm32/TASM280.TAB index f8644eec..b57fad84 100644 --- a/Tools/tasm32/TASM280.TAB +++ b/Tools/tasm32/TASM280.TAB @@ -127,8 +127,8 @@ DEC L 2D 1 NOP 1 DEC SP 3B 1 NOP 1 DI "" F3 1 NOP 1 DJNZ * 10 2 R1 1 - EI "" FB 1 NOP 1 +EI * 7FED 3 NOP 1 /* Z280 */ EX (SP),HL E3 1 NOP 1 EX (SP),IX E3DD 2 NOP 1 EX (SP),IY E3FD 2 NOP 1 @@ -158,6 +158,8 @@ IN L,(C) 68ED 2 NOP 1 IN A,(*) DB 2 NOP 1 +INW HL,(C) B7ED 2 NOP 1 /* Z280 */ + IN0 A,(*) 38ED 3 NOP 2 IN0 B,(*) 00ED 3 NOP 2 IN0 C,(*) 08ED 3 NOP 2 @@ -342,6 +344,8 @@ LD SP,HL F9 1 NOP 1 LD SP,IX F9DD 2 NOP 1 LD SP,IY F9FD 2 NOP 1 LD SP,* 31 3 NOP 1 +LDUD A,(HL) 86ED 2 NOP 1 /* Z280 */ +LDUP A,(HL) 96ED 2 NOP 1 /* Z280 */ LDCTL (C),HL 6EED 2 NOP 1 /* Z280 */ LDCTL HL,(C) 66ED 2 NOP 1 /* Z280 */ LDCTL USP,HL 8FED 2 NOP 1 /* Z280 */ @@ -378,6 +382,7 @@ OTDR "" BBED 2 NOP 1 OTIM "" 83ED 2 NOP 2 OTIMR "" 93ED 2 NOP 2 OTIR "" B3ED 2 NOP 1 +OTIRW "" 93ED 2 NOP 1 /* Z280 */ OUT (C),A 79ED 2 NOP 1 OUT (C),B 41ED 2 NOP 1 @@ -524,6 +529,9 @@ SBC HL,DE 52ED 2 NOP 1 SBC HL,HL 62ED 2 NOP 1 SBC HL,SP 72ED 2 NOP 1 SBC A,* DE 2 NOP 1 + +SC * 71ED 4 NOP 1 /* Z280 */ + SCF "" 37 1 NOP 1 SET *,(HL) C6CB 2 ZBIT 1 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/uz80as/z80.c b/Tools/unix/uz80as/z80.c index 60df3c08..214f6964 100644 --- a/Tools/unix/uz80as/z80.c +++ b/Tools/unix/uz80as/z80.c @@ -210,6 +210,13 @@ static const struct matchtab s_matchtab_z80[] = { { "MULTU A,a", "FD.ED.F9.d0.", 4, 0 }, { "OUTW (C),HL", "ED.BF.", 4, 0 }, { "RETIL", "ED.55.", 4, 0 }, + { "EI a", "ED.7F.d0.", 4, 0 }, + { "SC a", "ED.71.e0", 4, 0 }, + { "OTIRW", "ED.93.", 4, 0 }, + { "LDUD A,(HL)", "ED.86.", 4, 0 }, + { "LDUP A,(HL)", "ED.96.", 4, 0 }, + { "ADD HL,A", "ED.6D.", 4, 0 }, + { "INW HL,(C)", "ED.B7.", 4, 0 }, { NULL, NULL }, }; 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/cbops.h b/Tools/unix/zx/cbops.h deleted file mode 100644 index 47b69da0..00000000 --- a/Tools/unix/zx/cbops.h +++ /dev/null @@ -1,172 +0,0 @@ -/* 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/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/cpmint.h b/Tools/unix/zx/cpmint.h deleted file mode 100644 index e6878174..00000000 --- a/Tools/unix/zx/cpmint.h +++ /dev/null @@ -1,226 +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 internal declarations for the library. -*/ - -#include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_DIRENT_H -# include -#else -#ifdef __WATCOMC__ -# include -# include -#else -# include "dirent.h" -#endif -#endif -#ifdef HAVE_NDIR_H -# include -#endif -#ifdef HAVE_SYS_DIR_H -# include -#endif -#ifdef HAVE_SYS_NDIR_H -# include -#endif -#ifdef HAVE_WINDOWS_H -# include -#endif -#ifdef HAVE_WINNT_H -# include -#endif -#ifdef HAVE_SYS_VFS_H -# include -#endif -#ifdef HAVE_UTIME_H -# include -#endif -#ifdef HAVE_FCNTL_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif -#ifdef WIN32 -# define strcasecmp _stricmp -#endif - - -#ifdef __MSDOS__ - #include - #include - #include - #ifdef __GO32__ - #include - #include - #include - #endif -#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 -#else - #define EXT extern - #define INIT(x) -#endif - -/* The 16 directories to which the 16 CP/M drives are mapped */ - -EXT char redir_drive_prefix[16][CPM_MAXPATH]; - -/* Current drive and user */ - -EXT int redir_cpmdrive; -EXT int redir_cpmuser; - -/* Length of 1 read/write operation, bytes */ - -EXT int redir_rec_len INIT(128); - -/* Same, but in 128-byte records */ -EXT int redir_rec_multi INIT(1); - -/* Using a DRDOS system? */ -EXT int redir_drdos INIT(0); - -/* Default password */ -#ifdef __MSDOS__ -EXT char redir_passwd[8] INIT(""); -#endif - -EXT cpm_word redir_l_drives INIT(0); -EXT cpm_word redir_ro_drives INIT(0); - -#undef EXT -#undef INIT - - - -/* Convert FCB to a Unix filename, returning 1 if it's ambiguous */ -int redir_fcb2unix(cpm_byte *fcb, char *fname); - -/* Open FCB, set file attributes */ -int redir_ofile(cpm_byte * fcb, char *s); - -/* Check that the FCB we have is valid */ -int redir_verify_fcb(cpm_byte *fcb); - -#ifndef O_BINARY /* Necessary in DOS, not present in Linux */ -#define O_BINARY 0 -#endif - -/* Facilities for debug tracing */ - - -long zxlseek(int fd, long offset, int wh); - -#ifdef DEBUG - void redir_Msg(char *s, ...); - void redir_showfcb(cpm_byte *fcb); -#else - /* Warning: This is a GCC extension */ - #define redir_Msg(x, ...) - #define redir_showfcb(x) -#endif - - - -/* Get the "sequential access" file pointer out of an FCB */ - -long redir_get_fcb_pos(cpm_byte *fcb); - -/* Write "sequential access" pointer to FCB */ - -void redir_put_fcb_pos(cpm_byte *fcb, long npos); - -/* Convert time_t to CP/M day count/hours/minutes */ -dword redir_cpmtime(time_t t); -/* And back */ -time_t redir_unixtime(cpm_byte *c); - - -/* Functions to access 24-bit & 32-bit words in memory. These are always - little-endian. */ - -void redir_wr24(cpm_byte *addr, dword v); -void redir_wr32(cpm_byte *addr, dword v); -dword redir_rd24(cpm_byte *addr); -dword redir_rd32(cpm_byte *addr); - -/* If you have 64-bit file handles, you'll need to write separate wrhandle() - and rdhandle() routines */ -#define redir_wrhandle redir_wr32 -#define redir_rdhandle redir_rd32 - -/* Mark a drive as logged in */ - -void redir_log_drv(cpm_byte drv); -void redir_log_fcb(cpm_byte *fcb); - -/* Check if a drive is software read-only */ - -int redir_ro_drv(cpm_byte drv); -int redir_ro_fcb(cpm_byte *fcb); - -/* Translate errno to a CP/M error */ - -cpm_word redir_xlt_err(void); - -/* Get disc label */ -cpm_word redir_get_label(cpm_byte drv, char *pattern); - - -/* DRDOS set/get access rights - no-ops under MSDOS and Unix: - * - * CP/M password mode -> DRDOS password mode */ -cpm_word redir_drdos_pwmode(cpm_byte b); - -/* DRDOS password mode to CP/M password mode */ -cpm_byte redir_cpm_pwmode(cpm_word w); - -/* Get DRDOS access rights for a file */ -cpm_word redir_drdos_get_rights(char *path); - -/* Set DRDOS access rights and/or password */ -cpm_word redir_drdos_put_rights(char *path, cpm_byte *dma, cpm_word rights); - -/* Was the last error caused by invalid password? */ -cpm_word redir_password_error(void); - -/* Append password to filename (FILE.TYP -> FILE.TYP;PASSWORD) */ -void redir_password_append(char *s, cpm_byte *dma); - 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/cpmredir.c b/Tools/unix/zx/cpmredir.c deleted file mode 100644 index d8a5e337..00000000 --- a/Tools/unix/zx/cpmredir.c +++ /dev/null @@ -1,951 +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 handles actual reading and writing */ - -#define CPMDEF -#include "cpmint.h" - -#ifdef DEBUG -#define SHOWNAME(func) \ - { \ - char fname[CPM_MAXPATH]; \ - redir_fcb2unix(fcb, fname); \ - redir_Msg(func "(\"%s\")\n", fname); \ - } - -#else - #define SHOWNAME(func) -#endif - - -/* DISK BDOS FUNCTIONS */ - -/* General treatment: - * - * We use the "disk block number" fields in the FCB to store our file handle; - * this is a similar trick to that used by DOSPLUS, which stores its cluster - * number in there. It works if: - * - * a) sizeof(int) <= 8 bytes (64 bits). If it's more, this needs rewriting - * to use a hash table; - * b) the program never touches these bytes. Practically no CP/M program does. - * - * We store a "magic number" (0x00FD) in the first two bytes of this field, and - * if the number has been changed then we abort. - * - * nb: Since I wrote ZXCC, I have found that DOSPLUS uses 0x8080 as a magic - * number [well, actually this is an oversimplification, but a hypothetical - * program written against DOSPLUS would work with 0x8080]. Perhaps 0x8080 - * should be used instead. - * - * Format of the field: - * - * [--2 bytes--] magic number - * [--8 bytes--] file handle. 8 bytes reserved but only 4 currently used. - * [--2 bytes--] reserved. - * [--4 bytes--] file length. - */ -#define MAGIC_OFFSET 0x10 -#define HANDLE_OFFSET 0x12 -#define LENGTH_OFFSET 0x1C - -cpm_word fcb_open(cpm_byte *fcb, cpm_byte *dma) -{ - char fname[CPM_MAXPATH]; - int handle; - int drv, l; - char *s; - DIR *dir; - - /* Don't support ambiguous filenames */ - if (redir_fcb2unix(fcb, fname)) return 0x09FF; - - redir_log_fcb(fcb); - - drv = fcb[0] & 0x7F; - if (!drv) drv = redir_cpmdrive; else --drv; - - if (fcb[0] & 0x80) /* Open directory */ - { - if (fcb[0x0C]) return 0x0BFF; /* Can't assign "floating" dir */ - - if (!memcmp(fcb + 1, ". ", 11)) - { - return 0; /* Opening "." */ - } - if (!memcmp(fcb + 1, ".. ", 11)) - { - l = strlen(redir_drive_prefix[drv]) - 1; - s = redir_drive_prefix[drv]; - --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; /* "/" */ -#endif - ++l; - s[l] = 0; - return 0; - } -/* Opening some other directory */ - - dir = opendir(fname); - if (!dir) return 0xFF; /* Not a directory */ - closedir(dir); - strcpy(redir_drive_prefix[drv], fname); - strcat(redir_drive_prefix[drv], "/"); - return 0; - } - - /* Note: Some programs (MAC is an example) don't close a file - * if they opened it just to do reading. MAC then reopens the - * file (which rewinds it); this causes FCB leaks under some - * DOS-based emulators */ - - handle = redir_ofile(fcb, fname); - redir_Msg("fcb_open(\"%s\")\r\n", fname); - if (handle < 0 && redir_password_error()) - { - redir_Msg("1st chance open failed on %s\r\n", fname); - redir_password_append(fname, dma); - redir_Msg("Trying with %s\r\n", fname); - handle = redir_ofile(fcb, fname); - } - - - if (handle == -1) - { - redir_Msg("Ret: -1\n"); - if (redir_password_error()) return 0x7FF; - return 0xFF; - } - fcb[MAGIC_OFFSET ] = 0xFD; /* "Magic number" */ - fcb[MAGIC_OFFSET + 1] = 0x00; - -/* TODO: Should the magic number perhaps be 0x8080, as in DOSPLUS? */ - - redir_wrhandle(fcb + HANDLE_OFFSET, handle); - - redir_put_fcb_pos(fcb, fcb[0x0C] * 16384); - /* (v1.01) "seek" to beginning of extent, not file. - * This is necessary for the awful I/O code - * in LINK-80 to work - */ - - /* Get the file length */ - redir_wr32(fcb + 0x1C, zxlseek(handle, 0, SEEK_END)); - zxlseek(handle, 0, SEEK_SET); - - /* Set the last record byte count */ - if (fcb[0x20] == 0xFF) fcb[0x20] = fcb[0x1C] & 0x7F; - - redir_Msg("Ret: 0\n"); - - return 0; -} - - -cpm_word fcb_close(cpm_byte *fcb) -{ - int handle, drv; - - SHOWNAME("fcb_close") - - if ((handle = redir_verify_fcb(fcb)) < 0) return -1; - redir_Msg(" (at %lx)\n", zxlseek(handle, 0, SEEK_CUR)); - - if (fcb[0] & 0x80) /* Close directory */ - { - drv = fcb[0] & 0x7F; - if (!drv) drv = redir_cpmdrive; else drv--; -#ifdef __MSDOS__ - strcpy(redir_drive_prefix[drv] + 1, ":/"); -#else - strcpy(redir_drive_prefix[drv], "/"); -#endif - return 0; - } - - if (fcb[5] & 0x80) /* CP/M 3: Flush rather than close */ - { -#ifndef WIN32 - sync(); -#endif - return 0; - } - -#ifdef WIN32 - { - BOOL b; - redir_Msg(">CloseHandle() Handle=%lu\n", handle); - b = CloseHandle((HANDLE)handle); - redir_Msg("80h, let it be 80h - -*/ - - -cpm_word fcb_read(cpm_byte *fcb, cpm_byte *dma) -{ - int handle; - int rv, n, rd_len; - long npos; - - SHOWNAME("fcb_read") - - if ((handle = redir_verify_fcb(fcb)) < 0) return 9; /* Invalid FCB */ - - /* The program may have mucked about with the counters, so - * do an lseek() to where it should be. */ - - npos = redir_get_fcb_pos(fcb); - zxlseek(handle, npos, SEEK_SET); - redir_Msg(" (from %lx)\n", zxlseek(handle, 0, SEEK_CUR)); - - /* Read in the required amount */ - - memset(dma, 0x00, redir_rec_len); - -#ifdef WIN32 - { - BOOL b; - redir_Msg(">ReadFile() Handle=%lu, DMA=%lu, Len=%lu\n", handle, dma, redir_rec_len); - b = ReadFile((HANDLE)handle, dma, redir_rec_len, (unsigned long *)(&rv), NULL); - redir_Msg("= 0) && (rv < redir_rec_len)) - memset(dma + rv, 0x00, redir_rec_len - rv); - - /* rd_len = length supposedly read, bytes. Round to nearest 128 bytes. - */ - rd_len = ((rv + 127) / 128) * 128; - - npos += rd_len; - - /* Write new file pointer into FCB */ - - redir_put_fcb_pos(fcb, npos); - - if (rv < 0) - { - redir_Msg("Ret: -1\n"); - return redir_xlt_err(); /* unwritten extent */ - } - - /* Less was read in than asked for. Report the number of 128-byte - * records that _were_ read in. - */ - - if (rd_len < redir_rec_len) /* eof */ - { - /* 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 */ - 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; -} - - -cpm_word fcb_write(cpm_byte *fcb, cpm_byte *dma) -{ - int handle; - int rv; - long npos, len; - - SHOWNAME("fcb_write") - - if ((handle = redir_verify_fcb(fcb)) < 0) return 9; /* Invalid FCB */ - - /* Software write-protection */ - if (redir_ro_fcb(fcb)) return 0x02FF; - - /* Check for a seek */ - npos = redir_get_fcb_pos(fcb); - zxlseek(handle, npos, SEEK_SET); - - redir_Msg(" (to %lx)\n", zxlseek(handle, 0, SEEK_CUR)); - -#ifdef WIN32 - { - BOOL b; - redir_Msg(">WriteFile() Handle=%lu, DMA=%lu, Len=%lu\n", handle, dma, redir_rec_len); - b = WriteFile((HANDLE)handle, dma, redir_rec_len, (unsigned long *)(&rv), NULL); - 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); - b = ReadFile((HANDLE)handle, dma, redir_rec_len, (unsigned long *)(&rv), NULL); - redir_Msg("= 0) && (rv < redir_rec_len)) - memset(dma + rv, 0x00, redir_rec_len - rv); - - zxlseek(handle, offs, SEEK_SET); - - redir_put_fcb_pos(fcb, offs); - - rd_len = ((rv + 127) / 128) * 128; - - if (rv < 0) return redir_xlt_err(); /* Error */ - if (rd_len < redir_rec_len) /* eof */ - { - rd_len = ((rv + 127) / 128) << 8; /* 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; -} - - - -cpm_word fcb_randwr(cpm_byte *fcb, cpm_byte *dma) -{ - int handle; - int rv; - dword offs = redir_rd24(fcb + 0x21) * 128; - long len; - - SHOWNAME("fcb_randwr") - - if ((handle = redir_verify_fcb(fcb)) < 0) return 9; /* Invalid FCB */ - /* Software write-protection */ - if (redir_ro_fcb(fcb)) return 0x02FF; - - if (zxlseek(handle, offs, SEEK_SET) < 0) return 6; /* bad record no. */ -#ifdef WIN32 - { - BOOL b; - redir_Msg(">WriteFile() Handle=%lu, DMA=%lu, Len=%lu\n", handle, dma, redir_rec_len); - b = WriteFile((HANDLE)handle, dma, redir_rec_len, (unsigned long *)(&rv), NULL); - redir_Msg("WriteFile() Handle=%lu, DMA=%lu, Len=%lu\n", handle, zerorec, rl); - b = WriteFile((HANDLE)handle, zerorec, rl, (unsigned long *)(&rv), NULL); - redir_Msg("= 0) len += rv; - - if (rv < rl) - { - redir_wr32(fcb + LENGTH_OFFSET, len); - return redir_xlt_err(); - } - } - redir_wr32(fcb + LENGTH_OFFSET, offs); - - return fcb_randwr(fcb, dma); -} - -cpm_word fcb_tell(cpm_byte *fcb) -{ - int handle; - off_t rv; - - SHOWNAME("fcb_tell") - - if ((handle = redir_verify_fcb(fcb)) < 0) return 9; /* Invalid FCB */ - - rv = zxlseek(handle, 0, SEEK_CUR); - - if (rv < 0) return 0xFF; - - rv = rv >> 7; - fcb[0x21] = rv & 0xFF; - fcb[0x22] = (rv >> 8) & 0xFF; - fcb[0x23] = (rv >> 16) & 0xFF; - return 0; -} - - -cpm_word fcb_stat(cpm_byte *fcb) -{ - char fname[CPM_MAXPATH]; - struct stat st; - int rv; - - /* Don't support ambiguous filenames */ - if (redir_fcb2unix(fcb, fname)) return 0x09FF; - - rv = stat(fname, &st); - - redir_Msg("fcb_stat(\"%s\") fcb=%x\n", fname, (int)fcb); - if (rv < 0) - { - redir_Msg("ret: -1\n"); - return 0xFF; - } - - redir_wr24(fcb + 0x21, (st.st_size + 127) / 128); - - redir_Msg("ret: 0"); - return 0; -} - - -cpm_word fcb_multirec(cpm_byte rc) -{ - if (rc < 1 || rc > 128) return 0xFF; - - redir_rec_multi = rc; - redir_rec_len = 128 * rc; - redir_Msg("Set read/write to %d bytes\n", redir_rec_len); - return 0; -} - - -cpm_word fcb_date(cpm_byte *fcb) -{ - char fname[CPM_MAXPATH]; - struct stat st; - int rv; - - /* Don't support ambiguous filenames */ - if (redir_fcb2unix(fcb, fname)) return 0x09FF; - - rv = stat(fname, &st); - - redir_Msg("fcb_stat(\"%s\")\n", fname); - if (rv < 0) return 0xFF; - - redir_wr32(fcb + 0x18, redir_cpmtime(st.st_atime)); - redir_wr32(fcb + 0x1C, redir_cpmtime(st.st_ctime)); - - fcb[0x0C] = redir_cpm_pwmode(redir_drdos_get_rights(fname)); - return 0; -} - - - -cpm_word fcb_trunc(cpm_byte *fcb, cpm_byte *dma) -{ - char fname[CPM_MAXPATH]; - dword offs = redir_rd24(fcb + 0x21) * 128; - - /* 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); -#ifdef WIN32 - (void)offs; - return 0x06FF; /* Simply not implemented */ -#else - if (truncate(fname, offs)) - { - if (redir_password_error()) - { - redir_password_append(fname, dma); - if (!truncate(fname, offs)) return 0; - } - 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); - buf.modtime = redir_unixtime(dma + 4); - - /* 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); - - if (utime(fname, &buf)) - { - if (redir_password_error()) - { - redir_password_append(fname, dma); - if (!utime(fname, &buf)) return 0; - } - return redir_xlt_err(); - } -#endif - return 0; -} - - - -cpm_word fcb_chmod(cpm_byte *fcb, cpm_byte *dma) -{ - char fname[CPM_MAXPATH]; - struct stat st; - int handle, wlen, omode; - long offs, newoffs; - cpm_byte zero[128]; - - /* 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); - - if (stat(fname, &st)) return redir_xlt_err(); - -#ifdef __MSDOS__ - omode = 0; - if (fcb[9] & 0x80) omode |= 1; - if (fcb[10] & 0x80) omode |= 4; - if (!(fcb[11] & 0x80)) omode |= 0x20; - - if (_chmod(fname, 1, omode) < 0) - { - if (redir_password_error()) - { - redir_password_append(fname, dma); - if (_chmod(fname, 1, omode) >= 0) return 0; - } - return redir_xlt_err(); - } -#elif defined (WIN32) - omode = 0; - - if (fcb[9] & 0x80) omode |= FILE_ATTRIBUTE_READONLY; - if (fcb[10] & 0x80) omode |= FILE_ATTRIBUTE_SYSTEM; - if (!(fcb[11] & 0x80)) omode |= FILE_ATTRIBUTE_ARCHIVE; - - if (!omode) omode = FILE_ATTRIBUTE_NORMAL; - - SetFileAttributes(fname, omode); -#else - omode = st.st_mode; - if (fcb[9] & 0x80) /* Read-only */ - { - st.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH); - } - else st.st_mode |= S_IWUSR; - - if (omode != st.st_mode) - { - if (chmod(fname, st.st_mode)) return redir_xlt_err(); - } - -#endif - - if (fcb[6] & 0x80) /* Set exact size */ - { - if (stat(fname, &st)) return redir_xlt_err(); - - 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)); - } - if (newoffs == st.st_size) - { - ; /* Nothing to do! */ - } - 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) - { - wlen = newoffs - st.st_size; - if (wlen > 0x80) wlen = 0x80; - memset(zero, 0x1A, sizeof(zero)); - if (write(handle, zero, wlen) < wlen) - { - close(handle); - return redir_xlt_err(); - } - st.st_size += wlen; - } - close(handle); - } - return 0; -} - - - - -cpm_word fcb_setpwd(cpm_byte *fcb, cpm_byte *dma) -{ -#ifdef __MSDOS__ - char fname[CPM_MAXPATH]; - cpm_word rv; - - /* 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); - - rv = redir_drdos_put_rights(fname, dma, redir_drdos_pwmode(fcb[0x0c])); - if (rv || !(fcb[0x0c] & 1)) return rv; - return redir_drdos_put_rights(fname, dma, redir_drdos_pwmode(fcb[0x0c]) | 0x8000); -#else - return 0xFF; /* Unix doesn't do this */ -#endif -} - - -cpm_word fcb_getlbl(cpm_byte drv) -{ - redir_Msg("fcb_getlbl()\r\n"); -#ifdef __MSDOS__ - if (redir_drdos) return 0xA1; /* Supports passwords & Update stamps */ - return 0x21; /* Update stamps only */ -#else - return 0x61; /* Update & Access stamps */ -#endif -} - -cpm_word fcb_setlbl(cpm_byte *fcb, cpm_byte *dma) -{ -/* I am not letting CP/M fiddle with the host's FS settings - even if they - * could be altered, which they mostly can't. */ - - return 0x03FF; -} - - - -cpm_word fcb_defpwd(cpm_byte *pwd) -{ -#ifdef __MSDOS__ - union REGS r; - struct SREGS s; - - if (pwd[0] == 0 || pwd[0] == ' ') - { - redir_passwd[0] = 0; - } - else memcpy(redir_passwd, pwd, 8); - if (redir_drdos) - { - dosmemput(pwd, 8, __tb); - r.w.ax = 0x4454; - r.w.dx = __tb & 0x0F; - s.ds = __tb >> 4; - intdosx(&r, &r, &s); - } - -#endif - return 0; -} - - diff --git a/Tools/unix/zx/cpmredir.h b/Tools/unix/zx/cpmredir.h deleted file mode 100644 index 2584e239..00000000 --- a/Tools/unix/zx/cpmredir.h +++ /dev/null @@ -1,151 +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 the public interface to CPMREDIR. -*/ - -#ifndef CPMREDIR_H_INCLUDED - -#define CPMREDIR_H_INCLUDED 16-11-1998 - -/* The "cpm_byte" must be exactly 8 bits. - The "cpm_word" must be exactly 16 bits. */ - -typedef unsigned char cpm_byte; -typedef unsigned short cpm_word; - -/* Maximum length of a directory path */ -#ifdef _POSIX_PATH_MAX - #define CPM_MAXPATH _POSIX_PATH_MAX -#else - #ifdef _MAX_PATH - #define CPM_MAXPATH _MAX_PATH - #else - #define CPM_MAXPATH 260 - #endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* Initialise this library. Call this function first. - * - * Returns 0 if failed to initialise. - */ -int fcb_init(void); - -/* Deinitialise the library. */ - -void fcb_deinit(void); - -/* 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); - -/* 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: - * Returns 1 if OK, 0 if requested drive not available. - * - * NB: It is important that the localname should have a trailing - * directory separator! - */ - -int xlt_map(int drive, char *localdir); - -/* - * This revokes a mapping. No check is made whether CP/M has files open - * on the drive or not. - */ - -int xlt_umap(int drive); - -/* Find out if a drive is mapped, and if so to what directory */ - -char *xlt_getcwd(int drive); - - -/* BDOS functions. Eventually this should handle all disc-related BDOS - * functions. - * - * I am assuming that your emulator has the CP/M RAM in its normal address - * space, accessible as a range 0-64k. If this is not the case - * (eg: you are emulating banked memory, or using a segmented architecture) - * you will have to use "copy in and copy out" techniques. The "fcb" area - * must be 36 bytes long; the "dma" area should be 128 * the value set - * in fcb_multirec() [default is 1, so 128 bytes]. - * - */ - -cpm_byte fcb_reset (void); /* 0x0D */ -cpm_word fcb_drive (cpm_byte drv); /* 0x0E */ -cpm_word fcb_open (cpm_byte *fcb, cpm_byte *dma); /* 0x0F */ -cpm_word fcb_close (cpm_byte *fcb); /* 0x10 */ -cpm_word fcb_find1 (cpm_byte *fcb, cpm_byte *dma); /* 0x11 */ -cpm_word fcb_find2 (cpm_byte *fcb, cpm_byte *dma); /* 0x12 */ -cpm_word fcb_unlink(cpm_byte *fcb, cpm_byte *dma); /* 0x13 */ -cpm_word fcb_read (cpm_byte *fcb, cpm_byte *dma); /* 0x14 */ -cpm_word fcb_write (cpm_byte *fcb, cpm_byte *dma); /* 0x15 */ -cpm_word fcb_creat (cpm_byte *fcb, cpm_byte *dma); /* 0x16 */ -cpm_word fcb_rename(cpm_byte *fcb, cpm_byte *dma); /* 0x17 */ -cpm_word fcb_logvec(void); /* 0x18 */ -cpm_byte fcb_getdrv(void); /* 0x19 */ -/* DMA is a parameter to routines, not a separate call */ -cpm_word fcb_getalv(cpm_byte *alv, cpm_word max); /* 0x1B */ -/* Get alloc vector: caller must provide space and say how big it is. */ -cpm_word fcb_rodisk(void); /* 0x1C */ -cpm_word fcb_rovec (void); /* 0x1D */ -cpm_word fcb_chmod (cpm_byte *fcb, cpm_byte *dma); /* 0x1E */ -cpm_word fcb_getdpb(cpm_byte *dpb); /* 0x1F */ -cpm_byte fcb_user (cpm_byte usr); /* 0x20 */ -cpm_word fcb_randrd(cpm_byte *fcb, cpm_byte *dma); /* 0x21 */ -cpm_word fcb_randwr(cpm_byte *fcb, cpm_byte *dma); /* 0x22 */ -cpm_word fcb_stat (cpm_byte *fcb); /* 0x23 */ -cpm_word fcb_tell (cpm_byte *fcb); /* 0x24 */ -cpm_word fcb_resro (cpm_word bitmap); /* 0x25 */ -/* Access Drives and Free Drives are not supported. */ -cpm_word fcb_randwz(cpm_byte *fcb, cpm_byte *dma); /* 0x28 */ -/* Record locking calls not supported (though they could be) */ -cpm_word fcb_multirec(cpm_byte rc); /* 0x2C */ -/* Set hardware error action must be done by caller */ -cpm_word fcb_dfree (cpm_byte drive, cpm_byte *dma);/* 0x2E */ -cpm_word fcb_sync (cpm_byte flag); /* 0x30 */ -cpm_word fcb_purge (void); /* 0x62 */ -cpm_word fcb_trunc (cpm_byte *fcb, cpm_byte *dma); /* 0x63 */ -cpm_word fcb_setlbl(cpm_byte *fcb, cpm_byte *dma); /* 0x64 */ -cpm_word fcb_getlbl(cpm_byte drive); /* 0x65 */ -cpm_word fcb_date (cpm_byte *fcb); /* 0x66 */ -cpm_word fcb_setpwd(cpm_byte *fcb, cpm_byte *dma); /* 0x67 */ -cpm_word fcb_defpwd(cpm_byte *pwd); /* 0x6A */ -cpm_word fcb_sdate (cpm_byte *fcb, cpm_byte *dma); /* 0x74 */ -cpm_word fcb_parse (char *txt, cpm_byte *fcb); /* 0x98 */ - -/* fcb_parse returns length of filename parsed, 0 if EOL, 0xFFFF if error */ -#ifdef __cplusplus -} -#endif - - -#endif /* def CPMREDIR_H_INCLUDED */ diff --git a/Tools/unix/zx/dirent.c b/Tools/unix/zx/dirent.c deleted file mode 100644 index 87cf85a9..00000000 --- a/Tools/unix/zx/dirent.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - - Implementation of POSIX directory browsing functions and types for Win32. - - Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) - History: Created March 1997. Updated June 2003 and July 2012. - Rights: See end of file. - -*/ - -#include "dirent.h" -#include -#include /* _findfirst and _findnext set errno iff they return -1 */ -#include -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - -//typedef ptrdiff_t handle_type; /* C99's intptr_t not sufficiently portable */ -typedef long handle_type; /* C99's intptr_t not sufficiently portable */ - -struct DIR -{ - handle_type handle; /* -1 for failed rewind */ - struct _finddata_t info; - struct dirent result; /* d_name null iff first time */ - char *name; /* null-terminated char string */ -}; - -DIR *opendir(const char *name) -{ - DIR *dir = 0; - - if(name && name[0]) - { - size_t base_length = strlen(name); - const char *all = /* search pattern must end with suitable wildcard */ - strchr("/\\", name[base_length - 1]) ? "*" : "/*"; - - if((dir = (DIR *) malloc(sizeof *dir)) != 0 && - (dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0) - { - strcat(strcpy(dir->name, name), all); - - if((dir->handle = - (handle_type) _findfirst(dir->name, &dir->info)) != -1) - { - dir->result.d_name = 0; - } - else /* rollback */ - { - free(dir->name); - free(dir); - dir = 0; - } - } - else /* rollback */ - { - free(dir); - dir = 0; - errno = ENOMEM; - } - } - else - { - errno = EINVAL; - } - - return dir; -} - -int closedir(DIR *dir) -{ - int result = -1; - - if(dir) - { - if(dir->handle != -1) - { - result = _findclose(dir->handle); - } - - free(dir->name); - free(dir); - } - - if(result == -1) /* map all errors to EBADF */ - { - errno = EBADF; - } - - return result; -} - -struct dirent *readdir(DIR *dir) -{ - struct dirent *result = 0; - - if(dir && dir->handle != -1) - { - if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) - { - result = &dir->result; - result->d_name = dir->info.name; - } - } - else - { - errno = EBADF; - } - - return result; -} - -void rewinddir(DIR *dir) -{ - if(dir && dir->handle != -1) - { - _findclose(dir->handle); - dir->handle = (handle_type) _findfirst(dir->name, &dir->info); - dir->result.d_name = 0; - } - else - { - errno = EBADF; - } -} - -#ifdef __cplusplus -} -#endif - -/* - - Copyright Kevlin Henney, 1997, 2003, 2012. All rights reserved. - - Permission to use, copy, modify, and distribute this software and its - documentation for any purpose is hereby granted without fee, provided - that this copyright and permissions notice appear in all copies and - derivatives. - - This software is supplied "as is" without express or implied warranty. - - But that said, if there are any problems please get in touch. - -*/ diff --git a/Tools/unix/zx/dirent.h b/Tools/unix/zx/dirent.h deleted file mode 100644 index bbbfce52..00000000 --- a/Tools/unix/zx/dirent.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef DIRENT_INCLUDED -#define DIRENT_INCLUDED - -/* - - Declaration of POSIX directory browsing functions and types for Win32. - - Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) - History: Created March 1997. Updated June 2003. - Rights: See end of file. - -*/ - -#ifdef __cplusplus -extern "C" -{ -#endif - -typedef struct DIR DIR; - -struct dirent -{ - char *d_name; -}; - -DIR *opendir(const char *); -int closedir(DIR *); -struct dirent *readdir(DIR *); -void rewinddir(DIR *); - -/* - - Copyright Kevlin Henney, 1997, 2003. All rights reserved. - - Permission to use, copy, modify, and distribute this software and its - documentation for any purpose is hereby granted without fee, provided - that this copyright and permissions notice appear in all copies and - derivatives. - - This software is supplied "as is" without express or implied warranty. - - But that said, if there are any problems please get in touch. - -*/ - -#ifdef __cplusplus -} -#endif - -#endif 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/util.c b/Tools/unix/zx/util.c deleted file mode 100644 index cb22e18b..00000000 --- a/Tools/unix/zx/util.c +++ /dev/null @@ -1,377 +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 miscellaneous utility functions. -*/ - -#include "cpmint.h" - -/* In debug mode, lseek()s can be traced. */ - -#ifdef DEBUG - -long zxlseek(int fd, long offset, int wh) -{ -#ifdef WIN32 - long v; - redir_Msg(">SetFilePointer() Handle=%lu, Offset=%lu, Method=%lu\n", fd, offset, wh); - v = SetFilePointer((HANDLE)fd, offset, NULL, wh); - redir_Msg("= 0) return v; - - redir_Msg("lseek fails with errno = %d\n", errno); - if (errno == EBADF) redir_Msg(" (bad file descriptor %d)\n", fd); - if (errno == ESPIPE) redir_Msg(" (file %d is a pipe)\n", fd); - if (errno == EINVAL) redir_Msg(" (bad parameter %d)\n", wh); - - return -1; -#endif -} - -void redir_showfcb(cpm_byte *fd) -{ - int n; - - for (n = 0; n < 32; n++) - { - if (!n || n>= 12) printf("%02x ", fd[n]); - else printf("%c", fd[n] & 0x7F); - } - 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 */ - -long redir_get_fcb_pos(cpm_byte *fcb) -{ - long npos; - - npos = 524288L * fcb[0x0E]; /* S2 */ - npos += 16384L * fcb[0x0C]; /* Extent */ - npos += 128L * fcb[0x20]; /* Record */ - - return npos; -} - -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; -} - - -/* - * find a filename that works. - * note that this is where we handle the case sensitivity/non-case sensitivity - * horror. - * the name that is passed in should be in lower case. - * we'll modify it to the first one that matches - */ -void -swizzle(char *fullpath) -{ - struct stat ss; - char *slash; - DIR *dirp; - struct dirent *dentry; - - /* short circuit if ok */ - if (stat(fullpath, &ss) == 0) { - return; - } - - slash = strrchr(fullpath, '/'); - if (!slash) { - return; - } - *slash = '\0'; - dirp = opendir(fullpath); - *slash = '/'; - while ((dentry = readdir(dirp)) != NULL) { - if (strcasecmp(dentry->d_name, slash + 1) == 0) { - strcpy(slash + 1, dentry->d_name); - break; - } - } - closedir(dirp); -} - -/* - * 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) -{ - int n, q, drv, ddrv; - char s[2]; - - s[1] = 0; - q = 0; - drv = fcb[0] & 0x7F; - if (drv == '?') drv = 0; - - ddrv = fcb[0] & 0x7F; - if (ddrv < 0x1F) ddrv += '@'; - - redir_Msg("%c:%-8.8s.%-3.3s\n", - ddrv, - fcb + 1, - fcb + 9); - - if (!drv) strcpy(fname, redir_drive_prefix[redir_cpmdrive]); - else strcpy(fname, redir_drive_prefix[drv - 1]); - - for (n = 1; n < 12; n++) - { - s[0] = (fcb[n] & 0x7F); - if (s[0] == '?') q = 1; - if (isupper(s[0])) s[0] = tolower(s[0]); - if (s[0] != ' ') - { - if (n == 9) strcat(fname, "."); - strcat(fname, s); - } - } - return q; -} - -#ifndef EROFS /* Open fails because of read-only FS */ -#define EROFS EACCES -#endif - -int redir_ofile(cpm_byte *fcb, char *s) -{ - int h, rv; - - /* Software write-protection */ -#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; - } - redir_Msg("**2**"); - h = open(s, O_RDONLY | O_BINARY); - if (h < 0) return -1; - fcb[9] |= 0x80; - #endif -#endif - - return h; -} - - -/* Extract a file handle from where it was stored in an FCB by fcb_open() - or fcb_creat(). Aborts if the FCB has been tampered with. - - Note: Some programs (like GENCOM) close FCBs they never opened. This causes - the Corrupt FCB message, but no harm seems to ensue. */ - -int redir_verify_fcb(cpm_byte *fcb) -{ - if (fcb[16] != 0xFD || fcb[17] != 0x00) - { - fprintf(stderr,"cpmredir: Corrupt FCB\n"); - return -1; - } - return (int)(redir_rd32(fcb + 18)); - -} - -/* Print a trace message */ - -#ifdef DEBUG - -void redir_Msg(char *s, ...) -{ - va_list ap; - - va_start(ap, s); - printf("cpmredir trace: "); - vprintf(s, ap); - va_end(ap); - fflush(stdout); -} - -#endif - -#define BCD(x) (((x % 10)+16*(x/10)) & 0xFF) - -/* 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 */ - - return (d | (BCD(h) << 16) | (BCD(m) << 24)); -} - -#undef BCD - -#define UNBCD(x) (((x % 16) + 10 * (x / 16)) & 0xFF) - -time_t redir_unixtime(cpm_byte *c) -{ - time_t t; - cpm_word days; - - days = (c[0] + 256 * c[1]) + 2921; - - t = 60L * UNBCD(c[3]); - t += 3600L * UNBCD(c[2]); - t += 86400L * days; - - return t; -} - -#undef UNBCD - - -/* Functions to access 24-bit & 32-bit words in memory. These are always - little-endian. */ - -void redir_wr24(cpm_byte *addr, dword v) -{ - addr[0] = v & 0xFF; - addr[1] = (v >> 8) & 0xFF; - addr[2] = (v >> 16) & 0xFF; -} - -void redir_wr32(cpm_byte *addr, dword v) -{ - addr[0] = v & 0xFF; - addr[1] = (v >> 8) & 0xFF; - addr[2] = (v >> 16) & 0xFF; - addr[3] = (v >> 24) & 0xFF; -} - -dword redir_rd24(cpm_byte *addr) -{ - register dword rv = addr[2]; - - rv = (rv << 8) | addr[1]; - rv = (rv << 8) | addr[0]; - return rv; -} - - -dword redir_rd32(cpm_byte *addr) -{ - register dword rv = addr[3]; - - rv = (rv << 8) | addr[2]; - rv = (rv << 8) | addr[1]; - rv = (rv << 8) | addr[0]; - return rv; -} - - -void redir_log_drv(cpm_byte drv) -{ - if (!drv) redir_l_drives |= 1; - else redir_l_drives |= (1L << drv); -} - -void redir_log_fcb(cpm_byte *fcb) -{ - int drv = fcb[0] & 0x7F; - - if (drv && drv != '?') redir_log_drv(drv - 1); - else redir_log_drv(redir_cpmdrive); -} - - -int redir_ro_drv(cpm_byte drv) -{ - if (!drv) return redir_ro_drives & 1; - else return redir_ro_drives & (1L << drv); -} - -int redir_ro_fcb(cpm_byte *fcb) -{ - int drv = fcb[0] & 0x7F; - - if (drv && drv != '?') return redir_ro_drv(drv - 1); - else return redir_ro_drv(redir_cpmdrive); -} - - - -cpm_word redir_xlt_err(void) -{ - if (redir_password_error()) return 0x7FF; /* DRDOS pwd error */ - switch(errno) - { - case EISDIR: - case EBADF: return 9; /* Bad FCB */ - case EINVAL: return 0x03FF; /* Readonly file */ - case EPIPE: return 0x01FF; /* Broken pipe */ - case ENOSPC: return 1; /* No space */ - default: return 0xFF; /* Software error */ - } -} - 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.c b/Tools/unix/zx/zx.c deleted file mode 100644 index 88b20cb3..00000000 --- a/Tools/unix/zx/zx.c +++ /dev/null @@ -1,441 +0,0 @@ -#include "zx.h" - -#ifdef WIN32 -#include "windows.h" -#endif - -/* Global variables */ - -char *progname; -char **argv; -int argc; - -byte cpm_drive; -char *mypath; - -byte cpm_user; -extern byte cpm_error; - -byte RAM[65536]; /* The Z80's address space */ - -void load_comfile(void); /* Forward declaration */ - -static int deinit_term, deinit_gsx; - -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) -{ - fprintf(fp, "\tAF=%02x%02x BC=%02x%02x DE=%02x%02x HL=%02x%02x\n" - "\tIX=%04x IY=%04x PC=%04x\n", - a,f,b,c,d,e,h,l,pc,ix,iy); -} - - - -char *parse_to_fcb(char *s, int afcb) -{ - byte *fcb = &RAM[afcb+1]; - - RAM[afcb] = 0; - memset(fcb, ' ', 11); - - while (*s == ' ') ++s; - - while (1) - { - if (s[0] == 0) break; - if (s[0] == ' ') break; - if (s[1] == ':') - { - RAM[afcb] = s[0] - '@'; - if (RAM[afcb] > 16) RAM[afcb] -= 0x20; - s+=2; - continue; - } - if (s[0] == '.') - { - ++s; - fcb = &RAM[afcb+9]; - continue; - } - *fcb = *s; if (islower(*fcb)) *fcb = toupper(*fcb); - ++s; - ++fcb; - if (fcb >= &RAM[afcb+12]) break; - } - return s; -} - - -void Msg(char *s, ...) -{ -#ifdef DEBUG - va_list ap; - - va_start(ap, s); - printf("%s trace: ", progname); - vprintf(s, ap); - fflush(stdout); - if (s[strlen(s) - 1] == '\n') putchar('\r'); - va_end(ap); -#endif -} - - -void ed_fe(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f, - byte *h, byte *l, word *pc, word *ix, word *iy) -{ - switch(*a) - { - case 0xC0: - cpmbdos(a,b,c,d,e,f,h,l,pc,ix,iy); - break; - - case 0xC1: - load_comfile(); - break; - - case 0xC2: - fprintf(stderr,"%s: Incompatible BIOS.BIN\n", progname); - zx_term(); - zx_exit(1); - - case 0xC3: - cpmbios(a,b,c,d,e,f,h,l,pc,ix,iy); - break; - - 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); - - } -} - - -/* - * load_bios() loads the minimal CP/M BIOS and BDOS. - * - */ - -void load_bios(void) -{ - int bios_len; - - FILE * fp = NULL; - char biospath[CPM_MAXPATH + 1] = ""; - -#ifdef WIN32 - if (!fp) - { - GetModuleFileName(NULL, biospath, sizeof(biospath)); - strcpy(strrchr(biospath, '\\'), "\\bios.bin"); - fp = fopen(biospath, "rb"); - } -#else - if (!fp) { - strcpy(biospath, mypath); - strcpy(strrchr(biospath, '/'), "/bios.bin"); - fp = fopen(biospath, "rb"); - } -#endif - - if (!fp && BINDIR80) - { - strcpy(biospath, BINDIR80); - strcat(biospath, "bios.bin"); - fp = fopen(biospath, "rb"); - } - - if (!fp) fp = fopen("bios.bin", "rb"); - - if (!fp) - { - fprintf(stderr,"%s: Cannot locate bios.bin\n", progname); - zx_term(); - zx_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); - } - 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 - * - */ - -FILE *try_com(char *s) -{ - char fname[CPM_MAXPATH + 1]; - FILE *fp; - - strcpy(fname, s); - fp = fopen(s, "rb"); if (fp) return fp; - sprintf(s,"%s.com", fname); fp = fopen(s, "rb"); if (fp) return fp; - sprintf(s,"%s.COM", fname); fp = fopen(s, "rb"); if (fp) return fp; - sprintf(s,"%s.cpm", fname); fp = fopen(s, "rb"); if (fp) return fp; - sprintf(s,"%s.CPM", fname); fp = fopen(s, "rb"); if (fp) return fp; - - strcpy(s, fname); - return NULL; -} - -/* - * load_comfile() loads the COM file whose name was passed as a parameter. - * - */ - - -void load_comfile(void) -{ - int com_len; - char fname[CPM_MAXPATH + 1] = ""; - FILE *fp; - - if (BINDIR80) strcpy(fname, BINDIR80); - strcat(fname, argv[1]); - fp = try_com(fname); - if (!fp) - { - strcpy(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); - } - 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); - } - fclose(fp); - - memset(RAM + 0x0100 + com_len, 0, 0xFD00 - com_len); - - Msg("Loaded %d bytes from %s\n", com_len, fname); -} - -unsigned int in() { return 0; } -unsigned int out() { return 0; } - - - -/* - * xltname: Convert a unix filepath into a CP/M compatible drive:name form. - * The unix filename must be 8.3 or the CP/M code will reject it. - * - * This uses the library xlt_name to do the work, and then just strcat()s - * the result to the command line. - */ - -void zx_xltname(char *name, char *pcmd) -{ - char nbuf[CPM_MAXPATH + 1]; - - xlt_name(pcmd, nbuf); - - strcat(name, nbuf); -} - -/* main() parses the arguments to CP/M form. argv[1] is the name of the CP/M - program to load; the remaining arguments are arguments for the CP/M program. - - main() also loads the vestigial CP/M BIOS and does some sanity checks - on the endianness of the host CPU and the sizes of data types. - */ - -int main(int ac, char **av) -{ - int n; - char *pCmd, *str; - - argc = ac; - argv = av; -#ifdef __PACIFIC__ /* Pacific C doesn't support argv[0] */ - progname="ZX"; -#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; - - if (_isatty(_fileno(stdin))) - Msg("Using interactive console mode\n"); - else - Msg("Using standard input/ouput mode\n"); - - if (sizeof(int) > 8 || sizeof(byte) != 1 || sizeof(word) != 2) - { - fprintf(stderr,"%s: type lengths incorrect; edit typedefs " - "and recompile.\n", progname); - zx_exit(1); - } - - if (argc < 2) - { - fprintf(stderr,"%s: No CP/M program name provided.\n",progname); - zx_exit(1); - } - - - setmode(_fileno(stdin), O_BINARY ); - setmode(_fileno(stdout), O_BINARY ); - - /* Parse arguments. An argument can be either: - - * preceded by a '-', in which case it is copied in as-is, less the - dash; - * preceded by a '+', in which case it is parsed as a filename and - then concatenated to the previous argument; - * preceded by a '+-', in which case it is concatenated without - parsing; - * not preceded by either, in which case it is parsed as a filename. - - So, the argument string "--a -b c +-=q --x +/dev/null" would be rendered - into CP/M form as "-a b p:c=q -xd:null" */ - - if (!fcb_init()) - { - fprintf(stderr, "Could not initialise CPMREDIR library\n"); - zx_exit(1); - } - - 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++) - { - if (argv[n][0] == '+' && argv[n][1] == '-') - { - /* Append, no parsing */ - strcat(pCmd, argv[n] + 2); - } - else if (!argv[n][0] || argv[n][0] == '-') - { - /* Append with space; no parsing. */ - strcat(pCmd, " "); - strcat(pCmd, argv[n] + 1); - } - else if (argv[n][0] == '+') - { - zx_xltname(pCmd, argv[n]+1); - } - else /* Translate a filename */ - { - strcat(pCmd, " "); - zx_xltname(pCmd, argv[n]); - } - - } - pCmd[0x7F] = 0; /* Truncate to fit the buffer */ - RAM[0x80] = strlen(pCmd); - - str = parse_to_fcb(pCmd, 0x5C); - parse_to_fcb(str, 0x6C); - - // This statement is very useful when creating a client like zxc or zxas - Msg("Command tail is \"%s\"\n", pCmd); - - load_bios(); - - memset(RAM + 0xFE9C, 0, 0x64); /* Zap the SCB */ - RAM[0xFE98] = 0x06; - RAM[0xFE99] = 0xFE; /* FE06, BDOS entry */ - RAM[0xFEA1] = 0x31; /* BDOS 3.1 */ - RAM[0xFEA8] = 0x01; /* UK date format */ - RAM[0xFEAF] = 0x0F; /* CCP drive */ - -#ifdef USE_CPMIO - RAM[0xFEB6] = cpm_term_direct(CPM_TERM_WIDTH, -1); - RAM[0xFEB8] = cpm_term_direct(CPM_TERM_HEIGHT, -1); -#else - RAM[0xFEB6] = 79; - RAM[0xFEB8] = 23; -#endif - RAM[0xFED1] = 0x80; /* Buffer area */ - RAM[0xFED2] = 0xFF; - RAM[0xFED3] = '$'; - RAM[0xFED6] = 0x9C; - RAM[0xFED7] = 0xFE; /* SCB address */ - RAM[0xFED8] = 0x80; /* DMA address */ - RAM[0xFED9] = 0x00; - RAM[0xFEDA] = 0x0F; /* P: */ - RAM[0xFEE6] = 0x01; /* Multi sector count */ - RAM[0xFEFE] = 0x06; - RAM[0xFEFF] = 0xFE; /* BDOS */ - - cpm_drive = 0x0F; /* Start logged into P: */ - cpm_user = 0; /* and user 0 */ - -#ifdef USE_CPMIO - cpm_scr_init(); deinit_term = 1; -#endif -#ifdef USE_CPMGSX - gsx_init(); deinit_gsx = 1; -#endif - - /* Start the Z80 at 0xFF00, with stack at 0xFE00 */ - mainloop(0xFF00, 0xFE00); - - return zx_term(); -} - -void zx_exit(int code) -{ -#ifdef USE_CPMIO - if (deinit_term) cpm_scr_unit(); -#endif -#ifdef USE_CPMGSX - if (deinit_gsx) gsx_deinit(); -#endif - exit(code); -} - -int zx_term(void) -{ - word n; - - - //n = RAM[0x81]; /* Get the return code. This is Hi-Tech C */ - //n = (n << 8) | RAM[0x80]; /* specific and fails with other COM files */ - n = 0; - - putchar('\n'); - - if (cpm_error != 0) /* The CP/M "set return code" call was used */ - { /* (my modified Hi-Tech C library uses this */ - n = cpm_error; /* call) */ - } - if (n < 256 || n == 0xFFFF) - { - Msg("Return code %d\n", n); - return n; - } - else return 0; -} - - diff --git a/Tools/unix/zx/zx.h b/Tools/unix/zx/zx.h deleted file mode 100644 index dac69ce0..00000000 --- a/Tools/unix/zx/zx.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Change the directories in these #defines if necessary. Note trailing slash. - */ - -#include "config.h" - -#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/" -*/ -#endif - -#define SERIAL "ZXCC05" - -/* System include files */ - -#include -#include -#include -#include -#include -#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 -#endif -#ifdef WIN32 -#include -#endif -#include -#include -#ifdef __MSDOS -#include -#endif - -/* Library includes */ - -#ifdef USE_CPMIO -#include "cpmio.h" -#endif - -#ifdef USE_CPMGSX -#include "cpmgsx.h" -#endif - -#include "cpmredir.h" /* BDOS disc simulation */ - -typedef unsigned char byte; /* Must be exactly 8 bits */ -typedef unsigned short word; /* Must be exactly 16 bits */ - -/* Prototypes */ - -void ed_fe (byte *a, byte *b, byte *c, byte *d, byte *e, byte *f, - byte *h, byte *l, word *pc, word *ix, word *iy); -void cpmbdos(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f, - byte *h, byte *l, word *pc, word *ix, word *iy); -void cpmbios(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f, - byte *h, byte *l, word *pc, word *ix, word *iy); -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); - -byte cin(void); -void cout(byte); -int cstat(void); - -/* Global variables */ - -extern char *progname; -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/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/zx/zxbdos.c b/Tools/unix/zx/zxbdos.c deleted file mode 100644 index 3c4dd931..00000000 --- a/Tools/unix/zx/zxbdos.c +++ /dev/null @@ -1,561 +0,0 @@ -#include "zx.h" - -#define BDOS_DEF -#include "zxbdos.h" -#include "zxcbdos.h" -#include "zxdbdos.h" - -#ifdef __MSDOS__ -#include -#endif - -#define BCD(x) (((x % 10)+16*(x/10)) & 0xFF) - -/* Convert time_t to CP/M day count/hours/minutes */ -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 */ - - return (d | (BCD(h) << 16) | (BCD(m) << 24)); -} - - -byte get_time(cpm_word b) -{ - time_t t; - - time(&t); - wr32(b, cpmtime(t)); - - return (BCD(t % 60)); -} - - -/* Functions to access 24-bit & 32-bit words in memory. These are always - little-endian. */ - -void wr24(word addr, dword v) -{ - RAM[addr ] = v & 0xFF; - RAM[addr + 1] = (v >> 8) & 0xFF; - RAM[addr + 2] = (v >> 16) & 0xFF; -} - -void wr32(word addr, dword v) -{ - RAM[addr ] = v & 0xFF; - RAM[addr + 1] = (v >> 8) & 0xFF; - RAM[addr + 2] = (v >> 16) & 0xFF; - RAM[addr + 3] = (v >> 24) & 0xFF; -} - -dword rd24(word addr) -{ - register dword rv = RAM[addr + 2]; - - rv = (rv << 8) | RAM[addr + 1]; - rv = (rv << 8) | RAM[addr]; - return rv; -} - - -dword rd32(word addr) -{ - register dword rv = RAM[addr + 3]; - - rv = (rv << 8) | RAM[addr + 2]; - rv = (rv << 8) | RAM[addr + 1]; - rv = (rv << 8) | RAM[addr]; - return rv; -} - -#define peekw(addr) ( (((word)(RAM[addr + 1])) << 8) | RAM[addr]) - - -/* Get / set the program return code. We store this in 'C' form: 0 for - success, 1-255 for failure. Translate to/from the CP/M form of: - - 0x0000-0xFEFF for success - 0xFF00-0xFFFE for failure - - We also store the actual value so it can be returned - - */ - -word cpm_errcde(word DE) -{ - static word real_err = 0; - - if (DE == 0xFFFF) return real_err; - real_err = DE; - - if (DE == 0xFF00) cpm_error = 1; - else if (DE > 0xFF00) cpm_error = (DE & 0xFF); - else cpm_error = 0; - return 0; -} - - -#ifdef USE_CPMGSX -gsx_byte gsxrd(gsx_word addr) -{ - return RdZ80(addr); -} - -void gsxwr(gsx_word addr, gsx_byte value) -{ - WrZ80(addr, value); -} - -#endif - -#undef bc -#undef de -#undef hl - -void setw(byte *l, byte *h, word w) -{ - *l = (w & 0xFF); - *h = (w >> 8) & 0xFF; -} - -void cpmbdos(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f, - byte *h, byte *l, word *pc, word *ix, word *iy) -{ - word de = ((*d) << 8) | *e; - word hl = ((*h) << 8) | *l; - byte *pde = &RAM[de]; - byte *pdma = &RAM[cpm_dma]; - word temp; - int retv; - - Msg("BDOS service invoked: C=%02x DE=%04x\n", *c, de); - - switch(*c) - { - case 0: - *pc = 0; - break; - - case 1: /* Get a character */ -#ifdef USE_CPMIO - retv = cpm_bdos_1(); -#else - retv = cin(); -#endif - if (retv < 0) *pc = 0; - setw(l, h, retv); - break; - - case 2: /* Print a character */ -#ifdef USE_CPMIO - if (cpm_bdos_2(*e)) *pc = 0; -#else - cout(*e); -#endif - break; - - case 3: /* No auxin */ - setw(l, h, 0x1A); - break; - - case 4: /* No auxout */ - break; - - case 5: /* No printer */ - break; - - case 6: /* Direct console I/O */ - retv = cpm_bdos_6(*e); - if (retv < 0) *pc = 0; - setw(l, h, retv); - break; - - case 7: /* No auxist */ - case 8: /* No auxost */ - break; - - case 9: /* Print a $-terminated string */ -#ifdef USE_CPMIO - if (cpm_bdos_9((char *)pde)) *pc = 0; -# else - for (temp = 0; RAM[de + temp] != '$'; ++temp) - { - cout(RAM[de + temp]); - } -#endif - break; - - case 0x0A: - bdos_rdline(de, &(*pc)); - break; - - case 0x0B: /* Console status */ - //*l = *h = 0; /* No keys pressed */ - *l = cstat(); - *h = 0; - break; - - case 0x0C: /* Get CP/M version */ - -/* For GENCOM's benefit, claim to be v3.1 */ - - *l = 0x31; /* v3.1 */ - //*l = 0x22; /* v2.2 */ - *h = 0; /* CP/M, no network */ - break; - - case 0x0D: /* Re-log discs */ - fcb_reset(); - break; - - case 0x0E: /* Set default drive */ - setw(l, h, fcb_drive(*e)); - break; - - case 0x0F: /* Open using FCB */ - setw(l, h, x_fcb_open(pde, pdma)); - break; - - case 0x10: /* Close using FCB */ - setw(l, h, fcb_close(pde)); - break; - - case 0x11: /* Find first */ - setw(l, h, fcb_find1(pde, pdma)); - break; - - case 0x12: - setw(l, h, fcb_find2(pde, pdma)); - break; - - case 0x13: /* Delete using FCB */ - setw(l, h, fcb_unlink(pde, pdma)); - break; - - 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 */ - setw(l, h, fcb_write(pde, pdma)); - break; - - case 0x16: /* Create using FCB */ - setw(l, h, fcb_creat(pde, pdma)); - break; - - case 0x17: /* Rename using FCB */ - setw(l, h, fcb_rename(pde, pdma)); - break; - - case 0x18: /* Get login vector */ - setw(l, h, fcb_logvec()); - break; - - case 0x19: /* Get default drive */ - setw(l, h, cpm_drive); - break; - - case 0x1A: /* Set DMA */ - Msg("Set DMA to %04x\n", de); - cpm_dma = de; - break; - - case 0x1B: /* Get alloc vector */ - fcb_getalv(RAM + 0xFF80, 0x40); - setw(l, h, 0xFF80); - break; - - case 0x1C: /* Make disc R/O */ - setw(l, h, fcb_rodisk()); - break; - - case 0x1D: /* Get R/O vector */ - setw(l, h, fcb_rovec()); - break; - - case 0x1E: /* Set attributes */ - setw(l, h, fcb_chmod(pde, pdma)); - break; - - case 0x1F: /* Get DPB */ - fcb_getdpb(RAM + 0xFFC0); - setw(l, h, 0xFFC0); - break; /* Whoops. Missed that 'break'. */ - - case 0x20: /* Get/set uid */ - setw(l, h, fcb_user(*e)); - break; - - case 0x21: /* Read a record */ - setw(l, h, fcb_randrd(pde, pdma)); - break; - - case 0x22: /* Write a record */ - setw(l, h, fcb_randwr(pde, pdma)); - break; - - case 0x23: /* Get file size */ - setw(l, h, x_fcb_stat(pde)); - break; - - case 0x24: /* Get file pointer */ - setw(l, h, fcb_tell(pde)); - break; - - case 0x25: - setw(l, h, fcb_resro(de)); - break; - - /* MP/M drive access functions, not implemented */ - - case 0x28: /* Write with 0 fill */ - setw(l, h, fcb_randwz(pde, pdma)); - break; - - /* MP/M record locking functions, not implemented */ - - case 0x2C: /* Set no. of records to read/write */ - setw(l, h, fcb_multirec(*e)); - break; - - case 0x2D: /* Set error mode */ - err_mode = *e; - break; - - case 0x2E: - setw(l, h, fcb_dfree(*e, pdma)); - break; /* Whoops. Missed that 'break'. */ - - /* 0x2F: Chain */ - - case 0x30: - setw(l, h, fcb_sync(*e)); - break; - - case 0x31: - if (pde[1] == 0xFE) - { - RAM[0xFE9C + *pde] = pde[2]; - RAM[0xFE9D + *pde] = pde[3]; - } - else if (RAM[hl + 1] == 0xFF) - { - RAM[0xFE9C + *pde] = pde[2]; - } - else - { - *l = RAM[0xFE9C + *pde]; - *h = RAM[0xFE9D + *pde]; - } - break; - - case 0x32: - temp = *ix; - *ix = 3 * (pde[0] + 1); - *a = pde[1]; - *c = pde[2]; - *b = pde[3]; - *e = pde[4]; - *d = pde[5]; - *l = pde[6]; - *h = pde[7]; - cpmbios(a,b,c,d,e,f,h,l,pc,ix,iy); - *ix = temp; - break; - - case 0x3C: /* Communicate with RSX */ - *h = 0; *l = 0xFF; /* return error */ - break; - - case 0x62: /* Purge */ - setw(l, h, fcb_purge()); - break; - - case 0x63: /* Truncate file */ - setw(l, h, fcb_trunc(pde, pdma)); - break; - - case 0x64: /* Set label */ - setw(l, h, fcb_setlbl(pde, pdma)); - break; - - case 0x65: /* Get label byte */ - setw(l, h, fcb_getlbl(*e)); - break; - - case 0x66: /* Get file date */ - setw(l, h, fcb_date(pde)); - break; - - case 0x67: /* Set password */ - setw(l, h, fcb_setpwd(pde, pdma)); - break; - - case 0x68: /* Set time of day */ - /* Not advisable to let an emulator play with the clock */ - break; - - case 0x69: /* Get time of day */ - setw(l, h, get_time(de)); - break; - - case 0x6A: /* Set default password */ - setw(l, h, fcb_defpwd(pde)); - break; - - case 0x6B: /* Get serial number */ - memcpy(pde, SERIAL, 6); - break; - - case 0x6C: /* 0.03 set error code */ - setw(l, h, cpm_errcde(de)); - break; - -#ifdef USE_CPMIO - case 0x6D: /* Set/get console mode */ - setw(l, h, cpm_bdos_109(de)); - break; - - case 0x6E: /* Set/get string delimiter */ - setw(l, h, cpm_bdos_110(*e)); - break; - - case 0x6F: /* Send fixed length string to screen */ - if (cpm_bdos_111((char *)RAM + peekw(de), - peekw(de + 2))) - *pc = 0; - break; - - case 0x70: /* Send fixed length string to printer */ - break; - - /* 0x71: Strange PCP/M function */ -#else - case 0x6D: /* Set/get console mode */ - setw(l, h, 0); - break; - -#endif - -#ifdef USE_CPMGSX - case 0x73: /* GSX */ - setw(l, h, gsx80(gsxrd, gsxwr, de)); - break; -#endif - - case 0x74: /* Set date stamp */ - setw(l, h, fcb_sdate(pde, pdma)); - break; - - case 0x98: /* Parse filename */ - setw(l, h, fcb_parse((char *)RAM + peekw(de), - (byte *)RAM + peekw(de + 2))); - break; - - default: -#ifdef USE_CPMIO - cpm_scr_unit(); -#endif -#ifdef USE_CPMGSX - gsx_deinit(); -#endif - - 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); - break; - } - - *a = *l; - *b = *h; - - Msg("BDOS service completion.\n"); -} - - - -void cpmbios(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f, - byte *h, byte *l, word *pc, word *ix, word *iy) -{ - int func = (((*ix) & 0xFF) / 3) - 1; - - Msg("BIOS service invoked: func=%02x\n", func); - - switch(func) /* BIOS function */ - { - case 1: - zx_exit(zx_term()); /* Program termination */ - break; - - case 2: /* CONST */ -#ifdef USE_CPMIO - *a = cpm_const(); -#else - *a = cpm_bdos_6(0xFE); -#endif - break; - - case 3: /* CONIN */ -#ifdef USE_CPMIO - *a = cpm_conin(); -#else - *a = cpm_bdos_6(0xFD); -#endif - break; - - case 4: /* CONOUT */ -#ifdef USE_CPMIO - cpm_conout(*c); -#else - cpm_bdos_6(*c); -#endif - break; - - case 20: /* DEVTBL */ - setw(l, h, 0xFFFF); - break; - - case 22: /* DRVTBL */ - setw(l, h, 0xFFFF); - break; - - case 26: /* TIME */ - RAM[0xFEF8] = get_time(0xFEF4); - break; - - case 30: /* USERF!!! */ -#ifdef USE_CPMIO - cpm_bdos_110('$'); - cpm_bdos_9("This program has attempted to call USERF, " - "which is not implemented\r\n$"); -#else - printf("This program has attempted to call USERF, which " - "is not implemented.\n"); -#endif - zx_term(); - zx_exit(1); - break; - - default: -#ifdef USE_CPMIO - cpm_scr_unit(); -#endif -#ifdef USE_CPMGSX - gsx_deinit(); -#endif - - 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); - } - - Msg("BIOS service completion.\n"); -} diff --git a/Tools/unix/zx/zxcbdos.h b/Tools/unix/zx/zxcbdos.h deleted file mode 100644 index 7f724441..00000000 --- a/Tools/unix/zx/zxcbdos.h +++ /dev/null @@ -1,4 +0,0 @@ -void bdos_rdline(word line, word *PC); -int cpm_bdos_6(byte e); - - diff --git a/Tools/unix/zx/zxdbdos.c b/Tools/unix/zx/zxdbdos.c deleted file mode 100644 index f5f21f3b..00000000 --- a/Tools/unix/zx/zxdbdos.c +++ /dev/null @@ -1,88 +0,0 @@ -#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; -} - - - diff --git a/Tools/unix/zx/zxdbdos.h b/Tools/unix/zx/zxdbdos.h deleted file mode 100644 index 7a47b801..00000000 --- a/Tools/unix/zx/zxdbdos.h +++ /dev/null @@ -1,8 +0,0 @@ - - - -int fcbforce(byte *fcb, byte *odrv); - -word x_fcb_open(byte *fcb, byte *dma); -word x_fcb_stat(byte *fcb); - diff --git a/Tools/zx/COPYING b/Tools/unix/zxcc/COPYING similarity index 98% rename from Tools/zx/COPYING rename to Tools/unix/zxcc/COPYING index a43ea212..92851102 100644 --- a/Tools/zx/COPYING +++ b/Tools/unix/zxcc/COPYING @@ -1,339 +1,339 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - Appendix: How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) 19yy - - 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. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) 19yy name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. 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/zxcc/ReadMe.txt b/Tools/unix/zxcc/ReadMe.txt new file mode 100644 index 00000000..a0b0a63e --- /dev/null +++ b/Tools/unix/zxcc/ReadMe.txt @@ -0,0 +1,93 @@ +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 + +- Added a call to trackFile in fcb_close. I think it was always + supposed to be there. Was not causing any real problems other + than superfluous attempts by releaseFile to close files that + were already closed. + +--WBW 3:58 PM 3/2/2022 + diff --git a/Tools/unix/zxcc/cbops.h b/Tools/unix/zxcc/cbops.h new file mode 100644 index 00000000..6772b004 --- /dev/null +++ b/Tools/unix/zxcc/cbops.h @@ -0,0 +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 diff --git a/Tools/unix/zxcc/config.h.darwin b/Tools/unix/zxcc/config.h.darwin new file mode 100644 index 00000000..3a1ec05c --- /dev/null +++ b/Tools/unix/zxcc/config.h.darwin @@ -0,0 +1,8 @@ +#define HAVE_STDLIB_H +#define HAVE_STRING_H +#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..0f256eac --- /dev/null +++ b/Tools/unix/zxcc/config.h.windows @@ -0,0 +1,10 @@ +#define HAVE_WINDOWS_H +#define HAVE_FCNTL_H +#ifdef _MSC_VER + #define HAVE_DIRENT_H +#endif +#define HAVE_DIRECT_H +#define HAVE_IO_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 56% rename from Tools/unix/zx/cpmdrv.c rename to Tools/unix/zxcc/cpmdrv.c index 24042e5b..691e774f 100644 --- a/Tools/unix/zx/cpmdrv.c +++ b/Tools/unix/zxcc/cpmdrv.c @@ -1,184 +1,182 @@ -/* - - CPMREDIR: CP/M filesystem redirector - Copyright (C) 1998,2003 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 deals with drive-based functions. -*/ - -#include "cpmint.h" - -#ifdef WIN32 - -static char *drive_to_hostdrive(int cpm_drive) -{ - static char prefix[CPM_MAXPATH]; - char *lpfp; - DWORD dw; - - if (!redir_drive_prefix[cpm_drive]) return NULL; - dw = GetFullPathName(redir_drive_prefix[cpm_drive], sizeof(prefix), - prefix, &lpfp); - - if (!dw) return NULL; - if (prefix[1] == ':') /* If path starts with a drive, limit it */ - { /* to just that drive */ - prefix[2] = '/'; - prefix[3] = 0; - } - return prefix; -} -#endif - - -cpm_byte fcb_reset(void) -{ -#ifdef __MSDOS__ - bdos(0x0D, 0, 0); -#endif - - redir_l_drives = 0; - redir_cpmdrive = 0; /* A reset forces current drive to A: */ -/* redir_ro_drives = 0; Software write protect not revoked by func 0Dh. - * - * This does not follow true CP/M, but does match many 3rd-party replacements. - */ - return 0; -} - - -cpm_word fcb_drive (cpm_byte drv) -{ - if (redir_drive_prefix[drv][0]) - { - redir_cpmdrive = drv; - redir_log_drv(drv); - return 0; - } - else return 0x04FF; /* Drive doesn't exist */ -} - -cpm_byte fcb_getdrv(void) -{ - return redir_cpmdrive; -} - - -cpm_byte fcb_user (cpm_byte usr) -{ - if (usr != 0xFF) redir_cpmuser = usr % 16; - - redir_Msg("User: parameter %d returns %d\r\n", usr, redir_cpmuser); - - return redir_cpmuser; -} - - - -cpm_word fcb_logvec(void) -{ - return redir_l_drives; -} - - -cpm_word fcb_rovec(void) -{ - return redir_ro_drives; -} - - -cpm_word fcb_rodisk(void) -{ - cpm_word mask = 1; - - if (redir_cpmdrive) mask = mask << redir_cpmdrive; - - redir_ro_drives |= mask; - return 0; -} - - -cpm_word fcb_resro(cpm_word bitmap) -{ - redir_ro_drives &= ~bitmap; - - return 0; -} - - -cpm_word fcb_sync(cpm_byte flag) -{ -#ifdef WIN32 - return 0; -#else - sync(); return 0; /* Apparently some sync()s are void not int */ -#endif -} - - -cpm_word fcb_purge() -{ -#ifdef WIN32 - return 0; -#else - sync(); return 0; /* Apparently some sync()s are void not int */ -#endif -} - -/* Generic 8MB disk definition */ - -static cpm_byte exdpb[0x11] = { - 0x80, 0, /* 128 records/track */ - 0x04, 0x0F, /* 2k blocks */ - 0x00, /* 16k / extent */ - 0xFF, 0x0F, /* 4095 blocks */ - 0xFF, 0x03, /* 1024 dir entries */ - 0xFF, 0xFF, /* 16 directory blocks */ - 0x00, 0x80, /* Non-removable media */ - 0x00, 0x00, /* No system tracks */ - 0x02, 0x03 /* 512-byte sectors */ -}; - -cpm_word fcb_getdpb(cpm_byte *dpb) -{ - /* Return the example dpb */ - memcpy(dpb, &exdpb, 0x11); - return 0x11; -} - - -/* Create an entirely bogus ALV - * TODO: Make it a bit better */ - -cpm_word fcb_getalv(cpm_byte *alv, cpm_word max) -{ - if (max > 1024) max = 1024; - - memset(alv, 0xFF, max / 2); - memset(alv + (max / 2), 0, max / 2); - - return max; -} - -/* Get disk free space */ - -cpm_word fcb_dfree (cpm_byte drive, cpm_byte *dma) -{ - /* Return half of disk capacity */ - redir_wr24(dma, 0x8000L); /* 8MB / 128 / 2 */ - return 0; -} +/* + + CPMREDIR: CP/M filesystem redirector + Copyright (C) 1998,2003 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 deals with drive-based functions. +*/ + +#include "cpmint.h" + +#ifdef _WIN32 +static char* drive_to_hostdrive(int cpm_drive) +{ + static char prefix[CPM_MAXPATH]; + char* lpfp; + dword dw; + + if (!redir_drive_prefix[cpm_drive]) return NULL; + dw = GetFullPathName(redir_drive_prefix[cpm_drive], sizeof(prefix), + prefix, &lpfp); + + if (!dw) return NULL; + if (prefix[1] == ':') /* If path starts with a drive, limit it */ + { /* to just that drive */ + prefix[2] = '\\'; /* GetDiskFreeSpace should have trailing backslash */ + prefix[3] = 0; + } + return prefix; +} +#endif + + +cpm_byte fcb_reset(void) +{ +#ifdef __MSDOS__ + bdos(0x0D, 0, 0); +#endif + + redir_l_drives = 0; + redir_cpmdrive = 0; /* A reset forces current drive to A: */ +/* redir_ro_drives = 0; Software write protect not revoked by func 0Dh. + * + * This does not follow true CP/M, but does match many 3rd-party replacements. + */ + return 0; +} + + +cpm_word fcb_drive(cpm_byte drv) +{ + if (redir_drive_prefix[drv][0]) + { + redir_cpmdrive = drv; + redir_log_drv(drv); + return 0; + } + else return 0x04FF; /* Drive doesn't exist */ +} + +cpm_byte fcb_getdrv(void) +{ + return redir_cpmdrive; +} + + +cpm_byte fcb_user(cpm_byte usr) +{ + if (usr != 0xFF) redir_cpmuser = usr % 16; + + DBGMSGV("User: parameter %d returns %d\n", usr, redir_cpmuser); + + return redir_cpmuser; +} + + + +cpm_word fcb_logvec(void) +{ + return redir_l_drives; +} + + +cpm_word fcb_rovec(void) +{ + return redir_ro_drives; +} + + +cpm_word fcb_rodisk(void) +{ + cpm_word mask = 1; + + if (redir_cpmdrive) mask = mask << redir_cpmdrive; + + redir_ro_drives |= mask; + return 0; +} + + +cpm_word fcb_resro(cpm_word bitmap) +{ + redir_ro_drives &= ~bitmap; + + return 0; +} + + +cpm_word fcb_sync(cpm_byte flag) +{ +#ifdef _WIN32 + return 0; +#else + sync(); return 0; /* Apparently some sync()s are void not int */ +#endif +} + + +cpm_word fcb_purge() +{ +#ifdef _WIN32 + return 0; +#else + sync(); return 0; /* Apparently some sync()s are void not int */ +#endif +} + +/* Generic 8MB disk definition */ + +static cpm_byte exdpb[0x11] = { + 0x80, 0, /* 128 records/track */ + 0x04, 0x0F, /* 2k blocks */ + 0x00, /* 16k / extent */ + 0xFF, 0x0F, /* 4095 blocks */ + 0xFF, 0x03, /* 1024 dir entries */ + 0xFF, 0xFF, /* 16 directory blocks */ + 0x00, 0x80, /* Non-removable media */ + 0x00, 0x00, /* No system tracks */ + 0x02, 0x03 /* 512-byte sectors */ +}; + +cpm_word fcb_getdpb(cpm_byte* dpb) +{ + /* Return the example dpb */ + memcpy(dpb, &exdpb, 0x11); + return 0x11; +} + +/* Create an entirely bogus ALV + * TODO: Make it a bit better */ + +cpm_word fcb_getalv(cpm_byte* alv, cpm_word max) +{ + if (max > 1024) max = 1024; + + memset(alv, 0xFF, max / 2); + memset(alv + (max / 2), 0, max / 2); + + return max; +} + +/* Get disk free space */ + +cpm_word fcb_dfree(cpm_byte drive, cpm_byte* dma) +{ + /* Return half of disk capacity */ + 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 52% rename from Tools/unix/zx/cpmglob.c rename to Tools/unix/zxcc/cpmglob.c index 5566d8a4..3705b05e 100644 --- a/Tools/unix/zx/cpmglob.c +++ b/Tools/unix/zxcc/cpmglob.c @@ -1,583 +1,598 @@ -/* - - 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 implements those BDOS functions that use wildcard expansion. -*/ - -#include "cpmint.h" - -static cpm_byte *find_fcb; -static int find_n; -static int find_ext = 0; -static int find_xfcb = 0; -static int entryno; -static cpm_byte lastdma[0x80]; -static long lastsize; -static char target_name[CPM_MAXPATH]; - -static char upper(char c) -{ - if (islower(c)) return toupper(c); - return c; -} - -/* - * we need to handle case sensitive filesystems correctly. - * underlying files need to just work, irrespective if the files - * in the native filesystem are mixed, upper or lower. - * the naive code in the distributed zx will not work everywhere. - */ - -/* Does the string "s" match the CP/M FCB? */ -/* pattern[0-10] will become a CP/M name parsed from "s" if it matches. */ -/* If 1st byte of FCB is '?' then anything matches. */ - -static int cpm_match(char *s, cpm_byte *fcb, cpm_byte *pattern) -{ - int n, m; - char *dotpos; - - m = strlen(s); - - /* - * let's cook the filename into something that we can match against - * the fcb. we reject any that can't be valid cp/m filenames, - * normalizing case as we go. all this goes into 'pattern' - */ - for (n = 0; n < 11; n++) pattern[n] = ' '; - - /* The name must have 1 or 0 dots */ - dotpos = strchr(s, '.'); - if (!dotpos) { /* No dot. The name must be at most 8 characters */ - if (m > 8) return 0; - for (n = 0; n < m; n++) { - pattern[n] = upper(s[n]) & 0x7F; - } - } else { /* at least one dot */ - if (strchr(dotpos + 1, '.')) { /* More than 1 dot */ - return 0; - } - if (dotpos == s) { /* Dot right at the beginning */ - return 0; - } - if ((dotpos - s) > 8) { /* "name" > 8 characters */ - return 0; - } - if (strlen(dotpos + 1) > 3) { /* "type" > 3 characters */ - return 0; - } - for (n = 0; n < (dotpos - s); n++) { /* copy filename portion */ - pattern[n] = upper(s[n]) & 0x7F; - } - m = strlen(dotpos + 1); - for (n = 0; n < m; n++) { /* copy extention portion */ - pattern[n + 8] = upper(dotpos[n + 1]) & 0x7F; - } - } - - /* - * handle special case where fcb[0] == '?' or fcb[0] & 0x80 - * this is used to return a full directory list on bdos's - */ - if (((fcb[0] & 0x7F) == '?') || (fcb[0] & 0x80)) { - return 1; - } - - for (n = 0; n < 11; n++) { - if (fcb[n+1] == '?') continue; - if ((pattern[n] & 0x7F) != (fcb[n+1] & 0x7F)) { - return 0; - } - } - return 1; /* Success! */ -} - - -/* Get the next entry from the host's directory matching "fcb" */ - -static struct dirent * next_entry(DIR *dir, cpm_byte *fcb, cpm_byte *pattern, - struct stat *st) -{ - struct dirent *en; - int unsatisfied; - int drv = fcb[0] & 0x7F; - - if (drv == '?') drv = 0; - if (!drv) drv = redir_cpmdrive; - else drv--; - - for (unsatisfied = 1; unsatisfied; ) - { - /* 1. Get the next entry */ - - en = readdir(dir); - if (!en) return NULL; /* No next entry */ - ++entryno; /* 0 for 1st, 1 for 2nd, etc. */ - - /* 2. See if it matches. We do this first (in preference to - seeing if it's a subdirectory first) because it doesn't - require disc access */ - if (!cpm_match(en->d_name, fcb, pattern)) - { - continue; - } - /* 3. Stat it, & reject it if it's a directory */ - - strcpy(target_name, redir_drive_prefix[drv]); - strcat(target_name, en->d_name); - - if (stat(target_name, st)) - { - 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) - { - /* Searching for files only */ - if (fcb[0] != '?' && fcb[0] < 0x80) - { - continue; - } - } - unsatisfied = 0; - } - return en; -} - - - -void volume_label(int drv, cpm_byte *dma) -{ - struct stat st; - - memset(dma, 0x20, 12); /* Volume label */ - - /* Get label name */ - redir_get_label(drv, (char *)(dma + 1)); - /* [0x0c] = label byte - * [0x0d] = password byte (=0) - * [0x10-0x17] = password - * [0x18] = label create date - * [0x1c] = label update date - */ -#ifdef __MSDOS__ - dma[0x0c] = 0x21; /* Under DOS, only "update" */ - if (redir_drdos) dma[0x0c] |= 0x80; /* Under DRDOS, passwords allowed */ -#else - dma[0x0c] = 0x61; /* Label exists and time stamps allowed */ -#endif /* (update & access) */ - dma[0x0d] = 0; /* Label not passworded */ - dma[0x0f] = 0x80; /* Non-CP/M media */ - - if (stat(redir_drive_prefix[drv], &st)) - { - redir_Msg("stat() fails on '%s'\n", redir_drive_prefix[drv]); - return; - } - - redir_wr32(dma + 0x18, redir_cpmtime(st.st_atime)); - redir_wr32(dma + 0x1C, redir_cpmtime(st.st_mtime)); -} - - - -cpm_word redir_find(int n, cpm_byte *fcb, cpm_byte *dma) -{ - DIR *hostdir; - int drv, attrib; - long recs; - struct stat st; - struct dirent *de; - cpm_word rights; - - drv = (fcb[0] & 0x7F); - if (!drv || drv == '?') drv = redir_cpmdrive; - else drv--; - - if (find_xfcb) /* Return another extent */ - { - memcpy(dma, lastdma, 0x80); - dma[0] |= 0x10; /* XFCB */ - dma[0x0c] = dma[0x69]; /* Password mode */ - dma[0x0d] = 0x0A; /* Password decode byte */ - memset(dma + 0x10, '*', 7); - dma[0x17] = ' '; /* Encoded password */ - memcpy(lastdma, dma, 0x80); - - find_xfcb = 0; - return 0; - } - - if (find_ext) /* Return another extent */ - { - memcpy(dma, lastdma, 0x80); - dma[0x0c]++; - if (dma[0x0c] == 0x20) - { - dma[0x0c] = 0; - dma[0x0e]++; - } - lastsize -= 0x4000; - recs = (lastsize + 127) / 128; - dma[0x0f] = (recs > 127) ? 0x80 : (recs & 0x7F); - - if (lastsize <= 0x4000) find_ext = 0; - memcpy(lastdma, dma, 0x80); - - return 0; - } - - - memset(dma, 0, 128); /* Zap the buffer */ - - /* - If returning all entries, return a volume label. - */ - if ((fcb[0] & 0x7F) == '?') - { - if (!n) - { - volume_label(drv, dma); - return 0; - } - else --n; - } - - /* Note: This implies that opendir() works on a filename with a - trailing slash. It does under Linux, but that's the only assurance - I can give. - */ - - entryno = -1; - hostdir = opendir(redir_drive_prefix[drv]); - - if (!hostdir) - { - redir_Msg("opendir() fails on '%s'\n", redir_drive_prefix[drv]); - return 0xFF; - } - /* We have a handle to the directory. */ - while (n >= 0) - { - de = next_entry(hostdir, fcb, dma + 1, &st); - if (!de) - { - closedir(hostdir); - return 0xFF; - } - --n; - } - /* Valid entry found & statted. dma+1 holds filename. */ - - dma[0] = redir_cpmuser; /* Uid always matches */ - dma[0x0c] = 0; /* Extent counter, low */ - 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); - 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; - - - -/* TODO: Under Unix, work out correct RO setting */ - - 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 (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. */ - /* TODO: It should be in DOS */ - /* format */ - /* TODO: At 0x1A, 1st cluster */ - redir_wr32(dma + 0x1C, st.st_size); /* True size */ - - if (rights) /* Store password mode. Don't return an XFCB. */ - { - dma[0x69] = redir_cpm_pwmode(rights); - memcpy(lastdma, dma, 0x80); - } - - dma[0x60] = 0x21; /* XFCB */ - redir_wr32(dma + 0x61, redir_cpmtime(st.st_atime)); - redir_wr32(dma + 0x65, redir_cpmtime(st.st_mtime)); - - closedir(hostdir); - - if (st.st_size > 0x4000 && (fcb[0x0C] == '?')) /* All extents? */ - { - lastsize = st.st_size; - find_ext = 1; - memcpy(lastdma, dma, 0x80); - } - return 0; -} - - -#ifdef DEBUG -#define SHOWNAME(func) \ - { \ - char fname[CPM_MAXPATH]; \ - redir_fcb2unix(fcb, fname); \ - redir_Msg(func "(\"%s\")\n", fname); \ - } - -#else - #define SHOWNAME(func) -#endif - -cpm_word fcb_find1 (cpm_byte *fcb, cpm_byte *dma) /* 0x11 */ -{ -#ifdef DEBUG - int rv; -#endif - SHOWNAME("fcb_find1") - - redir_log_fcb(fcb); - - find_n = 0; - find_fcb = fcb; - find_ext = 0; - find_xfcb = 0; -#ifdef DEBUG - rv = redir_find(find_n, fcb, dma); - - if (rv < 4) - { - redir_Msg("Ret: %-11.11s\n", dma + 1); - } - else redir_Msg("Ret: Fail\n"); - return rv; -#else - return redir_find(find_n, find_fcb, dma); -#endif -} - -/* We don't bother with the FCB parameter - it's undocmented, and - * programs that do know about it will just pass in the same parameter - * that they did to function 0x11 */ - -cpm_word fcb_find2 (cpm_byte *fcb, cpm_byte *dma) /* 0x12 */ -{ -#ifdef DEBUG - int rv; - - char fname[CPM_MAXPATH]; - redir_fcb2unix(find_fcb, fname); - redir_Msg("fcb_find2(\"%s\") no. %d\n", fname, find_n); -#endif - ++find_n; -#ifdef DEBUG - rv = redir_find(find_n, find_fcb, dma); - - if (rv < 4) - { - redir_Msg("Ret: %-11.11s\n", dma + 1); - } - else redir_Msg("Ret: Fail\n"); - return rv; -#else - return redir_find(find_n, find_fcb, dma); -#endif -} - -/* Under CP/M, unlinking works with wildcards */ - -cpm_word fcb_unlink(cpm_byte *fcb, cpm_byte *dma) -{ - DIR *hostdir; - int drv; - struct dirent *de; - struct stat st; - int handle = 0; - int unpasswd = 0; - char fname[CPM_MAXPATH]; - - SHOWNAME("fcb_unlink") - - if (fcb[5] & 0x80) unpasswd = 1; /* Remove password rather than file */ - - redir_log_fcb(fcb); - - drv = (fcb[0] & 0x7F); - if (!drv || drv == '?') drv = redir_cpmdrive; - else drv--; - - if (redir_ro_drv(drv)) return 0x02FF; /* Error: R/O drive */ - -#ifdef DEBUG - redir_fcb2unix(fcb, fname); - redir_Msg("fcb_unlink(\"%s\")\n", fname); -#endif - - /* Note: This implies that opendir() works on a filename with a - trailing slash. It does under Linux, but that's the only assurance - I can give. - */ - - hostdir = opendir(redir_drive_prefix[drv]); - - if (!hostdir) - { - redir_Msg("opendir() fails on '%s'\n", redir_drive_prefix[drv]); - return 0xFF; - } - /* We have a handle to the directory. */ - do - { - de = next_entry(hostdir, fcb, (cpm_byte *)fname, &st); - if (de) - { - strcpy(target_name, redir_drive_prefix[drv]); - strcat(target_name, de->d_name); - redir_Msg("Deleting %s\n", de->d_name); - if (unpasswd) - { -#ifdef __MSDOS__ - if (redir_drdos) - { - handle = redir_drdos_put_rights (target_name, dma, 0); - } - else handle = 0; -#endif - } - else if (fcb[0] & 0x80) - { - handle = rmdir(target_name); - if (handle && redir_password_error()) - { - redir_password_append(target_name, dma); - handle = rmdir(target_name); - } - } - else - { - handle = unlink(target_name); - if (handle && redir_password_error()) - { - redir_password_append(target_name, dma); - handle = unlink(target_name); - } - } - - if (handle) de = NULL; /* Delete failed */ - } - } - while (de != NULL); - if (handle) - { - redir_Msg("Ret: -1\n"); - closedir(hostdir); - return 0xFF; - } - redir_Msg("Ret: 0\n"); - closedir(hostdir); - return 0; -} - - - - - -#ifdef __MSDOS__ -cpm_word redir_get_label(cpm_byte drv, char *pattern) -{ - char strs[10]; - struct ffblk fblk; - int done; - char *s; - int n; - - /* We need the drive prefix to be of the form "C:\etc..." */ - - memset(pattern, ' ', 11); - if (!redir_drive_prefix[drv][0] || redir_drive_prefix[drv][1] != ':') - return 0; - - sprintf(strs,"%c:/*.*", redir_drive_prefix[drv][0]); - - done = findfirst(strs, &fblk, FA_LABEL); - while (!done) - { - if ((fblk.ff_attrib & FA_LABEL) && - !(fblk.ff_attrib & (FA_SYSTEM | FA_HIDDEN))) - { - s = strchr(fblk.ff_name, '/'); - if (!s) s = strchr(fblk.ff_name, '\\'); - if (!s) s = strchr(fblk.ff_name, ':'); - if (!s) s = fblk.ff_name; - for (n = 0; n < 11; n++) - { - if (!(*s)) break; - if (*s == '.') - { - n = 7; - ++s; - continue; - } - pattern[n] = upper(*s); - ++s; - } - return 1; - } - done = findnext(&fblk); - } - return 0; -} -#else -cpm_word redir_get_label(cpm_byte drv, char *pattern) -{ - char *dname; - int l, n; - - memset(pattern, ' ', 11); - - dname = strrchr(redir_drive_prefix[drv], '/'); - if (dname) - { - ++dname; - l = strlen(dname); - if (l > 11) l = 11; - for (n = 0; n < l; n++) pattern[n] = upper(dname[l]); - } - else - { - pattern[0] = '.'; - } - return 0; -} - - - -#endif +/* + + 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 implements those BDOS functions that use wildcard expansion. +*/ + +#include "cpmint.h" +#ifdef _MSC_VER + #define S_ISDIR(mode) (((mode) & _S_IFDIR) != 0) +#endif + +static cpm_byte* find_fcb; +static int find_n; +static int find_ext = 0; +static int find_xfcb = 0; +static int entryno; +static cpm_byte lastdma[0x80]; +static long lastsize; +static char target_name[CPM_MAXPATH]; + +static char upper(char c) +{ + if (islower(c)) return toupper(c); + return c; +} + +/* + * we need to handle case sensitive filesystems correctly. + * underlying files need to just work, irrespective if the files + * in the native filesystem are mixed, upper or lower. + * the naive code in the distributed zx will not work everywhere. + */ + + /* + * Does the string "s" match the CP/M FCB? + * pattern[0-10] will become a CP/M name parsed from "s" if it matches. + * If 1st byte of FCB is '?' then anything matches. + */ + +static int cpm_match(char* s, cpm_byte* fcb, cpm_byte* pattern) +{ + int n; + size_t m; + char* dotpos; + + m = strlen(s); + + /* + * let's cook the filename into something that we can match against + * the fcb. we reject any that can't be valid cp/m filenames, + * normalizing case as we go. all this goes into 'pattern' + */ + + for (n = 0; n < 11; n++) pattern[n] = ' '; + + /* The name must have 1 or 0 dots */ + dotpos = strchr(s, '.'); + if (!dotpos) { /* No dot. The name must be at most 8 characters */ + if (m > 8) return 0; + for (n = 0; n < m; n++) { + pattern[n] = upper(s[n]) & 0x7F; + } + } + else { /* at least one dot */ + if (strchr(dotpos + 1, '.')) { /* More than 1 dot */ + return 0; + } + if (dotpos == s) { /* Dot right at the beginning */ + return 0; + } + if ((dotpos - s) > 8) { /* "name" > 8 characters */ + return 0; + } + if (strlen(dotpos + 1) > 3) { /* "type" > 3 characters */ + return 0; + } + for (n = 0; n < (dotpos - s); n++) { /* copy filename portion */ + pattern[n] = upper(s[n]) & 0x7F; + } + m = strlen(dotpos + 1); + for (n = 0; n < m; n++) { /* copy extention portion */ + pattern[n + 8] = upper(dotpos[n + 1]) & 0x7F; + } + } + + /* + * handle special case where fcb[0] == '?' or fcb[0] & 0x80 + * this is used to return a full directory list on bdos's + */ + + if (((fcb[0] & 0x7F) == '?') || (fcb[0] & 0x80)) { + return 1; + } + for (n = 0; n < 11; n++) + { + if (fcb[n + 1] == '?') continue; + if ((pattern[n] & 0x7F) != (fcb[n + 1] & 0x7F)) + { + return 0; + } + } + return 1; /* Success! */ +} + +/* Get the next entry from the host's directory matching "fcb" */ + +static struct dirent* next_entry(DIR* dir, cpm_byte* fcb, cpm_byte* pattern, + struct stat* st) +{ + struct dirent* en; + int unsatisfied; + int drv = fcb[0] & 0x7F; + + if (drv == '?') drv = 0; + if (!drv) drv = redir_cpmdrive; + else drv--; + + for (unsatisfied = 1; unsatisfied; ) + { + /* 1. Get the next entry */ + en = readdir(dir); + if (!en) return NULL; /* No next entry */ + ++entryno; /* 0 for 1st, 1 for 2nd, etc. */ + + /* 2. See if it matches. We do this first (in preference to + * seeing if it's a subdirectory first) because it doesn't + * require disc access */ + if (!cpm_match(en->d_name, fcb, pattern)) + { + continue; + } + + /* 3. Stat it, & reject it if it's a directory */ + strcpy(target_name, redir_drive_prefix[drv]); + strcat(target_name, en->d_name); + + if (stat(target_name, st)) + { + DBGMSGV("Can't stat %s so omitting it.\n", target_name); + continue; /* Can't stat */ + } + if (S_ISDIR(st->st_mode)) + { + /* Searching for files only */ + if (fcb[0] != '?' && fcb[0] < 0x80) + { + continue; + } + } + unsatisfied = 0; + } + return en; +} + +void volume_label(int drv, cpm_byte* dma) +{ + struct stat st; + + memset(dma, 0x20, 12); /* Volume label */ + + /* Get label name */ + redir_get_label(drv, (char*)(dma + 1)); + + /* [0x0c] = label byte + * [0x0d] = password byte (=0) + * [0x10-0x17] = password + * [0x18] = label create date + * [0x1c] = label update date + */ +#ifdef __MSDOS__ + dma[0x0c] = 0x21; /* Under DOS, only "update" */ + if (redir_drdos) dma[0x0c] |= 0x80; /* Under DRDOS, passwords allowed */ +#else + dma[0x0c] = 0x61; /* Label exists and time stamps allowed */ +#endif /* (update & access) */ + dma[0x0d] = 0; /* Label not passworded */ + dma[0x0f] = 0x80; /* Non-CP/M media */ + + if (stat(redir_drive_prefix[drv], &st)) + { + DBGMSGV("stat() fails on '%s'\n", redir_drive_prefix[drv]); + return; + } + + redir_wr32(dma + 0x18, redir_cpmtime(st.st_atime)); + redir_wr32(dma + 0x1C, redir_cpmtime(st.st_mtime)); +} + +cpm_word redir_find(int n, cpm_byte* fcb, cpm_byte* dma) +{ + DIR* hostdir; + int drv, attrib; + long recs; + struct stat st; + struct dirent* de; + cpm_word rights; + + drv = (fcb[0] & 0x7F); + if (!drv || drv == '?') drv = redir_cpmdrive; + else drv--; + + if (find_xfcb) /* Return another extent */ + { + memcpy(dma, lastdma, 0x80); + dma[0] |= 0x10; /* XFCB */ + dma[0x0c] = dma[0x69]; /* Password mode */ + dma[0x0d] = 0x0A; /* Password decode byte */ + memset(dma + 0x10, '*', 7); + dma[0x17] = ' '; /* Encoded password */ + memcpy(lastdma, dma, 0x80); + + find_xfcb = 0; + return 0; + } + + if (find_ext) /* Return another extent */ + { + memcpy(dma, lastdma, 0x80); + dma[0x0c]++; + if (dma[0x0c] == 0x20) + { + dma[0x0c] = 0; + dma[0x0e]++; + } + lastsize -= 0x4000; + recs = (lastsize + 127) / 128; + dma[0x0f] = (recs > 127) ? 0x80 : (recs & 0x7F); + + if (lastsize <= 0x4000) find_ext = 0; + memcpy(lastdma, dma, 0x80); + + return 0; + } + + memset(dma, 0, 128); /* Zap the buffer */ + + /* If returning all entries, return a volume label. */ + + if ((fcb[0] & 0x7F) == '?') + { + if (!n) + { + volume_label(drv, dma); + return 0; + } + else --n; + } + + /* Note: This implies that opendir() works on a filename with a + * trailing slash. It does under Linux, but that's the only assurance + * I can give. */ + + entryno = -1; + hostdir = opendir(redir_drive_prefix[drv]); + + if (!hostdir) + { + DBGMSGV("opendir() fails on '%s'\n", redir_drive_prefix[drv]); + return 0xFF; + } + + /* We have a handle to the directory. */ + while (n >= 0) + { + de = next_entry(hostdir, fcb, dma + 1, &st); + if (!de) + { + closedir(hostdir); + return 0xFF; + } + --n; + } + /* Valid entry found & statted. dma+1 holds filename. */ + + dma[0] = redir_cpmuser; /* Uid always matches */ + dma[0x0c] = 0; /* Extent counter, low */ + dma[0x0d] = st.st_size & 0x7F; /* Last record byte count */ + dma[0x0e] = 0; /* Extent counter, high */ + +#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; /* read only */ + if (attrib & 4) dma[10] |= 0x80; /* system */ + if (!(attrib & 0x20)) dma[11] |= 0x80; /* archive */ + +/* TODO: Under Unix, work out correct RO setting */ + + 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 (attrib & 2) dma[0x10] |= 0x20; + dma[0x10] |= ((entryno & 0x1FFF) >> 8); + dma[0x11] = dma[0x10]; + dma[0x12] = entryno & 0xFF; + + redir_wr32(dma + 0x16, (dword)st.st_mtime); /* Modification time. */ + /* TODO: It should be in DOS format */ + /* TODO: At 0x1A, 1st cluster */ + redir_wr32(dma + 0x1C, st.st_size); /* True size */ + + if (rights) /* Store password mode. Don't return an XFCB. */ + { + dma[0x69] = redir_cpm_pwmode(rights); + memcpy(lastdma, dma, 0x80); + } + + dma[0x60] = 0x21; /* XFCB */ + redir_wr32(dma + 0x61, redir_cpmtime(st.st_atime)); + redir_wr32(dma + 0x65, redir_cpmtime(st.st_mtime)); + + closedir(hostdir); + + if (st.st_size > 0x4000 && (fcb[0x0C] == '?')) /* All extents? */ + { + lastsize = st.st_size; + find_ext = 1; + memcpy(lastdma, dma, 0x80); + } + return 0; +} + +cpm_word fcb_find1(cpm_byte* fcb, cpm_byte* dma) /* 0x11 */ +{ +#ifdef DEBUG + int rv; +#endif + + FCBENT(fcb); + + redir_log_fcb(fcb); + + find_n = 0; + find_fcb = fcb; + find_ext = 0; + find_xfcb = 0; + +#ifdef DEBUG + rv = redir_find(find_n, fcb, dma); + + if (rv < 4) + { + DBGMSGV("Ret: %-11.11s\n", dma + 1); + } + else DBGMSG("Ret: Fail\n"); + FCBRET(rv); +#else + FCBRET(redir_find(find_n, find_fcb, dma)); +#endif +} + +/* We don't bother with the FCB parameter - it's undocmented, and + * programs that do know about it will just pass in the same parameter + * that they did to function 0x11 */ + +cpm_word fcb_find2(cpm_byte* fcb, cpm_byte* dma) /* 0x12 */ +{ +#ifdef DEBUG + int rv; + char fname[CPM_MAXPATH]; +#endif + + FCBENT(find_fcb); + +#ifdef DEBUG + redir_fcb2unix(find_fcb, fname); + DBGMSGV("file number %d, '%s'\n", find_n, fname); +#endif + + ++find_n; + +#ifdef DEBUG + rv = redir_find(find_n, find_fcb, dma); + + if (rv < 4) + { + DBGMSGV("Ret: %-11.11s\n", dma + 1); + } + else DBGMSG("Ret: Fail\n"); + FCBRET(rv); +#else + FCBRET(redir_find(find_n, find_fcb, dma)); +#endif +} + +/* Under CP/M, unlinking works with wildcards */ + +cpm_word fcb_unlink(cpm_byte* fcb, cpm_byte* dma) +{ + DIR* hostdir; + int drv; + struct dirent* de; + struct stat st; + int handle = 0; + int unpasswd = 0; + char fname[CPM_MAXPATH]; + int del_cnt = 0; + + FCBENT(fcb); + + if (fcb[5] & 0x80) unpasswd = 1; /* Remove password rather than file */ + + redir_log_fcb(fcb); + + drv = (fcb[0] & 0x7F); + if (!drv || drv == '?') drv = redir_cpmdrive; + else drv--; + + if (redir_ro_drv(drv)) + { + /* Error: R/O drive */ + DBGMSG("delete failed - R/O drive\n"); + FCBRET(0x02FF); + } + +#ifdef DEBUG + redir_fcb2unix(fcb, fname); + DBGMSGV("fcb_unlink('%s')\n", fname); +#endif + + /* Note: This implies that opendir() works on a filename with a + * trailing slash. It does under Linux, but that's the only assurance + * I can give.*/ + + hostdir = opendir(redir_drive_prefix[drv]); + + if (!hostdir) + { + DBGMSGV("opendir failed on '%s'\n", redir_drive_prefix[drv]); + FCBRET(0xFF); + } + + /* We have a handle to the directory. */ + do + { + de = next_entry(hostdir, fcb, (cpm_byte*)fname, &st); + if (de) + { + strcpy(target_name, redir_drive_prefix[drv]); + strcat(target_name, de->d_name); + DBGMSGV("deleting '%s'\n", de->d_name); + if (unpasswd) + { +#ifdef __MSDOS__ + if (redir_drdos) + { + handle = redir_drdos_put_rights(target_name, dma, 0); + } + else handle = 0; +#endif + } + else if (fcb[0] & 0x80) + { + DBGMSGV("rmdir '%s'\n", target_name); + handle = rmdir(target_name); + if (handle && redir_password_error()) + { + DBGMSGV("rmdir failed (errno=%lu): %s\n", errno, strerror(errno)); + redir_password_append(target_name, dma); + DBGMSGV("rmdir '%s'\n", target_name); + handle = rmdir(target_name); + } + if (handle) + DBGMSGV("rmdir failed (errno=%lu): %s\n", errno, strerror(errno)); + } + else + { + releaseFile(target_name); + DBGMSGV("unlink '%s'\n", target_name); + handle = unlink(target_name); + if (handle && redir_password_error()) + { + DBGMSGV("unlink failed (errno=%lu): %s\n", errno, strerror(errno)); + redir_password_append(target_name, dma); + releaseFile(target_name); + DBGMSGV("unlink '%s'\n", target_name); + handle = unlink(target_name); + } + if (handle) + DBGMSGV("unlink failed (errno=%lu): %s\n", errno, strerror(errno)); + } + + if (handle) + de = NULL; /* Delete failed */ + else + del_cnt++; + } + } while (de != NULL); + + if (!handle && !del_cnt) + DBGMSG("no matching directory entries\n"); + else + DBGMSGV("deleted %i file(s)\n", del_cnt); + + if (handle || !del_cnt) + { + DBGMSG("delete processing failed\n"); + closedir(hostdir); + FCBRET(0xFF); + } + + DBGMSG("delete processing succeeded\n"); + closedir(hostdir); + FCBRET(0); +} + +#ifdef __MSDOS__ +cpm_word redir_get_label(cpm_byte drv, char* pattern) +{ + char strs[10]; + struct ffblk fblk; + int done; + char* s; + int n; + + /* We need the drive prefix to be of the form "C:\etc..." */ + + memset(pattern, ' ', 11); + if (!redir_drive_prefix[drv][0] || redir_drive_prefix[drv][1] != ':') + return 0; + + sprintf(strs, "%c:/*.*", redir_drive_prefix[drv][0]); + + done = findfirst(strs, &fblk, FA_LABEL); + while (!done) + { + if ((fblk.ff_attrib & FA_LABEL) && + !(fblk.ff_attrib & (FA_SYSTEM | FA_HIDDEN))) + { + s = strchr(fblk.ff_name, '/'); + if (!s) s = strchr(fblk.ff_name, '\\'); + if (!s) s = strchr(fblk.ff_name, ':'); + if (!s) s = fblk.ff_name; + for (n = 0; n < 11; n++) + { + if (!(*s)) break; + if (*s == '.') + { + n = 7; + ++s; + continue; + } + pattern[n] = upper(*s); + ++s; + } + return 1; + } + done = findnext(&fblk); + } + return 0; +} +#else +cpm_word redir_get_label(cpm_byte drv, char* pattern) +{ + char* dname; + size_t l; + int n; + + memset(pattern, ' ', 11); + + dname = strrchr(redir_drive_prefix[drv], '/'); + if (dname) + { + ++dname; + l = strlen(dname); + if (l > 11) l = 11; + for (n = 0; n < l; n++) pattern[n] = upper(dname[l]); + } + else + { + pattern[0] = '.'; + } + return 0; +} + +#endif diff --git a/Tools/unix/zxcc/cpmint.h b/Tools/unix/zxcc/cpmint.h new file mode 100644 index 00000000..9520e05e --- /dev/null +++ b/Tools/unix/zxcc/cpmint.h @@ -0,0 +1,274 @@ +/* + + 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 internal declarations for the library. +*/ + +#include "config.h" +#include +#ifdef HAVE_STDLIB_H + #include +#endif +#include +#ifdef HAVE_STRING_H + #include +#endif +#include +#include +#ifdef _WIN32 + #include +#endif +#ifdef HAVE_SYS_TYPES_H + #include +#endif +#include +#include +#ifdef HAVE_DIRENT_H + #include +#endif +#ifdef HAVE_DIRECT_H + #include +#endif +#ifdef HAVE_IO_H + #include +#endif +#ifdef HAVE_NDIR_H + #include +#endif +#ifdef HAVE_SYS_DIR_H + #include +#endif +#ifdef HAVE_SYS_NDIR_H + #include +#endif +#ifdef HAVE_WINDOWS_H + #include +#endif +#ifdef HAVE_WINNT_H + #include +#endif +#ifdef HAVE_SYS_VFS_H + #include +#endif +#ifdef HAVE_UTIME_H + #include +#endif +#ifdef HAVE_FCNTL_H + #include +#endif +#ifdef HAVE_UNISTD_H + #include +#endif +#ifndef _WIN32 + #include + #include + #define _S_IFDIR S_IFDIR +#endif + +/* MSDOS includes removed */ + +#ifdef _WIN32 + #define DIRSEP "/" + #define mkdir(dir, mode) _mkdir(dir) + #define strcasecmp _stricmp + #define ftruncate _chsize +/* note Windows build assumes Windows is configured as a non case sensitive filesystem */ + #ifndef STDIN_FILENO + #define STDIN_FILENO _fileno(stdin) + #define STDOUT_FILENO _fileno(stdout) + #define STDERR_FILENO _fileno(stderr) + #endif +#else + #define DIRSEP "/\\:" + #define CASE_SENSITIVE_FILESYSTEM 1 +#endif + +#ifdef _WIN32 +int truncate(const char* path, off_t length); /* see util.c */ +#endif + +typedef unsigned char byte; /* Must be exactly 8 bits */ +typedef unsigned short word; /* Must be exactly 16 bits */ +typedef unsigned long dword; /* Must be at least 32 bits, and + >= sizeof(int) */ + +#include "cpmredir.h" + +#ifdef CPMDEF + #define EXT + #define INIT(x) =x +#else + #define EXT extern + #define INIT(x) +#endif + +/* The 16 directories to which the 16 CP/M drives are mapped */ + +EXT char redir_drive_prefix[16][CPM_MAXPATH]; + +/* Current drive and user */ + +EXT int redir_cpmdrive; +EXT int redir_cpmuser; + +/* Length of 1 read/write operation, bytes */ + +EXT int redir_rec_len INIT(128); + +/* Same, but in 128-byte records */ +EXT int redir_rec_multi INIT(1); + +/* Using a DRDOS system? */ +EXT int redir_drdos INIT(0); + +/* Default password */ +#ifdef __MSDOS__ +EXT char redir_passwd[8] INIT(""); +#endif + +EXT cpm_word redir_l_drives INIT(0); +EXT cpm_word redir_ro_drives INIT(0); + +#undef EXT +#undef INIT + +/* Convert FCB to a Unix filename, returning 1 if it's ambiguous */ +int redir_fcb2unix(cpm_byte* fcb, char* fname); + +/* Open FCB, set file attributes */ +int redir_ofile(cpm_byte* fcb, char* s); + +/* Check that the FCB we have is valid */ +int redir_verify_fcb(cpm_byte* fcb); + +#ifndef O_BINARY /* Necessary in DOS, not present in Linux */ +#define O_BINARY 0 +#endif + +/* Facilities for debug tracing */ + +long zxlseek(int fd, long offset, int wh); + +#ifdef _WIN32 +char* GetErrorStr(DWORD); +#endif + +#ifdef DEBUG +// long zxlseek(int fd, long offset, int wh); +// void redir_Msg(char *s, ...); +void DbgMsg(const char* file, int line, const char* func, 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) +#endif + +#ifdef DEBUG +#define FCBENT(fcb) \ + { \ + char fname[CPM_MAXPATH] = ""; \ + redir_fcb2unix(fcb, fname); \ + DBGMSGV("entry w/ FCB @ 0x%04X, filename:'%s'\n", fcb-RAM, fname); \ + } + +#define FCBRET(rc) \ + { \ + DBGMSGV("returning 0x%04X\n", rc); \ + return rc; \ + } + +#define DBGMSGV(s, ...) DbgMsg(__FILE__, __LINE__, __func__, s, __VA_ARGS__) +#define DBGMSG(s) DbgMsg(__FILE__, __LINE__, __func__, s) +#else +#define FCBENT(fcb) +#define FCBRET(rc) return rc; +#define DBGMSGV(s, ...) +#define DBGMSG(s) +#endif + +/* Get the "sequential access" file pointer out of an FCB */ + +long redir_get_fcb_pos(cpm_byte* fcb); + +/* Write "sequential access" pointer to FCB */ + +void redir_put_fcb_pos(cpm_byte* fcb, long npos); + +/* Convert time_t to CP/M day count/hours/minutes */ +dword redir_cpmtime(time_t t); +/* And back */ +time_t redir_unixtime(cpm_byte* c); + +/* Functions to access 24-bit & 32-bit words in memory. These are always + little-endian. */ + +void redir_wr24(cpm_byte* addr, dword v); +void redir_wr32(cpm_byte* addr, dword v); +dword redir_rd24(cpm_byte* addr); +dword redir_rd32(cpm_byte* addr); + +/* If you have 64-bit file handles, you'll need to write separate wrhandle() + and rdhandle() routines */ +#define redir_wrhandle redir_wr32 +#define redir_rdhandle redir_rd32 + +/* Mark a drive as logged in */ + +void redir_log_drv(cpm_byte drv); +void redir_log_fcb(cpm_byte* fcb); + +/* Check if a drive is software read-only */ + +int redir_ro_drv(cpm_byte drv); +int redir_ro_fcb(cpm_byte* fcb); + +/* Translate errno to a CP/M error */ + +cpm_word redir_xlt_err(void); + +/* Get disc label */ +cpm_word redir_get_label(cpm_byte drv, char* pattern); + +/* DRDOS set/get access rights - no-ops under MSDOS and Unix: + * + * CP/M password mode -> DRDOS password mode */ +cpm_word redir_drdos_pwmode(cpm_byte b); + +/* DRDOS password mode to CP/M password mode */ +cpm_byte redir_cpm_pwmode(cpm_word w); + +/* Get DRDOS access rights for a file */ +cpm_word redir_drdos_get_rights(char* path); + +/* Set DRDOS access rights and/or password */ +cpm_word redir_drdos_put_rights(char* path, cpm_byte* dma, cpm_word rights); + +/* Was the last error caused by invalid password? */ +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) + +extern byte RAM[65536]; /* The Z80's address space */ diff --git a/Tools/unix/zxcc/cpmparse.c b/Tools/unix/zxcc/cpmparse.c new file mode 100644 index 00000000..73919c68 --- /dev/null +++ b/Tools/unix/zxcc/cpmparse.c @@ -0,0 +1,124 @@ +/* + + 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/zxcc/cpmredir.c b/Tools/unix/zxcc/cpmredir.c new file mode 100644 index 00000000..ff32a3c0 --- /dev/null +++ b/Tools/unix/zxcc/cpmredir.c @@ -0,0 +1,1006 @@ +/* + + 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 handles actual reading and writing */ + +#define CPMDEF +#include "cpmint.h" + +/* DISK BDOS FUNCTIONS */ + +/* General treatment: + * + * We use the "disk block number" fields in the FCB to store our file handle; + * this is a similar trick to that used by DOSPLUS, which stores its cluster + * number in there. It works if: + * + * a) sizeof(int) <= 8 bytes (64 bits). If it's more, this needs rewriting + * to use a hash table; + * b) the program never touches these bytes. Practically no CP/M program does. + * + * We store a "magic number" (0x00FD) in the first two bytes of this field, and + * if the number has been changed then we abort. + * + * nb: Since I wrote ZXCC, I have found that DOSPLUS uses 0x8080 as a magic + * number [well, actually this is an oversimplification, but a hypothetical + * program written against DOSPLUS would work with 0x8080]. Perhaps 0x8080 + * should be used instead. + * + * Format of the field: + * + * [--2 bytes--] magic number + * [--8 bytes--] file handle. 8 bytes reserved but only 4 currently used. + * [--2 bytes--] reserved. + * [--4 bytes--] file length. + */ + +#define MAGIC_OFFSET 0x10 +#define HANDLE_OFFSET 0x12 +#define LENGTH_OFFSET 0x1C + +cpm_word fcb_open(cpm_byte* fcb, cpm_byte* dma) +{ + char fname[CPM_MAXPATH]; + int handle; + int drv; + size_t l; + char* s; + DIR* dir; + + FCBENT(fcb); + + /* Don't support ambiguous filenames */ + if (redir_fcb2unix(fcb, fname)) FCBRET(0x09FF); + + redir_log_fcb(fcb); + + drv = fcb[0] & 0x7F; + if (!drv) drv = redir_cpmdrive; else --drv; + + if (fcb[0] & 0x80) /* Open directory */ + { + if (fcb[0x0C]) FCBRET(0x0BFF); /* Can't assign "floating" dir */ + + if (!memcmp(fcb + 1, ". ", 11)) + { + FCBRET(0); /* Opening "." */ + } + if (!memcmp(fcb + 1, ".. ", 11)) + { + l = strlen(redir_drive_prefix[drv]) - 1; + s = redir_drive_prefix[drv]; + while (--l > 0 && !strchr(DIRSEP, s[l])) + --l; + if (l == 0) FCBRET(0); /* "/" or "\" */ +#ifdef _WIN32 + if (s[l] == ':' && l < 2) FCBRET(0); /* "C:" */ +#endif + s[l + 1] = 0; + FCBRET(0); + } + /* Opening some other directory */ + + dir = opendir(fname); + if (!dir) FCBRET(0xFF); /* Not a directory */ + closedir(dir); + strcpy(redir_drive_prefix[drv], fname); + strcat(redir_drive_prefix[drv], "/"); + FCBRET(0); + } + + /* Note: Some programs (MAC is an example) don't close a file + * if they opened it just to do reading. MAC then reopens the + * file (which rewinds it); this causes FCB leaks under some + * DOS-based emulators */ + + handle = redir_ofile(fcb, fname); + //DBGMSGV("fcb_open('%s')\n", fname); + if (handle < 0 && redir_password_error()) + { + DBGMSGV("1st chance open failed on %s\n", fname); + redir_password_append(fname, dma); + DBGMSGV("Trying with %s\n", fname); + handle = redir_ofile(fcb, fname); + } + + if (handle == -1) + { + if (redir_password_error()) FCBRET(0x7FF); + FCBRET(0xFF); + } + fcb[MAGIC_OFFSET] = 0xFD; /* "Magic number" */ + fcb[MAGIC_OFFSET + 1] = 0x00; + + /* TODO: Should the magic number perhaps be 0x8080, as in DOSPLUS? */ + + redir_wrhandle(fcb + HANDLE_OFFSET, handle); + + redir_put_fcb_pos(fcb, fcb[0x0C] * 16384); + /* (v1.01) "seek" to beginning of extent, not file. + * This is necessary for the awful I/O code + * in LINK-80 to work + */ + + /* Get the file length */ + redir_wr32(fcb + LENGTH_OFFSET, zxlseek(handle, 0, SEEK_END)); + zxlseek(handle, 0, SEEK_SET); + + /* Set the last record byte count */ + if (fcb[0x20] == 0xFF) fcb[0x20] = fcb[LENGTH_OFFSET] & 0x7F; + + FCBRET(0); +} + +cpm_word fcb_close(cpm_byte* fcb) +{ + int handle, drv; + + FCBENT(fcb); + + if ((handle = redir_verify_fcb(fcb)) < 0) FCBRET(-1); + DBGMSGV(" (at 0x%lX)\n", zxlseek(handle, 0, SEEK_CUR)); + + if (fcb[0] & 0x80) /* Close directory */ + { + drv = fcb[0] & 0x7F; + if (!drv) drv = redir_cpmdrive; else drv--; +#ifdef __MSDOS__ + strcpy(redir_drive_prefix[drv] + 1, ":/"); +#else + strcpy(redir_drive_prefix[drv], "/"); +#endif + FCBRET(0); + } + + if (fcb[5] & 0x80) /* CP/M 3: Flush rather than close */ + { +#ifdef _WIN32 + BOOL b; + DBGMSGV("flush file #%i\n", handle); + b = FlushFileBuffers((HANDLE)handle); + if (!b) + DBGMSGV("failed to flush file #%i (Error=%lu): %s\n", handle, GetLastError(), GetErrorStr(GetLastError())); +#else + DBGMSGV("flush file #%i\n", handle); + sync(); +#endif + FCBRET(0); + } + +#ifdef _WIN32 + { + BOOL b; + DBGMSGV("close file #%i\n", handle); + b = CloseHandle((HANDLE)handle); + if (!b) + { + DBGMSGV("failed to close file #%i (Error=%lu): %s\n", handle, GetLastError(), GetErrorStr(GetLastError())); + FCBRET(0xFF); + } + } +#else + DBGMSGV("close file #%i\n", handle); + if (close(handle)) + { + DBGMSGV("failed to close file #%i (Error=%lu): %s\n", handle, errno, strerror(errno)); + FCBRET(0xFF); + } +#endif + + trackFile(NULL, fcb, handle); + + FCBRET(0); +} + +/* In theory, fcb_read() is supposed to be sequential access - the program + just reads one record after another and lets the OS worry about file + pointers. + + In practice, it isn't so easy. For example, DR's LINK-80 does seeks when + the file size gets above 8k, and SAVE rewinds the file by setting the + counter fields to 0. + + Seeking is done by relying on the following fields: + + ex (FCB+12) = (position / 16k) % 32 + s2 (FCB+14) = position / 512k + cr (FCB+32) = (position % 16k) / 128 + + TODO: Set rc to number of 80h-byte records in last extent: ie: + + length of file - (file ptr - (file ptr % 16384)) / 128 + + if >80h, let it be 80h + +*/ + +cpm_word fcb_read(cpm_byte* fcb, cpm_byte* dma) +{ + int handle; + int rv, n, rd_len; + long npos; + + FCBENT(fcb); + + if ((handle = redir_verify_fcb(fcb)) < 0) FCBRET(9); /* Invalid FCB */ + + /* The program may have mucked about with the counters, so + * do an lseek() to where it should be. */ + + npos = redir_get_fcb_pos(fcb); + zxlseek(handle, npos, SEEK_SET); + DBGMSGV(" (from 0x%lX)\n", zxlseek(handle, 0, SEEK_CUR)); + + /* Read in the required amount */ + +#ifdef _WIN32 + { + BOOL b; + DBGMSGV("read file #%i @ 0x%X, %i bytes\n", handle, dma - RAM, redir_rec_len); + b = ReadFile((HANDLE)handle, dma, redir_rec_len, (unsigned long*)(&rv), NULL); + if (!b) + { + DBGMSGV("failed to read file #%i (Error=%lu): %s\n", handle, GetLastError(), GetErrorStr(GetLastError())); + rv = -1; + } + } +#else + DBGMSGV("read file #%i @ 0x%X, %i bytes\n", handle, dma - RAM, redir_rec_len); + rv = read(handle, dma, redir_rec_len); + if (rv == -1) + DBGMSGV("failed to read file #%i (errno=%lu): %s\n", handle, errno, strerror(errno)); +#endif + + /* read() can corrupt buffer area following data read if length + * of data read is less than buffer. Clean it up. */ + if (rv == -1) + memset(dma, 0x00, redir_rec_len); + else + memset(dma + rv, 0x00, redir_rec_len - rv); + + /* rd_len = length supposedly read, bytes. Round to nearest 128 + * bytes. */ + rd_len = ((rv + 127) / 128) * 128; + + npos += rd_len; + + /* Write new file pointer into FCB */ + + redir_put_fcb_pos(fcb, npos); + + if (rv < 0) + { + DBGMSG("Ret: -1\n"); + FCBRET(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. + */ + + if (rd_len < redir_rec_len) /* eof */ + { + /* Pack from the size actually read up to the size we claim + * to have read */ + rd_len = rd_len * 2; /* rd_len already sector * 128, so * 2 to move to High byte */ + FCBRET(rd_len | 1); /* eof */ + } + + DBGMSGV("Ret: 0 (bytes read=%d)\n", rv); + FCBRET(0); +} + +cpm_word fcb_write(cpm_byte* fcb, cpm_byte* dma) +{ + int handle; + int rv; + long npos, len; + + FCBENT(fcb); + + if ((handle = redir_verify_fcb(fcb)) < 0) FCBRET(9); /* Invalid FCB */ + + /* Software write-protection */ + if (redir_ro_fcb(fcb)) FCBRET(0x02FF); + + /* Check for a seek */ + npos = redir_get_fcb_pos(fcb); + zxlseek(handle, npos, SEEK_SET); + + DBGMSGV(" (to %lX)\n", zxlseek(handle, 0, SEEK_CUR)); + +#ifdef _WIN32 + { + BOOL b; + DBGMSGV("write file #%i @ 0x%X, %i bytes\n", handle, dma - RAM, redir_rec_len); + b = WriteFile((HANDLE)handle, dma, redir_rec_len, (unsigned long*)(&rv), NULL); + if (!b) + { + DBGMSGV("failed to write file #%i (Error=%lu): %s\n", handle, GetLastError(), GetErrorStr(GetLastError())); + rv = -1; + } + } +#else + DBGMSGV("write file #%i @ 0x%X, %i bytes\n", handle, dma - RAM, redir_rec_len); + rv = write(handle, dma, redir_rec_len); + if (rv == -1) + DBGMSGV("failed to write file #%i (errno=%lu): %s\n", handle, errno, strerror(errno)); +#endif + npos += redir_rec_len; + + redir_put_fcb_pos(fcb, npos); + + /* Update the file length */ + len = redir_rd32(fcb + LENGTH_OFFSET); + if (len < npos) redir_wr32(fcb + LENGTH_OFFSET, npos); + + if (rv < 0) FCBRET(redir_xlt_err()); /* error */ + if (rv < redir_rec_len) FCBRET(1); /* disk full */ + FCBRET(0); +} + +cpm_word fcb_creat(cpm_byte* fcb, cpm_byte* dma) +{ + char fname[CPM_MAXPATH]; + int handle; + + FCBENT(fcb); + + releaseFCB(fcb); /* release existing fcb usage */ + + /* Don't support ambiguous filenames */ + if (redir_fcb2unix(fcb, fname)) FCBRET(0x09FF); + DBGMSGV("fcb_creat('%s')\n", fname); + + /* Software write-protection */ + if (redir_ro_fcb(fcb)) FCBRET(0x02FF); + + redir_log_fcb(fcb); + + if (fcb[0] & 0x80) + { + handle = mkdir(fname, 0x777); + if (handle) FCBRET(redir_xlt_err()); + FCBRET(0); + } + releaseFile(fname); /* purge any open handles for this file */ + +#ifdef _WIN32 + DBGMSGV("create file '%s'\n", fname); + handle = (int)CreateFile(fname, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (handle == HFILE_ERROR) + { + DBGMSGV("failed to create file '%s' (Error=%lu): %s\n", fname, GetLastError(), GetErrorStr(GetLastError())); + FCBRET(0xFF); + } +#else + DBGMSGV("create file '%s'\n", fname); + handle = open(fname, O_RDWR | O_CREAT | O_EXCL | O_BINARY, + S_IREAD | S_IWRITE); + if (handle < 0) + { + DBGMSGV("failed to create file '%s' (Error=%lu): %s\n", fname, errno, strerror(errno)); + FCBRET(0xFF); + } +#endif + + trackFile(fname, fcb, handle); /* track new file */ + + fcb[MAGIC_OFFSET] = 0xFD; /* "Magic number" */ + fcb[MAGIC_OFFSET + 1] = 0; + redir_wrhandle(fcb + HANDLE_OFFSET, handle); + redir_wr32(fcb + LENGTH_OFFSET, 0); + redir_put_fcb_pos(fcb, 0); /* Seek to 0 */ + +#ifdef __MSDOS__ + if (redir_drdos && (fcb[6] & 0x80)) + { + cpm_word rights = redir_drdos_pwmode(dma[9]); + redir_drdos_put_rights(fname, dma, rights | 0x8000); + } +#endif + + FCBRET(0); +} + +cpm_word fcb_rename(cpm_byte* fcb, cpm_byte* dma) +{ + char ofname[CPM_MAXPATH], nfname[CPM_MAXPATH]; + cpm_byte sdrv, ddrv; + + FCBENT(fcb); + + releaseFCB(fcb); /* release any file associated with the fcb */ + redir_log_fcb(fcb); + + /* Don't support ambiguous filenames */ + if (redir_fcb2unix(fcb, ofname)) FCBRET(0x09FF); + if (redir_fcb2unix(fcb + 0x10, nfname)) FCBRET(0x09FF); + + /* Software write-protection */ + if (redir_ro_fcb(fcb)) FCBRET(0x02FF); + + if (fcb[0] & 0x80) FCBRET(0xFF); /* Can't rename directories */ + + /* Check we're not trying to rename across drives. Otherwise, it + * might let you do it if the two "drives" are on the same disk. */ + + sdrv = fcb[0] & 0x7F; if (!sdrv) sdrv = redir_cpmdrive + 1; + ddrv = fcb[0x10] & 0x7F; if (!ddrv) ddrv = redir_cpmdrive + 1; + + if (sdrv != ddrv) FCBRET(0xFF); + + DBGMSGV("rename '%s' to '%s'\n", ofname, nfname); + + releaseFile(ofname); /* need ofname and nfname to be closed */ + releaseFile(nfname); + if (rename(ofname, nfname)) + { + if (redir_password_error()) + { + redir_password_append(ofname, dma); + if (!rename(ofname, nfname)) FCBRET(0); + if (redir_password_error()) FCBRET(0x7FF); + } + FCBRET(0xFF); + } + + FCBRET(0); +} + +cpm_word fcb_randrd(cpm_byte* fcb, cpm_byte* dma) +{ + int handle; + int rv, n, rd_len; + dword offs = redir_rd24(fcb + 0x21) * 128; + + FCBENT(fcb); + + if ((handle = redir_verify_fcb(fcb)) < 0) FCBRET(9); /* Invalid FCB */ + + if (zxlseek(handle, offs, SEEK_SET) < 0) FCBRET(6); /* bad record no. */ + +#ifdef _WIN32 + { + BOOL b; + DBGMSGV("read file #%i @ 0x%X, %i bytes\n", handle, dma - RAM, redir_rec_len); + b = ReadFile((HANDLE)handle, dma, redir_rec_len, (unsigned long*)(&rv), NULL); + if (!b) + { + DBGMSGV("failed to read file #%i (Error=%lu): %s\n", handle, GetLastError(), GetErrorStr(GetLastError())); + rv = -1; + } + } +#else + DBGMSGV("read file #%i @ 0x%X, %i bytes\n", handle, dma - RAM, redir_rec_len); + rv = read(handle, dma, redir_rec_len); + if (rv == -1) + DBGMSGV("failed to read file #%i (errno=%lu): %s\n", handle, errno, strerror(errno)); +#endif + + // read() can corrupt buffer area following data read if length + // of data read is less than buffer. Clean it up. + if (rv == -1) + memset(dma, 0x00, redir_rec_len); + else + memset(dma + rv, 0x00, redir_rec_len - rv); + + zxlseek(handle, offs, SEEK_SET); + + redir_put_fcb_pos(fcb, offs); + + if (rv < 0) FCBRET(redir_xlt_err()); /* Error */ + + rd_len = ((rv + 127) / 128) * 128; + + /* 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 = rd_len * 2; /* rd_len already sector * 128, so * 2 to move to High byte */ + DBGMSGV("Ret: 0x%x\n", rd_len | 1); + FCBRET(rd_len | 1); /* eof */ + } + + FCBRET(0); +} + +cpm_word fcb_randwr(cpm_byte* fcb, cpm_byte* dma) +{ + int handle; + int rv; + dword offs = redir_rd24(fcb + 0x21) * 128; + dword len; + + FCBENT(fcb); + + if ((handle = redir_verify_fcb(fcb)) < 0) FCBRET(9); /* Invalid FCB */ + /* Software write-protection */ + if (redir_ro_fcb(fcb)) FCBRET(0x02FF); + + if (zxlseek(handle, offs, SEEK_SET) < 0) FCBRET(6); /* bad record no. */ + +#ifdef _WIN32 + { + BOOL b; + DBGMSGV("write file #%i @ 0x%X, %i bytes\n", handle, dma - RAM, redir_rec_len); + b = WriteFile((HANDLE)handle, dma, redir_rec_len, (unsigned long*)(&rv), NULL); + if (!b) + { + DBGMSGV("failed to write file #%i (Error=%lu): %s\n", handle, GetLastError(), GetErrorStr(GetLastError())); + rv = -1; + } + } +#else + DBGMSGV("write file #%i @ 0x%X, %i bytes\n", handle, dma - RAM, redir_rec_len); + rv = write(handle, dma, redir_rec_len); + if (rv == -1) + DBGMSGV("failed to write file #%i (errno=%lu): %s\n", handle, errno, strerror(errno)); +#endif + zxlseek(handle, offs, SEEK_SET); + redir_put_fcb_pos(fcb, offs); + + if (rv < 0) FCBRET(redir_xlt_err()); /* Error */ + /* Update the file length */ + 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); + /* WBW: Not actually a bug. Causes problems w/ GENCPM */ + // fcb[0x20] = (offs + rv) % 256; + } + + if (rv < redir_rec_len) FCBRET(1); /* disk full */ + FCBRET(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) +{ + FCBENT(fcb); + FCBRET(fcb_randwr(fcb, dma)); +} +#else +/* Write random with 0 fill */ +cpm_word fcb_randwz(cpm_byte* fcb, cpm_byte* dma) +{ + dword offs, len; + int handle, rl, rv; + cpm_byte zerorec[128]; + + FCBENT(fcb); + + if ((handle = redir_verify_fcb(fcb)) < 0) FCBRET(9); /* Invalid FCB */ + /* Software write-protection */ + if (redir_ro_fcb(fcb)) FCBRET(0x02FF); + + offs = redir_rd24(fcb + 0x21) * 128; + len = redir_rd32(fcb + LENGTH_OFFSET); + + redir_wr32(fcb + LENGTH_OFFSET, offs); + + memset(zerorec, 0, sizeof(zerorec)); + + while (len < offs) + { + memset(zerorec, 0, sizeof(zerorec)); + + rl = sizeof(zerorec); + if ((offs - len) < sizeof(zerorec)) rl = offs - len; +#ifdef _WIN32 + { + BOOL b; + DBGMSGV("write file #%i (zeroes), %i bytes\n", handle, redir_rec_len); + b = WriteFile((HANDLE)handle, zerorec, rl, (unsigned long*)(&rv), NULL); + if (!b) + { + DBGMSGV("failed to write file #%i (Error=%lu): %s\n", handle, GetLastError(), GetErrorStr(GetLastError())); + rv = -1; + } + } +#else + DBGMSGV("write file #%i (zeroes), %i bytes\n", handle, redir_rec_len); + rv = write(handle, zerorec, rl); + if (rv == -1) + DBGMSGV("failed to write file #%i (errno=%lu): %s\n", handle, errno, strerror(errno)); +#endif + if (rv >= 0) len += rv; + + if (rv < rl) + { + redir_wr32(fcb + LENGTH_OFFSET, len); + FCBRET(redir_xlt_err()); + } + } + redir_wr32(fcb + LENGTH_OFFSET, offs); + + FCBRET(fcb_randwr(fcb, dma)); +} +#endif + +cpm_word fcb_tell(cpm_byte* fcb) +{ + int handle; + off_t rv; + + FCBENT(fcb); + + if ((handle = redir_verify_fcb(fcb)) < 0) FCBRET(9); /* Invalid FCB */ + + rv = zxlseek(handle, 0, SEEK_CUR); + + if (rv < 0) FCBRET(0xFF); + + rv = rv >> 7; + fcb[0x21] = rv & 0xFF; + fcb[0x22] = (rv >> 8) & 0xFF; + fcb[0x23] = (rv >> 16) & 0xFF; + FCBRET(0); +} + +cpm_word fcb_stat(cpm_byte* fcb) +{ + char fname[CPM_MAXPATH]; + struct stat st; + int rv; + + FCBENT(fcb); + + /* Don't support ambiguous filenames */ + if (redir_fcb2unix(fcb, fname)) FCBRET(0x09FF); + + DBGMSGV("stat '%s', FCB=%0.4X\n", fname, fcb - RAM); + rv = stat(fname, &st); + if (rv < 0) + { + DBGMSGV("failed to stat file '%s' (errno=%lu): %s\n", fname, errno, strerror(errno)); + FCBRET(0xFF); + } + + redir_wr24(fcb + 0x21, (st.st_size + 127) / 128); + + FCBRET(0); +} + +cpm_word fcb_multirec(cpm_byte rc) +{ + if (rc < 1 || rc > 128) return 0xFF; + + redir_rec_multi = rc; + redir_rec_len = 128 * rc; + DBGMSGV("Set read/write to %d bytes\n", redir_rec_len); + return 0; +} + +cpm_word fcb_date(cpm_byte* fcb) +{ + char fname[CPM_MAXPATH]; + struct stat st; + int rv; + + FCBENT(fcb); + + /* 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)) FCBRET(0x09FF); + + DBGMSGV("stat '%s', FCB=%0.4X\n", fname, fcb - RAM); + rv = stat(fname, &st); + if (rv < 0) + { + DBGMSGV("failed to stat file '%s' (errno=%lu): %s\n", fname, errno, strerror(errno)); + FCBRET(0xFF); + } + + redir_wr32(fcb + 0x18, redir_cpmtime(st.st_atime)); + redir_wr32(fcb + 0x1C, redir_cpmtime(st.st_ctime)); + + fcb[0x0C] = redir_cpm_pwmode(redir_drdos_get_rights(fname)); + FCBRET(0); +} + +cpm_word fcb_trunc(cpm_byte* fcb, cpm_byte* dma) +{ + char fname[CPM_MAXPATH]; + dword offs = redir_rd24(fcb + 0x21) * 128; + + FCBENT(fcb); + + releaseFCB(fcb); /* CP/M requires truncated files be closed */ + /* Don't support ambiguous filenames */ + if (redir_fcb2unix(fcb, fname)) FCBRET(0x09FF); + + /* Software write-protection */ + if (redir_ro_fcb(fcb)) FCBRET(0x02FF); + + releaseFile(fname); /* after truncate open files are invalid */ + redir_log_fcb(fcb); + + DBGMSGV("truncate file '%s' at %lu\n", fname, offs); + if (truncate(fname, offs)) + { + DBGMSGV("failed to truncate file '%s' (errno=%lu): %s\n", fname, errno, strerror(errno)); + if (redir_password_error()) + { + redir_password_append(fname, dma); + DBGMSGV("truncate file '%s' w/ password at %lu\n", fname, offs); + if (!truncate(fname, offs)) FCBRET(0); + DBGMSGV("failed to truncate file '%s' (errno=%lu): %s\n", fname, errno, strerror(errno)); + } + FCBRET(redir_xlt_err()); + } + FCBRET(0); +} + +cpm_word fcb_sdate(cpm_byte* fcb, cpm_byte* dma) +{ + char fname[CPM_MAXPATH]; + struct utimbuf buf; + + FCBENT(fcb); + + buf.actime = redir_unixtime(dma); + buf.modtime = redir_unixtime(dma + 4); + + /* Don't support ambiguous filenames */ + if (redir_fcb2unix(fcb, fname)) FCBRET(0x09FF); + + /* Software write-protection */ + if (redir_ro_fcb(fcb)) FCBRET(0x02FF); + + redir_log_fcb(fcb); + + DBGMSGV("utime file '%s'\n", fname); + if (utime(fname, &buf)) + { + DBGMSGV("failed to utime file '%s' (Error=%lu): %s\n", fname, errno, strerror(errno)); + if (redir_password_error()) + { + redir_password_append(fname, dma); + DBGMSGV("utime file '%s' w/ password\n", fname); + if (!utime(fname, &buf)) FCBRET(0); + DBGMSGV("failed to utime file '%s' (Error=%lu): %s\n", fname, errno, strerror(errno)); + } + FCBRET(redir_xlt_err()); + } + FCBRET(0); +} + +cpm_word fcb_chmod(cpm_byte* fcb, cpm_byte* dma) +{ + char fname[CPM_MAXPATH]; + struct stat st; + int handle, wlen, omode; + long offs, newoffs; + cpm_byte zero[128]; + + FCBENT(fcb); + + /* Don't support ambiguous filenames */ + if (redir_fcb2unix(fcb, fname)) FCBRET(0x09FF); + + /* Software write-protection */ + if (redir_ro_fcb(fcb)) FCBRET(0x02FF); + + redir_log_fcb(fcb); + + DBGMSGV("stat '%s', FCB=%0.4X\n", fname, fcb - RAM); + if (stat(fname, &st)) + { + DBGMSGV("failed to stat file '%s' (errno=%lu): %s\n", fname, errno, strerror(errno)); + FCBRET(redir_xlt_err()); + } + +#ifdef __MSDOS__ + omode = 0; + if (fcb[9] & 0x80) omode |= 1; + if (fcb[10] & 0x80) omode |= 4; + if (!(fcb[11] & 0x80)) omode |= 0x20; + + if (_chmod(fname, 1, omode) < 0) + { + if (redir_password_error()) + { + redir_password_append(fname, dma); + if (_chmod(fname, 1, omode) >= 0) FCBRET(0); + } + FCBRET(redir_xlt_err()); + } +#elif defined (_WIN32) + omode = 0; + + if (fcb[9] & 0x80) omode |= FILE_ATTRIBUTE_READONLY; + if (fcb[10] & 0x80) omode |= FILE_ATTRIBUTE_SYSTEM; + if (!(fcb[11] & 0x80)) omode |= FILE_ATTRIBUTE_ARCHIVE; + + if (!omode) omode = FILE_ATTRIBUTE_NORMAL; + + { + BOOL b; + DBGMSGV("set attributes file '%s', FCB=%0.4X\n", fname, fcb - RAM); + b = SetFileAttributes(fname, omode); + if (!b) + { + DBGMSGV("failed to set attributes file '%s' (Error=%lu): %s\n", fname, GetLastError(), GetErrorStr(GetLastError())); + FCBRET(redir_xlt_err()); + } + } +#else + omode = st.st_mode; + if (fcb[9] & 0x80) /* Read-only */ + { + st.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH); + } + else st.st_mode |= S_IWUSR; + + if (omode != st.st_mode) + { + DBGMSGV("chmod '%s', FCB=%0.4X\n", fname, fcb - RAM); + if (chmod(fname, st.st_mode)) + { + DBGMSGV("failed to chmod file '%s' (errno=%lu): %s\n", fname, errno, strerror(errno)); + FCBRET(redir_xlt_err()); + } + } +#endif + + if (fcb[6] & 0x80) /* Set exact size */ + { + DBGMSGV("stat '%s', FCB=%0.4X\n", fname, fcb - RAM); + if (stat(fname, &st)) + { + DBGMSGV("failed to stat file '%s' (errno=%lu): %s\n", fname, errno, strerror(errno)); + FCBRET(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 */ + DBGMSGV("open '%s', FCB=%0.4X\n", fname, fcb - RAM); + handle = open(fname, O_RDWR | O_BINARY); + if (handle < 0) + { + DBGMSGV("failed to open file '%s' (errno=%lu): %s\n", fname, errno, strerror(errno)); + FCBRET(redir_xlt_err()); + } + DBGMSGV("file '%s' opened at #%i\n", fname, handle); + + newoffs = offs = ((st.st_size + 127) / 128) * 128; + if (fcb[0x20] & 0x7F) + { + newoffs -= fcb[0x20] & 0x7f; + //newoffs -= (0x80 - (fcb[0x20] & 0x7F)); + } + if (newoffs == st.st_size) + { + ; /* Nothing to do! */ + } + else if (newoffs < st.st_size) + { + DBGMSGV("ftruncate file #%i at %lu\n", handle, newoffs); + if (ftruncate(handle, newoffs)) + { + DBGMSGV("failed to ftruncate file #%i (errno=%lu): %s\n", handle, errno, strerror(errno)); + close(handle); + FCBRET(redir_xlt_err()); + } + } + else while (newoffs > st.st_size) + { + wlen = newoffs - st.st_size; + if (wlen > 0x80) wlen = 0x80; + memset(zero, 0x1A, sizeof(zero)); + DBGMSGV("write file #%i (zeroes), %lu bytes\n", handle, wlen); + if (write(handle, zero, wlen) < wlen) + { + DBGMSGV("failed to write file #%i (errno=%lu): %s\n", handle, errno, strerror(errno)); + close(handle); + FCBRET(redir_xlt_err()); + } + st.st_size += wlen; + } + close(handle); + } + FCBRET(0); +} + +cpm_word fcb_setpwd(cpm_byte* fcb, cpm_byte* dma) +{ +#ifdef __MSDOS__ + char fname[CPM_MAXPATH]; + cpm_word rv; + + FCBENT(fcb); + + /* Don't support ambiguous filenames */ + if (redir_fcb2unix(fcb, fname)) FCBRET(0x09FF); + + /* Software write-protection */ + if (redir_ro_fcb(fcb)) FCBRET(0x02FF); + + redir_log_fcb(fcb); + + rv = redir_drdos_put_rights(fname, dma, redir_drdos_pwmode(fcb[0x0c])); + if (rv || !(fcb[0x0c] & 1)) FCBRET(rv); + FCBRET(redir_drdos_put_rights(fname, dma, redir_drdos_pwmode(fcb[0x0c]) | 0x8000)); +#else + FCBRET(0xFF); /* Unix doesn't do this */ +#endif +} + +cpm_word fcb_getlbl(cpm_byte drv) +{ + DBGMSG("fcb_getlbl()\n"); +#ifdef __MSDOS__ + if (redir_drdos) return 0xA1; /* Supports passwords & Update stamps */ + return 0x21; /* Update stamps only */ +#else + return 0x61; /* Update & Access stamps */ +#endif +} + +cpm_word fcb_setlbl(cpm_byte* fcb, cpm_byte* dma) +{ + /* I am not letting CP/M fiddle with the host's FS settings - even if they + * could be altered, which they mostly can't. */ + + return 0x03FF; +} + +cpm_word fcb_defpwd(cpm_byte* pwd) +{ +#ifdef __MSDOS__ + union REGS r; + struct SREGS s; + + if (pwd[0] == 0 || pwd[0] == ' ') + { + redir_passwd[0] = 0; + } + else memcpy(redir_passwd, pwd, 8); + if (redir_drdos) + { + dosmemput(pwd, 8, __tb); + r.w.ax = 0x4454; + r.w.dx = __tb & 0x0F; + s.ds = __tb >> 4; + intdosx(&r, &r, &s); + } + +#endif + return 0; +} diff --git a/Tools/unix/zxcc/cpmredir.h b/Tools/unix/zxcc/cpmredir.h new file mode 100644 index 00000000..40810159 --- /dev/null +++ b/Tools/unix/zxcc/cpmredir.h @@ -0,0 +1,150 @@ +/* + 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 the public interface to CPMREDIR. +*/ + +#ifndef CPMREDIR_H_INCLUDED + +#define CPMREDIR_H_INCLUDED 16-11-1998 + +/* The "cpm_byte" must be exactly 8 bits. + The "cpm_word" must be exactly 16 bits. */ + +typedef unsigned char cpm_byte; +typedef unsigned short cpm_word; + +/* Maximum length of a directory path */ +#ifdef _POSIX_PATH_MAX + #define CPM_MAXPATH _POSIX_PATH_MAX +#else + #ifdef _MAX_PATH + #define CPM_MAXPATH _MAX_PATH + #else + #define CPM_MAXPATH 260 + #endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + /* Initialise this library. Call this function first. + * + * Returns 0 if failed to initialise. + */ + int fcb_init(void); + + /* Deinitialise the library. */ + + void fcb_deinit(void); + + /* 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); + + /* 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: + * Returns 1 if OK, 0 if requested drive not available. + * + * NB: It is important that the localname should have a trailing + * directory separator! + */ + + int xlt_map(int drive, char* localdir); + + /* + * This revokes a mapping. No check is made whether CP/M has files open + * on the drive or not. + */ + + int xlt_umap(int drive); + + /* Find out if a drive is mapped, and if so to what directory */ + + char* xlt_getcwd(int drive); + + /* BDOS functions. Eventually this should handle all disc-related BDOS + * functions. + * + * I am assuming that your emulator has the CP/M RAM in its normal address + * space, accessible as a range 0-64k. If this is not the case + * (eg: you are emulating banked memory, or using a segmented architecture) + * you will have to use "copy in and copy out" techniques. The "fcb" area + * must be 36 bytes long; the "dma" area should be 128 * the value set + * in fcb_multirec() [default is 1, so 128 bytes]. + * + */ + + cpm_byte fcb_reset(void); /* 0x0D */ + cpm_word fcb_drive(cpm_byte drv); /* 0x0E */ + cpm_word fcb_open(cpm_byte* fcb, cpm_byte* dma); /* 0x0F */ + cpm_word fcb_close(cpm_byte* fcb); /* 0x10 */ + cpm_word fcb_find1(cpm_byte* fcb, cpm_byte* dma); /* 0x11 */ + cpm_word fcb_find2(cpm_byte* fcb, cpm_byte* dma); /* 0x12 */ + cpm_word fcb_unlink(cpm_byte* fcb, cpm_byte* dma); /* 0x13 */ + cpm_word fcb_read(cpm_byte* fcb, cpm_byte* dma); /* 0x14 */ + cpm_word fcb_write(cpm_byte* fcb, cpm_byte* dma); /* 0x15 */ + cpm_word fcb_creat(cpm_byte* fcb, cpm_byte* dma); /* 0x16 */ + cpm_word fcb_rename(cpm_byte* fcb, cpm_byte* dma); /* 0x17 */ + cpm_word fcb_logvec(void); /* 0x18 */ + cpm_byte fcb_getdrv(void); /* 0x19 */ + /* DMA is a parameter to routines, not a separate call */ + cpm_word fcb_getalv(cpm_byte* alv, cpm_word max); /* 0x1B */ + /* Get alloc vector: caller must provide space and say how big it is. */ + cpm_word fcb_rodisk(void); /* 0x1C */ + cpm_word fcb_rovec(void); /* 0x1D */ + cpm_word fcb_chmod(cpm_byte* fcb, cpm_byte* dma); /* 0x1E */ + cpm_word fcb_getdpb(cpm_byte* dpb); /* 0x1F */ + cpm_byte fcb_user(cpm_byte usr); /* 0x20 */ + cpm_word fcb_randrd(cpm_byte* fcb, cpm_byte* dma); /* 0x21 */ + cpm_word fcb_randwr(cpm_byte* fcb, cpm_byte* dma); /* 0x22 */ + cpm_word fcb_stat(cpm_byte* fcb); /* 0x23 */ + cpm_word fcb_tell(cpm_byte* fcb); /* 0x24 */ + cpm_word fcb_resro(cpm_word bitmap); /* 0x25 */ + /* Access Drives and Free Drives are not supported. */ + cpm_word fcb_randwz(cpm_byte* fcb, cpm_byte* dma); /* 0x28 */ + /* Record locking calls not supported (though they could be) */ + cpm_word fcb_multirec(cpm_byte rc); /* 0x2C */ + /* Set hardware error action must be done by caller */ + cpm_word fcb_dfree(cpm_byte drive, cpm_byte* dma); /* 0x2E */ + cpm_word fcb_sync(cpm_byte flag); /* 0x30 */ + cpm_word fcb_purge(void); /* 0x62 */ + cpm_word fcb_trunc(cpm_byte* fcb, cpm_byte* dma); /* 0x63 */ + cpm_word fcb_setlbl(cpm_byte* fcb, cpm_byte* dma); /* 0x64 */ + cpm_word fcb_getlbl(cpm_byte drive); /* 0x65 */ + cpm_word fcb_date(cpm_byte* fcb); /* 0x66 */ + cpm_word fcb_setpwd(cpm_byte* fcb, cpm_byte* dma); /* 0x67 */ + cpm_word fcb_defpwd(cpm_byte* pwd); /* 0x6A */ + cpm_word fcb_sdate(cpm_byte* fcb, cpm_byte* dma); /* 0x74 */ + cpm_word fcb_parse(char* txt, cpm_byte* fcb); /* 0x98 */ + + /* fcb_parse returns length of filename parsed, 0 if EOL, 0xFFFF if error */ + +#ifdef __cplusplus +} +#endif + +#endif /* def CPMREDIR_H_INCLUDED */ diff --git a/Tools/unix/zxcc/dirent.c b/Tools/unix/zxcc/dirent.c new file mode 100644 index 00000000..1cdce1cb --- /dev/null +++ b/Tools/unix/zxcc/dirent.c @@ -0,0 +1,122 @@ +/* + + Implementation of POSIX directory browsing functions and types for Win32. + + Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) + History: Created March 1997. Updated June 2003 and July 2012. + Rights: See end of file. + +*/ +#pragma warning(disable : 4996) +#include "dirent.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + DIR* opendir(const char* name) { + DIR* dir = 0; + + if (name && name[0]) { + size_t base_length = strlen(name); + const char* all = /* search pattern must end with suitable wildcard */ + strchr("/\\", name[base_length - 1]) ? "*" : "/*"; + + if ((dir = (DIR*)malloc(sizeof * dir)) != 0 && + (dir->name = (char*)malloc(base_length + strlen(all) + 1)) != 0) { + strcat(strcpy(dir->name, name), all); + + if ((dir->handle = + (handle_type)_findfirst(dir->name, &dir->info)) != -1) { + dir->result.d_name = 0; + } + else /* rollback */ + { + free(dir->name); + free(dir); + dir = 0; + } + } + else /* rollback */ + { + free(dir); + dir = 0; + errno = ENOMEM; + } + } + else { + errno = EINVAL; + } + + return dir; + } + + int closedir(DIR* dir) { + int result = -1; + + if (dir) { + if (dir->handle != -1) { + result = _findclose(dir->handle); + } + + free(dir->name); + free(dir); + } + + if (result == -1) /* map all errors to EBADF */ + { + errno = EBADF; + } + + return result; + } + + struct dirent* readdir(DIR* dir) { + struct dirent* result = 0; + + if (dir && dir->handle != -1) { + if (!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) { + result = &dir->result; + result->d_name = dir->info.name; + } + } + else { + errno = EBADF; + } + + return result; + } + + void rewinddir(DIR* dir) { + if (dir && dir->handle != -1) { + _findclose(dir->handle); + dir->handle = (handle_type)_findfirst(dir->name, &dir->info); + dir->result.d_name = 0; + } + else { + errno = EBADF; + } + } + +#ifdef __cplusplus +} +#endif + +/* + + Copyright Kevlin Henney, 1997, 2003, 2012. All rights reserved. + + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose is hereby granted without fee, provided + that this copyright and permissions notice appear in all copies and + derivatives. + + This software is supplied "as is" without express or implied warranty. + + But that said, if there are any problems please get in touch. + +*/ \ No newline at end of file diff --git a/Tools/unix/zxcc/dirent.h b/Tools/unix/zxcc/dirent.h new file mode 100644 index 00000000..7db1a3ee --- /dev/null +++ b/Tools/unix/zxcc/dirent.h @@ -0,0 +1,58 @@ +#ifndef DIRENT_INCLUDED +#define DIRENT_INCLUDED + +/* + + Declaration of POSIX directory browsing functions and types for Win32. + + Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) + History: Created March 1997. Updated June 2003. + Rights: See end of file. + +*/ + +#include /* _findfirst and _findnext set errno iff they return -1 */ + +#ifdef __cplusplus +extern "C" +{ +#endif + + struct dirent { + char *d_name; + }; + + typedef ptrdiff_t handle_type; /* C99's intptr_t not sufficiently portable */ + + typedef struct { + handle_type handle; /* -1 for failed rewind */ + struct _finddata_t info; + struct dirent result; /* d_name null iff first time */ + char *name; /* null-terminated char string */ + } DIR; + + DIR *opendir(const char *); + int closedir(DIR *); + struct dirent *readdir(DIR *); + void rewinddir(DIR *); + + /* + + Copyright Kevlin Henney, 1997, 2003. All rights reserved. + + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose is hereby granted without fee, provided + that this copyright and permissions notice appear in all copies and + derivatives. + + This software is supplied "as is" without express or implied warranty. + + But that said, if there are any problems please get in touch. + + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Tools/unix/zx/drdos.c b/Tools/unix/zxcc/drdos.c similarity index 59% rename from Tools/unix/zx/drdos.c rename to Tools/unix/zxcc/drdos.c index 97bd583c..f62a3a5c 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\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/track.c b/Tools/unix/zxcc/track.c new file mode 100644 index 00000000..6b961e31 --- /dev/null +++ b/Tools/unix/zxcc/track.c @@ -0,0 +1,185 @@ +/* + + 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" + +/* 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. +*/ + +/* + * The FILETRACKER functionality was implemented primarily because + * MSDOS file interface does not allow opening files in shared mode. + * This port of zxcc deprecates MSDOS and uses WIN32 API calls to handle + * all file I/O. So, this means that FILETRACKER is now optional for + * for Windows as well as Unix. I have found some edge cases where + * FILETRACKER caused a CP/M program to misbehave. Specifically, ZSM4 + * reuses FCBs if files are included and does it such a way that the + * FILETRACKER is unable to solve the problem. For maximum + * compatibility, FILETRACKER may now be left off with the implication + * that a lot of file handles will be left open. + */ + +#ifdef FILETRACKER + +#include "cpmint.h" + +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; + DBGMSGV("releaseFile: \"%s\"\n", fname); + while (s->next) + if (strcmp(s->next->fname, fname) == 0) { + DBGMSGV(" closing file #%i: \"%s\"\n", s->next->handle, s->next->fname); +#ifdef _WIN32 + { + BOOL b; + b = CloseHandle((HANDLE)s->next->handle); + if (!b) + DBGMSGV(" failed to close file #%i (Error=%lu): %s\n", s->next->handle, GetLastError(), GetErrorStr(GetLastError())); + } +#else + if (close(s->next->handle)) + DBGMSGV(" failed to close file #%i (errno=%lu): %s\n", s->next->handle, errno, strerror(errno)); +#endif + s->next = rmHandle(s->next); + } + else + s = s->next; +} + +int trackFile(char* fname, void* fcb, int fd) { + track_t* s = (track_t*)&openFiles; + DBGMSGV("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) { + DBGMSGV(" closing file #%i: \"%s\"\n", s->next->handle, s->next->fname); +#ifdef _WIN32 + { + BOOL b; + b = CloseHandle((HANDLE)s->next->handle); + if (!b) + DBGMSGV(" failed to close file #%i (Error=%lu): %s\n", s->next->handle, GetLastError(), GetErrorStr(GetLastError())); + } +#else + if (close(s->next->handle)) + DBGMSGV(" failed to close file #%i (errno=%lu): %s\n", s->next->handle, errno, strerror(errno)); +#endif + } + DBGMSGV(" 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/zxcc/util.c b/Tools/unix/zxcc/util.c new file mode 100644 index 00000000..e26fa0db --- /dev/null +++ b/Tools/unix/zxcc/util.c @@ -0,0 +1,484 @@ +/* + + 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 miscellaneous utility functions. +*/ + +#include "cpmint.h" + +#ifdef _WIN32 + +char* GetErrorStr(dword dwErr) +{ + LPVOID lpMsgBuf; + static char ErrStr[256] = ""; + + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_MAX_WIDTH_MASK, + NULL, + dwErr, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&lpMsgBuf, + sizeof(ErrStr), NULL); + + strncpy(ErrStr, lpMsgBuf, sizeof(ErrStr)); + + LocalFree(lpMsgBuf); + + return ErrStr; +} + +#endif + +char* whence(int wh) +{ + switch (wh) + { + case SEEK_SET: return("SEEK_SET"); + case SEEK_CUR: return("SEEK_CUR"); + case SEEK_END: return("SEEK_END"); + default: return("SEEK_???"); + } +} + +/* In debug mode, lseek()s can be traced. */ + +long zxlseek(int fd, long offset, int wh) +{ +#ifdef _WIN32 + + long v; + DBGMSGV("seek on file #%i to 0x%lX using %s\n", fd, offset, whence(wh)); + v = SetFilePointer((HANDLE)fd, offset, NULL, wh); + if (v != INVALID_SET_FILE_POINTER) return v; + DBGMSGV("seek failed (Error=%lu): %s\n", GetLastError(), GetErrorStr(GetLastError())); + return -1; + +#else + + DBGMSGV("seek on #%i to 0x%lX using %s\n", fd, offset, whence(wh)); + long v = lseek(fd, offset, wh); + if (v >= 0) return v; + DBGMSGV("seek failed (errno=%lu): %s\n", errno, strerror(errno)); + return -1; + +#endif +} + +#ifdef DEBUG + +void redir_showfcb(cpm_byte* fd) +{ + int n; + + for (n = 0; n < 32; n++) + { + if (!n || n >= 12) printf("%02x ", fd[n]); + else printf("%c", fd[n] & 0x7F); + } + printf("\n"); +} + +#endif + +/* Get the "sequential access" file pointer out of an FCB */ + +long redir_get_fcb_pos(cpm_byte* fcb) +{ + long npos; + + npos = 524288L * fcb[0x0E]; /* S2 */ + npos += 16384L * fcb[0x0C]; /* Extent */ + npos += 128L * fcb[0x20]; /* Record */ + + return npos; +} + +void redir_put_fcb_pos(cpm_byte* fcb, long npos) +{ + fcb[0x20] = (npos / 128) % 128; /* Record */ + fcb[0x0C] = (npos / 16384) % 32; /* Extent */ + fcb[0x0E] = (npos / 524288L) % 64; /* S2 */ +} + +/* + * find a filename that works. + * note that this is where we handle the case sensitivity/non-case sensitivity + * horror. + * the name that is passed in should be in lower case. + * we'll modify it to the first one that matches + */ +void swizzle(char* fullpath) +{ + struct stat ss; + char* slash; + DIR* dirp; + struct dirent* dentry; + + /* short circuit if ok */ + if (stat(fullpath, &ss) == 0) { + return; + } + + slash = strrchr(fullpath, '/'); + if (!slash) { + return; + } + *slash = '\0'; + dirp = opendir(fullpath); + *slash = '/'; + while ((dentry = readdir(dirp)) != NULL) { + if (strcasecmp(dentry->d_name, slash + 1) == 0) { + strcpy(slash + 1, dentry->d_name); + break; + } + } + closedir(dirp); +} + +/* 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) +{ + int n, q, drv, ddrv; + char s[2]; + char buf[256]; + + s[1] = 0; + q = 0; + drv = fcb[0] & 0x7F; + if (drv == '?') drv = 0; + + ddrv = fcb[0] & 0x7F; + if (ddrv < 0x1F) ddrv += '@'; + + if (!drv) strcpy(fname, redir_drive_prefix[redir_cpmdrive]); + else strcpy(fname, redir_drive_prefix[drv - 1]); + + for (n = 1; n < 12; n++) + { + s[0] = (fcb[n] & 0x7F); + if (s[0] == '?') q = 1; + if (isupper(s[0])) s[0] = tolower(s[0]); + if (s[0] != ' ') + { + if (n == 9) strcat(fname, "."); + strcat(fname, s); + } + } + + sprintf(buf, "'%c:%-8.8s.%-3.3s' --> '%s'", ddrv, fcb + 1, fcb + 9, fname); + for (n = 0; buf[n] != '\0'; n++) + { + buf[n] &= 0x7F; + if (buf[n] < ' ') buf[n] = 'x'; + } + + DBGMSGV("%s\n", buf); + + return q; +} + +#ifndef EROFS /* Open fails because of read-only FS */ +#define EROFS EACCES +#endif + +int redir_ofile(cpm_byte* fcb, char* s) +{ + int h; + + /* Software write-protection */ + +#ifdef _WIN32 + + releaseFCB(fcb); + + if (!redir_ro_fcb(fcb)) + { + // Attempt to open existing file with read/write access + DBGMSGV("open existing file '%s' with read/write access\n", s); + h = (int)CreateFile(s, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (h != HFILE_ERROR) + { + DBGMSGV("file '%s' opened R/W as #%i\n", s, h); + return trackFile(s, fcb, h); + } + DBGMSGV("open R/W failed (errno=%lu): %s\n", GetLastError(), GetErrorStr(GetLastError())); + } + + // Attempt to open existing file with read-only access + DBGMSGV("open existing file '%s' with read-only access\n", s); + h = (int)CreateFile(s, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (h == HFILE_ERROR) + { + DBGMSGV("open R/O failed (errno=%lu): %s\n", GetLastError(), GetErrorStr(GetLastError())); + return -1; + } + DBGMSGV("file '%s' opened R/O as #%i\n", s, h); + fcb[9] |= 0x80; + +#elif defined(__MSDOS__) + + int rv; + if (!redir_ro_fcb(fcb)) + { + rv = _dos_open(s, O_RDWR, &h); + if (!rv) return h; + DBGMSGV("Open of %s fails: error %x\n", s, rv); + } + rv = _dos_open(s, O_RDONLY, &h); + if (rv) return -1; + fcb[9] |= 0x80; + +#else + + releaseFCB(fcb); + + swizzle(s); + + if (!redir_ro_fcb(fcb)) + { + // Attempt to open existing file with read/write access + DBGMSGV("open existing file '%s' with read/write access\n", s); + h = open(s, O_RDWR | O_BINARY); + if (h >= 0 || (errno != EACCES && errno != EROFS)) + { + DBGMSGV("file '%s' opened R/W as #%i\n", s, h); + return trackFile(s, fcb, h); + } + DBGMSGV("failed to open R/W (errno=%lu): %s\n", errno, strerror(errno)); + } + + // Attempt to open existing file with read-only access + DBGMSGV("open existing file '%s' with read-only access\n", s); + h = open(s, O_RDONLY | O_BINARY); + if (h < 0) + { + DBGMSGV("failed to open R/O (errno=%lu): %s\n", errno, strerror(errno)); + return -1; + } + DBGMSGV("file '%s' opened R/O as #%i\n", s, h); + fcb[9] |= 0x80; + +#endif + + return trackFile(s, fcb, h); +} + +/* Extract a file handle from where it was stored in an FCB by fcb_open() + or fcb_creat(). Aborts if the FCB has been tampered with. + + Note: Some programs (like GENCOM) close FCBs they never opened. This causes + the Corrupt FCB message, but no harm seems to ensue. */ + +int redir_verify_fcb(cpm_byte* fcb) +{ + if (fcb[16] != 0xFD || fcb[17] != 0x00) + { + fprintf(stderr, "cpmredir: Corrupt FCB\n"); + return -1; + } + return (int)(redir_rd32(fcb + 18)); +} + +/* Print a trace message */ + +#ifdef DEBUG + +void DbgMsg(const char* file, int line, const char* func, char* s, ...) +{ + va_list ap; + + va_start(ap, s); + fprintf(stderr, "%s(%s@%i): ", func, file, line); + vfprintf(stderr, s, ap); + va_end(ap); + fflush(stderr); +} + +#endif + +#define BCD(x) (((x % 10)+16*(x/10)) & 0xFF) + +/* Convert time_t to CP/M day count/hours/minutes */ +dword redir_cpmtime(time_t t) +{ + /* 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)); +} + +#undef BCD + +#define UNBCD(x) (((x % 16) + 10 * (x / 16)) & 0xFF) + +time_t redir_unixtime(cpm_byte* c) +{ + time_t t; + cpm_word days; + + days = (c[0] + 256 * c[1]) + 2921; + + t = 60L * UNBCD(c[3]); + t += 3600L * UNBCD(c[2]); + t += 86400L * days; + + return t; +} + +#undef UNBCD + +/* Functions to access 24-bit & 32-bit words in memory. These are always + little-endian. */ + +void redir_wr24(cpm_byte* addr, dword v) +{ + addr[0] = v & 0xFF; + addr[1] = (v >> 8) & 0xFF; + addr[2] = (v >> 16) & 0xFF; +} + +void redir_wr32(cpm_byte* addr, dword v) +{ + addr[0] = v & 0xFF; + addr[1] = (v >> 8) & 0xFF; + addr[2] = (v >> 16) & 0xFF; + addr[3] = (v >> 24) & 0xFF; +} + +dword redir_rd24(cpm_byte* addr) +{ + register dword rv = addr[2]; + + rv = (rv << 8) | addr[1]; + rv = (rv << 8) | addr[0]; + return rv; +} + +dword redir_rd32(cpm_byte* addr) +{ + register dword rv = addr[3]; + + rv = (rv << 8) | addr[2]; + rv = (rv << 8) | addr[1]; + rv = (rv << 8) | addr[0]; + return rv; +} + +void redir_log_drv(cpm_byte drv) +{ + if (!drv) redir_l_drives |= 1; + else redir_l_drives |= (1L << drv); +} + +void redir_log_fcb(cpm_byte* fcb) +{ + int drv = fcb[0] & 0x7F; + + if (drv && drv != '?') redir_log_drv(drv - 1); + else redir_log_drv(redir_cpmdrive); +} + +int redir_ro_drv(cpm_byte drv) +{ + if (!drv) return redir_ro_drives & 1; + else return redir_ro_drives & (1L << drv); +} + +int redir_ro_fcb(cpm_byte* fcb) +{ + int drv = fcb[0] & 0x7F; + + if (drv && drv != '?') return redir_ro_drv(drv - 1); + else return redir_ro_drv(redir_cpmdrive); +} + +cpm_word redir_xlt_err(void) +{ + if (redir_password_error()) return 0x7FF; /* DRDOS pwd error */ + + switch (errno) + { + case EISDIR: + case EBADF: return 9; /* Bad FCB */ + case EINVAL: return 0x03FF; /* Readonly file */ + case EPIPE: return 0x01FF; /* Broken pipe */ + case ENOSPC: return 1; /* No space */ + default: return 0xFF; /* Software error */ + } +} + +#ifdef _WIN32 + +int truncate(const char* path, off_t length) +{ + BOOL bResult; + HANDLE hFile; + DWORD dwOffset; + + DBGMSGV("truncate file %s to %lu\n", path, length); + + hFile = CreateFile(path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + DBGMSGV("truncate failed to open file (Error=%lu): %s\n", GetLastError(), GetErrorStr(GetLastError())); + return -1; + } + + dwOffset = SetFilePointer(hFile, length, NULL, FILE_BEGIN); + if (dwOffset == INVALID_SET_FILE_POINTER) + { + DBGMSGV("truncate failed to open file (Error=%lu): %s\n", GetLastError(), GetErrorStr(GetLastError())); + CloseHandle(hFile); + return -1; + } + + bResult = SetEndOfFile(hFile); + if (!bResult) + { + DBGMSGV("truncate failed to set end of file (Error=%lu): %s\n", GetLastError(), GetErrorStr(GetLastError())); + CloseHandle(hFile); + return -1; + } + + bResult = CloseHandle(hFile); + if (!bResult) + { + DBGMSGV("truncate failed to close file (Error=%lu): %s\n", GetLastError(), GetErrorStr(GetLastError())); + return -1; + } + + DBGMSGV("truncate set file length to %lu\n", dwOffset); + return 0; +} + +#endif diff --git a/Tools/unix/zxcc/xlt.c b/Tools/unix/zxcc/xlt.c new file mode 100644 index 00000000..a36f7f50 --- /dev/null +++ b/Tools/unix/zxcc/xlt.c @@ -0,0 +1,237 @@ +/* + + 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.\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.\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..59af1ed3 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\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 66% rename from Tools/unix/zx/z80.h rename to Tools/unix/zxcc/z80.h index 89e12a84..7634389f 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/zxcc/zxbdos.c b/Tools/unix/zxcc/zxbdos.c new file mode 100644 index 00000000..dab19e58 --- /dev/null +++ b/Tools/unix/zxcc/zxbdos.c @@ -0,0 +1,555 @@ +#include "zxcc.h" + +#define BDOS_DEF +#include "zxbdos.h" +#include "zxcbdos.h" +#include "zxdbdos.h" + +#ifdef __MSDOS__ +#include +#endif + +#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) +{ + 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)); +} + + +byte get_time(cpm_word b) +{ + time_t t; + + time(&t); + wr32(b, cpmtime(t)); + + return (BCD(t % 60)); +} + + +/* Functions to access 24-bit & 32-bit words in memory. These are always + little-endian. */ + +void wr24(word addr, dword v) +{ + RAM[addr] = v & 0xFF; + RAM[addr + 1] = (v >> 8) & 0xFF; + RAM[addr + 2] = (v >> 16) & 0xFF; +} + +void wr32(word addr, dword v) +{ + RAM[addr] = v & 0xFF; + RAM[addr + 1] = (v >> 8) & 0xFF; + RAM[addr + 2] = (v >> 16) & 0xFF; + RAM[addr + 3] = (v >> 24) & 0xFF; +} + +dword rd24(word addr) +{ + register dword rv = RAM[addr + 2]; + + rv = (rv << 8) | RAM[addr + 1]; + rv = (rv << 8) | RAM[addr]; + return rv; +} + + +dword rd32(word addr) +{ + register dword rv = RAM[addr + 3]; + + rv = (rv << 8) | RAM[addr + 2]; + rv = (rv << 8) | RAM[addr + 1]; + rv = (rv << 8) | RAM[addr]; + return rv; +} + +#define peekw(addr) ( (((word)(RAM[addr + 1])) << 8) | RAM[addr]) + + +/* Get / set the program return code. We store this in 'C' form: 0 for + success, 1-255 for failure. Translate to/from the CP/M form of: + + 0x0000-0xFEFF for success + 0xFF00-0xFFFE for failure + + We also store the actual value so it can be returned + + */ + +word cpm_errcde(word DE) +{ + static word real_err = 0; + + if (DE == 0xFFFF) return real_err; + real_err = DE; + + if (DE == 0xFF00) cpm_error = 1; + else if (DE > 0xFF00) cpm_error = (DE & 0xFF); + else cpm_error = 0; + return 0; +} + + +#ifdef USE_CPMGSX +gsx_byte gsxrd(gsx_word addr) +{ + return RdZ80(addr); +} + +void gsxwr(gsx_word addr, gsx_byte value) +{ + WrZ80(addr, value); +} + +#endif + +#undef bc +#undef de +#undef hl + +void setw(byte* l, byte* h, word w) +{ + *l = (w & 0xFF); + *h = (w >> 8) & 0xFF; +} + +void cpmbdos(byte* a, byte* b, byte* c, byte* d, byte* e, byte* f, + byte* h, byte* l, word* pc, word* ix, word* iy) +{ + word de = ((*d) << 8) | *e; + word hl = ((*h) << 8) | *l; + byte* pde = &RAM[de]; + byte* pdma = &RAM[cpm_dma]; + word temp; + int retv; + + DBGMSGV("BDOS service invoked: C=0x%02X DE=0x%04X\n", *c, de); + + switch (*c) + { + case 0: + *pc = 0; + break; + + case 1: /* Get a character */ +#ifdef USE_CPMIO + retv = cpm_bdos_1(); +#else + retv = cin(); +#endif + if (retv < 0) *pc = 0; + setw(l, h, retv); + break; + + case 2: /* Print a character */ +#ifdef USE_CPMIO + if (cpm_bdos_2(*e)) *pc = 0; +#else + cout(*e); +#endif + break; + + case 3: /* No auxin */ + setw(l, h, 0x1A); + break; + + case 4: /* No auxout */ + break; + + case 5: /* No printer */ + break; + + case 6: /* Direct console I/O */ + retv = cpm_bdos_6(*e); + if (retv < 0) *pc = 0; + setw(l, h, retv); + break; + + case 7: /* No auxist */ + case 8: /* No auxost */ + break; + + case 9: /* Print a $-terminated string */ +#ifdef USE_CPMIO + if (cpm_bdos_9((char*)pde)) *pc = 0; +# else + for (temp = 0; RAM[de + temp] != '$'; ++temp) + { + cout(RAM[de + temp]); + } +#endif + break; + + case 0x0A: + bdos_rdline(de, &(*pc)); + break; + + case 0x0B: /* Console status */ + // *l = *h = 0; /* No keys pressed */ + *l = cstat(); + *h = 0; + break; + + case 0x0C: /* Get CP/M version */ + + /* For GENCOM's benefit, claim to be v3.1 */ + + *l = 0x31; /* v3.1 */ + /* *l = 0x22; * v2.2 */ + *h = 0; /* CP/M, no network */ + break; + + case 0x0D: /* Re-log discs */ + fcb_reset(); + break; + + case 0x0E: /* Set default drive */ + setw(l, h, fcb_drive(*e)); + break; + + case 0x0F: /* Open using FCB */ + setw(l, h, x_fcb_open(pde, pdma)); + break; + + case 0x10: /* Close using FCB */ + setw(l, h, fcb_close(pde)); + break; + + case 0x11: /* Find first */ + setw(l, h, fcb_find1(pde, pdma)); + break; + + case 0x12: + setw(l, h, fcb_find2(pde, pdma)); + break; + + case 0x13: /* Delete using FCB */ + setw(l, h, fcb_unlink(pde, pdma)); + break; + + case 0x14: /* Sequential read using FCB */ + setw(l, h, fcb_read(pde, pdma)); + break; + + case 0x15: /* Sequential write using FCB */ + setw(l, h, fcb_write(pde, pdma)); + break; + + case 0x16: /* Create using FCB */ + setw(l, h, fcb_creat(pde, pdma)); + break; + + case 0x17: /* Rename using FCB */ + setw(l, h, fcb_rename(pde, pdma)); + break; + + case 0x18: /* Get login vector */ + setw(l, h, fcb_logvec()); + break; + + case 0x19: /* Get default drive */ + setw(l, h, cpm_drive); + break; + + case 0x1A: /* Set DMA */ + DBGMSGV("Set DMA to 0x%04X\n", de); + cpm_dma = de; + break; + + case 0x1B: /* Get alloc vector */ + fcb_getalv(RAM + 0xFF80, 0x40); + setw(l, h, 0xFF80); + break; + + case 0x1C: /* Make disc R/O */ + setw(l, h, fcb_rodisk()); + break; + + case 0x1D: /* Get R/O vector */ + setw(l, h, fcb_rovec()); + break; + + case 0x1E: /* Set attributes */ + setw(l, h, fcb_chmod(pde, pdma)); + break; + + case 0x1F: /* Get DPB */ + fcb_getdpb(RAM + 0xFFC0); + setw(l, h, 0xFFC0); + break; + + case 0x20: /* Get/set uid */ + setw(l, h, fcb_user(*e)); + break; + + case 0x21: /* Read a record */ + setw(l, h, fcb_randrd(pde, pdma)); + break; + + case 0x22: /* Write a record */ + setw(l, h, fcb_randwr(pde, pdma)); + break; + + case 0x23: /* Get file size */ + setw(l, h, x_fcb_stat(pde)); + break; + + case 0x24: /* Get file pointer */ + setw(l, h, fcb_tell(pde)); + break; + + case 0x25: + setw(l, h, fcb_resro(de)); + break; + + /* MP/M drive access functions, not implemented */ + + case 0x28: /* Write with 0 fill */ + setw(l, h, fcb_randwz(pde, pdma)); + break; + + /* MP/M record locking functions, not implemented */ + + case 0x2C: /* Set no. of records to read/write */ + setw(l, h, fcb_multirec(*e)); + break; + + case 0x2D: /* Set error mode */ + err_mode = *e; + break; + + case 0x2E: + setw(l, h, fcb_dfree(*e, pdma)); + break; + + /* 0x2F: Chain */ + + case 0x30: + setw(l, h, fcb_sync(*e)); + break; + + case 0x31: + if (pde[1] == 0xFE) + { + RAM[0xFE9C + *pde] = pde[2]; + RAM[0xFE9D + *pde] = pde[3]; + } + else if (RAM[hl + 1] == 0xFF) + { + RAM[0xFE9C + *pde] = pde[2]; + } + else + { + *l = RAM[0xFE9C + *pde]; + *h = RAM[0xFE9D + *pde]; + } + break; + + case 0x32: + temp = *ix; + *ix = 3 * (pde[0] + 1); + *a = pde[1]; + *c = pde[2]; + *b = pde[3]; + *e = pde[4]; + *d = pde[5]; + *l = pde[6]; + *h = pde[7]; + cpmbios(a, b, c, d, e, f, h, l, pc, ix, iy); + *ix = temp; + break; + + case 0x3C: /* Communicate with RSX */ + *h = 0; *l = 0xFF; /* return error */ + break; + + case 0x62: /* Purge */ + setw(l, h, fcb_purge()); + break; + + case 0x63: /* Truncate file */ + setw(l, h, fcb_trunc(pde, pdma)); + break; + + case 0x64: /* Set label */ + setw(l, h, fcb_setlbl(pde, pdma)); + break; + + case 0x65: /* Get label byte */ + setw(l, h, fcb_getlbl(*e)); + break; + + case 0x66: /* Get file date */ + setw(l, h, fcb_date(pde)); + break; + + case 0x67: /* Set password */ + setw(l, h, fcb_setpwd(pde, pdma)); + break; + + case 0x68: /* Set time of day */ + /* Not advisable to let an emulator play with the clock */ + break; + + case 0x69: /* Get time of day */ + setw(l, h, get_time(de)); + break; + + case 0x6A: /* Set default password */ + setw(l, h, fcb_defpwd(pde)); + break; + + case 0x6B: /* Get serial number */ + memcpy(pde, SERIAL, 6); + break; + + case 0x6C: /* 0.03 set error code */ + setw(l, h, cpm_errcde(de)); + break; + +#ifdef USE_CPMIO + case 0x6D: /* Set/get console mode */ + setw(l, h, cpm_bdos_109(de)); + break; + + case 0x6E: /* Set/get string delimiter */ + setw(l, h, cpm_bdos_110(*e)); + break; + + case 0x6F: /* Send fixed length string to screen */ + if (cpm_bdos_111((char*)RAM + peekw(de), + peekw(de + 2))) + *pc = 0; + break; + + case 0x70: /* Send fixed length string to printer */ + break; + + /* 0x71: Strange PCP/M function */ +#else + case 0x6D: /* Set/get console mode */ + setw(l, h, 0); + break; + +#endif + +#ifdef USE_CPMGSX + case 0x73: /* GSX */ + setw(l, h, gsx80(gsxrd, gsxwr, de)); + break; +#endif + + case 0x74: /* Set date stamp */ + setw(l, h, fcb_sdate(pde, pdma)); + break; + + case 0x98: /* Parse filename */ + setw(l, h, fcb_parse((char*)RAM + peekw(de), + (byte*)RAM + peekw(de + 2))); + break; + + default: +#ifdef USE_CPMIO + cpm_scr_unit(); +#endif +#ifdef USE_CPMGSX + gsx_deinit(); +#endif + + 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); + zxcc_exit(1); + break; + } + + *a = *l; + *b = *h; +} + +void cpmbios(byte* a, byte* b, byte* c, byte* d, byte* e, byte* f, + byte* h, byte* l, word* pc, word* ix, word* iy) +{ + int func = (((*ix) & 0xFF) / 3) - 1; + + DBGMSGV("BIOS service invoked: func=0x%02X\n", func); + + switch (func) /* BIOS function */ + { + case 1: + zxcc_exit(zxcc_term()); /* Program termination */ + break; + + case 2: /* CONST */ +#ifdef USE_CPMIO + * a = cpm_const(); +#else + * a = cpm_bdos_6(0xFE); +#endif + break; + + case 3: /* CONIN */ +#ifdef USE_CPMIO + * a = cpm_conin(); +#else + * a = cpm_bdos_6(0xFD); +#endif + break; + + case 4: /* CONOUT */ +#ifdef USE_CPMIO + cpm_conout(*c); +#else + cpm_bdos_6(*c); +#endif + break; + + case 20: /* DEVTBL */ + setw(l, h, 0xFFFF); + break; + + case 22: /* DRVTBL */ + setw(l, h, 0xFFFF); + break; + + case 26: /* TIME */ + RAM[0xFEF8] = get_time(0xFEF4); + break; + + case 30: /* USERF!!! */ +#ifdef USE_CPMIO + cpm_bdos_110('$'); + cpm_bdos_9("This program has attempted to call USERF, " + "which is not implemented\n$"); +#else + printf("This program has attempted to call USERF, which " + "is not implemented.\n"); +#endif + zxcc_term(); + zxcc_exit(1); + break; + + default: +#ifdef USE_CPMIO + cpm_scr_unit(); +#endif +#ifdef USE_CPMGSX + gsx_deinit(); +#endif + + fprintf(stderr, "%s: Unsupported BIOS call %d\n", progname, func); + dump_regs(stderr, *a, *b, *c, *d, *e, *f, *h, *l, *pc, *ix, *iy); + zxcc_exit(1); + } +} diff --git a/Tools/unix/zx/zxbdos.h b/Tools/unix/zxcc/zxbdos.h similarity index 75% rename from Tools/unix/zx/zxbdos.h rename to Tools/unix/zxcc/zxbdos.h index 4111c78e..fd7bebc2 100644 --- a/Tools/unix/zx/zxbdos.h +++ b/Tools/unix/zxcc/zxbdos.h @@ -1,50 +1,49 @@ -extern char *progname; -extern char **argv; -extern int argc; - -extern byte cpm_drive; -extern byte cpm_user; - -extern byte RAM[65536]; /* The Z80's address space */ - -extern void Msg(char *s, ...); - -#ifdef BDOS_DEF - -word cpm_dma = 0x80; /* DMA address */ -byte err_mode = 0xFF; -byte rec_multi = 1; -word rec_len = 128; -word ffirst_fcb = 0xFFFF; -byte cpm_error = 0; /* Error code returned by CP/M */ - -#else /* BDOS_DEF */ - -extern word cpm_dma, rec_len, ffirst_fcb; -extern byte err_mode, rec_multi, cpm_error; - -#endif /* BDOS_DEF */ - -#ifndef O_BINARY /* Necessary in DOS, not present in Linux */ -#define O_BINARY 0 -#endif - -typedef unsigned long dword; - -/* Functions in zxbdos.c */ - -void wr24(word addr, dword v); -void wr32(word addr, dword v); -dword rd24(word addr); -dword rd32(word addr); -dword cpmtime(time_t t); -word cpm_errcde(word DE); - -#ifdef USE_CPMGSX -gsx_byte gsxrd(gsx_word addr); -void gsxwr(gsx_word addr, gsx_byte value); -#endif - -void cpmbdos(); -void cpmbios(); - +extern char* progname; +extern char** argv; +extern int argc; + +extern byte cpm_drive; +extern byte cpm_user; + +extern byte RAM[65536]; /* The Z80's address space */ + +extern void Msg(char* s, ...); + +#ifdef BDOS_DEF + +word cpm_dma = 0x80; /* DMA address */ +byte err_mode = 0xFF; +byte rec_multi = 1; +word rec_len = 128; +word ffirst_fcb = 0xFFFF; +byte cpm_error = 0; /* Error code returned by CP/M */ + +#else /* BDOS_DEF */ + +extern word cpm_dma, rec_len, ffirst_fcb; +extern byte err_mode, rec_multi, cpm_error; + +#endif /* BDOS_DEF */ + +#ifndef O_BINARY /* Necessary in DOS, not present in Linux */ + #define O_BINARY 0 +#endif + +typedef unsigned long dword; + +/* Functions in zxbdos.c */ + +void wr24(word addr, dword v); +void wr32(word addr, dword v); +dword rd24(word addr); +dword rd32(word addr); +dword cpmtime(time_t t); +word cpm_errcde(word DE); + +#ifdef USE_CPMGSX +gsx_byte gsxrd(gsx_word addr); +void gsxwr(gsx_word addr, gsx_byte value); +#endif + +void cpmbdos(); +void cpmbios(); diff --git a/Tools/unix/zx/zxcbdos.c b/Tools/unix/zxcc/zxcbdos.c similarity index 62% rename from Tools/unix/zx/zxcbdos.c rename to Tools/unix/zxcc/zxcbdos.c index 355dd687..2777f85e 100644 --- a/Tools/unix/zx/zxcbdos.c +++ b/Tools/unix/zxcc/zxcbdos.c @@ -1,150 +1,149 @@ -#include "zx.h" -#include "zxbdos.h" -#include "zxcbdos.h" -#if !(defined(__MINGW32__) || defined(_MSC_BUILD) || defined(__WATCOMC__)) -#include -#endif -#ifdef WIN32 -#include -#endif - -/* Line input */ -#ifdef USE_CPMIO - - -void bdos_rdline(word line, word *PC) -{ - unsigned char *buf; - - if (!line) line = cpm_dma; - else RAM[line + 1] = 0; - - buf = (unsigned char *)&RAM[line]; - - if (cpm_bdos_10(buf)) *PC = 0; -} - -#else /* def USE_CPMIO */ - -void bdos_rdline(word line, word *PC) -{ - unsigned char c; - unsigned char *p; - int n; - int maxlen; - - if (!line) line = cpm_dma; - maxlen = RAM[line]; - - // fgets causes extra linefeeds, so we invent our own - //fgets((char *)(RAM + line + 2), maxlen, stdin); - - p = (RAM + line + 2); - n = 0; - - while (1) { - c = cin(); - if (c == '\r') - break; - if (c == '\b') { - if (n > 0) { - cout('\b'); - cout(' '); - cout('\b'); - n--; - p--; - } - } - else { - if (n < maxlen) { - cout(c); - *p++ = c; - n++; - } - } - } - - cout('\r'); - *p = '\0'; - - //RAM[line + 1] = strlen((char *)(RAM + line + 2)) - 1; - RAM[line + 1] = (unsigned char)n; - - Msg("Input: [%d] %-*.*s\n", RAM[line + 1], RAM[line + 1], RAM[line +1], (char *)(RAM+line+2)); -} -#endif /* ndef USE_CPMIO */ - -#ifndef USE_CPMIO - - -int cpm_bdos_6(byte e) -{ - int c; - - switch(e) { - case 0xFF: - if (cstat()) return cin(); - return 0; - - case 0xFE: - return cstat(); - - case 0xFD: - return cin(); - - default: - cout(e); - break; - } - return 0; -} -#endif - -#if defined(__MINGW32__) || defined(_MSC_BUILD) || defined(__WATCOMC__) - -byte cin() -{ - if (_isatty(_fileno(stdin))) - return getch(); - else - return getchar(); -} - -void cout(byte c) -{ - if (_isatty(_fileno(stdout))) - putch(c); - else - putchar(c); -} - -int cstat() -{ - if (_isatty(_fileno(stdin))) - return _kbhit() ? 0xFF : 0; - else - return 0xFF; -} - -#else /* defined(__MINGW32__) || defined(_MSC_BUILD) || defined(__WATCOMC__) */ - -byte cin() -{ - return getchar(); -} - -void cout(byte c) -{ - putchar(c); -} - -int cstat() -{ - int i; - - ioctl(_fileno(stdin), FIONREAD, &i); - if (i > 0) return 0xff; - return 0; -} - -#endif +#include "zxcc.h" +#include "zxbdos.h" +#include "zxcbdos.h" + +#ifndef _WIN32 +#include +#endif + +/* Line input */ +#ifdef USE_CPMIO + +void bdos_rdline(word line, word* PC) +{ + unsigned char* buf; + + if (!line) line = cpm_dma; + else RAM[line + 1] = 0; + + buf = (unsigned char*)&RAM[line]; + + if (cpm_bdos_10(buf)) *PC = 0; +} + +#else /* def USE_CPMIO */ + +void bdos_rdline(word line, word* PC) +{ + unsigned char c; + unsigned char* p; + int n; + int maxlen; + + if (!line) line = cpm_dma; + maxlen = RAM[line]; + + // fgets causes extra linefeeds, so we invent our own + // fgets((char *)(RAM + line + 2), maxlen, stdin); + + p = (RAM + line + 2); + n = 0; + + while (1) { + c = cin(); + if (c == '\r') + break; + if (c == '\b') { + if (n > 0) { + cout('\b'); + cout(' '); + cout('\b'); + n--; + p--; + } + } + else { + if (n < maxlen) { + cout(c); + *p++ = c; + n++; + } + } + } + + cout('\r'); + *p = '\0'; + + //RAM[line + 1] = strlen((char *)(RAM + line + 2)) - 1; + RAM[line + 1] = (unsigned char)n; + + DBGMSGV("Input: [%d] %-*.*s\n", RAM[line + 1], RAM[line + 1], RAM[line + 1], (char*)(RAM + line + 2)); +} +#endif /* ndef USE_CPMIO */ + +#ifndef USE_CPMIO + +int cpm_bdos_6(byte e) +{ + int c; + + switch (e) { + case 0xFF: + if (cstat()) return cin(); + return 0; + + case 0xFE: + return cstat(); + + case 0xFD: + return cin(); + + default: + cout(e); + break; + } + return 0; +} +#endif + +#ifdef _WIN32 +byte cin() +{ + if (_isatty(STDIN_FILENO)) + return getch(); + else + return getchar(); +} + +void cout(byte c) +{ + if (_isatty(STDOUT_FILENO)) + putch(c); + else + putchar(c); +} + +int cstat() +{ + if (_isatty(STDIN_FILENO)) + return _kbhit() ? 0xFF : 0; + else + return 0xFF; +} + +#else /* def _WIN32 */ + +byte cin() +{ + char c = 0; + + read(STDIN_FILENO, &c, 1); + return c; +} + +void cout(byte c) +{ + write(STDOUT_FILENO, &c, 1); + return; +} + +int cstat() +{ + int i; + + ioctl(STDIN_FILENO, FIONREAD, &i); + if (i > 0) return 0xFF; + return 0; +} + +#endif diff --git a/Tools/unix/zxcc/zxcbdos.h b/Tools/unix/zxcc/zxcbdos.h new file mode 100644 index 00000000..dde4c08d --- /dev/null +++ b/Tools/unix/zxcc/zxcbdos.h @@ -0,0 +1,6 @@ +void bdos_rdline(word line, word* PC); +int cpm_bdos_6(byte e); + +byte cin(void); +void cout(byte); +int cstat(void); diff --git a/Tools/unix/zxcc/zxcc.c b/Tools/unix/zxcc/zxcc.c new file mode 100644 index 00000000..21929704 --- /dev/null +++ b/Tools/unix/zxcc/zxcc.c @@ -0,0 +1,550 @@ +#include "zxcc.h" + +/* Global variables */ + +char* progname; +char** argv; +int argc; + +byte cpm_drive; +byte cpm_user; +extern byte cpm_error; + +char bindir80[CPM_MAXPATH] = ""; +char libdir80[CPM_MAXPATH] = ""; +char incdir80[CPM_MAXPATH] = ""; + +#ifndef _WIN32 +struct termios tc_orig; +#endif + +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); + +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) +{ + fprintf(fp, "\tAF=%02x%02x BC=%02x%02x DE=%02x%02x HL=%02x%02x\n" + "\tIX=%04x IY=%04x PC=%04x\n", + a, f, b, c, d, e, h, l, pc, ix, iy); +} + +char* parse_to_fcb(char* s, int afcb) +{ + byte* fcb = &RAM[afcb + 1]; + + RAM[afcb] = 0; + memset(fcb, ' ', 11); + + while (s[0] == ' ') /* skip leading spaces */ + { + s++; + } + while (1) + { + if (s[0] == 0) break; + if (s[0] == ' ') break; + if (s[1] == ':') + { + RAM[afcb] = s[0] - '@'; + if (RAM[afcb] > 16) RAM[afcb] -= 0x20; + s += 2; + continue; + } + if (s[0] == '.') + { + ++s; + fcb = &RAM[afcb + 9]; + continue; + } + *fcb = *s; if (islower(*fcb)) *fcb = toupper(*fcb); + ++s; + ++fcb; + if (fcb >= &RAM[afcb + 12]) break; + } + return s; +} + +void ed_fe(byte* a, byte* b, byte* c, byte* d, byte* e, byte* f, + byte* h, byte* l, word* pc, word* ix, word* iy) +{ + switch (*a) + { + case 0xC0: + cpmbdos(a, b, c, d, e, f, h, l, pc, ix, iy); + break; + + case 0xC1: + load_comfile(); + break; + + case 0xC2: + fprintf(stderr, "%s: Incompatible BIOS.BIN\n", progname); + zxcc_term(); + zxcc_exit(1); + + case 0xC3: + cpmbios(a, b, c, d, e, f, h, l, pc, ix, iy); + break; + + default: + fprintf(stderr, "%s: Z80 encountered invalid trap\n", progname); + dump_regs(stderr, *a, *b, *c, *d, *e, *f, *h, *l, *pc, *ix, *iy); + zxcc_term(); + zxcc_exit(1); + + } +} + +/* + * load_bios() loads the minimal CP/M BIOS and BDOS. + * + */ + +void load_bios(void) +{ + char dir[CPM_MAXPATH + 1], fname[CPM_MAXPATH + 1]; + char* q; + size_t bios_len; + + FILE* fp = fopen("bios.bin", "rb"); + if (!fp) + { + 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 + readlink("/proc/self/exe", dir, CPM_MAXPATH - 8); /* allow room for bios.bin */ +#endif + q = strrchr(dir, DIRSEPCH); + *++q = 0; + strcpy(fname, dir); + strcat(fname, "bios.bin"); + fp = fopen(fname, "rb"); + } + if (!fp) + { + fprintf(stderr, "%s: Cannot locate bios.bin\n", progname); + 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); + zxcc_term(); + zxcc_exit(1); + } + fclose(fp); + + DBGMSGV("Loaded %d bytes of BIOS\n", bios_len); +} +/* + * try_com() attempts to open file, file.com, file.COM, file.cpm and file.CPM + * + */ + +FILE* try_com(char* s) +{ + char fname[CPM_MAXPATH + 1]; + FILE* fp; + + strcpy(fname, s); + fp = fopen(s, "rb"); if (fp) return fp; + sprintf(s, "%s.com", fname); fp = fopen(s, "rb"); if (fp) return fp; + sprintf(s, "%s.COM", fname); fp = fopen(s, "rb"); if (fp) return fp; + sprintf(s, "%s.cpm", fname); fp = fopen(s, "rb"); if (fp) return fp; + sprintf(s, "%s.CPM", fname); fp = fopen(s, "rb"); if (fp) return fp; + + strcpy(s, fname); + return NULL; +} + +/* + * load_comfile() loads the COM file whose name was passed as a parameter. + * + */ + + +void load_comfile(void) +{ + size_t com_len; + char fname[CPM_MAXPATH + 1]; + FILE* fp; + + /* Look in current directory first */ + strcpy(fname, argv[1]); + fp = try_com(fname); + if (!fp) + { + 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\n", + progname, argv[1], argv[1], argv[1], argv[1], argv[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); + zxcc_term(); + zxcc_exit(1); + } + fclose(fp); + + /* read() can corrupt buffer area following data read if length + * of data read is less than buffer. Clean it up. */ + memset(RAM + 0x0100 + com_len, 0, 0xFD00 - com_len); + + DBGMSGV("Loaded %d bytes from %s\n", com_len, fname); +} + +unsigned int in() { return 0; } +unsigned int out() { return 0; } + +/* + * xltname: Convert a unix filepath into a CP/M compatible drive:name form. + * The unix filename must be 8.3 or the CP/M code will reject it. + * + * This uses the library xlt_name to do the work, and then just strcat()s + * the result to the command line. + */ + +void zxcc_xltname(char* name, char* pcmd) +{ + char nbuf[CPM_MAXPATH + 1]; + + xlt_name(pcmd, nbuf); + + strcat(name, nbuf); +} + +/* main() parses the arguments to CP/M form. argv[1] is the name of the CP/M + program to load; the remaining arguments are arguments for the CP/M program. + + main() also loads the vestigial CP/M BIOS and does some sanity checks + on the endianness of the host CPU and the sizes of data types. + */ + +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 = "ZXCC"; +#endif + progname = argv[0]; + + /* DJGPP includes the whole path in the program name, which looks + * untidy... + */ + while ((str = strpbrk(progname, DIRSEP))) + progname = str + 1; + +#ifdef DEBUG + fprintf(stderr, "\n\n"); + DBGMSG("Start of execution: "); + for (n = 0; n < argc; n++) + fprintf(stderr, " %s", argv[n]); + fprintf(stderr, "\n"); +#endif + + term_init(); + + if (sizeof(int) > 8 || sizeof(byte) != 1 || sizeof(word) != 2) + { + fprintf(stderr, "%s: type lengths incorrect; edit typedefs " + "and recompile.\n", progname); + zxcc_exit(1); + } + + if (argc < 2) + { + fprintf(stderr, "%s: No CP/M program name provided.\n", progname); + zxcc_exit(1); + } + + /* Parse arguments. An argument can be either: + + * preceded by a '-', in which case it is copied in as-is, less the + dash; + * preceded by a '+', in which case it is parsed as a filename and + then concatenated to the previous argument; + * preceded by a '+-', in which case it is concatenated without + parsing; + * not preceded by either, in which case it is parsed as a filename. + + So, the argument string "--a -b c +-=q --x +/dev/null" would be rendered + into CP/M form as "-a b p:c=q -xd:null" */ + + if (!fcb_init()) + { + fprintf(stderr, "Could not initialise CPMREDIR library\n"); + zxcc_exit(1); + } + +#ifdef FILETRACKER + DBGMSG("File tracking is ENABLED\n"); +#else + DBGMSG("File tracking is DISABLED\n"); +#endif + + /* 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, ""); + + DBGMSGV("BINDIR80=\"%s\"\n", bindir80); + DBGMSGV("LIBDIR80=\"%s\"\n", libdir80); + DBGMSGV("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++) + { + if (argv[n][0] == '+' && argv[n][1] == '-') + { + /* Append, no parsing */ + strcat(pCmd, argv[n] + 2); + } + else if (!argv[n][0] || argv[n][0] == '-') + { + /* Append with space; no parsing. */ + strcat(pCmd, " "); + strcat(pCmd, argv[n] + 1); + } + else if (argv[n][0] == '+') + { + zxcc_xltname(pCmd, argv[n] + 1); + } + else /* Translate a filename */ + { + strcat(pCmd, " "); + zxcc_xltname(pCmd, argv[n]); + } + + } + pCmd[0x7F] = 0; /* Truncate to fit the buffer */ + RAM[0x80] = (byte)strlen(pCmd); + + str = parse_to_fcb(pCmd, 0x5C); + parse_to_fcb(str, 0x6C); + + // This statement is very useful when creating a client like zxc or zxas + DBGMSGV("Command tail is \"%s\"\n", pCmd); + + load_bios(); + + memset(RAM + 0xFE9C, 0, 0x64); /* Zap the SCB */ + RAM[0xFE98] = 0x06; + RAM[0xFE99] = 0xFE; /* FE06, BDOS entry */ + RAM[0xFEA1] = 0x31; /* BDOS 3.1 */ + RAM[0xFEA8] = 0x01; /* UK date format */ + RAM[0xFEAF] = 0x0F; /* CCP drive */ + +#ifdef USE_CPMIO + RAM[0xFEB6] = cpm_term_direct(CPM_TERM_WIDTH, -1); + RAM[0xFEB8] = cpm_term_direct(CPM_TERM_HEIGHT, -1); +#else + RAM[0xFEB6] = 79; + RAM[0xFEB8] = 23; +#endif + RAM[0xFED1] = 0x80; /* Buffer area */ + RAM[0xFED2] = 0xFF; + RAM[0xFED3] = '$'; + RAM[0xFED6] = 0x9C; + RAM[0xFED7] = 0xFE; /* SCB address */ + RAM[0xFED8] = 0x80; /* DMA address */ + RAM[0xFED9] = 0x00; + RAM[0xFEDA] = 0x0F; /* P: */ + RAM[0xFEE6] = 0x01; /* Multi sector count */ + RAM[0xFEFE] = 0x06; + RAM[0xFEFF] = 0xFE; /* BDOS */ + + cpm_drive = 0x0F; /* Start logged into P: */ + cpm_user = 0; /* and user 0 */ + +#ifdef USE_CPMIO + cpm_scr_init(); deinit_term = 1; +#endif +#ifdef USE_CPMGSX + gsx_init(); deinit_gsx = 1; +#endif + + /* Start the Z80 at 0xFF00, with stack at 0xFE00 */ + mainloop(0xFF00, 0xFE00); + + return zxcc_term(); +} + +void zxcc_exit(int code) +{ +#ifdef USE_CPMIO + if (deinit_term) cpm_scr_unit(); +#endif +#ifdef USE_CPMGSX + if (deinit_gsx) gsx_deinit(); +#endif + exit(code); +} + +int zxcc_term(void) +{ + word n; + + //n = RAM[0x81]; /* Get the return code. This is Hi-Tech C */ + //n = (n << 8) | RAM[0x80]; /* specific and fails with other COM files */ + n = 0; + + putchar('\n'); + + if (cpm_error != 0) /* The CP/M "set return code" call was used */ + { /* (my modified Hi-Tech C library uses this */ + n = cpm_error; /* call) */ + } + + if (n < 256 || n == 0xFFFF) + DBGMSGV("Return code %d\n", n); + else + n = 0; + + term_reset(); + + return n; +} + +/* 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; + + DBGMSG("Enabling RAW Terminal IO\n"); + + if (tcgetattr(STDIN_FILENO, &tc_orig) == -1) + { + DBGMSG("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) + { + DBGMSG("Failed to enable RAW Terminal IO - tcsetattr() failed\n"); + zxcc_exit(1); + } + + DBGMSG("Enabled RAW Terminal IO\n"); + + return; +} + +void deinit_raw(void) +{ + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tc_orig) == -1) + { + DBGMSG("Failed to disable RAW Terminal IO - tcsetattr() failed\n"); + return; + } + + DBGMSG("Disabled RAW Terminal IO\n"); + + return; +} + +#endif + +void term_init(void) +{ +#ifdef _WIN32 + setmode(STDIN_FILENO, O_BINARY); + setmode(STDOUT_FILENO, O_BINARY); +#else + if (_isatty(STDIN_FILENO)) + raw_init(); +#endif + + if (_isatty(STDIN_FILENO)) + DBGMSG("Using interactive console mode\n"); + else + DBGMSG("Using standard input/output mode\n"); + + return; +} + +void term_reset(void) +{ +#ifndef _WIN32 + if (_isatty(STDIN_FILENO)) + deinit_raw(); +#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/zxcc/zxcc.h b/Tools/unix/zxcc/zxcc.h new file mode 100644 index 00000000..d60cd1ba --- /dev/null +++ b/Tools/unix/zxcc/zxcc.h @@ -0,0 +1,141 @@ +/* + * 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 + +/* the default sub directories trailing / is required */ +#ifdef _WIN32 + #define BIN80 "bin80\\" + #define LIB80 "lib80\\" + #define INC80 "include80\\" +#else + #define BIN80 "bin80/" + #define LIB80 "lib80/" + #define INC80 "include80/" +#endif + +#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" + +/* System include files */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H + #include +#endif +#ifdef _WIN32 + #include + #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 +#endif +#ifndef _WIN32 + #include + #include + #define _S_IFDIR S_IFDIR +#endif + +/* Library includes */ + +#ifdef USE_CPMIO + #include "cpmio.h" +#endif + +#ifdef USE_CPMGSX + #include "cpmgsx.h" +#endif + +typedef unsigned char byte; /* Must be exactly 8 bits */ +typedef unsigned short word; /* Must be exactly 16 bits */ + +#include "cpmredir.h" /* BDOS disc simulation */ + +/* Prototypes */ + +void ed_fe (byte *a, byte *b, byte *c, byte *d, byte *e, byte *f, + byte *h, byte *l, word *pc, word *ix, word *iy); +void cpmbdos(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f, + byte *h, byte *l, word *pc, word *ix, word *iy); +void cpmbios(byte *a, byte *b, byte *c, byte *d, byte *e, byte *f, + byte *h, byte *l, word *pc, word *ix, word *iy); +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, ...); +void DbgMsg(const char *file, int line, const char *func, char *s, ...); +int zxcc_term(void); +void zxcc_exit(int code); + +void term_init(void); +void term_reset(void); + +#ifdef DEBUG + #define DBGMSGV(s, ...) DbgMsg(__FILE__, __LINE__, __func__, s, __VA_ARGS__) + #define DBGMSG(s) DbgMsg(__FILE__, __LINE__, __func__, s) + +#else + #define DBGMSGV(s, ...) + #define DBGMSG(s) +#endif + +/* Global variables */ + +extern char *progname; +extern char **argv; +extern int argc; +extern byte RAM[65536]; /* The Z80's address space */ + +/* 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/zxcc/zxdbdos.c b/Tools/unix/zxcc/zxdbdos.c new file mode 100644 index 00000000..9a839e5e --- /dev/null +++ b/Tools/unix/zxcc/zxdbdos.c @@ -0,0 +1,91 @@ +#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/zxcc/zxdbdos.h b/Tools/unix/zxcc/zxdbdos.h new file mode 100644 index 00000000..16bcde18 --- /dev/null +++ b/Tools/unix/zxcc/zxdbdos.h @@ -0,0 +1,4 @@ +int fcbforce(byte* fcb, byte* odrv); + +word x_fcb_open(byte* fcb, byte* dma); +word x_fcb_stat(byte* fcb); 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/unix/zx/COPYING b/Tools/zxcc/COPYING similarity index 98% rename from Tools/unix/zx/COPYING rename to Tools/zxcc/COPYING index a43ea212..92851102 100644 --- a/Tools/unix/zx/COPYING +++ b/Tools/zxcc/COPYING @@ -1,339 +1,339 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - Appendix: How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) 19yy - - 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. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) 19yy name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. 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..9f6a04cf 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..fa4df35f 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/zxcc_ft.exe b/Tools/zxcc/zxcc_ft.exe new file mode 100644 index 00000000..9f8c9838 Binary files /dev/null and b/Tools/zxcc/zxcc_ft.exe differ diff --git a/Tools/zxcc/zxccdbg.exe b/Tools/zxcc/zxccdbg.exe new file mode 100644 index 00000000..7a8a7388 Binary files /dev/null and b/Tools/zxcc/zxccdbg.exe differ diff --git a/Tools/zxcc/zxccdbg_ft.exe b/Tools/zxcc/zxccdbg_ft.exe new file mode 100644 index 00000000..aa6a6c0f Binary files /dev/null and b/Tools/zxcc/zxccdbg_ft.exe differ