# 微處理機概論 ## 課程主要內容(巨觀) ### 主機板主要三大部分(micro controller) - **CPU (中央處理器)**(micro proccers) - Reg(存取暫存器解決應用問題):r0~r15 - 負責處理指令、運算和控制運算流程。 - **Mem (記憶體)** - 儲存資料和指令,供CPU存取和執行。 - **I/O (輸入輸出裝置)** - 包括鍵盤、螢幕、印表機等外部設備。 - 透過匯流排(BUS)連接。 #### 使用匯流排連接(BUS) - 用於在主機板上連接各種元件,實現資料和指令的傳輸。 #### CPU與I/O之間有介面晶片(Interface chips) - 晶片內有許多暫存器(Registers)。 - 下指令是為了擷取記憶體。 1. **New instructions**(給予新的指令):Independent I/O(INTEL) 2. **Memory-mapped I/O**(記憶體配置I/O的空間):(ARM) ### 本學期的程式都可以被歸類為驅動程式的一環 - 利用CPU寫程式去控制或跟I/O互動。 - CPU需要去Drive(驅動) I/O。 ![IMG_0918](https://hackmd.io/_uploads/SyGWffQnp.jpg) ### 2024/2/21 #### 16.2.1 The UART (介面晶片) ![IMG_0919](https://hackmd.io/_uploads/H1EmMG72p.jpg) The UART = The Universal Asynchronous Receiver/Transmitter - asynchronous = **非同步的** 需要有一個Buffer放資料 - synchronus = **同步** 會有很多限制導致效率變慢 - 在**非同步**的**傳送**(Transmitter)與**接收**(Reciver)時都需要一個**BUFFER** - Syncronization ==> RULES - Asycronizatioln ==> rules **(syncronization mechanisms 同步機制)** 在**非同步**之下都要探討**同步機制** #### 16.2.2 On-chip static RAM 可以讓使用者自由存取 0x4000 000 - 0x4000 3FFF AHB Peripherals/VPB Peripherals 留給介面晶片的位置 AHB與VPB是匯流排(BUS) ### 2024/02/27 #### 暫存器的空間稱為 = I/O space 記憶體的空間稱為 = Memory space 位置解碼器 Address Decoder Decoder的基本概念 = 一個位元(1bit)可以選取(0/1)兩個輸出 32-bit address 最多可以選擇2的32次方種輸出(4GB) 選擇到的輸出會勢能 LDR register, memory(effective address) 接下來交給CPU處理 CPU loads from memory to register (execution) 1. put the effective address into address bus to open a memory location 2. turn on read signal(CPU其中一個腳位)to let the data flow(data bus) from memory to CPU 3. read data from data bus into the register CPU store from register to memory STR register, memory 順序都一樣要把 2. read signal 改成 write signal 3. read data from data bus 改成 write(put) data into data bus #### bus有三種 address bus(單向從CPU流到周邊) 其中最重要的東西是address decoder Data bus 資料匯流排(雙向的) 由CPU利用read signal控制 #### Memory-mapped I/O same decoder for memory space and I/O space #### Independent I/O different decoder for memory and I/O #### Figure 16.2 4GB = 2的32次方 address decoder 有32個腳位 統稱 **32位元的位置** 假設2GB至4GB分配給I/O space 0GB至2GB分配給Memory space #### Figure 16.3 只有部分位置會置能 UART只有6個8位元的空間 每個位元都有功能沒有浪費 0xE000C000 0xE000C004 0xE000C008 0xE000C00C U0LCR(**Line Control Register**) 這個暫存器是可以讀寫的 初始值為0 0xE000C014 0xE000C01C Reciver <- BUFFER(aka Line) <- Transmitter Line Control Register = 規範Line format CPU initialize UART ### 2024/03/05 UART 有8位元 9600 bits/second 1 second = 15000000 clock cycles 15000000/9600 = 1562.5 16 bit 存不下 先把1562/16 = 97.~~625~~ 等同 shift right 4 bits (除以16) MOV r6, #0x61 將0x61存入UART的divisor latch 每個腳位都代表一個位元 進來或出來的資料都是位元流 每個腳位都有不同的功能 Write 0b0101 into bits 3-0 of register PINSEL0, the remaining bits unchanged 要把 0b0101 寫入bits 3,2,1,0 其他要保持不變 操作位元的行為: Read, Modify, Write 4個位元(bits)就是一個nibble 副程式的最後一行要有 BX LR 或者是 MOV PC, LR 否則會回不去主程式 PC => Program Counter 主程式呼叫副程式的方式: BX UARTConfig ;LR = return address LR => Link Register transmission speed ### 2024/03/26 CPU --POOL--> Peripheral CPU(IR) <--INTERRUPT00-- Peripheral(IR) 1. BUFFER EMPTY 2. DATA READY 3. IR: Interrupt Request 4. INTA: Interrupt Acknowledge - 終端確認 CPU 收到訊號後知道終端有什麼事情發生並且發送IR請CPU幫忙服務。 ```asm= LDR r5, =U0START wait LDRB r6, [r5, #LSR0] TST r6, #0x20 BEQ wait STRB r0, [r5] ``` #### 15.1 Cortext-M4 operation modes 版子選擇 TM4C1233H6PM ```asm= Stack EQU 0x00000100 DivbyZ EQU 0xD14 SYSHNDCTRL EQU 0xD24 Usagefault EQU 0xD2A NVICBase EQU 0xE000E000 AREA STACK, NOINIT, READWRITE, ALIGN=3 StackMem SPACE Stack PRESERVE8 AREA RESET, CODE, READONLY THUMB ; The vector table sits here ; we'll define just a few of them and leave the rest at 0 for now DCD StackMem+Stack ; top of stack DCD Reset_Handler ; Reset Handler DCD NmiISR ; NMI Handler DCD FalutISR ; Hard Fault Handler DCD IntDefaultHandler ; MPU Fault Handler DCD IntDefaultHandler ; Usage Fault Handler EXPORT Reset_Handler ENTRY Reset_Handler ; enable the edivide-by-zero trap ; located in the NVIC ; base: 0xE000E000 ; offset: 0xD14 ; bit: 4 LDR r6, =NVICBase LDR r7, =DivbyZ LDR r1, [r6, r7] ORR r1, #0x10 ; enable bit 4 STR r1, [r6, r7] ; now turn on the usage fault exception LDR r7, =SYSHNDCTRL LDR r1, [r6, r7] ORR r1, #0x40000 STR r1, [r6, r7] ; try out a divide by 2 then a divide by 0 MOV r0, #0 MOV r1, #0x11111111 MOV r2, #0x22222222 MOV r3, #0x33333333 ; this divide works just fine UDIV r4, r2, r1 ; this divide takes an exception UDIV r5, r3, r0 Exit B Exit NmiISR B NmiISR FaultISR B FaultISR IntDefaultHandler ; let's read the Usage Fault Status Register LDR r7, =Usagefault LDRH r1, [r6, r7] TEQ r1, #0x200 IT NE LDRNE r9, =0xDEADDEAD ; r1 should have bit 9 set indicating ; a divide-by-zero has taken place done B done ALIGN END ``` ## Quiz1 ![image](https://hackmd.io/_uploads/HkB9V0-JC.png) ## HW1 ### Part1 1. 執行課本p.348-349程式 印出字串”TKU-ECE+學號+英文名字" Ex: TKU-ECE 407443210 Michael 2. 改寫上述程式使能印出其反向字串 Ex: leahciM 012344704 ECE-UKT 3. Calculate Keil Tool System Clock Frequency and rewrite the initialization to show about 9600 baud on the divisor latch window **(1) [Prog1_1]** ![image](https://hackmd.io/_uploads/Byp8HUg1R.png) ```asm= AREA UARTDEMO, CODE, READONLY PINSEL0 EQU 0XE002C000 ; controls the function of pins U0START EQU 0xE000C000 ; start of UART0 register LCR0 EQU 0xC ; line control register for UART0 LSR0 EQU 0x14 ; line status register for UART0 RAMSTART EQU 0x40000000 ; start of onboard RAM for 2104 ENTRY start LDR sp, =RAMSTART ; set up stack pointer BL UARTConfig ; initialize/configure UART0 LDR r1, =CharData ; starting address of characters Loop LDRB r0, [r1], #1 ; load character, increment address CMP r0, #0 ; null terminated BLNE Transmit ; send character to UART BNE Loop ; contiune if not a '0' done B done UARTConfig STMIA sp!, {r5, r6, LR} LDR r5, =PINSEL0 ; base address of register LDR r6, [r5] ; get contents BIC r6, r6, #0xF ; clear out lower nibble ORR r6, r6, #0x5 ; sets p0.0 to Tx0 and P0.1 to Rx0 STR r6, [r5] LDR r5, =U0START MOV r6, #0x83 ; set 8 bits, no parity, 1 stop bit STRB r6, [r5, #LCR0] ; write control byte to LCR MOV r6, #0x61 ; 9400 baud @15 MHz VPB clock MOV r6, #3 ; set DLAB=0 STRB r6, [r5, #LCR0] ; Tx and Rx buffers set up LDMDB sp!, {r5, r6, PC} Transmit STMIA sp!, {r5, r6, LR} LDR r5, =U0START wait LDRB r6, [r5, #LSR0] ; get staus of buffer TST r6, #0x20 ; buffer empty? BEQ wait ; spin until buffer's empty STRB r0, [r5] LDMDB sp!, {r5, r6, PC} CharData DCB "TKU-ECE 411446510 TsaiPingCen", 0 END ``` 這段程式碼的功能是初始化UART0並從內存中讀取字符,然後通過UART將字符發送出去,直到讀取到空字符為止。 **(2) [Prog1_2]** ![image](https://hackmd.io/_uploads/B1Bc-dxkC.png) ```asm= AREA UARTDEMO, CODE, READONLY PINSEL0 EQU 0XE002C000 ; controls the function of pins U0START EQU 0xE000C000 ; start of UART0 register LCR0 EQU 0xC ; line control register for UART0 LSR0 EQU 0x14 ; line status register for UART0 RAMSTART EQU 0x40000000 ; start of onboard RAM for 2104 ENTRY start LDR sp, =RAMSTART ; set up stack pointer BL UARTConfig ; initialize/configure UART0 LDR r1, =CharData ; starting address of characters ADD r1, #28 ; TKU-ECE 411446510 TsaiPingCen has 29 character MOV r2, #29 ; to print string times Loop LDRB r0, [r1], #-1 ; load character, increment address CMP r2, #0 ; null terminated SUB r2, #1 BLNE Transmit ; send character to UART BNE Loop ; contiune if not a '0' done B done UARTConfig STMIA sp!, {r5, r6, LR} LDR r5, =PINSEL0 ; base address of register LDR r6, [r5] ; get contents BIC r6, r6, #0xF ; clear out lower nibble ORR r6, r6, #0x5 ; sets p0.0 to Tx0 and P0.1 to Rx0 STR r6, [r5] LDR r5, =U0START MOV r6, #0x83 ; set 8 bits, no parity, 1 stop bit STRB r6, [r5, #LCR0] ; write control byte to LCR MOV r6, #0x61 ; 9400 baud @15 MHz VPB clock MOV r6, #3 ; set DLAB=0 STRB r6, [r5, #LCR0] ; Tx and Rx buffers set up LDMDB sp!, {r5, r6, PC} Transmit STMIA sp!, {r5, r6, LR} LDR r5, =U0START wait LDRB r6, [r5, #LSR0] ; get staus of buffer TST r6, #0x20 ; buffer empty? BEQ wait ; spin until buffer's empty STRBNE r0, [r5] LDMDB sp!, {r5, r6, PC} CharData DCB "TKU-ECE 411446510 TsaiPingCen", 0 END ``` 反轉字串最主要的概念就是先將初始位置設定到字串的最後一個位置,然後反向讀取數據。 **(F5)** > 按F5時會完整將程式從第一行執行到最後一行 > 會將THR、TSR裡面的值會傳出來,當程式結束時,重新存取U0START(Receive) **(F10)** >按 F10 的時候會將程式碼逐步執行但輸出結果會如下圖。 ![image](https://hackmd.io/_uploads/rkaXY8gJA.png) 為甚麼會造成這樣的情況呢?我們仔細看程式碼可以知道 `BLNE Transmit` 的意思是當我讀取到的資料不等於零時,則跳轉到 `Transmit` 標記位置,否則繼續執行下一條指令。 我們在前面知道 UART 傳送資料的時候會先將資料送入到 `Transmitter Holding Register` 再送到 `Transmitter Shift Register` 接著輸出,於是因為 `F10` 是逐步執行程式碼,資料被卡在了 `Transmitter Holding Register` 跟 `Transmitter Shift Register` 裡面拿不出來了。 ![image](https://hackmd.io/_uploads/ByLP28gkA.png) ```asm= Loop LDRB r0, [r1], #1 ; load character, increment address CMP r0, #0 ; null terminated BLNE Transmit ; send character to UART BNE Loop ; contiune if not a '0' done B done ``` **(F11)** > 無窮迴圈 wait,因為使用F11沒有模擬輸出端,使傳出去的值卡在 `Transmitter holding register` 裡面,當在判斷THRE的狀態時,就會因為有值在裡面所以才會不斷進行迴圈。 ![image](https://hackmd.io/_uploads/S1T5T8ekR.png) ![image](https://hackmd.io/_uploads/ryGJRIeJR.png) ### 2024/04/09 ```arm= Stack EQU 0x00000100 DivbyZ EQU 0xD14 SYSHNDCTRL EQU 0xD24 Usagefault EQU 0xD2A NVICBase EQU 0xE000E000 AREA STACK, NOINIT, READWRITE, ALIGN=3 StackMem SPACE Stack PRESERVE8 AREA RESET, CODE, READONLY THUMB ; The vector table sits here ; we'll define just a few of them and leave the rest at 0 for now DCD StackMem+Stack ; top of stack DCD Reset_Handler ; Reset Handler DCD NmiISR ; NMI Handler DCD FalutISR ; Hard Fault Handler DCD IntDefaultHandler ; MPU Fault Handler DCD IntDefaultHandler ; Usage Fault Handler EXPORT Reset_Handler ENTRY Reset_Handler ; enable the edivide-by-zero trap () ; located in the NVIC ; base: 0xE000E000 ; offset: 0xD14 ; bit: 4 LDR r6, =NVICBase LDR r7, =DivbyZ LDR r1, [r6, r7] ORR r1, #0x10 ; enable bit 4 STR r1, [r6, r7] ; now turn on the usage fault exception LDR r7, =SYSHNDCTRL LDR r1, [r6, r7] ORR r1, #0x40000 STR r1, [r6, r7] ; try out a divide by 2 then a divide by 0 MOV r0, #0 MOV r1, #0x11111111 MOV r2, #0x22222222 MOV r3, #0x33333333 ; this divide works just fine UDIV r4, r2, r1 ; this divide takes an exception UDIV r5, r3, r0 Exit B Exit NmiISR B NmiISR FaultISR B FaultISR IntDefaultHandler ; let's read the Usage Fault Status Register LDR r7, =Usagefault LDRH r1, [r6, r7] TEQ r1, #0x200 IT NE LDRNE r9, =0xDEADDEAD ; r1 should have bit 9 set indicating ; a divide-by-zero has taken place done B done ALIGN END ``` ### 2024/04/23 啟動偵測錯誤的程式碼 ```asm= ; now turn on the usage fault exception LDR r7, =SYSHNDCTRL LDR r1, [r6, r7] LDR r1, #0x40000 STR r1, [r6, r7] ; 執行此行將會進行三個步驟 ; 1. Fetch according to PC ; 2. Update PC ; 3. decode ; 4. Execute ; 若將此行註解則不會偵測到 Divide by zero ``` 除予0的程式碼 ```asm= MOV r0, #0 MOV r1, #0x11111111 MOV r2, #0x22222222 MOV r3, #0x33333333 UDIV r4, r2, r1 UDIV r5, r3, r0 ; 執行此行將會執行三個步驟 ; 1. Stacking ; 2. Interrupt Table Lookup ; - 6x4=24 => Vector = 0x56 ; 3. LR (暫存) Exit B Exit ; PC = 0x4C + 4 = 0x50 -> 0x56 ``` 除予零時執行底下程式 如果跑到`IntDefaultHandler`分支的話,修改模式從 `Privileged thread mode` 改為 `privileged Handler mode` `pivileged handler mode` => 中斷服務程式 `privileged thread mode` => 被中斷服務程式 ```asm= IntDefaultHandler LDR r7, =Usagefault LDRH r1, [r6, r7] TST r1, #0x200 ; read bit 9 of the Usage Fault Status Register done B done ; 若改為 `BX LR` 將會回去出錯的地方 ``` 若放在 `thread mode` 的地方,則`privileged -> unprivileged` ```asm= IntDefaultHandler ; switch to user Thread mode ; 若放在thread mode MRS r8, CONTROL ORR r8, r8, #1 MSR CONTROL, r8 BX LR ; 回去被中斷的地方 ``` ![IMG_1042](https://hackmd.io/_uploads/Bk17n7r-A.jpg) ## HW2 (1) 加入以下兩字串宣稱divide_by_0 DCB “DIVIDE-BY-ZERO Event”, 0not_divide_by_0 DCB “No DIVIDE-BY-ZERO Event”, 0 查看usage fault status register後,如發生除以零錯誤,則將字串divide_by_0寫入從位址0x20000120開始的記憶體空間,反之,則將字串not_divide_by_0寫入從位址0x20000130開始的記憶體空間。(務必說明exception entry三步驟及exception exit兩步驟。) ```asm= Stack EQU 0x00000100 DivbyZ EQU 0xD14 SYSHNDCTRL EQU 0xD24 Usagefault EQU 0xD2A NVICBase EQU 0xE000E000 AREA STACK, NOINIT, READWRITE, ALIGN = 3 StackMem SPACE Stack PRESERVE8 AREA RESET, CODE, READONLY THUMB DCD StackMem + Stack DCD Reset_Handler DCD NmiISR DCD FaultISR DCD IntDefaultHandler DCD IntDefaultHandler ; MPU Fault Handler DCD IntDefaultHandler ; Usage Fault Handler EXPORT Reset_Handler ENTRY Reset_Handler ; 411446510 Tsai Ping Cen ;base: 0xE000E000 ;offset: 0xD14 ;bit: 4 LDR r6, =NVICBase LDR r7, =DivbyZ LDR r1, [r6, r7] ORR r1, #0x10 ;enable bit 4 STR r1, [r6, r7] ;turn on the usage fault exception LDR r7, =SYSHNDCTRL LDR r1, [r6, r7] ORR r1, #0x40000 STR r1, [r6, r7] ;try out a divide by 2 then a divide by 0! MOV r0, #0 MOV r1, #0x11111111 MOV r2, #0x22222222 MOV r3, #0x33333333 ;this divide works just fine UDIV r4, r2, r1 ;this divide takes an exception UDIV r5, r3, r0 Exit B Exit NmiISR B NmiISR FaultISR B FaultISR IntDefaultHandler LDR r7, =Usagefault LDRH r1, [r6, r7] TST r1, #0x200 BNE Happened BEQ NotHappened Happened LDR r3, =divide_by_0 LDR r1, =0x20000120 ; starting address of characters Loop LDRB r5, [r3], #1 STRB r5, [r1], #1 CMP r5, #0 BNE Loop ;MRS r8, CONTROL ;ORR r8, #1 ;MSR CONTROL, r8 ; 411446510 Tsai Ping Cen BX LR NotHappened LDR r3, =not_divide_by_0 LDR r1, =0x20000130 ; starting address of characters Loop2 LDRB r5, [r3], #1 STRB r5, [r1], #1 CMP r5, #0 BNE Loop2 MRS r8, CONTROL ORR r8, #1 MSR CONTROL, r8 BX LR ;r1 should have bits 9 set indicating ;a divide-by-zero has taken place done B done divide_by_0 DCB "DIVIDE-BY-ZERO Event", 0 not_divide_by_0 DCB "“No DIVIDE-BY-ZERO Event", 0 ALIGN END ``` (2) - (a) from privileged thread mode to unprivileged thread mode ```asm= Stack EQU 0x00000100 DivbyZ EQU 0xD14 SYSHNDCTRL EQU 0xD24 Usagefault EQU 0xD2A NVICBase EQU 0xE000E000 AREA STACK, NOINIT, READWRITE, ALIGN = 3 StackMem SPACE Stack PRESERVE8 AREA RESET, CODE, READONLY THUMB DCD StackMem + Stack DCD Reset_Handler DCD NmiISR DCD FaultISR DCD IntDefaultHandler DCD IntDefaultHandler ; MPU Fault Handler DCD IntDefaultHandler ; Usage Fault Handler EXPORT Reset_Handler ENTRY Reset_Handler ; 411446510 Tsai Ping Cen ;base: 0xE000E000 ;offset: 0xD14 ;bit: 4 LDR r6, =NVICBase LDR r7, =DivbyZ LDR r1, [r6, r7] ORR r1, #0x10 ;enable bit 4 STR r1, [r6, r7] ;turn on the usage fault exception LDR r7, =SYSHNDCTRL LDR r1, [r6, r7] ORR r1, #0x40000 STR r1, [r6, r7] ;try out a divide by 2 then a divide by 0! MOV r0, #0 MOV r1, #0x11111111 MOV r2, #0x22222222 MOV r3, #0x33333333 ; 411446510 Tsai Ping Cen ;this divide works just fine UDIV r4, r2, r1 ;this divide takes an exception UDIV r5, r3, r0 Exit B Exit NmiISR B NmiISR FaultISR B FaultISR IntDefaultHandler LDR r7, =Usagefault LDRH r1, [r6, r7] TST r1, #0x200 BNE Happened BEQ NotHappened Happened LDR r3, =divide_by_0 LDR r1, =0x20000120 ; starting address of characters Loop LDRB r5, [r3], #1 STRB r5, [r1], #1 CMP r5, #0 BNE Loop MRS r8, CONTROL ORR r8, #1 MSR CONTROL, r8 ; 411446510 Tsai Ping Cen BX LR NotHappened LDR r3, =not_divide_by_0 LDR r1, =0x20000130 ; starting address of characters Loop2 LDRB r5, [r3], #1 STRB r5, [r1], #1 CMP r5, #0 BNE Loop2 MRS r8, CONTROL ORR r8, #1 MSR CONTROL, r8 BX LR ;r1 should have bits 9 set indicating ;a divide-by-zero has taken place done B done divide_by_0 DCB "DIVIDE-BY-ZERO Event", 0 not_divide_by_0 DCB "“No DIVIDE-BY-ZERO Event", 0 ALIGN END ``` ### 第三部分 ![image](https://hackmd.io/_uploads/HkCquXNrA.png) ```asm= AREA STACK, CODE, READONLY ENTRY ; 411446510 Tsai Ping Cen LDR sp, =0x40000080 LDR r2, =0x70 BL set_priority_group_number BL read_priority_group_number LDR r4, =0xf LDR r5, =0x1f BL count done B done set_priority_group_number STMIA sp!, {r0, r1, lr} LDR r0, =0x400000c8 LDR r1, [r0] BIC r1, r1, #0x70 ORR r1, r1, r2 STR r1, [r0] LDMDB sp!, {r0, r1, pc} ; 411446510 Tsai Ping Cen read_priority_group_number STMIB sp!, {r0, r1, lr} LDR r0, =0x400000c8 LDR r3, [r0] LSR r3, r3, #4 AND r3, r3, #7 LDMDA sp!, {r0, r1, pc} count STMDA sp!, {r0, r1, lr} LDR r0, =0x400000c8 LDR r6, [r0] BIC r7, r6, r5 BIC r8, r6, r4 LDMIB sp!, {r0, r1, pc} ALIGN END ``` ## Quiz2 ![image](https://hackmd.io/_uploads/rkPKO9bHA.png) 2. Write a sequence of instructions to get the width of an interrupt priority register (address 0x40000486) and put the width in R2. - (a) using LSL with test pattern LSL. - (b) using LSR without test pattern LSR. > 第二小題(a)首先要設定 priority group 設定在 r2 這個暫存器中,接著使用 LSL(邏輯左移)和測試模式來獲取寬度。 > (a) 使用 LSL 和測試模式 1. 從地址 0x40000486 讀取寄存器的值。 2. 使用一個測試模式,逐位左移這個模式,並測試左移後的結果。 3. 計算左移的次數,直到測試結果為零,這樣就可以確定寄存器的寬度。 4. 將這個寬度存入 R2。 ```ASM= AREA pri, CODE, READONLY ENTRY LDR r0, =0x40000486 MOV r4, #0xFF ; test data STRB r4, [r0] LDRB r4, [r0] MOV r2, #0 MOV r3, #1 TEST CMP r2, #8 BEQ OUT TST r4, r3 BEQ OUT ADD r2, r2, #1 LSL r3, r3, #1 B TEST OUT done B done END ``` > (b) 使用 LSR 不用測試模式(意思是不要移動測試的值) 1. 從地址 0x40000486 讀取寄存器的值。 2. 使用一個測試模式,逐位右移要檢測bit width的值(0xFF),並測試右移後的結果。 3. 計算右移的次數,直到遇到1的時候跳出,這樣就可以確定寄存器的寬度。 4. 計算 8 - 遇到0的次數 = bit width ```asm= AREA pri, CODE, READONLY ENTRY LDR r0, =0x40000486 MOV r3, #0xFF ; 11111111 STRB r3, [r0] LDRB r3,[r0] MOV r1, #1 MOV r2, #0 MOV r4, #8 TEST CMP r2, #8 BEQ OUT TST r3, r1 BNE OUT ADD r2, r2, #1 LSR r3, r3, #1 B TEST OUT SUB r4, r2 MOV r2, r4 done B done END ``` ## 期末考可能會考的內容 - [ ] priority group number - [ ] 計算 IRQ 的 pre-emption priority及 subpriority LED ```asm= AREA LED, code, readonly ENTRY LDR r0, =0x40000000 SUB r7, r7, r7 MOV r6, #2 mainloop STR r6, [r0, #0x38] MOVT r7, 0xF0000 spin SUBS r7, r7, #1 BNE spin CMP r6, #8 LTE LT LSLLT r6, r6, #1 MOVGE r6, #2 B mainloop stop B stop END ```