+Lee Stewart Posted October 12, 2012 Author Share Posted October 12, 2012 Possibly! If could remember how fixSP works Does it get the address from a vector or is hard-coded? It would be better if FP AL routines restored the scratch-pad environment prior to returning to Forth, IMHO. It would certainly be faster. I guess you are looking for a definitive answer. Please proceed along the lines of AL routines restoring scratch-pad themselves by means of the built in subroutine in the TF ROM. So, yes, the FP Forth code would change in so far as calls to fixSP would be removed, and fixSP itself would be eliminated. Mark It gets the address from the same vector. I asked the question because the two actions are very different. fixSP uses it as the address from which to start copying 34 bytes to restore TF's scratchpad RAM. The routine you just posted branches to code at the vectored address. Of course, the code I'm looking at for fixSP is TF Assembler code that may not be up to date. Your last CODEd fixSP in the FP package may be different. I did not disassemble it to find out. ...lee Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 12, 2012 Share Posted October 12, 2012 Wow Lee! Excellent work on spotting that one! You're right, the build I posted earlier today contained the wrong address in the vector. It was pointing to the scratchpad code itself, rather than the code to restore the scratch-pad. Doh. Please use the build below. It loads PADVEC (>A010) with the address >6AEC (do $A010 @ $. to confirm). I can confirm categorically that the address held in PADVEC is the address of *code* in bank1 that restores the scratch-pad code. The code returns to the caller with an RT instruction. See the end of the file 1-06-Blocks.a99 New build and zipped source code attached. Apologies for any confusion caused! Sometimes I get confused myself! Mark TF-V1.2-12-OCT-2012-II.zip TF-V1.2-Source-12-Oct-2010.zip Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 12, 2012 Author Share Posted October 12, 2012 Wow Lee! Excellent work on spotting that one! You're right, the build I posted earlier today contained the wrong address in the vector. It was pointing to the scratchpad code itself, rather than the code to restore the scratch-pad. Doh. Please use the build below. It loads PADVEC (>A010) with the address >6AEC (do $A010 @ $. to confirm). I can confirm categorically that the address held in PADVEC is the address of *code* in bank1 that restores the scratch-pad code. The code returns to the caller with an RT instruction. See the end of the file 1-06-Blocks.a99 New build and zipped source code attached. Apologies for any confusion caused! Sometimes I get confused myself! Mark That does mean, then, that fixSP will have to be changed in the FP package because I am pretty sure that it is copying code itself using that vector. Either that or managing the returns fron xmllnk and gpllnk some other way as you suggested with dsrlnk. Actually, that may not be possible until v2.0 with the possible inclusion of the MDOS-derived package because the contents of 8354h (FP error) has to be captured before restoring TF. ...lee Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 12, 2012 Share Posted October 12, 2012 One solution to that is to simply have the FP routines push >8354 to the data stack, or, if that's inconvenient, to a Forth variable. VARIABLE FP_ERR ASM: SomeFPFunction ... ... <fp incantations!> ... $8354 @@ FP_ERR @@ MOV, \ load variable with fp error code ;ASM Hmmm... You're not using a Forth assembler, though are you...? So, if you don't want to push the FP error code to the stack every time (and I can't blame you for that) then you'd need a word to initialise the 'bridge' between the FP assembly code and Forth. It may do nothing more than tell the assembly routines the address of the FP_ERR variable: VARIABLE FP_ERR : FP_INIT ( 'fp_err -- ) $xxxx ! ; FP_ERR FP_INIT Here, FP_INIT takes the address of FP_ERR and supplies it to the FP code (by poking an address (probably a hard coded address) which is known to your machine code). Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 12, 2012 Author Share Posted October 12, 2012 One solution to that is to simply have the FP routines push >8354 to the data stack, or, if that's inconvenient, to a Forth variable. VARIABLE FP_ERR ASM: SomeFPFunction ... ... <fp incantations!> ... $8354 @@ FP_ERR @@ MOV, \ load variable with fp error code ;ASM Hmmm... You're not using a Forth assembler, though are you...? So, if you don't want to push the FP error code to the stack every time (and I can't blame you for that) then you'd need a word to initialise the 'bridge' between the FP assembly code and Forth. It may do nothing more than tell the assembly routines the address of the FP_ERR variable: VARIABLE FP_ERR : FP_INIT ( 'fp_err -- ) $xxxx ! ; FP_ERR FP_INIT Here, FP_INIT takes the address of FP_ERR and supplies it to the FP code (by poking an address (probably a hard coded address) which is known to your machine code). But, I am using the Forth assembler when needed. You may recall that I rewrote your gpllnk for the transcendentals. I will use whatever we need to use. I actually thought of the data stack solution, but there seemed to be too much work otherwise to shoehorn that in. The problem with putting the fixSP code inside of gpllnk is, I think, that gpllnk can be used for functions that don't use the FP error location. ...lee Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 12, 2012 Share Posted October 12, 2012 Hmmm... Okay, I think I see what you are saying. I was assuming here that transcendentals, and the FP library will be dumped and re-implemented using your FP library. That was certainly my intention. So GPLLNK wouldn't be called at all. It wouldn't even be present! Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 12, 2012 Share Posted October 12, 2012 I guess what I'm saying here is, I don't see where GPLLNK enters the equation (sorry for the pun!) with a newly implemented, native FP suite. Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 12, 2012 Author Share Posted October 12, 2012 I guess what I'm saying here is, I don't see where GPLLNK enters the equation (sorry for the pun!) with a newly implemented, native FP suite. ...so, you would like to include the FP library (FPL) in v1.2? If that is the case, I guess I need to get cracking! Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 12, 2012 Share Posted October 12, 2012 Yes I would. I think it would be a great feature, for both TIF and TF. There's really nothing wrong with TI FP stuff in terms of their accuracy, but interfacing to them in AL is a PITA, as we know! The big issue is the pesky 256 bytes of pad. Why oh why couldn't they have put more RAM in there?! Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 12, 2012 Author Share Posted October 12, 2012 Yes I would. I think it would be a great feature, for both TIF and TF. There's really nothing wrong with TI FP stuff in terms of their accuracy, but interfacing to them in AL is a PITA, as we know! The big issue is the pesky 256 bytes of pad. Why oh why couldn't they have put more RAM in there?! OK, Chief, I'll get on it right away! Well, after I get back from yet another party! Maybe, tomorrow... ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 14, 2012 Author Share Posted October 14, 2012 (edited) Floating Point Library--- OK, here's the TF assembler code for DSRLNK to invoke the cartridge ROM dsrlnk. Whatever this shakes out as could be used for other applications of dsrlnk; but, here I am only interested in using it to load the memory image of the FPL. Then, I can FORGET the first word that is used only for the image load, NL_PTR in this case, before going on to load the TF FP package: \ Prior to calling DSRLNK, \ 1. A PAB must be set up in VDP RAM, \ 2. A pointer (NL_PTR) to PAB+9 (filename length byte) \ shoud be set up to pass into DSRLNK and \ 3. The subroutine number (>8 or >A) should be on the stack. 0 VALUE NL_PTR 0 VALUE DSR_ERR ASM: DSRLNK ( subr -- ) $6000 @@ CLR, \ select bank 1 NL_PTR @@ $8356 @@ MOV, \ PAB+9 pointer R7 $0420 LI, \ construct BLWP instruction $A00C @@ R8 MOV, \ to DSRLNK *SP+ R9 MOV, \ pop DSR subroutine (8 or Ah) from stack R10 $045B LI, \ construct B *Rll instruction $830E @@ BL, \ execute above instructions at R7 $837C @@ R0 MOVB, \ get I/O error R0 $20 ANDI, \ pick off COND bit R0 DSR_ERR @@ MOV, \ move I/O error to DSR_ERR $A010 @@ R0 MOV, \ read pointer to scratchpad restore code R0 ** BL, \ restore scratchpad $6002 @@ CLR, \ select bank 0 ;ASM \ back to Forth The code that actually executes the branch to dsrlnk in cartridge ROM space is put in R7-R10, which is then launched. R11 gets used in the return from that code. Next, the error return is jammed into DSR_ERR to check for a DSR error. Perhaps I should also check the status byte of the PAB for specific file I/O errors. Finally, scratchpad RAM is restored before returning to TF. Anyway, the point of this post, besides showing you where I am with the FPL, is to get feedback on how this may need to be changed to get the desired result. You see, I haven't actually run it yet. ...lee Edited October 14, 2012 by Lee Stewart Quote Link to comment Share on other sites More sharing options...
Rod Van Orden Posted October 14, 2012 Share Posted October 14, 2012 Don't worry, Lee. When Einstein came up with E = M C **2, he hadn't run that yet either........... har har har.........! Rod Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 14, 2012 Share Posted October 14, 2012 Hi Lee, Nice job. I like the technique of executing code from within the register workspace. I also use that very same technique. In fact that is how I was able to add the ability to change TF's workspace on the fly (added in the last but one build, IIRC). Looking at your code, I think NL_PTR and DSR_ERR need to be VARIABLEs, not VALUEs. You see, your AL code is reffering to the addresses of the bodies of those words, as if they were variables. However, since they are values they will actually supply their *values* to the AL code, which is zero, which is not what you want! You need variables! I haven't studied the rest in mega detail yet but I thought I would post this as it just 'leapt' out at me from the screen, and it's the sort of bug that could take a while to track down (though Classic99's debugger would soon show you the error of your ways!) leading to a forehead slapping moment Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 14, 2012 Share Posted October 14, 2012 Okay, an additional observation: I could be wrong, but this phrase doesn't look quite right: $837C @@ R0 MOVB, \ get I/O error R0 $20 ANDI, \ pick off COND bit R0 DSR_ERR @@ MOV, \ move I/O error to DSR_ERR You're using a MOVB instruction (high byte) but your ANDI works on the low byte. Shouldn't the ANDI use an argument of >2000? If so, you will probably want to use an extra SWPB to move the result to the low byte just before you write it to the user variable on the Forth side - it's more convenient for the Forth programmer to have the error code 'right justified' IMHO. Mark Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 14, 2012 Share Posted October 14, 2012 One last comment, which isn't so useful, but is maybe worth considering: It should be possible to BSAVE your assembly code (and therefore BLOAD it) thereby not needing DSRLNK at all. This might make it easier during development, as you could assemble the code using the Forth assembler and BSAVE it, rather than using editor assembler, assemble it, create an option 5 etc etc. It's possible to manipulate HERE in TF by means of the variable H. Note: writing to HERE does nothing, but writing to H changes HERE. So: $2000 H ! And we're now compiling to low memory. If you display the variable FFAILM (First free address in low memory) before and after compiling some code you'll see the value change. Also the word MEM is useful (shows free bytes low, high, and total free bytes respectively). BSAVE saves from a start address that you supply, to HERE. So, having loaded your Forth assembler code via a block, you could do: $2000 <block> BSAVE and save the assembly code (in binary format) to a block(s) of your choosing. Now, (as you know) the assembler is not required to be in memory when loading the assembly code back into memory. It should be possible to script the manipulation of HERE during load time from a block; I've never tried it, I must give it a try. If it doesn't work then it strikes me there's a bug hidden somewhere. Anyway, it should be possible, in a block, to do something like this: HERE \ save HERE $2000 H ! \ set HERE 67 BLOAD DROP \ load the FP library into low memory H ! \ restore HERE Now your assembly code is in low memory, without the need for a binary loader, and high-level Forth code will be compiled into high memory, and the dictionary will link up just fine. As I say, it's six and two three's really. I just thought it might make the development cycle a little easier! Personally, that's how I would do it; I'd leverage the Forth environment as much as possible. As you know, it's pretty cool to be able to just type in assembly code and run it immediately! All the cart swapping (even on an emulator) is a pain, and waiting for editor assembler etc..... Blah... I don't think I'd have the patience to write an assembly application on the real hardware any more! FWIW Mark Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 14, 2012 Share Posted October 14, 2012 Just for kicks, I thought I'd post the release note for TF V1.2 as things currently stand (it's not being released yet). It's matured quite a lot, even from V1.1 which was pretty good. There's some useful information in the release note, too. Mark V1.2-ReleaseNote.pdf Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 14, 2012 Author Share Posted October 14, 2012 Hi Lee, Nice job. I like the technique of executing code from within the register workspace. I also use that very same technique. In fact that is how I was able to add the ability to change TF's workspace on the fly (added in the last but one build, IIRC). Looking at your code, I think NL_PTR and DSR_ERR need to be VARIABLEs, not VALUEs. You see, your AL code is reffering to the addresses of the bodies of those words, as if they were variables. However, since they are values they will actually supply their *values* to the AL code, which is zero, which is not what you want! You need variables! I haven't studied the rest in mega detail yet but I thought I would post this as it just 'leapt' out at me from the screen, and it's the sort of bug that could take a while to track down (though Classic99's debugger would soon show you the error of your ways!) leading to a forehead slapping moment Yeah, I don't know what I was thinking! ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 14, 2012 Author Share Posted October 14, 2012 (edited) Okay, an additional observation: I could be wrong, but this phrase doesn't look quite right: $837C @@ R0 MOVB, \ get I/O error R0 $20 ANDI, \ pick off COND bit R0 DSR_ERR @@ MOV, \ move I/O error to DSR_ERR You're using a MOVB instruction (high byte) but your ANDI works on the low byte. Shouldn't the ANDI use an argument of >2000? If so, you will probably want to use an extra SWPB to move the result to the low byte just before you write it to the user variable on the Forth side - it's more convenient for the Forth programmer to have the error code 'right justified' IMHO. Mark Thanks, again! I was in the C@ mode, which word does an 8-bit right shift. That said, I think using " R0 $2000 ANDI, " should work fine because I am only concerned about a non-zero value for DSR_ERR to indicate whether there was an error. H-m-m-m, with that in mind, would it be quicker to use " $837C @@ R0 MOV, " than " $837C @@ R0 MOVB, "? After all, the extra byte is masked out. ...lee Edited October 14, 2012 by Lee Stewart Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 14, 2012 Author Share Posted October 14, 2012 One last comment, which isn't so useful, but is maybe worth considering: It should be possible to BSAVE your assembly code (and therefore BLOAD it) thereby not needing DSRLNK at all. This might make it easier during development, as you could assemble the code using the Forth assembler and BSAVE it, rather than using editor assembler, assemble it, create an option 5 etc etc. ... FWIW Mark This would be an excellent way to do it were I starting from scratch. Here, however, I would need to translate 500 lines of ALC to TF ALC---a bit of a mind-numbing prospect. I will eventually get it down to under 400 lines---maybe even less then 350---still a daunting task. ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 14, 2012 Author Share Posted October 14, 2012 Floating Point Library--- OK, here's my latest attempt at DSRLNK to call into TF cartridge ROM's dsrlnk. It includes all of @Willsy's corrections and an optional method for executing the register code, which may need correcting because I'm not sure I have it right: \ Prior to calling DSRLNK, \ 1. A PAB must be set up in VDP RAM, \ 2. A pointer (NL_PTR) to PAB+9 (filename length byte) \ shoud be set up to pass into DSRLNK and \ 3. The subroutine number (>8 or >A) should be on the stack. VARIABLE NL_PTR VARIABLE DSR_ERR ASM: DSRLNK ( subr -- ) $6000 @@ CLR, \ select bank 1 NL_PTR @@ $8356 @@ MOV, \ PAB+9 pointer R7 $0420 LI, \ construct BLWP instruction $A00C @@ R8 MOV, \ to DSRLNK *SP+ R9 MOV, \ pop DSR subroutine (8 or Ah) from stack R10 $045B LI, \ construct B *Rll instruction $830E @@ BL, \ execute above instructions at R7 \ Maybe should use the following two instructions in place of the \ one above to allow for calling DSRLNK with a different workspace: \ R0 STWP, \ get WP \ 2 R7 * R0 ** + @@ BL, \ execute above instructions at R7 $837C @@ R0 MOV, \ get I/O error R0 $2000 ANDI, \ pick off COND bit R0 DSR_ERR @@ MOV, \ move I/O error to DSR_ERR $A010 @@ R0 MOV, \ read pointer to scratchpad restore code R0 ** BL, \ restore scratchpad $6002 @@ CLR, \ select bank 0 ;ASM \ back to Forth ...lee Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 14, 2012 Share Posted October 14, 2012 Lee, Here's a tested version of your DSRLNK code. I had it loading a file in the Classic99 folder called DEMO (8K long). There were a couple of bugs but nothing you wouldn't have found yourself in less than a minute. I've also added a wrapper, called OPT5 which builds the PAB and calls DSRLNK. Use it like this: S" DSK1.DEMO" OPT5 Your file should be loaded into VDP starting at >1018. That's as far as the code goes. The next step (for in the morning - unless you fancy a hack at it! ) is to add a little bit of code to OPT5 to move the code from VDP to the correct place in CPU ram, which is very easy, just make use of the first 6 bytes loaded into VDP, which tells you all you need to know. OBSERVATION: I tested it with a file called DEMO in the DSK1 folder of classic99. I think you'll have the same file unless you have deleted it. It DOES load the file into VDP (check VDP in the debugger at >1018 and also the messages in the debugger; there are no errors reported in the classic99 debug window). However, the COND bit always comes back as a 1. No idea why. Maybe it's normal? VARIABLE NL_PTR VARIABLE DSR_ERR ASM: DSRLNK ( subr -- ) DSR_ERR @@ CLR, \ zero DSR_ERR $6000 @@ CLR, \ select bank 1 NL_PTR @@ $8356 @@ MOV, \ address of name length byte to >8356 R7 $0420 LI, \ construct BLWP instruction $A00C @@ R8 MOV, \ to DSRLNK *SP+ R9 MOV, \ pop DSR subroutine (8 or Ah) from stack R10 $045B LI, \ construct B *Rll instruction R0 STWP, R0 14 AI, \ R0 points to the address of R7 R0 ** BL, $837C @@ R0 MOVB, \ get I/O error R0 $2000 ANDI, \ pick off COND bit R0 8 SRL, \ move error code to low byte R0 DSR_ERR @@ MOV, \ move I/O error to DSR_ERR $A010 @@ R0 MOV, \ read pointer to scratchpad restore code R0 ** BL, \ restore scratchpad $6002 @@ CLR, \ select bank 0 ;ASM \ back to Forth CREATE PAB_BUF 10 CHARS ALLOT : OPT5 ( "filename" -- ) FLUSH \ purge disk blocks $1000 >R \ address of PAB in VDP PAB_BUF 10 0 FILL \ zero pab 5 PAB_BUF C! \ load op-code to PAB byte 0 R@ 24 + PAB_BUF 2+ ! \ vdp address of loaded data in bytes 2 & 3 $2000 PAB_BUF 6 + ! \ maxi bytes to load in PAB bytes 6 & 7 DUP PAB_BUF 9 + C! \ length of file name to PAB byte 9 R@ 9 + NL_PTR ! \ set NL_PTR with vdp addr of length byte R@ PAB_BUF 10 VMBW \ write pab to VDP R> 10 + -ROT VMBW \ write filename to PAB 8 DSRLNK \ go load the file DSR_ERR @ ?DUP IF CR ." Disk error #" $. \ abort if error THEN ; S" DSK1.DEMO" OPT5 Finally, posted as a simple text file for your convenience. Also, there's a very good chance that a loaded file will spill into the TF block buffers in VDP. Hence the FLUSH in OPT5 before we get funky with the loader. VDP memory map attached for your added enlightenment Enjoy Mark. DSRLNK.txt Memory Map.zip <-- this is for V1.1 but VDP memory has not changed IIRC! [EDIT: I've *no* idea how to preserve the freaking spacing in posted code. Please share your secret with me!] Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 14, 2012 Author Share Posted October 14, 2012 Lee, Here's a tested version of your DSRLNK code. I had it loading a file in the Classic99 folder called DEMO (8K long). There were a couple of bugs but nothing you wouldn't have found yourself in less than a minute. I've also added a wrapper, called OPT5 which builds the PAB and calls DSRLNK. Thanks! I'll have a look later tonight. ... However, the COND bit always comes back as a 1. No idea why. Maybe it's normal? H-m-m-m, maybe it (837Ch) needs to be cleared first? ... Also, there's a very good chance that a loaded file will spill into the TF block buffers in VDP. Hence the FLUSH in OPT5 before we get funky with the loader. ... I haven't looked at OPT5, yet; but, I implied by the name that you think it's an E/A-option-5 file, which it's not. It is a memory image, however. It was saved as a normal object file, loaded, my FPLSAVE object code was loaded, FPLSAVE was run. Running FPLSAVE saves the memory image from 2700h- 3DF5h to DSK2.FPL. Enjoy Mark. [EDIT: I've *no* idea how to preserve the freaking spacing in posted code. Please share your secret with me!] I only manage the indents. The AA editor screws up any other spacing I attempt! The part I want indented I set off with blank lines, block the lines to be indented, hit the "right indent" icon on the toolbar, remove the set-off lines. It seems to keep the indents. ...lee Quote Link to comment Share on other sites More sharing options...
+InsaneMultitasker Posted October 14, 2012 Share Posted October 14, 2012 Thanks! I'll have a look later tonight. H-m-m-m, maybe it (837Ch) needs to be cleared first? A few thoughts: 1. Most DSRLNK routines reset the status bit via R15 of the caller's WS upon entry. Error codes are usually returned either in PAB byte 1 (level 3 IO routines) or 0x8350 (level 1 and 2 routines). The status bit compliments the error byte in determining the type of error. The two docs I reference in the FIXED file thread may be of some value to you. Note: many DSRLNK routines don't test the type of call (8 vs. A) and end up reporting errors for the latter type that aren't truly errors. 2. DSRLNK sets the status bit via the caller's workspace registers. Does this translate into setting/resetting the 837c status bit, ie, are you really testing the status bit you think you're testing? 3. Many (all?) peripheral cards expect DSRLNK to branch to their respective on-card routines using workspace 0x83E0. Strange things happen otherwise. I suspect the routine you are calling follows this convention. Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted October 15, 2012 Author Share Posted October 15, 2012 (edited) A few thoughts: 1. Most DSRLNK routines reset the status bit via R15 of the caller's WS upon entry. Error codes are usually returned either in PAB byte 1 (level 3 IO routines) or 0x8350 (level 1 and 2 routines). The status bit compliments the error byte in determining the type of error. The two docs I reference in the FIXED file thread may be of some value to you. Note: many DSRLNK routines don't test the type of call (8 vs. A) and end up reporting errors for the latter type that aren't truly errors. I had forgotten that level 1 and 2 disk DSR routines use FAC for the transfer block and 8350h of that area to return errors. Perhaps I should make DSRLNK explicitly level 3 ( DSRLNK call 8 ). TF doesn't use any level 1 or 2 calls anyway. That was a carryover from TI Forth. 2. DSRLNK sets the status bit via the caller's workspace registers. Does this translate into setting/resetting the 837c status bit, ie, are you really testing the status bit you think you're testing? 3. Many (all?) peripheral cards expect DSRLNK to branch to their respective on-card routines using workspace 0x83E0. Strange things happen otherwise. I suspect the routine you are calling follows this convention. 837Ch is the GPL status byte, which is checked by TI Forth's level 3 calls to DSRLNK , (it does not use the GPL's DSRLNK) though I cannot seem to find where that location gets set by TI Forth's DSRLNK , by Paolo Bagnaresi's practically identical dsrlnk used by TurboForth or by the DSR that's disassembled on Thierry's website. Both of the dsrlnk routines do, in fact, use the GPL workspace at 83E0h from where they start checking the DSR for the subroutine name until they return, unless there's an error, in which case they set, as you say, R15 (to 2000h) and the caller's R0's high byte to the PAB (PAB+1) or Transfer Block's (8350h) STATUS byte's first 3 bits shifted to the rightmost 3 bits. The complementarity of the COND bit with the PAB status byte (PAB byte 1) is significant IIRC only if the GPL COND bit = 0. If it's 1, it indicates there was a device error. I am also pretty sure that any access to GPL ought to first clear that byte; hence, my question. But apparently, I was laboring under a delusion, which raises the question as to why TI Forth's file management routine CHK-STAT checks the GPL STATUS byte. I guess the bottom line is that, though the file error code can be extracted from PAB+1 or 8350h depending on the call, R0 should already have the error code regardless of subroutine and the status register has the EQ bit set if there was an error. ...lee Edited October 15, 2012 by Lee Stewart Quote Link to comment Share on other sites More sharing options...
Willsy Posted October 15, 2012 Share Posted October 15, 2012 I guess the bottom line is that, though the file error code can be extracted from PAB+1 or 8350h depending on the call, R0 should already have the error code regardless of subroutine and the status register has the EQ bit set if there was an error. ...lee I think that's the long and the short of it, Lee, yes. Certainly, if I have interpreted Paolo's DSRLNK correctly, (which TF uses) then the error code if any is in R0. That's how the higher level code is written in TF, such as BLOCK. You'll see sequences such as: BLWP @DSRLNK DATA 8 JNE ERROR Since R0 will be non-zero on an error. I've posted the blocks source file below, which includes the DSRLNK code (scroll to the bottom). InsaneMultitasker, I'd be grateful if you could cast your eye over it too, and give your interpretation. There's some code towards the end which deals with DSRLNK code 10 calls, but TF only uses code 8 calls. Thanks! Mark 1-06-Blocks.zip 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.