@ vim:filetype=armasm: @ ARM940 initialization. @ Based on ogg940 code by Dzz. @ (c) Copyright 2007, Grazvydas "notaz" Ignotas .equ mmsp2_regs, (0xc0000000-0x02000000) @ assume we live @ 0x2000000 bank .equ shared_ctl, 0x00200000 @ this is where shared_ctl struncture is located @ exception table: .global code940 code940: b .b_reset @ reset b .b_undef @ undefined instructions b .b_swi @ software interrupt b .b_pabort @ prefetch abort b .b_dabort @ data abort b .b_reserved @ reserved b .b_irq @ IRQ b .b_fiq @ FIQ @ test .b_reset: mov r12, #0 b .Begin .b_undef: mov r12, #1 b .Begin .b_swi: mov r12, #2 b .Begin .b_pabort: mov r12, #3 b .Begin .b_dabort: mov r12, #4 b .Begin .b_reserved: mov r12, #5 b .Begin .b_irq: mov sp, #0x100000 @ reset stack sub sp, sp, #4 mov r0, #shared_ctl @ remember where we were when interrupt happened add r0, r0, #0x20 str lr, [r0] mov r0, #shared_ctl @ increment exception counter (for debug) add r0, r0, #(6*4) ldr r1, [r0] add r1, r1, #1 str r1, [r0] bl Main940 @ we should never get here b .b_reserved .b_fiq: mov r12, #7 b .Begin .Begin: mov sp, #0x100000 @ set the stack top (1M) sub sp, sp, #4 @ minus 4 @ set up memory region 0 -- the whole 4GB address space mov r0, #(0x1f<<1)|1 @ region data mcr p15, 0, r0, c6, c0, 0 @ opcode2 ~ data/instr mcr p15, 0, r0, c6, c0, 1 @ set up region 1 which is the first 2 megabytes. mov r0, #(0x14<<1)|1 @ region data mcr p15, 0, r0, c6, c1, 0 mcr p15, 0, r0, c6, c1, 1 @ set up region 2: 64k 0x200000-0x210000 mov r0, #(0x0f<<1)|1 orr r0, r0, #0x200000 mcr p15, 0, r0, c6, c2, 0 mcr p15, 0, r0, c6, c2, 1 @ set up region 3: 64k 0xbe000000-0xbe010000 (hw control registers) mov r0, #(0x0f<<1)|1 orr r0, r0, #mmsp2_regs mcr p15, 0, r0, c6, c3, 0 mcr p15, 0, r0, c6, c3, 1 @ region 4: 4K 0x00000000-0x00001000 (boot code protection region) mov r0, #(0x0b<<1)|1 mcr p15, 0, r0, c6, c4, 0 mcr p15, 0, r0, c6, c4, 1 @ region 5: 4M 0x00400000-0x00800000 (mp3 area part1) mov r0, #(0x15<<1)|1 orr r0, r0, #0x00400000 mcr p15, 0, r0, c6, c5, 0 mcr p15, 0, r0, c6, c5, 1 @ region 6: 8M 0x00800000-0x01000000 (mp3 area part2) mov r0, #(0x16<<1)|1 orr r0, r0, #0x00800000 mcr p15, 0, r0, c6, c6, 0 mcr p15, 0, r0, c6, c6, 1 @ set regions 1, 4, 5 and 6 to be cacheable (so the first 2M and mp3 area will be cacheable) mov r0, #(1<<1)|(1<<4)|(1<<5)|(1<<6) mcr p15, 0, r0, c2, c0, 0 mcr p15, 0, r0, c2, c0, 1 @ set region 1 to be bufferable too (only data) mov r0, #(1<<1) mcr p15, 0, r0, c3, c0, 0 @ set access protection @ data: [full, full, no, full, full, full, no access] for regions [6 5 4 3 2 1 0] mov r0, # (3<<12)|(3<<10)|(0<<8) orr r0, r0, #(3<<6)|(3<< 4)|(3<< 2)|(0<<0) mcr p15, 0, r0, c5, c0, 0 @ instructions: [no, no, full, no, no, full, no] mov r0, # (0<<12)|(0<<10)|(3<<8) orr r0, r0, #(0<<6)|(0<< 4)|(3<< 2)|(0<<0) mcr p15, 0, r0, c5, c0, 1 mrc p15, 0, r0, c1, c0, 0 @ fetch current control reg orr r0, r0, #1 @ 0x00000001: enable protection unit orr r0, r0, #4 @ 0x00000004: enable D cache orr r0, r0, #0x1000 @ 0x00001000: enable I cache @ bic r0, r0, #0xC0000000 @ orr r0, r0, #0x40000000 @ 0x40000000: synchronous, faster? orr r0, r0, #0xC0000000 @ 0xC0000000: async mcr p15, 0, r0, c1, c0, 0 @ set control reg @ flush (invalidate) the cache (just in case) mov r0, #0 mcr p15, 0, r0, c7, c6, 0 @ remember which exception vector we came from (increment counter for debug) mov r0, #shared_ctl add r0, r0, r12, lsl #2 ldr r1, [r0] add r1, r1, #1 str r1, [r0] @ remember last lr (for debug) mov r0, #shared_ctl add r0, r0, #0x20 str lr, [r0] @ ready to take first job-interrupt wait_for_irq: mrs r0, cpsr bic r0, r0, #0x80 msr cpsr_c, r0 @ enable interrupts mov r0, #0 mcr p15, 0, r0, c7, c0, 4 @ wait for IRQ @ mcr p15, 0, r0, c15, c8, 2 nop nop b .b_reserved @ next job getter .global wait_get_job @ int oldjob wait_get_job: mov r3, #mmsp2_regs orr r2, r3, #0x3B00 orr r2, r2, #0x0046 @ DUALPEND940 register ldrh r12,[r2] tst r0, r0 beq wgj_no_old sub r0, r0, #1 mov r1, #1 mov r1, r1, lsl r0 strh r1, [r2] @ clear finished job's pending bit bic r12,r12,r1 wgj_no_old: tst r12,r12 beq wgj_no_jobs mov r0, #0 wgj_loop: add r0, r0, #1 movs r12,r12,lsr #1 bxcs lr b wgj_loop wgj_no_jobs: mvn r0, #0 orr r2, r3, #0x4500 str r0, [r2] @ clear all pending interrupts in irq controller's SRCPND register orr r2, r2, #0x0010 str r0, [r2] @ clear all pending interrupts in irq controller's INTPND register b wait_for_irq .pool @ some asm utils are also defined here: .global spend_cycles @ c spend_cycles: mov r0, r0, lsr #2 @ 4 cycles/iteration sub r0, r0, #2 @ entry/exit/init .sc_loop: subs r0, r0, #1 bpl .sc_loop bx lr @ clean-flush function from ARM940T technical reference manual .global dcache_clean_flush dcache_clean_flush: mov r1, #0 @ init line counter ccf_outer_loop: mov r0, #0 @ segment counter ccf_inner_loop: orr r2, r1, r0 @ make segment and line address mcr p15, 0, r2, c7, c14, 2 @ clean and flush that line add r0, r0, #0x10 @ incremet segment counter cmp r0, #0x40 @ complete all 4 segments? bne ccf_inner_loop add r1, r1, #0x04000000 @ increment line counter cmp r1, #0 @ complete all lines? bne ccf_outer_loop bx lr @ clean-only version .global dcache_clean dcache_clean: mov r1, #0 @ init line counter cf_outer_loop: mov r0, #0 @ segment counter cf_inner_loop: orr r2, r1, r0 @ make segment and line address mcr p15, 0, r2, c7, c10, 2 @ clean that line add r0, r0, #0x10 @ incremet segment counter cmp r0, #0x40 @ complete all 4 segments? bne cf_inner_loop add r1, r1, #0x04000000 @ increment line counter cmp r1, #0 @ complete all lines? bne cf_outer_loop bx lr @ drain write buffer .global drain_wb drain_wb: mov r0, #0 mcr p15, 0, r0, c7, c10, 4 bx lr .global set_if_not_changed @ int *val, int oldval, int newval set_if_not_changed: swp r3, r2, [r0] cmp r1, r3 bxeq lr strne r3, [r0] @ restore value which was changed there by other core bx lr @ pad the protected region. .rept 1024 .long 0 .endr