ネゲート
mvn r0, #1 ; r0 <- -2mvn 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 件のコメント:
コメントを投稿