Created
February 15, 2011 20:06
-
-
Save muspellsson/828130 to your computer and use it in GitHub Desktop.
99 bottles of beer in FASM bootsector
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;======================================================================= | |
; an x86 bootsector implementation of | |
; 99 bottles of beer | |
; by Ivan Sukin <[email protected]> | |
; based on template made by shoorick | |
;======================================================================= | |
;======================================================================= | |
; Drive info | |
;======================================================================= | |
_bps equ 512 ; bytes per sector | |
_spt equ 18 ; sectors per track | |
_hds equ 2 ; number of heads | |
_trs equ 80 ; number of tracks | |
;======================================================================= | |
; First 3 bytes of bootsector | |
; Must be E9XXXX or EBXX90. | |
; 7C00h is the address where | |
; bootsector is put by BIOS | |
;======================================================================= | |
org 7C00h ; starting address | |
mov cx, 99 ; set CX to 99 right here | |
jmp short start ; short jmp (EB XX) | |
;======================================================================= | |
; Bootsector record (1 byte after standard) | |
;======================================================================= | |
more db "o more " ; OEM name and version (8 B) | |
more_l = $ - more ; !!! dirty hack | |
; !!! I've put some string here | |
dw _bps ; bytes per sector | |
db 1 ; sectors per allocation unit | |
dw 1 ; reserved sectors | |
db 2 ; number of FATs | |
dw 224 ; number of root dir entries | |
dw 2880 ; total sectors in logical volume | |
db 0F0h ; media descriptor byte | |
dw 9 ; number of sectors per FAT | |
dw _spt ; sectors per track | |
dw _hds ; number of heads | |
dd 0 ; number of hidden sectors | |
dd 0 ; total sectors in logical volume | |
; if volume size > 32 MiB | |
db 0 ; physical drive number | |
db 0 ; reserved | |
db 29h ; Extended Boot Signature record (29h) | |
dd 0 ; 32-bit binary volume ID | |
is db "Ivan Sukin " ; volume label (11 B) | |
db "(C) 2011" ; reserved (8 B) | |
is_l = $ - is ; !!! dirty hack | |
; !!! I've put my name here | |
;======================================================================= | |
; Entry point | |
;======================================================================= | |
start: | |
; Point segment registers to the beginning of current segment | |
mov ax, cs | |
mov ds, ax | |
; loop: begin | |
@@: | |
call put_cx_99 | |
cmp cl, 1 | |
je short cx_is_1 | |
call print_bott1 | |
call put_cx_99 | |
call print_bott2 | |
call print_endl1 | |
call print_bott3 | |
; print cx - 1 | |
dec cx | |
call put_cx_99 | |
; if next_value_of_cx == 1 then goto cx_will_be_1 | |
cmp cl, 1 | |
je short cx_will_be_1 | |
; else | |
call bott4_endl | |
jmp short @b | |
; loop: end | |
cx_will_be_1: | |
mov dx, b5_l | |
call bott5_helper | |
jmp short @b | |
; loop: end | |
cx_is_1: | |
mov dx, b6_l | |
call bott5_helper | |
mov al, "," | |
call put_char | |
mov al, " " | |
call put_char | |
call put_cx_99 | |
mov dx, b7_l | |
call bott5_helper | |
call print_endl1 | |
call print_bott3 | |
mov al, "N" | |
call put_char | |
call print_more | |
call bott4_endl | |
cx_is_0: | |
mov ax, "N" | |
call put_char | |
call print_more | |
call print_bott1 | |
mov al, "n" | |
call put_char | |
call print_more | |
call print_bott2 | |
call print_endl1 | |
mov dx, store_l | |
mov si, stor | |
call put_str | |
mov cx, 99 | |
call put_cx_99 | |
call bott4_endl | |
mov dx, is_l | |
mov si, is | |
call put_str | |
xor ah, ah | |
int 16h ; INT 16h -- function 00, Get keystroke | |
int 19h ; INT 19h -- Bootstrap loader | |
; (reboot) | |
;======================================================================= | |
; Many helper and printer procedures | |
; written for code shortening | |
;======================================================================= | |
bott4_endl: | |
call print_bott4 | |
call print_endl | |
ret | |
print_more: | |
mov dx, more_l | |
mov si, more | |
call put_str | |
ret | |
bott1_helper: | |
mov si, bott_1 | |
call put_str | |
ret | |
bott5_helper: | |
mov si, bott_5 | |
call put_str | |
ret | |
print_bott1: | |
mov dx, b1_l | |
call bott1_helper | |
ret | |
print_bott2: | |
mov dx, b2_l | |
call bott1_helper | |
ret | |
print_bott3: | |
mov dx, b3_l | |
mov si, bott_3 | |
call put_str | |
ret | |
print_bott4: | |
mov dx, b4_l | |
call bott1_helper | |
ret | |
print_endl: | |
mov dx, endl_l | |
mov si, endl | |
call put_str | |
ret | |
print_endl1: | |
mov dx, endl_l1 | |
mov si, endl | |
call put_str | |
ret | |
;======================================================================= | |
; Simple printing procedures | |
;======================================================================= | |
;======================================================================= | |
; Procedure put_char | |
; al -- character to output | |
; Uses: ax | |
;======================================================================= | |
put_char: | |
mov ah, 0Eh | |
int 10h | |
ret | |
;======================================================================= | |
; Procedure put_cx_99 | |
; Puts a value of CX | |
; assuming that it's in range | |
; 0 - 99 | |
; Uses: ax, bx | |
;======================================================================= | |
put_cx_99: | |
mov ax, cx | |
mov bl, 10 | |
div bl | |
mov bh, ah | |
test al, al | |
jz short @f | |
add al, '0' | |
call put_char | |
@@: | |
mov al, bh | |
add al, '0' | |
call put_char | |
mov al, " " | |
call put_char | |
ret | |
;======================================================================= | |
; Procedure put_str | |
; dx -- string lenth | |
; ds:si -- string address | |
; Uses: ah, dx | |
;======================================================================= | |
put_str: | |
lodsb | |
call put_char | |
dec dx | |
jnz short put_str | |
ret | |
;======================================================================= | |
; String data needed for the song | |
;======================================================================= | |
bott_1 db "bottles of beer on the wall, " | |
b1_l = $ - bott_1 | |
b2_l = 15 | |
bott_3 db "Take one down pass it around, " | |
b3_l = $ - bott_3 | |
b4_l = b1_l - 2 | |
bott_5 db "bottle of beer on the wall.", 13, 10, 10 | |
b5_l = $ - bott_5 | |
b6_l = b5_l - 4 | |
b7_l = b5_l - 16 | |
endl = $ - 4 | |
endl_l1 = 3 | |
endl_l = 4 | |
stor db "Go to store and buy some more, " | |
store_l = $ - stor | |
rb 7E00h-2-$ ; reserve the rest of bootsector except last two bytes | |
db 055h, 0AAh ; bootsector signature | |
;======================================================================= |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You may build this code with FASM (http://flatassembler.net) and then write it to diskette or try in emulator (the best choice is DOSBox).