2015年3月24日火曜日

armアセンブラメモ



ネゲート

mvn  r0, #1   ; r0 <- -2
mvn  r1, #2   ; r1 <- -3

cmn  r0, #1   ; if r0 == -1
bne  xxx
             ; r0=-1

関数定義


function

func_entry:
stmfd r13!, {<registers>,r14}
:
ldmfd r13!, {<registers>,pc} ; pop and return

func_entry:
: ; r0-r3以外使わない場合
:
mov pc, lr ; return

func_entry:
: ; r0-r3以外使わない場合(Thumb使用、最近のARMはこうするべき)
:
bx      lr ; return


func_entry:
stmfd r13!, {lr} ; 他の関数を呼ぶ場合
:
bl other_func
:
ldmfd r13!, {pc} ; return


mrsは、フラグレジスタ(ステータスレジスタ(s)を汎用レジスタ(r0))へ転送
msrは、その逆

 mrs r0, cpsr
 orr r0, r0, #0x80
 msr cpsr_c, r0



レジスタ一覧

r0-r15, 
cpsr
spsr
※spsrは、cpsrのsaveレジスタ


- alias(レジスタ別名呼称)

r0=a1 argument
:
r3=a4
r4=v1 register variable
:
r9=v6, rfp real frame pointer
r10=sl stack limit
r11=fp argument pointer
r12=ip temporary work space
r13=sp stack pointer
r14=lr link register
r15=pc program counter


例外発生時のレジスタ(svc:スーパバイザモード以外は一部のレジスタはバンク切替される)

cpsr[4:0]
priority mode   independent reg
0x10 - user
0x1f - system
0x13 - svc r13-14, spsr          
0x17 5 abort r13-14, spsr
0x1b 6 undef r13-14, spsr
0x12 4 irq r13-14, spsr
0x11 3 fiq r8-r14, spsr

reset 1
dabort 2

↑ SVCモードではr13(sp)とr14(lr),spsrは他モードと独立して存在するということ


cpsr: bit7=irq (1=disable)
cpsr: bit6=fiq (1=disable)

exception occured.

change processer mode

r14 <- return (befor exception) address

spsr <- cpsr cpsrはspsrに保存されるものの多重割込みを使用する場合自分でPushしたりする必要があるので注意

cpsr |= 0x80 // disable irq

FIQ ?
  cpsr |= 0x40 // disable fiq
pc <- exception vector address

transaction exception handler
//

--
movs pc, lr  ; pc <- lr, spsr -> cpsr
--
割込み発生時の割込みルーチンエントリ時、戻り値lrは再開番地と異なる。以下。

undef/swi
  :
  movs pc, lr

fiq/irq;
  :
  subs pc, lr, #4

prefetch:
  :
  subs pc, lr, #4

dabort:
  :
  subs pc, lr, #8


interrupt(stack use):
  sub lr, lr, #4   
  stmfd r13!, {r0-r7, lr}
  :
  ldmfd r13!, {r0-r7, pc}^

  ^ はmovsと同様 spsr->cpsrやってくれる

多重割込みの場合、spsrは自分でPushする必要があるから
interrupt:
    msr   cpsr, #(CPSR_SVC|CPSR_IRQ_BIT) 
    stmfd sp!, {r0-r3, ip, lr, pc} /* pcはダミー */
    msr   cpsr, #(CPSR_IRQ|CPSR_IRQ_BIT)
    sub   r0, lr, #4
    mrs   r1, spsr
    msr   cpsr, #(CPSR_SVC|CPSR_IRQ_BIT) 
    str   r0, [sp, #0x18] /* 戻り番地をダミーpcの保存スタック位置へ */
    stmfd sp!, {r1}       /* spsrをスタックに保存 */
    mov   lr, sp          /* この時点のスタックを復帰のため取得 */
    :
    


 add r0,r1,r2,lsl #2 ;r0:=r1+(r2<<2)
 add r0,r1,r2,lsl r3 ;r0:=r1+(r2<<r3)
             lsl(論理左シフト)
             lsr(論理右シフト)
             asr(算術右シフト)
             ror(右回転)
             rrx(キャリー付き右回転) 1ビットのシフトのみ
 add r0,r1,r2,rrx

 mov r0,#0 ; r0 <- 0
 mvn r0,#0 ; r0 <- -1
 add r0,r0,#1 ; inc r0
 sub r0,r0,#1 ; dec r0
 rsb r0,r0,#0 ; neg r0(2の補数=-r0)
 mvn r0,r0 ; cpl r0(1の補数)


 mov r0, pc ; pc + 8 -> r0

 ldr r0, adr ; [adr(pc + #n)] -> r0
 ldr r0, =adr ; adr -> r0
 adr r0, adr ; add r0, pc, #nnn

マルチ転送
LDMDA(ポストデクリメント) LDMFA(フル上昇) 1 0 0
LDMIA(ポストインクリメント) LDMFD(フル下降) 1 0 1
LDMDB(プリデクリメント) LDMEA(空上昇) 1 1 0
LDMIB(プリインクリメント) LDMED(空下降) 1 1 1


STMDA(ポストデクリメント) STMED(空下降) 0 0 0
STMIA(ポストインクリメント) STMEA(空上昇) 0 0 1
STMDB(プリデクリメント) STMFD(フル下降) 0 1 0
STMIB(プリインクリメント) STMFA(フル上昇) 0 1 1

なので、Pushは、PreDecrementなので、--, store
popは、load, ++
***** sp は最後の保存した値を指している ******

マルチ転送ではレジスタ保存の順序は、レジスタ番号の若い順に低位アドレスへ保存される。
stmfd r13!, {r0-r4, ip, lr, pc}   ; push pc ... push r0
ldmfd r13!, {r0-r4, ip, lr, pc}   ; pop r0 ... pop pc

-----------------------
gcc ld file
-----------------------
CFLAGS=-mcpu=arm7tdmi -mlittle-endian $(INC) -DNDEBUG -Wall \
-Os -fmessage-length=0 
LFLAGS=-Tboot/target_rom.ld -Wall -nostartfiles -Wl,-Map=$*.map

// debug
CFLAGS=-mcpu=arm7tdmi -mlittle-endian $(INC) -DNDEBUG -Wall \
-g3 -O0  -MMD -MP -MF"$@.d" -MT"$@.d" -fmessage-length=0 
LFLAGS=-Tboot/target_rom.ld -Wall -nostartfiles -Wl,-Map=$*.map

$(TARGET).out : $(OBJS) $(LIBKRNL)
$(CC) -o $@ $(OBJS) $(LIBKRNL) $(LFLAGS)
arm-none-eabi-objcopy -O ihex $@ $*.hex
arm-none-eabi-objcopy -O srec $@ target.srec
cmd /c copy /y target.srec $*.srec
cmd /c del target.srec
arm-none-eabi-objdump -h -S $@ >$*.lst

$(OBJDIR)/%.o : drv/%.c
$(CC) -o $@ $(CFLAGS) -c $<

-------- t2_rom.ld -----------------
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm","elf32-littlearm") 
OUTPUT_ARCH(arm)
ENTRY(start)
SEARCH_DIR(.)

/*
 * メモリサイズの指定
 */
MEMORY
{
  romL (rx)  : ORIGIN = 0x10000000, LENGTH = 32k
  romH (rx)  : ORIGIN = 0x10008000, LENGTH = 32k
  romMirror (rx) : ORIGIN = 0x00000000, LENGTH = 32k
  romMirrorH (rx) : ORIGIN = 0x00008000, LENGTH = 32k
  ram (rwx) : ORIGIN = 0x20000000, LENGTH = 32k
}

SECTIONS
{
    .text :
    {
        __text = . ;
        *(.vector)

        . = ALIGN(4);

        *(EXCLUDE_FILE(hi_rom/*.o *arm-none-eabi*) .text)
        *(.glue_7t)
        *(.glue_7)

        _etext = . ;
        PROVIDE (etext = .) ;
        . = ALIGN(4);

        *(EXCLUDE_FILE(hi_rom/*.o *arm-none-eabi*) .rodata)
        *(EXCLUDE_FILE(hi_rom/*.o *arm-none-eabi*) .rodata.*)
    } > romMirror AT>romL


   .textH : {
        . = ALIGN(4);
        *.o(.text)
        . = ALIGN(4);

        *.o(.rodata)
        . = ALIGN(4);
        *.o(.rodata.*)

   } >romMirrorH AT>romH

    . = ALIGN(4);
    __idata_start = . ;
    .data :
    {
        __data_start = . ;
        *(.data)
    } >ram AT>romL
    __idata_end = __idata_start + SIZEOF(.data);
    _edata  =  . ;
    PROVIDE (edata = .) ;

    . = ALIGN(4);
    .bss :
    {
        __bss_start = . ;
        *(.bss)
        *(COMMON)
        . = ALIGN(32 / 8);
    } >ram
    . = ALIGN(32 / 8);
    __bss_end = . ;
    _end = . ;
    PROVIDE (end = .) ;
}
---------------------
> romMirror AT>romL

romMirror(0番地)へロードされて実行
romL(0x10000番地)に格納されているものとする

srecordも
10000000
:
10000A70
10008000
10009B20
となっている。
内部コードの分岐先も、00000xxx

0 件のコメント: