Jump to content
IGNORED

Toward a Better (and Better-Documented) DSRLNK


Lee Stewart

Recommended Posts

8 hours ago, TheBF said:

This might be a good use for SAMS page or two so that you could select the block buffers or the utilities under program control. ?

(As long as you don't have to use the utilities on the block buffers) 

 

And there you nailed it. All of the low-level code needed for the return stack, bank-agnostic routines ( trampoline functions, block-I/O functions, VRAM functions, etc.) a handful of editable words ( (ABORT) FORTH ASSEMBLER ), and more. Of course, SAMS could be pressed into service as more block-buffer space, but the question had to do with the possibility of loading the E/A utilities from Forth, which seems an exercise in futility in fbForth because they are already part of the language.

 

...lee

  • Like 3
Link to comment
Share on other sites

14 minutes ago, Lee Stewart said:

...which seems an exercise in futility in fbForth because they are already part of the language.

 

...lee

Yes I was puzzling on that myself since you have VMBW, VMBR and the lot of them in the dictionary.

 

The one thing I toyed with was giving all those VDP words dual access.  The primary version would be a native sub-routine and the Forth words would BL the sub-routines.

I do this now with a sub-routine to set the VDP address in read or write mode.  I don't expose the name, but you can get the address with "carnal knowledge" of VC! and VC@.

 

' VC@ 2 CELLS + CONSTANT RMODE
' VC! 2 CELLS + CONSTANT WMODE

 

I didn't have room in 8K  a few years ago, but I have learned how to be more efficient so it's possible now if I don't expose the sub-routine names for all of them.

Might give it a go.

 

 

Edited by TheBF
typo
  • Like 3
Link to comment
Share on other sites

On 12/6/2023 at 2:32 PM, Lee Stewart said:

The above scenario implies that the initial call to open a file would be

       BLWP @DSRLNK
       DATA 8

 

Probably a question for the Assembly thread, but as I was playing with an example and was questioning....

 

Is there every a time when a value NOT 8 is used after BLWP @DSRLNK?

 

 

Link to comment
Share on other sites

9 hours ago, Lee Stewart said:

 

And there you nailed it. All of the low-level code needed for the return stack, bank-agnostic routines ( trampoline functions, block-I/O functions, VRAM functions, etc.) a handful of editable words ( (ABORT) FORTH ASSEMBLER ), and more. Of course, SAMS could be pressed into service as more block-buffer space, but the question had to do with the possibility of loading the E/A utilities from Forth, which seems an exercise in futility in fbForth because they are already part of the language.

 

...lee

So if they're part of the language of forth already then why is forth slower than assembly?

Or is it that only the utils in forth are faster or as fast as assy? And that the rest of forth, words, are only slower.? 

 

Link to comment
Share on other sites

5 hours ago, dhe said:

 

Probably a question for the Assembly thread, but as I was playing with an example and was questioning....

 

Is there every a time when a value NOT 8 is used after BLWP @DSRLNK?

 

Yes. The datum that follows BLWP @DSRLNK is the offset into the DSR of the list to search. DATA 8 tells DSRLNK to start at >4000+8 = >4008, containing the address of the start of the device list that contains level 3 devices like DSK1, etc., for the TI floppy DSR. DATA 10 starts the search at the address at >400A, the head of the subprogram list that contains level 1 and 2 subprograms.

 

Probably more information than you wanted, but level 1 and 2 subprograms for the TI DSR do not use a PAB as do level 3 DSRs, but rather, a “transfer block” starting at >834A (level 1) or >834C (level 2), which gets populated with information unique to the subprogram. A given transfer block may require an “additional information block” you can place where you want. Error codes are returned in the byte at >8350. Details for all three levels of DSRs/subprograms are in GPL Interface Specification for the 99_4 Disk Peripheral V2.0 03-28-1983.

 

...lee

Edited by Lee Stewart
additional information
  • Like 1
Link to comment
Share on other sites

1 hour ago, GDMike said:

So if they're part of the language of forth already then why is forth slower than assembly?

Or is it that only the utils in forth are faster or as fast as assy? And that the rest of forth, words, are only slower.? 

 

Much of a threaded interpretive language like fbForth is put together with high-level colon definitions that are compilations of cfas, which are addresses of executable code that are interpreted by the inner interpreter, that is, they are executed in turn. This is definitely slower than assembly language code (ALC). There are, however, a significant number of words that are written in ALC. The E/A-utility analogs are among them. They are marginally slower than ALC because they still go through the inner interpreter to get executed.

 

...lee

  • Thanks 1
Link to comment
Share on other sites

To give you some size of code perspective Mike on what Lee described there is an "entry" routine and an "EXIT" in every Forth colon definition.

 

In memory it looks like this:

 

<enter> <cfa> <cfa> .... <cfa>  <exit> 

 

It's not important here to understand the dirty details but you can see how much code runs for each Forth word. 

(The ALC is my dressed up Forth Assembler to help my feeble brain so it has some "pseudo-instructions" like POP etc)

 

The <enter> above is the address of a short piece of code but it still takes some time

l: _enter   IP RPUSH,        \ push IP register onto the return stack
            W IP MOV,        \ move PFA into Forth IP register
           _next JMP,

 

Then Forth's RETURN looks like this. 

l: _exit        IP RPOP,      \ pop an new IP address off return stack 
l: _next   *IP+ W  MOV,       \ move CFA into Working register & incr IP
              *W+  R5 MOV,    \ move contents of CFA to R5 & INCR W
              *R5  B,         \ branch to the address in R5

 

CODE words have overhead.  They look like this. 

<addr_of next_cell> <instruction> ... <instruction> <NEXT>  

At the end they run NEXT like you would use RT in native ALC but next is 3 instructions. 

 

So you can see if you write a code word with one instruction  like the Forth word +  It still has to run those last three instructions in NEXT every time it's finished.

So that's why indirect threaded Forth, which is what this is called, can be 4 to 10 times slower than pure ALC on short routines. 

However in a big application it is usually closer to 2 to 3 times slower.

 

"Thus endeth the lesson" as the Episcopalians say. :)

 

 (I didn't get this stuff for a long time so that's why I wrote this up for you) 

  • Like 1
Link to comment
Share on other sites

And to be fair on a sizable piece of code like VMBW those three instructions at the end in the NEXT routine don't mean very much.

The loop takes way more time. So Lee's utilities run at machine speed. 

  • Like 2
Link to comment
Share on other sites

8 hours ago, TheBF said:

And to be fair on a sizable piece of code like VMBW those three instructions at the end in the NEXT routine don't mean very much.

The loop takes way more time. So Lee's utilities run at machine speed. 

Gotcha. That makes total sense and like Lee said, and what I suspected was that some data is or can be pushed straight to, vmbw, for example and is quick, and other words rely doing math or calcs, and take much more time to accomplish as an example BUT with the advantage of using English words as defining the code function. Which I knew that part.

I just didn't understand that the forth kernel contained some of the basic functions which makes sense now but I didn't know it was there I thought it was compiled later.

Link to comment
Share on other sites

26 minutes ago, GDMike said:

I just didn't understand that the forth kernel contained some of the basic functions which makes sense now but I didn't know it was there I thought it was compiled later.

 

Those low-level functions are stored in the cartridge and copied to low RAM at startup. If you want to wade through it, it is posted on my website (see below), though it is behind a couple of builds:  Menu: Source Code-->Bank 1-->Low Level Support

 

One of these days soon I really will update my website. Sorry about its old age.

 

...lee

  • Like 2
Link to comment
Share on other sites

To compare, the PME (P-Machine Emulator) executing Pascal programs runs through 7-8 instructions (minimum) to execute one p-code. P-codes are the instructions executed by the virtual processor, the PME.

Additional interpretation instructions are executed for instructions that have parameters of some kind.

  • Like 3
Link to comment
Share on other sites

  • 1 month later...

Though I am happy (so far) with this DSRLNK as it stands, using it in fbForth 3.0 will seriously reduce available ROM space. What I would like to do is to modify the MG DSRLNK I am currently using to accommodate my changes to this thread’s DSRLNK, thus minimizing code bloat. I can capture all of the necessary parameters for the PAB parameter block except for the call instance, which gets chewed up by the DSR.

 

It occurred to me that I might be able to manage by unconditionally saving call instance = 1 for all successful DSR calls that go through the CRU search. Then, upon an unsuccessful non-CRU-search call that ought to succeed but has the wrong call instance, simply incrementing the call instance and executing again. If I do this in a loop with no limit, it is unlikely to be an infinite loop, but I probably ought to limit it to 2 or some other low number because I know of no examples of cards other than RS232 that use the call instance—and that is no higher than 2. Do you think 2 is high enough?

 

...lee

Link to comment
Share on other sites

1 hour ago, TheBF said:

Over my pay grade.  Is 'call instance' a DSR parameter? 

 

Yes. The console and E/A sources call it 'version' and, as far as I can tell, it is only used by RS232 cards. For PIO/2, RS232/3, RS232/4 devices, the device name is found and rejected because the version/instance is 1. When it comes back to DSRLNK, the version/instance is incremented and another card is sought. The second RS232 card accepts the device because the version/instance is now 2.

 

...lee

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

43 minutes ago, Lee Stewart said:

 

Yes. The console and E/A sources call it 'version' and, as far as I can tell, it is only used by RS232 cards. For PIO/2, RS232/3, RS232/4 devices, the device name is found and rejected because the version/instance is 1. When it comes back to DSRLNK, the version/instance is incremented and another card is sought. The second RS232 card accepts the device because the version/instance is now 2.

 

...lee

OK. So that is how they handle device name conflicts with two RS232 cards installed?

I had never thought about that problem. Kind of nasty. 

Link to comment
Share on other sites

22 minutes ago, TheBF said:

OK. So that is how they handle device name conflicts with two RS232 cards installed?

I had never thought about that problem. Kind of nasty. 

 

I wouldn’t call that a “device name conflict”. The DSR of RS232 cards handles PIO/1 ,RS232/1, RS232/2 in the first card reached and PIO/2, RS232/3, RS232/4 in the second card reached or not at all—the DSR is the same in both. True device name conflicts involve two or more cards having the same device names expecting to services all matching devices without regard to any other DSR. The card with the lowest CRU will service the device. Cards with higher CRUs will never get the opportunity.

 

...lee

  • Like 1
Link to comment
Share on other sites

20 minutes ago, Lee Stewart said:

 

I wouldn’t call that a “device name conflict”. The DSR of RS232 cards handles PIO/1 ,RS232/1, RS232/2 in the first card reached and PIO/2, RS232/3, RS232/4 in the second card reached or not at all—the DSR is the same in both. True device name conflicts involve two or more cards having the same device names expecting to services all matching devices without regard to any other DSR. The card with the lowest CRU will service the device. Cards with higher CRUs will never get the opportunity.

 

...lee

So when you strap the 2nd RS232 card as a 2nd card, it changes the names in ROM somehow or maps in ROM space with the extra names?

Link to comment
Share on other sites

31 minutes ago, TheBF said:

So when you strap the 2nd RS232 card as a 2nd card, it changes the names in ROM somehow or maps in ROM space with the extra names?

Nah, the code checks the instance number (R1) to know if to ignore the DSRLNK request and pass off to the next card.

 

See here: https://www.unige.ch/medecine/nouspikel/ti99/rs232c.htm#RomDSR

  • Like 2
  • Thanks 1
Link to comment
Share on other sites

49 minutes ago, TheBF said:

So when you strap the 2nd RS232 card as a 2nd card, it changes the names in ROM somehow or maps in ROM space with the extra names?

 

Nope—identical DSR code in both cards. The first thing the DSR does on a hit is to jump to a spot that sets R6 to 1 for the first group of devices and 2 for the second group. What it does next is to compare R6 to R1 (incoming call instance). If they are not equal, the return address is not incremented past the DSRLNKJMP SGO”, which takes DSRLNK to do more CRU device searching, incrementing the call instance on the next hit.

 

...lee

  • Like 3
Link to comment
Share on other sites

On 2/16/2024 at 1:43 PM, Lee Stewart said:

What I would like to do is to modify the MG DSRLNK I am currently using to accommodate my changes to this thread’s DSRLNK, thus minimizing code bloat. I can capture all of the necessary parameters for the PAB parameter block except for the call instance, which gets chewed up by the DSR.

 

As it turns out, after a successful DSRLNK call, neither >8354 (device name length [DNL]) nor >8356 (PAB+10+DNL) survives. >83D2 does still have the address of the next link in the device/subprogram chain, which would allow getting at the DNL to place in >8354, calculating the value to place in >8356, and the address of the DSR routine to run—admittedly a bit more work, but doable. I think the resulting code will still be significantly less than replacing the MG routine with the one we’ve been discussing. We’ll see.

 

...lee

Link to comment
Share on other sites

36 minutes ago, Lee Stewart said:

 

As it turns out, after a successful DSRLNK call, neither >8354 (device name length [DNL]) nor >8356 (PAB+10+DNL) survive. >83D2 does still have the address of the next link in the device/subprogram chain, which would allow getting at the DNL to place in >8354, calculating the value to place in >8356, and the address of the DSR routine to run—admittedly a bit more work, but doable. I think the resulting code will still be significantly less than replacing the MG routine with the one we’ve been discussing. We’ll see.

 

...lee

Could you make use of FbForth's return stack to save 8354, >8356?

This was not something the original TI99 designers had at their disposal.

 

  • Like 1
Link to comment
Share on other sites

23 minutes ago, TheBF said:

Could you make use of fbForth's return stack to save 8354, >8356?

This was not something the original TI99 designers had at their disposal.

 

 

The problem is that the MG DSRLNK goes through GPLLNK to call the console GPL DSRLNK, which is essentially a black box to our code. Those values are managed inside that black box and trashed before our code sees them. The other DSRLNK is under our control, which we can manipulate before and after the actual DSR execution, which allows us to capture everything.

 

...lee

  • Like 1
Link to comment
Share on other sites

Back to the DSRLNK subject of this thread...

 

For consistency, I am thinking that, even though my new PAB has an extra address pointer (PAB parameter block in CPU RAM) at its head, I should still put the name-length byte pointer (old PAB+9; new PAB+11) in >8356 instead of the pointer to the beginning of the new PAB as it currently stands—that is, after all, what gets passed to the DSR. It should then be no difficulty to modify DSRLNK to handle it. That would make one less conceptual change for the programmer. What do you think?

 

...lee

Link to comment
Share on other sites

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...