;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; An (almost) all-ACTION version of ; CHAIN.ACT, this version has the ; advantage of being understandable ; by those of us who do not read ; decimal code blocks easily. ; ; The very little bit of assembly ; language used is masked by via ; mnemonic DEFINEs. ; ; You can compile and run this version ; directly from an ACTION cartridge, ; with no unnecessary shenanigans. ; However, if you want to use this ; for a program to be run from DOS ; (whether with or without a RUNTIME ; package), then you must follow these ; steps carefully: ; ; [1] Include the appropriate portions ; of this code in your own program. ; (The "appropriate" section starts ; with the line of asterisks and ; ends with the second line of ; asterisks.) ; ; [2] From the monitor, "C"ompile your ; program. Do NOT run it yet. ; ; [3] Go to DOS ("D" command) and use ; the write-a-binary-file command ; of whatever DOS you are using to ; write the memory from $600 to ; $6F0 to a file. (This is a little ; overkill...the actual top end is ; lower than $6F0. You can find ; it if your really want to, but ; it probably isn't worth it.) ; ; For now, we will presume that ; you will write $600 to $6F0 to ; a file called "MYPROG.COM". ; ; [4] Go back to ACTION and compile ; your program again. Then use ; the monitor to "W"rite the ; program to disk. ; ; We will assume that you used a ; "W"rite file name of "TEMP.OBJ". ; ; [5] Back to DOS, again. This time ; use your DOS's Append-to-a-file ; command to append "TEMP.OBJ" to ; the end of "MYPROG.COM". ; ; You are done! "MYPROG.COM" should ; be a proper load file, and the ; CHAIN routine should be safely ; installed in page 6. ; ; NOTE: To append to a file with OSS's ; DOS XL, use a command line of ; this form (assumes the above names): ; ; COPY -AF TEMP.OBJ MYPROG.COM ; ; For other DOS's, read the manual. ; ; ANOTHER NOTE: "Chain" CAN get an ; error from its calls to CLOSE ; and OPEN (which it assumes are ; in the cartridge or RUNTIME ; library). You SHOULD provide an ; error handler!! ; ; ; YET ANOTHER NOTE: You really only ; need to go through steps 3 and ; 5 for the first program in a ; series that will be chained. ; The other programs MUST be compiled ; along with the CHAIN code, but ; they do not need to have the code ; actually be part of their load ; file so long as you do not corrupt ; page 6. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ;************************************ ; ; Beginning of important part! ; DEFINE GetBlock= "7", ; CIO command STAZ = "$85", ; STA zero page FuncVal = "$A0", ; functions rtn value here LDXIMM = "$A2", ; as in LDX #$nn JSR = "$20", RTS = "$60", JMPI = "$6C", ; as in JMP (nnn) Channel1= "$10", ; 16 * channel # CIOV = "$E456", PC = "$E", SavePC = "$6FE" ; OR ANY OTHER SAFE PLACE CARD INITV = $2E2, RUNV = $2E0 ; ; FIRST, DECLARE THE CALL TO CIO ; PROC CIO = CIOV(BYTE a,x ) ; ; THEN SET THE PC TO AN APPROPRIATE SPOT ; SET SavePC = PC^ SET PC = $600 ; ; In page 6, first the support routines ; PROC Do_Nothing = *() RETURN PROC Do_Init = *() [ JMPI INITV ] PROC Do_Run = *() [ JMPI RUNV ] ; ; Now, since we can't call the system ; GETD routine, we provide one: ; BYTE FUNC GetByte = *() BYTE ICCOM = $352 CARD ICLEN = $358 ICCOM = GetBlock ICLEN = 0 ; flag to CIO: one char in A CIO( 0, Channel1 ) [ STAZ FuncVal ; force return value RTS ] ; ; The main LOAD-A-FILE-FROM-CHANNEL-1 ; ; Actually, this routine does a ; "LOAD FILE AND THEN CHAIN" ; and the "CHAIN" takes place ONLY ; if the file has an INIT vector ; or RUN vector. ; CHAR FUNC Chain (BYTE ARRAY FileName ) BYTE ICCOM=$352, ; all these "IC" locations ICBAL=$354, ; apply ONLY to channel 1 !! ICBAH=$355, ICBLL=$358, ICBLH=$359, ICSTA=$353, ZSTL=$D4, ; zero page...saves code space ZSTH=$D5, ZENDL=$D6, ZENDH=$D7 CARD ICBUF=$354, ; all these are redefinitions ICLEN=$358, ; of the BYTEs defined just above ZSTART=$D4, ZEND=$D6 Close( 1 ) ; you COULD put these two Open( 1,FileName,4,0 ) ; lines in YOUR code, instead. RUNV = Do_Nothing DO INITV = Do_Nothing DO ZSTL = GetByte() ZSTH = GetByte() UNTIL ZSTH<>$FF OD ZENDL = GetByte() ZENDH = GetByte() ICBUF = ZSTART ICLEN = ZEND-ZSTART+1 ICCOM = 7 CIO( 0, Channel1 ) Do_Init() UNTIL ICSTA>1 OD DO_Run() RETURN (ICSTA) [ ] ; just to force code generation ; before the PC change ; ; NOW, WE GO BACK TO COMPILING OUR ; MAIN ROUTINE ; MODULE SET PC = SavePC^ ; restore ; ; end of important code ; ;************************************** ; ; This routine needs to be adapted ; to your own usage. Here, we ; simply ask for a filename. In ; REAL use, you would probably ; pass the filename as a parameter. ; PROC LoadFile() BYTE ARRAY FileN(100) ; TEMP!!! Zero( $6000,$600 ) Print( "WHAT FILE? " ) InputS( FileN ) IF Chain( FileN )<>3 THEN PrintE("UNSUCCESSFUL LOAD!") ELSE PrintE("SEEMS TO HAVE WORKED") FI RETURN FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF