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
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
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
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
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
def sh4LowerDoubleSpecials(list)
newList = []
list.each {
| node |
if node.is_a? Instruction
case node.opcode
when "bdltun", "bdgtun"
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"
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
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
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
$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"
$asm.puts "fmov.s #{operands[0].sh4OperandPostInc}, #{operands[1].sh4SingleLo}"
$asm.puts "fmov.s #{operands[0].sh4OperandPostInc}, #{operands[1].sh4SingleHi}"
when "storedReversedAndDecrementAddress"
$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"
$asm.puts ".word 0xfffd"
else
raise "Unhandled opcode #{opcode} at #{codeOriginString}"
end
end
end