@L}5 _$% l0$)$$Hȱ$ UhL" `e$$%`$%`  R@P!( L(1   Y I`  d  Ld M * @  $ % CC$$)%1 Udߥ$9%: !0 S$% DD˙`  }J)Lr d M * @  $ % CC$$)%1 Udߥ$9%: !0 S$%} DD˙`  }J)Lr J  ((  p L ()   J}L= ( L 0q A    IB JC;? D W } LL  ` W )LA!  ߰")-݆ p" } $G@LL 08`Q")<2Q0 -G$Ș݆ UL# ; p8(()(0ʥ)NQ` }$GȘ݆LU )L ݆ L GȘ ݆LL )W>Z   HH)H }p h  hyhy D L> L JJ    ! LA*` BF }7'8  M HN H` 8 Z  \LdJJ!"! GFE@F (!L }EE !E^ ^ E E7EȩEdE/EȩE  D } .L }  ;F d  ;?F7F? ( .   Z D LL d } . D  L    p  E` , d)  D L) 0BM݊L݉} ML  N݆ L NLML [ TEqEHȱEqEh 0Gȹ G} HLL GɛL  LFREE SECTORS G) *Gȩ GȽG GȌ*jj >G} C8jJ3j2CD( C202C ԠBX` N 1? l LlD:RAMDISK}.COMLu L1 L ;LHL  T`  `1  ɐ     `TU  } L ? .  t`GBJ ~DEHI B V0dV!}QDEHI VF9 ,0 ,0 s0hhL  L` H hDHEh"}DEL8HI4 0 HI,0 0  9 .G VLO#},0 L4*IJ`llD1:AUTORUN.SYSNEED MEM.SAV TO LOAD THIS FILE.D1:MEM.SAV J y08 B|DEHI$} V0 0`B;DEL`?<0LV`@ʆ v s? F0Ξ05: [ BDEHI%} VY8 B V  @  /DE `E:D1:DUP.SYSERROR-SAVING USER MEMORY ON DISKTYPE Y TO &}STILL RUN DOS B;DE J  (` 9 V⪍ ઍ  -'}LLu ÝDEHILV 9 .l 9 .l  `` s$B BH(}I|DE V BLV nB,DE JLV B V BLVDEIʩ BꭝLu  } 3E:}DISK OPERATING SYSTEM II VERSION COPYRIGHT 1984 ATARI CORP.A. DISK DIRECTORY I. FORMAT DISKB. RUN CARTRIDG*}E J. DUPLICATE DISKC. COPY FILE K. BINARY SAVED. DELETE FILE(S) L. BINARY LOADE. RENAME FILE M. RUN AT ADDRES+}SF. LOCK FILE N. CREATE MEM.SAVG. UNLOCK FILE O. DUPLICATE FILEH. WRITE DOS FILES P. FORMAT SINGLEL !N',}#"&))9(&*)/h)''-&؆莟R'S  vL/ˢ L }Insert DOS 2.0s, type Y Λx -}DEfHI 1莏#q! @ y0ɛ8A0,' ȅ 1 1ild! 1L!NO SUCH ITEMSELECT.} ITEM OR FOR MENU! 0 .z:*{}.|{ 1 0 0JB 18L%|DL/}%DIRECTORY--SEARCH SPEC,LIST FILE?[# 0 0 &|D3" 1L!NOT A DISK FILEN !B 1L!E# 1 !BD0}ED:}:1BJ|DE 1DEBHI 1 h0ߢ 0.1}  0?詛 1 y0YЛ 1 ;#L" ;#L! BL1TYPE "Y" TO DELETE...DELETE FILE SPEC2}COPY--FROM, TO?OPTION NOT ALLOWED736 FREE SECTORS COPYING---D1:DIRECK.COMl# 0|D .L/%#3}##JB|DE 1BHID#E 1#0: B 1L!#͑### B 1#c$0SY4}S1}:## # # .#Ƚ# # 𩛙## 1,#PD#ELJ- <.BJD#E 5}1 1HH 0hh|DL%1}:̳# L% #D#EL% 1 0 . .0O% 1L!WILD CARDS NOT A6}LLOWED IN DESTINATION 0 <.|K}N 2 FORMAT. t* 5) 1L!`) 0NΞ 0 L1) 1 L!BAD LOAD FILELOAD FROM WHAT FILE?) 0 ?}0#B 1L!WHAT FILE TO LOCK?) 0 0$B 1L!WHAT FILE TO UNLOCK?DUP DISK-SOURCE,DEST DRIVES?TYPE "Y" IF OK TO US@}E PROGRAM AREACAUTION: A "Y" INVALIDATES MEM.SAV.FE! +L1   `*  70 2 2A} 0.* 1 y0 0)INSERT BOTH DISKS, TYPE RETURN^, 1 y038逍 N, 1L! ,B}C, t*  Lx+, 0 ^, 1 y0 , ,0,0 ,L+ ,I0 ,Vǭ0C}Ξ, 0 }, 1 y0C,ШC, 0K'!" H H 'h h Lx+!EF 5L1L!D,I,HhD}` NOT ENOUGH ROOMINSERT SOURCE DISK,TYPE RETURNINSERT DESTINATION DISK,TYPE RETURNE}`  `8 rL1`-* 1P* 1 y0Y`hhL!NAME OF FILE TO MOVE?- 0 0|DL% <.F},^ 1 70 0 .@L# .BJ 1  DEHIB V L1 ,} 1 70,L.  G}JB|,#P#DE 1 HI BDEHHII 1 B 1 ,^ 1 70,0La- B V,#PH},^ 1 70 0L#L!-* 1P* 1 y0Yj383}mm ݭI}}`8}``|* ? ɛ,`|:-)| / 1L!`DESTINATION CANT BE DOJ}S.SYS0 0H{ 24Δ 28/L!/) 2 Π 2 0 ξK}hAΞB,0 J 1 BDEHI,HÝDE 1HIHIDELSAVE-GIVE L}FILE,START,END(,INIT,RUN)O S0 1`BDEPHI V` S0H 1 L!M}0 0 1L~0`PLEASE TYPE 1 LETTER,0`hhL! 70 1L0L<1 ,;ɛ7,"ɛ:ݦ1ݥN}A"D|ݤD|ȩ:|ȩ|ɛ,,(/+.ީ1 1,ɛ`轤{NAMEO} TOO LONG B VL!` L1I H1EΝDL1|mDiE` V0`8d/8 i:222 1 LP}!ERROR- 138ɛ+,' 20*.. өr2 1``2TOO MANY DIGITSINVALID HEXAQ}DECIMAL PARAMETER800 0 8 00`,0'D800 H,ɛh`2L1NEED D1 THRU D8uR} ECIMAL PARAMETER800 0 8 00`,0'D800 H,ɛh`2L1NEED D1 THRU D8u /* This software is copyright 1989 by John Dunning. See the file 'COPYLEFT.JRD' for the full copyright notice. */T} /* open kludge */ #include int open(name, mode) char * name; int mode; { char copen_mode; if U}(mode & O_RDONLY) copen_mode = 'r'; else if (mode & O_WRONLY) copen_mode = 'w'; else /* error */ return(V}-1); return(copen(name, copen_mode)); } if (mode & O_WRONLY) copen_mode = 'w'; else /* error */ return(0#define NOARGC /* no arg count passing */ #define FIXARGC /* don't expect arg counts passed in */ #include /* X} otoi -- convert unsigned octal string to integer nbr returns field size, else ERR on error */ otoi(octstr, Y}nbr) char *octstr; int *nbr; { int d,t; d=0; *nbr=0; while((*octstr>='0')&(*octstr<='7')) { t=*n Z}br; t=(t<<3) + (*octstr++ - '0'); if ((t>=0)&(*nbr<0)) return ERR; d++; *nbr=t; } return d; } t=*n w; ; smaller slicker hand-coded line-parsing routine ; ; assemble this with global.m65 ; ; _parseline(line, argv) char * \}line; int * argv; ; .globl __parseli __parseli: ldy #0 sty tmp1 ; use tmp1 as counter jsr popax ; get argv ptr ]}sta ptr2 ; save into ptr2 stx ptr2+1 jsr popax ; get line pointer sta ptr1 ; save in ptr1 stx ptr1+1 cpx #0 bn^}e parse1 ; test line pointer for zero-ness... lda ptr1 beq parse8 parse1: ; skip whitespace ldy #0 ; get a char _} lda (ptr1),y beq parse8 ; done! finish up and leave cmp #$9B ; EOL? beq parse8 ; yup, same as nul jsr white_p b`}cc parse2 ; not white parse1w: inc ptr1 ; bump string ptr bne parse1 inc ptr1+1 bne parse1 parse2: ; remembea}r the ptr, bump arg count ldy #0 lda ptr1 sta (ptr2),y ; store ptr lo iny lda ptr1+1 sta (ptr2),y ; ... ptr hi b}inc tmp1 ; and bump arg count clc lda ptr2 adc #2 ; bump argv ptr sta ptr2 bcc parse3 inc ptr2+1 parse3: c}; find next whitespace ldy #0 lda (ptr1),y ; get a char beq parse8 ; nul, we're done jsr white_p ; white? bcs pard}se4 ; yes, found end of this arg inc ptr1 bne parse3 inc ptr1+1 bne parse3 parse4: pha ; save the char for a see}c lda #0 sta (ptr1),y ; zap in eos pla ; get orig char back beq parse8 ; done! cmp #$9B bne parse1w ; nope, gf}o bump ptr and keep scanning parse8: ; load up arg count and return ldx #0 lda tmp1 rts ; ; return cond codesg} carry set if white, clear if non-white ; white_p: cmp #$7F ; > 7F? bcs w_ret1 ; yes, that's white cmp #$21 ; <= sh}pace? bcs w_ret0 ; no, it's data. w_ret1: sec rts w_ret0: clc rts _ret1 ; yes, that's white cmp #$21 ; <= sP#define NOARGC /* no arg count passing */ #define FIXARGC /* don't expect arg counts passed in */ /* This softwarej} is copyright 1989 by John Dunning. See the file 'COPYLEFT.JRD' for the full copyright notice. */ /* homebrew mek}mory management routines, by jrd */ /* these vars defined in heap.m65 */ extern int _himem; /* pointer to next unused l}mem */ /* permanent alloc */ pmalloc(nbytes) int nbytes; { int ptr; ptr = _himem; /* get current ptr */ _him}mem += nbytes; /* move up by nbytes */ return(ptr); } { int ptr; ptr = _himem; /* get current ptr */ _hi=; ; This software is copyright 1989 by John Dunning. See the file ; 'COPYLEFT.JRD' for the full copyright notice. ; o}; ; read(iocb, buf, size)->real size read ; .globl _read _read: jsr __rwsetup ; do common setup for read and write bp}eq read9 ; if size 0, it's a no-op lda #getchr ; iocb command code sta iccom,x jsr ciov ; read it bpl read9 cpy q}#$88 ; eof is treated specially beq read9 jmp ioreturn ; do common error stuff read9: lda icbll,x ; buf len lo phar} ; save it lda icblh,x ; get buf len hi tax ; in x pla ; get lo byte back rts ; icbll,x ; buf len lo phaa#define NOARGC /* no arg count passing */ #define FIXARGC /* don't expect arg counts passed in */ /* This software it}s copyright 1989 by John Dunning. See the file 'COPYLEFT.JRD' for the full copyright notice. */ /* handy util for 8-u}bitters. handed a prompt string, prompt with it, and read an arg string. parse it into the passed argv */ #include <v}stdio.h> int readargs(prompt, buf, argv) char * prompt; char * buf; char ** argv; { fputs(prompt, stderr); /* prompw}t */ fgets(buf, 80, stderr); /* get a buf */ return(_parseline(buf, argv)); } ; { fputs(prompt, stderr); /* prompV /* This software is copyright 1989 by John Dunning. See the file 'COPYLEFT.JRD' for the full copyright notice. */ y} /* rename a file */ int rename(old,new) char * old; char * new; { char str[80]; /* buffer for rename string z}*/ char * ptr; fn_default(old, 0, str); /* copy/default first name */ strcat(str, ","); /* put in the comma for a {}taridos */ if (ptr = strchr(new, ':')) ++ptr; /* skip the colon */ else ptr = new; strcat(str, ptr); |}strcat(str, "\n"); return(frename(str)); /* do the rename */ } colon */ else ptr = new; strcat(str, ptr); D#define NOARGC /* no arg count passing */ #define FIXARGC /* don't expect arg counts passed in */ /* ** reverse string in$~} place */ reverse(s) char *s; { char *j; int c; j = s + strlen(s) - 1; while(s < j) { c = *s; $} *s++ = *j; *j-- = c; } } har *j; int c; j = s + strlen(s) - 1; while(s < j) { c = *s; $+; ; Runtime code for scc65. ; assemble with atari.m65 and global.m65 .globl __start ; program lo memory boundary __start: (}; ; this is the first piece of actual generated code... ; jmp start ; so we don't need a start vector ; ; routines for inc/(}dec'ing sp ; ; .globl decsp2 ;decsp2: ; dec sp by 2 ; pha ; save a ; lda sp ; get sp lo ; sec ; sbc #2 ; sub 2 ; sta (}sp ; lda sp+1 ; get sp hi ; sbc #0 ; sub carry ; sta sp+1 ; pla ; get a back ; rts .globl addysp ; add Y to SP addysp:(} pha ; save A clc tya ; get the value adc sp ; add lo byte sta sp ; put it back bcc addysp_1 ; if no carry, we're(} done inc sp+1 ; inc hi byte addysp_1: pla ; get A back ; rts ; done jmp tstax ; return condition codes ; .globl in(}csp1 ;incsp1: ; ldy #1 ; bne addysp .globl incsp2 ; inc sp by 2 incsp2: ; do this by hand, cause it gets used a lot ; ldy (}#2 ; bne addysp inc sp bne *+4 inc sp+1 ; might as well do incsp1 here, as we have the code... .globl incsp1 incsp1: inc(} sp bne *+4 inc sp+1 rts .globl incsp3 ; inc sp by 3 incsp3: ldy #3 bne addysp .globl incsp4 ; inc sp by 4 incsp(}4: ldy #4 bne addysp .globl incsp5 ; inc sp by 5 incsp5: ldy #5 bne addysp .globl incsp6 ; inc sp by 6 incsp6: ldy(} #6 bne addysp .globl incsp7 ; inc sp by 7 incsp7: ldy #7 bne addysp .globl incsp8 ; inc sp by 8 incsp8: ldy #8 bn(}e addysp .globl subysp ; sub Y from SP subysp: pha ; save A sty tmp1 ; save the value lda sp ; get lo byte sec sb(}c tmp1 ; sub y val sta sp ; put it back ; wrong! ; bcs subysp_1 ; if carry, we're done ; dec sp+1 ; dec hi byte lda sp+1(} sbc #0 sta sp+1 subysp_1: pla ; get A back rts ; done .globl decsp1 decsp1: ldy #1 bne subysp .globl decsp2 de(}csp2: ; ; do this one by hand, cause it gets used a lot ; ; ldy #2 ; bne subysp pha sec lda sp sbc #2 sta sp lda sp+1 (}sbc #0 sta sp+1 pla rts .globl decsp3 decsp3: ldy #3 bne subysp .globl decsp4 decsp4: ldy #4 bne subysp .globl d(}ecsp5 decsp5: ldy #5 bne subysp .globl decsp6 decsp6: ldy #6 bne subysp .globl decsp7 decsp7: ldy #7 bne subysp .(}globl decsp8 decsp8: ldy #8 bne subysp ; ; ops for loading/indexing stack slots ; .globl ldaxysp ; load AX from SP@(Y) l(}daxysp: lda (sp),y ; get lo byte pha iny lda (sp),y ; get hi byte tax ; into x pla ; get lo byte back ; rts jmp (}tstax ; return cc ; .globl ldsrysp ; load SREG from SP@(Y) ;ldsrysp: ; pha ; save A ; lda (sp),y ; get lo byte ; sta sr(}eg ; store it ; iny ; lda (sp),y ; get hi byte ; sta sreg+1 ; store it ; pla ; get A back ; jsr ldaxysp ; just do the t(}hings we optimized ; jsr swapsreg ; out. ; rts .globl ldaysp ; load A from SP@(Y) ldaysp: ; zzz maybe do this on line?(} ldx #0 lda (sp),y bpl ldaysp_1 ; pos... ldx #$FF ldaysp_1: rts .globl ldauysp ; load A unsigned from SP@(Y) ldauysp:(} ; zzz maybe do this on line? ldx #0 lda (sp),y rts .globl locysp ; compute location of SP@(Y) in AX locysp: ldx sp+(}1 ; get hi byte clc ; set up for add tya ; get offset adc sp ; compute lo byte bcc locysp_1 inx ; add in carry l(}ocysp_1: rts .globl plocysp ; push addr y(sp) plocysp: jsr locysp jmp pushax ; ; routines for inc/dec'ing AX ; .glob(}l incax8 incax8: ldy #8 jmp indexax .globl incax7 incax7: ldy #7 jmp indexax .globl incax6 incax6: ldy #6 jmp indexax(} .globl incax5 incax5: ldy #5 jmp indexax .globl incax4 incax4: ldy #4 jmp indexax .globl incax3 incax3: ldy #7 jmp (}indexax .globl incax2 ; inc AX by 2 incax2: jsr incax1 ; inc it once, and fall thru .globl incax1 ; inc AX by 1 incax(}1: tay ; use Y as a temp iny tya bne incax1_1 ; if not zero, we're done inx ; inc top half incax1_1: ; rts ; done (} jmp tstax ; return cond codes ; .globl incaxi1 ; load AX indirect, and increment by 1 ;incaxi1: ; jsr ldaxi ; jmp incax1 (} ; .globl incaxi2 ; load AX indirect, and increment by 2 ;incaxi2: ; jsr ldaxi ; jmp incax2 ; .globl inci1spp ; load AX ind(}irect, inc 1, store thru SP@+ ;inci1spp: ; jsr incaxi1 ; jmp staxspp ; .globl inci2spp ; load AX indirect, inc 2, store thru(} SP@+ ;inci2spp: ; jsr incaxi2 ; jmp staxspp ; .globl decax2 ; dec AX by 2 decax2: jsr decax1 ; dec it once, and fall t(}hru .globl decax1 ; dec AX by 1 decax1: tay ; use Y as a temp dey tya cmp #$FF ; wrap? bne decax1_1 ; if not -1, w(}e're done dex ; dec top half decax1_1: ; rts ; done jmp tstax ; return cond codes ; .globl decaxi1 ; load AX indirec(}t, and decrement by 1 ;decaxi1: ; jsr ldaxi ; jmp decax1 ; .globl decaxi2 ; load AX indirect, and decrement by 2 ;decaxi2: (}; jsr ldaxi ; jmp decax2 ; .globl deci1spp ; load AX indirect, dec 1, store thru SP@+ ;deci1spp: ; jsr decaxi1 ; jmp staxspp(} ; .globl deci2spp ; load AX indirect, dec 2, store thru SP@+ ;deci2spp: ; jsr decaxi2 ; jmp staxspp ; ; push/pop things o(}n stack ; .globl push0 push0: lda #0 tax ; ... .globl pushax ; push AX pushax: jsr decsp2 ; dec sp ldy #0 ; get inde(}x sta (sp),y ; store lo byte pha ; save it txa ; get hi byte iny ; bump idx sta (sp),y ; store hi byte pla ; (}get A back rts ; done .globl popax ; pop stack into AX popax: ldy #0 lda (sp),y ; get lo byte pha ; stash it iny(} lda (sp),y ; get hi byte tax ; into x pla ; get lo byte back jmp incsp2 ; bump stack and return .globl popsreg (} ; pop stack into SREG popsreg: pha ; save A ldy #0 lda (sp),y ; get lo byte sta sreg ; store it iny lda (sp),y ; (}get hi byte sta sreg+1 ; store it pla ; get A back jmp incsp2 ; bump stack and return .globl pushwysp ; push a word(} from SP@(Y) pushwysp: ; pha ; save A ; txa ; pha ; save X lda (sp),y ; get lo byte pha ; Save it iny ; bump idx (} lda (sp),y ; get hi byte tax ; into X pla ; get back lo byte jsr pushax ; push that ; pla ; get original X ; tax (} ; into X ; pla ; get back original A rts .globl pushbysp ; push a byte from SP@(Y) pushbysp: lda (sp),y ; get lo byt(}e ldx #0 jsr pushax ; push that rts ; ; Various kinds of store operators ; .globl staxspidx ; store AX at SP@@(Y) staxs(}pidx: jsr staspic ; use common part pha iny lda tmp2 sta (ptr1),y tax pla jmp tstax .globl staspidx staspidx: jsr (}staspic ; use common part ldx tmp2 jmp tstax staspic: sta tmp1 stx tmp2 sty tmp3 jsr popax ; get the pointer sta ptr(}1 stx ptr1+1 ldy tmp3 lda tmp1 sta (ptr1),y rts .globl staxysp staxysp: sta (sp),y pha txa iny sta (sp),y pla (}jmp tstax .globl staysp staysp: sta (sp),y jmp tstax ; .globl stasreg ; store A thru SREG ;stasreg: ; ldy #0 ; sta (sreg(}),y ; rts ; .globl staxsreg ; store AX thru SREG ;staxsreg: ; ldy #0 ; sta (sreg),y ; store lo byte ; pha ; save A ; iny (}; bump idx ; txa ; get hi byte ; sta (sreg),y ; store it ; pla ; get A back ;; rts ; done ; jmp tstax ; return cc .g(}lobl staxspp ; store AX thru (sp), and pop staxspp: pha ; save A txa pha ; save X jsr popax ; pop addr into AX sta(} ptr1 ; save into a pointer stx ptr1+1 ldy #1 pla ; get hi byte back sta (ptr1),y ; store it tax ; back into X pla(} ; get lo byte dey sta (ptr1),y ; store it jmp tstax ; return cc .globl staspp ; store A thru (sp), and pop staspp: (} pha ; save A txa pha ; save X jsr popax ; pop addr into AX sta ptr1 ; save into a pointer stx ptr1+1 pla ; get(} X tax pla ; get lo byte ldy #0 sta (ptr1),y ; store it jmp tstax ; return cc ; ; Operations on AX ; .globl aslax(} ; shift AX left 1 aslax: asl A pha txa rol A tax pla rts ; .globl asrax ; shift AX right 1 ;asrax: ; pha ; txa ; p(}ha ; rol A ; get carry set right ; pla ; ror A ; do the real rotate ; tax ; pla ; ror A ; rts .globl ldaxi ; load AX ind(}irect thru AX ldaxi: sta tmpptr stx tmpptr+1 ldy #1 lda (tmpptr),y tax dey lda (tmpptr),y ; rts jmp tstax ; return c(}ond codes ; ; load A indirect thru AX ; .globl ldai ldai: sta tmpptr ; set pointer stx tmpptr+1 ldy #0 ; set idx lda (}(tmpptr),y ; get byte bpl ldai_1 ; pos... ldx #$FF rts ldai_1: ldx #0 ; rts jmp tstax ; return cond codes ; ; ldaui: l(}oad A (unsigned) from (AX) ; .globl ldaui ldaui: sta tmpptr ; set pointer stx tmpptr+1 ldx #0 ; set idx lda (tmpptr,x)(} ; get byte rts .globl negax ; negate ax negax: pha ; save A txa ; get X eor #$FF ; invert tax ; back to X pl(}a ; get A back eor #$FF ; invert clc adc #1 ; inc bcc negax_1 inx ; bump X negax_1: rts .globl lnegax ; logica(}l complement AX lnegax: stx tmp3 ora tmp3 beq lneg1 ; it's zero, so return 1 lda #0 tax rts lneg1: ldx #0 lda #1 rt(}s .globl complax ; one's complement AX complax: eor #$FF ; Not A pha txa eor #$FF ; Not X tax pla rts .globl i(}ndexax ; index in Y, add Y to AX indexax: sta tmp1 tya clc adc tmp1 bcc *+3 inx rts .globl plocidx ; push location(} of AX@(Y) plocidx: jsr indexax jmp pushax ; ; test (AX) ; ; .globl tstaxi ;tstaxi: ; jsr ldaxi ; and fall thru... ; ;(} test AX for nonzero-ness. return result in CC ; .globl tstax tstax: ; cmp #0 ; beq tstax_0 ; bpl tstax_p ; ; A was nega(}tive, try X ;tstax_0: ; A was 0, try X ; cpx #0 ;tstax_9: ; rts ;tstax_p: ; A was positive ; cpx #0 ; try X ; bpl tstax (} cpx #0 ; test X beq tstax_x0 ; 0, go see what A has rts tstax_x0: ; X was 0, try A cmp #0 ; test A bpl tstax_9 ; p(}os or zero is ok, just return ldy #1 ; force 'positive' tstax_9: rts ; done, just return .globl ldaxidx ; load AX fr(}om (AX)Y ldaxidx: jsr indexax ; compute address jmp ldaxi ; load indirect .globl ldaidx ; load A from (AX)Y ldaidx: j(}sr indexax ; compute address jmp ldai ; load indirect .globl ldauidx ; load A unsigned from (AX)Y ldauidx: jsr indexax(} ; compute address jmp ldaui ; load indirect .globl pushwidx ; push word at (AX)Y pushwidx: jsr indexax ; index jsr l(}daxi jmp pushax .globl pushbidx ; push byte at (AX)Y pushbidx: jsr indexax ; index jsr ldai jmp pushax ; ; operations(} on SREG ; .globl asltos asltos: jsr popsreg ; for optimized code .globl aslsreg ; shift SREG left AX times, result in A(}X aslsreg: cpx #0 ; X nonzero? bne aslsreg_0 ; no, just return 0 tay ; use Y as counter lda sreg+1 sta tmp1 ; use A (}and tmp1 as register lda sreg cpy #0 ; shift count 0? beq aslsreg_9 ; done shifting aslsreg_1: asl A ; shift A rol tmp(}1 dey ; dec counter bne aslsreg_1 aslsreg_9: ldx tmp1 ; get hi byte ; rts ; done jmp tstax aslsreg_0: lda #0 tax ;(} rts jmp tstax ; return status for optimized code .globl asrtos asrtos: jsr popsreg ; for optimized code .globl asrs(}reg ; shift SREG right by AX, result in AX asrsreg: cpx #0 ; X nonzero? bne aslsreg_0 ; no, just return 0 ; tax ; use X(} as counter ; php ; save Z flag, for zero counter ; lda sreg ; sta tmp1 ; use tmp1 and A as register ; lda sreg+1 ; and #$(}80 ; keep top bit ; sta tmp2 ; plp ; get Z flag back ; beq asrsreg_9 ; done shifting ;asrsreg_1: ; lsr A ; shift hi byte (}; ror tmp1 ; and lo byte ; ora tmp2 ; keep top bit ; dex ; dec counter ; bne asrsreg_1 ;asrsreg_9: ; tax ; put hi byte (}in X ; lda tmp1 ; and get lo byte ; rts ; this isn't right... test after loading AX... ; cmp #0 ; shift count 0? ; beq asl(}sreg_0 ; yes, return 0 tay ; use Y as shift counter lda sreg ldx sreg+1 ; get the value into AX cpy #0 beq asrsreg_9 (}; zero, return now ; cpx #0 ; test AX for minus-ness ; bpl *+5 ; jsr negax stx tmp1 ; leave hi byte in tmp1 asrsreg_1: ld(}x tmp1 ; get hi byte, cpx #$80 ; compare, to set carry bit if neg ror tmp1 ; shift hi byte, preserving hi bit ror A ;(} shift lo byte dey ; dec shift count bne asrsreg_1 ; 0? done ldx tmp1 ; get hi byte ; ldy sreg+1 ; original value nega(}tive? ; bpl *+5 ; jsr negax ; negate result asrsreg_9: jmp tstax ; return status for optimized code .globl addtos addtos(}: jsr popsreg ; for optimized code .globl addsreg ; add SREG to AX addsreg: clc adc sreg ; add lo byte pha txa adc (}sreg+1 ; add hi byte tax pla ; rts jmp tstax ; return status for optimized code ; .globl addimm ; add immediate follow(}ing word ;addimm: ; sta tmp1 ; save A ; stx tmp1+1 ; and X ; pla ; get return addr ; sta ptr1 ; pla ; sta ptr1+1 ; ldy #1(} ; lda (ptr1),y ; get lo byte ; clc ; adc tmp1 ; add to old A value ; sta tmp1 ; put it back ; iny ; lda (ptr1),y ; get hi (}byte ; adc tmp1+1 ; sta tmp1+1 ; clc ; adjust return addr ; lda ptr1 ; adc #3 ; so we can jump thru it ; sta ptr1 ; bcc *+(}4 ; inc ptr1+1 ; lda tmp1 ; get A back ; ldx tmp1+1 ; jmp (ptr1) .globl subtos subtos: jsr popsreg ; for optimized code (} .globl subsreg ; sub AX from SREG, result in AX subsreg: sta tmp1 stx tmp2 ; save AX lda sreg sec sbc tmp1 ; sub lo (}byte pha lda sreg+1 sbc tmp2 ; sub hi byte tax pla ; rts jmp tstax ; return status for optimized code ; .globl swaps(}reg ; swap AX and SREG ;swapsreg: ; sta tmp1 ; stx tmp2 ; lda sreg ; get lo byte ; ldx sreg+1 ; get hi byte ; ldy tmp1 ; st(}y sreg ; ldy tmp2 ; sty sreg+1 ; rts .globl ortos ortos: jsr popsreg ; for optimized code .globl orsreg ; OR sreg into (}AX orsreg: ora sreg pha txa ora sreg+1 tax pla ; rts jmp tstax ; return status for optimized code .globl xortos xor(}tos: jsr popsreg ; for optimized code .globl xorsreg ; XOR sreg into AX xorsreg: eor sreg pha txa eor sreg+1 tax pl(}a ; rts jmp tstax ; return status for optimized code .globl andtos andtos: jsr popsreg ; for optimized code .globl and(}sreg ; AND sreg into AX andsreg: and sreg pha txa and sreg+1 tax pla ; rts jmp tstax ; return status for optimized c(}ode ; .globl ldsr ; load sreg from following word ;ldsr: ; sta tmp1 ; save A ; pla ; get return addr ; sta ptr1 ; pla ; (}sta ptr1+1 ; ldy #1 ; lda (ptr1),y ; get lo byte ; sta sreg ; iny ; lda (ptr1),y ; get hi byte ; sta sreg+1 ; clc ; adjust (}return addr ; lda ptr1 ; adc #3 ; so we can jump thru it ; sta ptr1 ; bcc *+4 ; inc ptr1+1 ; lda tmp1 ; get A back ; jmp (p(}tr1) ; ; comparisons ; .globl axzerop axzerop: cmp #0 bne return1 cpx #0 bne return1 beq return0 .globl toseqax tose(}qax: jsr popsreg ; for optimized code .globl sregeqax ; SREG == AX sregeqax: cmp sreg ; A == sreg lo? bne return0 ; no(}pe, return 0 cpx sreg+1 ; X == sreg hi? bne return0 beq return1 .globl tosneax tosneax: jsr popsreg ; for optimized c(}ode .globl sregneax ; SREG != AX sregneax: cmp sreg ; A == sreg lo? bne return1 ; nope, return 1 cpx sreg+1 ; X == sre(}g hi? bne return1 beq return0 .globl tosltax tosltax: jsr popsreg ; for optimized code .globl sregltax ; SREG < AX sre(}gltax: ; really AX > SREG... cpx sreg+1 ; X < sreg hi? bmi return0 ; X < SR^ , return 0 bne return1 ; not =, so >; re(}turn 1 cmp sreg ; A < sreg lo? bcc return0 ; A < SR\, return 0 beq return0 bcs return1 .globl tosultax tosultax: jsr(} popsreg ; for optimized code .globl sregultax ; SREG u< AX sregultax: ; AX u> SREG cpx sreg+1 bcc return0 ; tos^ u< a(}x^ , return 0 bne return1 ; if ne, must be u>; return 1 cmp sreg bcc return0 beq return0 bcs return1 .globl tosleax t(}osleax: jsr popsreg ; for optimized code .globl sregleax ; SREG <= AX sregleax: ; AX >= SR cpx sreg+1 bmi return0 ; X(} < SR^, return 0 bne return1 ; X > SR^, return 1 cmp sreg bcc return0 ; u> , return 0 bcs return1 .globl tosuleax tos(}uleax: jsr popsreg ; for optimized code .globl sreguleax ; SREG u<= AX sreguleax: cpx sreg+1 bcc return0 ; X < SR^, ret(}urn 0 bne return1 ; X > SR^, return 1 cmp sreg bcc return0 bcs return1 ; ; return functions for comparison ops. these (}guys are careful ; to leave the condition codes correct for the AX value. Compiler ; depends on that when optimizing; beware(}! ; return1: ldx #0 lda #1 rts return0: lda #0 tax rts .globl tosgtax tosgtax: jsr popsreg ; for optimized code .(}globl sreggtax ; SREG > AX sreggtax: ; AX < SR cpx sreg+1 bmi return1 ; < , return 1 bne return0 ; not =, so >; return)} 0 cmp sreg bcc return1 ; < , return 1 bcs return0 .globl tosugtax tosugtax: jsr popsreg ; for optimized code .globl)} sregugtax ; SREG u> AX sregugtax: cpx sreg+1 bcc return1 ; < , return 1 bne return0 ; not =, so >; return 0 cmp sreg )}bcc return1 ; < , return 1 bcs return0 .globl tosgeax tosgeax: jsr popsreg ; for optimized code .globl sreggeax ; SREG)} >= AX sreggeax: ; AX <= SR cpx sreg+1 bmi return1 ; < , return 1 bne return0 ; not =, so >; return 0 cmp sreg bcc r)}eturn1 ; < , return 1 beq return1 bcs return0 .globl tosugeax tosugeax: jsr popsreg ; for optimized code .globl sregu)}geax ; AX u<= SREG sregugeax: cpx sreg+1 bcc return1 ; < , return 1 bne return0 ; not =, so >; return 0 cmp sreg bcc r)}eturn1 ; < , return 1 beq return1 bcs return0 ; kludgey constant for DIV, MOD ;onehalf: ; .byte $3F,$49,$99,$99,$99,$99 )} ; ; function ops ; .globl enterfun0 enterfun0: ldy #0 beq enterfun .globl enterfun1 enterfun1: ldy #1 bne enterfun )} .globl enterfun2 enterfun2: ldy #2 bne enterfun .globl enterfun3 enterfun3: ldy #3 bne enterfun .globl enterfun4 ent) }erfun4: ldy #4 bne enterfun .globl enterfun5 enterfun5: ldy #5 ; bne enterfun ; ; expect frame size in Y, push fp ; .g) }lobl enterfun enterfun: tya ; get arg count ; asl A ; clc ; adc sp ; add to sp ; pha ; lda sp+1 ; adc #0 ; tax ; pla ldx) } #0 ; just push arg count jmp pushax .globl exitfun ; exit a function. pop stack and rts exitfun: pha ; save A a sec) } ldy #0 lda (sp),y ; that's the pushed arg count asl A ; loses big for large arg counts... tay iny iny ; count the ) }word the count's stored in pla ; get it back jmp addysp ; pop that many word-sized things ; ; random stuff ; ; ; call)} value on in AX ; .globl callax callax: ; jsr popax ; pop function ptr ; jsr tos2ax ; get tos sta tmp1 stx tmp1+1 jmp ()}tmp1) ; jump there ; ; swap AX with TOS ; .globl swapstk swapstk: sta tmpptr stx tmpptr+1 ldy #1 ; index lda (sp),y )}tax lda tmpptr+1 sta (sp),y dey lda (sp),y pha lda tmpptr sta (sp),y pla rts ; whew! .globl pushwaxi pushwaxi: )} ; push word (ax) jsr ldaxi jmp pushax .globl pushbaxi ; push byte at (ax) pushbaxi: jsr ldai jmp pushax ; .globl ldax)}ysp ;ldaxysp: ; jsr locysp ; jmp ldaxi ; ; or ax with tos, pop ; ; .globl oraxtos ;oraxtos: ; ldy #0 ; ora (sp),y ; pha ; t)}xa ; iny ; ora (sp),y ; tax ; pla ; jmp incsp2 ; ; eor ax with tos, pop ; ; .globl eoraxtos ;eoraxtos: ; ldy #0 ; eor (sp),y )}; pha ; txa ; iny ; eor (sp),y ; tax ; pla ; jmp inc2sp ; ; and ax with tos, pop ; ; .globl andaxtos ;andaxtos: ; ldy #0 ; a)}nd (sp),y ; pha ; txa ; iny ; and (sp),y ; tax ; pla ; jmp inc2sp ; ; add Y to sp, leave result in AX ; ; .globl addrysp ;ad)}drysp: ; tya ; get offset ; clc ; set up for... ; adc sp ; add low byte ; pha ; lda sp+1 ; get hi byte ; adc #0 ; add)} carry ; tax ; xfer to x ; pla ; get a back ; rts ; done ; ; handler for case jump inst. ; .globl casejump casejump: )}; ; case table after the call to casejmp. val in AX. ; table is of the form ,,...,0. ; rts from casejmp )}for default case, else pop return addr ; addr and jmp to address ; sta tmp3 stx tmp4 ; save value pla ; get return addr)} sta ptr1 pla sta ptr1+1 ; store in ptr 1 inc ptr1 ; and adjust it, because of way 6502 works bne *+4 inc ptr1+1 case)}1: ldy #1 ; first see if at end lda (ptr1),y ; test address byte hi bne case2 ; nope, not yet dey lda (ptr1),y ; test )}address byte lo bne case2 ; oops, we're out of cases. compute return address; 2 + ptr1 clc lda ptr1 ; get lo byte adc #)}2 ; inc past the 0 sta ptr1 bcc *+4 ; deal with carry inc ptr1+1 jmp (ptr1) ; go there case2: ; test case value ag)}ainst this value ldy #3 lda (ptr1),y ; value hi cmp tmp4 ; match switchval hi? bne case3 ; no match, try next dey lda)} (ptr1),y ; val lo cmp tmp3 ; match switchval lo? bne case3 ; match! dey ; point at hi byte of addr lda (ptr1),y sta ) }ptr2+1 ; stuff in ptr to jump thru dey ; point at lo byte of addr lda (ptr1),y sta ptr2 jmp (ptr2) ; go there case3:)!} ; no match, try next case clause clc lda ptr1 ; get case ptr adc #4 ; add 4 sta ptr1 ; put it back bcc *+4 inc p)"}tr1+1 ; deal with carry jmp case1 ; and go try again ; ; save and restore AX ; .globl saveax saveax: sta svax stx svax)#}+1 rts .globl restax restax: lda svax ldx svax+1 jmp tstax ; ; support routines for runtime ; ;tos2ax: ; ldy #0 ;ytos2a)$}x: ; iny ; lda (sp),y ; tax ; dey ; lda (sp),y ; rts ; .globl popax ;popax: ; jsr tos2ax ; jsr inc2sp ; rts ; ; mult and)%} div, using fp routines ; ; .globl umul ;umul: ; unsigned multiply ; sta fr0 ; set up the first num ; stx fr0+1 ; jsr ifp)&} ; make a float out of it ; jsr fmove ; move to fr1 ; jsr popax ; get second arg ; sta fr0 ; set this one up ; stx fr0+1 )'}; jsr ifp ; floatify... ; jsr fmul ; mult them ; jsr fpi ; back to int ; lda fr0 ; ldx fr0+1 ; load it up ; rts ; and r)(}eturn .globl multos multos: jsr popsreg .globl smul ; signed multiply AX by SREG smul: ldy #0 sty tmp3 ; zap negative))} flag cpx #0 bpl *+7 inc tmp3 jsr negax sta tmpptr ; use sreg and tmpptr stx tmpptr+1 ; as regs lda sreg ldx sreg+1)*} bpl xsmul0 dec tmp3 jsr negax sta sreg stx sreg+1 xsmul0: lda #0 sta tmp1 ; tmp1/2 as accumulator sta tmp1+1 lda #)+}1 ; use A as bit mask against SREG xsmul1: bit sreg ; this bit in sreg set? beq xsmul2 ; nope, try next jsr xsmadd ; a),}dd AX val to accum xsmul2: asl tmpptr ; shift AX val left one rol tmpptr+1 asl A ; shift bitmask left one bcc xsmul1 ;)-} if bit not off end, keep working on lo byte lda #1 ; set up mask for hi byte xsmul3: bit sreg+1 ; this bit in sreg set? ).} beq xsmul4 ; nope, try next jsr xsmadd ; add AX val to accum xsmul4: asl tmpptr ; shift AX val left one rol tmpptr+1 )/}asl A ; shift bitmask left one bcc xsmul3 ; if not off end, keep working on hi byte ldx tmp1+1 ; load up accum lda tmp1)0} ldy tmp3 ; negate flag? beq xsmul9 jsr negax xsmul9: rts ; done! xsmadd: ; helper fun pha ; save bit mask cl)1}c lda tmpptr ; add AX value adc tmp1 ; to accumulator sta tmp1 lda tmpptr+1 adc tmp1+1 sta tmp1+1 pla ; get bitma)2}sk back rts ; done xsdiv0: ; error return lda #0 tax sta sreg sta sreg+1 rts .globl divtos divtos: jsr popsr)3}eg ; pop other value into sreg .globl sdiv ; signed divide SREG by AX, sdiv: ; result in AX, remainder in SREG ldy )4}#0 sty tmp3 ; zap denominator-negative flag sty tmp4 ; and numerator-negative flag jsr tstax ; AX zero? beq xsdiv0 ; )5}yup, give up now bpl xsdiv1 ; positive, it's ok inc tmp3 ; denom negative jsr negax ; negate it xsdiv1: sta ptr1 ; us)6}e tmpptr1 and SREG as regs stx ptr1+1 lda sreg ldx sreg+1 ; load up sreg jsr tstax ; what sort of value? beq xsdiv0 ;)7} zero, we lose bpl xsdiv2 ; positive, it's ok inc tmp4 ; set numerator-negative flag jsr negax ; negate it sta sreg s)8}tx sreg+1 xsdiv2: ldy #1 ; bit mask sty ptr2 dey sty ptr2+1 sty tmp1 ; use tmp1 as accum sty tmp1+1 ; ; shift ptr1 an)9}d ptr2 left until ptr1 is greater than SREG, ; then shift right until it's <= ; xsdiv3: lda ptr1+1 ; compare cmp sreg+1 ;):} p1 to sreg beq xsdiv3a ; eq, try second byte bcs xsdiv4 ; >, we're done shifting left bcc xsdiv3b ; <, shift left xsd);}iv3a: lda ptr1 cmp sreg ; compare lo byte beq xsdiv5 ; =, skip the right shift bcs xsdiv4 ; >, go right one xsdiv3b: )<}asl ptr1 ; shift p1 left 1 rol ptr1+1 asl ptr2 ; shift bitmask left one rol ptr2+1 jmp xsdiv3 ; round again. xsdiv4: )=} ; shift p1, mask right one lsr ptr1+1 ; shift p1 ror ptr1 lsr ptr2+1 ; shift bitmask ror ptr2 bcs xsdiv7a ; bit fel)>}l out end?!? ok, do exit processing ; ; whew! tmpptr1 (the divisor register) and tmpptr2 (the quotient bitmask) ; are now all)?} set to enter the divide loop ; xsdiv5: ; compare sreg to p1. if >=, subtract lda sreg+1 cmp ptr1+1 beq xsdiv5a ; try)@} lo byte bcs xsdiv6 ; >, go subtract bcc xsdiv7 ; <, go shift right xsdiv5a: lda sreg cmp ptr1 bcc xsdiv7 ; < go shif)A}t right xsdiv6: ; subtract p1 from sreg, and set bit in accum sec lda sreg ; subtract sbc ptr1 ; p1 sta sreg ; )B} from lda sreg+1 ; sreg sbc ptr1+1 sta sreg+1 lda ptr2 ; or ora tmp1 ; bitmask sta tmp1 ; into lda ptr2+1)C} ; quotient ora tmp1+1 sta tmp1+1 xsdiv7: lsr ptr1+1 ; shift p1 right ror ptr1 lsr ptr2+1 ror ptr2 bcc xsdiv5 ; )D}if no carry, round again xsdiv7a: ; ; done! ; lda tmp4 ; negate remainder? beq xsdiv8 lda sreg ldx sreg+1 jsr negax st)E}a sreg stx sreg+1 xsdiv8: lda tmp1 ldx tmp1+1 ldy tmp3 ; numerator neg... cpy tmp4 ; same as denom-neg? beq xsdiv9 ;)F} yes, skip the negate jsr negax xsdiv9: rts .globl modtos modtos: jsr divtos lda sreg ldx sreg+1 jmp tstax ; ; libra)G}ry routines ; .globl _strcpy _strcpy: jsr popax sta ptr1 stx ptr1+1 jsr popax sta ptr2 stx ptr2+1 ldy #0 strc1: lda)H} (ptr1),y sta (ptr2),y beq strc9 iny bne strc1 inc ptr1+1 inc ptr2+1 bne strc1 strc9: rts .globl _strlen _strlen: )I}jsr popax sta ptr1 stx ptr1+1 ldx #0 ; YX used as counter ldy #0 strlen1: lda (ptr1),y beq strlen9 iny bne strlen1 )J}inc ptr1+1 inx bne strlen1 strlen9: tya ; get low byte of counter, hi's all set rts ; ; find (char * str, int len, cha)K}r c) -> index ; ;_find: ; jsr tos2ax ; sta ptr1 ; stx ptr1+1 ; ldy #2 ; jsr ytos2ax ; sta tmp1 ; stx tmp1+1 ; ldy #4 ; jsr yt)L}os2ax ; gets char in A ; ldx #0 ; stx ptr2 ; use as counter here ; stx ptr2+1 ; ldy #0 ;find1: ; cmp (ptr1),y ; match? ;)M} beq find9 ; yup, return ; zzz ;find9: ; rts ; ; startup ; ;argv: ; .word 0,0,0,0,0,0,0,0 ; .word 0,0,0,0,0,0,0,0 start:)N} tsx stx origsp ; save system stk ptr ; ; lda #0 ; init stk ptr ; sta sp ; lda #$80 ; $80 for debugging... ; sta sp+1 ; )O} lda memtop ; memtop for real code sta sp lda memtop+1 sta sp+1 ; ; if running under SpartaDos, pass the command line to )P}_main ; lda $0700 ; check the sparta flag cmp #'S' beq startcmd ; nope, check for dos xl ; ; Try to guess what OS we're r)Q}unning under. ; Use the algorithm suggested by Dick Curzon. ; Look thru $0A. Should see a jmp, another jmp, ; and something )R}that's not a jump. ; ldy #0 lda (cpaloc),y cmp #$4C ; a jmp? bne start0 ; nope, give up ldy #3 lda (cpaloc),y cmp #$)S}4C ; a jmp? bne start0 ; nope ldy #6 lda (cpaloc),y cmp #$4C ; a jmp? beq start0 ; if yes, it's mydos or something )T}startcmd: ; ; parse command line etc. for now, assume Sparta or Dos XL ; clc lda cpaloc ; get pointer to adc #cpcmdb ; )U}cmd buf pha ; save lo byte lda cpaloc+1 adc #0 tax ; get hi byte pla ; get lo byte back jmp start1 start0: ; no c)V}ommand line, just pass null lda #0 tax start1: jsr pushax ; push the ptr ldy #1 ; 1 arg jsr __main ; ; fall thru to ex)W}it... ; rts ; done! ; .globl _exit _exit: ldx origsp txs ; rts jmp (dosvec) ; ; 1 arg jsr __main ; ; fall thru to ex(T; ; common rtn for read, write ; .globl __rwsetup __rwsetup: ldy #4 jsr ldaxysp ; get iocb sta tmp3 ; save it -Y}ldy #0 jsr ldaxysp ; get size php ; save cond codes, for zero-ness stx tmp2 ldx tmp3 ; iocb sta icbll,x lda t-Z}mp2 ; size hi sta icblh,x ldy #2 ; get buf addr jsr ldaxysp stx tmp2 ldx tmp3 sta icbal,x lda tmp2 sta icba-[}h,x jsr incsp6 ; pop args plp rts ; buf addr jsr ldaxysp stx tmp2 ldx tmp3 sta icbal,x lda tmp2 sta icba,- /* This software is copyright 1989 by John Dunning. See the file 'COPYLEFT.JRD' for the full copyright notice. */1]} /* standard startup piece for c programs. replace this by by supplying your own _main if you want... */ /* int 1^}_argv[16]; .. use PRNBUF instead */ int _argv = 0x3C0; /* Atari Rom OS's Printer buf, 32 bytes */ #ifdef parser /* th1_}e C parser. The .m65 one is in parselin.m65 */ static char ___ch; /* arg line parser. it's separate so it can be call1`}ed independently */ _parseline(line, argv) char * line; int * argv; { int nargs; char * p; nargs = 0; if ((1a}p = line) == 0) return(0); while (*p) /* while not at eos, scan */ { while (iswhite(___ch = *p)) *p++ = 0; /* za1b}p and skip whitespace */ if ((___ch == 0) || (___ch == '\n')) break; /* end of str, stop */ *argv++ = p; /* remember1c} the pointer */ ++nargs; while (!iswhite(*p)) ++p; /* find end of string */ } return(nargs); } #endif _main(c1d}mdline) char * cmdline; { main(_parseline(cmdline, _argv), _argv); } */ } return(nargs); } #endif _main(c0L /* cc65 stdio.h */ /* say we're running cc65 */ #define M6502 #define __CC65__ #define FILE char extern FILE * s5f}tdin; extern FILE * stdout; extern FILE * stderr; extern int errno; /* error number from open, etc */ #define EOF -1 5g}#define NULL 0 #define NEWLINE 0x9B #define YES 1 #define NO 0 no; /* error number from open, etc */ #define EOF -1 4CB%DOS SYSB*)DUP SYSBSOPEN C BWOTOI C B[PARSELINM65BiPMALLOC C BnREAD M65BsREADARGSC BxRENAME C B}REVERSE C BRUNTIME M65BXRWCOMMONM65B \STARTUP C BeSTDIO H BqSTDIO M65BSTRCAT C BSTRCHR M65BSTRCMP C BTIME C BTOASCII C BTOLOWER M65BTOUPPER M65BTPRINTF M65BUTOI C BWRITE M65BXTOI C ; ; This software is copyright 1989 by John Dunning. See the file ; 'COPYLEFT.JRD' for the full copyright notice. ; 9r} ; ; data and part of the code for Small-C io library ; this must be assembled with atari.m65 and global.m65 ; ; canne9s}d files. these are declared pointers to something, ; but they're really IOCBs. ; ; it'd be nice if we could make these be9t} on page 0... .globl _stdin _stdin: .word 0 ; default to screen/kbd .globl _stdout _stdout: .word 0 ; default t9u}o screen/kbd .globl _stderr _stderr: .word 0 ; default to screen/kbd .globl _errno _errno: .word 0 ; error numb9v}er ; ; ; internal helper fun for open routines. ; find a free iocb, return in x ; .globl findiocb findiocb: ldx #9w}$10 ; start at # 1 findiocb1: lda ichid,x ; get handler id cmp #$FF ; free? beq findiocb9 ; yup, return it txa 9x}clc adc #$10 ; next iocb tax cmp #$80 ; past last one? bcc findiocb1 ; nope, return it ldx #$FF ; return -1 fin9y}diocb9: rts ; ; copen(name, mode)->iocb # ; .globl _copen _copen: jsr popax ; get open mode sta tmp1 ; save i9z}t jsr popax ; get name sta fntemp stx fntemp+1 jsr findiocb ; try to find a free iocb bmi copenerr ; no free ones 9{} stx tmp4 lda tmp1 ; get open mode again cmp #'r ; read? bne copen1 lda #OPNIN ; open for input bne copen5 cop9|}en1: cmp #'w ; write? bne copen2 lda #OPNOT bne copen5 copen2: cmp #'a ; write append? bne copen3 lda #OPNOT9}}|APPEND bne copen5 copen3: cmp #'d ; directory? bne copenerr ; bogon, return err lda #OPNIN|DIRECT copen5: ldx9~} tmp4 sta icax1,x ; store open bits lda #0 sta icax2,x sta icbll,x sta icblh,x ; ; make sure the name's got an E9}OL at the end ; ldy #0 copen6: lda (fntemp),y and #$7F ; mask for non-inverted beq copen7 cmp #'a ; need to upc9}ase, for non-sparta dos'es bmi copen6a cmp #'z+1 bpl copen6a sec sbc #$20 ; subtract a space copen6a: ; sta cope9}nbuf,y sta casbuf,y ; use casbuf to save a little space iny bne copen6 copen7: lda #$9B ; sta copenbuf,y sta casb9}uf,y ; lda #copenbuf\ lda #casbuf\ sta icbal,x ; lda #copenbuf^ lda #casbuf^ sta icbah,x lda #open sta iccom,x 9} ; ; all set ; jsr ciov bpl copen8 ; ok, return it jmp ioreturn copen8: txa ; return iocb in ax ldx #0 rts 9} ; zzz copenerr: lda #$FF tax rts ;copenbuf: .byte " " ; ; common error vector for io t9}hings. do a JMP here right after calling ; CIOV. we expect status in Y. ; .globl ioreturn ioreturn: tya ; get retu9}rn code ldx #$FF ; return error sta _errno stx _errno+1 rts n Y. ; .globl ioreturn ioreturn: tya ; get retu8F#define FIXARGC #define NOARGC /* This software is copyright 1989 by John Dunning. See the file 'COPYLEFT.JRD' f=}or the full copyright notice. */ /* somebody ought to rewrite this in m65 code */ strcat(str1, str2) char * str1; char=} * str2; { strcpy(str1 + strlen(str1), str2); } to rewrite this in m65 code */ strcat(str1, str2) char * str1; char<6; ; strchr(str, chr); ; .globl _strchr _strchr: jsr popax ; get char sta tmp1 ; save it jsr popax ; get ptr sA}ta ptr1 stx ptr1+1 ldy #0 strchr1: lda (ptr1),y ; get a char bne strchrz ldx #0 ; oops! not found rts strchrz:A} cmp tmp1 ; match? bne strchr2 ; nope, keep searching ldx ptr1+1 ; hi byte of result tya ; compute lo byte clcA} adc ptr1 bcc *+3 inx jmp tstax ; return condition codes strchr2: iny ; bump index bne strchr1 inc ptr1+1 A} jmp strchr1 c *+3 inx jmp tstax ; return condition codes strchr2: iny ; bump index bne strchr1 inc ptr1+1 @#define NOARGC /* no arg count passing */ #define FIXARGC /* don't expect arg counts passed in */ /* This software iE}s copyright 1989 by John Dunning. See the file 'COPYLEFT.JRD' for the full copyright notice. */ /* return <0, E}0, >0 for st */ strcmp(s, t) char *s, *t; { while(*s == *t) { if(*s == 0) return (E}0); ++s; ++t; } return (*s - *t); } char *s, *t; { while(*s == *t) { if(*s == 0) return (D5#define NOARGC /* no arg count passing */ #define FIXARGC /* don't expect arg counts passed in */ /* This softwareI} is copyright 1989 by John Dunning. See the file 'COPYLEFT.JRD' for the full copyright notice. */ /* time-hackinI}g stuff */ #define RTCLOK ((char *)0x12) gtime(time) char * time; /* snapshot RTCLOK */ { time[0] = *(RTCLOK); I} time[1] = *(RTCLOK+1); time[2] = *(RTCLOK+2); } calctim(t0, xtime) char * t0; /* initial time */ char * xtime; I} /* 4 bytes, hr, min, sec, 60th */ { char t1[3]; int temp[4]; gtime(t1); /* get current time */ /* subtrace I}t0 from t1 */ #asm ldy #8 ; index of t1 jsr locysp ; point at it sta $E0 ; tmp ptr stx $E1 ldy #15 ; indeI}x of t0 jsr ldaxysp ; get pointer sta $D4 stx $D5 ldy #2 sec lda ($E0),y ; get t1 byte sbc ($D4),y ; I}sub t0 byte sta ($E0),y ; back in t1 dey lda ($E0),y ; get t1 byte sbc ($D4),y ; sub t0 byte sta ($E0),y ;I} back in t1 dey lda ($E0),y ; get t1 byte sbc ($D4),y ; sub t0 byte sta ($E0),y ; back in t1 #endasm /* tpI}rintf(" t1 %x %x %x\n", t1[0], t1[1], t1[2]); */ temp[3] = (t1[2] & 0x3F) * 100 / 64; /* compute hundreths */ temp[2I}] = ((t1[2] & 0xC0) / 64) | /* compute seconds */ ((t1[1] & 0xFF) * 4) | ((t1[0] & 0x1F) * 1024); tI}emp[1] = temp[2] / 60; /* ... minutes */ temp[2] = temp[2] % 60; temp[0] = temp[1] / 60; /* ... hours */ temp[1]I} = temp[1] % 60; /* tprintf(" temp %d %d %d %d\n", temp[0], temp[1], temp[2], temp[3]); */ xtime[0] = temp[0]; xtiI}me[1] = temp[1]; xtime[2] = temp[2]; xtime[3] = temp[3]; } [1], temp[2], temp[3]); */ xtime[0] = temp[0]; xtiHC#define NOARGC /* no arg count passing */ #define FIXARGC /* don't expect arg counts passed in */ /* return ASCII equiM}valent of c */ toascii(c) int c; { return (c); } /* don't expect arg counts passed in */ /* return ASCII equiL< .globl _tolower _tolower: jsr popax ; get the char cmp #'A ; < 'a'? bcc tolower9 ; yup, skip it cmp #'Z+1 ; > 'zQ} ? bcs tolower9 adc #$20 ; carry's already set tolower9: rts a'? bcc tolower9 ; yup, skip it cmp #'Z+1 ; > 'zPH .globl _toupper _toupper: jsr popax ; get the char cmp #'a ; < 'a'? bcc toupper9 ; yup, skip it cmp #'z+1 ; > 'zU} ? bcs toupper9 sec sbc #$20 toupper9: rts ar cmp #'a ; < 'a'? bcc toupper9 ; yup, skip it cmp #'z+1 ; > 'zT5; ; tiny printf etc. ; ; utils cconout: ; out char in a. bash regs ldx #0 pha ; save the char txa ; get a zerY}o sta icbal,x ; zap buf addr sta icbah,x sta icbll,x ; and buf len sta icblh,x lda #putchr ; say put a byte stY}a iccom,x pla ; get the byte again jsr ciov ; go do it rts pf_incs: ; inc str ptr inc ptr1 beq *+3 rts Y}inc ptr1+1 rts pf_nxta: ; get next arg sec ; dec arg ptr by 2 lda ptr2 sbc #2 sta ptr2 lda ptr2+1 sbc #0Y} sta ptr2+1 ldy #1 lda (ptr2),y ; get hi byte tax ; into x dey lda (ptr2),y ; get lo byte rts .globl _tpY}rintf _tprintf: sty argcnt ; save arg count lda argcnt asl A ; make an offset clc adc sp ; compute addr of ctlY} str + 2 sta ptr2 lda sp+1 adc #0 sta ptr2+1 ; jsr pf_nxta ; get control string sta ptr1 stx ptr1+1 ; ; maiY}n loop. ; printf0: ldy #0 lda (ptr1),y ; get a char bne *+5 jmp printf9 ; eos? go home cmp #'% ; a percent? bY}ne printf1 ; no, go print it jsr pf_incs ; bump control string ptr lda (ptr1),y ; get control char ; ; see what we haY}ve ; cmp #'s ; string? beq pf_str cmp #'d ; decimal? beq pf_dec cmp #'x ; hex? beq pf_hex cmp #'o ; octal?Y} beq pf_oct ; more later printf1: jsr cconout ; out the char printf2: jsr pf_incs ; bump control str jmp printf0Y} ; and go back for more pf_str: jsr pf_nxta ; get next arg sta ptr3 stx ptr3+1 pf_str1: ldy #0 lda (ptr3),y ; gY}et a char beq printf2 ; done, go home inc ptr3 bne *+4 inc ptr3+1 jsr cconout jmp pf_str1 pf_hex: jsr pf_nxtaY} ; get arg sta ptr3 stx ptr3+1 lda #4 sta tmp1 pf_hex1: lda ptr3+1 lsr A lsr A lsr A lsr A and #$0F tY}ax lda hex,x jsr cconout dec tmp1 ; dec counter beq pf_hex9 ; done! asl ptr3 rol ptr3+1 asl ptr3 rol ptr3+1Y} asl ptr3 rol ptr3+1 asl ptr3 rol ptr3+1 jmp pf_hex1 pf_hex9: jmp printf2 pf_oct: jmp printf2 pf_dec: jsr Y}pf_nxta ; get an arg sta fr0 stx fr0+1 ; set up to floatify cpx #0 ; neg? bpl pf_dec1 jsr negax sta fr0 ;Y} store it again stx fr0+1 lda #'- jsr cconout pf_dec1: jsr ifp jsr fasc ; ascify it ldy #0 sty tmp1 pf_dec2Y}: ldy tmp1 ; get idx lda (inbuff),y ; get a byte bmi pf_dec3 ; hi bit set? ok, done inc tmp1 jsr cconout jmpY} pf_dec2 pf_dec3: and #$7F ; mask it jsr cconout jmp printf2 printf9: lda argcnt ; get arg count asl A ; maY}ke it a byte count tay jmp addysp ; pop stack and return ; rts hex: .byte "0123456789ABCDEF" ; that's all ; maXv#define NOARGC /* no arg count passing */ #define FIXARGC /* don't expect arg counts passed in */ #include /* ]} utoi -- convert unsigned decimal string to integer nbr returns field size, else ERR on error */ #define ERR]} -1 utoi(decstr, nbr) char *decstr; int *nbr; { int d,t; d=0; *nbr=0; while((*decstr>='0')&(*decstr<='9'))]} { t=*nbr;t=(10*t) + (*decstr++ - '0'); if ((t>=0)&(*nbr<0)) return ERR; d++; *nbr=t; } return d]}; } { t=*nbr;t=(10*t) + (*decstr++ - '0'); if ((t>=0)&(*nbr<0)) return ERR; d++; *nbr=t; } return d\; ; write(iocb, buf, nbytes)->nbytes written ; .globl _write _write: jsr __rwsetup ; do common setup beq write9 ; ia}f size 0, it's a no-op lda #putchr sta iccom,x jsr ciov bpl write9 jmp ioreturn ; do common error vector stuff wria}te9: lda icbll,x ; get buf len lo pha lda icblh,x ; buf len hi tax pla rts ; do common error vector stuff wri`[#define NOARGC /* no arg count passing */ #define FIXARGC /* don't expect arg counts passed in */ #include /* e} xtoi -- convert hex string to integer nbr returns field size, else ERR on error */ /* what should this be?e}? -- jrd */ #define ERR -1 xtoi(hexstr, nbr) char *hexstr; int *nbr; { int d, b; char *cp; d = *nbr = 0; cp e}= hexstr; while(*cp == '0') ++cp; while(1) { switch(*cp) { case '0': case '1': case '2': e} case '3': case '4': case '5': case '6': case '7': case '8': case '9': b=48; break; e} case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': b=55; break; case 'a': case 'b': case 'c': e} case 'd': case 'e': case 'f': b=87; break; default: return (cp - hexstr); } if(d < 4) ++d; else return (e}ERR); *nbr = (*nbr << 4) + (*cp++ - b); } } ult: return (cp - hexstr); } if(d < 4) ++d; else return (d8