/ Disassembly of the DMS RF08 driver. / This version is at offset 2400 in the BUILDER, dec-d8-sbaf-pb. / Nov 20 2023: VRS / Downloaded the excellent start made by Dave R. from / https://forum.vcfed.org/index.php?attachments/dms-stuff-zip.1268325/ / Nov 21 2023: VRS / Created this document, which hopes to still document things while / actually assembling to re-create the original driver. / Dec 6 2023: VRS / Brought into alignment with the RF08 driver at location 2400 of / dec-d8-sbaf-pb. / Dec 9 2023: VRS / Clarified the comments on the code, and removed disassembly notes. / Added a block comment about the confusing calculations that convert / block number to disk offset. / DCMA=6601 / Reset controller state DIML=6615 / Clear then load Memory Extension Register DXAL=6643 / Clear then Load EMA DFSE=6621 / Skip if Error DFSC=6622 / Skip if Data Complete DISK=6623 / Skip if Error or Data Complete *2400 RELOC 7600 C6, 0006 / The BOOTSTRAP entry point and a constant. JMS SYSIO / Call SYSIO entry point. 0005 / Function code. 5 = WRITE. 0373 / Block = first disk scratch block. 7200 / Buffer address. OFUNC, .-. / Link field. Re-used below to store user function. HLT / Error HALT. JMS SYSIO / Call SYSIO entry point. 0005 / Function code. 5 = WRITE. 0374 / Block = second disk scratch block. 7400 / Buffer address. DADDRL, .-. / Link field. Re-used as low disk address. PLNKP, LNKPTR / 7752, so it doubles as a funky HLT. JMS SYSIO / Call SYSIO entry point. 0003 / Function code. 3 = READ. 0001 / Block = MONITOR (1ST PAGE OF SAVE). 7200 / Buffer address. CSLNK, .-. / Link field. Re-used as pointer to link in buffer. HLT / Error HALT. JMS SYSIO / Call SYSIO entry point. 0003 / Function code. 3 = READ. 0002 / Block = MONITOR (START). MONTOR, 7400 / Buffer address. Also Monitor starting address. CSBLK, .-. / Link field. Re-used to hold the disk block parameter. HLT / Error HALT. JMP I MONTOR / Jump to the monitor. C77, 0077 / Constant 0077. C40, 0040 / Constant 0040. C700, 0700 / Constant 0700. / An indirect error return is desired by the caller. INDIR, TAD PLNKP / Get a pointer to LNKPTR. DCA LNKPTR / Make LNKPTR point to itself. TAD I SYSIO / Load the error address DCA SYSIO / Do the indirection. JMP NOIND / Resume as if no indirection. / / JMS I SYSIO / WORD DESIRED FUNCTION / WORD DESIRED BLOCK / WORD DESIRED CORE ADDRESS (low 12 bits). / WORD LINK FIELD (Filled by WRITE, used by READ). / ERROR RETURN HERE / NORMAL RETURN HERE / / FUNCTION WORD / ============= / / 0 1 2 3 4 5 6 7 8 9 10 11 / U U - Unused bits. / R - 0=Normal return. 1=Indirect return. / U U U - Unit number 0-7 (if DECtape?). / F F F - Memory field 0-7. / F F F - Function. READ=3. WRITE=5. / / The ERROR RETURN in the indirect case is a pointer to a location in memory / to return to. It will return to the pointer in the case of an ERROR or to / pointer+1 in the case of NO ERROR. / / The computation of disk offset from block number is interesting. / Each of the eight units is 128K words long. This work out to 1016 blocks, / 129 word blocks, and an additional 8 words. / / Notice also that 16K = 1 + 127*129. The RF08 disk can protect 16K regions / of the media. For this reason, the blocks are skewed by a word, so that / the first 16K boundary will be a protection boundary. Note that the other / seven overhead words are at the far end, not spread across each 16K segment. / / Now, given a block number between 0 and 1015, one must calculate the word / at which that particular block is found. Ideally, one would multiply by / 129 (0201) and add one. Some drivers actually do this, using two words / to form the 18 bit product. This driver does something different. / / One calculation is performed to take the low 6 bits of the block number, / Multiply by 0200, add 1, and add the block number, forming the low word / of the disk offset. Note that if the LINK is set after this calculation, / then the result has *just* overflowed, and the upper word would need to be / incremented. This low word is used with the DMAR or DMAW instruction to / initiate the I/O operation. / / A seperate calculation is performed for the upper bits, which will be sent / to the controller with a DXAL instruction. In principle, what one would do / is to carry out a calculation of the upper disk address bits using values / scaled right by 12 bits. Note, however, that only values of 0-15 can / occur in the upper half of the block number. The calculation starts out / shifted 6 bits, and is moved right 4 bits so the result will fit, then / the remaining 2 bits right needed to multiply by 128 are done after the / offset for the unit number are added in. Note also that since the range / is only 0-15, the 1% error of multiplying by 128 instead of 129 is not / large enough to be a factor. / SYSIO, .-. / SYSIO SUBROUTINE. Return address. CLA CLL CMA RTL / Get -3 (7775) DCA RETRYS / Set up retry count. TAD I SYSIO / Get function desired. DCA OFUNC / Remember it TAD OFUNC / Get function desired. C200, AND C6 / Mask for read/write. TAD DMAX / Add 6600 to form DMAR or DMAW DCA DMARW / Store it for later TAD OFUNC / Get function desired. AND C70 / Mask with 70 to isolate field. TAD CDF0 / Make a CDF instruction. DCA USRCDF / Set up CDF for user field. ISZ SYSIO / Point to the block number TAD I SYSIO / Get the block number. DCA CSBLK / Save the block number. ISZ SYSIO / Point to the buffer address. TAD I SYSIO / Get the buffer address. TAD C200 / Point to the buffer's link word. DCA CSLNK / Save it. ISZ SYSIO / Bump to link parameter. TAD I SYSIO / Get link parameter JMS LNKUP / Fiddle the links. DCA INDPTR / Store the old link value. TAD SYSIO / Get address for link value DCA LNKPTR / Save it for later ISZ SYSIO / Bump to error return TAD OFUNC / Get function desired. RTL / Shift indirect bit to sign. SPA CLA / Indirect return desired? JMP INDIR / Yes, go set for indirection. NOIND, TAD OFUNC / Get function desired. AND C70 / Get field again. DIML / Send it to the controller. / DIML is required to clear AC here. TAD CSBLK / Get the block number. AND C77 / Mask for 6 bits. CLL RTR / Multiply by 0200. RTR RTR CLL IAC / Add one to align block boundary with / protection boundary. TAD CSBLK / Make 0201*block+1 == disk offset. DCA DADDRL / Save the low 12 bits of offset. SZL / Overflow? TAD C40 / Yes, set the relevant bit TAD CSBLK / Get the block number. RTR / Scale result to align with unit below. RTR AND C77 / Form high disk offset DCA WC / Save for a moment TAD OFUNC / Get function desired. AND C700 / Get the unit number. TAD WC / Add high block offset. CLL RAR / Align with controller's needs. DXAL / Send high block offset to controller. / DXAL is expected to clear AC. TAD N201 / Get -blocksize. DCA WC / Set up WC. TAD N201 / Get -blocksize. TAD CSLNK / Back up link pointer to start of buffer. DCA CA / Set up CA. TAD DADDRL / Get low disk address DMARW, .-. / Initiate read or write, clear AC. DISK / Finished the read? JMP .-1 / No, keep waiting. DFSE / Was there an error? JMP IOOK / No, return. ISZ RETRYS / Yes, last attempt? RETRY=7701 JMP RETRY / No, go do retry IOERR=7761 JMP IOERR / Yes, go return error N201, -201 / Constant (negative blocksize) C70, 70 / Constant (field mask) WC=7750 / Hardware requires this be here WC, .-. / Word Count CA=7751 / Hardware requires this be here CA, .-. / Current Address LNKPTR, .-. / Used to save a pointer to the link word INDPTR, .-. / 7777 or link pointer *.+1 / Unused *.+1 / Unused *.+1 / Unused RETRYS, .-. / Retry counter/flag. IOOK, ISZ SYSIO / Bump the return address to the normal return. IOERR, TAD INDPTR / Load link pointer JMS LNKUP / Update the link DCA I LNKPTR / Update the link field of the caller. DMAX, DCMA / Re-initialize the controller. / Also a convenient constant to construct DMAR/DMAW. JMP I SYSIO / Return from SYSIO subroutine. / / This routine is passed a new link value, updates the buffer, / and returns the old link value. LNKUP, .-. / Start of subroutine. DCA CA / Save AC for a moment. USRCDF, .-. / Change to the DF containing the buffer. TAD I CSLNK / Get the link word from the buffer. DCA WC / Store for a moment. TAD CA / Get the parameter value DCA I CSLNK / Store it into the user buffer's link word. CDF0, CDF 0 / Return to DF zero (current field). TAD WC / Load old link value from the buffer. JMP I LNKUP / Return to caller. $