├── .gitignore ├── GUIDE ├── LICENSE ├── Makefile ├── PROGRAMS ├── README ├── WHATIS ├── external_licences ├── basic ├── bricks ├── chess ├── coreutils ├── doom ├── fbird ├── himem ├── invaders ├── lights ├── nyan ├── pillman ├── reboot ├── rogue └── screensaver ├── installer.asm ├── lst └── .nomedia ├── makebase.py ├── makesoftware.sh ├── os.asm ├── osall.iso ├── pre-commit ├── shared ├── dummyfs.asm ├── fat12.asm └── fsloader.asm ├── software.txt ├── software_src ├── basic ├── bricks ├── charset ├── chess ├── clear ├── clock ├── disk ├── doom ├── download ├── ember ├── fat12 ├── fbird ├── heart ├── init32 ├── install ├── invaders ├── lba ├── lights ├── loadb ├── mine ├── multitd ├── pillman ├── pull ├── push ├── qm ├── reboot ├── rogue ├── screensaver ├── slide ├── snake ├── sokoban ├── sound ├── tetris └── upload ├── strip.py └── symbols.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.img 2 | *.inc 3 | *.lst 4 | lst/*.lst 5 | software/* 6 | -------------------------------------------------------------------------------- /GUIDE: -------------------------------------------------------------------------------- 1 | This guide is divided into two sections: 2 | 1. New users guide 3 | 2. Developers guide 4 | Section 1: 5 | 1.1 What is bootOS? 6 | bootOS is a monolithic operating system that fits in 7 | one boot sector. It's able to load, execute, and save 8 | programs. Also keeps a filesystem. It can work with 9 | any type of data storage. 10 | 11 | It relocates itself at 0000:7a00 and requires further 12 | 768 bytes of memory starting at 0000:7700. 13 | 14 | This operating system runs programs as boot sectors 15 | at 0000:7c00 16 | 17 | 1.2 What are the benefits of this bootOS? 18 | * Better line handling 19 | * More filespace (uses LBA) 20 | * More interrupts 21 | * Geometry independent 22 | * Software builder 23 | * Unlimited files 24 | 25 | 1.3 How can I run it? 26 | First of all, you need the packages "nasm", "qemu-kvm", "make" and "python3". 27 | bootOS is designed to be build on Linux (Debian) and wasn't tested somewhere else. 28 | To build a blank system without any software, you can run "make os.img". This can 29 | be done on Windows too. 30 | To build a system including all software, you can run "make software". 31 | If you want to exclude software, just add "E=software_src/something" at the beginning. 32 | If you want to build the installer, you can run "make installer". 33 | When you have booted the installer, you 34 | have to enter your drive's id. You can find the id under https://en.wikipedia.org/wiki/INT_13H#List_of_INT_13h_services. 35 | Note: Your boot drive has the id 80 or 00 if you are using a floppy disk. The installation should output the error code 0x00. 36 | Error code 0x01: 37 | Drive not readable. Is your usb stick plugged in? 38 | Error code 0x02: 39 | Drive is not writeable. Is it the CD ROM or something other? 40 | Error code 0x03: 41 | Source and target are the same drive. 42 | Error code 0x04: 43 | Already installed. Eject the CD/USB 44 | 1.4 How can contribute even though I cannot program? 45 | You can try it and try to find bugs. ;) 46 | 47 | Section 2: 48 | 2.1 Setup a small program 49 | The base program is very simple: 50 | org 0x7c00 51 | bits 16 52 | exit 53 | 2.2 A reference for all interrupts provided by bootOS 54 | int 0x20 Exit to operating system. 55 | int 0x21 Input key and show in screen. 56 | Entry: none 57 | Output: AL = ASCII key pressed. 58 | Affects: AH/BX/BP. 59 | int 0x22 Output character to screen. 60 | Entry: AL = Character. 61 | Output: none. 62 | Affects: AH/BX/BP. 63 | int 0x23 Load file. 64 | Entry: DS:BX = Filename terminated with zero. 65 | ES:DI = Point to source data (512 bytes) 66 | Output: Carry flag = 0 = Found, 1 = Not found. 67 | Affects: All registers (including ES). 68 | int 0x24 Save file. 69 | Entry: DS:BX = Filename terminated with zero. 70 | ES:DI = Point to data target (512 bytes) 71 | Output: Carry flag = 0 = Successful. 1 = Error. 72 | Affects: All registers (including ES). 73 | int 0x25 Delete file. 74 | Entry: DS:BX = Filename terminated with zero. 75 | Affects: All registers (including ES). 76 | int 0x26 Input line and save it to 0x7780. 77 | Entry: AL = promt character 78 | Affects: I don't know 79 | 2.3 The magic offsets 80 | bootOS provides two important offsets on build: 81 | * DB S 82 | * DW HD 83 | DB S is the offset where you can change the section. It's one byte. 84 | DW HD is the offset where you can change the drive and head. It's a word 0xhhdd. 85 | Note: it's safer and more beatiful to use the symbols in sysmap.inc! 86 | 2.4 The breakpoint 87 | If you want your code to run every loop before the "int int_input_line", you can replace the 88 | interrupt 0x27 with your code. This is used in the clock as you can see. 89 | 2.5 sysmap.inc 90 | sysmap.inc can be generated with "make symbols" and can be used to link your program 91 | to the running system. You just have to add '%include "../sysmap.inc"' to use the labels. 92 | This can be very useful to not waste space for code you already have in memory. 93 | Labels start with "bootOS.". (e.g. "bootOS.restart") 94 | This file provides the exit instruction. 95 | 2.6 32-bit access 96 | Note: this article is about init32. 97 | A 80386 or higher microprocessor allows you to access memory with 32-bit registers 98 | as long as you use the Address Size Override Prefix. Nasm does this usually when you 99 | don't define the bits (e.g. not "bits 16"). 100 | 101 | will be expanded... 102 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Oscar Toledo G. http://nanochess.org/ 2 | Copyright (c) 2020 Jakob Kirsch 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile contributed by jtsiomb 2 | 3 | src = os.asm 4 | FILES = . 5 | 6 | .PHONY: help 7 | help: 8 | @echo =====bootOS===== 9 | @echo all: make all 10 | @echo run: run 11 | @echo install: install on /dev/sdc 12 | @echo software: make os image with software 13 | @echo wipe: wipe /dev/sdc 14 | @echo installer: make installer 15 | @echo cdimg: make cd image 16 | @echo strip: strip image 17 | @echo symbols: create sysmap.inc 18 | @echo ================ 19 | 20 | .PHONY: all 21 | all: run 22 | 23 | os.img: $(src) 24 | nasm -f bin -o os.img -l os.lst $(src) 25 | .PHONY: clean 26 | clean: 27 | $(RM) *.img 28 | $(RM) *.lst 29 | $(RM) lst/*.lst 30 | $(RM) *.inc 31 | -$(RM) software/ -fr 32 | 33 | .PHONY: run 34 | run: os.img 35 | qemu-system-i386 -drive file=$<,format=raw -serial stdio -s -soundhw pcspk 36 | .PHONY: install 37 | install: 38 | dd if=os.img of=$M 39 | .PHONY: software 40 | software: os.img symbols 41 | mkdir software 42 | bash makesoftware.sh 43 | python3 makebase.py $(EXCLUDE) 44 | dd if=$< of=base.img conv=notrunc bs=512 count=1 45 | mv base.img os.img 46 | rm -fr software 47 | .PHONY: installer 48 | installer: 49 | nasm -f bin -o installer.img installer.asm 50 | cat os.img >> installer.img 51 | mv installer.img os.img 52 | .PHONY: cdimg 53 | cdimg: os.img 54 | dd if=/dev/zero of=tmp.img bs=512 count=2879 55 | dd if=os.img of=tmp.img count=512 count=2879 conv=notrunc 56 | mv tmp.img os.img 57 | genisoimage -pad -b os.img -R -o cd.img os.img 58 | .PHONY: strip 59 | strip: os.img 60 | python3 strip.py 61 | .PHONY: runkvm 62 | runkvm: os.img 63 | qemu-system-x86_64 -drive file=$<,format=raw --enable-kvm -serial stdio -s -soundhw pcspk 64 | .PHONY: symbols 65 | symbols: 66 | python3 symbols.py os.asm sysmap.inc 67 | .PHONY: upload 68 | upload: software 69 | @sudo cp os.img /smb/usb.img 70 | @echo Reboot the PC! 71 | -------------------------------------------------------------------------------- /PROGRAMS: -------------------------------------------------------------------------------- 1 | basic: 2 | A small basic interpreter. 3 | bricks: 4 | A game like Atari Breakout. 5 | charset: 6 | Shows you the current characters set. 7 | clear: 8 | Clears the screen. 9 | clock: 10 | Installs itself into memory to run every keypress and displays the time. 11 | disk: 12 | Changes the current disk (00-ff): 13 | 00 is the first floppy disk 14 | 01 is the second floppy disk 15 | ... 16 | 80 is the first hard disk 17 | 81 in the second hard disk 18 | ... 19 | e0 is the CD disk (only for live systems booted from CD disk) 20 | doom: 21 | A cubic version of doom. 22 | fbird: 23 | Floppy bird (a clone of Flappy Bird). 24 | head: 25 | Changes current head. (00-ff) 26 | install: 27 | Installs entered file into the bootsector of the specified drive (see command "disk" for drive notation). 28 | Note: It must be a valid bootsector -> no int 0x20, word 0x7c1e must be 0xaa55 29 | Note: This uninstalls bootOS from the bootsector but does not wipe the data. 30 | invaders: 31 | A invaders clone. 32 | jmp: 33 | Combines the disk, head and # command. 34 | Format: ddhh## 35 | lbaaviable: 36 | Checks, if the LBA extension is aviable. This is useful for os_new.asm. 37 | lights: 38 | Remember the sequence of lights. 39 | loadb: 40 | Loads a program for basic which was saved and sets the dirty bit. 41 | pillman: 42 | A pacman clone. 43 | push: 44 | Pushs a program into a memory section. \ 45 | pull: |--- For moving programs 46 | Pulls a program from a memory section. / 47 | reboot: 48 | Reboots the system (jumps to 0xffff:0000). 49 | rogue: 50 | A rogue like game. 51 | screensaver: 52 | A Julia fractal screensaver. 53 | sound: 54 | Plays music. 55 | init32: 56 | Initializes unreal mode. This allows other programs to access memory above 1MB. This program only works on 386+ 57 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | _ _ ____ _____ 2 | | | | | / __ \ / ____| 3 | | |__ ___ ___ | |_ | | | || (___ 4 | | '_ \ / _ \ / _ \| __|| | | | \___ \ 5 | | |_) || (_) || (_) | |_ | |__| | ____) | 6 | |_.__/ \___/ \___/ \__||\____/ |_____/ 7 | 8 | bootOS operating system in 512 bytes (boot sector) 9 | by Oscar Toledo G. Jul/22/2019 10 | fork by Jakob Kirsch Jan/19/2020 11 | 12 | http://nanochess.org 13 | https://github.com/nanochess/bootOS 14 | 15 | Note: Commit 0cbeecb917e4e5008351c2adedafffd13c0e83ae is the result of 117 commits (My original fork was on https://edugit.org/jakobkir/bootOS). 16 | 17 | If you want to assemble it, you must download the Netwide Assembler 18 | (nasm) from www.nasm.us 19 | 20 | Use this command line for an empty image: 21 | 22 | nasm -f bin os.asm -l os.lst -o os.img 23 | 24 | 25 | What is bootOS: 26 | 27 | bootOS is a monolithic operating system that fits in 28 | one boot sector. It's able to load, execute, and save 29 | programs. Also keeps a filesystem. It can work with 30 | any type of data storage. 31 | 32 | It relocates itself at 0000:7a00 and requires further 33 | 768 bytes of memory starting at 0000:7700. 34 | 35 | This operating system runs programs as boot sectors 36 | at 0000:7c00. 37 | 38 | It needs at least an 80386 CPU to work properly with all commands. 39 | If you only want the kernel to work, you should have at least an 80186 CPU. 40 | 41 | It provides the following services: 42 | 43 | int 0x20 Exit to operating system. 44 | int 0x21 Input key and show in screen. 45 | Entry: none 46 | Output: AL = ASCII key pressed. 47 | Affects: AH/BX/BP. 48 | int 0x22 Output character to screen. 49 | Entry: AL = Character. 50 | Output: none. 51 | Affects: AH/BX/BP. 52 | int 0x23 Load file. 53 | Entry: DS:BX = Filename terminated with zero. 54 | ES:DI = Point to source data (512 bytes) 55 | Output: Carry flag = 0 = Found, 1 = Not found. 56 | Affects: All registers (including ES). 57 | int 0x24 Save file. 58 | Entry: DS:BX = Filename terminated with zero. 59 | ES:DI = Point to data target (512 bytes) 60 | Output: Carry flag = 0 = Successful. 1 = Error. 61 | Affects: All registers (including ES). 62 | int 0x25 Delete file. 63 | Entry: DS:BX = Filename terminated with zero. 64 | Affects: All registers (including ES). 65 | int 0x26 Input line and save it to 0x7780. 66 | Entry: AL = promt character 67 | Affects: AX/BX/DX/BP/SI/DI 68 | 69 | Filesystem organization: 70 | 71 | Each entry in the directory is 16 bytes wide, and 72 | contains the ASCII name of the file finished with a 73 | zero byte. A sector has a capacity of 512 bytes, it 74 | means only 32 files can be kept in one section. 75 | Each section has a size of 256 sectors. 76 | Since it works with LBA the disk can keep up to 2TB of data. 77 | 78 | Deleting a file is a matter of zeroing a whole entry. 79 | 80 | Each file is one sector long. Its location in the 81 | disk is derived from its position in the directory. 82 | 83 | Starting bootOS kernel: 84 | 85 | Just enter "make runkvm". 86 | 87 | Installing bootOS to an usb stick: 88 | 89 | Just enter "sudo make install M=/path/to/usb". 90 | 91 | Installing bootOS with installer: 92 | 93 | Just enter "make installer" and "sudo make install". When you have booted the installer, you 94 | have to enter your drive's id. You can find the id under https://en.wikipedia.org/wiki/INT_13H#List_of_INT_13h_services. 95 | Note: Your boot drive has the id 80 or 00 if you are using a floppy disk. The installation should output the error code 0x00. 96 | Error code 0x01: 97 | Drive not readable. Is your usb stick plugged in? 98 | Error code 0x02: 99 | Drive is not writeable. Is it the CD ROM or something other? 100 | Error code 0x03: 101 | Source and target are the same drive. 102 | Error code 0x04: 103 | Already installed. Eject the CD/USB 104 | 105 | Installing bootOS from a CD: 106 | 107 | Just run "make cdimg" to make a CD image. Note: this feature is not longer maintained and may not work! 108 | 109 | Build bootOS with software: 110 | 111 | Just enter "make software". This will compile all files in the software_src directory and build the image. 112 | 113 | Full installation route: 114 | 115 | Enter "make clean && make software && make installer && sudo make install" for a installer USB stick. 116 | Enter "make clean && make software && sudo make install" for a live system USB stick. 117 | 118 | bootOS commands: 119 | 120 | ls Shows the directory's content. 121 | rm filename Deletes the "filename" file. 122 | edit Allows to enter up to 512 hexadecimal 123 | bytes to create another file. 124 | 125 | Notice the line size is 128 characters so 126 | you must break the input into chunks of 127 | 4, 8 or 16 bytes. 128 | 129 | It also allows to copy the last executed 130 | program just press Enter when the '<' prompt 131 | appears and type the new name. 132 | rl Run last program 133 | sl Save last program to disk 134 | 135 | other external commands: 136 | 137 | disk Change current disk. The disk number is stored at 0xffff in memory. Enter a disk number 138 | between 00 and ff behind the @. 80 is the first hard disk. 00 is the first floppy disk. 139 | push Copy a program to 0xa000 from disk \ 140 | pull Copy a program to disk from 0xa000 / used for copying between disks and sections 141 | clear Clear the screen. 142 | 143 | For example: (Character + is Enter key) 144 | 145 | >edit+ 146 | dir+ 152 | hello 153 | >hello+ 154 | Hello, world 155 | > 156 | 157 | 158 | bootOS programs: (Oh yes! we have software support) 159 | 160 | bricks https://github.com/nanochess/bricks 161 | fbird https://github.com/nanochess/fbird 162 | Pillman https://github.com/nanochess/pillman 163 | invaders https://github.com/nanochess/invaders 164 | bootBASIC https://github.com/nanochess/bootBASIC 165 | bootRogue https://github.com/nanochess/bootRogue 166 | Atomchess https://github.com/nanochess/Toledo-Atomchess 167 | (requires minimum 286 processor) 168 | 169 | Also our first 3rd party programs!!! 170 | 171 | bootSlide https://github.com/XlogicX/BootSlide 172 | (requires minimum 286 processor) 173 | tetranglix https://github.com/XlogicX/tetranglix 174 | (requires minimum 286 processor) 175 | snake https://gitlab.com/pmikkelsen/asm_snake 176 | (requires minimum 286 processor) 177 | mine https://gitlab.com/blevy/boot-sector-minesweeper 178 | (requires minimum Pentium II processor because rdtsc instruction) 179 | 180 | These programs provide a boot sector version and a COM 181 | file version. You need the boot sector version as the 182 | programs are loaded at address 0000:7c00. 183 | 184 | Enjoy it! 185 | 186 | 187 | Special thanks to Jakub Kądziołka (NieDzejkob) for finding 188 | some bugs and suggesting enhancements. 189 | 190 | 191 | >> ATTENTION << 192 | 193 | Would you like to learn 8086/8088 programming? Then you 194 | must get my new book Programming Boot Sector Games including 195 | a 8086/8088 crash course! 196 | 197 | Now available from Lulu: 198 | 199 | Soft-cover 200 | http://www.lulu.com/shop/oscar-toledo-gutierrez/programming-boot-sector-games/paperback/product-24188564.html 201 | 202 | Hard-cover 203 | http://www.lulu.com/shop/oscar-toledo-gutierrez/programming-boot-sector-games/hardcover/product-24188530.html 204 | 205 | eBook 206 | https://nanochess.org/store.html 207 | 208 | These are some of the example programs documented profusely 209 | in the book: 210 | 211 | * Guess the number. 212 | * Tic-Tac-Toe game. 213 | * Text graphics. 214 | * Mandelbrot set. 215 | * F-Bird game. 216 | * Invaders game. 217 | * Pillman game. 218 | * Toledo Atomchess. 219 | * bootBASIC language. 220 | 221 | After the success of my first book, if you need even 222 | More Boot Sector Games then you must get this book! 223 | 224 | Soft-cover http://www.lulu.com/shop/oscar-toledo-gutierrez/more-boot-sector-games/paperback/product-24462035.html 225 | 226 | Hard-cover http://www.lulu.com/shop/oscar-toledo-gutierrez/more-boot-sector-games/hardcover/product-24462029.html 227 | 228 | * Follow the Lights 229 | * bootRogue 230 | * bricks 231 | * cubicDoom 232 | * bootOS 233 | -------------------------------------------------------------------------------- /WHATIS: -------------------------------------------------------------------------------- 1 | multitd: 2 | This is a primitive multi threader. Not working yet. 3 | -------------------------------------------------------------------------------- /external_licences/basic: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Oscar Toledo G. http://nanochess.org/ 2 | Copyright (c) 2020 Jakob Kirsch 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /external_licences/bricks: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2019 Oscar Toledo G. http://nanochess.org/ 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /external_licences/chess: -------------------------------------------------------------------------------- 1 | See https://github.com/nanochess/Toledo-Atomchess 2 | -------------------------------------------------------------------------------- /external_licences/coreutils: -------------------------------------------------------------------------------- 1 | Note: Every unlicensed file belongs to the coreutils. 2 | 3 | MIT License 4 | 5 | Copyright (c) 2020 Jakob Kirsch 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /external_licences/doom: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Oscar Toledo G. http://nanochess.org/ 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /external_licences/fbird: -------------------------------------------------------------------------------- 1 | See https://github.com/nanochess/fbird/ 2 | -------------------------------------------------------------------------------- /external_licences/himem: -------------------------------------------------------------------------------- 1 | See https://wiki.osdev.org/Unreal_Mode 2 | -------------------------------------------------------------------------------- /external_licences/invaders: -------------------------------------------------------------------------------- 1 | See https://github.com/nanochess/invaders 2 | -------------------------------------------------------------------------------- /external_licences/lights: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Oscar Toledo G. http://nanochess.org/ 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /external_licences/nyan: -------------------------------------------------------------------------------- 1 | See https://github.com/brainsmoke/nyanmbr -------------------------------------------------------------------------------- /external_licences/pillman: -------------------------------------------------------------------------------- 1 | See https://github.com/nanochess/pillman 2 | -------------------------------------------------------------------------------- /external_licences/reboot: -------------------------------------------------------------------------------- 1 | See https://stackoverflow.com/questions/32682152/how-to-reboot-in-x86-assembly-from-16-bit-real-mode 2 | -------------------------------------------------------------------------------- /external_licences/rogue: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Oscar Toledo G. http://nanochess.org/ 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /external_licences/screensaver: -------------------------------------------------------------------------------- 1 | See https://github.com/kmcallister/phosphene 2 | Note: Some parts are modified by me. 3 | -------------------------------------------------------------------------------- /installer.asm: -------------------------------------------------------------------------------- 1 | org 0x7c00 2 | init: 3 | xor ax,ax ; Set all segments to zero 4 | mov ds,ax 5 | mov es,ax 6 | mov ss,ax 7 | mov sp,0x8000 8 | mov byte [0xffff], dl 9 | get_disk: 10 | mov al, "#" 11 | call input_line 12 | call xdigit ; Get a hexadecimal digit 13 | mov cl,4 14 | shl al,cl 15 | xchg ax,cx 16 | call xdigit ; Get a hexadecimal digit 17 | or al,cl 18 | mov ah, 0x00 19 | push ax 20 | cmp al, [0xffff] 21 | je error 22 | copy: push cs 23 | pop ds 24 | mov si, dap 25 | mov ah, 0x42 26 | mov dl, [0xffff] 27 | pusha 28 | int 0x13 29 | popa 30 | jc exit 31 | pop dx 32 | push dx 33 | mov ah, 0x43 34 | sub word [dap.lba_lower], 1 35 | pusha 36 | int 0x13 37 | popa 38 | jc exit 39 | add word [dap.lba_lower], 2 40 | cmp word [dap.lba_lower], 0xffff 41 | jne copy 42 | exit: 43 | mov si, success 44 | mov byte [0xfffe], 0xff 45 | _print: 46 | lodsb 47 | cmp al, 0x00 48 | je _exit 49 | pusha 50 | call output_char 51 | popa 52 | jmp _print 53 | _exit: 54 | mov ah,0x00 55 | int 0x16 56 | jmp 0xffff:0x0000 57 | error: mov si, error_msg 58 | jmp _print 59 | 60 | xdigit: 61 | lodsb 62 | cmp al,0x00 ; Zero character marks end of line 63 | je r 64 | sub al,0x30 ; Avoid spaces (anything below ASCII 0x30) 65 | jc xdigit 66 | cmp al,0x0a 67 | jc r 68 | sub al,0x07 69 | and al,0x0f 70 | stc 71 | r: 72 | ret 73 | input_line: 74 | call output_char; Output prompt character 75 | mov si,0xa000 ; Setup SI and DI to start of line buffer 76 | mov di,si ; Target for writing line 77 | mov dl, al 78 | os1: cmp al,0x08 ; Backspace? 79 | jne os2 80 | dec di ; Undo the backspace write 81 | cmp si, di 82 | je os2_ 83 | dec di ; Erase a character 84 | push ax 85 | mov al, " " 86 | call output_char 87 | mov al, 0x08 88 | call output_char 89 | pop ax 90 | os2: call input_key ; Read keyboard 91 | cmp al,0x0d ; CR pressed? 92 | jne os10 93 | mov al,0x00 94 | os10: stosb ; Save key in buffer 95 | jne os1 ; No, wait another key 96 | ret ; Yes, return 97 | os2_: mov al, dl 98 | call output_char 99 | jmp os2 100 | ; 101 | ; Read a key into al 102 | ; Also outputs it to screen 103 | ; 104 | input_key: 105 | mov ah,0x00 106 | int 0x16 107 | ; 108 | ; Screen output of character contained in al 109 | ; Expands 0x0d (CR) into 0x0a 0x0d (LF CR) 110 | ; 111 | output_char: 112 | cmp al,0x0d 113 | jne os3 114 | mov al,0x0a 115 | call output_char 116 | mov al,0x0d 117 | os3: 118 | mov ah,0x0e ; Output character to TTY 119 | mov bx,0x0007 ; Gray. Required for graphic modes 120 | int 0x10 ; BIOS int 0x10 = Video 121 | ret 122 | 123 | success: db "Success. Press a key to reboot...", 0x0d, 0 124 | error_msg: db "Cannot install to source drive!", 0x0d, 0 125 | 126 | dap: 127 | dap.header: db 0x10 128 | dap.unused: db 0x00 129 | dap.count: dw 0x0001 130 | dap.offset_offset: 131 | dw 0x0000 132 | dap.offset_segment: 133 | dw 0x1000 134 | dap.lba_lower: dq 0x0001 135 | dap.lba_upper: dq 0x0000 136 | 137 | times 510 - ($ - $$) db 0x00 138 | db 0x55, 0xaa 139 | -------------------------------------------------------------------------------- /lst/.nomedia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakiki6/bootOS/f6d557bdcda8f830cff7e2cc61a92ae2644d3dff/lst/.nomedia -------------------------------------------------------------------------------- /makebase.py: -------------------------------------------------------------------------------- 1 | import os, shutil, sys, math 2 | 3 | files = [] 4 | 5 | with open("software.txt", "r") as file: 6 | for line in file.readlines(): 7 | if line.startswith("#"): 8 | continue 9 | line = line[:-1] 10 | c = [] 11 | for file in line.split(" "): 12 | c.append(file.encode()) 13 | files.append(c) 14 | 15 | flash = bytearray(0) 16 | 17 | for s in range(0, len(files)): 18 | dir = bytearray(16 * 32) 19 | file_space = bytearray(512 * 256 - 2) 20 | container = files[s] 21 | for i in range(0, len(container)): 22 | file = container[i] 23 | with open("software/" + file.decode(), "rb") as f: 24 | content = f.read() 25 | if len(content) > 512: 26 | print(file.decode() + " is too big") 27 | continue 28 | dir[i*16:i*16+len(file)] = bytearray(file) 29 | file_space[i*512:i*512+512] = bytearray(content) 30 | flash += bytearray(512) + dir + file_space 31 | if not len(flash) % (512 * 256): 32 | continue 33 | flash += bytearray((256 * 512) - (len(flash) % (256 * 512))) 34 | 35 | with open("base.img", "wb") as output: 36 | output.write(flash) 37 | print("Wrote {} bytes of data".format(len(flash))) 38 | -------------------------------------------------------------------------------- /makesoftware.sh: -------------------------------------------------------------------------------- 1 | cd software_src 2 | touch ../lst/_.lst 3 | rm ../lst/*.lst 4 | for i in *; do nasm -f bin $i -o ../software/$i -l ../lst/$i.lst -P../sysmap.inc; done 5 | -------------------------------------------------------------------------------- /os.asm: -------------------------------------------------------------------------------- 1 | bits 16 2 | cpu 186 3 | 4 | stack: equ 0x7600 ; Stack pointer (grows to lower addresses) 5 | line: equ 0x7780 ; Buffer for line input 6 | sector: equ 0x7800 ; Sector data for directory 7 | osbase: equ 0x7a00 ; bootOS location 8 | boot: equ 0x7c00 ; Boot sector location 9 | 10 | entry_size: equ 16 ; Directory entry size 11 | sector_size: equ 512 ; Sector size 12 | max_entries: equ sector_size/entry_size 13 | 14 | ; 15 | ; Cold start of bootOS 16 | ; 17 | ; Notice it is loaded at 0x7c00 (boot) and needs to 18 | ; relocate itself to 0x7a00 (osbase), the instructions 19 | ; between 'start' and 'restart' shouldn't depend 20 | ; on the assembly location (osbase) because these 21 | ; are running at boot location (boot). 22 | ; 23 | org 0x7a00 ; osbase 24 | start: 25 | xor ax,ax ; Set all segments to zero 26 | mov ds,ax 27 | mov es,ax 28 | mov ss,ax 29 | mov sp,stack ; Set stack to guarantee data safety 30 | mov [disk.1 + 1], dl 31 | 32 | cld ; Clear D flag. 33 | mov si,boot ; Copy bootOS boot sector... 34 | mov di,osbase ; ...into osbase 35 | mov cx,sector_size 36 | rep movsb 37 | 38 | mov si,interrupt_table ; SI now points to interrupt_table 39 | mov di,0x0020*4 ; Address of service for int 0x20 40 | mov cl,7 41 | .load_vec: 42 | movsw ; Copy IP address 43 | stosw ; Copy CS address 44 | loop .load_vec 45 | int 0x20 ; Jump to real main and set CS:IP to fix the issue with some BIOSes 46 | ; 47 | ; Warm start of bootOS 48 | ; 49 | restart: 50 | cld ; Clear D flag. 51 | clc 52 | push cs ; Reinit all segment registers 53 | push cs 54 | push cs 55 | pop ds 56 | pop es 57 | pop ss 58 | mov sp,stack ; Restart stack 59 | 60 | mov al,'>' ; Command prompt 61 | int int_input_line ; Input line 62 | 63 | cmp byte [si],0x00 ; Empty line? 64 | je restart ; Yes, get another line 65 | 66 | mov di,commands ; Point to commands list 67 | 68 | ; Notice that filenames starting with same characters 69 | ; won't be recognized as such (so file lsab cannot be 70 | ; executed). 71 | os11: 72 | mov al,[di] ; Read length of command in chars 73 | inc di 74 | and ax,0x00ff ; Is it zero? 75 | je os12 ; Yes, jump 76 | xchg ax,cx 77 | push si ; Save current position 78 | rep cmpsb ; Compare statement 79 | jne os14 ; Equal? No, jump 80 | call word [di] ; Call command process 81 | jmp restart ; Go to expect another command 82 | 83 | os14: add di,cx ; Advance the list pointer 84 | inc di ; Avoid the address 85 | inc di 86 | pop si 87 | jmp os11 ; Compare another statement 88 | 89 | os12: mov bx,si ; Input pointer 90 | mov di,boot ; Location to read data 91 | int int_load_file ; Load file 92 | jc os7 ; Jump if error 93 | jmp bx 94 | 95 | ; 96 | ; File not found error 97 | ; 98 | os7: 99 | mov si, error_msg 100 | call output_string 101 | int int_restart 102 | 103 | ; 104 | ; >> COMMAND << 105 | ; rm filename 106 | ; 107 | rm_command: 108 | os22: 109 | mov bx,si ; Copy SI (buffer pointer) to BX 110 | lodsb 111 | cmp al,0x20 ; Avoid spaces 112 | je os22 113 | int int_delete_file 114 | jc os7 115 | ret 116 | 117 | ; 118 | ; 'ls' command 119 | ; 120 | ls_command: 121 | call read_dir ; Read the directory 122 | mov di,bx 123 | os18: 124 | cmp byte [di],0 ; Empty entry? 125 | je os17 ; Yes, jump 126 | mov si,di ; Point to data 127 | call output_string ; Show name 128 | os17: call next_entry 129 | jne os18 ; No, jump 130 | ret ; Return 131 | 132 | ; 133 | ; Get filename length and prepare for directory lookup 134 | ; Entry: 135 | ; si = pointer to string 136 | ; Output: 137 | ; si = unaffected 138 | ; di = pointer to start of directory 139 | ; cx = length of filename including zero terminator 140 | ; 141 | filename_length: 142 | push si 143 | xor cx,cx ; cx = 0 144 | .loop: 145 | lodsb ; Read character. 146 | inc cx ; Count character. 147 | cmp al,0 ; Is it zero (end character)? 148 | jne .loop ; No, jump. 149 | 150 | pop si 151 | mov di,sector ; Point to start of directory. 152 | ret 153 | 154 | ; 155 | ; >> SERVICE << 156 | ; Load file 157 | ; 158 | ; Entry: 159 | ; ds:bx = Pointer to filename ended with zero byte. 160 | ; es:di = Destination. 161 | ; Output: 162 | ; Carry flag = Set = not found, clear = successful. 163 | ; 164 | load_file: 165 | push di ; Save destination 166 | push es 167 | call find_file ; Find the file (sanitizes ES) 168 | mov ah,0x42 ; Read sector 169 | shared_file: 170 | pop es 171 | pop bx ; Restore destination on BX 172 | jc ret_cf ; Jump if error 173 | call disk ; Do operation with disk 174 | ; Carry guaranteed to be clear. 175 | ret_cf: 176 | mov bp,sp 177 | rcl byte [bp+4],1 ; Insert Carry flag in Flags (automatic usage of SS) 178 | iret 179 | 180 | ; 181 | ; >> SERVICE << 182 | ; Save file 183 | ; 184 | ; Entry: 185 | ; ds:bx = Pointer to filename ended with zero byte. 186 | ; es:di = Source. 187 | ; Output: 188 | ; Carry flag = Set = error, clear = good. 189 | ; 190 | save_file: 191 | push di ; Save origin 192 | push es 193 | push bx ; Save filename pointer 194 | int int_delete_file ; Delete previous file (sanitizes ES) 195 | pop bx ; Restore filename pointer 196 | call filename_length ; Prepare for lookup 197 | 198 | .find: es cmp byte [di],0 ; Found empty directory entry? 199 | je .empty ; Yes, jump and fill it. 200 | call next_entry 201 | jne .find 202 | jmp shared_file 203 | 204 | .empty: push di 205 | rep movsb ; Copy full name into directory 206 | call write_dir ; Save directory 207 | pop di 208 | call get_location ; Get location of file 209 | mov ah,0x43 ; Write sector 210 | jmp shared_file 211 | 212 | ; 213 | ; >> SERVICE << 214 | ; Delete file 215 | ; 216 | ; Entry: 217 | ; ds:bx = Pointer to filename ended with zero byte. 218 | ; Output: 219 | ; Carry flag = Set = not found, clear = deleted. 220 | ; 221 | delete_file: 222 | call find_file ; Find file (sanitizes ES) 223 | jc ret_cf ; If carry set then not found, jump. 224 | mov cx,entry_size 225 | call write_zero_dir 226 | jmp ret_cf 227 | 228 | ; 229 | ; Find file 230 | ; 231 | ; Entry: 232 | ; ds:bx = Pointer to filename ended with zero byte. 233 | ; Result: 234 | ; es:di = Pointer to directory entry 235 | ; Carry flag = Clear if found, set if not found. 236 | find_file: 237 | push bx 238 | call read_dir ; Read directory (sanitizes ES) 239 | pop si 240 | call filename_length ; Get filename length and setup DI 241 | os6: 242 | pusha 243 | repe cmpsb ; Compare name with entry 244 | popa 245 | je get_location ; Jump if equal. 246 | call next_entry 247 | jne os6 ; No, jump 248 | ret ; Return 249 | 250 | next_entry: 251 | add di,byte entry_size ; Go to next entry. 252 | cmp di,sector+sector_size-entry_size ; Complete directory? 253 | stc ; Error, not found. 254 | ret 255 | 256 | ; 257 | ; Get location of file on disk 258 | ; 259 | ; Entry: 260 | ; DI = Pointer to entry in directory. 261 | ; 262 | ; Result 263 | ; CL = Sector 264 | ; 265 | ; The position of a file inside the disk depends on its 266 | ; position in the directory. The first entry goes to 267 | ; track 1, the second entry to track 2 and so. 268 | ; 269 | get_location: 270 | ; mov cx, di 271 | ; sub cx, sector - entry_size - (1 << 4) 272 | lea cx,[di - (sector - entry_size - (1 << 4))] ; Get entry pointer into directory 273 | ; Plus one entry (files start on track 1) 274 | shr cx,4 ; Divide by 16 275 | ret 276 | 277 | ; 278 | ; Read the directory from disk 279 | ; 280 | read_dir: 281 | push cs ; bootOS code segment... 282 | pop es ; ...to sanitize ES register 283 | mov ah,0x42 284 | jmp short disk_dir 285 | 286 | write_zero_dir: 287 | mov al,0 288 | rep stosb 289 | ; 290 | ; Write the directory to disk 291 | ; 292 | write_dir: 293 | mov ah,0x43 294 | disk_dir: 295 | mov bx,sector 296 | mov cl, 0x01 297 | ; 298 | ; Do disk operation. 299 | ; 300 | ; Input: 301 | ; AH = 0x42 read disk, 0x43 write disk 302 | ; ES:BX = data source/target 303 | ; CL = Sector number 304 | ; 305 | disk: 306 | clc 307 | pusha 308 | push cs 309 | pop ds 310 | mov si, dap 311 | mov bp, si 312 | mov word [bp + (dap.offset_offset - dap)], bx 313 | mov word [bp + (dap.offset_segment - dap)], es 314 | mov byte [bp + (dap.lba_lower - dap)], cl 315 | .1: 316 | _disk2: 317 | mov dl, 0x80 318 | int 0x13 319 | popa 320 | jc disk 321 | ret 322 | 323 | ; 324 | ; Input line from keyboard 325 | ; Entry: 326 | ; al = prompt character 327 | ; Result: 328 | ; buffer 'line' contains line, finished with CR 329 | ; SI points to 'line'. 330 | ; 331 | input_line: 332 | int int_output_char ; Output prompt character 333 | mov si,line ; Setup SI and DI to start of line buffer 334 | mov di,si ; Target for writing line 335 | xchg ax, dx 336 | os1: cmp al,0x08 ; Backspace? 337 | jne os2 338 | dec di ; Undo the backspace write 339 | cmp si, di 340 | je os2_ 341 | dec di ; Erase a character 342 | mov al, " " 343 | int int_output_char 344 | mov al, 0x08 345 | int int_output_char 346 | mov al, dl 347 | os2: int int_input_key ; Read keyboard 348 | cmp al,0x0d ; CR pressed? 349 | jne os10 350 | mov al,0x00 351 | os10: stosb ; Save key in buffer 352 | jne os1 ; No, wait another key 353 | iret ; Yes, return 354 | os2_: mov al, dl 355 | int int_output_char 356 | jmp os2 357 | ; 358 | ; Read a key into al 359 | ; Also outputs it to screen 360 | ; 361 | input_key: 362 | mov ah,0x00 363 | int 0x16 364 | 365 | ; 366 | ; Screen output of character contained in al 367 | ; Expands 0x0d (CR) into 0x0a 0x0d (LF CR) 368 | ; 369 | output_char: 370 | cmp al,0x0d 371 | jne os3 372 | push ax 373 | mov al, 0x0a 374 | int int_output_char 375 | pop ax 376 | os3: 377 | mov ah,0x0e ; Output character to TTY 378 | mov bx,0x0007 ; Gray. Required for graphic modes 379 | int 0x10 ; BIOS int 0x10 = Video 380 | irt: iret 381 | 382 | ; 383 | ; Output string 384 | ; 385 | ; Entry: 386 | ; SI = address 387 | ; 388 | ; Implementation: 389 | ; It supposes that SI never points to a zero length string. 390 | ; 391 | output_string: 392 | cs lodsb ; Read character 393 | int int_output_char ; Output to screen 394 | cmp al,0x00 ; Is it 0x00 (terminator)? 395 | jne output_string ; No, the loop continues 396 | mov al,0x0d 397 | int int_output_char 398 | ret 399 | 400 | ; 401 | ; 'edit' command 402 | ; 403 | edit_command: 404 | mov di,boot ; Point to boot sector 405 | os23: push di 406 | mov al,'<' ; Prompt character 407 | int int_input_line ; Input line 408 | pop di 409 | cmp byte [si],0 ; Empty line? 410 | je os20 ; Yes, jump 411 | os19: call xdigit ; Get a hexadecimal digit 412 | jnc os23 413 | shl al,4 414 | xchg ax,cx 415 | call xdigit ; Get a hexadecimal digit 416 | or al,cl 417 | stosb ; Write one byte 418 | jmp os19 ; Repeat loop to complete line 419 | os20: 420 | mov al,'*' ; Prompt character 421 | int int_input_line ; Input line with filename 422 | push si 423 | pop bx 424 | mov di,boot ; Point to data entered 425 | int int_save_file ; Save new file 426 | ret 427 | 428 | ; 429 | ; Convert ASCII letter to hexadecimal digit 430 | ; 431 | xdigit: 432 | lodsb 433 | cmp al,0x00 ; Zero character marks end of line 434 | je os15 435 | sub al,0x30 ; Avoid spaces (anything below ASCII 0x30) 436 | jc xdigit 437 | cmp al,0x0a 438 | jc os15 439 | sub al,0x07 440 | and al,0x0f 441 | stc 442 | os15: 443 | ret 444 | 445 | 446 | 447 | ; 448 | ; Commands supported by bootOS 449 | ; 450 | commands: 451 | db 2,"ls" 452 | dw ls_command 453 | db 4,"edit" 454 | dw edit_command 455 | db 2,"rm" 456 | dw rm_command 457 | db 1, "/" 458 | dw 0x7c00 459 | 460 | dap: 461 | dap.header: 462 | db dap.end - dap ; header 463 | dap.unused: 464 | db 0x00 ; unused 465 | dap.count: 466 | dw 0x0001 ; number of sectors 467 | dap.offset_offset: 468 | dw 0 ; offset 469 | dap.offset_segment: 470 | dw 0 ; segment 471 | dap.lba_lower: 472 | dd 0 ; lba 473 | dap.lba_upper: 474 | dd 0 ; lba 475 | dap.end: 476 | 477 | 478 | int_restart: equ 0x20 479 | int_input_key: equ 0x21 480 | int_output_char: equ 0x22 481 | int_load_file: equ 0x23 482 | int_save_file: equ 0x24 483 | int_delete_file: equ 0x25 484 | int_input_line: equ 0x26 485 | 486 | interrupt_table: 487 | dw restart ; int 0x20 488 | dw input_key ; int 0x21 489 | dw output_char ; int 0x22 490 | dw load_file ; int 0x23 491 | dw save_file ; int 0x24 492 | dw delete_file ; int 0x25 493 | dw input_line ; int 0x26 494 | 495 | error_msg: 496 | db 0x13, 0x00 497 | 498 | %assign space_left 510-($-$$) 499 | %warning space_left bytes left 500 | 501 | times space_left db 0x00 502 | db 0x55,0xaa ; Make it a bootable sector 503 | 504 | times (2880 * 512) - ($ - $$) db 0x00 505 | -------------------------------------------------------------------------------- /osall.iso: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakiki6/bootOS/f6d557bdcda8f830cff7e2cc61a92ae2644d3dff/osall.iso -------------------------------------------------------------------------------- /pre-commit: -------------------------------------------------------------------------------- 1 | make clean software 2 | mv os.img osall.iso 3 | git add . 4 | -------------------------------------------------------------------------------- /shared/dummyfs.asm: -------------------------------------------------------------------------------- 1 | ; Entry: DS:BX = Filename terminated with zero. 2 | ; ES:DI = Point to source data (512 bytes) 3 | ; Output: Carry flag = 0 = Found, 1 = Not found. 4 | load_file: 5 | iret 6 | 7 | ; Entry: DS:BX = Filename terminated with zero. 8 | ; ES:DI = Point to data target (512 bytes) 9 | ; Output: Carry flag = 0 = Successful. 1 = Error. 10 | save_file: 11 | iret 12 | 13 | ; Entry: DS:BX = Filename terminated with zero. 14 | ; Output: None 15 | delete_file: 16 | iret 17 | 18 | ; Entry: ES:DI = Point to data target (seperated by \r) 19 | ; DS:BX = Directory name terminated with zero. 20 | ; Output: CL = Number of file. 21 | list_files: 22 | mov cl, 0x00 23 | ret 24 | -------------------------------------------------------------------------------- /shared/fat12.asm: -------------------------------------------------------------------------------- 1 | ; Entry: DS:BX = Filename terminated with zero. 2 | ; ES:DI = Point to source data (512 bytes) 3 | ; Output: Carry flag = 0 = Found, 1 = Not found. 4 | load_file: 5 | iret 6 | 7 | ; Entry: DS:BX = Filename terminated with zero. 8 | ; ES:DI = Point to data target (512 bytes) 9 | ; Output: Carry flag = 0 = Successful. 1 = Error. 10 | save_file: 11 | iret 12 | 13 | ; Entry: DS:BX = Filename terminated with zero. 14 | ; Output: None 15 | delete_file: 16 | iret 17 | 18 | ; Entry: ES:DI = Point to data target (seperated by \r) 19 | ; DS:BX = Directory name terminated with zero. 20 | ; Output: CL = Number of file. 21 | list_files: 22 | mov cl, 0x00 23 | ret 24 | -------------------------------------------------------------------------------- /shared/fsloader.asm: -------------------------------------------------------------------------------- 1 | org 0xe000 2 | bits 16 3 | 4 | current_dir: equ 0xe200 5 | dir_space: equ 0xe300 6 | 7 | stage1: mov si, 0x7c00 8 | mov di, 0xe000 9 | mov cx, 0x0200 10 | rep movsb 11 | stage2: jmp stage3 12 | stage3: mov si, int_table 13 | mov di, 0x0023 * 4 14 | mov cx, 3 15 | .copy: lodsw 16 | stosw 17 | xor ax, ax 18 | stosw 19 | loop .copy 20 | mov word [bootOS.commands + 3], ls_command 21 | mov di, current_dir 22 | mov cx, 0xfe 23 | mov al, "/" 24 | stosb 25 | xor ax, ax 26 | rep stosb 27 | .end: int 0x20 28 | 29 | ; here we include the fs driver 30 | %ifndef MODULE 31 | %define MODULE "../shared/dummyfs.asm" 32 | %endif 33 | 34 | %include MODULE 35 | 36 | ls_command: 37 | push cs 38 | pop es 39 | mov bx, current_dir 40 | mov di, dir_space 41 | push di 42 | mov cx, 0xff 43 | xor ax, ax 44 | rep stosb 45 | pop di 46 | call list_files 47 | mov ah, 0x0e 48 | mov bx, 0x0007 49 | mov si, dir_space 50 | inc cl 51 | jmp short .1 52 | .loop1: pusha 53 | mov al, 0x0a 54 | int 0x10 55 | mov al, 0x0d 56 | int 0x10 57 | popa 58 | .1: dec cl 59 | cmp cl, 0x00 60 | je .end 61 | .loop2: lodsb 62 | cmp al, 0x00 63 | je .loop1 64 | pusha 65 | int 0x10 66 | popa 67 | jmp .loop2 68 | .end: ret 69 | 70 | int_table: 71 | dw load_file 72 | dw save_file 73 | dw delete_file 74 | .end: 75 | -------------------------------------------------------------------------------- /software.txt: -------------------------------------------------------------------------------- 1 | # Coreutils 2 | clear clock disk fat12 init32 install lba loadb multitd pull push reboot sound qm upload download ember 3 | # Games 4 | basic charset chess doom fbird invaders lights mine pillman screensaver slide snake sokoban tetris heart 5 | # Dev 6 | -------------------------------------------------------------------------------- /software_src/basic: -------------------------------------------------------------------------------- 1 | ; 2 | ; bootBASIC interpreter in 512 bytes (boot sector) 3 | ; 4 | ; by Oscar Toledo G. 5 | ; http://nanochess.org/ 6 | ; 7 | ; (c) Copyright 2019 Oscar Toledo G. 8 | ; 9 | ; Creation date: Jul/19/2019. 10pm to 12am. 10 | ; Revision date: Jul/20/2019. 10am to 2pm. 11 | ; Added assignment statement. list now 12 | ; works. run/goto now works. Added 13 | ; system and new. 14 | ; Revision date: Jul/22/2019. Boot image now includes 'system' 15 | ; statement. 16 | ; 17 | 18 | ; 19 | ; USER'S MANUAL: 20 | ; 21 | ; Line entry is done with keyboard, finish the line with Enter. 22 | ; Only 19 characters per line as maximum. 23 | ; 24 | ; Backspace can be used, don't be fooled by the fact 25 | ; that screen isn't deleted (it's all right in the buffer). 26 | ; 27 | ; All statements must be in lowercase. 28 | ; 29 | ; Line numbers can be 1 to 999. 30 | ; 31 | ; 26 variables are available (a-z) 32 | ; 33 | ; Numbers (0-65535) can be entered and display as unsigned. 34 | ; 35 | ; To enter new program lines: 36 | ; 10 print "Hello, world!" 37 | ; 38 | ; To erase program lines: 39 | ; 10 40 | ; 41 | ; To test statements directly (interactive syntax): 42 | ; print "Hello, world!" 43 | ; 44 | ; To erase the current program: 45 | ; new 46 | ; 47 | ; To run the current program: 48 | ; run 49 | ; 50 | ; To list the current program: 51 | ; list 52 | ; 53 | ; To exit to command-line: 54 | ; ! 55 | ; To save the file (can be loaded with loadb): 56 | ; * 57 | ; 58 | ; 59 | ; Statements: 60 | ; var=expr Assign expr value to var (a-z) 61 | ; 62 | ; print expr Print expression value, new line 63 | ; print expr; Print expression value, continue 64 | ; print "hello" Print string, new line 65 | ; print "hello"; Print string, continue 66 | ; 67 | ; input var Input value into variable (a-z) 68 | ; 69 | ; goto expr Goto to indicated line in program 70 | ; 71 | ; if expr1 goto expr2 72 | ; If expr1 is non-zero then go to line, 73 | ; else go to following line. 74 | ; 75 | ; Examples of if: 76 | ; 77 | ; if c-5 goto 20 If c isn't 5, go to line 20 78 | ; 79 | ; Expressions: 80 | ; 81 | ; The operators +, -, / and * are available with 82 | ; common precedence rules and signed operation. 83 | ; 84 | ; You can also use parentheses: 85 | ; 86 | ; 5+6*(10/2) 87 | ; 88 | ; Variables and numbers can be used in expressions. 89 | ; 90 | ; Sample program (counting 1 to 10): 91 | ; 92 | ; 10 a=1 93 | ; 20 print a 94 | ; 30 a=a+1 95 | ; 40 if a-11 goto 20 96 | ; 97 | ; Sample program (Pascal's triangle, each number is the sum 98 | ; of the two over it): 99 | ; 100 | ; 10 input n 101 | ; 20 i=1 102 | ; 30 c=1 103 | ; 40 j=0 104 | ; 50 t=n-i 105 | ; 60 if j-t goto 80 106 | ; 70 goto 110 107 | ; 80 print " "; 108 | ; 90 j=j+1 109 | ; 100 goto 50 110 | ; 110 k=1 111 | ; 120 if k-i-1 goto 140 112 | ; 130 goto 190 113 | ; 140 print c; 114 | ; 150 c=c*(i-k)/k 115 | ; 160 print " "; 116 | ; 170 k=k+1 117 | ; 180 goto 120 118 | ; 190 print 119 | ; 200 i=i+1 120 | ; 210 if i-n-1 goto 30 121 | ; 122 | 123 | cpu 8086 124 | 125 | %ifndef com_file ; If not defined create a boot sector 126 | com_file: equ 0 127 | %endif 128 | 129 | %if com_file 130 | org 0x0100 131 | %else 132 | org 0x7c00 133 | %endif 134 | 135 | vars: equ 0x7e00 ; Variables (multiple of 256) 136 | running: equ 0x7e7e ; Running status 137 | line: equ 0x7e80 ; Line input 138 | program: equ 0x7f00 ; Program address 139 | stack: equ 0xff00 ; Stack address 140 | max_line: equ 1000 ; First unavailable line number 141 | max_length: equ 20 ; Maximum length of line 142 | max_size: equ max_line*max_length ; Max. program size 143 | 144 | start: 145 | %if com_file 146 | %else 147 | push cs ; For boot sector 148 | push cs ; it needs to setup 149 | push cs ; DS, ES and SS. 150 | pop ds 151 | pop es 152 | pop ss 153 | %endif 154 | cld ; Clear Direction flag 155 | cmp byte [0xfffc], 0x00 ; dirty byte 156 | jne main_loop 157 | mov di,program ; Point to program 158 | mov al,0x0d ; Fill with CR 159 | mov cx,max_size ; Max. program size 160 | rep stosb ; Initialize 161 | 162 | ; 163 | ; Main loop 164 | ; 165 | main_loop: 166 | mov sp,stack ; Reinitialize stack pointer 167 | int 0x27 168 | mov ax,main_loop 169 | push ax 170 | xor ax,ax ; Mark as interactive 171 | mov [running],ax 172 | mov al,'%' ; Show prompt 173 | int 0x26 ; Accept line 174 | call input_number ; Get number 175 | or ax,ax ; No number or zero? 176 | je statement ; Yes, jump 177 | call find_line ; Find the line 178 | xchg ax,di 179 | ; mov cx,max_length ; CX loaded with this value in 'find_line' 180 | rep movsb ; Copy entered line into program 181 | sharp_command: 182 | ret 183 | 184 | ; 185 | ; Handle 'if' statement 186 | ; 187 | if_statement: 188 | call expr ; Process expression 189 | or ax,ax ; Is it zero? 190 | je f6 ; Yes, return (ignore if) 191 | statement: 192 | call spaces ; Avoid spaces 193 | cmp byte [si],0x0d ; Empty line? 194 | je f6 ; Yes, return 195 | mov di,statements ; Point to statements list 196 | f5: mov al,[di] ; Read length of the string 197 | inc di ; Avoid length byte 198 | and ax,0x00ff ; Is it zero? 199 | je f4 ; Yes, jump 200 | xchg ax,cx 201 | push si ; Save current position 202 | f16: rep cmpsb ; Compare statement 203 | jne f3 ; Equal? No, jump 204 | pop ax 205 | call spaces ; Avoid spaces 206 | jmp word [di] ; Jump to process statement 207 | 208 | f3: add di,cx ; Advance the list pointer 209 | inc di ; Avoid the address 210 | inc di 211 | pop si 212 | jmp f5 ; Compare another statement 213 | 214 | f4: call get_variable ; Try variable 215 | push ax ; Save address 216 | lodsb ; Read a line letter 217 | cmp al,'=' ; Is it assignment '=' ? 218 | je assignment ; Yes, jump to assignment. 219 | 220 | ; 221 | ; An error happened 222 | ; 223 | error: 224 | mov si,error_message 225 | call print_2 ; Show error message 226 | jmp main_loop ; Exit to main loop 227 | 228 | error_message: 229 | db 0x13,0x0d ; Guess the words :P 230 | 231 | 232 | ; 233 | ; Handle 'input' statement 234 | ; 235 | input_statement: 236 | call get_variable ; Get variable address 237 | push ax ; Save it 238 | mov al,'?' ; Prompt 239 | int 0x26 ; Wait for line 240 | ; 241 | ; Second part of the assignment statement 242 | ; 243 | assignment: 244 | call expr ; Process expression 245 | pop di 246 | stosw ; Save onto variable 247 | ret 248 | 249 | ; 250 | ; Handle an expression. 251 | ; First tier: addition & subtraction. 252 | ; 253 | expr: 254 | call expr1 ; Call second tier 255 | f20: cmp byte [si],'-' ; Subtraction operator? 256 | je f19 ; Yes, jump 257 | cmp byte [si],'+' ; Addition operator? 258 | jne f6 ; No, return 259 | push ax 260 | call expr1_2 ; Call second tier 261 | f15: pop cx 262 | add ax,cx ; Addition 263 | jmp f20 ; Find more operators 264 | 265 | f19: 266 | push ax 267 | call expr1_2 ; Call second tier 268 | neg ax ; Negate it (a - b converted to a + -b) 269 | jmp f15 270 | 271 | ; 272 | ; Handle an expression. 273 | ; Second tier: division & multiplication. 274 | ; 275 | expr1_2: 276 | inc si ; Avoid operator 277 | expr1: 278 | call expr2 ; Call third tier 279 | f21: cmp byte [si],'/' ; Division operator? 280 | je f23 ; Yes, jump 281 | cmp byte [si],'*' ; Multiplication operator? 282 | jne f6 ; No, return 283 | 284 | push ax 285 | call expr2_2 ; Call third tier 286 | pop cx 287 | imul cx ; Multiplication 288 | jmp f21 ; Find more operators 289 | 290 | f23: 291 | push ax 292 | call expr2_2 ; Call third tier 293 | pop cx 294 | xchg ax,cx 295 | cwd ; Expand AX to DX:AX 296 | idiv cx ; Signed division 297 | jmp f21 ; Find more operators 298 | 299 | ; 300 | ; Handle an expression. 301 | ; Third tier: parentheses, numbers and vars. 302 | ; 303 | expr2_2: 304 | inc si ; Avoid operator 305 | expr2: 306 | call spaces ; Jump spaces 307 | lodsb ; Read character 308 | cmp al,'(' ; Open parenthesis? 309 | jne f24 310 | call expr ; Process inner expr. 311 | cmp byte [si],')' ; Closing parenthesis? 312 | je spaces_2 ; Yes, avoid spaces 313 | jmp error ; No, jump to error 314 | 315 | f24: cmp al,0x40 ; Variable? 316 | jnc f25 ; Yes, jump 317 | dec si ; Back one letter... 318 | call input_number ; ...to read number 319 | jmp spaces ; Avoid spaces 320 | 321 | f25: call get_variable_2 ; Get variable address 322 | xchg ax,bx 323 | mov ax,[bx] ; Read 324 | ret ; Return 325 | 326 | ; 327 | ; Get variable address 328 | ; 329 | get_variable: 330 | lodsb ; Read source 331 | get_variable_2: 332 | and al,0x1f ; 0x61-0x7a -> 0x01-0x1a 333 | add al,al ; x 2 (each variable = word) 334 | mov ah,vars>>8 ; Setup high-byte of address 335 | ; 336 | ; Avoid spaces 337 | ; 338 | spaces: 339 | cmp byte [si],' ' ; Space found? 340 | jne f22 ; No, return 341 | ; 342 | ; Avoid spaces after current character 343 | ; 344 | spaces_2: 345 | inc si ; Advance to next character 346 | jmp spaces 347 | 348 | ; 349 | ; Output unsigned number 350 | ; AX = value 351 | ; 352 | output_number: 353 | f26: 354 | xor dx,dx ; DX:AX 355 | mov cx,10 ; Divisor = 10 356 | div cx ; Divide 357 | or ax,ax ; Nothing at left? 358 | push dx 359 | je f8 ; No, jump 360 | call f26 ; Yes, output left side 361 | f8: pop ax 362 | add al,'0' ; Output remainder as... 363 | jmp output ; ...ASCII digit 364 | 365 | ; 366 | ; Read number in input 367 | ; AX = result 368 | ; 369 | input_number: 370 | xor bx,bx ; BX = 0 371 | f11: lodsb ; Read source 372 | sub al,'0' 373 | cmp al,10 ; Digit valid? 374 | cbw 375 | xchg ax,bx 376 | jnc f12 ; No, jump 377 | mov cx,10 ; Multiply by 10 378 | mul cx 379 | add bx,ax ; Add new digit 380 | jmp f11 ; Continue 381 | 382 | f12: dec si ; SI points to first non-digit 383 | f22: 384 | ret 385 | 386 | 387 | ; 388 | ; Handle 'goto' statement 389 | ; 390 | goto_statement: 391 | call expr ; Handle expression 392 | db 0xb9 ; MOV CX to jump over XOR AX,AX 393 | 394 | ; 395 | ; Handle 'run' statement 396 | ; (equivalent to 'goto 0') 397 | ; 398 | run_statement: 399 | xor ax,ax 400 | f10: 401 | call find_line ; Find line in program 402 | f27: cmp word [running],0 ; Already running? 403 | je f31 404 | mov [running],ax ; Yes, target is new line 405 | ret 406 | f31: 407 | push ax 408 | pop si 409 | add ax,max_length ; Point to next line 410 | mov [running],ax ; Save for next time 411 | call statement ; Process current statement 412 | mov ax,[running] 413 | cmp ax,program+max_size ; Reached the end? 414 | jne f31 ; No, continue 415 | ret ; Yes, return 416 | 417 | ; 418 | ; Find line in program 419 | ; Entry: 420 | ; ax = line number 421 | ; Result: 422 | ; ax = pointer to program 423 | find_line: 424 | mov cx,max_length 425 | mul cx 426 | add ax,program 427 | ret 428 | 429 | ; 430 | ; Handle "print" statement 431 | ; 432 | print_statement: 433 | lodsb ; Read source 434 | cmp al,0x0d ; End of line? 435 | je new_line ; Yes, generate new line and return 436 | cmp al,'"' ; Double quotes? 437 | jne f7 ; No, jump 438 | print_2: 439 | f9: 440 | lodsb ; Read string contents 441 | cmp al,'"' ; Double quotes? 442 | je f18 ; Yes, jump 443 | call output ; Output character 444 | jne f9 ; Jump if not finished with 0x0d (CR) 445 | ret ; Return 446 | 447 | f7: dec si 448 | call expr ; Handle expression 449 | call output_number ; Output result 450 | f18: lodsb ; Read next character 451 | cmp al,';' ; Is it semicolon? 452 | jne new_line ; No, jump to generate new line 453 | ret ; Yes, return 454 | 455 | ; 456 | ; Read a key into al 457 | ; Also outputs it to screen 458 | ; 459 | input_key: 460 | mov ah,0x00 461 | int 0x16 462 | ; 463 | ; Screen output of character contained in al 464 | ; Expands 0x0d (CR) into 0x0a 0x0d (LF CR) 465 | ; 466 | output: 467 | cmp al,0x0d 468 | jne f17 469 | ; 470 | ; Go to next line (generates LF+CR) 471 | ; 472 | new_line: 473 | mov al,0x0a 474 | call f17 475 | mov al,0x0d 476 | f17: 477 | mov ah,0x0e 478 | mov bx,0x0007 479 | int 0x10 480 | cmp al,0x0d 481 | ret 482 | 483 | list_statement: 484 | xor ax,ax ; Start from line zero 485 | f29: push ax 486 | call find_line ; Find program line 487 | xchg ax,si 488 | cmp byte [si],0x0d ; Empty line? 489 | je f30 ; Yes, jump 490 | pop ax 491 | push ax 492 | call output_number ; Show line number 493 | f32: lodsb ; Show line contents 494 | call output 495 | jne f32 ; Jump if it wasn't 0x0d (CR) 496 | f30: pop ax 497 | inc ax ; Go to next line 498 | cmp ax,max_line ; Finished? 499 | jne f29 ; No, continue 500 | f6: 501 | ret 502 | 503 | bye_statement: 504 | int 0x20 505 | 506 | save_statement: 507 | mov di, line 508 | inc di 509 | call spaces 510 | mov bx, di 511 | mov di, program 512 | int 0x24 513 | ret 514 | 515 | ; 516 | ; List of statements of bootBASIC 517 | ; First one byte with length of string 518 | ; Then string with statement 519 | ; Then a word with the address of the code 520 | ; 521 | statements: 522 | 523 | db 3,"run" 524 | dw run_statement 525 | 526 | db 5,"print" 527 | dw print_statement 528 | 529 | db 5,"input" 530 | dw input_statement 531 | 532 | db 2,"if" 533 | dw if_statement 534 | 535 | db 4,"goto" 536 | dw goto_statement 537 | 538 | db 1,"-" 539 | dw list_statement 540 | 541 | db 1,"*" 542 | dw save_statement 543 | 544 | db 1,"!" 545 | dw bye_statement 546 | 547 | db 1, "#" 548 | dw sharp_command 549 | 550 | 551 | times 512 - ($ - $$) nop 552 | -------------------------------------------------------------------------------- /software_src/bricks: -------------------------------------------------------------------------------- 1 | ; 2 | ; Bricks game in one boot sector 3 | ; 4 | ; by Oscar Toledo G. 5 | ; 6 | ; Creation date: Nov/02/2019. 7 | ; 8 | 9 | cpu 8086 10 | 11 | ; 12 | ; Press Left Shift to start the game 13 | ; Press Left Ctrl to move the paddle to the left 14 | ; Press Left Alt to move the paddle to the right 15 | ; 16 | 17 | %ifdef com_file 18 | org 0x0100 19 | %else 20 | org 0x7c00 21 | %endif 22 | 23 | old_time: equ 16 ; Old time 24 | ball_x: equ 14 ; X-coordinate of ball (8.8 fraction) 25 | ball_y: equ 12 ; Y-coordinate of ball (8.8 fraction) 26 | ball_xs: equ 10 ; X-speed of ball (8.8 fraction) 27 | ball_ys: equ 8 ; Y-speed of ball (8.8 fraction) 28 | beep: equ 6 ; Frame count to turn off sound 29 | bricks: equ 4 ; Remaining bricks 30 | balls: equ 2 ; Remaining balls 31 | score: equ 0 ; Current score 32 | 33 | ; 34 | ; Start of the game 35 | ; 36 | start: 37 | mov ax,0x0002 ; Text mode 80x25x16 colors 38 | int 0x10 ; Setup 39 | mov ax,0xb800 ; Address of video screen 40 | mov ds,ax ; Setup DS 41 | mov es,ax ; Setup ES 42 | sub sp,32 43 | xor ax,ax 44 | push ax ; Reset score 45 | mov al,4 46 | push ax ; Balls remaining 47 | mov bp,sp ; Setup stack frame for globals 48 | ; 49 | ; Start another level 50 | ; 51 | another_level: 52 | mov word [bp+bricks],273 ; 273 bricks on screen 53 | xor di,di 54 | mov ax,0x01b1 ; Draw top border 55 | mov cx,80 56 | cld 57 | rep stosw 58 | mov cl,24 ; 24 rows 59 | .1: 60 | stosw ; Draw left border 61 | mov ax,0x20 ; No bricks on this row 62 | push cx 63 | cmp cl,23 64 | jnb .2 65 | sub cl,15 66 | jbe .2 67 | mov al,0xdb ; Bricks on this row 68 | mov ah,cl 69 | .2: 70 | mov cl,39 ; 39 bricks per row 71 | .3: 72 | stosw 73 | stosw 74 | inc ah ; Increase attribute color 75 | cmp ah,0x08 76 | jne .4 77 | mov ah,0x01 78 | .4: 79 | loop .3 80 | pop cx 81 | 82 | mov ax,0x01b1 ; Draw right border 83 | stosw 84 | loop .1 85 | 86 | ; 87 | ; Start another ball 88 | ; 89 | mov di,0x0f4a ; Position of paddle 90 | another_ball: 91 | mov byte [bp+ball_x+1],0x28 ; Center X 92 | mov byte [bp+ball_y+1],0x14 ; Center Y 93 | xor ax,ax 94 | mov [bp+ball_xs],ax ; Static on screen 95 | mov [bp+ball_ys],ax 96 | mov byte [bp+beep],0x01 97 | 98 | mov si,0x0ffe ; Don't erase ball yet 99 | game_loop: 100 | call wait_frame ; Wait 1/18.2 secs. 101 | int 0x27 102 | mov word [si],0x0000 ; Erase ball 103 | 104 | call update_score ; Update score 105 | 106 | mov ah,0x02 ; Read modifier keys 107 | int 0x16 108 | test al,0x04 ; Left ctrl 109 | je .1 110 | mov byte [di+6],0 ; Erase right side of paddle 111 | mov byte [di+8],0 112 | sub di,byte 4 ; Move paddle to left 113 | cmp di,0x0f02 ; Limit 114 | ja .1 115 | mov di,0x0f02 116 | .1: 117 | test al,0x08 ; Left alt 118 | je .2 119 | xor ax,ax ; Erase left side of paddle 120 | stosw 121 | stosw ; DI increased automatically 122 | cmp di,0x0f94 ; Limit 123 | jb .2 124 | mov di,0x0f94 125 | .2: 126 | test al,0x02 ; Left shift 127 | je .15 128 | mov ax,[bp+ball_xs] ; Ball moving? 129 | add ax,[bp+ball_ys] 130 | jne .15 ; Yes, jump 131 | ; Setup movement of ball 132 | mov word [bp+ball_xs],0xff40 133 | mov word [bp+ball_ys],0xff80 134 | .15: 135 | mov ax,0x0adf ; Paddle graphic and color 136 | push di 137 | stosw ; Draw paddle 138 | stosw 139 | stosw 140 | stosw 141 | stosw 142 | pop di 143 | 144 | mov bx,[bp+ball_x] ; Draw ball 145 | mov ax,[bp+ball_y] 146 | call locate_ball ; Locate on screen 147 | test byte [bp+ball_y],0x80 ; Y-coordinate half fraction? 148 | mov ah,0x60 ; Interchange colors for smooth mov. 149 | je .12 150 | mov ah,0x06 151 | .12: mov al,0xdc ; Graphic 152 | mov [bx],ax ; Draw 153 | push bx 154 | pop si 155 | 156 | .14: 157 | mov bx,[bp+ball_x] ; Ball position 158 | mov ax,[bp+ball_y] 159 | add bx,[bp+ball_xs] ; Add movement speed 160 | add ax,[bp+ball_ys] 161 | push ax 162 | push bx 163 | call locate_ball ; Locate on screen 164 | mov al,[bx] 165 | cmp al,0xb1 ; Touching borders 166 | jne .3 167 | mov cx,5423 ; 1193180 / 220 168 | call speaker ; Generate sound 169 | pop bx 170 | pop ax 171 | cmp bh,0x4f 172 | je .8 173 | test bh,bh 174 | jne .7 175 | .8: 176 | neg word [bp+ball_xs] ; Negate X-speed if it touches a side 177 | .7: 178 | test ah,ah 179 | jnz .9 180 | neg word [bp+ball_ys] ; Negate Y-speed if it touches a side 181 | .9: jmp .14 182 | 183 | .3: 184 | cmp al,0xdf ; Touching paddle 185 | jne .4 186 | sub bx,di ; Subtract paddle position 187 | sub bx,byte 4 188 | mov cl,6 ; Multiply by 64 189 | shl bx,cl 190 | mov [bp+ball_xs],bx ; New X speed for ball 191 | mov word [bp+ball_ys],0xff80 ; Update Y speed for ball 192 | mov cx,2711 ; 1193180 / 440 193 | call speaker ; Generate sound 194 | pop bx 195 | pop ax 196 | jmp .14 197 | 198 | .4: 199 | cmp al,0xdb ; Touching brick 200 | jne .5 201 | mov cx,1355 ; 1193180 / 880 202 | call speaker ; Generate sound 203 | test bl,2 ; Aligned with brick? 204 | jne .10 ; Yes, jump 205 | dec bx ; Align 206 | dec bx 207 | .10: xor ax,ax ; Erase brick 208 | mov [bx],ax 209 | mov [bx+2],ax 210 | inc word [bp+score] ; Increase score 211 | neg word [bp+ball_ys] ; Negate Y speed (rebound) 212 | pop bx 213 | pop ax 214 | dec word [bp+bricks] ; One brick less on screen 215 | jne .14 ; Fully completed? No, jump. 216 | jmp another_level ; Start another level 217 | 218 | .5: 219 | pop bx 220 | pop ax 221 | .6: 222 | mov [bp+ball_x],bx ; Update ball position 223 | mov [bp+ball_y],ax 224 | cmp ah,0x19 ; Ball exited through bottom? 225 | je ball_lost ; Yes, jump 226 | jmp game_loop ; No, repeat game loop 227 | 228 | ; 229 | ; Ball lost 230 | ; 231 | ball_lost: 232 | mov cx,10846 ; 1193180 / 110 233 | call speaker ; Generate sound 234 | 235 | mov word [si],0 ; Erase ball 236 | dec byte [bp+balls] ; One ball less 237 | js .1 ; All finished? Yes, jump 238 | jmp another_ball ; Start another ball 239 | 240 | .1: call wait_frame.2 ; Turn off sound 241 | int 0x20 ; Exit to DOS / bootOS 242 | 243 | wait_frame: 244 | .0: 245 | mov ah,0x00 ; Read ticks 246 | int 0x1a ; Call BIOS 247 | cmp dx,[bp+old_time] ; Wait for change 248 | je .0 249 | mov [bp+old_time],dx 250 | 251 | dec byte [bp+beep] ; Decrease time to turn off beep 252 | jne .1 253 | .2: 254 | in al,0x61 255 | and al,0xfc ; Turn off 256 | out 0x61,al 257 | .1: 258 | 259 | ret 260 | 261 | ; 262 | ; Generate sound on PC speaker 263 | ; 264 | speaker: 265 | mov al,0xb6 ; Setup timer 2 266 | out 0x43,al 267 | mov al,cl ; Low byte of timer count 268 | out 0x42,al 269 | mov al,ch ; High byte of timer count 270 | out 0x42,al 271 | in al,0x61 272 | or al,0x03 ; Connect PC speaker to timer 2 273 | out 0x61,al 274 | mov byte [bp+beep],3 ; Duration 275 | ret 276 | 277 | ; 278 | ; Locate ball on screen 279 | ; 280 | locate_ball: 281 | mov al,0xa0 282 | mul ah ; AH = Y coordinate (row) 283 | mov bl,bh ; BH = X coordinate (column) 284 | mov bh,0 285 | shl bx,1 286 | add bx,ax 287 | ret 288 | 289 | ; 290 | ; Update score indicator (from bootRogue) 291 | ; 292 | update_score: 293 | mov bx,0x0f98 ; Point to bottom right corner 294 | mov ax,[bp+score] 295 | call .1 296 | mov al,[bp+balls] 297 | .1: 298 | xor cx,cx ; CX = Quotient 299 | .2: inc cx 300 | sub ax,10 ; Division by subtraction 301 | jnc .2 302 | add ax,0x0a3a ; Convert remainder to ASCII digit + color 303 | call .3 ; Put on screen 304 | xchg ax,cx 305 | dec ax ; Quotient is zero? 306 | jnz .1 ; No, jump to show more digits. 307 | 308 | .3: mov [bx],ax 309 | dec bx 310 | dec bx 311 | ret 312 | 313 | %ifdef com_file 314 | %else 315 | times 510-($-$$) db 0x4f 316 | db 0x55,0xaa ; Make it a bootable sector 317 | %endif 318 | -------------------------------------------------------------------------------- /software_src/charset: -------------------------------------------------------------------------------- 1 | 2 | ; 3 | ; Show the available charset 4 | ; 5 | ; by Oscar Toledo G. http://nanochess.org/ 6 | ; 7 | ; Creation date: Jun/27/2017. 8 | ; 9 | org 0x7c00 10 | cpu 8086 11 | 12 | mov ax, 0x0002 13 | int 0x10 14 | mov ax, 0xb800 15 | mov ds, ax 16 | mov es, ax 17 | 18 | xor di, di 19 | mov cx, 0x07d0 20 | mov al, " " 21 | mov ah, 0b00001111 22 | rep stosw 23 | 24 | mov di, 0x00a4 25 | mov al, 0x00 26 | 27 | a1: push di 28 | push ax 29 | mov cl, 4 30 | shr al, cl 31 | add al, 0x30 32 | cmp al, 0x3a 33 | jb a3 34 | add al, 0x07 35 | a3: stosb 36 | inc di 37 | 38 | pop ax 39 | push ax 40 | and al, 0x0f 41 | add al, 0x30 42 | cmp al, 0x3a 43 | jb a4 44 | add al, 0x07 45 | a4: stosb 46 | inc di 47 | mov al, 0x2d 48 | stosb 49 | inc di 50 | 51 | inc di 52 | inc di 53 | pop ax 54 | stosb 55 | pop di 56 | inc al 57 | jz a2 58 | 59 | add di, 0x00a0 60 | cmp di, 0x0fa0 61 | jb a1 62 | sub di, 0x0f00 - 14 63 | 64 | jmp a1 65 | 66 | a2: xor ax, ax 67 | int 0x16 68 | mov ax, 0x0002 69 | int 0x10 70 | int 0x20 71 | -------------------------------------------------------------------------------- /software_src/chess: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jakiki6/bootOS/f6d557bdcda8f830cff7e2cc61a92ae2644d3dff/software_src/chess -------------------------------------------------------------------------------- /software_src/clear: -------------------------------------------------------------------------------- 1 | mov ax, 0x0002 2 | int 0x10 3 | int 0x20 4 | -------------------------------------------------------------------------------- /software_src/clock: -------------------------------------------------------------------------------- 1 | bits 16 2 | org 0xe000 3 | 4 | init: xor ax, ax 5 | mov dx, ax 6 | mov es, ax 7 | mov ss, ax 8 | mov sp, 0x8000 9 | 10 | mov si, 0x7c00 11 | mov di, 0xe000 12 | mov cx, 0x0200 13 | rep movsb 14 | jmp start 15 | start: mov si, interrupts 16 | mov di, 0x0027 * 4 17 | mov cx, 0x0001 18 | .loop: movsw 19 | stosw 20 | loop .loop 21 | int 0x20 22 | 23 | main: pusha 24 | push ds 25 | push es 26 | pushf 27 | ;;;;;;;;;;;;;;;;;;;;; 28 | ; ; 29 | ; Clock ; 30 | ; ; 31 | ;;;;;;;;;;;;;;;;;;;;; 32 | mov ax, 0xb800 33 | mov ds, ax 34 | mov es, ax 35 | xor ax, ax 36 | mov di, 0x8d 37 | mov cx, 0x2 38 | rep stosw 39 | mov di, 0x0090 40 | mov ah, 0x02 41 | int 0x1a ; get time: ch=hours cl=minutes dh=seconds 42 | mov al, ch 43 | call digit 44 | call prnt 45 | mov al, cl 46 | call digit 47 | call prnt 48 | mov al, dh 49 | call digit 50 | ; date 51 | mov di, 0x0129 52 | mov cx, 0x2 53 | xor ax, ax 54 | rep stosw 55 | mov di, 0x012c 56 | mov ah, 0x04 57 | int 0x1a 58 | mov al, dl 59 | call digit 60 | call prnt2 61 | mov al, dh 62 | call digit 63 | call prnt2 64 | mov al, ch 65 | call digit 66 | mov al, cl 67 | call digit 68 | popf 69 | pop ds 70 | pop es 71 | popa 72 | iret 73 | 74 | digit: mov ah, al 75 | and ah, 0b11110000 76 | and al, 0b00001111 77 | shr ah, 4 78 | add ah, '0' 79 | add al, '0' 80 | push ax 81 | mov al, ah 82 | stosb 83 | mov al, 0b01110000 84 | stosb 85 | pop ax 86 | stosb 87 | mov al, 0b01110000 88 | stosb 89 | ret 90 | 91 | prnt: mov al, ":" 92 | stosb 93 | mov al, 0xf0 94 | stosb 95 | ret 96 | prnt2: mov al, "." 97 | stosb 98 | mov al, 0b01110000 99 | stosb 100 | ret 101 | 102 | interrupts: 103 | dw main -------------------------------------------------------------------------------- /software_src/disk: -------------------------------------------------------------------------------- 1 | org 0x7c00 2 | 3 | %include "../sysmap.inc" 4 | 5 | main: 6 | mov al, "@" 7 | call bootOS.input_line 8 | call bootOS.xdigit ; Get a hexadecimal digit 9 | mov cl,4 10 | shl al,cl 11 | xchg ax,cx 12 | call bootOS.xdigit ; Get a hexadecimal digit 13 | or al,cl 14 | mov byte [bootOS._disk2 + 1], al 15 | int 0x20 16 | -------------------------------------------------------------------------------- /software_src/doom: -------------------------------------------------------------------------------- 1 | ; 2 | ; CubicDoom 3 | ; 4 | ; by Oscar Toledo G. 5 | ; 6 | ; Creation date: Nov/21/2019. 7 | ; Revision date: Nov/22/2019. Now working. 8 | ; Revision date: Nov/23/2019. Optimized. 9 | ; Revision date: Nov/24/2019. Builds a world. Added evil cubes, and 10 | ; can shoot them. 517 bytes. 11 | ; Revision date: Nov/25/2019. Optimized last bytes. 509 bytes. 12 | ; Revision date: Nov/26/2019. Smaller extract. 508 bytes 13 | ; (Peter Ferrie). 14 | ; 15 | 16 | ; 17 | ; Tricks used: 18 | ; o "Slow" ray-casting so doesn't matter if hits horizontal or 19 | ; vertical wall. 20 | ; 21 | 22 | ; cpu 8086 23 | 24 | EMPTY: equ 0x00 ; Code for empty space 25 | WALL: equ 0x80 ; Code for wall 26 | ENEMY: equ 0xc0 ; Code for enemy, includes shot count 27 | 28 | %ifdef com_file 29 | org 0x0100 30 | %else 31 | org 0x7c00 32 | %endif 33 | 34 | down: equ 0x000b ; Enemies down 35 | shot: equ 0x000a ; Shot made 36 | rnd: equ 0x0008 ; Random number 37 | px: equ 0x0006 ; Current X position (4.12) 38 | py: equ 0x0004 ; Current Y position (4.12) 39 | pa: equ 0x0002 ; Current screen angle 40 | oldtim: equ 0x0000 ; Old time 41 | 42 | maze: equ 0xff00 ; Location of maze (16x16) 43 | 44 | ; 45 | ; Start of the game 46 | ; 47 | start: 48 | mov ax,0x0013 ; Graphics mode 320x200x256 colors 49 | int 0x10 ; Setup video mode 50 | ; mov ax,0xa000 ; Point to video memory. 51 | ; mov ds,ax 52 | ; mov es,ax 53 | push 0xa000 54 | pop ds 55 | push ds 56 | pop es 57 | restart: 58 | cld 59 | cs inc byte [game_loop.lvl_pointer + 2] 60 | xor cx,cx 61 | push cx ; shot+down 62 | in al, 0x40 63 | push ax ; rnd 64 | mov ah,0x18 ; Start point at maze 65 | push ax ; px 66 | push ax ; py 67 | mov cl,0x04 68 | push cx ; pa 69 | push cx ; oldtim 70 | mov bp,sp ; Setup BP to access variables 71 | 72 | mov bx,maze ; Point to maze 73 | .0: mov al,bl 74 | add al,0x11 ; Right and bottom borders at zero 75 | cmp al,0x22 ; Inside any border? 76 | jb .5 ; Yes, jump 77 | and al,0x0e ; Inside left/right border? 78 | mov al,EMPTY 79 | jne .4 ; No, jump 80 | .5: mov al,WALL 81 | .4: mov [bx],al ; Put into maze 82 | inc bx ; Next square 83 | jne .0 ; If BX is zero, maze completed 84 | 85 | mov cl,12 ; 12 walls and enemies 86 | mov [bp+down],cl ; Take note of enemies down 87 | mov di,maze+34 ; Point to center of maze 88 | mov dl,12 ; Modulo 12 for random number 89 | .2: 90 | call random 91 | mov byte [di+bx],WALL ; Setup a wall 92 | call random 93 | mov byte [di+bx],ENEMY ; Setup an enemy 94 | add di,byte 16 ; Go to next row of maze 95 | loop .2 ; Repeat until filled 96 | game_loop: 97 | call wait_frame ; Wait a frame 98 | 99 | and dl,31 ; 32 frames have passed? 100 | jnz .16 ; No, jump 101 | ; 102 | ; Move cubes 103 | ; 104 | call get_dir ; Get player position, also SI=0 105 | call get_pos ; Convert position to maze address 106 | mov cx,bx ; Save into CX 107 | 108 | mov bl,0 ; BH already ready, start at corner 109 | 110 | .17: cmp byte [bx],ENEMY 111 | jb .18 112 | cmp bx,cx ; Cube over player? 113 | jne .25 ; No, jump 114 | ; 115 | ; Handle death 116 | ; 117 | .22: 118 | mov byte [si],0x0c ; Blood pixel 119 | add si,byte 23 ; Advance by prime number 120 | .23: 121 | je restart ; Zero = full loop, restart game. 122 | jnb .22 ; Carry = one fill complete. 123 | push si 124 | call wait_frame ; Wait a frame (for fast machines) 125 | pop si 126 | jmp .22 ; Continue 127 | 128 | .25: 129 | mov di,bx 130 | mov al,bl 131 | mov ah,cl 132 | mov dx,0x0f0f ; Extract columns 133 | and dx,ax 134 | xor ax,dx ; Extract rows 135 | cmp ah,al ; Same row? 136 | je .19 ; Yes, jump 137 | lea di,[bx+0x10] ; Cube moves down 138 | jnb .19 139 | lea di,[bx-0x10] ; Cube moves up 140 | .19: cmp dh,dl ; Same column? 141 | je .20 ; Yes, jump 142 | dec di ; Cube goes left 143 | jb .20 144 | inc di ; Cube goes right 145 | inc di 146 | .20: cmp byte [di],0 ; Can move? 147 | jne .18 ; No, jump. 148 | mov al,[bx] ; Take cube 149 | mov byte [bx],0 ; Erase origin 150 | stosb ; Put into new place 151 | .18: 152 | inc bx ; Continue searching the maze... 153 | jne .17 ; ...until the end 154 | 155 | .16: 156 | 157 | ; 158 | ; Draw 3D view 159 | ; 160 | mov di,39 ; Column number is 39 161 | .2: 162 | lea ax,[di-20] ; Almost 60 degrees to the left 163 | add ax,[bp+pa] ; Get vision angle 164 | call get_dir ; Get position and direction 165 | .3: 166 | call read_maze ; Verify wall hit 167 | jnc .3 ; Continue if it was open space 168 | 169 | .4: 170 | mov cx,0x1204 ; Add grayscale color set... 171 | ; ...also load CL with 4. (division by 16) 172 | jz .24 ; Jump if normal wall 173 | mov ch,32 ; Rainbow 174 | 175 | cmp di,byte 20 176 | jne .24 ; Jump if not at center 177 | cmp byte [bp+shot],1 178 | je .24 ; Jump if not shooting 179 | call get_pos 180 | inc byte [bx] ; Increase cube hits 181 | .lvl_pointer: 182 | cmp byte [bx],ENEMY+3 ; 3 hits? 183 | jne .24 ; No, jump 184 | mov byte [bx],0 ; Yes, remove. 185 | dec byte [bp+down] ; One cube less 186 | je .23 ; Zero means to get another level 187 | .24: 188 | lea ax,[di+12] ; Get cos(-30) to cos(30) 189 | call get_sin ; Get cos (8 bit fraction) 190 | mul si ; Correct wall distance to... 191 | mov bl,ah ; ...avoid fishbowl effect 192 | mov bh,dl ; Divide by 256 193 | inc bx ; Avoid zero value 194 | 195 | mov ax,0x0800 ; Constant for projection plane 196 | cwd 197 | div bx ; Divide 198 | cmp ax,198 ; Limit to screen height 199 | jb .14 200 | mov ax,198 201 | .14: mov si,ax ; Height of wall 202 | 203 | shr ax,cl ; Divide distance by 16 204 | add al,ch ; Add palette index 205 | xchg ax,bx ; Put into BX 206 | 207 | push di 208 | dec cx ; CL=3. Multiply column by 8 pixels 209 | shl di,cl 210 | 211 | mov ax,200 ; Height of screen... 212 | sub ax,si ; ...minus wall height 213 | shr ax,1 ; Divide by 2 214 | 215 | push ax 216 | push si 217 | xchg ax,cx 218 | mov al,[bp+shot] ; Ceiling color 219 | call fill_column 220 | xchg ax,bx ; Wall color 221 | pop cx 222 | call fill_column 223 | mov al,0x03 ; Floor color (a la Wolfenstein) 224 | pop cx 225 | call fill_column 226 | pop di 227 | dec di ; Decrease column 228 | jns .2 ; Completed? No, jump. 229 | 230 | mov ah,0x02 ; Service 0x02 = Read modifier keys 231 | int 0x16 ; Call BIOS 232 | 233 | mov bx,[bp+pa] ; Get current angle 234 | test al,0x04 ; Left Ctrl pressed? 235 | je .8 236 | dec bx ; Decrease angle 237 | dec bx 238 | .8: 239 | test al,0x08 ; Left Alt pressed? 240 | je .9 241 | inc bx ; Increase angle 242 | inc bx 243 | .9: 244 | mov ah,1 ; No shot 245 | test al,0x01 ; Right shift pressed? 246 | je .11 247 | test bh,0x01 ; But not before? 248 | jne .11 249 | mov ah,7 ; Indicate shot 250 | 251 | .11: mov [bp+shot],ah 252 | mov bh,al 253 | mov [bp+pa],bx ; Update angle 254 | 255 | test al,0x02 ; Left shift pressed? 256 | je .10 257 | xchg ax,bx ; Put angle into AX 258 | call get_dir ; Get position and direction 259 | .5: call read_maze ; Move and check for wall hit 260 | jc .10 ; Hit, jump without updating position. 261 | cmp si,byte 4 ; Four times (the speed) 262 | jne .5 263 | 264 | mov [bp+px],dx ; Update X position 265 | mov [bp+py],bx ; Update Y position 266 | .10: 267 | jmp game_loop ; Repeat game loop 268 | 269 | ; 270 | ; Get a direction vector 271 | ; 272 | get_dir: 273 | xor si,si ; Wall distance = 0 274 | mov dx,[bp+px] ; Get X position 275 | push ax 276 | call get_sin ; Get sine 277 | xchg ax,cx ; Onto DX 278 | pop ax 279 | add al,32 ; Add 90 degrees to get cosine 280 | ; 281 | ; Get sine 282 | ; 283 | get_sin: 284 | test al,64 ; Angle >= 180 degrees? 285 | pushf 286 | test al,32 ; Angle 90-179 or 270-359 degrees? 287 | je .2 288 | xor al,31 ; Invert bits (reduces table) 289 | .2: 290 | and ax,31 ; Only 90 degrees in table 291 | mov bx,sin_table 292 | cs xlat ; Get fraction 293 | popf 294 | je .1 ; Jump if angle less than 180 295 | neg ax ; Else negate result 296 | .1: 297 | mov bx,[bp+py] ; Get Y position 298 | ret 299 | 300 | ; 301 | ; Read maze 302 | ; 303 | read_maze: 304 | inc si ; Count distance to wall 305 | add dx,cx ; Move X 306 | add bx,ax ; Move Y 307 | push bx 308 | push cx 309 | call get_pos 310 | mov bl,[bx] ; Read maze byte 311 | shl bl,1 ; Carry = 1 = wall, Zero = Wall 0 / 1 312 | pop cx 313 | pop bx 314 | ret ; Return 315 | 316 | ; 317 | ; Convert coordinates to position 318 | ; 319 | get_pos: 320 | mov bl,dh ; X-coordinate 321 | mov cl,0x04 ; Divide by 4096 322 | shr bl,cl 323 | and bh,0xf0 ; Y-coordinate / 4096 * 16 324 | or bl,bh ; Translate to maze array 325 | mov bh,maze>>8 326 | ret 327 | 328 | ; 329 | ; Fill a screen column 330 | ; 331 | fill_column: 332 | mov ah,al ; Duplicate pixel value 333 | .1: 334 | stosw ; Draw 2 pixels 335 | stosw ; Draw 2 pixels 336 | stosw ; Draw 2 pixels 337 | stosw ; Draw 2 pixels 338 | add di,0x0138 ; Go to next row 339 | loop .1 ; Repeat until fully drawn 340 | ret ; Return 341 | 342 | ; 343 | ; Generate a pseudo-random number (from bootRogue) 344 | ; 345 | random: 346 | mov al,251 347 | mul byte [bp+rnd] 348 | add al,83 349 | mov [bp+rnd],al 350 | mov ah,0 351 | div dl 352 | mov bl,ah 353 | mov bh,0 354 | ret 355 | 356 | ; 357 | ; Wait a frame (18.2 hz) 358 | ; 359 | wait_frame: 360 | .1: 361 | mov ah,0x00 ; Get ticks 362 | int 0x1a ; Call BIOS time service 363 | cmp dx,[bp+oldtim] ; Same as old time? 364 | je .1 ; Yes, wait. 365 | mov [bp+oldtim],dx 366 | ret 367 | 368 | ; 369 | ; Sine table (0.8 format) 370 | ; 371 | ; 32 bytes are 90 degrees. 372 | ; 373 | sin_table: 374 | db 0x00,0x09,0x16,0x24,0x31,0x3e,0x47,0x53 375 | db 0x60,0x6c,0x78,0x80,0x8b,0x96,0xa1,0xab 376 | db 0xb5,0xbb,0xc4,0xcc,0xd4,0xdb,0xe0,0xe6 377 | db 0xec,0xf1,0xf5,0xf7,0xfa,0xfd,0xff,0xff 378 | 379 | %ifdef com_file 380 | %else 381 | times 512-($-$$) nop 382 | %endif 383 | -------------------------------------------------------------------------------- /software_src/download: -------------------------------------------------------------------------------- 1 | start: mov ax, 0x0000 | 0b11111011 2 | mov dx, 0x0000 3 | int 0x14 4 | recv: mov di, 0xa000 5 | mov cx, 0x0200 6 | mov ah, 0x02 7 | mov dx, 0x0000 8 | cld 9 | .loop: int 0x14 10 | test ah, 0b1000000 11 | jnz .loop 12 | stosb 13 | loop .loop 14 | 15 | save: mov al, "?" 16 | int 0x26 17 | mov bx, si 18 | mov di, 0xa000 19 | int 0x24 20 | jc err 21 | int 0x20 22 | err: 23 | mov al, 0x13 24 | int 0x22 25 | int 0x20 26 | -------------------------------------------------------------------------------- /software_src/ember: -------------------------------------------------------------------------------- 1 | ; https://github.com/NieDzejkob/ember 2 | ; this overwrites bootOS :D 3 | ; you can install it to you hdd too 4 | 5 | ; commands to install: 6 | ; * run 7c08:90909090 7 | ; * removes the statement that loads dl from bootOS 8 | ; * run 7c00w00000000 9 | ; * installs it to the first sector 10 | ; * run 7f00:ea0000ffff 11 | ; * run 7f00g 12 | ; * reboots (executes jmp 0xffff:0x0000) 13 | 14 | ; memory map: 15 | ; [0000; 0400) IVT 16 | ; [0400; 0500) BDA 17 | ; [ ; 7a00) stack 18 | ; [7a00; 7c00) MBR 19 | ; [7e00; 7e10) EDD disk packet 20 | ; [7e10; ) variables 21 | 22 | org 0x7a00 23 | bits 16 24 | 25 | %define linebuffer 0x600 26 | ; Some BIOSes start with CS=07c0. Make sure this does not wreak havoc 27 | mbr: 28 | xor cx, cx 29 | mov ds, cx 30 | mov es, cx 31 | mov ss, cx 32 | mov dl, byte [bootOS.disk.1+1] 33 | cld 34 | mov si, 0x7c00 35 | mov di, 0x7a00 36 | mov ch, 0x02 37 | rep movsb 38 | jmp 0x0:start 39 | 40 | 41 | ivtptr: 42 | %define i_biosdisp 0x10 43 | %define i_biosdisk 0x13 44 | %define i_bioskbd 0x16 45 | 46 | %define i_readline 0x20 47 | dw readline 48 | 49 | %define i_putchar 0x21 50 | dw putchar 51 | 52 | %define i_diskread 0x22 53 | dw diskread 54 | 55 | %define i_diskwrite 0x23 56 | dw diskwrite 57 | .end: 58 | 59 | start: 60 | cli 61 | mov sp, 0x7a00 62 | mov [do_disk.disknum+1], dl 63 | sti 64 | 65 | mov di, 0x20 * 4 66 | mov si, ivtptr 67 | mov cl, ivtptr.end - ivtptr 68 | .ivtloop: 69 | movsw 70 | xor ax, ax 71 | stosw 72 | loop .ivtloop 73 | 74 | 75 | xor bx, bx 76 | shell: 77 | mov al, ')' 78 | int i_putchar 79 | 80 | int i_readline 81 | 82 | ; Speculatively parse a new pointer 83 | mov si, linebuffer 84 | call readhexword 85 | jc short .oldaddr 86 | xchg bx, ax ; mov bx, ax 87 | mov di, bx 88 | jmp short .gotaddr 89 | .oldaddr: 90 | mov si, linebuffer 91 | .gotaddr: 92 | 93 | ; command dispatch 94 | lodsb 95 | or al, al 96 | jnz short not_singledump 97 | 98 | mov cx, 1 99 | jmp short hexdump 100 | not_singledump: 101 | cmp al, '.' 102 | jnz short not_rangedump 103 | 104 | call readhexword 105 | jc parse_error 106 | 107 | sub ax, bx ; length in bytes 108 | add ax, 15 ; round up 109 | shr ax, 4 ; into line count 110 | mov cx, ax ; prepare loop counter 111 | 112 | call verify_end 113 | 114 | ; Print a hexdump 115 | ; Returns to `shell` 116 | ; Input: 117 | ; BX = data pointer 118 | ; CX = line count 119 | ; Output: 120 | ; BX = first unprinted byte 121 | ; CX = 0 122 | ; Clobbers AX 123 | hexdump: 124 | mov al, bh 125 | call writehexbyte 126 | mov al, bl 127 | call writehexbyte 128 | mov al, ':' 129 | int i_putchar 130 | push cx 131 | mov cx, 16 132 | .byteloop: 133 | mov al, ' ' 134 | int i_putchar 135 | mov al, [bx] 136 | inc bx 137 | call writehexbyte 138 | loop .byteloop 139 | mov al, `\r` 140 | int i_putchar 141 | pop cx 142 | loop hexdump 143 | jmp short shell 144 | 145 | not_rangedump: 146 | cmp al, ':' 147 | jnz short not_poke 148 | mov bx, di ; move the read location 149 | 150 | .loop: 151 | lodsb 152 | or al, al 153 | jz short shell 154 | 155 | cmp al, ' ' 156 | jz short .loop 157 | 158 | dec si 159 | call readhexbyte 160 | jc parse_error 161 | stosb 162 | jmp short .loop 163 | 164 | not_poke: 165 | cmp al, 'g' 166 | jnz short not_run 167 | 168 | call verify_end 169 | call di 170 | jmp short not_print.shell 171 | 172 | not_run: 173 | cmp al, 'w' 174 | jnz short .not_write 175 | mov cl, 0x00 176 | jmp short .continue 177 | .not_write: 178 | cmp al, 'r' 179 | mov cl, 0x01 180 | jnz short not_rw 181 | .continue: 182 | mov bx, di ; move the read location 183 | call readhexword 184 | jc short parse_error 185 | shl eax, 16 186 | call readhexword 187 | jc short parse_error 188 | ; eax should hold our lba now 189 | 190 | mov di, bx 191 | push es 192 | push cs 193 | pop es 194 | cmp cl, 0x01 195 | je .read 196 | int i_diskwrite 197 | jmp .continue2 198 | .read: 199 | int i_diskread 200 | .continue2: 201 | pop es 202 | 203 | jmp short not_print.shell 204 | 205 | not_rw: 206 | cmp al, 'p' 207 | jnz short not_print 208 | 209 | mov cx, 16 210 | mov si, di 211 | mov ah, 0x0e 212 | mov bx, 0x0007 213 | .loop: lodsb 214 | int 0x10 215 | loop .loop 216 | 217 | mov al, 0x0d 218 | int i_putchar 219 | 220 | add di, 16 221 | 222 | jmp short not_print.shell 223 | 224 | not_print: 225 | cmp al, 'd' 226 | jnz short not_drive 227 | xchg ax, di 228 | mov byte [do_disk.disknum+1], al 229 | 230 | .shell: jmp shell 231 | 232 | not_drive: 233 | cmp al, ';' 234 | jnz short parse_error ; TODO: make this a direct jump when features are finalized 235 | .loop lodsb 236 | cmp al, 0x00 237 | je not_print.shell 238 | stosb 239 | jmp .loop 240 | 241 | 242 | verify_end: 243 | lodsb 244 | or al, al 245 | jz short readhexbyte.fail ; borrow the return of some other routine 246 | pop ax ; discard the return address 247 | 248 | parse_error: 249 | dec si 250 | lodsb 251 | or al, al 252 | jz short .skip_char 253 | int i_putchar 254 | .skip_char: 255 | mov al, '?' 256 | int i_putchar 257 | mov al, 0x0d 258 | int i_putchar 259 | jmp near shell 260 | 261 | ; Parse a hexadecimal word. 262 | ; Input: 263 | ; SI = input buffer pointer 264 | ; Output (success): 265 | ; CF clear 266 | ; AX = parsed word 267 | ; SI = input + 4 268 | ; Output (failure): 269 | ; CF set 270 | ; SI = after first invalid character 271 | ; Clobbers DL 272 | readhexword: 273 | call readhexbyte 274 | jc short readhexbyte.fail 275 | mov ah, al 276 | ; fallthrough 277 | 278 | ; Parse a hexadecimal byte. 279 | ; Input: 280 | ; SI = input buffer pointer 281 | ; Output (success): 282 | ; CF clear 283 | ; AL = parsed byte 284 | ; SI = input + 2 285 | ; Output (failure): 286 | ; CF set 287 | ; AL = undefined 288 | ; SI = after invalid character 289 | ; Clobbers DL 290 | readhexbyte: 291 | lodsb 292 | call readhexchar 293 | jc short .fail 294 | shl al, 4 295 | mov dl, al 296 | lodsb 297 | call readhexchar 298 | jc short .fail 299 | or al, dl ; carry flag is clear 300 | .fail: 301 | ret 302 | 303 | ; Parse a hexadecimal digit. 304 | ; Input: 305 | ; AL = ASCII character 306 | ; Output (success): 307 | ; CF clear 308 | ; AL = digit value [0; 16) 309 | ; Output (failure): 310 | ; CF set 311 | ; AL = undefined 312 | readhexchar: 313 | sub al, '0' 314 | jc short .end 315 | cmp al, 10 ; jb = jc, so right now carry = ok 316 | cmc ; now, carry = try different range 317 | jnc short .end 318 | sub al, 'a' - '0' 319 | jc short .end 320 | add al, 10 321 | cmp al, 16 322 | cmc ; before, carry = ok. now, carry = error 323 | .end: 324 | ret 325 | 326 | ; Write a hexadecimal byte. 327 | ; Input: 328 | ; AL = the byte 329 | ; Output: 330 | ; (screen) 331 | ; AL = the lower nibble as ASCII 332 | ; DL = the byte, unchanged 333 | writehexbyte: 334 | mov dl, al 335 | shr al, 4 336 | call writehexchar 337 | mov al, dl 338 | and al, 0x0f 339 | ; fallthrough 340 | 341 | ; Write a hexadecimal digit. 342 | ; Input: 343 | ; AL = digit [0; 0x10) 344 | ; Output: 345 | ; (screen) 346 | ; AL = digit as ASCII 347 | writehexchar: 348 | add al, '0' 349 | cmp al, '9' 350 | jbe .ok 351 | add al, 'a' - '0' - 10 352 | .ok: 353 | int i_putchar 354 | ret 355 | 356 | ; Interrupt 0x23 357 | ; Write sector on the boot disk 358 | ; Input: 359 | ; eax = LBA 360 | ; es:di = operation buffer 361 | diskwrite: 362 | mov byte [do_disk.op+1], 0x43 363 | jmp short do_disk 364 | 365 | ; Interrupt 0x22 366 | ; Read sector on the boot disk 367 | ; Input: 368 | ; eax = LBA 369 | ; es:di = operation buffer 370 | ; Stops execution on error 371 | diskread: 372 | mov byte[do_disk.op+1], 0x42 373 | 374 | do_disk: 375 | pusha 376 | push ds 377 | 378 | push cs 379 | pop ds 380 | 381 | mov si, 0x7e00 382 | mov dword[si], 0x10010 383 | mov [si+4], di 384 | mov [si+6], es 385 | mov [si+8], eax 386 | xor eax, eax 387 | mov [si+12], eax 388 | .disknum: 389 | mov dl, 0 ; overwritten during init 390 | .op: 391 | mov ah, 0x42 ; overwritten when writing 392 | int i_biosdisk 393 | jc short error 394 | 395 | pop ds 396 | popa 397 | iret 398 | 399 | error: 400 | mov al, '!' 401 | int i_putchar 402 | jmp shell 403 | 404 | ; Interrupt 0x20 405 | ; Read a line of text and store it in the global `linebuffer` (0x600). The result is 406 | ; null-terminated. No overflow checking is performed. 407 | readline: 408 | pusha 409 | cld 410 | mov di, linebuffer 411 | .loop: 412 | mov ah, 0 413 | int i_bioskbd 414 | 415 | cmp al, 8 416 | jne short .nobackspace 417 | cmp di, linebuffer 418 | je short .loop 419 | dec di 420 | db 0xb4 ; load the opcode of the stosb to AH to skip its execution 421 | .nobackspace: 422 | stosb 423 | int i_putchar 424 | 425 | cmp al, `\r` 426 | jne short .loop 427 | 428 | dec di ; undo the store of the line terminatior 429 | mov byte[di], 0 430 | popa 431 | iret 432 | 433 | ; Interrupt 0x21 434 | ; Put a character on the screen. Expands \r into \r\n because the latter is required 435 | ; by the BIOS for a proper newline. \r is used to signify newlines because that's what 436 | ; the keyboard gives us. 437 | ; Input: 438 | ; AL = ASCII character 439 | putchar: 440 | pusha 441 | mov ah, 0x0e 442 | xor bx, bx 443 | int i_biosdisp 444 | cmp al, `\r` ; all registers are preserved by the BIOS function 445 | jne short .skip_newline 446 | mov al, `\n` 447 | int i_biosdisp 448 | .skip_newline: 449 | cmp al, `\b` 450 | jne short .skip_backspace 451 | mov al, ' ' 452 | int i_biosdisp 453 | mov al, `\b` 454 | int i_biosdisp 455 | .skip_backspace: 456 | popa 457 | iret 458 | 459 | times 510 - ($ - $$) db 0 460 | dw 0xaa55 461 | -------------------------------------------------------------------------------- /software_src/fat12: -------------------------------------------------------------------------------- 1 | %define MODULE "../shared/fat12.asm" 2 | 3 | %include "../shared/fsloader.asm" 4 | -------------------------------------------------------------------------------- /software_src/fbird: -------------------------------------------------------------------------------- 1 | ; 2 | ; F-bird text game in a bootsector 3 | ; 4 | ; by Oscar Toledo G. 5 | ; http://nanochess.org/ 6 | ; 7 | ; Creation date: Jun/04/2017. A messy unoptimized thing. 8 | ; Revision date: Jun/05/2017. Better usage of graphic charset. 9 | ; Removed a non-8088 long jump. Added 10 | ; sound. Solved bug when overwriting 11 | ; previous score. 12 | ; 13 | 14 | use16 15 | 16 | mov ax,0x0002 ; Set 80x25 text mode 17 | int 0x10 ; Call BIOS 18 | cld ; Reset direction flag (so stosw increments registers) 19 | mov ax,0xb800 ; Point to video segment 20 | mov ds,ax ; Both the source (common access) 21 | mov es,ax ; and target segments 22 | ; 23 | ; Game restart 24 | ; 25 | fb21: mov di,pipe ; Init variables in video segment (saves big bytes) 26 | xor ax,ax 27 | stosw ; pipe 28 | stosw ; score 29 | stosw ; grav 30 | mov al,0xa0 31 | stosw ; next 32 | mov al,0x60 33 | stosw ; bird 34 | 35 | mov di,0x004a ; Game title 36 | mov ax,0x0f46 ; 'F' in white, good old ASCII 37 | stosw 38 | mov al,0x2d ; '-' 39 | stosw 40 | mov al,0x42 ; 'B' 41 | stosw 42 | mov al,0x49 ; 'I' 43 | stosw 44 | mov al,0x52 ; 'R' 45 | stosw 46 | mov al,0x44 ; 'D' 47 | stosw 48 | mov cx,80 ; Introduce 80 columns of scenery 49 | fb1: push cx 50 | call scroll_scenery 51 | pop cx 52 | loop fb1 53 | 54 | fb23: mov ah,0x01 ; Check if key pressed 55 | int 0x16 56 | pushf 57 | xor ax,ax ; Wait for a key 58 | int 0x16 59 | popf 60 | jnz fb23 ; Jump if key was accumulated, if not already waited for key ;) 61 | 62 | ; 63 | ; Main loop 64 | ; 65 | fb12: mov al,[bird] ; Bird falls... 66 | add al,[grav] ; ...because of gravity... 67 | mov [bird],al ; ...into new position. 68 | and al,0xf8 ; Row is a 5.3 fraction, nullify fraction 69 | mov ah,0x14 ; Given integer is x8, multiply by 20 to get 160 per line 70 | mul ah ; Row into screen 71 | add ax,$0020 ; Fixed column 72 | xchg ax,di ; Pass to DI (AX cannot be used as pointer) 73 | mov al,[frame] 74 | and al,4 ; Wing movement each 4 frames 75 | jz fb15 76 | mov al,[di-160] ; Get character below 77 | mov word [di-160],$0d1e ; Draw upper wing 78 | add al,[di] ; Add another character below 79 | shr al,1 ; Normalize 80 | mov word [di],$0d14 ; Draw body 81 | jmp short fb16 82 | 83 | fb15: mov al,[di] ; Get character below 84 | mov word [di],$0d1f ; Draw body 85 | fb16: add al,[di+2] ; Get character below head 86 | mov word [di+2],$0d10 ; Draw head 87 | cmp al,0x40 ; Collision with scenery? 88 | jz fb19 89 | ; 90 | ; Stars and game over 91 | ; 92 | mov byte [di],$2a ; '*' Asterisks to indicate crashing 93 | mov byte [di+2],$2a 94 | mov di,0x07CA 95 | mov ax,0x0f42 ; 'B' in white, good old ASCII 96 | stosw 97 | mov al,0x4F ; 'O' 98 | stosw 99 | mov al,0x4E ; 'N' 100 | stosw 101 | mov al,0x4B ; 'K' 102 | stosw 103 | mov al,0x21 ; '!' 104 | stosw 105 | mov cx,30 ; Wait 100 frames 106 | fb20: push cx 107 | call wait_frame 108 | pop cx 109 | loop fb20 110 | jmp fb21 ; Restart 111 | 112 | fb19: call wait_frame ; Wait for frame 113 | mov al,[frame] 114 | and al,7 ; 8 frames have passed? 115 | jnz fb17 ; No, jump 116 | inc word [grav] ; Increase gravity 117 | fb17: 118 | mov al,$20 119 | mov [di-160],al ; Delete bird from screen 120 | mov [di+2],al 121 | stosb 122 | call scroll_scenery ; Scroll scenery 123 | call scroll_scenery ; Scroll scenery 124 | cmp byte [0x00a0],0xb0 ; Passed a column? 125 | jz fb27 126 | cmp byte [0x00a2],0xb0 ; Passed a column? 127 | fb27: jnz fb24 128 | inc word [score] ; Increase score 129 | mov ax,[score] 130 | mov di,0x008e ; Show current score 131 | fb25: xor dx,dx ; Extend AX to 32 bits 132 | mov bx,10 ; Divisor is 10 133 | div bx ; Divide 134 | add dx,0x0c30 ; Convert remaining 0-9 to ASCII, also put color 135 | xchg ax,dx 136 | std 137 | stosw 138 | mov byte [di],0x20 ; Clean at least one character of prev. score 139 | cld 140 | xchg ax,dx 141 | or ax,ax ; Score digits still remain? 142 | jnz fb25 ; Yes, jump 143 | fb24: mov ah,0x01 ; Any key pressed? 144 | int 0x16 145 | jz fb26 ; No, go to main loop 146 | mov ah,0x00 147 | int 0x16 ; Get key 148 | cmp al,0x1b ; Escape key? 149 | jne fb4 ; No, jump 150 | int 0x20 ; Exit to DOS or to oblivion (boot sector) 151 | fb4: mov ax,[bird] 152 | sub ax,0x10 ; Move bird two rows upward 153 | cmp ax,0x08 ; Make sure the bird doesn't fly free outside screen 154 | jb fb18 155 | mov [bird],ax 156 | fb18: mov byte [grav],0 ; Reset gravity 157 | mov al,0xb6 ; Flap sound 158 | out (0x43),al 159 | mov al,0x90 160 | out (0x42),al 161 | mov al,0x4a 162 | out (0x42),al 163 | in al,(0x61) 164 | or al,0x03 ; Turn on sound 165 | out (0x61),al 166 | fb26: jmp fb12 167 | 168 | ; 169 | ; Scroll scenery one column at a time 170 | ; 171 | scroll_scenery: 172 | ; 173 | ; Move whole screen 174 | ; 175 | mov si,0x00a2 ; Point to row 1, column 1 in SI 176 | mov di,0x00a0 ; Point to row 1, column 0 in DI 177 | fb2: mov cx,79 ; 79 columns 178 | repz ; Scroll!!! 179 | movsw 180 | mov ax,0x0e20 ; Clean last character 181 | stosw 182 | lodsw ; Advance source to keep pair source/target 183 | cmp si,0x0fa2 ; All scrolled? 184 | jnz fb2 ; No, jump 185 | ; 186 | ; Insert houses 187 | ; 188 | mov word [0x0f9e],0x02df ; Terrain 189 | in al,(0x40) ; Get "random" number 190 | and al,0x70 191 | jz fb5 192 | mov bx,0x0408 ; House of one floor 193 | mov [0x0efe],bx 194 | mov di,0x0e5e 195 | and al,0x20 ; Check "random" number 196 | jz fb3 197 | mov [di],bx ; House of two floors 198 | sub di,0x00a0 199 | fb3: mov word [di],0x091e ; Add roof 200 | ; 201 | ; Check if it's time to insert a column 202 | ; 203 | fb5: dec word [next] ; Decrease time (column really) for next pipe 204 | mov bx,[next] 205 | cmp bx,0x03 ; bx = 3,2,1,0 for the four columns making the pipe 206 | ja fb6 207 | jne fb8 208 | in al,(0x40) ; Get "random" number 209 | and ax,0x0007 ; Between 0 and 7 210 | add al,0x04 ; Between 4 and 11 211 | mov [tall],ax ; This will tell how tall the pipe is 212 | fb8: mov cx,[tall] 213 | or bx,bx ; Rightmost? 214 | mov dl,0xb0 215 | jz fb7 ; Yes, jump 216 | mov dl,0xdb 217 | cmp bx,0x03 ; Leftmost? 218 | jb fb7 ; No, jump 219 | mov dl,0xb1 220 | fb7: mov di,0x013e ; Start from top of screen 221 | mov ah,0x0a 222 | mov al,dl 223 | fb9: stosw 224 | add di,0x009e 225 | loop fb9 226 | mov al,0xc4 227 | stosw 228 | add di,0x009e*6+10 229 | mov al,0xdf 230 | stosw 231 | add di,0x009e 232 | fb10: mov al,dl 233 | stosw 234 | add di,0x009e 235 | cmp di,0x0f00 236 | jb fb10 237 | or bx,bx 238 | jnz fb6 239 | mov ax,[pipe] 240 | inc ax ; Increase total pipes shown 241 | mov [pipe],ax 242 | mov cl,3 243 | shr ax,cl 244 | mov ah,0x50 ; Decrease distance between pipes 245 | sub ah,al 246 | cmp ah,0x10 247 | ja fb11 248 | mov ah,0x10 249 | fb11: mov [next],ah ; Time for next pipe 250 | fb6: ret 251 | 252 | ; 253 | ; Wait for a frame 254 | ; 255 | wait_frame: 256 | mov ah,0x00 ; Use base clock tick 257 | int 0x1a 258 | fb14: push dx 259 | mov ah,0x00 ; Read again base clock tick 260 | int 0x1a 261 | pop bx 262 | cmp bx,dx ; Wait for change 263 | jz fb14 264 | inc word [frame] ; Increase frame count 265 | in al,(0x61) 266 | and al,0xfc ; Turn off sound 267 | out (0x61),al 268 | int 0x27 269 | ret 270 | 271 | nop 272 | 273 | db 0x55,0xaa ; Bootable signature 274 | 275 | pipe: equ 0x0fa0 276 | score: equ 0x0fa2 277 | grav: equ 0x0fa4 278 | next: equ 0x0fa6 279 | bird: equ 0x0fa8 280 | tall: equ 0x0faa 281 | frame: equ 0x0fac 282 | -------------------------------------------------------------------------------- /software_src/heart: -------------------------------------------------------------------------------- 1 | ; https://raw.githubusercontent.com/nanochess/heart/main/heart.asm 2 | 3 | ; 4 | ; Draw a heart using a heart curve equation 5 | ; (uses only integer arithmetic) 6 | ; 7 | ; by Oscar Toledo G. 8 | ; http://nanochess.org/ 9 | ; 10 | ; Creation date: Feb/14/2021. 11 | ; 12 | 13 | cpu 8086 14 | 15 | %ifdef com_file 16 | org 0x0100s 17 | %else 18 | org 0x7c00 19 | %endif 20 | 21 | ; 22 | ; Start of the program 23 | ; 24 | start: 25 | mov ax,0x0013 ; Graphics mode 320x200x256 colors 26 | int 0x10 ; Setup video mode 27 | mov ax,0xa000 ; Point to video memory 28 | mov ds,ax 29 | animate: 30 | mov cx,0x007f ; t = 127 (where pi * 2 is 128) 31 | main_loop: 32 | mov ax,cx ; sin(t) 33 | call get_sin 34 | mov bx,ax 35 | imul bx ; ^2 36 | call defrac 37 | imul bx ; ^3 38 | call defrac 39 | mov bx,40 ; Expand to fill screen horizontally 40 | imul bx 41 | call defrac 42 | add ax,160 ; Center horizontally 43 | push ax ; Save x-coord in stack. 44 | 45 | mov al,4 ; cos(4 * t) 46 | mul cl 47 | call get_cos 48 | push ax 49 | mov al,3 ; cos(3 * t) 50 | mul cl 51 | call get_cos 52 | shl ax,1 ; * 2 53 | push ax 54 | mov al,2 ; cos(2 * t) 55 | mul cl 56 | call get_cos 57 | mov bx,5 ; * 5 58 | imul bx 59 | push ax 60 | mov ax,cx 61 | call get_cos ; cos(t) * 13 62 | mov bx,13 63 | imul bx 64 | pop bx 65 | sub ax,bx ; 13*cos(t) - 5*cos(2*t) 66 | pop bx 67 | sub ax,bx ; 13*cos(t) - 5*cos(2*t) - 2*cos(3*t) 68 | pop bx 69 | sub ax,bx ; 13*cos(t) - 5*cos(2*t) - 2*cos(3*t) - cos(4*t) 70 | neg ax 71 | mov bx,3 ; Expand to fill screen vertically 72 | imul bx 73 | call defrac 74 | add ax,100 ; Center vertically 75 | mov bx,320 ; Get row pixel address 76 | mul bx 77 | pop bx 78 | add bx,ax ; Add column pixel address 79 | mov byte [bx],0x0c ; Paint a red pixel 80 | 81 | loop main_loop 82 | 83 | mov ah,0x00 ; Wait for a key 84 | int 0x16 85 | mov ax,0x0002 ; Restore text mode 86 | int 0x10 87 | int 0x20 ; Exit 88 | 89 | ; 90 | ; Remove fraction 91 | ; 92 | defrac: 93 | mov al,ah 94 | mov ah,dl 95 | ret 96 | 97 | ; 98 | ; Get cosine 99 | ; Input: al = angle (0-127) 100 | ; Output: ax = 8.8 fraction 101 | ; 102 | get_cos: 103 | add al,32 ; Add 90 degrees to get cosine 104 | ; 105 | ; Get sine 106 | ; Input: al = angle (0-127) 107 | ; Output: ax = 8.8 fraction 108 | ; 109 | get_sin: 110 | test al,64 ; Angle >= 180 degrees? 111 | pushf 112 | test al,32 ; Angle 90-179 or 270-359 degrees? 113 | je .2 114 | xor al,31 ; Invert bits (reduces table) 115 | .2: 116 | and ax,31 ; Only 90 degrees in table 117 | mov bx,sin_table 118 | cs xlat ; Get fraction 119 | popf 120 | je .1 ; Jump if angle less than 180 121 | neg ax ; Else negate result 122 | .1: 123 | ret 124 | 125 | ; 126 | ; Sine table (0.8 format) 127 | ; 128 | ; 32 bytes are 90 degrees. 129 | ; 130 | sin_table: 131 | db 0x00,0x09,0x16,0x24,0x31,0x3e,0x47,0x53 132 | db 0x60,0x6c,0x78,0x80,0x8b,0x96,0xa1,0xab 133 | db 0xb5,0xbb,0xc4,0xcc,0xd4,0xdb,0xe0,0xe6 134 | db 0xec,0xf1,0xf5,0xf7,0xfa,0xfd,0xff,0xff 135 | 136 | %ifdef com_file 137 | %else 138 | times 510-($-$$) db 0x4f 139 | db 0x55,0xaa ; Make it a bootable sector 140 | %endif 141 | -------------------------------------------------------------------------------- /software_src/init32: -------------------------------------------------------------------------------- 1 | [ORG 0x7c00] ; add to offsets 2 | 3 | start: 4 | xor ax, ax ; make it zero 5 | mov ds, ax ; DS=0 6 | mov ss, ax ; stack starts at seg 0 7 | mov sp, 0x7700 ; 7700h past code start, 8 | ; making the stack 7.5k in size 9 | cli ; no interrupts 10 | push ds ; save real mode 11 | 12 | lgdt [gdtinfo] ; load gdt register 13 | 14 | mov eax, cr0 ; switch to pmode by 15 | or al,1 ; set pmode bit 16 | mov cr0, eax 17 | 18 | jmp $+2 ; tell 386/486 to not crash 19 | 20 | mov bx, 0x08 ; select descriptor 1 21 | mov ds, bx ; 8h = 1000b 22 | 23 | mov cr0, eax 24 | jmp 0x8:pmode 25 | pmode: 26 | mov bx, 0x10 ; select descriptor 2, instead of 1 27 | mov ds, bx ; 10h = 10000b 28 | mov es, bx 29 | mov ss, bx 30 | mov fs, bx 31 | mov gs, bx 32 | 33 | and al,0xFE ; back to realmode 34 | mov cr0, eax ; by toggling bit again 35 | huge_unreal: 36 | sti 37 | int 0x20 38 | 39 | gdtinfo: 40 | dw gdt_end - gdt - 1 ;last byte in table 41 | dd gdt ;start of table 42 | 43 | gdt dd 0,0 ; entry 0 is always unused 44 | flatcode db 0xff, 0xff, 0, 0, 0, 10011010b, 10001111b, 0 45 | flatdata db 0xff, 0xff, 0, 0, 0, 10010010b, 11001111b, 0 46 | gdt_end: 47 | 48 | times 512-($-$$) db 0 ; fill sector w/ 0's 49 | -------------------------------------------------------------------------------- /software_src/install: -------------------------------------------------------------------------------- 1 | org 0x7c00 2 | install_command: 3 | mov al, "?" 4 | call input_line 5 | mov bx, si 6 | mov di, 0xa000 7 | int 0x23 8 | jc err 9 | cmp word [0xa1fe], 0xaa55 10 | jne err 11 | mov al, "@" 12 | call input_line 13 | call xdigit ; Get a hexadecimal digit 14 | mov cl,4 15 | shl al,cl 16 | xchg ax,cx 17 | call xdigit ; Get a hexadecimal digit 18 | or al,cl 19 | push ax 20 | xor ax, ax 21 | mov es, ax ; ES <- 0 22 | mov cx, 0x0001 23 | pop dx 24 | xor dh, dh 25 | mov bx, 0xa000; segment offset of the buffer 26 | mov ax, 0x0301; AH = 03 (disk write), AL = 01 (number of sectors to write) 27 | int 0x13 28 | jc err 29 | int 0x20 30 | err: 31 | mov al, 0x13 32 | int 0x22 33 | mov al, 0x0d 34 | int 0x22 35 | int 0x20 36 | xdigit: 37 | lodsb 38 | cmp al,0x00 ; Zero character marks end of line 39 | je r 40 | sub al,0x30 ; Avoid spaces (anything below ASCII 0x30) 41 | jc xdigit 42 | cmp al,0x0a 43 | jc r 44 | sub al,0x07 45 | and al,0x0f 46 | stc 47 | r: 48 | ret 49 | input_line: 50 | int 0x26 51 | ret 52 | -------------------------------------------------------------------------------- /software_src/lba: -------------------------------------------------------------------------------- 1 | org 0x7c00 2 | bits 16 3 | %include "../sysmap.inc" 4 | start: mov al, " " 5 | call fill 6 | mov al, 0x0a 7 | int 0x10 8 | mov al, "#" 9 | call fill 10 | int 0x26 11 | push cs 12 | pop ds 13 | 14 | call get_hex 15 | mov byte [bootOS.dap.lba_upper + 3], al 16 | call get_hex 17 | mov byte [bootOS.dap.lba_upper + 2], al 18 | call get_hex 19 | mov byte [bootOS.dap.lba_upper + 1], al 20 | call get_hex 21 | mov byte [bootOS.dap.lba_upper], al 22 | 23 | mov al, "@" 24 | call fill 25 | int 0x26 26 | 27 | call get_hex 28 | mov byte [bootOS.dap.lba_lower + 3], al 29 | call get_hex 30 | mov byte [bootOS.dap.lba_lower + 2], al 31 | call get_hex 32 | mov byte [bootOS.dap.lba_lower + 1], al 33 | call get_hex 34 | mov byte [bootOS.dap.lba_lower], al 35 | 36 | end: int 0x20 37 | 38 | get_hex: 39 | call bootOS.xdigit ; Get a hexadecimal digit 40 | shl al, 4 41 | xchg ax,cx 42 | call bootOS.xdigit ; Get a hexadecimal digit 43 | or al,cl 44 | ret 45 | 46 | fill: pusha 47 | mov ah, 0x0e 48 | mov bx, 0x0007 49 | int 0x10 50 | mov al, "-" 51 | mov cx, 8 52 | .loop: int 0x10 53 | loop .loop 54 | mov al, 0x0d 55 | int 0x10 56 | popa 57 | ret 58 | -------------------------------------------------------------------------------- /software_src/lights: -------------------------------------------------------------------------------- 1 | ; 2 | ; Follow the lights 3 | ; 4 | ; by Oscar Toledo G. 5 | ; 6 | ; Creation date: Jan/16/2020. 7 | ; Revision date: Jan/17/2020. 8 | ; Added victory tune after 31 good lights. 9 | ; 10 | 11 | ; 12 | ; Very useful info gathered from: 13 | ; https://www.waitingforfriday.com/?p=586 14 | ; 15 | cpu 8086 16 | 17 | %ifdef com_file 18 | org 0x0100 19 | %else 20 | org 0x7c00 21 | %endif 22 | 23 | old_time: equ 0x00 ; Old ticks 24 | button: equ 0x02 ; Button pressed 25 | next_seq: equ 0x04 ; Next seq. number 26 | timing: equ 0x06 ; Current timing 27 | memory: equ 0x08 ; Start of memory 28 | memory_end: equ 0xff ; End of memory 29 | 30 | start: 31 | xor ax,ax 32 | mov cx,memory_end/2 33 | .0: 34 | push ax ; Zero word initialize 35 | loop .0 ; Repeat until completed 36 | 37 | mov al,0x02 ; Text mode 80x25 38 | int 0x10 ; Set up video mode 39 | 40 | mov bp,sp ; Setup BP (Base Pointer) 41 | 42 | in al,0x40 ; Get a pseudorandom number 43 | xchg ax,si ; Put into SI 44 | 45 | cld ; Clear Direction flag. 46 | mov ax,0xb800 ; Point to video segment 47 | mov ds,ax 48 | mov es,ax 49 | 50 | call show_buttons ; Show buttons 51 | restart_game: 52 | xor ax,ax ; Restart sequence 53 | mov [bp+next_seq],ax 54 | game_loop: 55 | mov cl,15 ; Wait 0.8 seconds. 56 | call wait_ticks 57 | 58 | ; 59 | ; Add a new light to sequence 60 | ; 61 | mov di,[bp+next_seq] ; Curr. position. 62 | 63 | mov ax,97 ; Generate random number 64 | mul si 65 | add ax,23 66 | xchg ax,si ; SI = next seed. 67 | 68 | ; Notice it uses the 69 | ; high byte because the 70 | ; random period is 71 | ; longer. 72 | 73 | and ah,0x03 ; Extract random from AH 74 | add ah,0x31 ; Add ASCII 1 75 | mov [bp+di+memory],ah ; Save into memory 76 | 77 | mov ax,8 ; 8 approx 0.42 secs. 78 | cmp di,5 ; For 5 or fewer lights. 79 | jb .2 80 | mov al,6 ; 6 approx 0.32 secs. 81 | cmp di,13 ; For 13 or fewer lights. 82 | jb .2 83 | mov al,4 ; 4 approx 0.22 secs. 84 | .2: 85 | mov [bp+timing],ax 86 | cmp di,31 ; Doing the 31st light? 87 | je victory ; Yes, jump to victory. 88 | inc byte [bp+next_seq] 89 | 90 | ; 91 | ; Show current sequence 92 | ; 93 | xor di,di ; Restart counter 94 | .1: mov al,[bp+di+memory] ; Read light 95 | push di 96 | mov [bp+button],al ; Push button 97 | call show_buttons ; Show 98 | mov cx,[bp+timing] ; Wait 99 | call wait_ticks 100 | call speaker_off ; Turn off 101 | 102 | mov byte [bp+button],0 103 | call show_buttons ; Depress button 104 | call wait_tick 105 | pop di 106 | inc di ; Increase counter 107 | cmp di,[bp+next_seq] 108 | jne .1 109 | 110 | ; 111 | ; Empty keyboard buffer 112 | ; 113 | .9: 114 | mov ah,0x01 ; Check for key pressed. 115 | int 0x16 116 | je .8 ; No, jump. 117 | mov ah,0x00 ; Read key. 118 | int 0x16 119 | jmp .9 ; Repeat loop 120 | .8: 121 | ; 122 | ; Comparison of player input with 123 | ; sequence. 124 | ; 125 | xor di,di ; Restart counter 126 | .4: mov ah,0x00 ; Wait for a key 127 | int 0x16 128 | cmp al,0x1b ; Esc pressed? 129 | je exit_game ; Yes, jump. 130 | cmp al,0x31 ; Less than ASCII 1? 131 | jb .4 ; Yes, jump. 132 | cmp al,0x35 ; Higher than ASCII 4? 133 | jnb .4 ; Yes, jump. 134 | push ax 135 | push di 136 | mov [bp+button],al ; Push button 137 | call show_buttons ; Show 138 | mov cx,[bp+timing] ; Wait 139 | call wait_ticks 140 | call speaker_off ; Turn off 141 | 142 | mov byte [bp+button],0 143 | call show_buttons ; Depress button 144 | call wait_tick 145 | pop di 146 | pop ax 147 | cmp al,[bp+di+memory] ; Good hit? 148 | jne wrong ; No, jump 149 | 150 | inc di ; Increase counter 151 | cmp di,[bp+next_seq] 152 | jne .4 153 | jmp game_loop 154 | 155 | ; 156 | ; Player defeat by wrong button 157 | ; 158 | wrong: mov cx,28409 ; 1193180 / 42 159 | call speaker ; Failure tone 160 | mov cl,27 ; 1.5 secs 161 | call wait_ticks 162 | call speaker_off ; Turn off 163 | mov cl,27 ; 1.5 secs 164 | call wait_ticks 165 | jmp exit_game 166 | 167 | ; 168 | ; Victory 169 | ; 170 | victory: 171 | mov al,'2' ; Victory tune 172 | mov cx,14 ; 14 notes 173 | .1: push cx 174 | push ax 175 | mov byte [bp+button],al 176 | call show_buttons ; Play 177 | mov cl,2 ; Wait 0.1 secs. 178 | call wait_ticks 179 | mov byte [bp+button],0 ; Depress 180 | call show_buttons 181 | pop ax 182 | inc ax ; Next note 183 | cmp al,'5' ; If goes to 5... 184 | jne .2 185 | mov al,'1' ; ...go back to 1. 186 | .2: 187 | pop cx 188 | loop .1 189 | jmp wrong ; Finish and restart 190 | 191 | ; 192 | ; Exit game 193 | ; 194 | exit_game: 195 | mov ax,0x0002 ; Clear screen by... 196 | int 0x10 ; ...mode setup. 197 | int 0x20 ; Exit to DOS / bootOS. 198 | 199 | ; 200 | ; Show game buttons 201 | ; 202 | show_buttons: 203 | mov di,0x0166 ; Top left on screen 204 | mov bx,0x312f ; ASCII 1, white on green 205 | mov cx,2873 ; 1193180 / 415.305 hz 206 | call show_button 207 | 208 | mov di,0x0192 ; Top right on screen 209 | mov bx,0x324f ; ASCII 2, white on red 210 | mov cx,3835 ; 1193180 / 311.127 hz 211 | call show_button 212 | 213 | mov di,0x0846 ; Bottom left on screen 214 | mov bx,0x336f ; ASCII 3, white on brown 215 | mov cx,4812 ; 1193180 / 247.942 hz 216 | call show_button 217 | 218 | mov di,0x0872 ; Bottom right on screen 219 | mov bx,0x343f ; ASCII 4, white on turquoise 220 | mov cx,5746 ; 1193180 / 207.652 hz 221 | 222 | ; Fall-through 223 | 224 | show_button: 225 | mov al,0x20 ; Fill with spaces 226 | cmp bh,[bp+button] ; Is it pressed? 227 | jne .0 ; No, jump. 228 | call speaker ; Yes, play sound. 229 | mov al,0xb0 ; Semi-filled block 230 | .0: 231 | mov cx,10 ; 10 rows high. 232 | .1: push cx 233 | mov ah,bl ; Set attribute byte. 234 | mov cl,20 ; 20 columns width. 235 | rep stosw ; Fill on screen 236 | add di,160-20*2 ; Go to next row 237 | pop cx 238 | loop .1 ; Repeat until filled 239 | mov al,bh ; Get button number 240 | mov [di+20-5*160],ax ; Put on center 241 | ret ; Return 242 | 243 | ; 244 | ; Wait for one tick 245 | ; 246 | wait_tick: 247 | mov cl,1 248 | 249 | ; 250 | ; Wait for several ticks 251 | ; 252 | ; Input: 253 | ; CL = Number of ticks 254 | ; 255 | wait_ticks: 256 | mov ch,0 257 | .0: 258 | push cx ; Save counter 259 | .1: 260 | mov ah,0x00 ; Read ticks 261 | int 0x1a ; Call BIOS 262 | cmp dx,[bp+old_time] ; Wait for tick change 263 | je .1 264 | mov [bp+old_time],dx ; Save new tick 265 | pop cx ; Restore counter 266 | loop .0 ; Loop until complete 267 | ret ; Return 268 | 269 | ; 270 | ; Generate sound on PC speaker 271 | ; 272 | ; Input: 273 | ; CX = Frequency value. 274 | ; (calculate 1193180/freq = req. value) 275 | ; 276 | speaker: 277 | mov al,0xb6 ; Setup timer 2 278 | out 0x43,al 279 | mov al,cl ; Low byte of timer count 280 | out 0x42,al 281 | mov al,ch ; High byte of timer count 282 | out 0x42,al 283 | in al,0x61 284 | or al,0x03 ; Wire PC speaker to timer 2 285 | out 0x61,al 286 | ret 287 | 288 | ; 289 | ; Turn speaker off 290 | ; 291 | speaker_off: 292 | in al,0x61 293 | and al,0xfc ; Turn off 294 | out 0x61,al 295 | ret 296 | 297 | ; 298 | ; Boot sector signature 299 | ; 300 | %ifdef com_file 301 | %else 302 | times 510-($-$$) db 0x4f 303 | db 0x55,0xaa ; Make it a bootable sector 304 | %endif 305 | 306 | -------------------------------------------------------------------------------- /software_src/loadb: -------------------------------------------------------------------------------- 1 | org 0x7c00 2 | cs_command: 3 | mov al, "?" 4 | call input_line 5 | mov bx, si 6 | mov di, 0x7f00 7 | int 0x23 8 | jc err 9 | mov byte [0xfffc], 0x01 10 | int 0x20 11 | err: 12 | mov al, 0x13 13 | int 0x22 14 | int 0x20 15 | input_line: 16 | int 0x26 17 | ret 18 | -------------------------------------------------------------------------------- /software_src/mine: -------------------------------------------------------------------------------- 1 | ; From https://gitlab.com/blevy/boot-sector-minesweeper 2 | ; MIT license. 3 | ; Modified to exit to bootOS by nanochess (Sep/16/2019) 4 | 5 | BITS 16 6 | CPU 686 7 | 8 | ;; CONSTANTS 9 | 10 | ;; Boot sector load address 11 | %assign BootSector.Begin 0x7c00 12 | %assign BootSector.Size 512 13 | %assign BootSector.End BootSector.Begin + BootSector.Size 14 | 15 | %assign WordSize 2 16 | 17 | ;; Address and dimensions of text buffer 18 | %assign TextBuf.Seg 0xb800 19 | %assign TextBuf.Width 40 20 | %assign TextBuf.Height 25 21 | 22 | ;; Minefield dimensions 23 | %assign Map.Width TextBuf.Width 24 | %assign Map.Height TextBuf.Height 25 | %assign Map.Size Map.Width * Map.Height 26 | 27 | ;; Keyboard scan codes 28 | ;; http://www.ctyme.com/intr/rb-0045.htm#Table6 29 | %assign Key.Space 0x39 30 | %assign Key.Up 0x48 31 | %assign Key.Down 0x50 32 | %assign Key.Left 0x4b 33 | %assign Key.Right 0x4d 34 | 35 | ;; GLOBAL VARIABLES 36 | 37 | ;; TODO: Change global vars to a state struct 38 | 39 | ;; Global variables are stored after the boot sector at runtime. After the boot 40 | ;; sector, there is 480.5K of memory safe to use. 41 | ;; https://wiki.osdev.org/Memory_Map_(x86)#Overview 42 | 43 | %assign Vars.Begin BootSector.End 44 | 45 | ;; TODO: Document these 46 | %assign Map.Mines Vars.Begin 47 | %assign Map.Unveiled Map.Mines + Map.Size 48 | 49 | ;; Distance between Map.Mines and Map.Unveiled 50 | %assign Map.Mines.ToUnveiled (Map.Unveiled - Map.Mines) 51 | 52 | ;; Seed used for random number generation 53 | %assign RandomSeed Map.Unveiled + Map.Size 54 | 55 | %assign Vars.End RandomSeed + WordSize 56 | 57 | %assign Vars.Size Vars.End - Vars.Begin 58 | 59 | org BootSector.Begin 60 | 61 | BootMine: 62 | ; VGA text mode 0x00 63 | ; 320x200 pixel resolution 64 | ; 40x25 text resolution 65 | ; 16 colors 66 | ; http://www.ctyme.com/intr/rb-0069.htm 67 | xor ax, ax 68 | int 0x10 69 | 70 | ;; Populate Map.Mines with mines 71 | PopulateMines: 72 | mov di, Map.Mines 73 | mov cx, Map.Size 74 | .Loop: 75 | ; ax = rdtsc() & 0b111 ? 0 : 1 76 | rdtsc 77 | test al, 0x07 78 | jz .Mine 79 | .Empty: 80 | xor ax, ax 81 | jmp .WriteCell 82 | .Mine: 83 | mov ax, 1 84 | .WriteCell: 85 | stosb 86 | loop .Loop 87 | 88 | ;; Number empty cells with amount of neighboring mines 89 | NumCells: 90 | mov di, Map.Unveiled 91 | mov cx, Map.Size 92 | .Loop: 93 | ; Get digit for the cell at DI 94 | mov al, [di - Map.Mines.ToUnveiled] 95 | test ax, ax 96 | jz .Empty 97 | .Mine: 98 | mov ax, '*' 99 | jmp .WriteCell 100 | .Empty: 101 | mov ax, '0' 102 | 103 | ; Straight 104 | lea bx, [di - 1 - Map.Mines.ToUnveiled] 105 | call LeftIncIfMineAtCell 106 | lea bx, [di + 1 - Map.Mines.ToUnveiled] 107 | call RightIncIfMineAtCell 108 | lea bx, [di - Map.Width - Map.Mines.ToUnveiled] 109 | call IncIfMineAtCell 110 | lea bx, [di + Map.Width - Map.Mines.ToUnveiled] 111 | call IncIfMineAtCell 112 | 113 | ; Diagonal 114 | lea bx, [di - 1 - Map.Width - Map.Mines.ToUnveiled] 115 | call LeftIncIfMineAtCell 116 | lea bx, [di - 1 + Map.Width - Map.Mines.ToUnveiled] 117 | call LeftIncIfMineAtCell 118 | lea bx, [di + 1 - Map.Width - Map.Mines.ToUnveiled] 119 | call RightIncIfMineAtCell 120 | lea bx, [di + 1 + Map.Width - Map.Mines.ToUnveiled] 121 | call RightIncIfMineAtCell 122 | 123 | cmp ax, '0' 124 | jne .WriteCell 125 | .Zero: 126 | mov ax, ' ' 127 | .WriteCell: 128 | stosb 129 | loop .Loop 130 | 131 | ClearScreen: 132 | mov cx, Map.Size 133 | xor di, di 134 | mov ax, 0xa0 << 8 | '.' 135 | mov dx, TextBuf.Seg 136 | mov es, dx 137 | .Loop: 138 | stosw 139 | loop .Loop 140 | 141 | xor dx, dx 142 | mov es, dx 143 | xor bp, bp 144 | 145 | GameLoop: 146 | ; Get keystroke 147 | ; AH = BIOS scan code 148 | ; AL = ASCII character 149 | ; http://www.ctyme.com/intr/rb-1754.htm 150 | xor ax, ax 151 | int 0x16 152 | 153 | .CmpUp: 154 | cmp ah, Key.Up 155 | jne .CmpDown 156 | sub bp, Map.Width 157 | jmp WrapCursor 158 | .CmpDown: 159 | cmp ah, Key.Down 160 | jne .CmpLeft 161 | add bp, Map.Width 162 | jmp WrapCursor 163 | .CmpLeft: 164 | cmp ah, Key.Left 165 | jne .CmpRight 166 | dec bp 167 | jmp WrapCursor 168 | .CmpRight: 169 | cmp ah, Key.Right 170 | jne .CmpSpace 171 | inc bp 172 | jmp WrapCursor 173 | .CmpSpace: 174 | cmp ah, Key.Space 175 | jne GameLoop 176 | 177 | ClearCell: 178 | mov al, [bp + Map.Unveiled] 179 | .CmpEmpty: 180 | cmp al, ' ' 181 | jne .CmpMine 182 | call Flood 183 | jmp GameLoop 184 | .CmpMine: 185 | cmp al, '*' 186 | jne .Digit 187 | jmp GameOver 188 | .Digit: 189 | call TextBufSetCharAt 190 | 191 | WrapCursor: 192 | cmp bp, Map.Size 193 | jb SetCursorPos 194 | xor bp, bp 195 | 196 | SetCursorPos: 197 | xor bx, bx 198 | call GetCursorPos 199 | mov dh, al 200 | mov dl, ah 201 | ; Set cursor position 202 | ; DH = Row 203 | ; DL = Column 204 | ; http://www.ctyme.com/intr/rb-0087.htm 205 | mov ah, 0x02 206 | int 0x10 207 | 208 | jmp GameLoop 209 | 210 | ;; Split the linear cursor position in BP as COL:ROW in AH:AL 211 | ;; 212 | ;; Clobbered registers: 213 | ;; * CL 214 | GetCursorPos: 215 | mov ax, bp 216 | mov cl, Map.Width 217 | div cl 218 | ret 219 | 220 | ;; TODO: Use this method in more places 221 | ;; 222 | ;; Get the character at position BP in the text buffer in AL 223 | ;; 224 | ;; Clobbered registers: 225 | ;; * DX 226 | TextBufGetCharAt: 227 | push bp 228 | mov dx, TextBuf.Seg 229 | mov ds, dx 230 | add bp, bp 231 | mov al, [ds:bp] 232 | xor dx, dx 233 | mov ds, dx 234 | pop bp 235 | ret 236 | 237 | ;; TODO: Use this method in more places 238 | ;; 239 | ;; Put the character AL in the text buffer at position BP 240 | ;; 241 | ;; Clobbered registers: 242 | ;; * DX 243 | TextBufSetCharAt: 244 | push bp 245 | mov dx, TextBuf.Seg 246 | mov ds, dx 247 | add bp, bp 248 | mov [ds:bp], al 249 | xor dx, dx 250 | mov ds, dx 251 | pop bp 252 | ret 253 | 254 | RightIncIfMineAtCell: 255 | push bx 256 | push ax 257 | push dx 258 | sub bx, Map.Mines 259 | mov ax, bx 260 | cwd 261 | mov bx, Map.Width 262 | idiv bx 263 | test dx, dx 264 | pop dx 265 | pop ax 266 | pop bx 267 | jz IncIfMineAtCell.RetZero 268 | jmp IncIfMineAtCell 269 | 270 | LeftIncIfMineAtCell: 271 | push bx 272 | push ax 273 | push dx 274 | sub bx, Map.Mines 275 | mov ax, bx 276 | cwd 277 | mov bx, Map.Width 278 | idiv bx 279 | cmp dx, Map.Width - 1 280 | pop dx 281 | pop ax 282 | pop bx 283 | je IncIfMineAtCell.RetZero 284 | ;; TODO: Update comment 285 | ;; 286 | ;; Increment AX if there is a mine in Map.Mines at index BX, where BX is a 287 | ;; pointer inside Map.Mines. In the case where BX is outside Map.Mines, AX is 288 | ;; NOT incremented. 289 | ;; 290 | ;; Parameters 291 | ;; * BX - Pointer inside Map.Mines 292 | ;; Clobbered registers 293 | ;; * AX - either incremented or unchanged, depending on whether there is or 294 | ;; isn't a mine at BX, respectively 295 | IncIfMineAtCell: 296 | ; Bounds check 297 | cmp bx, Map.Mines 298 | jb .RetZero 299 | cmp bx, Map.Mines + Map.Size 300 | jae .RetZero 301 | ; Within map bounds. Dereference and add map pointer. 302 | add al, [bx] 303 | ret 304 | .RetZero: 305 | ; Outside map bounds. Do not increment. 306 | ret 307 | 308 | ;; Flood fill empty cells 309 | ;; 310 | ;; Parameters: 311 | ;; * BP - Cell index 312 | ;; Clobbered registers: 313 | ;; * Yes [TODO] 314 | Flood: 315 | push bp 316 | 317 | ; Base case: bounds check 318 | cmp bp, Map.Size 319 | jae .Ret 320 | 321 | ; Base case: visited cell 322 | call TextBufGetCharAt 323 | cmp al, '.' 324 | jne .Ret 325 | 326 | ; Body: unveil cell 327 | mov al, [bp + Map.Unveiled] 328 | call TextBufSetCharAt 329 | 330 | ; Base case: nonempty cell 331 | cmp al, ' ' 332 | jne .Ret 333 | 334 | ; Recursive case: flood adjacent cells 335 | 336 | ; Flood up 337 | push bp 338 | sub bp, Map.Width 339 | call Flood 340 | pop bp 341 | 342 | ; Flood down 343 | push bp 344 | add bp, Map.Width 345 | call Flood 346 | pop bp 347 | 348 | ; Flood left 349 | call GetCursorPos 350 | test ah, ah 351 | jz .Right 352 | push bp 353 | dec bp 354 | call Flood 355 | pop bp 356 | 357 | .Right: 358 | ; Flood right 359 | inc bp 360 | call GetCursorPos 361 | test ah, ah 362 | jz .Ret 363 | call Flood 364 | 365 | .Ret: 366 | pop bp 367 | ret 368 | 369 | GameOverStr: 370 | db 'GAME OVER' 371 | %assign GameOverStr.Len $ - GameOverStr 372 | 373 | ;; Unveil all the mines, print "GAME OVER" text, and allow restarting 374 | ;; TODO: Finish this 375 | GameOver: 376 | ; Print "GAME OVER" in center of screen 377 | mov ax, 0x1300 378 | mov bx, 0x00c0 379 | mov cx, GameOverStr.Len 380 | mov dx, ((TextBuf.Height / 2) << 8) | (TextBuf.Width / 2 - GameOverStr.Len / 2) 381 | mov bp, GameOverStr 382 | int 0x10 383 | 384 | ; Halt forever 385 | mov ah, 0x00 386 | int 0x16 387 | mov ax, 0x0002 388 | int 0x10 389 | int 0x20 390 | 391 | ;; Print program size at build time 392 | %assign CodeSize $ - $$ 393 | ;%warning Code is CodeSize bytes 394 | 395 | CodeEnd: 396 | ; Pad to size of boot sector, minus the size of a word for the boot sector 397 | ; magic value. If the code is too big to fit in a boot sector, the `times` 398 | ; directive uses a negative value, causing a build error. 399 | times (BootSector.Size - WordSize) - CodeSize db 0 400 | 401 | ; Boot sector magic 402 | dw 0xaa55 403 | 404 | ;; Boot sector ends here 405 | -------------------------------------------------------------------------------- /software_src/multitd: -------------------------------------------------------------------------------- 1 | org 0x7c00 2 | bits 16 3 | 4 | target: equ 0x08 5 | backup: equ 0xff 6 | stack: equ 0x8000 7 | 8 | 9 | setup_sched: 10 | push 0x0000 11 | pop es 12 | 13 | cli 14 | es mov ax, word [target * 4] 15 | es mov word [backup * 4], ax 16 | es mov ax, word [target * 4 + 2] 17 | es mov word [backup * 4 + 2], ax 18 | es mov word [target * 4], irq 19 | es mov word [target * 4 + 2], 0x0000 20 | 21 | mov al, 0b00110100 22 | out 0x43, al 23 | 24 | mov ax, 0x1000 25 | out 0x40, al 26 | mov al, ah 27 | out 0x40, al 28 | 29 | push cs 30 | pop es 31 | 32 | sti 33 | int 0x20 34 | 35 | irq: cli 36 | int backup 37 | jmp irq_save 38 | .s1: call sched 39 | jmp irq_load 40 | 41 | irq_save: 42 | ; structure: 43 | ; ss es ds regs ip cs flags 44 | ; = 14 bytes \ save 45 | pusha 46 | push ds 47 | push es 48 | push ss 49 | cs mov word [save_sp], sp 50 | cs mov word [save_ss], ss 51 | 52 | push 0x2000 53 | pop ss 54 | mov sp, stack 55 | push cs 56 | pop ds 57 | 58 | mov ax, [save_ss] 59 | push ax 60 | pop es 61 | mov si, word [save_sp] 62 | mov di, word [pid] 63 | shl di, 6 64 | push 0x3000 65 | pop ds 66 | push di 67 | 68 | mov cx, 32 69 | .loop: lodsb 70 | ds stosb 71 | loop .loop 72 | 73 | pop di 74 | cs mov ax, word [save_sp] 75 | mov word [di+32], ax 76 | cs mov ax, word [save_ss] 77 | mov word [di+34], ax 78 | 79 | push cs 80 | pop ds 81 | push cs 82 | pop es 83 | 84 | jmp irq.s1 85 | 86 | irq_load: 87 | mov si, word [pid] 88 | shl si, 6 89 | push 0x3000 90 | pop ds 91 | 92 | mov ax, word [si+32] 93 | cs mov word [save_sp], ax 94 | mov ax, word [si+34] 95 | cs mov word [save_ss], ax 96 | 97 | mov di, word [save_sp] 98 | mov ax, word [save_ss] 99 | push ax 100 | pop es 101 | 102 | mov cx, 32 103 | .loop: ds lodsb 104 | stosb 105 | loop .loop 106 | 107 | push cs 108 | pop ds 109 | 110 | mov sp, word [save_sp] 111 | mov ss, word [save_ss] 112 | 113 | pop ss 114 | pop es 115 | pop ds 116 | popa 117 | sti 118 | iret 119 | 120 | ; do your fancy stuff here 121 | sched: 122 | push 0x3000 123 | pop ds 124 | cs mov si, word [pid] 125 | shl si, 6 126 | .loop: mov al, byte [si+63] 127 | cmp al, 0 128 | je .found 129 | add si, 64 130 | jmp .loop 131 | .found: shr si, 6 132 | mov word [pid], si 133 | ret 134 | 135 | save_sp: 136 | dw 0 137 | save_ss: 138 | dw 0 139 | pid: 140 | dw 0 141 | -------------------------------------------------------------------------------- /software_src/pillman: -------------------------------------------------------------------------------- 1 | ; 2 | ; Pillman 3 | ; 4 | ; by Oscar Toledo G. 5 | ; http://nanochess.org/ 6 | ; 7 | ; (c) Copyright 2019 Oscar Toledo G. 8 | ; 9 | ; Creation date: Jun/11/2019. 10 | ; Revision date: Jun/12/2019. Draws level. 11 | ; Revision date: Jun/13/2019. Pillman can move. 12 | ; Revision date: Jun/14/2019. Now ghosts don't get stuck. Ghost are 13 | ; transparent. Pillman doesn't leave 14 | ; trash. 15 | ; Revision date: Jun/15/2019. Ghosts can catch pillman. Optimized. 16 | ; 509 bytes. 17 | ; Revision date: Jul/09/2019. Self-modifying code, move subroutine, 18 | ; cache routine address (Peter Ferrie). 19 | ; 504 bytes. 20 | ; Revision date: Jul/22/2019. Added Esc key to exit. 21 | ; 22 | 23 | cpu 8086 24 | 25 | %ifndef com_file ; If not defined create a boot sector 26 | com_file: equ 0 27 | %endif 28 | 29 | base: equ 0xf9fe ; Memory base (same segment as video) 30 | intended_dir: equ base+0x00 ; Next direction for player 31 | frame: equ base+0x01 ; Current video frame 32 | x_player: equ base+0x02 ; Saved X-coordinate of player 33 | y_player: equ ms6+0x01 ; Saved Y-coordinate of player 34 | old_time: equ base+0x06 ; Old time 35 | 36 | ; 37 | ; Maze should start at x,y coordinate multiple of 8 38 | ; 39 | BASE_MAZE: equ 16*X_OFFSET+32 40 | pos1: equ BASE_MAZE+21*8*X_OFFSET 41 | 42 | X_OFFSET: equ 0x0140 43 | 44 | MAZE_COLOR: equ 0x37 ; No color should be higher or equal value 45 | PILL_COLOR: equ 0x02 ; Color for pill 46 | PLAYER_COLOR: equ 0x0e ; Should be unique 47 | 48 | ; 49 | ; XOR combination of these plus PILL_COLOR shouldn't 50 | ; result in PLAYER_COLOR 51 | ; 52 | GHOST1_COLOR: equ 0x21 ; Ghost 1 color 53 | GHOST2_COLOR: equ 0x2e ; Ghost 2 color 54 | GHOST3_COLOR: equ 0x28 ; Ghost 3 color 55 | GHOST4_COLOR: equ 0x34 ; Ghost 4 color 56 | 57 | %if com_file 58 | org 0x0100 ; Start address for COM file 59 | %else 60 | org 0x7c00 ; Start address for boot sector 61 | %endif 62 | restart: 63 | mov ax,0x0013 ; Set mode 0x13 (320x200x256 VGA) 64 | int 0x10 ; Call BIOS 65 | cld 66 | mov ax,0xa000 ; Video segment 67 | mov ds,ax ; Use as source data segment 68 | mov es,ax ; Use as target data segment 69 | ; 70 | ; Draw the maze 71 | ; 72 | mov si,maze ; SI = Address of maze data 73 | mov di,BASE_MAZE ; DI = Address for drawing maze 74 | draw_maze_row: 75 | cs lodsw ; Load one word of data from Code Segment 76 | xchg ax,cx ; Put into AX 77 | mov bx,30*8 ; Offset of mirror position 78 | draw_maze_col: 79 | shl cx,1 ; Extract one tile of maze 80 | mov ax,MAZE_COLOR*0x0100+0x18 ; Carry = 0 = Wall 81 | jnc dm1 ; If bit was zero, jump to dm1 82 | mov ax,PILL_COLOR*0x0100+0x38 ; Carry = 1 = Pill 83 | dm1: call draw_sprite ; Draw tile 84 | add di,bx ; Go to mirror position 85 | sub bx,16 ; Mirror finished? 86 | jc dm2 ; Yes, jump 87 | call draw_sprite ; Draw tile 88 | sub di,bx ; Restore position 89 | sub di,8 ; Advance tile 90 | jmp draw_maze_col ; Repeat until finished 91 | 92 | ; 93 | ; Move ghost 94 | ; bh = color 95 | ; 96 | move_ghost: 97 | lodsw ; Load screen position 98 | xchg ax,di 99 | lodsw ; Load direction 100 | test ah,ah 101 | xchg ax,bx ; Color now in ah 102 | mov al,0x30 103 | push ax 104 | mov byte [si-1],0x02 ; Remove first time setup flag 105 | call move_sprite3 106 | pop ax 107 | ; 108 | ; Draw the sprite/tile 109 | ; 110 | ; ah = sprite color 111 | ; al = sprite (x8) 112 | ; di = Target address 113 | draw_sprite: 114 | push ax 115 | push bx 116 | push cx 117 | push di 118 | ds0: push ax 119 | mov bx,bitmaps-8 120 | cs xlat ; Extract one byte from bitmap 121 | xchg ax,bx 122 | mov cx,8 123 | ds1: mov al,bh 124 | shl bl,1 ; Extract one bit 125 | jc ds2 126 | xor ax,ax ; Background color 127 | ds2: 128 | cmp bh,0x10 ; Color < 0x10 129 | jc ds4 ; Yes, jump 130 | cmp byte [di],PLAYER_COLOR ; "Eats" player? 131 | je restart ; Yes, it should crash after several hundred games 132 | ds3: 133 | xor al,[di] ; XOR ghost again pixel 134 | ds4: 135 | stosb 136 | loop ds1 137 | add di,X_OFFSET-8 ; Go to next video line 138 | pop ax 139 | inc ax ; Next bitmap byte 140 | test al,7 ; Sprite complete? 141 | jne ds0 ; No, jump 142 | pop di 143 | pop cx 144 | pop bx 145 | pop ax 146 | ret 147 | 148 | dm2: 149 | add di,X_OFFSET*8-15*8 ; Go to next row 150 | cmp si,setup_data ; Maze completed? 151 | jne draw_maze_row ; No, jump 152 | 153 | ; 154 | ; Setup characters 155 | ; 156 | ; CX is zero at this point 157 | ; DI is equal to pos1 at this point 158 | ;mov di,pos1 159 | mov cl,5 ; 5 elements (player + ghosts) 160 | mov ax,2 ; Going to right 161 | dm3: 162 | cs movsw ; Copy position from Code Segment 163 | stosw ; Store desired direction 164 | loop dm3 ; Loop 165 | 166 | ; 167 | ; Main game loop 168 | ; 169 | game_loop: 170 | mov ah,0x00 171 | int 0x1a ; BIOS clock read 172 | cmp dx,[old_time] ; Wait for time change 173 | je game_loop 174 | mov [old_time],dx ; Save new time 175 | 176 | mov ah,0x01 ; BIOS Key available 177 | int 0x16 178 | mov ah,0x00 ; BIOS Read Key 179 | je no_key 180 | int 0x16 181 | no_key: 182 | mov al,ah 183 | cmp al,0x01 ; Esc key 184 | jne no_esc 185 | int 0x20 186 | no_esc: 187 | sub al,0x48 ; Code for arrow up? 188 | jc no_key2 ; Out of range, jump. 189 | cmp al,0x09 ; Farther than arrow down? 190 | jnc no_key2 ; Out of range, jump. 191 | mov bx,dirs 192 | cs xlat ; Translate direction to internal code 193 | mov [intended_dir],al ; Save as desired direction 194 | no_key2: 195 | mov si,pos1 ; SI points to data for player 196 | lodsw ; Load screen position 197 | xchg ax,di 198 | lodsw ; Load direction/type 199 | xchg ax,bx 200 | xor ax,ax ; Delete pillman 201 | call move_sprite2 ; Move 202 | xor byte [frame],0x80 ; Alternate frame 203 | mov ax,0x0e28 ; Closed mouth 204 | js close_mouth ; Jump if sign set. 205 | mov al,[pos1+2] ; Using current direction 206 | mov cl,3 ; Multiply by 8 207 | shl al,cl ; Show open mouth 208 | close_mouth: 209 | call draw_sprite ; Draw 210 | ; 211 | ; Move ghosts 212 | ; 213 | mov bp, move_ghost 214 | mov bh,GHOST1_COLOR 215 | call bp 216 | mov bh,GHOST2_COLOR 217 | call bp 218 | mov bh,GHOST3_COLOR 219 | call bp 220 | mov bh,GHOST4_COLOR 221 | call bp 222 | jmp game_loop 223 | 224 | ; 225 | ; DI = address on the screen 226 | ; BL = wanted direction 227 | ; 228 | move_sprite3: 229 | je move_sprite ; If zero, won't remove first time 230 | move_sprite2: 231 | call draw_sprite ; Remove ghost 232 | move_sprite: 233 | mov ax,di ; Prepare to extract pixel row/column 234 | xor dx,dx 235 | mov cx,X_OFFSET 236 | div cx 237 | ; Now AX = Row, DX = Column 238 | mov ah,dl 239 | or ah,al 240 | and ah,7 ; Both aligned at 8 pixels? 241 | jne ms0 ; No, jump because cannot change direction. 242 | ; AH is zero already 243 | ;mov ah,0 244 | ; 245 | ; Get available directions 246 | ; 247 | mov ch,MAZE_COLOR 248 | cmp [di-0x0001],ch ; Left 249 | adc ah,ah ; AH = 0000 000L 250 | cmp [di+X_OFFSET*8],ch ; Down 251 | adc ah,ah ; AH = 0000 00LD 252 | cmp [di+0x0008],ch ; Right 253 | adc ah,ah ; AH = 0000 0LDR 254 | cmp [di-X_OFFSET],ch ; Up 255 | adc ah,ah ; AH = 0000 LDRU 256 | 257 | test bh,bh ; Is it pillman? 258 | je ms4 ; Yes, jump 259 | 260 | ; 261 | ; Ghost 262 | ; 263 | test bl,0x05 ; Test BL for .... .D.U 264 | je ms6 ; No, jump 265 | ; Current direction is up/down 266 | cmp dx,[x_player] ; Compare X coordinate with player 267 | mov al,0x02 ; Go right 268 | jc ms8 ; Jump if X ghost < X player 269 | mov al,0x08 ; Go left 270 | jmp ms8 271 | 272 | ; Current direction is left/right 273 | ms6: cmp al,0x00 ; (SMC) Compare Y coordinate with player 274 | mov al,0x04 ; Go down 275 | jc ms8 ; Jump if Y ghost < Y player 276 | mov al,0x01 ; Go up 277 | ms8: 278 | test ah,al ; Can it go in intended direction? 279 | jne ms1 ; Yes, go in direction 280 | 281 | mov al,bl 282 | ms9: test ah,al ; Can it go in current direction? 283 | jne ms1 ; Yes, jump 284 | shr al,1 ; Try another direction 285 | jne ms9 286 | mov al,0x08 ; Cycle direction 287 | jmp ms9 288 | 289 | ; 290 | ; Pillman 291 | ; 292 | ms4: 293 | mov [x_player],dx ; Save current X coordinate 294 | cs mov [y_player],al ; Save current Y coordinate 295 | 296 | mov al,[intended_dir] 297 | test ah,al ; Can it go in intended direction? 298 | jne ms1 ; Yes, go in that direction 299 | 300 | ms5: and ah,bl ; Can it go in current direction? 301 | je ms2 ; No, stops 302 | 303 | ms0: mov al,bl 304 | 305 | ms1: mov [si-2],al ; Save new direction 306 | test al,5 ; If going up/down... 307 | mov bx,-X_OFFSET*2 ; ...bx = vertical movement 308 | jne ms3 309 | mov bx,1*2 ; ...bx = horizontal movement 310 | ms3: 311 | test al,12 312 | je ms7 313 | neg bx ; Reverse direction 314 | ms7: 315 | add di,bx ; Do move 316 | mov [si-4],di ; Save the new screen position 317 | ms2: 318 | ret 319 | 320 | ; 321 | ; Game bitmaps 322 | ; 323 | bitmaps: 324 | db 0x00,0x42,0xe7,0xe7,0xff,0xff,0x7e,0x3c ; dir = 1 325 | db 0x3c,0x7e,0xfc,0xf0,0xf0,0xfc,0x7e,0x3c ; dir = 2 326 | db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; Maze 327 | db 0x3c,0x7e,0xff,0xff,0xe7,0xe7,0x42,0x00 ; dir = 4 328 | db 0x3c,0x7e,0xff,0xff,0xff,0xff,0x7e,0x3c ; Closed mouth 329 | db 0x3c,0x7e,0xdb,0xdb,0xff,0xff,0xff,0xa5 ; Ghost 330 | db 0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00 ; Pill 331 | db 0x3c,0x7e,0x3f,0x0f,0x0f,0x3f,0x7e,0x3c ; dir = 8 332 | 333 | ; 334 | ; Maze shape 335 | ; 336 | maze: 337 | dw 0b0000_0000_0000_0000 338 | dw 0b0111_1111_1111_1110 339 | dw 0b0100_0010_0000_0010 340 | dw 0b0100_0010_0000_0010 341 | dw 0b0111_1111_1111_1111 342 | dw 0b0100_0010_0100_0000 343 | dw 0b0111_1110_0111_1110 344 | dw 0b0000_0010_0000_0010 345 | dw 0b0000_0010_0111_1111 346 | dw 0b0000_0011_1100_0000 347 | dw 0b0000_0010_0100_0000 348 | dw 0b0000_0010_0111_1111 349 | dw 0b0000_0010_0100_0000 350 | dw 0b0111_1111_1111_1110 351 | dw 0b0100_0010_0000_0010 352 | dw 0b0111_1011_1111_1111 353 | dw 0b0000_1010_0100_0000 354 | dw 0b0111_1110_0111_1110 355 | dw 0b0100_0000_0000_0010 356 | dw 0b0111_1111_1111_1111 357 | dw 0b0000_0000_0000_0000 358 | 359 | ; 360 | ; Starting positions 361 | ; 362 | setup_data: 363 | dw BASE_MAZE+0x78*X_OFFSET+0x78 364 | dw BASE_MAZE+0x30*X_OFFSET+0x70 365 | dw BASE_MAZE+0x40*X_OFFSET+0x78 366 | dw BASE_MAZE+0x20*X_OFFSET+0x80 367 | dw BASE_MAZE+0x30*X_OFFSET+0x88 368 | 369 | ; 370 | ; Convert arrow codes to internal directions 371 | ; 372 | dirs: 373 | db 0x01 ; 0x48 = Up arrow 374 | db 0x00 375 | db 0x00 376 | db 0x08 ; 0x4b = Left arrow 377 | db 0x00 378 | db 0x02 ; 0x4d = Right arrow 379 | db 0x00 380 | db 0x00 381 | db 0x04 ; 0x50 = Down arrow 382 | 383 | %if com_file 384 | %else 385 | times 510-($-$$) db 0x4f 386 | db 0x55,0xaa ; Make it a bootable sector 387 | %endif 388 | -------------------------------------------------------------------------------- /software_src/pull: -------------------------------------------------------------------------------- 1 | org 0x7c00 2 | cs_command: 3 | mov al, "?" 4 | call input_line 5 | mov bx, si 6 | mov di, 0xa000 7 | int 0x24 8 | jc err 9 | int 0x20 10 | err: 11 | mov al, 0x13 12 | int 0x22 13 | int 0x20 14 | input_line: 15 | int 0x26 16 | ret 17 | -------------------------------------------------------------------------------- /software_src/push: -------------------------------------------------------------------------------- 1 | org 0x7c00 2 | cs_command: 3 | mov al, "?" 4 | call input_line 5 | mov bx, si 6 | mov di, 0xa000 7 | int 0x23 8 | jc err 9 | int 0x20 10 | err: 11 | mov al, 0x13 12 | int 0x22 13 | int 0x20 14 | input_line: 15 | int 0x26 16 | ret 17 | -------------------------------------------------------------------------------- /software_src/qm: -------------------------------------------------------------------------------- 1 | org 0xb000 2 | bits 16 3 | 4 | start: mov si, 0x7c00 5 | mov di, 0xb000 6 | mov cx, 0x0200 7 | rep movsb 8 | 9 | push setup 10 | ret 11 | 12 | setup: mov si, splice 13 | mov di, bootOS.input_key 14 | mov cx, splice.end - splice 15 | rep movsb 16 | 17 | int 0x20 18 | 19 | hook: mov ah, 0x00 20 | int 0x16 21 | cmp ah, 0x48 22 | je down 23 | cmp ah, 0x50 24 | je up 25 | jmp bootOS.output_char 26 | up: add word [bootOS.dap.lba_lower + 1], 1 27 | adc word [bootOS.dap.lba_lower + 3], 0 28 | call update 29 | jmp hook 30 | down: sub word [bootOS.dap.lba_lower + 1], 1 31 | sbb word [bootOS.dap.lba_lower + 3], 0 32 | call update 33 | jmp hook 34 | update: pusha 35 | push es 36 | mov si, bootOS.dap.lba_lower + 1 37 | mov di, 0x009e 38 | push 0xb800 39 | pop es 40 | mov cx, 4 41 | mov bx, table 42 | loop: cs lodsb 43 | mov ah, al 44 | and al, 0x0f 45 | and ah, 0xf0 46 | shr ah, 4 47 | xlat 48 | std 49 | stosb 50 | cld 51 | dec di 52 | mov al, ah 53 | xlat 54 | std 55 | stosb 56 | cld 57 | dec di 58 | loop loop 59 | pop es 60 | popa 61 | ret 62 | 63 | splice: push hook 64 | ret 65 | .end: 66 | 67 | table: db "0123456789abcdef" -------------------------------------------------------------------------------- /software_src/reboot: -------------------------------------------------------------------------------- 1 | xor ax, ax 2 | mov ds, ax 3 | mov ax,0000 4 | mov [0472], ax 5 | jmp 0xFFFF:0000 6 | -------------------------------------------------------------------------------- /software_src/screensaver: -------------------------------------------------------------------------------- 1 | ;;;; phosphene 2 | ;;;; 3 | ;;;; fractal video feedback in the MBR 4 | ;;;; 5 | ;;;; by: keegan 6 | ;;;; greets: dei, mrule 7 | ;;;; 8 | ;;;; TO RUN: 9 | ;;;; nasm -f bin -o phosphene.mbr phosphene.asm 10 | ;;;; qemu -hda phosphene.mbr # or boot it for real 11 | 12 | 13 | ;;;; CONSTANTS 14 | 15 | ; MBR code runs in 16-bit mode at address 0x7C00 16 | bits 16 17 | org 0x7C00 18 | 19 | ; start of scratch ram 20 | ram_start equ 0x7E00 21 | 22 | ; address relative to ram_start where we 23 | ; store rendered text 24 | rendered_text equ 0x2000 25 | 26 | ; address of first element of stack, in ss 27 | stack_start equ 0x1000 28 | 29 | ; start of video RAM 30 | vram_start equ 0xA0000 31 | 32 | ; VGA palette registers 33 | vga_dac_addr equ 0x3C8 34 | 35 | ; VESA mode 101h: 640 x 480 x byte 36 | vesa_mode equ 0x101 37 | 38 | ; Feedback buffers: 39 | ; width : 512 pixels 40 | ; height: 3 segments of 128 pixels each 41 | ; 42 | ; The three segments: 43 | ; buffer A: 10000 20000 30000 44 | ; buffer B: 40000 50000 60000 45 | ; 46 | ; Use bit ops to find these from fs = 1000 or 4000 47 | width equ 512 48 | height equ 384 49 | 50 | ; viewport size = 2 log_2 e 51 | ; scale by the reciprocal 52 | height_scale equ height * 1000 / 2886 53 | width_scale equ width * 1000 / 2886 54 | 55 | ; text rendered in mode 13h 56 | text_width equ 64 57 | text_height equ 16 58 | text_num equ 2 59 | text_y equ 60 60 | text_x equ 192 61 | 62 | ; Color palette: 63 | ; Each channel is incremented at a different rate 64 | ; For stupid reasons, inc_red is rounded to a multiple of 4 65 | inc_red equ 4 ; u8 red increment per palette entry 66 | inc_green equ 5 ; u8 green " 67 | inc_blue equ 6 ; u8 blue " 68 | 69 | 70 | ;;;; GLOBAL VARIABLES 71 | ; ds, ss = scratch RAM 72 | ; fs = initial read segment per frame 73 | ; 74 | ; bp = frame counter 75 | ; si = 0 76 | 77 | 78 | ;;;; ENTRY POINT 79 | ; set up segments 80 | mov al, "?" 81 | int 0x26 82 | mov di, text 83 | mov cx, si 84 | sub cx, 0x7780 85 | rep movsb 86 | mov byte [di + 1], 0xaa 87 | xor ax, ax 88 | mov ds, ax 89 | mov es, ax 90 | 91 | ; set up stack 92 | mov ax, ram_start >> 4 93 | mov ss, ax 94 | mov sp, stack_start 95 | 96 | ; use mode 13h temporarily, for rendering text 97 | mov ax, 0x13 98 | int 0x10 99 | mov bx, 0x0F 100 | mov ah, 0x0E 101 | mov si, text 102 | load_text: 103 | lodsb 104 | int 0x10 105 | cmp al, 0xAA ; stop at end-of-MBR marker 106 | jne load_text 107 | 108 | ; save rendered text to RAM 109 | push ds 110 | push vram_start >> 4 111 | pop ds 112 | xor si, si 113 | mov di, ram_start + rendered_text 114 | mov cx, 320*text_num*text_height / 2 115 | rep movsw 116 | pop ds 117 | 118 | ; switch back to text mode 119 | ; going directly from 13h to 101h upsets 120 | ; some non-emulated hardware 121 | xor ax, ax 122 | int 0x10 123 | 124 | ; get info for VESA mode 101h 125 | mov ax, 0x4F01 126 | mov cx, vesa_mode 127 | push cx 128 | mov di, ram_start 129 | int 0x10 130 | 131 | ; enter the VESA mode 132 | mov ax, 0x4F02 133 | pop bx 134 | int 0x10 135 | 136 | ; compute 64 / window_granularity 137 | ; VESA call successful => ah = 0 138 | mov al, 64 139 | xor dx, dx 140 | div word [di+4] 141 | push ax ;; MUST BE BOTTOM PUSH 142 | 143 | ; set up a palette 144 | ; we assume the VESA mode has a VGA-compatible DAC 145 | mov dx, vga_dac_addr 146 | xor al, al 147 | out dx, al 148 | inc dx 149 | 150 | ; 6-bit RGB values in al, bh, ch 151 | ; cx used for termination too 152 | xor cx, cx 153 | palette: 154 | ; worth saving al due to short operands 155 | push ax 156 | out dx, al 157 | mov al, bh 158 | out dx, al 159 | mov al, ch 160 | out dx, al 161 | pop ax 162 | add al, inc_red >> 2 163 | add bx, inc_green << 6 164 | add cx, inc_blue << 6 165 | jnz palette 166 | 167 | ; initialize the FPU with some constants 168 | fninit 169 | mov word [di], height_scale 170 | fild word [di] 171 | mov byte [di], width_scale 172 | fild word [di] 173 | 174 | ; initialize frame counter and segments 175 | xor bp, bp 176 | 177 | ; select first buffer for reading 178 | push 0x1000 179 | pop fs 180 | 181 | 182 | ;;;; MAIN LOOP 183 | main_loop: 184 | ; restore clobbered ds 185 | push ss 186 | pop ds 187 | pusha 188 | mov ah, 0x01 189 | int 0x16 190 | jnz end 191 | popa 192 | 193 | 194 | ;;;; TEXT BLIT 195 | ; draw text into the read buffer 196 | mov ax, fs 197 | add ah, 0x10 198 | mov es, ax 199 | 200 | mov si, rendered_text 201 | test bp, 0x400 202 | jz text_first_message 203 | ; draw the second message sometimes 204 | add si, text_height * 320 205 | text_first_message: 206 | mov di, width * text_y + text_x 207 | text_blit: 208 | ; cx cleared by previous loop 209 | mov cl, text_width 210 | text_blit_row: 211 | lodsb 212 | add [es:di], al 213 | inc di 214 | loop text_blit_row 215 | add si, 320 - text_width 216 | add di, width - text_width 217 | cmp di, width * (text_y + text_height) 218 | jb text_blit 219 | 220 | 221 | ;;;; FEEDBACK 222 | xor si, si 223 | xor di, di 224 | 225 | ; initialize write segment register 226 | mov ax, fs 227 | xor ah, 0x50 228 | mov es, ax 229 | 230 | ; push frame count to the FPU stack and scale 231 | ; by width (arbitrary, convenient) 232 | mov [si], bp 233 | fild word [si] 234 | fdiv st1 235 | 236 | ; FPU stack: t h w 237 | 238 | fld st0 239 | fcos 240 | fxch 241 | fldl2e ; rel. period of k control pt. 242 | fmul 243 | fcos 244 | 245 | ; Move control point in a polar flower: 246 | ; j = cos(t) 247 | ; k = cos(log_2(e) * t) 248 | ; 249 | ; stack: j k h w 250 | 251 | ; offset control point to an interesting region 252 | ; center at (-ln(2) + 0i) 253 | ; flower radius 0.5 254 | fld1 255 | fadd st0 256 | fdiv st2, st0 257 | fdivp st1, st0 258 | fldln2 259 | fsubp st1, st0 260 | 261 | ; loop over pixels in the write buffer 262 | mov dx, height 263 | compute_row: 264 | mov cx, width 265 | compute_pix: 266 | 267 | pusha 268 | 269 | fldl2e ; used to offset viewport center to origin 270 | 271 | ; stack: o j k h w 272 | 273 | mov [si], dx 274 | fild word [si] 275 | fdiv st5 276 | fsub st1 277 | 278 | ; stack: y o j k h w 279 | 280 | mov [si], cx 281 | fild word [si] 282 | fdiv st5 283 | fsub st2 284 | 285 | ; stack: x y o j k h w 286 | 287 | fst st2 288 | fmul st2, st0 289 | fld st1 290 | fmul st0 291 | fsubp st3, st0 292 | 293 | ; stack: x y (x^2 - y^2) j k h w 294 | 295 | fmul 296 | fadd st0 297 | 298 | ; stack: 2xy (x^2 - y^2) j k h w 299 | 300 | fadd st3 301 | fld st2 302 | faddp st2, st0 303 | 304 | ; stack: 2xy+k (x^2 - y^2)+j j k h w 305 | 306 | fldl2e 307 | fadd st2, st0 308 | faddp st1, st0 309 | 310 | ; stack: (2xy + o) ((x^2 - y^2) + o) j k h w 311 | 312 | fmul st5 313 | fistp word [si] 314 | mov dx, [si] 315 | ; dx <- scaled (2xy + o) 316 | 317 | fmul st3 318 | fistp word [si] 319 | mov bx, [si] 320 | ; bx <- scaled ((x^2 - y^2) + o) 321 | 322 | 323 | ; wrap x coordinate 324 | and bh, 0x01 325 | 326 | ; default color for out-of-bounds pixels is 0 327 | ; al is 0 from earlier segment register load 328 | 329 | ; check bounds for y coordinate 330 | cmp dx, height 331 | jae compute_write 332 | 333 | ; extract segment from top 2 bits of y 334 | shl dx, 1 335 | shl dh, 4 336 | mov ax, fs 337 | add ah, dh 338 | mov gs, ax 339 | 340 | ; fetch at offset (y*width + x) 341 | ; width = 2**9, shifted 1 already 342 | xor dh, dh 343 | shl dx, 8 344 | add bx, dx 345 | mov al, [gs:bx] 346 | 347 | ; clamp color to avoid super blinky center regions 348 | cmp al, 0xF0 349 | jae compute_write 350 | 351 | ; color shift per map iteration, varying over time 352 | mov bx, bp 353 | and bh, 0x0F 354 | add al, bh 355 | 356 | compute_write: 357 | mov [es:di], al 358 | 359 | popa 360 | 361 | ; next column, output pixel 362 | inc di 363 | loop compute_pix 364 | 365 | ; advance write segment when di wraps 366 | test di, di 367 | jnz compute_no_seginc 368 | mov ax, es 369 | add ah, 0x10 370 | mov es, ax 371 | 372 | compute_no_seginc: 373 | ; next row 374 | dec dx 375 | jnz compute_row 376 | 377 | ; bump frame counter 378 | inc bp 379 | 380 | ; discard j, k from FPU stack 381 | fcompp 382 | 383 | 384 | ;;;; DRAW TO SCREEN 385 | ; swap feedback buffers 386 | mov ax, fs 387 | xor ah, 0x50 388 | mov fs, ax 389 | mov ds, ax 390 | 391 | ; access graphics memory through segment es 392 | push vram_start >> 4 393 | pop es 394 | 395 | ; reset our window into VRAM 396 | ; dx is 0 from earlier loop 397 | call setwin 398 | 399 | ; copy beginning of feedback buffer to 400 | ; center of screen 401 | xor si, si 402 | mov di, 48*640 + 64 403 | 404 | mov bx, height 405 | draw_row: 406 | mov cx, width 407 | draw_pix: 408 | movsb 409 | 410 | ; advance the graphics window by 64k when di wraps 411 | test di, di 412 | jnz draw_no_wininc 413 | add dl, [ss:stack_start-2] 414 | push bx 415 | call setwin 416 | pop bx 417 | 418 | draw_no_wininc: 419 | loop draw_pix 420 | 421 | ; end of row: 128 pixels of left/right border 422 | add di, 128 423 | dec bx 424 | 425 | ; advance read segment when !(row & 0x7F) 426 | test bl, 0x7F 427 | jnz draw_no_seginc 428 | mov ax, ds 429 | add ah, 0x10 430 | mov ds, ax 431 | xor si, si 432 | 433 | draw_no_seginc: 434 | test bx, bx 435 | jnz draw_row 436 | 437 | jmp main_loop 438 | 439 | 440 | setwin: 441 | ; call the VESA BIOS to set the VRAM window 442 | mov ax, 0x4F05 443 | xor bx, bx 444 | int 0x10 445 | ret 446 | 447 | end: 448 | xor ax, ax 449 | int 0x16 450 | mov ax,0x0003 ; Restore text mode 451 | int 0x10 452 | int 0x20 453 | 454 | text: 455 | db "1234" 456 | ;;;; PROGRAM END 457 | 458 | 459 | ; MBR required data 460 | padding: 461 | times 510 - ($-$$) db 0xff 462 | signature: 463 | db 0x55, 0xaa 464 | 465 | ; vim: ft=tasm 466 | -------------------------------------------------------------------------------- /software_src/slide: -------------------------------------------------------------------------------- 1 | ;15 Number Slider Game 2 | ; * Slide the numbers around until they are in order 3 | ; * This is boot sector ( <512 bytes) game 4 | ; * Controls to move are up/down/left/right 5 | ; * Any other key rescrambles numbers 6 | ; Some Fuckery: 7 | ; Polymorphic 8 | ; Abuse of "Call"/Ret 9 | ; * There are routines to move the tiles in the up/down/left/right direction, 10 | ; They are controlled by the user AND the scrambling routines. There is a 11 | ; 'valid' way to conditionally call and then return, but this requires a 12 | ; bit more space with all of the control/flow logic. I would rather just 13 | ; manually set the corresponding return points once, and then just do a 14 | ; bunch of conditional jumps, sort of evil, but less code. 15 | 16 | [ORG 0x7c00] 17 | LEFT EQU 75 18 | RIGHT EQU 77 19 | UP EQU 72 20 | DOWN EQU 80 21 | 22 | ;Init the environment 23 | xor ax, ax ; make it zero 24 | mov ds, ax ; DS=0 25 | mov ss, ax ; stack starts at 0 26 | mov sp, 0x9c00 ; 200h past code start 27 | mov ah, 0xb8 ; text video memory 28 | mov es, ax ; ES=0xB800 29 | mov al, 0x03 30 | int 0x10 31 | mov ah, 1 32 | mov ch, 0x26 33 | int 0x10 34 | ;Fill in all black 35 | mov cx, 0x07d0 ; whole screens worth 36 | cbw ; clear ax (black on black with null char) 37 | xor di, di ; first coordinate of video mem 38 | rep stosw ; push it to video memory 39 | 40 | mov bp, 0x9 ; blanklocation 41 | 42 | ; Evil? 43 | in al,(0x40) ; Get random 44 | cmp al, 0x10 ; 1 in 16 chance it will be evil 45 | ja draw_border ; If above, then not evil 46 | ; Evil (Descending solvability) 47 | mov ax, [boarddata] ; Get first and second board number 48 | xchg ah,al ; And then swap them 49 | mov [boarddata], ax ; (now evil, can't solve in ascending order) 50 | mov byte [border + 1], 0xcc ; Change border color to light red 51 | mov byte [tile1 + 2], 0x48 ; Change tile border to shaded red 52 | mov byte [tile2 + 1], 0x44 ; Change tile to red 53 | mov byte [number_color + 1], 0x40 ; Change number to black on red 54 | 55 | ;draw border 56 | draw_border: 57 | mov di, 1 * 160 + 44 ; corner to start on 58 | border: mov ah, 0xff ; white 59 | mov bx, 22 ; rows 60 | mov byte [rectrow + 1], 30 ; columns 61 | mov byte [nextline + 2], 0x64 ; value to get to next line 62 | call drawrect 63 | 64 | ; Scramble 65 | mov cl, 0xff ; Init to 255 rounds of movement 66 | scramble: 67 | dec cx 68 | je gameloop ; Once done, go to main game loop 69 | in al,(0x40) ; Get 'random' value 70 | and al, 3 ; Only preserve last 2 bits (for 4 possible up/down/left/right moves) 71 | push word scramble ; point of return instead of using call for the below jumps 72 | ; Do a random tile move based on random results 73 | ; cmp al, 0 ; and al,3 already did this comparison 74 | je up 75 | cmp al, 1 76 | je down 77 | cmp al, 2 78 | je left 79 | cmp al, 3 80 | je right 81 | 82 | ; The Main Game Loop 83 | gameloop: 84 | call drawboard ; Draw the blank tiles of the board 85 | waitkey: 86 | call displaytiles ; Put the actual (hex) numbers into the tiles 87 | mov ah, 1 ; Is there a key 88 | int 0x16 ; "" 89 | jz waitkey ; If not wait for a key 90 | cbw ; clear ax (Get the key) 91 | int 0x16 ; "" 92 | push word gameloop ; point of return instead of using call 93 | ; Get the Keys 94 | cmp ah, UP 95 | je up 96 | cmp ah, DOWN 97 | je down 98 | cmp ah, LEFT 99 | je left 100 | cmp ah, RIGHT 101 | je right 102 | cmp ah, 0x01 103 | je exit 104 | int 0x19 ; A non-directional key was pressed (reboot/rescramble) 105 | exit: 106 | mov ax,0x0002 ; Clear screen 107 | int 0x10 108 | int 0x20 ; Return to bootOS 109 | up: 110 | mov bx, bp ; get blank tile location 111 | cmp bx, 0xb ; Out of bounds? 112 | ja keysdone ; Then return (don't move anything) 113 | add bx, 4 ; get location above it 114 | mov al, [boarddata + bx] ; get value above it 115 | mov byte [boarddata + bx], 0 ; make it the new blank 116 | mov bp, bx ; update blank location 117 | sub bx, 4 ; revert to old blank location 118 | mov [boarddata + bx], al ; put new value in 119 | ret 120 | down: 121 | mov bx, bp ; get blank tile location 122 | cmp bx, 4 ; Out of bounds? 123 | jb keysdone ; Then return (don't move anything) 124 | sub bx, 4 ; get location above it 125 | mov al, [boarddata + bx] ; get value above it 126 | mov byte [boarddata + bx], 0 ; make it the new blank 127 | mov bp, bx ; update blank location 128 | add bx, 4 ; revert to old blank location 129 | mov [boarddata + bx], al ; put new value in 130 | ret 131 | left: 132 | mov bx, bp ; get blank tile location 133 | cmp bl, 3 ; All the way to the left? 134 | je keysdone ; return without moving anything 135 | cmp bl, 7 ; "" 136 | je keysdone ; "" 137 | cmp bl, 11 ; "" 138 | je keysdone ; "" 139 | cmp bl, 15 ; "" 140 | je keysdone ; "" 141 | add bl, 1 ; get location above it 142 | mov al, [boarddata + bx] ; get value above it 143 | mov byte [boarddata + bx], 0 ; make it the new blank 144 | mov bp, bx ; update blank location 145 | sub bl, 1 ; revert to old blank location 146 | mov [boarddata + bx], al ; put new value in 147 | ret 148 | right: 149 | mov bx, bp ; get blank tile location 150 | ; Test Right edge, this is aligned with positions 0, 4, 8, and 12. 151 | ; In binary, these are the only positions where the least significant 152 | ; bits are always 0, so the below instructions tests for this quality 153 | test bl, 0x1 ; is the last bit a 1 154 | jne right_cont ; if not (0), continue with movement 155 | test bl, 0x2 ; is the next bit a 1 156 | je keysdone ; if so, don't move anything ... somehow this is the right logic 157 | right_cont: 158 | sub bl, 1 ; get location above it 159 | mov al, [boarddata + bx] ; get value above it 160 | mov byte [boarddata + bx], 0 ; make it the new blank 161 | mov bp, bx ; update blank location 162 | add bl, 1 ; revert to old blank location 163 | mov [boarddata + bx], al ; put new value in 164 | ret 165 | keysdone: 166 | ret 167 | 168 | displaytiles: 169 | ; This is a routine for displaying all of the tiles 170 | xor bx, bx 171 | mov di, 4 * 160 + 52 ; Position of top-left tile 172 | displaytilesloop: 173 | number_color: mov ah, 0x30 ; Black on light-blue background 174 | mov al, byte [boarddata + bx] ; current number value in boarddata structure 175 | inc bx ; next tile digit for next iteration 176 | add al, 0x30 ; 'Convert' to ASCII 177 | cmp al, 0x3A ; Is it above '9' 178 | jb number ; If its below (in range of number), skip adjustment 179 | add al, 7 ; Get it into the ASCII A-F range 180 | number: 181 | cmp al, 0x30 ; Check to see if it's 0 (our blank tile) 182 | jne next_a ; Keep processing if it's not 183 | call blanktile ; Otherwise, draw a blank (black) tile 184 | jmp next_b ; Skip over normal printing of number 185 | 186 | next_a: 187 | stosw ; Print the Number 188 | 189 | next_b: 190 | add di, 12 ; Go to the next column 191 | cmp bx, 4 ; Check if it's the last column 192 | je nextrow ; If so, do a row adjustment 193 | cmp bx, 8 ; "" 194 | je nextrow ; "" 195 | cmp bx, 12 ; "" 196 | jne norows ; "" 197 | nextrow: 198 | add di, 744 ; Coordinate adjustment for going to next row 199 | norows: 200 | cmp bx, 0x10 ; check to see if last tile has been printed 201 | jne displaytilesloop ; otherwise keep getting and printing them 202 | ret 203 | 204 | blanktile: 205 | ; A Blank Tile for the '0' tile 206 | push bx ; Don't pave over bx, as other routines us it 207 | sub di, 326 ; Adjust coord from middle to upper-left corner of tile 208 | cbw ; clear ax (black) 209 | mov bx, 5 ; rows 210 | mov byte [rectrow + 1], 7 ; columns 211 | mov byte [nextline + 2], 0x92 ; Value to get to next line 212 | call drawrect ; Draw the black rectangle 213 | sub di, 472 ; Restore coordinate to middle of tile 214 | pop bx ; Restore bx 215 | ret 216 | 217 | drawboard: 218 | ; This routine graphically draws the tiles (without the numbers) 219 | mov dx, 2 * 160 + 46 - 758 ; This is much before the start position, helps keep a tighter loop 220 | mov si, 4 ; 4 rows 221 | row: 222 | add dx, 758 ; Advance to next row 223 | call drawtile 224 | add dx, 14 ; next column 225 | call drawtile 226 | add dx, 14 227 | call drawtile 228 | add dx, 14 229 | call drawtile 230 | dec si 231 | jne row 232 | ret 233 | 234 | drawtile: 235 | ; Color 1 236 | mov di, dx 237 | tile1: mov ax, 0x13b1 ; shaded corner border 238 | mov bx, 5 ; rows 239 | mov byte [rectrow + 1], 7 ; columns 240 | mov byte [nextline + 2], 0x92 ; Value to get to next line 241 | call drawrect 242 | ; Color 2 243 | mov di, dx 244 | tile2: mov ah, 0x33 ; inner light blue main part of tile 245 | mov bx, 4 ; rows 246 | mov byte [rectrow + 1], 6 ; columns 247 | mov byte [nextline + 2], 0x94 ; Value to get to next line 248 | call drawrect 249 | ret 250 | 251 | drawrect: 252 | ; Draws rectangle 253 | rectrow: mov cx, 0 ; columns, self-modified by caller 254 | rep stosw 255 | ; add di, (next line value) (ammount self-modified by caller) 256 | nextline: db 0x81, 0xc7, 0x00, 0x00 257 | dec bx 258 | jne rectrow 259 | ret 260 | 261 | ; Data structure for ordered game 262 | boarddata: 263 | db 0x06, 0x0e, 0x04, 0x08, 0x05, 0x09, 0x0c, 0x0f, 0x02, 0x00, 0x0b, 0x03, 0x0d, 0x0a, 0x07, 0x01 264 | 265 | ;BIOS sig and padding 266 | times 510-($-$$) db 0 267 | dw 0xAA55 268 | -------------------------------------------------------------------------------- /software_src/snake: -------------------------------------------------------------------------------- 1 | ; From https://gitlab.com/pmikkelsen/asm_snake 2 | ; MIT License 3 | ; Modified to exit with Esc key to bootOS (nanochess, Sep/16/2019) 4 | 5 | mov ax, 0x07C0 6 | mov ds, ax ; set DS to the point where code is loaded 7 | mov ah, 0x01 8 | mov cx, 0x2000 9 | int 0x10 ; clear cursor blinking 10 | mov ax, 0x0305 11 | mov bx, 0x031F 12 | int 0x16 ; increase delay before keybort repeat 13 | 14 | game_loop: 15 | call clear_screen ; clear the screen 16 | push word [snake_pos] ; save snake head position for later 17 | mov ah, 0x01 ; check if key available 18 | int 0x16 19 | jz done_clear ; if not, move on 20 | mov ah, 0x00 ; if the was a key, remove it from buffer 21 | int 0x16 22 | jmp update_snakepos 23 | done_clear: 24 | mov al, [last_move] ; no keys, so we use the last one 25 | update_snakepos: 26 | cmp al, 0x1b ; Esc key 27 | jne no_exit 28 | int 0x20 29 | no_exit: 30 | cmp al, 'a' 31 | je left 32 | cmp al, 's' 33 | je down 34 | cmp al, 'd' 35 | je right 36 | cmp al, 'w' 37 | jne done_clear 38 | up: 39 | dec byte [snake_y_pos] 40 | jmp move_done ; jump away 41 | left: 42 | dec byte [snake_x_pos] 43 | jmp move_done ; jump away 44 | right: 45 | inc byte [snake_x_pos] 46 | jmp move_done ; jump away 47 | down: 48 | inc word [snake_y_pos] 49 | move_done: 50 | mov [last_move], al ; save the direction 51 | mov si, snake_body_pos ; prepare body shift 52 | pop ax ; restore read position into ax for body shift 53 | update_body: 54 | mov bx, [si] ; get element of body into bx 55 | test bx, bx ; check if zero (not a part of the body) 56 | jz done_update ; if zero, done. Otherwise 57 | mov [si], ax ; move the data from ax, into current position 58 | add si, 2 ; increment pointer by two bytes 59 | mov ax, bx ; save bx into ax for next loop 60 | jmp update_body ; loop 61 | done_update: 62 | cmp byte [grow_snake_flag], 1 ; snake should grow? 63 | jne add_zero_snake ; if not: jump to add_zero_snake 64 | mov word [si], ax ; save the last element at the next position 65 | mov byte [grow_snake_flag], 0 ; disable grow_snake_flag 66 | add si, 2 ; increment si by 2 67 | add_zero_snake: 68 | mov word [si], 0x0000 69 | print_stuff: 70 | xor dx, dx ; set pos to 0x0000 71 | call move_cursor ; move cursor 72 | mov si, score_msg ; prepare to print score string 73 | call print_string ; print it 74 | mov ax, [score] ; move the score into ax 75 | call print_int ; print it 76 | mov dx, [food_pos] ; set dx to the food position 77 | call move_cursor ; move cursor there 78 | mov al, '*' ; use '*' as food symbol 79 | call print_char ; print food 80 | mov dx, [snake_pos] ; set dx to the snake head position 81 | call move_cursor ; move there 82 | mov al, '@' ; use '@' as snake head symbol 83 | call print_char ; print it 84 | mov si, snake_body_pos ; prepare to print snake body 85 | snake_body_print_loop: 86 | lodsw ; load position from the body, and increment si 87 | test ax, ax ; check if position is zero 88 | jz check_collisions ; if it was zero, move out of here 89 | mov dx, ax ; if not, move the position into dx 90 | call move_cursor ; move the cursor there 91 | mov al, 'o' ; use 'o' as the snake body symbol 92 | call print_char ; print it 93 | jmp snake_body_print_loop ; loop 94 | 95 | check_collisions: 96 | mov bx, [snake_pos] ; move the snake head position into bx 97 | cmp bh, 25 ; check if we are too far down 98 | jge game_over_hit_wall ; if yes, jump 99 | cmp bh, 0 ; check if we are too far up 100 | jl game_over_hit_wall ; if yes, jump 101 | cmp bl, 80 ; check if we are too far to the right 102 | jge game_over_hit_wall ; if yes, jump 103 | cmp bl, 0 ; check if we are too far to the left 104 | jl game_over_hit_wall ; if yes, jump 105 | mov si, snake_body_pos ; prepare to check for self-collision 106 | check_collisions_self: 107 | lodsw ; load position of snake body, and increment si 108 | cmp ax, bx ; check if head position = body position 109 | je game_over_hit_self ; if it is, jump 110 | or ax, ax ; check if position is 0x0000 (we are done searching) 111 | jne check_collisions_self ; if not, loop 112 | 113 | no_collision: 114 | mov ax, [snake_pos] ; load snake head position into ax 115 | cmp ax, [food_pos] ; check if we are on the food 116 | jne game_loop_continued ; jump if snake didn't hit food 117 | inc word [score] ; if we were on food, increment score 118 | mov bx, 24 ; set max value for random call (y-val - 1) 119 | call rand ; generate random value 120 | push dx ; save it on the stack 121 | mov bx, 78 ; set max value for random call 122 | call rand ; generate random value 123 | pop cx ; restore old random into cx 124 | mov dh, cl ; move old value into high bits of new 125 | mov [food_pos], dx ; save the position of the new random food 126 | mov byte [grow_snake_flag], 1 ; make sure snake grows 127 | game_loop_continued: 128 | mov cx, 0x0002 ; Sleep for 0,15 seconds (cx:dx) 129 | mov dx, 0x49F0 ; 0x000249F0 = 150000 130 | mov ah, 0x86 131 | int 0x15 ; Sleep 132 | jmp game_loop ; loop 133 | 134 | game_over_hit_self: 135 | push self_msg 136 | jmp game_over 137 | 138 | game_over_hit_wall: 139 | push wall_msg 140 | 141 | game_over: 142 | call clear_screen 143 | mov si, hit_msg 144 | call print_string 145 | pop si 146 | call print_string 147 | mov si, retry_msg 148 | call print_string 149 | wait_for_r: 150 | mov ah, 0x00 151 | int 0x16 152 | cmp al, 'r' 153 | jne wait_for_r 154 | mov word [snake_pos], 0x0F0F 155 | and word [snake_body_pos], 0 156 | and word [score], 0 157 | mov byte [last_move], 'd' 158 | jmp game_loop 159 | 160 | ; SCREEN FUNCTIONS ------------------------------------------------------------ 161 | clear_screen: 162 | mov ax, 0x0700 ; clear entire window (ah 0x07, al 0x00) 163 | mov bh, 0x0C ; light red on black 164 | xor cx, cx ; top left = (0,0) 165 | mov dx, 0x1950 ; bottom right = (25, 80) 166 | int 0x10 167 | xor dx, dx ; set dx to 0x0000 168 | call move_cursor ; move cursor 169 | ret 170 | 171 | move_cursor: 172 | mov ah, 0x02 ; move to (dl, dh) 173 | xor bh, bh ; page 0 174 | int 0x10 175 | ret 176 | 177 | print_string_loop: 178 | call print_char 179 | print_string: ; print the string pointed to in si 180 | lodsb ; load next byte from si 181 | test al, al ; check if high bit is set (end of string) 182 | jns print_string_loop ; loop if high bit was not set 183 | 184 | print_char: ; print the char at al 185 | and al, 0x7F ; unset the high bit 186 | mov ah, 0x0E 187 | int 0x10 188 | ret 189 | 190 | print_int: ; print the int in ax 191 | push bp ; save bp on the stack 192 | mov bp, sp ; set bp = stack pointer 193 | 194 | push_digits: 195 | xor dx, dx ; clear dx for division 196 | mov bx, 10 ; set bx to 10 197 | div bx ; divide by 10 198 | push dx ; store remainder on stack 199 | test ax, ax ; check if quotient is 0 200 | jnz push_digits ; if not, loop 201 | 202 | pop_and_print_digits: 203 | pop ax ; get first digit from stack 204 | add al, '0' ; turn it into ascii digits 205 | call print_char ; print it 206 | cmp sp, bp ; is the stack pointer is at where we began? 207 | jne pop_and_print_digits ; if not, loop 208 | pop bp ; if yes, restore bp 209 | ret 210 | ; UTILITY FUNCTIONS ----------------------------------------------------------- 211 | rand: ; random number between 1 and bx. result in dx 212 | mov ah, 0x00 213 | int 0x1A ; get clock ticks since midnight 214 | mov ax, dx ; move lower bits into ax for division 215 | xor dx, dx ; clear dx 216 | div bx ; divide ax by bx to get remainder in dx 217 | inc dx 218 | ret 219 | 220 | ; MESSAGES (Encoded as 7-bit strings. Last byte is an ascii value with its 221 | ; high bit set ---------------------------------------------------------------- 222 | retry_msg db '! press r to retr', 0xF9 ; y 223 | hit_msg db 'You hit', 0xA0 ; space 224 | self_msg db 'yoursel', 0xE6 ; f 225 | wall_msg db 'the wal', 0xEC ; l 226 | score_msg db 'Score:', 0xA0 ; space 227 | 228 | ; VARIABLES ------------------------------------------------------------------- 229 | grow_snake_flag db 0 230 | food_pos dw 0x0D0D 231 | score dw 1 232 | last_move db 'd' 233 | snake_pos: 234 | snake_x_pos db 0x0F 235 | snake_y_pos db 0x0F 236 | snake_body_pos dw 0x0000 237 | 238 | ; PADDING AND BOOT SIGNATURE -------------------------------------------------- 239 | times 510-($-$$) db 0 240 | db 0x55 241 | db 0xAA 242 | -------------------------------------------------------------------------------- /software_src/sokoban: -------------------------------------------------------------------------------- 1 | ; by Ish. 2 | ; Public domain from https://ish.works/bootsector/bootsector.html 3 | 4 | bits 16 ; tell NASM this is 16 bit code 5 | org 0x7c00 ; tell NASM that our code will be loaded at offset 0x7c00 6 | 7 | %define CURRENT_LEVEL 0x1000 8 | %define CURRENT_LEVEL_4 0x1004 9 | %define SCREEN_DS 0xb800 10 | 11 | boot: 12 | ; clear screen (re-set text mode) 13 | xor ah, ah 14 | mov al, 0x03 ; text mode 80x25 16 colours 15 | int 0x10 16 | 17 | ; disable cursor 18 | mov ah, 0x01 19 | mov ch, 0x3f 20 | int 0x10 21 | 22 | ; set up stack 23 | mov ax, 0x9000 24 | mov ss, ax 25 | mov sp, 0x400 26 | 27 | ; set current level to test level by copying 28 | mov si, test_level 29 | 30 | ; get width and height and multiply by each other 31 | mov ax, [si] 32 | mul ah 33 | 34 | ; set multiplied width and height + 4 as counter 35 | mov cx, ax 36 | ;add cx, 4 37 | 38 | mov di, CURRENT_LEVEL ; next address to copy to 39 | xor ax, ax 40 | mov es, ax 41 | 42 | ; copy map size and player position ("uncompressed") 43 | lodsw 44 | stosw 45 | lodsw 46 | stosw 47 | 48 | .copy_level_loop: 49 | ; load "compressed" byte: e.g. 0x28 or 0x44 into AL 50 | lodsb 51 | 52 | mov ah, al ; AX = 0x2828 53 | and ax, 0x0FF0 ; AX = 0x0820 (little endian: 20 08) 54 | shr al, 4 ; AX = 0x0802 (little endian: 02 08) 55 | 56 | ; save "uncompressed" word: e.g. 02 08 or 04 04 from AX 57 | stosw 58 | 59 | loop .copy_level_loop 60 | 61 | call draw_current_level 62 | 63 | .mainloop: 64 | ; read key 65 | xor ax, ax 66 | int 0x16 67 | 68 | cmp ah, 0x01 ; esc 69 | je end 70 | 71 | cmp ah, 0x50 ; down arrow 72 | je .try_move_down 73 | 74 | cmp ah, 0x48 ; up arrow 75 | je .try_move_up 76 | 77 | cmp ah, 0x4b ; left arrow 78 | je .try_move_left 79 | 80 | cmp ah, 0x4d ; right arrow 81 | je .try_move_right 82 | 83 | .redraw: 84 | call draw_current_level 85 | 86 | .check_win: 87 | 88 | ; get width and height 89 | mov ax, [CURRENT_LEVEL] ; al = width; ah = height 90 | mul ah 91 | mov cx, ax ; cx = size of map 92 | 93 | xor bx, bx ; bx = number of bricks-NOT-on-a-spot 94 | 95 | mov si, CURRENT_LEVEL_4 96 | .check_win_loop: 97 | lodsb 98 | cmp al, 2 99 | jne .not_a_brick 100 | inc bx 101 | .not_a_brick: 102 | loop .check_win_loop 103 | 104 | ; so, did we win? is the number of spotless bricks == 0?? 105 | cmp bx, 0 106 | je win 107 | jmp .mainloop 108 | 109 | 110 | .try_move_down: 111 | mov al, byte [CURRENT_LEVEL] ; (width of current level) to the right = 1 down 112 | call try_move 113 | jmp .redraw 114 | 115 | .try_move_up: 116 | mov al, byte [CURRENT_LEVEL] 117 | neg al ; (width of current level) to the left = 1 up 118 | call try_move 119 | jmp .redraw 120 | 121 | .try_move_left: 122 | mov al, -1 ; one to the left 123 | call try_move 124 | jmp .redraw 125 | 126 | .try_move_right: 127 | mov al, 1 ; one to the right 128 | call try_move 129 | jmp .redraw 130 | 131 | win: 132 | ; print a nice win message to the middle of the screen 133 | mov si, str_you_win 134 | 135 | ; destination position on screen 136 | mov ax, SCREEN_DS 137 | mov es, ax 138 | mov di, (80 * 12 + 40 - 6) * 2 139 | 140 | mov ah, 0x0F 141 | .loop: 142 | lodsb 143 | 144 | cmp al, 0 145 | je wait_for_esc 146 | 147 | stosw 148 | jmp .loop 149 | 150 | wait_for_esc: 151 | ; read key 152 | xor ax, ax 153 | int 0x16 154 | 155 | cmp ah, 0x01 ; esc 156 | je boot 157 | jmp wait_for_esc 158 | ; halt: 159 | ; cli ; clear interrupt flag 160 | ; hlt ; halt execution 161 | 162 | 163 | ;; functions: 164 | 165 | draw_current_level: 166 | ; get width and height 167 | mov cx, [CURRENT_LEVEL] ; cl = width; ch = height 168 | push cx ; put it in the stack for later reuse 169 | 170 | ; print in the middle and not in the corner 171 | mov di, 2000; middle of screen 172 | 173 | ; offset by half of width 174 | mov bl, cl 175 | and bx, 0x00FE 176 | sub di, bx 177 | 178 | ; offset by half of height 179 | mov cl, ch 180 | and cx, 0x00FE 181 | mov ax, 80 182 | mul cx 183 | sub di, ax 184 | 185 | 186 | mov si, CURRENT_LEVEL_4 ; source byte 187 | 188 | ; screen memory in text mode 189 | mov ax, SCREEN_DS 190 | mov es, ax 191 | 192 | .loop: 193 | mov bl, [si] 194 | xor bh, bh 195 | add bx, bx 196 | add bx, display_chars 197 | mov dx, [bx] 198 | mov [es:di], dx 199 | 200 | inc si 201 | add di, 2 202 | pop cx ; get counters 203 | dec cl ; subtract 1 from X axis counter 204 | jz .nextrow 205 | push cx 206 | jmp .loop 207 | 208 | .nextrow: 209 | dec ch ; subtract 1 from Y axis counter 210 | jz .finished 211 | mov cl, [CURRENT_LEVEL] 212 | push cx 213 | 214 | ; jump to next row down 215 | xor ch, ch 216 | neg cx 217 | add cx, 80 218 | add cx, cx 219 | add di, cx 220 | 221 | jmp .loop 222 | 223 | .finished: 224 | ret 225 | 226 | try_move: 227 | ; try to move the player 228 | ; al = offset of how much to move by 229 | pusha 230 | 231 | ; extend al into ax (signed) 232 | test al, al ; check if negative 233 | js .negative_al 234 | xor ah, ah 235 | jmp .after_al 236 | .negative_al: 237 | mov ah, 0xFF 238 | .after_al: 239 | push ax 240 | 241 | ; calculate total level size 242 | mov ax, [CURRENT_LEVEL] 243 | mul ah 244 | 245 | ; calculate requested destination position 246 | pop bx 247 | push bx 248 | mov dx, [CURRENT_LEVEL + 2] 249 | add bx, dx 250 | 251 | ; check if in bounds 252 | cmp bx, 0 253 | jl .finished 254 | cmp bx, ax 255 | jg .finished 256 | 257 | ; get value at destination position 258 | mov cl, [CURRENT_LEVEL_4 + bx] 259 | cmp cl, 4 260 | je .cant_push ; it's a wall 261 | test cl, 0x02 262 | jz .dont_push ; it's not a brick (on spot, or not), so don't try pushing 263 | 264 | ; try pushing brick 265 | pop cx ; get move offset 266 | push bx ; store player's destination position (brick's current position) 267 | 268 | mov dx, bx ; dx = current brick position 269 | add bx, cx ; bx = next brick position 270 | 271 | ; check bounds 272 | cmp bx, 0 273 | jl .cant_push 274 | cmp bx, ax 275 | jg .cant_push 276 | 277 | ; get value at destination position 278 | mov ch, [CURRENT_LEVEL_4 + bx] 279 | test ch, 0x0E ; test if the destination is occupied at all by ANDing with 0000 1110 280 | jnz .cant_push 281 | 282 | ; all checks passed! push the brick 283 | 284 | ; add new brick to screen 285 | or ch, 0x02 ; add brick bit, by ORing with 0000 0010 286 | mov [CURRENT_LEVEL_4 + bx], ch 287 | 288 | ; remove old brick from screen 289 | mov si, dx 290 | mov cl, [CURRENT_LEVEL_4 + si] 291 | and cl, 0xFD ; remove brick bit, by ANDing with 1111 1101 292 | mov [CURRENT_LEVEL_4 + si], cl 293 | 294 | mov dx, [CURRENT_LEVEL + 2] ; dx = current player position 295 | pop bx ; bx = next player position 296 | jmp .redraw_player 297 | 298 | .cant_push: 299 | pop bx 300 | jmp .finished 301 | 302 | .dont_push: 303 | pop cx ; don't need to have this offset in the stack anymore 304 | 305 | .redraw_player: 306 | ; remove old player from screen 307 | mov si, dx 308 | mov cl, [CURRENT_LEVEL_4 + si] 309 | and cl, 0xF7 ; remove player bit, by ANDing with 1111 0111 310 | mov [CURRENT_LEVEL_4 + si], cl 311 | 312 | ; add new player to screen 313 | mov ch, [CURRENT_LEVEL_4 + bx] 314 | or ch, 0x08 ; add player bit, by ORing with 0000 1000 315 | mov [CURRENT_LEVEL_4 + bx], ch 316 | 317 | ; update player position in memory 318 | mov [CURRENT_LEVEL + 2], bx 319 | 320 | .finished: 321 | 322 | popa 323 | ret 324 | 325 | end: 326 | int 0x20 327 | 328 | ; data section: 329 | 330 | ; 0000 0000 EMPTY 331 | ; 0000 0001 SPOT 332 | ; 0000 0010 BRICK 333 | ; 0000 0011 BRICK ON SPOT 334 | ; 0000 0100 WALL 335 | ; 0000 1000 PLAYER 336 | ; 0000 1001 PLAYER ON SPOT 337 | test_level: 338 | ; this was the original level format, which was quite big: 339 | 340 | ; db 9, 7 ; width, height 341 | ; dw 32 ; playerxy 342 | ; db 4,4,4,4,4,4,0,0,0 343 | ; db 4,0,0,0,0,4,0,0,0 344 | ; db 4,0,0,2,0,4,4,0,0 345 | ; db 4,0,2,4,1,9,4,4,4 346 | ; db 4,4,0,0,3,1,2,0,4 347 | ; db 0,4,0,0,0,0,0,0,4 348 | ; db 0,4,4,4,4,4,4,4,4 349 | ; db 14, 10 ;width, height 350 | ; dw 63 ;playerxy 351 | 352 | ; when i tried to put in THIS level (from https://www.youtube.com/watch?v=fg8QImlvB-k) 353 | ; i passed the 512 byte limit... 354 | 355 | ; db 4,4,4,4,4,4,4,4,4,4,4,4,0,0 356 | ; db 4,1,1,0,0,4,0,0,0,0,0,4,4,4 357 | ; db 4,1,1,0,0,4,0,2,0,0,2,0,0,4 358 | ; db 4,1,1,0,0,4,2,4,4,4,4,0,0,4 359 | ; db 4,1,1,0,0,0,0,8,0,4,4,0,0,4 360 | ; db 4,1,1,0,0,4,0,4,0,0,2,0,4,4 361 | ; db 4,4,4,4,4,4,0,4,4,2,0,2,0,4 362 | ; db 0,0,4,0,2,0,0,2,0,2,0,2,0,4 363 | ; db 0,0,4,0,0,0,0,4,0,0,0,0,0,4 364 | ; db 0,0,4,4,4,4,4,4,4,4,4,4,4,4 365 | 366 | ; so i compressed it! high nybble first, low nybble second 367 | db 14, 10 ;width, height 368 | dw 63 ;playerxy 369 | db 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x00 370 | db 0x41, 0x10, 0x04, 0x00, 0x00, 0x04, 0x44 371 | db 0x41, 0x10, 0x04, 0x02, 0x00, 0x20, 0x04 372 | db 0x41, 0x10, 0x04, 0x24, 0x44, 0x40, 0x04 373 | db 0x41, 0x10, 0x00, 0x08, 0x04, 0x40, 0x04 374 | db 0x41, 0x10, 0x04, 0x04, 0x00, 0x20, 0x44 375 | db 0x44, 0x44, 0x44, 0x04, 0x42, 0x02, 0x04 376 | db 0x00, 0x40, 0x20, 0x02, 0x02, 0x02, 0x04 377 | db 0x00, 0x40, 0x00, 0x04, 0x00, 0x00, 0x04 378 | db 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 379 | 380 | 381 | 382 | display_chars: db 0, 0x07 ; blank 383 | db 249, 0x07 ; spot 384 | db 4, 0x0C ; brick 385 | db 4, 0x0A ; brick on spot 386 | db 178, 0x71 ; wall 387 | db "5", 0x07 ; (no 5) 388 | db "6", 0x07 ; (no 6) 389 | db "7", 0x07 ; (no 7) 390 | db 1, 0x0F ; player 391 | db 1, 0x0F ; player on spot 392 | 393 | str_you_win: db 'YOU WIN! ',1,1,1,0 394 | 395 | times 512 - ($-$$) db 0 ; pad remaining 510 bytes with zeroes 396 | ;dw 0xaa55 ; magic bootloader magic - marks this 512 byte sector bootable! 397 | 398 | ; if you don't want your resulting file to be as big as a floppy, then comment the following line: 399 | 400 | ;times (1440 * 1024) - ($-$$) db 0 ; pad with zeroes to make a floppy-sized image -------------------------------------------------------------------------------- /software_src/sound: -------------------------------------------------------------------------------- 1 | ;;;;;;;; 2 | ; File format: 3 | ; 512 bytes sound: dw sound 4 | ;;;;;;;; 5 | org 0x7c00 6 | bits 16 7 | 8 | xor ax, ax 9 | push cs 10 | push cs 11 | push cs 12 | pop es 13 | pop ds 14 | pop ss 15 | start: 16 | call get_file 17 | call tone_init 18 | mov si, 0xc000 19 | mov cx, 1 20 | mov dx, 0 21 | loop: 22 | lodsw 23 | call tone 24 | cmp si, 0xc200 25 | ja end 26 | jmp loop 27 | 28 | 29 | get_file: 30 | mov al, "?" 31 | int 0x26 32 | mov bx, 0x7780 33 | mov di, 0xc000 34 | int 0x23 35 | jc err 36 | ret 37 | err: 38 | mov al, 0x13 39 | int 0x22 40 | mov al, 0x0d 41 | int 0x22 42 | jmp get_file 43 | 44 | tone_init: 45 | mov al,0xb6 ; Setup timer 2 46 | out 0x43,al 47 | in al,0x61 48 | or al,0x03 ; Wire PC speaker to timer 2 49 | out 0x61,al 50 | ret 51 | 52 | tone: ; cx:dx time in ms 53 | ; ax: frequency (calculate 1193180/freq = req. value) 54 | pusha 55 | xchg ax, bx 56 | mov al,bl ; Low byte of timer count 57 | out 0x42,al 58 | mov al,bh ; High byte of timer count 59 | out 0x42,al 60 | pusha 61 | mov ah, 0x86 62 | int 0x15 63 | popa 64 | popa 65 | ret 66 | end: 67 | in al,0x61 68 | and al,0xfc ; Turn off 69 | out 0x61,al 70 | int 0x20 71 | -------------------------------------------------------------------------------- /software_src/tetris: -------------------------------------------------------------------------------- 1 | ; Modified by nanochess for compatibility with VirtualBox, 2 | ; to require only 286 and also now it's in color. 3 | 4 | ; 16 bits, starting at 0x7C00. 5 | BITS 16 6 | ORG 0x7C00 7 | 8 | BSS EQU 0x0504 ; The byte at 0x0500 is also used, so align on next dword bound. 9 | BSS_SIZE EQU 438 10 | 11 | CUR_TETRAMINO EQU BSS ; 16 bytes. 12 | ROT_TETRAMINO EQU BSS + 16 ; 16 bytes. 13 | OFFSET EQU BSS + 32 ; 2 bytes. 14 | STACK EQU BSS + 38 ; 4 bytes reserved in beginning, 400 bytes. 15 | 16 | LEFT_SCANCODE EQU 0x4b 17 | RIGHT_SCANCODE EQU 0x4d 18 | 19 | UP_SCANCODE EQU 0x48 20 | DOWN_SCANCODE EQU 0x50 21 | 22 | SCORE_DIGITS EQU 5 23 | 24 | CPU 286 25 | 26 | ; Entry point. 27 | ; cs:ip -> linear address (usually 0x7C00, but irrelevant because we are position independent). 28 | start: 29 | ; Set up segments. 30 | xor ax, ax 31 | 32 | ; Stack. 33 | mov ss, ax 34 | mov sp, 0xB800 ;why not 35 | 36 | mov ds, ax 37 | mov es, ax 38 | 39 | ; Clear direction flag. 40 | cld 41 | 42 | ; Clear BSS 43 | mov di, BSS 44 | mov cx, di ;at least BSS_SIZE 45 | rep stosb 46 | 47 | ; Set to mode 0x03, or 80x25 text mode (ah is zero from above). 48 | mov al, 0x03 49 | int 0x10 50 | 51 | ; Hide the hardware cursor. 52 | mov ch, 0x26 53 | mov ax, 0x103 ; Some BIOS crash without the 03. 54 | int 0x10 55 | 56 | mov es, sp 57 | mov fs, sp 58 | 59 | ; White spaces on black background. 60 | xor di, di 61 | mov ax, 0x0F00 62 | mov cx, ax ; At least 80x25x2. 63 | rep stosw 64 | call pop_check 65 | 66 | ; Detects if CUR_TETRAMINO at OFFSET is colliding with any thing. 67 | ; si -> OFFSET. 68 | ; Output: 69 | ; Carry set if colliding. 70 | tetramino_collision_check: 71 | 72 | lea bx, [bp + check_collision - tetramino_collision_check] 73 | 74 | ; Processes the current tetramino, calling bx per "tetramino pixel". 75 | ; bx -> where to call to; al contains tetramino pixel, di the address into stack. 76 | tetramino_process: 77 | pusha 78 | 79 | ; Gets the offset into stack (i.e., address) into di. 80 | ; si -> points at OFFSET. 81 | ; Output: 82 | ; si -> points at CUR_TETRAMINO. 83 | ; di -> address into stack. 84 | ; Trashes ax. 85 | 86 | ; Calculate first index into screen. 87 | lodsw 88 | aad 0x10 89 | cmp byte [si-1], 0x10 90 | sbb ah, ah 91 | xchg bx, ax 92 | lea di, [si + (STACK - OFFSET) + 0xFE + bx] 93 | xchg bx, ax 94 | 95 | mov si, CUR_TETRAMINO 96 | 97 | mov cl, 0x10 98 | 99 | .loop: 100 | test cl, 0x13;0b1011 101 | jnz .load_loop 102 | 103 | ; Go to next line in stack. 104 | add di, 16 - 4 105 | 106 | .load_loop: 107 | lodsb 108 | 109 | ; Call wherever the caller wants us to go. 110 | call bx 111 | 112 | inc di 113 | loop .loop 114 | 115 | popa 116 | ret 117 | 118 | check_collision: 119 | or al,al 120 | jz .clear_carry 121 | 122 | cmp di, STACK + 400 123 | jae .colliding 124 | 125 | cmp byte [di],0 126 | 127 | .clear_carry: 128 | clc 129 | 130 | je .next_iter 131 | 132 | ; Colliding! 133 | .colliding: 134 | 135 | stc 136 | mov cl, 1 137 | .next_iter: 138 | ret 139 | 140 | ; Used by the stack joining part. 141 | merge: 142 | or [di], al 143 | ret 144 | 145 | ; All tetraminos in bitmap format. 146 | tetraminos: 147 | db 0xF0;0b11110000 ; I 148 | db 0xE2;0b11100010 ; J 149 | db 0x2E;0b00101110 ; L 150 | db 0x66;0b01100110 ; O 151 | db 0x36;0b00110110 ; S 152 | db 0xE4;0b11100100 ; T 153 | db 0x63;0b01100011 ; Z 154 | 155 | pop_check: 156 | pop bp ; Save some bytes. 157 | 158 | .borders: 159 | mov si, STACK - 3 160 | mov ax, 0x0101 161 | 162 | .borders_init: 163 | mov [si], ax 164 | mov [si + 2], ax 165 | mov [si + 4], ax 166 | 167 | add si, 16 168 | cmp si, STACK + 400 - 3 169 | jbe .borders_init 170 | 171 | ; Cleared dl implies "load new tetramino". 172 | xor dl, dl 173 | 174 | .event_loop: 175 | mov si, OFFSET 176 | 177 | ; For some reason this doesn't work with BootOS over VirtualBox 5.1.22 178 | %if 0 179 | mov bx, [0x046C] 180 | inc bx 181 | inc bx ; Wait for 2 PIT ticks. 182 | 183 | .busy_loop: 184 | cmp [0x046C], bx 185 | jne .busy_loop 186 | %else 187 | push dx 188 | .busy_loop1: 189 | mov ah,0x00 190 | int 0x1a 191 | cmp [0x1000],dx 192 | je .busy_loop1 193 | mov [0x1000],dx 194 | .busy_loop2: 195 | mov ah,0x00 196 | int 0x1a 197 | cmp [0x1000],dx 198 | je .busy_loop2 199 | mov [0x1000],dx 200 | pop dx 201 | xor cx,cx ; Or rotation doesn't work 202 | %endif 203 | ; If we don't need to load a new tetramino, yayy! 204 | test dl, dl 205 | jnz .input 206 | 207 | ; Load a tetramino to CUR_TETRAMINO, from the compressed bitmap format. 208 | 209 | .choose_tetramino: 210 | in al,(0x40) 211 | 212 | ; Only 7 tetraminos, index as 1-7. 213 | and ax, 7 214 | je .choose_tetramino 215 | 216 | ; Get the address of the tetramino (in bitmap format). 217 | cwd 218 | mov di,ax 219 | mov ah,al 220 | 221 | ; Load tetramino bitmap in dl. 222 | mov dl, [cs:bp + di + (tetraminos - tetramino_collision_check) - 1] 223 | shl dx, 4 224 | 225 | ; Convert from bitmap to array. 226 | mov di, CUR_TETRAMINO 227 | mov cl, 0x10 228 | 229 | .loop_bitmap: 230 | 231 | shl dx, 1 232 | 233 | ; If the bit we just shifted off was set, store number of tetramino. 234 | sbb al, al 235 | and al, ah 236 | mov [di], al 237 | inc di 238 | 239 | loop .loop_bitmap 240 | 241 | ; Loaded. 242 | mov dl, 6 243 | 244 | mov word [si], dx 245 | jmp .link_next_iter 246 | 247 | ; Check for input. 248 | .input: 249 | ; Check for keystroke. 250 | mov ah, 0x01 251 | int 0x16 252 | 253 | ; If no keystroke, increment vertical offset. 254 | jz .vertical_increment 255 | 256 | ; Clear the keyboard buffer. 257 | xor ah, ah 258 | int 0x16 259 | 260 | .exit: 261 | cmp ah, 0x01 262 | jne .left 263 | mov ax,0x0002 ; Clear screen 264 | int 0x10 265 | int 0x20 ; Return to bootOS 266 | 267 | ; Go left. 268 | .left: 269 | cmp ah, LEFT_SCANCODE 270 | jne .right 271 | 272 | dec byte [si] 273 | jmp .call_bp 274 | 275 | ; Go right. 276 | .right: 277 | cmp ah, RIGHT_SCANCODE 278 | jne .rotate 279 | 280 | inc byte [si] 281 | 282 | .call_bp: 283 | xor ah, LEFT_SCANCODE ^ RIGHT_SCANCODE 284 | call bp 285 | jc .left 286 | 287 | ; Rotate it. 288 | .rotate: 289 | cmp ah, UP_SCANCODE 290 | jne .vertical_increment 291 | 292 | inc cx 293 | 294 | .rotate_loop: 295 | ; Rotates CUR_TETRAMINO 90 degrees clock-wise. 296 | ; Output: 297 | ; CUR_TETRAMINO -> rotated tetramino. 298 | pusha 299 | push es 300 | 301 | ; Reset ES. 302 | push ds 303 | pop es 304 | 305 | mov si, CUR_TETRAMINO 306 | mov di, ROT_TETRAMINO + 3 307 | push si 308 | mov cl, 4 309 | 310 | .loop: 311 | mov ch, 4 312 | 313 | .tetramino_line: 314 | movsb 315 | scasw 316 | inc di 317 | dec ch 318 | jnz .tetramino_line 319 | 320 | sub di, 4*4+1 321 | loop .loop 322 | 323 | pop di 324 | mov cl, 4*4/2 ; CH would be zero, from above. 325 | rep movsw 326 | 327 | pop es 328 | popa 329 | 330 | loop .rotate_loop 331 | 332 | call bp 333 | ; To restore, just rotate 3 more times. 334 | mov cl, 3 335 | jc .rotate_loop 336 | 337 | .vertical_increment: 338 | mov cl, 1 339 | call upd_score 340 | 341 | ; Check if we can go below one byte, successfully. 342 | inc byte [si + 1] 343 | call bp 344 | .link_next_iter: 345 | jnc .next_iter 346 | 347 | ; If we can't, we need a new tetramino. 348 | dec byte [si + 1] 349 | je $ ; Game Over 350 | cwd 351 | 352 | ; Joins the current tetramino to the stack, and any complete lines together. 353 | ; si -> OFFSET. 354 | push es 355 | 356 | push ds 357 | pop es 358 | 359 | lea bx, [bp + merge - tetramino_collision_check] 360 | call tetramino_process 361 | 362 | mov si, STACK + 15 363 | std 364 | 365 | .loop_lines: 366 | push si 367 | mov cl, 16 368 | 369 | .line: 370 | lodsb 371 | test al, al 372 | loopnz .line ; If it was a blank, exit loop to indicate failure. 373 | 374 | jz .next_line 375 | 376 | lea cx, [si - (STACK - 1)] 377 | lea di, [si + 16] 378 | rep movsb 379 | mov cl, 64 380 | call upd_score 381 | 382 | .next_line: 383 | pop si 384 | add si, 16 385 | cmp si, STACK + 15 + 400 386 | jb .loop_lines 387 | 388 | cld 389 | pop es 390 | 391 | jmp .borders 392 | 393 | .next_iter: 394 | ; Display the stack. 395 | push si 396 | 397 | ; Add 24 characters padding in the front. 398 | mov ah, 0x0F 399 | mov di, 48 400 | mov si, STACK 401 | 402 | .loop_stack_lines: 403 | ; Copy 32 characters. 404 | mov cl, 16 405 | 406 | .stack_line: 407 | lodsb 408 | mov ah,al 409 | mov al,0xdb 410 | ; Store one character as two -- to make stack "squarish" on 80x25 display. 411 | stosw 412 | stosw 413 | 414 | loop .stack_line 415 | 416 | ; Handle remaining 24 characters in row, and starting 24 in next row. 417 | add di, 96 418 | cmp di, (25 * 160) ; If we go beyond the last row, we're over. 419 | jb .loop_stack_lines 420 | 421 | pop si 422 | 423 | ; Displays CUR_TETRAMINO at current OFFSET. 424 | ; si -> OFFSET. 425 | 426 | ; Calculate first index into screen. 427 | mov bx, [si] 428 | mov al, 40 429 | mul bh 430 | mov cl, 12 431 | add cl, bl 432 | add ax, cx 433 | 434 | ; One character takes 2 bytes in video memory. 435 | shl ax, 2 436 | xchg di, ax 437 | 438 | ; Loops for 16 input characters. 439 | mov cl, 0x10 440 | mov si, CUR_TETRAMINO 441 | 442 | mov ah, 0x0F 443 | 444 | .loop_tetramino: 445 | test cl, 0x13;0b1011 446 | jnz .load_tetramino 447 | 448 | ; Since each tetramino input is 4x4, we must go to next line 449 | ; at every multiple of 4. 450 | ; Since we output 2 characters for one input char, cover offset of 8. 451 | add di, (80 - 8) * 2 452 | 453 | .load_tetramino: 454 | lodsb 455 | or al,al 456 | mov ah,al 457 | mov al,0xdb 458 | ; Output two characters for "squarish" output. 459 | jne .load_tetramino2 460 | mov ax, [es:di] 461 | .load_tetramino2: 462 | stosw 463 | stosw 464 | 465 | loop .loop_tetramino 466 | 467 | jmp .event_loop 468 | 469 | upd_score: 470 | mov bx, SCORE_DIGITS * 2 471 | 472 | .chk_score: 473 | dec bx 474 | dec bx 475 | js $ 476 | mov al, '0' 477 | xchg [fs:bx], al 478 | or al, 0x30 479 | cmp al, '9' 480 | je .chk_score 481 | inc ax 482 | mov [fs:bx], al 483 | 484 | loop upd_score 485 | ret 486 | 487 | ; IT'S A SECRET TO EVERYBODY. 488 | db "ShNoXgSo" 489 | 490 | ; Padding. 491 | times 510 - ($ - $$) db 0 492 | 493 | BIOS_signature: 494 | dw 0xAA55 495 | -------------------------------------------------------------------------------- /software_src/upload: -------------------------------------------------------------------------------- 1 | start: mov ax, 0x0000 | 0b11111011 2 | mov dx, 0x0000 3 | int 0x14 4 | load_file: 5 | mov al, "?" 6 | int 0x26 7 | mov bx, si 8 | mov di, 0xa000 9 | int 0x23 10 | jc err 11 | 12 | send: mov si, 0xa000 13 | push cs 14 | pop es 15 | mov cx, 0x0200 16 | mov ah, 0x01 17 | mov dx, 0x0000 18 | cld 19 | .loop: lodsb 20 | pusha 21 | int 0x14 22 | test ah, 0b1000000 23 | mov ax, 0x0e00 24 | mov bx, 0x0007 25 | jz .err 26 | mov al, "." 27 | jmp .print 28 | .err: mov al, "!" 29 | .print: int 0x10 30 | popa 31 | loop .loop 32 | 33 | int 0x20 34 | 35 | err: 36 | mov al, 0x13 37 | int 0x22 38 | int 0x20 -------------------------------------------------------------------------------- /strip.py: -------------------------------------------------------------------------------- 1 | import math 2 | with open("os.img", "rb") as file: 3 | data = list(file.read()) 4 | digits = math.ceil(math.log(len(data), 10)) 5 | i = 0 6 | while data[len(data) - 1] == 0: 7 | data.pop() 8 | i += 1 9 | print("\r" + str(i).zfill(digits) + " bytes stripped...", end="") 10 | with open("os.img", "wb") as file: 11 | file.write(bytes(data)) 12 | print() 13 | -------------------------------------------------------------------------------- /symbols.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | 3 | if len(sys.argv) < 3: 4 | print("Usage:", sys.argv[0], "", "") 5 | exit(1) 6 | 7 | content = "" 8 | org = 0 9 | 10 | with open(sys.argv[1], "r") as file: 11 | for line in file.readlines(): 12 | ln = line 13 | if ";" in line: 14 | line = line.split(";")[0] + "\n" 15 | if ":" in line: 16 | line = line.split(":")[0] 17 | line = line.strip().replace(" ", "").replace("\t", "") 18 | if not "equ" in ln.split(";")[0]: 19 | content += f"%assign __{line} ($ - $$)\n%warning {line} at __{line} n\n" 20 | else: 21 | l = ln.split(";")[0].strip() 22 | l = l.split(":")[1] 23 | l = l.replace("equ", "").strip() 24 | content += f"%assign __{line} {l}\n%warning {line} at __{line} e\n" 25 | elif "org" in line: 26 | line = line.replace("org", "").strip() 27 | org = eval(line) 28 | content += ln 29 | 30 | with open("tmp.asm", "w") as file: 31 | file.write(content) 32 | 33 | os.system("nasm -f bin -o tmp.img tmp.asm 2> tmp.txt") 34 | 35 | os.unlink("tmp.img") 36 | os.unlink("tmp.asm") 37 | 38 | refs = [] 39 | last = "" 40 | 41 | with open("tmp.txt", "r") as file: 42 | for line in file.readlines(): 43 | line = line.strip() 44 | if line == "": 45 | continue 46 | line = line.split(":")[3].strip() 47 | line = line.replace("[-w+user]", "").strip() 48 | l = line.split(" ") 49 | line = " ".join(l[:-1]) 50 | couple = line.split(" at ") 51 | try: 52 | couple[1] = int(couple[1]) 53 | except: 54 | continue 55 | if l[-1] == "n": 56 | couple[1] += org 57 | if couple[0].startswith("."): 58 | couple[0] = last + couple[0] 59 | else: 60 | last = couple[0] 61 | refs.append(couple) 62 | 63 | content = "" 64 | for couple in refs: 65 | content += f"%define bootOS.{couple[0]} {couple[1]}\n" 66 | 67 | with open(sys.argv[2], "w") as file: 68 | file.write(content) 69 | 70 | os.unlink("tmp.txt") 71 | --------------------------------------------------------------------------------