An attempt to make an RC2014 module that emulates the TMS chip, with crisp DVI output and some additional RC2014 functionality
To make the experience fit your profile, pick a username and tell us what interests you.
I'm feeling just about ready to launch this version of the module:
This particular one has a couple of bodge wires. I've sorted those tracks and have new pcbs and some more Dr.VIPs due here in the next few days. Once those have arrived I feel confident about offering them for sale.
I took the module in its current state along to the Retro Computing Fair in Cambridge at the weekend. Spencer was happy to let me pop my machine on the end of the RC2014 table and run some of the demos. What a fantastic weekend it was and I was so happy to speak to one or two people who are following this project.
Over the last couple of posts I've been blowing hot and cold over the serial functionality. At one point I said that it was working like a charm and then had to backtrack because I realised that it wasn't. I've had a rough time trying to get it working properly.
I've made a breakthrough on that front tonight and really think that it's now working well enough for launch. Here's a very quick demo, showing how useful this feature is. Bear in mind that the regular TMS module for RC2014 (with real TMS chip) doesn't handle the serial, so with that module you're communicating with your OS via a terminal or terminal emulator until you've started a program that drives the TMS chip.
This module listens to the serial line and displays characters using the TMS 40-column text mode from startup. It's no full-featured terminal emulator, I have never planned to go down that route. It does just enough to allow you to use the OS from startup.
This is no less than the fourth revision of the PCB.
It still uses Dr.VIP which is a standalone project and could be useful for many other projects that need a Pico with as many GPIO as possible and an HDMI socket on the board, although that idea has now been overshadowed a little by the PicoVision project.
I have wondered whether I'd need dual RP2040s for this project but It turns out not.
This version of the card looks identical to the previous one, but the logic is simplified.
Finally the VRAM reading is working. This was a tough nut to crack. Earlier versions of the card didn't have this feature at all. In the last project log (with the last version of the module) I claimed that this feature was 'working like a charm'. Although it appeared to be initially, it wasn't working very well at all.
Why is this a big deal? The earlier cards are usable for most of the demos and games available at the moment, but certain operations, such as hi-res drawing are easier if you can read the existing VRAM data.
To cut a very long story short, It really is now working. The new board (predictably) needed a bodge wire, but I've corrected that in the design and because of Dr.VIP (and therefore no surface-mount components on the module itself) minor revisions of the board will only cost me a few quid.
The port select is still working (you can select $98/99 or 08/09 with a single jumper) but I've had to lose the serial communication, meaning that this version of the card won't have one of the features I set out to include, which is the terminal functionality at startup. It won't be truly standalone and like the "real TMS" module requires you to communicate with the computer via a terminal at least until you've started the program you want to run.
(I am aware that ROMWBW has some functionality to use a TMS card for terminal display but I haven't explored this yet.)
The other small sacrifice is that reading the status register gives you the vblank bit only. I had hoped to provide that whole byte which includes sprite collision and 'fifth sprite' information.
Both of these features are missing because of a shortage of GPIO pins, or in the case of the serial, the ones I have left can't be used with the hardware UART. I may be able to claw that feature back.
I'm not sure how important the sprite collision information is. This is pretty easy to work out in your own software if you know where your sprites are. The fifth sprite information probably isn't important at all because this project doesn't have a limit of four sprites per scanline.
As mentioned, plotting a point (and therefore drawing lines etc) is easier if you can read the existing video memory. Otherwise you have to keep your own copy of the pattern table (which may be faster than reading the VRAM, but will cost you about 6k of your ram.)
This is now working, and functions such as TmsPlotPixel in Mr Langston's excellent tms.asm library work perfectly. The drawing above is written in C and takes about 2.5 minutes to draw.
Here are some more screenshots (more accurately, poor photographs of my screen) of programs that use other modes:
In recent posts I've said that I wasn't happy with the mcu and surface-mount stuff being visible on the module's pcb alongside the through-hole stuff. I loved the way the feather looked when reversed but it doesn't have enough GPIO exposed.
So I designed my own RP2040 board to meet my needs for this project. I'd like to introduce Dr.VIP (an anagram of RP DVI). I've split that off into its own project because it'll have a life of its own and be useful for other projects.
In short it's an RP2040 board with:
I'll definitely be offering this separately.
The second important update relates to the module itself, which is now updated with more logic so that:
Separating the RP2040 from the module also has the advantage that if I want to prototype any small updates to the main module, it's now just a simple through-hole board with no assembly of small parts. If there is a hardware update, users will be able to update just the through-hole pcb or just the Dr.VIP, not necessarily everything.
I've tried to make the jumpers as user-friendly as possible:
What does the part about the ports mean? Well, this:
I know what you're thinking: "a starfield, whoop-de-do..."
However, this does represent an important step forward. The previous version of the board couldn't have displayed this program properly.
The little program above uses TmsPlotPixel from J B Langston's excellent library. It (and any routine that wants to plot or draw to a bitmap screen) depends on being able to read the TMS chip's VRAM.
You can get around this in software by keeping your own buffer. This would be at the expense of some speed and about 6k of ram (and more if you want to read the colour value). None of the existing examples for the RC2014 TMS video module make use of the plot routine so this didn't seem like a priority to me.
However, I came up against it and realised that it would be a necessary feature for this project.
So despite adding a bunch of logic, having to add to my software and designing the Dr.VIP board (which is a lot of changes all at once) this new version seems to be working like a charm. I'm still testing but to my surprise, I feel that this is just about finished.
What can you use this video module for?
J B Langston's TMS9918A module has been around for a long time. I've gathered together the examples that I've found (and built them for cpm and classic machines). These include demos and 'screen2' and 'screen3' artwork. I've added to that collection my own ports of 3D Monster Maze and Mazogs and (breaking news) I've been working on a port for RC2014 and hopefully MSX of David Stephenson's excellent game Tut Tut. (All shown below looking nice and clear and vibrant using my video module.) The module is also connected to the serial lines, so from startup it can display the OS stuff using the TMS 40-col text mode, and potentially accept keyboard input too.
This isn't just a milestone in this project but a milestone in my life. This isn't the first time that I've ordered a pcb assembled with surface mount parts but it is the first time I've designed a board with an RP2040 and supporting components. My expectations were about 50/50 on whether it would work or not. But as you can see, it does!! Yipeee!
(Try to ignore the ugly through-hole button soldered to surface-mount footprint).
This is really no more than at test to see whether I can put the RP2040 etc onto a board. As discussed in previous logs there is more functionality to add to this project but I didn't think it was sensible to start adding to the logic side at the same time as this big step.
So functionality-wise, this is exactly the same as the 'Feather' version shown previously. Now I have to knuckle down and add that other stuff - jumper for selecting the ports that this appears on and the ability to read the VRAM and all bits of the status register among other things.
How do I feel about this? I'm chuffed to bits that I've designed my own board with an RP2040 and that it works. This will branch off into other projects.
I have mixed feelings about this particular version of this project. Mainly because we have both surface-mount and through-hole components next to each other, which begs the question: why, if I have resistors, capacitors and ICs surface mounted to this board, are the other through-hole components not surface mount as well? (The answer to that is that the RC2014 itself is a DIY retro computer and the whole point is that it uses through-hole components including DIP ICs. Surface-mount looks out of place.)
There are other issues too - the microUSB port is fine for programming the microcontroller, but it's difficult to plug in a keyboard (with USBA to micro OTG adaptor) at the same time as the HDMI, sorry, DVI socket, because they're too close together.
In many ways the 'feather' version is great, it addresses many of these issues but it doesn't expose enough GPIO for my next stage. A Pi Pico with DVI 'sock' or other daughterboard would work but would be really ugly (a daughterboard on a daughterboard, and green to boot.)
I do have a plan which I think is a good solution. Stay tuned!
Over the last week I've spent a lot of time and money designing and ordering a new prototype with the RP2040 and supporting components surface-mounted to the module. The reasons for this are:
I don't know how all of this will go. But on the aesthetic point, I've been looking at it here on my desk and had an idea. Now that I've tried it it looks so good and seems so obvious that I'm not sure why I didn't think of this before.
Yes I've moved the Feather to the back of the board so that the gubbins on the dev board are not visible at all. (This has led to other ideas, that I won't go into for now.)
This has totally changed the way that I feel about this version. Not only is it working extremely well but with this one small change I really love the way it looks.
To the point of this log. When you order prototype pcbs, the minimum quantity is 5. Therefore I have four more of these boards, and would rather like to build them up and see them in use.
I need to be clear that I am actively working on this. I hope to have a version that will deal with the points discussed in the last log and have the components directly on the module, ie not use a dev board.
Here's a beauty parade.
After three versions of the board and lots of software development I finally have a finished module that does everything that I originally envisioned, without bodges!
It works on a cp/m RC2014, at 7 Mhz. It also works on a 32k RC2014, as long as the serial card is SIO/2 and not the ACIA (this has to do with port clashes. This video board is fixed at ports $98 + $99)
It runs all of the demos that J B Langston has shared for RC2014+TMS. The limitations of this version (I knew all of this from the start) are:
I believe that I can overcome all of these things and have a fully-compatible TMS9918A module for RC2014 with some basic serial in/out. This will also involve using a surface-mounted RP2040 rather than the Feather which will look much neater.
Here are a couple of videos which show this card in operation. To be honest they're the same videos as included in the last log but nothing has changed as far as the functionality goes, it's just a little more finished and polished hardware-wise.
The second demonstration shows how nice it is to have a little bit of terminal functionality.
It's been a while since I made any progress hardware-wise. I've spent a lot of time recently doing bits and pieces of other things while waiting for components for the latest version of the video board. Components that were actually sitting in my cart and not checked out! D'oh!
Anyway, now in possession of the latest version of the board and the components to populate it, naturally it didn't work and I had to do some troubleshooting and bodging.
But long story short, it now works, and my scheme to implement the status register (or at least one bit of it) has worked!
The TMS chip has several registers but only one can be read, the status register. One bit is very important, it's set when the picture reaches the vertical blank, and is reset when the register is read.
This is very useful. J B Langston's library contains a TmsProbe function which detects a TMS video card and by reading this register (a read to reset the bit, then a wait, then a read again to see whether it's been set). Many programs use this for timing and to make sure that they do the drawing in the vertical blank.
Implementing this register (or at least that particular bit) is thus very important. (Incidentally, the rest of the register has to do with sprite collision and the 'fifth sprite', ie indicating whether more than four sprites appear on a single scanline, and if so, the number of the fifth.)
I haven't managed to make a RP2040 respond quickly enough to a port read on a 7Mhz computer, so a bit of logic is required.
Happily that's working (after a spell of several other projects not working, this took me by surprise) and so I can now run a number of the RC2014 TMS examples, if not all of them.
Here is the plasma demo (by J B Langston, based on a Petscii version by Cruzer/Camelot) running perfectly and looking sharper than I've seen it before.
.. and here's the Nyan Cat demo. This uses the status register for the timing and to make sure the drawing is done in the vblank, so now this is nice and solid (which it wasn't when I ran this before using simple delays).
There are no changes to the hardware since the last log. I have received new boards but I'm waiting with some frustration on an order of one particular logic chip.
So I've been completing the sprite functionality. In the last log I demonstrated that sprites were working but I'd only implemented 16x16 unmagnified sprites.
The TMS chip has flags for sprite magnification and sprite size. 'size' determines whether the sprite definitions are 8x8 or 16x16. 'magnification' determines whether sprites are shown with pixels doubled in width and height, giving an effective size of up to 32x32 pixels on screen (but blocky).
I see no point to the 8x8 size. Obviously only 8 bytes of VRAM are used rather than 32, but it doesn't save VRAM because the definition for the second sprite still begins 32 bytes after the first. it's just the same as using the first 8 bytes of the sprite definition and setting the rest to 0 (transparent). Nevertheless, I'm trying to make sure that I've implemented everything on the TMS chip as documented so that existing software will run.
To test the magnification, I built this little demo / screensaver, which runs on an RC2014 with TMS video card. (photo below, you can see it running in the video which is further below.) I've built this demo with sprites magnified and without.
It's difficult to tell but there are six colours in the sprite, which is actually 8 overlaid sprites. We can only have four per scanline, so there's a dividing line about halfway down the bird (there's a change from light yellow to dark yellow). Four stacked sprites make the top half and four make the bottom half.
Making the sprite data was very laborious. I didn't quite go oldschool with graph paper but it was still a very manual process (with the data in the form %00001100 to help me see what I was doing).
So for future sprite-based work I decided to write a sprite designer tool. (Started but not finished yet). It will allow you to 'draw' the sprites on screen and then spit out the sprite definition data. It allows you to stack up to four sprites (and set the colour of each to one of the TMS's 15 colours) and see the sprites separately and stacked. It also allows you to hit keys to change the magnification and size flags on the TMS chip. This makes the Sprite designer a more useful tool for testing my TMS emulator than the original flappy demo!
In this video you can see the flappy demo working (I'll put that into my repository of programs to run on RC2014+TMS) and the work-in-progress sprite designer. I've shot short video clips of that running with my emulator and a real TMS chip, to show that the emulator matches the real chip in these respects.
It also shows the difference between the pin-sharp DVI output of the emulator vs the composite output of the real TMS chip. I like both for different reasons.
This project isn't just about getting a better picture. I need to say again (because of comments I've had) that it isn't going to be a drop-in TMS9918A replacement, but a RC2014 module. The additional terminal functionality will make it a very useful alternative to the TMS video card.
Since the last log I've received my first prototype boards. (This one accommodates the RP2040 DVI feather and the logic chips I need.
This is probably the most disastrous pcb I've received to date. There were multiple problems and you can see some of the bodge wires. There are others on the back.
At least it gets rid of the breadboard. I have only ever bought cheap breadboards and leads, so my breadboards are always sketchy (when it's working, don't touch it!)
Besides the ID10T errors, my system for providing the status register didn't work. I didn't breadboard it, but should have done because I would have found one glaring omission.
A revision of the board is on the way, and that should allow me to (at least) provide the most significant bit of the status register. In the meantime, my programs are having to avoid reading that register (J B Langston's library uses that register for the port detection and some demos use it for timing and/or drawing during the vblank. The bit is set to one when the vblank starts and reset to zero when the register is read).
On the software side, I've implemented sprite functionality. Well, so far just the 16x16 unmagnified mode, but the others should be simple to add now. This is working fine (see video below). One interesting point is that my code will display all 32 sprites on a scanline if required. I have to actually add the code to stop it at four, in order to match the TMS chip (and then set the 'fifth sprite' stuff in the status register - I'll come back to that).
So the question is whether to leave it open, allow my board to display all 32 sprites on a line - which is an enhancement to the original chip's functionality. Is that likely to break existing software? (I think that's unlikely - software is likely to check the 'fifth sprite' bit and take action to work around the problem when that happens. Anything that does this should continue to run, unaware that more sprites are being displayed on a row than should be possible.)
My current design allows for my software to control all bits in the status register but at present I'm only handling the 'F' bit (vblank). I will need to use more GPIO pins for this.
Another problem that's come to light is that software wanting to read VRAM may be a bit more common than I thought. I encountered this in the demo in the video below. I used the plotPixel call in J B L's tms library to draw the starfield and it didn't work as expected. It turns out that it calculates the relevant byte in vram, reads it and then uses 'or' to plot the pixel (or 'and' to unplot the pixel). It occurs to me that any software that draws or plots probably does the same.
I had intended to stop short of reading vram (because of a technical reason - the RP2040 isn't fast enough to respond to a port read. At least not with CPU at 7 Mhz. At least I don't think so.)
I now want to do this and I have devised a way to do it, it'll just need a bit more logic and more GPIO pins.
This and the other 6 bits of the status register add up to more GPIO pins than I have available with the feather, which is a real shame.
One option is to use a regular Pico with a DVI sock or similar. But I didn't really want to do that because it'll look really messy. (The feather's black colour is a real plus.) I haven't yet found a RP2040 board with DVI and more GPIO exposed than the feather. Please tell me if there is one.
So I'm going to go ahead with something I've wanted to do for a long time, which is to design my module with a RP2040 chip and supporting components directly on the pcb, rather than use a RP2040 dev board like the Feather or Pico.
The video below shows the picture from my current prototype, with a demo running on the RC2014 that puts 16 sprites on the screen at once, over a background in bitmap mode. I've adapted this from a classic demo that bounces one of these globes around the screen using...Read more »
This is a little-used screen mode. Each pixel can be any of the chip's 16 colours but the trade-off is that resolution is reduced to 64 x 48. The 'pixels' are bloxels that are 4x4 of the original pixels.
Here's a piece of artwork that uses this mode, it's called koi-boi by Spritus
(I have added koiboi.sc3 and my sc3view.com to my repository of files for RC2014+TMS9918A)
That's being displayed by my emulator. It took a little while to get here because of the complicated order that the bytes are displayed (a pattern is 2 bloxels wide by 8 deep, represented by 8 bytes in the pattern table. The pattern table is referred to by a byte in the name table. I'm still not sure that I've got this all correct but it works with the way that the name table is conventionally filled, which is 6 sections of 4 rows of 32 bytes, each group of 4 rows being identical.)
With that implemented, heres the Nyan Cat demo, running perfectly and looking very sharp.
I was extremely pleased to see that multicolour mode was working fine, and even more pleased to see that the emulator runs this demo without missing a beat, which is pretty intense in the amount of data it's sending to the TMS's video ram,
Then I had a 'hang on.....' moment. This shouldn't have run, or perhaps should have run at a faster speed, because the animation relies on being able to read the TMS chip's status register (a bit indicates the vertical blank) which my emulator doesn't yet supply. Then I noticed that as well as my emulator, I also had the real TMS module plugged into my RC2014 backplane! The two were working happily in parallel, both generating their video signal and the real chip providing valid data for the the status register.
Indeed, with the real TMS module pulled, this demo ran much more quickly. (and still appeared to run fine.)
[edit: after watching that video over and over, I think I can see tearing. It's not very obvious because the cat isn't moving very much, but this is as expected with the emulator not generating its own vblank signal. Once I've implemented that, any tearing should be gone.]
Here's another demo of my emulator in action, this time with my Life program which also uses the TMS mode 3. It's is perfectly suited to this program because there's obviously a trade-off between the number of cells and the speed that you can run. In fact the screen mode allows for colour, so I plan to add some colour to this program.
Over and out for now.
Become a member to follow this project and never miss any updates
By using our website and services, you expressly agree to the placement of our performance, functionality, and advertising cookies. Learn More