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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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)
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