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_binding() click to toggle source
# File metasm/cpu/sh4/decode.rb, line 200
def backtrace_binding
        @backtrace_binding ||= init_backtrace_binding
end
backtrace_is_function_return(expr, di=nil) click to toggle source
# File metasm/cpu/sh4/decode.rb, line 347
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 297
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 351
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 295
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.address, di.opcode.props[:memsz]/8)
                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 325
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.address, 4)
              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 211
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 293
def init_opcode_list
        init
end
opsz(di) click to toggle source
# File metasm/cpu/sh4/decode.rb, line 204
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 355
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