@L}5 _$% l0$)$$Hȱ$ UhL" `e$$%`$%`  R@P!( L(1   Y I`  d  Ld M * @  $ % CC$$)%1 Udߥ$9%: !0 S$% DD˙`  }J)Lr ;; Defs for Atari OS. These defs were stolen from ALBUG's SYSMAC.SML.; This file generates no code, just contains rom loca}tions etc.;; VECTOR TABLEEDITRV =$E400 ;EDITORSCRENV =$E410 ;TELEVISION SCREENKEYBDV =$E420 ;KEYBOA}RDPRINTV =$E430 ;PRINTERCASETV =$E440 ;CASSETTE; JUMP VECTOR TABLEDISKIV =$E450 ;DISK INITIALIZATION}DSKINV =$E453 ;DISK INTERFACECIOV =$E456 ;CIO ROUTINESIOV =$E459 ;SIO ROUTINESETVBV =$E45C ;SET V}ERTICAL BLANK VECTORSSYSVBV =$E45F ;SYSTEM VERTICAL BLANK ROUTINEXITVBV =$E462 ;EXIT VERTICAL BLANK ROUTINESIO }INV =$E465 ;SIO INITSENDEV =$E468 ;SEND ENABLE ROUTINEINTINV =$E46B ;INTERRUPT HANDLER INITCIOINV =$E46 }E ;CIO INITBLKBDV =$E471 ;BLACKBOARD MODEWARMSV =$E474 ;WARM START ENTRY POINTCOLDSV =$E477 ;COLD S }TART ENTRY POINTRBLOKV =$E47D ;CASSETTE READ BLOCK VECTORDSOPIV =$E480 ;CASSETTE OPEN FOR INPUT VECTOR; SOME } USEFUL INTERNAL ROUTINES;KGETCH =$F6E2 ;GET CHAR FROM KEYBOARD only on 800EOUTCH =$F6A4 ;OUTPUT CHAR TO SCREE }NPUTLIN =$F385 ;OUTPUT LINE TO IOCB#0; COMMAND CODES FOR IOCBOPEN =$03 ;OPEN FOR INPUT/OUTPUTGETREC =$05 } ;GET RECORD (TEXT)GETCHR =$07 ;GET CHARACTER(S)PUTREC =$09 ;PUT RECORD (TEXT)PUTCHR =$0B ;PUT CHARA}CTER(S)CLOSE =$0C ;CLOSE DEVICESTATIS =$0D ;STATUS REQUESTSPECIL =$0E ;SPECIAL ENTRY COMMANDS; SPECIA}L ENTRY COMMANDSDRAWLN =$11 ;DRAW LINEFILLIN =$12 ;DRAW LINE WITH RIGHT FILLRENAME =$20 ;RENAME DISK FI}LEDELETE =$21 ;DELETE DISK FILEFORMAT =$22 ;FORMAT DISKLOCKFL =$23 ;LOCK FILE (READ ONLY)UNLOCK =$24 } ;UNLOCK FILEPOINT =$25 ;POINT SECTORNOTE =$26 ;NOTE SECTORCCIO =$28 ;CONCURRENT I/O MODEIOCFRE =}$FF ;IOCB "FREE"; AUX1 VALUES FOR OPENAPPEND =$01 ;OPEN FOR APPENDDIRECT =$02 ;OPEN FOR DIRECTORY ACCE}SSOPNIN =$04 ;OPEN FOR INPUTOPNOT =$08 ;OPEN FOR OUTPUTOPNINO =OPNIN!OPNOT ;OPEN FOR INPUT/OUTPUTMXDMOD }=$10 ;OPEN FOR MIXED MODEINSCLR =$20 ;OPEN WITHOUT CLEARING SCREEN; OS STATUS CODESSUCCES =$01 ;SUCCESS}FUL OPERATIONBRKABT =$80 ;(128) BREAK KEY ABORTPRVOPN =$81 ;(129) IOCB ALREADY OPENNONDEV =$82 ;(130) NO}N-EX DEVICEWRONLY =$83 ;(131) IOCB OPENED FOR WRITE ONLYNVALID =$84 ;(132) INVALID COMMANDNOTOPN =$85 ;(}133) DEVICE OR FILE NOT OPENBADIOC =$86 ;(134) INVALID IOCB NUMBERRDONLY =$87 ;(135) IOCB OPENED FOR READ ONLY}EOFERR =$88 ;(136) END OF FILETRNRCD =$89 ;(137) TRUNCATED RECORDTIMOUT =$8A ;(138) DEVICE TIMEOUTDNACK } =$8B ;(139) DEVICE DOES NOT ACK COMMANDFRMERR =$8C ;(140) SERIAL BUS FRAMING ERRORCRSROR =$8D ;(141) CURS}OR OUT OF RANGEOVRRUN =$8E ;(142) SERIAL BUS DATA OVERRUNCHKERR =$8F ;(143) SERIAL BUS CHECKSUM ERRORDERROR =}$90 ;(144) DEVICE ERROR (OPERATION INCOMPLETE)BADMOD =$91 ;(145) BAD SCREEN MODE NUMBERFNCNOT =$92 ;(146) }FUNCTION NOT IN HANDLERSCRMEM =$93 ;(147) INSUFFICIENT MEMORY FOR SCREEN MODE; PAGE 0 LOCATIONSLINZBS =$00 };LINBUG STORAGE ; THESE LOCS ARE NOT CLEAREDCASINI =$02 ;CASSETTE INIT LOCRAMLO =$04 ;RAM POINTER FOR MEM T}ESTTRAMSZ =$06 ;TEMP LOC FOR RAM SIZETSTDAT =$07 ;RAM TEST DATA LOC; CLEARED ON COLDSTART ONLYWARMST =$08 } ;WARM START FLAGBOOTQ =$09 ;SUCCESSFUL BOOT FLAGDOSVEC =$0A ;DOS START VECTORDOSINI =$0C ;DOS INIT!} ADDRESSAPPMHI =$0E ;APPLICATION MEM HI LIMIT; CLEARED ON COLD OR WARM STARTINTZBS =$10 ; START OF OS RAM C"}LEAR LOC => $7FPOKMSK =$10 ;SYSTEM MASK FOR POKEY IRQ ENABLEBRKKEY =$11 ;BREAK KEY FLAGRTCLOK =$12 ;REAL#} TIME CLOCK (60HZ OR 16.66666 MS) ; 3 bytes; hi order, medium, lowBUFADR =$15 ;INDIRECT BUFFER ADDRESS REGICC$}OMT =$17 ;COMMAND FOR VECTOR HANDLERDSKFMS =$18 ;DISK FILE MANAGER POINTERDSKUTL =$1A ;DISK UTILITIES POI%}NTERPTIMOT =$1C ;PRINTER TIME OUT REGISTERPBPNT =$1D ;PRINT BUFFER POINTERPBUFSZ =$1E ;PRINT BUFFER SIZE&}PTEMP =$1F ;TEMP REGZIOCB =$20 ;PAGE 0 I/O CONTROL BLOCKIOCBSZ =16 ;NUMBER OF BYTES / IOCBMAXIOC =8*IO'}CBSZ ;LENGTH OF IOCB AREAIOCBAS =ZIOCBICHIDZ =$20 ;HANDLER INDEX NUMBER ($FF := IOCB FREE)ICDNOZ =$21 ;DE(}VICE NUMBER (DRIVE NUMBER)ICCOMZ =$22 ;COMMAND CODEICSTAZ =$23 ;STATUS OF LAST IOCB ACTIONICBALZ =$24 ;B)}UFFER ADDRESS (LOW)ICBAHZ =$25 ; " " (HIGH)ICPTLZ =$26 ;PUT BYTE ROUTINE ADDRESS - 1ICPTHZ =$27ICBLLZ *} =$28 ;BUFFER LENGTH (LOW)ICBLHZ =$29 ; " " (HIGH)ICAX1Z =$2A ;AUX INFOICAX2Z =$2BICSPRZ =$2C +} ;SPARE BYTES (CIO LOCAL USE)ICIDNO =ICSPRZ+2 ;IOCB LUMBER * 16CIOCHR =ICSPRZ+3 ;CHARACTER BYTE FOR CURRENT OPER,}ATIONOSSTATUS =$30 ;INTERNAL STATUS STORAGEOSCHKSUM =$31 ;CHECKSUM (SINGLE BYTE SUM WITH CARRY)BUNRLO =$32 -} ;POINTER TO DATA BUFFER (LO BYTE)BUFRHI =$33 ;POINTER TO DATA BUFFER (HI BYTE)BFENLO =$34 ;NEXT BYTE PAST E.}ND OF BUFFER (LO BYTE)BNENHI =$35 ;NEXT BYTE PAST END OF BUFFER (HI BYTE)CRETRY =$36 ;NUMBER OF COMMAND FRAM RE/}TRIESDRETRY =$39 ;NUMBER OF DEVICE RETRIESBUFRFL =$38 ;DATA BUFFER FULL FLAGRECVDN =$39 ;RECEIVE DONE FL0}AGXMTDON =$3A ;XMIT DONE FLAGCHKSNT =$3B ;CHECKSUM SENT FLAGNOCKSM =$3C ;NO CHECKSUM FOLLOWS DATA FLAG1}BPTR =$3D ;BUFFER POINTER (CASSETTE)FTYPE =$3E ;FILE TYPE (SHORT IRG/LONG IRG)FEOF =$3F ;END OF FILE FLAG2} (CASSETTE)FREQ =$40 ;FREQ COUNTER FOR CONSOLE SPEAKERSOUNDR =$41 ;NOISY I/O FLAG. (ZERO IS QUIET)CRITIC =$423} ;CRITICAL CODE IF NON-ZERO)FMSZPG =$43 ;DISK FILE MANAGER SYSTEM STORAGE (7 BYTES)CKEY =$4A ;SET WHEN G4}AME START PRESSEDCASSBT =$4B ;CASSETTE BOOT FLAGDSTAT =$4C ;DISPLAY STATUSATRACT =$4D ;ATTRACT MODE FLAG5}DRKMSK =$4E ;DARK ATTRACT MASKCOLRSH =$4F ;ATTRACT COLOR SHIFTER (XOR'D WITH PLAYFIELD)TMPCHR =$50 ;TEM6}P CHAR STORAGE (DISPLAY HANDLER)HOLD1 =$51 ;TEMP STG (DISPLAY HANDLER)LMARGN =$52 ;LEFT MARGINRMARGN =$53 7} ;RIGHT MARGINROWCRS =$54 ;CURSOR COUNTERSCOLCRS =$55DINDEX =$57 ;DISPLAY INDEX (VARIOUS QUANTS)SAVMSC =$58}8OLDROW =$5A ;PREVIOUS ROW/COLOLDCOL =$5BOLDCHR =$5D ;DATA UNDER CURSOROLDADR =$5ENEWROW =$60 ;POINT9} DRAWS TO HERENEWCOL =$61LOGCOL =$63 ;POINTS AT COLUMN IN LOGICAL LINEADRESS =$64 ;INDIRECT POINTERMLTTMP =:}$66 ;MULTIPLY TEMPOPNTMP =MLTTMP ;FIRST BYTE IS USED IN OPEN AS TEMPSAVADR =$68RAMTOP =$6A ;RAM SIZE DEF;}INED BY POWER ON LOGICBUFCNT =$6B ;BUFFER COUNTBUFSTR =$6C ;EDITOR GETCH POINTERBITMSK =$6E ;BIT MASKSH<}FAMT =$6F ;OUTCHR SHIFTROWAC =$70 ;USED BY "DRAW"COLAC =$72ENDPT =$74DELTAR =$76DELTAC =$77ROWINC =$7=}9COLINC =$7ASWPFLG =$7B ;NON-0 IF TXT AND RAM SWAPPEDHOLDCH =$7C ;CH BEFORE CNTL & SHFT PROCESSING IN KGETCH>}INSDAT =$7D ;INSERT CHAR SAVECOUNTR =$7E ;DRAW COUNTER;;; $80 TO $FF ARE RESERVED FOR USER APPLICATIONS; P?}AGE 2 LOCATIONSINTABS =$200 ;INTERRUPT TABLEVDSLST =$200 ;DISPLAY LIST NMI VECTORVPRCED =$202 ;PROCEED @}LINE IRQ VECTORVINTER =$204 ;INTERRUPT LINE IRQ VECTORVBREAK =$206 ;"BRK" VECTORVKEYBD =$208 ;POKEY KEYBA}OARD IRQ VECTORVSERIN =$20A ;POKEY SERIAL INPUT READYVSEROR =$20C ;POKEY SERIAL OUTPUT READYVSEROC =$20E B} ;POKEY SERIAL OUTPUT DONEVTIMR1 =$210 ;POKEY TIMER 1 IRQVTIMR2 =$212 ;POKEY TIMER 2 IRQVTIMR4 =$214 ;POC}KEY TIMER 4 IRQ (DO NOT USE)VIMIRQ =$216 ;IMMEDIATE IRQ VECTORCDTMV1 =$218 ;COUNT DOWN TIMER 1CDTMV2 =$21A D} ;COUNT DOWN TIMER 2CDTMV3 =$21C ;COUNT DOWN TIMER 3CDTMV4 =$21E ;COUNT DOWN TIMER 4CDTMV5 =$220 ;COUNE}T DOWN TIMER 5VVBLKI =$222 ;IMMEDIATE VERTICAL BLANK NMI VECTORVVBLKD =$224 ;DEFERRED VERTICAL BLANK NMI VECTORF}CDTMA1 =$226 ;COUNT DOWN TIMER 1 JSR ADDRESSCDTMA2 =$228 ;COUNT DOWN TIMER 2 JSR ADDRESSCDTMF3 =$22A ;COG}UNT DOWN TIMER 3 FLAGSRTIMR =$22B ;SOFTWARE REPEAT TIMERCDTMF4 =$22C ;COUNT DOWN TIMER 4 FLAGINTEMP =$22D H} ;IAN'S TEMP (???)CDTMF5 =$22E ;COUNT DOWN TIMER 5 FLAGSDMCTL =$22F ;SAVE DMACTL REGISTERDMACTL =$D400 I}; the real DMA control regSDLSTL =$230 ;SAVE DISPLAY LIST (LOW)SDLSTH =$231 ;SAVE DISPLAY LIST (HIGH)SSKCTL =J}$232 ;SKCTL REGISTER RAMLPENH =$234 ;LIGHT PEN HORIZ VALUELPENV =$235 ;LIGHT PEN VERT VALUE ; ($2K}36 - $239 SPARE)CDEVIC =$23A ;COMMAND FRAME BUFFER - DEVICECCOMND =$23B ;COMMANDCAUX1 =$23C ;COMMAND AUXL} BYTE 1CAUX2 =$23D ;COMMAND AUX BYTE 2TEMP =$23E ;YESERRFLG =$23F ;ERROR FLAG - ANY DEVICE ERROR EXCEPT M}TIMEOUTDFLAGS =$240 ;DISK FLAGS FROM SECTOR ONEDBSECT =$241 ;NUMBER OF DISK BOOT SECTORSBOOTAD =$242 ;AN}DDRESS FOR DISK BOOT LOADERCOLDST =$244 ;COLDSTART FLAG (1 = DOING COLDSTART) ;($245 SPARE)DSKTIM =$246 O} ;DISK TIME OUT REGLINBUF =$247 ;CHAR LINE BUFFER (40 BYTES)GPRIOR =$26F ;GLOBAL PRIORITY CELLPADDL0 =$270 P} ;POT 0 SHADOWPADDL1 =$271 ;POT 1 SHADOWPADDL2 =$272 ;POT 2 SHADOWPADDL3 =$273 ;POT 3 SHADOWPADDL4 Q}=$274 ;POT 4 SHADOWPADDL5 =$275 ;POT 5 SHADOWPADDL6 =$276 ;POT 6 SHADOWPADDL7 =$277 ;POT 7 SHADOWSR}TICK0 =$278 ;JOYSTICK 0 SHADOWSTICK1 =$279 ;JOYSTICK 1 SHADOWSTICK2 =$27A ;JOYSTICK 2 SHADOWSTICK3 =$27S}B ;JOYSTICK 3 SHADOWPTRIG0 =$27C ;PADDLE 0 TRIGGERPTRIG1 =$27D ;PADDLE 1 TRIGGERPTRIG2 =$27E ;PADDLT}E 2 TRIGGERPTRIG3 =$27F ;PADDLE 3 TRIGGERPTRIG4 =$280 ;PADDLE 4 TRIGGERPTRIG5 =$281 ;PADDLE 5 TRIGGERPTU}RIG6 =$282 ;PADDLE 6 TRIGGERPTRIG7 =$283 ;PADDLE 7 TRIGGERSTRIG0 =$284 ;JOYSTICK 0 TRIGGERSTRIG1 =$285 V} ;JOYSTICK 1 TRIGGERSTRIG2 =$286 ;JOYSTICK 2 TRIGGERSTRIG3 =$287 ;JOYSTICK 3 TRIGGERCSTAT =$288 ;(UW}NUSED)WMODE =$289 ;R/W FLAG FOR CASSETTEBLIM =$28A ;BUFFER LIMIT (CASSETTE) ;($28B - $28F SPARE)TXTROWX} =$290 ;TEXT ROWCRSTXTCOL =$291 ;TEXT ROWCOLTINDEX =$293 ;TEXT INDEXTXTMSC =$294 ;FOOLS CONVRT INTY}O NEW MSCTXTOLD =$296 ;OLDROW & OLDCOL FOR TEXT (AND THEN SOME)TMPX1 =$29CHOLD3 =$29DSUBTMP =$29EHOLD2 =$29FDZ}MASK =$2A0TMPLBT =$2A1OSESCFLG =$2A2 ;ESCAPE FLAGTABMAP =$2A3 ;TAB BUFFERLOGMAP =$2B2 ;LOGICAL LINE S[}TART BIT MAPINVFLG =$2B6 ;INVERSE VIDEO FLAG (ATARI KEY)FILFLG =$2B7 ;RIGHT FILL FLAG FOR DRAWTMPROW =$2B8TM\}PCOL =$2B9SCRFLG =$2BB ;SET IF SCROLL OCCURSHOLD4 =$2BC ;MORE DRAW TEMPSHOLD5 =$2BDSHFLOK =$2BE ;SHIF]}T LOCK KEYBOTSCR =$2BF ;BOTTOM OF SCREEN (24 NORM, 4 SPLIT)PCOLR0 =$2C0 ;P0 COLORPCOLR1 =$2C1 ;P1 COLOR^}PCOLR2 =$2C2 ;P2 COLORPCOLR3 =$2C3 ;P3 COLORCOLOR0 =$2C4 ;COLOR 0COLOR1 =$2C5COLOR2 =$2C6COLOR3 =$_}2C7COLOR4 =$2C8 ;BACKGROUND ;($2C9 - $2DF SPARE)GLBABS =$2E0 ;GLOBAL VARIABLES ;($2E0 - $2E3 SP`}ARE)RAMSIZ =$2E4 ;RAM SIZE (HI BYTE ONLY)MEMTOP =$2E5 ;TOP OF AVAILABLE MEMORYMEMLO =$2E7 ;BOTTOM OF AVAa}ILABLE MEMORY ;($2E9 SPARE)DVSTAT =$2EA ;STATUS BUFFERCBAUDL =$2EE ;CASSETTE BAUD RATE (LO BYTE)CBAUDHb} =$2EF ; " " " (HI BYTE)CRSINH =$2F0 ;CURSOR INHIBIT (00 = CURSOR ON)KEYDEL =$2F1 ;KEY DELAYc}CH1 =$2F2CHACT =$2F3 ;CHACTL REGISTER (SHADOW)CHBAS =$2F4 ;CHBAS REGISTER (SHADOW) ;($2F5 - $2F9 SPAREd})OSCHAR =$2FAATACHR =$2FB ;ATASCII CHARACTERCH =$2FC ;GLOBAL VARIABLE FOR KEYBOARDFILDAT =$2FD ;RIGHT e}FILL DATA (DRAW)DSPFLG =$2FE ;DISPLAY FLAG: DISP CONTROLS IF NON-ZEROSSFLAG =$2FF ;START/STOP FLAG (CNTL-1) FORf} PAGING; PAGE 3 LOCATIONSDCB =$300 ;DEVICE CONTROL BLOCKDDEVIC =$300 ;BUS I.D. NUMBERDUNIT =$301 ;UNg}IT NUMBERDCOMND =$302 ;BUS COMMANDDSTATS =$303 ;COMMAND TYPE/STATUS RETURNDBUFLO =$304 ;DATA BUFFER POINh}TERDBUFHI =$305 ; ...DTIMLO =$306 ;DEVICE TIME OUT IN 1 SEC. UNITSDUNUSE =$307 ;UNUSEDDBYTLO =$308 i} ;BYTE COUNTDBYTHI =$309 ; ...DAUX1 =$30A ;COMMAND AUXILLARY BYTESDAUX2 =$30B ; ...TIMER1 =$30C j} ;INITIAL TIMER VALUEADDCOR =$30E ;ADDITION CORRECTIONCASFLG =$30F ;CASSETTE MODE WHEN SETTIMER2 =$310 ;k}FINAL TIME VALUE (USED TO COMPUTE BAUD RATE)TEMP1 =$312 ;TEMP LOCATIONSTEMP2 =$314 ; ...TEMP3 =$315 ; ..l}.SAVIO =$316 ;SAVE SERIAL IN DATA PORTTIMFLG =$317 ;TIME OUT FLAG FOR BAUD RATE CORRECTIONSTACKP =$318 ;m}SIO STACK POINTER SAVE LOCTSTAT =$319 ;TEMP STATUS LOCHATABS =$31A ;HANDLER ADDRESS TABLE MAXDEV =$21 ;n}MAXIMUM HANDLER ADDRESS INDEX; IOCB OFFSETS IOCB =$340 ;I/O CONTROL BLOCKSICHID =$340 ;HANDLER INDEX ($FF =o} FREE)ICDNO =$341 ;DEVICE NUMBER (DRIVE NUMBER)ICCOM =$342 ;COMMAND CODEICSTA =$343 ;STATUSICBAL =$344p} ;BUFFER ADDRESSICBAH =$345 ; ...ICPTL =$346 ;PUT BYTE ROUTINE ADDRESS - 1ICPTH =$347 ; ...ICBLL q}=$348 ;BUFFER LENGTHICBLH =$349 ; ...ICAX1 =$34A ;AUXILLARY INFOICAX2 =$34B ; ...ICSPR =$34C r} ;4 SPARE BYTESPRNBUF =$3C0 ;PRINTER BUFFER ;($3EA - $3FC SPARE); PAGE 4 LOCATIONSCASBUF =$3FD ;CAs}SSETTE BUFFER; USER AREA STARTS HERE AND GOES TO THE END OF PAGE 5USAREA =$480;; Other random stuff;CONSOL = $D01t}F ; console switches start, select, option;ATASCII CHARACTER DEFSATCLR =$7D ;CLEAR SCREEN CHARACTERATRUB =$7E u} ;BACK SPACE (RUBOUT)ATTAB =$7F ;TABATEOL =$9B ;END-OF-LINEATDELL =$9C ; Delete lineATBEL =$FD v} ;CONSOLE BELLATURW =$1C ;UP-ARROWATDRW =$1D ;DOWN-ARROWATLRW =$1E ;LEFT-ARROWATRRW =$1F ;RIGHT-Aw}RROW; USEFUL VALUESLEDGE =2 ;LMARGN'S INITIAL VALUEREDGE =39 ;RMARGN'S INITIAL VALUE;; End of SYSMAC.SMLx};----------------------------------------------------------------;; defs from sysequ.asm;;; EXECUTE FLAG DEFINES;EXy}CYES = $80 ; EXECUTE IN PROGRESSEXCSCR = $40 ; ECHO EXCUTE INPUT TO SCREENEXCNEW = $10 ; EXECUTE START UP MODEEXCz}SUP = $20 ; COLD START EXEC FLAG;; MISC ADDRESS EQUATES;CPALOC = $0A ; POINTER TO CP/AWARMST = $08 ; WARM START{} (0=COLD)MEMLO = $2E7 ; AVAIL MEM (LOW) PTRMEMTOP = $2E5 ; AVAIL MEM (HIGH) PTRAPPMHI = $0E ; UPPER LIMIT OF APPL|}ICATION MEMORYINITADR = $2E2 ; ATARI LOAD/INIT ADRGOADR = $2E0 ; ATARI LOAD/GO ADRCARTLOC = $BFFA ; CARTRIDGE RUN}} LOCATIONCIO = $E456 ; CIO ENTRY ADREOL = $9B ; END OF LINE CHAR;;; CP/A FUNCTION AND VALUE DISPLACEMSNT; (I~}NDIRECT THROUGH CPALOC); IE. (CPALOC),Y;CPGNFN = 3 ; GET NEXT FILE NAMECPDFDV = $07 ; DEFAULT DRIVE (3 BY}TES)CPBUFP = $0A ; CMD BUFF NEXT CHAR POINTR (1 BYTE)CPEXFL = $0B ; EXECUTE FLAGCPEXFN = $0C ; EXECUTE FILE NAME }(16 BYTES)CPEXNP = $1C ; EXECUTE NOTE/POINT VALUESCPFNAM = $21 ; FILENAME BUFFERRUNLOC = $3D ; CP/A LOAD/RUN ADR}CPCMDB = $3F ; COMMAND BUFFER (60 BYTES);CPCMDGO = -6 ; CP SUBROUTINE VECTOR;;-------------------------------------}---------------------------;; Floating point defs;fr0 = $D4 ; float reg 0fr1 = $E0 ; float reg 1flptr = $FC} ; pointer to a fp numinbuff = $F3 ; pointer to ascii numifp = $D9AA ; int in fr0 -> float in fr0fpi = $D9}D2 ; float in fr0 -> int in fr0fasc = $D8E6 ; fr0 -> (inbuff)fmove = $DDB6 ; fr0 -> fr1fadd = $DA66 ; fr}0 + fr1 -> fr0fsub = $DA60 ; fr0 - fr1 -> fr0fmul = $DADB ; fr0 * fr1 -> fr0fdiv = $DB28 ; fr0 / fr1 -> fr0}fld1r = $DD98 ; fr1 <- (XY); end of atari.m65ul = $DADB ; fr0 * fr1 -> fr0fdiv = $DB28 ; fr0 / fr1 -> fr06;; bcopy(p1, p2, nbytes); .globl _bcopy_bcopy: jsr popax ; get nbytes sta tmp1 stx tmp1+1 jsr popax ;} p2 sta ptr2 stx ptr2+1 jsr popax ; p1 sta ptr1 stx ptr1+1bc1: lda tmp1+1 ; nbytes^ beq bc3 ldy} #0 ; set up to move 256bc2: lda (ptr1),y ; get a byte sta (ptr2),y ; store it iny bne bc2 inc ptr1+1 } ; bump ptrs inc ptr2+1 dec tmp1+1 jmp bc1 ; do another blockbc3: ldy #0 ; set up for last section of < 25}6bc4: cpy tmp1 ; done yet? beq bc5 ; yup, exit lda (ptr1),y ; get a byte sta (ptr2),y ; store it iny } bne bc4bc5: rts ; done!; beq bc5 ; yup, exit lda (ptr1),y ; get a byte sta (ptr2),y ; store it iny #;; bzero(ptr, nbytes); .globl _bzero_bzero: jsr popax ; get nbytes sta tmp1 stx tmp2 jsr popax ; get }ptr sta ptr1 stx ptr1+1 lda #0bz1: ldx tmp2 ; get nbytes^ beq bz3 ; zero, try lo ldy #0bz2: sta }(ptr1),y ; zap a byte iny bne bz2 inc ptr1+1 ; bump ptr^ dec tmp2 ; dec nbytes^ bne bz1 ; around agai}nbz3: ldy tmp1 beq bz5 ldy #0bz4: sta (ptr1),y ; zap a byte iny cpy tmp1 ; done? bne bz4bz5: rts}bz3: ldy tmp1 beq bz5 ldy #0bz4: sta (ptr1),y ; zap a byte iny cpy tmp1 ; done? bne bz4bz5: rts;; cgetc(iocb); .globl _fgetc_fgetc: .globl _cgetc_cgetc: jsr popax ; get iocb tax lda #0 sta icbll,x } sta icblh,x sta icbal,x sta icbah,x lda #getchr sta iccom,x jsr ciov bpl getc9 cpy #EOFERR ; EOF? } beq getceof jmp ioreturn ; go return errorgetc9: ldx #0 ; return hi byte 0 rtsgetceof: lda #$FF tax }rts; getceof jmp ioreturn ; go return errorgetc9: ldx #0 ; return hi byte 0 rtsgetceof: lda #$FF tax ;; simple version of fgets; cgets(str, size, iocb); char *str;; int size, iocb;; .globl _cgets_cgets: jsr popax } ; get iocb sta tmp1 ; stash iocb here jsr popax ; get size stx tmp2 ; save x ldx tmp1 ; get iocb }sta icbll,x ; store size lo lda tmp2 sta icblh,x ; store size hi jsr popax ; get buf addr stx ptr2+1 } ; save x sta ptr2 ; and a, we'll return it if not eof ldx tmp1 ; get iocb sta icbal,x ; store size lo ld}a tmp2 sta icbah,x ; store size hi lda #getrec ; get a line sta iccom,x jsr ciov cpy #0 bmi return0} ldx ptr2+1 ; return the pointer lda ptr2 rtsreturn0: lda #0 ; return NULL tax rtsy #0 bmi return0h;; close an iocb; .globl _cclose_cclose: .globl _close_close: jsr popax ; get iocb num tax lda #close }sta iccom,x jsr ciov tya bmi *+5 ldx #0 rts ldx #$FF rtsr popax ; get iocb num tax lda #close L;; close all iocbs; .globl _closeall_closeall: ldx #$10 lda #close sta iccom,x jsr ciov txa clc adc }#$10 tax cpx #$80 bcc _closeall+2 rtsall: ldx #$10 lda #close sta iccom,x jsr ciov txa clc adc 0;; cputc(ch, iocb); .globl _fputc_fputc: .globl _cputc_cputc: jsr popax ; get iocb sta tmp1 jsr popax } ; get char ldx tmp1 pha lda #0 sta icbll,x sta icblh,x sta icbal,x sta icbah,x lda #putchr sta ic}com,x pla jsr ciov bpl putc9 jmp ioreturn ; do common error stuffputc9: tya ldx #0 rts #putchr sta ick;; delete file.; fdelete(str);;xcb: .byte 0 .globl _fdelete_fdelete: jsr findiocb ; find a free iocb stx xc }b ; save it jsr popax ; get the name string ldy xcb sta icbal,y ; store str\ txa sta icbah,y ; stor }e str^ tya tax ; get iocb in x lda #delete ; get rename opcode sta iccom,x lda #0 sta icax1,x sta }icax2,x jsr ciov bpl del0 jmp ioreturn ; common error handling codedel0: tya ldx #0 rts; icax1,x sta l;; rename file.; frename(str);; str is already in the form needed by ataridos, ie ; "d:foo.bar,baz.txt";xcb: .byte 0$} .globl _frename_frename: jsr findiocb ; find a free iocb stx xcb ; save it jsr popax ; get the name stri$}ng ldy xcb sta icbal,y ; store str\ txa sta icbah,y ; store str^ tya tax ; get iocb in x lda #re$}name ; get rename opcode sta iccom,x lda #0 sta icax1,x sta icax2,x jsr ciov bpl ren0 jmp ioreturnre$}n0: tya ldx #0 rts; sta iccom,x lda #0 sta icax1,x sta icax2,x jsr ciov bpl ren0 jmp ioreturnre$;; get a kbd char.; assemble with atari.m65; .globl _kbdchar_kbdchar: jsr k ; call the internal routine ldx #(}0 ; so we can zap X before cmp #0 ; (setting cond codes and) rts ; returningk: lda keybdv+5 pha ld(}a keybdv+4 pha rtsefore cmp #0 ; (setting cond codes and) rts ; returningk: lda keybdv+5 pha ld(;; this file must be assembled into all files that you expect to; use as parts of C programs. it defines common low level ,}locations; like the stack ptr etc.;sp = $80 ; stack pointersreg = $82 ; secondary registerargcnt = $82 ; ,}same slot; temp for vararg funcstmpptr = $84 ; pointer to random frobfntemp = $86 ; pointer to file namesvax = ,} $88 ; slot to save/rest AX intoorigsp = $8A ; original system spptr1 = $8Cptr2 = $8Eptr3 = $90tmp1 = $9,}2tmp2 = $93tmp3 = $94tmp4 = $95; end global.m65ginal system spptr1 = $8Cptr2 = $8Eptr3 = $90tmp1 = $9,;;; heap defs for malloc and pmalloc;;; C variable (char * )_himem. contains pointer to next piece of; mem unallocated.0}; .globl __himem__himem: .word __FREEMEM ; defined by linker, top of executable;; C variable (memblock * )_freels0}t. contains head of linked list; of blocks of mem that have been freed; .globl __freelst__freelst: .word 0 ; nil0} to start with;; that's all for here. see pmalloc.c and malloc.c for code that uses them;__freelst: .word 0 ; nil0^;; return t if char is alpha; .globl _isalpha_isalpha: jsr popax ; get the char cmp #'A' bcc nope ; if l4}ess than 'A', return 0 cmp #'Z+1 bcc yup cmp #'a bcc nope cmp #'z+1 bcs nopeyup: lda #1 rtsnope: l4}da #0 rtsreturn 0 cmp #'Z+1 bcc yup cmp #'a bcc nope cmp #'z+1 bcs nopeyup: lda #1 rtsnope: l4; isdigit(c) -- decimal-p .globl _isdigit_isdigit: jsr popax ; get the char cmp #'0' ; < '0'? bcc ret0 8}; less, return 0 cmp #'9'+1 ; >= '8'? bcs ret0 ; yes, return 0 lda #1 ; no, return a 1 rtsret0: txa 8}rtsss, return 0 cmp #'9'+1 ; >= '8'? bcs ret0 ; yes, return 0 lda #1 ; no, return a 1 rtsret0: txa 8; isodigit(c) -- octal-p .globl _isodigit_isodigit: jsr popax ; get the char cmp #'0' ; < '0'? bcc ret0 <} ; less, return 0 cmp #'8' ; >= '8'? bcs ret0 ; yes, return 0 lda #1 ; no, return a 1 rtsret0: txa r<}tsless, return 0 cmp #'8' ; >= '8'? bcs ret0 ; yes, return 0 lda #1 ; no, return a 1 rtsret0: txa r<; iswhite(c) -- whitespace-p .globl _iswhite_iswhite: jsr popax ; get the char and #$7F ; mask hi bit beq @}ret0 cmp #$21 ; <= space? bcc ret1 ; less, return 1 cmp #$7F ; >= rubout? bcs ret1 ; yes, return 1re@}t0: txa ; no, return a 0 rtsret1: lda #1 rtsn 1 cmp #$7F ; >= rubout? bcs ret1 ; yes, return 1re@<;; itoa(i, s);; .globl _itoa_itoa: jsr popax ; get string addr sta ptr1 stx ptr1+1 jsr popax ; geD}t number sta fr0 stx fr0+1 ; set up to floatify cpx #0 ; neg? bpl itoa_1 jsr negax sta fr0 ;D} store it again stx fr0+1 lda #'- ldy #0 sta (ptr1),y ; stuff the neg sign inc ptr1 bne itoa_1 inc ptD}r1+1itoa_1: jsr ifp ; floatify it jsr fasc ; ascify it ldy #0itoa_2: lda (inbuff),y ; get a byte D} bmi itoa_3 ; hi bit set? ok, done sta (ptr1),y ; stash in caller's buffer iny jmp itoa_2itoa_3: and #$7D}F ; mask it sta (ptr1),y ; stash it lda #0 iny sta (ptr1),y rtsr iny jmp itoa_2itoa_3: and #$7DU;; smaller slicker hand-coded line-parsing routine;; assemble this with global.m65;; _parseline(line, argv) char * line;H} int * argv;; .globl __parseli__parseli: ldy #0 sty tmp1 ; use tmp1 as counter jsr popax ; get argv ptr H} sta ptr2 ; save into ptr2 stx ptr2+1 jsr popax ; get line pointer sta ptr1 ; save in ptr1 stx ptr1+1 H} cpx #0 bne parse1 ; test line pointer for zero-ness... lda ptr1 beq parse8parse1: ; skip whitespace lH}dy #0 ; get a char lda (ptr1),y beq parse8 ; done! finish up and leave cmp #$9B ; EOL? beq parse8 ; H}yup, same as nul jsr white_p bcc parse2 ; not whiteparse1w: inc ptr1 ; bump string ptr bne parse1 inc pH}tr1+1 bne parse1parse2: ; remember the ptr, bump arg count ldy #0 lda ptr1 sta (ptr2),y ; store ptr loH} iny lda ptr1+1 sta (ptr2),y ; ... ptr hi inc tmp1 ; and bump arg count clc lda ptr2 adc #2 ; bump aH}rgv ptr sta ptr2 bcc parse3 inc ptr2+1parse3: ; find next whitespace ldy #0 lda (ptr1),y ; get a chaH}r beq parse8 ; nul, we're done jsr white_p ; white? bcs parse4 ; yes, found end of this arg inc ptr1 bH}ne parse3 inc ptr1+1 bne parse3parse4: pha ; save the char for a sec lda #0 sta (ptr1),y ; zap in eos H} pla ; get orig char back beq parse8 ; done! cmp #$9B bne parse1w ; nope, go bump ptr and keep scanningH}parse8: ; load up arg count and return ldx #0 lda tmp1 rts;; return cond codes carry set if white, clear ifH} non-white;white_p: cmp #$7F ; > 7F? bcs w_ret1 ; yes, that's white cmp #$21 ; <= space? bcs w_ret0 H} ; no, it's data.w_ret1: sec rtsw_ret0: clc rts ; yes, that's white cmp #$21 ; <= space? bcs w_ret0 H:;; read(iocb, buf, size)->real size read; .globl _read_read: jsr __rwsetup ; do common setup for read and write bL}eq read9 ; if size 0, it's a no-op lda #getchr ; iocb command code sta iccom,x jsr ciov ; read it bpl rL}ead9 cpy #$88 ; eof is treated specially beq read9 jmp ioreturn ; do common error stuffread9: lda icbll,x L} ; buf len lo pha ; save it lda icblh,x ; get buf len hi tax ; in x pla ; get lo byte back rtL}s;buf len lo pha ; save it lda icblh,x ; get buf len hi tax ; in x pla ; get lo byte back rtL;; Runtime code for scc65.; assemble with atari.m65 and global.m65 .globl __start ; program lo memory boundary__staP}rt:;; this is the first piece of actual generated code...; jmp start ; so we don't need a start vector;; routines P}for inc/dec'ing sp;; .globl decsp2;decsp2: ; dec sp by 2; pha ; save a; lda sp ; get sp lo; sec;P} sbc #2 ; sub 2; sta sp; lda sp+1 ; get sp hi; sbc #0 ; sub carry; sta sp+1; pla ; get a back;P} rts .globl addysp ; add Y to SPaddysp: pha ; save A clc tya ; get the value adc sp ; add lo bP}yte sta sp ; put it back bcc addysp_1 ; if no carry, we're done inc sp+1 ; inc hi byteaddysp_1: pla ;P} get A back; rts ; done jmp tstax ; return condition codes; .globl incsp1;incsp1:; ldy #1; bne addyspP} .globl incsp2 ; inc sp by 2incsp2:; do this by hand, cause it gets used a lot; ldy #2; bne addysp inc sp P} bne *+4 inc sp+1; might as well do incsp1 here, as we have the code... .globl incsp1incsp1: inc sp bne *+4 P}inc sp+1 rts .globl incsp3 ; inc sp by 3incsp3: ldy #3 bne addysp .globl incsp4 ; inc sp by 4incP}sp4: ldy #4 bne addysp .globl incsp5 ; inc sp by 5incsp5: ldy #5 bne addysp .globl incsp6 ; inc spP} by 6incsp6: ldy #6 bne addysp .globl incsp7 ; inc sp by 7incsp7: ldy #7 bne addysp .globl incsp8 P} ; inc sp by 8incsp8: ldy #8 bne addysp .globl subysp ; sub Y from SPsubysp: pha ; save A sty tmp1 P} ; save the value lda sp ; get lo byte sec sbc tmp1 ; sub y val sta sp ; put it back; wrong!; bcs suP}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 bP}ack rts ; done .globl decsp1decsp1: ldy #1 bne subysp .globl decsp2decsp2:;; do this one by hand, caP}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+P}1 pla rts .globl decsp3decsp3: ldy #3 bne subysp .globl decsp4decsp4: ldy #4 bne subysp .globl P}decsp5decsp5: ldy #5 bne subysp .globl decsp6decsp6: ldy #6 bne subysp .globl decsp7decsp7: ldy #7P} bne subysp .globl decsp8decsp8: ldy #8 bne subysp;; ops for loading/indexing stack slots; .globl ldaxyspP} ; load AX from SP@(Y)ldaxysp: lda (sp),y ; get lo byte pha iny lda (sp),y ; get hi byte tax ; intP}o x pla ; get lo byte back; rts jmp tstax ; return cc; .globl ldsrysp ; load SREG from SP@(Y);ldsrysp:P}; pha ; save A; lda (sp),y ; get lo byte; sta sreg ; store it; iny; lda (sp),y ; get hi byte; stP}a sreg+1 ; store it; pla ; get A back; jsr ldaxysp ; just do the things we optimized; jsr swapsreg ; ouP}t.; rts .globl ldaysp ; load A from SP@(Y)ldaysp: ; zzz maybe do this on line? ldx #0 lda (sp),y rtsP} .globl locysp ; compute location of SP@(Y) in AXlocysp: ldx sp+1 ; get hi byte clc ; set up for add tP}ya ; get offset adc sp ; compute lo byte bcc locysp_1 inx ; add in carrylocysp_1: rts .globl plocP}ysp ; push addr y(sp)plocysp: jsr locysp jmp pushax ;; routines for inc/dec'ing AX; .globl incax8incax8: P} ldy #8 jmp indexax .globl incax7incax7: ldy #7 jmp indexax .globl incax6incax6: ldy #6 jmp indexax P} .globl incax5incax5: ldy #5 jmp indexax .globl incax4incax4: ldy #4 jmp indexax .globl incax3incax3: P} ldy #7 jmp indexax .globl incax2 ; inc AX by 2incax2: jsr incax1 ; inc it once, and fall thru .globl iP}ncax1 ; inc AX by 1incax1: tay ; use Y as a temp iny tya bne incax1_1 ; if not zero, we're done inx P} ; inc top halfincax1_1:; rts ; done jmp tstax ; return cond codes; .globl incaxi1 ; load AX indirect, aP}nd increment by 1;incaxi1:; jsr ldaxi; jmp incax1; .globl incaxi2 ; load AX indirect, and increment by 2;incaxQ}i2:; jsr ldaxi; jmp incax2; .globl inci1spp ; load AX indirect, inc 1, store thru SP@+;inci1spp:; jsr incaxi1Q}; jmp staxspp; .globl inci2spp ; load AX indirect, inc 2, store thru SP@+;inci2spp:; jsr incaxi2; jmp staxspp Q} ; .globl decax2 ; dec AX by 2decax2: jsr decax1 ; dec it once, and fall thru .globl decax1 ; dec AX by Q}1decax1: tay ; use Y as a temp dey tya cmp #$FF ; wrap? bne decax1_1 ; if not -1, we're done dex Q} ; dec top halfdecax1_1:; rts ; done jmp tstax ; return cond codes; .globl decaxi1 ; load AX indirect, aQ}nd decrement by 1;decaxi1:; jsr ldaxi; jmp decax1; .globl decaxi2 ; load AX indirect, and decrement by 2;decaxQ}i2:; jsr ldaxi; jmp decax2; .globl deci1spp ; load AX indirect, dec 1, store thru SP@+;deci1spp:; jsr decaxi1Q}; jmp staxspp; .globl deci2spp ; load AX indirect, dec 2, store thru SP@+;deci2spp:; jsr decaxi2; jmp staxspp Q} ;; push/pop things on stack; .globl push0push0: lda #0 tax; ... .globl pushax ; push AXpushax: jsr deQ }csp2 ; dec sp ldy #0 ; get index sta (sp),y ; store lo byte pha ; save it txa ; get hi byte inQ }y ; bump idx sta (sp),y ; store hi byte pla ; get A back rts ; done .globl popax ; pop stack Q }into AXpopax: ldy #0 lda (sp),y ; get lo byte pha ; stash it iny lda (sp),y ; get hi byte tax Q } ; into x pla ; get lo byte back jmp incsp2 ; bump stack and return .globl popsreg ; pop stack into SREQ }Gpopsreg: pha ; save A ldy #0 lda (sp),y ; get lo byte sta sreg ; store it iny lda (sp),y ; geQ}t hi byte sta sreg+1 ; store it pla ; get A back jmp incsp2 ; bump stack and return .globl pushwysp Q} ; push a word from SP@(Y)pushwysp:; pha ; save A; txa; pha ; save X lda (sp),y ; get lo byte pha Q} ; Save it iny ; bump idx lda (sp),y ; get hi byte tax ; into X pla ; get back lo byte jsr puQ}shax ; push that; pla ; get original X; tax ; into X; pla ; get back original A rts .globl pushQ}bysp ; push a byte from SP@(Y)pushbysp: lda (sp),y ; get lo byte ldx #0 jsr pushax ; push that rts;; VaQ}rious kinds of store operators; .globl staxspidx ; store AX at SP@@(Y)staxspidx: jsr staspic ; use common part Q}pha iny lda tmp2 sta (ptr1),y tax pla jmp tstax .globl staspidxstaspidx: jsr staspic ; use common paQ}rt ldx tmp2 jmp tstaxstaspic: sta tmp1 stx tmp2 sty tmp3 jsr popax ; get the pointer sta ptr1 stx Q} ptr1+1 ldy tmp3 lda tmp1 sta (ptr1),y rts .globl staxyspstaxysp: sta (sp),y pha txa iny sta (sQ}p),y pla jmp tstax .globl stayspstaysp: sta (sp),y jmp tstax; .globl stasreg ; store A thru SREG;stasrQ}eg:; ldy #0; sta (sreg),y; rts; .globl staxsreg ; store AX thru SREG;staxsreg:; ldy #0; sta (sreg),y ; stQ}ore lo byte; pha ; save A; iny ; bump idx; txa ; get hi byte; sta (sreg),y ; store it; pla ; Q}get A back;; rts ; done; jmp tstax ; return cc .globl staxspp ; store AX thru (sp), and popstaxspp: phQ}a ; save A txa pha ; save X jsr popax ; pop addr into AX sta ptr1 ; save into a pointer stx ptr1Q}+1 ldy #1 pla ; get hi byte back sta (ptr1),y ; store it tax ; back into X pla ; get lo byte deQ}y sta (ptr1),y ; store it jmp tstax ; return cc .globl staspp ; store A thru (sp), and popstaspp: pha Q} ; save A txa pha ; save X jsr popax ; pop addr into AX sta ptr1 ; save into a pointer stx ptr1+1 Q}pla ; get X tax pla ; get lo byte ldy #0 sta (ptr1),y ; store it jmp tstax ; return cc ;; OpeQ }rations on AX; .globl aslax ; shift AX left 1aslax: asl A pha txa rol A tax pla rts; .globl asraxQ!} ; shift AX right 1;asrax:; pha; txa; pha; rol A ; get carry set right; pla; ror A ; do the real rotaQ"}te; tax; pla; ror A; rts .globl ldaxi ; load AX indirect thru AXldaxi: sta tmpptr stx tmpptr+1 ldy Q#}#1 lda (tmpptr),y tax dey lda (tmpptr),y; rts jmp tstax ; return cond codes;; load A indirect thru AX;Q$} .globl ldaildai: sta tmpptr ; set pointer stx tmpptr+1 ldy #0 ; set idx lda (tmpptr),y ; get byte bpQ%}l ldai_1 ; pos... ldx #$FF rtsldai_1: ldx #0; rts jmp tstax ; return cond codes .globl negax ; neQ&}gate axnegax: pha ; save A txa ; get X eor #$FF ; invert tax ; back to X pla ; get A backQ'} eor #$FF ; invert clc adc #1 ; inc bcc negax_1 inx ; bump Xnegax_1: rts .globl lnegax ; logQ(}ical complement AXlnegax: stx tmp3 ora tmp3 beq lneg1 ; it's zero, so return 1 lda #0 tax rtslneg1: ldQ)}x #0 lda #1 rts .globl complax ; one's complement AXcomplax: eor #$FF ; Not A pha txa eor #$FF Q*} ; Not X tax pla rts .globl indexax ; index in Y, add Y to AXindexax: sta tmp1 tya clc adc tmp1 bccQ+} *+3 inx rts .globl plocidx ; push location of AX@(Y)plocidx: jsr indexax jmp pushax;; test (AX);; .Q,}globl tstaxi;tstaxi:; jsr ldaxi ; and fall thru...;; test AX for nonzero-ness. return result in CC; .globlQ-} tstaxtstax:; cmp #0; beq tstax_0; bpl tstax_p; ; A was negative, try X;tstax_0: ; A was 0, try X; Q.} cpx #0;tstax_9:; rts;tstax_p: ; A was positive; cpx #0 ; try X; bpl tstax cpx #0 ; test X beq tQ/}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 iQ0}s ok, just return ldy #1 ; force 'positive'tstax_9: rts ; done, just return .globl ldaxidx ; load AX frQ1}om (AX)Yldaxidx: jsr indexax ; compute address jmp ldaxi ; load indirect .globl ldaidx ; load A from (AX)Q2}Yldaidx: jsr indexax ; compute address jmp ldai ; load indirect .globl pushwidx ; push word at (AX)YpushwiQ3}dx: jsr indexax ; index jsr ldaxi jmp pushax .globl pushbidx ; push byte at (AX)Ypushbidx: jsr indexax Q4} ; index jsr ldai jmp pushax;; operations on SREG; .globl asltosasltos: jsr popsreg ; for optimized codeQ5} .globl aslsreg ; shift SREG left AX times, result in AXaslsreg: cpx #0 ; X nonzero? bne aslsreg_0 ; no, jusQ6}t return 0 tay ; use Y as counter lda sreg+1 sta tmp1 ; use A and tmp1 as register lda sreg cpy #0 ;Q7} shift count 0? beq aslsreg_9 ; done shiftingaslsreg_1: asl A ; shift A rol tmp1 dey ; dec counter bneQ8} aslsreg_1aslsreg_9: ldx tmp1 ; get hi byte; rts ; done jmp tstaxaslsreg_0: lda #0 tax; rts jQ9}mp tstax ; return status for optimized code .globl asrtosasrtos: jsr popsreg ; for optimized code .globl asQ:}rsreg ; shift SREG right by AX, result in AXasrsreg: cpx #0 ; X nonzero? bne aslsreg_0 ; no, just return 0; tQ;}ax ; use X as counter; php ; save Z flag, for zero counter; lda sreg; sta tmp1 ; use tmp1 and A as regisQ<}ter; lda sreg+1; and #$80 ; keep top bit; sta tmp2; plp ; get Z flag back; beq asrsreg_9 ; done shiftiQ=}ng;asrsreg_1:; lsr A ; shift hi byte; ror tmp1 ; and lo byte; ora tmp2 ; keep top bit; dex ; dec coQ>}unter; bne asrsreg_1;asrsreg_9:; tax ; put hi byte in X; lda tmp1 ; and get lo byte; rts; this isn't riQ?}ght... test after loading AX...; cmp #0 ; shift count 0?; beq aslsreg_0 ; yes, return 0 tay ; use Y as shiftQ@} counter lda sreg ldx sreg+1 ; get the value into AX cpy #0 beq asrsreg_9 ; zero, return now; cpx #0 ; QA}test AX for minus-ness; bpl *+5; jsr negax stx tmp1 ; leave hi byte in tmp1asrsreg_1: ldx tmp1 ; get hi byQB}te, cpx #$80 ; compare, to set carry bit if neg ror tmp1 ; shift hi byte, preserving hi bit ror A ; shift QC}lo byte dey ; dec shift count bne asrsreg_1 ; 0? done ldx tmp1 ; get hi byte; ldy sreg+1 ; original vaQD}lue negative?; bpl *+5; jsr negax ; negate resultasrsreg_9: jmp tstax ; return status for optimized code .QE}globl addtosaddtos: jsr popsreg ; for optimized code .globl addsreg ; add SREG to AXaddsreg: clc adc sregQF} ; add lo byte pha txa adc sreg+1 ; add hi byte tax pla; rts jmp tstax ; return status for optimizedQG} code; .globl addimm ; add immediate following word;addimm:; sta tmp1 ; save A; stx tmp1+1 ; and X; plaQH} ; get return addr; sta ptr1; pla; sta ptr1+1; ldy #1; lda (ptr1),y ; get lo byte; clc; adc tmp1 QI}; add to old A value; sta tmp1 ; put it back; iny; lda (ptr1),y ; get hi byte; adc tmp1+1; sta tmp1+1; clQJ}c ; adjust return addr; lda ptr1; adc #3 ; so we can jump thru it; sta ptr1; bcc *+4; inc ptr1+1; ldQK}a tmp1 ; get A back; ldx tmp1+1; jmp (ptr1) .globl subtossubtos: jsr popsreg ; for optimized code .gloQL}bl subsreg ; sub AX from SREG, result in AXsubsreg: sta tmp1 stx tmp2 ; save AX lda sreg sec sbc tmp1 QM} ; sub lo byte pha lda sreg+1 sbc tmp2 ; sub hi byte tax pla; rts jmp tstax ; return status for optimQN}ized code; .globl swapsreg ; swap AX and SREG;swapsreg:; sta tmp1; stx tmp2; lda sreg ; get lo byte; ldx QO} sreg+1 ; get hi byte; ldy tmp1; sty sreg; ldy tmp2; sty sreg+1; rts .globl ortosortos: jsr popsreg QP} ; for optimized code .globl orsreg ; OR sreg into AXorsreg: ora sreg pha txa ora sreg+1 tax pla; rtQQ}s jmp tstax ; return status for optimized code .globl xortosxortos: jsr popsreg ; for optimized code .globQR}l xorsreg ; XOR sreg into AXxorsreg: eor sreg pha txa eor sreg+1 tax pla; rts jmp tstax ; return sQS}tatus for optimized code .globl andtosandtos: jsr popsreg ; for optimized code .globl andsreg ; AND sreg intQT}o AXandsreg: and sreg pha txa and sreg+1 tax pla; rts jmp tstax ; return status for optimized code; QU} .globl ldsr ; load sreg from following word;ldsr:; sta tmp1 ; save A; pla ; get return addr; sta ptr1;QV} pla; sta ptr1+1; ldy #1; lda (ptr1),y ; get lo byte; sta sreg; iny; lda (ptr1),y ; get hi byte; sta sQW}reg+1; clc ; adjust return addr; lda ptr1; adc #3 ; so we can jump thru it; sta ptr1; bcc *+4; inc pQX}tr1+1; lda tmp1 ; get A back; jmp (ptr1);; comparisons; .globl axzeropaxzerop: cmp #0 bne return1 cpQY}x #0 bne return1 beq return0 .globl toseqaxtoseqax: jsr popsreg ; for optimized code .globl sregeqax ; QZ}SREG == AXsregeqax: cmp sreg ; A == sreg lo? bne return0 ; nope, return 0 cpx sreg+1 ; X == sreg hi? bneQ[} return0 beq return1 .globl tosneaxtosneax: jsr popsreg ; for optimized code .globl sregneax ; SREG != AXQ\}sregneax: cmp sreg ; A == sreg lo? bne return1 ; nope, return 1 cpx sreg+1 ; X == sreg hi? bne return1 Q]} beq return0 .globl tosltaxtosltax: jsr popsreg ; for optimized code .globl sregltax ; SREG < AXsregltax: Q^} ; really AX > SREG... cpx sreg+1 ; X < sreg hi? bmi return0 ; X < SR^ , return 0 bne return1 ; not =, soQ_} >; return 1 cmp sreg ; A < sreg lo? bcc return0 ; A < SR\, return 0 beq return0 bcs return1 .globl tosQ`}ultaxtosultax: jsr popsreg ; for optimized code .globl sregultax ; SREG u< AXsregultax: ; AX u> SREG cpx Qa}sreg+1 bcc return0 ; tos^ u< ax^ , return 0 bne return1 ; if ne, must be u>; return 1 cmp sreg bcc return0Qb} 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 cmQd}p sreg bcc return0 ; u> , return 0 bcs return1 .globl tosuleaxtosuleax: jsr popsreg ; for optimized codeQe} .globl sreguleax ; SREG u<= AXsreguleax: cpx sreg+1 bcc return0 ; X < SR^, return 0 bne return1 ; X > SRQf}^, return 1 cmp sreg bcc return0 bcs return1;; return functions for comparison ops. these guys are careful; to Qg}leave the condition codes correct for the AX value. Compiler; depends on that when optimizing; beware!;return1: ldx #0Qq}BATARI M65BBCOPY M65BBZERO M65BCGETC M65BCGETS M65BCLOSE M65BCLOSEALLM65BCPUTC M65BFDELETE M65BFRENAME M65BGETCH M65BGLOBAL M65BHEAP M65BISALPHA M65BISDIGIT M65BISODIGITM65BISWHITE M65BITOA M65BPARSELINM65BREAD M65BRUNTIME M65BRWCOMMONM65BSTDIO M65BSTRCHR M65BTOLOWER M65BTOUPPER M65BTPRINTF M65BWRITE M65B COPYLEFTDOC lda #1 rtsreturn0: lda #0 tax rts .globl tosgtaxtosgtax: jsr popsreg ; for optimized code .globl Qr} sreggtax ; SREG > AXsreggtax: ; AX < SR cpx sreg+1 bmi return1 ; < , return 1 bne return0 ; not =, so Qs}>; return 0 cmp sreg bcc return1 ; < , return 1 bcs return0 .globl tosugtaxtosugtax: jsr popsreg ; forQt} optimized code .globl sregugtax ; SREG u> AXsregugtax: cpx sreg+1 bcc return1 ; < , return 1 bne return0 Qu} ; not =, so >; return 0 cmp sreg bcc return1 ; < , return 1 bcs return0 .globl tosgeaxtosgeax: jsr popsrQv}eg ; for optimized code .globl sreggeax ; SREG >= AXsreggeax: ; AX <= SR cpx sreg+1 bmi return1 ; < , rQw}eturn 1 bne return0 ; not =, so >; return 0 cmp sreg bcc return1 ; < , return 1 beq return1 bcs return0Qx} .globl tosugeaxtosugeax: jsr popsreg ; for optimized code .globl sregugeax ; AX u<= SREGsregugeax: cpx sreQy}g+1 bcc return1 ; < , return 1 bne return0 ; not =, so >; return 0 cmp sreg bcc return1 ; < , return 1 Qz} beq return1 bcs return0; kludgey constant for DIV, MOD;onehalf:; .byte $3F,$49,$99,$99,$99,$99;; function opsQ{}; .globl enterfun0enterfun0: ldy #0 beq enterfun .globl enterfun1enterfun1: ldy #1 bne enterfun .gloQ|}bl enterfun2enterfun2: ldy #2 bne enterfun .globl enterfun3enterfun3: ldy #3 bne enterfun .globl enterQ}}fun4enterfun4: ldy #4 bne enterfun .globl enterfun5enterfun5: ldy #5; bne enterfun;; expect frame size iQ~}n Y, push fp; .globl enterfunenterfun: tya ; get arg count; asl A; clc; adc sp ; add to sp; pha; lQ}da sp+1; adc #0; tax; pla ldx #0 ; just push arg count jmp pushax .globl exitfun ; exit a function. Q}pop stack and rtsexitfun: pha ; save A a sec ldy #0 lda (sp),y ; that's the pushed arg count asl A ; lQ}oses big for large arg counts... tay iny iny ; count the word the count's stored in pla ; get it back jmpQ} addysp ; pop that many word-sized things;; random stuff;;; call value on in AX; .globl callaxcallax:; jsrQ} popax ; pop function ptr; jsr tos2ax ; get tos sta tmp1 stx tmp1+1 jmp (tmp1) ; jump there;; swap AQ}X with TOS; .globl swapstkswapstk: sta tmpptr stx tmpptr+1 ldy #1 ; index lda (sp),y tax lda tmpptr+Q}1 sta (sp),y dey lda (sp),y pha lda tmpptr sta (sp),y pla rts ; whew! .globl pushwaxipushwaxi: Q} ; push word (ax) jsr ldaxi jmp pushax .globl pushbaxi ; push byte at (ax)pushbaxi: jsr ldai jmp pushaxQ}; .globl ldaxysp;ldaxysp:; jsr locysp; jmp ldaxi;; or ax with tos, pop;; .globl oraxtos;oraxtos:; ldy Q}#0; ora (sp),y; pha; txa; iny; ora (sp),y; tax; pla; jmp incsp2;; eor ax with tos, pop;; .globl eoraQ}xtos;eoraxtos:; ldy #0; eor (sp),y; pha; txa; iny; eor (sp),y; tax; pla; jmp inc2sp;; and ax with tQ}os, pop;; .globl andaxtos;andaxtos:; ldy #0; and (sp),y; pha; txa; iny; and (sp),y; tax; pla; jmp Q}inc2sp;; add Y to sp, leave result in AX;; .globl addrysp;addrysp:; tya ; get offset; clc ; set up for.Q}..; adc sp ; add low byte; pha; lda sp+1 ; get hi byte; adc #0 ; add carry; tax ; xfer to x; plQ}a ; get a back; rts ; done;; handler for case jump inst.; .globl casejumpcasejump:;; case table after tQ}he call to casejmp. val in AX.; table is of the form ,,...,0.; rts from casejmp for default case, elseQ} pop return addr; addr and jmp to address; sta tmp3 stx tmp4 ; save value pla ; get return addr sta ptr1Q} pla sta ptr1+1 ; store in ptr 1 inc ptr1 ; and adjust it, because of way 6502 works bne *+4 inc ptr1+1cQ}ase1: ldy #1 ; first see if at end lda (ptr1),y ; test address byte hi bne case2 ; nope, not yet dey lda Q} (ptr1),y ; test address byte lo bne case2; oops, we're out of cases. compute return address; 2 + ptr1 clc lda ptrQ}1 ; get lo byte adc #2 ; inc past the 0 sta ptr1 bcc *+4 ; deal with carry inc ptr1+1 jmp (ptr1) ;Q} go therecase2: ; test case value against this value ldy #3 lda (ptr1),y ; value hi cmp tmp4 ; match swQ}itchval hi? bne case3 ; no match, try next dey lda (ptr1),y ; val lo cmp tmp3 ; match switchval lo? bne Q}case3; match! dey ; point at hi byte of addr lda (ptr1),y sta ptr2+1 ; stuff in ptr to jump thru dey Q}; point at lo byte of addr lda (ptr1),y sta ptr2 jmp (ptr2) ; go therecase3: ; no match, try next case cQ}lause clc lda ptr1 ; get case ptr adc #4 ; add 4 sta ptr1 ; put it back bcc *+4 inc ptr1+1 ; deaQ}l with carry jmp case1 ; and go try again;; save and restore AX; .globl saveaxsaveax: sta svax stx svax+1Q} rts .globl restaxrestax: lda svax ldx svax+1 jmp tstax;; support routines for runtime;;tos2ax:; ldy #Q}0;ytos2ax:; iny; lda (sp),y; tax; dey; lda (sp),y; rts; .globl popax;popax:; jsr tos2ax; jsr inc2spQ}; rts ;; mult and div, using fp routines;; .globl umul;umul: ; unsigned multiply; sta fr0 ; set up Q}the first num; stx fr0+1; jsr ifp ; make a float out of it; jsr fmove ; move to fr1; jsr popax ; get secQ}ond arg; sta fr0 ; set this one up; stx fr0+1; jsr ifp ; floatify...; jsr fmul ; mult them; jsr fpi Q} ; back to int; lda fr0; ldx fr0+1 ; load it up; rts ; and return .globl multosmultos: jsr popsreg Q} .globl smul ; signed multiply AX by SREGsmul: ldy #0 sty tmp3 ; zap negative flag cpx #0 bpl *+7 inc Q}tmp3 jsr negax sta tmpptr ; use sreg and tmpptr stx tmpptr+1 ; as regs lda sreg ldx sreg+1 bpl xsmul0Q} dec tmp3 jsr negax sta sreg stx sreg+1xsmul0: lda #0 sta tmp1 ; tmp1/2 as accumulator sta tmp1+1 lQ}da #1 ; use A as bit mask against SREGxsmul1: bit sreg ; this bit in sreg set? beq xsmul2 ; nope, try next Q} jsr xsmadd ; add AX val to accumxsmul2: asl tmpptr ; shift AX val left one rol tmpptr+1 asl A ; shift biQ}tmask left one bcc xsmul1 ; if bit not off end, keep working on lo byte lda #1 ; set up mask for hi bytexsmul3:Q} bit sreg+1 ; this bit in sreg set? beq xsmul4 ; nope, try next jsr xsmadd ; add AX val to accumxsmul4: aQ}sl tmpptr ; shift AX val left one rol tmpptr+1 asl A ; shift bitmask left one bcc xsmul3 ; if not off end,Q} keep working on hi byte ldx tmp1+1 ; load up accum lda tmp1 ldy tmp3 ; negate flag? beq xsmul9 jsr negaQ}xxsmul9: rts ; done!xsmadd: ; helper fun pha ; save bit mask clc lda tmpptr ; add AX valueQ} adc tmp1 ; to accumulator sta tmp1 lda tmpptr+1 adc tmp1+1 sta tmp1+1 pla ; get bitmask back rts Q} ; donexsdiv0: ; error return lda #0 tax sta sreg sta sreg+1 rts .globl divtosdivtos: jsr Q} popsreg ; pop other value into sreg .globl sdiv ; signed divide SREG by AX, sdiv: ; result in AX, remaindQ}er in SREG ldy #0 sty tmp3 ; zap denominator-negative flag sty tmp4 ; and numerator-negative flag jsr tstaxQ} ; AX zero? beq xsdiv0 ; yup, give up now bpl xsdiv1 ; positive, it's ok inc tmp3 ; denom negative jsrQ} negax ; negate itxsdiv1: sta ptr1 ; use tmpptr1 and SREG as regs stx ptr1+1 lda sreg ldx sreg+1 ; loaQ}d up sreg jsr tstax ; what sort of value? beq xsdiv0 ; zero, we lose bpl xsdiv2 ; positive, it's ok inc Q}tmp4 ; set numerator-negative flag jsr negax ; negate it sta sreg stx sreg+1xsdiv2: ldy #1 ; bit mask Q} sty ptr2 dey sty ptr2+1 sty tmp1 ; use tmp1 as accum sty tmp1+1;; shift ptr1 and ptr2 left until ptr1 is grQ}eater than SREG,; then shift right until it's <=;xsdiv3: lda ptr1+1 ; compare cmp sreg+1 ; p1 to sreg beq Q}xsdiv3a ; eq, try second byte bcs xsdiv4 ; >, we're done shifting left bcc xsdiv3b ; <, shift leftxsdiv3a: Q}lda ptr1 cmp sreg ; compare lo byte beq xsdiv5 ; =, skip the right shift bcs xsdiv4 ; >, go right onexsdiQ}v3b: asl ptr1 ; shift p1 left 1 rol ptr1+1 asl ptr2 ; shift bitmask left one rol ptr2+1 jmp xsdiv3 ; Q}round again.xsdiv4: ; shift p1, mask right one lsr ptr1+1 ; shift p1 ror ptr1 lsr ptr2+1 ; shift bitmaQ}sk ror ptr2 bcs xsdiv7a ; bit fell out end?!? ok, do exit processing;; whew! tmpptr1 (the divisor register) and tmQ}pptr2 (the quotient bitmask); are now all set to enter the divide loop;xsdiv5: ; compare sreg to p1. if >=, subtraQ}ct lda sreg+1 cmp ptr1+1 beq xsdiv5a ; try lo byte bcs xsdiv6 ; >, go subtract bcc xsdiv7 ; <, go shiQ}ft rightxsdiv5a: lda sreg cmp ptr1 bcc xsdiv7 ; < go shift rightxsdiv6: ; subtract p1 from sreg, and setQ} bit in accum sec lda sreg ; subtract sbc ptr1 ; p1 sta sreg ; from lda sreg+1 ; sreg sbQ}c ptr1+1 sta sreg+1 lda ptr2 ; or ora tmp1 ; bitmask sta tmp1 ; into lda ptr2+1 ; quotienQ}t ora tmp1+1 sta tmp1+1xsdiv7: lsr ptr1+1 ; shift p1 right ror ptr1 lsr ptr2+1 ror ptr2 bcc xsdiv5 Q} ; if no carry, round againxsdiv7a:;; done!; lda tmp4 ; negate remainder? beq xsdiv8 lda sreg ldx sreg+1Q} jsr negax sta sreg stx sreg+1xsdiv8: lda tmp1 ldx tmp1+1 ldy tmp3 ; numerator neg... cpy tmp4 ; sQ}ame as denom-neg? beq xsdiv9 ; yes, skip the negate jsr negaxxsdiv9: rts .globl modtosmodtos: jsr divtosQ} lda sreg ldx sreg+1 jmp tstax;; library routines; .globl _strcpy_strcpy: jsr popax sta ptr1 stx ptQ}r1+1 jsr popax sta ptr2 stx ptr2+1 ldy #0strc1: lda (ptr1),y sta (ptr2),y beq strc9 iny bne strc1Q} inc ptr1+1 inc ptr2+1 bne strc1strc9: rts .globl _strlen_strlen: jsr popax sta ptr1 stx ptr1+1 ldQ}x #0 ; YX used as counter ldy #0strlen1: lda (ptr1),y beq strlen9 iny bne strlen1 inc ptr1+1 inx bnQ}e strlen1strlen9: tya ; get low byte of counter, hi's all set rts;; find (char * str, int len, char c) -> indexQ};;_find:; jsr tos2ax; sta ptr1; stx ptr1+1; ldy #2; jsr ytos2ax; sta tmp1; stx tmp1+1; ldy #4; jsQ}r ytos2ax ; gets char in A; ldx #0; stx ptr2 ; use as counter here; stx ptr2+1; ldy #0;find1:; cmp Q} (ptr1),y ; match?; beq find9 ; yup, return; zzz;find9:; rts;; startup;;argv:; .word 0,0,0,0,0,0,0,0Q}; .word 0,0,0,0,0,0,0,0start: tsx stx origsp ; save system stk ptr;; lda #0 ; init stk ptr; sta sp; lQ}da #$80 ; $80 for debugging...; sta sp+1; lda memtop ; memtop for real code sta sp lda memtop+1 sta spQ}+1;; if running under SpartaDos, pass the command line to _main; lda $0700 ; check the sparta flag cmp #'S' beqQ} startcmd ; nope, check for dos xl;; Try to guess what OS we're running under.; Use the algorithm suggested by Dick CurzQ}on.; Look thru $0A. Should see a jmp, another jmp,; and something that's not a jump.; ldy #0 lda (cpaloc),y cmp Q}#$4C ; a jmp? bne start0 ; nope, give up ldy #3 lda (cpaloc),y cmp #$4C ; a jmp? bne start0 ; nopeQ} ldy #6 lda (cpaloc),y cmp #$4C ; a jmp? beq start0 ; if yes, it's mydos or somethingstartcmd:;; parse Q}command line etc. for now, assume Sparta or Dos XL; clc lda cpaloc ; get pointer to adc #cpcmdb ; cmd buf pQ}ha ; save lo byte lda cpaloc+1 adc #0 tax ; get hi byte pla ; get lo byte back jmp start1start0:Q}; no command line, just pass null lda #0 taxstart1: jsr pushax ; push the ptr ldy #1 ; 1 arg jsr __mainQ};; fall thru to exit...; rts ; done!; .globl _exit_exit: ldx origsp txs; rts jmp (dosvec);r __mainPt;; common rtn for read, write; .globl __rwsetup__rwsetup: ldy #4 jsr ldaxysp ; get iocb sta tmp3 ; save U}it ldy #0 jsr ldaxysp ; get size php ; save cond codes, for zero-ness stx tmp2 ldx tmp3 ; iocb staU} icbll,x lda tmp2 ; size hi sta icblh,x ldy #2 ; get buf addr jsr ldaxysp stx tmp2 ldx tmp3 sta iU}cbal,x lda tmp2 sta icbah,x jsr incsp6 ; pop args plp rts;r jsr ldaxysp stx tmp2 ldx tmp3 sta iTL;; data and part of the code for Small-C io library; this must be assembled with atari.m65 and global.m65;; canned filesY}. these are declared pointers to something,; but they're really IOCBs.;; it'd be nice if we could make these be on page 0Y}... .globl _stdin_stdin: .word 0 ; default to screen/kbd .globl _stdout_stdout: .word 0 ; default to scrY}een/kbd .globl _stderr_stderr: .word 0 ; default to screen/kbd .globl _errno_errno: .word 0 ; error numbY}er;;; internal helper fun for open routines.; find a free iocb, return in x; .globl findiocbfindiocb: ldx #$10 Y} ; start at # 1findiocb1: lda ichid,x ; get handler id cmp #$FF ; free? beq findiocb9 ; yup, return it txY}a clc adc #$10 ; next iocb tax cmp #$80 ; past last one? bcc findiocb1 ; nope, return it ldx #$FF ;Y} return -1findiocb9: rts;; copen(name, mode)->iocb #; .globl _copen_copen: jsr popax ; get open mode sta Y}tmp1 ; save it jsr popax ; get name sta fntemp stx fntemp+1 jsr findiocb ; try to find a free iocb bmi Y}copenerr ; no free ones stx tmp4 lda tmp1 ; get open mode again cmp #'r ; read? bne copen1 lda #OPNIN Y} ; open for input bne copen5copen1: cmp #'w ; write? bne copen2 lda #OPNOT bne copen5copen2: cmp #'a Y} ; write append? bne copen3 lda #OPNOT|APPEND bne copen5copen3: cmp #'d ; directory? bne copenerr ; bogY}on, return err lda #OPNIN|DIRECTcopen5: ldx tmp4 sta icax1,x ; store open bits lda #0 sta icax2,x sta Y}icbll,x sta icblh,x;; make sure the name's got an EOL at the end; ldy #0copen6: lda (fntemp),y and #$7F ; Y}mask for non-inverted beq copen7 cmp #'a ; need to upcase, for non-sparta dos'es bmi copen6a cmp #'z+1 bpl Y}copen6a sec sbc #$20 ; subtract a spacecopen6a:; sta copenbuf,y sta casbuf,y ; use casbuf to save a little spY}ace iny bne copen6copen7: lda #$9B; sta copenbuf,y sta casbuf,y; lda #copenbuf\ lda #casbuf\ sta icbaY}l,x; lda #copenbuf^ lda #casbuf^ sta icbah,x lda #open sta iccom,x;; all set; jsr ciov bpl copen8 Y}; ok, return it jmp ioreturncopen8: txa ; return iocb in ax ldx #0 rts; zzzcopenerr: lda #$FF tax rtY}s;copenbuf: .byte " ";; common error vector for io things. do a JMP here right after callingY}; CIOV. we expect status in Y.; .globl ioreturnioreturn: tya ; get return code ldx #$FF ; return error sY}ta _errno stx _errno+1 rts .globl ioreturnioreturn: tya ; get return code ldx #$FF ; return error sX!;; 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 .globl _tolower_tolower: jsr popax ; get the char cmp #'A ; < 'a'? bcc tolower9 ; yup, skip it cmp #'Za}+1 ; > 'z ? bcs tolower9 adc #$20 ; carry's already settolower9: rtsbcc tolower9 ; yup, skip it cmp #'Z`U .globl _toupper_toupper: jsr popax ; get the char cmp #'a ; < 'a'? bcc toupper9 ; yup, skip it cmp #'ze}+1 ; > 'z ? bcs toupper9 sec sbc #$20toupper9: rts #'a ; < 'a'? bcc toupper9 ; yup, skip it cmp #'zdA;; tiny printf etc.;; utilscconout: ; out char in a. bash regs ldx #0 pha ; save the char txa ; geti} a zero sta icbal,x ; zap buf addr sta icbah,x sta icbll,x ; and buf len sta icblh,x lda #putchr ; sai}y put a byte sta iccom,x pla ; get the byte again jsr ciov ; go do it rtspf_incs: ; inc str ptr ini}c ptr1 beq *+3 rts inc ptr1+1 rtspf_nxta: ; get next arg sec ; dec arg ptr by 2 lda ptr2 sbc #i}2 sta ptr2 lda ptr2+1 sbc #0 sta ptr2+1 ldy #1 lda (ptr2),y ; get hi byte tax ; into x dey ldai} (ptr2),y ; get lo byte rts .globl _tprintf _tprintf: sty argcnt ; save arg count lda argcnt asl A ;i} make an offset clc adc sp ; compute addr of ctl str + 2 sta ptr2 lda sp+1 adc #0 sta ptr2+1; jsr pf_i}nxta ; get control string sta ptr1 stx ptr1+1;; main loop.;printf0: ldy #0 lda (ptr1),y ; get a char bnj}e *+5 jmp printf9 ; eos? go home cmp #'% ; a percent? bne printf1 ; no, go print it jsr pf_incs ; buj}mp control string ptr lda (ptr1),y ; get control char;; see what we have; cmp #'s ; string? beq pf_str cmp j} #'d ; decimal? beq pf_dec cmp #'x ; hex? beq pf_hex cmp #'o ; octal? beq pf_oct; more laterprintf1j}: jsr cconout ; out the charprintf2: jsr pf_incs ; bump control str jmp printf0 ; and go back for morepf_j}str: jsr pf_nxta ; get next arg sta ptr3 stx ptr3+1pf_str1: ldy #0 lda (ptr3),y ; get a char beq printj}f2 ; done, go home inc ptr3 bne *+4 inc ptr3+1 jsr cconout jmp pf_str1pf_hex: jsr pf_nxta ; get argj} sta ptr3 stx ptr3+1 lda #4 sta tmp1pf_hex1: lda ptr3+1 lsr A lsr A lsr A lsr A and #$0F taxj} lda hex,x jsr cconout dec tmp1 ; dec counter beq pf_hex9 ; done! asl ptr3 rol ptr3+1 asl ptr3 roj}l ptr3+1 asl ptr3 rol ptr3+1 asl ptr3 rol ptr3+1 jmp pf_hex1pf_hex9: jmp printf2pf_oct: jmp printf2pj }f_dec: jsr pf_nxta ; get an arg sta fr0 stx fr0+1 ; set up to floatify cpx #0 ; neg? bpl pf_decj }1 jsr negax sta fr0 ; store it again stx fr0+1 lda #'- jsr cconoutpf_dec1: jsr ifp jsr fasc ;j } ascify it ldy #0 sty tmp1pf_dec2: ldy tmp1 ; get idx lda (inbuff),y ; get a byte bmi pf_dec3 ; j }hi bit set? ok, done inc tmp1 jsr cconout jmp pf_dec2pf_dec3: and #$7F ; mask it jsr cconout jmp prinj }tf2printf9: lda argcnt ; get arg count asl A ; make it a byte count tay jmp addysp ; pop stack andj} return; rtshex: .byte "0123456789ABCDEF"; that's all ; make it a byte count tay jmp addysp ; pop stack andh=;; write(iocb, buf, nbytes)->nbytes written; .globl _write_write: jsr __rwsetup ; do common setup beq write9 n}; if size 0, it's a no-op lda #putchr sta iccom,x jsr ciov bpl write9 jmp ioreturn ; do common error vector sn}tuffwrite9: lda icbll,x ; get buf len lo pha lda icblh,x ; buf len hi tax pla rts;common error vector slh CC65 ---- This is the (c) copyright notice for RA65, LINK65, LIBR65, and other Atari 8-bit programs. Said programs ar}re Copyright 1989, by John R. Dunning. All rights reserved, with the following exceptions: Anyone may copy or redistribr}ute these programs, provided that: 1: You don't charge anything for the copy. It is permissable to charge a nor}minal fee for media, etc. 2: All source code and documentation for the programs is made available as part or}f the distribution. 3: This copyright notice is preserved verbatim, and included in the distribution. Your} are allowed to modify these programs, and redistribute the modified versions, provided that the modifications are clearlyr} noted. There is NO WARRANTY with this software, it comes as is, and is distributed in the hope that it may be useful.r} This copyright notice is based on the one published by the Free Software Foundation, sometimes known as the GNU project.r} The idea is the same as theirs, ie the software is free, and is intended to stay that way. Everybody has the right to cr}opy, modify, and redistribute this software. Nobody has the right to prevent anyone else from copying, modifying or redisr}tributing it.d redistribute this software. Nobody has the right to prevent anyone else from copying, modifying or redisp