mirror of
https://github.com/Gehstock/Mist_FPGA.git
synced 2026-02-15 20:26:07 +00:00
460 lines
10 KiB
Verilog
460 lines
10 KiB
Verilog
//
|
|
// Z80 Compatible Bus wrapper for fz80 ver.0.52
|
|
//
|
|
// Version 0.52a
|
|
//
|
|
// Copyright (c) 2004 Tatsuyuki Sato
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
// copy of this software and associated documentation files (the "Software"),
|
|
// to deal in the Software without restriction, including without limitation
|
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
// and/or sell copies of the Software, and to permit persons to whom the
|
|
// Software is furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included
|
|
// in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
/*
|
|
note:
|
|
|
|
It should be necessary to set "`define M1" inf fz80.
|
|
---------------------------------------------------
|
|
|
|
-----------------------------
|
|
non-compatible spesification.
|
|
-----------------------------
|
|
|
|
1.no internal cycle
|
|
A internal cycle without bus cycle doesn't exist.
|
|
So some instruction is faster than Z80.
|
|
|
|
2.ealy tristate after reset
|
|
The "at" and "dt" assert after 1cycle from reset.
|
|
The Z80 is after 2cycles from reset.
|
|
|
|
3.busreq/busack timming are not checked yet.
|
|
|
|
4.halt always output 1(no supported).
|
|
|
|
-------------
|
|
state changes
|
|
-------------
|
|
+------+---+---+---+---+---+---+
|
|
|state |t1w|t1 |t2w|t2 |t3 |t4 |
|
|
+------+---+---+---+---+---+---+
|
|
| M1 | - | O | - | O*| O | O |
|
|
| MEM | - | O | - | O*| x | O |
|
|
| IO | - | O | - | O*| x | O |
|
|
| SpM1 | O | O | O | O | O | O |
|
|
+------+---+---+---+---+---+---+
|
|
*:sense wait (wait cycle)
|
|
|
|
histry:
|
|
2004. 9.16 ver.0.52a
|
|
bugfix power on reset error.
|
|
halt_n output always 1 (do not supported yet)
|
|
change `MREQ_INSIDE_RD logic.
|
|
|
|
2004. 9.10 ver.0.52
|
|
added power on reset
|
|
bugfix mreq inside rd mode
|
|
2004. 9. 9 ver.0.51
|
|
1st test version
|
|
*/
|
|
|
|
//`define FZ80C_NGC_LINK // xilinx XST link synthesized fz80c.v
|
|
//`define DEBUG_OUTPUT
|
|
|
|
// ----- design option -----
|
|
`define MREQ_INSIDE_RD // for wr = (rfsh & ~mreq_n & rd_n);
|
|
//`define FZ80C_POWER_ON_RESET // power on self reset
|
|
//`define DISABLE_BUSREQ_SYNC // bypass busreq/busack syncronize.
|
|
//`define DISABLE_REFRESH_CYCLE // no rfsh cycle & inst code fetch t4 raise
|
|
//`define NMI_SYNC_SENSE // nmi fall sense with clk
|
|
//`define DO_VAL_IF_DT 8'h00 // "do" set fixed value when output disable
|
|
|
|
module fz80c (/*AUTOARG*/
|
|
// Inputs
|
|
reset_n, clk, wait_n, int_n, nmi_n, busrq_n, di,
|
|
// Outputs
|
|
m1_n, mreq_n, iorq_n, rd_n, wr_n, rfsh_n, halt_n, busak_n,
|
|
`ifdef DEBUG_OUTPUT
|
|
ts,
|
|
wait_window,
|
|
`endif
|
|
A, At,
|
|
do,dt
|
|
);
|
|
|
|
input reset_n,clk;
|
|
input wait_n , busrq_n;
|
|
input int_n,nmi_n;
|
|
input [7:0] di;
|
|
|
|
output m1_n;
|
|
output mreq_n;
|
|
output iorq_n;
|
|
output rd_n;
|
|
output wr_n;
|
|
output rfsh_n;
|
|
output halt_n;
|
|
output busak_n; // (enable controll : mreq_n,iorq_n,rd_n,wr_n,rfsh_n)
|
|
output [15:0] A; // Address Bus
|
|
output [7:0] do; // Data Bus
|
|
output dt; // tristate controll : do
|
|
output At; // tristate controll : A
|
|
|
|
`ifdef DEBUG_OUTPUT
|
|
output [3:0] ts;
|
|
output wait_window;
|
|
`endif
|
|
|
|
`ifndef FZ80C_NGC_LINK
|
|
|
|
// internal register
|
|
reg [15:0] A;
|
|
reg [7:0] dinst_r;
|
|
reg [7:0] do_r;
|
|
reg [3:0] ts;
|
|
reg reset_s;
|
|
reg m1_r;
|
|
`ifndef DISABLE_REFRESH_CYCLE
|
|
reg rfsh_r;
|
|
`endif
|
|
reg mreq_r;
|
|
reg iorq_r;
|
|
reg wr_r;
|
|
reg rd_r;
|
|
reg wait_r;
|
|
reg dt_r,dt_t4;
|
|
`ifndef DISABLE_BUSREQ_SYNC
|
|
reg at_r;
|
|
reg busack_r;
|
|
reg busreq_r;
|
|
`endif
|
|
|
|
//reg halt_r;
|
|
|
|
`ifdef NMI_SYNC_SENSE
|
|
reg nmi_r1,nmi_r2;
|
|
`endif
|
|
|
|
// auto wait
|
|
reg tw1,tw2;
|
|
|
|
// gate signal base
|
|
reg t3l;
|
|
reg t04l;
|
|
|
|
`ifdef FZ80C_POWER_ON_RESET
|
|
reg por_n = 0;
|
|
reg por2_n = 0;
|
|
`endif
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
// FZ80
|
|
//////////////////////////////////////////////////////////////
|
|
wire start;
|
|
wire mreq;
|
|
wire iorq;
|
|
wire rd;
|
|
wire wr;
|
|
wire busack;
|
|
wire waitreq;
|
|
reg intreq;
|
|
reg nmireq;
|
|
wire busreq;
|
|
wire m1;
|
|
//wire [7:0] data_in = m1 ? dinst_r : di;
|
|
wire [7:0] data_in = ~rfsh_n ? dinst_r : di;
|
|
wire [7:0] data_out;
|
|
wire [15:0] adr ,radr;
|
|
wire nmiack;
|
|
//wire halt;
|
|
|
|
// mreq,iorq inside in rd_wr
|
|
//wire req_mask =
|
|
|
|
fz80 fz80(
|
|
.data_in(data_in),
|
|
.reset_in(reset_s),
|
|
.clk(~clk),
|
|
.adr(adr),
|
|
.intreq(intreq),
|
|
.nmireq(nmireq),
|
|
.busreq(busreq),
|
|
.start(start),
|
|
.mreq(mreq),
|
|
.iorq(iorq),
|
|
.rd(rd),
|
|
.wr(wr),
|
|
.data_out(data_out),
|
|
.busack_out(busack),
|
|
.intack_out(),
|
|
.mr(),
|
|
|
|
.m1(m1),
|
|
// .halt(halt),
|
|
.radr(radr),
|
|
.nmiack_out(nmiack),
|
|
.waitreq(waitreq)
|
|
);
|
|
|
|
///////////////////////////////////////////////////////
|
|
// wires
|
|
///////////////////////////////////////////////////////
|
|
|
|
// state value
|
|
wire t0 = ts[3:0]==0; // t0 : reset cycle
|
|
wire t1 = ts[0]; // t1 : spM1 = t1&t2
|
|
wire t2 = ts[1]; // t2 : spM1 = tw(1,2)
|
|
wire t3 = ts[2]; // M1.t3
|
|
wire t4 = ts[3]; // M1.t4 or MEM/IO.t3
|
|
|
|
wire t04 = ~t1 & ~t2 & ~t3; // T0 or T4
|
|
|
|
`ifdef DEBUG_OUTPUT
|
|
// wait input window
|
|
assign wait_window = t2 & ~wait_r;
|
|
`endif
|
|
|
|
// RFSH assert timming
|
|
`ifdef DISABLE_REFRESH_CYCLE
|
|
wire nxt_rfsh = 1'b0;
|
|
`else
|
|
wire nxt_rfsh = (m1&t2&wait_r)|t3; // T3 and T4
|
|
`endif
|
|
|
|
///////////////////////////////////////////////////////
|
|
// NMI eddge sense
|
|
///////////////////////////////////////////////////////
|
|
|
|
`ifndef NMI_SYNC_SENSE
|
|
wire nmi_clr = nmiack | reset_s;
|
|
always @(negedge nmi_n or posedge nmi_clr)
|
|
begin
|
|
if(nmi_clr) nmireq <= #1 1'b0;
|
|
else nmireq <= #1 1'b1;
|
|
end
|
|
`endif
|
|
|
|
///////////////////////////////////////////////////////
|
|
// Timming state controll
|
|
///////////////////////////////////////////////////////
|
|
|
|
`ifdef FZ80C_POWER_ON_RESET
|
|
always @(negedge clk)
|
|
begin
|
|
por_n <= #1 por2_n;
|
|
por2_n <= #1 1'b1;
|
|
end
|
|
// with por
|
|
always @(negedge clk or negedge por_n)
|
|
if(~por_n) reset_s <= #1 1'b1;
|
|
else reset_s <= #1 ~reset_n;
|
|
`else
|
|
// without por
|
|
always @(negedge clk) reset_s <= #1 ~reset_n;
|
|
`endif
|
|
|
|
always @(posedge clk)
|
|
begin
|
|
if (reset_s)
|
|
begin
|
|
dinst_r <= #1 8'h00;
|
|
ts <= #1 4'b0000; // reset cycle;
|
|
A <= #1 16'h0000;
|
|
m1_r <= #1 1'b1;
|
|
`ifndef DISABLE_REFRESH_CYCLE
|
|
rfsh_r <= #1 1'b1;
|
|
`endif
|
|
intreq <= #1 1'b0;
|
|
`ifdef NMI_SYNC_SENSE
|
|
nmireq <= #1 1'b0;
|
|
nmi_r2 <= #1 1'b0;
|
|
nmi_r1 <= #1 1'b0;
|
|
`endif
|
|
tw1 <= #1 1'b0;
|
|
tw2 <= #1 1'b0;
|
|
dt_t4 <= #1 1'b1;
|
|
`ifndef DISABLE_BUSREQ_SYNC
|
|
busreq_r <= #1 1'b1;
|
|
busack_r <= #1 1'b1;
|
|
at_r <= #1 1'b1;
|
|
`endif
|
|
|
|
iorq_r <= #1 1'b1;
|
|
rd_r <= #1 1'b1;
|
|
mreq_r <= #1 1'b1;
|
|
|
|
// halt_r <= #1 1'b1;
|
|
end else begin
|
|
// T1 T2 on , T3 T4 off
|
|
m1_r <= #1 ~m1 | nxt_rfsh;
|
|
|
|
`ifndef DISABLE_REFRESH_CYCLE
|
|
// T3 T4 on , T1 T2 off
|
|
rfsh_r <= #1 ~nxt_rfsh;
|
|
`endif
|
|
|
|
// T1(M1),T2,T4(IO) on , T1(IO),T3,T4(M1) off
|
|
iorq_r <= #1 ~iorq | t04 | tw1 | nxt_rfsh;
|
|
|
|
// T1(MEM),T2,T4(MEM) on,T1(IO),T3,T4(M1) off
|
|
rd_r <= #1 ~rd | (iorq&t04) | nxt_rfsh;
|
|
|
|
// T1,T2,T4(MEM) on T3,T4(M1) off
|
|
mreq_r <= #1 ~mreq | nxt_rfsh;
|
|
|
|
// timming state controll
|
|
ts[0] <= #1 (t1&tw1) | t04; // t1
|
|
ts[1] <= #1 (t2& ~wait_r) | (t1&~tw1); // t2
|
|
ts[2] <= #1 (t2& wait_r& m1); // t3
|
|
ts[3] <= #1 (t2& wait_r&~m1) | t3; // t4
|
|
|
|
// auto wait state
|
|
tw1 <= #1 ~t1 & (m1&iorq); // TW for SpecialM1
|
|
tw2 <= #1 t1 & iorq; // TW for IO and SpecialM1
|
|
|
|
// address / refresh address
|
|
A <= #1 nxt_rfsh ? radr : adr;
|
|
|
|
// IRQ (T4 raise)
|
|
intreq <= #1 ~int_n;
|
|
|
|
// NMI eddge sense
|
|
`ifdef NMI_SYNC_SENSE
|
|
nmi_r2 <= #1 nmi_r1;
|
|
nmi_r1 <= #1 ~nmi_n;
|
|
if(nmiack) nmireq <= #1 1'b0;
|
|
else if(~nmi_r2 & nmi_r1) nmireq <= #1 1'b1;
|
|
`endif
|
|
|
|
// Opcode Latch = T3 raise
|
|
if(t2) dinst_r <= #1 di;
|
|
|
|
// data outpot tristate , HOLD half clock in T4
|
|
dt_t4 <= #1 dt_r;
|
|
|
|
// busreq / busack & Address tristate
|
|
`ifndef DISABLE_BUSREQ_SYNC
|
|
busreq_r <= #1 ~busrq_n;
|
|
busack_r <= #1 ~busack;
|
|
at_r <= #1 ~busack;
|
|
`endif
|
|
|
|
// halt fetch
|
|
// if(m1&t4) halt_r <= #1 ~halt;
|
|
|
|
end
|
|
end
|
|
|
|
// clk fall event
|
|
always @(negedge clk)
|
|
begin
|
|
if (reset_s)
|
|
begin
|
|
t3l <= #1 1'b0;
|
|
t04l <= #1 1'b1;
|
|
wait_r <= #1 1'b1;
|
|
wr_r <= #1 1'b1;
|
|
dt_r <= #1 1'b1;
|
|
do_r <= #1 8'h00;
|
|
end else begin
|
|
// gate controll
|
|
t3l <= #1 t3;
|
|
|
|
// t4l-t0l | specialM1.t1l
|
|
t04l <= #1 t04 | (t1&m1&iorq);
|
|
|
|
// DataOutput
|
|
do_r <= #1 data_out;
|
|
|
|
// wait sense (T2 raise)
|
|
wait_r <= #1 (wait_n | (m1&iorq)) & ~tw2;
|
|
|
|
// data bus enable , T1,T2 on , T4 off
|
|
dt_r <= #1 ~wr | t04;
|
|
|
|
// T1(IO),T2 on , T1(MEM),T4 off
|
|
wr_r <= #1 ~wr | t4 | (mreq&t1);
|
|
end
|
|
end
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// fz80 input
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
assign waitreq = ~t4;
|
|
`ifdef DISABLE_BUSREQ_SYNC
|
|
assign busreq = ~busrq_n;
|
|
`else
|
|
assign busreq = busreq_r;
|
|
`endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// output signal
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// MREQ glidge mask
|
|
`ifdef MREQ_INSIDE_RD
|
|
reg mreq_dly;
|
|
always @(posedge clk or negedge rd_n)
|
|
begin
|
|
if(~rd_n) mreq_dly <= #1 1'b0;
|
|
else if(t04) mreq_dly <= #1 rd;
|
|
end
|
|
|
|
reg rd_hold_n;
|
|
always @(posedge clk or posedge mreq_n)
|
|
begin
|
|
if(mreq_n) rd_hold_n <= #1 1'b1;
|
|
else rd_hold_n <= #1 mreq_n | rd_n;
|
|
end
|
|
|
|
`else
|
|
wire mreq_dly = 0;
|
|
wire rd_hold_n = 1;
|
|
`endif
|
|
|
|
assign m1_n = m1_r;
|
|
`ifndef DISABLE_REFRESH_CYCLE
|
|
assign rfsh_n = rfsh_r;
|
|
`else
|
|
assign rfsh_n = 1'b1;
|
|
`endif
|
|
assign mreq_n = (mreq_r| t04l | mreq_dly) & (~t3l | rfsh_n);
|
|
assign iorq_n = iorq_r | t04l;
|
|
assign rd_n = (rd_r | t04l) & rd_hold_n;
|
|
assign wr_n = wr_r | t1;
|
|
assign dt = dt_r & dt_t4;
|
|
`ifndef DISABLE_BUSREQ_SYNC
|
|
assign At = at_r;
|
|
assign busak_n = busack_r;
|
|
`else
|
|
assign At = busack | reset_s;
|
|
assign busak_n = busack;
|
|
`endif
|
|
|
|
`ifdef DO_VAL_IF_DT
|
|
assign do = dt ? `DO_VAL_IF_DT : do_r;
|
|
`else
|
|
assign do = do_r;
|
|
`endif
|
|
|
|
//assign halt_n = halt_r;
|
|
assign halt_n = 1'b1;
|
|
|
|
`endif // FZ80C_USER_NGC_LINK
|
|
|
|
endmodule
|