Close

Brief Instruction Set Overview

A project log for Novasaur CP/M TTL Retrocomputer

Retrocomputer built from TTL logic running CP/M with no CPU or ALU

alastair-hewittAlastair Hewitt 04/08/2019 at 14:222 Comments

6 weeks in and the initial hand-drawn schematic is posted and the parts have been ordered. There have been requests for more information. I'll be filling in details as I move forward, but thought I would post a brief overview of the instruction set. The encoding of the instruction set has been shown in the project's background image since week 2, but hopefully this will help explain!

There are two fundamental operations:

The operand can be loaded to one of 8 registers:

The last two registers (PC, Pg) can be loaded conditionally, based on the sign of the accumulator. The page register also has an option to toggle between one of two banks of 64k providing a 17-bit address range. There is also a zero-page option to leave the X index register in tri-state after loading to enable quick access to a zero page (0x1YYFF).

The load operand typically takes 2 cycles to complete. The conditional load will complete in 1 cycle if the condition is not met (it does not need to load the operand). There is also a condition that always skips: NOP, so this can be defined with just one instruction byte (1 byte, 1 cycle).

The YATAC uses the ROM as the ALU to perform binary operations between the 8-bit accumulator A and one of the 4-bit halves of HL. There are three sets of ALU functions:

The FN8 set includes 8 functions like ADD, SUB, AND, OR, and requires 3 cycles (load instruction, first nibble, second nibble). The FN4 set includes the same 8 functions as FN8, but only performs the lower half of the nibble to complete in only 2-cycles. FN4 also includes 4 additional functions like MUL, DIV, and 4 sets of unary functions like INC, DEC, SQRT. The specific unary function within the set is defined by the 4-bit L register, specifying a total of 64 functions. The FNH is a special case targeting the last set of 16 unary functions specified by the H register.

Both the FN8 and FN4 functions leave the result in A. FNH can specify one of 8 possible registers: the first 6 listed above, or one of 2 expansion registers (EX, EY) available via the parallel port. The ALU instructions also specify the source of the data to use and whether to write the result to the RAM. The default is A, but both X, E, or the upper RAM1, or lower RAM0 can be sourced.

The very last unary function is a NOP, which passes the input to the output unchanged. This provides the ability to move data from A, X, E, RAM to one of the 8 possible registers. There is no specific MOV operation beyond this.

Discussions

Alastair Hewitt wrote 04/12/2019 at 21:28 point

The instructions specify everything that happens during all cycles of the execution (typically 4 cycles). The first cycle is loading the instruction, so that really doesn't count. The other 3 cycles are: load data, ALU Function, and store data. There isn't an explicit load instruction other than the operand loading. This loads the next byte from the ROM rather than using the ALU and can also store the accumulator to the zero page (RAM1 in mode 3 below).

The encoding uses up to 3 bits to specify what gets loaded/stored, 3 bits to define the destination register, and up to 4 bits for the ALU function. There's also 2 bits to specify how the operand is used, making a total of 12 bits. This doesn't fit in 8 bits, so some of these options are limited based on groups of ALU functions described in the log.

The 8 defined load/store options are defined in the "diode ROM" shown in the schematic. This may change, but this is what's currently shown:

0: Load A

1: Load A, Store RAM0

2: Load RAM0

3: Load A, Store RAM1

4: Load X

5: Load E

6: Load RAM1

7: Load RAM1, Store RAM1

I'm using the Harvard Architecture, so only the 128k of the lower ROM can contain program code that executes. I may do something similar to the Gigatron for running user programs, but I haven't given it too much thought yet.

Sorry for the confusion... I use the word NOP to mean two different things. There's a NOP instruction that doesn't do anything. Then there's a NOP ALU function that passes data between the two data bases. It would show up twice in the full instruction set. This is the only ALU function that I've defined so far. I probably won't finalize the others until I start developing the software and work out what I actually need.

I can upload the spreadsheet. It's basically a scratchpad I've been using to keep track of things. It's not designed for public consumption, but I'll add it to the file list so you can take a look.

The schematic is still a work in progress. I found some timing issues that I should be able to resolve. I'm also toying with the idea of using a Programable Logic Array. A single 16R8 would go a long way in reducing the combinational logic of the instruction decode and CPU state machine. I don't think it's "cheating" because these have been around since 1978.

  Are you sure? yes | no

roelh wrote 04/12/2019 at 13:38 point

Hi Alastair, thanks for posting your drawings, although most of it is hard to understand.

But your new details section, that explains how ROM and RAM are alternated between CPU and Video, is quite helpful.

About your instruction set, I have following questions:

 - What are the addressing modes for load ? 

 - You said there are load and ALU instructions. How do you store ?

 - You can not execute instructions from RAM ? Or would you do an interpreter for

      this, like Gigatron ?

 - It is a bit strange that NOP actually will be used to perform a useful function. Why not rename that to MOV ?

You have the encoding partially visible in the background, could you also put it in the files section ?

  Are you sure? yes | no