; *********************************************************************** ; * * ; * Initialisation Routines for the Timer Interrupts Program * ; * * ; *********************************************************************** ; Author: John Zaitseff ; Date: 18th June, 2003 ; Version: 1.4 ; This file contains the initialisation routines for the Timer Interrupts ; program (timer-irq.elf), as required for ELEC2041 Experiment 5 Task 7. ; In particular, it contains the ARM processor exception vector table and ; the boot code that (among other things) enables various hardware ; interrupts and sets the processor into User mode. .global _start ; "_start" is where the code starts running .extern main ; "main" is defined in another file .extern irq_handler ; "irq_handler" is also defined elsewhere .global irq_count ; Allow "irq_count" to be accessed globally .include "header-v3.s" ; Include various definitions ; ----------------------------------------------------------------------- ; The following code will be placed into the ".zeropage" section, NOT into ; the ".text" section. The GNU Linker will place the ".zeropage" section ; at address 0x0. .section .zeropage, "awx" ; For code located at address 0x00000000 _start: ; Start of the entire program ; ARM processor exception vector table ; The ARM processor exception vector table must appear at address 0x0. ; This particular table only handles the Reset and Interrupt exceptions; ; all other exceptions will NOT be handled correctly at all. ev00: b init ; Reset exception ev04: nop ; Undefined Instruction exception ev08: nop ; Software Interrupt exception ev0C: nop ; Prefetch Abort exception ev10: nop ; Data Abort exception ev14: nop ; (Not used) ev18: b irq_handler ; Interrupt exception ev1C: nop ; Fast Interrupt exception ; ----------------------------------------------------------------------- ; The following code will be placed into the ".ospage" section, NOT into ; the ".text" section. The GNU Linker will place the ".ospage" section at ; address 0x1000. .section .ospage, "awx" ; For "operating system" code ; Initialisation routine ; This routine is run at processor reset. It sets up the stacks for ; different processor modes, initialises the hardware interrupts ; corresponding to the counter/timer peripheral, then changes the ARM ; processor into User mode with the Fast and normal interrupts enabled. init: ; This code initially runs in Supervisor mode ; Set up the stack pointers ldr sp, =svc_stack_top ; Initialise SP_svc mrs r0, cpsr ; Get current value of CPSR into R0 bic r0, r0, #ARM_PSR_mode_mask ; Mask out the bottom 5 bits orr r1, r0, #ARM_PSR_mode_irq ; R1 = CPSR + IRQ mode msr cpsr_c, r1 ; Switch into IRQ mode ldr sp, =irq_stack_top ; and set SP_irq appropriately orr r1, r0, #ARM_PSR_mode_fiq ; R1 = CPSR + FIQ mode msr cpsr_c, r1 ; Switch into FIQ mode ldr sp, =fiq_stack_top ; and set SP_fiq appropriately orr r1, r0, #ARM_PSR_mode_sys ; R1 = CPSR + System mode msr cpsr_c, r1 ; Switch into System mode ldr sp, =usr_stack_top ; and set SP appropriately ; Note that User and System modes ; share the same registers ; Initialise the "irq_count" global variable to zero. This ; variable is expected to be used as a software-based counter in ; the interrupt handler in the file timer-irq.s. mov r1, #0 ; Set "irq_count" to zero every time this ldr r0,=irq_count ; initialisation code is run (at processor str r1, [r0] ; reset). "irq_count" is defined below. ; Set up the DSLMU Microcontroller Board hardware ldr r0, =iobase ; R0 = base of Microcontroller I/O space mov r1, #irq_timer ; R1 = enable IRQs mask for timer strb r1, [r0, #irq_enable] ; Actually enable the IRQs ; Switch to User mode with interrupts enabled mrs ip, cpsr ; Get current value of CPSR into IP (R12) bic ip, ip, #(ARM_PSR_i | ARM_PSR_f | ARM_PSR_mode_mask) ; Mask out bottom 5 bits. Also clear I and F ; bits; this enables the interrupts orr ip, ip, #ARM_PSR_mode_usr ; Set User mode msr cpsr, ip ; Actually make the changes to CPSR b main ; Now in User mode; jump to the main program ; ----------------------------------------------------------------------- ; Global variables .data ; Use the data section for global variables .align ; Make sure the variables are word-aligned irq_count: .word 0 ; Software-based counter that can be used by ; the interrupt service routine in timer-irq.s ; This counter is automatically set to zero ; in the initialisation code above. ; ----------------------------------------------------------------------- ; Stack space for the different processor modes .bss ; Use uninitialised memory for the stack .align ; Make sure the stack is word-aligned ; Technically, the stack should appear in its own section called ".stack". ; Doing it this way (using the ".bss" section), however, is easier. The ; ".bss" section is similar to the ".data" section, except that no values ; are actually stored in the final executable file. For that reason, the ; only assembler directives that make sense in the ".bss" section are ; ".align" and ".skip". If you do not understand this paragraph, ignore ; it. .skip 1024 ; Allow a 1KB stack for the User/System modes usr_stack_top: ; "usr_stack_top" points to top of this stack .skip 512 ; Allow 512 bytes stack for IRQ mode irq_stack_top: ; "irq_stack_top" points to top of this stack .skip 512 ; Allow 512 bytes stack for FIQ mode fiq_stack_top: ; "fiq_stack_top" points to top of this stack .skip 512 ; Allow 512 bytes stack for Supervisor mode svc_stack_top: ; "svc_stack_top" points to top of this stack .end