|
/* 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 "crt0.S"
|
|
|
|
|
|
|
|
|
|
; .section ".fixed_vectors","ax"
|
|
; KLUDGE!!! we remove the executable bit to avoid relaxation
|
|
.section ".fixed_vectors","a"
|
|
|
|
; DANGER!!!!
|
|
; we need to align these code sections to 32 bytes, which
|
|
; means we must not use any assembler instructions that are relaxed
|
|
; at linker time
|
|
; DANGER!!!!
|
|
|
|
.macro fixedim value
|
|
im \value
|
|
.endm
|
|
|
|
.macro jsr address
|
|
im _memreg ; save R0
|
|
load
|
|
im _memreg+4 ; save R1
|
|
load
|
|
im _memreg+8 ; save R2
|
|
load
|
|
fixedim \address
|
|
call
|
|
im _memreg+8
|
|
store ; restore R2
|
|
im _memreg+4
|
|
store ; restore R1
|
|
im _memreg
|
|
store ; restore R0
|
|
.endm
|
|
|
|
|
|
.macro jmp address
|
|
fixedim \address
|
|
poppc
|
|
.endm
|
|
|
|
|
|
.macro fast_neg
|
|
not
|
|
im 1
|
|
add
|
|
.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
|
|
|
|
.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
|
|
|
|
|
|
|
|
/* vectors */
|
|
.balign 32,0
|
|
# offset 0x0000 0000
|
|
.globl _start
|
|
_start:
|
|
; intSp must be 0 when we jump to _premain
|
|
|
|
im ZPU_ID
|
|
loadsp 0
|
|
im _cpu_config
|
|
store
|
|
config
|
|
jmp _premain
|
|
|
|
|
|
|
|
.balign 32,0
|
|
# offset 0x0000 0020
|
|
.globl _zpu_interrupt_vector
|
|
_zpu_interrupt_vector:
|
|
jmp ___zpu_interrupt_vector
|
|
|
|
|
|
.balign 16,0
|
|
# offset 0x0000 0030
|
|
.globl _memreg
|
|
.weak _memreg
|
|
_memreg:
|
|
|
|
|
|
/* instruction emulation code */
|
|
|
|
# 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
|
|
|
|
.globl ___zpu_interrupt_vector
|
|
.weak ___zpu_interrupt_vector
|
|
|
|
___zpu_interrupt_vector:
|
|
jsr _zpu_interrupt
|
|
poppc
|
|
|
|
.section ".rodata"
|
|
.balign 4,0
|
|
_mask:
|
|
.long 0x00ffffff
|
|
.long 0xff00ffff
|
|
.long 0xffff00ff
|
|
.long 0xffffff00
|
|
|
|
.data
|
|
.balign 4,0
|
|
|
|
.globl _hardware
|
|
_hardware:
|
|
.long 0
|
|
.globl _cpu_config
|
|
_cpu_config:
|
|
.long 0
|
|
|