type register = | ZERO | A0 | A1 | A2 | V0 | T0 | T1 | T2 | S0 | RA | SP | FP type address = | Alab of string | Areg of int * register type operand = | Oimm of int | Oreg of register type arith = Add | Sub | Mul | Div | Rem type condition = Eq | Ne | Le | Lt | Ge | Gt type label = string type instruction = | Move of register * register | Li of register * int | Li32 of register * int32 | La of register * label | Lw of register * address | Sw of register * address | Lb of register * address | Sb of register * address | Arith of arith * register * register * operand | Neg of register * register | Set of condition * register * register * operand | B of label | Beq of register * register * label | Beqz of register * label | Bnez of register * label | J of string | Jal of string | Jr of register | Jalr of register | Syscall | Label of string | Inline of string type word = Wint of int | Waddr of string type data = | Asciiz of string * string | Word of string * word list | Space of string * int | Align of int type code = | Clist of instruction list | Capp of code * code let nop = Clist [] let mips l = Clist l let inline s = Clist [Inline s] let (++) c1 c2 = Capp (c1, c2) type program = { text : code; data : data list; } open Format let print_register fmt = function | ZERO -> pp_print_string fmt "$0" | A0 -> pp_print_string fmt "$a0" | A1 -> pp_print_string fmt "$a1" | A2 -> pp_print_string fmt "$a2" | V0 -> pp_print_string fmt "$v0" | T0 -> pp_print_string fmt "$t0" | T1 -> pp_print_string fmt "$t1" | T2 -> pp_print_string fmt "$t2" | S0 -> pp_print_string fmt "$s0" | RA -> pp_print_string fmt "$ra" | SP -> pp_print_string fmt "$sp" | FP -> pp_print_string fmt "$fp" let print_arith fmt = function | Add -> pp_print_string fmt "add" | Sub -> pp_print_string fmt "sub" | Mul -> pp_print_string fmt "mul" | Div -> pp_print_string fmt "div" | Rem -> pp_print_string fmt "rem" let print_condition fmt = function | Eq -> pp_print_string fmt "seq" | Ne -> pp_print_string fmt "sne" | Lt -> pp_print_string fmt "slt" | Le -> pp_print_string fmt "sle" | Gt -> pp_print_string fmt "sgt" | Ge -> pp_print_string fmt "sge" let print_address fmt = function | Alab s -> pp_print_string fmt s | Areg (ofs, r) -> fprintf fmt "%d(%a)" ofs print_register r let print_operand fmt = function | Oimm i -> pp_print_int fmt i | Oreg r -> print_register fmt r let print_instruction fmt = function | Move (dst, src) -> fprintf fmt "\tmove %a, %a\n" print_register dst print_register src | Li (r, i) -> fprintf fmt "\tli %a, %d\n" print_register r i | Li32 (r, i) -> fprintf fmt "\tli %a, %ld\n" print_register r i | La (r, s) -> fprintf fmt "\tla %a, %s\n" print_register r s | Lw (r, a) -> fprintf fmt "\tlw %a, %a\n" print_register r print_address a | Sw (r, a) -> fprintf fmt "\tsw %a, %a\n" print_register r print_address a | Lb (r, a) -> fprintf fmt "\tlb %a, %a\n" print_register r print_address a | Sb (r, a) -> fprintf fmt "\tsb %a, %a\n" print_register r print_address a | Arith (a, dst, src, op) -> fprintf fmt "\t%a %a, %a, %a\n" print_arith a print_register dst print_register src print_operand op | Neg (dst, src) -> fprintf fmt "\tneg %a, %a\n" print_register dst print_register src | Set (cond, dst, src, op) -> fprintf fmt "\t%a %a, %a, %a\n" print_condition cond print_register dst print_register src print_operand op | B l -> fprintf fmt "\tb %s\n" l | Beq (r1, r2, l) -> fprintf fmt "\tbeq %a, %a, %s\n" print_register r1 print_register r2 l | Beqz (r, l) -> fprintf fmt "\tbeqz %a, %s\n" print_register r l | Bnez (r, l) -> fprintf fmt "\tbnez %a, %s\n" print_register r l | J s -> fprintf fmt "\tj %s\n" s | Jal s -> fprintf fmt "\tjal %s\n" s | Jalr r -> fprintf fmt "\tjalr %a\n" print_register r | Jr r -> fprintf fmt "\tjr %a\n" print_register r | Syscall -> fprintf fmt "\tsyscall\n" | Label s -> fprintf fmt "%s:\n" s | Inline s -> fprintf fmt "%s" s let rec print_code fmt = function | Clist l -> List.iter (print_instruction fmt) l | Capp (c1, c2) -> print_code fmt c1; print_code fmt c2 let print_word fmt = function | Wint n -> pp_print_int fmt n | Waddr s -> pp_print_string fmt s let rec print_list print fmt = function | [] -> () | [x] -> print fmt x | x :: r -> fprintf fmt "%a, %a" print x (print_list print) r let print_data fmt = function | Asciiz (l, s) -> fprintf fmt "%s:\n\t.asciiz %S\n" l s | Word (l, n) -> fprintf fmt "%s:\n\t.word %a\n" l (print_list print_word) n | Space (l, n) -> fprintf fmt "%s:\n\t.space %d\n" l n | Align n -> fprintf fmt "\t.align %d\n" n let print_program fmt p = fprintf fmt "\t.text\n"; print_code fmt p.text; fprintf fmt "\t.data\n"; List.iter (print_data fmt) p.data; fprintf fmt "@."