JZ2440裸ボード開発の練習#7割り込みと例外(1)

予備

割り込みと例外を入力すると、トピックを行使する前に、ARMのステータスと例外のメカニズムを調べるためにS3C2440のARMチップやリファレンスマニュアルを通読する必要があります。

知って最初に必要性が存在し、プログラムメモリ空間を節約するために存在ARMモードとThumbモードARM、16ビットの前記Thumbモードの命令長であり、ARMモード指示32ビット、模式的に我々は通常使用し、今のでメモリ容量のより多くのですターゲットアドレスオペランドBX最下位ビットはCPU Thumbモードをオンにします、1であるとき、大きな、ストレージのニーズを満たすことができ、主にThumbモードにARMモードからARMモードの使用は、プログラムのジャンプ命令BXを使用する必要があり、もちろん、だけでなく、コンパイラで、次のように親指パラメータは参加-mthumb。

	adr r0, thumb_func
	add r0, r0, #1  /* bit0=1时, bx就会切换CPU State到thumb state */
	bx r0
	
.code 16	
thumb_func:	
	bl main

ちょうど上記および関連する命令長ARMおよびThumbモードは、そこ操作のARMモードのセットは、異常に対応しているだけでなく、リソースへのアクセスを制限します。

上から下へ、上の図は、いくつかのリソースへのアクセスを制限するユーザーモード、高速割込みモード、割り込みモード、管理モード、終端モード、システムモード、未定義のモードで非特権ユーザモードモードは、あると直接関係を変更することはできません変換モードを達成するために登録します。終了モード終了命令プリフェッチは、読み出されたデータと終了に分割され、両方で異常モード(例えば、読んでいない)動作に入ります。未定義命令は、ARM命令セットに準拠していない手段を読んで、ARMは、モードに進むを知りません。FIQとIRQは、明確にする必要が割り込み、割り込み例外が属する、FIQは、経過時間に対して、データ転送のための処理割り込みで以下IRQ、より特殊目的レジスタがあることを理由のFIQ部は、複数の登録ができませんシーンを保存します。以下は、フラグの三角形は、特殊モードレジスタです。

個人的に最大の意義は、システムを復元するために特定のアクションを実行する機能である異常なパターンが存在するが、例外を入力した後、適切なハンドラにジャンプする必要があると思います。例外が発生した場合、PCはベクタテーブルに異常な異常に対応するアドレスを指すようになります、そして、我々が行う必要があり、この分野で仕事をするためにここにARM、ARMは、例外ベクタテーブルを設定すると、対応するアドレスに例外を確立することですベクタテーブル。

ARM異常パターンの上に入力する際に​​作られただけで何かがARMを記述する行う前に、あなたが最初にCPSRおよびSPSRレジスタを理解する必要があり、スケールに例外をジャンプしません。CPSR、現在のプログラムステータスレジスタ、現在のプログラムステータスレジスタ、SPSR、保存プログラムステータスレジスタ、保存プログラムステータスレジスタ。それはCPSRを使用または変更する必要が、使用CPSR元の値の後に必要がある場合は、値はSPSRにCPSRを保存されたときに、単にCPSRポイントのアーカイブでSPSRは、このステップでは、ARMの自動的に行われる必要があります。およびCPSRの使用は、より多くの、0-4bitモードビットは、それぞれのモード移行に対応する値に設定されている、第二のテーブルが見えるかもしれません。第5号は、そうでなければ、それは未知の状態になり、マニュアルを手動でこれを思い出させるために設定することができないことに注意しなければならない、ARMおよびThumbモードステータスビットは、上述あります。6割り込みビットは、割り込みに応答して設定されているイネーブル7が禁止されているビット。8-27ビットは、ARMを使用するフォローアップの機能を拡張したいと推定され、予約され、0に設定する必要があります。28-31ビットの動作は状態ビットの結果であった、より一般的には説明されません。

 

 私たちは今、異常切り替えるときにARMの下で物事をやってについて話すことができます。

1.(注:この対応LRは、専用のレジスタ・モードを持っている)レジスタ(LR)を保存するために、戻り値(PC +4またはPC + 8)R14

2.保存SPSRにCPSR(SPSRも排他モードでマッピングされています)

3.変更CPSRモードビット(0-4)モード値対応するモード

4.例外ベクタテーブルを、対応する例外PCポイントのアドレス

これまでのところ、プログラムは例外ハンドラに入ります。例外ハンドラでは、我々は、あるプログラムを実行する必要があります。

1. R13(SP)は、これに対応するモードでは、我々はC言語を使用するため、スタックハンドラを設定する必要があり、それぞれ独自のモードレジスタに登録しているため。

2.実際のハンドラを入力する前に、レジスタは、例外ハンドラが戻るの終了後に、元のプログラムが正常であることを保証するために、スタックを保存する必要が非排他的であるサイトを、保存する必要があります。

3.以前に保存されたPCがLRのリターンアドレスを指しながら、通常のプログラムの流れが戻るの終了前に、あなたは、CPSRへのオンサイト復旧、およびSPSRの回復値を保存する必要があります。それが中断された場合、また、あなたは再トリガを防ぐために、対応する割り込みビットをクリアする必要があります。

異なるリターンアドレスの異なるモード間で、ルックアップテーブルがそれに応じて処理する必要、ということに注意してください。

さらに、ユーザ・モードに加えて、他のモードは、直接現在のモードを変更するCPSRモードビットを変更することができます。

異常な

後に上記の予備知識と、操作は非常に簡単になっています。必要な手順は以下のとおりです。

例外処理ベクタテーブルを確立する1

スタックを設定し、前と2例外ハンドラの後にシーンを保存するためにサイトを復元

3.例外ハンドラ

現象を確認する必要性に起因して、元のプログラムでは、コードは非常に十分に追加することができますが、例外がスローされます。

次のように出力不定例外コードは、となります。

Start.S
---------------------------------
.text
.global _start

_start:
	B RESET	                        //异常向量表,参考芯片手册
	LDR pc,UNDEFIE                  //LDR取汇编的标号即取该地址内容,若为伪指令=,则为直接取地址
	LDR pc,SW_INTERRUPT             
	B ABORT_PREFETCH
	B ABORT_DATA
	B halt				            //reserve
	B IRQ_HANDLE
	B FIQ_HANDLE

UNDEFIE:                            //将目标地址放置在此处,防止编译器将地址放置在4k以外及其他
	.word DO_UND	                //因为硬件原因不能取到内容的地方
	
SW_INTERRUPT:
	.word DO_SWI
	

ABORT_PREFETCH:                    //此处未做实现,因此全部调到halt
ABORT_DATA:	
IRQ_HANDLE:
FIQ_HANDLE:
	B halt

DO_UND:
	//1.设置栈
	LDR SP,=0x34000000
	//2.保存现场
	STMDB SP!,{R0-R12,LR}

	//处理函数
	MRS R0,CPSR
	LDR R1,=UND_TEST_STRING
    BL ExecptionHandle
	
	//3.恢复现场,跳转回原来的位置
	LDMIA SP!,{R0-R12,PC}^              //^ 表示将SPSR恢复到CPSR中
	
DO_SWI:
	//1.设置栈
	LDR SP,=0x33e00000
	//2.保存现场
	STMDB SP!,{R0-R12,LR}
	
	//处理函数
	MRS R0,CPSR
	LDR R1,=SWI_TEST_STRING
    BL ExecptionHandle
	
	//3.恢复现场,跳转回原来的位置
	LDMIA SP!,{R0-R12,PC}^  //^ 表示将SPSR恢复到CPSR中

UND_TEST_STRING:
	.string "enter undefin mode!\n"    //汇编中定义带'\0'的字符串为.string
	
SWI_TEST_STRING:
	.string "enter swi mode!\n"

.align 4                                //4字节对齐。防止string的不对齐而取地址自动对齐造成的异常执行
RESET:
	MOV R0,#0
	LDR R1,[R0]
	
	STR R0,[R0]
	LDR R2,[R0]
	
	CMP R2,R0
	LDR SP,=0x40000000+4096
	MOVEQ SP,#4096
	STREQ R1,[R0]
	
	BL HardwareInitAll
	BL UartInit
	
TEST_UND:
	bl testPrint                    //调试时发现这里必须存在一个语句下面的未定义指令才会生效,
	.word 0xdeadc0de                //原因未知,已排除未对齐原因
	//bl testPrint
TEST_SWI:
	MRS R0,CPSR
	BIC R0,R0,#0x0F                //切换到usr模式
	MSR CPSR,R0
	SWI 0x123
	
	LDR pc,=main
halt:
    B halt
execption.h
----------------------------
#ifndef __EXCEPTION_H
#define __EXCEPTION_H

#include <stdint.h>

void UndExecptionHandle(uint32_t CPSR,char* string);

#endif
execption.c
------------------------

#include "execption.h"
#include "uart.h"

void ExecptionHandle(uint32_t CPSR,char* string)
{
	printHex(CPSR);
	puts(string);
}
uart.h
-----------------------------
#ifndef __UART_H
#define __UART_H

#include <stdint.h>

void UartInit(void);

void putc(uint8_t character);
uint8_t getc(void);

void printHex(uint32_t value);
void puts(char* string);
void testPrint();
#endif


#include "uart.h"


#include "s3c2440.h"


void UartInit(void)
{
	//GPIO init
	GPHCON &= ~((3<<6) | (3<<4));
	GPHCON |= (2<<6) | (2<<4);

	//UART init
	ULCON0 = 3;  //8n1
	UCON0 = (1<<2) | (1<<0);
	UBRDIV0 = (int32_t)( 50000000/ (115200 * 16) ) -1;
}


static uint8_t IsReadyToSend(void)
{
	return UTRSTAT0 & (1<<1);
}


static uint8_t IsReadyToReceive(void)
{
	return UTRSTAT0 & (1<<0);
}

void putc(uint8_t character)
{
	if(character==(uint8_t)('\n'))
	{
		while(!IsReadyToSend());
		UTXH0 = (uint8_t)'\r';
	}
	while(!IsReadyToSend());
	UTXH0 = character;
}

uint8_t getc(void)
{
	while(!IsReadyToReceive());
	return URXH0;
}

void printHex(uint32_t value)
{
	int i=0;	
	char output[8]={0};

	for(i = 0;i<8;i++)
	{
		output[i] = value & 0xf;
		value >>= 4;
	}

	puts("0x");
	for(i = 7; i>=0; i--)
	{
		if(output[i]>=0 && output[i]<=9)
			output[i] += '0';
		else
			output[i] = output[i] - 10 + 'A';
		putc(output[i]);
	}
	putc('\n');
}

void puts(char* string)
{
	while(*string)
	{
		putc(*string++);
	}
}

void testPrint()
{
	puts("111\n");
}

#include <stdint.h>

#include "s3c2440.h"
#include "led.h"
#include "uart.h"

int main()
{
	//HardwareInitAll();
	//UartInit();

	puts("main function!\n");
	while(1);
	return 0;
}

CPSR現象はターン定義された印刷モードでは、メインファンクション文字列と文字列は、文字列、CPSRのソフトウェア割り込み、ソフトウェア割り込みを未定義です。

ソフト割り込みSWIアクティブトリガーの遊びがあり、あなたは私たちのハンドラはアクションが操作の数に応じて実行する必要があるかを判断できるように、操作の数を取ることができます。ここでのアイデアはLR、抽出したアドレス、操作を完了するARM命令に従ってオペランド参照マニュアル抽出部の値によってSWIのアドレスを取得することです。

あなたはSWIを動作させるの数が0-23bitで見ることができます。命令が4バイトであり、アドレスはSWI LR-4を呼び出すことによって直接得ることができます。

Start.S

.text
.global _start

_start:
	B RESET	
	LDR pc,UNDEFIE
	LDR pc,SW_INTERRUPT

...//省略重复代码
	
DO_SWI:
	//1.设置栈
	LDR SP,=0x33e00000
	//2.保存现场
	STMDB SP!,{R0-R12,LR}
	
	//处理函数
	MRS R0,CPSR
	LDR R1,=SWI_TEST_STRING
	SUB R2,LR,#4                            //减去4,得到SWI地址
    BL SWIHandler
	
	//3.恢复现场,跳转回原来的位置
	LDMIA SP!,{R0-R12,PC}^  //^ 表示将SPSR恢复到CPSR中

UND_TEST_STRING:
	.string "enter undefin mode!\n"
	
SWI_TEST_STRING:
	.string "enter swi mode!\n"

...

TEST_SWI:
	MRS R0,CPSR
	BIC R0,R0,#0x0F
	MSR CPSR,R0
	SWI 0x123
	
	LDR pc,=main
halt:
    B halt
execption.c
-----------------------
#include "execption.h"
#include "uart.h"

void ExecptionHandle(uint32_t CPSR,char* string)
{
	printHex(CPSR);
	puts(string);
}


void SWIHandler(uint32_t CPSR,char* string,uint32_t* opera_address)
{
	ExecptionHandle(CPSR,string);
	printHex((*opera_address) & 0xFFFFFF);
}

印刷出力は0x123です。

 
公開された19元の記事 ウォン称賛7 ビュー6919

おすすめ

転載: blog.csdn.net/G_METHOD/article/details/104547407