code newname assembly code ... c; |
code creates (i.e. incrementally adds to the
resident Forth dictionary) a new Forth word named newname and enters
assembler mode so you can implement the new word in assembly language. c;
assembles the appropriate instruction sequence to return control to the Forth
execution engine and exits from assembler mode. You can then execute the
new word by typing its name, as with any other Forth word. |
label newname assembly code ... end-code |
label creates a new Forth word named newname
and enters assembler mode so you can assemble some machine instructions that
will be used within the context of the current Forth dictionary, but that
will not be called directly as a Forth word. end-code exits from assembler
mode. Later execution of newname pushes on the Forth stack the beginning
address of that sequence of machine instructions. label is typically
used to create instruction sequences, for example interrupt handlers, that
will be executed in a context other than from the Forth virtual machine. It is also possible to mix the constructs: code newname ... end-code creates a Forth word that can be executed by typing its name, but that will not return to Forth. label newname ... c; creates a code sequence that could be entered from elsewhere (e.g. from an exception hander), but which would enter Forth when it was done. |
start-assembling assembly code ... end-assembling |
start-assembling .. end-assembling is
uses to create a block of code that will later be written out to a file (often
in the form of a "dropin module") for use in a target system environment.
See Directives. |
Aliases for certain integer registers, reflecting their conventional use by MIPS compilers.sp rp up ip np base tos w
Aliases for certain integer registers, reflecting their use within the Forth virtual machine.The inconsistent naming (some alias names begin with $ and some don't) is historical accident - in part it is due to the fact that the names a0, a1, a2, and a3 conflict with hex numbers.
sp = $sp , rp=s6 , up=s3 , ip=s5, np=s1 , base=s2, tos=s4, w=t0
Opcodes |
Stack Operands |
Comments |
---|---|---|
ldl, ldr, lb, lh, lwl, lw, lbu, lhu, lwr, lwu, cache,
ll, lwc1, lwc2, pref, lld, ldc1, ldc2, ld |
( rs imm rt -- ) |
Load instructions - rt receives the data |
sb, sh, swl, sw, sdl, sdr, swr, sc, swc1, swc2, scd,
sdc1, sdc2, sd |
( rt rs imm -- ) |
Store instructions - rt supplies the data |
add, addu, sub, subu, and, or, xor, nor, slt, sltu,
dadd, daddu, dsub, dsubu |
( rs rt rd -- ) |
Two-operand instructions - rs OP rd -> rd |
lui |
( imm rt -- ) |
Load upper immediate - (imm << 16) -> rt |
sethi |
( imm1 rt -- ) |
Alternative form of lui - you specify the actual
immediate value that you want to appear in the register. E.g. h# 0f450000
$a2 sethi |
addi, addiu, slti, sltiu, daddi, daddiu, andi, ori,
xori |
( rs imm rt -- ) |
Two-operand immediate instructions - rs OP imm ->
rt |
j, jal |
( adr -- ) |
Jump/Jump and link to target address adr |
sll, srl, sra, dsll, dsrl, dsra, dsll32, dsrl32,
dsra32 |
( rt imm rd -- ) |
Shift instructions - rt SHIFT imm -> rd |
sllv, srlv, srav, dsllv, dsrlv, dsrav |
( rt rs rd -- ) |
Variable shift instructions - rt SHIFT rs -> rd |
mult, multu, div, divu, dmult, dmultu, ddiv, ddivu,
tge, tgeu, tlt, tltu, teq, tne |
( rs rt -- ) |
Two-operand instructions with implicit destination
register |
mfhi, mthi, mflo, mtlo |
( rd -- ) |
Access to HI and LO registers. rd is the source
of destination as appropriate. |
beq, bne, beql, bnel |
( adr rs rt -- ) |
Two-operand conditional branches - branch to address
'adr' if rs COND rt |
blez, bgtz, blezl, bgtzl, bltz, bgez, bltzl, bgezl,
bltzal, bgezal, bltzall, bgezall |
( adr rs -- ) |
One operand conditional branches - branch to address
'adr' if COND(rs) |
bra, bal | ( adr -- ) |
Branch, branch and link (the former is a special
case of a conditional branch) |
bc0f, bc0fl, bc0t, bc0tl, bc1f, bc1fl, bc1t, bc1tl |
( adr -- ) |
Coprocessor branches |
tgei, tgeiu, tlti, tltiu, teqi, tnei |
( rs imm -- ) |
Trap immediate - trap if rs COND imm |
syscall, break, sync, dbreak |
( -- ) |
Zero-operand instructions |
mtdr, mfdr |
( dbreg rt -) |
Access to debug registers |
single, double, float |
( -- ) |
Set the mode for subsequent floating point instructions |
addf, subf, mulf, divf |
( fs ft fd -- ) |
Two-operand floating point instructions - fs OP ft
-> fd |
sqrt, abs, movf, negf, round.w, trunc.w, ceil.w,
floor.w, cvt.s, cvt.d, cvt.w, cxx |
( fs fd -- ) |
One-operand floating point instructions - OP(fs)
-> fd |
mfc1, cfc1, mtc1, ctc1 |
( fs rt -- ) |
Floating-point coprocessor-register to integer-register
instructions |
mfc0, mtc0, dmfc0, dmtc0 |
( cpreg rt -- ) |
System coprocessor-register to integer-register instructions |
tlbp, tlbr, tlbwi, tlbwr,eret |
( -- ) |
TLB and exception instructions |
.s, .d, .w |
( -- ) |
Floating point formats |
dset |
( low high reg -- ) |
Assemble code to put the 64-bit number low, high
into the register |
li, set |
( n reg -- ) |
Assemble code to put the 32-bit number n into the
register (li and set are equivalent) |
la |
( adr dst -- ) |
Like li but sets a relocation bit for the Forth dictionary
file. |
brif |
( adr cond -- ) |
Assemble a branch from a conditional constructor
(see below) |
=, <> |
( rs rt -- cond ) |
Constructor for two-operand structured conditionals
- rs COND rt |
0<=, 0>, 0<, 0>= |
( rs -- cond ) |
Constructor for one-operand structured conditionals
- COND(rs) |
Usage Form |
Example |
Equivalent Code (in noreorder mode) |
Comments |
---|---|---|---|
cond if .. then |
t3 t4 <> if nop \ Delay t3 1 t3 addiu then |
beq t3,t4,1f nop addiu t3,1,t3 1: |
1) The conditional in this case is "t3 t4 <>",
i.e not equal, which takes two register operands. 2) Note the branch delay slot after the "if" 3) There is no delay slot after "then" because it just marks the target of a forward branch. |
cond if .. else
.. then |
t2 0> if $7 0 $4 lw \ Delay sp -4 sp addiu $a1 $a3 mult else $3 $4 $5 add \ Delay $7 4 $4 lw then |
blez t2,1f lw $4,0($7) addiu $sp,$sp,4 mult $a1,$a3 b 2f add $3,$4,$5 1: lw $4,4($7) 2: |
1) The conditional in this case is "t2 0>", i.e.
t2 greater than zero. 2) Note the branch delay slots after "if" and "else", because of the implicit branch around the else clause. |
begin .. again |
begin again t3 0 t4 lw \ Delay |
1: beq $0,$0,1b lw $t4,0($t4) |
1) In this infinite-loop example, there are no other
instructions between "begin" and "again". The important work is done in the
delay slot after the unconditional branch that "again" generates. It is of
course possible to put instructions between "begin" and "again" 2) Note that there is no delay slot after "begin", because "begin" does not generate a branch instruction; it marks the target of a backward branch. |
begin .. cond until |
begin s0 s1 s1 add t3 t4 t5 add t5 t6 = until nop \ Delay |
1: add $s1,$s0,$s1 add $t5,$t3,$t4 bne $t5,$t6,1b nop |
1) "until" generates a conditional backward branch,
so it has a delay slot 2) "\ Delay" is just a comment to remind you what is happening. It does not affect the code that is generated. |
begin .. cond while ... repeat |
begin $a0 8 $a1 lw $a1 $0 <> while nop \ Delay $a0 4 $a0 lw repeat nop \ Delay |
1: lw $a1,8($a0) beq $a1,$0, 2f nop lw $a0,4($a0) beq $0,$0,1b nop 2: |
1) "while" generates a conditional forward branch
past the "repeat", so it has a delay slot 2) "repeat" generates a conditional backward branch to "begin", so it has a delay slot 3) Note that the delay instruction can be on the same line as the "repeat" if you wish. This is generally true; since the assembler syntax is postfix without any need for "lookahead", line boundaries are irrelevant. You can put multiple opcodes on one line if you wish. |
ahead .. then |
ahead nop \ Delay 12345 , 6789 , 3 , then |
beq $0,$0, 1f nop .word 12345 .word 6786 .word 3 1: |
1) "ahead" generates an unconditional forward branch
to "then". It has a delay slot. 2) In this example we are using it to skip some data that we have placed in-line. 3) The most common use of unconditional forward branches is subsumed by the "if .. else .. then" construct, so "ahead" is rarely used. |
ahead .. but then |
ahead t0 0 t1 lw \ Delay begin t0 4 t2 lw t2 t3 t3 add but then t1 $0 = until t1 -1 t1 addiu \ Delay |
beq $0,$0,1f lw $t1,0($t0) 2: lw $t2,4($t0) add $t3,$t2,$t3 1: bne $t1,$0,2b addiu $t1,$t1,-1 |
This is an advanced usage in which two conditional
constructs ("begin .. until" and "ahead .. then") are not properly
nested. The intention here is to start the loop execution at the test condition
at the end. "ahead .. then" is used to branch forward to the test condition.
The "but" rearranges the assembler's control flow stack so that "then" can
resolve "ahead" without being confused by the intervening "begin". |
begin .. cond if .. then cond until |
begin t0 8 t1 lw t1 t2 <> if nop \ Delay t1 t3 t3 add then t1 -5 t1 addiu t1 0< until nop \ Delay |
1: lw $t1,8($t0) beq $t1,$t2,2f nop add $t3,$t1,$t3 2: addiu $t1,$t1,-5 bgez t1,1b nop |
This is a straightforward example of well-nested control
structures. Note the use of indentation to show the scope of the control flow. Especially note how the delay slots are indented the same as the code preceding the branch. |
Command |
Stack Effect |
Description |
---|---|---|
l: |
( label# -- ) |
(ell-colon) Create a local label with the given number |
f: |
( label# -- adr ) |
Return the address of the next occurrence of the
given local label in the forward direction |
b: |
( label# -- adr ) |
Return the address of the next occurrence of the
given local label in the backward direction |
Directive |
Stack | Description |
---|---|---|
start-assembling |
( -- ) |
Set asm-base to the current address within
Forth data space, thus marking that address as the start of memory that will
later be written to a file. Set asm-origin to 0. Arrange for
the names of any subsequent labels to be stored in a separate memory space.
|
end-assembling |
( -- ) |
Restore labels to their default behavior (i.e. label
names will subsequently be stored in-line in Forth data space rather than
in a separate area). |
label newname |
( -- ) |
Mark the current location in Forth data space so that
later execution of newname will return that address. When executed
within the context of start-assembling .. end-assembling , the label
name will be stored in a separate memory area outside of the Forth data space
(normally, in a Forth dictionary context, the Forth data space consists of
interspersed names and data). |
asm-origin |
( -- adr ) |
A Forth value that contains the address within
the target machine's address space that corresponds to the beginning of the
memory marked by start-assembling .The default value, set by start-assembling,
is 0, but it can be changed to an arbitrary value n by executing "n
to asm-origin" . |
asm-base |
( -- adr ) |
A Forth value that contains the start address within
the host machines address space of the beginning of the memory marked by
start-assembling . |
pad-to |
( adr -- ) |
Add 0x0 bytes to memory until the current address
within the target machine's address space is adr. Specifically, (
here - asm-origin ) = ( adr - asm-origin
) when pad-to completes. Aborts if the current address is already above adr
. |
align-to |
( n -- ) |
Add 0x0 bytes to memory until the current address
within the target machine's address space is a multiple of n |
assemble-little-endian |
( -- ) |
Configure the MIPS assembler to generate code in little-endian
byte order. The default is the byte order of the host system. |
assemble-big-endian |
( -- ) |
Configure the MIPS assembler to generate code in little-endian
byte order. The default is the byte order of the host system. |
c$, |
( adr len -- ) |
Place the bytes from the range adr len into
memory, followed by a null terminator byte (which need not be present in
the source range) and sufficient padding for four-byte alignment. This is
primarily used within the "reset" module to place the names of other dropin
modules in-line within the code. |