Files
TeslaRel410/sda4/DPL3/VRENDER/PXPL5SUP/CORE.S
T
CydandClaude Fable 5 db7745fcd0 sda4: commit the Glaze developer hard-drive dump
Un-ignored: the dev drive is the ground truth the restoration and
emulator work constantly reference (DPL3/LIBDPL + VRENDER i860 renderer
source, BT/RP live+dev game trees, VGL_LABS pod boot, scene/audio
content). Kept in-repo for the pod-owner community.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 19:41:15 -05:00

748 lines
14 KiB
ArmAsm

///*
// * Basic kernel operations, with apologies to the Intel Corp.
// *
// * Copyright (c) Division Ltd. 1991
// *
// * Author Jeff Sullivan
// *
// * SCCS ident: %W% %G%
// */
// #include <sys/trap.h>
// #include <sys/psl.h>
// #include <sys/reg.h>
#define DB_ALIGN .align 32
#define NOP6 nop;nop;nop;nop;nop;nop;nop
// special zero - page locations, expressed as signed quantities for
// the sake of the portland assembler, which must hold addresses as
// unsigned quantities, and so decides that ffffff80 is not within +-
// 32k of 0.!!
SV_PSR = -128
SV_FIR = -124
SV_R1 = -120
SV_ISP = -116
SV_KSP = -112
SV_DB = -108
SV_TSP = -104
SV_TSP1 = -100
RS_PSR = -96
RS_FIR = -92
RS_R1 = -88
RS_ISP = -84
// SV_PSR = 0xfffff000
// SV_FIR = 0xfffff004
// SV_R1 = 0xfffff008
// SV_ISP = 0xfffff00c
// SV_KSP = 0xfffff010
// SV_DB = 0xfffff014
// SV_TSP = 0xfffff018
// SV_TSP1 = 0xfffff01c
// RS_PSR = 0xfffff020
// RS_FIR = 0xfffff024
// RS_R1 = 0xfffff028
// RS_ISP = 0xfffff02c
TLOCK = -80
TRACE = -76
//
// trap handler
//
.globl alltraps
alltraps:
// branch here from 0xffffff00
// save a few registers and the pc (without causing more traps)
// only place we have to store stuff without using a register is
// offset(r0) e.g. first or last 32k
st.l r1,SV_R1(r0)
ld.c db,r1
st.l r1,SV_DB(r0)
st.c r0,db
ld.c fir,r1
st.l r1,SV_FIR(r0)
ld.c psr,r1 //r1 = PSR
st.l r1,SV_PSR(r0)
st.l sp,SV_ISP(r0)
//
// Ensure all trap bits clear to allow indirect branches
//
st.c r0,psr
//
// CHRG DEBUG we are always in Supervisor mode
//
// switch stacks if necessary
// e.g. were in User mode
// and PSR_PU,r1,r0
// bc waskern
// ld.l SV_KSP(r0),sp
waskern:
// nop //fix chip timing bug
// andnot 0xf,sp,sp //re-align sp to quad boundary
// ld.l SV_TSP(r0),r1
// st.l r1,SV_TSP1(r0)
// ld.l SV_PSR(r0),r1
// st.l sp,SV_TSP(r0)
// now that we have a valid stack, save more state
adds -256,sp,sp
adds -64,sp,sp
st.l r16,0(sp)
st.l r17,4(sp)
st.l r18,8(sp)
st.l r19,12(sp)
st.l r20,16(sp)
st.l r21,20(sp)
st.l r22,24(sp)
st.l r23,28(sp)
st.l r24,32(sp)
st.l r25,36(sp)
st.l r26,40(sp)
st.l r27,44(sp)
st.l r28,48(sp)
st.l r29,52(sp)
st.l r30,56(sp)
st.l r31,60(sp)
adds -48,sp,sp
st.l r4,0(sp)
st.l r5,4(sp)
st.l r6,8(sp)
st.l r7,12(sp)
st.l r8,16(sp)
st.l r9,20(sp)
st.l r10,24(sp)
st.l r11,28(sp)
st.l r12,32(sp)
st.l r13,36(sp)
st.l r14,40(sp)
st.l r15,44(sp)
adds -16,sp,sp
st.l r0,0(sp)
ld.l SV_R1(r0),r16
st.l r16,4(sp)
ld.l SV_ISP(r0),r16
st.l r16,8(sp)
st.l fp,12(sp)
//
// figure out trap reason (put in r20)
//
ld.l SV_FIR(r0),r16 // r16 contains fir
// External Interrupt ?
and PSR_IN,r1,r0
bc no_intr
or T_INTRPT,r0,r20
br got_ttype
nop
no_intr:
// Instruction Access Fault ?
and PSR_IAT,r1,r0
bc no_iat
or T_INSFLT,r0,r20
br got_ttype
nop
no_iat:
// Instruction Trap ?
and PSR_IT,r1,r0
bc no_it
// was an IT, but what kind?
ld.l 0(r16),r21 //this cant fault, already checked for IAT
xorh 0x4400,r21,r0 // trap r0,r0,r0
bnc not_bpt
or T_BPTFLT,r0,r20
br got_ttype
nop
not_bpt:
andh 0xffff,r21,r31
xorh 0x47e0,r31,r0 // trap r31,r31,r0
bnc not_sysc
or T_SYSCALL,r0,r20
br got_ttype
nop
not_sysc:
or T_PRIVINFLT,r0,r20
br got_ttype
nop
no_it:
// Floating Point Trap ?
and PSR_FT,r1,r0
bc no_ft
or T_ARITHTRAP,r0,r20
br got_ttype
nop
no_ft:
// Data Access Trap ?
and PSR_DAT,r1,r0
bc no_tbits //should never happen, except for RESET
or T_PAGEFLT,r0,r20
// figure out virtual address (r18)
// r/w (r19)
// align required (r21)
//
// in dual mode must look at fir +4!!
//
and PSR_DIM,r1,r0
bc not_di_mode
addu 4,r16,r16
not_di_mode:
ld.l 0(r16),r17 // instruction (this cant trap since no IAT)
andh 0x2000,r17,r0
bnc not_ld_st
//double check must be 000x.0x or 000x.11 (dont trust fir)
andh 0xe800,r17,r21
bc ls_ok
andh 0xec00,r17,r21
xorh 0x0c00,r21,r0
bc ls_ok
or T_COMPATFLT,r0,r20
br got_ttype
nop
ls_ok:
// ld or st
mov r0,r21
andh 0x1000,r17,r0
bc got_ls_aln
or 1,r21,r21
and 1,r17,r0
bc got_ls_aln
or 2,r21,r21
got_ls_aln:
andh 0x0800,r17,r0
bc is_ld
// st
or 1,r0,r19
// st EA
// const+src2 where const = dest|low11 sign extended
shr 19,r17,r22
and 0x7c,r22,r22
ld.l r22(sp),r22 //src2
shr 5,r17,r23
and 0xf800,r23,r23
and 0x07ff,r17,r24
or r23,r24,r23
shl 16,r23,r23
shra 16,r23,r23
and 1,r21,r24
nop
andnot r24,r23,r23 // adjusted const
br got_datp
adds r23,r22,r18 // EA
// ld
is_ld:
mov r0,r19
// ld EA
and 1,r21,r25
mov r0,r26
// at this point, we have:
// r17 - the instruction
// r25 - low order bits to throw away if const(reg)
// r26 - bit 0 set if we need auto-increment fixup
// r19,r21 already set
gen_ea:
shr 19,r17,r27
and 0x7c,r27,r27 //index of src2 * 4
ld.l r27(sp),r22 //src2
andh 0x0400,r17,r0
bc gen_r_r
// const src1
shl 16,r17,r23
shra 16,r23,r23
nop
andnot r25,r23,r23 // toss some low bits
br ai_fix
nop
// reg src1
gen_r_r:
shr 9,r17,r23
and 0x7c,r23,r23
ld.l r23(sp),r23 // src1
//value of src2 is in r22
//value of src1 is in r23
//index of src2 * 4 is in r27
//flag for autoinc fix in r26
ai_fix:
and 1,r26,r0
bc no_ai_fix
subs r22,r23,r22
adds r27,sp,r26
st.l r22,0(r26)
no_ai_fix:
br got_datp
adds r23,r22,r18
not_ld_st:
//dont trust chip!
//must be one of:
// fld,fst 0010.xx
// pst 0011.11
andh 0xf000,r17,r21
xorh 0x2000,r21,r0
bc fdat_ok
andh 0xfc00,r17,r21
xorh 0x3f00,r21,r0
bc fdat_ok
or T_COMPATFLT,r0,r20
br got_ttype
nop
fdat_ok:
and 1,r17,r26 //need autoinc fix?
or 3,r0,r21
and 2,r17,r0
bnc got_f_aln
or 4,r21,r21
and 4,r17,r0
bc got_f_aln
or 8,r21,r21
got_f_aln:
and 7,r21,r25
andh 0x1000,r17,r0
bnc is_pix
andh 0x0800,r17,r0
bc is_fld
// fst
or 1,r0,r19
br gen_ea
nop
// fld or pfld
is_fld:
mov r0,r19
br gen_ea
nop
// pst
is_pix:
or 1,r0,r19
br gen_ea
nop
got_datp:
br got_ttype
nop
//
// No Trap bits set so Must be Error or RESET
//
no_tbits:
or T_RESET,r0,r20
//
// OK WE HAVE THE TRAP TYPE
//
got_ttype:
adds -16,sp,sp
st.l r1,0(sp) //PSR
ld.l SV_FIR(r0),r16
st.l r16,4(sp) //FIR
st.l r20,8(sp) //trap type
ld.l SV_DB(r0),r16
st.l r16,12(sp) //DB
// clear trap bits in PSR, re-enable interrupts
// andnot 0x1f00,r1,r30
// st.c r30,psr
// call trap()
mov sp,r16
call _trap
// call flush_inv() to flush Data Cache and invalidate Instruction Cache
nop
call _flush_inv
nop
// restore state
.globl ret_user
ret_user:
ld.c psr,r1 //turn off interrupts for now
nop
andnot PSR_IM,r1,r1
st.c r1,psr
ld.l 0(sp),r1 //resume PSR
nop
andnot PSR_IM,r1,r1 //the bri will set PSR_IM
st.l r1,RS_PSR(r0)
ld.l 4(sp),r16
st.l r16,RS_FIR(r0) //resume PC
ld.l 12(sp),r16
st.c r16,db //resume DB
adds 16,sp,sp
ld.l 4(sp),r16
st.l r16,RS_R1(r0) //resume R1
ld.l 8(sp),r16
st.l r16,RS_ISP(r0) //resume SP
ld.l 12(sp),fp //resume FP
adds 16,sp,sp
ld.l 0(sp),r4
ld.l 4(sp),r5
ld.l 8(sp),r6
ld.l 12(sp),r7
ld.l 16(sp),r8
ld.l 20(sp),r9
ld.l 24(sp),r10
ld.l 28(sp),r11
ld.l 32(sp),r12
ld.l 36(sp),r13
ld.l 40(sp),r14
ld.l 44(sp),r15
adds 48,sp,sp
ld.l 0(sp),r16
ld.l 4(sp),r17
ld.l 8(sp),r18
ld.l 12(sp),r19
ld.l 16(sp),r20
ld.l 20(sp),r21
ld.l 24(sp),r22
ld.l 28(sp),r23
ld.l 32(sp),r24
ld.l 36(sp),r25
ld.l 40(sp),r26
ld.l 44(sp),r27
ld.l 48(sp),r28
ld.l 52(sp),r29
ld.l 56(sp),r30
ld.l 60(sp),r31
adds 64,sp,sp
adds 256,sp,sp
or PSR_IT,r1,r1
st.c r1,psr //set return PSR (with trap bit set)
//
// We are always in Supervisor Mode - So no need to restore SP
//
// NBBB BUGGER There seems to be a problem with this load immediately after
// the store to the same page. This results in the sp being
// set to an invalid value.
// st.l sp,SV_KSP(r0) //save kernel sp
// nop // ESSENTIAL FOR READ FIX
// nop // ESSENTIAL FOR READ FIX
// ld.l RS_ISP(r0),sp // return SP
ld.l RS_FIR(r0),r1 // return PC
bri r1
ld.l RS_R1(r0),r1
.globl _vstart
.align 4
_vstart:
//
// Enable Address Translation
// orh h%_kpde,r0,r16
// or l%_kpde,r16,r16
orh 0xffff,r0, r16
or 0xE000,r16,r16
//
// routine to turn on virtual memory
// (almost same as above -- may merge later)
ld.c dirbase,r17
and 0xfff,r17,r17
nop
andnot 0xfff,r16,r16
or DIR_ITI|DIR_ATE,r16,r16
or r17,r16,r16
mov 0xfffff000, r18
or 0x33, r0, r19
st.l r19,4(r18)
DB_ALIGN
st.c r16,dirbase
NOP6
orh h%virt1, r0, r1
or l%virt1, r1, r1
mov 0xfffff000, r18
or 0x34, r0, r19
st.l r19,8(r18)
bri r1
nop
virt1:
mov 0xfffff000, r18
or 0x35, r0, r19
st.l r19,12(r18)
call _flush_inv
nop
orh h%_sbss,r0,r16 // start address of bss in r16
or l%_sbss,r16,r16
mov r0,r17 // zero character in r17
orh h%_zzzend,r0,r18
or l%_zzzend,r18,r18
subs r18,r16,r18 // length of bss in r18
call _memset
nop
mov r0,r16
mov r0,r17
mov r0,r18
// enable interrupts
//
call __main
nop
call _ienable
nop
//
// Setup stdio
//
call __start_buffered_io
nop
//
// set the secret dos variable
//
#ifdef TARGET_DOS
or 1,r0,r31 // initialize DOS flag
orh ha%___PC_DOS,r0,r19
st.l r31,l%___PC_DOS(r19)
#endif
//
// Set up argc, argv, envp
//
adds -8, sp, sp //make room for argc, argv
// call __break_cmd_line // get command line from iserver
adds r0, sp, r16 // pass pointer to mem on stack
ld.l 0(sp), r16 //argc
ld.l 4(sp), r17 //argv
adds r0, r0, r18 //envp
adds 8, sp, sp //clear back stack
//
// Now Call MAIN -- i.e Application
//
call _main
nop
call _exit // main's return value is in r16 already
nop
// flush()
// flush data cache
.globl _flush
_flush:
mov 0xfffff000, r18
or 0x06, r0, r19
st.l r19, 4(r18)
// ld.c psr,r22
// nop
mov 0xfffff000, r18
or 0x09, r0, r19
st.l r19, 8(r18)
or 0x03, r0, r19
st.l r19, 12(r18)
// ld.c dirbase,r17
// nop
mov 0xfffff000, r18
or 0x07, r0, r19
st.l r19, 16(r18)
adds -1,r0,r19
or 127,r0,r20
or l%_bad,r0,r16
orh h%_bad,r16,r16 //pick an unused virtual address
adds -32,r16,r16
mov r16,r21
mov 0xfffff000, r18
or 0x08, r0, r23
st.l r23, 12(r18)
mov r17,r18
nop
andnot 0xf00,r18,r18
or 0x800,r18,r18
mov r18, r23
st.c r18,dirbase //RC = 2, RB = 0
bla r19,r20,flp1
nop
flp1:
ld.l 32(r16),r0
st.l r1,32(r16)
bla r19,r20,flp1
flush 32(r16)++
mov 0xffffff00, r3
or 0x09, r0, r2
st.l r2, 16(r3)
or 0x100,r23,r18
st.c r18,dirbase //RC = 2, RB = 1
or 127,r0,r20
mov r21,r16
adds 4096,r16,r16
bla r19,r20,flp2
nop
flp2:
ld.l 32(r16),r0
st.l r1,32(r16)
bla r19,r20,flp2
flush 32(r16)++
or 0x200,r23,r18
st.c r18,dirbase //RC = 2, RB = 1
or 127,r0,r20
mov r21,r16
adds 4096,r16,r16
bla r19,r20,flp3
nop
flp3:
ld.l 32(r16),r0
st.l r1,32(r16)
bla r19,r20,flp3
flush 32(r16)++
or 0x300,r23,r18
st.c r18,dirbase //RC = 2, RB = 1
or 127,r0,r20
mov r21,r16
adds 4096,r16,r16
bla r19,r20,flp4
nop
flp4:
ld.l 32(r16),r0
st.l r1,32(r16)
bla r19,r20,flp4
flush 32(r16)++
mov 0xffffff00, r3
or 0x0a, r0, r2
st.l r2, 16(r3)
st.c r17,dirbase
NOP6
st.c r22,psr
bri r1
nop
//
// flush data cache and invalidate tlb and instr cache
.globl _flush_inv
_flush_inv:
adds -4,sp,sp
st.l r1,0(sp)
call _flush
nop
ld.l 0(sp),r1
adds 4,sp,sp
//
// intentional fall through
//
// invalidate tlb and instr cache
.globl _inv_tlb_ic
_inv_tlb_ic:
ld.c dirbase,r16
or DIR_ITI,r16,r16
DB_ALIGN
st.c r16,dirbase
NOP6
DB_ALIGN
bri r1
nop
.globl _ienable
_ienable:
ld.c psr,r17
or PSR_IM,r17,r17
st.c r17,psr
bri r1
nop