M/C Part 18 Perhaps I'll start at the start. As I mentioned in part 17, I am (was) writing the SAM WIMP environment for SAMCo and, as with other systems, part of it involves file management. Now I had a few wee problems here. For a start, the hook codes for the DOS don't cover things like formatting and copying. Secondly, when BASIC and SCREEN$ etc are loaded, certain system variables have to be set up. This isn't done by the DOS either, but by the ROM. So, all the routines I needed existed in one form or another and can (as you all know) be accessed through BASIC. (I'll refer to this as the CLI - command line interface, just to be posey.) There is one solution - write my program in BASIC. Hmmm... probably NOT a good idea. Even writing some of it as BASIC routines and running them through the ROM jump table address JCALLBAS isn't going to allow users to have BASIC proggies in memory at the same time. By the way, although it might be possible to call ROM routines directly, this will cause ROM incompatibilities and is as good as forbidden amongst coders. So, what I have done, despite being pretty straightforward and not at all revolutionary is bloody useful. It envolves running BASIC subroutines indirectly, using the jump table and trapping errors. This is the theory: all the BASIC that everyone reads as keywords and decimal numbers is, in fact, stored rather sneakily. Instead of, for instance, storing PRINT as P-R-I-N-T the "token" value of 186 is stuck into memory. When the keyword needs printed on the screen, routines are run to expand the token into ASCII characters. You can actually vector these routines to provide your own commands, but more of that next month. ---- ----- Anyway, commands are stored as tokens from #90H to #FE. Functions (like INT, RND, PI etc) are stored as #FF followed by the token from #3B to #83. The other keywords (things like USING and THEN) are stored like commands, but with tokens from #85 to #8F. A full list of the keywords is supplied in pages 65/ 66 of the ATM. NB. MasterDOS and MasterBASIC use the reserved tokens above #F6 and below #3B. Numbers are stored twice. Firstly, the literal form is just the simple ASCII that appears on the screen. This is followed by #0E and an "invisible" five-byte form, the same as is used by the FPC (see previous articles). For our purposes, the literal form can be left out. Variables and symbols are stored just as ASCII, as you would expect. The line ends with a carriage return (#0D). Normal program lines start with line number and length. We will be using the edit line (the one that appears at the bottom of the screen) with has neither. Edit line? Let me explain... What we are going to do is to provide somewhere in memory, the tokenised version of a BASIC line. We adjust some system pointers to fool the ROM into thinking this is the normal line, and then we run it using the jump table entry JCALLBAS. The edit line is used because it simplifies everything - there's only one pointer and we can forget about line numbers and length. If you wish to run some kind of program from m/c you could always try adjusting all the BASIC pointers for your code, but I wouldn't advise it. Before I hit you with some code, let me mention a couple of things. Firstly, the edit line is refered to as line #FFFF BUT as far as I can work out, the first statement is number 1, NOT 0 like normal lines. I can't explain it, but it was the only way I could get it to work, so it makes using JCALLBAS a little trickier. When you CALL JCALLBAS, you supply HL as the line number. The first line of the routine is:- JCALLBAS JP CALBAS . . CALBAS CALL GOTO3 . . . GOTO3 XOR A LD (nsppc),A ; new statment no. LD (newppc),HL ; new line. RET As you can see, the routine automatically sets the statement to 0. Damn! To avoid ROM incompatibility, we can't just CALL 3 bytes past the start of the routine... or can we? The address of JCALLBAS is fixed, so the address of CALBAS is simply a DPEEK one byte past this. Something like this is needed:- LD IX,(jcallbas+1) LD DE,3 ADD IX,DE CALL #002D Fixed address #002D gives JP (IX). Effectively, CALL (IX). Now, all we have to do is set nsppc and newppc ourselves:- run_line LD A,1 LD HL,#FFFF LD (newppc),HL LD (nsppc),A LD IX,(jcallbas+1) LD DE,3 ADD IX,DE DEC A CALL #002D . . . However, the routine is not yet complete. We need to point the edit line to our code, and reset this afterwards. The BASIC line counters will have been altered, so to continue after the BASIC CALL to your m/c program, store the position, and stick it into nsppc and newppc at the end, to effectively GO TO the next statement. Oh, and error trapping is really easy too. After running your basic line, your code is re-entered with A = any error number. The only problems are the BREAK button which will re-enter Basic for the user, but the edit line will be pointing to the wrong place and the whole system will f**k. Just make sure ESC is enabled. (Your code would be re-entered with A = 14 or 84 for an escape.) Secondly, if you use a DOS command, make sure doser is 0, or that code will have priority, and you'll be left in pretty much the same situation as above. You can always restore is afterwards and, remember, all the error codes are trapped so there is no disadvantage. One final thing - JCALLBAS actually calls subroutines, ie. end with RETURN. An Example ---------- As a pretty cruddy example, let's print "Stevie T" ten times down the screen with blue paper and white ink. A simple FOR...NEXT loop methinks. The encoded line is:- line DB for_token FOR f=1 TO 10: DM "f=" DB #0E,0,0,1,0,0 DB to_token DB #0E,0,0,10,0,0 DM ":" DB print_token PRINT DB paper_token,#0E,0,0,9,0,0 PAPER 9; DM ";" DB pen_token,#0E,0,0,15,0,0 PEN 15; DM ";" DB """ DM "Stevie T" "Stevie T": DB """ DM ":" DB next_token NEXT f: DM "f" DM ":" DB return_token RETURN DB #0D Your code would include:- initialise LD HL,(eline) LD A,(elinep) LD (eline_store),HL LD (elinep_store),A RET eline_store DW 0 elinep_store DB 0 set_line LD HL,line LD A,line_page LD (elinep),a LD (eline),HL RET finish LD HL,(eline_store) LD A,(elinep_store) LD (elinep),a LD (eline),HL RET