home *** CD-ROM | disk | FTP | other *** search
- Extended BASIC Assembler
- ————————————————————————
- Version 1.75, 12 April 1997
- by Darren Salt <arcsalt@spuddy.mew.co.uk>
- Contains code from v1.00 and v1.30 by Adrian Lees
-
-
- It is recommended that you read through this document before first using
- ExtBASICasm, and check through it quickly when upgrading. It's entirely
- possible that one of the extras the module provides may cause a clash with
- existing programs, for example the APCS-R register names clashing with
- variables used as register names.
-
- Note also that OPT bit 5 has been altered.
-
-
- The module ExtBASICasm provides a patch for versions 1.05, 1.06, 1.14 and
- 1.16 of BASIC V, as supplied with RISC OS 3.1, 3.5, 3.6 and 3.7 respectively,
- to allow the direct use of the extra instructions provided by the ARM3, ARM6,
- ARM7, ARM8 and StrongARM processors. The missing floating-point and general
- coprocessor instructions, and some assembler directives more familiar (and a
- few unfamiliar) 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. Attempting to run it while BASIC
- is active and in ROM will not work - try "*RMFaster BASIC" at the BASIC
- prompt and you'll see why.
-
- The instructions added by the module are as follows:
-
-
- Extensions
- ——————————
-
- Optional parts are enclosed in {}
-
- OPT <value>
- Bit 4: ASSERT control (1 = enabled on 'second pass')
- Bit 5: APCS register names (1 = enabled)
- Bit 6: UMUL/UMULL control (0 = short forms, 1 = long forms)
-
- ALIGN
- Zero-initialises the memory if required.
-
- ALIGN <const>[,<const2>]
- Aligns to a multiple of const bytes plus an optional offset. const
- must be a power of 2 between 1 and 65536; const2 must be between 0
- and const-1 (default is 0). Also zero-initialises the memory.
- P% becomes (P% AND const-1)+const2; O% is also updated if necessary.
- Examples:
- ALIGN 4
- ALIGN 32
- ALIGN 16,8
-
- 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 for either form of DIV!
-
- 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>]
-
- LDR{cond}{B}L Rd,<address>
- LDR{cond}{B}L Rd,[Rm,#<offset>]{!}
- LDR{cond}{B}WL Rd,<offset>
- STR equivalents
- Addressing range is ±1MB; some offsets outside this range are also
- valid. Lengths are (in words):
- LDR 2 ADD/SUB Rd,Rm,#a:LDR Rd,[Rd,#b]
- LDR ...]! 2 ADD/SUB Rd,Rm,#a:LDR Rd,[Rd,#b]!
- STR 3 ADD/SUB Rm,Rm,#a:STR Rd,[Rm,#b]:SUB/ADD Rm,Rm,#a
- STR ...]! 2 ADD/SUB Rm,Rm,#a:STR Rd,[Rm,#b]!
-
- LDR{cond}{B}L Rd,{Rn},<address>
- LDR{cond}{B}L Rd,{Rn},[Rm,#<offset>]
- LDR{cond}{B}WL Rd,{Rn},<offset>
- STR equivalents
- [{Rn} is NOT optional]
- Equivalent to the LDR/STRs above, except that Rn (rather than Rd)
- is used to hold the address; always two words long. For example,
- ADRL R0,wibble:LDR R1,[R0] may be replaced with LDRL R1,{R0},wibble
- - one word shorter.
- Rd=Rn is not allowed.
- Assembles to ADD/SUB Rn,Rm,#a : LDR/STR Rd,[Rn,#b]!
-
- LDR{cond}{B}L Rd,[Rm],#<offset>
- STR equivalent
- Addressing range is ±1MB; some offsets outside this range are also
- valid. Two words long.
- Assembles to LDR/STR Rd,[Rm],#b:ADD/SUB Rm,Rm,#a
-
- NOTE: You should try to avoid using *sequences* of LDRLs or STRLs -
- there is usually a more efficient way.
-
- Also supported are the new ARM7M and StrongARM forms:
- LDRxxH, LDRxxSH, LDRxxSB and STR equivalents
- The standard forms are used, with the following exceptions:
- - no shifts
- - constant offsets in range -255 to 255
- The W forms are also supported.
- Long LDR{H|SH|SB} not yet implemented.
-
- SWAP{cond}[S] Rd,Rn
- Swaps Rd and Rn without using temporary store.
- Uses EOR method, is therefore three words long.
- If S is specified, then the flags are set according to Rn.
-
- VDU{cond}{X} <const>
- = SWI "OS_WriteI"+<const>
- With X present, XOS_WriteI is used instead.
-
- NOP{cond}
- = MOV{cond} R0,R0
-
- BRK{cond} [#<const>]
- Undefined instruction. If <const> is specified, then R14 is set to
- this value before the undefined instruction trap is taken.
-
- 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
-
- Negative constants
- Allowed in the following instructions:
- ADD, SUB ADC, SBC ADF, SUF
- AND, BIC MOV, MVN MVF, MNF
- CMP, CMN CMF, CNF CMFE, CNFE
- If the constant is invalid for one of these, it is negated or
- inverted, as appropriate, and the instruction changed to the other of
- the pair (eg. ADC becomes SBC). If the constant is still invalid, the
- "bad immediate constant" error is generated as normal.
-
-
- 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>
- xxx{cond}precW Fd,<offset>
-
- 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 F0,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, ACS, ATN, URD, NRM:
- xxx{cond}prec{round} Fd,<Fm | #value>
-
- * Floating point coprocessor status transfer
-
- CMF, CNF, CMFE, CNFE:
- xxx{cond} Fm,<Fn | #value>
-
-
- 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".
- The T flag is retained for compatibility reasons; it is automatically
- set anyway.
-
-
- 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>
- The bug causing an error when used in the form
- .label = "something"
- has been fixed.
-
- EQUFS, EQUFD, EQUFE, EQUFP, EQUF
- xxx <const>
-
- also 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.
-
- EQUPW, DCPW, PW
- xxx <pad_byte>,<string>,<const>
- xxx <pad_byte>,<const>,<string>
- Like EQUP, except that you specify the padding byte.
-
- EQUZ, DCZ, Z
- xxx <string>
- EQUS with automatic zero termination
-
- EQUZA, DCZA, ZA
- xxx <string>
- Equivalent to EQUZ followed by ALIGN
-
- Note: *ALL* the EQU... directives (and their equivalents) may have
- their arguments repeated as described in the Extensions section.
-
- FILL, %
- xxx{B|W|D} <const>{,{<value>}}
- Allocates <const> bytes of memory, initialised to <value> (or 0).
- B, W and D represent data lengths as for EQU; if omitted, then byte
- length is assumed. If the comma is present but no fill value, this is
- equivalent to adding the constant to P% (and O% if appropriate).
-
- 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.)
-
- COND <cond>
- Sets the condition code for use with = (when used as a condition
- code). It may be supplied as a condition code literal, a number (0 to
- 15), or a string containing a condition code literal. For example,
- all of the following are equivalent:
- COND 7 ; number
- COND VC ; condition code literal
- COND vc ; condition code literal
- COND "Vc" ; string containing cond. code lit.
- Example code:
- COND LT ; select LT condition code
- MOV= R0,#2 ; MOVLT R0,#2
- MOV=S R1,R2 ; MOVLTS R1,R2
-
-
- 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
-
- (The APCS names may be disabled by setting bit 5 of the OPT value.)
-
- Usage of these as variable names should be avoided where the variables will
- be used as register numbers, eg.
- SL=8
- DIM code% 16:P%=code%
- [OPT 3
- MOV SL,#0
- ]
- will actually assemble
- E3A0A000 MOV R10,#0
- unless you disable the APCS names.
-
- To help cope with this, the floating point and APCS-R register names
- (except for PC) must be terminated with some character not valid in a
- variable name in order to be recognised; they are otherwise treated as part
- of a variable name.
-
- * 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.
-
-
- Credits
- ———————
-
- Adrian Lees (last known at 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
-
- Martin Willers (m.willers@tu-bs.de):
- - for bug hunting :-)
-
- Reuben Thomas (rrt1001@cam.ac.uk):
- - for pointing out it might be useful to disable the APCS register names,
- and suggesting B/W/D suffix for FILL (and %) and -ve immediate constants
-