;; Introduce instruction types. ;; For spim I am considering splitting the instructions into the following ;; types . ;; "tarith1" - All arithmetic and bitwise operations ( mov,add, sub,cmp,sne,or etc.) ;; - No pseudo instructions in this type. ;; "tarith2" - Pseudo instructions which would result in 2 actual mips instructions being ;; - executed by spim. ;; "tmult" - Multiply (reg to reg) - Lets rework this based on the pseudo ;; instructions ;; "tdivide" - Divide (reg to reg) 2 instruction form ;; "tload" - Load instruction ;; "tstore" - store instruction ;; "tbranch" - Branch and jump instructions ;; FIXME: Remember to add later different instruction types for floating point. ;; ;; "other" - All other instructions ;; By default we assume all instructions to be of type other (define_attr "type" "tarith1, tarith2, tmult, tdivide, tload, tstore, tbranch, tcall, tother" (const_string "tother")) ;; The dummy instruction has been supported to ensure that are no empty ;; arrays are generated in source files of the generated compiler in the ;; initial levels.. (define_insn "dummy_pattern" [(reg:SI 0)] "1" "This stmnt should not be emitted!" ) ;; Functions in genemit.c read .md file for desired target and generates ;; gen_ function for each standard named pattern defined in ;; .md file. The function gen_ is in turn used to generate ;; RTLs at the time of transforming input program into RTL. The source ;; files cfgrtl.c, cse.c,expmed.c which contribute in cc1, use the ;; function gen_jump to generate insn corresponding to jump instruction. ;; If this pattern is not defined in machine description, the compiler, ;; fails in the linking phase because gen_jump is not defined. ;; For compiling _any_ program, jumps are a must. (define_insn "jump" [(set (pc) (label_ref (match_operand 0 "" "")))] "" { return "j \\t%l0"; } [(set_attr "type" "tbranch")]) (define_insn "indirect_jump" [(set (pc) (match_operand:SI 0 "register_operand" ""))] "" "jr \\t%0" [(set_attr "type" "tbranch")]) (define_expand "epilogue" [(clobber (const_int 0))] "" { spim_epilogue(); DONE; } ) (define_insn "IITB_return" [(return) (use (reg:SI 31))] "" "jr \\t\\$ra" [(set_attr "type" "tbranch")]) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; This is the basic standard named pattern, which is matched at the time of ;; GIMPLE to RTL conversion. Hence to add assignment operation in our machine ;; description, we have to define this standard pattern. We can have various ;; variants of this pattern depending upon which target instruction to emit, ;; and move patterns supported in the architecture. These variants can be ;; defined using define_insn patterns and constraints handling specific ;; pattern. ;;movmisalignm is to be used for unaligned memory boundaries. (define_expand "movsi" [(set (match_operand:SI 0 "nonimmediate_operand" "") (match_operand:SI 1 "general_operand" "") )] "" { if(GET_CODE(operands[1])==CONST_INT && INTVAL(operands[1])==0) { emit_insn(gen_move_zero(operands[0],gen_rtx_REG(SImode,0))); DONE; } else if(GET_CODE(operands[0])==MEM && GET_CODE(operands[1])!=REG) { if(!no_new_pseudos) { operands[1]=force_reg(SImode,operands[1]); } } } ) ;;Load patterns (define_insn "*load_word" [(set (match_operand:SI 0 "register_operand" "=r") (mem:SI (match_operand:SI 1 "address_operand" "p")))] "" "lw \\t%0, %a1" [(set_attr "type" "tload")]) ;;Constant loads (define_insn "*constant_load" [(set (match_operand:SI 0 "register_operand" "=r") (match_operand:SI 1 "const_int_operand" "i"))] "" "li \\t%0, %c1" ;; This can also be defined using the actual lui instruction along with shift insn, ;; but that will be used once shift operation is included in md file. [(set_attr "type" "tarith2")]) (define_insn "*symbolic_address_load" [(set (match_operand:SI 0 "register_operand" "=r") (match_operand:SI 1 "symbolic_operand" "S"))] "" "la \\t%0, %s1" [(set_attr "type" "tarith2")]) (define_insn "IITB_move_from_lo" [(set (match_operand:SI 0 "register_operand" "=r") (match_operand:SI 1 "LO_register_operand" "q"))] "" "mflo \\t%0" [(set_attr "type" "tarith1")]) (define_insn "IITB_move_to_lo" [(set (match_operand:SI 0 "LO_register_operand" "=q") (match_operand:SI 1 "register_operand" "r"))] "" "mtlo \\t%1" [(set_attr "type" "tarith1")]) ;; Here z is the constraint character defined in REG_CLASS_FROM_LETTER_P ;; The register $zero is used here. (define_insn "move_zero" [(set (match_operand:SI 0 "nonimmediate_operand" "=r,m") (match_operand:SI 1 "zero_register_operand" "z,z") )] "" "@ move \\t%0,%1 sw \\t%1, %m0" [(set_attr "type" "tarith1,tstore")]) ;;store patterns (define_insn "*store_word" [(set (mem:SI (match_operand:SI 0 "address_operand" "p")) (match_operand:SI 1 "register_operand" "r"))] "" "sw \\t%1, %a0" [(set_attr "type" "tstore")]) (define_insn "*move_regs" [(set (match_operand:SI 0 "register_operand" "=r") (match_operand:SI 1 "register_operand" "r") )] "" "move \\t%0,%1" [(set_attr "type" "tarith1")]) (define_insn "addsi3" [(set (match_operand:SI 0 "register_operand" "=r,r") (plus:SI (match_operand:SI 1 "register_operand" "r,r") (match_operand:SI 2 "nonmemory_operand" "r,K")) )] "" "@ add \\t%0, %1, %2 addi \\t%0, %1, %c2" [(set_attr "type" "tarith1")]) (define_expand "prologue" [(clobber (const_int 0))] "" { spim_prologue(); DONE; } ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Arithmatic and logical operations ;;=================================== (define_insn "abssi2" [(set (match_operand:SI 0 "register_operand" "=r") (abs:SI (match_operand:SI 1 "register_operand" "r")))] "" "abs \\t%0, %1" [(set_attr "type" "tarith1")]) (define_insn "andsi3" [(set (match_operand:SI 0 "register_operand" "=r,r") (and:SI (match_operand:SI 1 "register_operand" "r,r") (match_operand:SI 2 "nonmemory_operand" "r,K")) )] "" "@ and \\t%0, %1, %2 andi \\t%0, %1, %c2" [(set_attr "type" "tarith1")]) (define_expand "divsi3" [(parallel[(set (match_operand:SI 0 "register_operand" "") (div:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "register_operand" "")) ) (clobber (reg:SI 26)) (clobber (reg:SI 27))])] "" {} ) (define_split [(parallel [(set (match_operand:SI 0 "register_operand" "") (div:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "register_operand" "")) ) (clobber (reg:SI 26)) (clobber (reg:SI 27))])] "" [(parallel [(set (match_dup 3) (div:SI (match_dup 1) (match_dup 2))) (clobber (reg:SI 27))]) (set (match_dup 0) (match_dup 3)) ] "{operands[3]=gen_rtx_REG(SImode,26); }" ) (define_insn "IITB_divide" [(parallel[(set (match_operand:SI 0 "LO_register_operand" "=q") (div:SI (match_operand:SI 1 "register_operand" "r") (match_operand:SI 2 "register_operand" "r")) ) (clobber (reg:SI 27))])] "" "div \\t%1, %2" [(set_attr "type" "tdivide")]) (define_insn "udivsi3" [(set (match_operand:SI 0 "register_operand" "=r,r") (udiv:SI (match_operand:SI 1 "register_operand" "r,r") (match_operand:SI 2 "general_operand" "r,im")) )] "" "@ divu \\t%1, %2\\n mflo \\t%0 divu \\t%0, %1, %2" [(set_attr "type" "tdivide,tdivide")]) (define_insn "modsi3" [(parallel[(set (match_operand:SI 0 "register_operand" "=r") (mod:SI (match_operand:SI 1 "register_operand" "r") (match_operand:SI 2 "register_operand" "r")) )])] "" "rem \\t%0, %1, %2" [(set_attr "type" "tdivide")]) (define_insn "umodsi3" [(set (match_operand:SI 0 "register_operand" "=r") (umod:SI (match_operand:SI 1 "register_operand" "r") (match_operand:SI 2 "register_operand" "r")) )] "" "remu \\t%0, %1, %2" [(set_attr "type" "tdivide")]) (define_insn "mulsi3" [(set (match_operand:SI 0 "register_operand" "=r") (mult:SI (match_operand:SI 1 "register_operand" "r") (match_operand:SI 2 "register_operand" "r")) )] "" "mul \\t%0, %1, %2" [(set_attr "type" "tmult")]) (define_insn "umulsi3" [(set (match_operand:SI 0 "register_operand" "=r") (mult:SI (zero_extend:SI (match_operand:SI 1 "register_operand" "r")) (zero_extend:SI (match_operand:SI 2 "general_operand" "rmi"))) )] "" "mulou \\t%0, %1, %2" [(set_attr "type" "tmult")]) (define_insn "negsi2" [(set (match_operand:SI 0 "register_operand" "=r") (neg:SI (match_operand:SI 1 "register_operand" "r")) )] "" "neg \\t%0, %1" [(set_attr "type" "tarith1")]) ;;There is no standard pattern for NOR instruction, so currently omitting the pattern. (define_insn "one_cmplsi2" [(set (match_operand:SI 0 "register_operand" "=r") (not:SI (match_operand:SI 1 "register_operand" "r")))] "" "not \\t%0, %1" [(set_attr "type" "tarith1")]) (define_insn "iorsi3" [(set (match_operand:SI 0 "register_operand" "=r,r") (ior:SI (match_operand:SI 1 "register_operand" "r,r") (match_operand:SI 2 "nonmemory_operand" "r,K")) )] "" "@ or \\t%0, %1, %2 ori \\t%0, %1, %c2" [(set_attr "type" "tarith1,tarith1")]) (define_insn "xorsi3" [(set (match_operand:SI 0 "register_operand" "=r,r") (xor:SI (match_operand:SI 1 "register_operand" "r,r") (match_operand:SI 2 "nonmemory_operand" "r,K")) )] "" "@ xor \\t%0, %1, %2 xori \\t%0, %1, %c2" [(set_attr "type" "tarith1,tarith1")]) (define_insn "subsi3" [(set (match_operand:SI 0 "register_operand" "=r") (minus:SI (match_operand:SI 1 "register_operand" "r") (match_operand:SI 2 "register_operand" "r")) )] "" "sub \\t%0, %1, %2" [(set_attr "type" "tarith1")]) (define_insn "ashlsi3" [(set (match_operand:SI 0 "register_operand" "=r,r") (ashift:SI (match_operand:SI 1 "register_operand" "r,r") (match_operand:SI 2 "nonmemory_operand" "r,J")) )] "" "@ sllv \\t%0, %1, %2 sll \\t%0, %1, %c2" [(set_attr "type" "tarith2,tarith2")]) (define_insn "ashrsi3" [(set (match_operand:SI 0 "register_operand" "=r,r") (ashiftrt:SI (match_operand:SI 1 "register_operand" "r,r") (match_operand:SI 2 "nonmemory_operand" "r,J")) )] "" "@ srav \\t%0, %1, %2 sra \\t%0, %1, %c2" [(set_attr "type" "tarith2,tarith2")]) (define_insn "lshrsi3" [(set (match_operand:SI 0 "register_operand" "=r,r") (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,r") (match_operand:SI 2 "nonmemory_operand" "r,J")) )] "" "@ srlv \\t%0, %1, %2 srl \\t%0, %1, %c2" [(set_attr "type" "tarith2,tarith2")]) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Function calls ;;=============== (define_insn "call" [(call (match_operand:SI 0 "memory_operand" "m") (match_operand:SI 1 "immediate_operand" "i")) (clobber (reg:SI 31)) ] "" "* return emit_asm_call(operands,0); " [(set_attr "type" "tcall")]) (define_insn "call_value" [(set (match_operand:SI 0 "register_operand" "=r") (call (match_operand:SI 1 "memory_operand" "m") (match_operand:SI 2 "immediate_operand" "i"))) (clobber (reg:SI 31)) ] "" "* return emit_asm_call(operands,1); " [(set_attr "type" "tcall")]) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;Conditional code and branch instructions ;;======================================== (define_code_macro cond_code [lt ltu eq ge geu gt gtu le leu ne]) (define_expand "cmpsi" [(set (cc0) (compare (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "nonmemory_operand" "")))] "" { compare_op0=operands[0]; compare_op1=operands[1]; DONE; } ) (define_expand "b" [(set (pc) (if_then_else (cond_code:SI (match_dup 1) (match_dup 2)) (label_ref (match_operand 0 "" "")) (pc)))] "" { operands[1]=compare_op0; if(immediate_operand(compare_op1,SImode)) { operands[2]=force_reg(SImode,compare_op1); } else { operands[2]=compare_op1; } } ) (define_insn "*insn_b" [(set (pc) (if_then_else (cond_code:SI (match_operand:SI 1 "register_operand" "r") (match_operand:SI 2 "register_operand" "r")) (label_ref (match_operand 0 "" "")) (pc)))] "" "* return conditional_insn(,operands,0); " [(set_attr "type" "tbranch")]) ;; Begin modeling the pipeline here. ;; We have the following functional units as far as we are concerned. ;; We have a simple pipeline that has the following units. I am not bothering ;; to model the standard fetch, decode units and instead focussing on the ;; multiple functional units available for actual execution. ;; spimalu - Basic arithmetic and logical operations. All operations complete ;; in exactly one cycle. ;; mload - Load unit to load values for memory. This has a latency of 6 cycles. ;; mstore - Store unit to store values into memory. Latency of 0 cycles. ;; mul - multiply unit - 8 cycle latency for a multiply ;; div - Divide unit - 20 cycle latency for a divide. (define_automaton "spimv2") ;; Define our cpu units available. (define_cpu_unit "alu" "spimv2") (define_cpu_unit "ldu" "spimv2") (define_cpu_unit "stu" "spimv2") (define_cpu_unit "mlu" "spimv2") (define_cpu_unit "dvu" "spimv2") ;; Arithmetic and logical instructions for SPIM take one cycle. (define_insn_reservation "tarith1" 1 (eq_attr "type" "tarith1") "alu") ;; 2 cycle arithmetic instructions. (define_insn_reservation "tarith2" 2 (eq_attr "type" "tarith2") "alu, alu") ;; This uses the first 2 cycles to calculate the effective address. ;; 2 cycles are used in the load pipeline and then a further 2 cycles to return the result. (define_insn_reservation "load" 6 (eq_attr "type" "tload") "alu*2,ldu*2") ;; This uses the first 2 cycles to calculate the effective address. ;; 2 cycles are further used in the store pipeline ;; FIXME: change latency and check that the schedule is unaltered (define_insn_reservation "store" 0 (eq_attr "type" "tstore") "alu,alu,stu*2") ;; Mul instruction ;; mul - multiply unit - 8 cycle latency for a multiply (define_insn_reservation "mlu" 8 (eq_attr "type" "tmult") "mlu*5,nothing*3") ;; The multiplier has forwarding logic, so that the result is available to the ;; multiplier unit in 6 cycles (define_bypass 6 "mlu" "mlu") ;; div - Divide unit - 20 cycle latency for a divide. (define_insn_reservation "div" 20 (eq_attr "type" "tdivide") "dvu*10,nothing*10") ;; other - other instructions ;; Only the call insns use this - 25 cycle latency. (define_insn_reservation "other" 25 (eq_attr "type" "tcall,tother") "nothing*25")