In the TI parlance device drivers were called DSRs, or Device Service Routines. I started working one, in order to support disk drives (i.e. SD cards and PC access) in a manner compatible with existing TI software. Perhaps it is due to the terminology, perhaps it's because I never had a disk drive for the original TI, but it took some reading to start to understand how the software setup works. As one might expect for systems of the day, it does not seem complex. I got last evening to the point where the TI recognizes my DSR and calls it when DSK1 or DSK2 is accessed.
The way the TI firmware works is such that it constructs in video memory (of all places - but that was the primary memory of an unexpanded TI-99/4A) a structure called "PAB". It has the following layout (story continues after the code below):
Byte 0: OPCODE Byte 1: Flagbyte/status MSB 7 6 5 4 3 2 1 0 LSB | | | | | | | | | | | | | | | +— Filetype: 0=sequential, 1=relative record type | | | | | +-+--- Mode of operation(2): 00=Update, 01=Output, 10=Input, 11=Append | | | | +——— Datatype: 0=Display, 1=Internal | | | +————Record type: 0=Fixed length, 1=Variable length +-+-+—————————— Errorcode(3): 0 = no error Bytes 2,3: Data buffer address Byte 4: Logical record length: * Record length of fixed records or * Max length of variable record length (see flag byte) Byte 5: character count: * Number of characters to be transferred for write opcode, or * number of bytes actually read for a read opcode Bytes 6, 7: Record number: * only required for relative record type file * indicates the record number of the current I/O operation (0-32767) * highest bit ignored Byte 8: screen offset: * offset of the screen characters in respect to their normal ASCII value Byte 9: Name length: * Length of the file descriptor following the PAB Byte 10+: File descriptor: * device name and, if required, the filename and options. * the length of this descriptor is given in 9.
My simple DSR just computes the address of the PAB in VDP memory, and copies the PAB into CPU RAM at address >8010. This address would in a regular TI be mapped to the scratchpad RAM (the address decoding is not fully implemented, so the 256 byte RAM repeats in memory four times, but is normally accessed at address >8300). In my system the scratchpad is 1024 bytes, so I have 768 bytes of extra memory available in the memory map, in the region >8000..82FF which is unused by normal TI software.
My PC interface circuit has access to the external SRAM, including the region >8000..>82FF, so I was able to successfully read the PAB from TI's memory after my DSR routine copied it over there. So this is a starting point for a disk subsystem implementation! So far I have only tested what types of PAB's are created by TI BASIC using "save" and "load" commands. Basically I wrote a one line program, something like:
10 print "hello world" save DSK1.HELLOand the command save "DSK1.HELLO" resulted in a call into my DSR (after I realized that the device names indeed are case sensitive). The DSR copied the PAB from VDP RAM to CPU RAM, and from there I was able to read the following back to the PC:
8000 0b 14 00 01 07 00 12 34 00 01 60 df a7 b7 00 0e |.......4..`.....|
8010 06 00 3f ea 00 00 00 16 60 0a 44 53 4b 31 2e 48 |..?.....`.DSK1.H|
8020 45 4c 4c 4f 00 00 00 00 00 00 00 00 00 00 00 00 |ELLO............|
So we can see the opcode at memory location >8010 (6 stands for SAVE) and the device/filename can be seen from >801A onwards. My DSR at this point does not do much more, it just sets an error code and returns successfully to firmware i.e. BASIC.While the functionality at this point does not seem much, these are the building blocks to first create a disk subsystem on PC and later with the SD card available through the FPGA.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.