Articol disponibil numai în limba engleză
At the time the +3 (and +2A) came out, some games simply refused to play.
One of the reason for this was the “missing” IN #FF port (255 decimal). In fact, a true IN #FF port does not exists on neither Spectrum model.
How is that ?
(well, sort of)
I suppose you know how the vacuum tube of any (old, by now) TV works: the electron beam make left-right and up-down movements very fast, giving to the human eye the impression there is a still image.
Make border 0 or any other value different than the paper colour; you will see the Spectrum's TV display area like a “window”. Let's start with the electron beam from the top left corner of the screen. What is there ? The border - no image. Thus, at this moment, the video RAM is useless to be read, since no video-information is required. During this moment, the processor can make all (video) RAM access at full speed, no wait states. The video display mechanism does nothing, it is in a sort of “stand-by” state (it only generates H sync signals for the TV). The beam scans, scans and after 1/5 (approx.) from the top, it reaches the "window" zone; at this moment, the video RAM starts to be read by the video system display. When the beam reach the last 32 pixel of the first line (and the first pixel-line has been just displayed), the computer's video system goes again in "stand by" state until the next pixel-line. And so, line by line. When the bottom of the "window" has been reached, the video system pass definitively in "stand by" state, waiting the electron beam of the TV to reach again the top of the "window" - but this will happen again only after scanning the last 1/5 of the bottom TV screen and then the other 1/5 of the top of the next TV field.
If the processor has some business with the video RAM, it comes in conflict with the video display mechanism in the "window" moments. The conflict is solved by means of WAIT states on the processor side. Because of this, a time execution loop of a program that runs in the video RAM cannot be exactly predicted, except when synchronized with the Spectrum's interrupt mode (and even so very difficult).
On older models (up to +2) the data bus between the video RAM - on one side - and the non-video upper system RAM together with the processor - on the other side - were separated by 8 × 470 ohm resistors, one for each data line. This value is low enough to be transparent when the processor makes video RAM requests (for example, when the processor writes something at address #4200) and high enough if both memory banks are at the same time - but independently - accessed - the video RAM by the display system and the upper system RAM by the processor (for example, when the video system performs an attribute display for address #5802 and at the same time the processor writes something at address #9A00 (or any address greater than #8000)).
All input ports are circuits with three-state outputs. These outputs, connected to the data bus, are normally in high impedance state; they are only enabled to low impedance when the properly I/O address match the port address. For example, the IN #FE port (the keyboard reading) is enabled only when the #FE address is decoded at the same time with the nIORQ active (logical 0) and nRD active (logical 0).
What happens if the port does not exist ? For example an IN #F1 instruction ?
On +3 (and +2A) there's no physical circuit to be enabled - the processor reads nothing. But as all 8 data lines are pulled-up to +5 V with 8 × 10 Kohm resistors, the value read will be #FF (all data in logical 1).
On the other hand, on the old (+)48, +128 and +2 Spectrums, the processor may read something ! This something is the video display system. If the processor performs an IN #75 instruction and by coincidence at the same time the video system just displays an attribute with BRIGHT 1 / PAPER 2 / INK 6, then the IN #75 instruction will read the value #56 (86 decimal) ! This occurs because the 470 ohm resistors are the smallest impedance at that time on the data bus and the processor reads in fact the video data bus. The port reading can give a pixel value, an attribute value, or nothing (#FF) if the beam of the TV screen is at that moment somewhere in the border. This is completely random.
Some games are performing this reading. The port chosen by programmers is the IN #FF (255 decimal), but can be any other IN port that does not exist physically. There is a loop that works something like this:
LOOP IN A,(#FF) ; READ THIS PORT
CP A,#FF ; CHECK IF "BORDER" OR "WINDOW"
JP Z,LOOP ; JUMP BACK IF STILL BORDER
..... ; CONTINUE THE PROGRAM
This is a way to make a relationship of the game with the Spectrum display area. It is used like a second interrupt signal. The IN port will read #FF every time when the electron beam of the TV is in border area (since in this moment the video display system is in "stand-by" state) and will be different than #FF if in the "window" area. The loop assumes there is something visible on screen and the colour is of particular value. If, for example, all pixels are #FF and all attributes are #FF (FLASH 1 / BRIGHT 1 / PAPER 7 / INK 7 - difficult to believe, but possible) then this loop remains closed; or if someone remove the 470 ohm resistors, then again, this loop remain closed forever - you must reset the computer.
This last situation is present on the +3 (and +2A) computers. Here, the data separation between video RAM and the upper system RAM is done with transceivers (a better hardware solution), not with 470 ohm resistors. On these computers, an IN instruction to a non-present port will always read the #FF value, since the transceivers are normally in high impedance state (they are only enabled on specific memory address request).
As a result, (very) few games have problems. I am aware of this ones:
To make any +3 compatible with all software that uses the IN #FF port, there are two solutions:
For the first solution, you will need a few HCT-TTL (best) or LS-TTL (good enough) circuits. Maybe one day I will find some time to draw the schematic diagram for this.
For the second solution, connect a 470 ohm / 0.125 W or 0.25 W resistor between pins 17 of the IC 6 and pin 17 of the IC 4. That’s all !
I guess the second solution is easier to implement, even by a beginner in electronics :)
Important: don’t forget to isolate any open connection !
In the above first example, the only reason the connection of the wire with the resistor is not isolated is for the clarity of the connection shown.
In the above second example there is no need for isolation, because the resistor terminals are kept firmly at secure distance with silicone sealant.
In either case (the true or pseudo solution), I recommend that only D7 be involved. That means, an IN #FF value could only be #FF or #7F. It assumes the IN #FF request comes during a normal screen, with the FLASH attribute reset (i.e. no FLASH). I find simply absurd the assumption one will try to play Duet with the entire screen FLASH attribute set ! (in which case, the game will hang, like in the absence of the IN #FF port).
The simplified version for the IN #FF port (the second solution) has been implemented and tested by me on a few +3s and many +2As. Not any complain so far, only happy “customers” !
Note: I read one report saying that – after installing the 470 ohm resistor as described above – the +2A computer (in that case) had become unstable. This reminds me of another case – not related to the #FF port issue, but that could have the same origin – where a +2A (Spanish version if I remember well) was barely usable when playing games (it worked well only while in +2A Basic mode). In my case the gate array timing was imperfect in relation to the rest of the hardware components that happened to be on that board and introduced some unwanted spikes during RAM bank switching; the solution proved to be quite easy to apply: I just put two 120pF capacitors on processor’s A14 and A15 address lines (one between each address and GND). The owner was a heavy player and never got into any problem again :) (and yes, I then applied to it the #FF patch as well – the D7 / 470 ohm resistor solution)