Path: news.weeg.uiowa.edu!news.uiowa.edu!hobbes.physics.uiowa.edu!math.ohio-state.edu!cs.utexas.edu!swrinde!sgiblab!barrnet.net!nntp.crl.com!crl.crl.com!not-for-mail From: heaney@crl.com (John S. Heaney) Newsgroups: comp.sys.apple2.programmer Subject: Re: Dynamic Loadable Segments? Date: 21 Mar 1994 14:29:46 -0800 Organization: CRL Dialup Internet Access (415) 705-6060 [login: guest] Lines: 227 Message-ID: <2ml74q$ch3@crl.crl.com> References: <5e4u4fO.dsoft@delphi.com> <2mfljp$gr8@mary.iia.org> NNTP-Posting-Host: crl.crl.com In article , Joe Busnengo wrote: >Right. Maybe I should have been a little more clear in my original message. >I'm talking about loading segments from _separate load files_ that may or may >not be present when the program is running. What I'm saying is: how would I >use routines in those load files. I assume that I'd use LoadSegName, but after >that I'm stuck... I know that it can be done, because PRIZM can debug a >program of yours while it is still running. I would like to know how! :) The key routines are InitialLoad or InitialLoad2, UserShutDown, GetNewID and DeleteID. I wrote a program using videodisc drivers. Each player had its own driver, which the user selected from a list. After the driver was selected I had to unload any old driver and load the new one. Subsequent calls to the driver were routed through a single vector that was returned when the driver was loaded. Here are some code snippets. Note that this was written using the MPW IIGS Assembler. A new ID can be returned from InitialLoad without using GetNewID. And UserShutDown can free up the new UserID without calling Delete ID. I do not remember why I did that separately. It would probably be better not to. ; unload any existing player driver and load a new one specified in ; the player name handle. Set prefix 0 before calling. ; loadNewDriver PROC EXPORT EXPORT unLoadOldDriver ;global variables ; IMPORT segName IMPORT playerDispatch ;external procedures ; jsl unLoadOldDriver ;if there is one newDP v1 ;set's up a direct page referenced by d1. lda #pInitStatus ;driver starts in an initial state sta d1.driverStatus ldax d1.playerName ;lock the driver pathname handle jsl deref ; and get the pointer stax d1.driverListPtr ;------------------------------------------------------------ ; ; get a new user ID for the driver ; wordResult pea $1000 ;application type ID _GetNewID pla sta d1.driverID wordResult ;for new user ID if not using GetNewID longResult ;for start address of loaded program segment wordResult ;for Direct Page/stack address wordResult ;for Direct Page/stack buffer size lda d1.driverID ;new user ID just for driver pha pushlong d1.driverListPtr ;pathname address ptr pea 0 ;flag - use any memory _InitialLoad _ToolErrors dispErrFlag ;my error reporting pla ;already have user ID stored pulllong d1.driverAddr ;address of loaded segment pla ;don't need pla ;don't need php jsl quickUnLock ;unlock the filename handle plp pld rtl unLoadOldDriver newDP v1 ;set's up a direct page referenced by d1. lda d1.driverAddr+1 ;If there is a loaded driver beq noLoadDriver lda d1.driverStatus ; If the driver is initialized brTrue @notInit _KillPlayer ; reset the player @notInit ; endif wordResult ; echos user ID pei d1.driverID ; ID for the driver pea 0 ; purge with extreme prejudice _UserShutDown _ToolErrors dispErrFlag pla pei d1.driverID _DeleteID stz d1.driverAddr ; no driver loaded; clear address stz d1.driverAddr+2 noLoadDriver ;endif pld rtl ENDP As for actually calling the driver, I chose to make it easy on myself. I just use the same direct page for the caller and the driver. There is one entry point to the driver and I put a command number in the x register, which is used to fetch the routine pointer from a call table. I also use the a and y registers for passing parameters. Obviously, you could pass a parameter block pointer instead. So to call the driver I did something like this: playerDispatch PROC EXPORT newDP v1 ;set's up a direct page referenced by d1. lda d1.driverAddr+1 ;has a driver been installed? bne @gotDriver ;yes ;Try installing a default player jsl getDefPlayer bcc @gotDriver ;For whatever reason there is none. Alert the user. ldx #noDriverAlert jsr driverAlert bra exitDriver @gotDriver ;A driver is installed. See what the driver status is. There some other stuff in here, but the important thing is the call itself, which looks like the following. Note that I set my program bank to 0. The reference to v1.driverAddr is an absolute addressing reference to d1.driverAddr above, which is a direct page reference to the same location. phk ;fake a subroutine call pea firstReturn-1 jmp [v1.driverAddr] firstReturn bcc @goodInit jsr failedInit bcc @goodInit ;possible if the error was just a warning bra exitDriver @goodInit The driver itself receives the call and jumps to the correct routine based on the x register. ;----------------------------------------------- ; Top level for driver. Sets up for calling the individual routines. ; Parameters can be passed both ways in a/y. ; mainEntry phb ;save the data bank phk ;set data bank=code bank plb pha ;save a and reserve an RTS slot tsc ;save the stack pointer sta restoreStack pla ;get register A back cpx #callTableEnd-callTable-1 bge @invalidCall jsr (callTable,x) ;lda restoreStack/tcs/rts will bring us here bra @endInvalid @invalidCall sec lda #pErrUnsupported @endInvalid LONG ;just in case bcs @playerError ;If there is no error stz d1.driverStatus ;let everyone know @playerError plb rtl ;These are all of the calls that need to be handled by the driver. Calls that are ;not supported by the driver should return pErrUnsupported with the carry set. ;all calls return with an rts. callTable dc.w initCode dc.w startDisc dc.w chapterSearch dc.w frameSearch dc.w playDisc dc.w version dc.w model etc....you don't need to see them all. callTableEnd ;************************************************************************** ; Initialize communications for this player ; Enter with a = playerPort ; y = initCode, which is a player option that has previously ; been used to successfully init the player. 0 means that ; the player has never been initialized. ; Returns the successful player option in a. ; initCode etc.... Sorry if it looks like a mess. I threw it together as fast as I could. It should get you thinking in the right direction. Hope it helps. -- John Heaney The Devil is in the details. heaney@crl.com