; Copyright 1996 Acorn Computers Ltd ; ; Licensed under the Apache License, Version 2.0 (the "License"); ; you may not use this file except in compliance with the License. ; You may obtain a copy of the License at ; ; http://www.apache.org/licenses/LICENSE-2.0 ; ; Unless required by applicable law or agreed to in writing, software ; distributed under the License is distributed on an "AS IS" BASIS, ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ; See the License for the specific language governing permissions and ; limitations under the License. ; ; > Copro15ops ;macros for Coprocessor #15 operations (configuration), which run-time detect ;and cater for ARM 6,7,8,A (A=StrongARM). ;Routines detect which ARM directly by reading ARM ID register (avoids memory reads). ; 24-01-96 MJS Created ; 07-10-96 MJS Updated for proper ARM 810 support (not needed for RO 3.70) ; 10-03-97 MJS A few additions for chocolate flavour screen handling (possible ; Domain and FSR register use) in Phoebe OS ARM_config_cp CP 15 ;coprocessor number for configuration control ARM_ID_reg CN 0 ;processor ID ARM_control_reg CN 1 ;control ARM_tbase_reg CN 2 ;translation base (MMU) ARM_domain_reg CN 3 ;domain access control (MMU) ARM_FSR_reg CN 5 ;Fault status reg (MMU, read only on ARM 6/7) ARM_FAR_reg CN 6 ;Fault address reg (MMU, read only on ARM 6/7) ARM67_TLBflush_reg CN 5 ;TLB flush, ARMs 6 or 7 ARM67_TLBpurge_reg CN 6 ;TLB purge entry, ARMs 6 or 7 ARM67_cacheflush_reg CN 7 ;cache flush, ARMs 6 or 7 ARM8A_cache_reg CN 7 ;cache operations, ARMs 8 or StrongARM ARM8A_TLB_reg CN 8 ;TLB operations, ARMs 8 or StrongARM ARM8_cacheLD_reg CN 9 ;cache lock-down, ARM 8 ARM8_TLBLD_reg CN 10 ;TLB lock-down, ARM 8 ARM8_CTC_reg CN 15 ;Clock and test configuration ARMA_TCI_reg CN 15 ;Test,Clock and Idle control ;so that AASM will accept the general value for MCR CRm field C0 CN 0 C1 CN 1 C2 CN 2 C3 CN 3 C4 CN 4 C5 CN 5 C6 CN 6 C7 CN 7 C8 CN 8 C9 CN 9 C10 CN 10 C11 CN 11 C12 CN 12 C13 CN 13 C14 CN 14 C15 CN 15 ; ; ----------------- all ARMs --------------------------------------------- ; ;set MMU translation base MACRO ARM_MMU_transbase $reg,$cond MCR$cond ARM_config_cp,0,$reg,ARM_tbase_reg,C0,0 MEND ;set MMU domain access register MACRO ARM_MMU_domain $reg,$cond MCR$cond ARM_config_cp,0,$reg,ARM_domain_reg,C0,0 MEND ;read control register MACRO ARM_read_control $reg,$cond MRC$cond ARM_config_cp,0,$reg,ARM_control_reg,C0,0 MEND ;set control register MACRO ARM_write_control $reg,$cond MCR$cond ARM_config_cp,0,$reg,ARM_control_reg,C0,0 MEND ;read MMU fault status MACRO ARM_read_FSR $reg,$cond MRC$cond ARM_config_cp,0,$reg,ARM_FSR_reg,C0,0 MEND ;read MMU fault address MACRO ARM_read_FAR $reg,$cond MRC$cond ARM_config_cp,0,$reg,ARM_FAR_reg,C0,0 MEND ;read ID register to register $id ;bits 15:12 of returned ID will be 0,7,8,10 for ARM 6,7,8,A MACRO ARM_read_ID $id,$cond MRC$cond ARM_config_cp,0,$id,ARM_ID_reg,C0,0 MEND ;read ARM 'number' (6,7,8,&A currently) into $num MACRO ARM_number $num ARM_read_ID $num ANDS $num,$num,#&F000 MOVEQ $num,#&6000 ;catch and correct daft ARM 6 ID layout MOV $num,$num,LSR #12 MEND ;flush whole TLB (both data and instruction for StrongARM) ;trashes $temp MACRO ARM_flush_TLB $temp ARM_read_ID $temp AND $temp,$temp,#&F000 CMP $temp,#&8000 ;ARM 8? CMPNE $temp,#&A000 ;or StrongARM? MCRNE ARM_config_cp,0,R0,ARM67_TLBflush_reg,C0,0 MCREQ ARM_config_cp,0,R0,ARM8A_TLB_reg,C7,0 MEND ;flush whole cache (both data and instruction for StrongARM), ;without worrying about any cache cleaning ;trashes $temp MACRO ARM_flush_cache $temp ARM_read_ID $temp AND $temp,$temp,#&F000 CMP $temp,#&8000 ;ARM 8? CMPNE $temp,#&A000 ;or StrongARM? MCRNE ARM_config_cp,0,R0,ARM67_cacheflush_reg,C0,0 MCREQ ARM_config_cp,0,R0,ARM8A_cache_reg,C7,0 MEND ;flush whole TLB and cache (both data and instruction for StrongARM), ;without worrying about any cache cleaning ;trashes $temp MACRO ARM_flush_cacheandTLB $temp ARM_read_ID $temp AND $temp,$temp,#&F000 CMP $temp,#&8000 ;ARM 8? CMPNE $temp,#&A000 ;or StrongARM? MCRNE ARM_config_cp,0,R0,ARM67_cacheflush_reg,C0,0 MCRNE ARM_config_cp,0,R0,ARM67_TLBflush_reg,C0,0 MCREQ ARM_config_cp,0,R0,ARM8A_cache_reg,C7,0 MCREQ ARM_config_cp,0,R0,ARM8A_TLB_reg,C7,0 MEND ; ; -------------- ARM 6,7 only -------------------------------------------- ; ;flush cache MACRO ARM67_flush_cache $cond MCR$cond ARM_config_cp,0,R0,ARM67_cacheflush_reg,C0,0 MEND ;flush TLB MACRO ARM67_flush_TLB $cond MCR$cond ARM_config_cp,0,R0,ARM67_TLBflush_reg,C0,0 MEND ;flush TLB entry, virtual address in $reg MACRO ARM67_flush_TLBentry $reg,$cond MCR$cond ARM_config_cp,0,$reg,ARM67_TLBpurge_reg,C0,0 MEND ; ; -------------- ARM 810 only ---------------------------------------------- ; [ ARM810support ;turn off branch prediction ; - the forced mispredicted branch ensures that the predictor is trapped in ; this code segment when turned off ; - corrupts $temp and status flags ; MACRO ARM8_branchpredict_off $temp 01 ARM_read_control $temp BIC $temp,$temp,#&800 ;z bit (branch prediction) ARM_write_control $temp SEC ;set carry flag BCC %BT01 MEND ;turn on branch prediction MACRO ARM8_branchpredict_on $temp ARM_read_control $temp ORR $temp,$temp,#&800 ;z bit (branch prediction) ARM_write_control $temp MEND ;flush branch prediction, which is sufficient for an IMB (instruction memory ;barrier) on ARM 810, BUT... ; - intended for in line use only, where efficiency matters, or SWI call is ; awkward ; - general code should use SWI OS_SynchroniseCodeAreas to implement ; an IMB (instruction memory barrier) in future proof, ARM independent way ; - kernel code may use this without regard to which ARM running - ie. assumed ; harmless on other ARMs ; MACRO ARM8_branchpredict_flush SUB PC,PC,#4 ;flush, because PC is written by data op MEND ;clean cache entry ; - segment,index spec in $reg ; - bits 4..6 = segment (0..7) ; - bits 26..31 = index (0..63) ; - all other bits zero MACRO ARM8_clean_IDCentry $reg,$cond MCR$cond ARM_config_cp,0,$reg,ARM8A_cache_reg,C11,1 MEND ;flush cache entry - segment,index spec in $reg, as for ARM8_clean_IDCentry MACRO ARM8_flush_IDCentry $reg,$cond MCR$cond ARM_config_cp,0,$reg,ARM8A_cache_reg,C7,1 MEND ;clean and flush cache entry - segment,index spec in $reg, as for ARM8_clean_IDCentry ; ;if ARM810cleanflushbroken is TRUE, interrupts *must* be currently diabled (see below) ; MACRO ARM8_cleanflush_IDCentry $reg,$cond [ ARM810cleanflushbroken ARM8_clean_IDCentry $reg,$cond ARM8_flush_IDCentry $reg,$cond | MCR$cond ARM_config_cp,0,$reg,ARM8A_cache_reg,C15,1 ] MEND ;fully clean and flush cache (assumes no locked-down entries to preserve) ; ;if ARM810cleanflushbroken is TRUE, then we have to make sure interrupts are disabled during ;the sequence of 2 MCRs that make up ARM8_cleanflush_IDCentry, to avoid an interrupt hole. ;The hole occurs if an interrupt fills and dirties the particular cache entry after the clean ;but before the flush. We don't have this problem with StrongARM, because the entry is ;specified by virtual address, and RISC OS only cleans/flushes address space not currently ;involved in interrupts. ; [ ARM810cleanflushbroken MACRO ARM8_cleanflush_IDC $temp,$temp2 ;for simplicity, disable interrupts during entire operation - 26-bit assumed MOV $temp2,pc AND $temp2,$temp2,#I_bit EOR $temp2,$temp2,#I_bit ;temp := <current I> EOR <I set> TEQP $temp2,pc ;disable I MOV $temp,#0 ;initial segment and index 01 ARM8_cleanflush_IDCentry $temp ADD $temp,$temp,#1 :SHL: 26 ;next index CMP $temp,#1 :SHL: 26 ;last index done if index field wrapped to 0 BHS %BT01 ADD $temp,$temp,#1 :SHL: 4 ;next segment CMP $temp,#8 :SHL: 4 ;8 segments done? BLO %BT01 TEQP $temp2,pc ;restore I MEND | MACRO ARM8_cleanflush_IDC $temp MOV $temp,#0 ;initial segment and index 01 ARM8_cleanflush_IDCentry $temp ADD $temp,$temp,#1 :SHL: 26 ;next index CMP $temp,#1 :SHL: 26 ;last index done if index field wrapped to 0 BHS %BT01 ADD $temp,$temp,#1 :SHL: 4 ;next segment CMP $temp,#8 :SHL: 4 ;8 segments done? BLO %BT01 MEND ] ;flush whole TLB (actually, same as ARMA_flush_TLBs) MACRO ARM8_flush_TLB $cond MCR$cond ARM_config_cp,0,R0,ARM8A_TLB_reg,C7,0 MEND ;flush TLB entry, virtual address in $reg MACRO ARM8_flush_TLBentry $reg,$cond MCR$cond ARM_config_cp,0,$reg,ARM8A_TLB_reg,C7,1 MEND ;select external Refclk pin as fast clock (dynamic switching, asynchronous) MACRO ARM8_refclk_fclk $temp MRC ARM_config_cp,0,$temp,ARM8_CTC_reg,C0,0 BIC $temp, $temp,#&1 ;turn off dynamic bus switching (bit0) MCR ARM_config_cp,0,$temp,ARM8_CTC_reg,C0,0 BIC $temp,$temp,#&2 ;select asynchronous mode (default) (bit1) ORR $temp,$temp,#&4 ;select REFCLK as the FCLK source (bits3:2) BIC $temp,$temp,#&10 ;ensure L=0 when writing (PLL locked) (bit4) MCR ARM_config_cp,0,$temp,ARM8_CTC_reg,C0,0 NOP NOP NOP NOP ORR $temp,$temp,#&1 ;select dynamic clock switching (bit0) MCR ARM_config_cp,0,$temp,ARM8_CTC_reg,C0,0 MEND ;select PLL output as fast clock (dynamic switching, asynchronous) MACRO ARM8_pll_fclk $temp MRC ARM_config_cp,0,$temp,ARM8_CTC_reg,C0,0 BIC $temp,$temp,#&1 ;turn off dynamic bus switching (bit0) MCR ARM_config_cp,0,$temp,ARM8_CTC_reg,C0,0 BIC $temp,$temp,#&2 ;select asynchronous mode (default) (bit1) ORR $temp,$temp,#&C ;select PLLClkOut as the FCLK source (bits3:2) BIC $temp,$temp,#&10 ;ensure L=0 when writing (PLL locked) (bit4) MCR ARM_config_cp,0,$temp,ARM8_CTC_reg,C0,0 NOP NOP NOP NOP ORR $temp,$temp,#&1 ;select dynamic clock switching (bit0) MCR ARM_config_cp,0,$temp,ARM8_CTC_reg,C0,0 MEND ] ;ARM810support ; ; -------------- StrongARM only ------------------------------------------ ; ;clean whole data cache, using 16k private cleaner area at address in ;$cleanaddr ;trashes $cleanaddr,$temp1,$temp2 ; ;method: ;clean whole (16k) data cache by reading 16k private cleaner area in 8-word ;(one cache line) steps ; ;note: this routine should NOT be used as is without care - remember ; 1) interrupts should be off (to guarantee this clean is effective) ; 2) DC should be flushed afterwards (to guarantee next clean using ; private area is effective, ie. all private area flushed out now) ; see ARMA_fullycleanflush_DC for 'packaged routine' ; MACRO ARMA_clean_DC $cleanaddr,$temp1,$temp2 ADD $temp1,$cleanaddr,#16*1024 10 LDR $temp2,[$cleanaddr],#32 TEQ $temp1,$cleanaddr BNE %BT10 MEND ;flush whole data cache MACRO ARMA_flush_DC $cond MCR$cond ARM_config_cp,0,R0,ARM8A_cache_reg,C6,0 MEND ;clean data cache entry, virtual addr in $reg MACRO ARMA_clean_DCentry $reg,$cond MCR$cond ARM_config_cp,0,$reg,ARM8A_cache_reg,C10,1 MEND ;flush data cache entry, virtual addr in $reg MACRO ARMA_flush_DCentry $reg,$cond MCR$cond ARM_config_cp,0,$reg,ARM8A_cache_reg,C6,1 MEND ;clean and flush data cache entry, virtual addr in $reg MACRO ARMA_cleanflush_DCentry $reg,$cond MCR$cond ARM_config_cp,0,$reg,ARM8A_cache_reg,C14,1 MEND ;clean data cache for virtual address range from $lo (inclusive) to $hi (exclusive) ;corrupts $lo,$hi MACRO ARMA_clean_DCrange $lo,$hi BIC $lo,$lo,#31 ;align down to 8-word (1 cache line) boundary ADD $hi,$hi,#31 BIC $hi,$hi,#31 ;align up to 8-word boundary 01 ARMA_clean_DCentry $lo ;clean entry for virtual address $lo ADD $lo,$lo,#32 ;next line ARMA_clean_DCentry $lo ADD $lo,$lo,#32 ARMA_clean_DCentry $lo ADD $lo,$lo,#32 ARMA_clean_DCentry $lo ADD $lo,$lo,#32 CMP $lo,$hi BLO %BT01 MEND ;drain write buffer MACRO ARMA_drain_WB $cond MCR$cond ARM_config_cp,0,R0,ARM8A_cache_reg,C10,4 MEND ;flush whole instruction cache MACRO ARMA_flush_IC $WithoutNOPs,$cond MCR$cond ARM_config_cp,0,R0,ARM8A_cache_reg,C5,0 [ "$WithoutNOPs" = "" MOV R0,R0 ; 4 NOPS - up to 4 further instructions may come from IC before flush MOV R0,R0 MOV R0,R0 MOV R0,R0 ] MEND ;flush whole instruction cache and whole data cache MACRO ARMA_flush_ICandDC $WithoutNOPs,$cond MCR$cond ARM_config_cp,0,R0,ARM8A_cache_reg,C7,0 [ "$WithoutNOPs" = "" MOV R0,R0 ; 4 NOPS - up to 4 further instructions may come from IC before flush MOV R0,R0 MOV R0,R0 MOV R0,R0 ] MEND ;flush whole instruction TLB MACRO ARMA_flush_ITLB $cond MCR$cond ARM_config_cp,0,R0,ARM8A_TLB_reg,C5,0 MEND ;flush whole data TLB MACRO ARMA_flush_DTLB $cond MCR$cond ARM_config_cp,0,R0,ARM8A_TLB_reg,C6,0 MEND ;flush whole instruction and data TLBs MACRO ARMA_flush_TLBs $cond MCR$cond ARM_config_cp,0,R0,ARM8A_TLB_reg,C7,0 MEND ;flush data TLB entry, virtual address in $reg MACRO ARMA_flush_DTLBentry $reg,$cond MCR$cond ARM_config_cp,0,$reg,ARM8A_TLB_reg,C6,1 MEND ;fully clean and flush DC - see ARMA_clean_DC for more info ;assumed to be 26 bit mode MACRO ARMA_fullycleanflush_DC $cleanaddr,$temp1,$temp2,$temp3 MOV $temp3,pc ORR $temp1,$temp3,#I_bit TEQP $temp1,#0 ;disable IRQs ARMA_clean_DC $cleanaddr,$temp1,$temp2 ARMA_flush_DC TEQP $temp3,#0 ;restore IRQ state MEND ;enable core clock switching (fast core clock allowed) MACRO ARMA_fastcoreclock $cond MCR$cond ARM_config_cp,0,R0,ARMA_TCI_reg,C1,2 MEND ;disable core clock switching (core clock is memory clock) MACRO ARMA_slowcoreclock $cond MCR$cond ARM_config_cp,0,R0,ARMA_TCI_reg,C2,2 MEND END