龙芯开源社区

 找回密码
 注册新用户(newuser)
查看: 2274|回复: 1

8080 Source code

[复制链接]
发表于 2008-10-28 19:17:02 | 显示全部楼层 |阅读模式
Intel 8080 CPU Verilog core


  1. ed2k://|file|cpu8080.Source%20code.7z|6702136|81C11F3B89D893A9415BFAEA8847763E|h=4FF2WP5WOODWPL7DEJQOPVQIYPRB46Y4|/
复制代码


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
发表于 2008-10-30 00:28:18 | 显示全部楼层

本版积分规则

Archiver|手机版|小黑屋|Lemote Inc.

GMT+8, 2020-8-6 09:42 , Processed in 0.176949 second(s), 15 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表