09/28/2018 at 20:01 •
I spent a fair amount of time getting back to speed with the TMS99105 project. I have in the meantime advanced my own TMS9900 VHDL core. This sister project by now had a more compatible version of the TMS9918 video processor, and a little different memory map from the TMS99105 version.
As a reminder: In principle my two projects are almost identical, running on the same Pepino FPGA board, the only major exception being that the first version of the TI-99/4A clone uses the TMS99105 physical CPU chip on an external daughterboard, while my latter project is the same, but replaces the TMS99105 chip with my own version of the TMS9900 core, thus integrating it to the FPGA. As I have been working on this project more lately, it has gotten more advanced.
Nearly all of the VHDL files are identical between the two projects, the obvious differences being a different top-level module, integrating either the TMS99105 external CPU or the TMS9900 core as a VHDL module.
Enough of background - the difference that prevented me from running the Megademo on the TMS99105 system was that this version had an older version of the memory map, and did not support a "ROM" cartridge of 512K which is a requirement for the Megademo. To be more precise the Megademo comes in different versions, but the one of interest to me is the one that requires 512K of paged ROM space - and I provided that in the latter project by rearranging how the 1MB external memory of the Pepino board was divided between different functions.
I ran into great difficulty in simply copying the same memory layout over from the TMS9900 core system. After some intense head scratching I determined that the seeming insignificant memory map change resulted consistently in timing problems, making the TMS99105 system very unstable. For now I solved this problem by just bypassing the memory paging unit, therefore limiting the addressable RAM to 32K, down from 256K of paged memory while simultaneously allowing for a 512K ROM area to exist. The ROM area is paged too, having 64 pages of 8K in size, but this paging mechanism is very simple compared to the RAM paging system. The RAM paging seems to be on the critical path.
To cut long story short, with 512K of ROM space I was able for the first time to run the Megademo with the TMS99105 CPU. On real TI CPU iron, with my FPGA implementation of the rest of the TI-99/4A. Needless to say, it runs very fast, having about 7x the processing power of the original TI-99/4A. The most interesting aspect of this test of running the demo for me was that the TMS99105 version has the exact same problems as shown when using my own processor core. Most of the demo runs just fine, but a couple demo sections still show graphics glitches and towards the end the demo gets stuck. This proves to me that my TMS9900 clone is now getting "very" compatible, and that most likely the problems I am encountering now in the demo are due to 1) my TMS9918 video processor clone still having compatibility issues and 2) the place of the demo where execution gets stuck is likely due to poor implementation of some TI-99/4A feature used by the demo but not relating to graphics (smells like TMS9901 timer interrupt to me).
10/03/2017 at 07:43 •
I recently noticed that my TMS99105 project at hack-a-day has more followers than my successor project to this one, so I thought I will just provide here a quick link to that project. I understand that some people may be interested in the TMS99105 project in it's own right, and I really like this project too, it came well out.
After "completing" this project to a functional state I've worked on my VHDL implementation of the TMS9900 core, allowing the entire TI-99/4A to be re-created in the FPGA. That design is largely compatible with this one, all the peripherals like the TMS9918 and TMS9919 are the same in both projects. The source code to both projects is in the same repository, with the TMS9900 VHDL implementation being in the "soft-cpu" branch.
I may still make updates to this project too, as I really like the shiny TMS99105, and also because it is currently still more tested than the successor project. So as I make updates to the peripherals etc I will probably bring those improvements over to this project too.
04/01/2017 at 03:58 •
After a while a quick update: I found at AtariAge a really cool demo for the TI-99/4A, using scanline effects.
Unfortunately that did not work on my TMS99105+FPGA system, as my TMS9918 VHDL model did not support detecting 5 or more sprite per scanline condition. That's now fixed, and the demo runs :)
01/14/2017 at 05:30 •
It's been a while since my last update. During the time I haven't had that much time to put into the project. However, there is some nice progress:
I have fully assembled two boards and they work. As can be seen from the picture above, one extra wire is still needed to carry the CPU's write signal to the FPGA. All the other signals are delivered through the pin headers. The two headers carry a limited number of signals: the larger header has 16 signal pins. These are used in a three way multiplexing scheme, timing is based on the CPUs address latch signal. These are the phases:
- Address transfer from CPU to FPGA (early part of the address latch high). This part takes about 30 nanoseconds.
- Control signal transfer from FPGA to CPU and sampling of some CPU signals from the CPU to the FPGA. This takes the next 30 nanoseconds.
- The 16 data signals are treated as two groups of eight during this part of the cycle
- One group is from FPGA to CPU, in practice the FPGA clocks 8 signals to the 74ACT574 flop flops. These signals include CPU reset, interrupt, non-maskable interrupt, and other control signals, including the input for the green LEDs. One of the LEDs is simply toggled when 2^19 clocks of address latch are received and allows us to see that the CPU is running. The other LED is lit when the disk subsystem is active.
- The other 8 signal group is used to sample the status of some control lines of the CPU by the FPGA. A 74LVC245 buffer is driven active to do this. The signals include BST1, BST2, BST3, #MEM and #WR. The last one of these, #WR, appears so late in the cycle that I added the red wire depicted above to be able to continuously sample it, instead of trying to sample it during this control signal transfer window.
- Data transfer either to the CPU (reads) or from the CPU (writes). Writes are simply sampled a few 100MHz clock samples into the cycle when #WR has gone low. For reads the FPGA needs to present the CPU with the data for as long it samples it. That is the reason why the #RD signal is not among the multiplexed control signals but rather available directly to FPGA via the other header, which carries 6 control signals in total. Only two signals from the CPU are directly available via this header: #RD and ALATCH. The remaining 4 signals are control signals driven by the FPGA to control the various buffers and the aforementioned 74ACT574 latch. This part of the cycle takes the remaining 140 nanoseconds or so (a memory cycle is 200ns at 20MHz).
This timing sequence is somewhat visible in the logic analyser picture below:
In the picture there are a few notable signals:
- AL shows the CPU's address latch signal and is the basis of timing
- CTRLCP is the clock driving the 8-bit 74ACT574 register. The FPGA generates this signal once it has sampled the address over during AL high (the sampling occurs over the 16 signal pins).
- CTRLRD enables a 74LVC245 buffer so that the FPGA can read the bus status lines. Active low.
- BUSOE, when low, allows the FPGA to observe or drive the 16-bit multiplexed address/data bus of the CPU.
As can be seen in picture, BUSOE and CTRLRD are effectively the same signal, the other is just an inverted version as the 16 signal bus can only either be used for control signals or the address/data bus. CTRLRD is active for 30 nanoseconds. The rising edge of CTRLCP appears 20 ns into this cycle, to provide enough time for the buffers to settle.
12/20/2016 at 07:55 •
It is always a great feeling to get the physical boards from manufacturing :)
I had no real time to check the boards, but on the surface they seem fine. At least the connector measurements turned out ok and the board perfectly connects to the Pepino FPGA board.
The top of the board, photo taken through my magnifying glass / light:
Bottom side, with connectors mounted (no time yet for anything else):
A close up of the connection to the Pepino, it appears the SD card and audio jack are still accessible:
12/15/2016 at 21:24 •
I have trying to understand why in graphics mode 2 the last character cell was showing bogus information and finally understood the problem. It was on the hardware side, the character address was incremented too early, and the VHDL code was using the new value although it should still have used the old value. This has to do how character cells are treated in graphics mode 2: in this mode the screen supports 768 unique character values, but they are specified in a funny way. The screen is divided into 3 vertical bands of 256 characters, in each band the 8-bit character values are re-used.
My problem was that the increment for the very last character cell happened too early, causing that particular character to roll over to a non-existing "fourth set" of 256 characters. The same problem probably also caused problems for the last characters of the bands 0 and 1 too. Anyway, now it is fixed and Yin/Yang displays in all its glory without bugs - this bug actually was visible in the Parsec too - but not anymore. Updated code in GitHub.
12/08/2016 at 07:40 •
I have spent some hours designing a printed circuit board for this design. This will be a board that plugs in on top of the Pepino board. I did this on purpose using only through-hole components just in case there are people interested in building one of these. Personally I prefer SMD components, and that would have allowed the board to be somewhat smaller.
I also revised the schematics, to be able to support the entire TMS99105 feature set. That required some more signals. Since I'm already using all the pins available on the Pepino board, I put in a couple more buffers and a latch to store control signals. That will meant that the already multiplexed address/data bus will have another phase (under FPGA control) to read the additional CPU output signals (such as BST1, BST2 and BST3) and to latch control signals to the latch.
11/30/2016 at 18:54 •
I did a small update, now the sprite bug should be gone, although that did reveal another potential bug as can be seen in the picture below: the lower right hand corner has a missing block for whatever reason... But at least there are no red sprites in there.
While fixing the VDP, I also added a few more extra read only registers. These are 16-bit registers available in the address space of the CPU. Mostly they are there for convenience to have direct VDP memory pointers, VGA scanning registers actually allow changing of VDP memory synchronised to the scan.
Address Comments 8880 High byte returns contents of VDP register 0 (low byte zero) 8882 High byte returns contents of VDP register 1 (low byte zero) 8884 Pattern memory pointer in VDP memory (based on reg 2) 8886 Color table pointer in VDP memory (based on reg 3) 8888 Character table base address in VDP memory (based on reg 4) 888A Sprite attribute table base in VDP memory (based on reg 5) 888C Sprite pattern table base in VDP memory (based on reg 6) 888E High byte returns contents of VDP reg 7 (colours), low byte zero 8890 Current value of VDP memory pointer 8892 VGACol - current VGA scan column 8894 VGARow - current VGA scan row 8896 MSB: line buffer bank (toggles between 0 and 1, VGA refresh hardware reads from linebuffer indicated by this bit).
LSB: 1=when display blanking active
Bits 14..1: 0 when read
11/28/2016 at 19:47 •
I've been working rather slowly on the disk subsystem support. After fixing numerous bugs and my own misunderstandings, I was finally able to run TI's original Editor/Assembler software system on the TI-99/4A clone.
Getting editor assembler to work is an interesting milestone due to the way the cartridge works: actually the cartridge is a GROM only cartridge, so it does not contain any machine code software, just GPL code. It loads the machine code assembler from the disk (the files ASSM1 and ASSM2). These two files are loaded as binary programs. When assembling, the source coded is loaded from the disk as variable length record file, while assembler output (the object file in TI's tagged hex annotation) is written as a fixed record file.
To run the assembled program, the disk subsystem also needs to be able to load a fixed length record file. Thus overall there is a fair amount of different types of files that the disk subsystem needs to work with. I used Matthew Hagerty's nice Yin/Yang assembler program as a test. The output can be seen below, complete with bogus sprites. The sprites are there due to hardware bug I have in the sprite engine design, I guess it starts to be time to fix it... Basically the sprite engine does not properly recognize when to stop drawing sprites.
11/25/2016 at 09:37 •
I posted to youtube a new video showing the system running RXB 2015. I haven't had much time work on the design, but the little time I had I've been working on the disk support subsystem. Most of that code runs on the PC, and communicates with the system over USB. I'm starting to understand how the TI-99/4A disk system works.
In addition I remapped the memory of the FPGA system, so that the paged memory extension on the TI-99/4A clone now has access to 512K of RAM, up from the previous 256K.
I guess I need to try the game more on the classic99 emulator as I don't know if the game runs properly... At the end of video I got stuck... Sorry the video is pretty boring as I did not have time to work on it either. During loading you can see the sprite bugs in the top left hand corner - my VDP implementation still doesn't properly process the "no more sprites" code (vertical coordinate set to >D0), so it will spit out extra sprites. Sprite size doubling is not supported by the hardware, as can be seen from the size of the loading text.
From a technical point of view to get this far the system requires support for SAMS memory and the following disk subsystem opcodes: load, open, read, close. While they seem trivial, they are not exactly that. I went ahead and blatantly copied a bit of code from classic99 (the file buffering code)...