mirror of
				https://github.com/RaySollium99/picodrive.git
				synced 2025-10-27 21:48:50 +01:00 
			
		
		
		
	 e362c57310
			
		
	
	
		e362c57310
		
	
	
	
	
		
			
			git-svn-id: file:///home/notaz/opt/svn/PicoDrive@129 be3aeb3a-fb24-0410-a615-afba39da0efa
		
			
				
	
	
		
			282 lines
		
	
	
	
		
			7.7 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			282 lines
		
	
	
	
		
			7.7 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
| @ 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
 | |
| 
 |