class Metasm::Sh4
Public Class Methods
new(e = :little, transfersz = 0, fpprecision = 0)
click to toggle source
Calls superclass method
# File metasm/cpu/sh4/main.rb, line 11 def initialize(e = :little, transfersz = 0, fpprecision = 0) super() @endianness = e # transfer size mode # When SZ = 1 and big endian mode is selected, FMOV can # be used for double-precision floating-point data load or # store operations. In little endian mode, two 32-bit data size # moves must be executed, with SZ = 0, to load or store a # double-precision floating-point number. transfersz = 0 if @endianness == :little @transfersz = transfersz # PR = 0 : Floating point instructions are executed as single # precision operations. # PR = 1 : Floating point instructions are executed as double- # precision operations (the result of instructions for # which double-precision is not supported is undefined). # Setting [transfersz = fpprecision = 1] is reserved. # FPU operations are undefined in this mode. @fpprecision = fpprecision @size = 32 end
Public Instance Methods
addop(name, bin, *args)
click to toggle source
# File metasm/cpu/sh4/opcodes.rb, line 10 def addop(name, bin, *args) o = Opcode.new name, bin args.each { |a| o.args << a if @fields_mask[a] o.props[a] = true if @valid_props[a] o.fields[a] = [@fields_mask[a], @fields_shift[a]] if @fields_mask[a] } @opcode_list << o end
backtrace_is_function_return(expr, di=nil)
click to toggle source
# File metasm/cpu/sh4/decode.rb, line 343 def backtrace_is_function_return(expr, di=nil) expr.reduce_rec == :pr end
backtrace_update_function_binding(dasm, faddr, f, retaddrlist, *wantregs)
click to toggle source
# File metasm/cpu/sh4/decode.rb, line 163 def backtrace_update_function_binding(dasm, faddr, f, retaddrlist, *wantregs) retaddrlist.map! { |retaddr| dasm.decoded[retaddr] ? dasm.decoded[retaddr].block.list.last.address : retaddr } if retaddrlist b = f.backtrace_binding bt_val = lambda { |r| next if not retaddrlist bt = [] b[r] = Expression::Unknown # break recursive dep retaddrlist.each { |retaddr| bt |= dasm.backtrace(Expression[r], retaddr, :include_start => true, :snapshot_addr => faddr, :origin => retaddr) } b[r] = ((bt.length == 1) ? bt.first : Expression::Unknown) } wantregs = GPR::Sym if wantregs.empty? wantregs.map { |r| r.to_sym }.each(&bt_val) end
build_bin_lookaside()
click to toggle source
# File metasm/cpu/sh4/decode.rb, line 19 def build_bin_lookaside lookaside = (0..0xf).inject({}) { |h, i| h.update i => [] } opcode_list.each { |op| build_opcode_bin_mask op lookaside[(op.bin >> 12) & 0xf] << op } lookaside end
build_opcode_bin_mask(op)
click to toggle source
# File metasm/cpu/sh4/decode.rb, line 11 def build_opcode_bin_mask(op) op.bin_mask = 0 op.args.each { |f| op.bin_mask |= @fields_mask[f] << @fields_shift[f] } op.bin_mask ^= 0xffff end
dbg_register_list()
click to toggle source
# File metasm/cpu/sh4/main.rb, line 299 def dbg_register_list @dbg_register_list ||= GPR::Sym end
decode_cmp_cst(di, a0)
click to toggle source
# File metasm/cpu/sh4/decode.rb, line 193 def decode_cmp_cst(di, a0) case di.opcode.name when 'cmp/pl'; Expression[a0, :'>', 0] # signed when 'cmp/pz'; Expression[a0, :'>=', 0] # signed end end
decode_cmp_expr(di, a0, a1)
click to toggle source
interprets a condition code (in an opcode name) as an expression
# File metasm/cpu/sh4/decode.rb, line 183 def decode_cmp_expr(di, a0, a1) case di.opcode.name when 'cmp/eq'; Expression[a0, :'==', a1] when 'cmp/ge'; Expression[a0, :'>=', a1] # signed when 'cmp/gt'; Expression[a0, :'>', a1] # signed when 'cmp/hi'; Expression[a0, :'>', a1] # unsigned when 'cmp/hs'; Expression[a0, :'>=', a1] # unsigned end end
decode_findopcode(edata)
click to toggle source
# File metasm/cpu/sh4/decode.rb, line 41 def decode_findopcode(edata) return if edata.ptr >= edata.length di = DecodedInstruction.new(self) val = edata.decode_imm(:u16, @endianness) edata.ptr -= 2 op = @bin_lookaside[(val >> 12) & 0xf].find_all { |opcode| (val & opcode.bin_mask) == opcode.bin } op = transfer_size_mode(op) if op.length == 2 op = precision_mode(op) if op.length == 2 if op.length > 1 puts "current value: #{Expression[val]}, ambiguous matches:", op.map { |opcode| " #{opcode.name} - #{opcode.args.inspect} - #{Expression[opcode.bin]} - #{Expression[opcode.bin_mask]}" } #raise "Sh4 - Internal error" end if not op.empty? di.opcode = op.first di end end
decode_instr_op(edata, di)
click to toggle source
# File metasm/cpu/sh4/decode.rb, line 64 def decode_instr_op(edata, di) before_ptr = edata.ptr op = di.opcode di.instruction.opname = op.name di.opcode.props[:memsz] = (op.name =~ /\.l|mova/ ? 32 : (op.name =~ /\.w/ ? 16 : 8)) val = edata.decode_imm(:u16, @endianness) field_val = lambda{ |f| r = (val >> @fields_shift[f]) & @fields_mask[f] case f when :@rm, :@rn ,:@_rm, :@_rn, :@rm_, :@rn_; GPR.new(r) when :@disppc # The effective address is formed by calculating PC+4, # clearing the lowest 2 bits, and adding the zero-extended 8-bit immediate i # multiplied by 4 (32-bit)/ 2 (16-bit) / 1 (8-bit). curaddr = di.address+4 curaddr = (curaddr & 0xffff_fffc) if di.opcode.props[:memsz] == 32 curaddr+r*(di.opcode.props[:memsz]/8) when :@disprm, :@dispr0rn; (r & 0xf) * (di.opcode.props[:memsz]/8) when :@disprmrn; (r & 0xf) * 4 when :@dispgbr; Expression.make_signed(r, 16) when :disp8; di.address+4+2*Expression.make_signed(r, 8) when :disp12; di.address+4+2*Expression.make_signed(r, 12) when :s8; Expression.make_signed(r, 8) else r end } op.args.each { |a| di.instruction.args << case a when :r0; GPR.new 0 when :rm, :rn; GPR.new field_val[a] when :rm_bank, :rn_bank; RBANK.new field_val[a] when :drm, :drn; DR.new field_val[a] when :frm, :frn; FR.new field_val[a] when :xdm, :xdn; XDR.new field_val[a] when :fvm, :fvn; FVR.new field_val[a] when :vbr; VBR.new when :gbr; GBR.new when :sr; SR.new when :ssr; SSR.new when :spc; SPC.new when :sgr; SGR.new when :dbr; DBR.new when :mach; MACH.new when :macl; MACL.new when :pr; PR.new when :fpul; FPUL.new when :fpscr; FPSCR.new when :pc; PC.new when :@rm, :@rn, :@disppc Memref.new(field_val[a], nil) when :@_rm, :@_rn Memref.new(field_val[a], nil, :pre) when :@rm_, :@rn_ Memref.new(field_val[a], nil, :post) when :@r0rm Memref.new(GPR.new(0), GPR.new(field_val[:rm])) when :@r0rn, :@dispr0rn Memref.new(GPR.new(0), GPR.new(field_val[:rn])) when :@disprm Memref.new(field_val[a], GPR.new(field_val[:rm])) when :@disprmrn Memref.new(field_val[a], GPR.new(field_val[:rn])) when :disppc; Expression[field_val[:@disppc]] when :s8, :disp8, :disp12; Expression[field_val[a]] when :i16, :i8, :i5; Expression[field_val[a]] else raise SyntaxError, "Internal error: invalid argument #{a} in #{op.name}" end } di.bin_length += edata.ptr - before_ptr return if edata.ptr > edata.length di end
delay_slot(di=nil)
click to toggle source
# File metasm/cpu/sh4/decode.rb, line 347 def delay_slot(di=nil) (di and di.opcode.props[:delay_slot]) ? 1 : 0 end
disassembler_default_func()
click to toggle source
# File metasm/cpu/sh4/decode.rb, line 145 def disassembler_default_func df = DecodedFunction.new df.backtrace_binding = {} (0..7 ).each { |i| r = "r#{i}".to_sym ; df.backtrace_binding[r] = Expression::Unknown } (8..15).each { |i| r = "r#{i}".to_sym ; df.backtrace_binding[r] = Expression[r] } df.backtracked_for = [BacktraceTrace.new(Expression[:pr], :default, Expression[:pr], :x)] df.btfor_callback = lambda { |dasm, btfor, funcaddr, calladdr| if funcaddr != :default btfor elsif di = dasm.decoded[calladdr] and di.opcode.props[:saveip] btfor else [] end } df end
get_backtrace_binding(di)
click to toggle source
# File metasm/cpu/sh4/decode.rb, line 291 def get_backtrace_binding(di) a = di.instruction.args.map { |arg| case arg when GPR, XFR, XDR, FVR, DR, FR, XMTRX; arg.symbolic when MACH, MACL, PR, FPUL, PC, FPSCR; arg.symbolic when SR, SSR, SPC, GBR, VBR, SGR, DBR; arg.symbolic when Memref; arg.symbolic(di) else arg end } if binding = backtrace_binding[di.opcode.basename] bd = binding[di, *a] || {} di.instruction.args.grep(Memref).each { |m| next unless r = m.base and r.kind_of?(GPR) r = r.symbolic case m.action when :post bd[r] ||= Expression[r, :+, di.opcode.props[:memsz]/8] when :pre bd[r] ||= Expression[r, :-, di.opcode.props[:memsz]/8] end } bd else puts "unhandled instruction to backtrace: #{di}" if $VERBOSE {:incomplete_binding => Expression[1]} end end
get_xrefs_x(dasm, di)
click to toggle source
# File metasm/cpu/sh4/decode.rb, line 321 def get_xrefs_x(dasm, di) return [] if not di.opcode.props[:setip] val = case di.instruction.opname when 'rts'; :pr else di.instruction.args.last end val = case val when Reg; val.symbolic when Memref; arg.symbolic(di) else val end val = case di.instruction.opname when 'braf', 'bsrf'; Expression[[di.address, :+, 4], :+, val] else val end [Expression[val]] end
init()
click to toggle source
# File metasm/cpu/sh4/opcodes.rb, line 22 def init @opcode_list = [] # :@rm_ is used for @Rm+ # :@_rn is used for @-Rn # :@r0rm is used for @(R0, Rm) (same for r0rn) # :@r0gbr is used for @(R0, GBR) @fields_mask = { :rm => 0xf, :rn => 0xf, :@rm => 0xf, :@rn => 0xf, :@rm_ => 0xf, :@rn_ => 0xf, :@_rn => 0xf, :frm => 0xf, :frn => 0xf, :xdm => 0x7, :xdn => 0x7, :drm => 0x7, :drn => 0x7, :fvm => 0x3, :fvn => 0x3, :@r0rm => 0xf, :@r0rn => 0xf, :rm_bank => 0x7, :rn_bank => 0x7, :@disprm => 0xff, :@dispr0rn => 0xff, :@disprmrn => 0xf0f, :@dispgbr => 0xff, :@disppc => 0xff, :disp8 => 0xff, :disp12 => 0xfff, :disppc => 0xff, :i8 => 0xff, # zero-extendded 8-bit immediate :s8 => 0xff, # 8-bit displacement s is sign-extended, doubled and added to PC+4 } @fields_shift = { :rm => 4, :rn => 8, :@rm => 4, :@rn => 8, :@rm_ => 4, :@rn_ => 8, :@_rn => 8, :frm => 4, :frn => 8, :xdm => 5, :xdn => 9, :drm => 5, :drn => 9, :fvm => 8, :fvn => 10, :@r0rm => 4, :@r0rn => 8, :rm_bank => 7, :rn_bank => 4, :@disprm => 0, :@dispr0rn => 0, :@disprmrn => 0, :@dispgbr => 0, :@disppc => 0, :disp8 => 0, :disp12 => 0, :disppc => 0, :i8 => 0, :s8 => 0, } # implicit operands [:vbr, :gbr, :sr, :ssr, :spc, :sgr, :dbr, :mach, :macl, :pr, :fpul, :fpscr, :dbr, :pc, :r0].each { |a| @fields_mask[a] = @fields_shift[a] = 0 } @valid_props[:delay_slot] = true addop 'add', 0b0011 << 12 | 0b1100, :rm, :rn addop 'add', 0b0111 << 12, :s8, :rn addop 'addc', 0b0011 << 12 | 0b1110, :rm, :rn addop 'addv', 0b0011 << 12 | 0b1111, :rm, :rn addop 'and', 0b0010 << 12 | 0b1001, :rm, :rn addop 'and', 0b11001001 << 8, :i8, :r0 addop 'and.b', 0b11001101 << 8, :i8, :@r0gbr addop 'bf', 0b10001011 << 8, :disp8, :setip addop 'bf/s', 0b10001111 << 8, :disp8, :setip, :delay_slot addop 'bra', 0b1010 << 12, :disp12, :setip, :stopexec, :delay_slot addop 'braf', 0b0000 << 12 | 0b00100011, :rn, :setip, :stopexec, :delay_slot addop 'brk', 0b0000000000111011, :stopexec # causes a pre-execution BREAK exception addop 'bsr', 0b1011 << 12, :disp12, :setip, :saveip, :stopexec, :delay_slot addop 'bsrf', 0b0000 << 12 | 0b00000011, :rn, :setip, :saveip, :stopexec, :delay_slot addop 'bt', 0b10001001 << 8, :disp8, :setip addop 'bt/s', 0b10001101 << 8, :disp8, :setip, :delay_slot addop 'clrmac', 0b0000000000101000 addop 'clrs', 0b0000000001001000 addop 'clrt', 0b0000000000001000 addop 'cmp/eq', 0b0011 << 12 | 0b0000, :rm, :rn addop 'cmp/eq', 0b10001000 << 8, :s8, :r0 addop 'cmp/ge', 0b0011 << 12 | 0b0011, :rm, :rn addop 'cmp/gt', 0b0011 << 12 | 0b0111, :rm, :rn addop 'cmp/hi', 0b0011 << 12 | 0b0110, :rm, :rn addop 'cmp/hs', 0b0011 << 12 | 0b0010, :rm, :rn addop 'cmp/pl', 0b0100 << 12 | 0b00010101, :rn addop 'cmp/pz', 0b0100 << 12 | 0b00010001, :rn addop 'cmp/str', 0b0010 << 12 | 0b1100, :rm, :rn addop 'div0s', 0b0010 << 12 | 0b0111, :rm, :rn addop 'div0u', 0b0000000000011001 addop 'div1', 0b0011 << 12 | 0b0100, :rm, :rn addop 'dmuls.l', 0b0011 << 12 | 0b1101, :rm, :rn addop 'dmulu.l', 0b0011 << 12 | 0b0101, :rm, :rn addop 'dt', 0b0100 << 12 | 0b00010000, :rn addop 'exts.b', 0b0110 << 12 | 0b1110, :rm, :rn addop 'exts.w', 0b0110 << 12 | 0b1111, :rm, :rn addop 'extu.b', 0b0110 << 12 | 0b1100, :rm, :rn addop 'extu.w', 0b0110 << 12 | 0b1101, :rm, :rn # fpu instructions addop 'fabs', 0b1111 << 12 | 0b001011101, :drn addop 'fabs', 0b1111 << 12 | 0b01011101, :frn addop 'fadd', 0b1111 << 12 | 0b0 << 8 | 0b00000, :drm, :drn addop 'fadd', 0b1111 << 12 | 0b0000, :frm, :frn addop 'fcmp/eq', 0b1111 << 12 | 0b0 << 8 | 0b00100, :drm, :drn addop 'fcmp/eq', 0b1111 << 12 | 0b0100, :frm, :frn addop 'fcmp/gt', 0b1111 << 12 | 0b0 << 8 | 0b00101, :drm, :drn addop 'fcmp/gt', 0b1111 << 12 | 0b0101, :frm, :frn addop 'fcnvds', 0b1111 << 12 | 0b010111101, :drn, :fpul addop 'fcnvsd', 0b1111 << 12 | 0b010101101, :fpul, :drn addop 'fdiv', 0b1111 << 12 | 0b0 << 8 | 0b00011, :drm, :drn addop 'fdiv', 0b1111 << 12 | 0b0011, :frm, :frn addop 'fipr', 0b1111 << 12 | 0b11101101, :fvm, :fvn addop 'flds', 0b1111 << 12 | 0b00011101, :frn, :fpul addop 'fldi0', 0b1111 << 12 | 0b10001101, :frn addop 'fldi1', 0b1111 << 12 | 0b10011101, :frn addop 'float', 0b1111 << 12 | 0b000101101, :fpul, :drn addop 'float', 0b1111 << 12 | 0b00101101, :fpul, :frn addop 'fmac', 0b1111 << 12 | 0b1110, :fr0, :frm, :frn addop 'fmov', 0b1111 << 12 | 0b0 << 8 | 0b01100, :drm, :drn addop 'fmov', 0b1111 << 12 | 0b1 << 8 | 0b01100, :drm, :xdn addop 'fmov', 0b1111 << 12 | 0b01010, :drm, :@rn addop 'fmov', 0b1111 << 12 | 0b01011, :drm, :@_rn addop 'fmov', 0b1111 << 12 | 0b00111, :drm, :@r0rn addop 'fmov.s', 0b1111 << 12 | 0b1100, :frm, :frn addop 'fmov.s', 0b1111 << 12 | 0b1010, :frm, :@rn addop 'fmov.s', 0b1111 << 12 | 0b1011, :frm, :@_rn addop 'fmov.s', 0b1111 << 12 | 0b0111, :frm, :@r0rn addop 'fmov', 0b1111 << 12 | 0b0 << 8 | 0b11100, :xdm, :drn addop 'fmov', 0b1111 << 12 | 0b1 << 8 | 0b11100, :xdm, :xdn addop 'fmov', 0b1111 << 12 | 0b11010, :xdm, :@rn addop 'fmov', 0b1111 << 12 | 0b11011, :xdm, :@_rn addop 'fmov', 0b1111 << 12 | 0b10111, :xdm, :@r0rn addop 'fmov', 0b1111 << 12 | 0b0 << 8 | 0b1000, :@rm, :drn addop 'fmov', 0b1111 << 12 | 0b0 << 8 | 0b1001, :@rm_, :drn addop 'fmov', 0b1111 << 12 | 0b0 << 8 | 0b0110, :@r0rm, :drn addop 'fmov.s', 0b1111 << 12 | 0b1000, :@rm, :frn addop 'fmov.s', 0b1111 << 12 | 0b1001, :@rm_, :frn addop 'fmov.s', 0b1111 << 12 | 0b0110, :@r0rm, :frn addop 'fmov', 0b1111 << 12 | 0b1 << 8 | 0b1000, :@rm, :xdn addop 'fmov', 0b1111 << 12 | 0b1 << 8 | 0b1001, :@rm_, :xdn addop 'fmov', 0b1111 << 12 | 0b1 << 8 | 0b0110, :@r0rm, :xdn addop 'fmul', 0b1111 << 12 | 0b0 << 8 | 0b00010, :drm, :drn addop 'fmul', 0b1111 << 12 | 0b0010, :frm, :frn addop 'fneg', 0b1111 << 12 | 0b001001101, :drn addop 'fneg', 0b1111 << 12 | 0b01001101, :frn addop 'frchg', 0b1111101111111101 addop 'fschg', 0b1111001111111101 addop 'fsqrt', 0b1111 << 12 | 0b001101101, :drn addop 'fsqrt', 0b1111 << 12 | 0b01101101, :frn addop 'fsts', 0b1111 << 12 | 0b00001101, :fpul, :frn addop 'fsub', 0b1111 << 12 | 0b0 << 8 | 0b00001, :@drm, :drn addop 'fsub', 0b1111 << 12 | 0b0001, :frm, :frn addop 'ftrc', 0b1111 << 12 | 0b000111101, :drn, :fpul addop 'ftrc', 0b1111 << 12 | 0b00111101, :frn, :fpul addop 'ftrv', 0b1111 << 12 | 0b0111111101, :xmtrx, :fvn addop 'jmp', 0b0100 << 12 | 0b00101011, :rn, :setip, :stopexec, :delay_slot addop 'jsr', 0b0100 << 12 | 0b00001011, :rn, :setip, :saveip, :stopexec, :delay_slot addop 'ldc', 0b0100 << 12 | 0b00011110, :rn, :gbr addop 'ldc', 0b0100 << 12 | 0b00001110, :rn, :sr # privileged instruction addop 'ldc', 0b0100 << 12 | 0b00101110, :rn, :vbr # privileged instruction addop 'ldc', 0b0100 << 12 | 0b00111110, :rn, :ssr # privileged instruction addop 'ldc', 0b0100 << 12 | 0b01001110, :rn, :spc # privileged instruction addop 'ldc', 0b0100 << 12 | 0b11111010, :rn, :dbr # privileged instruction addop 'ldc', 0b0100 << 12 | 0b1 << 7 | 0b1110, :rn, :rn_bank # privileged instruction addop 'ldc.l', 0b0100 << 12 | 0b00010111, :@rn_, :gbr addop 'ldc.l', 0b0100 << 12 | 0b00000111, :@rn_, :sr # privileged instruction addop 'ldc.l', 0b0100 << 12 | 0b00100111, :@rn_, :vbr # privileged instruction addop 'ldc.l', 0b0100 << 12 | 0b00110111, :@rn_, :ssr # privileged instruction addop 'ldc.l', 0b0100 << 12 | 0b01000111, :@rn_, :spc # privileged instruction addop 'ldc.l', 0b0100 << 12 | 0b11110110, :@rn_, :dbr # privileged instruction addop 'ldc.l', 0b0100 << 12 | 0b1 << 7 | 0b0111, :@rn_, :rn_bank # privileged instruction addop 'lds', 0b0100 << 12 | 0b01101010, :rn, :fpscr addop 'lds.l', 0b0100 << 12 | 0b01100110, :@rn_, :fpscr addop 'lds', 0b0100 << 12 | 0b01011010, :rn, :fpul addop 'lds.l', 0b0100 << 12 | 0b01010110, :@rn_, :fpul addop 'lds', 0b0100 << 12 | 0b00001010, :rn, :mach addop 'lds.l', 0b0100 << 12 | 0b00000110, :@rn_, :mach addop 'lds', 0b0100 << 12 | 0b00011010, :rn, :macl addop 'lds.l', 0b0100 << 12 | 0b00010110, :@rn_, :macl addop 'lds', 0b0100 << 12 | 0b00101010, :rn, :pr addop 'lds.l', 0b0100 << 12 | 0b00100110, :@rn_, :pr addop 'ldtlb', 0b0000000000111000 addop 'mac.l', 0b0000 << 12 | 0b1111, :@rm_, :@rn_ addop 'mac.w', 0b0100 << 12 | 0b1111, :@rm_, :@rn_ addop 'mov', 0b0110 << 12 | 0b0011, :rm, :rn addop 'mov', 0b1110 << 12, :s8, :rn addop 'mov.b', 0b0010 << 12 | 0b0000, :rm, :@rn addop 'mov.b', 0b0010 << 12 | 0b0100, :rm, :@_rn addop 'mov.b', 0b0000 << 12 | 0b0100, :rm, :@r0rn addop 'mov.b', 0b11000000 << 8, :r0, :@dispgbr addop 'mov.b', 0b10000000 << 8, :r0, :@dispr0rn addop 'mov.b', 0b0110 << 12 | 0b0000, :@rm, :rn addop 'mov.b', 0b0110 << 12 | 0b0100, :@rm_, :rn addop 'mov.b', 0b0000 << 12 | 0b1100, :@r0rm, :rn addop 'mov.b', 0b11000100 << 8, :@dispgbr, :r0 addop 'mov.b', 0b10000100 << 8, :@dispr0rn, :r0 addop 'mov.l', 0b0010 << 12 | 0b0010, :rm, :@rn addop 'mov.l', 0b0010 << 12 | 0b0110, :rm, :@_rn addop 'mov.l', 0b0000 << 12 | 0b0110, :rm, :@r0rn addop 'mov.l', 0b11000010 << 8, :r0, :@dispgbr addop 'mov.l', 0b0001 << 12, :rm, :@disprmrn addop 'mov.l', 0b0110 << 12 | 0b0010, :@rm, :rn addop 'mov.l', 0b0110 << 12 | 0b0110, :@rm_, :rn addop 'mov.l', 0b0000 << 12 | 0b1110, :@r0rm, :rn addop 'mov.l', 0b11000110 << 8, :@dispgbr, :r0 addop 'mov.l', 0b1101 << 12, :@disppc, :rn addop 'mov.l', 0b0101 << 12, :@disprm, :rn addop 'mov.w', 0b0010 << 12 | 0b0001, :rm, :@rn addop 'mov.w', 0b0010 << 12 | 0b0101, :rm, :@_rn addop 'mov.w', 0b0000 << 12 | 0b0101, :rm, :@r0rn addop 'mov.w', 0b11000001 << 8, :r0, :@dispgbr addop 'mov.w', 0b10000001 << 8, :r0, :@dispr0rn addop 'mov.w', 0b0110 << 12 | 0b0001, :@rm, :rn addop 'mov.w', 0b0110 << 12 | 0b0101, :@rm_, :rn addop 'mov.w', 0b0000 << 12 | 0b1101, :@r0rm, :rn addop 'mov.w', 0b11000101 << 8, :@dispgbr, :r0 addop 'mov.w', 0b1001 << 12, :@disppc, :rn addop 'mov.w', 0b10000101 << 8, :@disprm, :r0 addop 'mova', 0b11000111 << 8, :disppc, :r0 # calculates an effective address using PC-relative with displacement addressing addop 'movca.l', 0b0000 << 12 | 11000011, :r0, :@rn # stores the long-word in R0 to memory at the effective address specified in Rn. addop 'movt', 0b0000 << 12 | 0b00101001, :rn # copies the T-bit to Rn addop 'mul.l', 0b0000 << 12 | 0b0111, :rm, :rn addop 'muls.w', 0b0010 << 12 | 0b1111, :rm, :rn addop 'mulu.w', 0b0010 << 12 | 0b1110, :rm, :rn addop 'neg', 0b0110 << 12 | 0b1011, :rm, :rn addop 'negc', 0b0110 << 12 | 0b1010, :rm, :rn addop 'nop', 0b0000000000001001 addop 'not', 0b0110 << 12 | 0b0111, :rm, :rn addop 'ocbi', 0b0000 << 12 | 0b10010011, :@rn # invalidates an operand cache block addop 'ocbp', 0b0000 << 12 | 0b10100011, :@rn # purges an operand cache block addop 'ocbwb', 0b0000 << 12 | 0b10110011, :@rn # write-backs an operand cache block addop 'or', 0b0010 << 12 | 0b1011, :rm, :rn addop 'or', 0b11001011 << 8, :i8, :r0 addop 'or.b', 0b11001111 << 8, :i8, :@r0gbr addop 'pref', 0b0000 | 0b10000011, :@rn # indicates a software-directed data prefetch addop 'rotcl', 0b0100 | 0b00100100, :rn addop 'rotcr', 0b0100 | 0b00100101, :rn addop 'rotl', 0b0100 | 0b00000100, :rn addop 'rotr', 0b0100 | 0b00000101, :rn addop 'rte', 0b0000000000101011, :setip, :stopexec, :delay_slot # returns from an exception or interrupt handling routine, privileged instruction addop 'rts', 0b0000000000001011, :setip, :stopexec, :delay_slot # returns from a subroutine addop 'sets', 0b0000000001011000 addop 'sett', 0b0000000000011000 addop 'shad', 0b0100 << 12 | 0b1100, :rm, :rn addop 'shal', 0b0100 << 12 | 0b00100000, :rn addop 'shar', 0b0100 << 12 | 0b00100001, :rn addop 'shld', 0b0100 << 12 | 0b1101, :rm, :rn addop 'shll', 0b0100 << 12 | 0b00000000, :rn addop 'shll2', 0b0100 << 12 | 0b00001000, :rn addop 'shll8', 0b0100 << 12 | 0b00011000, :rn addop 'shll16', 0b0100 << 12 | 0b00101000, :rn addop 'shlr', 0b0100 << 12 | 0b00000001, :rn addop 'shlr2', 0b0100 << 12 | 0b00001001, :rn addop 'shlr8', 0b0100 << 12 | 0b00011001, :rn addop 'shlr16', 0b0100 << 12 | 0b00101001, :rn addop 'sleep', 0b0000000000011011 # privileged instruction addop 'stc', 0b0000 << 12 | 0b00000010, :sr, :rn addop 'stc', 0b0000 << 12 | 0b00100010, :vbr, :rn addop 'stc', 0b0000 << 12 | 0b00110010, :ssr, :rn addop 'stc', 0b0000 << 12 | 0b01000010, :spc, :rn addop 'stc', 0b0000 << 12 | 0b00111010, :sgr, :rn addop 'stc', 0b0000 << 12 | 0b11111010, :dbr, :rn addop 'stc', 0b0000 << 12 | 0b1 << 7 | 0b0010, :rm_bank, :@_rn addop 'stc', 0b0000 << 12 | 0b00010010, :gbr, :rn addop 'stc.l', 0b0100 << 12 | 0b00000011, :sr, :@_rn addop 'stc.l', 0b0100 << 12 | 0b00100011, :vbr, :@_rn addop 'stc.l', 0b0100 << 12 | 0b00110011, :ssr, :@_rn addop 'stc.l', 0b0100 << 12 | 0b01000011, :spc, :@_rn addop 'stc.l', 0b0100 << 12 | 0b00110010, :sgr, :@_rn addop 'stc.l', 0b0100 << 12 | 0b11110010, :dbr, :@_rn addop 'stc.l', 0b0100 << 12 | 0b1 << 7 | 0b0011, :rm_bank, :@_rn addop 'stc.l', 0b0100 << 12 | 0b00010011, :gbr, :@_rn addop 'sts', 0b0000 << 12 | 0b01101010, :fpscr, :rn addop 'sts.l', 0b0100 << 12 | 0b01100010, :fpscr, :@_rn addop 'sts', 0b0000 << 12 | 0b01011010, :fpul, :rn addop 'sts.l', 0b0100 << 12 | 0b01010010, :fpul, :@_rn addop 'sts', 0b0000 << 12 | 0b00001010, :mach, :rn addop 'sts.l', 0b0100 << 12 | 0b00000010, :mach, :@_rn addop 'sts', 0b0000 << 12 | 0b00011010, :macl, :rn addop 'sts.l', 0b0100 << 12 | 0b00010010, :macl, :@_rn addop 'sts', 0b0000 << 12 | 0b00101010, :pr, :rn addop 'sts.l', 0b0100 << 12 | 0b00100010, :pr, :@_rn addop 'sub', 0b0011 << 12 | 0b1000, :rm, :rn addop 'subc', 0b0011 << 12 | 0b1010, :rm, :rn addop 'subv', 0b0011 << 12 | 0b1011, :rm, :rn addop 'swap.b', 0b0110 << 12 | 0b1000, :rm, :rn addop 'swap.w', 0b0110 << 12 | 0b1001, :rm, :rn addop 'tas.b', 0b0100 << 12 | 0b00011011, :@rn addop 'trapa', 0b11000011 << 8, :i8, :setip, :stopexec # This instruction causes a pre-execution trap. addop 'tst', 0b0010 << 12 | 0b1000, :rm, :rn addop 'tst', 0b11001000 << 8, :i8, :r0 addop 'tst.b', 0b11001100 << 8, :i8, :@r0gbr addop 'xor', 0b0010 << 12 | 0b1010, :rm, :rn addop 'xor', 0b11001010 << 8, :i8, :r0 addop 'xob.b', 0b11001110 << 8, :i8, :@r0gbr addop 'xtrct', 0b0010 << 12 | 0b1101, :rm, :rn end
init_backtrace_binding()
click to toggle source
# File metasm/cpu/sh4/decode.rb, line 207 def init_backtrace_binding @backtrace_binding ||= {} mask = lambda { |di| (1 << opsz(di)) - 1 } # 32bits => 0xffff_ffff opcode_list.map { |ol| ol.name }.uniq.each { |op| @backtrace_binding[op] ||= case op when 'ldc', 'ldc.l', 'lds', 'lds.l', 'stc', 'stc.l', 'mov', 'mov.l', 'sts', 'sts.l' lambda { |di, a0, a1| { a1 => Expression[a0] }} when 'stc.w', 'stc.b', 'mov.w', 'mov.b' lambda { |di, a0, a1| { a1 => Expression[a0, :&, mask[di]] }} when 'movt'; lambda { |di, a0| { a0 => :t_bit }} when 'mova'; lambda { |di, a0, a1| { a1 => Expression[a0] }} when 'exts.b', 'exts.w', 'extu.w' lambda { |di, a0, a1| { a1 => Expression[a0, :&, mask[di]] }} when 'cmp/eq', 'cmp/ge', 'cmp/ge', 'cmp/gt', 'cmp/hi', 'cmp/hs' lambda { |di, a0, a1| { :t_bit => decode_cmp_expr(di, a0, a1) }} when 'cmp/pl', 'cmp/pz' lambda { |di, a0| { :t_bit => decode_cmp_cst(di, a0) }} when 'tst'; lambda { |di, a0, a1| { :t_bit => Expression[[a0, :&, mask[di]], :==, [a1, :&, mask[di]]] }} when 'rte'; lambda { |di| { :pc => :spc , :sr => :ssr }} when 'rts'; lambda { |di| { :pc => :pr }} when 'sets'; lambda { |di| { :s_bit => 1 }} when 'sett'; lambda { |di| { :t_bit => 1 }} when 'clrs'; lambda { |di| { :s_bit => 0 }} when 'clrt'; lambda { |di| { :t_bit => 0 }} when 'clrmac'; lambda { |di| { :macl => 0, :mach => 0 }} when 'jmp'; lambda { |di, a0| { :pc => a0 }} when 'jsr', 'bsr', 'bsrf'; lambda { |di, a0| { :pc => Expression[a0], :pr => Expression[di.address, :+, 2*2] }} when 'dt'; lambda { |di, a0| res = Expression[a0, :-, 1] { :a0 => res, :t_bit => Expression[res, :==, 0] } } when 'add' ; lambda { |di, a0, a1| { a1 => Expression[[a0, :+, a1], :&, 0xffff_ffff] }} when 'addc' ; lambda { |di, a0, a1| res = Expression[[a0, :&, mask[di]], :+, [[a1, :&, mask[di]], :+, :t_bit]] { a1 => Expression[a0, :+, [a1, :+, :t_bit]], :t_bit => Expression[res, :>, mask[di]] } } when 'addv' ; lambda { |di, a0, a1| res = Expression[[a0, :&, mask[di]], :+, [[a1, :&, mask[di]]]] { a1 => Expression[a0, :+, [a1, :+, :t_bit]], :t_bit => Expression[res, :>, mask[di]] } } when 'shll16', 'shll8', 'shll2', 'shll' ; lambda { |di, a0| shift = { 'shll16' => 16, 'shll8' => 8, 'shll2' => 2, 'shll' => 1 }[op] { a0 => Expression[[a0, :<<, shift], :&, 0xffff] } } when 'shlr16', 'shlr8', 'shlr2','shlr'; lambda { |di, a0| shift = { 'shlr16' => 16, 'shlr8' => 8, 'shlr2' => 2, 'shlr' => 1 }[op] { a0 => Expression[a0, :>>, shift] } } when 'rotcl'; lambda { |di, a0| { a0 => Expression[[a0, :<<, 1], :|, :t_bit], :t_bit => Expression[a0, :>>, [opsz[di], :-, 1]] }} when 'rotcr'; lambda { |di, a0| { a0 => Expression[[a0, :>>, 1], :|, :t_bit], :t_bit => Expression[a0, :&, 1] }} when 'rotl'; lambda { |di, a0| shift_bit = [a0, :<<, [opsz[di], :-, 1]] { a0 => Expression[[a0, :<<, 1], :|, shift_bit], :t_bit => shift_bit } } when 'rotr'; lambda { |di, a0| shift_bit = [a0, :>>, [opsz[di], :-, 1]] { a0 => Expression[[a0, :>>, 1], :|, shift_bit], :t_bit => shift_bit } } when 'shal'; lambda { |di, a0| shift_bit = [a0, :<<, [opsz[di], :-, 1]] { a0 => Expression[a0, :<<, 1], :t_bit => shift_bit } } when 'shar'; lambda { |di, a0| shift_bit = Expression[a0, :&, 1] { a0 => Expression[a0, :>>, 1], :t_bit => shift_bit } } when 'sub'; lambda { |di, a0, a1| { a1 => Expression[[a1, :-, a0], :&, 0xffff_ffff] }} when 'subc'; lambda { |di, a0, a1| { a1 => Expression[a1, :-, [a0, :-, :t_bit]] }} when 'and', 'and.b'; lambda { |di, a0, a1| { a1 => Expression[[a0, :&, mask[di]], :|, [[a1, :&, mask[di]]]] }} when 'or', 'or.b'; lambda { |di, a0, a1| { a1 => Expression[[a0, :|, mask[di]], :|, [[a1, :&, mask[di]]]] }} when 'xor', 'xor.b'; lambda { |di, a0, a1| { a1 => Expression[[a0, :|, mask[di]], :^, [[a1, :&, mask[di]]]] }} when 'neg' ; lambda { |di, a0, a1| { a1 => Expression[mask[di], :-, a0] }} when 'negc' ; lambda { |di, a0, a1| { a1 => Expression[[[mask[di], :-, a0], :-, :t_bit], :&, mask[di]] }} when 'not'; lambda { |di, a0, a1| { a1 => Expression[a0, :^, mask[di]] }} when 'nop'; lambda { |*a| {} } when /^b/; lambda { |*a| {} } # branches end } @backtrace_binding end
init_opcode_list()
click to toggle source
# File metasm/cpu/sh4/main.rb, line 295 def init_opcode_list init end
opsz(di)
click to toggle source
# File metasm/cpu/sh4/decode.rb, line 200 def opsz(di) ret = @size ret = 8 if di and di.opcode.name =~ /\.b/ ret = 16 if di and di.opcode.name =~ /\.w/ ret end
precision_mode(list)
click to toggle source
when pr flag is set, floating point instructions are executed as double-precision operations thus register pair is used (DRn registers)
# File metasm/cpu/sh4/decode.rb, line 37 def precision_mode(list) @fpprecision == 0 ? list.reject { |op| op.args.include? :drn } : list.find_all { |op| op.args.include? :frn } end
replace_instr_arg_immediate(i, old, new)
click to toggle source
# File metasm/cpu/sh4/decode.rb, line 351 def replace_instr_arg_immediate(i, old, new) i.args.map! { |a| case a when Expression; a == old ? new : Expression[a.bind(old => new).reduce] when Memref a.base = (a.base == old ? new : Expression[a.base.bind(old => new).reduce]) if a.base.kind_of?(Expression) a else a end } end
transfer_size_mode(list)
click to toggle source
depending on transfert size mode (sz flag), fmov instructions manipulate single ou double precision values instruction aliasing appears when sz is not handled
# File metasm/cpu/sh4/decode.rb, line 30 def transfer_size_mode(list) return list if list.find { |op| not op.name.include? 'mov' } @transfersz == 0 ? list.find_all { |op| op.name.include? 'fmov.s' } : list.reject { |op| op.name.include? 'fmov.s' } end