A story about extending the Spectrum ROM.
   
And introducing an on-the-fly method for paging ROM banks
that mimics the mechanism as is used in Sinclairs Interface1.

by Roelof Koning.

  The Sinclair Spectrum was brought on the market at a moment in which the development of the 'system' (BASIC residing in ROM) was not yet completely finished. The Sinclair Interface 1 (IF1) hardware extension therefore had to bring extra 'system code' along. A clever method was used to 'add' this extra ROM code to the original ROM code inside the Spectrum.
  The same method, often named 'paging' or 'hard paging', was also used by manufacturers of other interfaces. It is an intrigueing method with intrigueing results, and among us for some 25 years now.
  The following story tries to explain, for those who are still active in the field of programming and developing and for those who are hoping that they one day will find the time for that, how still a new and probably usefull aspect was discovered.

Hard method
  Let us start with a view at the more or less classic situation regarding the Spectrum. A hardware manufacturer designed a nice add-on (IF1, Opus, PlusD, DivIDE, Spectranet) which needed its own software, and choose to supply this software in a ROM chip which resides in the add-on (interface). Such ROM chip is connected parallel with the original Spectrum ROM chip, and a kind of switch is installed which makes it possible to make one of these two ROMs active, depending on certain situations. It will be clear that for instance a disk interface that holds a ROM, will 'page in' (switch on, make active) this own ROM (and thus its own software) whenever some disk operation has to be executed. 
  The specific situations in which the Spectrum ROM is paged out and another ROM is paged in, are normally connected with certain ROM addresses. Address 8 (this is where RST 8 jumps to) is probably the best known. The Sinclair IF1 is using it, together with address 5896. 
  This 'paging' is only possible because the Spectrum has a connection on the edge connector by which the original ROM can be switched off. That possibility is all that Spectrum offers, all other switching gear (plus the connected 'logic') must be provided by the new add-on. The general picture is that interfaces (including IF1) have to be active and 'clever' in order to 'steal' control over the ROM area. 

  The switching logic of a 'clever' interface resides in a number of standard chips, or in a dedicated chip like the ULA in Interface1 or the PAL in the PlusD. An idea of the size of such switching gear can be gotten from the Opus Discovery, where some 9 standard logic chips are needed to get the basic 'switching mechanism' going. The 'switching' part of interfaces holding a ROM constitutes a considerable part of such interface. It was Sinclairs Interface 1 that opened this route to "active paging" of ROMs, and many add-on manufacturers followed there. 
  It should be noted that this method has a connection with a specific feature of the Sinclair software, where all error-handling is routed to one specific address in ROM, address 8. Whenever address 8 is 'addressed' by a program, this is registrated by a dedicated set of logic (electronic) gates and results in an electric signal which triggers the (electronic) switch. For all different conditions under which 'paging' must take place, such an 'address-decoding' device must be present. It looks as if Sinclair originally planned to use only address 8 for paging ROMs, and that later a second address (5896) had to be used for IF1 due to a bug in the Spectrum ROM. 
  This clever method of ROM-extension that left the Spectrum completely untouched was (and still is) impressive. 
 
Soft method
  A second method of 'paging' was used by Sinclair when the Spectrum128 arrived. Here the control over ROM (and RAM) areas is not 'stolen away' by a stranger but handed over by Spectrum ROM itself,  to a friendly 'colleague' ROM. For this purpose a few minor changes were made in the original ROM code. Now the Spectrum played an active role in 'paging', and a much simpler switching mechanism could be used, equivalent to using one or two standard logic chips. The name "passive paging" is suggested for this method, as the recepting 'add-on' remains passive although its presence is the reason that paging is needed. 
  Chips that can be used as ROM have become significantly cheaper since 1982, and sizes nowadays go far beyond the 16K as used in the Spectrum. Add-ons for the Spectrum are available (via Internet) that hold up to 128K ROM and 128K RAM, and even more. Often the ROM (non volatile) part is (re-)programmable.
These large ROMs or RAMs are split up in smaller parts that individually can be selected. Such parts are called 'banks' or 'pages', and usually have a number assigned. This article, by the way,  regards pages of 16K bytes that, when active, fill the Z80's address space from 0 to 16383.
  The 'paging' mechanism of such added memory is mostly based on a simple hardware switch, more or less equal to that of Spectrum 128,  which can be controlled by software. This switch can normally even be operated from BASIC by a command like OUT x,y where X is a port address and Y is the number of a memory bank. The hardware switch for this method usually consists of a so called "edge triggered flipflop", which makes that the actual switching is done at a specific moment during the Z80's activities, i.c. a specific state of its control signals.

On the fly method
  The method of 'active paging' lost in my view its significance when large capacity ROMs (EPROMs, FlashRAMs) became available and the prices went down. There is no longer a reason for keeping the original 'hard' Spectrum EPROM on duty, since a copy of it can find a place in a large capacity ROM. Such a copy of Spectrum's ROM can, in contrary with the original ROM inside the Spectrum, be modified for the designers specific needs. And among those needs might be the 'paging' of different ROM banks. Several add-ons featuring large capacity ROM are available nowadays.
  My own Spectrum system with a multi-page ROM (since 1987....) might serve here as a living example for this on-the-fly method. In my system is, for a number of (hardware related) reasons, chosen to switch between 16K ROM banks with an IN instruction in Machine Code. These banks are numbered 9 - 16 . And the code for switching banks is as follows:   
		bankswitch: 	PUSH AF
                     		IN A, (banknumber)
                                               	POP AF
                                               	RET
  This bank switch routine could reside in RAM, or as in the Spectrum 128, reside in the printer buffer. But such routine can also find a place in ROM. In which case the machine code in the 'departure' ROM and that in the 'arrival' ROM should match seamlessly. A simple method for that is having identical routines in both ROMs at the 'exchange address'. Let us consider the code given above.  
What happens exactly is this: the actual two bytes for the IN A,(number) instruction are 219 and "number". Knowledge of Machine Code (MC) is not necessary to see that when "number" is the port address for an I.O. operation, this number must be known, and therefore must be read, before that operation can take place. Which means that the complete instruction is processed at the departure side! Although the actual switch takes place during the last phase of this instruction, thus before the next instruction is handled. The same picture is valid for a more often found hardware situation, o.a.128K, where the instruction:   OUT (C), A    is used.  (here C= port address (in fact BC register) and  A= bank number) 
  This property of machine language I/O instructions creates the possibility to use identical pageing routines 'parallel' in different ROM banks, and then to switch between pages 'in real time'. In this case  'parallel' means that identical routines reside in different ROM banks on the same address. This address can be anywhere in ROM. 
  An logical extension to this idea is having two banks with identical routines that carry each others bank number. This creates a vice versa situation. In this way a Spectrum ROM could enter and leave an Extension ROM bank on the fly. 

  Let us assume that in ROM 9 the bankswitch routine holds 13 as bank number, and in ROM 13 the bankswitch routine (on the same address) holds 9 as number. 
Now anywhere in ROM 9 this code could exist: 	LD HL, 12345
                                                                        	PUSH HL
                                                                        	CALL bankswitch
This would make the program to continue running in ROM 13 at address 12345. And a similar code in ROM 13 could bring the program back to ROM 9, and so on. In fact this mechanism should be extended to suit more sophisticated functions, but this simple example might explain the basic idea for this moment.

Finally...
  The reason for this in-depth explanation of a long existing system lies in the present. I myself use, together with a 48K Spectrum, an Opus Discovery with 720K Floppy and  64MB hard disk. But the massive hard disk was long time ago replaced by a small Compact Flash card, and slowly but relentlessly good old floppy is becoming obsolete. Having the possibility to connect a larger ROM to the Spectrum, and the possibility for 'passive paging' of memory banks, it became clear that all the heavy Opus hardware in fact had become completely redundant. If only the 'disk operating system' could be ported to a passive-paged ROMbank, then all might fit inside an rubber 48K which then would become portable again....
For studying this problem, once more the Opus system was analized. And more than  expected was found this time....  

  Now of course the parts in Opus ROM that handle floppy disk, printer and joystick are useless without the specific Opus hardware. But thanks to the modular structure of the Opus system which is based on tables (a full disassembly available at WorldOfSpectrum) it is possible to isolate and replace all kind of routines. A lot of that was already done long ago.
  Here a comparison must be made with the more common (and even better documented) Interface1 ROM. This ROM has less to offer when the accompagnying hardware is not present. And a specific problem regarding IF1 is that the 'addressing' of the RS232 port and the NET is residing in the ULA chip. This makes it rather difficult, but probably not impossible, to address this hardware without having the "active paging" (and thus IF1 ROM) alert and thus interfering. (There's a challenge out there...) Examination of the famous Colliers expanded ROMs for both Spectrum and IF1 showed that no room was left there for experiments as the following. 
  This is the reason why not IF1 but the white raven Opus Discovery is taken further as example. But tests proved that the story is valid for IF1 too, which for some readers might be a more conveniant entry to the scheme explained here. 

  The conditions under which Opus actively pages in are documented: memory access in Spectrum ROM on addresses 0, 8, 72, 5896. Note that addresses 8 and 5896 are used by the Sinclair Interface 1 for the same purpose. Now, due to the design of Opus hardware, the actual moment of switching takes place as soon the Z80 processor has finished the 'opcode fetch' part of the instruction, which in fact is the moment after the first byte is read (by Z80) from the address concerned. 
  This means that the ' instruction' at the page-in address is read from the Spectrum ROM, but that any further processing (when needed) takes place in the Opus ROM! So for instance at address 8, where LD HL,(23645) is found in Spectrum ROM and JP 360 in Opus ROM, actually a LD HL,(360) is executed when this address is reached. And when Opus pages out at address 5960, the (single byte) RET instruction that is found there is read at Opus side, and executed at Spectrum side. (Equal to IF1's RET at 1792.) 
  This behaviour differs completely from the 'on-the-fly' bank switch system described above. Still it is this behaviour which makes it possible to mimic the "active paging" by using "passive" paging. This in turn makes it possible to migrate the Opus system (and IF1's) to new ROM bank-switching hardware without real trouble.
 
Its all software now
  The measures taken for a 'passive paging' Opus system are described here:
Of course both Spectrum and Opus ROM code must be available as file, for changing.
	In Spectrum ROM code, at address 15586 a small bank switch routine was poked. This address was chosen for no particular reason. Then at address 11 (not 8!) the LD (23647), HL was replaced by CALL 15586. Also at address 5897 (not 5896!) the three bytes of CALL 15586 were poked. These pokes destroy the original code but that is no problem. As explained above, the instruction at address 8 is not executed properly when 'active paging' is used, and is therefore repaired/ignored in Opus. And the code at 5897 resides in the "CLOSE-2" routine which must be replaced anyway as soon as new channels are introduced. 
	In Opus ROM code (now occupying a full 16K bank instead of the original 8K!), at address 15586, a small bank switch routine was poked, slightly differing from that in the Spectrum. Also in this ROM the few jumps to the normal exit address (5960) were changed into jumps to 15586. (addrs. 0, 119, 203 ,447, 1580 for OPUSv2.24) This was done only because there was no room to poke this jump at 5960.
(For IF1 a similar set of changes must be made, see addresses below under Notes.)
  In Opus ROM the paging address 0 seems to serve no specific purpose, and address 72 activates an extension for the keyboard interrupt in the Spectrum ROM. While neither was needed for this moment, these entrances in Opus-ROM were left out the new scheme.

The bankswitch routines: 		 SPECTRUM	OPUS
	  L15586:	DI		DI
			PUSH AF		PUSH AF
			IN   A,(13)  ;opusbank		IN     A,(9)  ;spectrumbank
			POP  AF		POP  AF 		
			EI		EI
                                                		RET		EX     (SP), HL
					DEC  HL
					DEC  HL
					DEC  HL
					EX     (SP), HL
					RET
  When on-the-fly going from Spectrum to Opus the code in red is executed, returning from Opus to Spectrum the code in blue is executed. 
  This concludes the complete list of changes needed to get the mechanism going! 

Owing an explanation
  When the bank switch routine is called in Spectrum ROM at address 11, then the return address, found on the stack, is 14. Because the CALL is a three bytes long instruction. Now, when the Opus ROM takes over, this address is fetched, 3 times decremented, and put back. Then the RET at the end of the routine takes this address (now 11 ! ) to jump to in the Opus ROM. Because the Opus system expects that execution of the three byte instruction at address 8,9,10 is corrupted (as explained above), this address 11 is exactly the right place to continue!
  When the bank switch routine is called in Spectrum ROM at address 5897, then the program continues at address 5897 in Opus. This is correct, because also 'normally' (the old situation), the (one byte instruction!) INC HL at 5896 in Spectrum is executed, and the next instruction is taken from 5897 in Opus. 
  The normal return from Opus to Spectrum consists of a simple RET at address 5960. The RET at the end of the bank switch routine (in Spectrum) now does exactly the same.

Some testing
  It was thrilling in an oldfashioned way to see how all the intricate features of the Opus system obeyed the new regime without any problem. Even PRINT USR 8 returned the version number as usual! 
  When testing the method with Interface1 ROM, doing a FORMAT "n";12: PRINT PEEK 23749 worked as expected. By making a few hook code calls (RST 8, DEFB #1C) to do some printing on screen, it was proved that the mechanisme worked here too. A number of typical Microdrive error messages could be generated by entering BASIC commands, which error messages were taken as proof that all was O.K.and working. The latter may sound funny. But in what other way can the message "Microdrive not present" (following CAT 1) be understood when even the complete Interface 1 is missing?

Conclusion
  From this experiment arises a more general idea that goes beyond migrating a disk system: 
The example regarding the Opus Discovery ROM is ment to demonstrate that 'passive' on-the-fly bank switching can be as functional as the "active paging" that is used by Interface1 and similars. 
It also provides a method by which hardware add-ons that were incompatible as long as 'active paging' was used, can now be used together, by preparing one (or more!) for 'passive paging'. Even a 'cascading' system can be thought of, or a 'tandem', which goes beyond the scope of this story...    
  This experiment, more specificly, demonstrates the fact that the "RST 8 route", as known from IF1, is also open for ROM/RAM interfaces that only feature a simple 'passive' paging mechanism. In this way for instance can the classic method for extending BASIC be used without the need for owning an IF1! 
  An added bonus might be that a major part of the electronic properties of the IF1 ULA chip now can be understood by studying the Opus diagram as example. 

Groningen, november 2008.

Notes:
All numbers given are in decimal, but some numbers might be more decimal than others. :-)
Exit addresses were found in IF1-v2 at: (decimal) 5, 97, 175, 545, 3477, 7822.