URL
https://opencores.org/ocsvn/nextz80/nextz80/trunk
Subversion Repositories nextz80
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 13 to Rev 14
- ↔ Reverse comparison
Rev 13 → Rev 14
/nextz80/trunk/Next8080CPU.v
0,0 → 1,1243
////////////////////////////////////////////////////////////////////////////////// |
// |
// This file is part of the Next8080 project |
// |
// Filename: Next8080CPU.v |
// Description: Implementation of 8080 compatible CPU |
// Version 1.0 |
// Creation date: 28Jan2018 |
// |
// Author: Nicolae Dumitrache |
// e-mail: ndumitrache@opencores.org |
// |
///////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2018 Nicolae Dumitrache |
// |
// This source file may be used and distributed without |
// restriction provided that this copyright statement is not |
// removed from the file and that any derivative work contains |
// the original copyright notice and the associated disclaimer. |
// |
// This source file is free software; you can redistribute it |
// and/or modify it under the terms of the GNU Lesser General |
// Public License as published by the Free Software Foundation; |
// either version 2.1 of the License, or (at your option) any |
// later version. |
// |
// This source is distributed in the hope that it will be |
// useful, but WITHOUT ANY WARRANTY; without even the implied |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
// PURPOSE. See the GNU Lesser General Public License for more |
// details. |
// |
// You should have received a copy of the GNU Lesser General |
// Public License along with this source; if not, download it |
// from http://www.opencores.org/lgpl.shtml |
// |
/////////////////////////////////////////////////////////////////////////////////// |
// |
// Comments: |
// |
// Next8080 processor features: |
// Fast conditional jump/call/ret takes only 1 T state if not executed |
// Each CPU machine cycle takes (mainly) one clock T state. This makes this processor over 4 times faster than a 8080 at the same |
// clock frequency (some instructions are up to 10 times faster). |
// Only 8080 instructions available (minus DAA, which = CPL) + some extra: JR, DJNZ |
// Only IM0 supported, flags 3 and 5 always 0, opcodes DD, ED, FD, CB treated as NOP |
// No H and N flags, always 0 |
// ~450 LUT6 |
// See NextZ80 for more detais |
/////////////////////////////////////////////////////////////////////////////////// |
|
`timescale 1ns / 1ps |
|
module Next8080 |
( |
input CLK, |
input RESET, |
input INT, |
input WAIT, |
input [7:0]DI, |
|
output [7:0]DO, |
output [15:0]ADDR, |
output reg WR, |
output reg MREQ, |
output reg IORQ, |
output reg HALT, |
output reg M1 |
); |
|
// connections and registers |
reg [1:0] CPUStatus = 0; // 0=HL-HL', 1=EI |
wire [7:0] ALU8FLAGS; |
wire [7:0] FLAGS; |
wire [7:0] ALU80; |
wire [7:0] ALU81; |
wire [15:0]ALU160; |
wire [7:0] ALU161; |
wire [15:0]ALU8OUT; |
|
reg [8:0] FETCH = 0; |
reg [2:0] STAGE = 0; |
wire [5:0] opd; |
wire [2:0] op16; |
wire op0mem = FETCH[2:0] == 6; |
wire op1mem = FETCH[5:3] == 6; |
|
// stage status |
reg [1:0]DO_SEL; // ALU80 - th - flags - ALU8OUT[7:0] |
reg ALU160_SEL; // regs - pc |
reg DINW_SEL; // ALU8OUT - DI |
reg [5:0]WE; // 5 = flags, 4 = PC, 3 = SP, 2 = tmpHI, 1 = hi, 0 = lo |
reg [4:0] ALU8OP; |
reg [2:0] ALU16OP; |
reg next_stage; |
reg [3:0]REG_WSEL; |
reg [3:0]REG_RSEL; |
reg [2:0]status; // 0=HL-HL', 1=EI, 2=set EI |
// FETCH[5:3]: 000 NZ, 001 Z, 010 NC, 011 C, 100 PO, 101 PE, 110 P, 111 M |
wire [7:0]FlagMux = {FLAGS[7], !FLAGS[7], FLAGS[2], !FLAGS[2], FLAGS[0], !FLAGS[0], FLAGS[6], !FLAGS[6]}; |
reg tzf; |
reg SRESET = 0; |
reg SINT = 0; |
|
Z80Reg CPU_REGS ( |
.rstatus(CPUStatus[0]), |
.M1(M1), |
.WE(WE), |
.CLK(CLK), |
.ALU8OUT(ALU8OUT), |
.DI(DI), |
.DO(DO), |
.ADDR(ADDR), |
.CONST({2'b00, FETCH[5:3], 3'b000}), // RST address |
.ALU80(ALU80), |
.ALU81(ALU81), |
.ALU160(ALU160), |
.ALU161(ALU161), |
.ALU8FLAGS(ALU8FLAGS), |
.FLAGS(FLAGS), |
.DO_SEL(DO_SEL), |
.ALU160_sel(ALU160_SEL), |
.REG_WSEL(REG_WSEL), |
.REG_RSEL(REG_RSEL), |
.DINW_SEL(DINW_SEL), |
.ALU16OP(ALU16OP), // used for post increment for ADDR, SP mux re-direct |
.WAIT(WAIT) |
); |
|
ALU8 CPU_ALU8 ( |
.D0(ALU80), |
.D1(ALU81), |
.FIN(FLAGS), |
.FOUT(ALU8FLAGS), |
.ALU8DOUT(ALU8OUT), |
.OP(ALU8OP) |
); |
|
ALU16 CPU_ALU16 ( |
.D0(ALU160), |
.D1(ALU161), |
.DOUT(ADDR), |
.OP(ALU16OP) |
); |
|
always @(posedge CLK) |
if(!WAIT) begin |
SRESET <= RESET; |
SINT <= INT; |
if(SRESET) FETCH <= 9'b110000000; |
else |
if(FETCH[8:6] == 3'b110) {FETCH[8:7]} <= 2'b00; // exit RESET state |
else begin |
if(M1) FETCH <= {1'b0, DI}; |
if(!next_stage & SINT & CPUStatus[1] & !status[2]) {FETCH[8:6], FETCH[1:0]} <= {3'b100, HALT, M1}; // INT request |
end |
if(next_stage) STAGE <= STAGE + 1'b1; |
else STAGE <= 0; |
CPUStatus[0] <= CPUStatus[0] ^ status[0]; |
if(status[2]) CPUStatus[1] <= status[1]; // EI |
tzf <= ALU8FLAGS[6]; |
end |
|
assign opd[0] = FETCH[0] ^ &FETCH[2:1]; |
assign opd[2:1] = FETCH[2:1]; |
assign opd[3] = FETCH[3] ^ &FETCH[5:4]; |
assign opd[5:4] = FETCH[5:4]; |
assign op16[2:0] = &FETCH[5:4] ? 3'b101 : {1'b0, FETCH[5:4]}; |
|
always @* begin |
DO_SEL = 2'bxx; // ALU80 - th - flags - ALU8OUT[7:0] |
ALU160_SEL = 1'bx; // regs - pc |
DINW_SEL = 1'bx; // ALU8OUT - DI |
WE = 6'bxxxxxx; // 5 = flags, 4 = PC, 3 = SP, 2 = tmpHI, 1 = hi, 0 = lo |
ALU8OP = 5'bxxxxx; |
ALU16OP = 3'b000; // NOP, post inc |
next_stage = 0; |
REG_WSEL = 4'bxxxx; |
REG_RSEL = 4'bx0xx; // prevents default 4'b0100 which leads to incorrect P flag value in some cases (like RLA) |
M1 = 1; |
MREQ = 1; |
WR = 0; |
HALT = 0; |
IORQ = 0; |
status = 3'b000; |
|
|
case(FETCH[8:6]) |
//------------------------------------------- block 00 ---------------------------------------------------- |
3'b000: |
case(FETCH[3:0]) |
// ----------------------- NOP, EX AF, AF', DJNZ, JR, JR c -------------------- |
4'b0000, 4'b1000: |
case(FETCH[5:4]) |
2'b00: begin // NOP, EX AF, AF' |
ALU160_SEL = 1; // PC |
WE = 6'b010x00; // PC |
end |
2'b01: |
if(!STAGE[0]) begin // DJNZ, JR - stage1 |
ALU160_SEL = 1; // pc |
WE = 6'b010100; // PC, tmpHI |
ALU8OP = 5'b01010; // DEC, for tzf only |
REG_WSEL = 4'b0000; // B |
next_stage = 1; |
M1 = 0; |
end else if(FETCH[3]) begin // JR - stage2 |
ALU160_SEL = 1; // pc |
WE = 6'b010x00; // PC |
ALU16OP = 3; // ADD |
end else begin // DJNZ - stage2 |
ALU160_SEL = 1; // pc |
DINW_SEL = 0; // ALU8OUT |
WE = 6'b010x10; // PC, hi |
ALU8OP = 5'b01010; // DEC |
ALU16OP = tzf ? 3'd0 : 3'd3; // NOP/ADD |
REG_WSEL = 4'b0000; // B |
end |
2'b10, 2'b11: // JR cc, stage1, stage2 |
case({STAGE[0], FlagMux[{1'b0, FETCH[4:3]}]}) |
2'b00, 2'b11: begin |
ALU160_SEL = 1; // pc |
WE = 6'b010x00; // PC |
ALU16OP = STAGE[0] ? 3'd3 : 3'd1; // ADD/ INC, post inc |
end |
2'b01: begin |
ALU160_SEL = 1; // pc |
WE = 6'b010100; // PC, tmpHI |
next_stage = 1; |
M1 = 0; |
end |
endcase |
endcase |
// ----------------------- LD rr,nn -------------------- |
4'b0001: // LD rr,nn, stage1 |
case({STAGE[1:0], op16[2]}) |
3'b00_0, 3'b00_1, 3'b01_0, 3'b01_1: begin // LD rr,nn, stage1,2 |
ALU160_SEL = 1; // pc |
DINW_SEL = 1; // DI |
WE = {4'b010x, STAGE[0] ? 1'b1 : 1'bx, !STAGE[0]}; // PC, lo/HI |
next_stage = 1; |
REG_WSEL = {op16, 1'bx}; |
M1 = 0; |
end |
3'b10_0, 3'b11_1: begin // BC, DE, HL, stage3, SP stage4 |
ALU160_SEL = 1; // pc |
WE = 6'b010x00; // PC |
end |
3'b10_1: begin // SP stage3 |
ALU160_SEL = 0; // regs |
WE = 6'b001x00; // SP |
ALU16OP = 4; // NOP |
next_stage = 1; |
REG_RSEL = 4'b101x; // tmpSP |
M1 = 0; |
MREQ = 0; |
end |
endcase |
// ----------------------- LD (BC) A - LD (DE) A - LD (nn) HL, LD (nn),A -------------------- |
// ----------------------- LD A (BC) - LD A (DE) - LD HL (nn), LD A (nn) -------------------- |
4'b0010, 4'b1010: |
case(STAGE[2:0]) |
3'b000: |
if(FETCH[5] == 0) begin // LD (BC) A, LD (DE) A - stage1 |
if(FETCH[3]) DINW_SEL = 1; // DI |
else DO_SEL = 2'b00; // ALU80 |
ALU160_SEL = 0; // regs |
WE = {4'b000x, FETCH[3], 1'bx}; // hi |
next_stage = 1; |
REG_WSEL = FETCH[3] ? 4'b011x : 4'b0110; // A |
REG_RSEL = {op16, 1'bx}; |
M1 = 0; |
WR = !FETCH[3]; |
end else begin // LD (nn) A - LD (nn) HL - stage 1 |
ALU160_SEL = 1; // PC |
DINW_SEL = 1; // DI |
WE = 6'b010xx1; // PC, lo |
next_stage = 1; |
REG_WSEL = 4'b111x; |
M1 = 0; |
end |
3'b001: |
if(FETCH[5] == 0) begin // LD (BC), A, LD (DE), A - stage2 |
ALU160_SEL = 1; // pc |
WE = 6'b010x00; // PC |
end else begin // LD (nn),A - LH (nn),HL - stage 2 |
ALU160_SEL = 1; // pc |
DINW_SEL = 1; // DI |
WE = 6'b010x10; // PC, hi |
next_stage = 1; |
REG_WSEL = 4'b111x; |
M1 = 0; |
end |
3'b010: begin |
ALU160_SEL = 1'b0; // regs |
REG_RSEL = 4'b111x; |
M1 = 0; |
WR = !FETCH[3]; |
next_stage = 1; |
if(FETCH[3]) begin // LD A (nn) - LD HL (nn) - stage 3 |
DINW_SEL = 1; // DI |
WE = {4'b000x, FETCH[4] ? 1'b1 : 1'bx, FETCH[4] ? 1'bx : 1'b1}; // lo/hi |
REG_WSEL = FETCH[4] ? 4'b011x : 4'b010x; // A or L |
end else begin // LD (nn),A - LD (nn),HL - stage 3 |
DO_SEL = 2'b00; // ALU80 |
WE = 6'b000x00; // nothing |
REG_WSEL = FETCH[4] ? 4'b0110 : 4'b0101; // A or L |
end |
end |
3'b011: |
if(FETCH[4]) begin // LD (nn),A - stage 4 |
ALU160_SEL = 1; // pc |
WE = 6'b010x00; // PC |
end else begin |
REG_RSEL = 4'b111x; |
M1 = 0; |
WR = !FETCH[3]; |
ALU160_SEL = 1'b0; // regs |
ALU16OP = 1; // INC |
next_stage = 1; |
if(FETCH[3]) begin // LD HL (nn) - stage 4 |
DINW_SEL = 1; // DI |
WE = 6'b000x10; // hi |
REG_WSEL = 4'b010x; // H |
end else begin // LD (nn),HL - stage 4 |
DO_SEL = 2'b00; // ALU80 |
WE = 6'b000x00; // nothing |
REG_WSEL = 4'b0100; // H |
end |
end |
3'b100: begin // LD (nn),HL - stage 5 |
ALU160_SEL = 1; // pc |
WE = 6'b010x00; // PC |
end |
endcase |
// ----------------------- inc/dec rr -------------------- |
4'b0011, 4'b1011: |
if(!STAGE[0]) |
if(op16[2]) begin // SP - stage1 |
ALU160_SEL = 0; // regs |
WE = 6'b001x00; // SP |
ALU16OP = {FETCH[3], 1'b0, FETCH[3]}; // post inc, dec |
next_stage = 1; |
REG_RSEL = 4'b101x; // sp |
M1 = 0; |
MREQ = 0; |
end else begin // BC, DE, HL - stage 1 |
ALU160_SEL = 1; // pc |
DINW_SEL = 0; // ALU8OUT |
WE = 6'b010x11; // PC, hi, lo |
ALU8OP = {4'b0111, FETCH[3]}; // INC16 / DEC16 |
REG_WSEL = {op16, 1'b0}; // hi |
REG_RSEL = {op16, 1'b1}; // lo |
end |
else begin // SP, stage2 |
ALU160_SEL = 1; // pc |
WE = 6'b010x00; // PC |
end |
// ----------------------- inc/dec 8 -------------------- |
4'b0100, 4'b0101, 4'b1100, 4'b1101: |
if(!op1mem) begin //regs |
DINW_SEL = 0; // ALU8OUT |
ALU160_SEL = 1; // pc |
WE = opd[3] ? 6'b110x01 : 6'b110x10; // flags, PC, hi/lo |
ALU8OP = {3'b010, FETCH[0], 1'b0}; // inc / dec |
REG_WSEL = {1'b0, opd[5:3]}; |
end else case({STAGE[1:0]}) |
2'b00: begin // (HL) - stage1 |
ALU160_SEL = 0; // regs |
DINW_SEL = 1; // DI |
WE = 6'b000001; // lo |
ALU16OP = 3'd0; |
next_stage = 1; |
REG_WSEL = 4'b011x; // tmpLO |
REG_RSEL = 4'b010x; // HL |
M1 = 0; |
end |
2'b01: begin // (HL) stage2 |
DO_SEL = 2'b11; // ALU80OUT |
ALU160_SEL = 0; // regs |
WE = 6'b100x0x; // flags |
ALU8OP = {3'b010, FETCH[0], 1'b0}; // inc / dec |
ALU16OP = 3'd0; |
next_stage = 1; |
REG_WSEL = 4'b0111; // tmpLO |
REG_RSEL = 4'b010x; // HL |
M1 = 0; |
WR = 1; |
end |
2'b10: begin // (HL) - stage3 |
ALU160_SEL = 1; // pc |
WE = 6'b010x00; // PC |
end |
endcase |
// ----------------------- ld r/(HL), n -------------------- |
4'b0110, 4'b1110: |
case({STAGE[1:0], op1mem}) |
3'b00_0, 3'b00_1: begin // r, (HL) - stage1 (read n) |
ALU160_SEL = 1; // pc |
DINW_SEL = 1; // DI |
WE = opd[3] ? 6'b010001 : 6'b010010; // PC, hi/lo |
next_stage = 1; |
REG_WSEL = {1'b0, opd[5:4], 1'bx}; |
M1 = 0; |
end |
3'b01_0, 3'b10_1: begin // r - stage2, (HL) - stage3 |
ALU160_SEL = 1; // pc |
WE = 6'b010x00; // PC |
end |
3'b01_1: begin // (HL) - stage2 |
DO_SEL = 2'b00; // ALU80 |
ALU160_SEL = 0; // regs |
WE = 6'b000x0x; // nothing |
ALU16OP = 3'd0; |
next_stage = 1; |
REG_WSEL = 4'b0111; // tmpLO |
REG_RSEL = 4'b010x; // HL |
M1 = 0; |
WR = 1; |
end |
endcase |
// ----------------------- rlca, rrca, rla, rra, daa, cpl, scf, ccf -------------------- |
4'b0111, 4'b1111: |
case(FETCH[5:3]) |
3'b000, 3'b001, 3'b010, 3'b011, 3'b100, 3'b101: begin // rlca, rrca, rla, rra, daa, cpl |
ALU160_SEL = 1; // pc |
DINW_SEL = 0; // ALU8OUT |
WE = 6'b110x1x; // flags, PC, hi |
ALU8OP = FETCH[5] ? {2'b01, !FETCH[3], 2'b01} : {3'b110, FETCH[4:3]}; |
REG_WSEL = 4'b0110; // A |
end |
3'b110, 3'b111: begin // scf, ccf |
ALU160_SEL = 1; // pc |
DINW_SEL = 0; // ALU8OUT |
WE = 6'b110x0x; // flags, PC |
ALU8OP = {4'b1010, !FETCH[3]}; |
end |
endcase |
// ----------------------- add 16 -------------------- |
4'b1001: |
if(!STAGE[0]) begin |
DINW_SEL = 0; // ALU8OUT |
WE = 6'b100x01; // flags, lo |
ALU8OP = 5'b10000; // ADD16LO |
next_stage = 1; |
REG_WSEL = 4'b0101; // L |
REG_RSEL = {op16, 1'b1}; |
M1 = 0; |
MREQ = 0; |
end else begin |
ALU160_SEL = 1; // pc |
DINW_SEL = 0; // ALU8OUT |
WE = 6'b110x10; // flags, PC, hi |
ALU8OP = 5'b10001; // ADD16HI |
REG_WSEL = 4'b0100; // H |
REG_RSEL = {op16, 1'b0}; |
end |
endcase |
|
// ---------------------------------------------- block 01 LD8 --------------------------------------------------- |
3'b001: |
case({STAGE[0], op1mem, op0mem}) |
3'b0_00, // LD r, r 1st stage |
3'b1_01: // LD r, (HL) 2nd stage |
begin |
ALU160_SEL = 1; // PC |
DINW_SEL = 0; // ALU8 |
WE = opd[3] ? 6'b010x01 : 6'b010x10; // PC and LO or HI |
ALU8OP = 29; // PASS D1 |
REG_WSEL = {1'b0, opd[5:4], 1'bx}; |
REG_RSEL = {1'b0, opd[2:0]}; |
end |
3'b0_01: // LD r, (HL) 1st stage |
begin |
ALU160_SEL = 0; // regs |
DINW_SEL = 1; // DI |
WE = 6'b000x01; // LO |
ALU16OP = 3'd0; // ADD - NOP |
next_stage = 1; |
REG_WSEL = 4'b011x; // A - tmpLO |
REG_RSEL = 4'b010x; // HL |
M1 = 0; |
end |
3'b0_10: // LD (HL), r 1st stage |
begin |
DO_SEL = 0; // ALU80 |
ALU160_SEL = 0; // regs |
WE = 6'b000x00; // no write |
ALU16OP = 3'd0; // ADD - NOP |
next_stage = 1; |
REG_WSEL = {1'b0, opd[2:0]}; |
REG_RSEL = 4'b010x; // HL |
M1 = 0; |
WR = 1; |
end |
3'b1_10: // LD (HL), r 2nd stage |
begin |
ALU160_SEL = 1; // pc |
WE = 6'b010x00; // PC |
end |
3'b0_11: begin // HALT |
WE = 6'b000x00; // no write |
M1 = 0; |
MREQ = 0; |
HALT = 1; |
end |
endcase |
// ---------------------------------------------- block 10 arith8 --------------------------------------------------- |
3'b010: |
case({STAGE[0], op0mem}) |
2'b0_0, // OP r,r 1st stage |
2'b1_1: // OP r, (HL) 2nd stage |
begin |
ALU160_SEL = 1; // pc |
DINW_SEL = 0; // ALU8OUT |
WE = {4'b110x, ~&FETCH[5:3], 1'bx}; // flags, PC, hi |
ALU8OP = {2'b00, FETCH[5:3]}; |
REG_WSEL = 4'b0110; // A |
REG_RSEL = {1'b0, opd[2:0]}; |
end |
2'b0_1: // OP r, (HL) 1st stage |
begin |
ALU160_SEL = 0; // HL |
DINW_SEL = 1; // DI |
WE = 6'b000x01; // lo |
ALU16OP = 3'd0; // ADD - NOP |
next_stage = 1; |
REG_WSEL = 4'b011x; // A-tmpLO |
REG_RSEL = 4'b010x; // HL |
M1 = 0; |
end |
endcase |
//------------------------------------------- block 11 ---------------------------------------------------- |
3'b011: |
case(FETCH[3:0]) |
// ----------------------- RET cc -------------------- |
4'b0000, 4'b1000: |
case(STAGE[1:0]) |
2'b00, 2'b01: // stage1, stage2 |
if(FlagMux[FETCH[5:3]]) begin // POP addr |
ALU160_SEL = 0; // regs |
DINW_SEL = 1; // DI |
WE = {4'b001x, STAGE[0] ? 1'b1 : 1'bx, !STAGE[0]}; // SP, lo/hi |
next_stage = 1; |
REG_WSEL = 4'b111x; // tmp16 |
REG_RSEL = 4'b101x; // SP |
M1 = 0; |
end else begin |
ALU160_SEL = 1; // pc |
WE = 6'b010x00; // PC |
end |
2'b10: begin // stage3 |
ALU160_SEL = 0; // regs |
WE = 6'b010x00; // PC |
REG_RSEL = 4'b111x; // tmp16 |
end |
endcase |
// ----------------------- POP -------------------- |
4'b0001: |
case(STAGE[1:0]) |
2'b00, 2'b01: begin |
if(op16[2]) begin // AF |
WE = STAGE[0] ? 6'b101x1x : 6'b001xx1; // flags, SP, lo/hi |
REG_WSEL = {3'b011, STAGE[0] ? 1'b1 : 1'bx}; |
if(STAGE[0]) ALU8OP = 30; // FLAGS <- D0 |
end else begin // r16 |
WE = STAGE[0] ? 6'b001x10 : 6'b001xx1; // SP, lo/hi |
REG_WSEL = {1'b0, FETCH[5:4], 1'bx}; |
end |
ALU160_SEL = 0; // regs |
DINW_SEL = 1; // DI |
next_stage = 1; |
REG_RSEL = 4'b101x; // SP |
M1 = 0; |
end |
2'b10: begin // stage3 |
ALU160_SEL = 1; // PC |
WE = 6'b010x00; // PC |
end |
endcase |
// ----------------------- JP cc -------------------- |
4'b0010, 4'b1010: |
case(STAGE[1:0]) |
2'b00, 2'b01: begin // stage1,2 |
if(FlagMux[FETCH[5:3]]) begin |
ALU160_SEL = 1; // pc |
DINW_SEL = 1; // DI |
WE = {4'b010x, STAGE[0] ? 1'b1 : 1'bx, !STAGE[0]}; // PC, hi/lo |
next_stage = 1; |
REG_WSEL = 4'b111x; // tmp7 |
M1 = 0; |
end else begin |
ALU160_SEL = 1; // pc |
WE = 6'b010x00; // PC |
ALU16OP = 2; // add2 |
end |
end |
2'b10: begin // stage3 |
ALU160_SEL = 0; // regs |
WE = 6'b010x00; // PC |
REG_RSEL = 4'b111x; // tmp7 |
end |
endcase |
// ----------------------- JP, OUT (n) A, EX (SP) HL, DI -------------------- |
4'b0011: |
case(FETCH[5:4]) |
2'b00: // JP |
case(STAGE[1:0]) |
2'b00, 2'b01: begin // stage1,2 - read addr |
ALU160_SEL = 1; // pc |
DINW_SEL = 1; // DI |
WE = {4'b010x, STAGE[0] ? 1'b1 : 1'bx, !STAGE[0]}; // PC, hi/lo |
next_stage = 1; |
REG_WSEL = 4'b111x; // tmp7 |
M1 = 0; |
end |
2'b10: begin // stage3 |
ALU160_SEL = 0; // regs |
WE = 6'b010x00; // PC |
REG_RSEL = 4'b111x; // tmp7 |
end |
endcase |
2'b01: // OUT (n), a - stage1 - read n |
case(STAGE[1:0]) |
2'b00: begin |
ALU160_SEL = 1; // pc |
DINW_SEL = 1; // DI |
WE = 6'b010x01; // PC, lo |
next_stage = 1; |
REG_WSEL = 4'b011x; // tmpLO |
M1 = 0; |
end |
2'b01: begin // stage2 - OUT |
DO_SEL = 2'b00; // ALU80 |
ALU160_SEL = 0; // regs |
WE = 6'b000x00; // nothing |
next_stage = 1; |
REG_WSEL = 4'b0110; // A |
REG_RSEL = 4'b011x; // A-tmpLO |
M1 = 0; |
MREQ = 0; |
WR = 1; |
IORQ = 1; |
end |
2'b10: begin // stage3 - fetch |
ALU160_SEL = 1; // PC |
WE = 6'b010x00; // PC |
end |
endcase |
2'b10: // EX (SP), HL |
case(STAGE[2:0]) |
3'b000, 3'b001: begin // stage1,2 - pop tmp16 |
ALU160_SEL = 0; // regs |
DINW_SEL = 1; // DI |
WE = {4'b001x, STAGE[0] ? 1'b1 : 1'bx, !STAGE[0]}; // SP, lo/hi |
next_stage = 1; |
REG_WSEL = 4'b111x; // tmp16 |
REG_RSEL = 4'b101x; // SP |
M1 = 0; |
end |
3'b010, 3'b011: begin // stage3,4 - push hl |
DO_SEL = 2'b00; // ALU80 |
ALU160_SEL = 0; // regs |
WE = 6'b001x00; // SP |
ALU16OP = 5; // dec |
next_stage = 1; |
REG_WSEL = {3'b010, STAGE[0]};// H/L |
REG_RSEL = 4'b101x; // SP |
M1 = 0; |
WR = 1; |
end |
3'b100, 3'b101: begin // stage5,6 |
ALU160_SEL = 1; // pc |
DINW_SEL = 0; // ALU8OUT |
WE = {1'b0, STAGE[0], 2'b0x, STAGE[0] ? 1'b1 : 1'bx, !STAGE[0]}; // PC, lo/hi |
ALU8OP = 29; // pass D1 |
next_stage = !STAGE[0]; |
REG_WSEL = 4'b010x; // HL |
REG_RSEL = {3'b111, !STAGE[0]}; // tmp16 |
M1 = STAGE[0]; |
MREQ = STAGE[0]; |
end |
endcase |
2'b11: begin // DI |
ALU160_SEL = 1; // PC |
WE = 6'b010x00; // PC |
status[2:1] = 2'b10; // set EI flags |
end |
endcase |
// ----------------------- CALL cc -------------------- |
4'b0100, 4'b1100: |
case(STAGE[2:0]) |
3'b000, 3'b001: // stage 1,2 - load addr |
if(FlagMux[FETCH[5:3]]) begin |
ALU160_SEL = 1; // pc |
DINW_SEL = 1; // DI |
WE = {4'b010x, STAGE[0] ? 1'b1 : 1'bx, !STAGE[0]}; // PC, hi/lo |
next_stage = 1; |
REG_WSEL = 4'b111x; // tmp7 |
M1 = 0; |
end else begin |
ALU160_SEL = 1; // pc |
WE = 6'b010x00; // PC |
ALU16OP = 2; // add2 |
end |
3'b010, 3'b011: begin // stage 3,4 - push pc |
DO_SEL = {1'b0, STAGE[0]}; // pc hi/lo |
ALU160_SEL = 0; // regs |
WE = 6'b001x00; // SP |
ALU16OP = 5; // DEC |
next_stage = 1; |
REG_WSEL = 4'b1xxx; // pc |
REG_RSEL = 4'b101x; // sp |
M1 = 0; |
WR = 1; |
end |
3'b100: begin // stage5 |
ALU160_SEL = 0; // regs |
WE = 6'b010x00; // PC |
REG_RSEL = 4'b111x; // tmp7 |
end |
endcase |
// ----------------------- PUSH -------------------- |
4'b0101: |
case(STAGE[1:0]) |
2'b00, 2'b01: begin // stage1,2 |
DO_SEL = {STAGE[0] & op16[2], 1'b0}; // FLAGS/ALU80 |
ALU160_SEL = 0; // regs |
WE = 6'b001x00; // SP |
ALU16OP = 5; // dec |
next_stage = 1; |
REG_WSEL = {1'b0, FETCH[5:4], STAGE[0]}; |
REG_RSEL = 4'b101x; // SP |
M1 = 0; |
WR = 1; |
end |
2'b10: begin //stage3 |
ALU160_SEL = 1; // PC |
WE = 6'b010x00; // PC |
end |
endcase |
// ----------------------- op A, n -------------------- |
4'b0110, 4'b1110: |
if(!STAGE[0]) begin // stage1, read n |
ALU160_SEL = 1; // pc |
DINW_SEL = 1; // DI |
WE = 6'b010x01; // PC, lo |
next_stage = 1; |
REG_WSEL = 4'b011x; // tmpLO |
M1 = 0; |
end else begin // stage 2 |
DINW_SEL = 0; // ALU8OUT[7:0] |
ALU160_SEL = 1; // pc |
WE = {4'b110x, ~&FETCH[5:3], 1'bx}; // flags, PC, hi |
ALU8OP = {2'b00, FETCH[5:3]}; |
REG_WSEL = 4'b0110; // A |
REG_RSEL = 4'b0111; // tmpLO |
end |
// ----------------------- RST -------------------- |
4'b0111, 4'b1111: |
case(STAGE[1:0]) |
2'b00, 2'b01: begin // stage 1,2 - push pc |
DO_SEL = {1'b0, STAGE[0]}; // pc hi/lo |
ALU160_SEL = 0; // regs |
WE = 6'b001x00; // SP |
ALU16OP = 5; // DEC |
next_stage = 1; |
REG_WSEL = 4'b1xxx; // pc |
REG_RSEL = 4'b101x; // sp |
M1 = 0; |
WR = 1; |
end |
2'b10: begin // stage3 |
ALU160_SEL = 0; // regs |
WE = 6'b010x00; // PC |
REG_RSEL = 4'b110x; // const |
end |
endcase |
// ----------------------- RET, EXX, JP (HL), LD SP HL -------------------- |
4'b1001: |
case(FETCH[5:4]) |
2'b00: // RET |
case(STAGE[1:0]) |
2'b00, 2'b01: begin // stage1, stage2 - pop addr |
ALU160_SEL = 0; // regs |
DINW_SEL = 1; // DI |
WE = {4'b001x, STAGE[0] ? 1'b1 : 1'bx, !STAGE[0]}; // SP, lo/hi |
next_stage = 1; |
REG_WSEL = 4'b111x; // tmp16 |
REG_RSEL = 4'b101x; // SP |
M1 = 0; |
end |
2'b10: begin // stage3 - jump |
ALU160_SEL = 0; // regs |
WE = 6'b010x00; // PC |
REG_RSEL = 4'b111x; // tmp16 |
end |
endcase |
2'b01: begin // EXX |
ALU160_SEL = 1; // PC |
WE = 6'b010x00; // PC |
end |
2'b10: begin // JP (HL) |
ALU160_SEL = 0; // regs |
WE = 6'b010x00; // PC |
REG_RSEL = 4'b010x; // HL |
end |
2'b11: begin // LD SP,HL |
if(!STAGE[0]) begin // stage1 |
ALU160_SEL = 0; // regs |
WE = 6'b001x00; // SP |
ALU16OP = 4; // NOP, no post inc |
next_stage = 1; |
REG_RSEL = 4'b010x; // HL |
M1 = 0; |
MREQ = 0; |
end else begin // stage2 |
ALU160_SEL = 1; // pc |
WE = 6'b010x00; // PC |
end |
end |
endcase |
// ----------------------- CB, IN A (n), EX DE HL, EI -------------------- |
4'b1011: |
case(FETCH[5:4]) |
2'b00: begin // CB prefix, nop |
ALU160_SEL = 1; // PC |
WE = 6'b010000; // PC |
end |
2'b01: // IN A, (n) |
case(STAGE[1:0]) |
2'b00: begin //stage1 - read n |
ALU160_SEL = 1; // pc |
DINW_SEL = 1; // DI |
WE = 6'b010x01; // PC, lo |
next_stage = 1; |
REG_WSEL = 4'b011x; // tmpLO |
M1 = 0; |
end |
2'b01: begin // stage2 - IN |
ALU160_SEL = 0; // regs |
DINW_SEL = 1; // DI |
WE = 6'b000x1x; // hi |
next_stage = 1; |
REG_WSEL = 4'b011x; // A |
REG_RSEL = 4'b011x; // A - tmpLO |
M1 = 0; |
MREQ = 0; |
IORQ = 1; |
end |
2'b10: begin // stage3 - fetch |
ALU160_SEL = 1; // PC |
WE = 6'b010x00; // PC |
end |
endcase |
2'b10: begin // EX DE, HL |
ALU160_SEL = 1; // PC |
WE = 6'b010x00; // PC |
status[0] = 1; |
end |
2'b11: begin // EI |
ALU160_SEL = 1; // PC |
WE = 6'b010x00; // PC |
status[2:1] = 2'b11; |
end |
endcase |
// ----------------------- CALL , DD, ED, FD -------------------- |
4'b1101: |
case(FETCH[5:4]) |
2'b00: // CALL |
case(STAGE[2:0]) |
3'b000, 3'b001: begin // stage 1,2 - load addr |
ALU160_SEL = 1; // pc |
DINW_SEL = 1; // DI |
WE = {4'b010x, STAGE[0] ? 1'b1 : 1'bx, !STAGE[0]}; // PC, hi/lo |
next_stage = 1; |
REG_WSEL = 4'b111x; // tmp7 |
M1 = 0; |
end |
3'b010, 3'b011: begin // stage 3,4 - push pc |
DO_SEL = {1'b0, STAGE[0]}; // pc hi/lo |
ALU160_SEL = 0; // regs |
WE = 6'b001x00; // SP |
ALU16OP = 5; // DEC |
next_stage = 1; |
REG_WSEL = 4'b1xxx; // pc |
REG_RSEL = 4'b101x; // sp |
M1 = 0; |
WR = 1; |
end |
3'b100: begin // stage5 - jump |
ALU160_SEL = 0; // regs |
WE = 6'b010x00; // PC |
REG_RSEL = 4'b111x; // tmp7 |
end |
endcase |
2'b01, 2'b10, 2'b11: begin // DD - IX, ED, FD - IY |
ALU160_SEL = 1; // PC |
WE = 6'b010x00; // PC |
end |
endcase |
endcase |
|
//------------------------------------------- // RST, INT ---------------------------------------------------- |
3'b110: begin // RESET: DI, pC <- 0 |
ALU160_SEL = 0; // regs |
WE = 6'bx1xx00; // PC |
ALU16OP = 4; // NOP |
REG_RSEL = 4'b110x; // const |
M1 = 0; |
MREQ = 0; |
status[2:1] = 2'b10; // DI |
end |
3'b100: begin // INT |
ALU160_SEL = 1; // pc |
WE = 6'b010x00; // PC |
ALU16OP = FETCH[1] ? 4 : 5; // NOP(HALT)/DEC(else) |
MREQ = 0; |
IORQ = 1; |
status[2:1] = 2'b10; // DI |
end |
endcase |
end |
|
endmodule |
|
//FLAGS: S Z X1 N X2 PV N C |
// OP[4:0] |
// 00000 - ADD D0,D1 |
// 00001 - ADC D0,D1 |
// 00010 - SUB D0,D1 |
// 00011 - SBC D0,D1 |
// 00100 - AND D0,D1 |
// 00101 - XOR D0,D1 |
// 00110 - OR D0,D1 |
// 00111 - CP D0,D1 |
// 01000 - INC D0 |
// 01001 - CPL D0 |
// 01010 - DEC D0 |
// 01101 - DAA=CPL |
// 01110 - INC16 |
// 01111 - DEC16 |
// 10000 - ADD16LO |
// 10001 - ADD16HI |
// 10010 - |
// 10011 - |
// 10100 - CCF, pass D0 |
// 10101 - SCF, pass D0 |
// 10110 - |
// 10111 - |
// 11000 - RLCA D0 |
// 11001 - RRCA D0 |
// 11010 - RLA D0 |
// 11011 - RRA D0 |
// 11101 - IN, pass D1 |
// 11110 - FLAGS <- D0 |
/////////////////////////////////////////////////////////////////////////////////// |
module ALU8( |
input [7:0]D0, |
input [7:0]D1, |
input [7:0]FIN, |
input [4:0]OP, |
|
output reg[7:0]FOUT, |
output reg [15:0]ALU8DOUT |
); |
|
wire parity = ~^ALU8DOUT[15:8]; |
wire zero = ~|ALU8DOUT[15:8]; |
reg cin; |
reg [7:0]_d1mux; |
wire [7:0]d1mux = OP[1] ? ~_d1mux : _d1mux; |
wire [8:0]sum = D0 + d1mux + cin; |
wire overflow = (D0[7] & d1mux[7] & !sum[7]) | (!D0[7] & !d1mux[7] & sum[7]); |
wire [7:0]log; |
reg [3:0]logop; |
wire csin = OP[1] ? FIN[0] : OP[0] ? D0[0] : D0[7]; |
wire [7:0]shift = OP[0] ? {csin, D0[7:1]} : {D0[6:0], csin}; |
wire [15:0]inc16 = OP[0] ? {D0, D1} - 1'b1 : {D0, D1} + 1'b1; |
|
LOG8 log8_unit |
( |
.A(D0), |
.B(D1), |
.O(log), |
.op(logop) |
); |
|
always @* begin |
ALU8DOUT = {sum[7:0], sum[7:0]}; |
logop = 4'bxxxx; |
case({OP[4:2]}) |
0,1,4,7: _d1mux = D1; |
default: _d1mux = 8'h01; |
endcase |
case({OP[2:0], FIN[0]}) |
0,1,2,7,8,9,10,11,12,13: cin = 0; |
3,4,5,6,14,15: cin = 1; |
endcase |
|
FOUT = {FIN[7:6], 3'b000, FIN[2], 1'b0, FIN[0]}; |
case(OP[4:0]) |
0,1,2,3,8,10: begin // ADD, ADC, SUB, SBC, INC, DEC |
FOUT[0] = OP[3] ? FIN[0] : (sum[8] ^ OP[1]); // inc/dec |
FOUT[2] = overflow; |
FOUT[6] = zero; |
FOUT[7] = ALU8DOUT[15]; |
end |
16,17: begin // ADD16LO, ADD16HI |
FOUT[0] = sum[8]; |
end |
7: begin // CP |
FOUT[0] = !sum[8]; |
FOUT[2] = overflow; |
FOUT[6] = zero; |
FOUT[7] = ALU8DOUT[15]; |
end |
4,5,6: begin //AND, XOR, OR |
ALU8DOUT = {log, log}; |
logop = OP[0] ? 4'b0110 : OP[1] ? 4'b1110 : 4'b1000; |
FOUT[0] = 0; |
FOUT[2] = parity; |
FOUT[6] = zero; |
FOUT[7] = ALU8DOUT[15]; |
end |
9,13: begin // CPL |
ALU8DOUT = {log, log}; |
logop = 4'b0011; // ~D0 |
FOUT[0] = FIN[0]; |
end |
14,15: begin // inc/dec 16 |
ALU8DOUT = inc16; |
FOUT[2] = ALU8DOUT != 0; |
end |
20,21: begin // CCF, SCF |
ALU8DOUT = {log, log}; |
logop = 4'b1100; // D0 |
FOUT[0] = OP[0] ? 1'b1 : !FIN[0]; |
end |
24,25,26,27: begin // ROT |
ALU8DOUT[15:8] = {shift, shift}; |
FOUT[0] = OP[0] ? D0[0] : D0[7]; |
end |
29: begin // IN, pass D1 |
ALU8DOUT = {log, log}; |
logop = 4'b1010; // D1 |
FOUT[2] = parity; |
FOUT[6] = zero; |
FOUT[7] = ALU8DOUT[15]; |
end |
30: {FOUT[7:6], FOUT[2], FOUT[0]} = {D0[7:6], D0[2], D0[0]}; // FLAGS <- D0 |
default:; |
endcase |
end |
endmodule |
|
module LOG8( |
input [7:0]A, |
input [7:0]B, |
input [3:0]op, // 0=0, 1=~(A|B), 2=~A&B, 3=~A, 4=A&~B, 5=~B, 6=A^B, 7=~(A&B), 8=A&B, 9=~(A^B), 10=B, 11=~A|B, 12=A, 13=A|~B, 14=A|B, 15=-1 |
|
output [7:0]O |
); |
|
assign O[0] = op[{A[0], B[0]}]; |
assign O[1] = op[{A[1], B[1]}]; |
assign O[2] = op[{A[2], B[2]}]; |
assign O[3] = op[{A[3], B[3]}]; |
assign O[4] = op[{A[4], B[4]}]; |
assign O[5] = op[{A[5], B[5]}]; |
assign O[6] = op[{A[6], B[6]}]; |
assign O[7] = op[{A[7], B[7]}]; |
endmodule |
|
module ALU16( |
input [15:0]D0, |
input [7:0]D1, |
input [2:0]OP, // 0-NOP, 1-INC, 2-INC2, 3-ADD, 4-NOP, 5-DEC, 6-DEC2 |
|
output wire[15:0] DOUT |
); |
|
reg [7:0] mux; |
always @* |
case(OP) |
0: mux = 8'd0; // post inc |
1: mux = 8'd1; // post inc |
2: mux = 8'd2; // post inc |
3: mux = D1; // post inc |
4: mux = 8'd0; // no post inc |
5: mux = -8'd1; // no post inc |
6: mux = -8'd2; // no post inc |
7: mux = 8'dx; |
endcase |
|
assign DOUT = D0 + {{8{mux[7]}}, mux}; |
endmodule |
|
module Z80Reg( |
input rstatus, // hl-de |
input M1, |
input [5:0]WE, // 5 = flags, 4 = PC, 3 = SP, 2 = tmpHI, 1 = hi, 0 = lo |
input CLK, |
input [15:0]ALU8OUT, // CPU data out bus (output of alu8) |
input [7:0]DI, // CPU data in bus |
input [15:0]ADDR, // CPU addr bus |
input [7:0]CONST, |
input [7:0]ALU8FLAGS, |
input [1:0]DO_SEL, // select DO betwen ALU8OUT lo and th register |
input ALU160_sel, // 0=REG_RSEL, 1=PC |
input [3:0]REG_WSEL, // rdow: [3:1] 0=BC, 1=DE, 2=HL, 3=A-TL, 4=I-x ----- [0] = 0HI,1LO |
input [3:0]REG_RSEL, // mux_rdor: [3:1] 0=BC, 1=DE, 2=HL, 3=A-TL, 4=I-R, 5=SP, 7=tmp ----- [0] = 0HI, 1LO |
input DINW_SEL, // select RAM write data between (0)ALU8OUT, and 1(DI) |
input [2:0]ALU16OP, // ALU16OP |
input WAIT, // wait |
|
output reg [7:0]DO, // CPU data out bus |
output reg [7:0]ALU80, |
output reg [7:0]ALU81, |
output reg [15:0]ALU160, |
output [7:0]ALU161, |
output [7:0]FLAGS |
); |
|
// latch registers |
reg [15:0]pc=0; // program counter |
reg [15:0]sp; // stack pointer |
reg [7:0]flg = 0; |
reg [7:0]th; // temp high |
|
// internal wires |
wire [15:0]rdor; // R out from RAM |
wire [15:0]rdow; // W out from RAM |
wire [2:0]SELW; // RAM W port sel |
wire [2:0]SELR; // RAM R port sel |
reg [15:0]DIN; // RAM W in data |
reg [15:0]mux_rdor; // (3)A reversed mixed with TL, (4)I mixed with R (5)SP |
|
//------------------------------------ RAM block registers ---------------------------------- |
// 0:BC, 1:DE, 2:HL, 3:A-x, 4:BC', 5:DE', 6:HL', 7:A'-x, 8:tmp |
RAM16X8D_regs regs_lo ( |
.DPO(rdor[7:0]), // Read-only data output |
.SPO(rdow[7:0]), // R/W data output |
.A(SELW), // R/W address |
.D(DIN[7:0]), // Write data input |
.DPRA(SELR), // Read-only address |
.WCLK(CLK), // Write clock input |
.WE(WE[0] & !WAIT) // Write enable input |
); |
|
RAM16X8D_regs regs_hi ( |
.DPO(rdor[15:8]), // Read-only data output |
.SPO(rdow[15:8]), // R/W data output |
.A(SELW), // R/W address |
.D(DIN[15:8]), // Write data input |
.DPRA(SELR), // Read-only address |
.WCLK(CLK), // Write clock input |
.WE(WE[1] & !WAIT) // Write enable input |
); |
|
wire [15:0]ADDR1 = ADDR + !ALU16OP[2]; // address post increment |
always @(posedge CLK) |
if(!WAIT) begin |
if(WE[2]) th <= DI; |
if(WE[3]) sp <= ADDR1; |
if(WE[4]) pc <= ADDR1; |
if(WE[5]) flg <= ALU8FLAGS; |
end |
|
assign ALU161 = th; |
assign FLAGS = flg; |
|
always @* begin |
DIN = DINW_SEL ? {DI, DI} : ALU8OUT; |
ALU80 = REG_WSEL[0] ? rdow[7:0] : rdow[15:8]; |
ALU81 = REG_RSEL[0] ? mux_rdor[7:0] : mux_rdor[15:8]; |
ALU160 = ALU160_sel ? pc : mux_rdor; |
|
case({REG_WSEL[3], DO_SEL}) |
0: DO = ALU80; |
1: DO = th; |
2: DO = FLAGS; |
3: DO = ALU8OUT[7:0]; |
4: DO = pc[15:8]; |
5: DO = pc[7:0]; |
6: DO = sp[15:8]; |
7: DO = sp[7:0]; |
endcase |
case({ALU16OP == 4, REG_RSEL[3:0]}) |
5'b01010, 5'b01011: mux_rdor = sp; |
5'b01100, 5'b01101, 5'b11100, 5'b11101: mux_rdor = {8'b0, CONST}; |
default: mux_rdor = rdor; |
endcase |
end |
|
RegSelect WSelectW(.SEL(REG_WSEL[3:1]), .RAMSEL(SELW), .rstatus(rstatus)); |
RegSelect WSelectR(.SEL(REG_RSEL[3:1]), .RAMSEL(SELR), .rstatus(rstatus)); |
|
endmodule |
|
|
module RegSelect( |
input [2:0]SEL, |
input rstatus, // 2=hl-de |
|
output reg [2:0]RAMSEL |
); |
|
always @* begin |
case(SEL) |
0: RAMSEL = 3'b000; // BC |
1: RAMSEL = rstatus ? 3'b010 : 3'b001; // HL - DE |
2: RAMSEL = rstatus ? 3'b001 : 3'b010; // DE - HL |
3: RAMSEL = 3'b011; // A-TL |
4: RAMSEL = 3'b100; // I-R |
5: RAMSEL = 3'b100; // tmp SP |
6: RAMSEL = 3'b100; // zero |
7: RAMSEL = 3'b100; // temp |
endcase |
end |
endmodule |
|
module RAM16X8D_regs( |
input [2:0]A, // R/W address |
input [7:0]D, // Write data input |
input [2:0]DPRA, // Read-only address |
input WCLK, // Write clock |
input WE, // Write enable |
|
output [7:0]DPO, // Read-only data output |
output [7:0]SPO // R/W data output |
); |
|
reg [7:0]data[4:0]; |
assign DPO = data[DPRA]; |
assign SPO = data[A]; |
|
always @(posedge WCLK) |
if(WE) data[A] <= D; |
|
endmodule |
|
/nextz80/trunk/NextZ80CPU.v
7,6 → 7,7
// Description: Implementation of Z80 compatible CPU |
// Version 1.0 |
// Creation date: 28Jan2011 - 18Mar2011 |
// Updated: 04Jan2019 - single file |
// |
// Author: Nicolae Dumitrache |
// e-mail: ndumitrache@opencores.org |
39,7 → 40,6
/////////////////////////////////////////////////////////////////////////////////// |
// |
// Comments: |
// This project was developed and tested on a XILINX Spartan3AN board. |
// |
// NextZ80 processor features: |
// All documented/undocumented intstructions are implemented |
53,8 → 53,7
// Fast block instructions: LDxR - 3 T states/byte, INxR/OTxR - 2 T states/byte, CPxR - 4 T states / byte |
// Each CPU machine cycle takes (mainly) one clock T state. This makes this processor over 4 times faster than a Z80 at the same |
// clock frequency (some instructions are up to 10 times faster). |
// Works at ~40MHZ on Spartan XC3S700AN speed grade -4) |
// Small size ( ~12% ~700 slices - on Spartan XC3S700AN ) |
// Up to 70MHZ on Spartan6 speed grade -2, ~800 LUT6 |
// Tested with ZEXDOC (fully compliant). |
// Tested with ZEXALL (all OK except CPx(R), LDx(R), BIT n, (IX/IY+d), BIT n, (HL) - fail because of the un-documented XF and YF flags). |
// |
63,19 → 62,20
|
module NextZ80 |
( |
input wire[7:0] DI, |
output wire[7:0] DO, |
output wire[15:0] ADDR, |
input [7:0]DI, |
input CLK, |
input RESET, |
input INT, |
input NMI, |
input WAIT, |
|
output [7:0]DO, |
output [15:0]ADDR, |
output reg WR, |
output reg MREQ, |
output reg IORQ, |
output reg HALT, |
output reg M1, |
input wire CLK, |
input wire RESET, |
input wire INT, |
input wire NMI, |
input wire WAIT |
output reg M1 |
); |
|
// connections and registers |
123,15 → 123,9
.CLK(CLK), |
.ALU8OUT(ALU8OUT), |
.DI(DI), |
.DO(DO), |
.ADDR(ADDR), |
.CONST(FETCH[7] ? {2'b00, FETCH[5:3], 3'b000} : 8'h66), // RST/NMI address |
.ALU80(ALU80), |
.ALU81(ALU81), |
.ALU160(ALU160), |
.ALU161(ALU161), |
.ALU8FLAGS(ALU8FLAGS), |
.FLAGS(FLAGS), |
.DO_SEL(DO_SEL), |
.ALU160_sel(ALU160_SEL), |
.REG_WSEL(REG_WSEL), |
139,7 → 133,14
.DINW_SEL(DINW_SEL), |
.XMASK(xmask), |
.ALU16OP(ALU16OP), // used for post increment for ADDR, SP mux re-direct |
.WAIT(WAIT) |
.WAIT(WAIT), |
|
.DO(DO), |
.ALU80(ALU80), |
.ALU81(ALU81), |
.ALU160(ALU160), |
.ALU161(ALU161), |
.FLAGS(FLAGS) |
); |
|
ALU8 CPU_ALU8 ( |
146,19 → 147,21
.D0(ALU80), |
.D1(ALU81), |
.FIN(FLAGS), |
.FOUT(ALU8FLAGS), |
.ALU8DOUT(ALU8OUT), |
.OP(ALU8OP), |
.EXOP(FETCH[8:3]), |
.LDIFLAGS(REG_WSEL[2]), // inc16 HL |
.DSTHI(!REG_WSEL[0]) |
.DSTHI(!REG_WSEL[0]), |
|
.FOUT(ALU8FLAGS), |
.ALU8DOUT(ALU8OUT) |
); |
|
ALU16 CPU_ALU16 ( |
.D0(ALU160), |
.D1(ALU161), |
.DOUT(ADDR), |
.OP(ALU16OP) |
.OP(ALU16OP), |
|
.DOUT(ADDR) |
); |
|
always @(posedge CLK) |
208,7 → 211,7
ALU16OP = 3'b000; // NOP, post inc |
next_stage = 0; |
REG_WSEL = 4'bxxxx; |
REG_RSEL = 4'bx0xx; // prevents default 4'b0100 which leads to incorrect P flag value in some cases (like RLA) |
REG_RSEL = 4'bx0xx; // prevents default 4'b0100 which leads to incorrect P flag value in some cases (like RLA) |
M1 = 1; |
MREQ = 1; |
WR = 0; |
241,8 → 244,8
ALU160_SEL = 1; // pc |
WE = 6'b010100; // PC, tmpHI |
if(!FETCH[3]) begin |
ALU8OP = 5'b01010; // DEC, for tzf only |
REG_WSEL = 4'b0000; // B |
ALU8OP = 5'b01010; // DEC, for tzf only |
REG_WSEL = 4'b0000; // B |
end |
next_stage = 1; |
M1 = 0; |
250,7 → 253,7
ALU160_SEL = 1; // pc |
WE = 6'b010x00; // PC |
ALU16OP = 3; // ADD |
end else begin // DJNZ - stage2 |
end else begin // DJNZ - stage2 |
ALU160_SEL = 1; // pc |
DINW_SEL = 0; // ALU8OUT |
WE = 6'b010x10; // PC, hi |
261,13 → 264,13
2'b10, 2'b11: // JR cc, stage1, stage2 |
case({STAGE[0], FlagMux[{1'b0, FETCH[4:3]}]}) |
2'b00, 2'b11: begin |
ALU160_SEL = 1; // pc |
WE = 6'b010x00; // PC |
ALU160_SEL = 1; // pc |
WE = 6'b010x00; // PC |
ALU16OP = STAGE[0] ? 3'd3 : 3'd1; // ADD/ INC, post inc |
end |
2'b01: begin |
ALU160_SEL = 1; // pc |
WE = 6'b010100; // PC, tmpHI |
ALU160_SEL = 1; // pc |
WE = 6'b010100; // PC, tmpHI |
next_stage = 1; |
M1 = 0; |
end |
288,7 → 291,7
ALU160_SEL = 1; // pc |
WE = 6'b010x00; // PC |
end |
3'b10_1: begin // SP stage3 |
3'b10_1: begin // SP stage3 |
ALU160_SEL = 0; // regs |
WE = 6'b001x00; // SP |
ALU16OP = 4; // NOP |
304,8 → 307,8
case(STAGE[2:0]) |
3'b000: |
if(FETCH[5] == 0) begin // LD (BC) A, LD (DE) A - stage1 |
if(FETCH[3]) DINW_SEL = 1; // DI |
else DO_SEL = 2'b00; // ALU80 |
if(FETCH[3]) DINW_SEL = 1; // DI |
else DO_SEL = 2'b00; // ALU80 |
ALU160_SEL = 0; // regs |
WE = {4'b000x, FETCH[3], 1'bx}; // hi |
next_stage = 1; |
340,12 → 343,12
WR = !FETCH[3]; |
next_stage = 1; |
if(FETCH[3]) begin // LD A (nn) - LD HL (nn) - stage 3 |
DINW_SEL = 1; // DI |
DINW_SEL = 1; // DI |
WE = {4'b000x, FETCH[4] ? 1'b1 : 1'bx, FETCH[4] ? 1'bx : 1'b1}; // lo/hi |
REG_WSEL = FETCH[4] ? 4'b011x : 4'b010x; // A or L |
end else begin // LD (nn),A - LD (nn),HL - stage 3 |
DO_SEL = 2'b00; // ALU80 |
WE = 6'b000x00; // nothing |
DO_SEL = 2'b00; // ALU80 |
WE = 6'b000x00;// nothing |
REG_WSEL = FETCH[4] ? 4'b0110 : 4'b0101; // A or L |
end |
end |
360,19 → 363,19
ALU160_SEL = 1'b0; // regs |
ALU16OP = 1; // INC |
next_stage = 1; |
if(FETCH[3]) begin // LD HL (nn) - stage 4 |
DINW_SEL = 1; // DI |
WE = 6'b000x10; // hi |
REG_WSEL = 4'b010x; // H |
end else begin // LD (nn),HL - stage 4 |
DO_SEL = 2'b00; // ALU80 |
WE = 6'b000x00; // nothing |
REG_WSEL = 4'b0100; // H |
if(FETCH[3]) begin // LD HL (nn) - stage 4 |
DINW_SEL = 1; // DI |
WE = 6'b000x10;// hi |
REG_WSEL = 4'b010x; // H |
end else begin // LD (nn),HL - stage 4 |
DO_SEL = 2'b00; // ALU80 |
WE = 6'b000x00;// nothing |
REG_WSEL = 4'b0100; // H |
end |
end |
3'b100: begin // LD (nn),HL - stage 5 |
ALU160_SEL = 1; // pc |
WE = 6'b010x00; // PC |
ALU160_SEL = 1; // pc |
WE = 6'b010x00;// PC |
end |
endcase |
// ----------------------- inc/dec rr -------------------- |
394,7 → 397,7
REG_WSEL = {op16, 1'b0}; // hi |
REG_RSEL = {op16, 1'b1}; // lo |
end |
else begin // SP, stage2 |
else begin // SP, stage2 |
ALU160_SEL = 1; // pc |
WE = 6'b010x00; // PC |
end |
403,7 → 406,7
if(!op1mem) begin //regs |
DINW_SEL = 0; // ALU8OUT |
ALU160_SEL = 1; // pc |
WE = opd[3] ? 6'b110x01 : 6'b110x10; // flags, PC, hi/lo |
WE = opd[3] ? 6'b110x01 : 6'b110x10;// flags, PC, hi/lo |
ALU8OP = {3'b010, FETCH[0], 1'b0}; // inc / dec |
REG_WSEL = {1'b0, opd[5:3]}; |
end else case({STAGE[1:0], CPUStatus[4]}) |
423,21 → 426,21
next_stage = 1; |
M1 = 0; |
end |
3'b01_0, 3'b10_1: begin // (HL) stage2, (X) - stage3 |
DO_SEL = 2'b11; // ALU80OUT |
ALU160_SEL = 0; // regs |
WE = 6'b100x0x; // flags |
3'b01_0, 3'b10_1: begin // (HL) stage2, (X) - stage3 |
DO_SEL = 2'b11; // ALU80OUT |
ALU160_SEL = 0; // regs |
WE = 6'b100x0x; // flags |
ALU8OP = {3'b010, FETCH[0], 1'b0}; // inc / dec |
ALU16OP = CPUStatus[4] ? 3'd3 : 3'd0; |
next_stage = 1; |
REG_WSEL = 4'b0111; // tmpLO |
REG_RSEL = 4'b010x; // HL |
REG_WSEL = 4'b0111; // tmpLO |
REG_RSEL = 4'b010x; // HL |
M1 = 0; |
WR = 1; |
end |
3'b10_0, 3'b11_1: begin // (HL) - stage3, (X) - stage 4 |
ALU160_SEL = 1; // pc |
WE = 6'b010x00; // PC |
3'b10_0, 3'b11_1: begin // (HL) - stage3, (X) - stage 4 |
ALU160_SEL = 1; // pc |
WE = 6'b010x00; // PC |
end |
endcase |
// ----------------------- ld r/(HL-X), n -------------------- |
637,7 → 640,7
if(op16[2]) begin // AF |
WE = STAGE[0] ? 6'b101x1x : 6'b001xx1; // flags, SP, lo/hi |
REG_WSEL = {3'b011, STAGE[0] ? 1'b1 : 1'bx}; |
if(STAGE[0]) ALU8OP = 30; // FLAGS <- D0 |
if(STAGE[0]) ALU8OP = 30; // FLAGS <- D0 |
end else begin // r16 |
WE = STAGE[0] ? 6'b001x10 : 6'b001xx1; // SP, lo/hi |
REG_WSEL = {1'b0, FETCH[5:4], 1'bx}; |
671,9 → 674,9
end |
end |
2'b10: begin // stage3 |
ALU160_SEL = 0; // regs |
WE = 6'b010x00; // PC |
REG_RSEL = 4'b111x; // tmp7 |
ALU160_SEL = 0; // regs |
WE = 6'b010x00; // PC |
REG_RSEL = 4'b111x; // tmp7 |
end |
endcase |
// ----------------------- JP, OUT (n) A, EX (SP) HL, DI -------------------- |
682,36 → 685,36
2'b00: // JP |
case(STAGE[1:0]) |
2'b00, 2'b01: begin // stage1,2 - read addr |
ALU160_SEL = 1; // pc |
DINW_SEL = 1; // DI |
ALU160_SEL = 1; // pc |
DINW_SEL = 1; // DI |
WE = {4'b010x, STAGE[0] ? 1'b1 : 1'bx, !STAGE[0]}; // PC, hi/lo |
next_stage = 1; |
REG_WSEL = 4'b111x; // tmp7 |
REG_WSEL = 4'b111x; // tmp7 |
M1 = 0; |
end |
2'b10: begin // stage3 |
ALU160_SEL = 0; // regs |
WE = 6'b010x00; // PC |
REG_RSEL = 4'b111x; // tmp7 |
ALU160_SEL = 0; // regs |
WE = 6'b010x00; // PC |
REG_RSEL = 4'b111x; // tmp7 |
end |
endcase |
2'b01: // OUT (n), a - stage1 - read n |
case(STAGE[1:0]) |
2'b00: begin |
ALU160_SEL = 1; // pc |
DINW_SEL = 1; // DI |
WE = 6'b010x01; // PC, lo |
ALU160_SEL = 1; // pc |
DINW_SEL = 1; // DI |
WE = 6'b010x01; // PC, lo |
next_stage = 1; |
REG_WSEL = 4'b011x; // tmpLO |
REG_WSEL = 4'b011x; // tmpLO |
M1 = 0; |
end |
2'b01: begin // stage2 - OUT |
DO_SEL = 2'b00; // ALU80 |
ALU160_SEL = 0; // regs |
WE = 6'b000x00; // nothing |
DO_SEL = 2'b00; // ALU80 |
ALU160_SEL = 0; // regs |
WE = 6'b000x00; // nothing |
next_stage = 1; |
REG_WSEL = 4'b0110; // A |
REG_RSEL = 4'b011x; // A-tmpLO |
REG_WSEL = 4'b0110; // A |
REG_RSEL = 4'b011x; // A-tmpLO |
M1 = 0; |
MREQ = 0; |
WR = 1; |
718,35 → 721,35
IORQ = 1; |
end |
2'b10: begin // stage3 - fetch |
ALU160_SEL = 1; // PC |
WE = 6'b010x00; // PC |
ALU160_SEL = 1; // PC |
WE = 6'b010x00; // PC |
end |
endcase |
2'b10: // EX (SP), HL |
case(STAGE[2:0]) |
3'b000, 3'b001: begin // stage1,2 - pop tmp16 |
ALU160_SEL = 0; // regs |
DINW_SEL = 1; // DI |
ALU160_SEL = 0; // regs |
DINW_SEL = 1; // DI |
WE = {4'b001x, STAGE[0] ? 1'b1 : 1'bx, !STAGE[0]}; // SP, lo/hi |
next_stage = 1; |
REG_WSEL = 4'b111x; // tmp16 |
REG_RSEL = 4'b101x; // SP |
REG_WSEL = 4'b111x; // tmp16 |
REG_RSEL = 4'b101x; // SP |
M1 = 0; |
end |
3'b010, 3'b011: begin // stage3,4 - push hl |
DO_SEL = 2'b00; // ALU80 |
ALU160_SEL = 0; // regs |
WE = 6'b001x00; // SP |
ALU16OP = 5; // dec |
DO_SEL = 2'b00; // ALU80 |
ALU160_SEL = 0; // regs |
WE = 6'b001x00; // SP |
ALU16OP = 5; // dec |
next_stage = 1; |
REG_WSEL = {3'b010, STAGE[0]};// H/L |
REG_RSEL = 4'b101x; // SP |
REG_RSEL = 4'b101x; // SP |
M1 = 0; |
WR = 1; |
end |
3'b100, 3'b101: begin // stage5,6 |
ALU160_SEL = 1; // pc |
DINW_SEL = 0; // ALU8OUT |
ALU160_SEL = 1; // pc |
DINW_SEL = 0; // ALU8OUT |
WE = {1'b0, STAGE[0], 2'b0x, STAGE[0] ? 1'b1 : 1'bx, !STAGE[0]}; // PC, lo/hi |
ALU8OP = 29; // pass D1 |
next_stage = !STAGE[0]; |
806,7 → 809,7
ALU16OP = 5; // dec |
next_stage = 1; |
REG_WSEL = {1'b0, FETCH[5:4], STAGE[0]}; |
REG_RSEL = 4'b101x; // SP |
REG_RSEL = 4'b101x; // SP |
M1 = 0; |
WR = 1; |
end |
858,18 → 861,18
2'b00: // RET |
case(STAGE[1:0]) |
2'b00, 2'b01: begin // stage1, stage2 - pop addr |
ALU160_SEL = 0; // regs |
DINW_SEL = 1; // DI |
ALU160_SEL = 0; // regs |
DINW_SEL = 1; // DI |
WE = {4'b001x, STAGE[0] ? 1'b1 : 1'bx, !STAGE[0]}; // SP, lo/hi |
next_stage = 1; |
REG_WSEL = 4'b111x; // tmp16 |
REG_RSEL = 4'b101x; // SP |
REG_WSEL = 4'b111x; // tmp16 |
REG_RSEL = 4'b101x; // SP |
M1 = 0; |
end |
2'b10: begin // stage3 - jump |
ALU160_SEL = 0; // regs |
WE = 6'b010x00; // PC |
REG_RSEL = 4'b111x; // tmp16 |
ALU160_SEL = 0; // regs |
WE = 6'b010x00; // PC |
REG_RSEL = 4'b111x; // tmp16 |
end |
endcase |
2'b01: begin // EXX |
1358,7 → 1361,7
DINW_SEL = 0; // ALU8OUT |
ALU160_SEL = 1; // pc |
WE = {!FETCH[7], 3'b10x, FETCH[7:6] == 2'b01 ? 2'b00 : {!opd[0], opd[0]}}; // flags, hi/lo |
ALU8OP = 28; // BIT |
ALU8OP = 28; // BIT |
REG_WSEL = {1'b0, opd[2:0]}; |
end |
4'b00_0_1, 4'b00_1_0, 4'b00_1_1: begin // stage1, (HL-X) - read data |
1365,7 → 1368,7
ALU160_SEL = 0; // regs |
DINW_SEL = 1; // DI |
WE = opd[0] ? 6'b000001 : 6'b000010; // lo/hi |
ALU16OP = CPUStatus[4] ? 3'd3 : 3'd0; // ADD - NOP |
ALU16OP = CPUStatus[4] ? 3'd3 : 3'd0; // ADD - NOP |
next_stage = 1; |
REG_WSEL = FETCH[7:6] == 2'b01 ? 4'b111x : {1'b0, opd[2:0]}; // dest, tmp16 for BIT |
REG_RSEL = 4'b010x; // HL |
1497,3 → 1500,524
end |
|
endmodule |
|
module Z80Reg( |
input [7:0]rstatus, // 0=af-af', 1=exx, 2=hl-de, 3=hl'-de',4=hl-ixy, 5=ix-iy, 6=IFF1, 7=IFF2 |
input M1, |
input [5:0]WE, // 5 = flags, 4 = PC, 3 = SP, 2 = tmpHI, 1 = hi, 0 = lo |
input CLK, |
input [15:0]ALU8OUT, // CPU data out bus (output of alu8) |
input [7:0]DI, // CPU data in bus |
input [15:0]ADDR, // CPU addr bus |
input [7:0]CONST, |
input [7:0]ALU8FLAGS, |
input [1:0]DO_SEL, // select DO betwen ALU8OUT lo and th register |
input ALU160_sel, // 0=REG_RSEL, 1=PC |
input [3:0]REG_WSEL, // rdow: [3:1] 0=BC, 1=DE, 2=HL, 3=A-TL, 4=I-x ----- [0] = 0HI,1LO |
input [3:0]REG_RSEL, // mux_rdor: [3:1] 0=BC, 1=DE, 2=HL, 3=A-TL, 4=I-R, 5=SP, 7=tmpSP ----- [0] = 0HI, 1LO |
input DINW_SEL, // select RAM write data between (0)ALU8OUT, and 1(DI) |
input XMASK, // 0 if REG_WSEL should not use IX, IY, even if rstatus[4] == 1 |
input [2:0]ALU16OP, // ALU16OP |
input WAIT, // wait |
|
output reg [7:0]DO, // CPU data out bus |
output reg [7:0]ALU80, |
output reg [7:0]ALU81, |
output reg [15:0]ALU160, |
output [7:0]ALU161, |
output [7:0]FLAGS |
); |
|
// latch registers |
reg [15:0]pc=0; // program counter |
reg [15:0]sp; // stack pointer |
reg [7:0]r; // refresh |
reg [15:0]flg = 0; |
reg [7:0]th; // temp high |
|
// internal wires |
wire [15:0]rdor; // R out from RAM |
wire [15:0]rdow; // W out from RAM |
wire [3:0]SELW; // RAM W port sel |
wire [3:0]SELR; // RAM R port sel |
reg [15:0]DIN; // RAM W in data |
reg [15:0]mux_rdor; // (3)A reversed mixed with TL, (4)I mixed with R (5)SP |
|
//------------------------------------ RAM block registers ---------------------------------- |
// 0:BC, 1:DE, 2:HL, 3:A-x, 4:I-x, 5:IX, 6:IY, 7:x-x, 8:BC', 9:DE', 10:HL', 11:A'-x, 12: tmpSP, 13:zero |
RAM16X8D_regs regs_lo |
( |
.A(SELW), // R/W address |
.D(DIN[7:0]), // Write data input |
.DPRA(SELR), // Read-only address |
.WCLK(CLK), // Write clock input |
.WE(WE[0] & !WAIT),// Write enable input |
|
.DPO(rdor[7:0]), // Read-only data output |
.SPO(rdow[7:0]) // R/W data output |
); |
|
RAM16X8D_regs regs_hi |
( |
.A(SELW), // R/W address |
.D(DIN[15:8]), // Write data input |
.DPRA(SELR), // Read-only address |
.WCLK(CLK), // Write clock input |
.WE(WE[1] & !WAIT),// Write enable input |
|
.DPO(rdor[15:8]), // Read-only data output |
.SPO(rdow[15:8]) // R/W data output |
); |
|
wire [15:0]ADDR1 = ADDR + !ALU16OP[2]; // address post increment |
wire [7:0]flgmux = {ALU8FLAGS[7:3], SELR[3:0] == 4'b0100 ? rstatus[7] : ALU8FLAGS[2], ALU8FLAGS[1:0]}; // LD A, I/R IFF2 flag on parity |
always @(posedge CLK) |
if(!WAIT) begin |
if(WE[2]) th <= DI; |
if(WE[3]) sp <= ADDR1; |
if(WE[4]) pc <= ADDR1; |
if({REG_WSEL, WE[0]} == 5'b10011) r <= ALU8OUT[7:0]; |
else if(M1) r[6:0] <= r[6:0] + 1; |
if(WE[5]) |
if(rstatus[0]) flg[15:8] <= flgmux; |
else flg[7:0] <= flgmux; |
end |
|
assign ALU161 = th; |
assign FLAGS = rstatus[0] ? flg[15:8] : flg[7:0]; |
|
always @* begin |
DIN = DINW_SEL ? {DI, DI} : ALU8OUT; |
ALU80 = REG_WSEL[0] ? rdow[7:0] : rdow[15:8]; |
ALU81 = REG_RSEL[0] ? mux_rdor[7:0] : mux_rdor[15:8]; |
ALU160 = ALU160_sel ? pc : mux_rdor; |
|
case({REG_WSEL[3], DO_SEL}) |
0: DO = ALU80; |
1: DO = th; |
2: DO = FLAGS; |
3: DO = ALU8OUT[7:0]; |
4: DO = pc[15:8]; |
5: DO = pc[7:0]; |
6: DO = sp[15:8]; |
7: DO = sp[7:0]; |
endcase |
case({ALU16OP == 4, REG_RSEL[3:0]}) |
5'b01001, 5'b11001: mux_rdor = {rdor[15:8], r}; |
5'b01010, 5'b01011: mux_rdor = sp; |
5'b01100, 5'b01101, 5'b11100, 5'b11101: mux_rdor = {8'b0, CONST}; |
default: mux_rdor = rdor; |
endcase |
end |
|
RegSelect WSelectW |
( |
.SEL(REG_WSEL[3:1]), |
.rstatus({rstatus[5], rstatus[4] & XMASK, rstatus[3:0]}), |
|
.RAMSEL(SELW) |
); |
|
RegSelect WSelectR |
( |
.SEL(REG_RSEL[3:1]), |
.rstatus(rstatus[5:0]), |
|
.RAMSEL(SELR) |
); |
|
endmodule |
|
|
module RegSelect( |
input [2:0]SEL, |
input [5:0]rstatus, // 0=af-af', 1=exx, 2=hl-de, 3=hl'-de',4=hl-ixy, 5=ix-iy |
|
output reg [3:0]RAMSEL |
); |
|
always @* begin |
RAMSEL = 4'bxxxx; |
case(SEL) |
0: RAMSEL = {rstatus[1], 3'b000}; // BC |
1: //DE |
if(rstatus[{1'b1, rstatus[1]}]) RAMSEL = {rstatus[1], 3'b010}; // HL |
else RAMSEL = {rstatus[1], 3'b001}; // DE |
2: // HL |
case({rstatus[5:4], rstatus[{1'b1, rstatus[1]}]}) |
0,4: RAMSEL = {rstatus[1], 3'b010}; // HL |
1,5: RAMSEL = {rstatus[1], 3'b001}; // DE |
2,3: RAMSEL = 4'b0101; // IX |
6,7: RAMSEL = 4'b0110; // IY |
endcase |
3: RAMSEL = {rstatus[0], 3'b011}; // A-TL |
4: RAMSEL = 4; // I-R |
5: RAMSEL = 12; // tmp SP |
6: RAMSEL = 13; // zero |
7: RAMSEL = 7; // temp reg for BIT/SET/RES |
endcase |
end |
endmodule |
|
module RAM16X8D_regs( |
input [3:0]A, // R/W address |
input [7:0]D, // Write data input |
input [3:0]DPRA, // Read-only address |
input WCLK, // Write clock |
input WE, // Write enable |
|
output [7:0]DPO, // Read-only data output |
output [7:0]SPO // R/W data output |
); |
|
reg [7:0]data[15:0]; |
assign DPO = data[DPRA]; |
assign SPO = data[A]; |
|
always @(posedge WCLK) |
if(WE) data[A] <= D; |
|
endmodule |
|
//FLAGS: S Z X1 N X2 PV N C |
// OP[4:0] |
// 00000 - ADD D0,D1 |
// 00001 - ADC D0,D1 |
// 00010 - SUB D0,D1 |
// 00011 - SBC D0,D1 |
// 00100 - AND D0,D1 |
// 00101 - XOR D0,D1 |
// 00110 - OR D0,D1 |
// 00111 - CP D0,D1 |
// 01000 - INC D0 |
// 01001 - CPL D0 |
// 01010 - DEC D0 |
// 01011 - RRD |
// 01100 - RLD |
// 01101 - DAA |
// 01110 - INC16 |
// 01111 - DEC16 |
// 10000 - ADD16LO |
// 10001 - ADD16HI |
// 10010 - |
// 10011 - |
// 10100 - CCF, pass D0 |
// 10101 - SCF, pass D0 |
// 10110 - |
// 10111 - |
// 11000 - RLCA D0 |
// 11001 - RRCA D0 |
// 11010 - RLA D0 |
// 11011 - RRA D0 |
// 11100 - {ROT, BIT, SET, RES} D0,EXOP |
// RLC D0 C <-- D0 <-- D0[7] |
// RRC D0 D0[0] --> D0 --> C |
// RL D0 C <-- D0 <-- C |
// RR D0 C --> D0 --> C |
// SLA D0 C <-- D0 <-- 0 |
// SRA D0 D0[7] --> D0 --> C |
// SLL D0 C <-- D0 <-- 1 |
// SRL D0 0 --> D0 --> C |
// 11101 - IN, pass D1 |
// 11110 - FLAGS <- D0 |
// 11111 - NEG D1 |
/////////////////////////////////////////////////////////////////////////////////// |
module ALU8( |
input [7:0] D0, |
input [7:0] D1, |
input [7:0] FIN, |
input [4:0] OP, |
input [5:0] EXOP, // EXOP[5:4] = 2'b11 for CPI/D/R |
input LDIFLAGS, // zero HF and NF on inc/dec16 |
input DSTHI, // destination lo |
|
output reg[7:0] FOUT, |
output reg [15:0] ALU8DOUT |
); |
|
wire [7:0] daaadjust; |
wire cdaa, hdaa; |
|
daa daa_adjust |
( |
.flags(FIN), |
.val(D0), |
|
.adjust(daaadjust), |
.cdaa(cdaa), |
.hdaa(hdaa) |
); |
|
wire parity = ~^ALU8DOUT[15:8]; |
wire zero = ALU8DOUT[15:8] == 0; |
reg csin, cin; |
wire [7:0]d0mux = OP[4:1] == 4'b1111 ? 0 : D0; |
reg [7:0]_d1mux; |
wire [7:0]d1mux = OP[1] ? ~_d1mux : _d1mux; |
wire [8:0]sum; |
wire hf; |
assign {hf, sum[3:0]} = d0mux[3:0] + d1mux[3:0] + cin; |
assign sum[8:4] = d0mux[7:4] + d1mux[7:4] + hf; |
wire overflow = (d0mux[7] & d1mux[7] & !sum[7]) | (!d0mux[7] & !d1mux[7] & sum[7]); |
reg [7:0]dbit; |
|
always @* begin |
ALU8DOUT = 16'hxxxx; |
FOUT = 8'hxx; |
case({OP[4:2]}) |
0,1,4,7: _d1mux = D1; |
2: _d1mux = 1; |
3: _d1mux = daaadjust; // DAA |
6,5: _d1mux = 8'hxx; |
endcase |
case({OP[2:0], FIN[0]}) |
0,1,2,7,8,9,10,11,12,13: cin = 0; |
3,4,5,6,14,15: cin = 1; |
endcase |
case(EXOP[3:0]) |
0: dbit = 8'b11111110; |
1: dbit = 8'b11111101; |
2: dbit = 8'b11111011; |
3: dbit = 8'b11110111; |
4: dbit = 8'b11101111; |
5: dbit = 8'b11011111; |
6: dbit = 8'b10111111; |
7: dbit = 8'b01111111; |
8: dbit = 8'b00000001; |
9: dbit = 8'b00000010; |
10: dbit = 8'b00000100; |
11: dbit = 8'b00001000; |
12: dbit = 8'b00010000; |
13: dbit = 8'b00100000; |
14: dbit = 8'b01000000; |
15: dbit = 8'b10000000; |
endcase |
case(OP[3] ? EXOP[2:0] : OP[2:0]) |
0,5: csin = D0[7]; |
1: csin = D0[0]; |
2,3: csin = FIN[0]; |
4,7: csin = 0; |
6: csin = 1; |
endcase |
case(OP[4:0]) |
0,1,2,3,8,10: begin // ADD, ADC, SUB, SBC, INC, DEC |
ALU8DOUT[15:8] = sum[7:0]; |
ALU8DOUT[7:0] = sum[7:0]; |
FOUT[0] = OP[3] ? FIN[0] : (sum[8] ^ OP[1]); // inc/dec |
FOUT[1] = OP[1]; |
FOUT[2] = overflow; |
FOUT[3] = ALU8DOUT[11]; |
FOUT[4] = hf ^ OP[1]; |
FOUT[5] = ALU8DOUT[13]; |
FOUT[6] = zero & (FIN[6] | ~EXOP[5] | ~DSTHI | OP[3]); //(EXOP[5] & DSTHI) ? (zero & FIN[6]) : zero; // adc16/sbc16 |
FOUT[7] = ALU8DOUT[15]; |
end |
16,17: begin // ADD16LO, ADD16HI |
ALU8DOUT[15:8] = sum[7:0]; |
ALU8DOUT[7:0] = sum[7:0]; |
FOUT[0] = sum[8]; |
FOUT[1] = OP[1]; |
FOUT[2] = FIN[2]; |
FOUT[3] = ALU8DOUT[11]; |
FOUT[4] = hf ^ OP[1]; |
FOUT[5] = ALU8DOUT[13]; |
FOUT[6] = FIN[6]; |
FOUT[7] = FIN[7]; |
end |
7: begin // CP |
ALU8DOUT[15:8] = sum[7:0]; |
FOUT[0] = EXOP[5] ? FIN[0] : !sum[8]; // CPI/D/R |
FOUT[1] = OP[1]; |
FOUT[2] = overflow; |
FOUT[3] = D1[3]; |
FOUT[4] = !hf; |
FOUT[5] = D1[5]; |
FOUT[6] = zero; |
FOUT[7] = ALU8DOUT[15]; |
end |
31: begin // NEG |
ALU8DOUT[15:8] = sum[7:0]; |
FOUT[0] = !sum[8]; |
FOUT[1] = OP[1]; |
FOUT[2] = overflow; |
FOUT[3] = ALU8DOUT[11]; |
FOUT[4] = !hf; |
FOUT[5] = ALU8DOUT[13]; |
FOUT[6] = zero; |
FOUT[7] = ALU8DOUT[15]; |
end |
4: begin // AND |
ALU8DOUT[15:8] = D0 & D1; |
FOUT[0] = 0; |
FOUT[1] = 0; |
FOUT[2] = parity; |
FOUT[3] = ALU8DOUT[11]; |
FOUT[4] = 1; |
FOUT[5] = ALU8DOUT[13]; |
FOUT[6] = zero; |
FOUT[7] = ALU8DOUT[15]; |
end |
5,6: begin //XOR, OR |
ALU8DOUT[15:8] = OP[0] ? (D0 ^ D1) : (D0 | D1); |
FOUT[0] = 0; |
FOUT[1] = 0; |
FOUT[2] = parity; |
FOUT[3] = ALU8DOUT[11]; |
FOUT[4] = 0; |
FOUT[5] = ALU8DOUT[13]; |
FOUT[6] = zero; |
FOUT[7] = ALU8DOUT[15]; |
end |
9: begin // CPL |
ALU8DOUT[15:8] = ~D0; |
FOUT[0] = FIN[0]; |
FOUT[1] = 1; |
FOUT[2] = FIN[2]; |
FOUT[3] = ALU8DOUT[11]; |
FOUT[4] = 1; |
FOUT[5] = ALU8DOUT[13]; |
FOUT[7:6] = FIN[7:6]; |
end |
11,12: begin // RLD, RRD |
if(OP[0]) ALU8DOUT = {D0[7:4], D1[3:0], D0[3:0], D1[7:4]}; |
else ALU8DOUT = {D0[7:4], D1[7:0], D0[3:0]}; |
FOUT[0] = FIN[0]; |
FOUT[1] = 0; |
FOUT[2] = parity; |
FOUT[3] = ALU8DOUT[11]; |
FOUT[4] = 0; |
FOUT[5] = ALU8DOUT[13]; |
FOUT[6] = zero; |
FOUT[7] = ALU8DOUT[15]; |
end |
13: begin // DAA |
ALU8DOUT[15:8] = sum[7:0]; |
FOUT[0] = cdaa; |
FOUT[1] = FIN[1]; |
FOUT[2] = parity; |
FOUT[3] = ALU8DOUT[11]; |
FOUT[4] = hdaa; |
FOUT[5] = ALU8DOUT[13]; |
FOUT[6] = zero; |
FOUT[7] = ALU8DOUT[15]; |
end |
14,15: begin // inc/dec 16 |
ALU8DOUT = {D0, D1} + (OP[0] ? 16'hffff : 16'h0001); |
FOUT[0] = FIN[0]; |
FOUT[1] = LDIFLAGS ? 1'b0 : FIN[1]; |
FOUT[2] = ALU8DOUT != 0; |
FOUT[3] = FIN[3]; |
FOUT[4] = LDIFLAGS ? 1'b0 : FIN[4]; |
FOUT[5] = FIN[5]; |
FOUT[6] = FIN[6]; |
FOUT[7] = FIN[7]; |
end |
20,21: begin // CCF, SCF |
ALU8DOUT[15:8] = D0; |
FOUT[0] = OP[0] ? 1'b1 : !FIN[0]; |
FOUT[1] = 1'b0; |
FOUT[2] = FIN[2]; |
FOUT[3] = ALU8DOUT[11]; |
FOUT[4] = OP[0] ? 1'b0 : FIN[0]; |
FOUT[5] = ALU8DOUT[13]; |
FOUT[6] = FIN[6]; |
FOUT[7] = FIN[7]; |
end |
24,25,26,27, 28: begin // ROT, BIT, RES, SET |
case({OP[2], EXOP[4:3]}) |
0,1,2,3,4: // rot - shift |
if(OP[2] ? EXOP[0] : OP[0]){ALU8DOUT[15:8], FOUT[0]} = {csin, D0}; // right |
else {FOUT[0], ALU8DOUT[15:8]} = {D0, csin}; // left |
5,6: begin // BIT, RES |
FOUT[0] = FIN[0]; |
ALU8DOUT[15:8] = D0 & dbit; |
end |
7: begin // SET |
FOUT[0] = FIN[0]; |
ALU8DOUT[15:8] = D0 | dbit; |
end |
endcase |
ALU8DOUT[7:0] = ALU8DOUT[15:8]; |
FOUT[1] = 0; |
FOUT[2] = OP[2] ? (EXOP[3] ? zero : parity) : FIN[2]; |
FOUT[3] = ALU8DOUT[11]; |
FOUT[4] = OP[2] & EXOP[3]; |
FOUT[5] = ALU8DOUT[13]; |
FOUT[6] = OP[2] ? zero : FIN[6]; |
FOUT[7] = OP[2] ? ALU8DOUT[15] : FIN[7]; |
end |
29: begin // IN, pass D1 |
ALU8DOUT = {D1, D1}; |
FOUT[0] = FIN[0]; |
FOUT[1] = 0; |
FOUT[2] = parity; |
FOUT[3] = ALU8DOUT[11]; |
FOUT[4] = 0; |
FOUT[5] = ALU8DOUT[13]; |
FOUT[6] = zero; |
FOUT[7] = ALU8DOUT[15]; |
end |
30: FOUT = D0; // FLAGS <- D0 |
default:; |
endcase |
end |
endmodule |
|
module daa ( |
input [7:0]flags, |
input [7:0]val, |
|
output [7:0]adjust, |
output reg cdaa, |
output reg hdaa |
); |
|
wire h08 = val[7:4] < 9; |
wire h09 = val[7:4] < 10; |
wire l05 = val[3:0] < 6; |
wire l09 = val[3:0] < 10; |
reg [1:0]aa; |
assign adjust = ({1'b0, aa[1], aa[1], 2'b0, aa[0], aa[0], 1'b0} ^ {8{flags[1]}}) + flags[1]; |
|
always @* begin |
case({flags[0], h08, h09, flags[4], l09}) |
5'b00101, 5'b01101: aa = 0; |
5'b00111, 5'b01111, 5'b01000, 5'b01010, 5'b01100, 5'b01110: aa = 1; |
5'b00001, 5'b01001, 5'b10001, 5'b10101, 5'b11001, 5'b11101: aa = 2; |
default: aa = 3; |
endcase |
case({flags[0], h08, h09, l09}) |
4'b0011, 4'b0111, 4'b0100, 4'b0110: cdaa = 0; |
default: cdaa = 1; |
endcase |
case({flags[1], flags[4], l05, l09}) |
4'b0000, 4'b0010, 4'b0100, 4'b0110, 4'b1110, 4'b1111: hdaa = 1; |
default: hdaa = 0; |
endcase |
end |
endmodule |
|
|
module ALU16( |
input [15:0]D0, |
input [7:0]D1, |
input [2:0]OP, // 0-NOP, 1-INC, 2-INC2, 3-ADD, 4-NOP, 5-DEC, 6-DEC2 |
|
output [15:0]DOUT |
); |
|
reg [7:0] mux; |
always @* |
case(OP) |
0: mux = 8'h00; // post inc |
1: mux = 8'h01; // post inc |
2: mux = 8'h02; // post inc |
3: mux = D1; // post inc |
4: mux = 8'h00; // no post inc |
5: mux = 8'hff; // no post inc |
6: mux = 8'hfe; // no post inc |
default: mux = 8'hxx; |
endcase |
|
assign DOUT = D0 + {{8{mux[7]}}, mux}; |
endmodule |
/nextz80/trunk/NextZ80_TestApp.7z
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
nextz80/trunk/NextZ80_TestApp.7z
Property changes :
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property