Jump to content
IGNORED

Toward a Better (and Better-Documented) DSRLNK


Lee Stewart

Recommended Posts

21 hours ago, Lee Stewart said:

I think it is even possible it was used by TI programmers on the 990 computers (@FarmerPotato?), but just not passed on to us in the E/A manual

That's an interesting question. Coincidentally, I was just reading about file access under DX10, a widely-used operating system for a 990.

 

Main difference:

 

GPL  must scan all ROMs for DSRs every time.

DX10 has all the information in one linked list in the operating system, let's call it PDTTBL.  It's permanent--you don't just plug in new devices. (See SYSGEN below)

The CRU address is only used by the DSR code itself.  There's no ROM to turn on.  CRU address is not stashed per file - only in the device PDT entry, which is permanent.

 

(By GPL I mean in the definition of our operating system, the way the 99/4 works.  Documents like 'The GPL interface to the disk peripheral" cover the DSR ROM.)

The OPEN #1 we all started with in TI BASIC?  The #1 is a system-wide concept for DX10: the LUNO or logical unit number!  Before using a device or file, you gave it a LUNO, logical unit number.  The table with LUNO stored file#, name, system buffer address, etc. Maybe it cached the DSR entry point.  There were global LUNOs for printers, and each user created private LUNOs.  

 

BASIC: 

OPEN #1:"DS01.DOCUMNT.DOC", OUTPUT     (DX10 filenames were 7.3 = familiar 10 chars total!)

 

In BASIC on DX10, I imagine it does this:

1. Set LUNO #144 to "DS01.DOCUMNT.DOC". That's done through an XOP. The DSR gets looked up and stashed in the LUNO table. 

 

2. Make a SCB starting with a 0 for DSR, the opcode 0 for OPEN, some flags, 0 for default record length, the LUNO #144 etc. (Our PAB is a subset of this. Alas, PAB has no file #.)

 

3. XOP @SCB,15

4. Check error code

The LUNO is constant through all OPEN,CLOSE,REWIND,CLOSE..

 

Other than through 99/4 BASIC, we have no LUNO table. If there were, that's where DSRLNK would cache the DSR, CRU etc. And the device name need not be a part of every PAB. 


There are many more similarities and differences in the actual DSRs.  The 99/4 interface is clearly a subset of DX10.

 

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

Gobs of detail on what a DSRLNK looks like in DX10.

 

DSRLNK?

PAB?

The analogue of a PAB is a Service Control Block.  All the XOPs have a SCB.  If you make Service Call 0, you fill out the rest of SCB.   The next byte after 0 is the DSR opcode, followed by flags and stuff that would be familiar to us.  

The analogue of DSRLNK is the Service Call 0 (clearly, the first and most important of service calls!)

You first set up a service control block:
 

MYFCB0 
    BYTE 0        * 0 is my desired function, I/O 
    BYTE 0        * say I want the OPEN opcode
... more DATA ...

 

then

 

XOP @MYFCB0,15

 

or

 

DXOP SVC,15.  * makes SVC a macro for XOP 15
SVC @MYFCB0

 

There's some great sample code in DX10 Volume 3 section 

 

 

Operating System Code is much simpler than DSRLNK! 

 

In DX10, inside Service Call 0, I imagine there is some code to match the device name, 2 characters like 'DS' for disk. (CS is cassette!)

It has to walk the global linked list, PDTTBL.  Remember that PDTTBL is permanent and has all the known devices.   Each entry of PDTTBL is analogous to the DSR list under one of our ROM headers. (Thierry calls this list the true DSRs, as opposed to the other linked lists in our ROM.)

 

If the PDTNAM field matches, it calls that DSR with a BLWP.  The DSR gets its own workspace, which is always set up with useful values.  


So I imagine code like this to match the 2 character device name:

 

	LI   R0,'DS'         the device we're looking for
	LI   R1,PDTTBL       pointer to the global table
DSR010
	MOV  *R1,R1          go to first or next entry
 	JEQ  DSR030          ?end of list, device not found
	C    PDTNAM(R1),R0   is this a match for our device?
	JNE	 DSR010
DSR020
	AI   PDT$,R1         point to the BLWP vector
	BLWP *R1             enter the DSR
DSR030
* error, device not found
	ORI  R15,>2000       set the EQ bit (i made this up)
	RTWP
        	

 

See how nice it is to have 2-char device names?  Just one Compare instruction!

 

The PDTTBL is a linked list of this data structure:


Reference:  5.3.1 WS for PDT - physical device table

 

* Layout of a PDT entry (pretend these are all DATA statements)
       DORG 0
PDTLNK        Link to next PDT
PDTMAP         Pointer to DSR map file
PDTR0    R0    Scratch
PDTPRB    R1    Pointer to PRB
PDTSDF    R2    Device status flags
PDTDTF    R3    Device type flags
PDTIB    R4    Pointer to device info block
        R5    Available for the DSR to use
        ...
        R11 
           R12    CRU base
        R13 Saved WS registers for RTWP
        ... 
        R15    
PDT$        PDT workspace address
PDTDSR        DSR entry point
PDTERR, PDTFLG, error code and flags
PDTNAM        Device name (2 characters like 'DS')    
PDTSL1        system log 1
PDTSL2        system log 2
PDTBUF        not used    
PDTBLN         Buffer length
PDTINT      Pointer to DSR interrupt routine
PDTDVQ        Device queue anchor
PDTTM1        Time out count 1
PDTTM2        Time out count 2
PDTSRB        Saved PRB address
PDTFQL        Priority DSR schedule queue word


DX10 enters the DSR with a BLWP. The code above sets up R1 to point to PDT$. After BLWP, the new WP points to the PDTR0 in the record.
The DSR will use RTWP to return.

 

GeneveOS

 

GeneveOS has one 'Master DSR' list like this.  Unfortunately, that ignores our GPL convention. Fortunately, ROMPAGE and the GeneveOS maintainers opened that up to scan PBox cards' DSR ROMs.

 

GEN990 or SYSGEN

 

DX10 is custom assembled and linked on every system when it is installed.  This is neat, because it doesn't bloat up with code for devices or features you don't use.

 

A program called GEN990 asks you about all the peripherals you have connected, the CRU address, the interrupt level, and the filename of each DSR.  From that, it is able to write the source code to make the PDTTBL.  After it generates code, the assembler is invoked.  Then the linker connects all the DX10 object code with the custom object. (actually my knowledge is extrapolated from the SYSGEN of its baby operating system, TXDS, which has all this on floppy disk.)

 

(Caveat: I'm still just a beginner. Read the DX10 books yourself.)

 

 

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

For complete information:

 

DX10 Operating System Application Programming Guide, Volume 3 (946250-9703)
DX10 Operating System Systems Programming Guide, Volume 5 (946250-9705)

 

All volumes  available on Bitsavers

 

See:

 

Volume 3, Section 3: DX10 I/O System
3.5 Logical Unit Numbers and Devices

Volume 3, Section 7:  Using Supervisor Calls (SVCs)
Volume 3, Section 9: Device I/O Supervisor Calls

Volume 3, Section 10: File I/O SVCs
 

Volume 5, Section 5: How to Write a Device Service  Routine
 

  • Like 3
Link to comment
Share on other sites

55 minutes ago, FarmerPotato said:

It has to walk the global linked list, PDTTBL.  Remember that PDTTBL is permanent and has all the known devices.

Similar to how the p-system does. But the p-system allows for a fixed number of devices (on the 99/4A, due to memory constraints), so it's suffcicient with a normal array. You simply index it with the device number to find pointers for where the code to implement the intrinsics unitclearunitread, unitwrite and unitbusy are located.

On machines with bigger memory the table can be larger than the 32 units available in the 99/4A.

Edited by apersson850
  • Like 4
Link to comment
Share on other sites

  • 1 month later...
On 10/3/2023 at 10:37 PM, Lee Stewart said:

In dissecting the various DSRLNK incarnations before the Bagnaresi/Sullivan DSRLNK, I am wondering why all of them, including the E/A version from which they were all derived (as far as I can tell) save the following (labels vary), even though they are not used within the routine or elsewhere (that I can find—maybe someone knows?):

 

SAVCRU DATA 0           CRU Address of the Peripheral
SAVENT DATA 0           Entry Address of DSR or Subprogram
SAVLEN DATA 0           Device or Subprogram name length
SAVPAB DATA 0           Pointer to Device or Subprogram in the PAB
SAVVER DATA 0           Version # of DSR

 

Most or all of these persist long enough to be captured after return to the calling routine without the need to save them in the above manner—even in the console DSRLNK, which does not save them elsewhere. The only one that surely does not survive is SAVVER (GPLWS R1)—and I am not sure it is necessary. Perhaps these saved values were intended for debugging.

 

I am even considering keeping the MG DSRLNK and trying to manage reruns of the various DSRs/subprograms in its shadow. The only feature I would like to have that will likely not be possible is starting the DSR search at a particular CRU address and circling around back to it to complete the search. Folks are probably used to managing CRU addresses in hardware to manage search order, but starting the DSR search at any desired CRU address from >1000 to >1F00 and circling back around to the starting address is a nifty feature of the Bagnaresi/Sullivan DSRLNK, which I kind of hate to give up.

 

Just thinking out loud here....

 

...lee

 

Getting back to this project after a hiatus cleaning up speech and sound management for the upcoming fbForth 3.0, it looks like GPLWS R1 does, in fact, survive a call to DSRLNK if it is sampled immediately following the return from DSRLNK. So...staying with the MG DSRLNK, I will only be giving up the ability of starting at any desired CRU.

 

As to the term DSR “version” saved as SAVVER, I changed them to “instance” and SAVNST, which clarifies the fact that we are not talking about the DSR version stored at >4001, but rather how many times a particular DSR or subprogram name was found before the one that actually worked. I still do not understand the utility of knowing this value, but I suppose I will keep it because the RS232 cards require it (see @JasonACT’s and my posts below.

 

Here is my current version of the Bagnaresi/Sullivan DSRLNK:  DSRLNK_LES_mod_of_Bagnaresi_V3B.a99

 

...lee

  • Like 3
Link to comment
Share on other sites

10 hours ago, Lee Stewart said:

but rather how many times a particular DSR or subprogram name was found before the one that actually worked. I still do not understand the utility of knowing this value, but I suppose I will keep it.

Quote
R1(>83E2) contains the number of time a routine with that name was called. Normally it is 1.
  • The card DSR check the DSR name in VDP memory to know if the user is accessing the first card (RS232, RS232/1, RS232/2, PIO or PIO/1) or the second (RS232/3, RS232/4, PIO/2).
  • If the call is meant for the second card, the routine checks the content of R1 and returns with B *R11 if it is 1. This will cause the DSR scanning routine to keep looking for cards with the same DSR name in their ROMs.
  • If the content of R1 matches the card number, the DSR is executed.

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

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

2 hours ago, JasonACT said:

Thanks for that.  From the above reference on Thierry’s site:

 

R1(>83E2) contains the number of time a routine with that name was called. Normally it is 1.

  • The card DSR check the DSR name in VDP memory to know if the user is accessing the first card (RS232, RS232/1, RS232/2, PIO or PIO/1) or the second (RS232/3, RS232/4, PIO/2).
  • If the call is meant for the second card, the routine checks the content of R1 and returns with B *R11 if it is 1. This will cause the DSR scanning routine to keep looking for cards with the same DSR name in their ROMs.
  • If the content of R1 matches the card number, the DSR is executed.

My focus here has been disk I/O, but, indeed, the above answers the instance question—certainly unnecessary for any disk DSR I know of. I believe the RS232 cards constitute the only case for needing GPLWS R1 preserved. Obviously, calling an RS232 DSR directly without having GPLWS R1 set to 1 or 2 will never work because of the following code from the TI RS232 ROM:

 

A415E  LI   6,>0001           pio pio/1
       JMP  A4168
*    ...
A4164  LI   6,>0002           pio/2
A4168  SETO 3                 R3=pio flag
       CLR  2                 R2=cru base
       JMP  A4190
A416E  LI   6,>0001           rs232 rs232/1
       JMP  A4184
A4174  LI   R6,>0001          rs232/2
       JMP  A418A
A417A  LI   R6,>0002          rs232/4
       JMP  A418A
A4180  LI   R6,>0002          rs232/3
A4184  LI   R2,>0040
       JMP  A418E
A418A  LI   R2,>0080
A418E  CLR  R3
A4190  STWP R4                save workspace (>83E0)
       MOV  R11,@>FF84(R4)    ret address in >8364
       C    R1,R6          <----THIS COMPARISON REQUIRES R1 SET TO..
*                               ..1 (FIRST CARD) OR 2 (SECOND CARD) ELSE---+
       JEQ  A419E             r1: calls the 1st or 2nd program (card)      |
       B    @A4480            ret with error: not found <------------<-----+
A419E  
*    ...
A4480  ANDI 12,>FF00          return
       MOV  @>FF84(4),11      ======
       SBO  2                 handshake out->1
       SBZ  1                 pio
       SBZ  7                 light off
       B    *11

 

Definitely keeping management of GPLWS R1 in place. Thanks again.

 

...lee

  • Like 2
Link to comment
Share on other sites

Just a little update:  Many of you may well already know that I had wrong the value of the PAB pointer passed to the DSR by DSRLNK. I thought it pointed to the filename that follows the ‘.’ separating the device name from the filename. Wrong! It actually points to the ‘.’—I misread the code. I didn’t figure it out until I got deeper into the TI disk DSR ROM. Here is the updated copy of the Bagnaresi/Sullivan DSRLNK routine:

 

DSRLNK_LES_mod_of_Bagnaresi_V3B.a99

 

...lee

  • Like 2
Link to comment
Share on other sites

I have been fighting the virus du jour the last few days so have been mostly horizontal. 

 

When I realized that what DSR really wanted was that address of the '.'  character I thought that it should be in a field in an extended PAB.

That way you eliminate the text searching stuff on file operations after a file was opened. 

I think the DSR code could factored so that there is an entry for FOPEN and an entry for all the other functions.

  • Like 2
  • Sad 2
Link to comment
Share on other sites

6 hours ago, TheBF said:

I have been fighting the virus du jour the last few days so have been mostly horizontal. 

 

I thought you were plagued with a computer virus until I saw “horizontal”. Get well soon (from Platitudes-R-Us)—but, seriously, I hope you mend quickly.

 

6 hours ago, TheBF said:

When I realized that what DSR really wanted was that address of the '.'  character I thought that it should be in a field in an extended PAB.

That way you eliminate the text searching stuff on file operations after a file was opened. 

I think the DSR code could factored so that there is an entry for FOPEN and an entry for all the other functions.

 

That is an interesting idea, but I think you would need too much carnal knowledge of the DSRs for that to work across different controllers. You might craft a workable solution for specific controllers, but that seems like a lot of work for little gain.

 

...lee

  • Like 1
Link to comment
Share on other sites

I am trying to make DSRLNK intelligent by letting it decide whether to search for a DSR/subprogram or to execute an already found DSR/subprogram. If it discovers it does not need to search, I want to have preserved the absolute minimum number of values between calls. For level 3 (DSR offset = 8 ) calls, I think I can rely on >8356 (passed to the DSR and pointing to the VRAM address following the device name) as always pointing to a ‘.’ and thus a unique identifier for level-3 calls. If so, I do not need to preserve the DSR offset between multiple calls to the same DSR. I merely need to check that address for a ‘.’ to decide on whether the offset was 8 or 10 (>A). Is there ever a level-3 call that does not have a ‘.’ following the device name?

 

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

       BLWP @DSRLNK
       DATA 8

 

and subsequent calls for the opened file might be just

       BLWP @DSRLNK

 

Of course, I could just use the normal call with the DATA directive for both contingencies, which would make it unnecessary to answer the above question. I would still like to know, however.

 

...lee

  • Like 1
Link to comment
Share on other sites

2 hours ago, Lee Stewart said:

 Is there ever a level-3 call that does not have a ‘.’ following the device name?

RS232 ? 

This is what I see on my hardware.

image.png.0b39e0e10c9ac349ce73193b9bae6eed.png

2 hours ago, Lee Stewart said:

 

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

       BLWP @DSRLNK
       DATA 8

 

and subsequent calls for the opened file might be just

       BLWP @DSRLNK

 

Of course, I could just use the normal call with the DATA directive for both contingencies, which would make it unnecessary to answer the above question. I would still like to know, however.

 

...lee

 

In the 2nd example would you not have to specify a "0" or some such parameter to indicate that the call does not search for a device? 

 

(I often wonder about passing parameters in the space after the call. I get that it make sense in Assembler but I wonder if it should be done another way for Forth or C) ?

 

 

Link to comment
Share on other sites

1 hour ago, TheBF said:

RS232 ? 

 

Yeah...I had forgotten about no required ‘.’ after the device name for the RS232 card devices.

 

1 hour ago, TheBF said:

In the 2nd example would you not have to specify a "0" or some such parameter to indicate that the call does not search for a device? 

 

No. It is my intention to write a DSRLNK that will figure out whether to search the CRU space for devices or directly execute an already found DSR/subprogram. I am leaning toward requiring the same calling protocol for either contingency. This would allow putting a call into a loop, with only the first call expected to perform the search.

 

1 hour ago, TheBF said:

(I often wonder about passing parameters in the space after the call. I get that it make sense in Assembler but I wonder if it should be done another way for Forth or C) ?

 

That makes sense for Forth and, probably for C, but parameter-passing in Assembler is probably most efficient via DATA directives.

 

...lee

  • Like 1
Link to comment
Share on other sites

My latest version of DSRLNK has the functionality to decide whether to make the CRU search for the appropriate DSR/Subprogram or to go directly to executing the already-found routine. It requires a PAB with an additional 2-byte pointer at the head of the PAB, which contains the address of a 12-byte Parameter Block (PB), the programmer must place in CPU RAM. This PAB Parameter Block has the following structure:

            +-------------------------+
    Byte  0 |  Call Flag (0=no call)  |
            +-------------------------+
    Byte  2 |  DSR/Subprogram Length  |
            +-------------------------+       
    Byte  4 |  Pathname '.' Pointer   |
            +-------------------------+       
    Byte  6 |      Call Instance      |
            +-------------------------+       
    Byte  8 |     DSR Entry Point     |
            +-------------------------+       
    Byte 10 |       CRU of Card       |
            +-------------------------+

 

Every call to DSRLNK must contain the usual trailing DATA 8 or DATA 10. The traditional pathname/subprogram-length pointer, >8356, must now always point to the PAB PB pointer at the head of the PAB. When the PAB and PAB PB are first created, the starting 2 bytes of the PAB PB (Call Flag) must be zeroed to indicate to DSRLNK that this is the first time it has been called for this PAB. A successful call will modify the Call Flag and populate the remainder of the PAB PB for subsequent calls, which will now skip the CRU search for the needed routine. Subsequent calls will read the necessary parameters from the PAB PB and execute the indicated DSR routine.

 

I am sure there are more, careful checks and additional functionality that could be added, but do take a look at the current code and the comments for more details.

 

I have not yet tested the code, so please use the utmost caution if you decide to use it—even for testing! Here is the current version:

 

DSRLNK_LES_mod_of_Bagnaresi_V3B.a99

 

...lee

  • Like 5
Link to comment
Share on other sites

Would like to use the new DSRLNK replacing my own version in Stevie that was based on Paolo’s work. 

Will not be able to do that soon, but I do have it added to my list of todo items. If I remember correctly I had to change some of the registers to make it work with spectra2 (which is the library that Stevie is based on). 

 

So my question is, if necessary, if it would be possible to change register usage with some proper equates on my end.

Anyway, excellent work Lee!

  • Thanks 1
Link to comment
Share on other sites

6 hours ago, retroclouds said:

Would like to use the new DSRLNK replacing my own version in Stevie that was based on Paolo’s work. 

Will not be able to do that soon, but I do have it added to my list of todo items. If I remember correctly I had to change some of the registers to make it work with spectra2 (which is the library that Stevie is based on). 

 

So my question is, if necessary, if it would be possible to change register usage with some proper equates on my end.

Anyway, excellent work Lee!

 

I would think that entirely possible. The only downside I see is the code bloat that might accompany the change.

 

...lee

  • Like 1
Link to comment
Share on other sites

  • 4 weeks later...
On 1/7/2024 at 7:06 AM, Lee Stewart said:

 

Haven’t tested the current code, yet. Got sidetracked with the fbForth SYSTEM utilities mods, Rich’s CALL CHAR(), and the E/A utilities thing over in the Assembly thread. ;-)

 

...lee

Lee what you told me awhile back when I was having problems with working out of the super cart was I didn't have the utilities and so I just copied I think it's 4K or 8K,(I think 4K), out of the hex 2000 address with the EA cart installed and then I just put that back in the 2000 address again when I'm ready to use it The battery back up in the supercart as a storage keeps it from dissolving for me.. And that worked wonderful for me.

BUT... Could it be put on a file and loaded in forth when needed?

Edited by GDMike
  • Thanks 1
Link to comment
Share on other sites

Not sure the best way to do this in FbForth, but the short answer is yes.

You can save up to 8K chunks of RAM as a "program" file and then drop them into memory.

I have some utilities for that.

 

FbForth has BSAVE and BLOAD which might do the job.

Consult Lee's excellent docs. :) 

 

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

12 hours ago, GDMike said:

BUT... Could it be put on a file and loaded in forth when needed?

 

12 hours ago, TheBF said:

Not sure the best way to do this in FbForth, but the short answer is yes.

 

fbForth has its own version of all of the E/A utilities (except for the loader and linker, of course), which are copied to low RAM. If you load the E/A utilities into low RAM (which you can certainly do), you will overwrite those utilities, as well as the Forth block buffers and a host of other low-level stuff fbForth requires to function at all.

 

...lee

  • Like 1
Link to comment
Share on other sites

2 hours ago, Lee Stewart said:

 

 

fbForth has its own version of all of the E/A utilities (except for the loader and linker, of course), which are copied to low RAM. If you load the E/A utilities into low RAM (which you can certainly do), you will overwrite those utilities, as well as the Forth block buffers and a host of other low-level stuff fbForth requires to function at all.

 

...lee

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) 

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...