/* Startup code for ZPU Copyright (C) 2005 Free Software Foundation, Inc. This 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 2, or (at your option) any later version. In addition to the permissions in the GNU General Public License, the Free Software Foundation gives you unlimited permission to link the compiled version of this file with other programs, and to distribute those programs without any restriction coming from the use of this file. (The General Public License restrictions do apply in other respects; for example, they cover modification of the file, and distribution when not linked into another program.) This 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; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ .file "mincrt0.S" /* Minimal startup code, usable where the core is complete enough not to require emulated instructions */ .section ".fixed_vectors","ax" ; KLUDGE!!! we remove the executable bit to avoid relaxation .section ".fixed_vectors","a" .macro fixedim value im \value .endm .macro jmp address fixedim \address poppc .endm .macro fast_neg not im 1 add .endm .macro mult1bit ; create mask of lowest bit in A loadsp 8 ; A im 1 and im -1 add not loadsp 8 ; B and add ; accumulate in C ; shift B left 1 bit loadsp 4 ; B addsp 0 storesp 8 ; B ; shift A right 1 bit loadsp 8 ; A flip addsp 0 flip storesp 12 ; A .endm .macro cimpl funcname ; save R0 im _memreg load ; save R1 im _memreg+4 load ; save R2 im _memreg+8 load loadsp 20 loadsp 20 fixedim \funcname call ; destroy arguments on stack storesp 0 storesp 0 im _memreg load ; poke the result into the right slot storesp 24 ; restore R2 im _memreg+8 store ; restore R1 im _memreg+4 store ; restore r0 im _memreg store storesp 4 poppc .endm .globl _start _start: jmp _premain /* vectors */ /* instruction emulation code */ nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop # opcode 34 # offset 0x0000 0040 .balign 32,0 _loadh: loadsp 4 ; by not masking out bit 0, we cause a memory access error ; on unaligned access im ~0x2 and load ; mult 8 loadsp 8 im 3 and fast_neg im 2 add im 3 ashiftleft ; shift right addr&3 * 8 lshiftright im 0xffff and storesp 8 poppc # opcode 35 # offset 0x0000 0060 .balign 32,0 _storeh: loadsp 4 ; by not masking out bit 0, we cause a memory access error ; on unaligned access im ~0x2 and load ; mask im 0xffff loadsp 12 im 3 and fast_neg im 2 add im 3 ashiftleft ashiftleft not and loadsp 12 im 0xffff nop fixedim _storehtail poppc # opcode 36 # offset 0x0000 0080 .balign 32,0 _lessthan: loadsp 8 fast_neg loadsp 8 add ; DANGER!!!! ; 0x80000000 will overflow when negated, so we need to mask ; the result above with the compare positive to negative ; number case loadsp 12 loadsp 12 not and not and ; handle case where we are comparing a negative number ; and positve number. This can underflow. E.g. consider 0x8000000 < 0x1000 loadsp 12 not loadsp 12 and or flip im 1 and storesp 12 storesp 4 poppc # opcode 37 # offset 0x0000 00a0 .balign 32,0 _lessthanorequal: loadsp 8 loadsp 8 lessthan loadsp 12 loadsp 12 eq or storesp 12 storesp 4 poppc # opcode 38 # offset 0x0000 00c0 .balign 32,0 _ulessthan: ; fish up arguments loadsp 4 loadsp 12 /* low: -1 if low bit dif is negative 0 otherwise: neg (not x&1 and (y&1)) x&1 y&1 neg (not x&1 and (y&1)) 1 1 0 1 0 0 0 1 -1 0 0 0 */ loadsp 4 not loadsp 4 and im 1 and neg /* high: upper 31-bit diff is only wrong when diff is 0 and low=-1 high=x>>1 - y>>1 + low extremes 0000 - 1111: low= neg(not 0 and 1) = 1111 (-1) high=000+ neg(111) +low = 000 + 1001 + low = 1000 OK 1111 - 0000 low=neg(not 1 and 0) = 0 high=111+neg(000) + low = 0111 OK */ loadsp 8 flip addsp 0 flip loadsp 8 flip addsp 0 flip sub ; if they are equal, then the last bit decides... add /* test if negative: result = flip(diff) & 1 */ flip im 1 and ; destroy a&b which are on stack storesp 4 storesp 4 storesp 12 storesp 4 poppc # opcode 39 # offset 0x0000 00e0 .balign 32,0 _ulessthanorequal: loadsp 8 loadsp 8 ulessthan loadsp 12 loadsp 12 eq or storesp 12 storesp 4 poppc # opcode 40 # offset 0x0000 0100 .balign 32,0 .globl _swap _swap: breakpoint ; tbd # opcode 41 # offset 0x0000 0120 .balign 32,0 _slowmult: im _slowmultImpl poppc # opcode 42 # offset 0x0000 0140 .balign 32,0 _lshiftright: loadsp 8 flip loadsp 8 ashiftleft flip storesp 12 storesp 4 poppc # opcode 43 # offset 0x0000 0160 .balign 32,0 _ashiftleft: loadsp 8 loadsp 8 im 0x1f and fast_neg im _ashiftleftEnd add poppc # opcode 44 # offset 0x0000 0180 .balign 32,0 _ashiftright: loadsp 8 loadsp 8 lshiftright ; handle signed value im -1 loadsp 12 im 0x1f and lshiftright not ; now we have an integer on the stack with the signed ; bits in the right position ; mask these bits with the signed bit. loadsp 16 not flip im 1 and im -1 add and ; stuff in the signed bits... or ; store result into correct stack slot storesp 12 ; move up return value storesp 4 poppc # opcode 45 # offset 0x0000 01a0 .balign 32,0 _call: ; fn loadsp 4 ; return address loadsp 4 ; store return address storesp 12 ; fn to call storesp 4 pushsp ; flush internal stack popsp poppc _storehtail: and loadsp 12 im 3 and fast_neg im 2 add im 3 ashiftleft nop ashiftleft or loadsp 8 im ~0x3 and store storesp 4 storesp 4 poppc # opcode 46 # offset 0x0000 01c0 .balign 32,0 _eq: loadsp 8 fast_neg loadsp 8 add not loadsp 0 im 1 add not and flip im 1 and storesp 12 storesp 4 poppc # opcode 47 # offset 0x0000 01e0 .balign 32,0 _neq: loadsp 8 fast_neg loadsp 8 add not loadsp 0 im 1 add not and flip not im 1 and storesp 12 storesp 4 poppc # opcode 48 # offset 0x0000 0200 .balign 32,0 _neg: loadsp 4 not im 1 add storesp 8 poppc # opcode 49 # offset 0x0000 0220 .balign 32,0 _sub: loadsp 8 loadsp 8 fast_neg add storesp 12 storesp 4 poppc # opcode 50 # offset 0x0000 0240 .balign 32,0 _xor: loadsp 8 not loadsp 8 and loadsp 12 loadsp 12 not and or storesp 12 storesp 4 poppc # opcode 51 # offset 0x0000 0260 .balign 32,0 _loadb: loadsp 4 im ~0x3 and load loadsp 8 im 3 and fast_neg im 3 add ; x8 addsp 0 addsp 0 addsp 0 lshiftright im 0xff and storesp 8 poppc # opcode 52 # offset 0x0000 0280 .balign 32,0 _storeb: loadsp 4 im ~0x3 and load ; mask away destination im _mask loadsp 12 im 3 and addsp 0 addsp 0 add load and im _storebtail poppc # opcode 53 # offset 0x0000 02a0 .balign 32,0 _div: jmp ___div # opcode 54 # offset 0x0000 02c0 .balign 32,0 _mod: jmp ___mod # opcode 55 # offset 0x0000 02e0 .balign 32,0 .globl _eqbranch _eqbranch: loadsp 8 ; eq not loadsp 0 im 1 add not and flip im 1 and ; mask im -1 add loadsp 0 storesp 16 ; no branch address loadsp 4 and ; fetch boolean & neg mask loadsp 12 not ; calc address & mask for branch loadsp 8 loadsp 16 add ; subtract 1 to find PC of branch instruction im -1 add and or storesp 4 storesp 4 storesp 4 poppc # opcode 56 # offset 0x0000 0300 .balign 32,0 .globl _neqbranch _neqbranch: loadsp 8 ; neq not loadsp 0 im 1 add not and flip not im 1 and ; mask im -1 add loadsp 0 storesp 16 ; no branch address loadsp 4 and ; fetch boolean & neg mask loadsp 12 not ; calc address & mask for branch loadsp 8 loadsp 16 add ; find address of branch instruction im -1 add and or storesp 4 storesp 4 storesp 4 poppc # opcode 57 # offset 0x0000 0320 .balign 32,0 .globl _poppcrel _poppcrel: add ; address of poppcrel im -1 add poppc # opcode 58 # offset 0x0000 0340 .balign 32,0 .globl _config _config: im 1 nop im _hardware store storesp 4 poppc # opcode 59 # offset 0x0000 0360 .balign 32,0 _pushpc: loadsp 4 im 1 add storesp 8 poppc # opcode 60 # offset 0x0000 0380 .balign 32,0 _syscall_emulate: .byte 0 # opcode 61 # offset 0x0000 03a0 .balign 32,0 _pushspadd: pushsp im 4 add loadsp 8 addsp 0 addsp 0 add storesp 8 poppc # opcode 62 # offset 0x0000 03c0 .balign 32,0 _halfmult: breakpoint # opcode 63 # offset 0x0000 03e0 .balign 32,0 _callpcrel: loadsp 4 loadsp 4 add im -1 add loadsp 4 storesp 12 ; return address storesp 4 pushsp ; this will flush the internal stack. popsp poppc .text _ashiftleftBegin: .rept 0x1f addsp 0 .endr _ashiftleftEnd: storesp 12 storesp 4 poppc _storebtail: loadsp 12 im 0xff and loadsp 12 im 3 and fast_neg im 3 add ; x8 addsp 0 addsp 0 addsp 0 ashiftleft or loadsp 8 im ~0x3 and store storesp 4 storesp 4 poppc ; NB! this is not an EMULATE instruction. It is a varargs fn. .globl _syscall _syscall: syscall poppc _slowmultImpl: loadsp 8 ; A loadsp 8 ; B im 0 ; C .LmoreMult: mult1bit ; cutoff loadsp 8 .byte (.LmoreMult-.Lbranch)&0x7f+0x80 .Lbranch: neqbranch storesp 4 storesp 4 storesp 12 storesp 4 poppc ___mod: cimpl __modsi3 ___div: cimpl __divsi3 .section ".rodata" .balign 4,0 _mask: .long 0x00ffffff .long 0xff00ffff .long 0xffff00ff .long 0xffffff00 .section ".text","ax" .global _boot .balign 4,0 _boot: im 0 poppc .global _break; _break: im _break poppc ; infinite loop _premain: im _break nop fixedim main poppc .data .balign 4,0 .globl _hardware _hardware: .long 0 .globl _cpu_config _cpu_config: .long 0 .section ".bss" .balign 4,0 .globl _memreg _memreg: .long 0 .long 0 .long 0 .long 0