;-------------------------------------------------------------------------------------------------------- ; ; 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 ; ; 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 . ;-------------------------------------------------------------------------------------------------------- .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.