Jump to content
IGNORED

DSRLINK Code Tutorial


TheBF

Recommended Posts

 

Ah yes the GROMs. Ok I will relent.

 

On another matter. I have created Forth words to turn on the disk card and I can read the header, and search for DSR names.

But from what I see in CLASSIC99 the address for DSK1 is >4800. However when I dump the ROM at address 4800 I see only zeros?

What am I missing here?

 

The screen shows my partially completed DSRLNK word operating... partially.

 

Unless you are using a disk image with “Type=3” (read, “use TI disk controller”) in the “[Diskn]” section of Classic99.ini you are referencing, I do not believe you can rely on the information at >4000 to be what you expect. I monitored >4000 while loading TI Forth and stopped it with F1 when I saw the values change from all zeros. The address in question pointed to executable code in >4000 – >5FFF ROM space.

 

...lee

Link to comment
Share on other sites

 

Unless you are using a disk image with “Type=3” (read, “use TI disk controller”) in the “[Diskn]” section of Classic99.ini you are referencing, I do not believe you can rely on the information at >4000 to be what you expect. I monitored >4000 while loading TI Forth and stopped it with F1 when I saw the values change from all zeros. The address in question pointed to executable code in >4000 – >5FFF ROM space.

 

...lee

 

OK. It is an emulator after all.

I know it's a little crazy but when I look at Paolo's DSR code I see a lot of things that I already have in the system and so it grates against my "Forthyness" to replicate them. :-)

 

For example here is the word to cut a string at the '.' character.

: /DOT    (  caddr len -- caddr len')  \ cut string at the dot
             2DUP [CHAR] . SCAN NIP -  ;

And here is the routine to find a DSR string in the ROM.

: DSRFIND ( addr len -- link | 0)
           /DOT DEV$ PLACE             
           'DSRLIST  ( -- >4008)
           BEGIN
              @ DUP 0=                 \ check for end of list
              SWAP DEV$ OVER >DSR$ =$  \ test string match in ROM
              ROT OR                   \ if either is true we're done.
           UNTIL ;

These 2 routines are about 50 80(or so) LOC in Paolo's code.

So that is my goal to remove the stuff that I can move into Forth and then only make the call with a small word in ALC.

 

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

On another matter. I have created Forth words to turn on the disk card and I can read the header, and search for DSR names.

But from what I see in CLASSIC99 the address for DSK1 is >4800. However when I dump the ROM at address 4800 I see only zeros?

What am I missing here?

 

 

Classic99's DSR is simulated.. when the emulator detects the PC at >4800 with (or the low level subprogram addresses, which are >4820 and up) with the Classic99 disk controller mapped in (always at >1100 today), it jumps to a handler routine written in C++ that parses the PAB and takes the appropriate action, then returns the CPU back to the caller. There's no actual 9900 code involved. :)

 

(Edit: the header at >4000 is 100% valid though, because the 9900 needs to parse that ;) )

Edited by Tursi
  • Like 2
Link to comment
Share on other sites

 

Classic99's DSR is simulated.. when the emulator detects the PC at >4800 with (or the low level subprogram addresses, which are >4820 and up) with the Classic99 disk controller mapped in (always at >1100 today), it jumps to a handler routine written in C++ that parses the PAB and takes the appropriate action, then returns the CPU back to the caller. There's no actual 9900 code involved. :)

 

(Edit: the header at >4000 is 100% valid though, because the 9900 needs to parse that ;) )

 

Excellent Thanks Tursi.

 

And if I have not said it before, thank you so much for CLASSIC99.

 

It has provide me with endless hours of fun and is and excellent Hack.

 

B

  • Like 1
Link to comment
Share on other sites

Small update for doing things the hard way.

 

I have Forth code now that can scan a card and retrieve the entry address for the device routine.

 

I am only scanning for 1 card at a time. My logic there is I know where the card is in the CRU map so why waste time?

The code is factored into small pieces so when I need to scan devices on another card it's trivial to do so.

\ DSKCARD a constant ie: the CRU address of the card (>1100)
         ?CARDOFF        ( if R12<>0 then turn that device off)
         DSKCARD Enable  
         ?CARDID         ( abort with message if we don't >AA)
         DSRFIND DUP ?DEVERR ( abort with message if don't find the device)

\ so to search the serial CARD would be
HEX      ?CARDOFF
         1300 Enable  
         ?CARDID
         DSRFIND DUP ?DEVERR

\ so cards will be enabled by the hi-level API for different devices.    

The code creates the PAB and updates the addresses at >8355 and >8356 as well but I am struggling to understand what this crazy little machine needs to call the device service code properly.

 

If I can get the calling sequence sorted out I think I have a DSR written in a high level language with just a little ALC.

 

<THEME_MUSIC>

 

"Dream... Dream, dream, dream...

 

</THEME_MUSIC>

Link to comment
Share on other sites

The code creates the PAB and updates the addresses at >8355 and >8356 as well but I am struggling to understand what this crazy little machine needs to call the device service code properly.

 

I am not sure I understand the problem. DSR device routines [type 8] are pretty straightforward most of the time, but DSR subprograms [type >A] can, indeed, be difficult to sort out.

 

For type 8 DSR calls:

  • the PAB must be properly set up for the call (open, read, write, ...)
  • the address of the PAB filename length byte is stored at >8356
  • the DSRLNK call searches for the device name in the device list of each DSR card
  • the entry point address in front of the found device name is executed with BL [or error if no device name is found in any DSR card]
  • upon return, process the PAB error flags
  • return to the routine that called DSRLNK.

 

For type >A DSR calls, things can get a little messy:

  • the PAB must be set up with the length byte of the subprogram name followed by the subprogram name (name of the level 1, read/write sectors subprogram name is >10, so the PAB contains only >0110)
  • the file transfer block info for the desired operation must be properly set up (this depends on the subprogram, but is usually at FAC or FAC+2, i.e., >834A or >834C
  • there may also be an “additional information” block required, which can be located at any desired CPU RAM)
  • the DSRLNK call searches for the subprogram name in the subprogram list of each DSR card
  • the entry point address in front of the found subprogram name is executed with BL [or error if no subprogram name is found in any DSR card]
  • the subprogram returns an error code at >8350
  • return to the routine that called DSRLNK.

I do not know whether something in the above verbiage is what you are seeking, but maybe it will lead you somewhere.

 

...lee

  • Like 2
Link to comment
Share on other sites

That's how I understood things too. Thank you for that succinct explanation.

 

I have the PAB set up actually per the E/A Manuals file example.

I created DSK1.DATA with BASIC so it's there.

The ASM version of the program indeed finds the file and and displays the contents on the screen.

 

So with your explanation and give the fact that I have found the device entry for DSK1

I should only need to:

  1. Create a DSR workspace
  2. Create a vector "DODSR" with the DSR workspace & a program that does a BL to the dev entry address
  3. BLWP @ DODSR
  4. which runs the BL to the device entry address
  5. RTWP back to Forth
  6. Examine the PAB status to see what happened.

Does that sound correct?

Link to comment
Share on other sites

Pretty much. Does DODSR do a change to the GPL workspace before turning on the cards and back to your DSR workspace upon return from the BL to dev entry address?

 

...lee

 

At this point no, but that is the kind of thing I am missing in the calling protocol. It seems like it has been followed like a recipe over the years.

I am looking for the minimal ALC needed to call the routine. :-)

 

Not sure what the GPL workspace needs to do if I have already discovered the entry address in the ROM?

 

I am trying what I wrote above now. Will let you know how it goes.

Link to comment
Share on other sites

Well you definitely need to be in the GPL workspace to BL *R9.

:)

 

So I did this:

CODE CALLDSR ( -- )
             83E0 LWPI,        \ change to GPL workspace
            *R9 BL,            \ GPL R9 already has the entry address
             DSRWKSP LWPI,
             RTWP,
            ENDCODE

And I got back home with an OK prompt ... but the interpreter had stopped.

One step closer.

Link to comment
Share on other sites

Minor progress on DSRLNK the hard way.

 

So here is the code that returns to Forth safely. When I look at the ROM listings I think the fact that it returns to R11+2 means there was an error.

Nothing happens in the PAB so I have a few more chicken entrails to examine. :-))

CODE: CALLDSR ( -- )
             83E0 LWPI,             \ change to GPL workspace
            *R9 BL,                 \ GPL R9 already has the entry address
             $$ JMP,                \ Return here if correct?
             DSRWKSP LWPI,          \ Returns here if error ?
             RTWP,                  \ Return to Forth
             NEXT,
             END-CODE

To call the 9900 style VECTOR I also made a new FORTH word in the system called ... what else...BLWP!

It allows me to put a vector on the Forth stack and bullwhip right into it. That's pretty cool.

CODE: BLWP  ( vector -- ) *TOS BLWP,  TOS POP, NEXT,  END-CODE

\ make a 9900 vector that we call with BLWP
\               workspace   compile program address
\               ---------   -----------------------
CREATE DSKLNK   DSRWKSP ,     ' CALLDSR >BODY ,

\ Usage:  DSKLNK BLWP

I have a dream. That one day, little CAMEL Forths, will be able to access the TI file system with minimal Assembly language code. :woozy:

  • Like 3
Link to comment
Share on other sites

R11+2 means it was successful, actually. I have some debug in Classic99 that is emitted when you call a DSRLNK with improper settings (meant to help debug code that talks TO dsrs...), let me see what I check there...

 

- Workspace must be GPLWS (0x83E0). Numerous DSRs assume and rely on this

- >83D0 should contain the CRU base of the DSR (I can't remember the reason for this, but something I considered important relied on it - I want to say not just boot tracking)

- DSR name length must be in >8354 as a word (just the device part, ie: DSK1 is >0004) - this is used to parse the PAB. Must be 1-7 characters

 

Then there's some PAB tests and stuff that doesn't really affect what you're trying to do. I guess I should note too that the tests in Classic99 are /after/ DSRLNK, for the actual DSR call itself.

 

Somewhere on this forum is posted TI's official DSR spec, too, meant for writing compatible DSRs. That may help?

  • Like 2
Link to comment
Share on other sites

I noticed when I tried to get the Horizon RAM-disk to work with the p-code card, that the ROS for that card made assumptions about what the usual DSRLNK code, the one TI have taught us to write, does with memory. The DSR is looking at memory at locations where the "standard" DSR does store them. But the p-code card has a completely different way of handling DSR calls. It does (of course) follow TI's rules for DSR calls, but only the expressed rules.

 

So the point of this post is that if you do DSR calls in a way that differs from the standard one, if you try to be smarter (the p-code card's code is more clever), then you'll find certain cards stop working.

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

R11+2 means it was successful, actually. I have some debug in Classic99 that is emitted when you call a DSRLNK with improper settings (meant to help debug code that talks TO dsrs...), let me see what I check there...

 

- Workspace must be GPLWS (0x83E0). Numerous DSRs assume and rely on this

- >83D0 should contain the CRU base of the DSR (I can't remember the reason for this, but something I considered important relied on it - I want to say not just boot tracking)

- DSR name length must be in >8354 as a word (just the device part, ie: DSK1 is >0004) - this is used to parse the PAB. Must be 1-7 characters

 

Then there's some PAB tests and stuff that doesn't really affect what you're trying to do. I guess I should note too that the tests in Classic99 are /after/ DSRLNK, for the actual DSR call itself.

 

Somewhere on this forum is posted TI's official DSR spec, too, meant for writing compatible DSRs. That may help?t

 

 

Thanks for all the detail Tursi. I managed to extract those things from Paolo's DSR code. I think I am doing them right.

And my code is consistently returning via R11+2 so it must be close.

I may be removing the CRU base from 83D0 too soon. I will play around with that.

 

I have most of the TI Docs here, but I missed subtle details when reading the text sometimes. It's part of the fun. :-)

Link to comment
Share on other sites

I noticed when I tried to get the Horizon RAM-disk to work with the p-code card, that the ROS for that card made assumptions about what the usual DSRLNK code, the one TI have taught us to write, does with memory. The DSR is looking at memory at locations where the "standard" DSR does store them. But the p-code card has a completely different way of handling DSR calls. It does (of course) follow TI's rules for DSR calls, but only the expressed rules.

 

So the point of this post is that if you do DSR calls in a way that differs from the standard one, if you try to be smarter (the p-code card's code is more clever), then you'll find certain cards stop working.

 

I have no doubt about being clever breaking stuff. Thanks for the polite warning. :-)

(I made a career out this kind of behavior in business, where I was accused of being "innovative". :D Business weenies don't always like that.)

 

I am trying to "follow" the rules whilst doing the grunt work of moving data into memory and such with Forth. As noted cutting a string at the '.' character and things like that are already written or a least the factors are written so cobbling the primitives together actually adds less code in some cases than re-writing everything in Assembler. When the whole thing works in some fashion I will post the low level code and the High level API that I come up with.

 

My end goal is my own amusement and ultimately I want to implement the file word set or a functional subset thereof for ANS/ISO Forth.

It's going to be a challenge to map a modern file command set to the old TI file system, but the standard makes allowances for "system dependencies" in this area thank goodness.

 

Thank you for weighing in on my toils. It makes it easier to live with myself and this somewhat strange pursuit that I am helpless to stop.

 

B

  • Like 2
Link to comment
Share on other sites

DSR opcode >0 on PAB >0F89, filename                                                                           
Releasing file buffer 0                                                                                                
Recycling unclosed file buffer 0                                                                                       
Opening DSK10.DSK1.DATA on drive type ClipBoard                                                                        
PAB requested file type is DF0                                                                                         
Allocating clipboard buffer (0)                                                                                        
Clipboard read 95 records                                                                                              
Restore set record number to 0        

Thanks for this feature Tursi. I was looking at dis-assembled code and my eyes were getting crossed.

This is showing me all the errors!

Link to comment
Share on other sites

IT Finally WORKS! :)

 

Big thanks to Lee, Willsy, Tursi and anyone else I might have forgotten who added their inputs.

 

I have a working Disk only DSRLNK with most of it programmed in Forth.

 

The code is pretty ugly yet but the big thing that I learned was the PAB address that we give normal DSR is NOT the PAB address that the DSR uses.

What????

 

Very odd, however the PAB address must start at the position of the '.' after the device name.

 

I accomplish this in Forth with a few simple words.

 

_FNAME

computes the address of the file name from a VDP or CPU ram address. (addr+9)

 

/DOT

Takes a stack string (addr,len) and computes a new string upto the location of the '.' char.

in BASIC it's like: SEG$(A$,1,POS(A$,".")) but a little faster. (ok a lot faster)

 

CREATEPAB ( text,len -- the-real-pab-address)

copies a pab buffer from CPU ram to a clean PAB address in VDP RAM and returns the "real PAB address" that begins at the first dot location in the string.

: _FNAME  ( PAB -- PAB+9) 9 + ;      \ compute the filename location

: /DOT    ( caddr len -- caddr len')   \ cut input string at the dot
           2DUP '.' SCAN NIP -  ;      

\ createpab does setup per e/a manual AND computes the
\ PAB address of the "DSK?.filename" without the device:
\ EXAMPLE:  DSK1.TEST  becomes  .TEST
\ usage: S" DSK1.DATA" CREATEPAB
: CREATEPAB  ( addr len -- real-PAB-addr) 
              2DUP                      \ dup the string info
              PDATA _FNAME PLACE        \ place the string in PDATA buffer

              PAB PSIZE 0 VFILL         \ erase VDP PAB memory

              PDATA PAB PSIZE VWRITE    \ write PDATA to VDP PAB

              /DOT NIP 1+ ( -- n)       \ compute offset upto '.'
                                        \ (nip string address. we don't need it)

              PAB _FNAME + ;            \ add offset to PAB _FNAME
                                        \ *this is the REAL PAB address that 
                                        \ DSR uses!!!

Opening a file is pretty ugly at the moment the comments explain the FORTHisms.

: OPEN  ( $addr len -- ) \  *STACK PICTURE*
         2DUP CREATEPAB  ( -- $addr len realpab)
         -ROT            ( -- realpab $addr len )
         DiskON ?CardID                           \ abort if card is not 'AA'
         DSRFIND         ( -- realpab link)

         DUP ?DEVERR                              \ ABORT if link=0

         DUP >DSR$       ( -- link $)             \ link->DSR$ ie: the name of the DSR
             C@ 8355 C!                           \ len(DSR$) -> hex8355
                         ( -- link)
         >ENTRY  83E0 9 REG# !                    \ convert link to DSR entry -> GPL.R9
        ( -- realpab ) 8356 !                     \ the "REAL" PAB file name stored here
         0 PAB VC!                                \ set the PAB to open opcode
         DSKLNK BLWP                              \ open the file
;

And the only ALC is CALLDSR . It's written in the cross-compiler's Forth and Assembler dialect.

I am not 100% sure, but it could be simplified by removing the its local workspace but keeping it this way means any TASK in CAMEL99 could call it from it's own task workspace and get home safely.

VARIABLE: DSRWKSP  [CC] 20 TALLOT [TC]

CODE: CALLDSR ( -- )
             83E0 LWPI,             \ change to GPL workspace
            *R9 BL,                 \ GPL R9 already has the entry address
             @@1 JMP,
             @@2 JMP,
@@1:         DSRWKSP @@ SETO,       \ return true flag IN R0 if there is an error
@@2:         DSRWKSP LWPI,          \ Returns here if error ?
             RTWP,                  \ Return to Forth
             NEXT,
             END-CODE
  • Like 3
Link to comment
Share on other sites

Looking good!

 

Have you ever looked at the TI Forth code for file I/O? I converted it to nearly all ALC for fbForth 2.0, but the Forth code might be instructive if you have not seen it. It is in blocks 68 – 71 of the TI Forth system diskette. Here is the Forth code from blocks 68 – 71:

( FILE I/O ROUTINES 12JUL82 LCT)                                
( Requires LOADing Screen #33, "System Synonyms")
HEX                                                     
0 VARIABLE PAB-ADDR                                             
0 VARIABLE PAB-BUF                                              
0 VARIABLE PAB-VBUF                                             
: FILE <BUILDS , , , DOES> DUP @ PAB-VBUF ! 2+ DUP @ PAB-BUF !  
    2+ @ PAB-ADDR ! ;                                           
: GET-FLAG PAB-ADDR @ 1+ VSBR ;                                 
: PUT-FLAG PAB-ADDR @ 1+ VSBW ;                                 
: SET-PAB PAB-ADDR @ DUP 0A 0 VFILL 2+ PAB-VBUF SWAP 2 VMBW ;   
: CLR-STAT GET-FLAG 1F AND PUT-FLAG ;                           
: CHK-STAT GET-FLAG 0E0 AND                                     
     837C C@ 20 AND OR 9 ?ERROR ;                               
: FXD GET-FLAG 0EF AND PUT-FLAG ;                               
: VRBL GET-FLAG 10 OR PUT-FLAG ;   
HEX                    
: DSPLY GET-FLAG 0F7 AND PUT-FLAG ;                             
: INTRNL GET-FLAG 8 OR PUT-FLAG ;                               
: I/OMD GET-FLAG 0F9 AND ;                                      
: INPT I/OMD 4 OR PUT-FLAG ;                                    
: OUTPT I/OMD 2 OR PUT-FLAG ;                                   
: UPDT I/OMD PUT-FLAG ;                                         
: APPND I/OMD 6 OR PUT-FLAG ;                                   
: SQNTL GET-FLAG 0FE AND PUT-FLAG ;                             
: RLTV GET-FLAG 1 OR PUT-FLAG ;                                 
: REC-LEN PAB-ADDR @ 4 + VSBW ;                                 
: CHAR-CNT! PAB-ADDR @ 5 + VSBW ;                               
: CHAR-CNT@ PAB-ADDR @ 5 + VSBR ;                               
: REC-NO DUP SWPB PAB-ADDR @ 6 + VSBW PAB-ADDR @ 7 + VSBW ;     
: N-LEN! PAB-ADDR @ 9 + VSBW ;                                  
HEX                    
( COMPILE A STRING WHICH IS MOVED TO VDP-ADDR AT EXECUTION)     
                                                                
: (F-D")                                                        
    PAB-ADDR @ 0A + R COUNT DUP 1+ =CELLS R> +                  
    >R >R SWAP R VMBW R> N-LEN! ;                               
: F-D" 22 STATE @                                               
    IF                                                          
      COMPILE (F-D") WORD HERE C@                               
      1+ =CELLS ALLOT                                           
    ELSE                                                        
      PAB-ADDR @ 0A + SWAP WORD HERE COUNT >R SWAP R            
      VMBW R> N-LEN!                                            
    ENDIF ; IMMEDIATE                                           
HEX                                                     
: DOI/O CLR-STAT PAB-ADDR @ VSBW PAB-ADDR @ 9 + 8356 !          
  0 837C C! DSRLNK CHK-STAT ;                                   
: OPN 0 DOI/O ;                                                 
: CLSE 1 DOI/O ;                                                
: RD 2 DOI/O PAB-VBUF @ PAB-BUF @ CHAR-CNT@ VMBR CHAR-CNT@ ;    
: WRT >R PAB-BUF @ PAB-VBUF @ R VMBW R> CHAR-CNT! 3 DOI/O ;     
: RSTR REC-NO 4 DOI/O ;                                         
: LD REC-NO 5 DOI/O ;                                           
: SV REC-NO 6 DOI/O ;                                           
: DLT 7 DOI/O ;                                                 
: SCRTCH REC-NO 8 DOI/O ;                                       
: STAT 9 DOI/O PAB-ADDR @ 8 + VSBR ;                            

The above code relies on DSRLNK code written in ALC that is identical to E/A code and practically identical to Paolo’s code, as near as I can tell.

 

If you need the code for the system synonyms or other code used by the above, I will post it as soon as I can.

 

...lee

Link to comment
Share on other sites

LOL. You are reading my mind. Thank you.

 

I had played with some of this before and I am just testing my ideas now.

The Forth Standard specifies something called a "file access method" (FAM)

So CREATE-FILE is defined as:

 CREATE-FILE ( c-addr u fam -- fileid ior )

There are also 3 words, R/W R/O W/O that return the "FAM".

 

I was struggling with how to do this with all the variations possible in the 99-4a file system. Just recently I had a small epiphany.

 

So here is what I came up with. The file mode control words assemble all the bits that define a file in a variable called, what else FAM.

2 BASE !
VARIABLE FAM  \ we build the file mode bits in this variable
: FAM@     FAM @ ;
: FAM!     FAM ! ;
\                  mask bits         added bits  store
\                  ---------        ----------- --------
: DISPLAY    ( -- ) FAM@ 11101111 AND              FAM! ;  \ Text file
: INTERNAL   ( -- ) FAM@               00010000 OR FAM! ;  \ binary file

: VARI       ( -- ) FAM@ 11110111 AND  00001000 OR FAM! ;  \ VARIABLE is a keyword in Forth

: UPDATE     ( -- ) FAM@ 11111001 AND              FAM! ;
: OUTPUT     ( -- ) FAM@ 11111001 AND  00000010 OR FAM! ;
: INPUT      ( -- ) FAM@ 11111001 AND  00000100 OR FAM! ;
: APPEND     ( -- ) FAM@               00000110 OR FAM! ;

: SEQUENTIAL ( -- ) FAM@ 11111110 AND              FAM! ;
: RELATIVE   ( -- ) FAM@               00000001 OR FAM! ;

: fixed      ( -- ) FAM@ 11110111 AND FAM! ;
HEX
\ set record length and set mode for FIXED files
: FIXED      ( c --) PAB 4 +  V! fixed ;

These are doing exactly the same thing as the TI-Forth code but are keeping track inside the FAM variable instead of in the FLAGS field in the PAB.

 

Then I defined the ANS words like this:

\ ANS/ISO Forth FILE ACCESS METHODs (FAM)
: R/W     ( -- fam)  UPDATE FAM @ ;
: R/O     ( -- fam)  INPUT  FAM @ ;
: W/O     ( -- fam)  OUTPUT FAM @ ;

So I figure you can type file mode words until the cows come home and then when you create-file or open-file etc. you just insert the R/W or whatever and the hi-level word takes care of it.

 

This is as far as I have gotten . I refactored the pab creation and magic address writing to the word NEWFILE just now.

Then I made my file operations all lowercase primitives ( open,read,write,close etc.)

They just fill in the OPCODE in PAB and do the BLWP magic and return the error bits to the stack.

 

Then the final interface will look like ANS Forth. (UNTESTED!) Once it's working I will get to file handles for 3 files. "Make it work first"

: CREATE-FILE ( c-addr u fam -- fileid ior )   \ fam is the "read/write" file access method.
               -ROT NEWFILE  FLG!              \ create PAB, set the file mode
               open ( -- err)                  \ call open primitive
               1 SWAP  ;                       \ return a file id (ALWAYS 1) and error

As you can see I had lots of time to dream about the innards before I could make it work. That only took me oh... well let's say... I started thinking about it a year ago. :mad:

As I look at the TI-Forth code I can probably simplify further.

 

And I see that need to fix my error words.

 

Thanks again for all your support. It makes a real difference.

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

A Disk ONLY DSRLINK in (Mostly) Forth

 

Here is the DSR Link code itself just for the record after all my jaw-wagging.

There is general principle from Chuck Moore the inventor of Forth that every word should have one function. The large search through all the cards model of the classic DSR is not consistent with that thinking. Since we know the normal address of the Expansion unit's disk card I chose to only search that card. The code is factored in such a way that I can create a serial comm. card or another card DSR very easily when I need it.

The result is that the device searches are fast and specific. This is perhaps more important here since the search is in Forth and not Assembler.

 

Edit: This adds 390 bytes to the Forth system which includes the names of all the words and the linkage headers.

HEX
1100 CONSTANT DSKCARD    \ No need to scan for the Floppy DISK CARD. It's here
4000 CONSTANT 'ID        \ DSR ROM ID = >AA
4008 CONSTANT 'DSRLIST   \ start of linked list of DSR devices

CREATE DEV$   8 ALLOT    \ DEV$ holds the counted string left of the '.'

: >DSR$   ( link -- $) 4 +  ;          \ convert list link to DSR$

: =$ ( $1 $2 -- flag) OVER C@ 1+ S= 0= ; \ compare 2 counted strings

\ DSRFIND searches for a matching device NAME in the DSR ROM
\ It returns the device's link-field. ( code address is in the next CELL)
: DSRFIND ( addr len -- link_addr)
           /DOT DEV$ PLACE             \ cut input string, copy to DEV$
           'DSRLIST                    \ 1st LINK in ROM DSR linked list
           BEGIN
              @                        \ fetch the next link
              DUP 0=                   \ test for end of list
              SWAP DEV$ OVER >DSR$ =$  \ test string match in ROM
              ROT OR                   \ if either is true we're done.
           UNTIL ;

\ card control lexicon
: Enable   ( CRU -- )
           CRU@ OVER <>                \ fetch CRU (R12), is this a new card?
           IF   0 SBZ                  \ if so, turn it off
           THEN CRU! 0 SBO ;           \ then turn on the requested card

: Disable  ( CRU -- )  CRU! 0 SBZ ;

\ diskcard control
: DiskON  ( -- ) DSKCARD  DUP 83D0 !  Enable ;   \ CRU copied to 83D0 (magic)
: DiskOFF ( -- ) DSKCARD  Disable ;

\ DSR error handlers
: ?CardID  ( -- )      'ID C@ AA <> ABORT" CARD not enabled"  ;
: ?DEVERR  ( link -- ) 0= ABORT" Device not found" ;

\ primitives that convert something to another thing
: REG#   ( workspace n -- addr)   CELLS +  ; \ addr is Register n in workspace
: >ENTRY ( DSRlink -- entry_addr) CELL+ @ ;

\ DSKLNK is DISK ONLY dsrlink. Simpler than general purpose.
\ make a 9900 vector that we call with BLWP
\               workspace    ALC program address
\               ---------   -----------------------
CREATE DSKLNK   DSRWKSP ,     ' CALLDSR >BODY ,

\ ---------------- END OF DSR ------------------------

And the only ALC is here

VARIABLE: DSRWKSP  [CC] 20 TALLOT [TC]

CODE: CALLDSR ( -- )
             83E0 LWPI,             \ change to GPL workspace
            *R9 BL,                 \ GPL R9 already has the entry address
             @@1 JMP,               \ Returns here if error ?
             @@2 JMP,
@@1:         DSRWKSP @@ SETO,       \ return true flag IN R0 if there is an error
@@2:         DSRWKSP LWPI,                       
             RTWP,                  \ Return to Forth
             NEXT,
             END-CODE

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

I should add that the DSRLNK of the TI Forth code I posted above includes “type 8” as part of the call.

 

Also, I can add the stack effects to the Forth words for the TI Forth code, if you like. I might do it anyway—it’s not like I am strapped for time. | :)

 

...lee

Link to comment
Share on other sites

I should add that the DSRLNK of the TI Forth code I posted above includes “type 8” as part of the call.

 

Also, I can add the stack effects to the Forth words for the TI Forth code. if you like. I might do it anyway—it’s not like I am strapped for time. | :)

 

...lee

 

No need for stack pictures. It all makes sense to me now.

 

And... it's very helpful.

Link to comment
Share on other sites

 

At this point no, but that is the kind of thing I am missing in the calling protocol. It seems like it has been followed like a recipe over the years.

I am looking for the minimal ALC needed to call the routine. :-)

 

Not sure what the GPL workspace needs to do if I have already discovered the entry address in the ROM?

 

I am trying what I wrote above now. Will let you know how it goes.

You should know that ALC DSR is limited to just ROM and is incapable of finding other DSR devices.

i.e. GPL DSR, Devices that use GPL DSR or do you have access to GPL device listings.

 

A good example is using GPL I can catalog Hard Drives or RAM DISK or Disk drives with less code.

Also as GPL finds all devices you would need to really load up a ton of code to do this in Assembly.

 

It is just more effective and less costly in RAM to use GPL DSR for devices.

Edited by RXB
Link to comment
Share on other sites

You should know that ALC DSR is limited to just ROM and is incapable of finding other DSR devices.

i.e. GPL DSR, Devices that use GPL DSR or do you have access to GPL device listings.

 

A good example is using GPL I can catalog Hard Drives or RAM DISK or Disk drives with less code.

Also as GPL finds all devices you would need to really load up a ton of code to do this in Assembly.

 

It is just more effective and less costly in RAM to use GPL DSR for devices.

 

I have know doubt using GPL is more space efficient. It's the machines native O/S language.

And from what I have seen in your videos one can do anything with GPL and you especially so. ;-)

 

I should be able to re-use some of these Forth routines to get to GPL routines. (?)

Programming Forth works it's very much like you're creating a "GPL" in that you are building a set of language operations that let you do more with less code as you go along.

 

I may have to create a more comprehensive scanner to find things, but I think it's doable but it will have to wait until I get past this job. ;-)

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