Files
zOS/startup/appcrt0.s

314 lines
13 KiB
ArmAsm

;--------------------------------------------------------------------------------------------------------
;
; Name: appcrt0.h
; Created: July 2019
; Author(s): Philip Smart
; Description: ZPUTA application startup code.
; This is the assembler startup file of any C compiled APPlication for the zOS/ZPUTA
; program. It specifies the entry points into zOS/ZPUTA for standard functions
; and also the stack manipulation to handle parameters and return codes for the
; C APPlication (ie. ZPUTA Calls APP with parameters and APP returns a result code).
;
; Credits:
; Copyright: (c) 2019-2020 Philip Smart <philip.smart@net2net.org>
;
; History: July 2019 - Initial script written.
;
;--------------------------------------------------------------------------------------------------------
; This source file is free software: you can redistribute it and#or modify
; it under the terms of the GNU General Public License as published
; by the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This source file is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http:;;www.gnu.org;licenses;>.
;--------------------------------------------------------------------------------------------------------
.file "appcrt0.s"
.include "zpu_macros.s"
.section ".fixed_vectors","a"
; Define the location where the pointer to the interrupt handler is stored.
.global _inthandler_fptr
.set _inthandler_fptr, 0x00000400
.balign 16,0
.global _start
_start: im 0 ; Store return address into stack.
pushspadd
popsp
fixedim _premain ; Jump to initialisation routine.
poppc
; Fixed entry point for ZPUTA API calls. Return codes are stored in ZPUTA namespace so a transfer must take
; place into the app namespace. This is implemented by the API jumping to this fixed entry point and the
; return code copied.
.balign 16,0
_callret:
im _memreg+16 ; Get address of memreg 1 in zputa
load
load ; Get value at _memreg in zputa
im _memreg ;
store ; Place return code into memreg 1 in this app.
poppc ; Return to original caller.
;-----------------------------------------------
; ZPUTA API Function Entry Points
;-----------------------------------------------
;
; Entry points in the parent program, ZPUTA, where the relevvant named functions can be accessed. The
; entry point in this table is used as the address for the specified function in the APPlication such that
; a call to a library function in the APPlication is actually using code in ZPUTA at runtime thus minimising
; code in the APPlication.
;
.equ funcNext, 0x06;
.equ funcAddr, OS_BASEADDR+0x20;
defapifunc break funcAddr
;
; putc and xprint calls.
;
.equ funcAddr, funcAddr+funcNext;
defapifunc putchar funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc xputc funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc xfputc funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc xputs funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc xgets funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc xfgets funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc xfputs funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc xatoi funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc uxatoi funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc xprintf funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc xvprintf funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc xsprintf funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc xfprintf funcAddr
;
; getc calls
;
.equ funcAddr, funcAddr+funcNext;
defapifunc getserial funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc getserial_nonblocking funcAddr
;
; Util calls
;
; .equ funcAddr, funcAddr+funcNext;
; defapifunc crc32_init funcAddr
; .equ funcAddr, funcAddr+funcNext;
; defapifunc crc32_addword funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc get_dword funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc rtcSet funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc rtcGet funcAddr
;
;FatFS System Calls
;
.equ funcAddr, funcAddr+funcNext;
defapifunc f_open funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_close funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_read funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_write funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_lseek funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_truncate funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_sync funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_opendir funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_closedir funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_readdir funcAddr
;.equ funcAddr, funcAddr+funcNext;
;defapifunc f_findfirst funcAddr
;.equ funcAddr, funcAddr+funcNext;
;defapifunc f_findnext funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_mkdir funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_unlink funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_rename funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_stat funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_chmod funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_utime funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_chdir funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_chdrive funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_getcwd funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_getfree funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_getlabel funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_setlabel funcAddr
;.equ funcAddr, funcAddr+funcNext;
;defapifunc f_forward funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_expand funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_mount funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_mkfs funcAddr
;.equ funcAddr, funcAddr+funcNext;
;defapifunc f_fdisk funcAddr
;.equ funcAddr, funcAddr+funcNext;
;defapifunc f_setcp funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_putc funcAddr
;.equ funcAddr, funcAddr+funcNext;
;defapifunc f_puts funcAddr
;.equ funcAddr, funcAddr+funcNext;
;defapifunc f_printf funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc f_gets funcAddr
;
; Low level disk calls.
;
.equ funcAddr, funcAddr+funcNext;
defapifunc disk_read funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc disk_write funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc disk_ioctl funcAddr
;
; Miscellaneous calls.
;
.equ funcAddr, funcAddr+funcNext;
defapifunc getStrParam funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc getUintParam funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc set_serial_output funcAddr
; .equ funcAddr, funcAddr+funcNext;
; defapifunc printBytesPerSec funcAddr
.equ funcAddr, funcAddr+funcNext;
defapifunc printFSCode funcAddr
;--------------------------------------
; Start of the main application program
;--------------------------------------
; Define weak linkage for _premain, so that it can be overridden
.section ".text","ax"
.weak _premain
; Clear BSS data, then start app() - the main entry point into the
; APPlication.
_premain:
im __bss_start__ ; bssptr
.clearloop:
loadsp 0 ; bssptr bssptr
im __bss_end__ ; __bss_end__ bssptr bssptr
ulessthanorequal ; (bssptr<=__bss_end__?) bssptr
impcrel .done ; &.done (bssptr<=__bss_end__?) bssptr
neqbranch ; bssptr
im 0x55aa44bb ; 0 bssptr - Load TOS with 0, the value to initialise memory with.
loadsp 4 ; bssptr 0 bssptr - Load the address pointer into TOS.
loadsp 0 ; bssptr bssptr 0 bssptr - And into NOS by loading again into TOS.
im 4 ; 4 bssptr bssptr 0 bssptr - Increment the address pointer by adding 4.
add ; bssptr+4 bssptr 0 bssptr
storesp 12 ; bssptr 0 bssptr+4 - Store the updated address pointer back on to stack.
store ; (write 0->bssptr) bssptr+4 - Now write 0.
im .clearloop ; &.clearloop bssptr+4
poppc ; bssptr+4 - Jump back to .clearloop by pushing address onto stack (ie. load TOS) then popping it into PC.
.done:
im .appret ; &.appret bssptr+4
storesp 4 ; &.appret
im 8 ; Param5 = address of cfgSoC structure in ZPUTA memory space to be available in this application.
pushspadd
load
im cfgSoC ; Setup the location of the pointer to cfgSoC variable in the app
store ; and place value into the pointer.
im 7 ; Param4 = address of G(lobal) structure in ZPUTA memory space to be available in this application.
pushspadd
load
im G ; Setup the location of the pointer to G(lobal) variable in the app
store ; and place value into the pointer.
im 6 ; Param3 = memreg 1 address in zputa, location where return code is expected to be placed.
pushspadd
load
im _memreg+16 ; Set the store location to memreg 4 in the app
store ; and place memreg 1 in zputa into memreg 4 of this app.
im 5 ; &Param2 &.appret
pushspadd
load
nop
im 5 ; &Param1 &Param2 &.appret
pushspadd
load
im app ; &app &Param1 &Param2 &.appret
call ; &.appret
im _memreg ; Get return code from memreg 1 in this app.
load
im _memreg+16 ; Get address of memreg 1 in zputa
load
store ; Place return code into memreg 1 in zputa.
.appret:
im 5 ; Adjust stack so that return address is in TOS
pushspadd
popsp
poppc ; Return to zputa (caller).
; NB! this is not an EMULATE instruction. It is a varargs fn.
.global _syscall
_syscall:
syscall
poppc
.section ".rodata"
.balign 4,0
_mask: .long 0x00ffffff
.long 0xff00ffff
.long 0xffff00ff
.long 0xffffff00
.section ".bss"
.balign 4,0
.global _memreg
; C required memory registers stored at begininning of bss segment.
_memreg:.long 0
.long 0
.long 0
.long 0
.long 0 ; Non standard memory register used to hold the address of memreg in ZPUTA so this application can query it.
; End of startup code.