139 lines
3.1 KiB
Text
139 lines
3.1 KiB
Text
putch: equ 2 ; Write character
|
|
puts: equ 9 ; Write string
|
|
fopen: equ 15 ; Open file
|
|
fread: equ 20 ; Read record
|
|
setdma: equ 26 ; Set DMA address
|
|
fcb: equ 5Ch ; FCB for first file on command line
|
|
org 100h
|
|
;;; Open source file given on command line
|
|
lxi d,fcb
|
|
mvi c,fopen
|
|
call 5 ; Open file
|
|
inr a ; A=FF = error
|
|
lxi d,efile
|
|
jz s_out ; If error, print error message and stop
|
|
lxi d,src ; Start reading file at src
|
|
;;; Load the entire source file into memory
|
|
block: push d ; Set DMA address to next free location
|
|
mvi c,setdma
|
|
call 5
|
|
lxi d,fcb ; Read 128-byte record
|
|
mvi c,fread
|
|
call 5
|
|
pop d ; Advance pointer by 128 bytes
|
|
lxi h,128
|
|
dad d
|
|
xchg
|
|
dcr a ; A=1 = end of file
|
|
jz block ; If not EOF, read next block
|
|
xchg
|
|
mvi m,26 ; Terminate last block with EOF byte to be sure
|
|
lxi b,src ; BC = source pointer
|
|
ins: ldax b ; Get current instruction
|
|
cpi 26 ; If EOF, stop
|
|
rz
|
|
ori 32 ; Make lowercase
|
|
push b ; Keep source pointer
|
|
cpi 'h' ; H=hello
|
|
cz hello
|
|
cpi 'q' ; Q=quine
|
|
cz quine
|
|
cpi '9' ; 9=bottles
|
|
cz botls
|
|
cpi '+' ; +=increment
|
|
cz incr
|
|
pop b ; Restore source pointer
|
|
inx b ; Next instruction
|
|
jmp ins
|
|
;;; Increment accumulator
|
|
incr: lxi h,accum
|
|
inr m
|
|
ret
|
|
;;; Print "Hello, World"
|
|
hello: lxi d,histr
|
|
jmp s_out
|
|
;;; Print the source
|
|
quine: lxi h,src ; Pointer to source
|
|
qloop: mov a,m ; Load byte
|
|
cpi 26 ; Reached the end?
|
|
rz ; If so, stop
|
|
push h ; Otherwise, keep pointer
|
|
mov e,a
|
|
mvi c,putch ; Print character
|
|
call 5
|
|
pop h ; Restore pointer
|
|
inx h ; Next byte
|
|
jmp qloop
|
|
;;; 99 bottles of beer
|
|
botls: mvi e,99 ; 99 bottles
|
|
bverse: call nbeer ; _ bottle(s) of beer
|
|
lxi h,otw ; on the wall
|
|
call bstr
|
|
call nbeer ; _ bottle(s) of beer
|
|
lxi h,nl ; \r\n
|
|
call bstr
|
|
lxi h,tod ; Take one down and pass it around
|
|
call bstr
|
|
dcr e ; Decrement counter
|
|
push psw ; Keep status
|
|
call nbeer ; _ bottle(s) of beer
|
|
lxi h,otw
|
|
call bstr ; on the wall
|
|
lxi h,nl ; \r\n
|
|
call bstr
|
|
pop psw ; restore status
|
|
jnz bverse ; If not at 0, next verse
|
|
ret
|
|
nbeer: push d ; keep counter
|
|
call btlstr ; _ bottle(s)
|
|
lxi d,ofbeer
|
|
call s_out ; of beer
|
|
pop d
|
|
ret
|
|
bstr: push d ; keep counter
|
|
xchg ; print string in HL
|
|
call s_out
|
|
pop d ; restore counter
|
|
ret
|
|
;;; Print "N bottle(s)"
|
|
btlstr: push d ; Keep counter
|
|
mov a,e ; Print number
|
|
call num
|
|
lxi d,bottle
|
|
call s_out ; Print " bottle"
|
|
pop d ; Restore counter
|
|
dcr e ; If counter is 1,
|
|
rz ; then stop,
|
|
mvi e,'s' ; otherwise, print S
|
|
mvi c,putch
|
|
jmp 5
|
|
;;; Print number (0-99) in A
|
|
num: ana a ; If 0, print "no more"
|
|
lxi d,nomore
|
|
jz s_out
|
|
mvi b,'0'-1 ; Tens digit
|
|
nloop: inr b ; Increment tens digit
|
|
sui 10 ; Subtract 10
|
|
jnc nloop
|
|
adi '0'+10 ; Ones digit
|
|
lxi d,snum-1
|
|
stax d ; Store ones digit
|
|
mov a,b ; Tens digit zero?
|
|
cpi '0'
|
|
jz s_out ; If so, only print ones digit
|
|
dcx d ; Otherwise, store tens digit
|
|
stax d
|
|
s_out: mvi c,puts ; Print result
|
|
jmp 5
|
|
efile: db 'File error.$'
|
|
histr: db 'Hello, world!',13,10,'$'
|
|
db '..'
|
|
snum: db '$'
|
|
nomore: db 'No more$'
|
|
bottle: db ' bottle$'
|
|
ofbeer: db ' of beer$'
|
|
otw: db ' on the wall',13,10,'$'
|
|
tod: db 'Take one down and pass it around'
|
|
nl: db 13,10,'$'
|
|
accum: db 0 ; Accumulator
|
|
src: equ $ ; Program source
|