15

After reading mcleod_ideafix's answer about the Inves Spectrum+'s "randomize of death", specifically his article on the subject, one thing struck me as odd. From César Hernández Bañó's research:

...It happened that, if you poke'd certain ROM addresses (yes, ROM addresses), the border didn't respond to new BORDER commands, so the speaker to BEEP commands. After some research, we discovered that pokeing ROM addresses whose least significant byte was 254, blocked any data from entering the ULA.

From the main article:

This feature can be used to alter the way other ports work. If I do a:

FOR n=0 TO 63: POKE n*256+p,v: NEXT n

Then, port "p" will be affected by mask "v". That is, any value written to port "p" will be AND'ed with "v". I've tried this with even ports other than 254 and it works. It seems that port reading operations are not affected, so I cannot test if this works for odd ports too, as the only even port the Inves has is the Kempston joystick (port 223), which is a read-only port.

Why does this occur, and why would this feature have been built into the Inves Spectrum+?

  • 2
    My answer to your previous question about RAND USR 4665 contains a link to an article which explains in detail why is that. Note that this affects only the Inves Spectrum+ clone, which is not a ZX Spectrum computer. The original Sinclair ZX Spectrum doesn't suffer for this issue. If you prefer, I can extract that part of the article, translate it into english and post here as an answer. The article is here: zxprojects.com/inves – mcleod_ideafix Feb 7 '17 at 21:26
  • @mcleod_ideafix That would be great! Thanks. – wizzwizz4 Feb 7 '17 at 22:07
22

The following is an excerpt from the article César Hernández Bañó and I wrote about the internals of the Inves Spectrum+, exposed after a detailed work of reverse enginnering.

First, some background: César is the author of the first (and AFAIK, only) emulator that handles the oddities of the Inves Spectrum+. With time, his emulator has evolved and now it supports other clones, such as ZX-UNO and TBBlue. As the question states, César did his own research and discover that strange feature.

The second part of the question comes from another article I wrote BEFORE the reverse engineering work. On that part, I speculate with the possibility that this oddity might work with other ports, not only port $FE. Our reverse engineering work proved that this is not true, and the oddity only affects to write ports handled by the Inves itself.

OTOH, the equivalent of the ULA in the Inves is a gate array manufactured by Texas Instruments (in fact, most chips inside the Inves come from TI). This gate array is the TAHC10, and it has the equivalent of one thousand 2-input NAND gates. In the following parragraphs, any reference to "ULA" must be translated to "TAHC10" unless otherwise stated.

So the question should be reformulated as "Why did POKEing ROM addresses mask port writes to the TAHC10 on the Inves Spectrum+?"

Before starting the electronic analysis, I was under the suspect that RAM could be colliding with the CPU when an I/O write bus cycle was in curse. That sounded crazy because I/O writes and memory reads are completely different bus cycles and no decent system designed around the Z80 processor should confuse both (because the Z80 uses a different address space for both memory and I/O, so different signals are activated for each bus cycle).

So I was very surprised to find out that the TAHC10 doesn't use the WR (write) signal from the CPU at all (in fact, the WR signal goes from the Z80 only to the rear expansion bus). For TAHC10, any bus cycle that is not a read cycle (signal RD asserted) is a write cycle. Then, the crazyness began to be plausible.

This will be clear if you look at the partially drawn Inves schematic, which includes nearly all the logic circuits:

Inves Spectrum partial schematic

The section of interest is the one that comprises the TAHC10, RAM and several logic circuits. This section shows two data buses, labelled D and VD. D is the data bus directly connected to the Z80. VD is the data bus directly connected to the TAHC10. VD is normally used for the TAHC to read pixel data from VRAM, but as the Inves Spectrum doesn't differentiate between contended memory and non contended memory, there is only one physical RAM memory bank, and that is the bank implemented with two DRAM memories of 64Kx4 bit each. This means that the Inves Spectrum+ shipped with an actual amount of 64KBytes of RAM and 16KBytes of ROM.

This also means that every memory bus cycle between CPU and RAM must transfer data from VD to D (memory read) or from D to VD (memory writes). Analogously, port writes to TAHC must transfer the data to write from D to VD, as the TAHC has not a separate data bus to talk with the Z80.

And it's this arrangement of data buses and its interaction, which produces the issue.

Although VD and D are isolated each from another, there are two ICs that allow them to be connected, driven by the TAHC10: they are IC14 and IC15.

IC15 is a latch, capable of storing 1 byte of information. Its input comes from the VD bus and its output goes to the D bus. This latch is used to store a byte read from memory, so it is available to the CPU even if the memory is no longer available. It's loaded when its ENC input is 1, and that happens when output /MUXOE from TAHC10 is 0.

OTOH, IC14 is a tristate buffer. When enabled, it allows the flow of data from D to VD. This happens when /MUXOE is 0 y /RD is 1. It's the output of IC19A, and it's labelled /BUFFEROE .

So, everytime the Z80 wants to use RAM, /MUXOE is 0. This opens the muxes IC20 and IC21, to drive address inputs on DRAM chips, and establish a connection from VD to D, or viceversa.

TAHC10 and DRAM section

The article has several sections. One of them is about how Inves implemented the different read and write ports a Spectrum has. The issue affects to port $FE (only A0 is decoded, as in the original ZX Spectrum).

Port $FE, write. This port is integrated within the TAHC10, for obvious reasons: border colour and speaker are managed from here. As the TAHC only has one data bus (VD) and this is isolated from the Z80 data bus (D), it's logical to assume that the same latches and buffers that participate in RAM access bus cycles, will also participate here.

As I was warned from César and his research, the test program that was written to study write bus cycles to port $FE was desgined the following way:

First, the program writes specific values into RAM. More concretely, address $40FE is written with value $00. Address $41FE with value $F0 and address $42FE with value $FF. According to César tests, the value that will be written into port $xxFE will be the binary AND between the value coming from the Z80 and the value that would be previously written into memory address $xxFE (that is, the same address used for the I/O port, but referred to memory).

After this, the program continously writes the same value ( $AA ) to I/O ports $40FE, $41FE and $42FE. The data we see on the VD bus is the same that the TAHC10 will see and accept. Our goal is to check whether memory is being accessed at the same time as the I/O bus cycle is in curse.

This is the chronogram for the I/O write bus cycle to port $40FE. Let's recall that memory address $40FE contains $00.

I/O bus cycle, port $40FE

Signal IORQULA is asserted (active negative) when /IORQ is asserted and A0 is 0 (this is the same IORQULA signal present in the Sinclair ZX Spectrum). TAHC10 sees that /RD has not been asserted, so it infers that this is an I/O write bus cycle, so it gets ready to accept data coming from the VD data bus as the new value for border, speaker, etc by asserting /BUFFEROE. As /BUFFEROE is asserted, value $AA from the Z80 can be seen on VD. While this happens, MUXSEL and /MUXOE are also asserted, so a memory read cycle is performed from the same address that it is being used for the I/O bus cycle, which results in data stored in memory at that address to show on VD too. At that precise time, that is, several nanoseconds after /CAS is asserted, VD data bus has a mix of the data from the CPU (provided by IC15) and data from memory.

IC15 is a 74LS244 transceiver, with a pullup of 50 ohms and bipolar transistors. OTOH, RAM IC TMS4464 is a SMOS device (N-channel scalable MOS), which means that its output stage is implemented with NMOS transistors with a not very strong pullup (another NMOS in enhanced mode acting like a resistor), but with a very strong pulldown, nearly a perfect short circuit to ground. At the end, this means that a 0 bit coming from a memory data bus pin will "win" against whichever value comes from IC15, and that a 1 bit coming from memory will easily be defeated by the value of the signal from IC15. So, this is actually a wired-AND operation between data from memory and data from IC15 (CPU).

This means that while the RAM is outputting data $00, the wire-AND logic makes the result value seen by TAHC10 to be $00 as well. As for the value read by TAHC10, my thoughts are that it uses a transparent latch that is opened (transparent mode) during the time /MUXOE is asserted. The first half of that time, about a half of a period of the CPU clock, the internal TAHC10 latch sees the original $AA value, so during that first half, border colour and speaker behave accordingly. By the start of the second half, the RAM has outputted its data, wire-ANDing it with Z80 data, and as /MUXOE is deasserted, this last ANDed value is the definitive value that the TAHC10 internal latch keeps. From the user point of view, what it's happening is that during a pixel time (a semiperiod of the CPU clock) the border exhibits its true colour (the one we wanted to write) to inmediately follow to the colour resulting of the ANDed operation.

An I/O write bus cycle to port $41FE shows this behaviour:

I/O write bus cycle to port $41FE

Value read from memory is $F0, which wire-ANDed with the value the Z80 wants to write, $AA, results in the value being $A0, which is the final value the TAHC10 sees.

And last, when an I/O write bus cycle is performed to port $42FE, the data coming from memory is $FF, which means that data coming from IC15 (from CPU) is not altered so the TAHC10 sees it unmasked.

I/O write bus cycle to port $42FE

And this is why POKEs to memory addresses result in this strage issue for port $FE. In fact, it doesn't mind if the address is from ROM or RAM, as regardless the address used, it's the RAM chip which is activated.

The reason behind "why ROM addresses" (César didn't realize at the time that this worked with RAM addresses as well) is because within the Inves ROM (mostly a copy of the Sinclair ROM) any write operation to port $FE is performed by using the instruction OUT ($FE),A. This instruction puts value $FE to the lower part of the address bus, but it also puts the current value of A on the upper part of the address bus. As the ROM writes a value to port $FE so that it always has its three most significant bits with 0 (relevant bits are bits 0 to 4), such value won't be greater than $1F, so POKEing a $00 value on every memory address whose lower part is $FE and its upper part ranges from $00 to $1F, we get the "sticky black colour" effect, and no sound at all. If we issue a OUT 32*256+254,7 instruction, border will be white again (memory address $20FE was not affected by our previous massive POKE operation). If we then issue a POKE 32*256+254,0 , the previous working OUT instruction won't work any longer. In fact, and as most memory addresses whose upper part is greater than $3F are loaded with $00, it will very difficult to find an address that works. This is because any address with an upper part greater than $3F is actually a RAM address, not a ROM address.

(to be continued)


Un comando NEW, RANDOMIZE USR 0, o el botón de reset, hacen que se vuelva a ejecutar la rutina de inicialización de la memoria, que es idéntica a la del ZX Spectrum. Esta rutina no toca los valores en ROM porque se supone que en la ROM no se puede escribir, por tanto no tiene sentido chequearla. Así, cualquier valor que se pokeara en ROM, allí seguirá, impidiendo que el color del borde cambie o el sonido funcione.

La pregunta es lógica: si para cualquier acceso de escritura al puerto $FE sucede esta combinación AND con el contenido de la memoria, ¿cómo es que un Inves recién encendido no muestra comportamientos extraños? Después de todo, el contenido de la memoria es aleatorio en el momento del encendido. ¿O no?

Cuando se enciende un Spectrum, sea de Sinclair, Amstrad o un Inves, si ya tenemos sintonizado el canal para que se vea la imagen desde el primer momento, y sobre todo si el equipo lleva apagado varios minutos, se puede ver durante una fracción de segundo una imagen característica, de franjas verticales, a veces negras y blancas, a veces de otros colores. Si el ordenador está estropeado y no puede iniciarse, el patrón queda fijo en pantalla y todos lo interpretamos como un Spectrum averiado. Un Spectrum “sano” sólo mostrará esta imagen por un momento, para seguidamente poner a negro toda la zona de paper, y a continuación, volver a borrarlo dejando el fondo blanco y en la parte inferior el conocido mensaje de copyright.

Spectrum with initial memory contents enter image description here

egún el fabricante y tipo de memoria que lleve, el patrón de franjas verticales es diferente. Pueden ser franjas muy anchas, de unos 8 caracteres de ancho como ocurre con algunos modelos +2A/3, o pueden ser franjas de unos 4 caracteres de ancho, como ocurre en la mayoría de Spectrum’s de 16K y 48K.

Esas franjas que se ven no son más que la interpretación en forma de imagen de los valores iniciales que contienen las celdillas de memoria. En una memoria DRAM, al contrario que las SRAM, quien guarda el valor de un bit es la capacitancia residual que se origina al fabricar un transistor MOS. La carga almacenada es muy pequeña y necesita ser amplificada y refrescada cada cierto tiempo.

Aquí no he encontrado información adicional, pero especulo con que bits que se guarden en posiciones adyacentes lo hagan con la polaridad invertida unos de otros, de forma que guardar un 1 lógico no siempre signifique cargar el condensador, y guardar un 0 no siempre signifique descargarlo. Como en muchas ocasiones hay grandes regiones de memoria con el mismo valor, estos cambios de polaridad podrían mejorar la inmunidad al ruido del propio chip.

Así, lo habitual es que tras un periodo prolongado con el equipo apagado, todos los condensadores que almacenan bits estén descargados, pero como el valor que se interpreta por los amplificadores es distinto según dónde esté ubicado el condensador, el resultado neto es que la memoria vuelca datos en forma de patrón regular de 1’s y 0’s.

El Inves monta casi todos los chips de Texas Instruments. Los chips de memoria también lo son, y su patrón de bits sin inicializar es del tipo 1111 0000 1111 0000 …. . Es decir: la dirección $0000 contiene un valor inicial que se interpreta como $F (los 4 bits a 1). La dirección $0001, el valor $0, y así sucesivamente. Al tener dos memorias del mismo fabricante, la secuencia que tenemos es $FF, $00, $FF, $00, etc. En la zona de memoria que guarda la información de la pantalla, esa secuencia hace que se vea el siguiente patrón al encender un Inves:

Inves initial memory contents

Y lo curioso de este patrón es que en las direcciones de memoria par guarda el valor $FF. Dado que el acceso al puerto $FE en escritura es un acceso a un puerto par, y dado que en practicamente todos los casos, la parte alta de la dirección de puerto será un valor comprendido entre $00 y $1F, la dirección de memoria que entra en conlicto con el puerto pertenece al espacio de ROM, a donde se espera que no se haga ninguna escritura. Es por esto que este fallo de diseño podría haber pasado inadvertido.

Claro está que si un programa realiza escrituras a ROM (por ejemplo como parte de una protección de carga para obtener un bloque de carga superior a lo que un copión de la época puede manejar) o bien por un efecto secundario de alguna rutina (por ejemplo para hacer un scroll vertical y no tener que chequear si la última fila se copia en ROM), hay posibilidad de que alguna de las direcciones de memoria “sensibles” ($xxFE) resulte alterada, creando el pequeño desastre en el bus VD que hemos visto.

Por otra parte, si se avería un Inves Spectrum y al repararlo se cambian los chips de memoria por otros que no cumplan con ese patrón de datos iniciales, es muy posible que desde el mismo momento del arranque, el color del borde no funcione como debiera, o el equipo se quede mudo.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.