Last week, I wrote about a “multi-core” project that I was working on 30 years ago. To be fair, it was actually “multi-CPU” rather than “multi-core”, but many of the challenges were similar, as was the initial design decision to take the approach of distributing the processing capacity. It is interesting to draw a comparison between the system we were developing all those years ago and modern ideas for multi-core design. A common approach, which I mentioned here, for example, is to use one core for real time functionality [running an RTOS like Nucleus perhaps] and another for non-real-time activity [maybe running Android or Linux].
Using multiple CPUs [or cores] presents a variety of challenges. One is the division of labor, which was reasonably straightforward in this case. Another is communication between the processors …
In designing the UPO, we considered a number of means by which the two CPUs might be connected. As they were separate boxes, serial and parallel connections were considered. Nowadays, I am sure that USB would have been an option too. But we were very concerned about any possible compromise of the real-time performance of the console microprocessor. Also, we did not want the user to be faced with the UPO freezing while it waited for attention from the console. So, clearly a buffering mechanism was needed and shared memory seemed to be a good option.
A small memory board was designed. I have no idea of the hardware architecture, except that I seem to recall that the TI-9900 had priority over the SB-11, as it could not afford to be delayed by slow memory access. If I remember correctly, the board was 2K [words, probably].
It was down to us to define a protocol for communication, so we aimed to produce something that was simple and reliable. We divided the memory into two halves; one was a buffer for communication from the UPO to the console and the other for the opposite direction. The first word of each buffer was for a command/status code, which was simply a non-zero value. We did not use interrupts. The receiving CPU just polled the first word when appropriate, awaiting a non-zero value. When a command was found, any data could be copied and the command word cleared to zero indicating that the processing was complete. So, the UPO sending a command to the console might go through a sequence like this:
- Write data to the buffer [second word onwards].
- Write a command to the first word.
- Poll the word, waiting for it to become zero.
If it was expecting a response, it would then start monitoring the other buffer.
Of course, there were other facilities to handle a situation where one CPU did not respond after a timeout period.
Nowadays, multi-core and multi-chip systems have a variety of interconnection technologies, but shared memory is still very common. A number of standardized protocols have been developed over the years, including derivatives of TCP/IP. In recent years, the Multicore Association produced MCAPI, which is rapidly gaining broad acceptance in multi-core embedded system designs. This will be the subject of another future blog posting.