mirror of
https://github.com/Gehstock/Mist_FPGA.git
synced 2026-02-04 07:32:37 +00:00
200 lines
6.7 KiB
Verilog
200 lines
6.7 KiB
Verilog
//////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// This file is part of the NextZ80 project
|
|
// http://www.opencores.org/cores/nextz80/
|
|
//
|
|
// Filename: NextZ80Regs.v
|
|
// Description: Implementation of Z80 compatible CPU - registers
|
|
// Version 1.0
|
|
// Creation date: 28Jan2011 - 18Mar2011
|
|
//
|
|
// Author: Nicolae Dumitrache
|
|
// e-mail: ndumitrache@opencores.org
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2011 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
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
`timescale 1ns / 1ps
|
|
|
|
module Z80Reg(
|
|
input wire [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 wire M1,
|
|
input wire [5:0]WE, // 5 = flags, 4 = PC, 3 = SP, 2 = tmpHI, 1 = hi, 0 = lo
|
|
input wire CLK,
|
|
input wire [15:0]ALU8OUT, // CPU data out bus (output of alu8)
|
|
input wire [7:0]DI, // CPU data in bus
|
|
output reg [7:0]DO, // CPU data out bus
|
|
input wire [15:0]ADDR, // CPU addr bus
|
|
input wire [7:0]CONST,
|
|
output reg [7:0]ALU80,
|
|
output reg [7:0]ALU81,
|
|
output reg [15:0]ALU160,
|
|
output wire[7:0]ALU161,
|
|
input wire [7:0]ALU8FLAGS,
|
|
output wire [7:0]FLAGS,
|
|
|
|
input wire [1:0]DO_SEL, // select DO betwen ALU8OUT lo and th register
|
|
input wire ALU160_sel, // 0=REG_RSEL, 1=PC
|
|
input wire [3:0]REG_WSEL, // rdow: [3:1] 0=BC, 1=DE, 2=HL, 3=A-TL, 4=I-x ----- [0] = 0HI,1LO
|
|
input wire [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 wire DINW_SEL, // select RAM write data between (0)ALU8OUT, and 1(DI)
|
|
input wire XMASK, // 0 if REG_WSEL should not use IX, IY, even if rstatus[4] == 1
|
|
input wire [2:0]ALU16OP, // ALU16OP
|
|
input wire WAIT // wait
|
|
);
|
|
|
|
// 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 (
|
|
.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
|
|
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]), .RAMSEL(SELW), .rstatus({rstatus[5], rstatus[4] & XMASK, rstatus[3:0]}));
|
|
RegSelect WSelectR(.SEL(REG_RSEL[3:1]), .RAMSEL(SELR), .rstatus(rstatus[5:0]));
|
|
|
|
endmodule
|
|
|
|
|
|
module RegSelect(
|
|
input [2:0]SEL,
|
|
output reg [3:0]RAMSEL,
|
|
input [5:0]rstatus // 0=af-af', 1=exx, 2=hl-de, 3=hl'-de',4=hl-ixy, 5=ix-iy
|
|
);
|
|
|
|
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(
|
|
output [7:0]DPO, // Read-only data output
|
|
output [7:0]SPO, // R/W data output
|
|
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
|
|
);
|
|
|
|
reg [7:0]data[15:0];
|
|
assign DPO = data[DPRA];
|
|
assign SPO = data[A];
|
|
|
|
always @(posedge WCLK)
|
|
if(WE) data[A] <= D;
|
|
|
|
endmodule
|