123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785 |
- # Copyright (C) 2013 Apple Inc. All rights reserved.
- # Copyright (C) 2013 Cisco Systems, Inc. All rights reserved.
- #
- # Redistribution and use in source and binary forms, with or without
- # modification, are permitted provided that the following conditions
- # are met:
- # 1. Redistributions of source code must retain the above copyright
- # notice, this list of conditions and the following disclaimer.
- # 2. Redistributions in binary form must reproduce the above copyright
- # notice, this list of conditions and the following disclaimer in the
- # documentation and/or other materials provided with the distribution.
- #
- # THIS SOFTWARE IS PROVIDED BY CISCO SYSTEMS, INC. ``AS IS'' AND ANY
- # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CISCO SYSTEMS, INC. OR ITS
- # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- require 'risc'
- class Node
- def sh4SingleHi
- doubleOperand = sh4Operand
- raise "Bogus register name #{doubleOperand}" unless doubleOperand =~ /^dr/
- "fr" + ($~.post_match.to_i).to_s
- end
- def sh4SingleLo
- doubleOperand = sh4Operand
- raise "Bogus register name #{doubleOperand}" unless doubleOperand =~ /^dr/
- "fr" + ($~.post_match.to_i + 1).to_s
- end
- end
- class SpecialRegister < NoChildren
- def sh4Operand
- @name
- end
- def dump
- @name
- end
- def register?
- true
- end
- end
- SH4_TMP_GPRS = [ SpecialRegister.new("r3"), SpecialRegister.new("r11"), SpecialRegister.new("r13") ]
- SH4_TMP_FPRS = [ SpecialRegister.new("dr10") ]
- class RegisterID
- def sh4Operand
- case name
- when "a0"
- "r4"
- when "a1"
- "r5"
- when "t0"
- "r0"
- when "t1"
- "r1"
- when "t2"
- "r2"
- when "t3"
- "r10"
- when "t4"
- "r6"
- when "cfr"
- "r14"
- when "sp"
- "r15"
- when "lr"
- "pr"
- else
- raise "Bad register #{name} for SH4 at #{codeOriginString}"
- end
- end
- end
- class FPRegisterID
- def sh4Operand
- case name
- when "ft0", "fr"
- "dr0"
- when "ft1"
- "dr2"
- when "ft2"
- "dr4"
- when "ft3"
- "dr6"
- when "ft4"
- "dr8"
- when "fa0"
- "dr12"
- else
- raise "Bad register #{name} for SH4 at #{codeOriginString}"
- end
- end
- end
- class Immediate
- def sh4Operand
- raise "Invalid immediate #{value} at #{codeOriginString}" if value < -128 or value > 127
- "##{value}"
- end
- end
- class Address
- def sh4Operand
- raise "Bad offset #{offset.value} at #{codeOriginString}" if offset.value < 0 or offset.value > 60
- if offset.value == 0
- "@#{base.sh4Operand}"
- else
- "@(#{offset.value}, #{base.sh4Operand})"
- end
- end
- def sh4OperandPostInc
- raise "Bad offset #{offset.value} for post inc at #{codeOriginString}" unless offset.value == 0
- "@#{base.sh4Operand}+"
- end
- def sh4OperandPreDec
- raise "Bad offset #{offset.value} for pre dec at #{codeOriginString}" unless offset.value == 0
- "@-#{base.sh4Operand}"
- end
- end
- class BaseIndex
- def sh4Operand
- raise "Unconverted base index at #{codeOriginString}"
- end
- end
- class AbsoluteAddress
- def sh4Operand
- raise "Unconverted absolute address at #{codeOriginString}"
- end
- end
- #
- # Lowering of shift ops for SH4. For example:
- #
- # rshifti foo, bar
- #
- # becomes:
- #
- # negi foo, tmp
- # shad tmp, bar
- #
- def sh4LowerShiftOps(list)
- newList = []
- list.each {
- | node |
- if node.is_a? Instruction
- case node.opcode
- when "ulshifti", "ulshiftp", "urshifti", "urshiftp", "lshifti", "lshiftp", "rshifti", "rshiftp"
- if node.opcode[0, 1] == "u"
- type = "l"
- direction = node.opcode[1, 1]
- else
- type = "a"
- direction = node.opcode[0, 1]
- end
- if node.operands[0].is_a? Immediate
- maskedImm = Immediate.new(node.operands[0].codeOrigin, node.operands[0].value & 31)
- if maskedImm.value == 0
- # There is nothing to do here.
- elsif maskedImm.value == 1 or (type == "l" and [2, 8, 16].include? maskedImm.value)
- newList << Instruction.new(node.codeOrigin, "sh#{type}#{direction}x", [maskedImm, node.operands[1]])
- else
- tmp = Tmp.new(node.codeOrigin, :gpr)
- if direction == "l"
- newList << Instruction.new(node.codeOrigin, "move", [maskedImm, tmp])
- else
- newList << Instruction.new(node.codeOrigin, "move", [Immediate.new(node.operands[0].codeOrigin, -1 * maskedImm.value), tmp])
- end
- newList << Instruction.new(node.codeOrigin, "sh#{type}d", [tmp, node.operands[1]])
- end
- else
- tmp = Tmp.new(node.codeOrigin, :gpr)
- newList << Instruction.new(node.codeOrigin, "move", [Immediate.new(node.operands[0].codeOrigin, 31), tmp])
- newList << Instruction.new(node.codeOrigin, "andi", [node.operands[0], tmp])
- if direction == "r"
- newList << Instruction.new(node.codeOrigin, "negi", [tmp, tmp])
- end
- newList << Instruction.new(node.codeOrigin, "sh#{type}d", [tmp, node.operands[1]])
- end
- else
- newList << node
- end
- else
- newList << node
- end
- }
- newList
- end
- #
- # Lowering of simple branch ops for SH4. For example:
- #
- # baddis foo, bar, baz
- #
- # will become:
- #
- # addi foo, bar, tmp
- # bs tmp, baz
- #
- def sh4LowerSimpleBranchOps(list)
- newList = []
- list.each {
- | node |
- if node.is_a? Instruction
- annotation = node.annotation
- case node.opcode
- when /^b(addi|subi|ori|addp)/
- op = $1
- bc = $~.post_match
- case op
- when "addi", "addp"
- op = "addi"
- when "subi", "subp"
- op = "subi"
- when "ori", "orp"
- op = "ori"
- end
- if bc == "s"
- raise "Invalid operands number (#{node.operands.size})" unless node.operands.size == 3
- if node.operands[1].is_a? RegisterID or node.operands[1].is_a? SpecialRegister
- newList << Instruction.new(node.codeOrigin, op, node.operands[0..1])
- newList << Instruction.new(node.codeOrigin, "bs", node.operands[1..2])
- else
- tmpVal = Tmp.new(node.codeOrigin, :gpr)
- tmpPtr = Tmp.new(node.codeOrigin, :gpr)
- addr = Address.new(node.codeOrigin, tmpPtr, Immediate.new(node.codeOrigin, 0))
- newList << Instruction.new(node.codeOrigin, "leap", [node.operands[1], tmpPtr])
- newList << Instruction.new(node.codeOrigin, "loadi", [addr, tmpVal])
- newList << Instruction.new(node.codeOrigin, op, [node.operands[0], tmpVal])
- newList << Instruction.new(node.codeOrigin, "storei", [tmpVal, addr])
- newList << Instruction.new(node.codeOrigin, "bs", [tmpVal, node.operands[2]])
- end
- else
- newList << node
- end
- when "bmulio", "bmulpo"
- raise "Invalid operands number (#{node.operands.size})" unless node.operands.size == 3
- tmp1 = Tmp.new(node.codeOrigin, :gpr)
- tmp2 = Tmp.new(node.codeOrigin, :gpr)
- newList << Instruction.new(node.codeOrigin, node.opcode, [tmp1, tmp2].concat(node.operands))
- else
- newList << node
- end
- else
- newList << node
- end
- }
- newList
- end
- #
- # Lowering of double accesses for SH4. For example:
- #
- # loadd [foo, bar, 8], baz
- #
- # becomes:
- #
- # leap [foo, bar, 8], tmp
- # loaddReversedAndIncrementAddress [tmp], baz
- #
- def sh4LowerDoubleAccesses(list)
- newList = []
- list.each {
- | node |
- if node.is_a? Instruction
- case node.opcode
- when "loadd"
- tmp = Tmp.new(codeOrigin, :gpr)
- addr = Address.new(codeOrigin, tmp, Immediate.new(codeOrigin, 0))
- newList << Instruction.new(codeOrigin, "leap", [node.operands[0], tmp])
- newList << Instruction.new(node.codeOrigin, "loaddReversedAndIncrementAddress", [addr, node.operands[1]], node.annotation)
- when "stored"
- tmp = Tmp.new(codeOrigin, :gpr)
- addr = Address.new(codeOrigin, tmp, Immediate.new(codeOrigin, 0))
- newList << Instruction.new(codeOrigin, "leap", [node.operands[1].withOffset(8), tmp])
- newList << Instruction.new(node.codeOrigin, "storedReversedAndDecrementAddress", [node.operands[0], addr], node.annotation)
- else
- newList << node
- end
- else
- newList << node
- end
- }
- newList
- end
- #
- # Lowering of double specials for SH4.
- #
- def sh4LowerDoubleSpecials(list)
- newList = []
- list.each {
- | node |
- if node.is_a? Instruction
- case node.opcode
- when "bdltun", "bdgtun"
- # Handle specific floating point unordered opcodes.
- newList << Instruction.new(codeOrigin, "bdnan", [node.operands[0], node.operands[2]])
- newList << Instruction.new(codeOrigin, "bdnan", [node.operands[1], node.operands[2]])
- newList << Instruction.new(codeOrigin, node.opcode[0..-3], node.operands)
- when "bdnequn", "bdgtequn", "bdltequn"
- newList << Instruction.new(codeOrigin, node.opcode[0..-3], node.operands)
- when "bdneq", "bdgteq", "bdlteq"
- # Handle specific floating point ordered opcodes.
- outlabel = LocalLabel.unique("out_#{node.opcode}")
- outref = LocalLabelReference.new(codeOrigin, outlabel)
- newList << Instruction.new(codeOrigin, "bdnan", [node.operands[0], outref])
- newList << Instruction.new(codeOrigin, "bdnan", [node.operands[1], outref])
- newList << Instruction.new(codeOrigin, node.opcode, node.operands)
- newList << outlabel
- else
- newList << node
- end
- else
- newList << node
- end
- }
- newList
- end
- #
- # Lowering of misplaced labels for SH4.
- #
- def sh4LowerMisplacedLabels(list)
- newList = []
- list.each {
- | node |
- if node.is_a? Instruction
- case node.opcode
- when "jmp"
- if node.operands[0].is_a? LabelReference
- tmp = Tmp.new(codeOrigin, :gpr)
- newList << Instruction.new(codeOrigin, "jmpf", [tmp, node.operands[0]])
- else
- newList << node
- end
- when "call"
- if node.operands[0].is_a? LabelReference
- tmp1 = Tmp.new(codeOrigin, :gpr)
- tmp2 = Tmp.new(codeOrigin, :gpr)
- newList << Instruction.new(codeOrigin, "callf", [tmp1, tmp2, node.operands[0]])
- else
- newList << node
- end
- else
- newList << node
- end
- else
- newList << node
- end
- }
- newList
- end
- class Sequence
- def getModifiedListSH4
- result = @list
- # Verify that we will only see instructions and labels.
- result.each {
- | node |
- unless node.is_a? Instruction or
- node.is_a? Label or
- node.is_a? LocalLabel or
- node.is_a? Skip
- raise "Unexpected #{node.inspect} at #{node.codeOrigin}"
- end
- }
- result = sh4LowerShiftOps(result)
- result = sh4LowerSimpleBranchOps(result)
- result = riscLowerMalformedAddresses(result) {
- | node, address |
- if address.is_a? Address
- case node.opcode
- when "btbz", "btbnz", "cbeq", "bbeq", "bbneq", "bbb", "loadb"
- (0..15).include? address.offset.value and
- ((node.operands[0].is_a? RegisterID and node.operands[0].sh4Operand == "r0") or
- (node.operands[1].is_a? RegisterID and node.operands[1].sh4Operand == "r0"))
- when "loadh"
- (0..30).include? address.offset.value and
- ((node.operands[0].is_a? RegisterID and node.operands[0].sh4Operand == "r0") or
- (node.operands[1].is_a? RegisterID and node.operands[1].sh4Operand == "r0"))
- else
- (0..60).include? address.offset.value
- end
- else
- false
- end
- }
- result = sh4LowerDoubleAccesses(result)
- result = sh4LowerDoubleSpecials(result)
- result = riscLowerMisplacedImmediates(result, ["storeb", "storei", "storep", "muli", "mulp", "andi", "ori", "xori",
- "cbeq", "cieq", "cpeq", "cineq", "cpneq", "cib", "baddio", "bsubio", "bmulio", "baddis",
- "bbeq", "bbneq", "bbb", "bieq", "bpeq", "bineq", "bpneq", "bia", "bpa", "biaeq", "bpaeq", "bib", "bpb",
- "bigteq", "bpgteq", "bilt", "bplt", "bigt", "bpgt", "bilteq", "bplteq", "btiz", "btpz", "btinz", "btpnz", "btbz", "btbnz"])
- result = riscLowerMalformedImmediates(result, -128..127)
- result = sh4LowerMisplacedLabels(result)
- result = riscLowerMisplacedAddresses(result)
- result = assignRegistersToTemporaries(result, :gpr, SH4_TMP_GPRS)
- result = assignRegistersToTemporaries(result, :gpr, SH4_TMP_FPRS)
- return result
- end
- end
- def sh4Operands(operands)
- operands.map{|v| v.sh4Operand}.join(", ")
- end
- def emitSH4Load32(constant, dest)
- outlabel = LocalLabel.unique("load32out")
- constlabel = LocalLabel.unique("load32const")
- $asm.puts "mov.l #{LocalLabelReference.new(codeOrigin, constlabel).asmLabel}, #{dest.sh4Operand}"
- $asm.puts "bra #{LocalLabelReference.new(codeOrigin, outlabel).asmLabel}"
- $asm.puts "nop"
- $asm.puts ".balign 4"
- constlabel.lower("SH4")
- $asm.puts ".long #{constant}"
- outlabel.lower("SH4")
- end
- def emitSH4Load32AndJump(constant, scratch)
- constlabel = LocalLabel.unique("load32const")
- $asm.puts "mov.l #{LocalLabelReference.new(codeOrigin, constlabel).asmLabel}, #{scratch.sh4Operand}"
- $asm.puts "jmp @#{scratch.sh4Operand}"
- $asm.puts "nop"
- $asm.puts ".balign 4"
- constlabel.lower("SH4")
- $asm.puts ".long #{constant}"
- end
- def emitSH4LoadImm(operands)
- if operands[0].value == 0x40000000
- # FirstConstantRegisterIndex const is often used (0x40000000).
- # It's more efficient to "build" the value with 3 opcodes without branch.
- $asm.puts "mov #64, #{operands[1].sh4Operand}"
- $asm.puts "shll16 #{operands[1].sh4Operand}"
- $asm.puts "shll8 #{operands[1].sh4Operand}"
- elsif (-128..127).include? operands[0].value
- $asm.puts "mov #{sh4Operands(operands)}"
- elsif (-32768..32767).include? operands[0].value
- constlabel = LocalLabel.unique("loadconstant")
- $asm.puts "mov.w @(6, PC), #{operands[1].sh4Operand}"
- $asm.puts "bra #{LocalLabelReference.new(codeOrigin, constlabel).asmLabel}"
- $asm.puts "nop"
- $asm.puts ".word #{operands[0].value}"
- constlabel.lower("SH4")
- else
- emitSH4Load32(operands[0].value, operands[1])
- end
- end
- def emitSH4Branch(sh4opcode, operand)
- $asm.puts "#{sh4opcode} @#{operand.sh4Operand}"
- $asm.puts "nop"
- end
- def emitSH4ShiftImm(val, operand, direction)
- tmp = val
- while tmp > 0
- if tmp >= 16
- $asm.puts "shl#{direction}16 #{operand.sh4Operand}"
- tmp -= 16
- elsif tmp >= 8
- $asm.puts "shl#{direction}8 #{operand.sh4Operand}"
- tmp -= 8
- elsif tmp >= 2
- $asm.puts "shl#{direction}2 #{operand.sh4Operand}"
- tmp -= 2
- else
- $asm.puts "shl#{direction} #{operand.sh4Operand}"
- tmp -= 1
- end
- end
- end
- def emitSH4BranchIfT(label, neg)
- outlabel = LocalLabel.unique("branchIfT")
- sh4opcode = neg ? "bt" : "bf"
- $asm.puts "#{sh4opcode} #{LocalLabelReference.new(codeOrigin, outlabel).asmLabel}"
- if label.is_a? LocalLabelReference
- $asm.puts "bra #{label.asmLabel}"
- $asm.puts "nop"
- else
- emitSH4Load32AndJump(label.asmLabel, SH4_TMP_GPRS[0])
- end
- outlabel.lower("SH4")
- end
- def emitSH4IntCompare(cmpOpcode, operands)
- $asm.puts "cmp/#{cmpOpcode} #{sh4Operands([operands[1], operands[0]])}"
- end
- def emitSH4CondBranch(cmpOpcode, neg, operands)
- emitSH4IntCompare(cmpOpcode, operands)
- emitSH4BranchIfT(operands[2], neg)
- end
- def emitSH4CompareSet(cmpOpcode, neg, operands)
- emitSH4IntCompare(cmpOpcode, operands)
- if !neg
- $asm.puts "movt #{operands[2].sh4Operand}"
- else
- outlabel = LocalLabel.unique("compareSet")
- $asm.puts "mov #0, #{operands[2].sh4Operand}"
- $asm.puts "bt #{LocalLabelReference.new(codeOrigin, outlabel).asmLabel}"
- $asm.puts "mov #1, #{operands[2].sh4Operand}"
- outlabel.lower("SH4")
- end
- end
- def emitSH4BranchIfNaN(operands)
- raise "Invalid operands number (#{operands.size})" unless operands.size == 2
- $asm.puts "fcmp/eq #{sh4Operands([operands[0], operands[0]])}"
- $asm.puts "bf #{operands[1].asmLabel}"
- end
- def emitSH4DoubleCondBranch(cmpOpcode, neg, operands)
- if cmpOpcode == "lt"
- $asm.puts "fcmp/gt #{sh4Operands([operands[0], operands[1]])}"
- else
- $asm.puts "fcmp/#{cmpOpcode} #{sh4Operands([operands[1], operands[0]])}"
- end
- emitSH4BranchIfT(operands[2], neg)
- end
- class Instruction
- def lowerSH4
- $asm.comment codeOriginString
- case opcode
- when "addi", "addp"
- if operands.size == 3
- if operands[0].sh4Operand == operands[2].sh4Operand
- $asm.puts "add #{sh4Operands([operands[1], operands[2]])}"
- elsif operands[1].sh4Operand == operands[2].sh4Operand
- $asm.puts "add #{sh4Operands([operands[0], operands[2]])}"
- else
- $asm.puts "mov #{sh4Operands([operands[0], operands[2]])}"
- $asm.puts "add #{sh4Operands([operands[1], operands[2]])}"
- end
- else
- $asm.puts "add #{sh4Operands(operands)}"
- end
- when "subi", "subp"
- raise "#{opcode} with #{operands.size} operands is not handled yet" unless operands.size == 2
- if operands[0].is_a? Immediate
- $asm.puts "add #{sh4Operands([Immediate.new(codeOrigin, -1 * operands[0].value), operands[1]])}"
- else
- $asm.puts "sub #{sh4Operands(operands)}"
- end
- when "muli", "mulp"
- $asm.puts "mul.l #{sh4Operands(operands[0..1])}"
- $asm.puts "sts macl, #{operands[-1].sh4Operand}"
- when "negi", "negp"
- if operands.size == 2
- $asm.puts "neg #{sh4Operands(operands)}"
- else
- $asm.puts "neg #{sh4Operands([operands[0], operands[0]])}"
- end
- when "andi", "andp", "ori", "orp", "xori", "xorp"
- raise "#{opcode} with #{operands.size} operands is not handled yet" unless operands.size == 2
- sh4opcode = opcode[0..-2]
- $asm.puts "#{sh4opcode} #{sh4Operands(operands)}"
- when "shllx", "shlrx"
- raise "Unhandled parameters for opcode #{opcode}" unless operands[0].is_a? Immediate
- if operands[0].value == 1
- $asm.puts "shl#{opcode[3, 1]} #{operands[1].sh4Operand}"
- else
- $asm.puts "shl#{opcode[3, 1]}#{operands[0].value} #{operands[1].sh4Operand}"
- end
- when "shld", "shad"
- $asm.puts "#{opcode} #{sh4Operands(operands)}"
- when "loaddReversedAndIncrementAddress"
- # As we are little endian, we don't use "fmov @Rm, DRn" here.
- $asm.puts "fmov.s #{operands[0].sh4OperandPostInc}, #{operands[1].sh4SingleLo}"
- $asm.puts "fmov.s #{operands[0].sh4OperandPostInc}, #{operands[1].sh4SingleHi}"
- when "storedReversedAndDecrementAddress"
- # As we are little endian, we don't use "fmov DRm, @Rn" here.
- $asm.puts "fmov.s #{operands[0].sh4SingleHi}, #{operands[1].sh4OperandPreDec}"
- $asm.puts "fmov.s #{operands[0].sh4SingleLo}, #{operands[1].sh4OperandPreDec}"
- when "ci2d"
- $asm.puts "lds #{operands[0].sh4Operand}, fpul"
- $asm.puts "float fpul, #{operands[1].sh4Operand}"
- when "fii2d"
- $asm.puts "lds #{operands[0].sh4Operand}, fpul"
- $asm.puts "fsts fpul, #{operands[2].sh4SingleLo}"
- $asm.puts "lds #{operands[1].sh4Operand}, fpul"
- $asm.puts "fsts fpul, #{operands[2].sh4SingleHi}"
- when "fd2ii"
- $asm.puts "flds #{operands[0].sh4SingleLo}, fpul"
- $asm.puts "sts fpul, #{operands[1].sh4Operand}"
- $asm.puts "flds #{operands[0].sh4SingleHi}, fpul"
- $asm.puts "sts fpul, #{operands[2].sh4Operand}"
- when "addd", "subd", "muld", "divd"
- sh4opcode = opcode[0..-2]
- $asm.puts "f#{sh4opcode} #{sh4Operands(operands)}"
- when "bcd2i"
- $asm.puts "ftrc #{operands[0].sh4Operand}, fpul"
- $asm.puts "sts fpul, #{operands[1].sh4Operand}"
- $asm.puts "float fpul, #{SH4_TMP_FPRS[0].sh4Operand}"
- $asm.puts "fcmp/eq #{sh4Operands([operands[0], SH4_TMP_FPRS[0]])}"
- $asm.puts "bf #{operands[2].asmLabel}"
- $asm.puts "tst #{sh4Operands([operands[1], operands[1]])}"
- $asm.puts "bt #{operands[2].asmLabel}"
- when "bdnan"
- emitSH4BranchIfNaN(operands)
- when "bdneq"
- emitSH4DoubleCondBranch("eq", true, operands)
- when "bdgteq"
- emitSH4DoubleCondBranch("lt", true, operands)
- when "bdlt"
- emitSH4DoubleCondBranch("lt", false, operands)
- when "bdlteq"
- emitSH4DoubleCondBranch("gt", true, operands)
- when "bdgt"
- emitSH4DoubleCondBranch("gt", false, operands)
- when "baddio", "baddpo", "bsubio", "bsubpo"
- raise "#{opcode} with #{operands.size} operands is not handled yet" unless operands.size == 3
- $asm.puts "#{opcode[1, 3]}v #{sh4Operands([operands[0], operands[1]])}"
- $asm.puts "bt #{operands[2].asmLabel}"
- when "bmulio", "bmulpo"
- raise "Invalid operands number (#{operands.size})" unless operands.size == 5
- $asm.puts "dmuls.l #{sh4Operands([operands[2], operands[3]])}"
- $asm.puts "sts macl, #{operands[3].sh4Operand}"
- $asm.puts "sts mach, #{operands[0].sh4Operand}"
- $asm.puts "cmp/pz #{operands[3].sh4Operand}"
- $asm.puts "movt #{operands[1].sh4Operand}"
- $asm.puts "dt #{operands[1].sh4Operand}"
- $asm.puts "cmp/eq #{sh4Operands([operands[0], operands[1]])}"
- $asm.puts "bf #{operands[4].asmLabel}"
- when "btiz", "btpz", "btbz", "btinz", "btpnz", "btbnz"
- if operands.size == 3
- $asm.puts "tst #{sh4Operands([operands[0], operands[1]])}"
- else
- if operands[0].sh4Operand == "r0"
- $asm.puts "cmp/eq #0, r0"
- else
- $asm.puts "tst #{sh4Operands([operands[0], operands[0]])}"
- end
- end
- emitSH4BranchIfT(operands[-1], (opcode[-2, 2] == "nz"))
- when "cieq", "cpeq", "cbeq"
- emitSH4CompareSet("eq", false, operands)
- when "cineq", "cpneq", "cbneq"
- emitSH4CompareSet("eq", true, operands)
- when "cib", "cpb", "cbb"
- emitSH4CompareSet("hs", true, operands)
- when "bieq", "bpeq", "bbeq"
- emitSH4CondBranch("eq", false, operands)
- when "bineq", "bpneq", "bbneq"
- emitSH4CondBranch("eq", true, operands)
- when "bib", "bpb", "bbb"
- emitSH4CondBranch("hs", true, operands)
- when "bia", "bpa", "bba"
- emitSH4CondBranch("hi", false, operands)
- when "biaeq", "bpaeq"
- emitSH4CondBranch("hs", false, operands)
- when "bigteq", "bpgteq", "bbgteq"
- emitSH4CondBranch("ge", false, operands)
- when "bilt", "bplt", "bblt"
- emitSH4CondBranch("ge", true, operands)
- when "bigt", "bpgt", "bbgt"
- emitSH4CondBranch("gt", false, operands)
- when "bilteq", "bplteq", "bblteq"
- emitSH4CondBranch("gt", true, operands)
- when "bs"
- $asm.puts "cmp/pz #{operands[0].sh4Operand}"
- $asm.puts "bf #{operands[1].asmLabel}"
- when "call"
- if operands[0].is_a? LocalLabelReference
- $asm.puts "bsr #{operands[0].asmLabel}"
- $asm.puts "nop"
- elsif operands[0].is_a? RegisterID or operands[0].is_a? SpecialRegister
- emitSH4Branch("jsr", operands[0])
- else
- raise "Unhandled parameters for opcode #{opcode} at #{codeOriginString}"
- end
- when "callf"
- $asm.puts ".balign 4"
- $asm.puts "mov r0, #{operands[0].sh4Operand}"
- $asm.puts "mova @(14, PC), r0"
- $asm.puts "lds r0, pr"
- $asm.puts "mov.l @(6, PC), #{operands[1].sh4Operand}"
- $asm.puts "jmp @#{operands[1].sh4Operand}"
- $asm.puts "mov #{operands[0].sh4Operand}, r0"
- $asm.puts ".long #{operands[2].asmLabel}"
- when "jmp"
- if operands[0].is_a? LocalLabelReference
- $asm.puts "bra #{operands[0].asmLabel}"
- $asm.puts "nop"
- elsif operands[0].is_a? RegisterID or operands[0].is_a? SpecialRegister
- emitSH4Branch("jmp", operands[0])
- else
- raise "Unhandled parameters for opcode #{opcode} at #{codeOriginString}"
- end
- when "jmpf"
- emitSH4Load32AndJump(operands[1].asmLabel, operands[0])
- when "ret"
- $asm.puts "rts"
- $asm.puts "nop"
- when "loadb"
- $asm.puts "mov.b #{sh4Operands(operands)}"
- $asm.puts "extu.b #{sh4Operands([operands[1], operands[1]])}"
- when "loadh"
- $asm.puts "mov.w #{sh4Operands(operands)}"
- $asm.puts "extu.w #{sh4Operands([operands[1], operands[1]])}"
- when "loadi", "loadis", "loadp", "storei", "storep"
- $asm.puts "mov.l #{sh4Operands(operands)}"
- when "move"
- if operands[0].is_a? LabelReference
- emitSH4Load32(operands[0].asmLabel, operands[1])
- elsif operands[0].is_a? Immediate
- emitSH4LoadImm(operands)
- else
- $asm.puts "mov #{sh4Operands(operands)}"
- end
- when "leap"
- if operands[0].is_a? BaseIndex
- biop = operands[0]
- if biop.scale > 0
- $asm.puts "mov #{sh4Operands([biop.index, operands[1]])}"
- if biop.scaleShift > 0
- emitSH4ShiftImm(biop.scaleShift, operands[1], "l")
- end
- $asm.puts "add #{sh4Operands([biop.base, operands[1]])}"
- else
- $asm.puts "mov #{sh4Operands([biop.base, operands[1]])}"
- end
- if biop.offset.value != 0
- $asm.puts "add #{sh4Operands([biop.offset, operands[1]])}"
- end
- elsif operands[0].is_a? Address
- if operands[0].base != operands[1]
- $asm.puts "mov #{sh4Operands([operands[0].base, operands[1]])}"
- end
- if operands[0].offset.value != 0
- $asm.puts "add #{sh4Operands([operands[0].offset, operands[1]])}"
- end
- else
- raise "Unhandled parameters for opcode #{opcode} at #{codeOriginString}"
- end
- when "ldspr"
- $asm.puts "lds #{sh4Operands(operands)}, pr"
- when "stspr"
- $asm.puts "sts pr, #{sh4Operands(operands)}"
- when "break"
- # This special opcode always generates an illegal instruction exception.
- $asm.puts ".word 0xfffd"
- else
- raise "Unhandled opcode #{opcode} at #{codeOriginString}"
- end
- end
- end
|