aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB. Watson <urchlay@slackware.uk>2022-10-31 18:09:28 -0400
committerB. Watson <urchlay@slackware.uk>2022-10-31 18:09:28 -0400
commitfb8e8801a3a3a9907e3dfeba239c3f07eb3a8933 (patch)
tree1904371ab09dcff45593fb0c18ae9000f72ca292
parentb0d6af17e313ac574fc7db761c79a812ec2ecf15 (diff)
downloaddla-asm-fb8e8801a3a3a9907e3dfeba239c3f07eb3a8933.tar.gz
Print elapsed time in MM:SS.CC
-rw-r--r--dla.s310
-rw-r--r--mmss.s150
2 files changed, 307 insertions, 153 deletions
diff --git a/dla.s b/dla.s
index debb196..3388f6a 100644
--- a/dla.s
+++ b/dla.s
@@ -18,43 +18,55 @@
maxlines = $C0 ; 192 lines of display
screenbytes = maxlines * linelen
dl_len = 202 ; remember to update this if you modify the display list!
-
+ dlist = screen - dl_len
DMA_ON = $21
DEFAULTPART = 1000
- maxparticles = $80 ; 2 bytes
- pixptr = $82
- pixmask = $84
- cursor_x = $85 ; cursor x/y are args to plot/unplot/locate
- cursor_y = $86
- min_x = $87 ; limits: if the particle gets outside this box,
- max_x = $88 ; delete it and spawn a new one.
- min_y = $89
- max_y = $8a
- circlesize = $8b ; 0 to 3
- part_x = $8c ; x/y coords of current particle
- part_y = $8d
- particles = $8e ; 2 bytes
- spawn_x = $90 ; 2 bytes
- spawn_y = $92 ; 2 bytes
-
- dlist = screen - dl_len
-
linebuf = $0580
textbuf = $0590
- fptmp = $05a0
- cloksav = $a0
- seedtype = $9f
- old_dma = $9c
- old_dl = $9d
+ .bss
+ .org $80
+
+maxparticles: .res 2 ; user's response to "How many particles?"
+seedtype: .res 1 ; user's response to seed type prompt (minus one; 0-3)
+
+pixptr: .res 2 ; used by plotsetup and friends
+pixmask: .res 1 ; ditto.
+cursor_x: .res 1 ; cursor x/y are args to plot/unplot/locate
+cursor_y: .res 1
+
+min_x: .res 1 ; limits: if the particle gets outside this box,
+max_x: .res 1 ; delete it and spawn a new one.
+min_y: .res 1
+max_y: .res 1
+
+circlesize: .res 1 ; 0 to 3
+
+part_x: .res 1 ; x/y coords of current particle
+part_y: .res 1
+particles: .res 2
+spawn_x: .res 2
+spawn_y: .res 2
+
+cloksav: .res 3 ; hold RTCLOK here while we convert to MM:SS.CC
+
+old_dma: .res 1 ; these 3 are for restoring GR.0 mode
+old_dl: .res 2
+old_savmsc: .res 2
+
+tmp1: .res 1
+fptmp: .res 6
+
+ .code
xex_org loadaddr
.include "io.s" ; printchrx and getchrx
.include "printint.s"
+ .include "mmss.s"
; init stuff gets done once, at startup
init:
lda #0
- sta seedtype
+ sta seedtype ; default seed type is the single pixel
sta LMARGN
lda SDMCTL
sta old_dma
@@ -62,6 +74,10 @@ init:
sta old_dl
lda SDLSTH
sta old_dl+1
+ lda SAVMSC
+ sta old_savmsc
+ lda SAVMSC+1
+ sta old_savmsc+1
; set default particles (if user just hits return)
lda #<DEFAULTPART
@@ -71,18 +87,7 @@ init:
; "New" option jumps here, restore GR.0 screen
getargs:
- lda #$90
- sta COLOR2
- lda #$0e
- sta COLOR1
- lda #$ff
- sta CH
- lda old_dl
- sta SDLSTL
- lda old_dl+1
- sta SDLSTH
- lda old_dma
- sta SDMCTL
+ jsr restore_gr0
; print banner and prompt.
printbanner:
@@ -94,8 +99,8 @@ printbanner:
ldx maxparticles+1
jsr printdecw
- lda #<prompt
- ldx #>prompt
+ lda #<partprompt
+ ldx #>partprompt
jsr printmsg
; use CIO to read input, so user can use backspace/etc.
@@ -132,18 +137,21 @@ usedefault:
ldx #>seedprompt2
jsr printmsg
-readgen:
+readseed:
jsr getchrx
cmp #$9b
- beq generate
+ beq dfltseed ; use default if user pressed return
cmp #$31
- bcc readgen
+ bcc readseed
cmp #$35
- bcs readgen
+ bcs readseed
and #$0f
tax
dex
stx seedtype
+dfltseed:
+ lda #$9b
+ jsr printchr
generate: ;;; start of generate()
jsr initscreen
@@ -243,89 +251,13 @@ main_done:
lda RTCLOK+2
sta cloksav+2
-; print menu
- ldx #menulen
-menuloop:
- lda menumsg,x
- sta textbuf,x
- dex
- bpl menuloop
-
-; calculate and print elapsed time in minutes.
-; uses the floating point ROM routines, because it's easier to code
-; this way and we don't need speed here.
- ldx #0
- stx FR0
- inx
- stx FR0+1
- jsr IFP ; FR0 now FP 256.0
- jsr FMOVE ; FR1 = FR0 (both are 256.0)
- jsr FMUL ; FR0 = FR0 * FR1 (65536.0)
- jsr FMOVE ; FR1 = FR0
- ldx #0
- stx FR0+1
- lda cloksav
- sta FR0
- jsr IFP ; FR0 now cloksav in FP, FR1 = 65536.0
- jsr FMUL ; FR0 = FR0 * FR1
- jsr FMOVE ; FR1 = FR0, aka the high byte of cloksav in jiffies
- lda cloksav+1 ; convert low 2 bytes of cloksav to FP...
- sta FR0+1
- lda cloksav+2
- sta FR0
- jsr IFP ; ...ok, now:
- jsr FADD ; add the high bytes in jiffies, result in FR0 again
-
- ; we now have the 3-byte jiffy count in FR0.
- ; 3600 NTSC jiffies or 3000 PAL jiffies = 1 minute, so divide.
- ; floating point constants:
- ; 3600.0 is $41,$36,$00,$00,$00,$00
- ; 3000.0 is $41,$30,$00,$00,$00,$00
- ldx #FR1
- jsr ZF1
- lda #$41 ; excess-64 base-100 exponent and sign (bit 7 = 0 means positive)
- sta FR1
- ldx #$36 ; 1st mantissa BCD byte, NTSC
- lda PAL
- and #$0e
- bne ntsc
- ldx #$30 ; 1st mantissa BCD byte, PAL
-ntsc:
- stx FR1+1
- jsr FDIV ; FR0 = FR0 / FR1
- jsr FASC ; render as ASCII
-
- ; Now clean up the output from FASC and copy it to our menu line.
- ; FASC puts its results at LBUFF ($0580, aka linebuf).
- ; Unfortunately it can have a leading zero, and the last
- ; digit has the high bit set (as a terminator). We want only
- ; 6 characters including the decimal point, which could be e.g.
- ; 0.1234 (the 0 will show as a space) or 1.2345 12.345 123.45 1234.5
- ; Really elegant software would print this as minutes and seconds,
- ; with tenths of seconds, e.g. 1:23.4. Not that worried about it though.
- ldx #$ff
- lda linebuf
- cmp #'0' ; skip the leading zero if present (a space will be seen in its place)
- bne ascloop
- inx
-ascloop:
- inx
- lda linebuf,x
- and #$df ; convert to screencode
- bmi ascdone ; hit the terminator digit
- sta textbuf,x
- cpx #6
- bne ascloop
- beq xdone
-
-ascdone:
- and #$7f
- sta textbuf,x
- inx
+ ; print elapsed time. see mmss.s for gory details.
+ jsr print_mmss
-xdone:
- lda #$6d ; screen code for "m"
- sta textbuf,x
+ ; print menu, wait for keystroke.
+ lda #<menumsg
+ ldx #>menumsg
+ jsr printmsg
; user might have hit some random key during plotting; ignore it.
keyloop:
@@ -352,19 +284,27 @@ notredo:
;;; Subroutine: saveimage
;;; Does exactly what it says on the tin: saves the image.
-;;; For now, the filename is hardcoded and there's no error checking.
-;;; TODO: prompt for filename, report errors (with retry).
+;;; User is prompted for a filename. In case of disk error,
+;;; there's a "Retry [Y/n]?" prompt.
saveimage:
+ jsr restore_gr0 ; back to GR.0, so we can...
+ lda #<saveprompt
+ ldx #>saveprompt
+ jsr printmsg ; ...prompt for, and...
+ jsr readline ; ...let the user type a filename.
+
; CIO is nice, but it's kind of a PITA to use...
; OPEN #1,8,0,<filename>
ldx #$10
lda #3 ; OPEN
sta ICCOM,x
- lda #<filename
+ lda #<linebuf
sta ICBAL,x
- lda #>filename
+ lda #>linebuf
sta ICBAH,x
- lda #fnlen
+ ldy ICBLL ; length returned by CIO when we called readline...
+ dey ; ...but one byte too long.
+ tya
sta ICBLL,x
lda #0
sta ICBLH,x
@@ -372,6 +312,8 @@ saveimage:
lda #8
sta ICAX1,x
jsr CIOV
+ cpy #1
+ bne save_error
; write data to file
ldx #$10
@@ -386,13 +328,43 @@ saveimage:
lda #>screenbytes
sta ICBLH,x
jsr CIOV
+ cpy #1
+ bne save_error
; CLOSE #1
ldx #$10
lda #$0c ; close
sta ICCOM,x
jsr CIOV
- jmp keyloop
+ cpy #1
+ bne save_error
+ jmp getargs
+
+save_error:
+ tya
+ pha
+ lda #<diskerrmsg
+ ldx #>diskerrmsg
+ jsr printmsg
+ pla
+ jsr printdecb
+ lda #<retrymsg
+ ldx #>retrymsg
+ jsr printmsg
+get_retry_key:
+ jsr getchr
+ cmp #$9b
+ beq jsaveimage
+ and #$5f ; ignore case
+ cmp #'Y'
+ beq jsaveimage
+ cmp #'N'
+ bne get_retry_key
+ jmp getargs
+jsaveimage:
+ lda #$9b
+ jsr printchr
+ jmp saveimage
;;; Subroutine: set_limits
;;; Sets the X/Y min/max limits based on circlesize
@@ -445,6 +417,14 @@ isloop:
lda #>dlist
sta SDLSTH
+ lda #<textbuf
+ sta SAVMSC
+ lda #>textbuf
+ sta SAVMSC+1
+ lda #0
+ sta ROWCRS
+ sta COLCRS
+ sta COLCRS+1
rts
;;; Subroutine: plotsetup
@@ -697,48 +677,72 @@ readline:
sta ICBAH
lda #0
sta ICBLH
- lda #10
+ lda #32 ; buffer length; longer than we need
sta ICBLL
lda #5
sta ICCOM
ldx #0
jmp CIOV
+;;; Subroutine: restore_gr0
+;;; Restore the OS's GRAPHICS 0 display, so we can use E:
+restore_gr0:
+ lda #$90
+ sta COLOR2
+ lda #$0e
+ sta COLOR1
+ lda #$ff
+ sta CH
+ lda old_dl
+ sta SDLSTL
+ lda old_dl+1
+ sta SDLSTH
+ lda old_dma
+ sta SDMCTL
+ lda old_savmsc
+ sta SAVMSC
+ lda old_savmsc+1
+ sta SAVMSC+1
+ rts
+
;;;;; end of executable code, data tables from here on out.
-; prompts
+; prompts.
+; banner and saveprompt must start with a clear-screen code.
banner:
.byte $7d, "Diffusion Limited Aggregate",$9b
.byte "Urchlay's ASM version 0.0.7",$9b,$9b
.byte "Particle count range: 1 to 65535",$9b
.byte "How many particles [",$0
-prompt:
+
+partprompt:
.byte "]? ",$0
+
seedprompt:
.byte $9b,"Seed Type: ",$9b,"1=Dot 2=Plus 3=4Dots 4=Line [",$0
+
seedprompt2:
.byte "]? ",$0
-; screen codes for menu
+saveprompt:
+ .byte $7d, "Save: Enter filename, including Dn:",$9b,"> ",$0
+
+diskerrmsg:
+ .byte "I/O Error ",$0
+
+retrymsg:
+ .byte " Retry [Y/n]? ",$0
+
+; this prompt has to be <22 bytes long, and can NOT contain any
+; screen control codes, because when it's printed we're only
+; printing to a 32-byte buffer (which we told the OS was the
+; start of a GR.0 screen, but that was designated "a lie").
menumsg:
- .byte $00,$00,$00 ; 3 digits of minutes
- .byte $00 ; 1 decimal point
- .byte $00,$00 ; 2 digits fractional minutes
- .byte $00 ; 1 the letter "m"
- .byte $00,$00 ; 2 spaces
- .byte 'S'-$20+$80 ; 1
- scrcode "ave " ; 3
- .byte 'R'-$20+$80 ; 1
- scrcode "edo " ; 4
- .byte 'N'-$20+$80 ; 1
- scrcode "ew?" ; 4
- .byte $80 ; 1 (cursor)
- .byte $00,$00,$00,$00 ; 4 (filler)
-menulen = * - menumsg - 1
-
- ; filename for Save command
-filename: .byte "D:DLA.IMG"
-fnlen = *-filename+1
+ .byte " "
+ .byte ' ','S'|$80,"ave"
+ .byte ' ','R'|$80,"edo"
+ .byte ' ','N'|$80,"ew? "
+ .byte 0
; jump table for seed functions
seeds_l: .byte <(seed_point-1),<(seed_plus-1),<(seed_4pt-1),<(seed_long-1)
diff --git a/mmss.s b/mmss.s
new file mode 100644
index 0000000..f1423b5
--- /dev/null
+++ b/mmss.s
@@ -0,0 +1,150 @@
+
+print_mmss:
+; calculate and print elapsed time
+; uses the floating point ROM routines, because it's easier to code
+; this way and we don't need speed here.
+ ldx #0 ; low byte of 256 (0)
+ stx FR0
+ inx
+ stx FR0+1 ; high byte of 256 (1)
+ jsr IFP ; FR0 now FP 256.0
+ jsr FMOVE ; FR1 = FR0 (both are 256.0)
+ jsr FMUL ; FR0 = FR0 * FR1 (65536.0) (and FR1 is now garbage, but...)
+ jsr FMOVE ; FR1 = FR0 (didn't need it anyway)
+
+ ; cloksav is 3 bytes, MSB-first (like RTCLOK).
+ ; first, convert the highest byte to jiffies:
+ ldx #0
+ stx FR0+1
+ lda cloksav
+ sta FR0
+ jsr IFP ; FR0 now cloksav in FP, FR1 = 65536.0
+ jsr FMUL ; FR0 = FR0 * FR1
+ jsr FMOVE ; FR1 = FR0, aka the high byte of cloksav in jiffies
+
+ ; next, convert low 2 bytes of cloksav to FP...
+ lda cloksav+1
+ sta FR0+1
+ lda cloksav+2
+ sta FR0
+ jsr IFP ; ...ok, now:
+ jsr FADD ; add the high bytes in jiffies, result in FR0 again
+
+ ; copy to fptmp before dividing (we need it later)
+ ldx #<fptmp
+ ldy #>fptmp
+ jsr FST0R
+
+ ; we now have the 3-byte jiffy count in FR0 and fptmp.
+ ; 3600 NTSC jiffies or 3000 PAL jiffies = 1 minute, so divide.
+ ; floating point constants:
+ ; 3600.0 is $41,$36,$00,$00,$00,$00
+ ; 3000.0 is $41,$30,$00,$00,$00,$00
+ jsr load_jpm_fr1
+
+ jsr FDIV ; FR0 = FR0 / FR1 (and FR1 is now garbage)
+
+ ; FR0 is now minutes elapsed (e.g. 1.5, for 90 sec). Only print the
+ ; integer part...
+ ; FP ROM has no equivalent to trunc(). You might think you could call
+ ; FPI followed by IFP, but FPI rounds up (e.g. 1.5 comes out as 2,
+ ; not 1). But it's not hard to do:
+ lda FR0 ; exponent
+ beq truncdone
+ and #$4f ; ignore sign
+ sec
+ sbc #$3f ; A gets either 1 or 2
+ tax
+ lda #0
+truncloop:
+ sta FR0+1,x
+ inx
+ cpx #5
+ bne truncloop
+truncdone:
+
+ ; print digits in FR0
+ lda FR0
+ and #$03
+ sta tmp1
+ inc tmp1
+ ldx #0
+floop:
+ lda FR0+1,x
+ jsr printhex
+ inx
+ cpx tmp1
+ bcc floop
+
+floopdone:
+ ; done printing minutes, let's have the separator
+ lda #':'
+ jsr printchr
+
+ ; multiplication and division trash FR1, which is annoying.
+ jsr load_jpm_fr1
+ jsr FMUL
+ jsr FMOVE
+
+ ; reload original jiffy count into FR0
+ ldx #<fptmp
+ ldy #>fptmp
+ jsr FLD0R
+
+ ; subtract FR1. FR0 ends up with jiffies modulo jiffies-per-sec.
+ jsr FSUB
+
+ ; load 0.6 into FR1 so we can divide by it.
+ ; result will be number of centisec.
+ jsr zero_fr1
+ lda #$3f
+ sta FR1
+ lda #$60
+ sta FR1+1
+ jsr FDIV
+
+ ; *now* we can actually make use of FPI's rounding!
+ jsr FPI
+ jsr IFP
+
+ ; FR0 has division result, which is centiseconds.
+ ; if the exponent is 0, we're OK. otherwise, shift down
+ ; one byte so we print 00 for the seconds.
+ lda FR0
+ and #$0f
+ bne twodigits
+ lda FR0+1
+ sta FR0+2
+ lda #0
+ sta FR0+1
+twodigits:
+ lda FR0+1
+ jsr printhex
+ lda #'.'
+ jsr printchr
+ lda FR0+2
+ jsr printhex
+
+ rts
+
+; load jiffies-per-minute into FR1. needs done twice so
+; it's a subroutine.
+load_jpm_fr1:
+ jsr zero_fr1
+ lda #$41 ; excess-64 base-100 exponent and sign (bit 7 = 0 means positive)
+ sta FR1
+ ldx #$36 ; 1st mantissa BCD byte, NTSC
+ lda PAL
+ and #$0e
+ bne ntsc
+ ldx #$30 ; 1st mantissa BCD byte, PAL
+ntsc:
+ stx FR1+1
+ rts
+
+; ZF1 does *not* just clear out FR0, it uses the X reg as an 8-bit
+; pointer (to zero page only).
+zero_fr1:
+ ldx #FR1
+ jsr ZF1
+ rts