Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!rutgers!apple!claris!kevin From: kevin@claris.com (Kevin Watts) Newsgroups: comp.sys.apple Subject: Re: Computer languages on the various Apple Corp computers Message-ID: <10211@claris.com> Date: 25 May 89 03:39:16 GMT References: <2075@umbc3.UMBC.EDU> Organization: Claris Corporation, Santa Clara CA Lines: 96 From article <2075@umbc3.UMBC.EDU>, by cs472226@umbc5.umbc.edu (David Wood (CS472226)): > In article <10204@claris.com> kevin@claris.com (Kevin Watts) writes: >> >> [using the direct page as 'registers'] won't work >>at all if the direct page register is used to set up a stack frame, which >>is essential for a high level language and pretty much so in any sizable >>hand-coded assembler project. > > Why not shave off 2, 4, 8, 16, or however many bytes of storage above > the bottom of the stack at the end of the page (stacks build down) and > reserve it for those values that you would otherwise contain in > registers? ... The problem is not space (in practice only a few K bytes are required for a stack unless you're using recursion heavily), but the addressing modes of the 65816. Although the stack may be of any size up to 64K, in bank 0, only 256 bytes at a time may be accessed efficiently. Which 256 bytes is controlled by the direct page register, which contains a word indicating the bottom of the 256 byte range. A stack frame, for those who don't know, is set up by a routine when it is called. It allows easy access to parameters passed on the stack and local variables allocated on the stack. On the 65816 the direct page register is the way to do this. Here's some sample code for a routine that takes two words as parameters and needs two longs of local space: (I'm using the C calling conventions and jsr/rts for simplicity - the IIGS ToolBox routines use Pascal conventions and jsl/rtl) Calling sequence: pea #1234 ; push 1st parameter pea #5678 ; push 2nd parameter jsr MyRoutine pla ; pop the parameters off the stack pla . . MyRoutine PROC Par1 equ 15 Par2 equ 13 Local1 equ 5 Local2 equ 1 phd ; save old direct page register tsc ; transfer stack ptr to accumulator sec ; create stack space for sbc #8 ; our locals (two longs = 8 bytes) tcs ; transfer accumulator back to stack ptr tcd ; set up direct page for stack frame ; now the stack looks like this: (with offsets from the 'top' of the stack) ; +15 | $1234 | <- Par1 ; +13 | $5678 | <- Par2 ; +11 | addr | <- return address ; +9 | old d | <- saved direct page value ; | | ; +5 | | <- Local1 ; | | ; +1 | | <- Local2 ; S -> <- D lda Par1 clc adc Par2 sta Local1 . . tsc clc adc #8 tcs pld rts Well, I've wandered a bit, but I hope this is useful. The point is that the direct page register is changing on every procedure call, so it can't be used to indicate a static 'set of registers' in bank 0. If you don't need stack frames anywhere (i.e. pass all parameters in registers or globals, don't use any local variables - generally poor programming practices and virtually impossible if you want recursion), then it would definitely make sense to allocate up to 256 bytes in bank 0 and keep the direct page register permanently pointing to it, thereby providing a small but fast set of global variables - fast enough to consider 'registers' if you like. The same tricks can be managed even if you do need stack frames, but only at the cost of frequently saving, setting and restoring the direct page register; it's usually faster not to bother. (In case it's not clear, there's no direct relationship between the stack and the direct page - only using the direct page register to set up a stack frame creates one) -- Kevin Watts ! Any opinions expressed here are my own, and are not Claris Corporation ! neccessarily shared by anyone else. Unless they are kevin@claris.com ! patently absurd, in which case they're not mine either.