sh4.rb 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785
  1. # Copyright (C) 2013 Apple Inc. All rights reserved.
  2. # Copyright (C) 2013 Cisco Systems, Inc. All rights reserved.
  3. #
  4. # Redistribution and use in source and binary forms, with or without
  5. # modification, are permitted provided that the following conditions
  6. # are met:
  7. # 1. Redistributions of source code must retain the above copyright
  8. # notice, this list of conditions and the following disclaimer.
  9. # 2. Redistributions in binary form must reproduce the above copyright
  10. # notice, this list of conditions and the following disclaimer in the
  11. # documentation and/or other materials provided with the distribution.
  12. #
  13. # THIS SOFTWARE IS PROVIDED BY CISCO SYSTEMS, INC. ``AS IS'' AND ANY
  14. # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  16. # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CISCO SYSTEMS, INC. OR ITS
  17. # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18. # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19. # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  20. # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  21. # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  23. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. require 'risc'
  25. class Node
  26. def sh4SingleHi
  27. doubleOperand = sh4Operand
  28. raise "Bogus register name #{doubleOperand}" unless doubleOperand =~ /^dr/
  29. "fr" + ($~.post_match.to_i).to_s
  30. end
  31. def sh4SingleLo
  32. doubleOperand = sh4Operand
  33. raise "Bogus register name #{doubleOperand}" unless doubleOperand =~ /^dr/
  34. "fr" + ($~.post_match.to_i + 1).to_s
  35. end
  36. end
  37. class SpecialRegister < NoChildren
  38. def sh4Operand
  39. @name
  40. end
  41. def dump
  42. @name
  43. end
  44. def register?
  45. true
  46. end
  47. end
  48. SH4_TMP_GPRS = [ SpecialRegister.new("r3"), SpecialRegister.new("r11"), SpecialRegister.new("r13") ]
  49. SH4_TMP_FPRS = [ SpecialRegister.new("dr10") ]
  50. class RegisterID
  51. def sh4Operand
  52. case name
  53. when "a0"
  54. "r4"
  55. when "a1"
  56. "r5"
  57. when "t0"
  58. "r0"
  59. when "t1"
  60. "r1"
  61. when "t2"
  62. "r2"
  63. when "t3"
  64. "r10"
  65. when "t4"
  66. "r6"
  67. when "cfr"
  68. "r14"
  69. when "sp"
  70. "r15"
  71. when "lr"
  72. "pr"
  73. else
  74. raise "Bad register #{name} for SH4 at #{codeOriginString}"
  75. end
  76. end
  77. end
  78. class FPRegisterID
  79. def sh4Operand
  80. case name
  81. when "ft0", "fr"
  82. "dr0"
  83. when "ft1"
  84. "dr2"
  85. when "ft2"
  86. "dr4"
  87. when "ft3"
  88. "dr6"
  89. when "ft4"
  90. "dr8"
  91. when "fa0"
  92. "dr12"
  93. else
  94. raise "Bad register #{name} for SH4 at #{codeOriginString}"
  95. end
  96. end
  97. end
  98. class Immediate
  99. def sh4Operand
  100. raise "Invalid immediate #{value} at #{codeOriginString}" if value < -128 or value > 127
  101. "##{value}"
  102. end
  103. end
  104. class Address
  105. def sh4Operand
  106. raise "Bad offset #{offset.value} at #{codeOriginString}" if offset.value < 0 or offset.value > 60
  107. if offset.value == 0
  108. "@#{base.sh4Operand}"
  109. else
  110. "@(#{offset.value}, #{base.sh4Operand})"
  111. end
  112. end
  113. def sh4OperandPostInc
  114. raise "Bad offset #{offset.value} for post inc at #{codeOriginString}" unless offset.value == 0
  115. "@#{base.sh4Operand}+"
  116. end
  117. def sh4OperandPreDec
  118. raise "Bad offset #{offset.value} for pre dec at #{codeOriginString}" unless offset.value == 0
  119. "@-#{base.sh4Operand}"
  120. end
  121. end
  122. class BaseIndex
  123. def sh4Operand
  124. raise "Unconverted base index at #{codeOriginString}"
  125. end
  126. end
  127. class AbsoluteAddress
  128. def sh4Operand
  129. raise "Unconverted absolute address at #{codeOriginString}"
  130. end
  131. end
  132. #
  133. # Lowering of shift ops for SH4. For example:
  134. #
  135. # rshifti foo, bar
  136. #
  137. # becomes:
  138. #
  139. # negi foo, tmp
  140. # shad tmp, bar
  141. #
  142. def sh4LowerShiftOps(list)
  143. newList = []
  144. list.each {
  145. | node |
  146. if node.is_a? Instruction
  147. case node.opcode
  148. when "ulshifti", "ulshiftp", "urshifti", "urshiftp", "lshifti", "lshiftp", "rshifti", "rshiftp"
  149. if node.opcode[0, 1] == "u"
  150. type = "l"
  151. direction = node.opcode[1, 1]
  152. else
  153. type = "a"
  154. direction = node.opcode[0, 1]
  155. end
  156. if node.operands[0].is_a? Immediate
  157. maskedImm = Immediate.new(node.operands[0].codeOrigin, node.operands[0].value & 31)
  158. if maskedImm.value == 0
  159. # There is nothing to do here.
  160. elsif maskedImm.value == 1 or (type == "l" and [2, 8, 16].include? maskedImm.value)
  161. newList << Instruction.new(node.codeOrigin, "sh#{type}#{direction}x", [maskedImm, node.operands[1]])
  162. else
  163. tmp = Tmp.new(node.codeOrigin, :gpr)
  164. if direction == "l"
  165. newList << Instruction.new(node.codeOrigin, "move", [maskedImm, tmp])
  166. else
  167. newList << Instruction.new(node.codeOrigin, "move", [Immediate.new(node.operands[0].codeOrigin, -1 * maskedImm.value), tmp])
  168. end
  169. newList << Instruction.new(node.codeOrigin, "sh#{type}d", [tmp, node.operands[1]])
  170. end
  171. else
  172. tmp = Tmp.new(node.codeOrigin, :gpr)
  173. newList << Instruction.new(node.codeOrigin, "move", [Immediate.new(node.operands[0].codeOrigin, 31), tmp])
  174. newList << Instruction.new(node.codeOrigin, "andi", [node.operands[0], tmp])
  175. if direction == "r"
  176. newList << Instruction.new(node.codeOrigin, "negi", [tmp, tmp])
  177. end
  178. newList << Instruction.new(node.codeOrigin, "sh#{type}d", [tmp, node.operands[1]])
  179. end
  180. else
  181. newList << node
  182. end
  183. else
  184. newList << node
  185. end
  186. }
  187. newList
  188. end
  189. #
  190. # Lowering of simple branch ops for SH4. For example:
  191. #
  192. # baddis foo, bar, baz
  193. #
  194. # will become:
  195. #
  196. # addi foo, bar, tmp
  197. # bs tmp, baz
  198. #
  199. def sh4LowerSimpleBranchOps(list)
  200. newList = []
  201. list.each {
  202. | node |
  203. if node.is_a? Instruction
  204. annotation = node.annotation
  205. case node.opcode
  206. when /^b(addi|subi|ori|addp)/
  207. op = $1
  208. bc = $~.post_match
  209. case op
  210. when "addi", "addp"
  211. op = "addi"
  212. when "subi", "subp"
  213. op = "subi"
  214. when "ori", "orp"
  215. op = "ori"
  216. end
  217. if bc == "s"
  218. raise "Invalid operands number (#{node.operands.size})" unless node.operands.size == 3
  219. if node.operands[1].is_a? RegisterID or node.operands[1].is_a? SpecialRegister
  220. newList << Instruction.new(node.codeOrigin, op, node.operands[0..1])
  221. newList << Instruction.new(node.codeOrigin, "bs", node.operands[1..2])
  222. else
  223. tmpVal = Tmp.new(node.codeOrigin, :gpr)
  224. tmpPtr = Tmp.new(node.codeOrigin, :gpr)
  225. addr = Address.new(node.codeOrigin, tmpPtr, Immediate.new(node.codeOrigin, 0))
  226. newList << Instruction.new(node.codeOrigin, "leap", [node.operands[1], tmpPtr])
  227. newList << Instruction.new(node.codeOrigin, "loadi", [addr, tmpVal])
  228. newList << Instruction.new(node.codeOrigin, op, [node.operands[0], tmpVal])
  229. newList << Instruction.new(node.codeOrigin, "storei", [tmpVal, addr])
  230. newList << Instruction.new(node.codeOrigin, "bs", [tmpVal, node.operands[2]])
  231. end
  232. else
  233. newList << node
  234. end
  235. when "bmulio", "bmulpo"
  236. raise "Invalid operands number (#{node.operands.size})" unless node.operands.size == 3
  237. tmp1 = Tmp.new(node.codeOrigin, :gpr)
  238. tmp2 = Tmp.new(node.codeOrigin, :gpr)
  239. newList << Instruction.new(node.codeOrigin, node.opcode, [tmp1, tmp2].concat(node.operands))
  240. else
  241. newList << node
  242. end
  243. else
  244. newList << node
  245. end
  246. }
  247. newList
  248. end
  249. #
  250. # Lowering of double accesses for SH4. For example:
  251. #
  252. # loadd [foo, bar, 8], baz
  253. #
  254. # becomes:
  255. #
  256. # leap [foo, bar, 8], tmp
  257. # loaddReversedAndIncrementAddress [tmp], baz
  258. #
  259. def sh4LowerDoubleAccesses(list)
  260. newList = []
  261. list.each {
  262. | node |
  263. if node.is_a? Instruction
  264. case node.opcode
  265. when "loadd"
  266. tmp = Tmp.new(codeOrigin, :gpr)
  267. addr = Address.new(codeOrigin, tmp, Immediate.new(codeOrigin, 0))
  268. newList << Instruction.new(codeOrigin, "leap", [node.operands[0], tmp])
  269. newList << Instruction.new(node.codeOrigin, "loaddReversedAndIncrementAddress", [addr, node.operands[1]], node.annotation)
  270. when "stored"
  271. tmp = Tmp.new(codeOrigin, :gpr)
  272. addr = Address.new(codeOrigin, tmp, Immediate.new(codeOrigin, 0))
  273. newList << Instruction.new(codeOrigin, "leap", [node.operands[1].withOffset(8), tmp])
  274. newList << Instruction.new(node.codeOrigin, "storedReversedAndDecrementAddress", [node.operands[0], addr], node.annotation)
  275. else
  276. newList << node
  277. end
  278. else
  279. newList << node
  280. end
  281. }
  282. newList
  283. end
  284. #
  285. # Lowering of double specials for SH4.
  286. #
  287. def sh4LowerDoubleSpecials(list)
  288. newList = []
  289. list.each {
  290. | node |
  291. if node.is_a? Instruction
  292. case node.opcode
  293. when "bdltun", "bdgtun"
  294. # Handle specific floating point unordered opcodes.
  295. newList << Instruction.new(codeOrigin, "bdnan", [node.operands[0], node.operands[2]])
  296. newList << Instruction.new(codeOrigin, "bdnan", [node.operands[1], node.operands[2]])
  297. newList << Instruction.new(codeOrigin, node.opcode[0..-3], node.operands)
  298. when "bdnequn", "bdgtequn", "bdltequn"
  299. newList << Instruction.new(codeOrigin, node.opcode[0..-3], node.operands)
  300. when "bdneq", "bdgteq", "bdlteq"
  301. # Handle specific floating point ordered opcodes.
  302. outlabel = LocalLabel.unique("out_#{node.opcode}")
  303. outref = LocalLabelReference.new(codeOrigin, outlabel)
  304. newList << Instruction.new(codeOrigin, "bdnan", [node.operands[0], outref])
  305. newList << Instruction.new(codeOrigin, "bdnan", [node.operands[1], outref])
  306. newList << Instruction.new(codeOrigin, node.opcode, node.operands)
  307. newList << outlabel
  308. else
  309. newList << node
  310. end
  311. else
  312. newList << node
  313. end
  314. }
  315. newList
  316. end
  317. #
  318. # Lowering of misplaced labels for SH4.
  319. #
  320. def sh4LowerMisplacedLabels(list)
  321. newList = []
  322. list.each {
  323. | node |
  324. if node.is_a? Instruction
  325. case node.opcode
  326. when "jmp"
  327. if node.operands[0].is_a? LabelReference
  328. tmp = Tmp.new(codeOrigin, :gpr)
  329. newList << Instruction.new(codeOrigin, "jmpf", [tmp, node.operands[0]])
  330. else
  331. newList << node
  332. end
  333. when "call"
  334. if node.operands[0].is_a? LabelReference
  335. tmp1 = Tmp.new(codeOrigin, :gpr)
  336. tmp2 = Tmp.new(codeOrigin, :gpr)
  337. newList << Instruction.new(codeOrigin, "callf", [tmp1, tmp2, node.operands[0]])
  338. else
  339. newList << node
  340. end
  341. else
  342. newList << node
  343. end
  344. else
  345. newList << node
  346. end
  347. }
  348. newList
  349. end
  350. class Sequence
  351. def getModifiedListSH4
  352. result = @list
  353. # Verify that we will only see instructions and labels.
  354. result.each {
  355. | node |
  356. unless node.is_a? Instruction or
  357. node.is_a? Label or
  358. node.is_a? LocalLabel or
  359. node.is_a? Skip
  360. raise "Unexpected #{node.inspect} at #{node.codeOrigin}"
  361. end
  362. }
  363. result = sh4LowerShiftOps(result)
  364. result = sh4LowerSimpleBranchOps(result)
  365. result = riscLowerMalformedAddresses(result) {
  366. | node, address |
  367. if address.is_a? Address
  368. case node.opcode
  369. when "btbz", "btbnz", "cbeq", "bbeq", "bbneq", "bbb", "loadb"
  370. (0..15).include? address.offset.value and
  371. ((node.operands[0].is_a? RegisterID and node.operands[0].sh4Operand == "r0") or
  372. (node.operands[1].is_a? RegisterID and node.operands[1].sh4Operand == "r0"))
  373. when "loadh"
  374. (0..30).include? address.offset.value and
  375. ((node.operands[0].is_a? RegisterID and node.operands[0].sh4Operand == "r0") or
  376. (node.operands[1].is_a? RegisterID and node.operands[1].sh4Operand == "r0"))
  377. else
  378. (0..60).include? address.offset.value
  379. end
  380. else
  381. false
  382. end
  383. }
  384. result = sh4LowerDoubleAccesses(result)
  385. result = sh4LowerDoubleSpecials(result)
  386. result = riscLowerMisplacedImmediates(result, ["storeb", "storei", "storep", "muli", "mulp", "andi", "ori", "xori",
  387. "cbeq", "cieq", "cpeq", "cineq", "cpneq", "cib", "baddio", "bsubio", "bmulio", "baddis",
  388. "bbeq", "bbneq", "bbb", "bieq", "bpeq", "bineq", "bpneq", "bia", "bpa", "biaeq", "bpaeq", "bib", "bpb",
  389. "bigteq", "bpgteq", "bilt", "bplt", "bigt", "bpgt", "bilteq", "bplteq", "btiz", "btpz", "btinz", "btpnz", "btbz", "btbnz"])
  390. result = riscLowerMalformedImmediates(result, -128..127)
  391. result = sh4LowerMisplacedLabels(result)
  392. result = riscLowerMisplacedAddresses(result)
  393. result = assignRegistersToTemporaries(result, :gpr, SH4_TMP_GPRS)
  394. result = assignRegistersToTemporaries(result, :gpr, SH4_TMP_FPRS)
  395. return result
  396. end
  397. end
  398. def sh4Operands(operands)
  399. operands.map{|v| v.sh4Operand}.join(", ")
  400. end
  401. def emitSH4Load32(constant, dest)
  402. outlabel = LocalLabel.unique("load32out")
  403. constlabel = LocalLabel.unique("load32const")
  404. $asm.puts "mov.l #{LocalLabelReference.new(codeOrigin, constlabel).asmLabel}, #{dest.sh4Operand}"
  405. $asm.puts "bra #{LocalLabelReference.new(codeOrigin, outlabel).asmLabel}"
  406. $asm.puts "nop"
  407. $asm.puts ".balign 4"
  408. constlabel.lower("SH4")
  409. $asm.puts ".long #{constant}"
  410. outlabel.lower("SH4")
  411. end
  412. def emitSH4Load32AndJump(constant, scratch)
  413. constlabel = LocalLabel.unique("load32const")
  414. $asm.puts "mov.l #{LocalLabelReference.new(codeOrigin, constlabel).asmLabel}, #{scratch.sh4Operand}"
  415. $asm.puts "jmp @#{scratch.sh4Operand}"
  416. $asm.puts "nop"
  417. $asm.puts ".balign 4"
  418. constlabel.lower("SH4")
  419. $asm.puts ".long #{constant}"
  420. end
  421. def emitSH4LoadImm(operands)
  422. if operands[0].value == 0x40000000
  423. # FirstConstantRegisterIndex const is often used (0x40000000).
  424. # It's more efficient to "build" the value with 3 opcodes without branch.
  425. $asm.puts "mov #64, #{operands[1].sh4Operand}"
  426. $asm.puts "shll16 #{operands[1].sh4Operand}"
  427. $asm.puts "shll8 #{operands[1].sh4Operand}"
  428. elsif (-128..127).include? operands[0].value
  429. $asm.puts "mov #{sh4Operands(operands)}"
  430. elsif (-32768..32767).include? operands[0].value
  431. constlabel = LocalLabel.unique("loadconstant")
  432. $asm.puts "mov.w @(6, PC), #{operands[1].sh4Operand}"
  433. $asm.puts "bra #{LocalLabelReference.new(codeOrigin, constlabel).asmLabel}"
  434. $asm.puts "nop"
  435. $asm.puts ".word #{operands[0].value}"
  436. constlabel.lower("SH4")
  437. else
  438. emitSH4Load32(operands[0].value, operands[1])
  439. end
  440. end
  441. def emitSH4Branch(sh4opcode, operand)
  442. $asm.puts "#{sh4opcode} @#{operand.sh4Operand}"
  443. $asm.puts "nop"
  444. end
  445. def emitSH4ShiftImm(val, operand, direction)
  446. tmp = val
  447. while tmp > 0
  448. if tmp >= 16
  449. $asm.puts "shl#{direction}16 #{operand.sh4Operand}"
  450. tmp -= 16
  451. elsif tmp >= 8
  452. $asm.puts "shl#{direction}8 #{operand.sh4Operand}"
  453. tmp -= 8
  454. elsif tmp >= 2
  455. $asm.puts "shl#{direction}2 #{operand.sh4Operand}"
  456. tmp -= 2
  457. else
  458. $asm.puts "shl#{direction} #{operand.sh4Operand}"
  459. tmp -= 1
  460. end
  461. end
  462. end
  463. def emitSH4BranchIfT(label, neg)
  464. outlabel = LocalLabel.unique("branchIfT")
  465. sh4opcode = neg ? "bt" : "bf"
  466. $asm.puts "#{sh4opcode} #{LocalLabelReference.new(codeOrigin, outlabel).asmLabel}"
  467. if label.is_a? LocalLabelReference
  468. $asm.puts "bra #{label.asmLabel}"
  469. $asm.puts "nop"
  470. else
  471. emitSH4Load32AndJump(label.asmLabel, SH4_TMP_GPRS[0])
  472. end
  473. outlabel.lower("SH4")
  474. end
  475. def emitSH4IntCompare(cmpOpcode, operands)
  476. $asm.puts "cmp/#{cmpOpcode} #{sh4Operands([operands[1], operands[0]])}"
  477. end
  478. def emitSH4CondBranch(cmpOpcode, neg, operands)
  479. emitSH4IntCompare(cmpOpcode, operands)
  480. emitSH4BranchIfT(operands[2], neg)
  481. end
  482. def emitSH4CompareSet(cmpOpcode, neg, operands)
  483. emitSH4IntCompare(cmpOpcode, operands)
  484. if !neg
  485. $asm.puts "movt #{operands[2].sh4Operand}"
  486. else
  487. outlabel = LocalLabel.unique("compareSet")
  488. $asm.puts "mov #0, #{operands[2].sh4Operand}"
  489. $asm.puts "bt #{LocalLabelReference.new(codeOrigin, outlabel).asmLabel}"
  490. $asm.puts "mov #1, #{operands[2].sh4Operand}"
  491. outlabel.lower("SH4")
  492. end
  493. end
  494. def emitSH4BranchIfNaN(operands)
  495. raise "Invalid operands number (#{operands.size})" unless operands.size == 2
  496. $asm.puts "fcmp/eq #{sh4Operands([operands[0], operands[0]])}"
  497. $asm.puts "bf #{operands[1].asmLabel}"
  498. end
  499. def emitSH4DoubleCondBranch(cmpOpcode, neg, operands)
  500. if cmpOpcode == "lt"
  501. $asm.puts "fcmp/gt #{sh4Operands([operands[0], operands[1]])}"
  502. else
  503. $asm.puts "fcmp/#{cmpOpcode} #{sh4Operands([operands[1], operands[0]])}"
  504. end
  505. emitSH4BranchIfT(operands[2], neg)
  506. end
  507. class Instruction
  508. def lowerSH4
  509. $asm.comment codeOriginString
  510. case opcode
  511. when "addi", "addp"
  512. if operands.size == 3
  513. if operands[0].sh4Operand == operands[2].sh4Operand
  514. $asm.puts "add #{sh4Operands([operands[1], operands[2]])}"
  515. elsif operands[1].sh4Operand == operands[2].sh4Operand
  516. $asm.puts "add #{sh4Operands([operands[0], operands[2]])}"
  517. else
  518. $asm.puts "mov #{sh4Operands([operands[0], operands[2]])}"
  519. $asm.puts "add #{sh4Operands([operands[1], operands[2]])}"
  520. end
  521. else
  522. $asm.puts "add #{sh4Operands(operands)}"
  523. end
  524. when "subi", "subp"
  525. raise "#{opcode} with #{operands.size} operands is not handled yet" unless operands.size == 2
  526. if operands[0].is_a? Immediate
  527. $asm.puts "add #{sh4Operands([Immediate.new(codeOrigin, -1 * operands[0].value), operands[1]])}"
  528. else
  529. $asm.puts "sub #{sh4Operands(operands)}"
  530. end
  531. when "muli", "mulp"
  532. $asm.puts "mul.l #{sh4Operands(operands[0..1])}"
  533. $asm.puts "sts macl, #{operands[-1].sh4Operand}"
  534. when "negi", "negp"
  535. if operands.size == 2
  536. $asm.puts "neg #{sh4Operands(operands)}"
  537. else
  538. $asm.puts "neg #{sh4Operands([operands[0], operands[0]])}"
  539. end
  540. when "andi", "andp", "ori", "orp", "xori", "xorp"
  541. raise "#{opcode} with #{operands.size} operands is not handled yet" unless operands.size == 2
  542. sh4opcode = opcode[0..-2]
  543. $asm.puts "#{sh4opcode} #{sh4Operands(operands)}"
  544. when "shllx", "shlrx"
  545. raise "Unhandled parameters for opcode #{opcode}" unless operands[0].is_a? Immediate
  546. if operands[0].value == 1
  547. $asm.puts "shl#{opcode[3, 1]} #{operands[1].sh4Operand}"
  548. else
  549. $asm.puts "shl#{opcode[3, 1]}#{operands[0].value} #{operands[1].sh4Operand}"
  550. end
  551. when "shld", "shad"
  552. $asm.puts "#{opcode} #{sh4Operands(operands)}"
  553. when "loaddReversedAndIncrementAddress"
  554. # As we are little endian, we don't use "fmov @Rm, DRn" here.
  555. $asm.puts "fmov.s #{operands[0].sh4OperandPostInc}, #{operands[1].sh4SingleLo}"
  556. $asm.puts "fmov.s #{operands[0].sh4OperandPostInc}, #{operands[1].sh4SingleHi}"
  557. when "storedReversedAndDecrementAddress"
  558. # As we are little endian, we don't use "fmov DRm, @Rn" here.
  559. $asm.puts "fmov.s #{operands[0].sh4SingleHi}, #{operands[1].sh4OperandPreDec}"
  560. $asm.puts "fmov.s #{operands[0].sh4SingleLo}, #{operands[1].sh4OperandPreDec}"
  561. when "ci2d"
  562. $asm.puts "lds #{operands[0].sh4Operand}, fpul"
  563. $asm.puts "float fpul, #{operands[1].sh4Operand}"
  564. when "fii2d"
  565. $asm.puts "lds #{operands[0].sh4Operand}, fpul"
  566. $asm.puts "fsts fpul, #{operands[2].sh4SingleLo}"
  567. $asm.puts "lds #{operands[1].sh4Operand}, fpul"
  568. $asm.puts "fsts fpul, #{operands[2].sh4SingleHi}"
  569. when "fd2ii"
  570. $asm.puts "flds #{operands[0].sh4SingleLo}, fpul"
  571. $asm.puts "sts fpul, #{operands[1].sh4Operand}"
  572. $asm.puts "flds #{operands[0].sh4SingleHi}, fpul"
  573. $asm.puts "sts fpul, #{operands[2].sh4Operand}"
  574. when "addd", "subd", "muld", "divd"
  575. sh4opcode = opcode[0..-2]
  576. $asm.puts "f#{sh4opcode} #{sh4Operands(operands)}"
  577. when "bcd2i"
  578. $asm.puts "ftrc #{operands[0].sh4Operand}, fpul"
  579. $asm.puts "sts fpul, #{operands[1].sh4Operand}"
  580. $asm.puts "float fpul, #{SH4_TMP_FPRS[0].sh4Operand}"
  581. $asm.puts "fcmp/eq #{sh4Operands([operands[0], SH4_TMP_FPRS[0]])}"
  582. $asm.puts "bf #{operands[2].asmLabel}"
  583. $asm.puts "tst #{sh4Operands([operands[1], operands[1]])}"
  584. $asm.puts "bt #{operands[2].asmLabel}"
  585. when "bdnan"
  586. emitSH4BranchIfNaN(operands)
  587. when "bdneq"
  588. emitSH4DoubleCondBranch("eq", true, operands)
  589. when "bdgteq"
  590. emitSH4DoubleCondBranch("lt", true, operands)
  591. when "bdlt"
  592. emitSH4DoubleCondBranch("lt", false, operands)
  593. when "bdlteq"
  594. emitSH4DoubleCondBranch("gt", true, operands)
  595. when "bdgt"
  596. emitSH4DoubleCondBranch("gt", false, operands)
  597. when "baddio", "baddpo", "bsubio", "bsubpo"
  598. raise "#{opcode} with #{operands.size} operands is not handled yet" unless operands.size == 3
  599. $asm.puts "#{opcode[1, 3]}v #{sh4Operands([operands[0], operands[1]])}"
  600. $asm.puts "bt #{operands[2].asmLabel}"
  601. when "bmulio", "bmulpo"
  602. raise "Invalid operands number (#{operands.size})" unless operands.size == 5
  603. $asm.puts "dmuls.l #{sh4Operands([operands[2], operands[3]])}"
  604. $asm.puts "sts macl, #{operands[3].sh4Operand}"
  605. $asm.puts "sts mach, #{operands[0].sh4Operand}"
  606. $asm.puts "cmp/pz #{operands[3].sh4Operand}"
  607. $asm.puts "movt #{operands[1].sh4Operand}"
  608. $asm.puts "dt #{operands[1].sh4Operand}"
  609. $asm.puts "cmp/eq #{sh4Operands([operands[0], operands[1]])}"
  610. $asm.puts "bf #{operands[4].asmLabel}"
  611. when "btiz", "btpz", "btbz", "btinz", "btpnz", "btbnz"
  612. if operands.size == 3
  613. $asm.puts "tst #{sh4Operands([operands[0], operands[1]])}"
  614. else
  615. if operands[0].sh4Operand == "r0"
  616. $asm.puts "cmp/eq #0, r0"
  617. else
  618. $asm.puts "tst #{sh4Operands([operands[0], operands[0]])}"
  619. end
  620. end
  621. emitSH4BranchIfT(operands[-1], (opcode[-2, 2] == "nz"))
  622. when "cieq", "cpeq", "cbeq"
  623. emitSH4CompareSet("eq", false, operands)
  624. when "cineq", "cpneq", "cbneq"
  625. emitSH4CompareSet("eq", true, operands)
  626. when "cib", "cpb", "cbb"
  627. emitSH4CompareSet("hs", true, operands)
  628. when "bieq", "bpeq", "bbeq"
  629. emitSH4CondBranch("eq", false, operands)
  630. when "bineq", "bpneq", "bbneq"
  631. emitSH4CondBranch("eq", true, operands)
  632. when "bib", "bpb", "bbb"
  633. emitSH4CondBranch("hs", true, operands)
  634. when "bia", "bpa", "bba"
  635. emitSH4CondBranch("hi", false, operands)
  636. when "biaeq", "bpaeq"
  637. emitSH4CondBranch("hs", false, operands)
  638. when "bigteq", "bpgteq", "bbgteq"
  639. emitSH4CondBranch("ge", false, operands)
  640. when "bilt", "bplt", "bblt"
  641. emitSH4CondBranch("ge", true, operands)
  642. when "bigt", "bpgt", "bbgt"
  643. emitSH4CondBranch("gt", false, operands)
  644. when "bilteq", "bplteq", "bblteq"
  645. emitSH4CondBranch("gt", true, operands)
  646. when "bs"
  647. $asm.puts "cmp/pz #{operands[0].sh4Operand}"
  648. $asm.puts "bf #{operands[1].asmLabel}"
  649. when "call"
  650. if operands[0].is_a? LocalLabelReference
  651. $asm.puts "bsr #{operands[0].asmLabel}"
  652. $asm.puts "nop"
  653. elsif operands[0].is_a? RegisterID or operands[0].is_a? SpecialRegister
  654. emitSH4Branch("jsr", operands[0])
  655. else
  656. raise "Unhandled parameters for opcode #{opcode} at #{codeOriginString}"
  657. end
  658. when "callf"
  659. $asm.puts ".balign 4"
  660. $asm.puts "mov r0, #{operands[0].sh4Operand}"
  661. $asm.puts "mova @(14, PC), r0"
  662. $asm.puts "lds r0, pr"
  663. $asm.puts "mov.l @(6, PC), #{operands[1].sh4Operand}"
  664. $asm.puts "jmp @#{operands[1].sh4Operand}"
  665. $asm.puts "mov #{operands[0].sh4Operand}, r0"
  666. $asm.puts ".long #{operands[2].asmLabel}"
  667. when "jmp"
  668. if operands[0].is_a? LocalLabelReference
  669. $asm.puts "bra #{operands[0].asmLabel}"
  670. $asm.puts "nop"
  671. elsif operands[0].is_a? RegisterID or operands[0].is_a? SpecialRegister
  672. emitSH4Branch("jmp", operands[0])
  673. else
  674. raise "Unhandled parameters for opcode #{opcode} at #{codeOriginString}"
  675. end
  676. when "jmpf"
  677. emitSH4Load32AndJump(operands[1].asmLabel, operands[0])
  678. when "ret"
  679. $asm.puts "rts"
  680. $asm.puts "nop"
  681. when "loadb"
  682. $asm.puts "mov.b #{sh4Operands(operands)}"
  683. $asm.puts "extu.b #{sh4Operands([operands[1], operands[1]])}"
  684. when "loadh"
  685. $asm.puts "mov.w #{sh4Operands(operands)}"
  686. $asm.puts "extu.w #{sh4Operands([operands[1], operands[1]])}"
  687. when "loadi", "loadis", "loadp", "storei", "storep"
  688. $asm.puts "mov.l #{sh4Operands(operands)}"
  689. when "move"
  690. if operands[0].is_a? LabelReference
  691. emitSH4Load32(operands[0].asmLabel, operands[1])
  692. elsif operands[0].is_a? Immediate
  693. emitSH4LoadImm(operands)
  694. else
  695. $asm.puts "mov #{sh4Operands(operands)}"
  696. end
  697. when "leap"
  698. if operands[0].is_a? BaseIndex
  699. biop = operands[0]
  700. if biop.scale > 0
  701. $asm.puts "mov #{sh4Operands([biop.index, operands[1]])}"
  702. if biop.scaleShift > 0
  703. emitSH4ShiftImm(biop.scaleShift, operands[1], "l")
  704. end
  705. $asm.puts "add #{sh4Operands([biop.base, operands[1]])}"
  706. else
  707. $asm.puts "mov #{sh4Operands([biop.base, operands[1]])}"
  708. end
  709. if biop.offset.value != 0
  710. $asm.puts "add #{sh4Operands([biop.offset, operands[1]])}"
  711. end
  712. elsif operands[0].is_a? Address
  713. if operands[0].base != operands[1]
  714. $asm.puts "mov #{sh4Operands([operands[0].base, operands[1]])}"
  715. end
  716. if operands[0].offset.value != 0
  717. $asm.puts "add #{sh4Operands([operands[0].offset, operands[1]])}"
  718. end
  719. else
  720. raise "Unhandled parameters for opcode #{opcode} at #{codeOriginString}"
  721. end
  722. when "ldspr"
  723. $asm.puts "lds #{sh4Operands(operands)}, pr"
  724. when "stspr"
  725. $asm.puts "sts pr, #{sh4Operands(operands)}"
  726. when "break"
  727. # This special opcode always generates an illegal instruction exception.
  728. $asm.puts ".word 0xfffd"
  729. else
  730. raise "Unhandled opcode #{opcode} at #{codeOriginString}"
  731. end
  732. end
  733. end