📄 8080 cpu .v
字号:
////////////////////////////////////////////////////////////////////////////////
// Company: //
// Engineer: Scott Moore //
// //
// Additional contributions by: //
// //
// Chris N. Strahm - Modifications for Altera Quartus build. //
// //
// Create Date: 11:45:32 09/04/2006 //
// Design Name: //
// Module Name: cpu8080 //
// Project Name: cpu8080 //
// Target Devices: xc3c200, xc3s1000 //
// Tool versions: //
// Description: //
// //
// Executes the 8080 instruction set. It is designed to be an internal //
// cell. Each of the I/Os are positive logic, and all signals are //
// constant with the exception of the data bus. The control signals are //
// fully decoded (unlike the orignal 8080), and features read and write //
// signals for both memory and I/O space. The I/O space is an 8 bit //
// address as in the original 8080. It does NOT echo the lower 8 bits to //
// the higher 8 bits, as was the practice in some systems. //
// //
// Like the original 8080, the interrupt vectoring is fully external. The //
// the external controller forces a full instruction onto the data bus. //
// The sequence begins with the assertion of interrupt request. The CPU //
// will then assert interrupt acknowledge, then it will run a special //
// read cycle with inta asserted for each cycle of a possibly //
// multibyte instruction. This matches the original 8080, which typically //
// used single byte restart instructions to form a simple interrupt //
// controller, but was capable of full vectoring via insertion of a jump, //
// call or similar instruction. //
// //
// Note that the interrupt vector instruction should branch. This is //
// because the PC gets changed by the vector instruction, so if it does //
// not branch, it will have skipped a number of bytes after the interrupt //
// equivalent to the vector instruction. The only instructions that //
// should really be used to vector are jmp, rst and call instructions. //
// Specifically, rst and call instruction compensate for the pc movement //
// by putting the pc unmodified on the stack. //
// //
// The memory, I/O and interrupt fetches all obey a simple clocking //
// sequence as follows. The CPU uses the positive clock edge to assert //
// and sample signals and data. The external logic theoretically uses the //
// negative edge to check signal assertions and sample data, but it can //
// either use the negative edge, or actually be asynronous logic. //
// //
// A standard read sequence is as follows: //
// //
// 1. At the positive clock edge, readmem, readio or readint is asserted. //
// 2. At the negative clock edge (or immediately), the external memory //
// places data onto the data bus. //
// 3. We hold automatically for one cycle. //
// 4. At the next positive clock edge, the data is sampled, and the read //
// Signal is deasserted. //
// //
// A standard write sequence is as follows: //
// //
// 1. At the positive edge, data is asserted on the data bus. //
// 2. At the next postive clock edge, writemem or writeio is asserted. //
// 3. At the next positive clock edge, writemem or writeio is deasserted. //
// 4. At the next positive edge, the data is deasserted. //
// //
// Dependencies: //
// //
// Revision: //
// Revision 0.01 - File Created //
// Additional Comments: //
// //
////////////////////////////////////////////////////////////////////////////////
`timescale 1ns / 1ps
//
// Build option
//
// Uncomment this line to build without wait state ability. Many FPGA
// applications don't require wait states. This can save silicon area.
//
// Defining this option will cause the wait line to be ignored.
//
// `define NOWAIT
//
// Build option
//
// Uncomment this line to build without I/O instruction ability. An application
// may have memory mapped I/O only, and not require I/O instructions. This can
// save silicon area.
//
// Defining this option will cause I/O instructions to be treated as no-ops.
// alternately, you can modify what they do.
//
// `define NOIO
//
// CPU states
//
`define cpus_idle 6'h00 // Idle
`define cpus_fetchi 6'h01 // Instruction fetch
`define cpus_fetchi2 6'h02 // Instruction fetch 2
`define cpus_fetchi3 6'h03 // Instruction fetch 3
`define cpus_fetchi4 6'h04 // Instruction fetch 4
`define cpus_halt 6'h05 // Halt (wait for interrupt)
`define cpus_alucb 6'h06 // alu cycleback
`define cpus_indcb 6'h07 // inr/dcr cycleback
`define cpus_movmtbc 6'h08 // Move memory to bc
`define cpus_movmtde 6'h09 // Move memory to de
`define cpus_movmthl 6'h0a // Move memory to hl
`define cpus_movmtsp 6'h0b // Move memory to sp
`define cpus_lhld 6'h0c // LHLD
`define cpus_jmp 6'h0d // JMP
`define cpus_write 6'h0e // write byte
`define cpus_write2 6'h0f // write byte #2
`define cpus_write3 6'h10 // write byte #3
`define cpus_write4 6'h11 // write byte #4
`define cpus_read 6'h12 // read byte
`define cpus_read2 6'h13 // read byte #2
`define cpus_read3 6'h14 // read byte #3
`define cpus_pop 6'h15 // POP completion
`define cpus_in 6'h16 // IN
`define cpus_in2 6'h17 // IN #2
`define cpus_in3 6'h18 // IN #3
`define cpus_out 6'h19 // OUT
`define cpus_out2 6'h1a // OUT #2
`define cpus_out3 6'h1b // OUT #3
`define cpus_out4 6'h1c // OUT #4
`define cpus_movtr 6'h1d // move to register
`define cpus_movrtw 6'h1e // move read to write
`define cpus_movrtwa 6'h1f // move read to write address
`define cpus_movrtra 6'h20 // move read to read address
`define cpus_accimm 6'h21 // accumulator immediate operations
`define cpus_daa 6'h22 // DAA completion
`define cpus_call 6'h23 // CALL completion
`define cpus_ret 6'h24 // RET completion
`define cpus_movtalua 6'h25 // move to alu a
`define cpus_movtalub 6'h26 // move to alu b
`define cpus_indm 6'h27 // inc/dec m
//
// Register numbers
//
`define reg_b 3'b000 // B
`define reg_c 3'b001 // C
`define reg_d 3'b010 // D
`define reg_e 3'b011 // E
`define reg_h 3'b100 // H
`define reg_l 3'b101 // L
`define reg_m 3'b110 // M
`define reg_a 3'b111 // A
//
// ALU operations
//
`define aluop_add 3'b000 // add
`define aluop_adc 3'b001 // add with carry in
`define aluop_sub 3'b010 // subtract
`define aluop_sbb 3'b011 // subtract with borrow in
`define aluop_and 3'b100 // and
`define aluop_xor 3'b101 // xor
`define aluop_or 3'b110 // or
`define aluop_cmp 3'b111 // compare
//
// State macros
//
`define mac_writebyte 1 // write a byte
`define mac_readbtoreg 2 // read a byte, place in register
`define mac_readdtobc 4 // read double byte to BC
`define mac_readdtode 6 // read double byte to DE
`define mac_readdtohl 8 // read double byte to HL
`define mac_readdtosp 10 // read double byte to SP
`define mac_readbmtw 12 // read byte and move to write
`define mac_readbmtr 15 // read byte and move to register
`define mac_sta 17 // STA
`define mac_lda 21 // LDA
`define mac_shld 26 // SHLD
`define mac_lhld 31 // LHLD
`define mac_writedbyte 37 // write double byte
`define mac_pop 39 // POP
`define mac_xthl 41 // XTHL
`define mac_accimm 45 // accumulator immediate
`define mac_jmp 46 // JMP
`define mac_call 48 // CALL
`define mac_in 52 // IN
`define mac_out 53 // OUT
`define mac_rst 54 // RST
`define mac_ret 56 // RET
`define mac_alum 58 // op a,m
`define mac_indm 60 // inc/dec m
module cpu8080(addr, // Address out
data, // Data bus
readmem, // Memory read
writemem, // Memory write
readio, // Read I/O space
writeio, // Write I/O space
intr, // Interrupt request
inta, // Interrupt request
waitr, // Wait request
reset, // Reset
clock); // System clock
output [15:0] addr;
inout [7:0] data;
output readmem;
output writemem;
output readio;
output writeio;
input intr;
output inta;
input waitr;
input reset;
input clock;
// Output or input lines that need to be registered
reg readmem;
reg writemem;
reg [15:0] pc;
reg [15:0] addr;
reg readio;
reg writeio;
reg inta;
reg [15:0] sp;
// Local registers
reg [5:0] state; // CPU state machine
reg [2:0] regd; // Destination register
reg [7:0] datao; // Data output register
reg dataeno; // Enable output data
reg [15:0] waddrhold; // address holding for write
reg [15:0] raddrhold; // address holding for read
reg [7:0] wdatahold; // single byte write data holding
reg [7:0] wdatahold2; // single byte write data holding
reg [7:0] rdatahold; // single byte read data holding
reg [7:0] rdatahold2; // single byte read data holding
reg [1:0] popdes; // POP destination code
reg [5:0] statesel; // state map selector
reg [5:0] nextstate; // next state output
reg eienb; // interrupt enable delay shift reg
reg [7:0] opcode; // opcode holding
// Register file. Note that 3'b110 (6) is not used, and is the code for a
// memory reference.
reg [7:0] regfil[0:7];
// The flags are represented individually
reg carry; // carry bit
reg auxcar; // auxiliary carry bit
reg sign; // sign bit
reg zero; // zero bit
reg parity; // parity bit
reg ei; // interrupt enable
reg intcyc; // in interrupt cycle
// ALU communication
wire [7:0] alures; // result
reg [7:0] aluopra; // left side operand
reg [7:0] aluoprb; // right side operand
reg alucin; // carry in
wire alucout; // carry out
wire alupar; // parity out
wire aluaxc; // auxiliary carry
reg [2:0] alusel; // alu operational select
// Instantiate the ALU
alu alu(alures, aluopra, aluoprb, alucin, alucout, aluzout, alusout, alupar,
aluaxc, alusel);
always @(posedge clock)
if (reset) begin // syncronous reset actions
state <= `cpus_fetchi; // Clear CPU state to initial fetch
pc <= 0; // reset program counter to 1st location
dataeno <= 0; // get off the data bus
readmem <= 0; // all signals out false
writemem <= 0;
readio <= 0;
writeio <= 0;
inta <= 0;
intcyc <= 0;
ei <= 1; // interrupts on by default
eienb <= 0;
end else case (state)
`cpus_fetchi: begin // start of instruction fetch
// if interrupt request is on, enter interrupt cycle, else exit it now
if (intr&&ei) begin
intcyc <= 1; // enter interrupt cycle
inta <= 1; // activate interrupt acknowledge
ei <= 0; // disable interrupts
end else begin
intcyc <= 0; // leave interrupt cycle
readmem <= 1; // activate instruction memory read
end
addr <= pc; // place current program count on output
if (eienb) ei <=1; // process delayed interrupt enable
eienb <=0; // reset interrupt enabler
state <= `cpus_fetchi2; // next state
end
`cpus_fetchi2: begin // wait
state <= `cpus_fetchi3; // next state
end
`cpus_fetchi3: begin // complete instruction memory read
`ifndef NOWAIT
if (!waitr)
`endif
begin // no wait selected, otherwise cycle
opcode <= data; // latch opcode
readmem <= 0; // Deactivate instruction memory read
inta <= 0; // and interrupt acknowledge
state <= `cpus_fetchi4; // next state
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -