We now know enough to implement most of the functions called for in
[[MIPSCODER]].
We still haven't decided on an implementation of labels,
and there is one subtlety in multiplication and division,
but the rest is set.
«[[MIPSCODER]] functions»=
val emitstring = keep STRINGCONST (* literals *)
exception BadReal = IEEEReal.BadReal
val low_order_offset = Emitter.low_order_offset
val realconst = keep (STRINGCONST o order_real o IEEEReal.realconst)
val emitlong = keep EMITLONG
«label functions» (* labels *)
val slt = keep SLT (* control flow *)
val beq = delay BEQ
val jump = delay JUMP
val slt_double = delay SLT_D
val seq_double = delay SEQ_D
val bcop1 = delay BCOP1
val add = keep ADD (* arithmetic *)
val and' = keep AND
val or = keep OR
val xor = keep XOR
val op sub = keep SUB
«multiplication and division functions»
val neg_double = keep NEG_D
val mul_double = keep MUL_D
val div_double = keep DIV_D
val add_double = keep ADD_D
val sub_double = keep SUB_D
val move = keep MOVE
fun lbu (a,b,c) = delay LOAD (Byte,a,b,c) (* load and store *)
fun lw (a,b,c) = delay LOAD (Word,a,b,c)
fun lwc1 (a,b,c) = delay LOAD (Floating,a,b,c)
fun sb (a,b,c) = keep STORE (Byte,a,b,c)
fun sw (a,b,c) = keep STORE (Word,a,b,c)
fun swc1 (a,b,c) = delay STORE (Floating,a,b,c)
val lui = keep LUI
val sll = keep SLL (* shift *)
val sra = keep SRA
fun align() = () (* never need to align on MIPS *)
val mark = keep (fn () => MARK)
val comment = keep COMMENT
@
Multiplication has a minor complication; the
result has to be fetched from the LO register.
«multiplication and division functions»=
fun mult (op1, op2, result) = keeplist [MFLO result, MULT (op1, op2)]
val mfhi = keep MFHI
@
Division has a major complication; I must test for divide by zero since
the hardware does not.
If the divisor is zero, I cause an overflow exception by
adding [[limitreg]] to itself.
«multiplication and division functions»=
fun op div (op1, op2, result) =
let val next = newlabel()
in keeplist [
MFLO result, (* get the result *)
DEFINE next, (* skip to here if nonzero *)
BREAK 7, (* signals zerodivide *)
DIV (op1, op2), (* divide in delay slot *)
BEQ (false, Reg 0, op2, next) (* skip if divisor nonzero *)
]
end
@
For now, labels are just pointers to integers.
During code generation, those integers will be set to positions
in the instruction stream, and then they'll be useful as addresses
relative to the program counter pointer (to be held in [[Reg pcreg]]).
«definition of [[Label]]»=
type Label = int ref
«label functions»=
fun newlabel () = ref 0
val define = keep DEFINE
val emitlab = keep EMITLAB
@
Here's the overall plan of this structure:
«*»=
functor MipsCoder(Emitter: EMITTER) : MIPSCODER = struct
open Emitter
«definition of [[Label]]»
datatype Register = Reg of int
datatype EA = Direct of Register
| Immed of int
| Immedlab of Label
«definition of [[instr]]»
«instruction stream and its functions»
structure M = struct
«[[MIPSCODER]] functions»
end
open M
«functions that assemble [[instr]]s into code»
«statistics»
end (* MipsInstr *)
@