diff options
-rw-r--r-- | dla.s | 310 | ||||
-rw-r--r-- | mmss.s | 150 |
2 files changed, 307 insertions, 153 deletions
@@ -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) @@ -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 |