128 lines
5.7 KiB
Forth
128 lines
5.7 KiB
Forth
(* Types and utilities for the abstract syntax of MIPS. *)
|
|
|
|
module Mips
|
|
|
|
open AbSyn
|
|
|
|
type reg = RN of int | RS of string
|
|
type imm = int
|
|
type addr = string
|
|
|
|
type Instruction =
|
|
LABEL of addr (* Angiver en label, man fx kan hoppe til *)
|
|
| COMMENT of string (* Placerer en kommentar i assemblerkoden *)
|
|
|
|
| LA of reg*addr (* LA($rd,addr): $rd = addr (label) *)
|
|
| LUI of reg*imm (* LUI($rd,imm): $rd = (imm << 16) *)
|
|
| LW of reg*reg*imm (* LW($rd,$rs,imm): $rd = Mem[$rs + imm] *)
|
|
| LB of reg*reg*imm (* LB($rd,$rs,imm): $rd = Mem[$rs + imm] *)
|
|
| SW of reg*reg*imm (* SW($rw,$rm,imm): Mem[$rm + imm] = $rw *)
|
|
| SB of reg*reg*imm (* SB($rb,$rm,imm): Mem[$rm + imm] = $rb *)
|
|
|
|
(* Aritmetiske instruktioner *)
|
|
| ADD of reg*reg*reg (* ADD($rd,$rs,$rt): $rd = $rs + $rt. *)
|
|
| ADDI of reg*reg*imm (* ADDI($rd,$rs,imm): $rd = $rs + imm *)
|
|
| SUB of reg*reg*reg (* SUB($rd,$rs,$rt): $rd = $rs - $rt. *)
|
|
| MUL of reg*reg*reg (* MUL($rd,$rs,$rt): $rd = $rs * $rt, no overflow. *)
|
|
| DIV of reg*reg*reg (* DIV($rd,$rs,$rt): $rd = quotient($rd / $rs), no overflow. *)
|
|
|
|
(* Bitvise operatorer *)
|
|
| AND of reg*reg*reg (* AND($rd,$rs,$rt): $rd = $rs & $rt *)
|
|
| ANDI of reg*reg*imm (* ANDI($rd,$rs,imm): $rd = $rs & imm *)
|
|
| OR of reg*reg*reg (* OR($rd,$rs,$rt): $rd = $rs | $rt *)
|
|
| ORI of reg*reg*imm (* ORI($rd,$rs,imm): $rd = $rs | imm *)
|
|
| XOR of reg*reg*reg (* XOR($rd,$rs,$rt): $rd = $rs ^ $rt *)
|
|
| XORI of reg*reg*imm (* XORI($rd,$rs,imm): $rd = $rs ^ imm *)
|
|
|
|
(* Bit-shifting *)
|
|
| SLL of reg*reg*imm (* SLL($rd,$rs,imm): $rd = $rs << imm *)
|
|
| SRA of reg*reg*imm (* SRA($rd,$rs,imm): $rd = $rs >> imm *)
|
|
|
|
(* Instruktioner til sammenligning *)
|
|
| SLT of reg*reg*reg (* SLT($rd,$rs,$rt): $rd = $rs < $rt *)
|
|
| SLTI of reg*reg*imm (* SLTI($rd,$rs,imm): $rd = $rs < imm *)
|
|
| BEQ of reg*reg*addr (* BEQ($rs,$rt,addr): if ($rs == $rd) goto(addr) *)
|
|
| BNE of reg*reg*addr (* BNE($rs,$rt,addr): if ($rs != $rd) goto(addr) *)
|
|
| BGEZ of reg*addr (* BGEZ($rs,addr): if ($rs >= $0) goto(addr) *)
|
|
| J of addr (* J(addr): goto(addr) *)
|
|
| JR of reg * reg list (* JR($rd,regs): goto($rd) *)
|
|
| JAL of addr* reg list (* JAL(addr,regs): $RA = $PC; goto(addr) *)
|
|
| NOP
|
|
| SYSCALL (* Udfører det systemkald som er nævnt i $2 *)
|
|
|
|
(* Angiver direktiverne .globl, .text, .data, .space, ascii, .asciiz, .align *)
|
|
| GLOBL of addr
|
|
| TEXT of addr
|
|
| DATA of addr
|
|
| SPACE of int
|
|
| ASCII of string
|
|
| ASCIIZ of string
|
|
| ALIGN of int
|
|
|
|
(* Diverse pseudo-instruktioner *)
|
|
let MOVE (rd,rs) = ORI (rd, rs, 0) (* MOVE($rd,$rs): $rd = $rs *)
|
|
let LI (rd,imm) = ORI (rd, RN 0, imm) (* LI($rd,imm): $rd = imm *)
|
|
let SUBI (rd, rs, imm) = ADDI (rd, rs, -imm)
|
|
|
|
type Prog = Instruction list
|
|
|
|
(* Pretty-print a list of MIPS instructions in the
|
|
format accepted by the MARS MIPS simulator. *)
|
|
let rec ppMipsProg instructions =
|
|
String.concat "\n" (List.map ppMips instructions)
|
|
|
|
(* Pretty-print a single MIPS instruction for .asm output *)
|
|
and ppMips inst =
|
|
match inst with
|
|
| LABEL l -> l + ":"
|
|
| COMMENT s -> "# " + s
|
|
|
|
| LA (rt,l) -> "\tla\t" + ppReg rt + ", " + l
|
|
| LUI (rt,v) -> "\tlui\t" + ppReg rt + ", " + imm2str v
|
|
| LW (rd,rs,v) -> "\tlw\t" + ppReg rd + ", " + imm2str v + "(" + ppReg rs + ")"
|
|
| LB (rd,rs,v) -> "\tlb\t" + ppReg rd + ", " + imm2str v + "(" + ppReg rs + ")"
|
|
| SW (rd,rs,v) -> "\tsw\t" + ppReg rd + ", " + imm2str v + "(" + ppReg rs + ")"
|
|
| SB (rd,rs,v) -> "\tsb\t" + ppReg rd + ", " + imm2str v + "(" + ppReg rs + ")"
|
|
|
|
| ADD (rd,rs,rt) -> "\tadd\t" + ppReg rd + ", " + ppReg rs + ", " + ppReg rt
|
|
| ADDI (rd,rs,v) -> "\taddi\t" + ppReg rd + ", " + ppReg rs + ", " + imm2str v
|
|
| SUB (rd,rs,rt) -> "\tsub\t" + ppReg rd + ", " + ppReg rs + ", " + ppReg rt
|
|
| MUL (rd,rs,rt) -> "\tmul\t" + ppReg rd + ", " + ppReg rs + ", " + ppReg rt
|
|
| DIV (rd,rs,rt) -> "\tdiv\t" + ppReg rd + ", " + ppReg rs + ", " + ppReg rt
|
|
|
|
| AND (rd,rs,rt) -> "\tand\t" + ppReg rd + ", " + ppReg rs + ", " + ppReg rt
|
|
| ANDI (rd,rs,v) -> "\tandi\t" + ppReg rd + ", " + ppReg rs + ", " + imm2str v
|
|
| OR (rd,rs,rt) -> "\tor\t" + ppReg rd + ", " + ppReg rs + ", " + ppReg rt
|
|
| ORI (rd,rs,v) -> "\tori\t" + ppReg rd + ", " + ppReg rs + ", " + imm2str v
|
|
| XOR (rd,rs,rt) -> "\txor\t" + ppReg rd + ", " + ppReg rs + ", " + ppReg rt
|
|
| XORI (rd,rs,v) -> "\txori\t" + ppReg rd + ", " + ppReg rs + ", " + imm2str v
|
|
|
|
| SLL (rd,rt,v) -> "\tsll\t" + ppReg rd + ", " + ppReg rt + ", " + imm2str v
|
|
| SRA (rd,rt,v) -> "\tsra\t" + ppReg rd + ", " + ppReg rt + ", " + imm2str v
|
|
|
|
| SLT (rd,rs,rt) -> "\tslt\t" + ppReg rd + ", " + ppReg rs + ", " + ppReg rt
|
|
| SLTI (rd,rs,v) -> "\tslti\t" + ppReg rd + ", " + ppReg rs + ", " + imm2str v
|
|
| BEQ (rs,rt,l) -> "\tbeq\t" + ppReg rs + ", " + ppReg rt + ", " + l
|
|
| BNE (rs,rt,l) -> "\tbne\t" + ppReg rs + ", " + ppReg rt + ", " + l
|
|
| BGEZ (rs,l) -> "\tbgez\t" + ppReg rs + ", " + l
|
|
| J l -> "\tj\t" + l
|
|
| JAL (l,argRegs) -> "\tjal\t" + l
|
|
| JR (r,resRegs) -> "\tjr\t" + ppReg r
|
|
| NOP -> "\tnop"
|
|
| SYSCALL -> "\tsyscall"
|
|
|
|
| GLOBL s -> "\t.globl\t" + s
|
|
| TEXT s -> "\t.text\t" + s
|
|
| DATA s -> "\t.data\t" + s
|
|
| SPACE s -> "\t.space\t" + string s
|
|
| ASCII s -> "\t.ascii\t\"" + toCString s + "\""
|
|
| ASCIIZ s -> "\t.asciiz\t\"" + toCString s + "\""
|
|
| ALIGN s -> "\t.align\t" + string s
|
|
|
|
and ppReg r =
|
|
match r with
|
|
| RN n -> "$" + string n
|
|
| RS s -> s
|
|
|
|
and imm2str (i:imm) = string i (* maybe add some sanity checks here *)
|