├── .gitignore ├── LICENSE.md ├── Makefile ├── README.md ├── atdef.a86 ├── ball.c ├── baselib.a86 ├── bldhack.bat ├── bldhack.sub ├── ccpm86 ├── ccpm86.cfg ├── ciotest.c ├── clock.a86 ├── clrhack.bat ├── clrhack.sub ├── cls.a86 ├── clsansi.a86 ├── conio.c ├── conio.h ├── cpm86 ├── cpm86.cfg ├── cpmbase.img ├── debug.c ├── debug.h ├── dirent.c ├── dirent.h ├── dos ├── dos.cfg ├── dosbase.img ├── dosver.asm ├── dpb.c ├── dump.c ├── env.dat ├── getch.c ├── gfx.asm ├── gfx.h ├── images ├── cpm86.png └── cpmapps.png ├── init.a86 ├── ls.c ├── mem.a86 ├── mode.c ├── more.c ├── os.asm ├── pause.a86 ├── pce ├── .gitignore ├── AUTHORS ├── LICENSE.md ├── Makefile ├── bldpce.bat ├── bldpce.sub ├── clrpce.bat ├── clrpce.sub ├── pce.a86 ├── pceclock.a86 ├── pceexit.a86 ├── pceinit.a86 ├── pcelib.a86 ├── pcemnt.a86 ├── pcetime.a86 └── pcever.a86 ├── printenv.c ├── reboot.a86 ├── rm.c ├── rtcdef.a86 ├── skel.a86 ├── startup.0 ├── test.txt ├── time.a86 ├── tinylib.a86 ├── tod.a86 ├── touch.c ├── util.c ├── util.h ├── ver.a86 ├── wc.c └── write.c /.gitignore: -------------------------------------------------------------------------------- 1 | rom 2 | **/*.lock 3 | **/*.lha 4 | **/*.zip 5 | **/.D* 6 | **/*.log 7 | **/*.cmd 8 | **/*.exe 9 | **/*.com 10 | **/*.lib 11 | **/.*.swp 12 | **/*.obj 13 | **/*.o 14 | **/hack*.img 15 | **/dostest.img 16 | **/cpmhd.img 17 | **/ccpm86-*.img 18 | **/ccpmtest.img 19 | **/cpm86-*.img 20 | **/cpmtest.img 21 | **/pcpm*.img 22 | **/cdos-*.img 23 | **/dosplus-*.img 24 | **/*.sym 25 | **/*.lst 26 | **/*.map 27 | **/.vscode 28 | **/push 29 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 tsupplis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | AS=aztec34_as 2 | CC=aztec34_cc 3 | AR=aztec34_lib 4 | MASM=pcdev_masm 5 | LINK=pcdev_link 6 | EXE2BIN=pcdev_exe2bin 7 | CFLAGS=-I. -B +0 -D__CPM86__ 8 | STRIP=aztec34_sqz 9 | LDFLAGS=-lc86 10 | LD=aztec34_link 11 | LINK86=pcdev_linkcmd 12 | RASM86=pcdev_rasm86 13 | 14 | TOOLS=rm.cmd more.cmd write.cmd dump.cmd mode.cmd ls.cmd \ 15 | cls.cmd pause.cmd reboot.cmd tod.cmd ver.cmd touch.cmd wc.cmd \ 16 | atinit.cmd attime.cmd ciotest.cmd ball.cmd getch.cmd \ 17 | printenv.cmd mem.cmd dosver.com 18 | EXTRAS=clsansi.cmd rtctime.cmd rtcinit.cmd 19 | PCETOOLS=pce/pceexit.cmd pce/pcever.cmd pce/pcemnt.cmd pce/pcetime.cmd \ 20 | pce/pceinit.cmd 21 | 22 | all: binaries 23 | 24 | binaries: $(TOOLS) $(EXTRAS) 25 | (cd pce;make binaries) 26 | 27 | dist: hack-bin.zip pce-bin.zip hack.img 28 | 29 | hack-bin.zip pce-bin.zip: binaries 30 | rm -f pce-bin.zip 31 | zip pce-bin.zip $(PCETOOLS) 32 | rm -f hack-bin.zip 33 | zip hack-bin.zip $(TOOLS) 34 | 35 | hack.img: cpmtest.img 36 | cp $< $@ 37 | 38 | wc.cmd: wc.o util.lib 39 | $(LD) -o $@ $^ $(LDFLAGS) 40 | 41 | printenv.cmd: printenv.o util.lib 42 | $(LD) -o $@ $^ $(LDFLAGS) 43 | 44 | getch.cmd: getch.o util.lib 45 | $(LD) -o $@ $^ $(LDFLAGS) 46 | 47 | ls.cmd: ls.o util.lib 48 | $(LD) -o $@ $^ $(LDFLAGS) 49 | 50 | ciotest.cmd: ciotest.o util.lib 51 | $(LD) -o $@ $^ $(LDFLAGS) 52 | 53 | cp.cmd: cp.o util.lib 54 | $(LD) -o $@ $^ $(LDFLAGS) 55 | 56 | touch.cmd: touch.o 57 | $(LD) -o $@ $^ $(LDFLAGS) 58 | 59 | rm.cmd: rm.o util.lib 60 | $(LD) -o $@ $^ $(LDFLAGS) 61 | 62 | write.cmd: write.o 63 | $(LD) -o $@ $< $(LDFLAGS) 64 | 65 | dump.cmd: dump.o 66 | $(LD) -o $@ $< $(LDFLAGS) 67 | 68 | ball.cmd: ball.o util.lib 69 | $(LD) -o $@ $^ $(LDFLAGS) 70 | 71 | mode.cmd: mode.o util.lib 72 | $(LD) -o $@ $^ $(LDFLAGS) 73 | 74 | more.cmd: more.o 75 | $(LD) -o $@ $< $(LDFLAGS) 76 | 77 | util.lib: util.o conio.o dirent.o dpb.o debug.o os.o gfx.o 78 | rm -f $@ 79 | $(AR) $@ $^ 80 | 81 | gfx.o: gfx.asm 82 | $(AS) $< 83 | $(STRIP) $@ 84 | 85 | os.o: os.asm 86 | $(AS) $< 87 | $(STRIP) $@ 88 | 89 | ls.c: dirent.h debug.h 90 | 91 | dirent.c: dirent.h debug.h 92 | 93 | debug.c: debug.h 94 | 95 | rm.c: dirent.h 96 | 97 | tod.obj: tod.a86 baselib.a86 tinylib.a86 98 | 99 | ver.obj: ver.a86 tinylib.a86 100 | 101 | attime.obj: time.a86 baselib.a86 tinylib.a86 clock.a86 102 | $(RASM86) $< $$ pz sz iatdef.a86 103 | mv time.obj attime.obj 104 | 105 | rtctime.obj: time.a86 baselib.a86 tinylib.a86 clock.a86 106 | $(RASM86) $< $$ pz sz irtcdef.a86 107 | mv time.obj rtctime.obj 108 | 109 | mem.obj: mem.a86 tinylib.a86 110 | 111 | atinit.obj: init.a86 baselib.a86 tinylib.a86 clock.a86 112 | $(RASM86) $< $$ pz sz iatdef.a86 113 | mv init.obj atinit.obj 114 | 115 | rtcinit.obj: init.a86 baselib.a86 tinylib.a86 clock.a86 116 | $(RASM86) $< $$ pz sz irtcdef.a86 117 | mv init.obj rtcinit.obj 118 | 119 | dosver.com: dosver.exe 120 | $(EXE2BIN) dosver.exe dosver.com 121 | 122 | dosver.exe: dosver.obj 123 | $(LINK) dosver \; 124 | 125 | dosver.obj: dosver.asm 126 | $(MASM) dosver \; 127 | 128 | %.cmd: %.obj 129 | $(LINK86) $* '[$$sz]' 130 | 131 | %.obj: %.a86 132 | $(RASM86) $< $$ pz sz 133 | 134 | %.o: %.c 135 | $(CC) $(CFLAGS) $< 136 | $(STRIP) $@ 137 | 138 | clean: 139 | $(RM) *.o *.h86 *.log *.sym *.prn *.lst *.obj $(TOOLS) util.lib 140 | $(RM) dosver.exe $(EXTRAS) 141 | $(RM) cpmtest.img ccpmtest.img dostest.img hack.img 142 | (cd pce;make clean) 143 | 144 | 145 | dostest.img: binaries Makefile test.txt env.dat 146 | (cd pce;make binaries) 147 | cp dosbase.img dostest.img 148 | -for i in $(PCETOOLS) $(TOOLS) $(EXTRAS);do \ 149 | mcopy -o -i dostest.img $$i ::`basename $$i|tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ` ; \ 150 | done 151 | mcopy -o -i dostest.img test.txt ::TEST.TXT 152 | mcopy -o -i dostest.img env.dat ::ENV.DAT 153 | mdir -w -i dostest.img ::*.* 154 | 155 | ccpmtest.img: binaries cpmtest.img startup.0 156 | (cd pce;make binaries) 157 | cp cpmtest.img ccpmtest.img 158 | cpmcp -f ibmpc-514ss ccpmtest.img startup.0 0: 159 | 160 | cpmtest.img: binaries Makefile test.txt env.dat 161 | (cd pce;make binaries) 162 | cp cpmbase.img cpmtest.img 163 | cpmcp -f ibmpc-514ss cpmtest.img $(PCETOOLS) 0: 164 | cpmcp -f ibmpc-514ss cpmtest.img $(TOOLS) 0: 165 | cpmcp -f ibmpc-514ss cpmtest.img $(EXTRAS) 0: 166 | cpmcp -f ibmpc-514ss cpmtest.img test.txt 0: 167 | cpmcp -f ibmpc-514ss cpmtest.img env.dat 0: 168 | cpmls -F -f ibmpc-514ss cpmtest.img 0:*.* 169 | 170 | test: cpmtest 171 | 172 | ccpmtest: ccpmtest.img 173 | @./ccpm86 174 | 175 | cpmtest: cpmtest.img 176 | @./cpm86 177 | 178 | dostest: dostest.img 179 | @./dos 180 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CP/M-86 Hacking 2 | 3 | ## Synopsis 4 | 5 | A couple of experiments for fun with CP/M-86. The focus is on IBM XT CP/M-86 and derivatives on PC. But most of the tools work with the Just4Fun V20-MBC SBC. 6 | 7 | ## Where to find CP/M-86? 8 | 9 | The source for CP/M-86 doc, sources and binaries is http://www.cpm.z80.de. 10 | 11 | A cleaned-up distribution and kernel is available at https://github.com/tsupplis/cpm86-kernel. This distribution is working well in virtual environments, patched with all known patches, 'y2k' friendly (it contains the version of tod which sources are in this project) and AT friendly. 12 | 13 | ## Tools 14 | 15 | - LS: Directory listing 16 | ``` 17 | INF: Usage: ls [-h] | [-a] [-p] [-s|-r] [-l|-b] filepat 18 | INF: File listing utility 19 | INF: where filepat is [user/]filespec with wildcard 20 | INF: -h for help 21 | INF: -a for all files (including system) 22 | INF: -p for for pausing one screen at a time 23 | INF: -s for alphabetic sorting 24 | INF: -r for reverse alphabetic sorting 25 | INF: -l for long listing 26 | INF: -b for basic listing 27 | ``` 28 | - RM: File delete 29 | ``` 30 | INF: Usage: rm [-h] | [-a][-i] filepat 31 | INF: File delete utility 32 | INF: where filepat is [user/]filespec with wildcard 33 | INF: -h for help 34 | INF: -a to include both dir and sys files 35 | INF: -i for user validation per file 36 | INF: -f force file deletion even if read only 37 | ``` 38 | - MORE: File content list with pause 39 | ``` 40 | INF: Usage: more -h | [infile] 41 | INF: File paging utility 42 | INF: where infile is [user/]filespec 43 | INF: -h for help 44 | ``` 45 | - WRITE: Equivalent of cat>file 46 | ``` 47 | INF: Usage: write -h | [-a] filename 48 | INF: File write/create utility 49 | INF: where filename is [user/]filespec 50 | INF: -h for help 51 | INF: -a to happen to existing file 52 | ``` 53 | (Ctrl-C or Ctrl-Z used to finish input) 54 | - DUMP: Hexadecimal dump 55 | ``` 56 | INF: Usage: dump -h | [-p][-r] [infile] 57 | INF: Hexa file dump utility 58 | INF: where infile is [user/]filespec 59 | INF: -h for help 60 | INF: -p pausing every page 61 | INF: -r raw output 62 | ``` 63 | - MODE: Screen setup (CP/M-86 1.1 for PC/XT only) 64 | ``` 65 | INF: Usage: mode -h | option option ... 66 | INF: Console configuration utility 67 | INF: -h for help 68 | INF: and options: 69 | INF: cls Clear screen 70 | INF: cursor=on Show cursor 71 | INF: cursor=off Hide cursor 72 | INF: statln=on Show status line 73 | INF: statln=off Hide status line 74 | INF: status= Set status line message 75 | INF: fg= Set foreground color (1-F) 76 | INF: bg= Set background color (1-F) 77 | ``` 78 | - TOUCH: Empty file creation 79 | ``` 80 | INF: Usage: touch [-h] | filespec 81 | INF: Empty file creation utility 82 | INF: -h for help 83 | ``` 84 | - WC: File content counter 85 | ``` 86 | INF: Usage: wc [-h] | [-a] filepat [filepat] ... 87 | INF: File word/line/character count utility 88 | INF: where filepat is [user/]filespec with wildcard 89 | INF: -h for help 90 | INF: -a to include both dir and sys files 91 | ``` 92 | - PRINTENV: Print Environment Variables 93 | ``` 94 | INF: Usage: printenv [-h] 95 | INF: Display environment variables 96 | INF: -h for help 97 | ``` 98 | For the status, (\\s: space, \\\\: \\, \\u: upper, \\l: lower) 99 | - REBOOT: Simple cold or warm reboot (PC only) 100 | - CLS: Clear screen (clsansi is a vt100/ansi version as opposed to vt52 for PC) 101 | - PAUSE: submit tool waiting for a keystroke 102 | - TOD: Replacement for CP/M-86 without the 78-99 year constraint and date/time validation including leap years. It does not fix the visual issue of the century hard coded to 19. Patches exist for that. It has exactly the same behaviour as the original CP/M-86 tod.cmd tool. (CP/M-86 1.1 for PC/XT only) 103 | - VER: Displays the BDOS version (DOSVER.COM is provided to display MS-DOS Compatibility on PC-MODE compatible OSes) 104 | - MEM: Displays the available and system memory 105 | - BALL: A simple CGA demo (CP/M-86 1.1 for PC/XT, DOS Plus and CCP/M-86 or Concurrent DOS BDOS > 3.1) (take on https://www.z80cpu.eu/mirrors/klaw/bouncy.zip) 106 | - GETCH: A simple keyboard scanner 107 | - AT clock tools 108 | - ATTIME: Sync up clock (PC/XT with an AT compatible clock only) 109 | - ATINIT: Sync up clock and display boot banner (PC/XT with an AT compatible clock only) 110 | - RTC clock tools 111 | - RTCTIME: Sync up clock (PC/XT with Dallas clock (at port 02C0h by default)) 112 | - RTCINIT: Sync up clock and display boot banner (PC/XT with an Dallas clock (at port 02C0h by default) 113 | - PCE tools (PCE Emulator only) 114 | - PCETIME: Sync up clock 115 | - PCEINIT: Sync up clock and display boot banner 116 | - PCEVER: Displays the Emulator version 117 | - PCEEXIT: Leaves the Emulator 118 | - PCEMNT: Mount a disk image from the host 119 | 120 | ATINIT, RTCINIT and PCEINIT tools provide a quick configuration dump equivalent to what CP/M-86 1.1 displays on boot 121 | 122 | ``` 123 | CP/M-86 1.1, BDO 2.2 124 | Hardware Configuration: 125 | - System Memory: 640Kb 126 | - Available Memory: 607Kb 127 | - Math Coprocessor: No 128 | - Floppy Drive(s): 2 129 | - Hard Disk(s): 1 130 | - Parallel Port(s): 1 131 | - Serial Port(s): 2 132 | Date now: 2021-9-27 22:17:39.0 133 | ``` 134 | 135 | All the C tools (rm, ls, mode, more, write, dump) benefit from the file specification pattern of Aztec C: [user]/[drive]:[filespec]. as well basic \file redirects are supported. 136 | 137 | ## What CP/M-86? 138 | 139 | Unless mentioned otherwise, all the tools are working on 140 | - CP/M-86 1.1 141 | - DOS Plus 1.2 142 | - Personal CP/M 2.04 143 | - Concurrent DOS 3.2, DOS 4.1 6.21 144 | 145 | For the following OSes, only the files tools work well. Interacting with the bios is generally prohibited (ATINIT/ATTIME and PCEINIT/PCETIME)... 146 | - Concurrent CP/M 3.0 147 | - Concurrent CP/M 3.1 148 | 149 | Those OSes work incredibly well on PCE on floppy and HD images. This emulator is simple, small and works a treat. Fantastic... 150 | 151 | ![CP/M-86 1.1](images/cpm86.png) 152 | 153 | ![CP/M-86 1.1 Apps](images/cpmapps.png) 154 | 155 | ## PCE tools shortcuts 156 | 157 | - pcetime has no option, It displays and sets up the clock using 158 | - BDOS Function 68h (T_SET) if BDOS >= 3.0 (Dates from 01/01/1978) 159 | - Using System Variable Control Block through BDOS Function 31h (S_SYSVAR) on BDOS= 2.2 160 | - pcemnt needs to accomodate CCP uppercasing so an toggle character '^' is used to this effect: 161 | - /Mnt^/User/^JOhn/^test.img becomes /mnt/USERS/john/TEST.IMG 162 | 163 | ## Build Environment 164 | - Makefile for DOS Aztec C cross compilers targetting CP/M-86. (May require adaptation. emu2 is used to run dos compiler on unix/mac) 165 | - aztec c compiler version 3.4 166 | - rasm86/linkcmd, DOS version from Digital Research (http://www.cpm.z80.de/binary.html) 167 | 168 | ``` 169 | LINK86 Linkage Editor 02/Feb/87 Version 2.02 170 | Cross Linker: DOS -> CPM-86 & CDOS-286 1/2/86 171 | ``` 172 | ``` 173 | RASM-86 Assembler 12-Mar-87 PC-DOS Version 1.4a 174 | ``` 175 | - The Super Cool emu2 DOS emulator to run the DR tools on macOS and Linux (https://github.com/dmsc/emu2). This is an incredible way to bring dos command line development tools to a modern and up to date shell/make/whatever based dev environment. Another stunning emulator. Emu2 and PCE are an incredible pair. 176 | 177 | For a rudimentary, cross development environment, look at (https://github.com/tsupplis/cpm86-crossdev). 178 | 179 | Some submit/batch scripts are provided for dos (aztec 3.4) and cp/m-86 (aztec 3.2) are also available. 180 | 181 | ## Test Environment 182 | - CP/M-86 1.1 for IBM PC XT patched at https://github.com/tsupplis/cpm86-kernel 183 | - CP/M-86 1.1, CCP/M-86 3.1 and PCP/M-2.0 can be found on (http://www.cpm.z80.de) 184 | - DOS Plus 1.2 and Patched kernel can be found on (https://www.seasip.info/Cpm/dosplus.html) 185 | - The Excellent PCE emulator (http://www.hampa.ch/pce/pce-ibmpc.html) 186 | - mtools 4 and cpmtools 2.20 187 | 188 | ## Quick points on CP/M-86 189 | Despite being a very primitive OS (in some cases actually enjoyably primitive...No time management at all outside of the clock, for example), it is possible to do quite an amount of things with a couple of good tools: 190 | - DR CB86 2.0 (http://www.cpm.z80.de/binary.html) 191 | - DR C86 1.11 (http://www.cpm.z80.de/binary.html) 192 | - Aztec C 3.2 (Although Aztec C 3.4 or C 4.10 (ANSI) cross compilation from DOS is better) (https://www.aztecmuseum.ca/compilers.htm) 193 | - Turbo Pascal 3.01A and Poly Pascal 3.1 (Turbo Pascal Sibling) 194 | - RASM86 Macro Assembler (http://www.cpm.z80.de/binary.html) 195 | - Microsoft Basic (http://www.retroarchive.org/cpm/lang/lang.htm) and Personal Basic Interpreters (http://www.cpm.z80.de/binary.html) 196 | - PL/M-86 (Only cross compilation from DOS) 197 | 198 | The big cool thing with this tiny OS is how small it is. I never configure more than 128K on my PCE VM and a single person can play as a hobbyist with it. As mention earlier it works also super well with the Just4Fun V20-MBC SBC (https://hackaday.io/project/170924-v20-mbc-a-v20-8088-8080-cpu-homebrew-computer). Cool other thing: it is Y2K compliant with TOD replacement above and a small visual hack. Yep no date management ... 199 | 200 | It makes The early sources of MS-DOS as attractive. MS-DOS 2.X is far more flexible and has a bigger ecosystem than CP/M-86. This makes it more of a challenge ;-) 201 | 202 | DR tools are available through (http://www.cpm.z80.de/binary.html) and many other sources. 203 | I found the last release of Turbo Pascal and Poly Pascal on a very exhaustive danish site focused on the RC700 series computers who are by the way also emulated by PCE. They are not PC compatible but both pascal are generic and work on the IBM PC based CP/M-86 family. 204 | - (https://rc700.dk/software.php?name=RC750_TurboPascal_v3.01a) 205 | - (https://rc700.dk/software.php?name=RC759_PolyPascal_v3.1) 206 | 207 | But the files need to be extracted from disk images using cpmtools using the following definition: 208 | 209 | ``` 210 | diskdef rc75x 211 | seclen 1024 212 | tracks 154 213 | sectrk 8 214 | blocksize 2048 215 | maxdir 512 216 | boottrk 4 217 | os 3 218 | end 219 | ``` 220 | 221 | Turbo Pascal 3.01A is the last releasse on CP/M-86 (Don't forget to configure it using 222 | tinst) and is in english. Poly pascal is also in english but the message file and the online help are in Danish. Not a big deal to translate them. Poly Pascal is really a twin, sibling or ancestor of Turbo Pascal. Kinda cool to play with it. 223 | 224 | Macro assembler, C, Pascal, Structure Basic ... what else do we need? 225 | 226 | Cross Compilation can be done either using DOS emulation (emu2, pce) or using a hybrid OS 227 | - DOS Plus 1.2 228 | - Concurrent DOS 6.21 XM 229 | 230 | ... run all the tools above (Both in their DOS and CP/M version) and you can test directly the cmd binaries. 231 | 232 | A few CP/M-86 emulators for DOS exist (ame86.exe, cpm86.exe) unfortunately their sources 233 | are not to be seen anywhere and they woulld need a bit of maintenance. only rudimentary 234 | programs work. 235 | 236 | Finally, Assembly using asm86 and gencmd can also be done but it needs to be done on CP/M environments (CP/M-80 or CPM-86 derivatives can be used) 237 | 238 | It is a bit lacking on the tooling side though ... so I will port tools little by little for comfort sake. 239 | - VE+ 2.03 (or better VE+ 2.33a) is really the only strong editor I found. (http://www.retroarchive.org/cpm/text/text.htm) (There is also TED a basic editor that allows you to stay away from ED). 240 | - Automation through submit is very very rudimentary (no dream of makefiles) 241 | - There is no real solid CP/M-86 emulation as mentioned... But piggy backing the INT E0H API end point on emu2 perhaps? after all the 2 CP/M-86 and DOS 1.1 APIs are pretty much aligned... 242 | 243 | Still it is a funny bit of discovery and archeology... 244 | -------------------------------------------------------------------------------- /atdef.a86: -------------------------------------------------------------------------------- 1 | ATCLOCK EQU 1 2 | -------------------------------------------------------------------------------- /ball.c: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed under the MIT license. See LICENSE file in the project root for details. 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define BALL_WIDTH 8 10 | #define BALL_HEIGHT 8 11 | 12 | int seq=0; 13 | int ball[4][BALL_WIDTH*BALL_HEIGHT]= { 14 | { 15 | 0, 0, 0, 0, 0, 0, 0, 0, 16 | 0, 0, 1, 1, 1, 1, 0, 0, 17 | 0, 1, 2, 2, 3, 2, 1, 0, 18 | 0, 1, 2, 2, 3, 3, 1, 0, 19 | 0, 1, 2, 2, 2, 2, 1, 0, 20 | 0, 1, 2, 2, 2, 2, 1, 0, 21 | 0, 0, 1, 1, 1, 1, 0, 0, 22 | 0, 0, 0, 0, 0, 0, 0, 0 23 | }, 24 | { 25 | 0, 0, 0, 0, 0, 0, 0, 0, 26 | 0, 0, 1, 1, 1, 1, 0, 0, 27 | 0, 1, 2, 2, 2, 2, 1, 0, 28 | 0, 1, 2, 2, 2, 2, 1, 0, 29 | 0, 1, 2, 2, 3, 3, 1, 0, 30 | 0, 1, 2, 2, 3, 2, 1, 0, 31 | 0, 0, 1, 1, 1, 1, 0, 0, 32 | 0, 0, 0, 0, 0, 0, 0, 0 33 | }, 34 | { 35 | 0, 0, 0, 0, 0, 0, 0, 0, 36 | 0, 0, 1, 1, 1, 1, 0, 0, 37 | 0, 1, 2, 2, 2, 2, 1, 0, 38 | 0, 1, 2, 2, 2, 2, 1, 0, 39 | 0, 1, 3, 3, 2, 2, 1, 0, 40 | 0, 1, 2, 3, 2, 2, 1, 0, 41 | 0, 0, 1, 1, 1, 1, 0, 0, 42 | 0, 0, 0, 0, 0, 0, 0, 0 43 | }, 44 | { 45 | 0, 0, 0, 0, 0, 0, 0, 0, 46 | 0, 0, 1, 1, 1, 1, 0, 0, 47 | 0, 1, 2, 3, 2, 2, 1, 0, 48 | 0, 1, 3, 3, 2, 2, 1, 0, 49 | 0, 1, 2, 2, 2, 2, 1, 0, 50 | 0, 1, 2, 2, 2, 2, 1, 0, 51 | 0, 0, 1, 1, 1, 1, 0, 0, 52 | 0, 0, 0, 0, 0, 0, 0, 0 53 | } 54 | }; 55 | 56 | #ifndef __STDC__ 57 | draw_map(x, y, map, width, height) 58 | int x; 59 | int y; 60 | int * map; 61 | int width; 62 | int height; 63 | #else 64 | void draw_map(int x, int y, int *map, int width, int height) 65 | #endif 66 | { 67 | int offset=0; 68 | int x_offset=0; 69 | int y_offset=0; 70 | int length=width*height; 71 | do { 72 | gfx_pixel(x + x_offset, y + y_offset, ball[seq/4][offset]); 73 | offset++; 74 | x_offset++; 75 | x_offset=x_offset%width; 76 | if (!x_offset) { 77 | y_offset++; 78 | } 79 | } while (offset < length); 80 | } 81 | 82 | #ifndef __STDC__ 83 | box(x, y, width, height) 84 | int x; 85 | int y; 86 | int width; 87 | int height; 88 | #else 89 | void box(int x, int y, int width, int height) 90 | #endif 91 | { 92 | int curx = x; 93 | int cury = y; 94 | width += x; 95 | height += y; 96 | do { 97 | gfx_pixel(curx++, cury, 1); 98 | } while (curx != width); 99 | do { 100 | gfx_pixel(curx, cury++, 1); 101 | } while (cury != height); 102 | do { 103 | gfx_pixel(curx--, cury, 1); 104 | } while (curx != x); 105 | do { 106 | gfx_pixel(curx, cury--, 1); 107 | } while (cury != y); 108 | } 109 | 110 | #define BOX_X 89 111 | #define BOX_Y 59 112 | #define BOX_WIDTH 139 113 | #define BOX_HEIGHT 78 114 | #define BOX_THICKNESS 1 115 | 116 | 117 | #ifndef __STDC__ 118 | ball_demo() 119 | #else 120 | void ball_demo() 121 | #endif 122 | { 123 | int x = BOX_X+1; 124 | int y = BOX_Y+1; 125 | int xinc = 1; 126 | int yinc = 1; 127 | int ver=osver(); 128 | 129 | box(BOX_X, BOX_Y, BOX_WIDTH, BOX_HEIGHT); 130 | do { 131 | x += xinc; 132 | y += yinc; 133 | if (x > BOX_X+BOX_WIDTH-BALL_WIDTH-BOX_THICKNESS) 134 | xinc = -1; 135 | else if (x <= BOX_X+BOX_THICKNESS) 136 | xinc = 1; 137 | if (y > BOX_Y+BOX_HEIGHT-BALL_WIDTH-BOX_THICKNESS) 138 | yinc = -1; 139 | else if (y <= BOX_Y+BOX_THICKNESS) 140 | yinc = 1; 141 | draw_map(x, y, ball, BALL_WIDTH, BALL_HEIGHT); 142 | seq++; 143 | if(seq>12) seq=0; 144 | delay(1); 145 | } while (!kbhit()); 146 | getch(); 147 | } 148 | 149 | #ifndef __STDC__ 150 | int main(argc, argv) 151 | int argc; 152 | char **argv; 153 | #else 154 | int main(int argc, char **argv) 155 | #endif 156 | { 157 | int x = BOX_X+1; 158 | int y = BOX_Y+1; 159 | int xinc = 1; 160 | int yinc = 1; 161 | 162 | if((osver()==0x31 || osver()==0x30) && (ostype()&OSTYPE_MULTIUSER)) { 163 | fprintf(stderr,"INF: No support for direct BIOS access on CCP/M 3.x\n"); 164 | exit(-1); 165 | } 166 | freopen("con:", "r", stdin); 167 | freopen("con:", "w", stdout); 168 | statline(STATLINE_OFF); 169 | gfx_mode(MODE_CGA_320X200); 170 | gfx_palette(CGA_PALETTE_GRY); 171 | ball_demo(); 172 | gfx_mode(MODE_TEXT); 173 | statline(STATLINE_ON); 174 | clrscr(); 175 | return 0; 176 | } 177 | -------------------------------------------------------------------------------- /baselib.a86: -------------------------------------------------------------------------------- 1 | ; 2 | ; Licensed under the MIT license. See LICENSE file in the project root for details. 3 | ; 4 | 5 | clear_keys: 6 | push ax 7 | push cx 8 | push dx 9 | mov dx,0FFh 10 | mov cx,06h 11 | int 0E0h 12 | or al, 0 13 | jnz clear_keys 14 | pop dx 15 | pop cx 16 | pop ax 17 | ret 18 | 19 | in_key: 20 | push cx 21 | push dx 22 | mov dx,0FFh 23 | mov cx,06h 24 | int 0E0h 25 | pop dx 26 | pop cx 27 | ret 28 | 29 | wait_key: 30 | push cx 31 | push bx 32 | push dx 33 | push di 34 | mov bx, 01h 35 | wait_key_l2: 36 | mov di, 0FFFh 37 | wait_key_l1: 38 | push di 39 | push bx 40 | mov dx,0FFh 41 | mov cx,06h 42 | int 0E0h 43 | pop bx 44 | pop di 45 | or ax, 0 46 | jnz wait_end 47 | dec di 48 | jnz wait_key_l1 49 | dec bx 50 | jnz wait_key_l2 51 | wait_end: 52 | pop di 53 | pop dx 54 | pop bx 55 | pop cx 56 | ret 57 | 58 | delay: 59 | push bx 60 | push di 61 | mov bx, 05h 62 | delay_l2: 63 | mov di, 0FFFFh 64 | delay_l1: 65 | dec di 66 | jnz delay_l1 67 | dec bx 68 | jnz delay_l2 69 | pop di 70 | pop bx 71 | ret 72 | 73 | parse_opt: 74 | push ax 75 | push bx 76 | push dx 77 | mov bh, 1h 78 | cld 79 | mov ah, 1 80 | parse_opt_skip: 81 | jcxz parse_opt_done 82 | lodsb 83 | call to_lower 84 | dec cx 85 | cmp al, 32 86 | jbe parse_opt_skip 87 | xor ah, ah 88 | cmp al, '"' 89 | je parse_opt_quote 90 | parse_opt_next: 91 | cmp al, '^' 92 | je pon_nostore 93 | stosb 94 | pon_nostore: 95 | jcxz parse_opt_done 96 | lodsb 97 | call to_lower 98 | dec cx 99 | cmp al, 32 100 | jbe parse_opt_done 101 | jmp parse_opt_next 102 | parse_opt_quote: 103 | jcxz parse_opt_done 104 | lodsb 105 | call to_lower 106 | dec cx 107 | cmp al, '"' 108 | je parse_opt_done 109 | cmp al, '^' 110 | je parse_opt_quote 111 | stosb 112 | jmp parse_opt_quote 113 | 114 | parse_opt_done: 115 | xor al, al 116 | stosb 117 | shr ah, 1 118 | pop dx 119 | pop bx 120 | pop ax 121 | ret 122 | 123 | to_lower: 124 | cmp al, '^' 125 | jne to_lower_cnt 126 | or bh, bh 127 | jz to_lower_on 128 | xor bh, bh 129 | jmp to_lower_end 130 | to_lower_on: 131 | mov bh, 1 132 | jmp to_lower_end 133 | to_lower_cnt: 134 | or bh, bh 135 | jz to_lower_end 136 | cmp al, 'A' 137 | jb to_lower_end 138 | cmp al, 'Z' 139 | ja to_lower_end 140 | add al, 32 141 | to_lower_end: 142 | ret 143 | 144 | print_dec4: 145 | mov dx, 4 146 | jmp print_dec 147 | 148 | print_dec2: 149 | mov dx, 2 150 | xor ah, ah 151 | print_dec: 152 | push dx 153 | mov dx, 10 154 | push dx 155 | push ax 156 | call print_uint16 157 | add sp, 6 158 | ret 159 | 160 | disk_count: 161 | push bx 162 | push cx 163 | push ds 164 | push es 165 | mov cx,0Ch 166 | int 0E0h 167 | cmp ax,1041h 168 | jz disk_count_dosplus 169 | 170 | mov ax,80h 171 | call disk_count_dsk 172 | xor ah,ah 173 | jmp disk_count_end 174 | disk_count_dosplus: 175 | mov cl,9Ah 176 | int 0E0h 177 | push ds 178 | push es 179 | push es 180 | pop ds 181 | mov ax,81h 182 | mov cx,0 183 | callf ds:dword ptr 28h[bx] 184 | mov cx,bx 185 | pop es 186 | pop ds 187 | mov ax,es:word ptr 2[bx] 188 | disk_count_end: 189 | pop es 190 | pop ds 191 | pop cx 192 | pop bx 193 | ret 194 | 195 | disk_count_dsk: 196 | push bx 197 | push cx 198 | push dx 199 | push ds 200 | push es 201 | push di 202 | push si 203 | mov dl,al 204 | ;push dx 205 | ;mov ah,00h 206 | ;int 13h 207 | ;pop dx 208 | mov ah,08h 209 | int 13h 210 | jnc disk_count_dsk_end 211 | clc 212 | mov dl,0 213 | disk_count_dsk_end: 214 | mov ah,bl 215 | mov al,dl 216 | pop si 217 | pop di 218 | pop es 219 | pop ds 220 | pop dx 221 | pop cx 222 | pop bx 223 | ret 224 | 225 | check_286_plus: 226 | push ax 227 | pushf 228 | ; ========================================== 229 | ; === CHECK #1 ============================= 230 | ; ========================================== 231 | ; Sets FLAGS to 0x0 and then immediately reads it back. On an 8086/80186, bits 232 | ; 12-15 always come back set. On a 80286+ this is not the case. 233 | ; 8086/80186 behavior: clc 234 | ; 80286+ behavior: stc 235 | xor ax,ax ; AX=0x0 236 | push ax 237 | popf ; pop 0x0 into FLAGS 238 | pushf 239 | pop ax ; pop FLAGS into AX 240 | 241 | and ax,0F000h ; bits 12-13: IOPL, always 1 on 86/186 242 | cmp ax,0F000h ; bit 14: NT, always 1 on 86/186 243 | ; bit 15: Reserved, always 1 on 86/186, always 0 on 286+ 244 | jz check_186_minus 245 | popf 246 | stc 247 | pop ax 248 | ret 249 | check_186_minus: 250 | popf 251 | clc 252 | pop ax 253 | ret 254 | 255 | 256 | 257 | 258 | -------------------------------------------------------------------------------- /bldhack.bat: -------------------------------------------------------------------------------- 1 | as os.asm 2 | sqz os.o 3 | as gfx.asm 4 | sqz gfx.o 5 | cc -D__CPM86__ -I. util.c 6 | sqz util.o 7 | cc -D__CPM86__ -I. dirent.c 8 | sqz dirent.o 9 | cc -D__CPM86__ -I. conio.c 10 | sqz conio.o 11 | cc -D__CPM86__ -I. dpb.c 12 | sqz dpb.o 13 | cc -D__CPM86__ -I. debug.c 14 | sqz debug.o 15 | lb util.lib util.o conio.o dirent.o dpb.o debug.o os.o gfx.o 16 | cc -D__CPM86__ -I. dump.c 17 | sqz dump.o 18 | ln -o dump.cmd dump.o util.lib -lc86 19 | cc -D__CPM86__ -I. more.c 20 | sqz more.o 21 | ln -o mode.cmd more.o util.lib -lc86 22 | cc -D__CPM86__ -I. mode.c 23 | sqz mode.o 24 | ln -o mode.cmd mode.o util.lib -lc86 25 | cc -D__CPM86__ -I. write.c 26 | sqz write.o 27 | ln -o write.cmd write.o util.lib -lc86 28 | cc -D__CPM86__ -I. ls.c 29 | sqz ls.o 30 | ln -o ls.cmd ls.o util.lib -lc86 31 | cc -D__CPM86__ -I. touch.c 32 | sqz touch.o 33 | ln -o touch.cmd touch.o -lc86 34 | cc -D__CPM86__ -I. rm.c 35 | sqz rm.o 36 | ln -o rm.cmd rm.o util.lib -lc86 37 | cc -D__CPM86__ -I. printenv.c 38 | sqz printenv.o 39 | ln -o printenv.cmd printenv.o util.lib -lc86 40 | cc -D__CPM86__ -I. ciotest.c 41 | sqz ciotest.o 42 | ln -o ciotest.cmd ciotest.o util.lib -lc86 43 | cc -D__CPM86__ -I. ball.c 44 | sqz ball.o 45 | ln -o ball.cmd ball.o util.lib -lc86 46 | cc -D__CPM86__ -I. getch.c 47 | sqz getch.o 48 | ln -o getch.cmd getch.o util.lib -lc86 49 | rasm86 atinit $ pz sz 50 | link86 atinit[$sz] 51 | rasm86 attime $ pz sz 52 | link86 attime[$sz] 53 | rasm86 mem $ pz sz 54 | link86 mem[$sz] 55 | rasm86 ver $ pz sz 56 | link86 ver[$sz] 57 | rasm86 clsansi $ pz sz 58 | link86 clsansi[$sz] 59 | rasm86 cls $ pz sz 60 | link86 cls[$sz] 61 | rasm86 pause $ pz sz 62 | link86 pause[$sz] 63 | rasm86 tod $ pz sz 64 | link86 tod[$sz] 65 | rasm86 reboot $ pz sz 66 | link86 reboot[$sz] 67 | -------------------------------------------------------------------------------- /bldhack.sub: -------------------------------------------------------------------------------- 1 | as os.asm 2 | as gfx.asm 3 | cc -D__CPM86__ -Ip: -Ic: util.c 4 | cc -D__CPM86__ -Ip: -Ic: dirent.c 5 | cc -D__CPM86__ -Ip: -Ic: conio.c 6 | cc -D__CPM86__ -Ip: -Ic: dpb.c 7 | cc -D__CPM86__ -Ip: -Ic: debug.c 8 | lb util.lib util.o conio.o dirent.o dpb.o debug.o os.o gfx.o 9 | cc -D__CPM86__ -Ip: -Ic: dump.c 10 | sqz dump.o 11 | ln -o dump.cmd dump.o util.lib p:c.lib 12 | cc -D__CPM86__ -Ip: -Ic: more.c 13 | sqz more.o 14 | ln -o mode.cmd more.o util.lib p:c.lib 15 | cc -D__CPM86__ -Ip: -Ic: mode.c 16 | sqz mode.o 17 | ln -o mode.cmd mode.o util.lib p:c.lib 18 | cc -D__CPM86__ -Ip: -Ic: write.c 19 | sqz write.o 20 | ln -o write.cmd write.o util.lib p:c.lib 21 | cc -D__CPM86__ -Ip: -Ic: ls.c 22 | sqz ls.o 23 | ln -o ls.cmd ls.o util.lib p:c.lib 24 | cc -D__CPM86__ -Ip: -Ic: touch.c 25 | sqz touch.o 26 | ln -o touch.cmd touch.o p:c.lib 27 | cc -D__CPM86__ -Ip: -Ic: rm.c 28 | sqz rm.o 29 | ln -o rm.cmd rm.o util.lib p:c.lib 30 | cc -D__CPM86__ -Ip: -Ic: printenv.c 31 | sqz printenv.o 32 | ln -o printenv.cmd printenv.o util.lib p:c.lib 33 | cc -D__CPM86__ -Ip: -Ic: ciotest.c 34 | sqz ciotest.o 35 | ln -o ciotest.cmd ciotest.o util.lib p:c.lib 36 | cc -D__CPM86__ -Ip: -Ic: ball.c 37 | sqz ball.o 38 | ln -o ball.cmd ball.o util.lib p:c.lib 39 | cc -D__CPM86__ -Ip: -Ic: getch.c 40 | sqz getch.o 41 | ln -o getch.cmd getch.o util.lib p:c.lib 42 | rasm86 atinit $$ pz sz 43 | link86 atinit[$$sz] 44 | rasm86 attime $$ pz sz 45 | link86 attime[$$sz] 46 | rasm86 mem $$ pz sz 47 | link86 mem[$$sz] 48 | rasm86 ver $$ pz sz 49 | link86 ver[$$sz] 50 | rasm86 clsansi $$ pz sz 51 | link86 clsansi[$$sz] 52 | rasm86 cls $$ pz sz 53 | link86 cls[$$sz] 54 | rasm86 pause $$ pz sz 55 | link86 pause[$$sz] 56 | rasm86 tod $$ pz sz 57 | link86 tod[$$sz] 58 | rasm86 reboot $$ pz sz 59 | link86 reboot[$$sz] 60 | -------------------------------------------------------------------------------- /ccpm86: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | lockfile=`dirname $0`/ibmxt.lock 3 | graph=vga 4 | if [ ! -z "$1" ];then 5 | graph=$1 6 | fi 7 | if ( set -o noclobber; echo "$$" > "$lockfile") 2> /dev/null; then 8 | 9 | trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT 10 | 11 | cd "`dirname $0`" 12 | pce-ibmpc -c `basename $0`.cfg -l `basename $0`-pce.log -g "$graph" -r 13 | 14 | # clean up after yourself, and release your trap 15 | rm -f "$lockfile" 16 | trap - INT TERM EXIT 17 | else 18 | echo "Lock Exists: $lockfile owned by $(cat $lockfile)" 19 | fi 20 | -------------------------------------------------------------------------------- /ccpm86.cfg: -------------------------------------------------------------------------------- 1 | path = "rom" 2 | 3 | system { 4 | model = "5160" 5 | 6 | boot = 0 7 | rtc = 1 8 | 9 | memtest = 0 10 | 11 | floppy_disk_drives = 2 12 | 13 | patch_bios_init = 1 14 | patch_bios_int19 = 1 15 | } 16 | 17 | cpu { 18 | model = "8088" 19 | speed = 16 20 | } 21 | 22 | load { 23 | format = "binary" 24 | address = 0xfe000 25 | file = "ibm-xt-1982-11-08.rom" 26 | } 27 | 28 | load { 29 | format = "binary" 30 | address = 0xf6000 31 | file = "ibm-basic-1.10.rom" 32 | } 33 | 34 | load { 35 | format = "binary" 36 | address = 0xf0000 37 | file = "ibmpc-pcex.rom" 38 | } 39 | 40 | 41 | ram { 42 | address = 0 43 | size = 640K 44 | } 45 | 46 | rom { 47 | address = 0xf0000 48 | size = 64K 49 | } 50 | 51 | terminal { 52 | driver = "sdl" 53 | 54 | # escape = "CtrlRight" 55 | 56 | scale = 1 57 | border = 0 58 | fullscreen = 0 59 | 60 | mouse_mul_x = 1 61 | mouse_div_x = 1 62 | mouse_mul_y = 1 63 | mouse_div_y = 1 64 | } 65 | 66 | terminal { 67 | driver = "x11" 68 | 69 | # escape = "CtrlRight" 70 | 71 | scale = 1 72 | 73 | mouse_mul_x = 2 74 | mouse_div_x = 5 75 | mouse_mul_y = 2 76 | mouse_div_y = 5 77 | } 78 | 79 | terminal { 80 | driver = "null" 81 | } 82 | 83 | video { 84 | device = "hgc" 85 | color = "amber" 86 | blink = 30 87 | } 88 | 89 | video { 90 | device = "vga" 91 | blink = 30 92 | enable_irq = 0 93 | irq = 2 94 | 95 | rom { 96 | address = 0xc0000 97 | size = 32768 98 | default = 0xff 99 | file = "ibm-vga-1986-10-27.rom" 100 | } 101 | } 102 | 103 | video { 104 | device = "ega" 105 | switches = 0x09 # EGA with EGA monitor (EGA mode) 106 | blink = 30 107 | enable_irq = 0 108 | irq = 2 109 | 110 | rom { 111 | address = 0xc0000 112 | size = 16384 113 | default = 0xff 114 | file = "ibm-ega-1984-09-13.rom" 115 | } 116 | } 117 | 118 | video { 119 | device = "cga" 120 | font = 1 121 | blink = 30 122 | } 123 | 124 | video { 125 | device = "mda" 126 | color = "green" 127 | blink = 30 128 | } 129 | 130 | speaker { 131 | volume = 250 132 | lowpass = 8000 133 | sample_rate = 44100 134 | 135 | # driver = "oss:dev=/dev/dsp:lowpass=5000:wav=speaker.wav:wavfilter=0" 136 | driver = "sdl:lowpass=5000" 137 | } 138 | 139 | serial { 140 | uart = "8250" 141 | address = 0x3f8 142 | irq = 4 143 | multichar = 1 144 | driver = "stdio:file/dev/null:flush=1" 145 | } 146 | 147 | parport { 148 | address = 0x378 149 | driver = "stdio:file=/dev/null:flush=1" 150 | } 151 | 152 | parport { 153 | address = 0x278 154 | driver = "stdio:file/dev/null:flush=1" 155 | } 156 | 157 | cassette { 158 | enable = 1 159 | file = "cas1.cas" 160 | # pcm = 1 161 | filter = 1 162 | mode = "load" 163 | position = 0 164 | append = 0 165 | } 166 | 167 | fdc { 168 | address = 0x3f0 169 | irq = 6 170 | 171 | drive0 = 0x00 172 | drive1 = 0x01 173 | 174 | accurate = 0 175 | } 176 | 177 | disk { 178 | drive = 0x00 179 | type = "auto" 180 | file = "cdos-3.2.img" 181 | optional = 0 182 | } 183 | 184 | disk { 185 | drive = 0x01 186 | type = "auto" 187 | file = "cpmtest.img" 188 | optional = 1 189 | } 190 | -------------------------------------------------------------------------------- /ciotest.c: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed under the MIT license. See LICENSE file in the project root for details. 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #ifndef __STDC__ 10 | int main(argc,argv) 11 | int argc; 12 | char **argv; 13 | #else 14 | int main(int argc, char **argv) 15 | #endif 16 | { 17 | int i; 18 | int c; 19 | int j; 20 | 21 | clrscr(); 22 | cursor(CURSOR_OFF); 23 | statline(STATLINE_OFF); 24 | gotoxy(0,0);cputs("(0,0)"); 25 | gotoxy(0,74);cputs("(0,79)"); 26 | gotoxy(23,73);wrapline(WRAPLINE_OFF);cputs("(23,79)");wrapline(WRAPLINE_ON); 27 | gotoxy(23,0);cputs("(23,0)"); 28 | for(i=0;i<10;i++) { 29 | gotoxy(3+i,1); 30 | textcolor(2); 31 | printf("[%02d] Line Added ----------",i+1); 32 | textcolor(4); 33 | printf("oooooooooooo"); 34 | } 35 | c=getch(); 36 | for(j=0;j<40;j++){ 37 | for(i=0;i<10;i++) { 38 | gotoxy(3+i,1); 39 | textcolor(j%16); 40 | printf("[%02d] Line Added ----------",i+1); 41 | } 42 | c=getch(); 43 | } 44 | c=getch(); 45 | textcolor(4); 46 | gotoxy(23,26); 47 | printf("[press a key to continue]"); 48 | c=getch(); 49 | delline(); 50 | crtreset(); 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /clrhack.bat: -------------------------------------------------------------------------------- 1 | del *.cmd 2 | del *.obj 3 | del *.o 4 | del util.lib 5 | -------------------------------------------------------------------------------- /clrhack.sub: -------------------------------------------------------------------------------- 1 | era *.cmd 2 | era *.obj 3 | era *.o 4 | era util.lib 5 | -------------------------------------------------------------------------------- /cls.a86: -------------------------------------------------------------------------------- 1 | ; 2 | ; Licensed under the MIT license. See LICENSE file in the project root for details. 3 | ; 4 | 5 | title 'Clear Screen' 6 | 7 | cseg 8 | mov cx, cs 9 | mov ds, cx 10 | mov es, cx 11 | mov dx, offset cls_hdr 12 | mov cl,9 13 | int 0E0h 14 | xor cx,cx 15 | int 0E0h 16 | cls_hdr db 27,'E$' 17 | end 18 | -------------------------------------------------------------------------------- /clsansi.a86: -------------------------------------------------------------------------------- 1 | ; 2 | ; Licensed under the MIT license. See LICENSE file in the project root for details. 3 | ; 4 | 5 | title 'Clear Screen' 6 | 7 | cseg 8 | mov cx,ds 9 | mov es,cx 10 | mov dx, offset cls_hdr 11 | mov cl,9 12 | int 0E0h 13 | xor cx,cx 14 | int 0E0h 15 | 16 | dseg 17 | cls_hdr db 27,'[2J',27,'[H$' 18 | end 19 | -------------------------------------------------------------------------------- /conio.c: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed under the MIT license. See LICENSE file in the project root for details. 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #ifdef __STDC__ 10 | #include 11 | #else 12 | char * malloc(); 13 | #endif 14 | 15 | 16 | int kbhit() { 17 | return bdos(6,254); 18 | } 19 | 20 | #define GETCH_BUFLEN (64) 21 | 22 | static char * getch_buffer=0; 23 | 24 | #ifndef __STDC__ 25 | int cputc(c) 26 | char c; 27 | #else 28 | int cputc(char c) 29 | #endif 30 | { 31 | return bdos(2,c); 32 | } 33 | 34 | #ifndef __STDC__ 35 | int cputs(str) 36 | char *str; 37 | #else 38 | int cputs(char *str) 39 | #endif 40 | { 41 | while (*str) { 42 | bdos(2,*str++); 43 | } 44 | return 0; 45 | } 46 | 47 | int getch() 48 | { 49 | int i,c,d; 50 | static int s=0; 51 | static int o=0; 52 | 53 | if(getch_buffer==0) { 54 | getch_buffer=(char*)malloc(GETCH_BUFLEN+1); 55 | } 56 | if(s>0) { 57 | c=getch_buffer[o];s--;o++; 58 | o=o%GETCH_BUFLEN; 59 | return c; 60 | } 61 | while(!(c=bdos(6,255))) 62 | continue; 63 | while(s0x22) { 79 | cputs("\x1be\x1bz"); 80 | } else { 81 | cputs("\x1bm\x1b0\x1b1\x1bq\x1bt\x1bu"); 82 | } 83 | } 84 | 85 | #ifndef __STDC__ 86 | clrscr() 87 | #else 88 | void clrscr() 89 | #endif 90 | { 91 | cputs("\x1bE"); 92 | } 93 | 94 | #ifndef __STDC__ 95 | clreos() 96 | #else 97 | void clreos() 98 | #endif 99 | { 100 | cputs("\x1bJ"); 101 | } 102 | 103 | #ifndef __STDC__ 104 | clreol() 105 | #else 106 | void clreol() 107 | #endif 108 | { 109 | cputs("\x1bK"); 110 | } 111 | 112 | #ifndef __STDC__ 113 | delchar() 114 | #else 115 | void delchar() 116 | #endif 117 | { 118 | cputs("\x1bN"); 119 | } 120 | 121 | #ifndef __STDC__ 122 | insline() 123 | #else 124 | void insline() 125 | #endif 126 | { 127 | cputs("\x1bL"); 128 | } 129 | 130 | #ifndef __STDC__ 131 | delline() 132 | #else 133 | void delline() 134 | #endif 135 | { 136 | cputs("\x1bM"); 137 | } 138 | 139 | #ifndef __STDC__ 140 | gotoxy(x, y) 141 | int x; 142 | int y; 143 | #else 144 | void gotoxy(int x, int y) 145 | #endif 146 | { 147 | char msg[5]; 148 | msg[0]=27; 149 | msg[1]='Y'; 150 | msg[2]=x+32; 151 | msg[3]=y+32; 152 | msg[4]=0; 153 | cputs(msg); 154 | } 155 | 156 | #ifndef __STDC__ 157 | cursor(cmd) 158 | int cmd; 159 | #else 160 | void cursor(int cmd) 161 | #endif 162 | { 163 | switch(cmd) { 164 | case CURSOR_ON: 165 | if(osver()>0x22) 166 | cputs("\x1be"); 167 | else 168 | cputs("\x1bm"); 169 | break; 170 | case CURSOR_OFF: 171 | if(osver()>0x22) 172 | cputs("\x1bf"); 173 | else 174 | cputs("\x1bn"); 175 | break; 176 | case CURSOR_SAVE: 177 | cputs("\x1bj"); 178 | break; 179 | case CURSOR_RESTORE: 180 | cputs("\x1bk"); 181 | break; 182 | } 183 | } 184 | 185 | #ifndef __STDC__ 186 | wrapline(on) 187 | int on; 188 | #else 189 | void wrapline(int on) 190 | #endif 191 | { 192 | cputs(on?"\x1bv":"\x1bw"); 193 | } 194 | 195 | #ifndef __STDC__ 196 | scrmode(m) 197 | int m; 198 | #else 199 | void scrmode(int m) 200 | #endif 201 | { 202 | if(osver()>0x22) { 203 | return; 204 | } 205 | switch(m) { 206 | case SCRMODE_DEFAULT: 207 | crtreset(); 208 | clrscr(); 209 | break; 210 | case SCRMODE_COL80: 211 | ; 212 | #asm 213 | push ax 214 | push bx 215 | push cx 216 | push dx 217 | mov al, 3 218 | mov ah, 0 219 | int 10h 220 | pop dx 221 | pop cx 222 | pop bx 223 | pop ax 224 | #endasm 225 | statline(STATLINE_OFF); 226 | statline(STATLINE_ON); 227 | clrscr(); 228 | break; 229 | case SCRMODE_COL40: 230 | ; 231 | #asm 232 | push ax 233 | push bx 234 | push cx 235 | push dx 236 | mov ax, 0 237 | int 10h 238 | pop dx 239 | pop cx 240 | pop bx 241 | pop ax 242 | #endasm 243 | statline(STATLINE_OFF); 244 | clrscr(); 245 | break; 246 | case SCRMODE_MONO: 247 | cputs("\x1by"); 248 | break; 249 | case SCRMODE_COLOR: 250 | cputs("\x1bx"); 251 | break; 252 | } 253 | } 254 | 255 | #ifndef __STDC__ 256 | statline(on) 257 | int on; 258 | #else 259 | void statline(int on) 260 | #endif 261 | { 262 | int os=osver(); 263 | if(os>0x31) { 264 | xstatline(on?2:1); 265 | return; 266 | } 267 | if(os==0x22) { 268 | cputs(on?"\x1b1":"\x1b0"); 269 | return; 270 | } 271 | } 272 | 273 | #ifndef __STDC__ 274 | textcolor(fg) 275 | int fg; 276 | #else 277 | void textcolor(int fg) 278 | #endif 279 | { 280 | unsigned char msg[8]; 281 | if(fg<1) { 282 | return; 283 | } 284 | msg[0]=27; 285 | msg[1]='j'; 286 | msg[2]=27; 287 | msg[3]='b'; 288 | msg[4]=((unsigned char)fg); 289 | msg[5]=27; 290 | msg[6]='k'; 291 | msg[7]=0; 292 | cputs((char*)msg); 293 | } 294 | 295 | 296 | #ifndef __STDC__ 297 | setstatus(arg) 298 | char* arg; 299 | #else 300 | void setstatus(char* arg) 301 | #endif 302 | { 303 | int i=0; 304 | int es; 305 | int bx; 306 | int ax; 307 | int segs[4]; 308 | int escape=0; 309 | int upper=0; 310 | 311 | if(osver()>0x22) { 312 | return; 313 | } 314 | segread(segs); 315 | ax=bdosx(49,0,&es,&bx); 316 | while(i<14) { 317 | if(*arg=='\\') { 318 | escape=1; 319 | arg++; 320 | continue; 321 | } 322 | if(*arg) { 323 | char c; 324 | c=*arg; 325 | if(escape) { 326 | escape=0; 327 | switch(c) { 328 | case 'u': 329 | case 'U': 330 | upper=1; 331 | c=0; 332 | break; 333 | case 'l': 334 | case 'L': 335 | upper=0; 336 | c=0; 337 | break; 338 | case 's': 339 | case 'S': 340 | c=' '; 341 | break; 342 | case '\\': 343 | c=' '; 344 | break; 345 | default: 346 | c=0; 347 | break; 348 | } 349 | } 350 | if(!c) { 351 | arg++; 352 | continue; 353 | } 354 | if(c<' ') { 355 | c=' '; 356 | } 357 | if(isalpha(c) && !upper) { 358 | pokeb(bx+0x32+i,es,tolower(c)); 359 | } else { 360 | pokeb(bx+0x32+i,es,c); 361 | } 362 | i++; 363 | arg++; 364 | } else { 365 | pokeb(bx+0x32+i,es,' '); 366 | i++; 367 | } 368 | } 369 | } 370 | -------------------------------------------------------------------------------- /conio.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONIO_H_ 2 | #define _CONIO_H_ 3 | 4 | 5 | /* 6 | Licensed under the MIT license. See LICENSE file in the project root for details. 7 | */ 8 | 9 | #define WRAPLINE_OFF 0 10 | #define WRAPLINE_ON 1 11 | 12 | #define STATLINE_OFF 0 13 | #define STATLINE_ON 1 14 | 15 | #define CURSOR_OFF 0 16 | #define CURSOR_ON 1 17 | #define CURSOR_SAVE 2 18 | #define CURSOR_RESTORE 3 19 | 20 | #define SCRMODE_DEFAULT 0 21 | #define SCRMODE_COL80 1 22 | #define SCRMODE_COL40 2 23 | #define SCRMODE_MONO 4 24 | #define SCRMODE_COLOR 8 25 | 26 | #ifndef __STDC__ 27 | int kbhit(); 28 | int getch(); 29 | clrscr(); 30 | crtreset(); 31 | clreol(); 32 | clreos(); 33 | delline(); 34 | insline(); 35 | delchar(); 36 | cursor(); 37 | statline(); 38 | wrapline(); 39 | gotoxy(); 40 | textcolor(); 41 | setstatus(); 42 | int cputs(); 43 | int cputc(); 44 | scrmode(); 45 | #else 46 | int kbhit(); 47 | int getch(); 48 | void clrscr(); 49 | void crtreset(); 50 | void clreol(); 51 | void clreos(); 52 | void delline(); 53 | void insline(); 54 | void delchar(); 55 | void cursor(int on); 56 | void statline(int on); 57 | void wrapline(int on); 58 | void gotoxy(int x, int y); 59 | void textcolor(int fg); 60 | void setstatus(char * s); 61 | int cputs(char *); 62 | int cputc(char); 63 | void scrmode(int); 64 | #endif 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /cpm86: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | lockfile=`dirname $0`/ibmxt.lock 3 | graph=vga 4 | if [ ! -z "$1" ];then 5 | graph=$1 6 | fi 7 | if ( set -o noclobber; echo "$$" > "$lockfile") 2> /dev/null; then 8 | 9 | trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT 10 | 11 | cd "`dirname $0`" 12 | pce-ibmpc -c `basename $0`.cfg -l `basename $0`-pce.log -g "$graph" -r 13 | 14 | # clean up after yourself, and release your trap 15 | rm -f "$lockfile" 16 | trap - INT TERM EXIT 17 | else 18 | echo "Lock Exists: $lockfile owned by $(cat $lockfile)" 19 | fi 20 | -------------------------------------------------------------------------------- /cpm86.cfg: -------------------------------------------------------------------------------- 1 | path = "rom" 2 | 3 | system { 4 | model = "5160" 5 | 6 | boot = 0 7 | rtc = 1 8 | 9 | memtest = 0 10 | 11 | floppy_disk_drives = 2 12 | 13 | patch_bios_init = 1 14 | patch_bios_int19 = 1 15 | } 16 | 17 | cpu { 18 | model = "8088" 19 | speed = 16 20 | } 21 | 22 | load { 23 | format = "binary" 24 | address = 0xfe000 25 | file = "ibm-xt-1982-11-08.rom" 26 | } 27 | 28 | load { 29 | format = "binary" 30 | address = 0xf6000 31 | file = "ibm-basic-1.10.rom" 32 | } 33 | 34 | load { 35 | format = "binary" 36 | address = 0xf0000 37 | file = "ibmpc-pcex.rom" 38 | } 39 | 40 | ram { 41 | address = 0 42 | size = 640K 43 | } 44 | 45 | xms { 46 | xms_size = 0M 47 | umb_size = 128K 48 | umb_segm = 0xd000 49 | hma = 1 50 | } 51 | 52 | rom { 53 | address = 0xf0000 54 | size = 64K 55 | } 56 | 57 | terminal { 58 | driver = "sdl" 59 | 60 | # escape = "CtrlRight" 61 | 62 | scale = 1 63 | border = 0 64 | fullscreen = 0 65 | 66 | mouse_mul_x = 1 67 | mouse_div_x = 1 68 | mouse_mul_y = 1 69 | mouse_div_y = 1 70 | } 71 | 72 | terminal { 73 | driver = "x11" 74 | 75 | # escape = "CtrlRight" 76 | 77 | scale = 1 78 | 79 | mouse_mul_x = 2 80 | mouse_div_x = 5 81 | mouse_mul_y = 2 82 | mouse_div_y = 5 83 | } 84 | 85 | terminal { 86 | driver = "null" 87 | } 88 | 89 | video { 90 | device = "hgc" 91 | color = "amber" 92 | blink = 30 93 | } 94 | 95 | video { 96 | device = "vga" 97 | blink = 30 98 | enable_irq = 0 99 | irq = 2 100 | 101 | rom { 102 | address = 0xc0000 103 | size = 32768 104 | default = 0xff 105 | file = "ibm-vga-1986-10-27.rom" 106 | } 107 | } 108 | 109 | video { 110 | device = "ega" 111 | switches = 0x09 # EGA with EGA monitor (EGA mode) 112 | blink = 30 113 | enable_irq = 0 114 | irq = 2 115 | 116 | rom { 117 | address = 0xc0000 118 | size = 16384 119 | default = 0xff 120 | file = "ibm-ega-1984-09-13.rom" 121 | } 122 | } 123 | 124 | video { 125 | device = "cga" 126 | font = 1 127 | blink = 30 128 | } 129 | 130 | video { 131 | device = "mda" 132 | color = "green" 133 | blink = 30 134 | } 135 | 136 | speaker { 137 | volume = 250 138 | lowpass = 8000 139 | sample_rate = 44100 140 | 141 | # driver = "oss:dev=/dev/dsp:lowpass=5000:wav=speaker.wav:wavfilter=0" 142 | driver = "sdl:lowpass=5000" 143 | } 144 | 145 | serial { 146 | uart = "8250" 147 | address = 0x3f8 148 | irq = 4 149 | multichar = 1 150 | driver = "stdio:file/dev/null:flush=1" 151 | } 152 | 153 | parport { 154 | address = 0x378 155 | driver = "stdio:file=/dev/null:flush=1" 156 | } 157 | 158 | parport { 159 | address = 0x278 160 | driver = "stdio:file/dev/null:flush=1" 161 | } 162 | 163 | cassette { 164 | enable = 1 165 | file = "cas1.cas" 166 | # pcm = 1 167 | filter = 1 168 | mode = "load" 169 | position = 0 170 | append = 0 171 | } 172 | 173 | fdc { 174 | address = 0x3f0 175 | irq = 6 176 | 177 | drive0 = 0x00 178 | drive1 = 0x01 179 | 180 | accurate = 0 181 | } 182 | 183 | if (cfg.hdc) { 184 | rom { 185 | address = 0xc8000 186 | size = 32K 187 | } 188 | 189 | load { 190 | format = "binary" 191 | address = 0xc8000 192 | file = "st-506/ibm-mfm-1987.rom" 193 | } 194 | 195 | hdc { 196 | address = 0x320 197 | irq = 5 198 | 199 | drive0 = 0x80 200 | drive1 = 0x81 201 | 202 | switches = 0x00 203 | } 204 | } 205 | 206 | 207 | disk { 208 | drive = 0x00 209 | type = "auto" 210 | file = "cpm86-1.1.img" 211 | optional = 0 212 | } 213 | 214 | disk { 215 | drive = 0x01 216 | type = "auto" 217 | file = "cpmtest.img" 218 | optional = 0 219 | } 220 | 221 | 222 | disk { 223 | drive = 0x80 224 | type = "auto" 225 | file = "cpmhd.img" 226 | optional = 1 227 | } 228 | 229 | -------------------------------------------------------------------------------- /cpmbase.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tsupplis/cpm86-hacking/ccea6c9ea4634fb2b92c680d06ce1c867e11c333/cpmbase.img -------------------------------------------------------------------------------- /debug.c: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed under the MIT license. See LICENSE file in the project root for details. 3 | */ 4 | 5 | #include 6 | #ifdef __STDC__ 7 | #include 8 | #endif 9 | #include "debug.h" 10 | 11 | /*#define DEBUG*/ 12 | #ifndef __STDC__ 13 | unsigned long debug_dump_hex(fd, data, size, offset, raw) 14 | FILE *fd; 15 | char *data; 16 | unsigned int size; 17 | unsigned long offset; 18 | int raw; 19 | #else 20 | unsigned long debug_dump_hex(FILE *fd, char*data, unsigned int size, 21 | unsigned long offset, int raw) 22 | #endif 23 | { 24 | #ifdef DEBUG 25 | char ascii[17]; 26 | unsigned int i, j; 27 | ascii[16] = '\0'; 28 | for (i = 0; i < size; ++i) { 29 | if (i % 16 == 0 && !raw) { 30 | fprintf(fd, "%06x: ", offset); 31 | } 32 | offset++; 33 | fprintf(fd, "%02x ", ((unsigned char *)data)[i]); 34 | if (data[i] >= ' ' && data[i] <= '~') { 35 | ascii[i % 16] = data[i]; 36 | } else { 37 | ascii[i % 16] = '.'; 38 | } 39 | if ((i + 1) % 8 == 0 || i + 1 == size) { 40 | if (!raw) { 41 | fprintf(fd, " "); 42 | } 43 | if ((i + 1) % 16 == 0) { 44 | if (raw) { 45 | fprintf(fd, "\n"); 46 | } else { 47 | fprintf(fd, "| %s \n", ascii); 48 | } 49 | } else if (i + 1 == size) { 50 | ascii[(i + 1) % 16] = '\0'; 51 | if ((i + 1) % 16 <= 8) { 52 | if (!raw) { 53 | fprintf(fd, " "); 54 | } 55 | } 56 | for (j = (i + 1) % 16; j < 16; ++j) { 57 | if (!raw) { 58 | fprintf(fd, " "); 59 | } 60 | } 61 | if (raw) { 62 | fprintf(fd, "\n"); 63 | } else { 64 | fprintf(fd, "| %s \n", ascii); 65 | } 66 | } 67 | } 68 | } 69 | #endif 70 | return offset; 71 | } 72 | 73 | -------------------------------------------------------------------------------- /debug.h: -------------------------------------------------------------------------------- 1 | #ifndef _DEBUG_H 2 | #define _DEBUG_H 3 | 4 | /* 5 | Licensed under the MIT license. See LICENSE file in the project root for details. 6 | */ 7 | 8 | #ifndef __STDC__ 9 | unsigned long debug_dump_hex(); 10 | #else 11 | unsigned long debug_dump_hex(FILE *fd, char*data, unsigned int size, 12 | unsigned long offset, int raw); 13 | #endif 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /dirent.c: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed under the MIT license. See LICENSE file in the project root for details. 3 | */ 4 | 5 | #include 6 | #ifdef __STDC__ 7 | #include 8 | #endif 9 | #include 10 | #include 11 | 12 | /*#define DEBUG*/ 13 | 14 | #ifdef DEBUG 15 | #include "debug.h" 16 | #endif 17 | 18 | #ifndef __STDC__ 19 | int dirent_next(fcb, root, last, all_extents) 20 | char * fcb; 21 | dirent_t * root; 22 | dirent_t ** last; 23 | int all_extents; 24 | #else 25 | int dirent_next(char * fcb, dirent_t * root, dirent_t ** last, int all_extents) 26 | #endif 27 | { 28 | int rc=0; 29 | unsigned char* f=0; 30 | dirent_t* cursor=0; 31 | int i; 32 | 33 | rc=bdos(18,fcb); 34 | if(rc==255) { 35 | return rc; 36 | } 37 | i=rc; 38 | f=(unsigned char*)(0x80+rc*32); 39 | #ifdef DEBUG 40 | fprintf(stderr,"dirent_next->fcb\n",rc); 41 | debug_dump_hex(stderr, (unsigned char*)(fcb), 33, 0L, 0); 42 | fprintf(stderr,"->%d\n",rc); 43 | debug_dump_hex(stderr, (unsigned char*)(0x80), 32*4, 0L, 0); 44 | getchar(); 45 | #endif 46 | cursor=root; 47 | while(cursor) { 48 | if(!memcmp(f+1,(cursor->entry)+1,11)) { 49 | if(root->is_fat) { 50 | unsigned int * s=(unsigned int *)(f+28); 51 | cursor->blocks=((unsigned long)(*s)+cursor->block_size-1)/ 52 | cursor->block_size; 53 | #ifdef DEBUG 54 | fprintf(stderr,"---------->fat blocks %ld\n",*s); 55 | fprintf(stderr,"---------->fat blocks %ld\n",*s+cursor->block_size-1); 56 | fprintf(stderr,"---------->fat blocks %ld\n",cursor->blocks); 57 | fprintf(stderr,"---------->fat block size %ld\n",cursor->block_size); 58 | #endif 59 | } else if(root->drive_blocks<=256) { 60 | int j; 61 | char *blocks; 62 | blocks=(char*)(f+16); 63 | for(j=0;j<16;j++) { 64 | if(!blocks[j]) 65 | break; 66 | cursor->blocks++; 67 | } 68 | } else { 69 | int j; 70 | int *blocks; 71 | blocks=(int*)(f+16); 72 | for(j=0;j<8;j++) { 73 | if(!blocks[j]) 74 | break; 75 | cursor->blocks++; 76 | } 77 | } 78 | cursor->fcbs++; 79 | rc=0; 80 | return rc; 81 | } 82 | cursor=cursor->next; 83 | } 84 | cursor=(dirent_t*)malloc(sizeof(dirent_t)); 85 | if(!cursor) { 86 | return -2; 87 | } 88 | memset(cursor,0,sizeof(dirent_t)); 89 | memcpy(cursor->entry,f,12); 90 | cursor->drive=root->drive; 91 | cursor->block_size=root->block_size; 92 | cursor->drive_blocks=root->drive_blocks; 93 | cursor->is_fat=root->is_fat; 94 | if(root->is_fat) { 95 | unsigned int * s=(unsigned int *)(f+28); 96 | cursor->blocks=((unsigned long)(*s)+cursor->block_size-1)/ 97 | cursor->block_size; 98 | #ifdef DEBUG 99 | fprintf(stderr,"---------->fat blocks %ld\n",*s); 100 | fprintf(stderr,"---------->fat blocks %ld\n",*s+cursor->block_size-1); 101 | fprintf(stderr,"---------->fat blocks %ld\n",cursor->blocks); 102 | fprintf(stderr,"---------->fat block size %ld\n",cursor->block_size); 103 | #endif 104 | } else if(root->drive_blocks<=256) { 105 | int j; 106 | char *blocks; 107 | blocks=(char*)(f+16); 108 | for(j=0;j<16;j++) { 109 | if(!blocks[j]) 110 | break; 111 | cursor->blocks++; 112 | } 113 | } else { 114 | int j; 115 | int *blocks; 116 | blocks=(int*)(f+16); 117 | for(j=0;j<8;j++) { 118 | if(!blocks[j]) 119 | break; 120 | cursor->blocks++; 121 | } 122 | } 123 | cursor->fcbs=1; 124 | last[0]->next=cursor; 125 | last[0]=cursor; 126 | rc=0; 127 | return rc; 128 | } 129 | 130 | #ifndef __STDC__ 131 | int dirent_first(fcb, root) 132 | char * fcb; 133 | dirent_t ** root; 134 | #else 135 | int dirent_first(char * fcb, dirent_t ** root) 136 | #endif 137 | { 138 | int rc=0; 139 | unsigned char* f=0; 140 | int is_fat=dirent_is_fat(fcb[0]-1); 141 | 142 | rc=bdos(17,fcb); 143 | if(rc==255) { 144 | *root=0; 145 | return rc; 146 | } 147 | f=(unsigned char*)(0x80+rc*32); 148 | #ifdef DEBUG 149 | fprintf(stderr,"dirent_first->fcb\n",rc); 150 | debug_dump_hex(stderr, (unsigned char*)(fcb), 33, 0L, 0); 151 | fprintf(stderr,"->%d\n",rc); 152 | debug_dump_hex(stderr, (unsigned char*)(0x80), 32*4, 0L, 0); 153 | getchar(); 154 | #endif 155 | root[0]=(dirent_t*)malloc(sizeof(dirent_t)); 156 | if(!root[0]) { 157 | return -2; 158 | } 159 | memset(root[0],0,sizeof(dirent_t)); 160 | memcpy(root[0]->entry,f,12); 161 | root[0]->drive=fcb[0]-1; 162 | root[0]->is_fat=is_fat; 163 | { 164 | dpb_t dpb; 165 | dpb_load(root[0]->drive,&dpb); 166 | root[0]->block_size=128<drive_blocks=dpb.dsm+1; 168 | #ifdef DEBUG 169 | fprintf(stderr,"disk_info->%lu %lu\n",root[0]->block_size,root[0]->drive_blocks); 170 | getchar(); 171 | #endif 172 | } 173 | if(root[0]->is_fat) { 174 | unsigned int * s=(unsigned int *)(f+28); 175 | root[0]->blocks=((unsigned long)(*s)+root[0]->block_size-1)/root[0]->block_size; 176 | #ifdef DEBUG 177 | fprintf(stderr,"---------->fat blocks %ld\n",*s); 178 | fprintf(stderr,"---------->fat blocks %ld\n",*s+root[0]->block_size-1); 179 | fprintf(stderr,"---------->fat blocks %ld\n",root[0]->blocks); 180 | fprintf(stderr,"---------->fat block size %ld\n",root[0]->block_size); 181 | #endif 182 | } else if(root[0]->drive_blocks<=256) 183 | { 184 | int j; 185 | char *blocks; 186 | blocks=(char*)(f+16); 187 | for(j=0;j<16;j++) { 188 | if(!blocks[j]) 189 | break; 190 | root[0]->blocks++; 191 | } 192 | } else { 193 | int j; 194 | int *blocks; 195 | blocks=(int*)(f+16); 196 | for(j=0;j<8;j++) { 197 | if(!blocks[j]) 198 | break; 199 | root[0]->blocks++; 200 | } 201 | } 202 | root[0]->fcbs=1; 203 | rc=0; 204 | return rc; 205 | } 206 | 207 | 208 | #ifndef __STDC__ 209 | dirent_t* dirent_merge_sorted(lst1,lst2,sort_order) 210 | dirent_t* lst1; 211 | dirent_t* lst2; 212 | int sort_order; 213 | #else 214 | dirent_t* dirent_merge_sorted(dirent_t* lst1, dirent_t* lst2, int sort_order) 215 | #endif 216 | { 217 | dirent_t* result = 0; 218 | 219 | if (!lst1) 220 | return lst2; 221 | else if (!lst2) 222 | return lst1; 223 | 224 | if(memcmp(lst1->entry+1,lst2->entry+1,11)*sort_order<0) { 225 | result = lst1; 226 | result->next = dirent_merge_sorted(lst1->next, lst2, sort_order); 227 | } 228 | else { 229 | result = lst2; 230 | result->next = dirent_merge_sorted(lst1, lst2->next, sort_order); 231 | } 232 | return result; 233 | } 234 | 235 | #ifndef __STDC__ 236 | dirent_split(source, front, back) 237 | dirent_t* source; 238 | dirent_t** front; 239 | dirent_t** back; 240 | #else 241 | void dirent_split(dirent_t* source, dirent_t** front, dirent_t** back) 242 | #endif 243 | { 244 | dirent_t* slow = source; 245 | dirent_t* fast = source->next; 246 | 247 | while (fast && fast->next) { 248 | fast = fast->next; 249 | if (fast) { 250 | slow = slow->next; 251 | fast = fast->next; 252 | } 253 | } 254 | 255 | *front = source; 256 | *back = slow->next; 257 | slow->next = 0; 258 | } 259 | 260 | #ifndef __STDC__ 261 | dirent_sort(root, sort_order) 262 | dirent_t** root; 263 | int sort_order; 264 | #else 265 | dirent_sort(dirent_t** root, int sort_order) 266 | #endif 267 | { 268 | dirent_t* head = *root; 269 | dirent_t* entry1; 270 | dirent_t* entry2; 271 | 272 | if ((head == 0) || (head->next == 0)) { 273 | return; 274 | } 275 | 276 | dirent_split(head, &entry1, &entry2); 277 | 278 | if(entry1 && entry1->next) dirent_sort(&entry1, sort_order); 279 | if(entry2 && entry2->next) dirent_sort(&entry2, sort_order); 280 | 281 | *root = dirent_merge_sorted(entry1, entry2, sort_order); 282 | } 283 | 284 | #ifndef __STDC__ 285 | int dirent_free(root) 286 | dirent_t * root; 287 | #else 288 | int dirent_free(dirent_t * root) 289 | #endif 290 | { 291 | while(root) { 292 | dirent_t *temp=root->next; 293 | free(root); 294 | root=temp; 295 | } 296 | return 0; 297 | } 298 | 299 | #ifndef __STDC__ 300 | int dirent_is_fat(drive) 301 | int drive; 302 | #else 303 | int dirent_is_fat(int drive) 304 | #endif 305 | { 306 | char fcb[40]; 307 | int rc=0; 308 | unsigned char* f=0; 309 | int curdrive=getcurdrv(); 310 | 311 | setcurdrv(drive); 312 | 313 | fcbinit("",fcb); 314 | memset(fcb,0,sizeof(fcb)); 315 | memset(fcb,'?',12); 316 | #ifdef DEBUG 317 | fprintf(stderr,"dirent_is_fat->curdrive %u\n",drive); 318 | fprintf(stderr,"dirent_is_fat->newdrive %u\n",drive); 319 | fprintf(stderr,"dirent_is_fat->fcb\n",rc); 320 | debug_dump_hex(stderr, (unsigned char*)(fcb), 33, 0L, 0); 321 | #endif 322 | rc=bdos(17,fcb); 323 | setcurdrv(curdrive); 324 | if(rc==255) { 325 | return 0; 326 | } 327 | f=(unsigned char*)(0x80+rc*32); 328 | #ifdef DEBUG 329 | fprintf(stderr,"->%d\n",rc); 330 | debug_dump_hex(stderr, (unsigned char*)(0x80), 32*4, 0L, 0); 331 | getchar(); 332 | #endif 333 | if(f[0x0F]==0x80 && f[0]==' ') { 334 | return 1; 335 | } 336 | return 0; 337 | } 338 | 339 | #ifndef __STDC__ 340 | int dirent_load(path, root, ouser, odrive, sort_order, all_extents) 341 | char * path; 342 | dirent_t ** root; 343 | int *ouser; 344 | int *odrive; 345 | int sort_order; 346 | int all_extents; 347 | #else 348 | int dirent_load(char * path, dirent_t ** root,int * ouser,int * odrive, 349 | int sort_order,int all_extents) 350 | #endif 351 | { 352 | char fcb[40]; 353 | int user; 354 | int rc=0; 355 | dirent_t * last=0; 356 | unsigned long count=0; 357 | 358 | memset(fcb,0,sizeof(fcb)); 359 | user=fcbinit(path,fcb); 360 | if(user==255) { 361 | user=getusr(); 362 | } 363 | if(ouser) { 364 | *ouser=user; 365 | } 366 | if(fcb[0]==0) { 367 | fcb[0]=getcurdrv()+1; 368 | } 369 | if(odrive) { 370 | *odrive=fcb[0]-1; 371 | } 372 | if(fcb[1]==' ') { 373 | int i; 374 | for(i=1;i<12;i++) { 375 | fcb[i]='?'; 376 | } 377 | } 378 | if(all_extents) { 379 | fcb[12]='?'; 380 | fcb[14]='?'; 381 | } 382 | #ifdef DEBUG 383 | fprintf(stderr,"dirent_load->fcb\n"); 384 | debug_dump_hex(stderr, (unsigned char*)(fcb), 33, 0L, 0); 385 | getchar(); 386 | #endif 387 | 388 | setusr(user); 389 | bdos(26,(char*)0x80); 390 | rc=dirent_first(fcb,root); 391 | if(rc) { 392 | return rc; 393 | } 394 | last=*root; 395 | count=1; 396 | while(!(rc=dirent_next(fcb,*root,&last,all_extents))) { 397 | count++; 398 | } 399 | if(rc==255) { 400 | rc=0; 401 | } 402 | #ifdef DEBUG 403 | fprintf(stderr,"dirent_load->done\n",rc); 404 | #endif 405 | rstusr(); 406 | if(sort_order) 407 | dirent_sort(root,sort_order); 408 | return rc; 409 | } 410 | 411 | #ifndef __STDC__ 412 | int dirent_fcb(fcb, d) 413 | char * fcb; 414 | dirent_t * d; 415 | #else 416 | int dirent_fcb(char * fcb, dirent_t * d) 417 | #endif 418 | { 419 | int stat=d->entry[0]; 420 | memcpy(fcb+1,d->entry+1,11); 421 | fcb[0]=d->drive+1; 422 | return stat; 423 | } 424 | -------------------------------------------------------------------------------- /dirent.h: -------------------------------------------------------------------------------- 1 | #ifndef _DIRENT_H_ 2 | #define _DIRENT_H_ 3 | 4 | /* 5 | Licensed under the MIT license. See LICENSE file in the project root for details. 6 | */ 7 | 8 | typedef struct _dirent_t { 9 | unsigned char entry[12+1]; 10 | int drive; 11 | unsigned long blocks; 12 | unsigned long drive_blocks; 13 | unsigned long block_size; 14 | int is_fat; 15 | unsigned long fcbs; 16 | struct _dirent_t * next; 17 | } dirent_t; 18 | 19 | #ifndef __STDC__ 20 | int dirent_next(); 21 | int dirent_first(); 22 | int dirent_free(); 23 | int dirent_load(); 24 | int dirent_is_fat(); 25 | int dirent_fcb(); 26 | #else 27 | int dirent_next(char * fcb, dirent_t * root, dirent_t ** last, int all_extents); 28 | int dirent_first(char * fcb, dirent_t ** root); 29 | int dirent_free(dirent_t * root); 30 | int dirent_load(char * path, dirent_t ** root,int *ouser, int *odrive, int sort_order, 31 | int all_extents); 32 | int dirent_is_fat(int drive); 33 | int dirent_fcb(char *fcb,dirent_t *d); 34 | 35 | #endif 36 | 37 | #define dirent_is_sys(a) (a->entry[10]&~0x7F) 38 | #define dirent_is_ro(a) (a->entry[9]&~0x7F) 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /dos: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | lockfile=`dirname $0`/ibmxt.lock 3 | graph=vga 4 | if [ ! -z "$1" ];then 5 | graph=$1 6 | fi 7 | if ( set -o noclobber; echo "$$" > "$lockfile") 2> /dev/null; then 8 | 9 | trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT 10 | 11 | cd "`dirname $0`" 12 | pce-ibmpc -c `basename $0`.cfg -l `basename $0`-pce.log -g "$graph" -r 13 | 14 | # clean up after yourself, and release your trap 15 | rm -f "$lockfile" 16 | trap - INT TERM EXIT 17 | else 18 | echo "Lock Exists: $lockfile owned by $(cat $lockfile)" 19 | fi 20 | -------------------------------------------------------------------------------- /dos.cfg: -------------------------------------------------------------------------------- 1 | path = "rom" 2 | 3 | system { 4 | model = "5160" 5 | 6 | boot = 0 7 | rtc = 1 8 | 9 | memtest = 0 10 | 11 | floppy_disk_drives = 2 12 | 13 | patch_bios_init = 1 14 | patch_bios_int19 = 1 15 | } 16 | 17 | cpu { 18 | model = "8088" 19 | speed = 16 20 | } 21 | 22 | load { 23 | format = "binary" 24 | address = 0xfe000 25 | file = "ibm-xt-1982-11-08.rom" 26 | } 27 | 28 | load { 29 | format = "binary" 30 | address = 0xf6000 31 | file = "ibm-basic-1.10.rom" 32 | } 33 | 34 | load { 35 | format = "binary" 36 | address = 0xf0000 37 | file = "ibmpc-pcex.rom" 38 | } 39 | 40 | 41 | ram { 42 | address = 0 43 | size = 512K 44 | } 45 | 46 | rom { 47 | address = 0xf0000 48 | size = 64K 49 | } 50 | 51 | terminal { 52 | driver = "sdl" 53 | 54 | # escape = "CtrlRight" 55 | 56 | scale = 1 57 | border = 0 58 | fullscreen = 0 59 | 60 | mouse_mul_x = 1 61 | mouse_div_x = 1 62 | mouse_mul_y = 1 63 | mouse_div_y = 1 64 | } 65 | 66 | terminal { 67 | driver = "x11" 68 | 69 | # escape = "CtrlRight" 70 | 71 | scale = 1 72 | 73 | mouse_mul_x = 2 74 | mouse_div_x = 5 75 | mouse_mul_y = 2 76 | mouse_div_y = 5 77 | } 78 | 79 | terminal { 80 | driver = "null" 81 | } 82 | 83 | video { 84 | device = "hgc" 85 | color = "amber" 86 | blink = 30 87 | } 88 | 89 | video { 90 | device = "vga" 91 | blink = 30 92 | enable_irq = 0 93 | irq = 2 94 | 95 | rom { 96 | address = 0xc0000 97 | size = 32768 98 | default = 0xff 99 | file = "ibm-vga-1986-10-27.rom" 100 | } 101 | } 102 | 103 | video { 104 | device = "ega" 105 | switches = 0x09 # EGA with EGA monitor (EGA mode) 106 | blink = 30 107 | enable_irq = 0 108 | irq = 2 109 | 110 | rom { 111 | address = 0xc0000 112 | size = 16384 113 | default = 0xff 114 | file = "ibm-ega-1984-09-13.rom" 115 | } 116 | } 117 | 118 | video { 119 | device = "cga" 120 | font = 1 121 | blink = 30 122 | } 123 | 124 | video { 125 | device = "mda" 126 | color = "green" 127 | blink = 30 128 | } 129 | 130 | speaker { 131 | volume = 250 132 | lowpass = 8000 133 | sample_rate = 44100 134 | 135 | # driver = "oss:dev=/dev/dsp:lowpass=5000:wav=speaker.wav:wavfilter=0" 136 | driver = "sdl:lowpass=5000" 137 | } 138 | 139 | serial { 140 | uart = "8250" 141 | address = 0x3f8 142 | irq = 4 143 | multichar = 1 144 | driver = "stdio:file/dev/null:flush=1" 145 | } 146 | 147 | parport { 148 | address = 0x378 149 | driver = "stdio:file=/dev/null:flush=1" 150 | } 151 | 152 | parport { 153 | address = 0x278 154 | driver = "stdio:file/dev/null:flush=1" 155 | } 156 | 157 | cassette { 158 | enable = 1 159 | file = "cas1.cas" 160 | # pcm = 1 161 | filter = 1 162 | mode = "load" 163 | position = 0 164 | append = 0 165 | } 166 | 167 | fdc { 168 | address = 0x3f0 169 | irq = 6 170 | 171 | drive0 = 0x00 172 | drive1 = 0x01 173 | drive2 = 0x02 174 | 175 | accurate = 0 176 | } 177 | 178 | disk { 179 | drive = 0x00 180 | type = "auto" 181 | file = "dosplus-1.2.img" 182 | optional = 0 183 | } 184 | 185 | disk { 186 | drive = 0x01 187 | type = "auto" 188 | file = "dostest.img" 189 | optional = 0 190 | } 191 | -------------------------------------------------------------------------------- /dosbase.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tsupplis/cpm86-hacking/ccea6c9ea4634fb2b92c680d06ce1c867e11c333/dosbase.img -------------------------------------------------------------------------------- /dosver.asm: -------------------------------------------------------------------------------- 1 | 2 | program segment 3 | assume cs:program, ds:program 4 | org 100h 5 | _start: 6 | mov cx,0Ch 7 | int 0E0h 8 | push ax 9 | lea dx,[_header] 10 | mov ah, 09h 11 | int 21h 12 | pop ax 13 | cmp al,41h 14 | jb _print_v1 15 | mov ah, 30h 16 | int 21h 17 | push ax 18 | xor ah,ah 19 | call _print_dec 20 | mov dl, '.' 21 | mov ah, 02h 22 | int 21h 23 | pop ax 24 | mov al,ah 25 | xor ah,ah 26 | call _print_dec 27 | lea dx,[_nl] 28 | mov ah, 09h 29 | int 21h 30 | jmp _exit 31 | _print_v1: 32 | lea dx,[_v1] 33 | mov ah, 09h 34 | int 21h 35 | _exit: 36 | int 20h 37 | _print_dec: 38 | mov cx,0 39 | mov dx,0 40 | _print_dec_loop: 41 | cmp ax,0 42 | je _print_dec_1 43 | mov bx,10 44 | div bx 45 | push dx 46 | inc cx 47 | xor dx,dx 48 | jmp _print_dec_loop 49 | _print_dec_1: 50 | cmp cx,0 51 | je _print_dec_exit 52 | pop dx 53 | add dx,48 54 | mov ah,02h 55 | int 21h 56 | dec cx 57 | jmp _print_dec_1 58 | _print_dec_exit: 59 | ret 60 | 61 | _header db "MS-DOS Level $" 62 | _v1 db "1.1" 63 | _nl db 13, 10, "$" 64 | program ends 65 | end _start 66 | -------------------------------------------------------------------------------- /dpb.c: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed under the MIT license. See LICENSE file in the project root for details. 3 | */ 4 | 5 | #include 6 | #ifdef __STDC__ 7 | #include 8 | #else 9 | char *malloc(); 10 | #endif 11 | #include 12 | 13 | #ifndef __STDC__ 14 | dpb_load(drive, dpb) 15 | int drive; 16 | dpb_t* dpb; 17 | #else 18 | dpb_load(int drive, dpb_t*dpb) 19 | #endif 20 | { 21 | int i; 22 | int es; 23 | int bx; 24 | int ax; 25 | int segs[4]; 26 | int curdrive=getcurdrv(); 27 | unsigned char *ptr=(unsigned char *)dpb; 28 | 29 | setcurdrv(drive); 30 | segread(segs); 31 | ax=bdosx(31,0,&es,&bx); 32 | for(i=0;i<15;i++) 33 | ptr[i]=peekb(bx+i,es); 34 | setcurdrv(curdrive); 35 | } 36 | 37 | 38 | -------------------------------------------------------------------------------- /dump.c: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed under the MIT license. See LICENSE file in the project root for details. 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #ifdef __STDC__ 9 | #include 10 | #else 11 | char * malloc(); 12 | #endif 13 | 14 | #ifndef __STDC__ 15 | unsigned long dump_hex(fd, data, size, offset, raw) 16 | FILE *fd; 17 | char *data; 18 | unsigned int size; 19 | unsigned long offset; 20 | int raw; 21 | #else 22 | unsigned long dump_hex(FILE *fd, char*data, unsigned int size, 23 | unsigned long offset, int raw) 24 | #endif 25 | { 26 | char ascii[17]; 27 | unsigned int i, j; 28 | ascii[16] = '\0'; 29 | for (i = 0; i < size; ++i) { 30 | if (i % 16 == 0 && !raw) { 31 | fprintf(fd, "%06x: ", offset); 32 | } 33 | offset++; 34 | fprintf(fd, "%02x ", ((unsigned char *)data)[i]); 35 | if (data[i] >= ' ' && data[i] <= '~') { 36 | ascii[i % 16] = data[i]; 37 | } else { 38 | ascii[i % 16] = '.'; 39 | } 40 | if ((i + 1) % 8 == 0 || i + 1 == size) { 41 | if (!raw) { 42 | fprintf(fd, " "); 43 | } 44 | if ((i + 1) % 16 == 0) { 45 | if (raw) { 46 | fprintf(fd, "\n"); 47 | } else { 48 | fprintf(fd, "| %s \n", ascii); 49 | } 50 | } else if (i + 1 == size) { 51 | ascii[(i + 1) % 16] = '\0'; 52 | if ((i + 1) % 16 <= 8) { 53 | if (!raw) { 54 | fprintf(fd, " "); 55 | } 56 | } 57 | for (j = (i + 1) % 16; j < 16; ++j) { 58 | if (!raw) { 59 | fprintf(fd, " "); 60 | } 61 | } 62 | if (raw) { 63 | fprintf(fd, "\n"); 64 | } else { 65 | fprintf(fd, "| %s \n", ascii); 66 | } 67 | } 68 | } 69 | } 70 | return offset; 71 | } 72 | 73 | int getch() { 74 | int i, c, d; 75 | static int s = 0; 76 | 77 | if (s > 0) { 78 | c = s; 79 | s = 0; 80 | return c; 81 | } 82 | while (!(c = bdos(6, 255))) 83 | ; 84 | while (d = bdos(6, 255)) 85 | ; 86 | return c; 87 | } 88 | 89 | #define BUFLEN (16*1024) 90 | 91 | #ifndef __STDC__ 92 | int main(argc, argv) 93 | int argc; 94 | char **argv; 95 | #else 96 | int main(int argc, char **argv) 97 | #endif 98 | { 99 | int c, i, ctr = 0; 100 | int flag_pause = 0; 101 | int flag_raw = 0; 102 | unsigned long offset = 0; 103 | char *infile = 0; 104 | FILE *infp = 0; 105 | int process = 1; 106 | char *buffer=malloc(BUFLEN); 107 | 108 | 109 | i = 1; 110 | while (i < argc) { 111 | if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-H")) { 112 | fprintf(stderr, "INF: Usage: dump -h | [-p][-r] [infile]\n"); 113 | fprintf(stderr, "INF: Hexa file dump utility\n"); 114 | fprintf(stderr, "INF: where infile is [user/]filespec\n"); 115 | fprintf(stderr, "INF: -h for help\n"); 116 | fprintf(stderr, "INF: -p pausing every page\n"); 117 | fprintf(stderr, "INF: -r raw output\n"); 118 | exit(0); 119 | } 120 | if(argv[i][0]=='-') { 121 | int j=1; 122 | while(argv[i][j]) { 123 | switch(argv[i][j]) { 124 | case 'r': 125 | case 'R': 126 | flag_raw=1; 127 | break; 128 | case 'p': 129 | case 'P': 130 | flag_pause=1; 131 | break; 132 | default: 133 | fprintf(stderr, "INF: Usage: dump -h | [-p][-r] [infile]\n"); 134 | fprintf(stderr,"ERR: Wrong parameters\n"); 135 | exit(0); 136 | break; 137 | } 138 | j++; 139 | } 140 | i++; 141 | continue; 142 | } 143 | 144 | if (!infile) { 145 | infile = argv[i]; 146 | i++; 147 | break; 148 | } 149 | } 150 | 151 | if(!isatty(fileno(stdout))) { 152 | flag_pause=0; 153 | } 154 | if (!infile) { 155 | if(!isatty(fileno(stdin))) { 156 | infp = stdin; 157 | } else { 158 | fprintf(stderr, "ERR: No file specified and tty not redirected\n"); 159 | exit(-1); 160 | } 161 | } else { 162 | infp = fopen(infile, "r"); 163 | if (!infp) { 164 | fprintf(stderr, "ERR: File %s not found or accessible\n", infile); 165 | exit(-1); 166 | } 167 | fclose(stdin); 168 | } 169 | 170 | while (process) { 171 | c = fread(buffer, 1, flag_pause ? 16 : BUFLEN, infp); 172 | if (c < 1) { 173 | break; 174 | } 175 | if (!flag_pause) { 176 | int d; 177 | int ctrlc=0; 178 | while(bdos(11,0)) { 179 | d=bdos(1,0); 180 | if(d==3) ctrlc=1; 181 | } 182 | if(ctrlc) { 183 | break; 184 | } 185 | } 186 | 187 | offset = dump_hex(stdout, buffer, c, offset, flag_raw); 188 | ctr++; 189 | if (ctr > 22) { 190 | ctr = 0; 191 | if (flag_pause) { 192 | int d = 0; 193 | int wt = 1; 194 | printf("[More]"); 195 | while (wt) { 196 | d = getch(); 197 | switch (d) { 198 | case 'q': 199 | case 'Q': 200 | printf("\x08\x08\x08\x08\x08\x08 "); 201 | wt = 0; 202 | process = 0; 203 | break; 204 | case 3: 205 | printf("\x08\x08\x08\x08\x08\x08^C "); 206 | process = 0; 207 | wt = 0; 208 | break; 209 | case 13: 210 | printf("\x08\x08\x08\x08\x08\x08 "); 211 | printf("\x08\x08\x08\x08\x08\x08"); 212 | wt = 0; 213 | ctr = 22; 214 | break; 215 | case 32: 216 | printf("\x08\x08\x08\x08\x08\x08 "); 217 | printf("\x08\x08\x08\x08\x08\x08"); 218 | wt = 0; 219 | ctr = 0; 220 | break; 221 | } 222 | } 223 | } 224 | } 225 | } 226 | if (infile) { 227 | fclose(infp); 228 | } 229 | exit(0); 230 | } 231 | -------------------------------------------------------------------------------- /env.dat: -------------------------------------------------------------------------------- 1 | Hello=Bonjour 2 | ; Comment 3 | A=Yo 4 | EA=45 5 | B= This is a small test 6 | A = 678 7 | 8 | -------------------------------------------------------------------------------- /getch.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #ifndef __STDC__ 6 | int main(argc, argv) 7 | int argc; 8 | char **argv; 9 | #else 10 | int main(int argc, char **argv) 11 | #endif 12 | { 13 | int c; 14 | freopen("con:", "r", stdin); 15 | freopen("con:", "w", stdout); 16 | fprintf (stderr,"INF: Keyboard Scanner. type letter 'q' to leave ...\n"); 17 | while(1) { 18 | c=getch(); 19 | if(isprint(c)) { 20 | fprintf(stderr, "INF: 0x%02x [%-3d] -> %c\n",c,c,c); 21 | } else if(c>=0 && c<' ') { 22 | fprintf(stderr, "INF: 0x%02x [%-3d] -> ^%c\n",c,c,c+'A'-1); 23 | } else { 24 | fprintf(stderr, "INF: 0x%02x [%-3d]\n",c,c); 25 | } 26 | if(c=='q') { 27 | fprintf (stderr,"INF: Bye ...\n"); 28 | break; 29 | } 30 | } 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /gfx.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; Licensed under the MIT license. See LICENSE file in the project root for details. 3 | ; 4 | codeseg segment para public 'code' 5 | assume cs:codeseg 6 | 7 | public gfx_palette_ 8 | gfx_palette_ proc near 9 | push bp 10 | mov bp,sp 11 | push bx 12 | push dx 13 | mov bx,word ptr 4[bp] 14 | xor al,al 15 | mov ah,0Bh 16 | int 10h 17 | pop dx 18 | pop bx 19 | pop bp 20 | xor ax,ax 21 | ret 22 | gfx_palette_ endp 23 | 24 | public gfx_mode_ 25 | gfx_mode_ proc near 26 | push bp 27 | mov bp,sp 28 | mov al,byte ptr 4[bp] 29 | xor ah,ah 30 | int 10h 31 | pop bp 32 | xor ax,ax 33 | ret 34 | gfx_mode_ endp 35 | 36 | public gfx_pixel_ 37 | gfx_pixel_ proc near 38 | push bp 39 | mov bp,sp 40 | push di 41 | push si 42 | push bx 43 | push cx 44 | push dx 45 | mov ah, 0ch 46 | mov al, byte ptr 8[bp] 47 | mov bh, 0 48 | mov cx, word ptr 4[bp] 49 | mov dx, word ptr 6[bp] 50 | int 10h 51 | pop dx 52 | pop cx 53 | pop bx 54 | pop si 55 | pop di 56 | pop bp 57 | xor ax,ax 58 | ret 59 | gfx_pixel_ endp 60 | 61 | codeseg ends 62 | end 63 | -------------------------------------------------------------------------------- /gfx.h: -------------------------------------------------------------------------------- 1 | #ifndef _GFX_H_ 2 | #define _GFX_H_ 3 | 4 | /* 5 | Licensed under the MIT license. See LICENSE file in the project root for details. 6 | */ 7 | 8 | #define CGA_PALETTE_CMW 0x101 9 | #define CGA_PALETTE_GRY 0x100 10 | 11 | #define MODE_CGA_320X200 4 12 | #define MODE_CGA_640X200 6 13 | #define MODE_TEXT 3 14 | 15 | #ifndef __STDC__ 16 | gfx_mode(); 17 | gfx_palette(); 18 | gfx_pixel(); 19 | #else 20 | void gfx_mode(int mode); 21 | void gfx_palette(int palette); 22 | void gfx_pixel(int x, int y, int palette); 23 | #endif 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /images/cpm86.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tsupplis/cpm86-hacking/ccea6c9ea4634fb2b92c680d06ce1c867e11c333/images/cpm86.png -------------------------------------------------------------------------------- /images/cpmapps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tsupplis/cpm86-hacking/ccea6c9ea4634fb2b92c680d06ce1c867e11c333/images/cpmapps.png -------------------------------------------------------------------------------- /init.a86: -------------------------------------------------------------------------------- 1 | ; 2 | ; Licensed under the MIT license. See LICENSE file in the project root for details. 3 | ; 4 | 5 | title 'ATINIT - Start CP/M' 6 | 7 | cseg 8 | 9 | mov cx,ds 10 | mov es,cx 11 | mov cx, 20h 12 | xor dx,dx 13 | mov dl, 0FFh 14 | int 0E0h 15 | mov byte ptr bkp_user, al 16 | call cls 17 | call print_cpm_ver 18 | mov cx,0Ch 19 | int 0E0h 20 | cmp ax,1430h 21 | jz wrg_os 22 | cmp ax,1431h 23 | jz wrg_os 24 | sub ax,1462h 25 | ja hw_end 26 | call print_hw 27 | jmp hw_end 28 | wrg_os: 29 | lea si, msg_wrg_os 30 | call print_str 31 | call quit 32 | hw_end: 33 | lea si, msg_rtc 34 | call print_str 35 | mov cx, 20h 36 | xor dx,dx 37 | mov dl, byte ptr bkp_user 38 | int 0E0h 39 | 40 | include clock.a86 41 | 42 | cls: 43 | push ax 44 | push bx 45 | push cx 46 | mov dx,27 47 | mov cl,02h 48 | int 0E0h 49 | mov dx,'E' 50 | mov cl,02h 51 | int 0E0h 52 | pop cx 53 | pop bx 54 | pop ax 55 | ret 56 | 57 | print_hw: 58 | push ax 59 | push bx 60 | push cx 61 | push dx 62 | push es 63 | push si 64 | lea si, msg_hw_hdr 65 | call print_str 66 | lea si, msg_hw_mem 67 | call print_str 68 | int 12h 69 | mov bx,10 70 | call print_uint16 71 | lea si, msg_hw_kb 72 | call print_str 73 | lea si, msg_hw_amem 74 | call print_str 75 | mov dx,offset mcb 76 | mov cl,35h 77 | int 0E0h 78 | mov ax, word ptr mlen 79 | mov cl,6 80 | shr ax, cl 81 | inc ax 82 | inc ax 83 | mov bx,10 84 | call print_uint16 85 | lea si, msg_hw_kb 86 | call print_str 87 | lea si, msg_hw_87 88 | call print_str 89 | int 11h 90 | add ax,0040h 91 | and ax,0fff3h 92 | push ax 93 | and al,2 94 | jz no_87 95 | lea si, msg_hw_yes 96 | jmp done_87 97 | no_87: 98 | lea si, msg_hw_no 99 | done_87: 100 | call print_str 101 | lea si, msg_hw_flp 102 | call print_str 103 | pop ax 104 | push ax 105 | xor ah,ah 106 | mov cl,06h 107 | shr al,cl 108 | and al,07h 109 | mov bx,10 110 | call print_uint16 111 | lea si, msg_nl 112 | call print_str 113 | lea si, msg_hw_dsk 114 | call print_str 115 | call disk_count 116 | mov bx,10 117 | call print_uint16 118 | lea si, msg_nl 119 | call print_str 120 | lea si, msg_hw_par 121 | call print_str 122 | pop ax 123 | push ax 124 | mov cl,0Eh 125 | shr ax,cl 126 | and al,03h 127 | mov bx,10 128 | call print_uint16 129 | lea si, msg_nl 130 | call print_str 131 | lea si, msg_hw_ser 132 | call print_str 133 | pop ax 134 | mov cl,09h 135 | shr ax,cl 136 | and al,07h 137 | mov bx,10 138 | call print_uint16 139 | lea si, msg_nl 140 | call print_str 141 | pop si 142 | pop es 143 | pop dx 144 | pop cx 145 | pop bx 146 | pop ax 147 | ret 148 | 149 | print_cpm_ver: 150 | push si 151 | push ax 152 | push bx 153 | push cx 154 | push dx 155 | mov cx,0Ch 156 | int 0E0h 157 | push ax 158 | cmp ah,15h 159 | jz print_ver_mpm 160 | cmp ax,1430h 161 | jz print_ver_ccpm 162 | cmp ax,1431h 163 | jz print_ver_ccpm 164 | cmp ax,1466h 165 | jae print_ver_mdos 166 | cmp ah,14h 167 | jz print_ver_cdos 168 | cmp ax,1041h 169 | jz print_ver_dosp 170 | cmp ax,22h 171 | jz print_ver_cpm 172 | lea si, msg_cpm86 173 | call print_str 174 | jmp print_ver_base 175 | print_ver_cpm: 176 | lea si, msg_pccpm86 177 | call print_str 178 | jmp print_ver_base 179 | print_ver_dosp: 180 | lea si, msg_dosp 181 | call print_str 182 | jmp print_os_ver 183 | print_ver_mpm: 184 | lea si, msg_mpm86 185 | call print_str 186 | jmp print_os_ver 187 | print_ver_cdos: 188 | lea si, msg_cdos 189 | call print_str 190 | jmp print_os_ver 191 | print_ver_mdos: 192 | lea si, msg_mdos 193 | call print_str 194 | jmp print_os_ver 195 | print_ver_ccpm: 196 | lea si, msg_ccpm86 197 | call print_str 198 | jmp print_os_ver 199 | print_os_ver: 200 | mov cx,0A3h 201 | int 0E0h 202 | mov ax,bx 203 | xor ah,ah 204 | mov bx,10 205 | mov dl,al 206 | mov cl,4 207 | shr al, cl 208 | and al,0Fh 209 | call print_uint16 210 | mov al,'.' 211 | call print_char 212 | mov al,dl 213 | xor ah,ah 214 | and al,0Fh 215 | call print_uint16 216 | lea si, msg_ver_sep 217 | call print_str 218 | jmp print_ver_base 219 | print_ver_base: 220 | pop ax 221 | lea si, msg_ver_hdr 222 | call print_str 223 | xor ah,ah 224 | mov bx,10 225 | mov dl,al 226 | mov cl,4 227 | shr al, cl 228 | and al,0Fh 229 | call print_uint16 230 | mov al,'.' 231 | call print_char 232 | mov al,dl 233 | xor ah,ah 234 | and al,0Fh 235 | call print_uint16 236 | lea si, msg_nl 237 | call print_str 238 | print_ver_end: 239 | pop dx 240 | pop cx 241 | pop bx 242 | pop ax 243 | pop si 244 | ret 245 | 246 | include tinylib.a86 247 | include baselib.a86 248 | 249 | dseg 250 | 251 | mcb dw 0 252 | mlen dw 65534 253 | mext db 0 254 | month_siz db 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 255 | month_day dw 000,031,059,090,120,151,181,212,243,273,304,334 256 | msg_wrg_os db 'Not supported by this operating system.',13,10,0 257 | msg_interr db 'AT BIOS interrupt error ...',13,10,0 258 | msg_86err db 'Not an AT class system ...',13,10,0 259 | msg_rtc db 'Date now: ',0 260 | msg_cpm86 db 'CP/M-86, ',0 261 | msg_pccpm86 db 'CP/M-86 1.1, ',0 262 | msg_ccpm86 db 'Concurrent CP/M-86 ',0 263 | msg_mpm86 db 'MP/M-86 ',0 264 | msg_cdos db 'Concurrent DOS ',0 265 | msg_mdos db 'Multiuser DOS ',0 266 | msg_dosp db 'DOSPLUS ',0 267 | msg_ver_hdr db 'BDOS ',0 268 | msg_ver_sep db ', ',0 269 | msg_hw_hdr db 'Hardware Configuration: ',13,10,0 270 | msg_hw_mem db ' - System Memory: ',0 271 | msg_hw_amem db ' - Available Memory: ',0 272 | msg_hw_87 db ' - Math Coprocessor: ',0 273 | msg_hw_flp db ' - Floppy Drive(s): ',0 274 | msg_hw_dsk db ' - Hard Disk(s): ',0 275 | msg_hw_par db ' - Parallel Port(s): ',0 276 | msg_hw_ser db ' - Serial Port(s): ',0 277 | msg_hw_yes db 'Yes',13,10,0 278 | msg_hw_no db 'No',13,10,0 279 | msg_hw_kb db 'Kb',13,10,0 280 | msg_nl db 13,10,0 281 | tm_buffer rs 256 282 | stamp_year rw 1 283 | stamp_hours rb 1 284 | stamp_mins rb 1 285 | stamp_secs rb 1 286 | bkp_user rw 0 287 | db 0 288 | 289 | end 290 | -------------------------------------------------------------------------------- /ls.c: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed under the MIT license. See LICENSE file in the project root for details. 3 | */ 4 | 5 | #include 6 | #ifdef __STDC__ 7 | #include 8 | #endif 9 | #include 10 | #include 11 | 12 | int getch() 13 | { 14 | int i, c, d; 15 | static int s = 0; 16 | 17 | if (s > 0) { 18 | c = s; 19 | s = 0; 20 | return c; 21 | } 22 | while (!(c = bdos(6, 255))) 23 | ; 24 | while (d = bdos(6, 255)) 25 | ; 26 | return c; 27 | } 28 | 29 | #ifndef __STDC__ 30 | dirent_print_name(f, d, pack) 31 | FILE * f; 32 | dirent_t * d; 33 | int pack; 34 | #else 35 | void dirent_print_name(FILE * f, dirent_t * d, int pack) 36 | #endif 37 | { 38 | int i; 39 | for(i=1;i<9;i++) { 40 | if(((d->entry[i])&0x7F)==' ' && pack) { 41 | break; 42 | } 43 | fputc((d->entry[i])&0x7F,f); 44 | } 45 | if(((d->entry[9])&0x7F)==' ') { 46 | if(!pack) { 47 | fputc(' ',f); 48 | } 49 | } else { 50 | fputc('.',f); 51 | } 52 | for(i=9;i<12;i++) { 53 | if(((d->entry[i])&0x7F)==' ' && pack) { 54 | break; 55 | } 56 | fputc((d->entry[i])&0x7F,f); 57 | } 58 | } 59 | 60 | 61 | #ifndef __STDC__ 62 | int main(argc,argv) 63 | int argc; 64 | char **argv; 65 | #else 66 | int main(int argc, char **argv) 67 | #endif 68 | { 69 | char *pat="*.*"; 70 | dirent_t * root; 71 | dirent_t * cursor; 72 | int rc; 73 | int sort_order=0; 74 | int count=0; 75 | int i; 76 | int flag_all=0; 77 | int flag_mode=0; 78 | int flag_pause=0; 79 | unsigned int block_size=0; 80 | unsigned long all_size=0; 81 | int ctr=0; 82 | int process=1; 83 | int user; 84 | int drive; 85 | 86 | i=1; 87 | while(idrive,&dpb); 164 | block_size=128<blocks*block_size/1024; 193 | all_size+=size; 194 | count++; 195 | if(flag_mode==1) { 196 | fprintf(stdout,"%c%c ", 197 | dirent_is_sys(cursor)?'S':'-', 198 | dirent_is_ro(cursor)?'R':'-'); 199 | dirent_print_name(stdout,cursor,0); 200 | fprintf(stdout," %4luK %4lu FCB(s) %4lu Block(s)\n",size,cursor->fcbs, cursor->blocks); 201 | ctr++; 202 | } else if(flag_mode==2) { 203 | dirent_print_name(stdout,cursor,1); 204 | fprintf(stdout,"\n"); 205 | ctr++; 206 | } else { 207 | fprintf(stdout,"%c",dirent_is_sys(cursor)?'*':' '); 208 | dirent_print_name(stdout,cursor,0); 209 | fprintf(stdout,"%5luK",size); 210 | if(count%4!=0) { 211 | fprintf(stdout,","); 212 | } 213 | if((count%4==0)) { 214 | fprintf(stdout,"\n"); 215 | ctr++; 216 | } 217 | } 218 | } 219 | if(!flag_mode && count%4!=0 && !cursor->next) { 220 | fprintf(stdout,"\n"); 221 | ctr++; 222 | } 223 | if (ctr > 22 || (ctr >21 && !cursor->next)) { 224 | ctr = 0; 225 | if (flag_pause) { 226 | int d = 0; 227 | int wt = 1; 228 | printf("[More]"); 229 | while (wt) { 230 | d = getch(); 231 | switch (d) { 232 | case 'q': 233 | case 'Q': 234 | printf("\x08\x08\x08\x08\x08\x08 "); 235 | wt = 0; 236 | process = 0; 237 | break; 238 | case 3: 239 | printf("\x08\x08\x08\x08\x08\x08^C "); 240 | process = 0; 241 | wt = 0; 242 | break; 243 | case 13: 244 | printf("\x08\x08\x08\x08\x08\x08 "); 245 | printf("\x08\x08\x08\x08\x08\x08"); 246 | wt = 0; 247 | ctr = 22; 248 | break; 249 | case 32: 250 | printf("\x08\x08\x08\x08\x08\x08 "); 251 | printf("\x08\x08\x08\x08\x08\x08"); 252 | wt = 0; 253 | ctr = 0; 254 | break; 255 | } 256 | } 257 | } 258 | } 259 | cursor=cursor->next; 260 | } 261 | if(flag_mode<2) { 262 | fprintf(stdout,"%d File(s) %luK",count,all_size); 263 | } 264 | dirent_free(root); 265 | return 0; 266 | } 267 | 268 | -------------------------------------------------------------------------------- /mem.a86: -------------------------------------------------------------------------------- 1 | ; 2 | ; Licensed under the MIT license. See LICENSE file in the project root for details. 3 | ; 4 | 5 | title 'Memory' 6 | 7 | cseg 8 | 9 | mov cx,ds 10 | mov es,cx 11 | mov dx,offset mcb 12 | mov cl,35h 13 | int 0E0h 14 | mov ax, word ptr mlen 15 | mov cl,6 16 | shr ax, cl 17 | inc ax 18 | mov bx,10 19 | call print_uint16 20 | lea si, msg_sep 21 | call print_str 22 | mov cx,0Ch 23 | int 0E0h 24 | cmp ax,1430h 25 | jz ccpm3x 26 | cmp ax,1431h 27 | jz ccpm3x 28 | int 12h 29 | cmp ax,640 30 | ja fixax 31 | jmp prram 32 | ccpm3x: 33 | mov bx,40h 34 | mov es,bx 35 | mov bx,13h 36 | mov ax, es:[bx] 37 | fixax: 38 | mov ax, 640 39 | prram: 40 | mov bx,10 41 | call print_uint16 42 | lea si, msg_nl 43 | call print_str 44 | call quit 45 | 46 | include tinylib.a86 47 | 48 | dseg 49 | 50 | mcb dw 0 51 | mlen dw 65534 52 | mext db 0 53 | msg_sep db 'K/',0 54 | msg_nl db 'K',13,10,0 55 | 56 | end 57 | -------------------------------------------------------------------------------- /mode.c: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed under the MIT license. See LICENSE file in the project root for details. 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | typedef struct _cmd_t { 12 | char * name; 13 | char * vt_cmd; 14 | char * desc; 15 | #ifndef __STDC__ 16 | int (*fn)(); 17 | #else 18 | int (*fn)(char *); 19 | #endif 20 | int prefix; 21 | int cpm86; 22 | } _cmd_t; 23 | 24 | #ifndef __STDC__ 25 | int status(arg) 26 | char* arg; 27 | #else 28 | int status(char* arg) 29 | #endif 30 | { 31 | setstatus(arg); 32 | } 33 | 34 | #ifndef __STDC__ 35 | int set_mode(arg) 36 | char* arg; 37 | #else 38 | int set_mode(char* arg) 39 | #endif 40 | { 41 | if(!istrcmp("default",arg,0)) { 42 | scrmode(SCRMODE_DEFAULT); 43 | } else if(!istrcmp("col80",arg,0)) { 44 | scrmode(SCRMODE_COL80); 45 | } else if(!istrcmp("col40",arg,0)) { 46 | scrmode(SCRMODE_COL40); 47 | } else if(!istrcmp("color",arg,0)) { 48 | scrmode(SCRMODE_COLOR); 49 | } else if(!istrcmp("mono",arg,0)) { 50 | scrmode(SCRMODE_MONO); 51 | } else { 52 | return -1; 53 | } 54 | return 0; 55 | } 56 | #ifndef __STDC__ 57 | int cls(arg) 58 | char* arg; 59 | #else 60 | int cls(char* arg) 61 | #endif 62 | { 63 | clrscr(); 64 | return 0; 65 | } 66 | 67 | #ifndef __STDC__ 68 | int cursor_on(arg) 69 | char* arg; 70 | #else 71 | int cursor_on(char* arg) 72 | #endif 73 | { 74 | cursor(CURSOR_ON); 75 | return 0; 76 | } 77 | 78 | #ifndef __STDC__ 79 | int cursor_off(arg) 80 | char* arg; 81 | #else 82 | int cursor_off(char* arg) 83 | #endif 84 | { 85 | cursor(CURSOR_OFF); 86 | return 0; 87 | } 88 | 89 | #ifndef __STDC__ 90 | int statline_on(arg) 91 | char* arg; 92 | #else 93 | int statline_on(char* arg) 94 | #endif 95 | { 96 | statline(STATLINE_ON); 97 | return 0; 98 | } 99 | 100 | #ifndef __STDC__ 101 | int statline_off(arg) 102 | char* arg; 103 | #else 104 | int statline_off(char* arg) 105 | #endif 106 | { 107 | statline(STATLINE_OFF); 108 | return 0; 109 | } 110 | 111 | #ifndef __STDC__ 112 | int fg(arg) 113 | char* arg; 114 | #else 115 | int fg(char* arg) 116 | #endif 117 | { 118 | char fg=255; 119 | if(strlen(arg)>1) { 120 | return -1; 121 | } 122 | if(arg[0]>='1' && arg[0]<='9') { 123 | fg=arg[0]-'0'; 124 | } else if(arg[0]>='a' && arg[0]<='f') { 125 | fg=arg[0]-'a'+10; 126 | } else if(arg[0]>='A' && arg[0]<='F') { 127 | fg=arg[0]-'A'+10; 128 | } else { 129 | return -1; 130 | } 131 | fprintf(stdout,"\x1bb%c",fg); 132 | return 0; 133 | } 134 | 135 | #ifndef __STDC__ 136 | int bg(arg) 137 | char* arg; 138 | #else 139 | int bg(char* arg) 140 | #endif 141 | { 142 | char bg=255; 143 | if(strlen(arg)>1) { 144 | return -1; 145 | } 146 | if(arg[0]>='0' && arg[0]<='9') { 147 | bg=arg[0]-'0'; 148 | } else if(arg[0]>='a' && arg[0]<='f') { 149 | bg=arg[0]-'a'+10; 150 | } else if(arg[0]>='A' && arg[0]<='F') { 151 | bg=arg[0]='A'+10; 152 | } else { 153 | return -1; 154 | } 155 | fprintf(stdout,"\x1bc%c",bg); 156 | return 0; 157 | } 158 | 159 | _cmd_t cmds[]= { 160 | {"cls", 0, "Clear screen",cls, 0, 0x2000}, 161 | {"cursor=on", 0, "Show cursor", cursor_on, 0 , 0x2000}, 162 | {"cursor=off", 0, "Hide cursor", cursor_off, 0, 0x2000}, 163 | {"statln=on", 0, "Show status line", statline_on, 0, 0x22}, 164 | {"statln=off", 0, "Hide status line", statline_off, 0, 0x22}, 165 | {"status=", 0, "Set status line message", status, 1, 0x22}, 166 | {"scr=", 0, "Set screen mode (default,col80,col40,mono,color)", set_mode, 1, 0x22}, 167 | {"fg=", 0, "Set foreground color (1-F)", fg, 1, 0x2000}, 168 | {"bg=", 0, "Set background color (1-F)", bg, 1, 0x2000}, 169 | {0,0,0,0} 170 | }; 171 | 172 | 173 | #ifndef __STDC__ 174 | int main(argc, argv) 175 | int argc; 176 | char **argv; 177 | #else 178 | int main(int argc, char **argv) 179 | #endif 180 | { 181 | int index=0; 182 | int done=0; 183 | int arg=1; 184 | int os=osver(); 185 | 186 | if(argc<2) { 187 | exit(0); 188 | } 189 | if(!strcmp(argv[1],"-h")||!strcmp(argv[1],"-H")) { 190 | fprintf(stderr, "INF: Usage: mode -h | option option ...\n"); 191 | fprintf(stderr, "INF: Console configuration utility\n"); 192 | fprintf(stderr, "INF: -h for help\n"); 193 | fprintf(stderr, "INF: and options:\n"); 194 | index=0; 195 | while(cmds[index].name) { 196 | if(os>cmds[index].cpm86) { 197 | index++; 198 | continue; 199 | } 200 | fprintf(stderr, "INF: %-10s %s\n",cmds[index].name,cmds[index].desc); 201 | index++; 202 | } 203 | exit(0); 204 | } 205 | freopen("con:", "w", stdout); 206 | while(argcmds[index].cpm86) { 212 | index++; 213 | continue; 214 | } 215 | done=1; 216 | if(cmds[index].fn) { 217 | if(cmds[index].fn(argv[arg]+strlen(cmds[index].name))) { 218 | fprintf(stderr, "ERR: Action(%s) failed\n",argv[arg]); 219 | exit(-1); 220 | } 221 | } 222 | if(cmds[index].vt_cmd) { 223 | printf("%s",cmds[index].vt_cmd); 224 | } 225 | break; 226 | } 227 | index++; 228 | } 229 | if(!done) { 230 | fprintf(stderr, "ERR: Action(%s) unknown\n",argv[arg]); 231 | exit(-1); 232 | } 233 | arg++; 234 | } 235 | exit(0); 236 | } 237 | 238 | -------------------------------------------------------------------------------- /more.c: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed under the MIT license. See LICENSE file in the project root for details. 3 | */ 4 | 5 | #include 6 | 7 | int getch() 8 | { 9 | int i, c, d; 10 | static int s = 0; 11 | 12 | if (s > 0) { 13 | c = s; 14 | s = 0; 15 | return c; 16 | } 17 | while (!(c = bdos(6, 255))) 18 | ; 19 | while (d = bdos(6, 255)) 20 | ; 21 | return c; 22 | } 23 | 24 | #ifndef __STDC__ 25 | int main(argc, argv) 26 | int argc; 27 | char **argv; 28 | #else 29 | int main(int argc, char **argv) 30 | #endif 31 | { 32 | int c, d = 0; 33 | int process = 1; 34 | FILE *infp = 0; 35 | int flag_pause=1; 36 | char * infile=0; 37 | int i; 38 | int col=0; 39 | int ctr=0; 40 | int space=0; 41 | 42 | i=1; 43 | while (i < argc) { 44 | if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-H")) { 45 | fprintf(stderr, "INF: Usage: more -h | [infile]\n"); 46 | fprintf(stderr, "INF: File paging utility\n"); 47 | fprintf(stderr, "INF: where infile is [user/]filespec\n"); 48 | fprintf(stderr, "INF: -h for help\n"); 49 | exit(0); 50 | } 51 | 52 | if (!infile) { 53 | infile = argv[i]; 54 | i++; 55 | break; 56 | } 57 | } 58 | 59 | 60 | if(infile) { 61 | infp = fopen(infile, "r"); 62 | if (0 == infp) { 63 | fprintf(stderr, "ERR: File %s not found or accessible\n", infile); 64 | exit(-1); 65 | } 66 | } else { 67 | infp=stdin; 68 | } 69 | 70 | if(!infp && isatty(0)) { 71 | fprintf(stderr, "ERR: No file specified and tty not redirected\n"); 72 | exit(-1); 73 | } 74 | if(!isatty(fileno(stdout))) { 75 | flag_pause=0; 76 | } 77 | 78 | 79 | while (process) { 80 | if(space) { 81 | c=' '; 82 | space--; 83 | } else { 84 | if (infile) 85 | c = fgetc(infp); 86 | else 87 | c = getchar(); 88 | if(c==9) { 89 | c=' ';space+=3; 90 | } 91 | } 92 | if (c == EOF || c == 26) 93 | break; 94 | 95 | if (c == '\n') { 96 | putchar(c); 97 | col=0; 98 | ctr++; 99 | } else { 100 | putchar(c); 101 | col++; 102 | } 103 | if(col==80) { 104 | col=col%80; 105 | ctr++; 106 | } 107 | if (flag_pause) { 108 | if (ctr > 22) { 109 | int wt = 1; 110 | printf("[More]"); 111 | while (wt) { 112 | d = getch(); 113 | switch (d) { 114 | case 'q': 115 | case 'Q': 116 | printf("\x08\x08\x08\x08\x08\x08 "); 117 | wt = 0; 118 | process = 0; 119 | break; 120 | case 3: 121 | printf("\x08\x08\x08\x08\x08\x08^C "); 122 | process = 0; 123 | wt = 0; 124 | break; 125 | case 13: 126 | printf("\x08\x08\x08\x08\x08\x08 "); 127 | printf("\x08\x08\x08\x08\x08\x08"); 128 | wt = 0; 129 | ctr = 22; 130 | break; 131 | case 32: 132 | printf("\x08\x08\x08\x08\x08\x08 "); 133 | printf("\x08\x08\x08\x08\x08\x08"); 134 | wt = 0; 135 | ctr = 0; 136 | break; 137 | } 138 | } 139 | } else { 140 | int d; 141 | int ctrlc=0; 142 | while(bdos(11,0)) { 143 | d=bdos(1,0); 144 | if(d==3) ctrlc=1; 145 | } 146 | if(ctrlc) { 147 | break; 148 | } 149 | } 150 | } 151 | } 152 | if (infile) { 153 | fclose(infp); 154 | } 155 | exit(0); 156 | } 157 | -------------------------------------------------------------------------------- /os.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; Licensed under the MIT license. See LICENSE file in the project root for details. 3 | ; 4 | codeseg segment para public 'code' 5 | dataseg segment para public 'data' 6 | dataseg ends 7 | 8 | assume cs:codeseg, ds:dataseg 9 | extrn memset_:near 10 | bss scb_pb_:word,257 11 | ; 12 | 13 | public setcurdrv_ 14 | setcurdrv_ proc near 15 | push bp 16 | mov bp,sp 17 | push es 18 | push di 19 | push si 20 | push bx 21 | push cx 22 | push dx 23 | mov dx,word ptr 4[bp] 24 | mov cx,0Eh 25 | int 0E0h 26 | pop dx 27 | pop cx 28 | pop bx 29 | pop si 30 | pop di 31 | pop es 32 | pop bp 33 | ret 34 | setcurdrv_ endp 35 | 36 | public getccpdrv_ 37 | getccpdrv_ proc near 38 | push bp 39 | mov bp,sp 40 | push es 41 | push di 42 | push si 43 | push bx 44 | push cx 45 | push dx 46 | mov cx,0Ch 47 | int 0E0h 48 | cmp ax,22h 49 | jz ccpdrv_cp11sv 50 | cmp ax,1430h 51 | jae ccpdrv_ccp3xsd 52 | cmp ax,1041h 53 | jz ccpdrv_4xsv 54 | cmp ax,1050h 55 | jz ccpdrv_4xsv 56 | jmp ccpdrv_none 57 | ccpdrv_cp11sv: 58 | mov cx,31h 59 | int 0E0h 60 | add bx, 17h 61 | xor ah, ah 62 | mov al, es:[bx] 63 | jmp ccpdrv_end 64 | ccpdrv_ccp3xsd: 65 | mov cx, 9Ah 66 | int 0E0h 67 | xor ah,ah 68 | add bx, 4Bh 69 | mov al, es:[bx] 70 | jmp ccpdrv_end 71 | ccpdrv_4xsv: 72 | mov al,86h 73 | mov byte ptr scb_pb_,al 74 | mov al,0h 75 | mov byte ptr scb_pb_+1,al 76 | mov dx, offset scb_pb_ 77 | mov cx,31h 78 | int 0E0h 79 | xor ah,ah 80 | mov al,byte ptr scb_pb_+2 81 | cmp bx,0FFFh 82 | jnz ccpdrv_end 83 | ccpdrv_none: 84 | mov ax,0FFFh 85 | ccpdrv_end: 86 | pop dx 87 | pop cx 88 | pop bx 89 | pop si 90 | pop di 91 | pop es 92 | pop bp 93 | ret 94 | getccpdrv_ endp 95 | 96 | public getcurdrv_ 97 | getcurdrv_ proc near 98 | push bp 99 | mov bp,sp 100 | push es 101 | push di 102 | push si 103 | push bx 104 | push cx 105 | push dx 106 | mov cx,19h 107 | int 0E0h 108 | pop dx 109 | pop cx 110 | pop bx 111 | pop si 112 | pop di 113 | pop es 114 | pop bp 115 | ret 116 | getcurdrv_ endp 117 | 118 | public delay_ 119 | delay_ proc near 120 | push bp 121 | mov bp,sp 122 | push es 123 | push di 124 | push si 125 | push bx 126 | push cx 127 | push dx 128 | mov cx,0Ch 129 | int 0E0h 130 | sub al,22H 131 | jz delay_bios 132 | mov bl, 3 133 | mov al, byte ptr 4[bp] 134 | mul bl 135 | mov dx,ax 136 | ;mov dx, word ptr 4[bp] 137 | mov cx,8Dh 138 | int 0E0h 139 | jmp delay_end 140 | delay_bios: 141 | mov ah, 00h 142 | int 01Ah 143 | add dx, word ptr 4[bp] 144 | mov bx, dx 145 | delay_lp: 146 | int 01Ah 147 | cmp dx, bx 148 | jl delay_lp 149 | delay_end: 150 | pop dx 151 | pop cx 152 | pop bx 153 | pop si 154 | pop di 155 | pop es 156 | pop bp 157 | xor ax,ax 158 | ret 159 | delay_ endp 160 | 161 | public bdosx_ 162 | bdosx_ proc near 163 | push bp 164 | mov bp,sp 165 | push es 166 | push di 167 | push si 168 | push bx 169 | push cx 170 | mov cx,word ptr 4[bp] 171 | mov dx,word ptr 6[bp] 172 | int 0E0h 173 | mov cx,bx 174 | mov bx,word ptr 10[bp] 175 | mov word ptr [bx],cx 176 | mov cx,es 177 | mov bx,word ptr 8[bp] 178 | mov word ptr [bx],cx 179 | pop cx 180 | pop bx 181 | pop si 182 | pop di 183 | pop es 184 | pop bp 185 | and ax,255 186 | ret 187 | bdosx_ endp 188 | 189 | public ostype_ 190 | ostype_ proc near 191 | push bp 192 | mov bp,sp 193 | push ds 194 | push es 195 | push di 196 | push si 197 | push bx 198 | push cx 199 | mov cx,0Ch 200 | int 0E0h 201 | mov al,ah 202 | xor ah,ah 203 | cmp al,0 204 | jnz ostypeend 205 | mov al,10h 206 | ostypeend: 207 | pop cx 208 | pop bx 209 | pop si 210 | pop di 211 | pop es 212 | pop ds 213 | pop bp 214 | ret 215 | ostype_ endp 216 | 217 | public osver_ 218 | osver_ proc near 219 | push bp 220 | mov bp,sp 221 | push ds 222 | push es 223 | push di 224 | push si 225 | push bx 226 | push cx 227 | mov cx,0Ch 228 | int 0E0h 229 | xor ah,ah 230 | pop cx 231 | pop bx 232 | pop si 233 | pop di 234 | pop es 235 | pop ds 236 | pop bp 237 | ret 238 | osver_ endp 239 | 240 | public bioskey_ 241 | bioskey_ proc near 242 | push bp 243 | mov bp,sp 244 | push ds 245 | mov ah, 0 246 | int 16h 247 | pop ds 248 | pop bp 249 | ret 250 | bioskey_ endp 251 | 252 | public pckey_ 253 | pckey_ proc near 254 | push bp 255 | mov bp,sp 256 | push ds 257 | push bx 258 | cli 259 | xor ax,ax 260 | in al, 60h 261 | in al, 60h 262 | push ax 263 | in al, 61h 264 | mov bl, al 265 | or al, 80h 266 | out 61h, al 267 | mov al, bl 268 | out 61h, al 269 | mov al, 20h 270 | out 20h,al 271 | pop ax 272 | sti 273 | pop bx 274 | pop ds 275 | pop bp 276 | ret 277 | pckey_ endp 278 | 279 | public xstatline_ 280 | xstatline_ proc near 281 | push bp 282 | mov bp,sp 283 | push es 284 | push ds 285 | push si 286 | push ax 287 | push bx 288 | push cx 289 | mov cl,0Ch 290 | int 0E0h 291 | push ax 292 | mov cl,9Ah 293 | int 0E0h 294 | mov cx, word ptr 4[bp] 295 | xor ch,ch 296 | pop ax 297 | cmp ax, 1041h 298 | jz xst_dosplus 299 | cmp ax, 1432h 300 | jb xst_exit 301 | mov si, word ptr [68h] ;[4Eh] for Dos Plus 302 | jmp xst_call 303 | xst_dosplus: 304 | mov si, word ptr [4Eh] 305 | xst_call: 306 | mov dx,0 307 | push es 308 | mov es, 10h[si] 309 | pop ds 310 | mov ax,20H 311 | call dword ptr[28h] 312 | xst_exit: 313 | pop cx 314 | pop bx 315 | pop ax 316 | pop si 317 | pop ds 318 | pop es 319 | pop bp 320 | ret 321 | xstatline_ endp 322 | 323 | codeseg ends 324 | 325 | end 326 | -------------------------------------------------------------------------------- /pause.a86: -------------------------------------------------------------------------------- 1 | ; 2 | ; Licensed under the MIT license. See LICENSE file in the project root for details. 3 | ; 4 | 5 | title 'Pause for Key' 6 | 7 | cseg 8 | mov cx,ds 9 | mov es,cx 10 | mov dx, offset msg_hdr 11 | mov cl,9 12 | int 0E0h 13 | pause: 14 | mov ah,1 15 | int 16h 16 | jnz got_key 17 | jmp pause 18 | got_key: 19 | mov ah,0 20 | int 16h 21 | xor ax,ax 22 | mov dx,offset msg_clear 23 | mov cl,9 24 | int 0E0h 25 | xor cx,cx 26 | int 0E0h 27 | 28 | dseg 29 | msg_hdr db 'Press any key to continue...','$' 30 | msg_clear db 13,27,'K$' 31 | end 32 | -------------------------------------------------------------------------------- /pce/.gitignore: -------------------------------------------------------------------------------- 1 | baselib.a86 2 | tinylib.a86 3 | -------------------------------------------------------------------------------- /pce/AUTHORS: -------------------------------------------------------------------------------- 1 | Hampa Hug 2 | -------------------------------------------------------------------------------- /pce/Makefile: -------------------------------------------------------------------------------- 1 | LINK86=pcdev_linkcmd 2 | RASM86=pcdev_rasm86 3 | 4 | TOOLS=pceexit.cmd pcever.cmd pcemnt.cmd pcetime.cmd pceinit.cmd 5 | 6 | all: binaries 7 | 8 | binaries: $(TOOLS) 9 | 10 | pceinit.obj: pceinit.a86 pce.a86 pcelib.a86 baselib.a86 tinylib.a86 11 | 12 | pcetime.obj: pcetime.a86 pce.a86 pcelib.a86 baselib.a86 tinylib.a86 13 | 14 | pcemnt.obj: pcemnt.a86 pce.a86 pcelib.a86 baselib.a86 tinylib.a86 15 | 16 | pceexit.obj: pceexit.a86 pce.a86 pcelib.a86 baselib.a86 tinylib.a86 17 | 18 | pcever.obj: pcever.a86 pce.a86 pcelib.a86 baselib.a86 tinylib.a86 19 | 20 | tinylib.a86: ../tinylib.a86 21 | cp $< $@ 22 | 23 | baselib.a86: ../baselib.a86 24 | cp $< $@ 25 | 26 | %.cmd: %.obj 27 | $(LINK86) $* '[$$sz]' 28 | 29 | %.obj: %.a86 30 | $(RASM86) $< $$ pz sz 31 | 32 | clean: 33 | $(RM) *.o *.h86 *.log *.sym *.prn *.lst *.obj $(TOOLS) 34 | $(RM) baselib.a86 35 | -------------------------------------------------------------------------------- /pce/bldpce.bat: -------------------------------------------------------------------------------- 1 | rasm86 pcever $ pz sz 2 | linkcmd pcever[$sz] 3 | rasm86 pcetime $ pz sz 4 | linkcmd pcetime[$sz] 5 | rasm86 pcemnt $ pz sz 6 | linkcmd pcemnt[$sz] 7 | rasm86 pceinit $ pz sz 8 | linkcmd pceinit[$sz] 9 | rasm86 pceexit $ pz sz 10 | linkcmd pceexit[$sz] 11 | -------------------------------------------------------------------------------- /pce/bldpce.sub: -------------------------------------------------------------------------------- 1 | rasm86 pcever $$ pz sz 2 | linkcmd pcever[$$sz] 3 | rasm86 pcetime $$ pz sz 4 | linkcmd pcetime[$$sz] 5 | rasm86 pcemnt $$ pz sz 6 | linkcmd pcemnt[$$sz] 7 | rasm86 pceinit $$ pz sz 8 | linkcmd pceinit[$$sz] 9 | rasm86 pceexit $$ pz sz 10 | linkcmd pceexit[$$sz] 11 | -------------------------------------------------------------------------------- /pce/clrpce.bat: -------------------------------------------------------------------------------- 1 | del pce*.cmd 2 | del pce*.obj 3 | -------------------------------------------------------------------------------- /pce/clrpce.sub: -------------------------------------------------------------------------------- 1 | era pce*.cmd 2 | era pce*.obj 3 | -------------------------------------------------------------------------------- /pce/pce.a86: -------------------------------------------------------------------------------- 1 | ; This program is free software; you can redistribute it and/or modify 2 | ; it under the terms of the GNU General Public License as published by 3 | ; the Free Software Foundation; either version 2 of the License, or 4 | ; (at your option) any later version. 5 | ; 6 | ; This program is distributed in the hope that it will be useful, 7 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | ; GNU General Public License for more details. 10 | ; 11 | ; You should have received a copy of the GNU General Public License along 12 | ; with this program; if not, write to the Free Software Foundation, Inc., 13 | ; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 14 | 15 | 16 | pce_hook_ver equ 0001h 17 | pce_hook_verstr equ 0002h 18 | pce_hook_abort equ 0101h 19 | pce_hook_setmsg equ 0200h 20 | pce_hook_localtm equ 0302h 21 | -------------------------------------------------------------------------------- /pce/pceclock.a86: -------------------------------------------------------------------------------- 1 | ; This program is free software; you can redistribute it and/or modify 2 | ; it under the terms of the GNU General Public License as published by 3 | ; the Free Software Foundation; either version 2 of the License, or 4 | ; (at your option) any later version. 5 | ; 6 | ; This program is distributed in the hope that it will be useful, 7 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | ; GNU General Public License for more details. 10 | ; 11 | ; You should have received a copy of the GNU General Public License along 12 | ; with this program; if not, write to the Free Software Foundation, Inc., 13 | ; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 14 | 15 | 16 | call pce_hook_check 17 | jc not_pce 18 | mov ax, pce_hook_localtm 19 | call pce_hook 20 | jc hook_err 21 | mov word ptr tm_buffer, ax 22 | mov word ptr tm_buffer+2, bx 23 | mov word ptr tm_buffer+4, cx 24 | mov word ptr tm_buffer+6, dx 25 | call print_time 26 | mov cx,0Ch 27 | int 0E0h 28 | sub al,29H 29 | ja cpm31_cpm 30 | call cpm_set_time 31 | call quit 32 | cpm31_cpm: 33 | call cpm31_set_time 34 | call quit 35 | 36 | not_pce: 37 | lea si, msg_notpce 38 | call print_str 39 | call quit 40 | hook_err: 41 | lea si, msg_hookerr 42 | call print_str 43 | call quit 44 | 45 | print_time: 46 | push bx 47 | push si 48 | mov bx, 10 49 | mov ax, word ptr tm_buffer ; year 50 | call print_dec4 51 | mov al, '-' 52 | call print_char 53 | mov al, byte ptr tm_buffer+3 ; month 54 | inc ax 55 | call print_dec2 56 | mov al, '-' 57 | call print_char 58 | mov al, byte ptr tm_buffer+2 ; day 59 | inc ax 60 | call print_dec2 61 | mov al, ' ' 62 | call print_char 63 | mov al, byte ptr tm_buffer+5 ; hour 64 | call print_dec2 65 | mov al, ':' 66 | call print_char 67 | mov al, byte ptr tm_buffer+4 ; minute 68 | call print_dec2 69 | mov al, ':' 70 | call print_char 71 | mov al, byte ptr tm_buffer+7 ; second 72 | call print_dec2 73 | mov al, '.' 74 | call print_char 75 | mov al, byte ptr tm_buffer+6 ; centisecond 76 | call print_dec2 77 | lea si, msg_nl 78 | call print_str 79 | pop si 80 | pop bx 81 | ret 82 | 83 | leap_days: 84 | push si 85 | push cx 86 | push dx 87 | mov cl, 2 88 | shr ax, cl 89 | mov dx, ax 90 | and ax, 3 91 | jnz leap_days_end 92 | lea cx, month_day 93 | add cx, bx 94 | add cx, bx 95 | mov si, cx 96 | mov cx, [si] 97 | cmp cx, 59 98 | jae leap_days_end 99 | dec dx 100 | leap_days_end: 101 | mov ax,dx 102 | pop dx 103 | pop cx 104 | pop si 105 | ret 106 | 107 | cpm31_set_time: 108 | push es 109 | push si 110 | push ax 111 | push bx 112 | push cx 113 | push dx 114 | ; (year-1978)*365 115 | mov ax, word ptr tm_buffer 116 | push ax 117 | sub ax, 1978 118 | mov cx, 365 119 | mul cx 120 | mov dx, ax 121 | ; +day 122 | mov cl, byte ptr tm_buffer+2 123 | xor ch, ch 124 | add cl, 1 125 | add dx, cx 126 | ; +leap_days(1978,0) 127 | mov ax, 1979 128 | mov bx, 0 129 | call leap_days 130 | sub dx, ax 131 | ; +month_days 132 | mov bl, byte ptr tm_buffer+3 133 | xor bh, bh 134 | lea cx, month_day 135 | add cx, bx 136 | add cx, bx 137 | mov si, cx 138 | mov cx, [si] 139 | add dx, cx 140 | ; +leap_days(year, month) 141 | pop ax 142 | mov bl, byte ptr tm_buffer+3 143 | xor bh, bh 144 | call leap_days 145 | add dx, ax 146 | mov word ptr stamp_year, dx 147 | mov al, byte ptr tm_buffer+5 148 | xor ah, ah 149 | mov bl, 10 150 | div bl 151 | mov cl, 4 152 | rol al, cl 153 | add al, ah 154 | mov byte ptr stamp_hours, al 155 | mov al, byte ptr tm_buffer+4 156 | xor ah, ah 157 | mov bl, 10 158 | div bl 159 | mov cl, 4 160 | rol al, cl 161 | add al, ah 162 | mov byte ptr stamp_mins, al 163 | mov al, byte ptr tm_buffer+7 164 | xor ah, ah 165 | mov bl, 10 166 | div bl 167 | mov cl, 4 168 | rol al, cl 169 | add al, ah 170 | mov byte ptr stamp_secs, al 171 | mov cx,ds 172 | mov es,cx 173 | lea dx, stamp_year 174 | mov cl, 68h 175 | int 0E0h 176 | pop dx 177 | pop cx 178 | pop bx 179 | pop ax 180 | pop si 181 | pop es 182 | ret 183 | 184 | cpm_set_time: 185 | push es 186 | push ax 187 | push bx 188 | push cx 189 | push dx 190 | cli 191 | mov cl, 31h ;Call Get Sysdata Addrs interrupt. 192 | int 0E0h ;CP/M interrupt. ES:BX -> Sysdata. 193 | add bx, 20h ;ES:BX now -> 17 bytes of time/date data. 194 | xor ah, ah 195 | mov al, byte ptr tm_buffer+3 ;Month 196 | inc al 197 | mov dl, 10 198 | div dl 199 | add al, '0' 200 | mov es:[bx], al 201 | inc bx 202 | mov al, ah 203 | add al, '0' 204 | mov es:[bx], al 205 | inc bx 206 | inc bx 207 | xor ah, ah 208 | mov al, byte ptr tm_buffer+2 ;Day 209 | inc al 210 | mov dl, 10 211 | div dl 212 | add al, '0' 213 | mov es:[bx], al 214 | inc bx 215 | mov al, ah 216 | add al, '0' 217 | mov es:[bx], al 218 | inc bx 219 | inc bx 220 | xor dx, dx 221 | mov ax, word ptr tm_buffer ;Year 222 | mov cx, 100 223 | div cx 224 | mov ax, dx 225 | xor ah, ah 226 | mov dl, 10 227 | div dl 228 | add al, '0' 229 | mov es:[bx], al 230 | inc bx 231 | mov al, ah 232 | add al, '0' 233 | mov es:[bx], al 234 | inc bx 235 | inc bx 236 | xor ah, ah 237 | mov al, byte ptr tm_buffer+5 ;Hour 238 | mov dl, 10 239 | div dl 240 | add al, '0' 241 | mov es:[bx], al 242 | inc bx 243 | mov al, ah 244 | add al, '0' 245 | mov es:[bx], al 246 | inc bx 247 | inc bx 248 | xor ah, ah 249 | mov al, byte ptr tm_buffer+4 ;Min 250 | mov dl, 10 251 | div dl 252 | add al, '0' 253 | mov es:[bx], al 254 | inc bx 255 | mov al, ah 256 | add al, '0' 257 | mov es:[bx], al 258 | inc bx 259 | inc bx 260 | xor ah, ah 261 | mov al, byte ptr tm_buffer+7 ;Sec 262 | mov dl, 10 263 | div dl 264 | add al, '0' 265 | mov es:[bx], al 266 | inc bx 267 | mov al, ah 268 | add al, '0' 269 | mov es:[bx], al 270 | sti 271 | pop dx 272 | pop cx 273 | pop bx 274 | pop ax 275 | pop es 276 | ret 277 | 278 | -------------------------------------------------------------------------------- /pce/pceexit.a86: -------------------------------------------------------------------------------- 1 | ; This program is free software; you can redistribute it and/or modify 2 | ; it under the terms of the GNU General Public License as published by 3 | ; the Free Software Foundation; either version 2 of the License, or 4 | ; (at your option) any later version. 5 | ; 6 | ; This program is distributed in the hope that it will be useful, 7 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | ; GNU General Public License for more details. 10 | ; 11 | ; You should have received a copy of the GNU General Public License along 12 | ; with this program; if not, write to the Free Software Foundation, Inc., 13 | ; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 14 | 15 | title 'PCEEXIT - Leave Emulator ' 16 | 17 | include pce.a86 18 | 19 | cseg 20 | 21 | lea si, msg_hdr 22 | call print_str 23 | call pce_hook_check 24 | jc not_pce 25 | call delay 26 | mov ax, pce_hook_abort 27 | call pce_hook 28 | jc hook_err 29 | xor al, al 30 | call quit 31 | not_pce: 32 | lea si, msg_notpce 33 | call print_str 34 | call quit 35 | hook_err: 36 | lea si, msg_hookerr 37 | call print_str 38 | call quit 39 | 40 | include pcelib.a86 41 | include tinylib.a86 42 | include baselib.a86 43 | 44 | dseg 45 | msg_hdr db 'Exiting PCE ...',13,10,0 46 | msg_notpce db 'Not running under PCE',13,10,0 47 | msg_hookerr db 'PCE Hook Error',13,10,0 48 | 49 | end 50 | -------------------------------------------------------------------------------- /pce/pceinit.a86: -------------------------------------------------------------------------------- 1 | ; This program is free software; you can redistribute it and/or modify 2 | ; it under the terms of the GNU General Public License as published by 3 | ; the Free Software Foundation; either version 2 of the License, or 4 | ; (at your option) any later version. 5 | ; 6 | ; This program is distributed in the hope that it will be useful, 7 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | ; GNU General Public License for more details. 10 | ; 11 | ; You should have received a copy of the GNU General Public License along 12 | ; with this program; if not, write to the Free Software Foundation, Inc., 13 | ; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 14 | 15 | 16 | title 'PCEINIT - Start CP/M' 17 | 18 | include pce.a86 19 | 20 | cseg 21 | mov cx,ds 22 | mov es,cx 23 | call cls 24 | call print_cpm_ver 25 | mov cx,0Ch 26 | int 0E0h 27 | cmp ax,1430h 28 | jz wrg_os 29 | cmp ax,1431h 30 | jz wrg_os 31 | sub ax,1462h 32 | ja hw_end 33 | call print_hw 34 | jmp hw_end 35 | wrg_os: 36 | lea si, msg_wrg_os 37 | call print_str 38 | call quit 39 | hw_end: 40 | lea si, msg_rtc 41 | call print_str 42 | 43 | include pceclock.a86 44 | 45 | cls: 46 | push ax 47 | push bx 48 | push cx 49 | mov dx,27 50 | mov cl,02h 51 | int 0E0h 52 | mov dx,'E' 53 | mov cl,02h 54 | int 0E0h 55 | pop cx 56 | pop bx 57 | pop ax 58 | ret 59 | 60 | print_hw: 61 | push ax 62 | push bx 63 | push cx 64 | push dx 65 | push es 66 | push si 67 | lea si, msg_hw_hdr 68 | call print_str 69 | lea si, msg_hw_mem 70 | call print_str 71 | int 12h 72 | mov bx,10 73 | call print_uint16 74 | lea si, msg_hw_kb 75 | call print_str 76 | lea si, msg_hw_amem 77 | call print_str 78 | mov dx,offset mcb 79 | mov cl,35h 80 | int 0E0h 81 | mov ax, word ptr mlen 82 | mov cl,6 83 | shr ax, cl 84 | inc ax 85 | inc ax 86 | mov bx,10 87 | call print_uint16 88 | lea si, msg_hw_kb 89 | call print_str 90 | lea si, msg_hw_87 91 | call print_str 92 | int 11h 93 | add ax,0040h 94 | and ax,0fff3h 95 | push ax 96 | and al,2 97 | jz no_87 98 | lea si, msg_hw_yes 99 | jmp done_87 100 | no_87: 101 | lea si, msg_hw_no 102 | done_87: 103 | call print_str 104 | lea si, msg_hw_flp 105 | call print_str 106 | pop ax 107 | push ax 108 | xor ah,ah 109 | mov cl,06h 110 | shr al,cl 111 | and al,07h 112 | mov bx,10 113 | call print_uint16 114 | lea si, msg_nl 115 | call print_str 116 | lea si, msg_hw_dsk 117 | call print_str 118 | call disk_count 119 | mov bx,10 120 | call print_uint16 121 | lea si, msg_nl 122 | call print_str 123 | lea si, msg_hw_par 124 | call print_str 125 | pop ax 126 | push ax 127 | mov cl,0Eh 128 | shr ax,cl 129 | and al,03h 130 | mov bx,10 131 | call print_uint16 132 | lea si, msg_nl 133 | call print_str 134 | lea si, msg_hw_ser 135 | call print_str 136 | pop ax 137 | mov cl,09h 138 | shr ax,cl 139 | and al,07h 140 | mov bx,10 141 | call print_uint16 142 | lea si, msg_nl 143 | call print_str 144 | pop si 145 | pop es 146 | pop dx 147 | pop cx 148 | pop bx 149 | pop ax 150 | ret 151 | 152 | print_cpm_ver: 153 | push si 154 | push ax 155 | push bx 156 | push cx 157 | push dx 158 | mov cx,0Ch 159 | int 0E0h 160 | push ax 161 | cmp ah,15h 162 | jz print_ver_mpm 163 | cmp ax,1430h 164 | jz print_ver_ccpm 165 | cmp ax,1431h 166 | jz print_ver_ccpm 167 | cmp ax,1466h 168 | jae print_ver_mdos 169 | cmp ah,14h 170 | jz print_ver_cdos 171 | cmp ax,1041h 172 | jz print_ver_dosp 173 | cmp ax,22h 174 | jz print_ver_cpm 175 | lea si, msg_cpm86 176 | call print_str 177 | jmp print_ver_base 178 | print_ver_cpm: 179 | lea si, msg_pccpm86 180 | call print_str 181 | jmp print_ver_base 182 | print_ver_dosp: 183 | lea si, msg_dosp 184 | call print_str 185 | jmp print_os_ver 186 | print_ver_mpm: 187 | lea si, msg_mpm86 188 | call print_str 189 | jmp print_os_ver 190 | print_ver_cdos: 191 | lea si, msg_cdos 192 | call print_str 193 | jmp print_os_ver 194 | print_ver_mdos: 195 | lea si, msg_mdos 196 | call print_str 197 | jmp print_os_ver 198 | print_ver_ccpm: 199 | lea si, msg_ccpm86 200 | call print_str 201 | jmp print_os_ver 202 | print_os_ver: 203 | mov cx,0A3h 204 | int 0E0h 205 | mov ax,bx 206 | xor ah,ah 207 | mov bx,10 208 | mov dl,al 209 | mov cl,4 210 | shr al, cl 211 | and al,0Fh 212 | call print_uint16 213 | mov al,'.' 214 | call print_char 215 | mov al,dl 216 | xor ah,ah 217 | and al,0Fh 218 | call print_uint16 219 | lea si, msg_ver_sep 220 | call print_str 221 | jmp print_ver_base 222 | print_ver_base: 223 | pop ax 224 | lea si, msg_ver_hdr 225 | call print_str 226 | xor ah,ah 227 | mov bx,10 228 | mov dl,al 229 | mov cl,4 230 | shr al, cl 231 | and al,0Fh 232 | call print_uint16 233 | mov al,'.' 234 | call print_char 235 | mov al,dl 236 | xor ah,ah 237 | and al,0Fh 238 | call print_uint16 239 | lea si, msg_nl 240 | call print_str 241 | print_ver_end: 242 | pop dx 243 | pop cx 244 | pop bx 245 | pop ax 246 | pop si 247 | ret 248 | 249 | include pcelib.a86 250 | include tinylib.a86 251 | include baselib.a86 252 | 253 | dseg 254 | 255 | mcb dw 0 256 | mlen dw 65534 257 | mext db 0 258 | month_siz db 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 259 | month_day dw 000,031,059,090,120,151,181,212,243,273,304,334 260 | msg_wrg_os db 'Not supported by this operating system.',13,10,0 261 | msg_notpce db 'Not running under PCE ...',13,10,0 262 | msg_hookerr db 'No PCE RTC clock ...',13,10,0 263 | msg_rtc db 'Date now: ',0 264 | msg_cpm86 db 'CP/M-86, ',0 265 | msg_pccpm86 db 'CP/M-86 1.1, ',0 266 | msg_ccpm86 db 'Concurrent CP/M-86 ',0 267 | msg_mpm86 db 'MP/M-86 ',0 268 | msg_cdos db 'Concurrent DOS ',0 269 | msg_mdos db 'Multiuser DOS ',0 270 | msg_dosp db 'DOSPLUS ',0 271 | msg_ver_hdr db 'BDOS ',0 272 | msg_ver_sep db ', ',0 273 | msg_hw_hdr db 'Hardware Configuration: ',13,10,0 274 | msg_hw_mem db ' - System Memory: ',0 275 | msg_hw_amem db ' - Available Memory: ',0 276 | msg_hw_87 db ' - Math Coprocessor: ',0 277 | msg_hw_flp db ' - Floppy Drive(s): ',0 278 | msg_hw_dsk db ' - Hard Disk(s): ',0 279 | msg_hw_par db ' - Parallel Port(s): ',0 280 | msg_hw_ser db ' - Serial Port(s): ',0 281 | msg_hw_yes db 'Yes',13,10,0 282 | msg_hw_no db 'No',13,10,0 283 | msg_hw_kb db 'Kb',13,10,0 284 | msg_nl db 13,10,0 285 | tm_buffer rs 256 286 | stamp_year rw 1 287 | stamp_hours rb 1 288 | stamp_mins rb 1 289 | stamp_secs rb 1 290 | db 0 291 | 292 | end 293 | -------------------------------------------------------------------------------- /pce/pcelib.a86: -------------------------------------------------------------------------------- 1 | ; This program is free software; you can redistribute it and/or modify 2 | ; it under the terms of the GNU General Public License as published by 3 | ; the Free Software Foundation; either version 2 of the License, or 4 | ; (at your option) any later version. 5 | ; 6 | ; This program is distributed in the hope that it will be useful, 7 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | ; GNU General Public License for more details. 10 | ; 11 | ; You should have received a copy of the GNU General Public License along 12 | ; with this program; if not, write to the Free Software Foundation, Inc., 13 | ; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 14 | 15 | 16 | cseg 17 | pce_hook_check: 18 | xor ax, ax 19 | db 0D5h 20 | db 000h 21 | sub ax, 0FCEh 22 | jnz pce_hook_check_notpce 23 | ret 24 | pce_hook_check_notpce: 25 | mov ax, 0FFFFh 26 | stc 27 | ret 28 | pce_hook: 29 | clc 30 | db 0D5h 31 | db 000h 32 | ret 33 | 34 | -------------------------------------------------------------------------------- /pce/pcemnt.a86: -------------------------------------------------------------------------------- 1 | ; This program is free software; you can redistribute it and/or modify 2 | ; it under the terms of the GNU General Public License as published by 3 | ; the Free Software Foundation; either version 2 of the License, or 4 | ; (at your option) any later version. 5 | ; 6 | ; This program is distributed in the hope that it will be useful, 7 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | ; GNU General Public License for more details. 10 | ; 11 | ; You should have received a copy of the GNU General Public License along 12 | ; with this program; if not, write to the Free Software Foundation, Inc., 13 | ; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 14 | 15 | 16 | title 'PCEMNT - Mount Image File' 17 | 18 | include pce.a86 19 | 20 | cseg 21 | 22 | mov cx, ds 23 | mov es, cx 24 | lea si, msg_hdr 25 | call print_str 26 | call pce_hook_check 27 | jc not_pce 28 | mov si, 80h 29 | lodsb 30 | mov cl, al 31 | xor ch, ch 32 | lea di, str1 33 | call parse_opt 34 | jc usage 35 | lea di, str2 36 | call parse_opt 37 | lea di, str1 38 | jc insert 39 | 40 | id: 41 | lea si, msg_id 42 | call print_str 43 | mov al,' ' 44 | call print_char 45 | mov si, di 46 | call print_str 47 | lea si, msg_id 48 | mov ax, pce_hook_setmsg 49 | call pce_hook 50 | jc hook_err 51 | lea di, str2 52 | mov al,' ' 53 | call print_char 54 | insert: 55 | lea si, msg_insert 56 | call print_str 57 | mov al,' ' 58 | call print_char 59 | mov si, di 60 | call print_str 61 | lea si, msg_conclude 62 | call print_str 63 | lea si, msg_insert 64 | mov ax, pce_hook_setmsg 65 | call pce_hook 66 | jc hook_err 67 | call quit 68 | 69 | usage: 70 | lea si, msg_usage 71 | call print_str 72 | call quit 73 | 74 | not_pce: 75 | lea si, msg_notpce 76 | call print_str 77 | call quit 78 | hook_err: 79 | lea si, msg_hookerr 80 | call print_str 81 | call quit 82 | 83 | include pcelib.a86 84 | include tinylib.a86 85 | include baselib.a86 86 | 87 | dseg 88 | 89 | msg_id db 'disk.id',0 90 | msg_insert db 'disk.insert',0 91 | msg_usage db 'usage: pcemnt [drive] [filename]',13,10,0 92 | msg_hdr db 'Requesting PCE mount ...',13,10,0 93 | msg_notpce db 'Not running under PCE',13,10,0 94 | msg_hookerr db 'PCE Hook Error',13,10,0 95 | msg_conclude db ' ...',13,10,0 96 | str1 rs 256 97 | str2 rs 256 98 | db 0 99 | 100 | end 101 | -------------------------------------------------------------------------------- /pce/pcetime.a86: -------------------------------------------------------------------------------- 1 | ; This program is free software; you can redistribute it and/or modify 2 | ; it under the terms of the GNU General Public License as published by 3 | ; the Free Software Foundation; either version 2 of the License, or 4 | ; (at your option) any later version. 5 | ; 6 | ; This program is distributed in the hope that it will be useful, 7 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | ; GNU General Public License for more details. 10 | ; 11 | ; You should have received a copy of the GNU General Public License along 12 | ; with this program; if not, write to the Free Software Foundation, Inc., 13 | ; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 14 | 15 | 16 | title 'PCETIME - Time Sync App' 17 | 18 | include pce.a86 19 | 20 | cseg 21 | 22 | mov cx,ds 23 | mov es,cx 24 | lea si, msg_hdr 25 | call print_str 26 | 27 | include pceclock.a86 28 | include pcelib.a86 29 | include tinylib.a86 30 | include baselib.a86 31 | 32 | dseg 33 | 34 | month_siz db 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 35 | month_day dw 000,031,059,090,120,151,181,212,243,273,304,334 36 | msg_hdr db 'Requesting PCE time ...',13,10,0 37 | msg_notpce db 'Not running under PCE',13,10,0 38 | msg_hookerr db 'PCE Hook Error',13,10,0 39 | msg_cpm31 db 'CP/M 31 ...',13,10,0 40 | msg_nl db 13,10,0 41 | tm_buffer rs 256 42 | stamp_year rw 1 43 | stamp_hours rb 1 44 | stamp_mins rb 1 45 | stamp_secs rb 1 46 | 47 | db 0 48 | 49 | end 50 | -------------------------------------------------------------------------------- /pce/pcever.a86: -------------------------------------------------------------------------------- 1 | ; This program is free software; you can redistribute it and/or modify 2 | ; it under the terms of the GNU General Public License as published by 3 | ; the Free Software Foundation; either version 2 of the License, or 4 | ; (at your option) any later version. 5 | ; 6 | ; This program is distributed in the hope that it will be useful, 7 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | ; GNU General Public License for more details. 10 | ; 11 | ; You should have received a copy of the GNU General Public License along 12 | ; with this program; if not, write to the Free Software Foundation, Inc., 13 | ; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 14 | 15 | 16 | title 'PCEVER - Display Emulator Version' 17 | 18 | include pce.a86 19 | 20 | cseg 21 | 22 | lea si, msg_hdr 23 | call print_str 24 | call pce_hook_check 25 | jc not_pce 26 | lea di, buffer 27 | mov cx, ds 28 | mov es, cx 29 | mov cx, 256 30 | mov ax, pce_hook_verstr 31 | call pce_hook 32 | jc hook_err 33 | mov ax, pce_hook_ver 34 | call pce_hook 35 | jc hook_err 36 | 37 | lea si, msg_verstr1 38 | call print_str 39 | lea si, buffer 40 | call print_str 41 | lea si, msg_verstr2 42 | call print_str 43 | xchg cx, ax 44 | xor ah, ah 45 | mov bx, 16 46 | mov al, dh 47 | call print_uint16 48 | mov al, '.' 49 | call print_char 50 | mov al, dl 51 | call print_uint16 52 | mov al, '.' 53 | call print_char 54 | mov al, ch 55 | call print_uint16 56 | xor al, al 57 | lea si, msg_verstr3 58 | call print_str 59 | call quit 60 | 61 | not_pce: 62 | lea si, msg_notpce 63 | call print_str 64 | call quit 65 | hook_err: 66 | lea si, msg_hookerr 67 | call print_str 68 | call quit 69 | 70 | include pcelib.a86 71 | include tinylib.a86 72 | include baselib.a86 73 | 74 | dseg 75 | org 100h 76 | 77 | msg_hdr db 'Requesting PCE version ...',13,10,0 78 | msg_notpce db 'Not running under PCE',13,10,0 79 | msg_hookerr db 'PCE Hook Error',13,10,0 80 | msg_verstr1 db 'PCE version ',0 81 | msg_verstr2 db ' (',0 82 | msg_verstr3 db ')',13,10,0 83 | buffer rs 256 84 | db 0 85 | 86 | end 87 | -------------------------------------------------------------------------------- /printenv.c: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed under the MIT license. See LICENSE file in the project root for details. 3 | */ 4 | 5 | #include 6 | #ifdef __STDC__ 7 | #include 8 | #endif 9 | #include 10 | #include 11 | 12 | #ifndef __STDC__ 13 | int main(argc,argv) 14 | int argc; 15 | char **argv; 16 | #else 17 | int main(int argc, char **argv) 18 | #endif 19 | { 20 | int i; 21 | 22 | i=1; 23 | while(i 6 | #ifdef __STDC__ 7 | #include 8 | #endif 9 | #include 10 | #include 11 | 12 | int getch() 13 | { 14 | int i, c, d; 15 | static int s = 0; 16 | 17 | if (s > 0) { 18 | c = s; 19 | s = 0; 20 | return c; 21 | } 22 | while (!(c = bdos(6, 255))) 23 | ; 24 | while (d = bdos(6, 255)) 25 | ; 26 | return c; 27 | } 28 | 29 | 30 | #ifndef __STDC__ 31 | int main(argc,argv) 32 | int argc; 33 | char **argv; 34 | #else 35 | int main(int argc, char **argv) 36 | #endif 37 | { 38 | int i; 39 | 40 | dirent_t * root; 41 | dirent_t * cursor; 42 | int rc; 43 | char * pat=0; 44 | int ask=0; 45 | int all=0; 46 | int force=0; 47 | FILE *conout; 48 | 49 | i=1; 50 | while(ientry[0]),cursor->drive+'A'); 123 | offset=strlen(path); 124 | for(j=1;j<9;j++) { 125 | if(((cursor->entry[j])&0x7F)==' ') { 126 | continue; 127 | } 128 | path[offset++]=cursor->entry[j]&0x7F; 129 | } 130 | for(j=9;j<12;j++) { 131 | if(((cursor->entry[j])&0x7F)==' ') { 132 | break; 133 | } 134 | if(!dot) { 135 | dot=1; 136 | path[offset++]='.'; 137 | } 138 | path[offset++]=cursor->entry[j]&0x7F; 139 | } 140 | path[offset]=0; 141 | 142 | if(dirent_is_sys(cursor) && !all) { 143 | cursor=cursor->next; 144 | continue; 145 | } 146 | if(dirent_is_ro(cursor)) { 147 | if(force) { 148 | char ro_fcb[40]; 149 | int ou; 150 | int u; 151 | memset(ro_fcb,0,sizeof(ro_fcb)); 152 | ou=getusr(); 153 | u=dirent_fcb(ro_fcb,cursor); 154 | fcb_clear_ro(ro_fcb); 155 | setusr(u); 156 | debug_dump_hex(stderr, (unsigned char*)(ro_fcb), 33, 0L, 0); 157 | bdos(30,ro_fcb); 158 | setusr(ou);; 159 | } else { 160 | cursor=cursor->next; 161 | continue; 162 | } 163 | } 164 | { 165 | int delete=1; 166 | fprintf(conout,"INF: Deleting %s ",path); 167 | if(ask) { 168 | int c; 169 | 170 | fprintf(conout,"(Y/N)"); 171 | while(1) { 172 | c=getch(); 173 | if(c=='y'||c=='Y') { 174 | fprintf(stdout,"\x08\x08\x08\x08\x08 "); 175 | fprintf(stdout,"\x08\x08\x08\x08\x08"); 176 | delete=1; 177 | break; 178 | } 179 | if(c=='n'||c=='N') { 180 | fprintf(stdout,"\x08\x08\x08\x08\x08Skipping\n"); 181 | delete=0; 182 | break; 183 | } 184 | if(c==3) { 185 | fprintf(stdout,"\x08\x08\x08\x08\x08 "); 186 | fprintf(stdout,"\x08\x08\x08\x08\x08^C"); 187 | dirent_free(root); 188 | exit(0); 189 | break; 190 | } 191 | } 192 | } else { 193 | } 194 | if(delete) { 195 | if(unlink(path)) { 196 | fprintf(conout,"Failed\n",path); 197 | } else { 198 | fprintf(conout,"OK\n",path); 199 | } 200 | } 201 | } 202 | cursor=cursor->next; 203 | } 204 | dirent_free(root); 205 | exit(0); 206 | } 207 | -------------------------------------------------------------------------------- /rtcdef.a86: -------------------------------------------------------------------------------- 1 | ATCLOCK EQU 0 2 | CPORT EQU 02C0h 3 | DPORT EQU CPORT + 1 4 | DS12C887 EQU 0 5 | -------------------------------------------------------------------------------- /skel.a86: -------------------------------------------------------------------------------- 1 | ; 2 | ; Licensed under the MIT license. See LICENSE file in the project root for details. 3 | ; 4 | 5 | title 'Skeleton' 6 | 7 | cseg 8 | mov cx,ds 9 | mov es,cx 10 | mov dx, offset msg_hdr 11 | mov cl,9 12 | int 0E0h 13 | xor cx,cx 14 | int 0E0h 15 | 16 | dseg 17 | msg_hdr db 'Test',13,10,'$' 18 | end 19 | -------------------------------------------------------------------------------- /startup.0: -------------------------------------------------------------------------------- 1 | A:SUBMIT A:DEFAULT0.SUB 2 | -------------------------------------------------------------------------------- /test.txt: -------------------------------------------------------------------------------- 1 | a 2 | A 3 | B 4 | C 5 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 6 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 7 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 8 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 9 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 10 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 11 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 12 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 13 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 14 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 15 | -------------------------------------------------------------------------------- /time.a86: -------------------------------------------------------------------------------- 1 | ; 2 | ; Licensed under the MIT license. See LICENSE file in the project root for details. 3 | ; 4 | 5 | title 'ATTIME - AT clock time Sync App' 6 | 7 | cseg 8 | 9 | mov cx,ds 10 | mov es,cx 11 | mov cx,0Ch 12 | int 0E0h 13 | cmp ax,1430h 14 | jz wrg_os 15 | cmp ax,1431h 16 | jz wrg_os 17 | jmp at_time 18 | wrg_os: 19 | lea si, msg_wrg_os 20 | call print_str 21 | call quit 22 | at_time: 23 | lea si, msg_hdr 24 | call print_str 25 | 26 | include clock.a86 27 | 28 | include tinylib.a86 29 | include baselib.a86 30 | 31 | dseg 32 | 33 | month_siz db 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 34 | month_day dw 000,031,059,090,120,151,181,212,243,273,304,334 35 | msg_wrg_os db 'Not supported by this operating system.',13,10,0 36 | msg_hdr db 'Requesting BIOS time ...',13,10,0 37 | msg_interr db 'AT BIOS interrupt error ...',13,10,0 38 | msg_86err db 'Not an AT class system ...',13,10,0 39 | msg_cpm31 db 'CP/M 31 ...',13,10,0 40 | msg_nl db 13,10,0 41 | tm_buffer rs 256 42 | stamp_year rw 1 43 | stamp_hours rb 1 44 | stamp_mins rb 1 45 | stamp_secs rb 1 46 | 47 | db 0 48 | 49 | end 50 | -------------------------------------------------------------------------------- /tinylib.a86: -------------------------------------------------------------------------------- 1 | ; 2 | ; Licensed under the MIT license. See LICENSE file in the project root for details. 3 | ; 4 | 5 | quit: 6 | xor cx,cx 7 | int 0E0h 8 | ret 9 | 10 | print_char: 11 | push cx 12 | push dx 13 | push bx 14 | xor ah, ah 15 | mov dx, ax 16 | mov cl, 2 17 | int 0E0h 18 | pop bx 19 | pop dx 20 | pop cx 21 | ret 22 | 23 | print_uint16: 24 | push ax 25 | push cx 26 | push dx 27 | push bx 28 | push es 29 | xor cx, cx 30 | print_uint16_next1: 31 | xor dx, dx 32 | div bx 33 | cmp dl, 10 34 | jb print_uint16_isdigit 35 | add dl, 'A' - 10 - '0'; 36 | print_uint16_isdigit: 37 | add dl, '0' 38 | push dx 39 | inc cx 40 | or ax, ax 41 | jnz print_uint16_next1 42 | print_uint16_next2: 43 | pop ax 44 | push cx 45 | push dx 46 | mov dx,ax 47 | xor dh,dh 48 | mov cx, 02h 49 | int 0E0h 50 | pop dx 51 | pop cx 52 | loop print_uint16_next2 53 | pop es 54 | pop bx 55 | pop dx 56 | pop cx 57 | pop ax 58 | ret 59 | 60 | print_str: 61 | push ax 62 | push bx 63 | push cx 64 | push dx 65 | push es 66 | push si 67 | cld 68 | print_str_next: 69 | lodsb 70 | or al, al 71 | jz print_str_done 72 | mov dx, ax 73 | xor dh, dh 74 | mov cx, 02h 75 | int 0E0h 76 | jmp print_str_next 77 | print_str_done: 78 | pop si 79 | pop es 80 | pop dx 81 | pop cx 82 | pop bx 83 | pop ax 84 | ret 85 | 86 | -------------------------------------------------------------------------------- /tod.a86: -------------------------------------------------------------------------------- 1 | ; 2 | ; Licensed under the MIT license. See LICENSE file in the project root for details. 3 | ; 4 | 5 | title 'CP/M-86 TOD replacement' 6 | 7 | 8 | code cseg 9 | 10 | mov cx,ds 11 | mov es,cx 12 | mov cx,0Ch 13 | int 0E0h 14 | sub al,22H 15 | ja wrg_os 16 | call arg_avail 17 | or ax,ax 18 | jz just_show 19 | call parse_date 20 | or ax,ax 21 | jnz wrg_fmt 22 | call check_date 23 | or ax,ax 24 | jnz wrg_fmt 25 | call cpm_set_time 26 | cmp ax,0 27 | jnz wrg_fmt 28 | just_show: 29 | call clear_keys 30 | just_show_time: 31 | call cpm_show_time 32 | mov cl, byte ptr disp_loop 33 | or cl, 0 34 | jz loop_just_show 35 | call quit 36 | loop_just_show: 37 | call wait_key 38 | or ax, 0 39 | jnz loop_show_done 40 | lea si, msg_back 41 | call print_str 42 | jmp just_show_time 43 | loop_show_done: 44 | call clear_keys 45 | call quit 46 | wrg_os: 47 | lea si, msg_wrg_os 48 | call print_str 49 | call quit 50 | wrg_fmt: 51 | lea si, msg_wrg_fmt 52 | call print_str 53 | call quit 54 | 55 | arg_avail: 56 | push cx 57 | push si 58 | mov si, 80h 59 | mov cl, byte ptr [si] 60 | or cl,cl 61 | jz arg_noarg 62 | tail_loop: 63 | inc si 64 | mov al, ds:[si] 65 | cmp al,' ' 66 | je tail_loop 67 | cmp al,0Dh 68 | je arg_noarg 69 | cmp al,00h 70 | je arg_noarg 71 | arg_args: 72 | cmp al, 'P' 73 | je arg_loop 74 | mov ax,1 75 | jmp arg_end 76 | arg_loop: 77 | mov al, 0 78 | mov byte ptr disp_loop, al 79 | arg_noarg: 80 | mov ax,0 81 | jmp arg_end 82 | arg_end: 83 | pop si 84 | pop cx 85 | ret 86 | 87 | parse_date: 88 | push es 89 | push bx 90 | push dx 91 | push di 92 | mov cx,ds 93 | mov es,cx 94 | 95 | mov di, 80h ; date 96 | lea si, tmz_date 97 | 98 | pd_spc: 99 | inc di 100 | mov al, [di] 101 | cmp al, ' ' 102 | je pd_spc 103 | 104 | mov cx, 2 105 | pd_year: 106 | mov al, [di] ; year 107 | call isdigit 108 | or ah, ah 109 | jnz pd_err 110 | mov [si], al 111 | inc si 112 | inc di 113 | dec cx 114 | or cx,cx 115 | jnz pd_year 116 | 117 | mov al, [di] 118 | cmp al, '/' 119 | jne pd_err 120 | inc si 121 | inc di 122 | 123 | mov cx, 2 124 | pd_month: 125 | mov al, [di] ; month 126 | call isdigit 127 | or ah, ah 128 | jnz pd_err 129 | mov [si], al 130 | inc si 131 | inc di 132 | dec cx 133 | or cx,cx 134 | jnz pd_month 135 | 136 | mov al, [di] 137 | cmp al, '/' 138 | jne pd_err 139 | inc si 140 | inc di 141 | 142 | mov cx, 2 143 | pd_day: 144 | mov al, [di] ; day 145 | call isdigit 146 | or ah, ah 147 | jnz pd_err 148 | mov [si], al 149 | inc si 150 | inc di 151 | dec cx 152 | or cx,cx 153 | jnz pd_day 154 | 155 | inc si 156 | jnz pt_spc 157 | pd_err: 158 | jmp pt_err 159 | 160 | pt_section: 161 | inc di 162 | pt_spc: 163 | mov al, [di] 164 | cmp al, ' ' 165 | je pt_section 166 | 167 | mov cx, 2 168 | pt_hour: 169 | mov al, [di] ; hour 170 | call isdigit 171 | or ah, ah 172 | jnz pt_err 173 | mov [si], al 174 | inc si 175 | inc di 176 | dec cx 177 | or cx,cx 178 | jnz pt_hour 179 | 180 | mov al, [di] 181 | cmp al, ':' 182 | jne pt_err 183 | inc si 184 | inc di 185 | 186 | mov cx, 2 187 | pt_min: 188 | mov al, [di] ; minute 189 | call isdigit 190 | or ah, ah 191 | jnz pt_err 192 | mov [si], al 193 | inc si 194 | inc di 195 | dec cx 196 | or cx,cx 197 | jnz pt_min 198 | 199 | mov al, [di] 200 | cmp al, ':' 201 | jne pt_err 202 | inc si 203 | inc di 204 | 205 | mov cx, 2 206 | pt_sec: 207 | mov al, [di] ; second 208 | call isdigit 209 | or ah, ah 210 | jnz pt_err 211 | mov [si], al 212 | inc si 213 | inc di 214 | dec cx 215 | or cx,cx 216 | jnz pt_sec 217 | 218 | mov ax,0 219 | jmp pt_end 220 | pt_err: 221 | mov ax,1 222 | jmp pt_end 223 | pt_end: 224 | pop di 225 | pop dx 226 | pop bx 227 | pop es 228 | ret 229 | 230 | check_date: 231 | push bx 232 | push cx 233 | push dx 234 | 235 | mov al, byte ptr tmz_date+6 ;check leap year 236 | sub al, '0' 237 | xor ah,ah 238 | mov bl,10 239 | imul bl 240 | xor bh, bh 241 | mov bl, byte ptr tmz_date+7 242 | sub bl, '0' 243 | add ax, bx 244 | or ax, ax 245 | jz no_leap 246 | and ax, 3 247 | jnz no_leap 248 | mov bx, offset month_siz+2 249 | mov ax, 29 250 | mov [bx], ax 251 | no_leap: 252 | mov al, byte ptr tmz_date ;check month 253 | sub al, '0' 254 | xor ah,ah 255 | mov bl,10 256 | imul bl 257 | xor bh, bh 258 | mov bl, byte ptr tmz_date+1 259 | sub bl, '0' 260 | add ax, bx 261 | mov dx, ax 262 | cmp ax, 12 263 | ja ckd_err 264 | cmp ax, 1 265 | jb ckd_err 266 | 267 | mov al, byte ptr tmz_date+3 ;check day 268 | sub al, '0' 269 | xor ah,ah 270 | mov bl,10 271 | imul bl 272 | xor bh, bh 273 | mov bl, byte ptr tmz_date+4 274 | sub bl, '0' 275 | add ax, bx 276 | mov bx, offset month_siz 277 | add bx,dx 278 | mov cl, [bx] 279 | xor ch, ch 280 | cmp ax, cx 281 | ja ckd_err 282 | cmp ax, 1 283 | jb ckd_err 284 | jmp ck_time 285 | 286 | ckd_err: 287 | jmp ckt_err 288 | ck_time: 289 | mov al, byte ptr tmz_time ;check hour 290 | sub al, '0' 291 | xor ah,ah 292 | mov bl,10 293 | imul bl 294 | xor bh, bh 295 | mov bl, byte ptr tmz_time+1 296 | sub bl, '0' 297 | add ax, bx 298 | cmp ax, 23 299 | ja ckt_err 300 | 301 | mov al, byte ptr tmz_time+3 ;check minutes 302 | sub al, '0' 303 | xor ah,ah 304 | mov bl,10 305 | imul bl 306 | xor bh, bh 307 | mov bl, byte ptr tmz_time+4 308 | sub bl, '0' 309 | add ax, bx 310 | cmp ax, 59 311 | ja ckt_err 312 | 313 | mov al, byte ptr tmz_time+6 ;check seconds 314 | sub al, '0' 315 | xor ah,ah 316 | mov bl,10 317 | imul bl 318 | xor bh, bh 319 | mov bl, byte ptr tmz_time+7 320 | sub bl, '0' 321 | add ax, bx 322 | cmp ax, 59 323 | ja ckt_err 324 | 325 | mov ax,0 326 | jmp ckt_end 327 | ckt_err: 328 | mov ax,1 329 | jmp ckt_end 330 | ckt_end: 331 | pop dx 332 | pop cx 333 | pop bx 334 | ret 335 | 336 | cpm_set_time: 337 | push es 338 | push ds 339 | push si 340 | push di 341 | push bx 342 | push cx 343 | push dx 344 | cli 345 | 346 | mov cl, 31h ;Call Get Sysdata Addrs interrupt. 347 | int 0E0h ;CP/M interrupt. ES:BX -> Sysdata. 348 | add bx, 20h ;ES:BX now -> 17 bytes of time/date data. 349 | mov di, bx 350 | mov byte ptr tmz_sep,',' 351 | lea si, tmz_date 352 | mov cx, 17 353 | cst_cpy: mov bl, ds:[si] ;copy source to destination 354 | mov es:[di], bl 355 | inc si ;increment source and destination 356 | inc di 357 | dec cx ;decrement count 358 | jnz cst_cpy ;if not zero goto next bit 359 | sti 360 | mov ax, 0 361 | pop dx 362 | pop cx 363 | pop bx 364 | pop di 365 | pop si 366 | pop ds 367 | pop es 368 | ret 369 | 370 | cpm_show_time: 371 | push es 372 | push ds 373 | push si 374 | push di 375 | push ax 376 | push bx 377 | push cx 378 | push dx 379 | cli 380 | 381 | mov cl, 31h ;Call Get Sysdata Addrs interrupt. 382 | int 0E0h ;CP/M interrupt. ES:BX -> Sysdata. 383 | add bx, 20h ;ES:BX now -> 17 bytes of time/date data. 384 | mov di, bx 385 | lea si, tmz_date 386 | mov cx, 17 387 | csh_cpy: mov bl, es:[di] ;copy source to destination 388 | mov ds:[si], bl 389 | inc si ;increment source and destination 390 | inc di 391 | dec cx ;decrement count 392 | jnz csh_cpy ;if not zero goto next bit 393 | sti 394 | lea si, tmz_date 395 | mov byte ptr tmz_sep,9 396 | call print_str 397 | pop dx 398 | pop cx 399 | pop bx 400 | pop ax 401 | pop di 402 | pop si 403 | pop ds 404 | pop es 405 | ret 406 | 407 | isdigit: 408 | cmp al, '0' 409 | jb id_err 410 | cmp al, '9' 411 | ja id_err 412 | mov ah, 0 413 | jmp id_end 414 | id_err: 415 | mov ah, 1 416 | id_end: 417 | ret 418 | 419 | include tinylib.a86 420 | include baselib.a86 421 | 422 | data dseg 423 | month_siz db 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 424 | msg_wrg_os db 'Requires CP/M-86 1.1',13,10,0 425 | msg_wrg_fmt db 'Invalid Date & Time Format',13,10 426 | db 'Please retry using:',13,10 427 | db 'X>TOD MM/DD/YY HH:MM:SS',13,10 428 | db 'where YY is in range 00-99 for 2000 to 2099',13,10,0 429 | msg_nl db 13,10,0 430 | msg_back db 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 431 | disp_loop db 1 432 | tmz_date db '01/01/01' 433 | tmz_sep db 9 434 | tmz_time db '01:01:01' 435 | db 0 436 | tm_buffer rs 256 437 | db 0 438 | 439 | end 440 | -------------------------------------------------------------------------------- /touch.c: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed under the MIT license. See LICENSE file in the project root for details. 3 | */ 4 | 5 | #include 6 | #ifdef __STDC__ 7 | #include 8 | #endif 9 | #include 10 | #include 11 | 12 | #ifndef __STDC__ 13 | int main(argc,argv) 14 | int argc; 15 | char **argv; 16 | #else 17 | int main(int argc, char **argv) 18 | #endif 19 | { 20 | int i; 21 | FILE * fp; 22 | char * filename=0; 23 | 24 | i=1; 25 | while(i 2 | #include 3 | #include 4 | 5 | #ifdef __STDC__ 6 | #include 7 | #include 8 | #endif 9 | 10 | /*#define DEBUG_LOW */ 11 | 12 | #define VALLEN 256 13 | #define VARLEN 16 14 | 15 | typedef struct _entry_t { 16 | char * var; 17 | char * val; 18 | struct _entry_t * next; 19 | } entry_t; 20 | 21 | static entry_t * le_entries=0; 22 | static int loaded=0; 23 | 24 | #define STATE_INIT 0 25 | #define STATE_NL 1 26 | #define STATE_VAR 2 27 | #define STATE_VAL 3 28 | #define STATE_PRESEP 4 29 | #define STATE_POSTSEP 5 30 | #define STATE_ERROR 6 31 | #define STATE_EOF 7 32 | #define STATE_COMMENT 8 33 | 34 | #ifndef __STDC__ 35 | static st_val(c,val,state,offset) 36 | int c; 37 | char * val; 38 | int * state; 39 | int * offset; 40 | #else 41 | static void st_val(int c, char * val, int * state, int * offset) 42 | #endif 43 | { 44 | #ifdef DEBUG_LOW 45 | fprintf(stderr,"DBG: %d:%d[%c]\n",*state,*offset,(char)c>=' '?c:'.'); 46 | #endif 47 | if(c==EOF) { 48 | val[*offset]=0; 49 | *offset=0; 50 | *state=STATE_EOF; 51 | return; 52 | } 53 | if(c=='\n' || c=='\r') { 54 | val[*offset]=0; 55 | *offset=0; 56 | *state=STATE_NL; 57 | return; 58 | } 59 | if(*offset=' '?c:'.'); 78 | #endif 79 | if(c==' ' || c=='\t') { 80 | return; 81 | } 82 | if(c==EOF) { 83 | val[*offset]=0; 84 | *offset=0; 85 | *state=STATE_EOF; 86 | return; 87 | } 88 | if(c=='\n' || c=='\r') { 89 | val[*offset]=0; 90 | *offset=0; 91 | *state=STATE_NL; 92 | return; 93 | } 94 | val[*offset]=c; 95 | *offset=*offset+1; 96 | *state=STATE_VAL; 97 | return; 98 | } 99 | 100 | #ifndef __STDC__ 101 | static st_presep(c,state,offset) 102 | int c; 103 | int * state; 104 | int * offset; 105 | #else 106 | static void st_presep(int c, int * state, int * offset) 107 | #endif 108 | { 109 | #ifdef DEBUG_LOW 110 | fprintf(stderr,"DBG: %d:%d[%c]\n",*state,*offset,(char)c>=' '?c:'.'); 111 | #endif 112 | if(c==' ' || c=='\t') { 113 | return; 114 | } 115 | if(c=='=') { 116 | *state=STATE_POSTSEP; 117 | return; 118 | } 119 | *state=STATE_ERROR; 120 | return; 121 | } 122 | 123 | #ifndef __STDC__ 124 | static st_var(c,var,state,offset) 125 | int c; 126 | char * var; 127 | int * state; 128 | int * offset; 129 | #else 130 | static void st_var(int c, char * var, int * state, int * offset) 131 | #endif 132 | { 133 | #ifdef DEBUG_LOW 134 | fprintf(stderr,"DBG: %d:%d[%c]\n",*state,*offset,(char)c>=' '?c:'.'); 135 | #endif 136 | if(c==' ' || c=='\t') { 137 | var[*offset]=0; 138 | *offset=0; 139 | if(strlen(var)) { 140 | *state=STATE_PRESEP; 141 | } else { 142 | *state=STATE_ERROR; 143 | } 144 | return; 145 | } 146 | if(c=='=') { 147 | var[*offset]=0; 148 | *offset=0; 149 | if(strlen(var)) { 150 | *state=STATE_POSTSEP; 151 | } else { 152 | *state=STATE_ERROR; 153 | } 154 | return; 155 | } 156 | if(isalnum(c)) { 157 | if(*offset=' '?c:'.'); 186 | #endif 187 | if(c==';') { 188 | *state=STATE_COMMENT; 189 | *offset=0; 190 | return; 191 | } 192 | if(c==' ' || c=='\t') { 193 | return; 194 | } 195 | if(c=='\n' || c=='\t') { 196 | return; 197 | } 198 | if(isalnum(c)) { 199 | var[*offset]=toupper(c); 200 | *offset=*offset+1; 201 | *state=STATE_VAR; 202 | return; 203 | } 204 | if(c=='_') { 205 | var[*offset]=c; 206 | *offset=*offset+1; 207 | *state=STATE_VAR; 208 | return; 209 | } 210 | *state=STATE_ERROR; 211 | return; 212 | } 213 | 214 | #ifndef __STDC__ 215 | static st_comment(c,state,offset) 216 | int c; 217 | int * state; 218 | int * offset; 219 | #else 220 | static void st_comment(int c, int * state, int * offset) 221 | #endif 222 | { 223 | #ifdef DEBUG_LOW 224 | fprintf(stderr,"DBG: %d:%d[%c]\n",*state,*offset,(char)c>=' '?c:'.'); 225 | #endif 226 | if(c==EOF) { 227 | *state=EOF; 228 | } else if(c=='\n' || c=='\r') { 229 | *state=STATE_INIT; 230 | } 231 | } 232 | 233 | 234 | #ifndef __STDC__ 235 | entry_t * new_entry(current,var,val) 236 | entry_t * current; 237 | char * var; 238 | char * val; 239 | #else 240 | entry_t * new_entry(entry_t * current, char * var, char * val) 241 | #endif 242 | { 243 | int i; 244 | entry_t * e=(entry_t*)malloc(sizeof(entry_t)); 245 | if(!e) { 246 | return e; 247 | } 248 | e->var=(char *)malloc(strlen(var)+1); 249 | if(!e->var) { 250 | free(e); 251 | return 0; 252 | } 253 | strcpy(e->var,var); 254 | e->val=(char *)malloc(strlen(val)+1); 255 | if(!e->val) { 256 | free(e->var); 257 | free(e); 258 | return 0; 259 | } 260 | strcpy(e->val,val); 261 | for(i=strlen(e->val)-1;i>-1;i--) { 262 | if(isspace(e->val[i])) { 263 | e->val[i]=0; 264 | }else{ 265 | break; 266 | } 267 | } 268 | #ifdef DEBUG 269 | fprintf(stderr,"DBG: Added entry(%s,%s)\n",e->var,e->val); 270 | #endif 271 | e->next=current; 272 | return e; 273 | } 274 | 275 | static char lef_var[VARLEN+1]; 276 | static char lef_val[VALLEN+1]; 277 | 278 | #ifndef __STDC__ 279 | static int lef(path) 280 | char * path; 281 | #else 282 | static int lef(char * path) 283 | #endif 284 | { 285 | FILE *fp; 286 | int state=STATE_INIT; 287 | int offset=0; 288 | int loop=1; 289 | int c; 290 | entry_t * current; 291 | char *var=lef_var; 292 | char *val=lef_val; 293 | current=le_entries; 294 | 295 | fp=fopen(path, "r"); 296 | if(!fp) { 297 | #ifdef DEBUG 298 | fprintf(stderr,"DBG: Could not find file %s\n",path); 299 | #endif 300 | return -1; 301 | } 302 | while(loop) { 303 | c=fgetc(fp); 304 | switch(state) { 305 | case STATE_INIT: 306 | st_init(c,var,&state,&offset); 307 | break; 308 | case STATE_NL: 309 | current=new_entry(current,var,val); 310 | if(current) { 311 | le_entries=current; 312 | } else { 313 | loop=0; 314 | break; 315 | } 316 | state=STATE_INIT; 317 | st_init(c,var,&state,&offset); 318 | break; 319 | case STATE_PRESEP: 320 | st_presep(c,&state,&offset); 321 | break; 322 | case STATE_POSTSEP: 323 | st_postsep(c,val,&state,&offset); 324 | break; 325 | case STATE_COMMENT: 326 | st_comment(c,&state,&offset); 327 | break; 328 | case STATE_VAR: 329 | st_var(c,var,&state,&offset); 330 | break; 331 | case STATE_VAL: 332 | st_val(c,val,&state,&offset); 333 | break; 334 | case STATE_EOF: 335 | current=new_entry(current,var,val); 336 | if(current) { 337 | le_entries=current; 338 | } 339 | loop=0; 340 | break; 341 | case STATE_ERROR: 342 | loop=0; 343 | break; 344 | } 345 | } 346 | fclose(fp); 347 | return 0; 348 | } 349 | 350 | #ifndef __STDC__ 351 | int istrcmp (p1, p2, p) 352 | char *p1; 353 | char *p2; 354 | int p; 355 | #else 356 | int istrcmp (char *p1, char *p2,int p) 357 | #endif 358 | { 359 | unsigned char *s1 = (unsigned char *) p1; 360 | unsigned char *s2 = (unsigned char *) p2; 361 | unsigned char c1, c2; 362 | 363 | do 364 | { 365 | c1 = (unsigned char) tolower(*s1++); 366 | c2 = (unsigned char) tolower(*s2++); 367 | if (c1 == '\0') 368 | if(p) { 369 | return 0; 370 | } else { 371 | return c1 - c2; 372 | } 373 | } 374 | while (c1 == c2); 375 | 376 | return c1 - c2; 377 | } 378 | 379 | 380 | #ifndef __STDC__ 381 | static le() 382 | #else 383 | static void le() 384 | #endif 385 | { 386 | char path[20]; 387 | char drv; 388 | 389 | if(loaded) { 390 | return; 391 | } 392 | 393 | strcpy(path,"?:ENV.DAT"); 394 | 395 | drv=getcurdrv()+'A'; 396 | path[0]=drv; 397 | loaded=!lef(path); 398 | 399 | if(loaded) { 400 | return; 401 | } 402 | 403 | strcpy(path,"0/?:ENV.DAT"); 404 | 405 | if(getusr()!=0) { 406 | drv=getcurdrv()+'A'; 407 | path[2]=drv; 408 | loaded=!lef(path); 409 | } 410 | 411 | if(loaded) { 412 | return; 413 | } 414 | 415 | drv=getccpdrv()+'A'; 416 | if(drv>=0 && drv!=path[2]){ 417 | path[2]=drv; 418 | loaded=!lef(path); 419 | } 420 | loaded=1; 421 | } 422 | 423 | #ifndef __STDC__ 424 | printenv(fp) 425 | FILE *fp; 426 | #else 427 | void printenv(FILE * fp) 428 | #endif 429 | { 430 | entry_t * cursor; 431 | 432 | le(); 433 | cursor=le_entries; 434 | while(cursor) { 435 | fprintf(fp,"%s=%s\n",cursor->var,cursor->val); 436 | cursor=cursor->next; 437 | } 438 | } 439 | 440 | #ifndef __STDC__ 441 | char* getenv(v) 442 | char *v; 443 | #else 444 | char* getenv(const char *v) 445 | #endif 446 | { 447 | entry_t * cursor; 448 | 449 | le(); 450 | cursor=le_entries; 451 | while(cursor) { 452 | if(!istrcmp(cursor->var,(char*)v,0)) { 453 | return cursor->val; 454 | } 455 | cursor=cursor->next; 456 | } 457 | return 0; 458 | } 459 | 460 | -------------------------------------------------------------------------------- /util.h: -------------------------------------------------------------------------------- 1 | #ifndef _OS_H_ 2 | #define _OS_H_ 3 | 4 | /* 5 | Licensed under the MIT license. See LICENSE file in the project root for details. 6 | */ 7 | 8 | typedef struct dpb_t { 9 | unsigned int spt; 10 | unsigned char bsh; 11 | unsigned char blm; 12 | unsigned char exm; 13 | unsigned int dsm; 14 | unsigned int drm; 15 | unsigned char al0; 16 | unsigned char al1; 17 | unsigned int cks; 18 | unsigned int off; 19 | } dpb_t; 20 | 21 | 22 | #ifndef __STDC__ 23 | int keyb(); 24 | int osver(); 25 | int getcurdrv(); 26 | int setcurdrv(); 27 | int getccpdrv(); 28 | int bdosx(); 29 | int istrcmp(); 30 | char * getenv(); 31 | printenv(); 32 | delay(); 33 | typedef unsigned int size_t; 34 | #else 35 | int keyb(); 36 | int osver(); 37 | int ostype(); 38 | int getcurdrv(); 39 | int setcurdrv(int drv); 40 | int getccpdrv(); 41 | int bdosx(int cx, int dx, int* es, int *bx); 42 | int istrcmp (char *p1, char *p2,int p); 43 | char *getenv(const char *name); 44 | void printenv(FILE * fp); 45 | void delay(unsigned int delay); 46 | #endif 47 | #define OSTYPE_MULTIUSER 0x04 48 | 49 | #ifndef __STDC__ 50 | dpb_load(); 51 | #else 52 | dpb_load(int drive, dpb_t*dpb); 53 | #endif 54 | 55 | #ifndef __STDC__ 56 | char *malloc(); 57 | #endif 58 | 59 | #define fcb_is_sys(fcb) (fcb[10]&~0x7F) 60 | #define fcb_is_ro(fcb) (fcb[9]&~0x7F) 61 | #define fcb_set_sys(fcb) (fcb[10]|=0x80) 62 | #define fcb_set_ro(fcb) (fcb[9]|=0x80) 63 | #define fcb_clear_sys(fcb) (fcb[10]&=0x7F) 64 | #define fcb_clear_ro(fcb) (fcb[9]&=0x7F) 65 | 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /ver.a86: -------------------------------------------------------------------------------- 1 | ; 2 | ; Licensed under the MIT license. See LICENSE file in the project root for details. 3 | ; 4 | 5 | title 'CP/M Version' 6 | 7 | 8 | cseg 9 | mov cx,ds 10 | mov es,cx 11 | call print_cpm_ver 12 | call quit 13 | 14 | print_cpm_ver: 15 | push si 16 | push ax 17 | push bx 18 | push cx 19 | push dx 20 | mov cx,0Ch 21 | int 0E0h 22 | push ax 23 | cmp ah,15h 24 | jz print_ver_mpm 25 | cmp ax,1430h 26 | jz print_ver_ccpm 27 | cmp ax,1431h 28 | jz print_ver_ccpm 29 | cmp ax,1466h 30 | jae print_ver_mdos 31 | cmp ax,1450h 32 | jae print_ver_cdosxm 33 | cmp ah,14h 34 | jz print_ver_cdos 35 | cmp ax,1041h 36 | jz print_ver_dosp 37 | cmp ax,22h 38 | jz print_ver_cpm 39 | lea si, msg_cpm86 40 | call print_str 41 | jmp print_ver_base 42 | print_ver_cpm: 43 | lea si, msg_pccpm86 44 | call print_str 45 | jmp print_ver_base 46 | print_ver_dosp: 47 | lea si, msg_dosp 48 | call print_str 49 | jmp print_os_ver 50 | print_ver_mpm: 51 | lea si, msg_mpm86 52 | call print_str 53 | jmp print_os_ver 54 | print_ver_cdosxm: 55 | lea si, msg_cdosxm 56 | call print_str 57 | jmp print_os_ver 58 | print_ver_cdos: 59 | lea si, msg_cdos 60 | call print_str 61 | jmp print_os_ver 62 | print_ver_mdos: 63 | lea si, msg_mdos 64 | call print_str 65 | jmp print_os_ver 66 | print_ver_ccpm: 67 | lea si, msg_ccpm86 68 | call print_str 69 | jmp print_os_ver 70 | print_os_ver: 71 | mov cx,0A3h 72 | int 0E0h 73 | mov ax,bx 74 | xor ah,ah 75 | mov bx,10 76 | mov dl,al 77 | mov cl,4 78 | shr al, cl 79 | and al,0Fh 80 | call print_uint16 81 | mov al,'.' 82 | call print_char 83 | mov al,dl 84 | xor ah,ah 85 | and al,0Fh 86 | call print_uint16 87 | lea si, msg_ver_sep 88 | call print_str 89 | jmp print_ver_base 90 | print_ver_base: 91 | pop ax 92 | lea si, msg_ver_hdr 93 | call print_str 94 | xor ah,ah 95 | mov bx,10 96 | mov dl,al 97 | mov cl,4 98 | shr al, cl 99 | and al,0Fh 100 | call print_uint16 101 | mov al,'.' 102 | call print_char 103 | mov al,dl 104 | xor ah,ah 105 | and al,0Fh 106 | call print_uint16 107 | lea si, msg_nl 108 | call print_str 109 | print_ver_end: 110 | pop dx 111 | pop cx 112 | pop bx 113 | pop ax 114 | pop si 115 | ret 116 | 117 | include tinylib.a86 118 | 119 | dseg 120 | msg_cpm86 db 'CP/M-86, ',0 121 | msg_pccpm86 db 'CP/M-86 1.1, ',0 122 | msg_ccpm86 db 'Concurrent CP/M-86 ',0 123 | msg_mpm86 db 'MP/M-86 ',0 124 | msg_cdosxm db 'Concurrent DOS XM ',0 125 | msg_cdos db 'Concurrent DOS ',0 126 | msg_mdos db 'Multiuser DOS ',0 127 | msg_dosp db 'DOS Plus ',0 128 | msg_ver_hdr db 'BDOS ',0 129 | msg_ver_sep db ', ',0 130 | msg_nl db 13,10,0 131 | end 132 | -------------------------------------------------------------------------------- /wc.c: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed under the MIT license. See LICENSE file in the project root for details. 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #ifdef __STDC__ 11 | #include 12 | #else 13 | char *malloc(); 14 | #endif 15 | 16 | #define BUFLEN (16*1024) 17 | 18 | #ifndef __STDC__ 19 | int parse_file(filename, w, l, c) 20 | char *filename; 21 | unsigned long * w; 22 | unsigned long * l; 23 | unsigned long * c; 24 | #else 25 | int parse_file(char * filename, unsigned long *w, unsigned long *l, 26 | unsigned long *c) 27 | #endif 28 | { 29 | FILE *infp; 30 | int count; 31 | int ic; 32 | int state=0; 33 | int eof=0; 34 | char * buffer; 35 | 36 | if (!(infp = fopen(filename, "r"))) { 37 | return -1; 38 | } 39 | buffer=malloc(BUFLEN); 40 | 41 | *w = 0; 42 | *l = 0; 43 | *c = 0; 44 | while(!eof && (count = fread(buffer,1,BUFLEN,infp)) != 0) { 45 | int i; 46 | for(i=0;ientry[0]),cursor->drive+'A'); 150 | offset=strlen(path); 151 | for(j=1;j<9;j++) { 152 | if(((cursor->entry[j])&0x7F)==' ') { 153 | continue; 154 | } 155 | path[offset++]=cursor->entry[j]&0x7F; 156 | } 157 | for(j=9;j<12;j++) { 158 | if(((cursor->entry[j])&0x7F)==' ') { 159 | break; 160 | } 161 | if(!dot) { 162 | dot=1; 163 | path[offset++]='.'; 164 | } 165 | path[offset++]=cursor->entry[j]&0x7F; 166 | } 167 | path[offset]=0; 168 | 169 | if(dirent_is_sys(cursor) && !all) { 170 | cursor=cursor->next; 171 | continue; 172 | } 173 | if (!flag_break) { 174 | int d; 175 | while(bdos(11,0)) { 176 | d=bdos(1,0); 177 | if(d==3) ctrlc=1; 178 | } 179 | } 180 | if(parse_file(path,&w,&l,&c)) { 181 | fprintf(stderr,"ERR: File error on '%s'\n",path); 182 | } else { 183 | tw+=w; 184 | tl+=l; 185 | tc+=c; 186 | fprintf(stdout, "%-20s %-6lu %-6lu %-6lu\n",path,w,l,c); 187 | } 188 | cursor=cursor->next; 189 | if(ctrlc) { 190 | break; 191 | } 192 | } 193 | dirent_free(root); 194 | i++; 195 | } 196 | if(!ctrlc) { 197 | fprintf(stdout, "%-20s %-6lu %-6lu %-6lu\n","TOTAL",tw,tl,tc); 198 | } 199 | exit(0); 200 | } 201 | -------------------------------------------------------------------------------- /write.c: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed under the MIT license. See LICENSE file in the project root for details. 3 | */ 4 | 5 | #include 6 | 7 | #ifdef __STDC__ 8 | #include 9 | #else 10 | char * malloc(); 11 | #endif 12 | 13 | #include 14 | #include 15 | 16 | #define BUFLEN (16*1024) 17 | 18 | #define GETCH_BUFLEN (12) 19 | static char getch_buffer[GETCH_BUFLEN]; 20 | 21 | int getch() 22 | { 23 | int i,c,d; 24 | static int s=0; 25 | static int o=0; 26 | 27 | if(s>0) { 28 | c=getch_buffer[o];s--;o++; 29 | o=o%GETCH_BUFLEN; 30 | return c; 31 | } 32 | while(!(c=bdos(6,255))) 33 | continue; 34 | while(s0) { 95 | printf("\b \b"); 96 | offset--; 97 | } 98 | continue; 99 | } 100 | switch(c) { 101 | case EOF: 102 | printf("%s","\n"); 103 | eof=1; 104 | break; 105 | case 3: 106 | printf("%s","^C\n"); 107 | eof=1; 108 | break; 109 | case 26: 110 | printf("%s","^Z\n"); 111 | eof=1; 112 | break; 113 | case '\r': 114 | printf("%s","\r\n"); 115 | buffer[offset]=0; 116 | fprintf(fp,"%s\n",buffer); 117 | offset=0; 118 | continue; 119 | default: 120 | if(c<' ') { 121 | continue; 122 | } 123 | } 124 | if(eof) { 125 | break; 126 | } 127 | if(offset==BUFLEN) { 128 | continue; 129 | } 130 | buffer[offset++]=c; 131 | putchar(c); 132 | } 133 | if(offset>0) { 134 | buffer[offset]=0; 135 | fprintf(fp,"%s",buffer); 136 | fflush(fp); 137 | } 138 | fputc(26,fp); 139 | fprintf(stderr,"INF: --END--\n"); 140 | fprintf(stderr,"INF: Closing file '%s' ...",argv[arg_offset]); 141 | fflush(fp); 142 | fclose(fp); 143 | return 0; 144 | } 145 | --------------------------------------------------------------------------------