mirror of https://github.com/wwarthen/RomWBW.git
37 changed files with 1177 additions and 791 deletions
@ -0,0 +1,411 @@ |
|||||
|
;=============================================================================== |
||||
|
; SIMER - Display system timer value |
||||
|
; |
||||
|
;=============================================================================== |
||||
|
; |
||||
|
; Author: Wayne Warthen (wwarthen@gmail.com) |
||||
|
;_______________________________________________________________________________ |
||||
|
; |
||||
|
; Usage: |
||||
|
; TIMER [/C] [/?] |
||||
|
; ex: TIMER (display current timer value) |
||||
|
; TIMER /? (display version and usage) |
||||
|
; TIMER /C (display timer value continuously) |
||||
|
; |
||||
|
; Operation: |
||||
|
; Reads and displays system timer value. |
||||
|
;_______________________________________________________________________________ |
||||
|
; |
||||
|
; Change Log: |
||||
|
; 2018-01-14 [WBW] Initial release |
||||
|
;_______________________________________________________________________________ |
||||
|
; |
||||
|
; ToDo: |
||||
|
;_______________________________________________________________________________ |
||||
|
; |
||||
|
;=============================================================================== |
||||
|
; Definitions |
||||
|
;=============================================================================== |
||||
|
; |
||||
|
stksiz .equ $40 ; Working stack size |
||||
|
; |
||||
|
restart .equ $0000 ; CP/M restart vector |
||||
|
bdos .equ $0005 ; BDOS invocation vector |
||||
|
; |
||||
|
ident .equ $FFFE ; loc of RomWBW HBIOS ident ptr |
||||
|
; |
||||
|
rmj .equ 2 ; intended CBIOS version - major |
||||
|
rmn .equ 9 ; intended CBIOS version - minor |
||||
|
; |
||||
|
bf_sysget .equ $F8 ; HBIOS: SYSGET function |
||||
|
bf_sysgettimer .equ $D0 ; TIMER subfunction |
||||
|
; |
||||
|
;=============================================================================== |
||||
|
; Code Section |
||||
|
;=============================================================================== |
||||
|
; |
||||
|
.org $100 |
||||
|
; |
||||
|
; setup stack (save old value) |
||||
|
ld (stksav),sp ; save stack |
||||
|
ld sp,stack ; set new stack |
||||
|
; |
||||
|
; initialization |
||||
|
call init ; initialize |
||||
|
jr nz,exit ; abort if init fails |
||||
|
; |
||||
|
; process |
||||
|
call process ; do main processing |
||||
|
jr nz,exit ; abort on error |
||||
|
; |
||||
|
exit: ; clean up and return to command processor |
||||
|
call crlf ; formatting |
||||
|
ld sp,(stksav) ; restore stack |
||||
|
;jp restart ; return to CP/M via restart |
||||
|
ret ; return to CP/M w/o restart |
||||
|
; |
||||
|
; Initialization |
||||
|
; |
||||
|
init: |
||||
|
call crlf ; formatting |
||||
|
ld de,msgban ; point to version message part 1 |
||||
|
call prtstr ; print it |
||||
|
; |
||||
|
initx |
||||
|
; initialization complete |
||||
|
xor a ; signal success |
||||
|
ret ; return |
||||
|
; |
||||
|
; Process |
||||
|
; |
||||
|
process: |
||||
|
; look for start of parms |
||||
|
ld hl,$81 ; point to start of parm area (past len byte) |
||||
|
call nonblank ; skip to next non-blank char |
||||
|
jp z,process0 ; no parms, go to display |
||||
|
; |
||||
|
; check for special option, introduced by a "/" |
||||
|
cp '/' ; start of options? |
||||
|
jp nz,usage ; yes, handle option |
||||
|
call option ; do option processing |
||||
|
ret nz ; done if non-zero reture |
||||
|
; |
||||
|
process0: |
||||
|
call crlf2 ; formatting |
||||
|
; |
||||
|
process1: |
||||
|
ld b,bf_sysget ; HBIOS SYSGET function |
||||
|
ld c,bf_sysgettimer ; TIMER subfunction |
||||
|
rst 08 ; call HBIOS, DE:HL := timer value |
||||
|
|
||||
|
ld a,(first) |
||||
|
or a |
||||
|
ld a,0 |
||||
|
ld (first),a |
||||
|
jr nz,process1a |
||||
|
|
||||
|
; test for new value |
||||
|
ld a,(last) ; last LSB value to A |
||||
|
cp l ; compare to current LSB |
||||
|
jr z,process2 ; if equal, bypass display |
||||
|
|
||||
|
process1a: |
||||
|
; save and print new value |
||||
|
ld a,l ; new LSB value to A |
||||
|
ld (last),a ; save as last value |
||||
|
call prtcr ; back to start of line |
||||
|
call nz,prthex32 ; display it |
||||
|
; |
||||
|
process2: |
||||
|
ld a,(cont) ; continuous display? |
||||
|
or a ; test for true/false |
||||
|
jr z,process3 ; if false, get out |
||||
|
; |
||||
|
ld c,6 ; BDOS: direct console I/O |
||||
|
ld e,$FF ; input char |
||||
|
call bdos ; call BDOS, A := char |
||||
|
or a ; test for zero |
||||
|
jr z,process1 ; loop until char pressed |
||||
|
; |
||||
|
process3: |
||||
|
xor a ; signal success |
||||
|
ret |
||||
|
; |
||||
|
; Handle special options |
||||
|
; |
||||
|
option: |
||||
|
; |
||||
|
inc hl ; next char |
||||
|
ld a,(hl) ; get it |
||||
|
cp '?' ; is it a '?'? |
||||
|
jp z,usage ; yes, display usage |
||||
|
cp 'C' ; is it a 'C', continuous? |
||||
|
jp z,setcont ; yes, set continuous display |
||||
|
jp errprm ; anything else is an error |
||||
|
; |
||||
|
usage: |
||||
|
; |
||||
|
call crlf2 ; blank line |
||||
|
ld de,msguse ; point to usage message |
||||
|
call prtstr ; print it |
||||
|
or $FF ; signal no action performed |
||||
|
ret ; and return |
||||
|
; |
||||
|
setcont: |
||||
|
; |
||||
|
or $FF ; set A to true |
||||
|
ld (cont),a ; and save it |
||||
|
xor a ; signal success |
||||
|
ret ; and done |
||||
|
; |
||||
|
; Print character in A without destroying any registers |
||||
|
; |
||||
|
prtchr: |
||||
|
push bc ; save registers |
||||
|
push de |
||||
|
push hl |
||||
|
ld e,a ; character to print in E |
||||
|
ld c,$02 ; BDOS function to output a character |
||||
|
call bdos ; do it |
||||
|
pop hl ; restore registers |
||||
|
pop de |
||||
|
pop bc |
||||
|
ret |
||||
|
; |
||||
|
prtdot: |
||||
|
; |
||||
|
; shortcut to print a dot preserving all regs |
||||
|
push af ; save af |
||||
|
ld a,'.' ; load dot char |
||||
|
call prtchr ; print it |
||||
|
pop af ; restore af |
||||
|
ret ; done |
||||
|
; |
||||
|
prtcr: |
||||
|
; |
||||
|
; shortcut to print a dot preserving all regs |
||||
|
push af ; save af |
||||
|
ld a,13 ; load CR value |
||||
|
call prtchr ; print it |
||||
|
pop af ; restore af |
||||
|
ret ; done |
||||
|
; |
||||
|
; Print a zero terminated string at (DE) without destroying any registers |
||||
|
; |
||||
|
prtstr: |
||||
|
push de |
||||
|
; |
||||
|
prtstr1: |
||||
|
ld a,(de) ; get next char |
||||
|
or a |
||||
|
jr z,prtstr2 |
||||
|
call prtchr |
||||
|
inc de |
||||
|
jr prtstr1 |
||||
|
; |
||||
|
prtstr2: |
||||
|
pop de ; restore registers |
||||
|
ret |
||||
|
; |
||||
|
; Print the value in A in hex without destroying any registers |
||||
|
; |
||||
|
prthex: |
||||
|
push af ; save AF |
||||
|
push de ; save DE |
||||
|
call hexascii ; convert value in A to hex chars in DE |
||||
|
ld a,d ; get the high order hex char |
||||
|
call prtchr ; print it |
||||
|
ld a,e ; get the low order hex char |
||||
|
call prtchr ; print it |
||||
|
pop de ; restore DE |
||||
|
pop af ; restore AF |
||||
|
ret ; done |
||||
|
; |
||||
|
; print the hex word value in bc |
||||
|
; |
||||
|
prthexword: |
||||
|
push af |
||||
|
ld a,b |
||||
|
call prthex |
||||
|
ld a,c |
||||
|
call prthex |
||||
|
pop af |
||||
|
ret |
||||
|
; |
||||
|
; print the hex dword value in de:hl |
||||
|
; |
||||
|
prthex32: |
||||
|
push bc |
||||
|
push de |
||||
|
pop bc |
||||
|
call prthexword |
||||
|
push hl |
||||
|
pop bc |
||||
|
call prthexword |
||||
|
pop bc |
||||
|
ret |
||||
|
; |
||||
|
; Convert binary value in A to ascii hex characters in DE |
||||
|
; |
||||
|
hexascii: |
||||
|
ld d,a ; save A in D |
||||
|
call hexconv ; convert low nibble of A to hex |
||||
|
ld e,a ; save it in E |
||||
|
ld a,d ; get original value back |
||||
|
rlca ; rotate high order nibble to low bits |
||||
|
rlca |
||||
|
rlca |
||||
|
rlca |
||||
|
call hexconv ; convert nibble |
||||
|
ld d,a ; save it in D |
||||
|
ret ; done |
||||
|
; |
||||
|
; Convert low nibble of A to ascii hex |
||||
|
; |
||||
|
hexconv: |
||||
|
and $0F ; low nibble only |
||||
|
add a,$90 |
||||
|
daa |
||||
|
adc a,$40 |
||||
|
daa |
||||
|
ret |
||||
|
; |
||||
|
; Print value of A or HL in decimal with leading zero suppression |
||||
|
; Use prtdecb for A or prtdecw for HL |
||||
|
; |
||||
|
prtdecb: |
||||
|
push hl |
||||
|
ld h,0 |
||||
|
ld l,a |
||||
|
call prtdecw ; print it |
||||
|
pop hl |
||||
|
ret |
||||
|
; |
||||
|
prtdecw: |
||||
|
push af |
||||
|
push bc |
||||
|
push de |
||||
|
push hl |
||||
|
call prtdec0 |
||||
|
pop hl |
||||
|
pop de |
||||
|
pop bc |
||||
|
pop af |
||||
|
ret |
||||
|
; |
||||
|
prtdec0: |
||||
|
ld e,'0' |
||||
|
ld bc,-10000 |
||||
|
call prtdec1 |
||||
|
ld bc,-1000 |
||||
|
call prtdec1 |
||||
|
ld bc,-100 |
||||
|
call prtdec1 |
||||
|
ld c,-10 |
||||
|
call prtdec1 |
||||
|
ld e,0 |
||||
|
ld c,-1 |
||||
|
prtdec1: |
||||
|
ld a,'0' - 1 |
||||
|
prtdec2: |
||||
|
inc a |
||||
|
add hl,bc |
||||
|
jr c,prtdec2 |
||||
|
sbc hl,bc |
||||
|
cp e |
||||
|
ret z |
||||
|
ld e,0 |
||||
|
call prtchr |
||||
|
ret |
||||
|
; |
||||
|
; Start a new line |
||||
|
; |
||||
|
crlf2: |
||||
|
call crlf ; two of them |
||||
|
crlf: |
||||
|
push af ; preserve AF |
||||
|
ld a,13 ; <CR> |
||||
|
call prtchr ; print it |
||||
|
ld a,10 ; <LF> |
||||
|
call prtchr ; print it |
||||
|
pop af ; restore AF |
||||
|
ret |
||||
|
; |
||||
|
; Get the next non-blank character from (HL). |
||||
|
; |
||||
|
nonblank: |
||||
|
ld a,(hl) ; load next character |
||||
|
or a ; string ends with a null |
||||
|
ret z ; if null, return pointing to null |
||||
|
cp ' ' ; check for blank |
||||
|
ret nz ; return if not blank |
||||
|
inc hl ; if blank, increment character pointer |
||||
|
jr nonblank ; and loop |
||||
|
; |
||||
|
; Convert character in A to uppercase |
||||
|
; |
||||
|
ucase: |
||||
|
cp 'a' ; if below 'a' |
||||
|
ret c ; ... do nothing and return |
||||
|
cp 'z' + 1 ; if above 'z' |
||||
|
ret nc ; ... do nothing and return |
||||
|
res 5,a ; clear bit 5 to make lower case -> upper case |
||||
|
ret ; and return |
||||
|
; |
||||
|
; Add the value in A to HL (HL := HL + A) |
||||
|
; |
||||
|
addhl: |
||||
|
add a,l ; A := A + L |
||||
|
ld l,a ; Put result back in L |
||||
|
ret nc ; if no carry, we are done |
||||
|
inc h ; if carry, increment H |
||||
|
ret ; and return |
||||
|
; |
||||
|
; Jump indirect to address in HL |
||||
|
; |
||||
|
jphl: |
||||
|
jp (hl) |
||||
|
; |
||||
|
; Errors |
||||
|
; |
||||
|
erruse: ; command usage error (syntax) |
||||
|
ld de,msguse |
||||
|
jr err |
||||
|
; |
||||
|
errprm: ; command parameter error (syntax) |
||||
|
ld de,msgprm |
||||
|
jr err |
||||
|
err: ; print error string and return error signal |
||||
|
call crlf ; print newline |
||||
|
; |
||||
|
err1: ; without the leading crlf |
||||
|
call prtstr ; print error string |
||||
|
; |
||||
|
err2: ; without the string |
||||
|
; call crlf ; print newline |
||||
|
or $FF ; signal error |
||||
|
ret ; done |
||||
|
; |
||||
|
;=============================================================================== |
||||
|
; Storage Section |
||||
|
;=============================================================================== |
||||
|
; |
||||
|
last .db 0 ; last LSB of timer value |
||||
|
cont .db 0 ; non-zero indicates continuous display |
||||
|
first .db $FF ; first pass flag (true at start) |
||||
|
; |
||||
|
stksav .dw 0 ; stack pointer saved at start |
||||
|
.fill stksiz,0 ; stack |
||||
|
stack .equ $ ; stack top |
||||
|
; |
||||
|
; Messages |
||||
|
; |
||||
|
msgban .db "TIMER v1.0, 14-Jan-2018",13,10 |
||||
|
.db "Copyright (C) 2018, Wayne Warthen, GNU GPL v3",0 |
||||
|
msguse .db "Usage: TIMER [/C] [/?]",13,10 |
||||
|
.db " ex. TIMER (display current timer value)",13,10 |
||||
|
.db " TIMER /? (display version and usage)",13,10 |
||||
|
.db " TIMER /C (display timer value continuously)",0 |
||||
|
msgprm .db "Parameter error (TIMER /? for usage)",0 |
||||
|
; |
||||
|
.end |
||||
File diff suppressed because it is too large
Binary file not shown.
Binary file not shown.
Loading…
Reference in new issue