Close

CPU was synthesis passed!

A project log for TMS9900 compatible CPU core in VHDL

Retro challenge 2017/04 project to create a TMS9900 compatible CPU core. Again in a month... Failure could be an option...

erik-piehlErik Piehl 04/26/2017 at 20:240 Comments

I wrestled today with two of the remaining instructions, LDCR and STCR, but before explaining them, I did plug in the CPU to my EP994A project (TI-99/4A clone), basically replacing the external TMS99105 interface - and synthesis did pass!!!!!! Wow! I did a really stupid integration, just wiring signals in there in a semi logical way, as to force the logic synthesis to do something - and it did! The very first attempt succeeded! It will not work for sure, as the bus interface I created is different from the TMS99105 - it has vastly different timing, so I need to modify the integration logic quite a bit.

But here is the interesting stuff, a comparison of how many logic resources were consumed on the Xilinx XC6LX9 FPGA, with "only" the TI-99/4A logic, and with the logic including the CPU (granted the CPU is bogus and the integration even more bogus - but we don't care, the ballbark is what matters):

TI-99/4A + external TMS99105 TI-99/4A + new TMS9900 core
Number of slice registers used 966 1248
Number of slice LUTs 1402 2663
Number of slice LUTs % 24% 46%
LUTs used as logic 1381 2636
LUTs used as memory 9 14
Occupied slices 36% 64%

I like these results :) It means that the FPGA easily accommodated the CPU implementation with the rest of the TI-99/4A logic. In fact even if the CPU is totally bogus and much more logic is required, it will fit in. In fact on this relatively small FPGA there is enough space to add at least one more TMS9900 core. Also the instruction decode etc. is completely state machine based, so it does not use any of the memory blocks of the FPGA. The CPU could be partially microcoded by using a memory block to save logic if necessary.

Of course a working integration of the CPU will change the numbers - but integrating the on-board CPU is actually more straightforward than interfacing to an external CPU. And if it becomes complex I can always modify the CPU bus interface...

Still DIV and MPY instructions are not implemented, but I think I will next focus in getting the CPU integrated so that I can actually prove that it works in the FPGA implementation. This could be a lot of work...

LDCR and STCR instructions

Before doing the synthesis I spent quite a bit of time of implementing and simulating two of the remaining four instructions:

They were both nasty instructions to make. The bit serial CRU interface on the TMS9900 uses the address bus to tell the external world which bit is addressed. When writing or reading more than one bit - which is pretty much always the case with these instructions - the CPU must increment the address and shift bits appropriately. It also needs to separately handle transfers between 1 and 8 bits, and 9 and 16 bits. Between 1 and 8 bits the CPU operates in "byte mode", so for example when using the auto increment addressing mode:

LDCR *R3+,5

Writes 5 bits from the address pointed to by R3 and it auto increments R3 by 1. But if the bit counter is higher:

LDCR *R3+,9

The auto increment is by two. This gets more hairy with the opposite direction, for example with

STCR *R3+,5

This will read 5 bits and do a byte write to the address pointed to by R3. Since the external bus is 16 bits wide, the CPU actually must do a read-modify-write cycle and modify either the low or high byte (depending on the LSB address bit).

To make things a little more involved, the number of bits transferred is encoded into 4 bits, with the value 0000 indicating 16 bits. So that needs to be handled properly too.

My implementation seems to do the appropriate things now, based on my limited experience of running on the real iron and reading the data sheet. The data sheet is really not verbose as to how these instructions work. The instructions also mess around with flags, but I did not implement that support yet.

Discussions