Jump to content

Recommended Posts

I have created Camel Forth Kernel for TI-99 and the plan is to add ANS/ISO Forth file words to it

so it can extend itself with more source code.

 

I have code that creates and manipulates PABs using the ANS syntax but now I need to

interface to the file system, which is black magic to me.

 

Lee Stewart has graciously provided the source for TI-Forth it has the " Universal Device Service Routine Link by MG"

It looks great but there many things it does that I don't really understand.

 

So if anybody has a place with stash of secret documents I would be delighted to know about them.

 

Or if you have any gotchas to watch out for I would love to know about them too.

 

Thanks in advance.

 

BF

 

I am thinking about now that there might be simpler hobbies to pursue... nah!

  • Like 3
Link to comment
https://forums.atariage.com/topic/262846-dsrlink-code-tutorial/
Share on other sites

Also, look at Chapter 8 “Access to File I/O Using TI-99/4A Device Service Routines” and Appendix K “Diskette Format Details” in fbForth 2.0: A File-Based Cartridge Implementation of TI Forth (see post #1 of fbForth—TI Forth with File-based Block I/O ). Chapter 8 is based on information in the E/A manual. Appendix K is information collected from TI’s Software Specifications for the 99/4 Disk Peripheral (March 28, 1983). And, as @Willsy said, there is lots of help here on this forum.

 

...lee

  • Like 1

The idea behind DSRLNK is pretty simple. Every peripheral device (card) may define a linked list of devices names and a linked list of subprogram IDs. Each element contains the name and an address to branch to. DSRLNK starts with the device at CRU address >1000 (advancing in steps of >0100 until >2000), turns on the ROM of the card, and searches linearly through the list until it finds the given device name or subprogram ID. When found, it branches to the associated address.

Edited by mizapf
  • Like 1

TI BASIC and Extended Basic use a version of DSR LINK to find all the SUBPROGRAM's in the TI.

The TI BASIC versions are not the same as the Extended Basic listings.

 

EXTENDED BASIC

[0573] A026 A0,30    LINK1  DATA LINK2
[0574] A028 05,53,4F        STRI 'SOUND'           SOUND
       A02B 55,4E,44
[0575] A02E AA,3E           DATA XSOUND
[0576] A030 A0,3A    LINK2  DATA LINK3

99/4 GPL-ASSEMBLER (Pass 3) correct                                   PAGE 0010 
EQUATES EXEC-359
[0577] A032 05,43,4C        STRI 'CLEAR'           CLEAR
       A035 45,41,52
[0578] A038 AA,18           DATA CLEAR
[0579] A03A A0,44    LINK3  DATA LINK4
[0580] A03C 05,43,4F        STRI 'COLOR'           COLOR
       A03F 4C,4F,52
[0581] A042 A9,1D           DATA COLOR
[0582] A044 A0,4E    LINK4  DATA LINK5
[0583] A046 05,47,43        STRI 'GCHAR'           GCHAR 
       A049 48,41,52
[0584] A04C A8,FA           DATA GCHAR
[0585] A04E A0,58    LINK5  DATA LINK6
[0586] A050 05,48,43        STRI 'HCHAR'           HCHAR
       A053 48,41,52
[0587] A056 AB,03           DATA HCHAR
[0588] A058 A0,62    LINK6  DATA LINK7
[0589] A05A 05,56,43        STRI 'VCHAR'           VCHAR 
       A05D 48,41,52
[0590] A060 AB,26           DATA VCHAR
[0591] A062 A0,6B    LINK7  DATA LINKA
[0592] A064 04,43,48        STRI 'CHAR'            CHAR 
       A067 41,52
[0593] A069 AB,46           DATA CHARLY
[0594] A06B A0,73    LINKA  DATA LINKB
[0595] A06D 03,4B,45        STRI 'KEY'             KEY
       A070 59
[0596] A071 BC,FD           DATA ZKEY
[0597] A073 A0,7D    LINKB  DATA LINKC
[0598] A075 05,4A,4F        STRI 'JOYST'           JOYST
       A078 59,53,54
[0599] A07B BE,15           DATA ZJOYST
[0600] A07D A0,88    LINKC  DATA LINKD
[0601] A07F 06,53,43        STRI 'SCREEN'          KEY
       A082 52,45,45
       A085 4E
[0602] A086 AC,C9           DATA BORDER
[0603] A088 A0,94    LINKD  DATA LINKE
[0604] A08A 07,56,45        STRI 'VERSION'         VERSION
       A08D 52,53,49
       A090 4F,4E
[0605] A092 AA,1F           DATA VERS
[0606] A094 AE,00    LINKE  DATA LINKS1
[0607] A096 03,45,52        STRI 'ERR'             ERR
       A099 52
[0608] A09A AC,F9           DATA ERRWXY

TI BASIC

4D1A : DATA >4D24 Next entry g
4D1C : DATA >3538 Routine address
4D1E : DATA >05 Length of name
4D1F : TEXT ':SOUND:' name
4D24 : DATA >4D2E
4D26 : DATA >351C
4D28 : DATA >05
4D29 : TEXT ':CLEAR:'
4D2E : DATA >4D38
4D30 : DATA >5713
4D32 : DATA >05
4D33 : TEXT ':COLOR

As you can see the order is not the same so you can not use the SUBPROGRAM search in the OS for Extended Basic it has different version.

Now GPL DSR Links are different too:

 

GPL DSR

<0476> FD2A FD,A6    VEIW40 DATA EADSR             * Viewer 40 Column
<0477> FD2C FD,32           DATA MV40
<0478> FD2E 03,56,34        STRI 'V40'
       FD31 30

The above DSR LINK was a RXB EA device to list in 40 columns called V40 and the next device was EADSR called EA.

I've been working on the inverse side of this, and find understanding comes from these documents:

 

DSR (Device Service Routine) / Disk & File Management

Device Service Routine Specification for the TI-99/4(A) Personal Computer PDF

Functional Specification for the 99/4 Disk Peripheral PDF

Software Specification for the 99/4 Disk Peripheral PDF

GPL Interface Specification for the 99/4 Disk Peripheral PDF

File Management Specification for the TI-99/4 Home Computer PDF

 

They are all over in POST #1 of the Development resources thread: http://atariage.com/forums/topic/153704-ti-994a-development-resources/?p=1881598

 

Scroll down to section "3. Technical Documentation"

 

I find things make more sense when I understand both sides of the conversation. ( Although I've still never coded a direct call to DSRLNK :( )

 

-M@

OK here's a question.

 

In the E/A Assembler I just state:

 

REF GPLLNK

.

.

BLWP @GPLLNK

 

and I can call the system with what already exists or am I missing something there?

 

I am not using E/A, I am using my own Assembler. Is there an address for GPLLNK

or is there code loaded by E/A that I don't have access to and must write myself?

 

BF

Does your assembler support DEF and REF instructions? These are used by the loader inside the Editor/Assembler module. When you enter the module, utility functions like GPLLNK or DSRLNK are installed in low memory, and their addresses are put into the REF/DEF table together with a label that must be defined by DEF. The loader can handle references by retrieving that entry in the table and putting it at the respective places in the object code.

 

If you want to use the console routines, you do not need GPLLNK but you need a routine that does the same. You could disassemble GPLLNK and use it in your code.

https://github.com/endlos99/xdt99/tree/master/lib

 

In here there are dsrlnk routines...

 

-M@

 

There is a comment in the above reference that says the MG DSRLNK cannot be used in cartridge space (ROM) because it is self-modifying. This is certainly true, but it can be modified to run in ROM with the addresses that get modified moved to RAM. For insight into how to do that, see the code for GPLLNK (from MG via Smart Programmer) in TurboForth source code in “Resources” at turboforth.net. As I said somewhere above, I used the MG code for DSRLNK (and GPLLNK, as well), with some modification, for fbForth. The MG routine is particularly useful in that it invokes the console GPL DSRLNK, which can service DSRs in GROM space as well as the console's cassette routines. The Editor/Assembler, TI Forth and Paolo Bagneresi (used by @Willsy in TurboForth) routines do not—they only service DSRs in >4000 – >5FFF CPU ROM/RAM space.

 

...lee

  • Like 2

I have always said the normal TI EA DSRLNK sucks as it will not find anything but DSR in the ROM and ROM only DSR LINKS.

 

The GPL DSRLNK is much more compatible with everything in the TI99/4A, it will find all the DSR headers of any kind that the EA DSRLNK will service them.

 

So I 100% agree with Lee Stewart!

Edited by RXB

 

There is a comment in the above reference that says the MG DSRLNK cannot be used in cartridge space (ROM) because it is self-modifying. This is certainly true, but it can be modified to run in ROM with the addresses that get modified moved to RAM. For insight into how to do that, see the code for GPLLNK (from MG via Smart Programmer) in TurboForth source code in “Resources” at turboforth.net. As I said somewhere above, I used the MG code for DSRLNK (and GPLLNK, as well), with some modification, for fbForth. The MG routine is particularly useful in that it invokes the console GPL DSRLNK, which can service DSRs in GROM space as well as the console's cassette routines. The Editor/Assembler, TI Forth and Paolo Bagneresi (used by @Willsy in TurboForth) routines do not—they only service DSRs in >4000 – >5FFF CPU ROM/RAM space.

 

...lee

 

Ok thanks for this. I found the Bagneresi code online. It sounds like what I need. I will start there.

Does your assembler support DEF and REF instructions? These are used by the loader inside the Editor/Assembler module. When you enter the module, utility functions like GPLLNK or DSRLNK are installed in low memory, and their addresses are put into the REF/DEF table together with a label that must be defined by DEF. The loader can handle references by retrieving that entry in the table and putting it at the respective places in the object code.

 

If you want to use the console routines, you do not need GPLLNK but you need a routine that does the same. You could disassemble GPLLNK and use it in your code.

 

It could support REF and DEF if I understood the loader better. I am using binary file loaded with menu option 5 on the E/A module. Does that put the DEFs in low memory. I don't see anything there?

No, the loader is only used with option 3 of E/A or with CALL LOAD in TI BASIC when the E/A is plugged in. Binary files are already linked, so there is no need for REF/DEF.

 

Note that the object file format (DIS/FIX 80, see http://www.ninerpedia.org/index.php?title=Tagged_Object_Codefor more information) is a relocatable file format. While loading, the addresses are adapted by the loader to the loading destination automatically.

 

By that way you can load e.g. two object files where one file includes a DEF SUBPRG and a label SUBPRG. This label is put into the REF/DEF table together with the actual address where that label is located after loading. Now you can load a second file including a REF SUBPRG, and the loader looks up the address from the table and replaces the addresses in the second program while loading.

  • Like 2

Ok that's what I thought. And since I insist on doing things the hard way I will have to roll my own with the help of all the example code lying around.

 

Sometimes I think I should buy a good whip so I could beat myself up physically as well as inflicting this mental torture. :-)

 

Addicted to code...

 

B

  • Like 1

Here is my latest question.

 

So I have been looking at the code GPLLNK and DSRLNK in Fb Forth and I realized that I don't know what some of these equates mean.

 

This declares where the new workspace will be for GPLLNK. Where is it?

GLNKWS EQU $LO+$-LLVSPT->18

 

And this is the entry point but I don't understand where this is either.

GPLLNK EQU $LO+$-LLVSPT

 

Help required.

 

BF

To make sense of these values, you need the Assembler listing for fbForth 2.0:9: fbForth200.lst


LLVSPT is the first label in fbForth101_LowLevelSupport.a99 and is the source location in ROM of the first statement of fbForth’s low-level support to copy to low RAM. In the current build, this address is >6140.


$LO is the destination location in low RAM for copying the first source instruction pointed to by LLVSPT above. In the current build, this address is >3020, immediately following the four fbForth block buffers.


$ is always the address of the current instruction.


$LO+$-LLVSPT is my device for computing the low RAM address of the current instruction. This is necessary for labels that are used in the relocated code. $-LLVSPT is the distance from the starting source address, LLVSPT, of the current instruction’s address and is the same for both source and destination. Adding $LO to this distance yields the address in low RAM of the current instruction:


Source Destination

Label ROM Address RAM Address

------- ----------- -----------

GLNKWS >68B2 >377A = >3020 + >68B2 - >6140 - >18

GPLLNK >68A8 >3788 = >3020 + >68A8 - >6140


...lee

OK that all makes sense.

 

So for my testing purposes, I can just make my own GLNKWS with BSS and GPLLNK will be where ever my code begins in my Forth kernel, correct?

 

Or are there magic things I need to know about the register usage like overlapping workspaces in the GLNKWS?

 

Sincere thanks for your help Lee.

 

B

OK that all makes sense.

 

So for my testing purposes, I can just make my own GLNKWS with BSS and GPLLNK will be where ever my code begins in my Forth kernel, correct?

 

Or are there magic things I need to know about the register usage like overlapping workspaces in the GLNKWS?

 

Sincere thanks for your help Lee.

 

B

 

Re GPLLNK and DSRLNK workspaces, they are where they are in their respective routines to save space (this from Craig Miller of MG). They overlap program code that eliminates redundant assignments and, in the case of DSRLNK, gets executed only once. Putting the workspaces elsewhere would only require insuring their contents have what is expected by the two routines. You would need to carefully parse the routines for that purpose.

 

It is not necessary to overlap the two workspaces. They are not overlapped in the fbForth code, but you could map GLNKWS onto DSRWS R9 because GLNKWS R0 – R6 are not used. And, with judicious re-working of GPLLNK code, you could probably overlap the next four registers, as well.

 

...lee

Thanks Lee,

 

I am going to make the goal get it working first. Then I will try moving the goal posts. :-)

 

I reviewed the Bagnaresi code as well, and it might be a more straight forward translation.

 

I feel a bit of the clouds clearing.

 

 

BF

... I reviewed the Bagnaresi code as well, and it might be a more straight forward translation. ...

 

Keep in mind that the Bagnaresi code is a complete DSRLNK, whereas the MG version is merely the front-end to calling the console’s GPL DSRLNK.

 

...lee

 

[EDIT: I should add that the console GPL DSRLNK provides for cassette I/O and GROM DSRs, whereas the Bagnaresi code does not.]

  • Like 1
  • 10 months later...

I've noticed that the static version of the DSRLNK provided by xdt99, which I cobbled together from Tim's version, doesn't work at all.

.

There is a comment in the above reference that says the MG DSRLNK cannot be used in cartridge space (ROM) because it is self-modifying. This is certainly true, but it can be modified to run in ROM with the addresses that get modified moved to RAM. For insight into how to do that, see the code for GPLLNK (from MG via Smart Programmer) in TurboForth source code in “Resources” at turboforth.net.

 

My attempt to fix the MG DSRLNK wasn't really successful, and I also couldn't find your code. Which section has it?

 

Despite all these versions, I also tried to write my own DSRLNK, but just for DSR ROM so far. The code to transfer execution to the peripheral looks like

.

       ; found DSR entry
       li   r1, 1
       mov  r1, @>83e2        ; 1 in gpl r1
       mov  r3, @>8354        ; pointer to start of device name
       a    r3, r5
       mov  r5, @>8356        ; pointer to '.'
       mov  r12, @>83d0       ; copy of CRU address
       mov  *r6, @>83d2       ; next DSR chain entry
       mov  @2(r6), @>83f2    ; target address in gpl r9
       mov  r12, @>83f8       ; r12 in gpl r12
       lwpi >83e0
       bl   *r9
       nop
       lwpi >8300
       sbo  0
       rt

.

Unfortunately, when I run this, the TI gets stuck in an endless loop within R@>04DE->05A0, which is GPL FMT?! Am I missing any values that are required for correct initialization?

 

DSR routine authors are told that all those memory addresses are based on the current workspace pointer, so they aren't implemented assuming we have ram in >8300. The routine should access VDP memory through one of the addresses or relative to one of the addresses in the last few registers... and well GROM port is in one of them as well, if needed.

 

So, if code has already made a mess of R13,R14,R15, in GPLWS, then the ROM code is not likely to work. I don't know if this is setup by DSRLNK, entry into GPL/OS ROM space, or just setup once before powerup routines get a go...

 

The ROM code is also told it can scribble over FAC. DSRLNK in the console, copies FAC off to VDP, then restores before exiting the entire DSRLNK routine.

 

That nop after bl *r9 will break functionality of cards like TIPI, that need to execute, determine if they really want to service the request, and if not, return to the loop that scans for more eligible DSR routines. 2% of TI owners are using this functionality. Hopefully more in the near future.

 

Do you mean sbz on your second to last line?

 

-M@

My attempt to fix the MG DSRLNK wasn't really successful, and I also couldn't find your code. Which section has it?

 

It is in “Source Code-->Bank 1-->Low Level Support” on my website below. In a bit, I will post my latest assembler listing so you can find the actual low RAM addresses. This code, however, has minimal modification because it winds up in modifiable low RAM. I will locate the source for @Willsy’s source that modifies the MG GPLLNK to run from ROM after a bit. Right now, dinner calls.

 

...lee

  • Like 1

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