I've been doing some deep testing of PDP11 BASIC, and uncovered a couple of bugs with the PDP11 Tube Client.
When you use byte operations when the destination is a register - ie MOVB blah,Rn - the byte value is sign extended, so the resultant value is &00-&7F or &FF80-&FFFF. This affects the return values from OSRDCH, OSBGET, OSFIND, OSARGS, OSGBPB, OSFILE. This hadn't caused an issue as when calling from BASIC any call to these return via 'return8bit' so an explict &000000nn value is passed "up" the evaluator, plus when testing from machine code most calls happened to usually return <&80 (see note). This was essentially a brain fart, as whenever byte values were read at any time, they were always then written as byte values, so the sign extension was always hidden and had no effects.
However, it does affect OSWORD &13 and &14 as the OSWORD handler fetches a length byte from a lookup table. For these two calls the length byte is &80, and the handler then proceeds to attempt to transfer &FF80 bytes to the host! A simple patch to change those table entries to &7F works fine. Only three bytes need to be changed to fix this, for a patched update to v0.30a at https://mdfs.net/Software/Tube/PDP11 which I'll add to the PiTube GitHub after some more testing.
However, OSWORD calls &80+ have the length byte in the OSWORD control block, and if the user constructs a control block with a length byte of &80 - which the API allows as the maximum allowable - the call will fail. This will require a proper fix to the OSWORD handler, and I'll work on this as part of clamping the API return values and the next bug.
A second bug is that the OSBYTE handler juggles the return values with SWAB - which clears the Carry flag. This results in OSBYTE calls that return a status in Carry always returning Carry Clear. This only affects INKEY, which in BASIC is not noticed as R2 is tested instead, and the buffer read/write/examine calls. I'll fix this as part of the OSWORD &80+ fix. This needs a bit of work as there are only six bytes remaining spare.
*Explanatory notes:
The sign extended return values would only be visible if making an API call from machine code, and then manipulating the byte value as a word. In the majority of cases this would have had no effects anyway due to the implementation history of the existing host systems.
OSARGS returns a value in R0 only for reading the filing system number. On 8-bit systems the filing system number is always <&80 as bit 7 is used internally as part of the temporary filing system handler.
OSFIND returns a value in R0 when opening a file. Most filing systems return handles <&80, typically &11-&15 for DFS, &30-&37 for ADFS, etc. Only "recently" have filing systems started having a handle range &80+ such as HostFS returning &80+n, LinkFS returning &A0+n, etc. Even with a sign-extended handle, the extension would be invisible as when an OSBGET/BPUT/GBPB call is made with that handle, only a byte is passed to the API anyway.
OSFILE returns a value in R0 representing the object type. This is normally, 0=nothing, 1=file, 2=directory, with extensions for 3=imagefile (1+2) and 4+n as symbolic link. However, the API specificaltion allows &FF=run-only file, which HADFS does return.
OSGBPB returns a value in R0 which has supposed to indicate if the call has been actioned, but different implementations have implemented this badly, with differing implementations of R0=0 for "done", or R0=unchanged for "no action", or R0=random value, so code nearly universally ignores this and just looks at the control block to check for explicit changes indicating an action has occured.
OSBGET will return whatever is read from the file, so half of those bytes with be >&7F. Sign extension is invisible if the returned values are manipulated as bytes.
OSRDCH will return whatever keypress is returned, byte read from EXEC file or serial input, and that could be >&7F if, for instance, a function key is pressed that is set to return a character >&7F, etc. Again, sign extension is invisible if the returned values are manipulated as bytes.
When you use byte operations when the destination is a register - ie MOVB blah,Rn - the byte value is sign extended, so the resultant value is &00-&7F or &FF80-&FFFF. This affects the return values from OSRDCH, OSBGET, OSFIND, OSARGS, OSGBPB, OSFILE. This hadn't caused an issue as when calling from BASIC any call to these return via 'return8bit' so an explict &000000nn value is passed "up" the evaluator, plus when testing from machine code most calls happened to usually return <&80 (see note). This was essentially a brain fart, as whenever byte values were read at any time, they were always then written as byte values, so the sign extension was always hidden and had no effects.
However, it does affect OSWORD &13 and &14 as the OSWORD handler fetches a length byte from a lookup table. For these two calls the length byte is &80, and the handler then proceeds to attempt to transfer &FF80 bytes to the host! A simple patch to change those table entries to &7F works fine. Only three bytes need to be changed to fix this, for a patched update to v0.30a at https://mdfs.net/Software/Tube/PDP11 which I'll add to the PiTube GitHub after some more testing.
However, OSWORD calls &80+ have the length byte in the OSWORD control block, and if the user constructs a control block with a length byte of &80 - which the API allows as the maximum allowable - the call will fail. This will require a proper fix to the OSWORD handler, and I'll work on this as part of clamping the API return values and the next bug.
A second bug is that the OSBYTE handler juggles the return values with SWAB - which clears the Carry flag. This results in OSBYTE calls that return a status in Carry always returning Carry Clear. This only affects INKEY, which in BASIC is not noticed as R2 is tested instead, and the buffer read/write/examine calls. I'll fix this as part of the OSWORD &80+ fix. This needs a bit of work as there are only six bytes remaining spare.
*Explanatory notes:
The sign extended return values would only be visible if making an API call from machine code, and then manipulating the byte value as a word. In the majority of cases this would have had no effects anyway due to the implementation history of the existing host systems.
OSARGS returns a value in R0 only for reading the filing system number. On 8-bit systems the filing system number is always <&80 as bit 7 is used internally as part of the temporary filing system handler.
OSFIND returns a value in R0 when opening a file. Most filing systems return handles <&80, typically &11-&15 for DFS, &30-&37 for ADFS, etc. Only "recently" have filing systems started having a handle range &80+ such as HostFS returning &80+n, LinkFS returning &A0+n, etc. Even with a sign-extended handle, the extension would be invisible as when an OSBGET/BPUT/GBPB call is made with that handle, only a byte is passed to the API anyway.
OSFILE returns a value in R0 representing the object type. This is normally, 0=nothing, 1=file, 2=directory, with extensions for 3=imagefile (1+2) and 4+n as symbolic link. However, the API specificaltion allows &FF=run-only file, which HADFS does return.
OSGBPB returns a value in R0 which has supposed to indicate if the call has been actioned, but different implementations have implemented this badly, with differing implementations of R0=0 for "done", or R0=unchanged for "no action", or R0=random value, so code nearly universally ignores this and just looks at the control block to check for explicit changes indicating an action has occured.
OSBGET will return whatever is read from the file, so half of those bytes with be >&7F. Sign extension is invisible if the returned values are manipulated as bytes.
OSRDCH will return whatever keypress is returned, byte read from EXEC file or serial input, and that could be >&7F if, for instance, a function key is pressed that is set to return a character >&7F, etc. Again, sign extension is invisible if the returned values are manipulated as bytes.
Statistics: Posted by jgharston — Sun Apr 28, 2024 2:22 am