+Lee Stewart Posted April 27, 2014 Author Share Posted April 27, 2014 Lee, you could potentially keep things the same--if you put an E/A grom in your cartridge using an ÜberGROM board. . .bonus there is that the cart then can become a dual-use item if you leave the option to boot it into the E/A. Gazoo's GPL loader could also be modified to help here, as it then guarantees the boot bank of the cartridge by setting it during the GPL power-up routines. I may be off-base here, but I hope the idea is of use. Thanks, Jim. That's an option I hadn't considered. I still think I want to keep it to a 32KB – 64KB ROM; but, it certainly is worth considering. Thanks again. ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted April 28, 2014 Author Share Posted April 28, 2014 (edited) Regarding using MG's Univeral GPLLNK/DSRLNK (see following spoiler), I do not see where it checks >8350 for any error when DSRLNK is called with >A instead of >8. *--------------------------------------------------------------------* * GPLLNK- A universal GPLLNK - 6/21/85 - MG * * This routine will work with any GROM library slot since it is * * indexed off of R13 in the GPLWS. (It does require Mem Expansion) * * This GPLLNK does NOT require a module to be plugged into the * * GROM port so it will work with the Editor/Assembler, * * Mini Memory (with Mem Expansion), Extended Basic, the Myarc * * CALL LR("DSKx.xxx") or the CorComp Disk Manager Loaders. * * It saves and restores the current GROM Address in case you want * * to return back to GROM for Basic or Extended Basic CALL LINKs * * or to return to the loading module. * * * * ENTER: The same way as the E/A GPLLNK, i.e., BLWP @GPLLNK * * DATA >34 * * * * NOTES: Do Not REF GPLLNK when using this routine in your code. * * * * 70 Bytes - including the GPLLNK Workspace * *--------------------------------------------------------------------* GPLWS EQU >83E0 GPL workspace GR4 EQU GPLWS+8 GPL workspace R4 GR6 EQU GPLWS+12 GPL workspace R6 STKPNT EQU >8373 GPL Stack pointer LDGADD EQU >60 Load & ECUTE GROM address entry point XTAB27 EQU >200E Low Mem XML table location 27 GETSTK EQU >166C GPLLNK DATA GLNKWS R7 Set up BLWP Vectors DATA GLINK1 R8 RTNAD DATA XMLRTN R9 address where GPL XML returns to us GXMLAD DATA >176C R10 GROM Address for GPL XML (0F 27 Opcode) DATA >50 R11 Initialized to >50 where PUTSTK address resides GLNKWS EQU $->18 GPLLNK's workspace of which only BSS >08 R12-R15 ...registers R7 through R15 are used GLINK1 MOV *R11,@GR4 Put PUTSTK Address into R4 of GPL WS MOV *R14+,@GR6 Put GPL Routine Address in R6 of GPL WS MOV @XTAB27,R12 Save the value at >200E MOV R9,@XTAB27 Put XMLRTN Address into >200E LWPI GPLWS Load GPL WS BL *R4 Save current GROM Address on stack MOV @GXMLAD,@>8302(R4) Push GPL XML Add on stack for GPL ReTurn INCT @STKPNT Adjust the stack pointer B @LDGADD Execute our GPL Routine XMLRTN MOV @GETSTK,R4 Get GETSTK pointer BL *R4 Restore GROM address off the stack LWPI GLNKWS Load our WS MOV R12,@XTAB27 Restore >200E RTWP All Done - Return to Caller *--------------------------------------------------------------------* * DSRLNK - A Universal Device Service Routine Link - MG * * (Uses console GROM 0's DSRLNK routine) * * (Do not REF DSRLNK or GPLLNK when using these routines) * * (This DSRLNK will also handle Subprograms and CS1, CS2) * * * * ENTER: The same way as the E/A DSRLNK, i.e., BLWP @DSRLNK * * DATA 8 * * * * NOTES: Must be used with a GPLLNK routine * * Returns ERRORs the same as the E/A DSRLNK * * EQ bit set on return if error * * ERROR CODE in caller's MSB of Register 0 on return * * * * 186 Bytes total - including GPLLNK, DSRLNK and both Workspaces * *--------------------------------------------------------------------* PUTSTK EQU >50 Push GROM Add to stack pointer TYPE EQU >836D DSRLNK Type byte for GPL DSRLNK NAMLEN EQU >8356 Device name length pointer in VDP PAB VWA EQU >8C02 VDP Write Address location VRD EQU >8800 VDP Read Data byte location GR4LB EQU >83E9 GPL Workspace R4 Lower byte GSTAT EQU >837C GPL Status byte location DSRLNK DATA DSRWS,DLINK1 Set BLWP Vectors DSRWS EQU $ Start of DSRLNK workspace DR3LB EQU $+7 lower byte of DSRLNK workspace R3 DLINK1 MOV R12,R12 R0 Have we already looked up the LINK address? JNE DLINK3 R1 YES! Skip lookup routine *<<-------------------------------------------------------------------------->>* * This section of code is only executed once to find the GROM address * * for the GPL DSRNK - which is placed at DSRADD and R12 is set to >2000 * * to indicate that the address is found and to be used as a mask for EQ & CND * *------------------------------------------------------------------------------* LWPI GPLWS R2,R3 else load GPL workspace MOV @PUTSTK,R4 R4,R5 Store current GROM address on the stack BL *R4 R6 LI R4,>11 R7,R8 Load R4 with address of LINK routine vector MOVB R4,@>402(R13) R9,R10 Set up GROM with address for vector ***les*** Note on above instruction: ***les*** 1. R13 of GPLWS has >9800=GRMRD (GROM Read Data) ***les*** 2. >402 added to GRMRD yields >9C02=GRMWA (GROM Write Address) JMP DLINK2 R11 Jump around R12-R15 DATA 0 R12 contains >2000 flag when set DATA 0,0,0 R13-R15 contains WS, PC & ST for RTWP DLINK2 MOVB @GR4LB,@>402(R13) Finish setting up GROM address MOV @GETSTK,R5 Take some time & set up GETSTK pointer MOVB *R13,@DSRAD1 Get the GPL DSR LINK vector INCT @DSRADD Adjust it to get past GPL FETCH instruction BL *R5 Restore the GROM address off the stack LWPI DSRWS Reload DSRLNK workspace LI R12,>2000 Set flag to signify DSRLNK address is set *<<-------------------------------------------------------------------------->>* DLINK3 INC R14 Adjust R14 to point to caller's DSR Type byte MOVB *R14+,@TYPE Move it into >836D for GPL DSRLNK MOV @NAMLEN,R3 Save VDP address of Name Length AI R3,-8 Adjust it to point to PAB Flag byte BLWP @GPLLNK Execute DSR LINK DSRADD BYTE >03 High byte of GPL DSRLNK address DSRAD1 BYTE >00 Lower byte of GPL DSRLNK address *----Error Check & Report to Caller's R0 and EQU bit------------------------- MOVB @DR3LB,@VWA Set up LSB of VDP Add for Error Flag MOVB R3,@VWA Set up MSB of VDP Add for Error Flag SZCB R12,R15 Clear EQ bit for Error Report MOVB @VRD,R3 Get PAB Error Flag SRL R3,5 Adjust it to 0-7 error code MOVB R3,*R13 Put it into Caller's R0 (msb) JNE SETEQ If it's not zero, set EQ bit COC @GSTAT,R12 Else, test CND bit for Link Error (00) JNE DSREND No Error, Just return SETEQ SOCB R12,R15 Error, so set Caller's EQ bit DSREND RTWP All Done - Return to Caller The DSRLNK coded by Paolo Bagnaresi et al. is basically the same as what is used in fbForth except for the explicit checking of >8350 if the >A (subroutine) route is taken. This seems to be what sets it apart from the DSRLNK in fbForth, TI Forth and the above MG routine. I suppose I can use whatever is easiest to include in fbForth 2.0 as long as I include the >8350 check or, at the very least, include a caveat to users. In all fairness to the TI programmers, they did not actually code a word to use DSRLNK for subroutines (>A), so the Forth programmer would be on her/his own there, anyway. Since I am trying to be as compatible as possible with TI Forth, I probably don't need to bother with it, either—except, possibly, in a discussion about how the Forth programmer might use DSRLNK >A if they really needed it. Sorry for rambling—just thinking out loud.... ...lee Edited April 28, 2014 by Lee Stewart Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted April 28, 2014 Author Share Posted April 28, 2014 How do I set up ALC in a ROM bank so that it can later be copied from ROM to RAM? Can I use DORG within the ROM space (>6000 – >7FFF) prior to the block of code I want to move? I understand how @Willsy did it in TurboForth for small blocks of code by using EQUates; but, I need to move a sizable block to low RAM and would prefer to avoid using a relative EQUate for every label after the first. ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted April 28, 2014 Author Share Posted April 28, 2014 One way (perhaps the only way) I see to use DORG in ROM space to work out copying a large block of code (~2600 bytes!) to RAM is to copy the relevant code into ROM space preceded by DORGing the starting RAM address. Then, I could follow that code with a copy without any labels except one at the beginning and one at the end to facilitate copying. The only problem is to work out a consistent way to blank all the labels automagically. I suppose I could write a sed (or similar utility) script to do my bidding. Any other suggestions? ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted April 29, 2014 Author Share Posted April 29, 2014 I hit upon a way to use EQUates that is somewhat less painful for large blocks of ALC than @Willsy's method. The following snippet is from TurboForth ALC and that is followed by how I would do it now: @Willsy's— docol equ >8320 ; address of this routine in PAD toRAM dect rstack ; make space on return stack mov pc,*rstack ; save PC to return stack mov r6,pc ; place in PC and drop down to NEXT ;NEXT ; loads the next CFA and branches to the address in the CFA. _next equ docol+6 ; address of this routine in PAD mov *pc+,r6 ; get CFA in r6 mov *r6+,r7 ; get contents of CFA b *r7 ; execute it ;EXIT ; exits from a FORTH high level word (i.e. a word entered with DOCOL) exit equ _next+6 ; address of this routine in PAD data exit+2 ; called by NEXT, so needs a pointer mov *rstack+,pc ; place saved PC into PC & pop return stack b *next ; do next instruction Mine— docol equ >8320 ; address of this routine in PAD toRAM dect rstack ; make space on return stack mov pc,*rstack ; save PC to return stack mov r6,pc ; place in PC and drop down to NEXT ;NEXT ; loads the next CFA and branches to the address in the CFA. _next equ docol+$-toRAM ; address of this routine in PAD mov *pc+,r6 ; get CFA in r6 mov *r6+,r7 ; get contents of CFA b *r7 ; execute it ;EXIT ; exits from a FORTH high level word (i.e. a word entered with DOCOL) exit equ docol+$-toRAM ; address of this routine in PAD data exit+2 ; called by NEXT, so needs a pointer mov *rstack+,pc ; place saved PC into PC & pop return stack b *next ; do next instruction Note lines 8 and 15 in each snippet. In my modification, every label after the first is EQUated to docol+$-toRAM, which correctly tracks the addresses. This works and is only tedious initially. I can test it before hoisting to ROM by simply manipulating the docol EQUate, if necessary. ...lee 2 Quote Link to comment Share on other sites More sharing options...
Willsy Posted April 29, 2014 Share Posted April 29, 2014 Oh me likey velly much! Yoo velly clever! I'm going to steal that technique Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted April 29, 2014 Author Share Posted April 29, 2014 Oh me likey velly much! Yoo velly clever! I'm going to steal that technique Have at it! And, to think I can occasionally still do this, even at my advanced age! ...lee 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted May 1, 2014 Author Share Posted May 1, 2014 (edited) Making headway! I may have a first run at an fbForth 2.0 cartridge very soon! Just as soon as I can reduce the dictionary footprint by a few hundred more bytes to do a test, I should be able to do my first proof of concept. Woo-hoo! ...lee Edited May 1, 2014 by Lee Stewart 1 Quote Link to comment Share on other sites More sharing options...
+Ksarul Posted May 1, 2014 Share Posted May 1, 2014 Excellent! I like this thought. . . Quote Link to comment Share on other sites More sharing options...
Willsy Posted May 1, 2014 Share Posted May 1, 2014 Get at it Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted May 2, 2014 Author Share Posted May 2, 2014 I'm trying to figure out which words in the resident dictionary are good candidates for moving their payload to other ROM banks with stubs in bank0. I figure words involved with interpretation could probably be moved without a big performance hit—words like (FIND) and ENCLOSE , perhaps. I am looking particularly at the words that involve the most code—I'll post a list soon. Any suggestions? ...lee Quote Link to comment Share on other sites More sharing options...
Willsy Posted May 2, 2014 Share Posted May 2, 2014 This was an issue for me, too. In the end, I kept (what I felt were) the most commonly used words, and/or short words in bank 0. That amounted to: The most commonly used stack used stack words; The most commonly used math words; Run-time looping e.g. (DO) (LOOP) et al; Anything that was implemented in Forth. In later releases that got changed, as I moved some common stack and math words to pad ram for added whizziness! Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted May 2, 2014 Author Share Posted May 2, 2014 ... In later releases that got changed, as I moved some common stack and math words to pad ram for added whizziness! How did you handle the problem with location >8370? Your currently available source does not have that fixed. I'm guessing you just use two copy loops—one that ends before >836E and a second that begins at >837E. ...lee Quote Link to comment Share on other sites More sharing options...
Willsy Posted May 2, 2014 Share Posted May 2, 2014 Yep I think that's what I did. Must update the source! Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted May 2, 2014 Author Share Posted May 2, 2014 Another thought — Currently, the headers in fbForth from EXECUTE – TASK consume 3KB of space in the resident dictionary, with an average of ~10 bytes/word (min: 4 bytes; max: 16 bytes). If I put the headers in another bank, I could recover that 3KB in bank 0 for the extra words I want to put there. I would need to re-write all the words that search the linked list of words; but, I think that is pretty small. It would increase the time for compilation of new words; but, that is a slow process, anyway. Execution won't be any slower except for words that involve word searches. I wonder if that is too big a sacrifice.... ...lee Quote Link to comment Share on other sites More sharing options...
+Ksarul Posted May 2, 2014 Share Posted May 2, 2014 It depends on what you want to hoist into its place, Lee. If it is something important, I would say do it. If it is just a nice to have, and that item would work fine outside of bank 0, then it really just depends on how much work you want to put into it. Quote Link to comment Share on other sites More sharing options...
Willsy Posted May 2, 2014 Share Posted May 2, 2014 Yep I think that's what I did. Must update the source! Checked this evening. Looks like the source is up-to-date. The code to restore scratch-pad does indeed write two sections to pad, but it's a single routine. Scroll to the bottom of 1-06-Blocks Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted May 3, 2014 Author Share Posted May 3, 2014 (edited) Checked this evening. Looks like the source is up-to-date. The code to restore scratch-pad does indeed write two sections to pad, but it's a single routine. Scroll to the bottom of 1-06-Blocks Not by my read. There's only one copy of the block of code between toRAM and copyend. The code between _lit and _dup is written right over >836E – >837E, destroying the integrity of the DSR buffers in high VRAM if >8370 was other than >37D7, which is the case for the nanoPEB and CF7+. That DATA statement needs to be bypassed so that >8370 remains as it was before the copy. EDIT: I was hitting a cached copy. I see the fix, now. ...lee Edited May 9, 2014 by Lee Stewart Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted May 8, 2014 Author Share Posted May 8, 2014 During an exchange of PMs with @Willsy on the subject of splitting the Forth headers out to another bank for added space in bank 0, I think I am convinced of its viability. Consequently, I will try to work out what I need to do with the dictionary searching/manipulating words by modifying the headers of a handful of words at the beginning of the dictionary. This will be truly like trying to keep several balls in the air at once. Should be fun! I will report back, periodically. ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted May 9, 2014 Author Share Posted May 9, 2014 Prototyping the header split-out is coming along nicely. So far, the only snags I've run into are the user variables, CONTEXT and CURRENT , which store the vlfas (vocabulary link field addresses) of the context and current vocabularies, respectively. I can mitigate part of the problem by putting the vocabulary words currently in the resident dictionary ( FORTH and ASSEMBLER ) into RAM. The other part of the problem is that, if the user dereferences one of those vlfas, it will be pointing to the wrong bank because the default bank will be bank 0, not the bank with the headers. LATEST does this with CURRENT @ @ , which could also be a problem. As long as the resulting nfas (name field addresses) are only ever used by dictionary search/manipulation routines, all will be well. I certainly have control of what words in the resident dictionary do with an nfa or lfa (link field address), but none over what a user might decide to do, other than a stern and prominent caveat. I will certainly need to proceed carefully through these murky waters. ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted May 11, 2014 Author Share Posted May 11, 2014 Wouldn't you know it—while slogging through this cartridge project, I found a bug in CREATE ! It really only matters if a user decides to change the maximum width of the names of new word definitions to some value less than 31. I may or may not fix it for fbForth 1.0. I have fixed it for the fbForth 2.0 cartridge version. Otherwise, progress is slow but happening. I'm still a little concerned about CONTEXT and CURRENT . I'm still on the split-header path—we'll see... ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted May 12, 2014 Author Share Posted May 12, 2014 Woohoo! I pretty much have all of the header words working with a handful of headers split out to a location different from the physical location of the code fields and parameter fields. There may be one or two additional words that need to go with the headers, but that's it. Now, it's mostly the tedium of logistics to hoist the code into cartridge space. The most tedious task will be splitting out all 314 of the headers in the resident dictionary. I also need to move (or convert to ALC and move) some of the longer words out of bank 0. Once I do all that, I should be able to plan and execute the conversion—still a little ways off. If all of the above gives me enough additional space in bank 0, I want to hoist all of the file I/O and graphics words into cartridge space. Oh—I almost forgot about the editors—I want to put them in cartridge space, as well.... ...lee 2 Quote Link to comment Share on other sites More sharing options...
Willsy Posted May 13, 2014 Share Posted May 13, 2014 It's going to be awesome! Quote Link to comment Share on other sites More sharing options...
+Ksarul Posted May 13, 2014 Share Posted May 13, 2014 Excellent news, Lee! I can't wait to play with it! Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted May 14, 2014 Author Share Posted May 14, 2014 OK, I got the headers all moved, the redundant labels commented out and the threaded list of pfa pointers added! I thought this was going to take me a week or two; but, with the help of a few macros in Notepad++, I got it done in a couple of days! Moving right along.... ...lee 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.