From: tolsson@login.dkuug.dk (Thomas Olsson) Newsgroups: comp.sys.acorn.tech Subject: Re: Help on BASIC/Assembler Date: 21 Sep 94 01:50:57 +0200 Organization: DKnet NNTP-Posting-Host: login.dknet.dk X-Newsreader: FidoMail v. 1.95 A number of people have asked me to post the method of calling Basic functions from mc. This is the facts about what is available when you do a CALL, and is taken from a posting in c.s.a by Roger Wilson, 10 Sep 92: ----- cut ----- The value in r14 can be returned to with MOV PC,R14 but it also points to an array of useful values: B CALL2REAL ;0th entry in table is return address ;the following values are words containing an offset from ARGP (R8) ;word aligned 256 bytes & STRACC ;string accumulator ;word aligned words offset from ARGP & PAGE ;current program PAGE & TOP ;current program TOP & LOMEM ;current variable start & HIMEM ;current stack end & MEMLIMIT ;limit of available memory & FSA ;free space start (high water mark/FD stack limit) & TALLY ;value of COUNT & TIMEOF ;offset from TIME readable by OSWORD & ESCWORD ;exception flag word (contains escflg, trcflg) & WIDTHLOC ;value of WIDTH-1 ;internal BASIC routines B VARIND ;get value of lv B STOREA ;store value into lv B STSTORE ;store string into type 128 strings B LVBLNK ;convert string "variable name" to lv address and type B CREATE ;create new variable B EXPR ;use expression analyser on string B MATCH ;lexical analyse source string to destination string B TOKENADDR ;pointer to string for particular token & 0 ;stop point for ****** Minerva programs ;new on BASIC V 1.03 & 9 ;length of extensions B FSTA ;store fp in r0-r3 as 5 bytes at r9 B FLDA :load fp from r9 as 5 bytes into r0-r3 B FADD ;add fp in r0-r3 to 5 bytes at r9, result in r0-r3 B FSUB ;subtract fp in r0-r3 from 5 bytes at r9, result in r0-r3 B FMUL ;multiply fp in r0-r3 by 5 bytes at r9, result in r0-r3 B FDIV ;divide fp in 5 bytes at r9 by r0-r3, result in r0-r3 B FLOAT ;float an integer in r0 to an fp in r0-r3 B FIX ;fix an fp in r0-r3 to an integer in r0 B FSQRT ;square root of r0-r3 Note that the list is held in two different forms: the first section is exactly like BASIC 1.02: a list terminated by zero. The list could not be simply extended because of some unfortunate assumptions bound into poorly written application programs, so a second list has been tacked on the end. A client can check the number of extensions field (i.e. the field after the zero) and it will be 0 or negative if there aren't any. The pointer TIMEOF is particularly interesting. On Arthur this location holds a meaningless value; on other systems it holds the offset which should be subtracted from the time read from the system if one wishes to agree with the value given by PRINT TIME. However the next three words offset from the argument register after TIMEOF (i.e. [R8,TIMEOF+4] etc.) contain: LOCALARLIST: a pointer to a list of local arrays. INSTALLLIST: a pointer to the list of installed libraries. LIBRARYLIST: a pointer to the list of libraries. The local array list is not going to be much use, but the ability to scan the libraries allows (say) find commands to be installed which can find a procedure whereever it is. The list consists of a pointer (0 is the end of the list) to a word (which is the next pointer) and a BASIC program in internal form immediately following the word. The list is organised in the search order. The internal routines are only guarenteed to work in processor user mode. The following functions are provided: VARIND: entry with r0=address of lv, r9=type of lv, r12=LINE. Returns with r0..r3 as the value, r9 the type of the value as follows: r9 type where &40000000 integer in r0 &80000000 float in r0..r3 Uses no other registers (including stack). Possible error if asked to take value of an array fred(): will need r12 valid for this error to be reported correctly. STOREA: entry with r0..r3 value, r9=type of value and r4=address of lv, r5=type of lv, r8=ARGP, r12=LINE (for errors) and r13=SP (for out of store chcek on string allocation). Will convert between various formats e.g. integer and float or produce an error if conversion is impossible. Returns with r0..r7 destroyed. Stack not used. STSTORE: entry with r4=address of lv, r2=length (address of end), r3=address of start, r8=ARGP, r12=LINE (for out of store error) and r13=SP (for out of store check). The string must start on a word boundary, the length must be 255 or less. Uses r0, r1, r5, r6, r7. Preserves input registers. Stack not used. LVBLNK: entry with r11 pointing to start of string, r8=ARGP, r12=LINE (many errors possible e.g. subscript error in array) and r13=stack (will be used for evaluation of subscript list: calls EXPR). The string will be processed to read one variable name and provide an address and type which can be given to VARIND. Returns with NE status if a variable has been found. Address in r0, type (see above) in r9. If there is an EQ status then if the carry is set it cannot possibly be a variable else if the carry is clear it could be, but isn't known to the interpreter (and registers are set to values for CREATE). Uses all registers. CREATE: create a variable. Input is the failure of LVBLNK to find something. Thus we have r10=first char of item, r3=second char of item or 0, r4 and r11 pointers to start and end of other chars, r8=ARGP, r12=LINE, r13=STACK, r9 contains the number of zero bytes on the end. It is recommended that CREATE is called immediately after a failed LVBLNK only. Uses all registers. Return parameters as LVBLNK. The LVBLNK and CREATE routines can be combined together to provide a routine which checks for a variable to assign to and creates it if necessary: SAFELV STMFD SP!,{R14} BL LVBLNK LDMNEFD SP!,{PC} LDMCSFD SP!,{PC} BL CREATE LDMFD SP!,{PC} EXPR: entry with r11 pointing to start of string, r8=ARGP, r12=LINE, r13=STACK . EXPR stops after reading one expression (like those in the PRINT statement). Uses all registers. The value is returned like VARIND. If status EQ it read a string, if status NE and plus it read an integer word (in r0) if status NE and minus it read a floating point value (in r0..r3). r9 contains the type: the status can be recreated by TEQ r9,#0. r10 contains the delimiting character, r11 points to the one after. MATCH: entry with r1=source string (terminated by ASCII CR=13), r2=destination string, r3=MODE, r4=CONSTA, r13=STACK. Note that MATCH does not need ARGP or LINE. The MODE value is 0 for LEFT MODE (i.e. before an equals sign) and 1 for RIGHT MODE (after an equals sign or in an expression). The CONSTA value is 0 for don't pack constants using token &8D, &8D itself for pack. Both MODE and CONSTA will be updated during use of the routine e.g. GOTO will change CONSTA to &8D to read the constant, PRINT will change MODE to 1 to read the expression. Starting values of MODE=0 and CONSTA=0 will lexcially analyse a statement; MODE=1 and CONSTA=0 an expression; MODE=0 and CONSTA=&8D is used to extract line numbers in command mode and probably has little use. MODE affects the values assigned to tokens for HIMEM etc. Uses r0-r5. r1 and r2 are left pointing after the CR codes in the strings. r5 contains status about failures to analyse the line correctly: it can be used or disregarded: values >= &1000 imply mismatched brackets, bit 8 set implies a line number was found that was too large to be put into a &8D constant and if r5 AND 255 equals 1 it implies mismatched string quotes. TOKENADDR: entry with r0 as the token value, r12=pointer to next byte of token string. The value in r12 is only used when the address of a two byte token is required. No other register are used or required. Returns r1 as the pointer to the first character of a string, terminated by a value >=&7F (which is the first byte of the token value). r0 is set to the address of the start of the token table itself. r12 will have been incremented by 1 if a two byte token was used. FSTA: Saves the five byte form of a floating point number. Entry with r0-r3 as the floating point value, r9=address of destination. Stack not used. No error possible. r2 altered (but this does not affect the fp value of r0-r3). FLDA: Loads the five byte form of a floating point number. Entry with address in r9. Exit with r0-r3 as floating point value. Stack not used. No error possible. FADD: Add floating point value in r0-r3 to five byte form at r9. Result in r0-r3. Stack not used. Overflow error possible. Uses r4-r7. FSUB: Subtract floating point value in r0-r3 from five byte form at r9. Result in r0-r3. Stack not used. Overflow error possible. Uses r4-r7. FMUL: Multiply floating point value in r0-r3 by five byte form at r9. Result in r0-r3. Stack not used. Overflow error possible. Uses r4-r7. FDIV: Divide five byte form at r9 by floating point value in r0-r3. Result in r0-r3. Stack not used. Divide by zero and overflow error possible. Uses r4-r7. FLOAT: Float an integer in r0 to a floating point value in r0-r3. Stack not used, no error possible. Sets type field in r9 to FLOATING (&80000000). FIX: Fix a floating point value in r0-r3 to an integer in r0. Stack not used. Overflow error possible. Sets type field in r9 to INTEGER (&40000000). FSQRT: Square root of floating point value in r0-r3 return in r0-r3. Uses r4-r7. ----- cut ----- As you see, you can do a lot to your basic program and variables from an mc routine. I have made an example, so you don't need to figure everything out yourself: DIM MC%100,L%-1 FORI%=8TO10STEP2 P%=MC% [OPTI% STMFD R13!,{R14} SWI "OS_WriteS" ="This is from mc":=10:=13:=0 ADR R11,string ADD R10,R14,#&44 ; R10 is address of EXPR (see above) MOV R14,PC ; R14 is return address for expr MOV PC,R10 ; Execute EXPR (also needs R8 & R12 as on ; entry to MC%) SWI "OS_WriteS" ="This is back in the mc":=10:=13:=0 LDMFD R13!,{PC}^ .string =&A4 ; Token value for FN ="basic_bit":=13 ; function name ] NEXT PRINT"This is from basic" CALLMC% PRINT"This is back in basic" END DEFFNbasic_bit PRINT"This is from basic, in the middle of the mc" =0 Hope this helps! Thomas. === Two can live as cheaply as one, for half as long. === --- FidoMail v.1.96 (08 Sep 1994)