URL
https://opencores.org/ocsvn/cpu8080/cpu8080/trunk
Subversion Repositories cpu8080
[/] [cpu8080/] [branches/] [samiam95124/] [project/] [cpu8080.txt] - Rev 7
Go to most recent revision | Compare with Previous | Blame | View Log
Intel 8080 CPU Verilog core
2006/9/12
PROJECT: 8080 CPU
LANGUAGE: VERILOG
TARGET: Xilinx xc3s1000-4
OVERVIEW
This core was implemented as a first project in Verilog by an old schematic
design engineer. There were a few reasons for implementing an 8080 processor.
First, it was the first true general purpose processor available. Second, it
was, by nature, designed to be compact in instruction set and implementation.
Third, it has a rich set of software applications, including assemblers,
compilers and operating systems.
More often, A Z80 target is used in Verilog or VHDL, with the idea that the
Z80 is the superset of the 8080. However, the Z80 is significantly more
complex than the 8080. The 8080 can make a useful maintainence processor for
SOC systems, since it consumes a small amount of resources. The 8080 has a
significant body of support, since it was a primary 8 bit processor before
the Z80, and coding for the 8080 instruction set often continued even after
general Z80 use, because that was the universal subset of both processors.
My own experience with 8080 coding lasted perhaps a year, then I switched
to the Z80. Although he Z80 was a significantly more usable processor to
code for than a 8080, it made a mildly non-orthogonal instruction set much
more so. I have worked on several processors through the series, including
working on the design for the Z280, a Z80 16 bit replacement at Zilog
Corporation, so hopefully nobody can accuse me of bias against the Z80 :-)
The core presented is completely compatible with the original 8080 instruction
set, although the exact handling of the two undefined bits in the status (flags)
register have not been verified to be identical to the original. This only
matters for "trick" code that expects a value which is pop'ed into the PSW
to be preserved when subsequently pushed. This core preserves all bits,
including the undefined bits, which means such code would function correctly.
Also needing verification to the original are the illegal opcodes, which on
this core are treated as nops.
The pinout is decidedly not compatible with the original pinout. The original
8080 pinout was a multiplexed nightmare that was never really designed to be
directly used. Intel was attempting to save on pins, and much of the CPU status
was sent out on every cycle via the data pins. Intel subsequently came out with
"demultiplexor" chips to result in simple signals.
The cpu8080 signals are a simple unmultiplexed 16 bit address, and a
bidirectional, separate 8 bit data bus. The read and write for each of memory
and I/O spaces are all separately decoded. An interrupt request and acknowledge
is implemented sufficient to allow an external interrupt controller to be
connected. A readint signal is implemented that is true for the entire time that
an interrupt fetch is occuring. This allows simple implementation of full
vectoring mode.
There were two vectoring modes on the 8080. The most famous one was the use of
a single instruction byte that was forced onto the data lines during an
interrupt acknowledge cycle. This instruction could be any valid instruction,
but was most likely a restart, which gave 8 possible vector locations for the
interrupt.
It was not as well known, but the original 8080 could accept a full 2 or 3 byte
instruction via the interrupt acknowledge cycle. This was used by advanced
Intel interrupt controllers to place a full CALL instruction on the data lines,
and thus achieve full arbitrary address vectoring. I have included such an
advanced interrupt controller as an accessory to the cpu8080 core, also in
verilog.
IMPLEMENTATION
The 8080 is implemented with a standard finite state machine. At the next
positive edge after reset, the state, PC, all of the bus signals are reset to
false, and the interrupt enable is set. All of the registers, including the
stack, are left undefined at reset.
At the fetch instruction state, the current pc is placed on the address bus,
and a read instruction cycle occurs. In fetch2, the readmem signal is
deactivated, and the opcode is now on the data lines. We read it without
latching.
The instruction decode starts by splitting the instruction by the top two bits.
This breaks down as follows:
00 - General instructions, including carry control, rotates, double adds,
increment and decrement, and many types of loads.
01 - The "mov" instruction.
10 - Register or memory to accumulator operations.
11 - General instructions, including jumps and calls, interrupt enable and
disable, and I/O.
The move and accumulator operations are handled as one case. The others both
break down into a further case based on the lower 6 bits of the instruction.
Quite a few instructions are handled in a single case. For these instructions,
the only required finish is to set the next pc, then set the next state back
to fetch instruction.
The other class of instruction is those that require other bus read or write
transactions to complete. This includes instructions that read or write memory,
and those that have a byte or word parameter following.
To handle these, there are quite a few states I call "follow" states. When a
fetch2 state handler needs extra states to complete, it sets the next state to
one of these follow states, and that state will occur on the next positive
clock. The follow states can then chain further follow states, and so on,
until the entire instruction is complete.
To "talk" between states, several registers are employed as "mailboxes". For
example, the regd register tells the follow states where to put fetched data
meant for a register.
Many multistate instructions are handled completely with follow states. However,
a system exists for more complex instructions I call the "macro state
generator". This is just a ROM that holds a series of follow states to be
chained up to complete instructions. These are much like subroutines, and they
use special follow states that get the next state from the macro table, then
advance the macro state selector. The chain of follow states ends when either
a terminal state is in the table, a state that ends by selecting the fetch
instruction 1 as the next state, or because the macro table specifically
selects that as the next state.
The most commonly used macro states are the read and write states. It takes
four states to write, and two to read. An instruction can use a lot of them,
and do it repetitively. For example, the "xthl" instruction must perform two
byte reads, followed by two byte writes. The read and write routines use
general registers to keep the addresses they must read or write, and up to
two bytes of data to be read or written.
The only submodule in cpu8080 is the alu. It knows how to implement 8 kinds of
arithmetic operations, add, add with carry, subtract, subtract with borrow, and,
or, xor and compare. All of the 8080 flags are calculated within the alu. The
compare operation is actually a subtract that discards the result, and passes
the A operand out as the result.
To operate the ALU, the input operands and flags are placed on its input
registers, then the output result and flags are moved to the appropriate
registers. Each time this occurs, we give a full cycle for the alu to perform
this action.
Scott Moore
Go to most recent revision | Compare with Previous | Blame | View Log