5
Utilities
The Wedge: Adding Commands to Atari BASIC
Charles Brannon
You can customize your Atari BASIC by adding new commands to the language itself. To demonstrate how to do it, the program below adds five DOS commands to BASIC—including a directory command. There are two versions of the same program. Program 1 is a BASIC loader. Type it in normally, and it creates a machine language program for you from the information in the DATA statements. Program 2 is an assembly listing of the same routine. It shows how the machine language works and is useful to programmers who know machine language or want to learn more about it. It's not necessary, however, to understand Program 2 in order to make good use of Program 1.

A letter published some months ago in COMPUTE!'s "Ask The Readers" column regretted the need for "this POKE or that POKE" to accomplish various tasks. The required solution is an "expanded command set:" An enticing prospect, adding commands to a language, and a seemingly impossible one, too.

Atari BASIC, like most microcomputer BASICs, is burned into nonvolatile ROM memory. The machine language routines to list, save, edit, and run your program cannot be altered or patched in any way. (However, on a 48K Atari, you can copy the BASIC cartridge to disk as a binary file, modify it with a machine language monitor, and load it into the top of memory where it will act almost as a ROM cartridge.)

The most common (and easiest to implement) extension of a language is the addition of immediate mode commands. These direct commands, which are not usually executed in a program, but from the keyboard, include RUN, SAVE, LIST, NEW, DOS, etc. Thanks to Atari's modular Operating System (OS), we can easily add this type of command.

An Overview of Atari's Operating System

To understand how the wedge works, we'll have to delve into the mysterious 10K ROM. If you just want to use the program and aren't concerned about the technical details, feel free to skip ahead. The operating system (OS) of a computer is responsible for all input and output to and from disk, cassette, printer, and keyboard. It can also perform such chores as memory management and screen display. On many microcomputers, the OS does not exist as a separate entity, but is incorporated into the BASIC interpreter.

The Atari, on the other hand, is the first microcomputer with a general-purpose, plug-in operating system. This goes hand in hand with the use of program and game cartridges. All programs running on an Atari use a common set of routines, from floating point arithmetic to high-resolution graphics routines such as PLOT, DRAWTO, and FILL.

A Mini-Language

So, instead of BASIC providing a marginal operating system (which on many machines is a maze of machine language calls, requiring incompatible register setup and initialization), we have a BASIC cartridge which uses universal OS routines. A good OS simulates a mini-language. It provides documented, unchanging (between various revisions), unified subroutines with full parameter passing and error-checking.

Furthermore, a good OS is extensible. All the major routines and subroutines are accessed indirectly, through pointers. That is why the Atari is so flexible. If you want to change the personality of your computer, just change one of the vectors of a given routine to point to your machine language routine. Your program can then pass on control to the default program.

A Flexible Computer

This indirection is visible throughout the Atari. At the low end is color indirection, where you can change the color of anything drawn to another color merely by changing one color register. The default character set pointer can be changed to point to a user-designed character set. The system interrupt routines and display list interrupts are all fully accessible via a table of pointers. The BREAK key can be masked; the keyboard scan routine can be modified or by-passed; exotic peripherals can be serviced. And all input/output devices are user-definable, from the keyboard to the disk drive.

A notable peculiarity of the Atari is that not just the disk drive or printer, but also the TV screen and keyboard, are considered peripherals. You don't print a character to the screen on the Atari; you send a character or buffer to the Editor device.

Chain of Command

Through the hierarchy of a subset of the OS, the CIO (Central Input/Output), BASIC politely requests a line of input from screen and keyboard. After BASIC makes this request, control is passed to CIO, wnich calls the Editor. The Editor lets the user enter a line of text (which can be up to three screen lines long). The user can use cursor controls to edit the line or to move the cursor anywhere on the screen to edit another line.

When RETURN is pressed, the line the cursor is on is placed into a buffer (block of memory). Next, CIO gives this information to the calling routine via another buffer. The CIO is designed to be easy to use from machine language. If you think it sounds complicated, imagine performing an these tasks without an operating system.

Driving a Wedge

We don't have to modify BASIC at all. We just "wedge" our way into the Editor device E:. As intimated, even the "system" devices such as E: or D: (the disk driver) can be replaced. Usually, however, you don't want to replace a vectored routine; you just want to insert an additional task. In this case, you point the vector to your routine, which performs the little extra task and then calls the main routine. This by-pass explains the term wedge.

The Handler Table contains the names of all the devices. If you wanted to, you could change the name of the cassette device (C:) to another character, such as T: (for tape), by finding the C in the table and changing it to a T. Along with each name, the Handler Table includes an address that points to another table of addresses that point to all the functions of that particular device. This is multilevel indirection. There is even a vector that points to a list of vectors!

We want to modify the Editor, so we change the first vector to point to our list of vectors. All we really need to do is change one of the vectors in the Editor's list of vectors, the "Get Character" address. Since this list is in ROM, at $E400, we need to copy this 16-byte table to RAM, modify it, and repoint the Handler Table to our RAM version of the Editor Handler Table.

Wedging into a Vector

A Monitor Monarchy

Now that we've got the operating system calling our routine instead of the Editor in ROM, we've got total control of almost all console input/output. The Get Character routine, instead of calling E:, asks us for an ASCII character, presumably from the screen and keyboard. We comply by calling the default routine in ROM.

This seems rather roundabout, doesn't it? But we reserve the right to monitor all characters returned to the operating system, and hence, BASIC. We get to examine every line of input before that line is returned to BASIC, where any strange new commands would be scorned with an error message.

So, we just catch the carriage return code and leisurely examine the input buffer, located at $0580. All we have to do is compare it against a table of commands, and, if we find a match, execute the command. If not, we just return the line to CIO (and CIO gives it back to BASIC) on the assumption that it's either a blank line, a BASIC command, or a syntax error. Sounds simple, but such a "parsing" routine is quite a headache to code and understand.

A REMarkable Solution

After we've intercepted and executed the line, how do we prevent a syntax error when we return the line to BASIC? (And since we've "cut in," we have to follow protocol and return something.) One solution would be to erase the buffer by filling it with spaces. An easier trick would be to change the first character of the line to a period; for example, SCRATCH D:TEMP would become .CRATCH D:TEMP. Since BASIC interprets a leading period as an abbreviation for REM, BASIC conveniently ignores the command and returns READY (which it wouldn't if we merely blanked out the line).

The parser routine makes it easy for you to add commands. Just place the name of each command, followed by a zero, and the address where you want control to be transferred after the command is recognized, in COMTBL (COMmand TaBLe, see Program 2). The length of the line is found in LENGTH, and the second character after the command is returned in PARMS (since this is where any parameters would be).

Note that the length is one character past the end of the string, assuming you number from zero. Your command processor can find the command string in LBUFF ($0580).

Theoretically, this technique can be used to add commands to any language environment. You only have to find a way to make the language processor ignore commands when you return the line (such as blanking it out). Of course, the commands themselves are usually language-specific.

Copious Commands

Now the way is open to add a plethora of BASIC utility commands. Of course, these will have to be written in machine language and interfaced with the Wedge. I've included the resident DOS commands LOCK, UNLOCK, RENAME, and SCRATCH, as well as DIR to print the directory.

You can study the assembly listing (Program 2). If you have an assembler, try typing it in and modifying it. It contains a wealth of techniques and information, such as pattern matching, indirect subroutine calls, making a routine "RESET-proof" using CIO for input/output from machine language, long branching, modular programming, calling BASIC's ERROR routine, even pressing SYSTEM RESET from within a program.

Using the Wedge

A machine language program can be hard to enter into the Atari without an assembler. Program 1 will write the machine language to disk in the form of an AUTORUN.SYS file. Save this program so you can write copies to any disk. When you boot this disk the AUTORUN file will automatically load and initialize the Wedge. You can use the Wedge's console DOS directly, without waiting for the disk utility package (DUP.SYS) to load in, and without losing any programs in memory.

Commands provided are DIR (lists the directory of drive one), LOCK, UNLOCK, SCRATCH (delete), and RENAME. Remember to include the D: (or D2: for drive two, if you have one) in the filename with all the commands except DIR. With RENAME, use the convention RENAME D: oldname, newname.

The Wedge is "persistent"; in other words, it reinitializes itself when you press SYSTEM RESET, so it's kind of hard to get rid of it. An additional command, KILL, removes the Wedge. You can bring back the Wedge with PRINT USR(7936).

These commands are just a start. Many others are possible: RENUMBER, FIND, AUTO line number, UPDATE (removes unused variables from the variable name table), and more.

Program 1. BASIC Wedgemaker
100 REM WEDGE BASIC LOADER
110 GRAPHICS 0:? "Insert a DOS 2.0S diskette"
120 ? "with DOS.SYS in drive 1."
130 ? :? "Press RETURN when you have done this"
140 IF PEEK(764)<>12 THEN 140
150 POKE 764,255
160 ? :? "Now writing the Wedge AUTORUN.SYS file"
170 TRAP 190
180 OPEN #1,8,0,"D:AUTORUN.SYS":TRAP 40000:GOTO 200
190 CLOSE #1:? :? "Can't open AUTORUN.SYS for write.":END 
200 PUT #1,255:PUT #1,255:REM $FFFF HEADER
210 PUT #1,0:PUT #1,31:REM $1F00 START
220 PUT #1,74:PUT #1,33:REM $214A END
230 FOR I=7936 TO 8522+6:REM INCLUDE 6-BYTE AUTORUN
240 READ A:TRAP 310:PUT #1,A:TRAP 40000
250 CKSUM=CKSUM+A
260 NEXT I
270 IF CKSUM<>60435 THEN ? "{BELL}Bad number in DATA statements.":ERR=1
280 CLOSE #1
290 IF  NOT ERR THEN ? :? "DATA ok, write successful."
300 END 
310 ? :? "Error-";PEEK(195);" when attempting disk write.":CLOSE #1:END 
320 REM 
330 REM Following is the decimal
340 REM equivalent of Wedge 1.0
350 REM Must be typed in perfectly
360 REM in order to function.
370 REM 
7936 DATA 104,165,12,141,37,31
7942 DATA 165,13,141,38,31,169
7948 DATA 36,133,12,169,31,133
7954 DATA 13,32,43,31,32,92
7960 DATA 31,169,75,141,231,2
7966 DATA 169,33,141,232,2,96
7972 DATA 32,64,21,32,11,31
7978 DATA 96,169,80,141,68,3
7984 DATA 169,31,141,69,3,169
7990 DATA 0,141,73,3,169,12
7996 DATA 141,72,3,169,11,141
8002 DATA 66,3,162,0,32,86
8008 DATA 228,152,48,1,96,76
8014 DATA 55,33,65,116,97,114
8020 DATA 105,32,87,101,100,103
8026 DATA 101,155,160,0,185,26
8032 DATA 3,201,69,240,7,200
8038 DATA 200,192,34,208,243,96
8044 DATA 200,169,165,153,26,3
8050 DATA 200,169,31,153,26,3
8056 DATA 162,0,189,0,228,157
8062 DATA 165,31,232,224,16,208
8068 DATA 245,169,184,141,169,31
8074 DATA 169,31,141,170,31,24
8080 DATA 173,4,228,105,1,141
8086 DATA 186,31,173,5,228,105
8092 DATA 0,141,187,31,169,0
8098 DATA 133,203,96,251,243,51
8104 DATA 246,184,31,163,246,51
8110 DATA 246,60,246,76,228,243
8116 DATA 56,1,1,125,32,32
8122 DATA 62,246,8,201,155,240
8128 DATA 4,230,203,40,96,140
8134 DATA 181,31,142,182,31,165
8140 DATA 203,240,86,169,51,133
8146 DATA 205,169,32,133,206,160
8152 DATA 0,177,205,217,128,5
8158 DATA 208,12,200,177,205,240
8164 DATA 40,196,203,208,240,76
8170 DATA 37,32,201,255,240,53
8176 DATA 160,0,177,205,240,9
8182 DATA 230,205,144,2,230,206
8188 DATA 76,242,31,24,165,205
8194 DATA 105,3,133,205,144,2
8200 DATA 230,206,76,215,31,200
8206 DATA 132,204,177,205,141,183
8212 DATA 31,200,177,205,141,184
8218 DATA 31,108,183,31,160,0
8224 DATA 169,46,153,128,5,169
8230 DATA 0,133,203,169,155,172
8236 DATA 181,31,174,182,31,40
8242 DATA 96,68,73,82,0,125
8248 DATA 32,83,67,82,65,84
8254 DATA 67,72,0,22,33,76
8260 DATA 79,67,75,0,27,33
8266 DATA 85,78,76,79,67,75
8272 DATA 0,32,33,82,69,78
8278 DATA 65,77,69,0,37,33
8284 DATA 75,73,76,76,0,42
8290 DATA 33,255,155,50,54,32
8296 DATA 70,82,69,69,32,83
8302 DATA 69,67,84,79,82,83
8308 DATA 155,155,0,0,68,58
8314 DATA 42,46,42,162,80,169
8320 DATA 12,157,66,3,32,86
8326 DATA 228,162,80,169,3,157
8332 DATA 66,3,169,6,157,74
8338 DATA 3,169,120,157,68,3
8344 DATA 169,32,157,69,3,32
8350 DATA 86,228,152,16,3,76
8356 DATA 55,33,162,80,169,5
8362 DATA 157,66,3,169,100,157
8368 DATA 68,3,141,68,3,169
8374 DATA 32,157,69,3,141,69
8380 DATA 3,169,20,157,72,3
8386 DATA 141,72,3,32,86,228
8392 DATA 152,48,13,169,9,141
8398 DATA 66,3,162,0,32,86
8404 DATA 228,76,166,32,162,80
8410 DATA 169,12,157,66,3,32
8416 DATA 86,228,76,30,32,162
8422 DATA 80,157,66,3,169,0
8428 DATA 157,73,3,164,203,153
8434 DATA 128,5,56,152,229,204
8440 DATA 157,72,3,24,169,128
8446 DATA 101,204,157,68,3,169
8452 DATA 5,105,0,157,69,3
8458 DATA 32,86,228,152,16,3
8464 DATA 76,55,33,76,30,32
8470 DATA 169,33,76,229,32,169
8476 DATA 35,76,229,32,169,36
8482 DATA 76,229,32,169,32,76
8488 DATA 229,32,173,37,31,133
8494 DATA 12,173,38,31,133,13
8500 DATA 76,116,228,72,162,80
8506 DATA 169,12,157,66,3,32
8512 DATA 86,228,104,162,255,154
8518 DATA 133,185,76,64,185
9000 REM DATA FOR AUTORUN ADDRESS
9010 DATA 224,2,225,2,1,31
9020 REM END OF DATA STATEMENTS

Listing. BASIC Wedgemaker.
Download (Saved BASIC) / Download (Listed BASIC)

Program 2. Wedge Assembly Source
0100 ; The Atari Wedge
0110 ;
0120            *=$1F00
0130 ICCOM    =$0342
0140 ICBADR   =$0344
0150 ICBLEN   =$0348
0160 ICAUX1   =$034A
0170 COPN     =$03
0180 CPTXTR   =$09
0190 CGTXTR   =$05
0200 CPBINR   =$0B
0210 CCLOSE   =$0C
0220 CIO      =$E456
0230 OPDIR    =$06
0240 HATABS   =$031A
0250 LBUFF    =$0580
0260 LENGTH   =$CB
0270 MEMLO    =$02E7
0280 PARMS    =$CC
0290 COM      =$CD
0300 DOSINIT  =$0C
0310 ENTRY PLA              ;For BASIC initialization
0320 ; Make wedge "RESET-proof"
0330 INIT
0340          LDA DOSINIT     ;Save DOS
0350          STA REINIT+1    ;initialization
0360          LDA DOSINIT+1   ;inside the REINIT
0370          STA REINIT+2    ;JSR call
0380 ;
0390 INIT2    LDA #REINIT&255 ;Replace DOS init
0400          STA DOSINIT     ;with Wedge
0410          LDA #REINIT/256 ;init
0420          STA DOSINIT+1
0430          JSR MSG ;Print message
0440          JSR ECHANGE     ; hookup new E:
0450          LDA #ENDWEDGE&255 ;Bump up
0460          STA MEMLO
0470          LDA #ENDWEDGE/256 ;low memory pointer
0480          STA MEMLO+1
0490          RTS
0500 ;
0510 REINIT   JSR XXXX       ;XXXX is filled in with DOSINIT
0520          JSR INIT2
0530 XXXX     RTS
0540 ;
0550 ; Print "welcome" message
0560 ;
0570 MSG      LDA #WMSG&255  ;Store address of
0580          STA ICBADR     ;message
0590          LDA #WMSG/256
0600          STA ICBADR+1
0610          LDA #0         ;Set length
0620          STA ICBLEN+1
0630          LDA #12
0640          STA ICBLEN
0650          LDA #CPBINR    ;Ignore carriage-returns
0660          STA ICCOM
0670          LDX #0         ;File 0, the editor
0680          JSR CIO        ;Call CIO to print it
0690          TYA
0700          BMI ERR        ;If no error, return
0710          RTS
0720 ERR      JMP ERROR
0730 ;
0740 WMSG     .BYTE "Atari Wedge 2.0",155
0750 ;
0760 ; Following replaces the old E:
0770 ;
0780 ECHANGE  LDY #0         ;Search for E:
0790 ELOOP    LDA HATABS,Y   ;in handler table
0800          CMP #'E
0810          BEQ EFOUND     ;Found end?
0820          INY            ;no, next entry
0830          INY
0840          CPY #34        ;end of table?
0850          BNE ELOOP
0860          RTS            ;return
0870 ;
0880 ; Store new handler table address
0890 ;
0900 EFOUND   INY
0910          LDA #WEDGETAB&255
0920          STA HATABS,Y
0930          INY
0940          LDA #WEDGETAB/256
0950          STA HATABS,Y
0960 ; Transfer Editor table to Wedge table
0970          LDX #0
0980 XFER     LDA $E400,X
0990          STA WEDGETAB,X
1000          INX
1010          CPX #16
1020          BNE XFER
1030 ; Patch in MYINPUT routine
1040          LDA #MYINPUT-1&255
1050          STA WEDGETAB+4
1060          LDA #MYINPUT-1/256
1070          STA WEDGETAB+5
1080          CLC
1090          LDA $E404      ; Get character address
1100          ADC #1         ; Actual address is +1
1110          STA MYINPUT+1  ; Egads!
1120          LDA $E405      ; Self-modifying code!
1130          ADC #0         ;(Accept any carry)
1140          STA MYINPUT+2
1150          LDA #0
1160          STA LENGTH     ;Clear length initially
1170          RTS
1180 ;
1190 ; Wedge handler address table
1200 WEDGETAB *=*+16
1210 YSAVE    *=*+1          ;Used to save Y register
1220 XSAVE    *=*+1          ;Ditto for X
1230 JUMPADR  *=*+2          ;used for indirect JMP
1240 MYINPUT
1250 ; The $F63E address is actually placed here by above code
1260 ; to permit this routine to run on the Revision B OS
1270 ; (where it wouldn't necessarily be $F63E)
1280          JSR $F63E      ;Get a character from E:
1290          PHP
1300          CMP #155       ;End of line? (CR)
1310          BEQ ENDLINE    ;Yes, complete line ready
1320          INC LENGTH
1330          PLP
1340          RTS            ;No, let CIO have the character
1350 ENDLINE
1360          STY YSAVE      ;Save Y for CIO
1370          STX XSAVE
1380          LDA LENGTH
1390          BEQ RETURN.LINE
1400 LOOKUP
1410          LDA #COMTBL&255 ;Set up indirect pointer for
1420          STA COM
1430          LDA #COMTBL/256 ;command table
1440          STA COM+1
1450 NEXTCOM  LDY #0
1460 COMPLOOP
1470          LDA (COM),Y    ;Compare command against line buffer
1480          CMP LBUFF,Y    ;Okay so far?
1490          BNE NOTSAME    ;no match
1500          INY
1510          LDA (COM), Y   ;is next character null?
1520          BEQ COMFOUND   ;yes, command found
1530          CPY LENGTH     ;exceeded limits?
1540          BNE COMPLOOP   ;if not, continue comparison
1550          JMP RETURN.LINE ;give line to language
1560 NOTSAME  CMP #255       ;End of table?
1570          BEQ RETURN.LINE
1580          LDY #0         ;No, skip over command
1590 FINDEND  LDA (COM),Y
1600          BEQ ENDCOM     ;Hit the zero yet?
1610          INC COM        ;No, next character
1620          BCC NOINC1
1630          INC COM+1
1640 NOINC1   JMP FINDEND    ;continue until null byte found
1650 ENDCOM   CLC            ;Add 3 to skip over null byte
1660          LDA COM        ;and JMP address
1670          ADC #3
1680          STA COM
1690          BCC NOINC2     ;Check for carry
1700          INC COM+1
1710 NOINC2   JMP NEXTCOM
1720 COMFOUND
1730          INY
1740          STY PARMS      ;Y is index into parameters
1750          LDA (COM),Y     ;Load JUMPADR with command address
1760          STA JUMPADR
1770          INY
1780          LDA (COM),Y
1790          STA JUMPADR+1
1800          JMP (JUMPADR)  ;Execute'
1810 EXIT     LDY #0         ;Commands return here
1820          LDA #'.        ;Change first character to
1830          STA LBUFF,Y    ;"." or REM
1840 ;                       Allows BASIC to ignore line
1850 RETURN.LINE
1860          LDA #0
1870          STA LENGTH
1880 NOAUTO
1890          LDA #155       ;Return EOL to CIO
1900          LDY YSAVE      ;Restore Y
1910          LDX XSAVE      ;and X
1920          PLP            ;and processor status
1930          RTS            ;That's it
1940 COMTBL
1950 ; Wedge commands and command table
1960 ; Format is:
1970 ; .BYTE "COMMAND",0
1980 ; .WORD COMMAND.ADDRESS
1990 ; End of table is
2000 ; .BYTE 255
2010          .BYTE "DIR",0
2020          .WORD DIR
2030          .BYTE "SCRATCH",0
2040          .WORD SCRATCH
2050          .BYTE "LOCK",0
2060          .WORD LOCK
2070          .BYTE "UNLOCK",0
2080          .WORD UNLOCK
2090          .BYTE "RENAME",0
2100          .WORD RENAME
2110          .BYTE "KILL",0
2120          .WORD KILL
2130          .BYTE 255
2140 ;
2150 DIRBUF   *=*+20
2160 DIRNAME  .BYTE "D:*.*"
2170 ;
2180 ; Start of commands:
2190 ;
2200 DIR
2210          LDX #$50       ; IOCB#5
2220          LDA #CCLOSE
2230          STA ICCOM,X
2240          JSR CIO  ;CLOSE#5
2250 ; OPEN#5,6,0,"D:*.*"
2260          LDX #$50       ;channel#5
2270          LDA #COPN      ;open command
2280          STA ICCOM,X
2290          LDA #OPDIR     ;speical "directory" command
2300          STA ICAUX1,X
2310          LDA #DIRNAME&255 ;filename (wildcard)
2320          STA ICBADR,X
2330          LDA #DIRNAME/256
2340          STA ICBADR+1,X
2350          JSR CIO          ;set it up!
2360          TYA
2370          BPL NOERR1
2380          JMP ERROR
2390 ; Print a line to the Editor
2400 NOERR1
2410 NEXT     LDX #$50       ;#5
2420          LDA #CGTXTR    ;Get a line
2430          STA ICCOM,X
2440          LDA #DIRBUF&255 ;Put it into the buffer
2450          STA ICBADR,X
2460          STA ICBADR
2470          LDA #DIRBUF/256
2480          STA ICBADR+1,X
2490          STA ICBADR+1
2500          LDA #20          ; Maximum length is 20
2510          STA ICBLEN,X    ;(actually 17)
2520          STA ICBLEN
2530          JSR CIO
2540          TYA             ;Check for end of file
2550          BMI ENDIR       ;On error, finished directory
2560 NOERR2   LDA #CPTXTR     ;Put text record (print a line)
2570          STA ICCOM
2580          LDX #0          ; Channel 0 is open to the Editor
2590          JSR CIO
2600          JMP NEXT        ;Read next line
2610 ;
2620 ENDIR    LDX #$50        ;CLOSE#5
2630          LDA #CCLOSE
2640          STA ICCOM,X
2650          JSR CIO
2660          JMP EXIT
2670 ;End of directory routine
2680 ;
2690 ;Following routine is used by lock
2700 ;unlock, scratch, and rename
2710 ;Filename buffer is in LBUFF
2720 ;e.g. LOCK D:TEMP
2730 ; this     ^   portion is used
2740 ; to tell CIO the filename.
2750 CALLCIO
2760         LDX #$50       ;Use file 5 (XIO n,#5,etc.)
2770         STA ICCOM,X    ;Store command
2780         LDA #0         ;Clear MSB
2790         STA ICBLEN+1,X ;of length
2800         LDY LENGTH
2810         STA LBUFF,Y
2820         SEC            ;Get length
2830         TYA            ;of filename
2840         SBC PARMS      ;(skip over command name)
2850         STA ICBLEN,X
2860         CLC
2870         LDA #LBUFF&255 ;PARMS is start of parameters,
2880         ADC PARMS      ;the space in LBUFF
2890         STA ICBADR,X   ;after the command
2900         LDA #LBUFF/256
2910         ADC #0         ;Catch any carry
2920         STA ICBADR+1,X
2930         JSR CIO ;Do the job
2940         TYA
2950         BPL NOERR3
2960         JMP ERROR
2970 NOERR3  JMP EXIT
2980 ;
2990 SCRATCH LDA #33
3000         JMP CALLCIO
3010 LOCK    LDA #35
3020         JMP CALLCIO
3030 UNLOCK  LDA #36
3040         JMP CALLCIO
3050 RENAME  LDA #32
3060         JMP CALLCIO
3070 ;
3080 ;Remove Wedge
3090 ;
3100 KILL    LDA REINIT+1 ;Restore old DOS
3110         STA DOSINIT  ;vector
3120         LDA REINIT+2
3130         STA DOSINIT+1
3140         JMP $E474    ;"Press" SYSTEM RESET
3150 ;
3160 ; End of current wedge
3170 ; (Although more commands can be added.)
3180 ; See future issues of COMPUTE'
3190 ;
3200 ERROR    PHA        ;Save error code
3210          LDX #$50   ;close file 5
3220          LDA #CCLOSE
3230          STA ICCOM,X
3240          JSR CIO
3250          PLA        ;retrieve error code
3260          LDX #$FF   ;reset stack
3270          TXS
3280          STA $B9    ;tell BASIC the error code
3290          JMP $B940  ;call the ERROR routine
3300 ;                    in the BASIC cartridge
3310 ;
3320 ENDWEDGE
3330 ; Autorun
3340 ;
3350         *=$02E0
3360         .WORD INIT
3370 ;
3380         .END

Listing. Wedge Assembly Source.
Download (Saved OBJect) / Download (Listed ASeMbly)


Return to Table of Contents | Previous Section | Next Section