|Detecting Interface 1 Presence|
It's useful to be able to detect if the Interface 1 is present. Then a program can chose to use Interface 1 facilities, such as saving to microdrive, and avoid using them if absent.
The original Spectrum ROM has a bug in the CLOSE# routine that causes a crash with an attempt to close an unopened stream higher than stream 3. Consequently, the Interface 1 hooks into the CLOSE routine to fix the bug and to close Interface 1 channels. So, using CLOSE# will create the extended system variables if the Interface 1 is present.
Stream 0 defaults to the
"K"eyboard channel and is
re-attached to it at various times during program execution. So doing
CLOSE#0 is effectively a null operation, with the side effect
that the Interface 1 is woken up.
Location 23734 is the first byte of the CHANS area on an unexpanded
Spectrum, and will contain 244, the low byte of the PRINT_OUT routine at
&09F4. With the Interface 1 woken up, location 23734 is FLAGS3. As the
top four bits only ever have one set at a time it can never contain &F4.
So, the following code will set
int1 to non-zero if the
Interface 1 is present, and sets it to zero on an unexpanded Spectrum.
LET int1=0:CLOSE#0:IF PEEK 23734<>244 THEN LET int1=1The program can then do things like:
IF int1 THEN CLEAR#:OPEN #9,"b"
W CI\*]\k. (The JGHROM traps this error and converts it to
Unknown command.) In machine code, though, you can trap this error and continue. This can be done with the following code.
XOR A:LD (INT1OK),A ; Assume unexpanded Spectrum LD HL,(ERR_SP):PUSH HL ; Save current ERR_SP CALL CheckInt1 ; Call the check code, stacking a return to here POP HL:LD (ERR_SP),HL ; Restore ERR_SP ; program continues... .CheckInt1 LD (ERR_SP),SP ; Point ERR_SP to the return from here RST &08:DEFB &31 ; Attempt to initialise Interface 1 LD A,&FF:LD (INT1OK),A ; Set flag to non-zero to show Interface 1 present RETAn alternative method is as follows:
XOR A:LD (INT1OK),A ; Assume unexpanded Spectrum LD HL,(ERR_SP):PUSH HL ; Save current ERR_SP LD HL,CheckRet:PUSH HL ; Fake a return address to CheckRet RST &08:DEFB &31 ; Attempt to initialise Interface 1 LD A,&FF:LD (INT1OK),A ; Set flag to non-zero to show Interface 1 present POP HL ; Lose CheckRet from stack .CheckRet ; An error returns to here POP HL:LD (ERR_SP),HL ; Restore ERR_SP ; program continues...