"Color Expander for ZX-Spectrum" - this is the title of the article published in the echo fido7.zx.spectrum on August 3, 1997. The article described the idea of ​​solving one of the main problems of the ZX-Spectrum platform - attribute clash . The publication aroused some interest at that time, and I would like to tell about technical details and the history of the issue.
I will not go deep into the technical details and just structurally describe the idea and solution.
The development story began in the early spring of 1994, when the country was still experiencing "changes in the draft", which led to the massive closure of deferrals and the appeal of students of vocational schools and technical schools. I was lucky - I was in my last year at the Leningrad Radiotechnical College and in such a way the state agreed to give a short-term delay for the accelerated receipt of a diploma with the replacement of diploma design with an exam in all subjects. He left the army on March 1, 1994, as a certified radio technician.
In the armed forces at that time there was an unprecedented influx of the same specialists of the middle technical level, though this slightly ruined the autumn-spring conscription system in the heads of the “grandfathers” who already had a clear gradation in the names, they dubbed this non-standard call “goblin”. Among the “booming” there were enough people who were fond of ZX-Spectrum, and Alexander Gumin was in my unit (he wrote games on the ZX-Spectrum under the ANCCAN label with Denis Markelov and became known for his adaptation of Mortal Kombat for this platform in 1997), who to talk about programming and hardware.
Closer to the middle of April 1994, at the end of the “young fighter’s course,” Alexander and I were transferred to the construction battalion located in Strelna, a suburb of St. Petersburg. There, we had to master the difficult specialty of cable-splicer for several months. Life in this part flowed slowly and study alternated with outfits, which mostly strained hands, but gave the brain time for reflection. So, in one of the outfits in the kitchen, my floor and thinking about the ZX-Spectrum and its capabilities, I came up with the idea - how to overcome the "conflict of attributes."
I pondered this idea until the end of the service and became more and more convinced that "it could work." Unfortunately, the idea of ​​the viability of the platform itself, to which I was going to apply this idea, visited me less often. However, in Russia, the ZX-Spectrum flashed most vividly in the sky from about 1991 to 1996. Some Russian producers of its clones have risen so much that they have sponsored programs on TV (for example, the Bi-Em company has sponsored the program “The Jungle's Name” for some time). But during the service there were other problems, so I decided to postpone all issues related to commerce until I was sent to the reserve. Periodically and without revealing details, I was interested in various experts on the topic of technical feasibility and validity of the approach. He kept the idea in deep secret and did not even share it with Alexander Gumin, only vaguely indicating to him that he had found a very simple solution to increase the number of colors while maintaining backward compatibility.
Having entered the “citizen” in 1997 and got a job as a software engineer of the second category at the St. Petersburg company “Information Technologies and Models”, I began to gradually become interested in the question of commercializing the solution. For some reason, I was sure that if you just give a hint about the solution found, everyone will start tearing with their hands and money will pour in. I started phoning the well-known, at that time in the field of "Spectrum-building", manufacturers and merchants, such as Sergey Zonov, Vyacheslav Skutin (Nemo) and others. Sergey Zonov simply told me that “the train has already left” and there is no longer any commercial sense in this undertaking. Vyacheslav Skutin, being an orthodox spektrumist, took hostility with any idea in which they tried to change something on the platform and this was also a completely dead version. I decided that there was little talk and at least something needed to be done and it was best to start with an emulator in order to get promotional materials and experimental data.
In 1998, taking as a basis one of the existing at that time open-source ZX-Spectrum emulators written in Pascal, I made a primitive emulator of four computers working in parallel. Under it, I partially adapted the game After The War 2, coloring some of its sprites. The system worked, and in addition to the pleasure of a working idea, I got at my disposal screenshots confirming the idea of ​​coloring existing games.
In 1998, I visited the Peters company, which was developing its new Sprinter platform at that time. He made an attempt to interest their director Nikolai Noskov. They invested heavily in the new development and, according to the law of meanness, the Sprinter's super-flexible architecture, capable of emulating almost any single-processor platform on the Z80, could not extend four processors. However, a visit to this company was very useful, as he met with the author of the platform Sprinter Ivan Makarchenko and learned about new opportunities in the field of development on FPGAs.
Soon the 1998th crisis “withered” and there was a naive hope that interest in the ZX-Spectrum could revive. In the beginning of 1999, we (with my partner at that time, Andrei Savichev) even had plans to create the “National Spectrum Fund” and one meeting was held on this subject in the new office of the same Peters company. But they do not enter the same river twice and of course nothing came of it. Already in 1999, all ideas on the topic of hardware implementation of the platform were discarded (we worked on this development with Sergey Egorov, but we didn’t go further than the schemes). Until 2007, I practically did not deal with the platform, but there was time and decided to rewrite the emulator and work out the details of the platform, checking the approaches and let them "virtually".
Standard video mode ZX-Spectrum, displays 256 by 192 pixels. In monochrome mode, this requires only 6144 bytes, which is approximately 10% of the total memory field (against 50% on BK-0010). Color information is stored in an additional 768 bytes located immediately after the pixel data. The palette consists of eight colors and two shades. The color of the illuminated and discarded pixels is determined immediately for the 8 by 8 pixel block, and the hue is determined immediately for the color of the illuminated and discarded pixels.
It looks colorful and a relatively small amount of data is sent very quickly, but it requires incredible efforts and art from artists and programmers when developing color games and screensavers. The slightest inconsistency in the graph leads to a conflict of attributes. Most developers did their job perfectly and against the backdrop of BK-0010, with its only four colors (but for every point!), Spectrum quasi-color looked very advantageous and fresh.
With the development of the platform to ZX-Spectrum 128, the ability to switch hardware between two pages of video memory was added. Programmers quickly found a way to get multi-color using a very quick change of displayed video pages and dynamic change of color attributes.
Due to this, it was even possible to programmatically raise the screen resolution (which is perfectly shown, for example, in the "Dead Morose" demo, where text with a resolution of 256, 512 and 768 horizontal points simultaneously runs).
But any software solutions requiring an increase in the flow of video information led to an increase in processor consumption, which is very critical in the case of dynamic games. There was no unused source of computing power reserves in the system. Everything hangs on the processor in the ZX-Spectrum and gives it a little unloading, except that the music processor is in the field of sound effects.
My idea was that you could add three more processors, throwing on each of them the processing of its color component. The received data from each processor’s own video memory should be integrated, forming a YRGB value for each pixel . Standard color attributes are ignored. Parallel processing of information should ensure that there is no sagging performance.
I can’t say that it was original in the idea, because it was inspired by the reading of the translated book “The Computer Gains Mind” (Mir Publishing House, 1990), which described a certain Pixar graphics platform developed in Lucasfilm. And according to TRIZ it’s just a transition from a mono-system to a poly-system.
A very painful question for any development - and who will write the program? (in particular, the Sprinter platform came across this "pitfall"). In my case, the issue with the software was automatically resolved through the fact that very rarely existing programs checked what kind of data they recorded in video memory and simply worked with them “like a postman with a sealed letter”. According to my calculations, it turned out that most of the existing gaming programs could quite easily survive the adaptation of their video data without changes in the executable code. Of course, games with a package of graphics or internal optimizations in its output to the screen were cut off. Adapting such programs would require research and alteration of the executable code. The development of specialized ROMs was not required at all.
I think that this concept is applicable to any old household platform (for example, AGAT, Radio86RK, BK-0010, etc.), where there is no dedicated video accelerator and the processor works directly with video memory to form a picture.
In the first version of the emulator, I just made four ZX-Spectrum 48s working synchronously. But what’s easy to simulate on the emulator is very difficult to repeat on real hardware. It is quite difficult to ensure the loading of data into four computing modules and to make a synchronous start from the same address. A similar solution Spec256 introduces for this a specialized virtual 64-bit SIMD Z80, which does not exist in nature. As part of a more realistic (and more complex) solution to this problem, the ZX-Poly platform was formed.
From “Color Extender” to ZX-Poly
Processor modules
ZX-Poly is a computing platform based on the ZX-Spectrum 128 containing four processor modules. Each module has its own externally visible addressable system IO ports. Although the processor modules share the system control signals (RESET, NMI, CLK and INT), they work independently.
There is a certain ranking depending on the index of the module - the smaller the index, the higher the rank, respectively, "module 0" is master in the system. Write access to the system ports of the module is allowed only to the module with the same or higher rank, there are no reading restrictions. This was done because there were thoughts about developing a specialized OS.
A very important detail is that all processor devices used must be of the same manufacturer (and it would be nice to have one production series), since the slightest difference in their internal organization or optimization may violate the consistency of the system.
Immediately after the start of the system, only the master module (CPU0) is launched, the remaining modules are in WAIT mode, so for the user everything goes unnoticed.
In the IO space, ZX-Poly adds the following ports available for writing and reading:
- main configuration port $ 3D00
- module 0 - $ 00FF, $ 10FF, $ 20FF, $ 30FF
- module 1 - $ 01FF, $ 11FF, $ 21FF, $ 31FF
- module 2 - $ 02FF, $ 12FF, $ 22FF, $ 32FF
- module 3 - $ 03FF, $ 13FF, $ 23FF, $ 33FF
The main ZX-Poly configuration port is $ 3D00. Only the master module can write to it, but it is available for reading to all modules and each of its own specialized information is returned. In particular, a module can find out its index, whether its memory is mapped to IO ports of the main module, its memory offset in the heap, etc. Also, the configuration port of the base platform $ 7FFD has undergone minor changes, which uses unused bits in the original.
Memory
As in the original architecture of the ZX-Spectrum 128, there are ROM and RAM. If the organization and work with ROM practically did not change, then RAM turned into a common “heap” of 512 KB in which each processor works with a dedicated 128 KB window (this is 8 pages of 16 KB in ZX-Spectrum 128). The window offset can be changed in increments of 64 Kb and all processor modules can be projected to work with a fully or partially overlapping piece of memory in the heap. The ROM can be disabled and the RAM0 RAM page will be connected in its place (this allows you to make a "full-color" version of the base OS, for example, a basic interpreter). After a hardware RESET, all modules receive automatic offsets to disjoint memory windows in the heap.
The processor module master (CPU0), has the ability to map the address spaces of other modules (CPU1-3) into the area of ​​its IO ports. Those. he can write to the port, changing the state of the memory cell of a given module, and at the same time, it is possible to generate an NMI signal on a mapped module. When reading from the memory cells of the mapped module, INT generation is possible. This was done to emulate virtual devices using modules 1-3.
Video controller
The main “cherry” is of course a video controller, for the sake of it everything was started. In total, the platform supports five video modes.
ZX-Spectrum 128 Video Modes (mode 0,1,2,3)
These video modes are unremarkable and do not differ at all from the standard ZX-Spectrum 128 video mode. The current video page of the selected processor module with attribute coloring is displayed. Immediately after the start of the system, mode 0 is activated, i.e. The video page of the master module (CPU0) is displayed.
ZX-Poly 256x192 (mode 4)
This video mode does not use any data from the attribute area at all. The pixel bit of each module is combined with pixel data from other modules and the generated four bits are used to generate a color-brightness YRGB signal.
Each module is responsible for its component:
- module 0 (master) for Green (green).
- module 1 for Red (red)
- Module 2 for Blue (Blue)
- module 3 for brightness
If you start an unadapted game in this mode, it will be just black and white.
ZX-Poly 256x192 with masking by INK + PAPER (mode 6)
Like the previous one, it provides 16 colors for each point, but there is one “trick”. In some ZX-Spectrum programs, graphic elements are hidden using the identical INK and PAPER values ​​in the attributes, especially in scroller games. If you remove this possibility, then the graphic elements begin to accumulate on the screen, breaking the picture. Therefore, the state of INK and PAPER is analyzed from the attribute of the master module read from the video memory (CPU0) and if they are identical, then all points are highlighted with the color taken from INK / PAPER (of course, taking into account the brightness).
ZX-Poly 256x192 with masking by FLASH + INK + PAPER (mode 7)
Mode is a combination of mode 4 and mode 6. For the readable attributes of the master module (CPU0), the FLASH bit is analyzed and if it is set (which is rare in dynamic games on the playing field), then an 8 by 8 pixel block is output in mode 6 mode ( with masking with identical INK and PAPER). If FLASH is reset, then the block is displayed as on a regular ZX-Spectrum. The FLASH bit is not practiced in its direct role and there will be no blinking on.
This mode is very convenient to avoid repainting game information panels and some in-game effects (for example, when game developers flash on the playing field through attributes).
ZX-Poly 512x384 with attributes (mode 5)
Attributes are used in almost the same way as in the original platform, without any changes (even the FLASH bit). The video pixel data of each module is colored with an attribute from the video memory of this module and, after passing through the coloring, are displayed in a checkerboard pattern, which is why one familiarity block is 16 by 16 points.
This mode allows you to double the resolution of applications, without changing the executable code. True, experiments with the same Pinocchio game showed that in bright games with large details, the effect will be poorly noticeable. Since these are some kind of virtual pixels, the games do not know anything about it and the minimum possible movement of game elements is at the level of two virtual pixels. I think that this mode is good for games with small game objects in a familiar place.
A much better effect in this video mode was obtained on text applications, for example, on the ZX-Word text editor, where only the font was processed without changes in the executable code.
Multitasking
Despite the fact that the processors in the system use the same source of control signals, they work independently. The system cannot be called a full-fledged SIMD , since each processor processes instructions from its own memory block, it simply uses the ability to "palm off" the same instructions. If one of the processors encounters a different team in memory, then “its paths will diverge” with the others, and in the case of an adapted game, the picture will be stratified.
Potentially, you can calculate execution paths taktovno and achieve both discrepancies and convergence of threads of execution, but it is very difficult and probably interesting only to "demosceners". For simplicity, primitive synchronization mechanisms have been added.
Synchronization mechanisms
Local RESET
This mechanism allows you to simultaneously send a RESET signal to all processor modules, but the first three bytes will be read by each module from its internal ports. This allows you to execute the JP ADDR command by transferring all the modules synchronously to the same memory location.
Stop address
This is a mechanism for all modules except the master module (CPU0). You can write a specific address to the module’s ports, when executing a command on it (determined by the M1 signal), the local WAIT signal will be installed on the module’s processor, which will be active until this address is changed in the ports or a system-wide or local RESET is passed. It is possible to read the last address executed by the module, but rather conditionally, since the 16-bit address is packed in bytes.
System emulator
In 2007, a new version of the emulator was written in JavaSE. Within its framework, the subsystems of the Z80 processor (with tick-wise emulation and unit-test coverage of commands) and the FDD of the K1818VG93 controller were written. The application requires JDK 1.8+ .
The emulator was designed to verify the compatibility of the platform with existing ZX-Spectrum software and device ports, and in general, it showed that 80% of running programs work without conflict with innovations. It can also be used as an emulator of the usual ZX-Spectrum 128, for this you need to enable the Options-> ZX 128 Mode , while the ZX-Poly subsystem in the emulator is blocked to increase compatibility.
Only the test ROM is supplied with the emulator, since the official ZX-Spectrum ROM is the subject of copyright. But it can be downloaded via the Internet by selecting File-> Options from the menu
If the games do not use any packages of sprites, then coloring is quite simple. Care must be taken when there are optimizations in the executable code for outputting sprites, as this can lead to desynchronization of processor modules.
A bootloader was developed to load data into modules from a disk and simultaneously start simultaneously. Its code for TAP and TR-DOS is presented in the project.
Together with the emulator, a small (also written in Java) utility for coloring applications was developed.
The entire project is published on GitHub under the GNU GPLv3 license .