@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;; itoa(i, s);; .globl _itoa_itoa: jsr popax ; get string addr sta ptr1 stx ptr1+1 jsr popax ; geT}t number sta fr0 stx fr0+1 ; set up to floatify cpx #0 ; neg? bpl itoa_1 jsr negax sta fr0 ;U} store it again stx fr0+1 lda #'- ldy #0 sta (ptr1),y ; stuff the neg sign inc ptr1 bne itoa_1 inc ptV}r1+1itoa_1: jsr ifp ; floatify it jsr fasc ; ascify it ldy #0itoa_2: lda (inbuff),y ; get a byte W} bmi itoa_3 ; hi bit set? ok, done sta (ptr1),y ; stash in caller's buffer iny jmp itoa_2itoa_3: and #$7X}F ; mask it sta (ptr1),y ; stash it lda #0 iny sta (ptr1),y rtsr iny jmp itoa_2itoa_3: and #$7U#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//*** itoab(n,s,b) - Conve Z}rt "unsigned" n to characters in s using base b.** NOTE: This is a non-standard function.*/itoab(n, s, b) [}int n; char *s; int b; $( char *ptr; int lowbit; ptr = s; b >>= 1; do $( lowbit = n & 1; n = (n >> 1) & \}32767; *ptr = ((n % b) << 1) + lowbit; if(*ptr < 10) *ptr += '0'; else *ptr += 55; ++ptr; $) while(n /= b); ]} *ptr = 0; reverse (s);$)1) + lowbit; if(*ptr < 10) *ptr += '0'; else *ptr += 55; ++ptr; $) while(n /= b); #define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in */#include /*** i_}tod -- convert nbr to signed decimal string of width sz** right adjusted, blank filled; returns str**** if `}sz > 0 terminate with null byte** if sz = 0 find end of string** if sz < 0 use last byte for data*/itod(nbra}, str, sz) int nbr; char str[]; int sz; $( char sgn; if(nbr<0) $(nbr = -nbr; sgn='-';$) else sgn=' '; if(sz>0b}) str[--sz]=NULL; else if(sz<0) sz = -sz; else while(str[sz]!=NULL) ++sz; while(sz) $( str[--sz]=(nbr%10+'0');c} if((nbr=nbr/10)==0) break; $) if(sz) str[--sz]=sgn; while(sz>0) str[--sz]=' '; return str;$)z]=(nbr%10+'0');m#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//*** itoo -- converts nbre} to octal string of length sz** right adjusted and blank filled, returns str**** if sz > 0 terminate with nf}ull byte** if sz = 0 find end of string** if sz < 0 use last byte for data*/itoo(nbr, str, sz) int nbr; g}char str[]; int sz; $( int digit; if(sz>0) str[--sz]=0; else if(sz<0) sz = -sz; else while(str[sz]!=0) ++sz; wh}hile(sz) $( digit=nbr&7; nbr=(nbr>>3)&8191; str[--sz]=digit+48; if(nbr==0) break; $) while(sz) str[--si}z]=' '; return str;$)t=nbr&7; nbr=(nbr>>3)&8191; str[--sz]=digit+48; if(nbr==0) break; $) while(sz) str[--s#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in */#include /*** ik}tou -- convert nbr to unsigned decimal string of width sz** right adjusted, blank filled; returns str**** il}f sz > 0 terminate with null byte** if sz = 0 find end of string** if sz < 0 use last byte for data*/itou(nm}br, str, sz) int nbr; char str[]; int sz; $( int lowbit; if(sz>0) str[--sz]=NULL; else if(sz<0) sz = -sz; elsn}e while(str[sz]!=NULL) ++sz; while(sz) $( lowbit=nbr&1; nbr=(nbr>>1)&32767; /* divide by 2 */ str[--sz]=(o}(nbr%5)<<1)+lowbit+'0'; if((nbr=nbr/5)==0) break; $) while(sz) str[--sz]=' '; return str;$)2 */ str[--sz]=(i#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//*** itox -- converts nbrq} to hex string of length sz** right adjusted and blank filled, returns str**** if sz > 0 terminate with nulr}l byte** if sz = 0 find end of string** if sz < 0 use last byte for data*/itox(nbr, str, sz) int nbr; cs}har str[]; int sz; $( int digit, offset; if(sz>0) str[--sz]=0; else if(sz<0) sz = -sz; else while(str[sz]!=0) ++st}z; while(sz) $( digit=nbr&15; nbr=(nbr>>4)&4095; if(digit<10) offset=48; else offset=55; str[--sz]=digit+ou}ffset; if(nbr==0) break; $) while(sz) str[--sz]=' '; return str;$)set=48; else offset=55; str[--sz]=digit+oP/* open kludge */#include int open(name, mode)char * name;int mode;$( char copen_mode; if (mode & O_RDON w}LY) copen_mode = 'r'; else if (mode & O_WRONLY) copen_mode = 'w'; else /* error */ return(-1); return(cop x}en(name, copen_mode));$) lse if (mode & O_WRONLY) copen_mode = 'w'; else /* error */ return(-1); return(cop #define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in */#include /*** o$z}toi -- convert unsigned octal string to integer nbr** returns field size, else ERR on error*/otoi(octstr, nbr) ${}char *octstr; int *nbr; $( int d,t; d=0; *nbr=0; while((*octstr>='0')&(*octstr<='7')) $( t=*nbr; t=(t<$|}<3) + (*octstr++ - '0'); if ((t>=0)&(*nbr<0)) return ERR; d++; *nbr=t; $) return d;$)$( t=*nbr; t=(t<$e;; 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 bne parse1 ; test line pointer for zero-ness... lda ptr1 beq parse8parse1: ; skip whitespace l(}dy #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 bcc parse2 ; not whiteparse1w: inc ptr1 ; bump string ptr bne parse1 inc p(}tr1+1 bne parse1parse2: ; remember the ptr, bump arg count ldy #0 lda ptr1 sta (ptr2),y ; store ptr lo(} iny lda ptr1+1 sta (ptr2),y ; ... ptr hi inc tmp1 ; and bump arg count clc lda ptr2 adc #2 ; bump a(}rgv ptr sta ptr2 bcc parse3 inc ptr2+1parse3: ; find next whitespace ldy #0 lda (ptr1),y ; get a cha(}r beq parse8 ; nul, we're done jsr white_p ; white? bcs parse4 ; yes, found end of this arg inc ptr1 b(}ne parse3 inc ptr1+1 bne parse3parse4: pha ; save the char for a sec lda #0 sta (ptr1),y ; zap in eos (} pla ; get orig char back beq parse8 ; done! cmp #$9B bne parse1w ; nope, go bump ptr and keep scanning(}parse8: ; load up arg count and return ldx #0 lda tmp1 rts;; return cond codes carry set if white, clear if(} non-white;white_p: cmp #$7F ; > 7F? bcs w_ret1 ; yes, that's white cmp #$21 ; <= space? bcs w_ret0 (} ; no, it's data.w_ret1: sec rtsw_ret0: clc rts ; yes, that's white cmp #$21 ; <= space? bcs w_ret0 (:#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//* * homebrew memory man,}agement routines, by jrd *//* these vars defined in heap.m65 */extern int _himem; /* pointer to next unused mem */,}/* permanent alloc */pmalloc(nbytes)int nbytes;$( int ptr; ptr = _himem; /* get current ptr */ _himem += nbytes;,} /* move up by nbytes */ return(ptr);$)tes;$( int ptr; ptr = _himem; /* get current ptr */ _himem += nbytes;,-;; read(iocb, buf, size)->real size read; .globl _read_read: jsr __rwsetup ; do common setup for read and write b0}eq read9 ; if size 0, it's a no-op lda #getchr ; iocb command code sta iccom,x jsr ciov ; read it bpl r0}ead9 cpy #$88 ; eof is treated specially beq read9 jmp ioreturn ; do common error stuffread9: lda icbll,x 0} ; buf len lo pha ; save it lda icblh,x ; get buf len hi tax ; in x pla ; get lo byte back rt0}s;buf len lo pha ; save it lda icblh,x ; get buf len hi tax ; in x pla ; get lo byte back rt0#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//* handy util for 8-bitte4}rs. handed a prompt string, prompt with it, and read an arg string. parse it into the passed argv */#include 4}int readargs(prompt, buf, argv)char * prompt;char * buf;char ** argv;$( fputs(prompt, stderr); /* prompt */ fgets(4}buf, 80, stderr); /* get a buf */ return(_parseline(buf, argv));$)gv;$( fputs(prompt, stderr); /* prompt */ fgets(4G-*- Mode: Text -*- This is the readme file for libsrc.arc and libsrc-a.arc. This is the latest library sourcecode for8} CC65, as of 10/12/89. Allknown bugs have been fixed. Due to popular demand, I've madetwo versions of this arc; one con8}-taining Ascii files (libsrc), and the other Atascii (libsrc-a). Thedata is identical, other than that. As before, thi8}s stuff is copyleft1989 by JRD; please read copyleft.jrdfor details. Help stamp out softwarehoarding!t. As before, thi8i/* rename a file */int rename(old,new)char * old;char * new;$( char str[80]; /* buffer for rename string */ ch<}ar * ptr; fn_default(old, 0, str); /* copy/default first name */ strcat(str, ","); /* put in the comma for ataridos <}*/ if (ptr = strchr(new, ':')) ++ptr; /* skip the colon */ else ptr = new; strcat(str, ptr); strcat(str,<} "\n"); return(frename(str)); /* do the rename */$) the colon */ else ptr = new; strcat(str, ptr); strcat(str,<8#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//*** reverse string in pl@}ace */reverse(s) char *s; $( char *j; int c; j = s + strlen(s) - 1; while(s < j) $( c = *s; *s++ = *@}j; *j-- = c; $)$) $( char *j; int c; j = s + strlen(s) - 1; while(s < j) $( c = *s; *s++ = *@;; Runtime code for scc65.; assemble with atari.m65 and global.m65 .globl __start ; program lo memory boundary__staD}rt:;; this is the first piece of actual generated code...; jmp start ; so we don't need a start vector;; routines D}for inc/dec'ing sp;; .globl decsp2;decsp2: ; dec sp by 2; pha ; save a; lda sp ; get sp lo; sec;D} sbc #2 ; sub 2; sta sp; lda sp+1 ; get sp hi; sbc #0 ; sub carry; sta sp+1; pla ; get a back;D} rts .globl addysp ; add Y to SPaddysp: pha ; save A clc tya ; get the value adc sp ; add lo bD}yte sta sp ; put it back bcc addysp_1 ; if no carry, we're done inc sp+1 ; inc hi byteaddysp_1: pla ;D} get A back; rts ; done jmp tstax ; return condition codes; .globl incsp1;incsp1:; ldy #1; bne addyspD} .globl incsp2 ; inc sp by 2incsp2:; do this by hand, cause it gets used a lot; ldy #2; bne addysp inc sp D} bne *+4 inc sp+1; might as well do incsp1 here, as we have the code... .globl incsp1incsp1: inc sp bne *+4 D}inc sp+1 rts .globl incsp3 ; inc sp by 3incsp3: ldy #3 bne addysp .globl incsp4 ; inc sp by 4incD}sp4: ldy #4 bne addysp .globl incsp5 ; inc sp by 5incsp5: ldy #5 bne addysp .globl incsp6 ; inc spD} by 6incsp6: ldy #6 bne addysp .globl incsp7 ; inc sp by 7incsp7: ldy #7 bne addysp .globl incsp8 D} ; inc sp by 8incsp8: ldy #8 bne addysp .globl subysp ; sub Y from SPsubysp: pha ; save A sty tmp1 D} ; save the value lda sp ; get lo byte sec sbc tmp1 ; sub y val sta sp ; put it back; wrong!; bcs suD}bysp_1 ; if carry, we're done; dec sp+1 ; dec hi byte lda sp+1 sbc #0 sta sp+1subysp_1: pla ; get A bD}ack rts ; done .globl decsp1decsp1: ldy #1 bne subysp .globl decsp2decsp2:;; do this one by hand, caD}use it gets used a lot;; ldy #2; bne subysp pha sec lda sp sbc #2 sta sp lda sp+1 sbc #0 sta sp+D}1 pla rts .globl decsp3decsp3: ldy #3 bne subysp .globl decsp4decsp4: ldy #4 bne subysp .globl D}decsp5decsp5: ldy #5 bne subysp .globl decsp6decsp6: ldy #6 bne subysp .globl decsp7decsp7: ldy #7D} bne subysp .globl decsp8decsp8: ldy #8 bne subysp;; ops for loading/indexing stack slots; .globl ldaxyspD} ; load AX from SP@(Y)ldaxysp: lda (sp),y ; get lo byte pha iny lda (sp),y ; get hi byte tax ; intD}o x pla ; get lo byte back; rts jmp tstax ; return cc; .globl ldsrysp ; load SREG from SP@(Y);ldsrysp:D}; pha ; save A; lda (sp),y ; get lo byte; sta sreg ; store it; iny; lda (sp),y ; get hi byte; stD}a sreg+1 ; store it; pla ; get A back; jsr ldaxysp ; just do the things we optimized; jsr swapsreg ; ouD}t.; rts .globl ldaysp ; load A from SP@(Y)ldaysp: ; zzz maybe do this on line? ldx #0 lda (sp),y rtsD} .globl locysp ; compute location of SP@(Y) in AXlocysp: ldx sp+1 ; get hi byte clc ; set up for add tD}ya ; get offset adc sp ; compute lo byte bcc locysp_1 inx ; add in carrylocysp_1: rts .globl plocD}ysp ; push addr y(sp)plocysp: jsr locysp jmp pushax ;; routines for inc/dec'ing AX; .globl incax8incax8: D} ldy #8 jmp indexax .globl incax7incax7: ldy #7 jmp indexax .globl incax6incax6: ldy #6 jmp indexax D} .globl incax5incax5: ldy #5 jmp indexax .globl incax4incax4: ldy #4 jmp indexax .globl incax3incax3: D} ldy #7 jmp indexax .globl incax2 ; inc AX by 2incax2: jsr incax1 ; inc it once, and fall thru .globl iD}ncax1 ; inc AX by 1incax1: tay ; use Y as a temp iny tya bne incax1_1 ; if not zero, we're done inx D} ; inc top halfincax1_1:; rts ; done jmp tstax ; return cond codes; .globl incaxi1 ; load AX indirect, aD}nd increment by 1;incaxi1:; jsr ldaxi; jmp incax1; .globl incaxi2 ; load AX indirect, and increment by 2;incaxD}i2:; jsr ldaxi; jmp incax2; .globl inci1spp ; load AX indirect, inc 1, store thru SP@+;inci1spp:; jsr incaxi1D}; jmp staxspp; .globl inci2spp ; load AX indirect, inc 2, store thru SP@+;inci2spp:; jsr incaxi2; jmp staxspp D} ; .globl decax2 ; dec AX by 2decax2: jsr decax1 ; dec it once, and fall thru .globl decax1 ; dec AX by D}1decax1: tay ; use Y as a temp dey tya cmp #$FF ; wrap? bne decax1_1 ; if not -1, we're done dex D} ; dec top halfdecax1_1:; rts ; done jmp tstax ; return cond codes; .globl decaxi1 ; load AX indirect, aD}nd decrement by 1;decaxi1:; jsr ldaxi; jmp decax1; .globl decaxi2 ; load AX indirect, and decrement by 2;decaxD}i2:; jsr ldaxi; jmp decax2; .globl deci1spp ; load AX indirect, dec 1, store thru SP@+;deci1spp:; jsr decaxi1D}; jmp staxspp; .globl deci2spp ; load AX indirect, dec 2, store thru SP@+;deci2spp:; jsr decaxi2; jmp staxspp D} ;; push/pop things on stack; .globl push0push0: lda #0 tax; ... .globl pushax ; push AXpushax: jsr deD}csp2 ; dec sp ldy #0 ; get index sta (sp),y ; store lo byte pha ; save it txa ; get hi byte inD}y ; bump idx sta (sp),y ; store hi byte pla ; get A back rts ; done .globl popax ; pop stack D}into AXpopax: ldy #0 lda (sp),y ; get lo byte pha ; stash it iny lda (sp),y ; get hi byte tax D} ; into x pla ; get lo byte back jmp incsp2 ; bump stack and return .globl popsreg ; pop stack into SRED}Gpopsreg: pha ; save A ldy #0 lda (sp),y ; get lo byte sta sreg ; store it iny lda (sp),y ; geD}t hi byte sta sreg+1 ; store it pla ; get A back jmp incsp2 ; bump stack and return .globl pushwysp D} ; push a word from SP@(Y)pushwysp:; pha ; save A; txa; pha ; save X lda (sp),y ; get lo byte pha D} ; Save it iny ; bump idx lda (sp),y ; get hi byte tax ; into X pla ; get back lo byte jsr puD}shax ; push that; pla ; get original X; tax ; into X; pla ; get back original A rts .globl pushD}bysp ; push a byte from SP@(Y)pushbysp: lda (sp),y ; get lo byte ldx #0 jsr pushax ; push that rts;; VaD}rious kinds of store operators; .globl staxspidx ; store AX at SP@@(Y)staxspidx: jsr staspic ; use common part D}pha iny lda tmp2 sta (ptr1),y tax pla jmp tstax .globl staspidxstaspidx: jsr staspic ; use common paD}rt ldx tmp2 jmp tstaxstaspic: sta tmp1 stx tmp2 sty tmp3 jsr popax ; get the pointer sta ptr1 stx D} ptr1+1 ldy tmp3 lda tmp1 sta (ptr1),y rts .globl staxyspstaxysp: sta (sp),y pha txa iny sta (sD}p),y pla jmp tstax .globl stayspstaysp: sta (sp),y jmp tstax; .globl stasreg ; store A thru SREG;stasrD}eg:; ldy #0; sta (sreg),y; rts; .globl staxsreg ; store AX thru SREG;staxsreg:; ldy #0; sta (sreg),y ; stD}ore lo byte; pha ; save A; iny ; bump idx; txa ; get hi byte; sta (sreg),y ; store it; pla ; D}get A back;; rts ; done; jmp tstax ; return cc .globl staxspp ; store AX thru (sp), and popstaxspp: phD}a ; save A txa pha ; save X jsr popax ; pop addr into AX sta ptr1 ; save into a pointer stx ptr1D}+1 ldy #1 pla ; get hi byte back sta (ptr1),y ; store it tax ; back into X pla ; get lo byte deD}y sta (ptr1),y ; store it jmp tstax ; return cc .globl staspp ; store A thru (sp), and popstaspp: pha D} ; save A txa pha ; save X jsr popax ; pop addr into AX sta ptr1 ; save into a pointer stx ptr1+1 D}pla ; get X tax pla ; get lo byte ldy #0 sta (ptr1),y ; store it jmp tstax ; return cc ;; OpeD}rations on AX; .globl aslax ; shift AX left 1aslax: asl A pha txa rol A tax pla rts; .globl asraxD} ; shift AX right 1;asrax:; pha; txa; pha; rol A ; get carry set right; pla; ror A ; do the real rotaD}te; tax; pla; ror A; rts .globl ldaxi ; load AX indirect thru AXldaxi: sta tmpptr stx tmpptr+1 ldy D}#1 lda (tmpptr),y tax dey lda (tmpptr),y; rts jmp tstax ; return cond codes;; load A indirect thru AX;D} .globl ldaildai: sta tmpptr ; set pointer stx tmpptr+1 ldy #0 ; set idx lda (tmpptr),y ; get byte bpD}l ldai_1 ; pos... ldx #$FF rtsldai_1: ldx #0; rts jmp tstax ; return cond codes .globl negax ; neD}gate axnegax: pha ; save A txa ; get X eor #$FF ; invert tax ; back to X pla ; get A backD} eor #$FF ; invert clc adc #1 ; inc bcc negax_1 inx ; bump Xnegax_1: rts .globl lnegax ; logD}ical complement AXlnegax: stx tmp3 ora tmp3 beq lneg1 ; it's zero, so return 1 lda #0 tax rtslneg1: ldD}x #0 lda #1 rts .globl complax ; one's complement AXcomplax: eor #$FF ; Not A pha txa eor #$FF D} ; Not X tax pla rts .globl indexax ; index in Y, add Y to AXindexax: sta tmp1 tya clc adc tmp1 bccD} *+3 inx rts .globl plocidx ; push location of AX@(Y)plocidx: jsr indexax jmp pushax;; test (AX);; .D}globl tstaxi;tstaxi:; jsr ldaxi ; and fall thru...;; test AX for nonzero-ness. return result in CC; .globlD} tstaxtstax:; cmp #0; beq tstax_0; bpl tstax_p; ; A was negative, try X;tstax_0: ; A was 0, try X; D} cpx #0;tstax_9:; rts;tstax_p: ; A was positive; cpx #0 ; try X; bpl tstax cpx #0 ; test X beq tD}stax_x0 ; 0, go see what A has rtststax_x0: ; X was 0, try A cmp #0 ; test A bpl tstax_9 ; pos or zero iD}s ok, just return ldy #1 ; force 'positive'tstax_9: rts ; done, just return .globl ldaxidx ; load AX frD}om (AX)Yldaxidx: jsr indexax ; compute address jmp ldaxi ; load indirect .globl ldaidx ; load A from (AX)D}Yldaidx: jsr indexax ; compute address jmp ldai ; load indirect .globl pushwidx ; push word at (AX)YpushwiD}dx: jsr indexax ; index jsr ldaxi jmp pushax .globl pushbidx ; push byte at (AX)Ypushbidx: jsr indexax D} ; index jsr ldai jmp pushax;; operations on SREG; .globl asltosasltos: jsr popsreg ; for optimized codeD} .globl aslsreg ; shift SREG left AX times, result in AXaslsreg: cpx #0 ; X nonzero? bne aslsreg_0 ; no, jusD}t return 0 tay ; use Y as counter lda sreg+1 sta tmp1 ; use A and tmp1 as register lda sreg cpy #0 ;D} shift count 0? beq aslsreg_9 ; done shiftingaslsreg_1: asl A ; shift A rol tmp1 dey ; dec counter bneD} aslsreg_1aslsreg_9: ldx tmp1 ; get hi byte; rts ; done jmp tstaxaslsreg_0: lda #0 tax; rts jD}mp tstax ; return status for optimized code .globl asrtosasrtos: jsr popsreg ; for optimized code .globl asE}rsreg ; shift SREG right by AX, result in AXasrsreg: cpx #0 ; X nonzero? bne aslsreg_0 ; no, just return 0; tE}ax ; use X as counter; php ; save Z flag, for zero counter; lda sreg; sta tmp1 ; use tmp1 and A as regisE}ter; lda sreg+1; and #$80 ; keep top bit; sta tmp2; plp ; get Z flag back; beq asrsreg_9 ; done shiftiE}ng;asrsreg_1:; lsr A ; shift hi byte; ror tmp1 ; and lo byte; ora tmp2 ; keep top bit; dex ; dec coE}unter; bne asrsreg_1;asrsreg_9:; tax ; put hi byte in X; lda tmp1 ; and get lo byte; rts; this isn't riE}ght... test after loading AX...; cmp #0 ; shift count 0?; beq aslsreg_0 ; yes, return 0 tay ; use Y as shiftE} counter lda sreg ldx sreg+1 ; get the value into AX cpy #0 beq asrsreg_9 ; zero, return now; cpx #0 ; E}test AX for minus-ness; bpl *+5; jsr negax stx tmp1 ; leave hi byte in tmp1asrsreg_1: ldx tmp1 ; get hi byE}te, cpx #$80 ; compare, to set carry bit if neg ror tmp1 ; shift hi byte, preserving hi bit ror A ; shift E }lo byte dey ; dec shift count bne asrsreg_1 ; 0? done ldx tmp1 ; get hi byte; ldy sreg+1 ; original vaE }lue negative?; bpl *+5; jsr negax ; negate resultasrsreg_9: jmp tstax ; return status for optimized code .E }globl addtosaddtos: jsr popsreg ; for optimized code .globl addsreg ; add SREG to AXaddsreg: clc adc sregE } ; add lo byte pha txa adc sreg+1 ; add hi byte tax pla; rts jmp tstax ; return status for optimizedE } code; .globl addimm ; add immediate following word;addimm:; sta tmp1 ; save A; stx tmp1+1 ; and X; plaE} ; get return addr; sta ptr1; pla; sta ptr1+1; ldy #1; lda (ptr1),y ; get lo byte; clc; adc tmp1 E}; add to old A value; sta tmp1 ; put it back; iny; lda (ptr1),y ; get hi byte; adc tmp1+1; sta tmp1+1; clE}c ; adjust return addr; lda ptr1; adc #3 ; so we can jump thru it; sta ptr1; bcc *+4; inc ptr1+1; ldE}a tmp1 ; get A back; ldx tmp1+1; jmp (ptr1) .globl subtossubtos: jsr popsreg ; for optimized code .gloE}bl subsreg ; sub AX from SREG, result in AXsubsreg: sta tmp1 stx tmp2 ; save AX lda sreg sec sbc tmp1 E} ; sub lo byte pha lda sreg+1 sbc tmp2 ; sub hi byte tax pla; rts jmp tstax ; return status for optimE}ized code; .globl swapsreg ; swap AX and SREG;swapsreg:; sta tmp1; stx tmp2; lda sreg ; get lo byte; ldx E} sreg+1 ; get hi byte; ldy tmp1; sty sreg; ldy tmp2; sty sreg+1; rts .globl ortosortos: jsr popsreg E} ; for optimized code .globl orsreg ; OR sreg into AXorsreg: ora sreg pha txa ora sreg+1 tax pla; rtE}s jmp tstax ; return status for optimized code .globl xortosxortos: jsr popsreg ; for optimized code .globE}l xorsreg ; XOR sreg into AXxorsreg: eor sreg pha txa eor sreg+1 tax pla; rts jmp tstax ; return sE}tatus for optimized code .globl andtosandtos: jsr popsreg ; for optimized code .globl andsreg ; AND sreg intE}o AXandsreg: and sreg pha txa and sreg+1 tax pla; rts jmp tstax ; return status for optimized code; E} .globl ldsr ; load sreg from following word;ldsr:; sta tmp1 ; save A; pla ; get return addr; sta ptr1;E} pla; sta ptr1+1; ldy #1; lda (ptr1),y ; get lo byte; sta sreg; iny; lda (ptr1),y ; get hi byte; sta sE}reg+1; clc ; adjust return addr; lda ptr1; adc #3 ; so we can jump thru it; sta ptr1; bcc *+4; inc pE}tr1+1; lda tmp1 ; get A back; jmp (ptr1);; comparisons; .globl axzeropaxzerop: cmp #0 bne return1 cpE}x #0 bne return1 beq return0 .globl toseqaxtoseqax: jsr popsreg ; for optimized code .globl sregeqax ; E }SREG == AXsregeqax: cmp sreg ; A == sreg lo? bne return0 ; nope, return 0 cpx sreg+1 ; X == sreg hi? bneE!} return0 beq return1 .globl tosneaxtosneax: jsr popsreg ; for optimized code .globl sregneax ; SREG != AXE"}sregneax: cmp sreg ; A == sreg lo? bne return1 ; nope, return 1 cpx sreg+1 ; X == sreg hi? bne return1 E#} beq return0 .globl tosltaxtosltax: jsr popsreg ; for optimized code .globl sregltax ; SREG < AXsregltax: E$} ; really AX > SREG... cpx sreg+1 ; X < sreg hi? bmi return0 ; X < SR^ , return 0 bne return1 ; not =, soE%} >; return 1 cmp sreg ; A < sreg lo? bcc return0 ; A < SR\, return 0 beq return0 bcs return1 .globl tosE&}ultaxtosultax: jsr popsreg ; for optimized code .globl sregultax ; SREG u< AXsregultax: ; AX u> SREG cpx E'}sreg+1 bcc return0 ; tos^ u< ax^ , return 0 bne return1 ; if ne, must be u>; return 1 cmp sreg bcc return0E(} beq return0 bcs return1 .globl tosleaxtosleax: jsr popsreg ; for optimized code .globl sregleax ; SREG = SR cpx sreg+1 bmi return0 ; X < SR^, return 0 bne return1 ; X > SR^, return 1 cmE*}p sreg bcc return0 ; u> , return 0 bcs return1 .globl tosuleaxtosuleax: jsr popsreg ; for optimized codeE+} .globl sreguleax ; SREG u<= AXsreguleax: cpx sreg+1 bcc return0 ; X < SR^, return 0 bne return1 ; X > SRE,}^, return 1 cmp sreg bcc return0 bcs return1;; return functions for comparison ops. these guys are careful; to E-}leave the condition codes correct for the AX value. Compiler; depends on that when optimizing; beware!;return1: ldx #0E.} lda #1 rtsreturn0: lda #0 tax rts .globl tosgtaxtosgtax: jsr popsreg ; for optimized code .globl E/} sreggtax ; SREG > AXsreggtax: ; AX < SR cpx sreg+1 bmi return1 ; < , return 1 bne return0 ; not =, so E0}>; return 0 cmp sreg bcc return1 ; < , return 1 bcs return0 .globl tosugtaxtosugtax: jsr popsreg ; forE1} optimized code .globl sregugtax ; SREG u> AXsregugtax: cpx sreg+1 bcc return1 ; < , return 1 bne return0 E2} ; not =, so >; return 0 cmp sreg bcc return1 ; < , return 1 bcs return0 .globl tosgeaxtosgeax: jsr popsrE3}eg ; for optimized code .globl sreggeax ; SREG >= AXsreggeax: ; AX <= SR cpx sreg+1 bmi return1 ; < , rE4}eturn 1 bne return0 ; not =, so >; return 0 cmp sreg bcc return1 ; < , return 1 beq return1 bcs return0E5} .globl tosugeaxtosugeax: jsr popsreg ; for optimized code .globl sregugeax ; AX u<= SREGsregugeax: cpx sreE6}g+1 bcc return1 ; < , return 1 bne return0 ; not =, so >; return 0 cmp sreg bcc return1 ; < , return 1 E7} beq return1 bcs return0; kludgey constant for DIV, MOD;onehalf:; .byte $3F,$49,$99,$99,$99,$99;; function opsE8}; .globl enterfun0enterfun0: ldy #0 beq enterfun .globl enterfun1enterfun1: ldy #1 bne enterfun .gloE9}bl enterfun2enterfun2: ldy #2 bne enterfun .globl enterfun3enterfun3: ldy #3 bne enterfun .globl enterE:}fun4enterfun4: ldy #4 bne enterfun .globl enterfun5enterfun5: ldy #5; bne enterfun;; expect frame size iE;}n Y, push fp; .globl enterfunenterfun: tya ; get arg count; asl A; clc; adc sp ; add to sp; pha; lE<}da sp+1; adc #0; tax; pla ldx #0 ; just push arg count jmp pushax .globl exitfun ; exit a function. E=}pop stack and rtsexitfun: pha ; save A a sec ldy #0 lda (sp),y ; that's the pushed arg count asl A ; lE>}oses big for large arg counts... tay iny iny ; count the word the count's stored in pla ; get it back jmpE?} addysp ; pop that many word-sized things;; random stuff;;; call value on in AX; .globl callaxcallax:; jsrE@} popax ; pop function ptr; jsr tos2ax ; get tos sta tmp1 stx tmp1+1 jmp (tmp1) ; jump there;; swap AEA}X with TOS; .globl swapstkswapstk: sta tmpptr stx tmpptr+1 ldy #1 ; index lda (sp),y tax lda tmpptr+EB}1 sta (sp),y dey lda (sp),y pha lda tmpptr sta (sp),y pla rts ; whew! .globl pushwaxipushwaxi: EC} ; push word (ax) jsr ldaxi jmp pushax .globl pushbaxi ; push byte at (ax)pushbaxi: jsr ldai jmp pushaxED}; .globl ldaxysp;ldaxysp:; jsr locysp; jmp ldaxi;; or ax with tos, pop;; .globl oraxtos;oraxtos:; ldy EE}#0; ora (sp),y; pha; txa; iny; ora (sp),y; tax; pla; jmp incsp2;; eor ax with tos, pop;; .globl eoraEF}xtos;eoraxtos:; ldy #0; eor (sp),y; pha; txa; iny; eor (sp),y; tax; pla; jmp inc2sp;; and ax with tEG}os, pop;; .globl andaxtos;andaxtos:; ldy #0; and (sp),y; pha; txa; iny; and (sp),y; tax; pla; jmp EH}inc2sp;; add Y to sp, leave result in AX;; .globl addrysp;addrysp:; tya ; get offset; clc ; set up for.EI}..; adc sp ; add low byte; pha; lda sp+1 ; get hi byte; adc #0 ; add carry; tax ; xfer to x; plEJ}a ; get a back; rts ; done;; handler for case jump inst.; .globl casejumpcasejump:;; case table after tEK}he call to casejmp. val in AX.; table is of the form ,,...,0.; rts from casejmp for default case, elseEL} pop return addr; addr and jmp to address; sta tmp3 stx tmp4 ; save value pla ; get return addr sta ptr1EM} pla sta ptr1+1 ; store in ptr 1 inc ptr1 ; and adjust it, because of way 6502 works bne *+4 inc ptr1+1cEN}ase1: ldy #1 ; first see if at end lda (ptr1),y ; test address byte hi bne case2 ; nope, not yet dey lda EO} (ptr1),y ; test address byte lo bne case2; oops, we're out of cases. compute return address; 2 + ptr1 clc lda ptrEP}1 ; get lo byte adc #2 ; inc past the 0 sta ptr1 bcc *+4 ; deal with carry inc ptr1+1 jmp (ptr1) ;EQ} go therecase2: ; test case value against this value ldy #3 lda (ptr1),y ; value hi cmp tmp4 ; match swER}itchval hi? bne case3 ; no match, try next dey lda (ptr1),y ; val lo cmp tmp3 ; match switchval lo? bne ES}case3; match! dey ; point at hi byte of addr lda (ptr1),y sta ptr2+1 ; stuff in ptr to jump thru dey ET}; point at lo byte of addr lda (ptr1),y sta ptr2 jmp (ptr2) ; go therecase3: ; no match, try next case cEU}lause clc lda ptr1 ; get case ptr adc #4 ; add 4 sta ptr1 ; put it back bcc *+4 inc ptr1+1 ; deaEV}l with carry jmp case1 ; and go try again;; save and restore AX; .globl saveaxsaveax: sta svax stx svax+1EW} rts .globl restaxrestax: lda svax ldx svax+1 jmp tstax;; support routines for runtime;;tos2ax:; ldy #EX}0;ytos2ax:; iny; lda (sp),y; tax; dey; lda (sp),y; rts; .globl popax;popax:; jsr tos2ax; jsr inc2spEY}; rts ;; mult and div, using fp routines;; .globl umul;umul: ; unsigned multiply; sta fr0 ; set up EZ}the first num; stx fr0+1; jsr ifp ; make a float out of it; jsr fmove ; move to fr1; jsr popax ; get secE[}ond arg; sta fr0 ; set this one up; stx fr0+1; jsr ifp ; floatify...; jsr fmul ; mult them; jsr fpi E\} ; back to int; lda fr0; ldx fr0+1 ; load it up; rts ; and return .globl multosmultos: jsr popsreg E]} .globl smul ; signed multiply AX by SREGsmul: ldy #0 sty tmp3 ; zap negative flag cpx #0 bpl *+7 inc E^}tmp3 jsr negax sta tmpptr ; use sreg and tmpptr stx tmpptr+1 ; as regs lda sreg ldx sreg+1 bpl xsmul0E_} dec tmp3 jsr negax sta sreg stx sreg+1xsmul0: lda #0 sta tmp1 ; tmp1/2 as accumulator sta tmp1+1 lE`}da #1 ; use A as bit mask against SREGxsmul1: bit sreg ; this bit in sreg set? beq xsmul2 ; nope, try next Ea} jsr xsmadd ; add AX val to accumxsmul2: asl tmpptr ; shift AX val left one rol tmpptr+1 asl A ; shift biEb}tmask left one bcc xsmul1 ; if bit not off end, keep working on lo byte lda #1 ; set up mask for hi bytexsmul3:Ec} bit sreg+1 ; this bit in sreg set? beq xsmul4 ; nope, try next jsr xsmadd ; add AX val to accumxsmul4: aEd}sl tmpptr ; shift AX val left one rol tmpptr+1 asl A ; shift bitmask left one bcc xsmul3 ; if not off end,Ee} keep working on hi byte ldx tmp1+1 ; load up accum lda tmp1 ldy tmp3 ; negate flag? beq xsmul9 jsr negaEf}xxsmul9: rts ; done!xsmadd: ; helper fun pha ; save bit mask clc lda tmpptr ; add AX valueEg} adc tmp1 ; to accumulator sta tmp1 lda tmpptr+1 adc tmp1+1 sta tmp1+1 pla ; get bitmask back rts Eq}B%DOS SYSB*)DUP SYSBSITOA M65BYITOAB C B^ITOD C BdITOO C BjITOU C BpITOX C BvOPEN C ByOTOI C B}PARSELINM65BPMALLOC C BREAD M65BREADARGSC BREADME TXTBRENAME C BREVERSE C BRUNTIME M65BRWCOMMONM65BSTARTUP C BSTDIO H BSTDIO M65BSTRCAT C BSTRCHR M65BSTRCMP C B TIME C BTOASCII C BTOLOWER M65BTOUPPER M65BTPRINTF M65BUTOI C BWRITE M65BXTOI C ; donexsdiv0: ; error return lda #0 tax sta sreg sta sreg+1 rts .globl divtosdivtos: jsr Er} popsreg ; pop other value into sreg .globl sdiv ; signed divide SREG by AX, sdiv: ; result in AX, remaindEs}er in SREG ldy #0 sty tmp3 ; zap denominator-negative flag sty tmp4 ; and numerator-negative flag jsr tstaxEt} ; AX zero? beq xsdiv0 ; yup, give up now bpl xsdiv1 ; positive, it's ok inc tmp3 ; denom negative jsrEu} negax ; negate itxsdiv1: sta ptr1 ; use tmpptr1 and SREG as regs stx ptr1+1 lda sreg ldx sreg+1 ; loaEv}d up sreg jsr tstax ; what sort of value? beq xsdiv0 ; zero, we lose bpl xsdiv2 ; positive, it's ok inc Ew}tmp4 ; set numerator-negative flag jsr negax ; negate it sta sreg stx sreg+1xsdiv2: ldy #1 ; bit mask Ex} sty ptr2 dey sty ptr2+1 sty tmp1 ; use tmp1 as accum sty tmp1+1;; shift ptr1 and ptr2 left until ptr1 is grEy}eater than SREG,; then shift right until it's <=;xsdiv3: lda ptr1+1 ; compare cmp sreg+1 ; p1 to sreg beq Ez}xsdiv3a ; eq, try second byte bcs xsdiv4 ; >, we're done shifting left bcc xsdiv3b ; <, shift leftxsdiv3a: E{}lda ptr1 cmp sreg ; compare lo byte beq xsdiv5 ; =, skip the right shift bcs xsdiv4 ; >, go right onexsdiE|}v3b: asl ptr1 ; shift p1 left 1 rol ptr1+1 asl ptr2 ; shift bitmask left one rol ptr2+1 jmp xsdiv3 ; E}}round again.xsdiv4: ; shift p1, mask right one lsr ptr1+1 ; shift p1 ror ptr1 lsr ptr2+1 ; shift bitmaE~}sk ror ptr2 bcs xsdiv7a ; bit fell out end?!? ok, do exit processing;; whew! tmpptr1 (the divisor register) and tmE}pptr2 (the quotient bitmask); are now all set to enter the divide loop;xsdiv5: ; compare sreg to p1. if >=, subtraE}ct lda sreg+1 cmp ptr1+1 beq xsdiv5a ; try lo byte bcs xsdiv6 ; >, go subtract bcc xsdiv7 ; <, go shiE}ft rightxsdiv5a: lda sreg cmp ptr1 bcc xsdiv7 ; < go shift rightxsdiv6: ; subtract p1 from sreg, and setE} bit in accum sec lda sreg ; subtract sbc ptr1 ; p1 sta sreg ; from lda sreg+1 ; sreg sbE}c ptr1+1 sta sreg+1 lda ptr2 ; or ora tmp1 ; bitmask sta tmp1 ; into lda ptr2+1 ; quotienE}t ora tmp1+1 sta tmp1+1xsdiv7: lsr ptr1+1 ; shift p1 right ror ptr1 lsr ptr2+1 ror ptr2 bcc xsdiv5 E} ; if no carry, round againxsdiv7a:;; done!; lda tmp4 ; negate remainder? beq xsdiv8 lda sreg ldx sreg+1E} jsr negax sta sreg stx sreg+1xsdiv8: lda tmp1 ldx tmp1+1 ldy tmp3 ; numerator neg... cpy tmp4 ; sE}ame as denom-neg? beq xsdiv9 ; yes, skip the negate jsr negaxxsdiv9: rts .globl modtosmodtos: jsr divtosE} lda sreg ldx sreg+1 jmp tstax;; library routines; .globl _strcpy_strcpy: jsr popax sta ptr1 stx ptE}r1+1 jsr popax sta ptr2 stx ptr2+1 ldy #0strc1: lda (ptr1),y sta (ptr2),y beq strc9 iny bne strc1E} inc ptr1+1 inc ptr2+1 bne strc1strc9: rts .globl _strlen_strlen: jsr popax sta ptr1 stx ptr1+1 ldE}x #0 ; YX used as counter ldy #0strlen1: lda (ptr1),y beq strlen9 iny bne strlen1 inc ptr1+1 inx bnE}e strlen1strlen9: tya ; get low byte of counter, hi's all set rts;; find (char * str, int len, char c) -> indexE};;_find:; jsr tos2ax; sta ptr1; stx ptr1+1; ldy #2; jsr ytos2ax; sta tmp1; stx tmp1+1; ldy #4; jsE}r ytos2ax ; gets char in A; ldx #0; stx ptr2 ; use as counter here; stx ptr2+1; ldy #0;find1:; cmp E} (ptr1),y ; match?; beq find9 ; yup, return; zzz;find9:; rts;; startup;;argv:; .word 0,0,0,0,0,0,0,0E}; .word 0,0,0,0,0,0,0,0start: tsx stx origsp ; save system stk ptr;; lda #0 ; init stk ptr; sta sp; lE}da #$80 ; $80 for debugging...; sta sp+1; lda memtop ; memtop for real code sta sp lda memtop+1 sta spE}+1;; if running under SpartaDos, pass the command line to _main; lda $0700 ; check the sparta flag cmp #'S' beqE} startcmd ; nope, check for dos xl;; Try to guess what OS we're running under.; Use the algorithm suggested by Dick CurzE}on.; Look thru $0A. Should see a jmp, another jmp,; and something that's not a jump.; ldy #0 lda (cpaloc),y cmp E}#$4C ; a jmp? bne start0 ; nope, give up ldy #3 lda (cpaloc),y cmp #$4C ; a jmp? bne start0 ; nopeE} ldy #6 lda (cpaloc),y cmp #$4C ; a jmp? beq start0 ; if yes, it's mydos or somethingstartcmd:;; parse E}command line etc. for now, assume Sparta or Dos XL; clc lda cpaloc ; get pointer to adc #cpcmdb ; cmd buf pE}ha ; save lo byte lda cpaloc+1 adc #0 tax ; get hi byte pla ; get lo byte back jmp start1start0:E}; no command line, just pass null lda #0 taxstart1: jsr pushax ; push the ptr ldy #1 ; 1 arg jsr __mainE};; fall thru to exit...; rts ; done!; .globl _exit_exit: ldx origsp txs; rts jmp (dosvec);r __mainDt;; common rtn for read, write; .globl __rwsetup__rwsetup: ldy #4 jsr ldaxysp ; get iocb sta tmp3 ; save I}it ldy #0 jsr ldaxysp ; get size php ; save cond codes, for zero-ness stx tmp2 ldx tmp3 ; iocb staI} icbll,x lda tmp2 ; size hi sta icblh,x ldy #2 ; get buf addr jsr ldaxysp stx tmp2 ldx tmp3 sta iI}cbal,x lda tmp2 sta icbah,x jsr incsp6 ; pop args plp rts;r jsr ldaxysp stx tmp2 ldx tmp3 sta iHL/* standard startup piece for c programs. replace this by by supplying your own _main if you want... *//* int _argv[16M}]; .. use PRNBUF instead */int _argv = 0x3C0; /* Atari Rom OS's Printer buf, 32 bytes */#ifdef parser/* the C parser.M} The .m65 one is in parselin.m65 */static char ___ch;/* arg line parser. it's separate so it can be called independentlM}y */_parseline(line, argv)char * line;int * argv;$( int nargs; char * p; nargs = 0; if ((p = line) == 0) returM}n(0); while (*p) /* while not at eos, scan */ $( while (iswhite(___ch = *p)) *p++ = 0; /* zap and skip whitespaM}ce */ if ((___ch == 0) || (___ch == '\n')) break; /* end of str, stop */ *argv++ = p; /* remember the pointer *M}/ ++nargs; while (!iswhite(*p)) ++p; /* find end of string */ $) return(nargs);$)#endif_main(cmdline)char * cmM}dline;$( main(_parseline(cmdline, _argv), _argv);$) string */ $) return(nargs);$)#endif_main(cmdline)char * cmL8/* cc65 stdio.h *//* say we're running cc65 */#define M6502#define __CC65__#define FILE charextern FILE * stdin;extQ}ern FILE * stdout;extern FILE * stderr;extern int errno; /* error number from open, etc */#define EOF -1#define NULL Q}0#define NEWLINE 0x9B#define YES 1#define NO 0t errno; /* error number from open, etc */#define EOF -1#define NULL P2;; data and part of the code for Small-C io library; this must be assembled with atari.m65 and global.m65;; canned filesU}. these are declared pointers to something,; but they're really IOCBs.;; it'd be nice if we could make these be on page 0U}... .globl _stdin_stdin: .word 0 ; default to screen/kbd .globl _stdout_stdout: .word 0 ; default to scrU}een/kbd .globl _stderr_stderr: .word 0 ; default to screen/kbd .globl _errno_errno: .word 0 ; error numbU}er;;; internal helper fun for open routines.; find a free iocb, return in x; .globl findiocbfindiocb: ldx #$10 U} ; start at # 1findiocb1: lda ichid,x ; get handler id cmp #$FF ; free? beq findiocb9 ; yup, return it txU}a clc adc #$10 ; next iocb tax cmp #$80 ; past last one? bcc findiocb1 ; nope, return it ldx #$FF ;U} return -1findiocb9: rts;; copen(name, mode)->iocb #; .globl _copen_copen: jsr popax ; get open mode sta U}tmp1 ; save it jsr popax ; get name sta fntemp stx fntemp+1 jsr findiocb ; try to find a free iocb bmi U}copenerr ; no free ones stx tmp4 lda tmp1 ; get open mode again cmp #'r ; read? bne copen1 lda #OPNIN U} ; open for input bne copen5copen1: cmp #'w ; write? bne copen2 lda #OPNOT bne copen5copen2: cmp #'a U} ; write append? bne copen3 lda #OPNOT|APPEND bne copen5copen3: cmp #'d ; directory? bne copenerr ; bogU}on, return err lda #OPNIN|DIRECTcopen5: ldx tmp4 sta icax1,x ; store open bits lda #0 sta icax2,x sta U}icbll,x sta icblh,x;; make sure the name's got an EOL at the end; ldy #0copen6: lda (fntemp),y and #$7F ; U}mask for non-inverted beq copen7 cmp #'a ; need to upcase, for non-sparta dos'es bmi copen6a cmp #'z+1 bpl U}copen6a sec sbc #$20 ; subtract a spacecopen6a:; sta copenbuf,y sta casbuf,y ; use casbuf to save a little spU}ace iny bne copen6copen7: lda #$9B; sta copenbuf,y sta casbuf,y; lda #copenbuf\ lda #casbuf\ sta icbaU}l,x; lda #copenbuf^ lda #casbuf^ sta icbah,x lda #open sta iccom,x;; all set; jsr ciov bpl copen8 U}; ok, return it jmp ioreturncopen8: txa ; return iocb in ax ldx #0 rts; zzzcopenerr: lda #$FF tax rtU}s;copenbuf: .byte " ";; common error vector for io things. do a JMP here right after callingU}; CIOV. we expect status in Y.; .globl ioreturnioreturn: tya ; get return code ldx #$FF ; return error sU}ta _errno stx _errno+1 rts .globl ioreturnioreturn: tya ; get return code ldx #$FF ; return error sT!#define FIXARGC#define NOARGC/* somebody ought to rewrite this in m65 code */strcat(str1, str2)char * str1;char * str2;Y}$( strcpy(str1 + strlen(str1), str2);$)ought to rewrite this in m65 code */strcat(str1, str2)char * str1;char * str2;X,;; strchr(str, chr);; .globl _strchr_strchr: jsr popax ; get char sta tmp1 ; save it jsr popax ; get ]}ptr sta ptr1 stx ptr1+1 ldy #0strchr1: lda (ptr1),y ; get a char bne strchrz ldx #0 ; oops! not found]} rtsstrchrz: cmp tmp1 ; match? bne strchr2 ; nope, keep searching ldx ptr1+1 ; hi byte of result tya ]} ; compute lo byte clc adc ptr1 bcc *+3 inx jmp tstax ; return condition codesstrchr2: iny ; bump i]}ndex bne strchr1 inc ptr1+1 jmp strchr1 inx jmp tstax ; return condition codesstrchr2: iny ; bump i\2#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//*** return <0, 0, >0 a}aUording to** st*/strcmp(s, t) char *s, *t; $( while(*s == *t) $( if(*s == 0) return (0); a} ++s; ++t; $) return (*s - *t);$)p(s, t) char *s, *t; $( while(*s == *t) $( if(*s == 0) return (0); `+#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//* * time-hacking stuffe} */#define RTCLOK ((char *)0x12)gtime(time)char * time; /* snapshot RTCLOK */$( time[0] = *(RTCLOK); time[1] = *e}(RTCLOK+1); time[2] = *(RTCLOK+2);$)calctim(t0, xtime)char * t0; /* initial time */char * xtime; /* 4 bytes,e} hr, min, sec, 60th */$( char t1[3]; int temp[4]; gtime(t1); /* get current time *//* subtrace t0 from t1 */e}#asm ldy #8 ; index of t1 jsr locysp ; point at it sta $E0 ; tmp ptr stx $E1 ldy #15 ; index of t0 jse}r ldaxysp ; get pointer sta $D4 stx $D5 ldy #2 sec lda ($E0),y ; get t1 byte sbc ($D4),y ; sub t0 byte e} sta ($E0),y ; back in t1 dey lda ($E0),y ; get t1 byte sbc ($D4),y ; sub t0 byte sta ($E0),y ; back in te}1 dey lda ($E0),y ; get t1 byte sbc ($D4),y ; sub t0 byte sta ($E0),y ; back in t1#endasm/* tprintf(" t1 e}%x %x %x\n", t1[0], t1[1], t1[2]); */ temp[3] = (t1[2] & 0x3F) * 100 / 64; /* compute hundreths */ temp[2] = ((t1[2] e}& 0xC0) / 64) | /* compute seconds */ ((t1[1] & 0xFF) * 4) | ((t1[0] & 0x1F) * 1024); temp[1] = tempe}[2] / 60; /* ... minutes */ temp[2] = temp[2] % 60; temp[0] = temp[1] / 60; /* ... hours */ temp[1] = temp[1]e} % 60;/* tprintf(" temp %d %d %d %d\n", temp[0], temp[1], temp[2], temp[3]); */ xtime[0] = temp[0]; xtime[1] = temp[1]e}; xtime[2] = temp[2]; xtime[3] = temp[3];$), temp[1], temp[2], temp[3]); */ xtime[0] = temp[0]; xtime[1] = temp[1]d1#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in *//*** return ASCII equivali}ent of c*/toascii(c) int c; $( return (c);$)IXARGC /* don't expect arg counts passed in *//*** return ASCII equivalh4 .globl _tolower_tolower: jsr popax ; get the char cmp #'A ; < 'a'? bcc tolower9 ; yup, skip it cmp #'Zm}+1 ; > 'z ? bcs tolower9 adc #$20 ; carry's already settolower9: rtsbcc tolower9 ; yup, skip it cmp #'ZlU .globl _toupper_toupper: jsr popax ; get the char cmp #'a ; < 'a'? bcc toupper9 ; yup, skip it cmp #'zq}+1 ; > 'z ? bcs toupper9 sec sbc #$20toupper9: rts #'a ; < 'a'? bcc toupper9 ; yup, skip it cmp #'zpA;; tiny printf etc.;; utilscconout: ; out char in a. bash regs ldx #0 pha ; save the char txa ; getu} a zero sta icbal,x ; zap buf addr sta icbah,x sta icbll,x ; and buf len sta icblh,x lda #putchr ; sau}y put a byte sta iccom,x pla ; get the byte again jsr ciov ; go do it rtspf_incs: ; inc str ptr inu}c ptr1 beq *+3 rts inc ptr1+1 rtspf_nxta: ; get next arg sec ; dec arg ptr by 2 lda ptr2 sbc #u}2 sta ptr2 lda ptr2+1 sbc #0 sta ptr2+1 ldy #1 lda (ptr2),y ; get hi byte tax ; into x dey ldau} (ptr2),y ; get lo byte rts .globl _tprintf _tprintf: sty argcnt ; save arg count lda argcnt asl A ;u} make an offset clc adc sp ; compute addr of ctl str + 2 sta ptr2 lda sp+1 adc #0 sta ptr2+1; jsr pf_u}nxta ; get control string sta ptr1 stx ptr1+1;; main loop.;printf0: ldy #0 lda (ptr1),y ; get a char bnu}e *+5 jmp printf9 ; eos? go home cmp #'% ; a percent? bne printf1 ; no, go print it jsr pf_incs ; buu}mp control string ptr lda (ptr1),y ; get control char;; see what we have; cmp #'s ; string? beq pf_str cmp u} #'d ; decimal? beq pf_dec cmp #'x ; hex? beq pf_hex cmp #'o ; octal? beq pf_oct; more laterprintf1u}: jsr cconout ; out the charprintf2: jsr pf_incs ; bump control str jmp printf0 ; and go back for morepf_u}str: jsr pf_nxta ; get next arg sta ptr3 stx ptr3+1pf_str1: ldy #0 lda (ptr3),y ; get a char beq printu}f2 ; done, go home inc ptr3 bne *+4 inc ptr3+1 jsr cconout jmp pf_str1pf_hex: jsr pf_nxta ; get argu} sta ptr3 stx ptr3+1 lda #4 sta tmp1pf_hex1: lda ptr3+1 lsr A lsr A lsr A lsr A and #$0F taxu} lda hex,x jsr cconout dec tmp1 ; dec counter beq pf_hex9 ; done! asl ptr3 rol ptr3+1 asl ptr3 rou}l ptr3+1 asl ptr3 rol ptr3+1 asl ptr3 rol ptr3+1 jmp pf_hex1pf_hex9: jmp printf2pf_oct: jmp printf2pu}f_dec: jsr pf_nxta ; get an arg sta fr0 stx fr0+1 ; set up to floatify cpx #0 ; neg? bpl pf_decu}1 jsr negax sta fr0 ; store it again stx fr0+1 lda #'- jsr cconoutpf_dec1: jsr ifp jsr fasc ;u} ascify it ldy #0 sty tmp1pf_dec2: ldy tmp1 ; get idx lda (inbuff),y ; get a byte bmi pf_dec3 ; u}hi bit set? ok, done inc tmp1 jsr cconout jmp pf_dec2pf_dec3: and #$7F ; mask it jsr cconout jmp prinu}tf2printf9: lda argcnt ; get arg count asl A ; make it a byte count tay jmp addysp ; pop stack andu} return; rtshex: .byte "0123456789ABCDEF"; that's all ; make it a byte count tay jmp addysp ; pop stack andt=#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in */#include /*** uy}toi -- convert unsigned decimal string to integer nbr** returns field size, else ERR on error*/#define ERR -1utoy}i(decstr, nbr) char *decstr; int *nbr; $( int d,t; d=0; *nbr=0; while((*decstr>='0')&(*decstr<='9')) $( y}t=*nbr;t=(10*t) + (*decstr++ - '0'); if ((t>=0)&(*nbr<0)) return ERR; d++; *nbr=t; $) return d;$) $( xq;; write(iocb, buf, nbytes)->nbytes written; .globl _write_write: jsr __rwsetup ; do common setup beq write9 }}; if size 0, it's a no-op lda #putchr sta iccom,x jsr ciov bpl write9 jmp ioreturn ; do common error vector s}}tuffwrite9: lda icbll,x ; get buf len lo pha lda icblh,x ; buf len hi tax pla rts;common error vector s|h#define NOARGC /* no arg count passing */#define FIXARGC /* don't expect arg counts passed in */#include /*** x}toi -- convert hex string to integer nbr** returns field size, else ERR on error*//* what should this be?? -- jrd} */#define ERR -1xtoi(hexstr, nbr) char *hexstr; int *nbr; $( int d, b; char *cp; d = *nbr = 0; cp = hexstr; whi}le(*cp == '0') ++cp; while(1) $( switch(*cp) $( case '0': case '1': case '2': case '3': case '4}': case '5': case '6': case '7': case '8': case '9': b=48; break; case 'A': case 'B': c}ase 'C': case 'D': case 'E': case 'F': b=55; break; case 'a': case 'b': case 'c': case 'd': case 'e': case }'f': b=87; break; default: return (cp - hexstr); $) if(d < 4) ++d; else return (ERR); *nbr = (*nbr << 4)} + (*cp++ - b); $)$)efault: return (cp - hexstr); $) if(d < 4) ++d; else return (ERR); *nbr = (*nbr << 4)