home *** CD-ROM | disk | FTP | other *** search
- Extended BASIC Assembler
- ————————————————————————
- Version 1.67, 3 March 1996
- by Darren Salt
- Contains code from v1.00 and v1.30 by Adrian Lees
-
-
- The module ExtBASICasm provides a patch for versions 1.05, 1.06 and 1.14 of
- BASIC V, as supplied with RISC OS 3.1, 3.5 and 3.6 respectively, to allow the
- direct use of the extra instructions provided by the ARM3, ARM6 and ARM7
- processors. The missing floating-point and general coprocessor instructions,
- and some assembler directives more familiar to Acorn Assembler users have
- been added; also the APCS-R register names may be used.
-
- To make the necessary changes to the BASIC module it must be located in RAM.
- The ExtBASICasm module will therefore attempt to RMFaster the BASIC module
- which will require a small amount of memory in the RMA, in addition to that
- required by the ExtBASICasm module itself. More importantly, BASIC must not
- be active, ie. running, at the time because then the module cannot be removed
- to allow it to be moved. Loading ExtBASICasm should therefore be performed at
- the command line. It is safe to do this from the ShellCLI, ie. whilst the
- desktop is active, even with BASIC programs running because BASIC holds all
- its information within the application workspace.
-
- The instructions added by the module are as follows:
-
- Extensions
- ——————————
- OPT <value>
- Bit 4: ASSERT control (1 = enabled on 'second pass')
- Bit 5: LDC/STC T flag control (1 = automatically set)
- Bit 6: UMUL/UMULL control (0 = short forms, 1 = long forms)
-
- MUL{cond}{S} Rd,Rm,<#const>
- variable length; Rd=Rm if <2 ADD/RSB
- May cause 'duplicate register' if Rd=Rm and const is not simple - ie.
- not 0, (2^x)-1, 2^x, (2^x+2^y)
-
- MLA{cond}{S} Rd,Rm,<#const>,Ra
- variable length; Rd=Rm if <2 ADD/RSB
- Rd=Ra causes 'duplicate register' error if const is not simple, as
- for MUL; Rd=Rm=Ra is special in that MLA Rd,Rd,#c,Rd = MUL Rd,Rd,#c+1
- If Rd=Ra and const=0, no code is generated (none necessary).
-
- DIV Rq,Rr,Rn,Rd,Rt [SGN Rs]
- Integer division by register
- Rq = quotient Rn = numerator Rt = temporary store
- Rr = remainder Rd = denominator Rs = sign store
- If Rs omitted then division is unsigned.
- Rr may be same register as Rn *or* Rn may be same as Rs.
- All other registers must be different.
- Rt and Rs (if specified) are corrupted.
-
- DIV Rq,Rr,Rn,#d[,[Rt]] [SGN Rs]
- Integer division by constant
- Registers as above
- If Rs omitted then division is unsigned.
- If Rt omitted and is required for this division then error given.
- All registers must be different.
- If specified, Rt and Rs are corrupted.
- (Uses generator to build code - fast but may be long)
- Notes: Uses Fourier method. For unsigned values, this is fixed to
- handle unsigned top-bit-set properly, *except* for div by 3
- which works for values up to &C0000000. Ideas and code
- gratefully received...
-
- *** Note no conditional!
-
- ADR{cond}L Rd,<const>
- Fixed length (two words)
-
- ADR{cond}X Rd,<const>
- Fixed length (three words)
-
- ADR{cond}W Rd,<const>
- Addressing relative to R12, one to three words
- <const> MUST be defined before it is used
- Adds/subtracts const to/from R12, storing result in Rd
- Up to you to ensure that R12 correctly set up...
-
- LDR, STR:
- XXX{cond}{B}W Rd,<offset>
- Load/store word/byte at [R12,#<offset>]
-
- Also supported are the new ARM7M forms:
- LDRxxH, LDRxxSH, LDRxxSB and equivalent STRs
- The standard forms are used, with the following exceptions:
- - no shifts
- - constant offsets in range 0 to 255, +ve and -ve
- The W forms are also supported.
-
- SWAP{cond} Rd,Rn
- Swaps Rd and Rn without using temporary store
- Uses EOR method, is therefore three words long
-
-
- VDU{cond}{X} <const>
- = SWI "OS_WriteI"+<const>
- With X present, XOS_WriteI is used instead.
-
- NOP{cond}
- = MOV{cond} R0,R0
-
-
- EQUx, DCx, =
- XXX <value>[,<value>]^
- Extended form of EQUD, EQUW, DCB, etc.
- Instead of, eg. DCD 0 : DCD 12 : DCD branch
- you can now use DCD 0, 12, branch
-
-
- ARM3 and later (including ARM250)
- —————————————————————————————————
-
- SWP{cond}{B} Rd,Rm,[Rn]
-
-
- ARM6 and later
- ——————————————
-
- MRS{cond} Rd,<psr>
- MSR{cond} <psr{f}>,Rm
-
-
- ARM7 and later
- ——————————————
-
- UMUL, SMUL, UMLA, SMLA:
- xxx{cond}{S} Rl,Rh,Rm,Rn
-
- The 'official' forms UMULL, SMULL, UMLAL, SMLAL are used *instead of*
- the 'short' forms if OPT bit 6 is set.
- Unfortunately it's not possible to allow both forms at once: how
- would you interpret "UMULLS" - UMUL condition LS or UMULL with S bit?
-
-
- Floating-point instructions
- ———————————————————————————
-
- Floating point coprocessor data transfer
-
- LDF, STF:
- xxx{cond}prec Fd,[Rn]{,#offset}
- xxx{cond}prec Fd,[Rn,#offset]{!}
- xxx{cond}prec Fd,<label | const>
-
- LFM, SFM:
- xxx{cond} Fd,m,[Rn]{,#offset}
- xxx{cond} Fd,m,[Rn,#offset]{!}
- xxx{cond} Fd,m,<label | const>
-
- LFM{cond}{stack} Fd,m,[Rn]{!}
- SFM{cond}{stack} Fd,m,[Rn]{!}
- LFS{cond}{stack} Rn{!},<fp register list>
- LFS{cond}{stack} Rn{!},<fp register list>
-
- LFM, SFM, LFS and SFS use extended precision. The <fp register list>
- is much as for LDM and STM, with restrictions: you must specify a
- register or a sequence of registers, and the list must be compatible
- with LFM and SFM - eg.
- LFSFD R13!,{F3} LFMFD F3,1,[R13]! LFM F3,1,[R13],#12
- SFSFD R13!,{F5-F0} SFMFD F5,4,[R13]! SFM F5,4,[R13,#-36]!
- LFSDB R13,{F1,F0} LFMDB F0,2,[R13] LFM R0,2,[R13,#-24]
- - for each row, all the instructions have the same effect.
- Available stack types are DB, IA, EA, FD.
- Note that example 2 wraps around - F5, F6, F7, F0 _in that order_.
-
- * Floating point coprocessor register transfer
-
- FLT{cond}prec{round} Fn,Rd
- FIX{cond}{round} Rd,Fn
- WFS, RFS, WFC, RFC:
- xxx{cond} Rd
-
- * Floating point coprocessor data operations
-
- ADF, MUF, SUF, RSF, DVF, RDF, POW, RPW, RMF, FML, FDV, FRD, POL:
- xxx{cond}prec{round} Fd,Fn,<Fm | #value>
-
- MVF, MNF, ABS, RND, SQT, LOG, LGN, EXP,
- SIN, COS, TAN, ASN, ACN, ATN, URD, NRM:
- xxx{cond}prec{round} Fd,<Fm | #value>
-
- * Floating point coprocessor status transfer
-
- CMF, CNF, CMFE, CNFE:
- xxx{cond} Fm,Fn
-
-
- General co-processor instructions
- —————————————————————————————————
-
- * Coprocessor data operations
-
- CDO, CDP:
- xxx{cond} CP#,copro_opcode,Cd,Cn,Cm{,const}
-
- The values of copro_opcode and the optional constant must lie within
- the range 0..15.
-
- * Coprocessor data transfer
-
- MCR, MCR:
- xxx{cond} CP#,<const1>,Rd,Cn,Cm{,<const2>}
-
- LDC, STC:
- xxx{cond}{L}{T} CP#,Cd,[Rn]{,#offset}
- xxx{cond}{L} CP#,Cd,[Rn{,#offset}]{!}
-
- L and T may be specified in either order. So if you want an
- unconditional LDC with both flags set, use LDCTL or LDCALLT since
- LDCLT will be assembled as "LDC with T and L clear, if less than".
- Also, setting bit 5 of the OPT value causes the W flag to be set
- automatically (in the pre-indexed form).
-
-
- Assembler directives
- ————————————————————
-
- * Conditional - will STOP if expression is FALSE:
-
- ASSERT <expression>
-
- Bit 4 of the OPT value controls ASSERT. When it and bit 1 are zero,
- ASSERTs are ignored.
-
- * Constants
-
- = <const|string>[,<const|string>]*
- The bug causing an error when used in the form
- .label = "something"
- has been fixed.
-
- EQUFS, EQUFD, EQUFE, EQUFP, EQUF
- xxx <const>
-
- and the DC.. and |.. equivalents.
-
- These directives accept an expression that evaluates to either an
- integer or a real number. The result is then converted into the
- required precision and stored in the object code at P%, or O% if
- indirect assembly is being used. EQUF is a synonym for EQUFD.
-
- directive EQUFS EQUFD EQUFE EQUFP
- bytes used 4 8 12 12
-
- EQUP, DCP, P
- xxx <string>,<const>
- xxx <const>,<string>
- Fixed-length string allocation. If the string is too short, then the
- remaining space is padded with nulls; if it is too long, it is
- truncated to the specified length.
-
- EQUZ, DCZ, Z
- xxx <string>
- EQUS with automatic zero termination
-
- Note: *ALL* the EQU... directives (and their equivalents) may have
- their arguments repeated as described in the Extensions section.
-
- FILL, %
- xxx <const>{,<byte>}
- Allocates <const> bytes of memory, initialised to <byte> (or 0).
- If comma is present but no fill byte, then no initialisation is done.
-
- FILE <filename>
- Loads the specified file, allocating just enough space for it.
-
- ^ <offset>
- Initialises the workspace address pointer to the given value.
- This is used and updated by #.
- Typical use:
- ^ 0
- ...
- # flags, 4
- ...
- LDRW R0,flags
-
- # <variable>, <length>
- Sets the variable to the current value of the workspace address
- pointer, which is then incremented by <length>.
- This does not alter P% or O%.
- (Note: the variable is assigned before the length is evaluated.)
-
-
- Notes
- —————
-
- * Registers are specified in the following form:
-
- ARM registers: R0..R15
- using APCS-R names: A1..A4 V1..V6 SL FP IP SP LR PC
- Floating-point registers: F0..F7
- General co-processor registers: C0..C15
-
- * Coprocessor numbers (CP#) may be specified using either of the following
- forms:
-
- P0..P15
- CP0..CP15
-
- * Wherever a register or coprocessor number is specified, an expression may
- be substituted in the usual manner allowed by BASIC V. This module employs
- the routines used within BASIC to evaluate all expressions (eg. register
- numbers, offsets and labels) and hence its interpretation of expressions is
- guaranteed to be the same as BASIC.
-
- * There is a subtle inconsistency between the ARM2/3 and ARM6 datasheets
- regarding the ARM's interpretation of the W-bit in the post-indexed LDC/STC
- instructions.
-
- The behaviour of each processor is described below:
-
- ARM2 and ARM3
-
- Setting the W bit for post-indexed expressions forces the -TRANS pin
- low for the transfer cycle, indicating to the memory system that no
- address translation should be performed for this access. Write-back
- occurs independently of the setting of the W bit.
-
- Note that in user mode the W bit is ignored.
-
- ARM6 and later
-
- The W bit must be set to ensure that write-back occurs.
-
- This module will assemble all post-indexed LDC/STC instructions (except LFM
- and SFM) without setting the W bit unless the T suffix is appended to the
- opcode. ie. the behaviour of the assembler matches the ARM2 rather than the
- ARM6. When assembling code for the ARM6 and later, all post-indexed
- instructions should include the T suffix to ensure that the W bit is set.
-
- LFM and SFM are special cases in that they aren't implemented in the 'old'
- versions of the FPEmulator; in the 'new' versions (eg. v2.87), it appears
- that the ARM6 interpretation is used.
-
-
-
- Wish list
- —————————
-
- * Extend 'W' to LDF/STF, and possibly LFM/SFM
-
- ...though when is anybody's guess!
-
-
-
- Credits
- ———————
-
- Adrian Lees (A.M.Lees-CSEE93@@cs.bham.ac.uk):
- - for the original ExtBas and the EQU comma extension, and for the use of
- some of his code
-
- Michael Rozdoba (TechForum / Acorn Answers):
- - for including the "General recursive method for Rb := Ra * C, C a
- constant" from Appendix C of the manual for Acorn's desktop assembler,
- and the late Acorn Computing (Sept 1994) for printing it;
- - for the division code generator (Archimedes World, May 1995), which was
- included, slightly trimmed, and debugged to handle top-bit-set unsigned
- numbers properly... I hope!
-
- Dominic Symes of !Zap fame (dominic.symes@armltd.co.uk):
- - for pointing out that ANDEQ R0,R0,R0 could usefully be replaced by DCD 0
-