Jump to content
IGNORED

Toward a Better (and Better-Documented) DSRLNK


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

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