Jump to content
IGNORED

DSRLINK Code Tutorial


TheBF

Recommended Posts

I might have found a bug in CLASSIC99 when using TYPE 3 disks or I still don't understand things.

 

I was working over my DSRLNK and it worked perfectly when reading the file status field in the PAB while using TYPE 1 and TYPE 2 disks.

But with a type three disk I never got a change in status when I hit the EOF.

 

I spent a long time cursing my inability to find the problem in the Asm code. :)

 

In desperation I wanted to see what I was missing so I ran the equivalent program in BASIC and... it doesn't seem to find the EOF bits in the status flag either.

 

Here is the BASIC program:

100 REM   CATALOG DISK PROGRAM    
110 PRINT "Input DSKx. :";
120 INPUT DSK$
130 OPEN #1:DSK$,INPUT ,INTERNAL,RELATIVE
140 INPUT #1:N$,X,Y,Z
150 PRINT N$,X;Y;Z
160 GOTO 140
170 CLOSE #1
180 END

Run it and INPUT a type 1 or 2 disk and it will error out on 140.

But on a type 3 disk it runs forever, just like my Forth programs.

 

Is my analysis correct?

 

I am not sure you have chosen the best example file for this topic. DSKx.CATALOG is not a real file. The DSR provides the user with exactly 128 “records” with null strings for nonexistent file names. These are always presented alphabetically with the null records at the end. This allows you to abort reading records at the first record with a null filename string, which is how I do it in fbForth 2.0 (ported from TurboForth). Having not yet analyzed the DSR routine that generates the “file”, I cannot say how it may differ from normal file access.

 

The above notwithstanding, I did try to dig through the DSR’s READ routine to see if it handled VARIABLE files differently from FIXED files regarding incrementing the PAB to the next record to be read. I think it does, but I was having a little trouble following the ALC. I do know that, for RELATIVE files in TI Basic, TI recommended to use a method different from EOF to check for the last record read. I would also say that the fault for the failure of your code to error out when it passed the end of file may lie more with TI Basic’s INPUT than with the DSR’s READ routine. I say this partly because the DSR’s READ routine only seems to distinguish between VARIABLE and FIXED files, not whether they were opened in SEQUENTIAL or RELATIVE mode. Of course, I may have missed something. I would certainly try your code on a file of your own making before concluding there is a problem with Classic99.

 

...lee

Link to comment
Share on other sites

OK that makes sense. I thought that all files would report EOF the same way. I see now that the directory is a fixed length file with empty records.

 

So I can change my disk directory utilities to test for a null file name. Simple.

 

Thanks Lee

 

But for the record, Classic99 reports an EOF with type 1 and type 2 files.

Edited by TheBF
Link to comment
Share on other sites

"Type 1" and "Type 2", being FIAD and DOAD, are DSRs that I wrote, that (originally, at least) behave like I believe a DSR should. All input is through the PAB, and all behaviors run through standard interfaces. "Type 3" runs the TI disk controller ROM, which everyone else considers perfection. ;) Directories are handled very differently from files there.

 

Your code is just hoping that a file error will stop it. With a quick look at the disk DSR, it appears it will report EOF after 128 records are read, without regard to how many files are on the disk. It DOES check whether it's out of files, and if it is, then yeah, it /explicitly/ returns the zero size record instead of EOF.

 

I suppose I could make my DSR work that way too, but it seems kind of dumb. Still, I'll take a note. ;)

Link to comment
Share on other sites

As long as we know it's not a big deal to be sure.

 

While I am here, I notice that the DSR code I took from here clears R1 and then does INC R1 before it does the BL *R9.

 

Is that something that other programs use to count the entries into the DSR? It doesn't seem to make a difference if I comment those 2 lines out.

Link to comment
Share on other sites

As long as we know it's not a big deal to be sure.

 

While I am here, I notice that the DSR code I took from here clears R1 and then does INC R1 before it does the BL *R9.

 

Is that something that other programs use to count the entries into the DSR? It doesn't seem to make a difference if I comment those 2 lines out.

 

R1 is only important if the caller of DSRLNK cares which instance of a device/program routine was run. R1 will only ever contain 1 if the first hit on the name search runs successfully and takes the normal return by performing “INCT R11” before returning. A DSR may actually contain the device/program name sought, but refuse to run it or otherwise take the error return immediately following “BL *R9”, i.e., not do the normal “INCT R11” before returning. If the error return is taken, the same DSR search continues until the device/program is either found again (a duplicate name[?]) or the list is exhausted. If the list is exhausted, the next DSR ROM is searched. If the name is found in any of these subsequent searches, R1 is incremented and saved as are the new entry point and CRU. Once a device/program routine is run to completion with the normal return, R1 is likely trashed, but the caller of DSRLNK can use the saved value of R1 to discover which instance of the device/program routine was run as well as its entry point and which card (by its CRU) did the deed from the other saved values.

 

The saved values that appear unimportant because they are not actually used in the E/A-type DSRLNK may have been put there for debugging purposes or future use. I agree with your conclusions that they are not critical to your current programming, but, with the exception of the saved R1, they certainly could be used to shorten file access for already open files. Saving R1 appears only useful as a debugging tool.

 

...lee

Link to comment
Share on other sites

Your knowledge of this machine is always amazing Lee.

 

I tried a version without GPL R1 being incremented before each call and it messed up sometimes so It stays.

 

For anyone who's interested here is the current DSR Link I am using, re-written for the XFC99 cross-assembler.

It seems to work pretty well now. I replaced some jumps with structured loops and if/endif which helps me see the shape of the code.

There are conditions where the code jumps out of the structured loops. I left these alone because a complete re-write is needed if I wanted it "pretty".

(make it work, then make it better)

 

EDIT: The original posted version was un-reliable due to me trying to keep interrupts on in part of DSRLNK code.

I have re-posted the reliable version. Interrupts are disabled while the code runs.

 

 

 

\ DSRLNK for XFC99 cross-compiler/Assembler

\ PASSES error code back to Forth workspace, TOS register

\ Source:
\ http://atariage.com/forums/topic/283914-specialized-file-access-from-xb/page-2
\ by InsaneMultitasker via Thierry Nouspikel

CROSS-ASSEMBLING  XASSEMBLER DEFINITIONS

\ we need more labels than I normally use for Forth style CODE Words
 A DUP refer: @@A    binder: @@A:

CROSS-COMPILING XASSEMBLER DEFINITIONS
\ MACRO to simplify the VDP code
: VDPWA, ( reg -- )
       DUP           SWPB,   \ setup VDP address
       DUP VDPWA @@  MOVB,
       DUP           SWPB,
           VDPWA @@  MOVB,
                     NOP,  ;
                     
: [TOS]    8 (R13)  ;  \ gives access to Forth top of stack register

[CC] HEX

TARGET-COMPILING
\ 8C02 EQU VDPWA
\ 8C00 EQU VDWWD
\ 8800 EQU VDPRD

l: HEX20   20 BYTE,
l: HEXAA   AA BYTE,
l: PERIOD  2E BYTE,  \ '.'
          .EVEN

l: NAMBUF  BSS  6    \ no header string space
l: H2000   DATA 2000
l: CYC1    DATA 0000
l: H1300   DATA 1300

\ take some space in Forth DATA stack for a workspace
[CC] SP0 100 - [TC] VALUE: DREGS

[CC] 5 2* DREGS + [TC] EQU DREG(5)

CLR-JMPTABLE

l: DSR1                      \ headless code
      *R14+     R5   MOV,    \ get '8'->R5, auto inc for return
       HEX20 @@ R15  SZCB,   \ >20 eq flag=0
       8356 @@  R0   MOV,    \ [PAB FNAME] to R0
       R0       R9   MOV,    \ dup R0 to R9
       R9       -8   ADDI,   \ R9-8 = [PAB FLG]
       R0           VDPWA,
       VDPRD @@ R1   MOVB,   \ R1= length of FNAME

\ setup to copy VDP FNAME ->namebuf to '.' character
       R1       R3   MOVB,   \ DUP length byte to R3
       R3       08   SRL,    \ swap the byte to other side
       R4            SETO,   \ R4 = -1
       R2   NAMBUF   LI,     \ R2 is ^namebuf
       BEGIN,
         R0            INC,    \ point to next fname VDP address
         R4            INC,    \ counter starts at 0
         R4       R3   CMP,    \ is counter = fnamelength
         @@1           JEQ,    \ if true goto @@1:
         R0          VDPWA,    \ set VDP address
         VDPRD @@ R1  MOVB,    \ read next VDP char from fname
         R1      *R2+ MOVB,    \ copy to namebuf & inc pointer
         R1 PERIOD @@ CMPB,    \ is it a '.'
       EQ UNTIL,                 \ until '.' found  34 bytes!!!

@@1:   R4        R4  MOV,    \ test R4(device name length)=0
       @@6           JEQ,    \ if so, goto ERROR6
       R4        07  CMPI,   \ is dev name length>7
       @@8           JGT,    \ if so, goto @@8 (ERROR6)
       83D0 @@       CLR,    \ erase magic CRU addr. holder
       R4   8354 @@  MOV,    \ put length in magic address
       R4            INC,    \ +1 points to '.' character
       R4   8356 @@  ADD,    \ add offset to PAB address (makes "real PAB")

\ ==== GPL WORKSPACE ====
       83E0         LWPI,    \ SROM (search ROM device list)
       R1           CLR,     \ MAGIC GPL REGISTER=0
       H2000 @@ CYC1 @@ MOV, \ init the CYC1 variable ??
       R12     1000 LI,      \ init CRU base to 1000
       @@A          JMP,

@@9:   R12   1000   LI,      \ init CRU address
       H1300 @@ CYC1 @@ MOV, \
@@A:
       BEGIN,  \ scan for I/O cards
         R12   R12   MOV,
         NE IF,              \ if card address<>0
              00 SBZ,        \ turn off card
         ENDIF,
         R12    0100  ADDI,  \ advance CRU to next card
         83D0 @@      CLR,   \ erase magic addres
         R12    2000  CMPI,  \
         @@9          JEQ,   \ Scan ROM
         R12  CYC1 @@ CMP,
         @@5          JEQ,   \ no more cards. goto ERROR5
\ card activation...
         R12  83D0 @@ MOV,   \ save card CRU in magic address
         00           SBO,   \ turn on the card
         R2   4000    LI,    \ ROM start addr -> R2
        *R2  HEXAA @@ CMPB,  \ test for card present
       EQ UNTIL,             \ loop until card is found
       DREG(5) @@ R2 ADD,    \ add '8'+4000= >4008 DSR ROM list
       @@9          JMP,

@@3: \ scan ROM linked list for code address
       BEGIN,
         BEGIN,
           83D2 @@   R2 MOV,   \ start of ROM device list -> R2
           00           SBO,   \ turn card on
@@9:      *R2       R2  MOV,   \ Fetch next link
           @@A          JEQ,   \ if link=0 goto @@A (NEXT CARD)
           R2  83D2 @@  MOV,   \ save link address in magic address
           R2           INCT,  \ R2 = code pointer
          *R2+      R9  MOV,   \ fetch code address ->R9
           8355 @@  R5  MOVB,  \ dev length->R5
           @@4          JEQ,   \ if 0 we have a string match
           R5      *R2+ CMPB,  \
         EQ UNTIL,

\ find dev string match
         R5       08  SRL,     \ shift length byte
         R6   NAMBUF  LI,      \ R6 holds ^nambuf
         BEGIN,
           *R6+   *R2+  CMPB,  \ compare namebuf to ROM string
            @@3         JNE,   \ if mismatch goto @@3
            R5          DEC,   \ dec the counter register
         EQ UNTIL,
@@4: \ DJUMP4 run DSR code
         R1            INC,    \ count entries into the DSR ?
        *R9            BL,     \ call the DSR code
       AGAIN,                  \ try next card

\   -- DSR returns here if we are done --
       00            SBZ,  \ Turn off the card
       DREGS         LWPI, \ ==== DSR Workspace ====
       R9           VDPWA, \ set vdp address
       VDPRD @@  R1  MOVB, \ read error value to DREGS R1
       R1 0D         SRL,  \ shift error to correct range
       @@7           JNE,  \ if error<>0 goto @@7
                     RTWP, \ else return to Forth workspace

\ error condition handlers
@@5:    DREGS        LWPI,
@@6:                       \ dev. name too long
@@8:    R1           SETO, \ dev. name not found: code = -1
@@7:    R1     [TOS] MOV,  \ put error code in Forth
        HEX20 @@ R15 SOCB, \ set EQ flag = 1
                     RTWP,
\    ====== DSR LINK ENDS======

\ the vector for BLWP
l: DLNK   DREGS T, DSR1 T,

CODE: DSRLNK  ( -- ior)
        TOS PUSH,          \ space for error code on Forth stack
        TOS CLR,
        0 LIMI,            \ critical that we disable interrupts here.
        DLNK @@      BLWP,
        8            DATA,
        2 LIMI,
        NEXT,
        END-CODE

 

 

Edited by TheBF
Link to comment
Share on other sites

  • 1 year later...
  • the address of the PAB filename length byte is stored at >8356

Can someone explain this to me in relation to what I'm using as my "filename length" byte?

I have the following:

#COUNT BSS 16

This keeps track of the length of my filename that a user would create earlier in the process.

How would I store that correctly to >8356?

Could I just simply do:

Mov  @COUNT, @>8356 

But I thought>8356 needs an address, not the actual number length of my filename?

Just trying to figure this.

Thx

 

Link to comment
Share on other sites

36 minutes ago, GDMike said:
  • the address of the PAB filename length byte is stored at >8356

Can someone explain this to me in relation to what I'm using as my "filename length" byte?

I have the following:  #COUNT BSS 16

This keeps track of the length of my filename that a user would create earlier in the process.  How would I store that correctly to >8356?

Could I just simply do:  Mov  @COUNT, @>8356 

But I thought>8356 needs an address, not the actual number length of my filename?

 

PABs are stored in VRAM. The first 10 bytes are fixed and contain I/O information for the DSR. The last of these bytes, byte 9, is the filename length byte. The rest of the PAB is for the filename, including the device name, say DSK1. If a file is named SNP001 on DSK1, PAB byte 9 would be 11 followed by DSK1.SNP001. The VRAM address of the PAB’s filename length byte is what you must store at >8356, not whatever copy of it you may be storing in CPU RAM (CRAM). Whatever PAB information you track in CRAM must eventually get copied to the PAB before calling DSRLNK. Good discussions of file handling are in Section 18 of the E/A Manual and Chapter 8 of the fbForth 2.0 Manual.

 

If you store your PAB in VRAM at >0500, the address of the filename length byte is >0500 + 9 = >0509, which is what you would store at >8356 before calling DSRLNK.

 

...lee

  • Like 3
Link to comment
Share on other sites

Yes, in a PM, I suggested...

 

Then MOVB  @COUNT,@FSPAB+9, should work.

 

I was a little confused at that point in our dialog.:roll:

 

That should be...

 

MOV @COUNT,@PBAD+9

 

However, in your code that I was reviewing, you had not yet copied your PAB to VDPRAM! But that must be done before you execute the DSR.

 

EDIT: OK, above is still wrong ...correcting, testing,:D.


OK... I'm back on track...

 

The original example...

 

Then MOVB  @COUNT,@FSPAB+9, should work.

 

...is correct, but, for a different issue ...namely, how to move the length byte
from @COUNT into the "PAB data", located in CPURAM.

 

Quote

Could I just simply do:

Mov  @COUNT, @>8356 

No, this would move the "number length" into >8356.

 

To move the address of where that length byte is in VDPRAM, use:

 

LI   R6,PBAD+9
MOV  R6,POINTR

 

But, you must also move the PAB data into VDPRAM...

 

* DO THE WRITE!
 
     LI   R0,PBAD
     LI   R1,FSPAB
     LI   R2,20
     BLWP @VMBW


LI R2,20, is from the example given in the Molesworth book Pg. 82('DSK1.FILE '), the example shows a trailing space, perhaps for a single digit to be appended, but as Lee mentioned, "The first 10 bytes are fixed and contain I/O information for the DSR.", If your DEVICE+FILENAME might be longer, you should increase the value given to R2 accordingly. It should be permissible to use the max. length you wish to allow/device can handle, rather than the exact length your user provides at each individual entry. The length does need to be specific in byte 9, of the PAB at each and every call of the DSR though.

 

Ahh, back to my own personal drudgery!:ponder:

Edited by HOME AUTOMATION
Spellin' ...correcting,,, Ahh.
  • Like 1
Link to comment
Share on other sites

Yes, and I'm doubling back over again because I'm trying to understand it. 

I see where your coming from now, as it's starting to make sense. 

Lee has it here: in fb manual, section#8

"Access to File I/O Using TI-99/4A Device Service Routines"

Documented real nice.

I might actually learn something now. 

TBD...

 

 

  • Like 1
Link to comment
Share on other sites

I'm going to start fresh in the morning I'm looking over the vram mapping which is, I've been having a hard time trying to find it, but I have some info on it now. 

Because you really have to follow it to get the DSR link right.

But I'll start back on this in the morning.

I understand how the PAB works I just don't understand the addressing involved and how much space those addresses need. So I'll pick it up in the morning

  • Like 1
Link to comment
Share on other sites

5 hours ago, HOME AUTOMATION said:

Since the filename length is specified as a single byte, shouldn't COUNT BSS 1, suffice? In your PM, you seem to offer differing accounts of how COUNT is used.:)

To me it depends on how one sees the world.

In the E/A Manual the count and the string are understood to be separate pieces of data. This is an Assembly Language view of the computer IMHO.

 

One can look at the count and the text as part of something called a byte counted string, where the 1st byte is the length.

So GDMike's BSS 16 gives you room for this entire data structure. 

 

Of course one has to remember in your code that this label is pointing one these "counted strings" but it's not a big thing to remember once you commit to the concept.

 

 

  • Like 1
Link to comment
Share on other sites

5 hours ago, HOME AUTOMATION said:

Since the filename length is specified as a single byte, shouldn't COUNT BSS 1, suffice? In your PM, you seem to offer differing accounts of how COUNT is used.:)

Ok? I had something in mind at the time and it made sense, but I don't see Why I can't make , COUNT BSS 1

Let's roll with that, since I can't talk myself out of it. Lol

Let's move on... I've got this understood.

Thx everyone

Link to comment
Share on other sites

5 hours ago, HOME AUTOMATION said:

Since the filename length is specified as a single byte, shouldn't COUNT BSS 1, suffice? In your PM, you seem to offer differing accounts of how COUNT is used.:)

Also keep in mind that the following are the same as far as length.  I'm not entirely sure, but I think the use of the BSS statement does not dictate the byte is automatically a >00 byte by all assemblers while the BYTE statement does.

 

COUNT BSS   1

COUNT BYTE 0

 

If you have no other single byte labels before or after, then you will have actually used two bytes of memory space as all instructions are on even byte boundaries.

 

Myself, I always add an EVEN statement after the use of odd number BSS's or BYTE statements.

 

Beery

  • Like 1
Link to comment
Share on other sites

It is important that a byte counted string have the count (length) byte be contiguous with the string it is counting, so it might be best to use a combination of BYTE and TEXT directives:

COUNT  BYTE 0
FNAME  TEXT '               '
       EVEN

Copying to the PAB in VRAM at VPAB, say, is easily done by

       LI   R0,VPAB+9
       LI   R1,COUNT
       LI   R2 16
       BLWP @VMBW

because FNAME starts immediately after the COUNT byte.

 

...lee

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

Like this.

FSPAB EQU >79E

And, correct. I'm using TEXT mode.

 

********************  code

* DO THE WRITE!
 
       LI   R0,PBAD
       LI   R1,FSPAB
       LI   R2,20
       BLWP @VMBW
 
IM SUPPOSED TO DO A BL @ DSR FROM HERE
   WHICH IS NEED TO CREATE.

 

 

 

 

 

SBUFF  EQU  >1000             * BUFFER ADDRESS
PBAD   EQU  >79E              * PAB ADDRESS
FSPAB  DATA >0012,SBUFF,>8000,>0000,>0000
*             OP DV     128
COUNT  BYTE 0
FLNM   BSS  16
STATUS EQU  >837C
POINT  EQU  >8356
READP  BYTE >02
CLOSEP BYTE >01
EOFP   DATA 0
ERRM   TEXT '* I/O ERROR * '
CPUBF  BSS  80
LENP   BSS  2

Edited by GDMike
Link to comment
Share on other sites

If everything in the last post is workable, ill move on to hopefully create the DSR routine. Im guessing, the DSR section will be called to do the actual data move from CPU ram, where MY SCREEN DATA is stored, and find its way into VRAM and then onto DISK.

 

Edited by GDMike
Link to comment
Share on other sites

Where you can position you PAB in VDP RAM does of course depend on your runtime environment.

If you make support routines running under Extended BASIC you have one scenario. If you are using Pascal, Forth or whatever, you have different scenarios.

When you run a pure assembly program, you define the scenario. There are assumptions when your program starts, depending on if it's loaded by Editor/Assembler module or something else, but you can change them as you like.

 

The BYTE and DATA directives generate code with specific data.

BYTE 27

BYTE 32

DATA 15364

will generate four bytes of code.

BSS 4

as well as

BES 4

will reserve space for four bytes of data, but no specific value will be loaded. Normally, the loader program will just skip these bytes, and start loading values four bytes further ahead.

 

Thus

COUNT BSS 16

will reserve the same amount of space as

COUNT BYTE 0

      BSS 15

but in the second case, you are certain that COUNT is set to zero when the program starts.

 

  • Thanks 1
Link to comment
Share on other sites

now, ive got to create the DSR routine.

Ive started this with, following the example, from "introduction to assembly language" page 84

DSR    LI  R6,FSPAB+9

this is supposed to look at my FILENAME that the user placed into FLNM??

i hope and pray!!

 

 

then I move R6 @ point!

MOV  R6,POINT     * >8356

 

Edited by GDMike
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...