What I learned about calling a DSR.
For the uber-gurus (German/Sanskrit... interesting) all of this will be old news but I am happy I went through the process.
So for all those crazy people who might want to write a DSR interface system in some other language here goes.
First of all here is all the assembly language that I use to call the system ROMS. I use a DSR workspace but all it does is allow to me to get back to my Forth workspace. So it wastes 13 of the registers but it's a very convenient way to switch out the Forth workspace and get back.
( I could move the top of the workspace into Console ROM space and keep the bottom 3 registers in RAM I think, but I have not tried it yet)
\ This is the only code used to CALL the DSR ROM code
CODE: CALLDSR ( -- ) \ *called with Forth word BLWP
83E0 LWPI, \ change to GPL workspace
*R9 BL, \ GPL R9 already has the entry address
0BF0 DATA, \ This normally has DATA 8 in it. :-)
DSRWKSP LWPI, \ back to the dummy workspace
RTWP, \ Return to Forth
I made decisions that others might frown upon but I did it anyway.
1. I know where there disk card is in CRU space and I don't want to access any other system calls with this code so I use the address >1100 as a constant.
2. I know that card has an ID byte at the beginning >4000 so that is a constant called 'ID (Forth speak: the address of ID)
3. I know the link list of DSR names & routines is starts at address
4800 >4008 so that is a constant called 'DSRLIST. ( * Master Lee found my typo. I am gonna get a 'C' on this paper I bet)
You need a way to create a TMS9900 vector.
(Assembler equivalent: DISKLINK DATA DSRWKSP,CALLDSR
And you need to be able to BLWP to that vector. I created a new Forth word in ALC for this. It was just 2 instructions so no biggy.
You need a way to cut a string like: "DSK1.MYFILE" into "DSK1" which is the device name.
You need a way to search the linked list of Device names in the ROM, searching for the string you cut above.
My code called DSRFIND takes the full filename and extracts the device name into a temp string variable.
It searches via the links until it finds the device or hits the zero at the end of the list.
I found it easier to just return the link address (in the ROM) at the end of the search. I convert that link to the code address later.
If the device is not found DSRFIND returns zero.
You need to have basic CRU control. CAMEL99 Forth has CRU! that puts a value into R12 and CRU@ which reads R12.
And 0SBO and 0SBZ which do one ALC instruction each. ( SBO 0 and SBZ 0 )
With CRU control you need smart Card control word that checks if R12 has and address in it and if so turn if off, then change the address and turn on the new address. I called that ENABLE. DISABLE simply loads R12 and turns off that address.
When you enable the Disk controller card you need to store that CRU address in >83D0 also. I don't know why.
Edit: Not needed. This is seems to be a variable used by the console DSR. Your DSR can use it as such, but does not need to.
I will use some Forth code to help me remember/ explain what happens next.
: NEWFILE ( $addr len -- )
2DUP MAKEPAB ( -- $addr len realpab)
-ROT ( -- realpab $addr len )
DSRFIND ( -- realpab link)
DUP ?DEVERR \ ABORT if link=0
DUP 4 + ( -- link $) \ link+4=DSR$ ie: the name of the DSR
C@ 8355 C! \ len(DSR$) -> hex8355
( -- link)
>ENTRY 83E0 9 REG# ! \ DSR code entry into GPL.R9
( -- realpab ) 8356 ! \ the "REAL" PAB file name stored here
1. MAKEPAB creates a PAB in VDP memory with the full string (DSK1.MYFILE), the file mode byte, the buffer address, and the record size
BUT... it also does something *magic*.
You must get the address in your newly created VDP PAB at the dot character in the full filename.
So remember this is the VDP address of the dot character in the filename field of the PAB.
Put that somewhere safe in your chosen language you will need it shortly. I call it the "realpab"
2. Turn on the Disk card at CRU >1100 . Check the Card ID >AA is now present at address >4000
3. Run DSRFIND to find your DEV string that you extracted
4. Test your result: If it's zero error out. (my code just aborts to Forth console with a message)
If you found a good link, add 4 to it, that's the address of the string in the ROM.
Read a byte at that address and store the byte in >8355. ( It's length of the device string in ROM).
5. Take the LINK you found and increment by 2 to get to the code-address field.
Read the contents of that field and you have code-entry-address (runnable code)
Stuff that code-entry-address into R9 of the GPL workspace. (you can only do that in the 9900 family)
6. Remember that "realpab"? Put that address into memory at >8356.
Wasn't that fun? Not my idea of a nice API to a file system.
The FINAL CALL
I call this FILEOP and it does the following:
- Put the file operation byte into PAB
- Fetch the flag at PAB, mask off the upper 3 bits and put it back to clear err bits.
- Clear the GPL status byte
- Turn the disk (which must copy the CRU address to >83DO (REMEMBER?)
- BLWP to the VECTOR
- Read the error byte at PAB , (shift 5 bits to the right to see them correctly)
- Read the GPL byte and check for errors
- Turn the disk card off
: FILEOP ( c -- n)
PAB VC! \ write opcode byte to VDP PAB
PAB_FLG@ 1F AND PAB_FLG! \ clear err code bits
0 GPLSTAT C! \ clear GPL status register
DSKLNK BLWP ERR@
What a weird OS. But we love it Is that a problem...?
Edited by TheBF, Sun Apr 1, 2018 7:32 AM.