; ; Copyright (c) 2012, RISC OS Open Ltd ; Copyright (c) 2012, Adrian Lees ; All rights reserved. ; ; Redistribution and use in source and binary forms, with or without ; modification, are permitted provided that the following conditions are met: ; * Redistributions of source code must retain the above copyright ; notice, this list of conditions and the following disclaimer. ; * Redistributions in binary form must reproduce the above copyright ; notice, this list of conditions and the following disclaimer in the ; documentation and/or other materials provided with the distribution. ; * Neither the name of RISC OS Open Ltd nor the names of its contributors ; may be used to endorse or promote products derived from this software ; without specific prior written permission. ; ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ; ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ; POSSIBILITY OF SUCH DAMAGE. ; ; With many thanks to Broadcom Europe Ltd for releasing the source code to ; its Linux drivers, thus making this port possible. ; AREA |!!!ROMStart|, CODE, READONLY, PIC GET Hdr:ListOpts GET Hdr:Macros GET Hdr:System GET Hdr:Machine. GET Hdr:HALSize. GET Hdr:HALEntries GET hdr.BCM2835 GET hdr.StaticWS GET hdr.CastleMacros IMPORT Interrupt_Init IMPORT HAL_IRQEnable IMPORT HAL_IRQDisable IMPORT HAL_IRQClear IMPORT HAL_IRQSource IMPORT HAL_IRQStatus IMPORT HAL_FIQEnable IMPORT HAL_FIQDisable IMPORT HAL_FIQDisableAll IMPORT HAL_FIQClear IMPORT HAL_FIQSource IMPORT HAL_FIQStatus IMPORT HAL_IRQMax IMPORT Timer_Init IMPORT HAL_Timers IMPORT HAL_TimerDevice IMPORT HAL_TimerGranularity IMPORT HAL_TimerMaxPeriod IMPORT HAL_TimerSetPeriod IMPORT HAL_TimerPeriod IMPORT HAL_TimerReadCountdown IMPORT HAL_TimerIRQClear IMPORT HAL_CounterRate IMPORT HAL_CounterPeriod IMPORT HAL_CounterRead IMPORT HAL_CounterDelay IMPORT IIC_Init IMPORT HAL_IICBuses IMPORT HAL_IICType IMPORT HAL_IICTransfer IMPORT HAL_IICMonitorTransfer IMPORT HAL_NVMemoryType IMPORT HAL_NVMemorySize IMPORT HAL_NVMemoryPageSize IMPORT HAL_NVMemoryProtectedSize IMPORT HAL_NVMemoryProtection IMPORT HAL_NVMemoryRead IMPORT HAL_NVMemoryWrite IMPORT HAL_UARTPorts IMPORT HAL_UARTStartUp IMPORT HAL_UARTShutdown IMPORT HAL_UARTFeatures IMPORT HAL_UARTReceiveByte IMPORT HAL_UARTTransmitByte IMPORT HAL_UARTLineStatus IMPORT HAL_UARTInterruptEnable IMPORT HAL_UARTRate IMPORT HAL_UARTFormat IMPORT HAL_UARTFIFOSize IMPORT HAL_UARTFIFOClear IMPORT HAL_UARTFIFOEnable IMPORT HAL_UARTFIFOThreshold IMPORT HAL_UARTInterruptID IMPORT HAL_UARTBreak IMPORT HAL_UARTModemControl IMPORT HAL_UARTModemStatus IMPORT HAL_UARTDevice IMPORT HAL_DebugRX IMPORT HAL_DebugTX IMPORT HAL_ATAControllerInfo IMPORT HAL_KbdScanSetup IMPORT HAL_KbdScan IMPORT HAL_KbdScanFinish IMPORT HAL_KbdScanInterrupt IMPORT HAL_USBControllerInfo IMPORT SDIO_InitDevices IMPORT DMA_InitDevices IMPORT GPIO_InitDevices IMPORT VCHIQ_InitDevices IMPORT Video_InitDevices IMPORT RTC_InitDevices IMPORT HAL_SendHostMessage IMPORT HAL_QueryPlatform EXPORT HAL_Base IMPORT RamAd IMPORT SerNo IMPORT Displ HAL_Base [ HALDebug EXPORT HAL_DebugHexTX4 EXPORT HAL_DebugTXStrInline ] EXPORT reset EXPORT workspace ENTRY reset B start undef B undefined_instr swi B swi_instr pabort B prefetch_abort dabort B data_abort irq B interrupt fiq B fast_interrupt ALIGN 256 atags ; list of 'atags' structures constructed here by the loader code ; running on VideoCore, describing ; - available memory ; - command line parameters, including framebuffer parameters ALIGN 4096 end_stack workspace % sizeof_workspace LTORG ; exception handlers just for use during HAL init, ; in case something goes wrong interrupt B . fast_interrupt B . swi_instr B . prefetch_abort B . data_abort B . undefined_instr B . start MSR CPSR_c,#F32_bit+I32_bit+SVC32_mode ADRL v1, HAL_Base + OSROM_HALSize ; v1 -> RISC OS image LDR v8, [v1, #OSHdr_Entries] ADD v8, v8, v1 ; v8 -> RISC OS entry table ; Ensure CPU is 'set up' (typically enables ICache) MOV a1, #0 CallOSM OS_InitARM ADRL sb,workspace ADRL R13,end_stack ADRL r4, reset STR r4, MMUOffBaseAddr LDR r4,=IO_Base STR r4,PeriBase [ HALDebug mov a1, #1 bl HAL_UARTStartUp ; start early for debug use bl HAL_DebugTXStrInline DCB "HalStartup",10,0 ALIGN ] ; Enable USB power ; Note - may need changing to enable other devices in future ; Looks like we need to write the logical OR of all the devices we want enabled MOV r1, #0 LDR r0,=(16:SHL:MB_Pwr_USB)+MB_Chan_Pwr BL HAL_SendHostMessage ; query the platform and set up a frame buffer. BL HAL_QueryPlatform LDR r3, FB_Base mov r0,r3 bl HAL_DebugHexTX4 [ HALDebug bl HAL_DebugTXStrInline DCB "HalStartup2",10,0 ALIGN ] ADRL a3, workspace ADRL lr,RamAd LDR lr, [lr] ADD a3, a3, lr LDMIA a3, {v3, v4} ; v3=base, v4=size STR v3, ARM_Base STR v4, ARM_Size [ HALDebug ADRL a1, reset BL HAL_DebugHexTX4 MOV a1, v3 BL HAL_DebugHexTX4 MOV a1, v4 BL HAL_DebugHexTX4 BL HAL_DebugTXStrInline DCB "ROM start, RAM start, RAM size", 10, 0 ALIGN ] relocate_code ; Relocate ROM to high end of RAM ADRL v1, HAL_Base + OSROM_HALSize LDR v2, [v1, #OSHdr_ImageSize] LDR lr, [v1, #OSHdr_Flags] TST lr, #OSHdrFlag_SupportsCompression LDRNE lr, [v1, #OSHdr_CompressedSize] MOVEQ lr, v2 SUB v1, v1, #OSROM_HALSize ; Start of HAL ADD v2, v2, #OSROM_HALSize ; Size of HAL+OS ADD lr, lr, #OSROM_HALSize ; Size of compressed HAL+OS ADD v5, v1, lr ; End of OS ADD v7, v3, v4 ; End of RAM SUB ip, v7, v2 ; New start address of HAL CMP v1, ip BEQ relocate_10 ; No copy needed CMP v1, v7 BHI relocate_20 ; We're in some ROM above RAM. OK to continue with copy. CMP v5, ip BLS relocate_20 ; We're in some ROM/RAM below our copy destination. OK to continue with copy. ; Else we currently overlap the area we want to copy ourselves into. SUB ip, v1, lr ; Copy the HAL+OS to just before itself. relocate_20 MOV a1, ip ; Copy dest MOV a2, v1 ; Copy source MOV a3, lr ; Copy length relocate_30 LDR a4, [a2], #4 SUBS a3, a3, #4 STR a4, [a1], #4 BGT relocate_30 MOV a1, #0 MCR p15, 0, a1, c7, c10, 4 ; drain write buffer MCR p15, 0, a1, c7, c5, 0 ; invalidate I-Cache ; Jump to our new copy ADR a1, relocate_code SUB a2, ip, v1 ADD a1, a1, a2 ; relocate our branch target ADD v8, v8, a2 ; Update OS entry table ptr MOV pc, a1 relocate_10 ; Copy completed, reset stack & workspace ptrs ADD sp, v3, #4096 ; Use RAM for stack instead of bits of ROM ADRL sb, workspace ; However workspace is still in ROM :( [ HALDebug BL HAL_DebugTXStrInline DCB "ROM relocated", 10, 0 ALIGN ] ; Clear RAM ; v3 is start of RAM ; ip is end of RAM/start of ROM ; Note this code will clear the stack, but there shouldn't be anything on it yet anyway MOV a1, ip MOV a2, #0 MOV a3, #0 MOV a4, #0 MOV v1, #0 MOV v4, #0 MOV v5, #0 MOV v7, #0 MOV lr, #0 clear_lp1 STMDB a1!,{a2-a4,v1,v4,v5,v7,lr} STMDB a1!,{a2-a4,v1,v4,v5,v7,lr} STMDB a1!,{a2-a4,v1,v4,v5,v7,lr} STMDB a1!,{a2-a4,v1,v4,v5,v7,lr} CMP a1, v3 BHI clear_lp1 mov a2, v3 MOV a3, ip [ HALDebug bl HAL_DebugTXStrInline DCB "HalStartup3 .. rst rend",10,0 ALIGN mov a1,a2 bl HAL_DebugHexTX4 mov a1,a3 bl HAL_DebugHexTX4 ] MVN a4, #0 MOV a1, #0 STR a1, [sp, #-4]! ;reference handle (NULL for first call) CallOSM OS_AddRAM STR a1,[sp] ;ref for next call ; OS kernel informed of RAM areas LDR a4,[sp],#4 ;!!! ref from last AddRAM MOV a1, #OSStartFlag_RAMCleared ADRL a2, HAL_Base + OSROM_HALSize ; a2 -> RISC OS image ADR a3, HALdescriptor CallOSM OS_Start ; OS_Start doesn't return....invokes HAL_Init after MMU activation [ HALDebug sign_on = "BCM2835 Raspberry Pi",13,10,0 start_os = "Starting OS",13,10,0 ALIGN ] HALdescriptor DATA DCD HALFlag_NCNBWorkspace DCD HAL_Base - HALdescriptor DCD OSROM_HALSize DCD HAL_EntryTable - HALdescriptor DCD HAL_Entries DCD sizeof_workspace HAL_EntryTable DATA HALEntry HAL_Init HALEntry HAL_IRQEnable HALEntry HAL_IRQDisable HALEntry HAL_IRQClear HALEntry HAL_IRQSource HALEntry HAL_IRQStatus HALEntry HAL_FIQEnable HALEntry HAL_FIQDisable HALEntry HAL_FIQDisableAll HALEntry HAL_FIQClear HALEntry HAL_FIQSource HALEntry HAL_FIQStatus HALEntry HAL_Timers HALEntry HAL_TimerDevice HALEntry HAL_TimerGranularity HALEntry HAL_TimerMaxPeriod HALEntry HAL_TimerSetPeriod HALEntry HAL_TimerPeriod HALEntry HAL_TimerReadCountdown HALEntry HAL_CounterRate HALEntry HAL_CounterPeriod HALEntry HAL_CounterRead HALEntry HAL_CounterDelay HALEntry HAL_NVMemoryType HALEntry HAL_NVMemorySize HALEntry HAL_NVMemoryPageSize HALEntry HAL_NVMemoryProtectedSize HALEntry HAL_NVMemoryProtection NullEntry ; HAL_NVMemoryIICAddress HALEntry HAL_NVMemoryRead HALEntry HAL_NVMemoryWrite HALEntry HAL_IICBuses HALEntry HAL_IICType NullEntry ; HAL_IICSetLines NullEntry ; HAL_IICReadLines NullEntry ; HAL_IICDevice HALEntry HAL_IICTransfer HALEntry HAL_IICMonitorTransfer NullEntry ; HAL_VideoFlybackDevice NullEntry ; HAL_VideoSetMode NullEntry ; HAL_VideoWritePaletteEntry NullEntry ; HAL_VideoWritePaletteEntries NullEntry ; HAL_VideoReadPaletteEntry NullEntry ; HAL_VideoSetInterlace NullEntry ; HAL_VideoSetBlank NullEntry ; HAL_VideoSetPowerSave NullEntry ; HAL_VideoUpdatePointer NullEntry ; HAL_VideoSetDAG NullEntry ; HAL_VideoVetMode NullEntry ; HAL_VideoPixelFormats NullEntry ; HAL_VideoFeatures NullEntry ; HAL_VideoBufferAlignment NullEntry ; HAL_VideoOutputFormat NullEntry ; HALEntry HAL_MatrixColumns NullEntry ; HALEntry HAL_MatrixScan NullEntry ; HALEntry HAL_TouchscreenType NullEntry ; HALEntry HAL_TouchscreenRead NullEntry ; HALEntry HAL_TouchscreenMode NullEntry ; HALEntry HAL_TouchscreenMeasure HALEntry HAL_MachineID HALEntry HAL_ControllerAddress HALEntry HAL_HardwareInfo HALEntry HAL_SuperIOInfo HALEntry HAL_PlatformInfo NullEntry ; HALEntry HAL_CleanerSpace HALEntry HAL_UARTPorts HALEntry HAL_UARTStartUp HALEntry HAL_UARTShutdown HALEntry HAL_UARTFeatures HALEntry HAL_UARTReceiveByte HALEntry HAL_UARTTransmitByte HALEntry HAL_UARTLineStatus HALEntry HAL_UARTInterruptEnable HALEntry HAL_UARTRate HALEntry HAL_UARTFormat HALEntry HAL_UARTFIFOSize HALEntry HAL_UARTFIFOClear HALEntry HAL_UARTFIFOEnable HALEntry HAL_UARTFIFOThreshold HALEntry HAL_UARTInterruptID HALEntry HAL_UARTBreak HALEntry HAL_UARTModemControl HALEntry HAL_UARTModemStatus HALEntry HAL_UARTDevice HALEntry HAL_Reset HALEntry HAL_DebugRX HALEntry HAL_DebugTX NullEntry ; HAL_PCIFeatures NullEntry ; HAL_PCIReadConfigByte NullEntry ; HAL_PCIReadConfigHalfword NullEntry ; HAL_PCIReadConfigWord NullEntry ; HAL_PCIWriteConfigByte NullEntry ; HAL_PCIWriteConfigHalfword NullEntry ; HAL_PCIWriteConfigWord NullEntry ; HAL_PCISpecialCycle NullEntry ; HAL_PCISlotTable NullEntry ; HAL_PCIAddresses HALEntry HAL_ATAControllerInfo NullEntry ; HAL_ATASetModes NullEntry ; HAL_ATACableID HALEntry HAL_InitDevices HALEntry HAL_KbdScanSetup HALEntry HAL_KbdScan HALEntry HAL_KbdScanFinish HALEntry HAL_KbdScanInterrupt HALEntry HAL_PhysInfo HALEntry HAL_USBControllerInfo HALEntry HAL_IRQMax NullEntry ; HALEntry HAL_VideoRender NullEntry ; HAL_USBPortPower NullEntry ; HAL_USBPortStatus NullEntry ; HAL_USBPortDevice NullEntry ; HALEntry HAL_VideoIICOp HALEntry HAL_TimerIRQClear NullEntry ; HAL_TimerIRQStatus HALEntry HAL_ExtMachineID NullEntry ; HALEntry HAL_VideoFramestoreAddress NullEntry ; HALEntry HAL_UARTDefault NullEntry ; HALEntry HAL_VideoStartupMode HAL_Entries * (.-HAL_EntryTable)/4 ;-------------------------------------------------------------------------------------- ; HAL Initialisation callback from OS kernel ;-------------------------------------------------------------------------------------- HAL_Init STMFD R13!,{R8,R14} MOV R8,a2 BL SetUpOSEntries MOV a1, #0 ; map in the IO space LDR a2, =IO_Base LDR a3, =IO_Size CallOS OS_MapInIO STR a1, PeriBase MOV a1,#0 ; start the uart ..we use it for debug BL HAL_UARTStartUp ; restart to capture logical io address bl HAL_DebugTXStrInline DCB "HalStart from OS",10,0 ALIGN MOV a4, sb ; confirm the caching mode in use in GPU ADRL sb, workspace ; where we remembered it is LDR a3, FB_Size LDR a2, FB_Base ; effectively part of the ROM image LDR a1, FB_CacheMode ; GPU cache mode mov sb, a4 STR a3, FB_Size ; put in our workspace STR a2, FB_Base ; for HAL_FramestoreAddress use STR a1, FB_CacheMode ADRL sb, workspace ; where we remembered it is LDR a3, VC_Size ; VC Start LDR a2, VC_Base ; VC_Size LDR a1, ARM_Base LDR ip, ARM_Size mov sb, a4 STR a3, VC_Size ; VC Start STR a2, VC_Base ; VC_Size STR a1, ARM_Base STR ip, ARM_Size ADRL sb, workspace ; where we remembered it is LDR a3, Board_Model LDR a2, Board_Revision LDR a1, ARM_DMAChannels mov sb, a4 STR a3, Board_Model STR a2, Board_Revision STR a1, ARM_DMAChannels MOV a1, #0 ; map in the whole of the VC memory as ; IO to avoid subsequent logical ; address space fragmentation LDR a2, VC_Base LDR a3, VC_Size mov r0,a2 bl HAL_DebugHexTX4 mov r0,a3 bl HAL_DebugHexTX4 CallOS OS_MapInIO STR a1, VC_Logical bl HAL_DebugHexTX4 ; Get the physical address of NCNB workspace ; R8 -> start of NCNB workspace STR R8, NCNBAddr MOV a1,R8 CallOS OS_LogToPhys LDR a3, FB_CacheMode ORR a1, a1, a3 STR a1, NCNBPhysAddr BL Interrupt_Init ; initialise our interrupts BL Timer_Init BL IIC_Init [ HALDebug STR v1,[sp,#-4]! ADRL v1,hal_init txloop txbusylp MOV a1,#0 BL HAL_UARTLineStatus TST a1,#&20 BEQ txbusylp MOV a1,#0 LDRB a2,[v1],#1 BL HAL_UARTTransmitByte LDRB a1,[v1] TEQ a1,#0 BNE txloop LDR v1,[sp],#4 LDMFD R13!,{R8,PC} uart_started = " UART started",13,10,0 hal_init = " HAL Init completed",13,10,0 ALIGN | LDMFD R13!,{R8,PC} ] ; Initialise and relocate the entry table. SetUpOSEntries ROUT STR a1, OSheader LDR a2, [a1, #OSHdr_NumEntries] CMP a2, #HighestOSEntry+1 MOVHI a2, #HighestOSEntry+1 ADRL a3, OSentries LDR a4, [a1, #OSHdr_Entries] ADD a4, a4, a1 05 SUBS a2, a2, #1 LDR ip, [a4, a2, LSL #2] ADD ip, ip, a4 STR ip, [a3, a2, LSL #2] BNE %BT05 MOV pc, lr HAL_ControllerAddress MOV a1, #0 MOV pc, lr HAL_HardwareInfo LDR ip, =&FFFFFF00 STR ip, [a1] MOV ip, #0 STR ip, [a2] LDR ip, =&00FFFF00 STR ip, [a3] MOV pc, lr HAL_PlatformInfo MOV ip, #2_10000 ; no podules,no PCI cards,no multi CPU,no soft off,and soft ROM STR ip, [a2] MOV ip, #2_11111 ; mask of valid bits STR ip, [a3] MOV pc, lr HAL_SuperIOInfo MOV ip, #0 STR ip, [a1] STR ip, [a2] MOV pc, lr HAL_MachineID ; ADR ip, MachAD LDR ip, MachAD LDMIA ip, {a1, a2} mov pc, lr MachAD DCD :INDEX:workspace + :INDEX:MachineID HAL_ExtMachineID MOVS ip, a1 MOV a1, #0 MOV pc, lr HAL_Reset MRS a1, CPSR ORR a1, a1, #I32_bit+F32_bit ; paranoia, don't allow reset to be interrupted MSR CPSR_c, a1 LDR a1, PeriBase ADD a1, a1, #PM_Base DoMemBarrier a3 LDR a2, [a1, #PM_Rstc] MOV a3, #PM_Password BIC a2, a2, #PM_Rst_WCfgSet ORR a2, a2, #PM_Rst_WCfg_FullRst ORR a2, a2, a3 ADD a3, a3, #10 STR a3, [a1, #PM_Wdog] STR a2, [a1, #PM_Rstc] B . HAL_PhysInfo ROUT TEQ a1, #PhysInfo_GetTableSize MOVEQ a1, #524288 ; Two pages in each byte, so (2^32)/(4096*2) STREQ a1, [a2] MVNEQ a1, #0 MOVEQ pc, lr TEQ a1, #PhysInfo_HardROM MOVEQ a1, #0 ; No hard ROM MOVEQ a2, #0 STMEQIA a3, {a1-a2} MVNEQ a1, #0 MOVEQ pc, lr TEQ a1, #PhysInfo_WriteTable MOVNE a1, #0 MOVNE pc, lr Push "v1-v5,lr" LDR v1, ARM_Base LDR v2, ARM_Size ADD v2, v1, v2 STMIA a3, {v1-v2} ; All RAM the OS knows about will be here ; Majority of table is unused, so prefill it LDR v3, =&88888888 ; Unused regions (or RAM) MOV a1, v3 MOV a3, v3 MOV a4, v3 ADD v4, a2, #524288 10 STMIA a2!, {a1,a3,a4,v3} CMP a2, v4 BLO %BT10 ; Fill in IO region SUB a2, a2, #524288-(IO_Base>>13) ORR a1, a1, a1, LSR #1 ; Pattern for IO regions ORR a3, a3, a3, LSR #1 ORR a4, a4, a4, LSR #1 ORR v3, v3, v3, LSR #1 ADD v5, a2, #IO_Size>>13 20 STMIA a2!, {a1,a3,a4,v3} CMP a2, v5 BLO %BT20 ; VC memory is effectively IO, so fill it in as such SUB a2, v4, #524288 LDR v1, VC_Base LDR v2, VC_Size ADD a2, a2, v1, LSR #13 ADD v5, a2, v2, LSR #13 30 STMIA a2!, {a1,a3,a4,v3} CMP a2, v5 BLO %BT30 MVN a1, #0 Pull "v1-v5,pc" HAL_Null MOV pc, lr HAL_InitDevices STR lr, [sp, #-4]! BL Video_InitDevices ; Must be before DMA_InitDevices BL SDIO_InitDevices BL DMA_InitDevices BL GPIO_InitDevices BL VCHIQ_InitDevices BL RTC_InitDevices LDR pc, [sp], #4 [ HALDebug ; a2-> null terminated string HAL_DebugTXS ROUT STMFD sp!, {a1,lr} SUB a2,a2,#1 1 LDRB a1, [a2,#1]! TEQ a1, #&0 LDMEQFD sp!, {a2,pc} BL HAL_DebugTX B %BT1 HAL_DebugHexTX stmfd r13!, {r0-r3,lr} b jbdt1 HAL_DebugHexTX2 stmfd r13!, {r0-r3,lr} b jbdt2 HAL_DebugHexTX4 stmfd r13!, {r0-r3,lr} mov r0,r0,ror #24 ; hi byte bl jbdtxh mov r0,r0,ror #24 bl jbdtxh jbdt2 mov r0,r0,ror #24 bl jbdtxh mov r0,r0,ror #24 jbdt1 bl jbdtxh mov r0,#' ' bl HAL_DebugTX ldmfd r13!, {r0-r3,pc} HAL_DebugTXStrInline stmfd r13!, {r0-r3} ; lr points to prinstring, immediately ; following call, null terminated sub r3,lr,#1 1 ldrb r0,[r3,#1]! ; pop next char, auto incr teq r0,#0 ; terminating null biceq lr,r3,#3 ; round down address ldmeqfd r13!,{r0-r3} addeq pc,lr,#4 ; return to next word bl HAL_DebugTX ; else send, then b %bt1 ; loop jbdtxh stmfd r13!,{r0-r3,lr} ; print byte as hex and a4,a1,#&f ; get low nibble and a1,a1,#&f0 ; get hi nibble mov a1,a1,lsr #4 ; shift to low nibble cmp a1,#&9 ; 9? addle a1,a1,#&30 addgt a1,a1,#&37 ; convert letter if needed bl HAL_DebugTX cmp a4,#9 addle a1,a4,#&30 addgt a1,a4,#&37 bl HAL_DebugTX ldmfd r13!,{r0-r3,pc} | HAL_DebugTX HAL_DebugS HAL_DebugHexTX HAL_DebugHexTX2 HAL_DebugHexTX4 MOV pc, lr HAL_DebugTXStrInline stmfd r13!, {r0-r3} ; lr points to prinstring, immediately ; following call, null terminated sub r3,lr,#1 1 ldrb r0,[r3,#1]! ; pop next char, auto incr teq r0,#0 ; terminating null biceq lr,r3,#3 ; round down address ldmeqfd r13!,{r0-r3} addeq pc,lr,#4 ; return to next word b %bt1 ; loop ] END