URL
https://opencores.org/ocsvn/wb_z80/wb_z80/trunk
Subversion Repositories wb_z80
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 16 to Rev 17
- ↔ Reverse comparison
Rev 16 → Rev 17
/trunk/rtl/z80_core_top.v
0,0 → 1,178
/////////////////////////////////////////////////////////////////////////////////////////////// |
//// |
//// file name: z80_core_top.v |
//// description: interconnect module for z80 core. |
//// project: wb_z80 //// |
//// |
//// Author: B.J. Porcella |
//// bporcella@sbcglobal.net |
//// |
//// |
//// |
/////////////////////////////////////////////////////////////////////////////////////////////// |
//// |
//// Copyright (C) 2000-2002 B.J. Porcella |
//// Real Time Solutions |
//// |
//// |
//// 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY |
//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR |
//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
//// POSSIBILITY OF SUCH DAMAGE. |
//// |
/////////////////////////////////////////////////////////////////////////////////////////////// |
// CVS Log |
// |
// $Id: z80_core_top.v,v 1.1 2004-04-27 21:27:13 bporcella Exp $ |
// |
// $Date: 2004-04-27 21:27:13 $ |
// $Revision: 1.1 $ |
// $Author: bporcella $ |
// $Locker: $ |
// $State: Exp $ |
// |
// Change History: |
// $Log: not supported by cvs2svn $ |
// Revision 1.1.1.1 2004/04/13 23:47:42 bporcella |
// import first files |
// |
// |
// |
// connects modules: |
// memstate2.v // main state machine for z8 |
// inst_exec.v // main execution engine for z80 |
// generic_spram.v // main memory (on board) |
// z80_sdram_config.v // fundamentally wishbone glue logic - not on top per design guidelines |
//-------1---------2---------3--------Module Name and Port List------7---------8---------9--------0 |
module z80_core_top( wb_dat_o, |
wb_stb_o, |
wb_cyc_o, |
wb_we_o, |
wb_adr_o, |
wb_tga_o, |
bist_ack_o, |
bist_err_o, |
wb_ack_i, |
wb_clk_i, |
wb_dat_i, |
bist_req_i, |
int_req_i |
|
|
); |
|
//-------1---------2---------3--------Output Ports---------6---------7---------8---------9--------0 |
|
output [7:0] wb_dat_o; |
output wb_stb_o; |
output wb_cyc_o; |
output wb_we_o; |
output [15:0] wb_adr_o; |
output [1:0] wb_tga_o; |
output bist_ack_o; |
output bist_err_o; |
|
|
//-------1---------2---------3--------Input Ports----------6---------7---------8---------9--------0 |
|
input wb_ack_i; |
input wb_clk_i; |
input [7:0] wb_dat_i; |
input bist_req_i; |
input int_req_i; |
|
|
//-------1---------2---------3--------Parameters-----------6---------7---------8---------9--------0 |
//-------1---------2---------3--------Wires------5---------6---------7---------8---------9--------0 |
wire [15:0] wb_adr_o; |
wire [15:0] add_out; // output of adder (may not wb_adr_o) |
wire [9:0] ir1, ir2; |
wire [15:0] nn; |
wire [15:0] sp; |
wire [7:0] ar, fr, br, cr, dr, er, hr, lr; |
wire [15:0] ixr, iyr; |
wire [7:0] wb_dat_i, wb_dat_o, sdram_do, cfg_do; |
wire [15:0] add16; // ir2 execution engine output for sp updates |
|
|
|
|
|
|
|
//-------1---------2---------3--------Registers--5---------6---------7---------8---------9--------0 |
//-------1---------2---------3--------Assignments----------6---------7---------8---------9--------0 |
//-------1---------2---------3--------State Machines-------6---------7---------8---------9--------0 |
|
z80_memstate2 i_z80_memstate2( |
.wb_adr_o(wb_adr_o), .wb_we_o(wb_we_o), .wb_cyc_o(wb_cyc_o), .wb_stb_o(wb_stb_o), .wb_tga_o(wb_tga_o), .wb_dat_o(wb_dat_o), |
.exec_ir2(exec_ir2), .ir1(ir1), .ir2(ir2), .ir1dd(ir1dd), .ir1fd(ir1fd), .ir2dd(ir2dd), .ir2fd(ir2fd), .nn(nn), .sp(sp), |
.upd_ar(upd_ar), .upd_br(upd_br), .upd_cr(upd_cr), .upd_dr(upd_dr), .upd_er(upd_er), .upd_hr(upd_hr), .upd_lr(upd_lr),.upd_fr(upd_fr), |
.beq0(beq0), .ceq0(ceq0), |
.ar(ar), .fr(fr), .br(br), .cr(cr), .dr(dr), .er(er), .hr(hr), .lr(lr), |
.ixr(ixr), .iyr(iyr), |
.wb_dat_i(cfg_do), .wb_ack_i(wb_ack_i), |
.int_req_i(int_req_i), |
.add16(add16), |
.wb_clk_i(wb_clk_i), |
.rst_i(rst_i) // keep this generic - may turn out to be different from wb_rst |
); |
|
|
z80_inst_exec i_z80_inst_exec( |
.br_eq0(br_eq0), |
.cr_eq0(cr_eq0), |
.upd_ar(upd_ar), .upd_br(upd_br), .upd_cr(upd_cr), .upd_dr(upd_dr), .upd_er(upd_er), .upd_hr(upd_hr), .upd_lr(upd_lr),.upd_fr(upd_fr), |
.ar(ar), .fr(fr), .br(br), .cr(cr), .dr(dr), .er(er), .hr(hr), .lr(lr), |
.ixr(ixr), .iyr(iyr), .add16(add16), |
.exec_ir2(exec_ir2), |
.exec_decbc(exec_decbc), .exec_decb(exec_decb), |
.ir2(ir2), |
.clk(wb_clk_i), |
.rst(rst_i), |
.nn(nn), .sp(sp), |
.dd_grp(dd_grp), |
.fd_grp(fd_grp) |
); |
|
// The parameter passed to i_generic_sprem specifies the number of address bits used by the |
// memory -- and thus the memory size. We expect to use 15 here in the released documentation - |
// giving an onboard 32k SRAM and allowing 32k space for off-chip memory. Note that any change to |
// this parameter requires modifications to the decode logic in z80_sdram_cfg. |
// |
// The generic_spram is being used here per Open Cores coding guidelines. I'm not sure I'm totally |
// happy with this...... Depending on which target technology is specified, read behavior changes. |
// It is easy to insure all possible behavior will in fact operate properly -- see the data reduction |
// logic in sdram_cfg.v -- but still... I guess the important thing to be aware of is that |
// big memories like this typically require special back-end handleing. This is likely to prove |
// no exception - despite the work that has been done to make this file as generally useful as |
// possible. |
|
generic_spram #(12) i_generic_spram( |
// Generic synchronous single-port RAM interface |
.clk(wb_clk_i), .rst(rst_i), .ce(cfg_ce_spram_o), .we(wb_we_o), .oe(1'b1), .addr(wb_adr_o[11:0]), .di(wb_dat_o), .do(sdram_do) |
); |
|
|
|
z80_sdram_cfg i_z80_sdram_cfg( |
.cfg_ce_spram_o(cfg_ce_spram_o), .cfg_do(cfg_do), .cfg_ack_o(cfg_ack_o), .sdram_di(sdram_do), |
.wb_adr_i(wb_adr_o), .wb_dat_i(wb_dat_i), .wb_ack_i(wb_ack_i), .wb_stb_i(wd_stb_o), |
.wb_cyc_i(wb_cyc_o), .wb_tga_i(wb_tga_o) ); |
|
|
endmodule |
/trunk/rtl/files.txt
0,0 → 1,8
+incdir+. |
z80_core_top.v |
z80_inst_exec.v |
z80_memstate2.v |
z80_sdram_cfg.v |
generic_spram.v |
|
|
/trunk/rtl/generic_spram.v
0,0 → 1,429
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Generic Single-Port Synchronous RAM //// |
//// //// |
//// This file is part of memory library available from //// |
//// http://www.opencores.org/cvsweb.shtml/generic_memories/ //// |
//// //// |
//// Description //// |
//// This block is a wrapper with common single-port //// |
//// synchronous memory interface for different //// |
//// types of ASIC and FPGA RAMs. Beside universal memory //// |
//// interface it also provides a behavioral model of generic //// |
//// single-port synchronous RAM. //// |
//// It also contains a synthesizeable model for FPGAs. //// |
//// It should be used in all OPENCORES designs that want to be //// |
//// portable accross different target technologies and //// |
//// independent of target memory. //// |
//// //// |
//// Supported ASIC RAMs are: //// |
//// - Artisan Single-Port Sync RAM //// |
//// - Avant! Two-Port Sync RAM (*) //// |
//// - Virage Single-Port Sync RAM //// |
//// - Virtual Silicon Single-Port Sync RAM //// |
//// //// |
//// Supported FPGA RAMs are: //// |
//// - Generic FPGA (VENDOR_FPGA) //// |
//// Tested RAMs: Altera, Xilinx //// |
//// Synthesis tools: LeonardoSpectrum, Synplicity //// |
//// - Xilinx (VENDOR_XILINX) //// |
//// - Altera (VENDOR_ALTERA) //// |
//// //// |
//// To Do: //// |
//// - fix avant! two-port ram //// |
//// - add additional RAMs //// |
//// //// |
//// Author(s): //// |
//// - Richard Herveille, richard@asics.ws //// |
//// - Damjan Lampret, lampret@opencores.org //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2000 Authors and OPENCORES.ORG //// |
//// //// |
//// 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 //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
// |
// CVS Revision History |
// |
// $Log: not supported by cvs2svn $ |
// Revision 1.3 2001/11/09 00:34:19 samg |
// minor changes: unified with all common rams |
// |
// Revision 1.2 2001/11/08 19:32:59 samg |
// corrected output: output not valid if ce low |
// |
// Revision 1.1.1.1 2001/09/14 09:57:09 rherveille |
// Major cleanup. |
// Files are now compliant to Altera & Xilinx memories. |
// Memories are now compatible, i.e. drop-in replacements. |
// Added synthesizeable generic FPGA description. |
// Created "generic_memories" cvs entry. |
// |
// Revision 1.2 2001/07/30 05:38:02 lampret |
// Adding empty directories required by HDL coding guidelines |
// |
// |
|
//`include "timescale.v" |
|
//`define VENDOR_XILINX |
//`define VENDOR_ALTERA |
//`define VENDOR_FPGA |
|
module generic_spram( |
// Generic synchronous single-port RAM interface |
clk, rst, ce, we, oe, addr, di, do |
); |
|
// |
// Default address and data buses width |
// |
parameter aw = 6; //number of address-bits |
parameter dw = 8; //number of data-bits |
|
// |
// Generic synchronous single-port RAM interface |
// |
input clk; // Clock, rising edge |
input rst; // Reset, active high |
input ce; // Chip enable input, active high |
input we; // Write enable input, active high |
input oe; // Output enable input, active high |
input [aw-1:0] addr; // address bus inputs |
input [dw-1:0] di; // input data bus |
output [dw-1:0] do; // output data bus |
|
// |
// Module body |
// |
|
`ifdef VENDOR_FPGA |
// |
// Instantiation synthesizeable FPGA memory |
// |
// This code has been tested using LeonardoSpectrum and Synplicity. |
// The code correctly instantiates Altera EABs and Xilinx BlockRAMs. |
// |
reg [dw-1 :0] mem [(1<<aw) -1:0]; |
reg [aw-1:0] raddr; |
|
always@(posedge clk) |
begin |
// read operation |
raddr <= #1 addr; // read address needs to be registered to read clock |
|
// write operation |
if (we && ce) |
mem[addr] <= #1 di; |
end |
|
assign #1 do = mem[raddr]; |
|
`else |
|
`ifdef VENDOR_XILINX |
|
wire [dw-1:0] q; // output from xilinx ram |
// |
// Instantiation of FPGA memory: |
// |
// Virtex/Spartan2 BlockRAMs |
// |
xilinx_ram_sp xilinx_ram( |
.clk(clk), |
.rst(rst), |
.addr(addr), |
.di(di), |
.en(ce), |
.we(we), |
.do(do) |
); |
|
defparam |
xilinx_ram.dwidth = dw, |
xilinx_ram.awidth = aw; |
|
`else |
|
`ifdef VENDOR_ALTERA |
|
// |
// Instantiation of FPGA memory: |
// |
// Altera FLEX EABs |
// |
|
altera_ram_sp altera_ram( |
.inclock(clk), |
.address(addr), |
.data(di), |
.we(we && ce), |
.q(do) |
); |
|
defparam |
altera_ram.dwidth = dw, |
altera_ram.awidth = aw; |
|
`else |
|
`ifdef VENDOR_ARTISAN |
|
// |
// Instantiation of ASIC memory: |
// |
// Artisan Synchronous Single-Port RAM (ra1sh) |
// |
artisan_ssp #(dw, 1<<aw, aw) artisan_ssp( |
.CLK(clk), |
.CEN(~ce), |
.WEN(~we), |
.A(addr), |
.D(di), |
.OEN(~oe), |
.Q(do) |
); |
|
`else |
|
`ifdef VENDOR_AVANT |
|
// |
// Instantiation of ASIC memory: |
// |
// Avant! Asynchronous Two-Port RAM |
// |
avant_atp avant_atp( |
.web(~we), |
.reb(), |
.oeb(~oe), |
.rcsb(), |
.wcsb(), |
.ra(addr), |
.wa(addr), |
.di(di), |
.do(do) |
); |
|
`else |
|
`ifdef VENDOR_VIRAGE |
|
// |
// Instantiation of ASIC memory: |
// |
// Virage Synchronous 1-port R/W RAM |
// |
virage_ssp virage_ssp( |
.clk(clk), |
.adr(addr), |
.d(di), |
.we(we), |
.oe(oe), |
.me(ce), |
.q(do) |
); |
|
`else |
|
`ifdef VENDOR_VIRTUALSILICON |
|
// |
// Instantiation of ASIC memory: |
// |
// Virtual Silicon Single-Port Synchronous SRAM |
// |
virtualsilicon_spram #(1<<aw, aw-1, dw-1) virtualsilicon_ssp( |
.CK(clk), |
.ADR(addr), |
.DI(di), |
.WEN(~we), |
.CEN(~ce), |
.OEN(~oe), |
.DOUT(do) |
); |
|
`else |
|
// |
// Generic single-port synchronous RAM model |
// |
|
// |
// Generic RAM's registers and wires |
// |
reg [dw-1:0] mem [(1<<aw)-1:0]; // RAM content |
wire [dw-1:0] q; // RAM output |
reg [aw-1:0] raddr; // RAM read address |
// |
// Data output drivers |
// |
assign do = (oe & ce) ? q : {dw{1'bz}}; |
|
// |
// RAM read and write |
// |
|
// read operation |
always@(posedge clk) |
if (ce) // && !we) |
raddr <= #1 addr; // read address needs to be registered to read clock |
|
assign #1 q = rst ? {dw{1'b0}} : mem[raddr]; |
|
// write operation |
always@(posedge clk) |
if (ce && we) |
mem[addr] <= #1 di; |
|
// Task prints range of memory |
// *** Remember that tasks are non reentrant, don't call this task in parallel for multiple instantiations. |
task print_ram; |
input [aw-1:0] start; |
input [aw-1:0] finish; |
integer rnum; |
begin |
for (rnum=start;rnum<=finish;rnum=rnum+1) |
$display("Addr %h = %h",rnum,mem[rnum]); |
end |
endtask |
|
`endif // !VIRTUALSILICON_SSP |
`endif // !VIRAGE_SSP |
`endif // !AVANT_ATP |
`endif // !ARTISAN_SSP |
`endif // !VENDOR_ALTERA |
`endif // !VENDOR_XILINX |
`endif // !VENDOR_FPGA |
|
endmodule |
|
|
// |
// Black-box modules |
// |
|
`ifdef VENDOR_ALTERA |
module altera_ram_sp ( |
address, |
inclock, |
we, |
data, |
q) /* synthesis black_box */; |
|
parameter awidth = 7; |
parameter dwidth = 8; |
|
input [awidth -1:0] address; |
input inclock; |
input we; |
input [dwidth -1:0] data; |
output [dwidth -1:0] q; |
|
// synopsis translate_off |
// exemplar translate_off |
|
syn_ram_irou #( |
"UNUSED", |
dwidth, |
awidth, |
1 << awidth |
) |
altera_spram_model ( |
.Inclock(inclock), |
.Address(address), |
.Data(data), |
.WE(we), |
.Q(q) |
); |
|
// exemplar translate_on |
// synopsis translate_on |
|
endmodule |
`endif // VENDOR_ALTERA |
|
`ifdef VENDOR_XILINX |
module xilinx_ram_sp ( |
clk, |
rst, |
addr, |
di, |
en, |
we, |
do) /* synthesis black_box */ ; |
|
parameter awidth = 7; |
parameter dwidth = 8; |
|
input clk; |
input rst; |
input [awidth -1:0] addr; |
input [dwidth -1:0] di; |
input en; |
input we; |
output [dwidth -1:0] do; |
|
// insert simulation model |
|
|
// synopsys translate_off |
// exemplar translate_off |
|
C_MEM_SP_BLOCK_V1_0 #( |
awidth, |
1, |
"0", |
1 << awidth, |
1, |
1, |
1, |
1, |
1, |
1, |
1, |
"", |
16, |
0, |
0, |
1, |
1, |
dwidth |
) |
xilinx_spram_model ( |
.CLK(clk), |
.RST(rst), |
.ADDR(addr), |
.DI(di), |
.EN(en), |
.WE(we), |
.DO(do) |
); |
|
// exemplar translate_on |
// synopsys translate_on |
|
endmodule |
`endif // VENDOR_XILINX |
|
/trunk/rtl/z80_inst_exec.v
0,0 → 1,1235
/////////////////////////////////////////////////////////////////////////////////////////////////// |
// // |
// file name: inst_exec.v // |
// description: main execution engine for wishbone z80 // |
// project: wb_z80 // |
// // |
// Author: B.J. Porcella // |
// e-mail: bporcella@sbcglobal.net // |
// // |
// // |
// // |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2000-2002 B.J. Porcella // |
// Real Time Solutions // |
// // |
// // |
// 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY // |
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED // |
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS // |
// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR // |
// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, // |
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // |
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE // |
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR // |
// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // |
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // |
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT // |
// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // |
// POSSIBILITY OF SUCH DAMAGE. // |
// // |
//-------1---------2---------3--------Comments on file -------------7---------8---------9--------0 |
// |
// This file contains the data related registers of the z80 and the |
// logic required to update them. Included registers are: |
// ar fr |
// br cr |
// dr er |
// hr lr |
// ixr |
// iyr |
// intr |
// |
// and the "prime" registers |
// ap fp |
// bp cp |
// dp ep |
// hp lp |
// |
// This logic can be considered a "slave" to the memstate sequencer (in memstate2.v). |
// as memstate sequencer executes any instruction from ir1 (the of - os pipe) the instruction |
// gets transferred to ir2 - which now becomes active. |
// |
// In the case of any memory type instruction (HL) , the pipeline must stall 1 tick to get the |
// operand into the nn register. This file logic needs not understand any of that -- just |
// execute when told to (ir2_val). |
// |
// From a block diagram standpoint this file is somewhat messy. There are multiple ALU's and |
// multiple source multiplexors. Part of the reason for this is hardware speed - the |
// various additions start pretty early in the cycle ( as not much decode logic is needed to |
// get them started. In parallel with that - the destination selectors ( which require more |
// complex decoding logic ) are "doing thier thing" No claim that this is absolute optimum - any |
// good synthesizer should be able to make the basic structure faster when flattened. However, |
// the intention is that even if the synthesizer is pretty primitive -- reasonably fast hardware |
// will be produced. |
// |
//-------1---------2---------3--------CVS Log -----------------------7---------8---------9--------0 |
// |
// $Id: z80_inst_exec.v,v 1.1 2004-04-27 21:27:13 bporcella Exp $ |
// |
// $Date: 2004-04-27 21:27:13 $ |
// $Revision: 1.1 $ |
// $Author: bporcella $ |
// $Locker: $ |
// $State: Exp $ |
// |
// Change History: |
// $Log: not supported by cvs2svn $ |
// Revision 1.4 2004/04/19 19:13:27 bporcella |
// real lint problems pretty much fixed -- need another look - but need to get on to other things first |
// |
// Revision 1.3 2004/04/19 05:09:11 bporcella |
// fixed some lint problems -- |
// |
// Revision 1.2 2004/04/18 18:50:08 bporcella |
// fixed some lint problems -- |
// |
// Revision 1.1.1.1 2004/04/13 23:49:54 bporcella |
// import first files |
// |
// |
// |
//-------1---------2---------3--------Module Name and Port List------7---------8---------9--------0 |
module z80_inst_exec( br_eq0, |
cr_eq0, |
upd_ar, upd_br, upd_cr, upd_dr, upd_er, upd_hr, upd_lr,upd_fr, |
ar, fr, br, cr, dr, er, hr, lr, |
ixr, iyr, add16, |
exec_ir2, |
exec_decbc, exec_decb, |
ir2, |
clk, |
rst, |
nn, sp, |
dd_grp, |
fd_grp |
); |
|
//-------1---------2---------3--------Output Ports---------6---------7---------8---------9--------0 |
output br_eq0; |
output cr_eq0; |
output upd_ar, upd_br, upd_cr, upd_dr, upd_er, upd_hr, upd_lr,upd_fr; |
output [7:0] ar, fr, br, cr, dr, er, hr, lr; |
output [15:0] ixr, iyr; |
output [15:0] add16; |
//-------1---------2---------3--------Input Ports----------6---------7---------8---------9--------0 |
input exec_ir2; |
input exec_decbc; // in general this needs to happen at different time from exec |
input exec_decb; // in general - we don't have the EB instruction (yet) when this hits |
input [9:0] ir2; |
input clk; |
input rst; |
input [15:0] nn, sp; |
input dd_grp; // this must be ir2 |
input fd_grp; |
|
//-------1---------2---------3--------Parameters-----------6---------7---------8---------9--------0 |
`include "opcodes.v" |
|
//-------1---------2---------3--------Wires----------------6---------7---------8---------9--------0 |
|
//wire [7:0] src_pqr; // arithmetic sources gven by ir2[2:0] |
wire [7:0] src_hr ; |
wire [7:0] src_lr ; |
//wire [7:0] alu_out; // {CF. 8bit_result} |
//wire alu_cry; |
|
//wire c_in0, c_out7, c_in8, c_out11, cout15; |
wire [15:0] src_a, src_b; |
wire [15:0] add16; |
wire sf, zf, f5f, hf, f3f, pvf, nf, cf; |
wire [7:0] daa_alu; // {cry, number} hf goes to 0 always. |
wire daa_cry; |
wire upd_ar, upd_br, upd_cr, upd_dr, upd_er, upd_fr, upd_hr, upd_lr; |
wire c_8out3; |
wire [7:0] add_8bit; |
|
wire [15:0] src_dblhr ; |
//wire src_cb_r20 ; |
wire [7:0] src_pqr20 ; |
wire [7:0] src_pqr53 ; |
wire [15:0] src_dbl ; |
wire [7:0] alu8_fr ; |
wire alu8_nf ; |
wire c_8out7 ; |
wire alu8_cry ; |
wire alu8_hcry ; |
wire [7:0] alu8_out ; |
wire add16_ofl ; |
wire c_16out7 ; |
wire c_16out11 ; |
wire c_16out15 ; |
wire c_16in0 ; |
wire sh_cry ; |
wire [7:0] sh_alu ; |
wire sh_alu_act ; |
wire bit_alu_act ; |
wire [7:0] bit_alu ; |
wire [7:0] decc_alu ; |
wire [7:0] decb_alu ; |
wire upd_a_alu8 ; |
wire up_a_sh_alu ; |
wire up_a_src_pqr ; |
wire up_a_n ; |
wire upd_b_alu8 ; |
wire up_b_src_pqr ; |
wire up_b_add16 ; |
wire [7:0] sh_src ; |
|
wire up_c_add16 ; |
wire upd_c_alu8 ; |
wire up_c_src_pqr ; |
wire up_d_add16 ; |
wire upd_d_alu8 ; |
wire up_d_src_pqr ; |
wire up_e_add16 ; |
wire upd_e_alu8 ; |
wire up_e_src_pqr ; |
wire up_h_add16 ; |
wire upd_h_alu8 ; |
wire upd_h_src_pqr ; |
wire up_l_add16 ; |
wire upd_l_alu8 ; |
wire upd_l_src_pqr ; |
|
wire upd_fr_alu8 ; |
wire upd_fr_add16 ; |
wire upd_fr_edadd16 ; |
wire upd_fr_sh ; |
wire upd_fr_cbsh ; |
wire eb_blk_mv ; |
wire ed_blk_cp ; |
wire c_8in0 ; |
|
//-------1---------2---------3--------Registers------------6---------7---------8---------9--------0 |
|
reg [7:0] ar, fr, br, cr, dr, er, hr, lr, intr; |
reg [7:0] ap, fp, bp, cp, dp, ep, hp, lp; |
reg [15:0] ixr, iyr; |
//-------1---------2---------3--------Assignments----------6---------7---------8---------9--------0 |
|
// it appears that dd and fd as a prefix to cb has a significantly modfied fuction...... |
// specifically, it is assumed that a memory operation is to be implemented (ix + d) |
// , In fact the |
// pipeline is such that we can make a fetch for free - so we will do that..... the |
// prefix flags should not be set here -- all we will know on execution is that it is a |
// cb instruction. ---- src is always nn |
assign src_hr = dd_grp ? ixr[15:8] : |
fd_grp ? iyr[15:8] : |
hr ; |
|
assign src_lr = dd_grp ? ixr[7:0] : |
fd_grp ? iyr[7:0] : |
lr ; |
|
assign src_dblhr = dd_grp ? ixr : // ed grp instructions (ADC HL ; SBC HL are not affected - |
fd_grp ? iyr : // instruction assembler assures this - ed_grp has no prefix |
{hr, lr} ; |
// ddcb_grp not defined - src_cb_r20 not used. Why these lines? 4/17/2004 |
//assign src_cb_r20 = (ddcb_grp | fdcb_grp) ? nn[7:0] : |
// cb_grp ? src_pqr20 : |
// ar ; |
assign br_eq0 = ~|br; // for first cut do this quick and dirty. |
assign cr_eq0 = ~|cr; // if this becomes a critical path - make these registers. |
assign src_pqr20 = {8{ir2[2:0]==REG8_B }} & br | |
{8{ir2[2:0]==REG8_C }} & cr | |
{8{ir2[2:0]==REG8_D }} & dr | |
{8{ir2[2:0]==REG8_E }} & er | |
{8{ir2[2:0]==REG8_H }} & src_hr | |
{8{ir2[2:0]==REG8_L }} & src_lr | |
{8{ir2[2:0]==REG8_MEM}} & nn[15:8] | |
{8{ir2[2:0]==REG8_A }} & ar ; |
|
assign src_pqr53 = {8{ir2[5:3]==REG8_B }} & br | |
{8{ir2[5:3]==REG8_C }} & cr | |
{8{ir2[5:3]==REG8_D }} & dr | |
{8{ir2[5:3]==REG8_E }} & er | |
{8{ir2[5:3]==REG8_H }} & src_hr | |
{8{ir2[5:3]==REG8_L }} & src_lr | |
{8{ir2[5:3]==REG8_MEM}} & nn[15:8] | |
{8{ir2[5:3]==REG8_A }} & ar ; |
|
|
assign src_dbl = {16{ir2[5:4]==2'b00}} & {br, cr} | |
{16{ir2[5:4]==2'b01}} & {dr, er} | |
{16{ir2[5:4]==2'b10}} & src_dblhr | // HL, ixr, iyr |
{16{ir2[5:4]==2'b11}} & sp ; |
|
assign sh_src = ir2[8] & dd_grp ? nn[15:8] : |
ir2[8] & fd_grp ? nn[15:8] : |
ir2 ? src_pqr20 : |
ar ; |
// I wonder how well the synthesizer can reduce this??? - It is probably worth spending |
// some time during physical design to see if a more low level description would help -- |
// there is somebody out there who knows - and there is probably a good low level description. |
// |
// guess its kind of important to understand precisely what the synthesizer does |
// with some of the status things we need also. |
// |
// |
// The nastiest status to get is HF. Really need 4 bit adders to do that ( or reproduce a lot |
// of logic.) I don't have a lot of confdence in the synthesier's ability to minimize arithmetic |
// operations -- Its a moving target of course, but I've seen some really silly stuff come out |
// of synthesis when you use a "+" operator. guess I will be pretty explicit here. |
// Documentation of the HF is srange. IN and OUT operators are defined as X -- but 16 bit operations |
// get set by CRY from bit 11. (Do I care??? ) well probably not but it is documented - so should |
// be tested i guess. |
// |
// |
// may want to re-define as a module with carry look-ahead ? |
// |
// Had a notion to define a single adder - subtractor for both 8 and 16 bit operations, but |
// getting into source mux issues that solution scared me..... Worry the cry flag might |
// become a worst case path. As defined, a good chunk of the decode process can go on in |
// parallel with the cry computation --- with final decisions made using a small mux at |
// the flag register. |
// ------------ 8 bit adder for accumulator ops plus the INC DEC ops --------------------- |
// It is documented that the hf is modified by the INC and DEC ops even if ar is not the |
// destination of result --- clearly hf and nf are pretty usless on a INC B but ours is |
// not to reason why :-) ---- well its fun to bitch about silly stuff like this. |
// ( not as much fun to deal with instruction tests testing "features" -- or worse programmers |
// who figure out ways to use theses "features". ) |
// |
// 8 bit adder with cry out of bit 3 used for most operations on A as well as the |
// inc/dec instructions. also need to get ED44 (ar <= -ar) working here |
wire [7:0] src_pqri; // use just here and below |
wire [7:0] src_aor_cnst = ed_blk_cp ? ar : // CPI CPIR CPD CPDR |
ir2[9] ? 8'h0 : // for ed44 -a //ed_grp == ir2[9] |
ir2[7] ? ar : |
ir2[0] ? 8'hff : |
8'h00 ; |
|
//--------------- the "standard" flag logic ----------------------------- |
// sf zf f5f hf |
assign alu8_fr ={alu8_out[7], ~|alu8_out, alu8_out[5], alu8_hcry, |
// f3f fpv fn fc |
alu8_out[3], alu8_out[7], alu8_nf, c_8out7 }; |
|
//assign alu8_pvf = (ir2[7:3]==5'b10100 | ir2[7:3]==5'b10101 | ir2[7:3]==5'b10110) ? |
// ~^alu8_out : // even parity |
// (src_aor_cnst[7]==src_pqri[7]) & (src_aor_cnst[7]!=alu8_out[7]) ; // ofl |
|
assign alu8_nf = (ir2[7:3]==5'b10010) | |
(ir2[7:3]==5'b10011) | |
(ir2[7:6]==2'b00) & ir2[0] | |
ir2[9] ; |
|
assign {c_8out3, add_8bit[3:0]} = {1'b0, src_aor_cnst[3:0]} + {1'b0, src_pqri[3:0]} + {4'b0, c_8in0}; |
//wire [4:0] ha_temp = {1'b0, src_aor_cnst[3:0]} + {1'b0, src_pqri[3:0]} + {4'b0, c_8in0}; |
//assign c_8out3 |
|
assign {c_8out7, add_8bit[7:4]} = {1'b0, src_aor_cnst[7:4]} + {1'b0, src_pqri[7:4]} + {4'b0, c_8out3}; |
|
// notice that both inputs and outputs of the adder are being selected below. |
// making ed_blk_cp high priority kind of negates the origional idea of making the |
// decodes fast here --- course when all is included this can't be too fast. |
// Just note for syntheses that this is a slow path that could be improved with some thought. |
// 1 1 8 8 1 |
assign {alu8_cry, alu8_hcry, alu8_out, src_pqri, c_8in0 }= |
|
ed_blk_cp ? {c_8out7,c_8out3, add_8bit, ~src_pqr20, 1'h1} : //CPI CPIR CPD CPDR |
|
{19{ir2[7:3]==5'b10000}} & ({c_8out7,c_8out3, add_8bit, src_pqr20, 1'b0} ) |// a+src |
{19{ir2[7:3]==5'b10001}} & ({c_8out7,c_8out3, add_8bit, src_pqr20, cf} ) |// a+src+cf |
{19{ir2[7:3]==5'b10010}} & ({c_8out7,c_8out3, add_8bit, ~src_pqr20, 1'h1} ) |// a-src |
{19{ir2[7:3]==5'b10011}} & ({c_8out7,c_8out3, add_8bit, ~src_pqr20, ~cf } ) |// a-src-cf |
{19{ir2[7:3]==5'b10100}} & ({1'b0 ,1'b1 , ar & src_pqr20, src_pqr20, 1'b0} ) |// a&src |
{19{ir2[7:3]==5'b10101}} & ({1'b0 ,1'b0 , ar ^ src_pqr20, src_pqr20, 1'b0} ) |// a^src |
{19{ir2[7:3]==5'b10110}} & ({1'b0 ,1'b0 , ar | src_pqr20, src_pqr20, 1'b0} ) |// a|src |
{19{ir2[7:3]==5'b10111}} & ({c_8out7,c_8out3, add_8bit, src_pqr20, 1'h1}) |// a-src |
{19{(ir2[7:6]==2'b00)& ~ir2[0] }}& ({ cf,c_8out3, add_8bit, src_pqr53, 1'h1}) |// inc_r main |
{19{(ir2[7:6]==2'b00)& ir2[0] }}& ({ cf,c_8out3, add_8bit, src_pqr53, 1'h0}) |// dec_r |
{19{(ir2[7:6]==2'b01) }}& ({c_8out7,c_8out3, add_8bit, ~ar, 1'h1}) ;// ed44 -a |
|
|
// do some hand decoding here |
// ADDsHL_BC = 'h09, DECsBC = 'h0B, INCsBC = 'h03 compair with {ir2[7:6],ir2[3:0]} |
// ADDsHL_DE = 'h19, DECsDE = 'h1B INCsDE = 'h13 ED_SBCsHL_REG = 6'b01__0010 |
// ADDsHL_HL = 'h29, DECsHL = 'h2B INCsHL = 'h23 ED_ADCsHL_REG = 6'b01__1010 |
// ADDsHL_SP = 'h39, DECsSP = 'h3B INCsSP = 'h33 |
// by inspection just use ir2[3:0] - i guess in a pinch we do't need ir2[2] = but let the |
// synthesizer figure that out. - it should be able to. |
// |
|
|
// ---------------- 16 bit adder with bit 11 carrry out and bit 8 carry in ------------------ |
// |
assign add16_ofl = (src_a[15] == src_b[15]) & (src_a[15] != add16[15]); |
///tmp/lint/wb_z80/rtl/inst_exec.v(363): Warning 22014: synchronous loop without set/reset detected on signal "src_b[11:8]" (OC) |
assign {c_16out7, add16[7:0]} = {1'b0, src_a[7:0]} + {1'b0, src_b[7:0] } + {8'b0, c_16in0}; |
assign {c_16out11, add16[11:8]} = {1'b0, src_a[11:8]} + {1'b0, src_b[11:8] } + {4'b0, c_16out7}; |
assign {c_16out15, add16[15:12]} = {1'b0, src_a[15:12]} + {1'b0, src_b[15:12]} + {4'b0, c_16out11}; |
|
assign { src_a, src_b, c_16in0} = // assigning 33 bits |
{33{ir2[3:0] == 4'h9}} & {src_dblhr, src_dbl ,1'b0 } | //ADD |
{33{ir2[3:0] == 4'hb}} & {16'hffff , src_dbl ,1'b0 } | //DEC |
{33{ir2[3:0] == 4'h3}} & {16'h0001 , src_dbl ,1'b0 } | //INC |
{33{ir2[3:0] == 4'h2}} & {src_dblhr, ~src_dbl , ~cf } | //SBC |
{33{ir2[3:0] == 4'ha}} & {src_dblhr, src_dbl , cf } ; //ADC |
|
//-------------------------- sh alu -------------------------------------------------- |
// shift insructions. Think of these as 8 shift types: |
// RLC RL RRC RR SLA SLL SRA SRL The SLL types appear to be undocumented -- but possibly used |
// in assembly code as they appear to have some utility - and by all accounts operate reliably. |
// The first four are implemented in a single byte inaruction . (A <= sh_op A ) |
// All 8 are implemented in the CB group with all registers as potential sources (and dests). |
// if dd_grp or fd_grp is prefix..... source is always the memory. This is undocumented - but |
// may be a useful hint for simplyfing the total machine. Destination registers |
// (if any) get a copy of the updated memory location (This is also true of the bit set and |
// clear instructions in the cb_grp. |
|
assign {sh_cry, sh_alu} = {9{ir2[5:3]==3'b000}} & {sh_src, sh_src[7] } | //RLC |
{9{ir2[5:3]==3'b001}} & {sh_src[0], sh_src[0], sh_src[7:1]} | // RRC |
{9{ir2[5:3]==3'b010}} & {sh_src, cf } | //RL |
{9{ir2[5:3]==3'b011}} & {sh_src[0], cf, sh_src[7:1] } | // RR |
{9{ir2[5:3]==3'b100}} & {sh_src, 1'b0} | //SLA |
{9{ir2[5:3]==3'b101}} & {sh_src[0], sh_src[7], sh_src[7:1]} | //SRA |
{9{ir2[5:3]==3'b110}} & {sh_src, 1'b1} | //SLL |
{9{ir2[5:3]==3'b111}} & {sh_src[0], 1'b0, sh_src[7:1]} ; //SRL |
|
|
// shift insts |
assign sh_alu_act = ir2[9:6] == 4'b0100; |
//CB_RLC = 7'b01_00_000, // these must be compaired with ir2[9:3] |
//CB_RRC = 7'b01_00_001, // these must be compaired with ir2[9:3] |
//CB_RL = 7'b01_00_010, // these must be compaired with ir2[9:3] |
//CB_RR = 7'b01_00_011, // these must be compaired with ir2[9:3] |
//CB_SLA = 7'b01_00_100, // these must be compaired with ir2[9:3] |
//CB_SRA = 7'b01_00_101, // these must be compaired with ir2[9:3] |
//CB_SLL = 7'b01_00_110, // these must be compaired with ir2[9:3] |
//CB_SRL = 7'b01_00_111, // these must be compaired with ir2[9:3] |
|
//---------------------------- bit test alu --------------------------------------- |
// bit test insts |
//CB_BIT = 4'b01_01, // these must be compaired with ir2[9:6] |
//CB_RES = 4'b01_10, // these must be compaired with ir2[9:6]assign |
//CB_SET = 4'b01_11, // these must be compaired with ir2[9:6] |
assign bit_alu_act = ir2[9:6] == CB_BIT | |
ir2[9:6] == CB_RES | |
ir2[9:6] == CB_RES ; |
|
wire [7:0] bit_decode = {8{ir2[5:3] == 3'h0}} & 8'h01 | |
{8{ir2[5:3] == 3'h1}} & 8'h02 | |
{8{ir2[5:3] == 3'h2}} & 8'h04 | |
{8{ir2[5:3] == 3'h3}} & 8'h08 | |
{8{ir2[5:3] == 3'h4}} & 8'h10 | |
{8{ir2[5:3] == 3'h5}} & 8'h20 | |
{8{ir2[5:3] == 3'h6}} & 8'h40 | |
{8{ir2[5:3] == 3'h7}} & 8'h80 ; |
|
assign bit_alu = {8{ir2[9:6] == CB_BIT}} & ( sh_src & bit_decode) | |
{8{ir2[9:6] == CB_RES}} & ( sh_src & ~bit_decode) | |
{8{ir2[9:6] == CB_RES}} & ( sh_src | bit_decode) ; |
|
|
//------------ dec bc alu --------------------------------------------- |
//exec_decbc; these are all we know (in general) |
//exec_decb; |
assign decc_alu = cr + 8'hff ; |
assign decb_alu = br + ( exec_decb ? 8'hff : // just dec b if io blk move |
cr_eq0 ? 8'hff : // cry out if c in this case |
8'h00 ); // only dec c reg this tick |
// ------------------ daa alu ------------------------------------------------------- |
// the documentation does not cover all cases here -- only those that matter (i suppose). |
// ( documentation assumes you are operating with 2 daa'd numbers -- but of course the |
// ar can contain many values that don't fit that assumption when this instruction is executed. |
// Any arbitrary instruction test may test un-documented cases. |
// |
// this leaves me to guess what the actual logic is - and how to match it. |
// So I am doing that -- see what happens. If an instruction test breaks this... I should be |
// able to fix it easily. |
// |
wire [3:0] ls_nbl = (!nf & hf) ? 4'h6: |
(!nf & (ar[3:0] > 4'h9)) ? 4'h6: |
(nf & hf ) ? 4'ha: |
4'h0; |
|
wire [4:0] ms_nbl = (!nf & cf) ? 5'h16: // includes new cry |
(!nf & (ar[3:0] > 4'h9)) ? 5'h16: |
(!nf & (ar[3:0] == 4'h9) & |
(ar[3:0] > 4'h9)) ? 5'h16: |
(nf & !cf & hf ) ? 5'h0f: |
(nf & cf & !hf ) ? 5'h1a: |
(nf & cf & hf ) ? 5'h19: |
5'h00; |
|
|
assign {daa_cry, daa_alu} = { ms_nbl[4], {ar + { ms_nbl[3:0], ls_nbl}} } ; |
|
|
//-------1---------2---------3--------State Machines-------6---------7---------8---------9--------0 |
|
// update ar |
|
assign upd_a_alu8 = |
ADDsA_B == ir2 | SUBsB == ir2 | ANDsB == ir2 | ORsB == ir2 | |
ADDsA_C == ir2 | SUBsC == ir2 | ANDsC == ir2 | ORsC == ir2 | |
ADDsA_D == ir2 | SUBsD == ir2 | ANDsD == ir2 | ORsD == ir2 | |
ADDsA_E == ir2 | SUBsE == ir2 | ANDsE == ir2 | ORsE == ir2 | |
ADDsA_H == ir2 | SUBsH == ir2 | ANDsH == ir2 | ORsH == ir2 | |
ADDsA_L == ir2 | SUBsL == ir2 | ANDsL == ir2 | ORsL == ir2 | |
ADDsA_6HL7 == ir2 | SUBs6HL7 == ir2 | ANDs6HL7 == ir2 | ORs6HL7 == ir2 | |
ADDsA_A == ir2 | SUBsA == ir2 | ANDsA == ir2 | ORsA == ir2 | |
ADCsA_B == ir2 | SBCsB == ir2 | XORsB == ir2 | |
ADCsA_C == ir2 | SBCsC == ir2 | XORsC == ir2 | INCsA == ir2 | |
ADCsA_D == ir2 | SBCsD == ir2 | XORsD == ir2 | DECsA == ir2 | |
ADCsA_E == ir2 | SBCsE == ir2 | XORsE == ir2 | |
ADCsA_H == ir2 | SBCsH == ir2 | XORsH == ir2 | |
ADCsA_L == ir2 | SBCsL == ir2 | XORsL == ir2 | |
ADCsA_6HL7 == ir2 | SBCs6HL7 == ir2 | XORs6HL7 == ir2 | |
ADCsA_A == ir2 | SBCsA == ir2 | XORsA == ir2 | |
ADDsA_N == ir2 | // ADD A,N ; C6 XX ADDsA_6HL7 = 'h86 |
ADCsA_N == ir2 | // ADC A,N ; CE XX ADCsA_6HL7 = 'h8E |
SUBsN == ir2 | // SUB N ; D6 XX SUBs6HL7 = 'h96 |
SBCsA_N == ir2 | // SBC A,N ; DE XX |
ANDsN == ir2 | // AND N ; E6 XX |
XORsN == ir2 | // XOR N ; EE XX |
ORsN == ir2 ; // OR N ; F6 XX |
assign up_a_sh_alu = |
RLCA == ir2 | // RLCA ; 07 |
RRCA == ir2 | // RRCA ; 0F |
RRA == ir2 | // RRA ; 1F |
RLA == ir2 ; // RLA ; 17 |
assign up_a_src_pqr = |
LDsA_B == ir2 | // LD A,B ; 78 |
LDsA_C == ir2 | // LD A,C ; 79 |
LDsA_D == ir2 | // LD A,D ; 7A |
LDsA_E == ir2 | // LD A,E ; 7B |
LDsA_H == ir2 | // LD A,H ; 7C |
LDsA_L == ir2 | // LD A,L ; 7D |
LDsA_6HL7 == ir2 | // LD A,(HL) ; 7E |
LDsA_A == ir2 ; // LD A,A ; 7F |
assign up_a_n = |
LDsA_N == ir2 | // LD A,N ; 3E XX |
LDsA_6BC7 == ir2 | // LD A,(BC) ; 0A |
LDsA_6DE7 == ir2 | // LD A,(DE) ; 1A |
LDsA_6NN7 == ir2 | // LD A,(NN) ; 3A XX XX |
INsA_6N7 == ir2 | // IN A,(N) ; DB XX |
(ED_INsREG_6C7 == {ir2[9:6],ir2[2:0]}) & (ir2[5:3] == REG8_A) ; |
|
|
//EXsAF_AFp = 10'h08,// EX AF,AF' ; 08 |
//EXX = 10'hD9,// EXX ; D9 |
//DAA = 10'h27,// DAA ; 27 |
//CPL = 10'h2F,// CPL ; 2F a <= ~a |
//POPsAF = 10'hF1,// POP AF ; F1 |
// don't forget these beauties not affected by prefixes |
//ED_RRD = 'h67// RRD ; |
//ED_RLD = 'h6F// RLD ; ED 6F nibble roates A (HL) |
//ED_NEG = 5'b01___100, // A<= -A compair with {ir2[9:6],ir2[2:0]} |
|
//------------------------------- ar ------------------------------------------ |
|
assign upd_ar = upd_a_alu8 | up_a_sh_alu | up_a_src_pqr | up_a_n | ir2 == EXsAF_AFp | |
ir2 == EXX | ir2 == DAA | ir2 == CPL | ir2 == POPsAF | |
ir2[2:0] == REG8_A & bit_alu_act | ir2[2:0] == REG8_A & sh_alu_act | |
ir2== ED_RRD | {ir2[9:6], ir2[2:0]} == ED_NEG | |
ir2 == ED_LDsA_I ; |
|
always @(posedge clk) |
begin |
if (upd_a_alu8 & exec_ir2) ar <= alu8_out; |
if (up_a_sh_alu & exec_ir2) ar <= sh_alu; |
if (up_a_src_pqr & exec_ir2) ar <= src_pqr20; |
if (up_a_n & exec_ir2) ar <= nn[7:0]; |
if (ir2 == EXsAF_AFp & exec_ir2) ar <= ap; |
if (ir2 == EXX & exec_ir2) ar <= ap; |
if (ir2 == DAA & exec_ir2) ar <= daa_alu; |
if (ir2 == CPL & exec_ir2) ar <= ~ar; |
if (ir2 == POPsAF & exec_ir2) ar <= nn[15:8]; |
if (ir2[2:0] == REG8_A & |
bit_alu_act & exec_ir2) ar <= bit_alu; |
if (ir2[2:0] == REG8_A & |
sh_alu_act & exec_ir2) ar <= sh_alu; |
if (ir2 == ED_RRD & exec_ir2) ar[3:0] <= nn[3:0]; |
if (ir2 == ED_RLD & exec_ir2) ar[3:0] <= nn[7:4]; |
if ({ir2[9:6], ir2[2:0]} == ED_NEG & exec_ir2) ar <= alu8_out; // ED44 this done by alu8 for flags |
if (ir2 == ED_LDsA_I & exec_ir2) ar <= ir2[7:0] ; |
end |
|
|
|
|
// update br |
//assign upd_b_decbc = |
// ED_LDI == ir2 | // LDI ; ED A0 |
// ED_CPI == ir2 | // CPI ; ED A1 |
// ED_LDD == ir2 | // LDD ; ED A8 |
// ED_CPD == ir2 | // CPD ; ED A9 |
// ED_LDIR == ir2 | // LDIR ; ED B0 |
// ED_CPIR == ir2 | // CPIR ; ED B1 |
// ED_LDDR == ir2 | // LDDR ; ED B8 |
// ED_CPDR == ir2 ;// CPDR ; ED B9 |
|
//assign eb_io = |
|
// ED_INI == ir2 | // INI ; ED A2 |
// ED_IND == ir2 | // IND ; ED AA |
// ED_OUTD == ir2 | // OUTD ; ED AB |
// ED_OUTI == ir2 | // OUTI ; ED A3 |
// ED_INIR == ir2 | // INIR ; ED B2 |
// ED_OTIR == ir2 | // OTIR ; ED B3 |
// ED_INDR == ir2 | // INDR ; ED BA |
// ED_OTDR == ir2 ; // OTDR ; ED BB |
|
assign upd_b_alu8 = |
INCsB == ir2 |// INC B ; 04 |
DECsB == ir2 ;// DEC B ; 05 |
|
|
assign up_b_src_pqr = |
LDsB_B == ir2 |// LD B,B ; 40 |
LDsB_C == ir2 |// LD B,C ; 41 |
LDsB_D == ir2 |// LD B,D ; 42 |
LDsB_E == ir2 |// LD B,E ; 43 |
LDsB_H == ir2 |// LD B,H ; 44 |
LDsB_L == ir2 |// LD B,L ; 45 |
LDsB_6HL7 == ir2 |// LD B,(HL) ; 46 |
LDsB_A == ir2 ;// LD B,A ; 47 |
assign up_b_add16 = |
INCsBC == ir2 |// INC BC ; 03 |
DECsBC == ir2 ;// DEC BC ; 0B |
//LDsBC_nn = 10'h01,// LD BC,NN ; 01 XX XX |
//POPsBC = 10'hC1,// POP BC ; C1 |
//EXX = 10'hD9,// EXX ; D9 |
//LDsB_N = 10'h06,// LD B,N ; 06 XX |
//DJNZs$t2 = 10'h10,// DJNZ $+2 ; 10 XX //pre dec br |
//ED_RRD = 'h67// RRD ; ED 67 nibble roates A HL |
//ED_RLD = 'h6F// RLD ; ED 6F nibble roates A HL |
//ED_INsREG_6C7 = 5'b01___000,// compair with {ir2[7:6],ir2[2:0]} really (BCio) |
|
//------------------------------- br ----------------------------------------- |
|
assign upd_br = upd_b_alu8 | up_b_src_pqr | up_b_add16 | LDsBC_NN == ir2 | |
POPsBC == ir2 | EXX == ir2 | LDsB_N == ir2 | |
ir2[2:0] == REG8_B & bit_alu_act | ir2[2:0] == REG8_B & sh_alu_act | |
DJNZs$t2 == ir2 | (ED_INsREG_6C7 == {ir2[9:6],ir2[2:0]}) & (ir2[5:3] == REG8_B); |
|
|
always @(posedge clk) |
begin |
if ( upd_b_alu8 & exec_ir2) br <= alu8_out; |
if ( up_b_src_pqr & exec_ir2) br <= src_pqr20; |
if ( up_b_add16 & exec_ir2) br <= add16[15:8]; |
if ( LDsBC_NN == ir2 & exec_ir2) br <= nn[15:8]; |
if ( POPsBC == ir2 & exec_ir2) br <= nn[15:8]; |
if ( EXX == ir2 & exec_ir2) br <= bp; |
if ( LDsB_N == ir2 & exec_ir2) br <= nn[7:0]; |
if (ir2[2:0] == REG8_B & |
bit_alu_act & exec_ir2) br <= bit_alu; |
if (ir2[2:0] == REG8_B & |
sh_alu_act & exec_ir2) br <= sh_alu; |
if ( DJNZs$t2 == ir2 & exec_ir2) br <= br + 8'hff; // use seperate adder here as no flags |
// change -- we need br==0. for now |
// use |br. If we need more speed add |
// a ff. |
if (exec_decb | exec_decbc) br <= decb_alu; |
if ( (ED_INsREG_6C7 == {ir2[7:6],ir2[2:0]}) & (ir2[5:3] == REG8_B) & exec_ir2 ) |
br <= nn[7:0]; |
end |
|
|
// update cr |
assign up_c_add16 = |
INCsBC == ir2 |// INC BC ; 03 |
DECsBC == ir2 ;// DEC BC ; 0B, |
assign upd_c_alu8 = |
INCsC == ir2 |// INC C ; 0C |
DECsC == ir2 ;// DEC C ; 0D |
assign up_c_src_pqr = |
LDsC_B == ir2 |// LD C,B ; 48 |
LDsC_C == ir2 |// LD C,C ; 49 |
LDsC_D == ir2 |// LD C,D ; 4A |
LDsC_E == ir2 |// LD C,E ; 4B |
LDsC_H == ir2 |// LD C,H ; 4C |
LDsC_L == ir2 |// LD C,L ; 4D |
LDsC_6HL7 == ir2 |// LD C,(HL) ; 4E |
LDsC_A == ir2 ;// LD C,A ; 4F |
|
|
//LDsC_N == ir2 |// LD C,N ; 0E XX |
//LDsBC_NN = 10'h01,// LD BC,NN ; 01 XX XX |
//POPsBC = 10'hC1,// POP BC ; C1 |
//EXX = 10'hD9,// EXX ; D9 |
//ED_INsREG_6C7 = 5'b01___000,// compair with {ir2[9:6],ir2[2:0]} really (BCio) |
|
//------------------------------- cr ----------------------------------------- |
assign upd_cr = upd_c_alu8 | up_c_src_pqr | up_c_add16 | LDsBC_NN == ir2 | |
POPsBC == ir2 | EXX == ir2 | LDsC_N == ir2 | |
ir2[2:0] == REG8_C & bit_alu_act | ir2[2:0] == REG8_C & sh_alu_act | |
(ED_INsREG_6C7 == {ir2[9:6],ir2[2:0]}) & (ir2[5:3] == REG8_C); |
|
|
|
always @(posedge clk) |
begin |
if ( upd_c_alu8 & exec_ir2) cr <= alu8_out; |
if ( up_c_src_pqr & exec_ir2) cr <= src_pqr20; |
if ( up_c_add16 & exec_ir2) cr <= add16[7:0]; |
if ( LDsBC_NN == ir2 & exec_ir2) cr <= nn[7:0]; |
if ( POPsBC == ir2 & exec_ir2) cr <= nn[7:0]; |
if ( EXX == ir2 & exec_ir2) cr <= cp; |
if ( LDsC_N == ir2 & exec_ir2) cr <= nn[7:0]; |
if (ir2[2:0] == REG8_C & |
bit_alu_act & exec_ir2) cr <= bit_alu; |
if (ir2[2:0] == REG8_C & |
sh_alu_act & exec_ir2) cr <= sh_alu; |
if ( exec_decbc) cr <= decc_alu; |
if ((ED_INsREG_6C7 == {ir2[9:6],ir2[2:0]}) & (ir2[5:3] == REG8_C) & exec_ir2) |
cr <= nn[7:0]; |
|
end |
|
|
// update dr |
assign up_d_add16 = |
INCsDE == ir2 | // INC DE ; 13 |
DECsDE == ir2 ; // DEC DE ; 1B |
|
assign upd_d_alu8 = |
INCsD == ir2 | // INC D ; 14 |
DECsD == ir2 ; // DEC D ; 15 |
assign up_d_src_pqr = |
LDsD_B == ir2 | //LD D,B ; 50 |
LDsD_C == ir2 | //LD D,C ; 51 |
LDsD_D == ir2 | //LD D,D ; 52 |
LDsD_E == ir2 | //LD D,E ; 53 |
LDsD_H == ir2 | //LD D,H ; 54 |
LDsD_L == ir2 | //LD D,L ; 55 |
LDsD_6HL7 == ir2 | //LD D,(HL) ; 56endmodule |
LDsD_A == ir2 ; //LD D,A ; 57 |
|
|
//LDsD_N = 10'h16,// LD D,N ; 16 XX |
//LDsDE_NN = 10'h11,// LD DE,NN ; 11 XX XX |
//POPsDE = 10'hD1,// POP DE ; D1 |
//EXX = 10'hD9,// EXX ; D9 |
//EXsDE_HL = 10'hEB,// EX DE,HL ; EB |
//ED_INsREG_6C7 = 5'b01___000,// compair with {ir2[9:6],ir2[2:0]} really (BCio) |
|
//---------------------------------- dr ------------------------------------ |
|
assign upd_dr = upd_d_alu8 | up_d_src_pqr | up_d_add16 | LDsDE_NN == ir2 | |
POPsDE == ir2 | EXX == ir2 | EXsDE_HL == ir2 | LDsD_N == ir2 | |
ir2[2:0] == REG8_D & bit_alu_act | ir2[2:0] == REG8_D & sh_alu_act | |
(ED_INsREG_6C7 == {ir2[9:6],ir2[2:0]}) & (ir2[5:3] == REG8_D); |
|
|
|
|
|
|
always @(posedge clk) |
begin |
if ( upd_d_alu8 & exec_ir2) dr <= alu8_out; |
if ( up_d_src_pqr & exec_ir2) dr <= src_pqr20; |
if ( up_d_add16 & exec_ir2) dr <= add16[15:8]; |
if ( LDsDE_NN == ir2 & exec_ir2) dr <= nn[15:8]; |
if ( POPsDE == ir2 & exec_ir2) dr <= nn[15:8]; |
if ( EXX == ir2 & exec_ir2) dr <= dp; |
if ( EXsDE_HL == ir2 & exec_ir2) dr <= hr; |
if ( LDsD_N == ir2 & exec_ir2) dr <= nn[7:0]; |
if (ir2[2:0] == REG8_D & |
bit_alu_act & exec_ir2) dr <= bit_alu; |
if (ir2[2:0] == REG8_D & |
sh_alu_act & exec_ir2) dr <= sh_alu; |
if ((ED_INsREG_6C7 == {ir2[9:6],ir2[2:0]}) |
& (ir2[5:3] == REG8_D) & exec_ir2) |
dr <= nn[7:0]; |
|
end |
|
// update er |
assign up_e_add16 = |
INCsDE == ir2 |// INC DE ; 13 |
DECsDE == ir2 ;// DEC DE ; 1B |
assign upd_e_alu8 = |
INCsE == ir2 |// INC E ; 1C |
DECsE == ir2 ;// DEC E ; 1D |
assign up_e_src_pqr = |
LDsE_B == ir2 |// LD E,B ; 58 |
LDsE_C == ir2 |// LD E,C ; 59 |
LDsE_D == ir2 |// LD E,D ; 5A |
LDsE_E == ir2 |// LD E,E ; 5B |
LDsE_H == ir2 |// LD E,H ; 5C |
LDsE_L == ir2 |// LD E,L ; 5D |
LDsE_6HL7 == ir2 |// LD E,(HL) ; 5E |
LDsE_A == ir2 ;// LD E,A ; 5F |
|
//LDsE_N = 10'h1E,// LD E,N ; 1E XX |
//LDsDE_NN = 10'h11,// LD DE,NN ; 11 XX XX |
//POPsDE = 10'hD1,// POP DE ; D1 |
//EXX = 10'hD9,// EXX ; D9 |
//EXsDE_HL = 10'hEB,// EX DE,HL ; EB |
//ED_INsREG_6C7 = 5'b01___000,// compair with {ir2[9:6],ir2[2:0]} really (BCio) |
|
//---------------------------------- er ------------------------------------ |
|
|
assign upd_er = upd_e_alu8 | up_e_src_pqr | up_e_add16 | LDsDE_NN == ir2 | |
POPsDE == ir2 | EXX == ir2 | EXsDE_HL == ir2 | LDsD_N == ir2 | |
ir2[2:0] == REG8_E & bit_alu_act | ir2[2:0] == REG8_E & sh_alu_act | |
(ED_INsREG_6C7 == {ir2[9:6],ir2[2:0]}) & (ir2[5:3] == REG8_E); |
|
|
|
|
|
|
|
|
|
always @(posedge clk) |
begin |
if ( upd_e_alu8 & exec_ir2) er <= alu8_out; |
if ( up_e_src_pqr & exec_ir2) er <= src_pqr20; |
if ( up_e_add16 & exec_ir2) er <= add16[7:0]; |
if ( LDsDE_NN == ir2 & exec_ir2) er <= nn[7:0]; |
if ( POPsDE == ir2 & exec_ir2) er <= nn[7:0]; |
if ( EXX == ir2 & exec_ir2) er <= ep; |
if ( EXsDE_HL == ir2 & exec_ir2) er <= hr; |
if ( LDsE_N == ir2 & exec_ir2) er <= nn[7:0]; |
if (ir2[2:0] == REG8_E & |
bit_alu_act & exec_ir2) er <= bit_alu; |
if (ir2[2:0] == REG8_E & |
sh_alu_act & exec_ir2) er <= sh_alu; |
if ((ED_INsREG_6C7 == {ir2[9:6],ir2[2:0]}) & (ir2[5:3] == REG8_E) & exec_ir2) |
er <= nn[7:0]; |
|
end |
|
|
// update hr |
assign up_h_add16 = |
ADDsHL_BC == ir2 | // ADD HL,BC ; 09 |
ADDsHL_DE == ir2 | // ADD HL,DE ; 19 |
ADDsHL_HL == ir2 | // ADD HL,HL ; 29 |
ADDsHL_SP == ir2 | // ADD HL,SP ; 39 |
INCsHL == ir2 | // INC HL ; 23 |
DECsHL == ir2 ; // DEC HL ; 2B |
assign upd_h_alu8 = |
INCsH == ir2 | // INC H ; 24 |
DECsH == ir2 ; // DEC H ; 25 |
assign upd_h_src_pqr = |
LDsH_B == ir2 | // LD H,B ; 60 |
LDsH_C == ir2 | // LD H,C ; 61 |
LDsH_D == ir2 | // LD H,D ; 62 |
LDsH_E == ir2 | // LD H,E ; 63 |
LDsH_H == ir2 | // LD H,H ; 64 |
LDsH_L == ir2 | // LD H,L ; 65 |
LDsH_6HL7 == ir2 | // LD H,(HL) ; 66 |
LDsH_A == ir2 ; // LD H,A ; 67 |
//ED_INsREG_6C7 = 5'b01___000,// compair with {ir2[9:6],ir2[2:0]} really (BCio) |
|
//POPsHL = 10'hE1,// POP HL ; E1 |
//EXs6SP7_HL = 10'hE3,// EX (SP),HL ; E3 |
//LDsHL_NN = 10'h21,// LD HL,NN ; 21 XX XX |
//LDsHL_6NN7 = 10'h2A,// LD HL,(NN) ; 2A XX XX |
//LDsH_N = 10'h26,// LD H,N ; 26 XX |
|
// only these are not affected by dd and fd prefixes |
//EXsDE_HL = 10'hEB,// EX DE,HL ; EB |
//EXX = 10'hD9,// EXX ; D9 |
|
//---------------------------------- hr ------------------------------------ |
// we just check hr and lr - the prefixes for use of ix and iy imply that something |
// pretty strange has to happen for a hazard related to use of those registers. We can |
// assume upd hr impies upd ix and iy without adverse timing consequences. |
// |
assign upd_hr = upd_h_alu8 | upd_h_src_pqr | up_h_add16 | LDsHL_NN == ir2 | LDsHL_6NN7== ir2 | |
POPsHL == ir2 | EXX == ir2 | EXsDE_HL == ir2 | LDsH_N == ir2 | |
ir2[2:0] == REG8_H & bit_alu_act | ir2[2:0] == REG8_H & sh_alu_act | |
(ED_INsREG_6C7 == {ir2[9:6],ir2[2:0]}) & (ir2[5:3] == REG8_H); |
|
|
|
|
wire exec_hlir2 = exec_ir2 & !(dd_grp | fd_grp); |
|
always @(posedge clk) |
begin |
if ( upd_h_alu8 & exec_hlir2) hr <= alu8_out; |
if ( upd_h_src_pqr & exec_hlir2) hr <= src_pqr20; |
if ( up_h_add16 & exec_hlir2) hr <= add16[15:8]; |
if ( LDsHL_NN == ir2 & exec_hlir2) hr <= nn[15:8]; |
if ( LDsHL_6NN7== ir2 & exec_hlir2) hr <= nn[15:8]; |
if ( POPsHL == ir2 & exec_hlir2) hr <= nn[15:8]; |
if ( EXs6SP7_HL== ir2 & exec_hlir2) hr <= nn[15:8]; |
if ( EXX == ir2 & exec_ir2) hr <= hp; |
if ( EXsDE_HL == ir2 & exec_ir2) hr <= dr; |
if ( LDsH_N == ir2 & exec_hlir2) hr <= nn[7:0]; |
if (ir2[2:0] == REG8_H & |
bit_alu_act & exec_hlir2) hr <= bit_alu; |
if (ir2[2:0] == REG8_H & |
sh_alu_act & exec_hlir2) hr <= sh_alu; |
if ((ED_INsREG_6C7 == {ir2[9:6],ir2[2:0]}) & (ir2[5:3] == REG8_H) & exec_ir2) |
hr <= nn[7:0]; |
|
end |
|
// update lr |
assign up_l_add16 = |
ADDsHL_BC == ir2 |// ADD HL,BC ; 09 |
ADDsHL_DE == ir2 |// ADD HL,DE ; 19 |
ADDsHL_HL == ir2 |// ADD HL,HL ; 29 |
ADDsHL_SP == ir2 |// ADD HL,SP ; 39 |
INCsHL == ir2 |// INC HL ; 23 |
DECsHL == ir2 ;// DEC HL ; 2B |
assign upd_l_alu8 = |
INCsL == ir2 |// INC L ; 2C |
DECsL == ir2 ;// DEC L ; 2D |
assign upd_l_src_pqr = |
LDsL_B == ir2 |// LD L,B ; 68 |
LDsL_C == ir2 |// LD L,C ; 69 |
LDsL_D == ir2 |// LD L,D ; 6A |
LDsL_E == ir2 |// LD L,E ; 6B |
LDsL_H == ir2 |// LD L,H ; 6C |
LDsL_L == ir2 |// LD L,L ; 6D |
LDsL_6HL7 == ir2 |// LD L,(HL) ; 6E |
LDsL_A == ir2 ;// LD L,A ; 6F |
//EXX = 10'hD9,// EXX ; D9 |
//POPsHL = 10'hE1,// POP HL ; E1 |
//EXs6SP7_HL = 10'hE3,// EX (SP),HL ; E3 |
//EXsDE_HL = 10'hEB,// EX DE,HL ; EB |
//LDsHL_NN = 10'h21,// LD HL,NN ; 21 XX XX |
//LDsHL_6NN7 = 10'h2A,// LD HL,(NN) ; 2A XX XX |
//LDsL_N = 10'h2E,// LD L,N ; 2E XX |
//ED_INsREG_6C7 |
|
|
|
//---------------------------------- lr ------------------------------------ |
assign upd_lr = upd_l_alu8 | upd_l_src_pqr | up_l_add16 | LDsHL_NN == ir2 | LDsHL_6NN7== ir2 | |
POPsHL == ir2 | EXX == ir2 | EXsDE_HL == ir2 | LDsL_N == ir2 | |
ir2[2:0] == REG8_L & bit_alu_act | ir2[2:0] == REG8_L & sh_alu_act | |
(ED_INsREG_6C7 == {ir2[9:6],ir2[2:0]}) & (ir2[5:3] == REG8_L); |
|
|
|
always @(posedge clk) |
begin |
if ( upd_l_alu8 & exec_hlir2) lr <= alu8_out; |
if ( upd_l_src_pqr & exec_hlir2) lr <= src_pqr20; |
if ( up_l_add16 & exec_hlir2) lr <= add16[7:0]; |
if ( LDsHL_NN == ir2 & exec_hlir2) lr <= nn[7:0]; |
if ( LDsHL_6NN7== ir2 & exec_hlir2) lr <= nn[7:0]; |
if ( POPsHL == ir2 & exec_hlir2) lr <= nn[7:0]; |
if ( EXs6SP7_HL== ir2 & exec_hlir2) lr <= nn[7:0]; |
if ( EXX == ir2 & exec_ir2) lr <= lp; |
if ( EXsDE_HL == ir2 & exec_ir2) lr <= er; |
if ( LDsL_N == ir2 & exec_hlir2) lr <= nn[7:0]; |
if (ir2[2:0] == REG8_L & |
bit_alu_act & exec_hlir2) lr <= bit_alu; |
if (ir2[2:0] == REG8_L & |
sh_alu_act & exec_hlir2) lr <= sh_alu; |
if ((ED_INsREG_6C7 == {ir2[9:6],ir2[2:0]}) & (ir2[5:3] == REG8_L) & exec_ir2) |
lr <= nn[7:0]; |
|
end |
//------------------------ ixr --------------------------------------------- |
wire exec_ixir2 = exec_ir2 & dd_grp; |
always @(posedge clk) |
begin |
if ( upd_l_alu8 & exec_ixir2) ixr[7:0] <= alu8_out; |
if ( upd_l_src_pqr & exec_ixir2) ixr[7:0] <= src_pqr20; |
if ( up_l_add16 & exec_ixir2) ixr[7:0] <= add16[7:0]; |
if ( LDsHL_NN == ir2 & exec_ixir2) ixr[7:0] <= nn[7:0]; |
if ( LDsHL_6NN7== ir2 & exec_ixir2) ixr[7:0] <= nn[7:0]; |
if ( POPsHL == ir2 & exec_ixir2) ixr[7:0] <= nn[7:0]; |
if ( EXs6SP7_HL== ir2 & exec_ixir2) ixr[7:0] <= nn[7:0]; |
|
if ( LDsL_N == ir2 & exec_ixir2) ixr[7:0] <= nn[7:0]; |
if (ir2[2:0] == REG8_L & |
bit_alu_act & exec_ixir2) ixr[7:0] <= bit_alu; |
if (ir2[2:0] == REG8_L & |
sh_alu_act & exec_ixir2) ixr[7:0] <= sh_alu; |
|
end |
|
always @(posedge clk) |
begin |
if ( upd_h_alu8 & exec_ixir2) ixr[15:8] <= alu8_out; |
if ( upd_h_src_pqr & exec_ixir2) ixr[15:8] <= src_pqr20; |
if ( up_h_add16 & exec_ixir2) ixr[15:8] <= add16[15:8]; |
if ( LDsHL_NN == ir2 & exec_ixir2) ixr[15:8] <= nn[15:8]; |
if ( LDsHL_6NN7== ir2 & exec_ixir2) ixr[15:8] <= nn[15:8]; |
if ( POPsHL == ir2 & exec_ixir2) ixr[15:8] <= nn[15:8]; |
if ( EXs6SP7_HL== ir2 & exec_ixir2) ixr[15:8] <= nn[15:8]; |
|
if ( LDsH_N == ir2 & exec_ixir2) ixr[15:8] <= nn[7:0]; |
if (ir2[2:0] == REG8_H & |
bit_alu_act & exec_ixir2) ixr[15:8] <= bit_alu; |
if (ir2[2:0] == REG8_H & |
sh_alu_act & exec_ixir2) ixr[15:8] <= sh_alu; |
|
end |
|
//------------------------ iyr --------------------------------------------- |
wire exec_iyir2 = exec_ir2 & fd_grp; |
always @(posedge clk) |
begin |
if ( upd_l_alu8 & exec_iyir2) iyr[7:0] <= alu8_out; |
if ( upd_l_src_pqr & exec_iyir2) iyr[7:0] <= src_pqr20; |
if ( up_l_add16 & exec_iyir2) iyr[7:0] <= add16[7:0]; |
if ( LDsHL_NN == ir2 & exec_iyir2) iyr[7:0] <= nn[7:0]; |
if ( LDsHL_6NN7== ir2 & exec_iyir2) iyr[7:0] <= nn[7:0]; |
if ( POPsHL == ir2 & exec_iyir2) iyr[7:0] <= nn[7:0]; |
if ( EXs6SP7_HL== ir2 & exec_iyir2) iyr[7:0] <= nn[7:0]; |
|
if ( LDsL_N == ir2 & exec_iyir2) iyr[7:0] <= nn[7:0]; |
if (ir2[2:0] == REG8_L & |
bit_alu_act & exec_iyir2) iyr[7:0] <= bit_alu; |
if (ir2[2:0] == REG8_L & |
sh_alu_act & exec_iyir2) iyr[7:0] <= sh_alu; |
|
end |
|
always @(posedge clk) |
begin |
if ( upd_h_alu8 & exec_iyir2) iyr[15:8] <= alu8_out; |
if ( upd_h_src_pqr & exec_iyir2) iyr[15:8] <= src_pqr20; |
if ( up_h_add16 & exec_iyir2) iyr[15:8] <= add16[15:8]; |
if ( LDsHL_NN == ir2 & exec_iyir2) iyr[15:8] <= nn[15:8]; |
if ( LDsHL_6NN7== ir2 & exec_iyir2) iyr[15:8] <= nn[15:8]; |
if ( POPsHL == ir2 & exec_iyir2) iyr[15:8] <= nn[15:8]; |
if ( EXs6SP7_HL== ir2 & exec_iyir2) iyr[15:8] <= nn[15:8]; |
|
if ( LDsH_N == ir2 & exec_iyir2) iyr[15:8] <= nn[7:0]; |
if (ir2[2:0] == REG8_H & |
bit_alu_act & exec_iyir2) iyr[15:8] <= bit_alu; |
if (ir2[2:0] == REG8_H & |
sh_alu_act & exec_iyir2) iyr[15:8] <= sh_alu; |
|
end |
|
|
//---------------------------- prime regiters (shadows?) ---------------- |
|
always @(posedge clk) |
begin |
if (ir2 == EXsAF_AFp & exec_ir2) |
begin |
ap <= ar; |
fp <= fr; |
end |
if (ir2 == EXX & exec_ir2) |
begin |
ap <= ar; |
fp <= fr; |
bp <= br; |
cp <= cr; |
dp <= dr; |
ep <= er; |
hp <= hr; |
lp <= lr; |
end |
end |
//-------------------------- flag registers ------------------------------- |
// This is a mess - There is in general no reasonable way to get this stuff to follow |
// z80 exactly. --- in some of the undocumented cases, there is not even a |
// guess expressed about what is actually done. In some of the other undocumented |
// cases, what is claimed happens is soo silly that It is hard for me to believe |
// it matters ( unfortunately i am far too aware that one man's garbage can be |
// anothers treasure --- or....., its amazing how silly |
// behavior (bug?) can become a feature. In any case, The attempt (at first blush) is |
// only to get the documented stuff right -- although if undocumented behavior |
// falls out, great. For exmple, I will typically update f3f and f5f with alu output - |
// these flags are documented as "undefined". |
// |
// some of the wierd stuff to worry about: |
// 16 bit ops: |
// the ed insts SBC ADC muck with all flags but |
// the ADD inst doesn't change sf zf or pvf. |
// and the 16 bit INC and DEC insts touch nothing |
// |
// the ED_RLD and RRD instructions muck with flags based on ar -- these operations |
// should be correct rleative to subsequent DAA's i suppose. |
|
// update all flags from alu8 for logic operations pv <= parity else ofl |
// INC and DEC same as but no cf change oh my god why? done in logic above |
|
assign upd_fr_alu8 = |
ADCsA_A == ir2 | ANDsA == ir2 | ORsA == ir2 | SUBsA == ir2 | DECsA == ir2 | |
ADCsA_B == ir2 | ANDsB == ir2 | ORsB == ir2 | SUBsB == ir2 | DECsB == ir2 | |
ADCsA_C == ir2 | ANDsC == ir2 | ORsC == ir2 | SUBsC == ir2 | DECsC == ir2 | |
ADCsA_D == ir2 | ANDsD == ir2 | ORsD == ir2 | SUBsD == ir2 | DECsD == ir2 | |
ADCsA_E == ir2 | ANDsE == ir2 | ORsE == ir2 | SUBsE == ir2 | DECsE == ir2 | |
ADCsA_H == ir2 | ANDsH == ir2 | ORsH == ir2 | SUBsH == ir2 | DECsH == ir2 | |
ADCsA_L == ir2 | ANDsL == ir2 | ORsL == ir2 | SUBsL == ir2 | DECsL == ir2 | |
ADCsA_6HL7==ir2 | ANDs6HL7 ==ir2 | ORs6HL7 ==ir2 | SUBs6HL7 ==ir2 | INCsA == ir2 | |
ADDsA_A == ir2 | CPsA == ir2 | SBCsA == ir2 | XORsA == ir2 | INCsB == ir2 | |
ADDsA_B == ir2 | CPsB == ir2 | SBCs6HL7 ==ir2 | XORsB == ir2 | INCsC == ir2 | |
ADDsA_C == ir2 | CPsC == ir2 | SBCsB == ir2 | XORsC == ir2 | INCsD == ir2 | |
ADDsA_D == ir2 | CPsD == ir2 | SBCsC == ir2 | XORsD == ir2 | INCsE == ir2 | |
ADDsA_E == ir2 | CPsE == ir2 | SBCsD == ir2 | XORsE == ir2 | INCsH == ir2 | |
ADDsA_H == ir2 | CPsH == ir2 | SBCsE == ir2 | XORsH == ir2 | INCsL == ir2 | |
ADDsA_L == ir2 | CPsL == ir2 | SBCsH == ir2 | XORsL == ir2 | INCs6HL7 == ir2 | |
ADDsA_6HL7== ir2| CPs6HL7 ==ir2 | SBCsL == ir2 | XORs6HL7 == ir2 | DECs6HL7 == ir2 | |
ED_NEG == {ir2[9:6],ir2[2:0]} ; //7'b1001___100, A<= -A |
|
|
|
// update h n c (f5, f3) from alu16 |
assign upd_fr_add16 = |
ADDsHL_BC == ir2 | // ADD HL,BC ; 09 |
ADDsHL_DE == ir2 | // ADD HL,DE ; 19 |
ADDsHL_HL == ir2 | // ADD HL,HL ; 29 |
ADDsHL_SP == ir2 ; // ADD HL,SP ; 39 |
// INCsBC == ir2 | // INC BC ; 03 no flag changes for these |
// INCsDE == ir2 | // INC DE ; 13 |
// INCsHL == ir2 | // INC HL ; 23 |
// INCsSP == ir2 ; // INC SP ; 33 |
|
// update all flags from alu16 |
assign upd_fr_edadd16 = |
ED_SBCsHL_REG == {ir2[9:6],ir2[3:0]} | // compair with {ir2[9:6],ir2[3:0]} |
ED_ADCsHL_REG == {ir2[9:6],ir2[3:0]} ; // compair with {ir2[9:6],ir2[3:0]} |
|
|
// the shifts probably muck with all flags (some operations are |
// guarenteed not to change certain flags ) |
// docs say sf and zf never change for these ops. |
assign upd_fr_sh = |
RLA == ir2 |// RLA ; 17 |
RLCA == ir2 |// RLCA ; 07 |
RRA == ir2 |// RRA ; 1F |
RRCA == ir2 ;// RRCA ; 0F |
// sf and zf do change for theses |
assign upd_fr_cbsh = |
CB_RLC == ir2[9:3] | // these must be compaired with ir2[9:3] |
CB_RRC == ir2[9:3] | // these must be compaired with ir2[9:3] |
CB_RL == ir2[9:3] | // these must be compaired with ir2[9:3] |
CB_RR == ir2[9:3] | // these must be compaired with ir2[9:3] |
CB_SLA == ir2[9:3] | // these must be compaired with ir2[9:3] |
CB_SRA == ir2[9:3] | // these must be compaired with ir2[9:3] |
CB_SLL == ir2[9:3] | // these must be compaired with ir2[9:3] |
CB_SRL == ir2[9:3] ; // these must be compaired with ir2[9:3] |
|
// pretty nomal stuff here |
//CB_BIT = 4'b01_01, // these must be compaired with ir2[9:6] |
// which alu? -- done from alu8 |
//ED_NEG = 5'b01___100, // compair with {ir2[7:6],ir2[2:0]} all A<= -A |
|
// rmw 8 types these handled by standard INC and DEC logic done. |
//INCs6HL7 = 'h34,// INC (HL) ; 34 |
//DECs6HL7 = 'h35,// DEC (HL) ; 35 |
|
// ED Block Move messyness upd_b_decbc 4/19/2004 not used - probably not needed |
// hf and nf <= 0 pnf<= BC==0 |
//assign eb_blk_mv = |
// ED_LDI == ir2 | // LDI ; ED A0 (DE++) <= (HL++) , BC-- |
// ED_LDD == ir2 | // LDD ; ED A8 (DE--) <= (HL--) , BC-- |
// ED_LDIR == ir2 | // LDIR ; ED B0 (DE++) <= (HL++) , BC-- Repeat til BC==0 |
// ED_LDDR == ir2 ;// LDDR ; ED B8 (DE--) <= (HL--) , BC-- Repeat til BC==0 |
// only c not affected - nf<=1 ? |
assign ed_blk_cp = |
ED_CPI == ir2 | // CPI ; ED A1 A - (HL++) , BC-- |
ED_CPD == ir2 | // CPD ; ED A9 A - (HL--) , BC-- |
ED_CPIR == ir2 | // CPIR ; ED B1 A - (HL++) , BC-- repeat if(|B |
ED_CPDR == ir2 ;// CPDR ; ED B9 A - (HL--) , BC-- repeat if(|B |
|
// all the ed i/o muck with all flags -- wonderful cf? |
// use the aluoutput for the b-1 computation. |
// --------- eb_io |
//ED_INI = 'hA2// INI ; ED A2 (HL++) <- (Cio) , B-- |
//ED_IND = 'hAA// IND ; ED AA (HL--) <- (Cio) , B-- |
//ED_INIR = 'hB2// INIR ; ED B2 (HL++) <- (Cio) , B-- repeat if(|B) |
//ED_INDR = 'hBA// INDR ; ED BA (HL--) <- (Cio) , B-- repeat if(|B) |
//ED_OUTI = 'hA3// OUTI ; ED A3 (Cio) <-(HL++) , B-- |
//ED_OUTD = 'hAB// OUTD ; ED AB (Cio) <-(HL--) , B-- |
//ED_OTIR = 'hB3// OTIR ; ED B3 (Cio) <-(HL++) , B-- rpt if(|B) |
//ED_OTDR = 'hBB// OTDR ; ED BB (Cio) <-(HL--) , B-- rpt if(|B) |
|
//ED_INsREG_6C7 = 5'b01___000,// compair with {ir2[7:6],ir2[2:0]} really (BCio) |
|
|
|
// special problems -- lol more special problems ???? |
//CCF = 'h3F,// CCF ; 3F // h<=c c<=~C N<=0 F3,F5? |
//CPL = 'h2F,// CPL ; 2F // H<=1 N<=1 F3,F5? |
//DAA = 'h27,// DAA ; 27 // H<=0??? |
//SCF = 'h37,// SCF ; 37 |
//ED_RRD = 'h67// RRD ; ED 67 nibble roates A HL |
//ED_RLD = 'h6F// RLD ; ED 6F nibble roates A HL |
//ED_LDsA_I = 'h57// LD A,I ; ED 57 move I to A |
|
assign { sf, zf, f5f, hf, f3f, pvf, nf, cf} = fr; |
// gotta say those little ~^ operators down there worry me. Only 4 levels of xor - but jeeze |
// there are a lot of them. I guess in most FPGA's it doesn't matter what the op is - just |
// how many terms. |
|
|
// do we need the exe_ir2 term here? isn't it added in the hazard term anyway? |
assign upd_fr = exec_ir2 & ( ( upd_fr_alu8 ) | |
( upd_fr_add16) | |
( upd_fr_edadd16) | |
( upd_fr_sh ) | |
( upd_fr_cbsh ) | |
(CB_BIT == ir2[9:6]) | |
( ed_blk_cp ) | |
(ED_INsREG_6C7 == {ir2[7:6],ir2[2:0]}) | |
(CCF == ir2 ) | |
(CPL == ir2 ) | |
(DAA == ir2 ) | |
(SCF == ir2 ) | |
(ED_RRD == ir2) | |
(ED_RLD == ir2) | |
(ED_LDsA_I == ir2) | |
(ir2 == EXsAF_AFp ) | |
(ir2 == EXX ) ); |
|
|
|
wire iff2 = 1'b0; // this is supposed to be int ff #2 which is not (yet) implmented |
always @(posedge clk) |
begin |
if (exec_ir2) |
begin |
if ( upd_fr_alu8 ) fr <= alu8_fr; // assembled above with 8 bit ALU |
if ( upd_fr_add16) fr <= {sf, zf, add16[13], c_16out11, add16[11], pvf, 1'b0, c_16out15}; |
if ( upd_fr_edadd16) fr <= {add16[15], ~|add16, add16[13], c_16out11, |
add16[11], add16_ofl, ~ir2[3], c_16out15}; |
if ( upd_fr_sh ) fr <= {sf, zf, sh_alu[5], 1'b0, sh_alu[3], pvf, 1'b0, sh_cry}; |
if ( upd_fr_cbsh ) fr <= {sh_alu[7], ~|sh_alu, sh_alu[5], 1'b0, |
sh_alu[3], ~^sh_alu, 1'b0, sh_cry}; |
if (CB_BIT == ir2[9:6]) fr <={bit_alu[7], ~|bit_alu, bit_alu[5], 1'b1, //no idea why hf<=1 |
bit_alu[3], ~|bit_alu, 1'b0 , cf };// pvf == zf ??? |
if ( ed_blk_cp ) fr <= {alu8_out[7], ~|alu8_out, alu8_out[5], alu8_hcry,//std a-n stuff |
alu8_out[3], alu8_out[7], 1'b1, cf }; //cept nf and cf |
if (ED_INsREG_6C7 == {ir2[7:6],ir2[2:0]}) |
fr <= {nn[7], ~|nn[7:0], nn[5], 1'b0, nn[3], ~^nn[7:0], 1'b0, cf}; |
if (CCF == ir2 ) fr <= {sf, zf, f5f, cf, f3f, pvf, nf, ~cf}; |
if (CPL == ir2 ) fr <= {sf, zf, ar[5], 1'b1, ar[3], pvf, 1'b1, cf}; |
if (DAA == ir2 ) fr <= {daa_alu[7], ~|daa_alu, daa_alu[5], 1'b0, // hf sb (logically) 0 |
daa_alu[3], ~^daa_alu, nf, daa_cry }; |
if (SCF == ir2 ) fr <= { sf, zf, ar[5], 1'b0, ar[3], pvf, 1'b0, 1'b1 }; // very strange |
if (ED_RRD == ir2) fr <= { sf, ~|{ar[7:4],nn[3:0]}, ar[5], 1'b0, |
ar[3], ~^{ar[7:4],nn[3:0]}, 1'b0 , cf }; |
if (ED_RLD == ir2) fr <= { sf, ~|{ar[7:4],nn[7:4]}, ar[5], 1'b0, |
ar[3], ~^{ar[7:4],nn[7:4]}, 1'b0 , cf }; |
if (ED_LDsA_I == ir2) fr <= { ir2[7], ~|ir2, ir2[5], 1'b0, ir2[3], iff2, 1'b0, cf }; // iff2 ? |
if (ir2 == EXsAF_AFp) fr <= fp; |
if (ir2 == EXX ) fr <= fp; |
|
|
end |
// in the case of blk_cp the update above is executed 2nd - and so these are don't cares. |
if (exec_decb ) fr <= {decb_alu[7], ~|decb_alu, decb_alu[5], hf, |
decb_alu[3], pvf, 1'b0, cf }; |
if (exec_decbc ) fr[5:1] <= { decb_alu[5], 1'b0, decb_alu[3], ~|decb_alu, 1'b0 }; |
end |
|
|
//----------------------- intr ----------------------------------------------------------- |
|
always @(posedge clk or posedge rst) |
if (rst) intr <= 8'h0; |
else if (( ED_LDsI_A == ir2) & exec_ir2) intr <= ar; |
|
endmodule |
/trunk/rtl/z80_memstate2.v
0,0 → 1,1616
/////////////////////////////////////////////////////////////////////////////////////////////////// |
// // |
// file name: memstate2.v // |
// description: memory opertions for z80 // |
// project: wb_z80 // |
// // |
// Author: B.J. Porcella // |
// e-mail: bporcella@sbcglobal.net // |
// // |
// // |
// // |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2000-2002 B.J. Porcella // |
// Real Time Solutions // |
// // |
// // |
// 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY // |
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED // |
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS // |
// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR // |
// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, // |
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // |
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE // |
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR // |
// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // |
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // |
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT // |
// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // |
// POSSIBILITY OF SUCH DAMAGE. // |
// // |
//-------1---------2---------3--------Comments on file -------------7---------8---------9--------0 |
// The memory state controller controls the wb bus, and provides address sequencing. |
// Insructions are fetched in order (using PC) until the istate machine indicates that |
// a complete instruction is in the first pipline stage (ir1). In general, operands are being |
// fetched (stored) to satisfy ir1 while concurrently instructions are being executed from ir2. |
// this situation can result in a number of potential hazards. As an example, if the ir2 |
// instruction changes the flag register and the ir1 instruction is a conditional jump, |
// a hazard is generated by the hazard logic, and execution of the ir1 operation is delayed |
// until the completion of the flag update. |
// |
// Reset starts execution at 0. |
// The PC and SP are described in this file. modifications to other index registers - |
// HL IX and IY are computed here -- |
// For the block moves address updates are computed here -- and commanded here. |
// Strobes for the second address update are generally co-incident with count updates, but |
// we provide seperate strobe update lines for clarity. |
// |
// BASIC ARCHITECTURE OF THIS FILE pc and sp not shown, but are inputs to src mux. |
// _____ and may be updated from adder output. |
// | | |
// | | pc-1 register is required to implement relative jumps. |
// | | |
// _____ |lit | |\ |
// | | | | | \ |
// | | |src2 | | \ _____ _____ |
// | | | |----->| | | | | | |
// |src | |_____| |adder|------->| | | | |
// |mux | | | | | | | |
// | |------------------->| / |2/1 |------->|wb | |
// | | | | / |mux | |adr | |
// |_____| | |/ | | | | |
// ------------------->| | | | |
// |_____| |_____| |
// |
// |
// |
// |
// Operand Stores: |
// At first cut, I thought I'ld execute operand stores immediately from the memory sequencer |
// (essentially before ir2 got the store data). While this might be modestly faster in |
// systems that take multiple clocks to complete a memory store, On consideration, I decided |
// to forgo the extra speed for conceptual simplicity.... execute operand stores on op_ph1, |
// and let the inst_exec engine suply the operand. |
// |
// On second thought, above is not only wastful of time, but also inconsistent with the overall |
// schems of things - and so somewhat more complex. If we simply execute the OS from ir1, |
// There is less state to contdend with, as well as extra speed. |
// |
// Block Moves fundamentally execute from ir2. We initiate the first operand fetch from ir1. |
// |
// 3/18/2004 Second time through. In impleenting the execution logic it became clear that |
// there were "minor" problems with the handling of the DD and FD prefix insts (especially |
// DDCD and FDCB --- collectively called PFxCB below. On review, I had to question the |
// value of "breaking up" the ir0 execution engine between the istate sequencer and the |
// memstate sequencer. While I dislike state sequencers of much more than 16 states -- |
// the interaction between these sequencers was becomming harder to track than a single |
// state macine. Thus - this file is getting re-worked. I will call it memstate2 (at least |
// for awhile) as I wish to keep the old file around. I want to show (in the state machine |
// logic) what the next memory operation is.... guess the best method consistent with my |
// documentation practices is to define a register (mem_op) = { if, wb_we_o, wb_cyc_o }. |
// This will require auxillary logic for computing the address --- but most of the decodes |
// required will be there anyway. |
// On further reflection, I think I will bite-the-bullet and use an always to define next_state. |
// I don't like to use always to define wires, but I also want to dicument the setting of |
// exec_ir2 in the same place - that is 3 different things. |
// |
// Hazards: |
// There are 2 kinds of hazards: mem_hazard => we are storing into the next instruction location |
// reg_hazard => we are modifying a register (ir2) that we are using |
// here (ir1) |
// In the former case, we throw out the instruction that arrives on the next tick, and restart the |
// instruction pipeline, In the latter case, we simply wait a tick for the ir2 operaton to |
// complete before starting the ir1 operation |
//-------1---------2---------3--------CVS Log -----------------------7---------8---------9--------0 |
// |
// $Id: z80_memstate2.v,v 1.1 2004-04-27 21:27:13 bporcella Exp $ |
// |
// $Date: 2004-04-27 21:27:13 $ |
// $Revision: 1.1 $ |
// $Author: bporcella $ |
// $Locker: $ |
// $State: Exp $ |
// |
// Change History: |
// $Log: not supported by cvs2svn $ |
// Revision 1.8 2004/04/19 19:13:28 bporcella |
// real lint problems pretty much fixed -- need another look - but need to get on to other things first |
// |
// Revision 1.7 2004/04/19 05:09:11 bporcella |
// fixed some lint problems -- |
// |
// Revision 1.6 2004/04/18 18:50:09 bporcella |
// fixed some lint problems -- |
// |
// Revision 1.5 2004/04/17 15:18:02 bporcella |
// 4th lint try |
// Miha claims reports are now correct |
// |
// Revision 1.4 2004/04/16 18:16:57 bporcella |
// try lint |
// |
// Revision 1.3 2004/04/16 17:06:54 bporcella |
// no code change - added a comment and test lint |
// |
// Revision 1.2 2004/04/16 16:21:04 bporcella |
// no code change - added a comment and test lint |
// |
// Revision 1.1.1.1 2004/04/13 23:50:19 bporcella |
// import first files |
// |
// |
// |
//-------1---------2---------3--------Module Name and Port List------7---------8---------9--------0 |
module z80_memstate2(wb_adr_o, wb_we_o, wb_cyc_o, wb_stb_o, wb_tga_o, wb_dat_o, |
exec_ir2, ir1, ir2, ir1dd, ir1fd, ir2dd, ir2fd, nn, sp, |
|
upd_ar, upd_br, upd_cr, upd_dr, upd_er, upd_hr, upd_lr,upd_fr, |
beq0, ceq0, |
ar, fr, br, cr, dr, er, hr, lr, intr, |
ixr, iyr, |
wb_dat_i, wb_ack_i, wb_clk_i, rst_i, |
int_req_i, |
add16, |
wb_clk_i, |
rst_i |
|
|
); |
|
//-------1---------2---------3--------Output Ports---------6---------7---------8---------9--------0 |
// mod only to checkout lint |
// mod again for lint check -- first check pretty wierd |
// 3rd lint try |
// 4th lint try |
output [15:0] wb_adr_o; |
output wb_we_o; |
output wb_cyc_o; |
output wb_stb_o; |
//output wb_lock; // bit set and clear insts should be atomic - could matter sometime |
output [1:0] wb_tga_o; |
output [7:0] wb_dat_o; // from nn |
//output [15:0] add_out; (may not wb_adr_o) 4/18/2004?? why? |
|
output exec_ir2; |
output [9:0] ir1, ir2; |
output ir1dd, ir2dd; |
output ir1fd, ir2fd; |
output [15:0] nn; |
output [15:0] sp; |
|
|
|
|
//-------1---------2---------3--------Input Ports----------6---------7---------8---------9--------0 |
input upd_ar, upd_br, upd_cr, upd_dr, upd_er, upd_hr, upd_lr,upd_fr; |
|
input beq0, ceq0; |
input [7:0] ar, fr, br, cr, dr, er, hr, lr, intr; |
input [15:0] ixr, iyr; |
input [7:0] wb_dat_i; |
input wb_ack_i, wb_clk_i, rst_i; |
input int_req_i; |
input [15:0] add16; // ir2 execution engine output for sp updates |
|
|
//-------1---------2---------3--------Parameters-----------6---------7---------8---------9--------0 |
`include "opcodes.v" // states of the main memory sequencer |
|
|
parameter TAG_IO = 2'b01, // need to review general wb usage to undrstand how best to |
TAG_INT = 2'b10; // document this. |
// 12na // 1 is ir1 2 is ir2 n is nn gets memory a is activate ir2 |
parameter IPIPE_NOP = 4'b0000, // guess I could define single bits and add them up |
IPIPE_A2 = 4'b0001, // would keep from getting lint bitching -- but heck |
IPIPE_ENN = 4'b0010, // I'm married -> an expert at ignoring such stuff :-) |
IPIPE_ENNA2 = 4'b0011, |
IPIPE_EN2 = 4'b0100, |
IPIPE_EN2A2 = 4'b0101, |
IPIPE_ENNEN2 = 4'b0110, |
IPIPE_ENNEN2A2 = 4'b0111, |
IPIPE_EN1 = 4'b1000, |
IPIPE_EN1A2 = 4'b1001, |
IPIPE_BOGUS = 4'b1010, // no reason (yet) to load both n and ir1 |
IPIPE_BOUS2 = 4'b1011, |
IPIPE_EN12 = 4'b1100, |
IPIPE_EN12A2 = 4'b1101, |
IPIPE_BOGUS3 = 4'b1110, |
IPIPE_BOGUS4 = 4'b1111; |
|
// well at first cut I tried to make this 2 state macines both less than 16 states. |
// this is 56 states at first cut. Assignemnt is subject to change. |
|
// ------ mem state decoder state machine states -------------------------------- |
parameter DEC_IDLE = 6'h00, |
DEC_HALT = 6'h01, |
DEC_IF1 = 6'h02, |
DEC_IF2 = 6'h03, |
DEC_IF2A = 6'h04, |
DEC_EXEC = 6'h05, |
DEC_CB = 6'h06, |
DEC_DDFD = 6'h07, |
DEC_ED = 6'h08, |
DEC_EDNN1 = 6'h09, |
DEC_EDNN2 = 6'h0a, |
DEC_EDRD1 = 6'h0b, |
DEC_EDRD2 = 6'h0c, |
DEC_EDWR = 6'h0d, |
DEC_EDBCP1 = 6'h0e, |
DEC_EDBCP2 = 6'h0f, |
DEC_EDBCP3 = 6'h10, |
DEC_EDBIN1 = 6'h11, |
DEC_EDBIN2 = 6'h12, |
DEC_EDBIN3 = 6'h13, |
DEC_EDBOUT1 = 6'h14, |
DEC_EDBOUT2 = 6'h15, |
DEC_EDBOUT3 = 6'h16, |
DEC_EDBMV1 = 6'h17, |
DEC_EDBMV2 = 6'h18, |
DEC_EDBMV3 = 6'h19, |
DEC_N = 6'h1a, |
DEC_NIN = 6'h1b, |
DEC_NN = 6'h1c, |
DEC_NNCALL1 = 6'h1d, |
DEC_NNCALL2 = 6'h1e, |
DEC_NNOS1 = 6'h1f, |
DEC_NNOS2 = 6'h20, |
DEC_NNOS3 = 6'h21, |
DEC_NNOF1 = 6'h22, |
DEC_NNOF2 = 6'h23, |
DEC_NNOF3 = 6'h24, |
DEC_NNOF4 = 6'h25, |
DEC_DDOS = 6'h26, |
DEC_DDOF = 6'h27, |
DEC_OF = 6'h28, |
DEC_POP = 6'h29, |
DEC_PUSH = 6'h2a, |
DEC_RMW = 6'h2b, |
DEC_RMW2 = 6'h2c, |
DEC_CBM = 6'h2d, |
DEC_PFxCB = 6'h2e, |
DEC_PFxCB2 = 6'h2f, |
DEC_PFxCB3 = 6'h30, |
DEC_PFxCB4 = 6'h31, |
DEC_INT1 = 6'h32, |
DEC_INT2 = 6'h33, |
DEC_INT3 = 6'h34, |
DEC_INT4 = 6'h35, |
DEC_INT5 = 6'h36, |
DEC_RET = 6'h37, |
DEC_NNJMP = 6'h38, |
DEC_RET2 = 6'h39 ; |
|
// initial decode assignemnts. These assignemens are made to wires on an initial decode |
// to help document next state transitions |
parameter I1_CB = 4'h0, |
I1_DDFD = 4'h1, |
I1_ED = 4'h2, |
I1_JMP = 4'h3, |
I1_N = 4'h4, |
I1_NN = 4'h5, |
I1_OF = 4'h6, |
I1_OS = 4'h7, |
I1_POP = 4'h8, |
I1_PUSH = 4'h9, |
I1_RET = 4'ha, |
I1_RMW = 4'hb, |
I1_RST = 4'hc, |
I1_R2R = 4'hd ; |
|
|
// A note here on the choices of mnemonics..... in general, the target registers of |
// memory ops are specified by an instruction register (ir1 for stores ir2 for loads). |
// so Menomics in general are specifying the address source. However, there are exceptions. |
// |
parameter MEM_NOP = 5'h00, |
MEM_IFPP1 = 5'h01, |
MEM_OS1 = 5'h02, // only invoked on I1 OS multiple address sources and data sources |
MEM_OF1 = 5'h03, // Address from HL unless LD A,(BC) or LD A,(DE) (used for rmw) |
MEM_OFSP = 5'h04, // works for both POP and RET |
MEM_OSSP = 5'h05, // if DEC_EXEC op from ir1 else msb nn (implies we store from lsb nn) |
// used in CALL also. |
MEM_OFIXpD = 5'h06, // used for prefix op fetches - all single bytes |
MEM_OSIXpD = 5'h07, // data source is same as MEM_OS1 |
MEM_OSADR = 5'h08, // used (at lesat) for prefixed rmw -- perhaps others. |
|
MEM_CALL = 5'h09, // pc<=nn, nn<=pc, wb_adr_o<=sp OS |
MEM_OSNN = 5'h0a, // if DEC_EXEC op from ir1 else msb nn |
MEM_OFNN = 5'h0b, // striaghtfoward |
MEM_OFADRP1 = 5'h0c, // used (at least) when double ops above |
MEM_OSADRP1 = 5'h0d, // "" "" "" |
|
MEM_IFRST = 5'h0e, // special address transfer |
MEM_IFREL_N = 5'h0f, // special address transfer for jmp rel |
MEM_JMPHL = 5'h10, // another special jump transfer |
MEM_IFNN = 5'h11, // used by call and return |
|
|
MEM_OFHL_PM = 5'h12, // special block move ops |
MEM_OSHL_PM = 5'h13, // special block move ops |
MEM_OSDE_PM = 5'h14, // special block move ops |
|
MEM_IOF_C = 5'h15, // special i/o ops |
MEM_IOS_C = 5'h16, // operand is ar |
MEM_IOF_N = 5'h17, |
MEM_IOS_N = 5'h18, |
MEM_OS_HL_N = 5'h19, |
|
MEM_OSSP_PCM2 = 5'h1a, // int code (call |
MEM_OSSP_P = 5'h1b, // |
MEM_INTA = 5'h1c, |
MEM_IFINT = 5'h1d, |
MEM_DECPC = 5'h1e ; |
|
|
|
|
|
|
|
|
|
//-------1---------2---------3--------Wires----------------6---------7---------8---------9--------0 |
|
|
//wire use_sp; // old names probably from first go-around |
//wire use_pc; |
//wire use_hl; |
//wire use_de; |
//wire use_bc; |
//wire use_flags; |
wire cb_mem; |
//wire br_test8t; // branch test true (8 test field) |
//wire br_test4t; // branch test true (4 test field) |
|
//wire ofos; |
//wire any_os; // most terms above only valid on mem_exec this includes all stores |
wire wb_rdy_nhz; |
wire dec_blk_inc; |
wire we_next; |
wire hazard; |
wire wb_int; |
wire [15:0] hl, de, bc; |
wire [3:0] mem_exec_dec; |
|
//wire use_a ;old names for hazard dect. remove |
//wire use_b ; |
//wire use_c ; |
//wire use_d ; |
//wire use_e ; |
//wire use_h ; |
//wire use_l ; |
// don't forget that as 1r1 is executed it is transferred to ir2. Anything I need to know |
// about subsequent operations must be stored. |
// 6 5 4 15 |
// assign {next_dec_state, next_mem_state, next_pipe_state} = next_state; |
wire [5:0] next_dec_state; |
wire [4:0] next_mem_state; |
wire [3:0] next_pipe_state; |
wire ed_dbl_rd; |
//-------1---------2---------3--------Registers------------6---------7---------8---------9--------0 |
|
reg [15:0] pc; |
reg [15:0] sp; |
reg [15:0] wb_adr_o; |
reg wb_we_o; |
reg wb_cyc_o; |
reg wb_stb_o; |
//reg wb_lock; Not used (yet -- don't delete) |
reg [1:0] wb_tga_o; |
|
reg blk_inc_flg; |
reg [9:0] ir1, ir2; |
reg ir1dd, ir2dd; |
reg ir1fd, ir2fd; |
reg [15:0] nn; |
|
reg [14:0] next_state; // a wire assigned in an alowys loop. |
|
reg [5:0] dec_state; // the register set each clock from next_dec_state; |
|
//reg of16_reg, os16_reg, rmw8_reg, call_reg, ret_reg, ioi; |
//reg push_reg; |
//reg pop_reg; |
reg inst_haz; |
reg exec_ir2; |
reg blk_rpt_flg; |
reg blk_io_flg; |
reg flag_os1; |
reg int_en, en_int_next; |
reg wb_irq_sync; |
//-------1---------2---------3--------Assignments----------6---------7---------8---------9--------0 |
// |
// ir is 10 bits most significant codes ir1[9:8] = { EDgrp, CBgrp } DDgrp and FDgrp are modifiers |
|
|
assign wb_dat_o = nn[15:8]; |
|
wire sf, zf, f5f, hf, f3f, pvf, nf, cf; |
assign { sf, zf, f5f, hf, f3f, pvf, nf, cf} = fr; // no load on f5f, f3f ok hf nf used in inst_exec.v |
|
|
assign hl = {hr, lr}; |
assign de = {dr, er}; |
assign bc = {br, cr}; |
|
|
// this "groups" the instructions to determine first memory operation |
|
parameter I1DCNT = 4; // parameter used below simply to make possible change easier. |
assign mem_exec_dec = |
{I1DCNT {CBgrp == ir1}} & I1_CB |// CBgrp is rotates and bi |
{I1DCNT {DDgrp == ir1}} & I1_DDFD|// DDgrp |
{I1DCNT {FDgrp == ir1}} & I1_DDFD|// FDgrp FD |
{I1DCNT {EDgrp == ir1}} & I1_ED |// EDgrp ED |
{I1DCNT {JPsHL == ir1}} & I1_JMP |// JP HL ; E9 // doc |
{I1DCNT {ADCsA_N == ir1}} & I1_N |// ADC A,N ; CE XX |
{I1DCNT {ADDsA_N == ir1}} & I1_N |// ADD A,N ; C6 XX |
{I1DCNT {ANDsN == ir1}} & I1_N |// AND N ; E6 XX |
{I1DCNT {CPsN == ir1}} & I1_N |// CP N ; FE XX |
{I1DCNT {INsA_6N7 == ir1}} & I1_N |// IN A,(N) ; DB XX |
{I1DCNT {JRs$t2 == ir1}} & I1_N |// JR $+2 ; 18 XX |
{I1DCNT {JRsC_$t2 == ir1}} & I1_N |// JR C,$+2 ; 38 XX |
{I1DCNT {JRsNC_$t2 == ir1}} & I1_N |// JR NC,$+2 ; 30 XX |
{I1DCNT {JRsZ_$t2 == ir1}} & I1_N |// JR Z,$+2 ; 28 XX |
{I1DCNT {JRsNZ_$t2 == ir1}} & I1_N |// JR NZ,$+2 ; 20 XX |
{I1DCNT {LDs6HL7_N == ir1}} & I1_N |// LD (HL),N ; 36 XX |
{I1DCNT {LDsA_N == ir1}} & I1_N |// LD A,N ; 3E XX |
{I1DCNT {LDsB_N == ir1}} & I1_N |// LD B,N ; 06 XX |
{I1DCNT {LDsC_N == ir1}} & I1_N |// LD C,N ; 0E XX |
{I1DCNT {LDsD_N == ir1}} & I1_N |// LD D,N ; 16 XX |
{I1DCNT {LDsE_N == ir1}} & I1_N |// LD E,N ; 1E XX |
{I1DCNT {LDsH_N == ir1}} & I1_N |// LD H,N ; 26 XX |
{I1DCNT {LDsL_N == ir1}} & I1_N |// LD L,N ; 2E XX |
{I1DCNT {ORsN == ir1}} & I1_N |// OR N ; F6 XX |
{I1DCNT {OUTs6N7_A == ir1}} & I1_N |// OUT (N),A ; D3 XX |
{I1DCNT {SBCsA_N == ir1}} & I1_N |// SBC A,N ; DE XX |
{I1DCNT {SUBsN == ir1}} & I1_N |// SUB N ; D6 XX |
{I1DCNT {XORsN == ir1}} & I1_N |// XOR N ; EE XX |
{I1DCNT {CALLsC_NN == ir1}} & I1_NN |// CALL C,NN ; DC XX XX |
{I1DCNT {CALLsNC_NN == ir1}} & I1_NN |// CALL NC,NN ; D4 XX XX |
{I1DCNT {CALLsNN == ir1}} & I1_NN |// CALL NN ; CD XX XX |
{I1DCNT {CALLsNZ_NN == ir1}} & I1_NN |// CALL NZ,NN ; C4 XX XX |
{I1DCNT {CALLsPE_NN == ir1}} & I1_NN |// CALL PE,NN ; EC XX XX |
{I1DCNT {CALLsPO_NN == ir1}} & I1_NN |// CALL PO,NN ; E4 XX XX |
{I1DCNT {CALLsP_NN == ir1}} & I1_NN |// CALL P,NN ; F4 XX XX |
{I1DCNT {CALLsZ_NN == ir1}} & I1_NN |// CALL Z,NN ; CC XX XX |
{I1DCNT {CALLsM_NN == ir1}} & I1_NN |// CALL M,NN ; FC XX XX |
{I1DCNT {JP == ir1}} & I1_NN |// JP ; C3 XX XX |
{I1DCNT {JPsC == ir1}} & I1_NN |// JP C ; DA XX XX |
{I1DCNT {JPsM == ir1}} & I1_NN |// JP M, ; FA XX XX |
{I1DCNT {JPsNC == ir1}} & I1_NN |// JP NC, ; D2 XX XX |
{I1DCNT {JPsNZ == ir1}} & I1_NN |// JP NZ ; C2 XX XX |
{I1DCNT {JPsP == ir1}} & I1_NN |// JP P ; F2 XX XX |
{I1DCNT {JPsPE == ir1}} & I1_NN |// JP PE, ; EA XX XX |
{I1DCNT {JPsPO == ir1}} & I1_NN |// JP PO ; E2 XX XX |
{I1DCNT {JPsZ == ir1}} & I1_NN |// JP Z ; CA XX XX |
{I1DCNT {LDs6NN7_A == ir1}} & I1_NN |// LD (NN),A ; 32 XX XX |
{I1DCNT {LDs6NN7_HL == ir1}} & I1_NN |// LD (NN),HL ; 22 XX XX |
{I1DCNT {LDsA_6NN7 == ir1}} & I1_NN |// LD A,(NN) ; 3A XX XX |
{I1DCNT {LDsBC_NN == ir1}} & I1_NN |// LD BC,NN ; 01 XX XX |
{I1DCNT {LDsDE_NN == ir1}} & I1_NN |// LD DE,NN ; 11 XX XX |
{I1DCNT {LDsHL_6NN7 == ir1}} & I1_NN |// LD HL,(NN) ; 2A XX XX |
{I1DCNT {LDsHL_NN == ir1}} & I1_NN |// LD HL,NN ; 21 XX XX |
{I1DCNT {LDsSP_NN == ir1}} & I1_NN |// LD SP,NN ; 31 XX XX |
{I1DCNT {ADCsA_6HL7 == ir1}} & I1_OF |// ADC A,(HL) ; 8E |
{I1DCNT {ADDsA_6HL7 == ir1}} & I1_OF |// ADD A,(HL) ; 86 |
{I1DCNT {ANDs6HL7 == ir1}} & I1_OF |// AND (HL) ; A6 |
{I1DCNT {CPs6HL7 == ir1}} & I1_OF |// CP (HL) ; BE |
{I1DCNT {LDsA_6BC7 == ir1}} & I1_OF |// LD A,(BC) ; 0A |
{I1DCNT {LDsA_6DE7 == ir1}} & I1_OF |// LD A,(DE) ; 1A |
{I1DCNT {LDsA_6HL7 == ir1}} & I1_OF |// LD A,(HL) ; 7E |
{I1DCNT {LDsB_6HL7 == ir1}} & I1_OF |// LD B,(HL) ; 46 |
{I1DCNT {LDsC_6HL7 == ir1}} & I1_OF |// LD C,(HL) ; 4E |
{I1DCNT {LDsD_6HL7 == ir1}} & I1_OF |// LD D,(HL) ; 56 |
{I1DCNT {LDsE_6HL7 == ir1}} & I1_OF |// LD E,(HL) ; 5E |
{I1DCNT {LDsH_6HL7 == ir1}} & I1_OF |// LD H,(HL) ; 66 |
{I1DCNT {LDsL_6HL7 == ir1}} & I1_OF |// LD L,(HL) ; 6E |
{I1DCNT {ORs6HL7 == ir1}} & I1_OF |// OR (HL) ; B6 |
{I1DCNT {SBCs6HL7 == ir1}} & I1_OF |// SBC (HL) ; 9E |
{I1DCNT {SUBs6HL7 == ir1}} & I1_OF |// SUB (HL) ; 96 |
{I1DCNT {XORs6HL7 == ir1}} & I1_OF |// XOR (HL) ; AE |
{I1DCNT {LDs6BC7_A == ir1}} & I1_OS |// LD (BC),A ; 02 |
{I1DCNT {LDs6DE7_A == ir1}} & I1_OS |// LD (DE),A ; 12 |
{I1DCNT {LDs6HL7_A == ir1}} & I1_OS |// LD (HL),A ; 77 |
{I1DCNT {LDs6HL7_B == ir1}} & I1_OS |// LD (HL),B ; 70 |
{I1DCNT {LDs6HL7_C == ir1}} & I1_OS |// LD (HL),C ; 71 |
{I1DCNT {LDs6HL7_D == ir1}} & I1_OS |// LD (HL),D ; 72 |
{I1DCNT {LDs6HL7_E == ir1}} & I1_OS |// LD (HL),E ; 73 |
{I1DCNT {LDs6HL7_H == ir1}} & I1_OS |// LD (HL),H ; 74 |
{I1DCNT {LDs6HL7_L == ir1}} & I1_OS |// LD (HL),L ; 75 |
{I1DCNT {POPsAF == ir1}} & I1_POP |// POP AF ; F1 |
{I1DCNT {POPsBC == ir1}} & I1_POP |// POP BC ; C1 |
{I1DCNT {POPsDE == ir1}} & I1_POP |// POP DE ; D1 |
{I1DCNT {POPsHL == ir1}} & I1_POP |// POP HL ; E1 |
{I1DCNT {PUSHsAF == ir1}} & I1_PUSH|// PUSH AF ; F5 |
{I1DCNT {PUSHsBC == ir1}} & I1_PUSH|// PUSH BC ; C5 |
{I1DCNT {PUSHsDE == ir1}} & I1_PUSH|// PUSH DE ; D5 |
{I1DCNT {PUSHsHL == ir1}} & I1_PUSH|// PUSH HL ; E5 |
{I1DCNT {ADCsA_A == ir1}} & I1_R2R |// ADC A,A ; 8F |
{I1DCNT {ADCsA_B == ir1}} & I1_R2R |// ADC A,B ; 88 |
{I1DCNT {ADCsA_C == ir1}} & I1_R2R |// ADC A,C ; 89 |
{I1DCNT {ADCsA_D == ir1}} & I1_R2R |// ADC A,D ; 8A |
{I1DCNT {ADCsA_E == ir1}} & I1_R2R |// ADC A,E ; 8B |
{I1DCNT {ADCsA_H == ir1}} & I1_R2R |// ADC A,H ; 8C |
{I1DCNT {ADCsA_L == ir1}} & I1_R2R |// ADC A,L ; 8D |
{I1DCNT {ADDsA_A == ir1}} & I1_R2R |// ADD A,A ; 87 |
{I1DCNT {ADDsA_B == ir1}} & I1_R2R |// ADD A,B ; 80 |
{I1DCNT {ADDsA_C == ir1}} & I1_R2R |// ADD A,C ; 81 |
{I1DCNT {ADDsA_D == ir1}} & I1_R2R |// ADD A,D ; 82 |
{I1DCNT {ADDsA_E == ir1}} & I1_R2R |// ADD A,E ; 83 |
{I1DCNT {ADDsA_H == ir1}} & I1_R2R |// ADD A,H ; 84 |
{I1DCNT {ADDsA_L == ir1}} & I1_R2R |// ADD A,L ; 85 |
{I1DCNT {ADDsHL_BC == ir1}} & I1_R2R |// ADD HL,BC ; 09 |
{I1DCNT {ADDsHL_DE == ir1}} & I1_R2R |// ADD HL,DE ; 19 |
{I1DCNT {ADDsHL_HL == ir1}} & I1_R2R |// ADD HL,HL ; 29 |
{I1DCNT {ADDsHL_SP == ir1}} & I1_R2R |// ADD HL,SP ; 39 |
{I1DCNT {ANDsA == ir1}} & I1_R2R |// AND A ; A7 |
{I1DCNT {ANDsB == ir1}} & I1_R2R |// AND B ; A0 |
{I1DCNT {ANDsC == ir1}} & I1_R2R |// AND C ; A1 |
{I1DCNT {ANDsD == ir1}} & I1_R2R |// AND D ; A2 |
{I1DCNT {ANDsE == ir1}} & I1_R2R |// AND E ; A3 |
{I1DCNT {ANDsH == ir1}} & I1_R2R |// AND H ; A4 |
{I1DCNT {ANDsL == ir1}} & I1_R2R |// AND L ; A5 |
{I1DCNT {CCF == ir1}} & I1_R2R |// CCF ; 3F |
{I1DCNT {CPL == ir1}} & I1_R2R |// CPL ; 2F |
{I1DCNT {CPsA == ir1}} & I1_R2R |// CP A ; BF |
{I1DCNT {CPsB == ir1}} & I1_R2R |// CP B ; B8 |
{I1DCNT {CPsC == ir1}} & I1_R2R |// CP C ; B9 |
{I1DCNT {CPsD == ir1}} & I1_R2R |// CP D ; BA |
{I1DCNT {CPsE == ir1}} & I1_R2R |// CP E ; BB |
{I1DCNT {CPsH == ir1}} & I1_R2R |// CP H ; BC |
{I1DCNT {CPsL == ir1}} & I1_R2R |// CP L ; BD |
{I1DCNT {DAA == ir1}} & I1_R2R |// DAA ; 27 |
{I1DCNT {DECsA == ir1}} & I1_R2R |// DEC A ; 3D |
{I1DCNT {DECsB == ir1}} & I1_R2R |// DEC B ; 05 |
{I1DCNT {DECsBC == ir1}} & I1_R2R |// DEC BC ; 0B |
{I1DCNT {DECsC == ir1}} & I1_R2R |// DEC C ; 0D |
{I1DCNT {DECsD == ir1}} & I1_R2R |// DEC D ; 15 |
{I1DCNT {DECsDE == ir1}} & I1_R2R |// DEC DE ; 1B |
{I1DCNT {DECsE == ir1}} & I1_R2R |// DEC E ; 1D |
{I1DCNT {DECsH == ir1}} & I1_R2R |// DEC H ; 25 |
{I1DCNT {DECsHL == ir1}} & I1_R2R |// DEC HL ; 2B |
{I1DCNT {DECsL == ir1}} & I1_R2R |// DEC L ; 2D |
{I1DCNT {DECsSP == ir1}} & I1_R2R |// DEC SP ; 3B |
{I1DCNT {DI == ir1}} & I1_R2R |// DI ; F3 |
{I1DCNT {DJNZs$t2 == ir1}} & I1_R2R |// DJNZ $+2 ; 10 XX |
{I1DCNT {EI == ir1}} & I1_R2R |// EI ; FB |
{I1DCNT {EXX == ir1}} & I1_R2R |// EXX ; D9 |
{I1DCNT {EXsAF_AFp == ir1}} & I1_R2R |// EX AF,AF' ; 08 |
{I1DCNT {EXsDE_HL == ir1}} & I1_R2R |// EX DE,HL ; EB |
{I1DCNT {HALT == ir1}} & I1_R2R |// HALT ; 76 |
{I1DCNT {INCsA == ir1}} & I1_R2R |// INC A ; 3C |
{I1DCNT {INCsB == ir1}} & I1_R2R |// INC B ; 04 |
{I1DCNT {INCsBC == ir1}} & I1_R2R |// INC BC ; 03 |
{I1DCNT {INCsC == ir1}} & I1_R2R |// INC C ; 0C |
{I1DCNT {INCsD == ir1}} & I1_R2R |// INC D ; 14 |
{I1DCNT {INCsDE == ir1}} & I1_R2R |// INC DE ; 13 |
{I1DCNT {INCsE == ir1}} & I1_R2R |// INC E ; 1C |
{I1DCNT {INCsH == ir1}} & I1_R2R |// INC H ; 24 |
{I1DCNT {INCsHL == ir1}} & I1_R2R |// INC HL ; 23 |
{I1DCNT {INCsL == ir1}} & I1_R2R |// INC L ; 2C |
{I1DCNT {INCsSP == ir1}} & I1_R2R |// INC SP ; 33 |
{I1DCNT {LDsA_A == ir1}} & I1_R2R |// LD A,A ; 7F |
{I1DCNT {LDsA_B == ir1}} & I1_R2R |// LD A,B ; 78 |
{I1DCNT {LDsA_C == ir1}} & I1_R2R |// LD A,C ; 79 |
{I1DCNT {LDsA_D == ir1}} & I1_R2R |// LD A,D ; 7A |
{I1DCNT {LDsA_E == ir1}} & I1_R2R |// LD A,E ; 7B |
{I1DCNT {LDsA_H == ir1}} & I1_R2R |// LD A,H ; 7C |
{I1DCNT {LDsA_L == ir1}} & I1_R2R |// LD A,L ; 7D |
{I1DCNT {LDsB_A == ir1}} & I1_R2R |// LD B,A ; 47 |
{I1DCNT {LDsB_B == ir1}} & I1_R2R |// LD B,B ; 40 |
{I1DCNT {LDsB_C == ir1}} & I1_R2R |// LD B,C ; 41 |
{I1DCNT {LDsB_D == ir1}} & I1_R2R |// LD B,D ; 42 |
{I1DCNT {LDsB_E == ir1}} & I1_R2R |// LD B,E ; 43 |
{I1DCNT {LDsB_H == ir1}} & I1_R2R |// LD B,H ; 44 |
{I1DCNT {LDsB_L == ir1}} & I1_R2R |// LD B,L ; 45 |
{I1DCNT {LDsC_A == ir1}} & I1_R2R |// LD C,A ; 4F |
{I1DCNT {LDsC_B == ir1}} & I1_R2R |// LD C,B ; 48 |
{I1DCNT {LDsC_C == ir1}} & I1_R2R |// LD C,C ; 49 |
{I1DCNT {LDsC_D == ir1}} & I1_R2R |// LD C,D ; 4A |
{I1DCNT {LDsC_E == ir1}} & I1_R2R |// LD C,E ; 4B |
{I1DCNT {LDsC_H == ir1}} & I1_R2R |// LD C,H ; 4C |
{I1DCNT {LDsC_L == ir1}} & I1_R2R |// LD C,L ; 4D |
{I1DCNT {LDsD_A == ir1}} & I1_R2R |// LD D,A ; 57 |
{I1DCNT {LDsD_B == ir1}} & I1_R2R |// LD D,B ; 50 |
{I1DCNT {LDsD_C == ir1}} & I1_R2R |// LD D,C ; 51 |
{I1DCNT {LDsD_D == ir1}} & I1_R2R |// LD D,D ; 52 |
{I1DCNT {LDsD_E == ir1}} & I1_R2R |// LD D,E ; 53 |
{I1DCNT {LDsD_H == ir1}} & I1_R2R |// LD D,H ; 54 |
{I1DCNT {LDsD_L == ir1}} & I1_R2R |// LD D,L ; 55 |
{I1DCNT {LDsE_A == ir1}} & I1_R2R |// LD E,A ; 5F |
{I1DCNT {LDsE_B == ir1}} & I1_R2R |// LD E,B ; 58 |
{I1DCNT {LDsE_C == ir1}} & I1_R2R |// LD E,C ; 59 |
{I1DCNT {LDsE_D == ir1}} & I1_R2R |// LD E,D ; 5A |
{I1DCNT {LDsE_E == ir1}} & I1_R2R |// LD E,E ; 5B |
{I1DCNT {LDsE_H == ir1}} & I1_R2R |// LD E,H ; 5C |
{I1DCNT {LDsE_L == ir1}} & I1_R2R |// LD E,L ; 5D |
{I1DCNT {LDsH_A == ir1}} & I1_R2R |// LD H,A ; 67 |
{I1DCNT {LDsH_B == ir1}} & I1_R2R |// LD H,B ; 60 |
{I1DCNT {LDsH_C == ir1}} & I1_R2R |// LD H,C ; 61 |
{I1DCNT {LDsH_D == ir1}} & I1_R2R |// LD H,D ; 62 |
{I1DCNT {LDsH_E == ir1}} & I1_R2R |// LD H,E ; 63 |
{I1DCNT {LDsH_H == ir1}} & I1_R2R |// LD H,H ; 64 |
{I1DCNT {LDsH_L == ir1}} & I1_R2R |// LD H,L ; 65 |
{I1DCNT {LDsL_A == ir1}} & I1_R2R |// LD L,A ; 6F |
{I1DCNT {LDsL_B == ir1}} & I1_R2R |// LD L,B ; 68 |
{I1DCNT {LDsL_C == ir1}} & I1_R2R |// LD L,C ; 69 |
{I1DCNT {LDsL_D == ir1}} & I1_R2R |// LD L,D ; 6A |
{I1DCNT {LDsL_E == ir1}} & I1_R2R |// LD L,E ; 6B |
{I1DCNT {LDsL_H == ir1}} & I1_R2R |// LD L,H ; 6C |
{I1DCNT {LDsL_L == ir1}} & I1_R2R |// LD L,L ; 6D |
{I1DCNT {LDsSP_HL == ir1}} & I1_R2R |// LD SP,HL ; F9 |
{I1DCNT {NOP == ir1}} & I1_R2R |// NOP ; 00 |
{I1DCNT {ORsA == ir1}} & I1_R2R |// OR A ; B7 |
{I1DCNT {ORsB == ir1}} & I1_R2R |// OR B ; B0 |
{I1DCNT {ORsC == ir1}} & I1_R2R |// OR C ; B1 |
{I1DCNT {ORsD == ir1}} & I1_R2R |// OR D ; B2 |
{I1DCNT {ORsE == ir1}} & I1_R2R |// OR E ; B3 |
{I1DCNT {ORsH == ir1}} & I1_R2R |// OR H ; B4 |
{I1DCNT {ORsL == ir1}} & I1_R2R |// OR L ; B5 |
{I1DCNT {RLA == ir1}} & I1_R2R |// RLA ; 17 |
{I1DCNT {RLCA == ir1}} & I1_R2R |// RLCA ; 07 |
{I1DCNT {RRA == ir1}} & I1_R2R |// RRA ; 1F |
{I1DCNT {RRCA == ir1}} & I1_R2R |// RRCA ; 0F |
{I1DCNT {SBCsA == ir1}} & I1_R2R |// SBC A ; 9F |
{I1DCNT {SBCsB == ir1}} & I1_R2R |// SBC B ; 98 |
{I1DCNT {SBCsC == ir1}} & I1_R2R |// SBC C ; 99 |
{I1DCNT {SBCsD == ir1}} & I1_R2R |// SBC D ; 9A |
{I1DCNT {SBCsE == ir1}} & I1_R2R |// SBC E ; 9B |
{I1DCNT {SBCsH == ir1}} & I1_R2R |// SBC H ; 9C |
{I1DCNT {SBCsL == ir1}} & I1_R2R |// SBC L ; 9D |
{I1DCNT {SCF == ir1}} & I1_R2R |// SCF ; 37 |
{I1DCNT {SUBsA == ir1}} & I1_R2R |// SUB A ; 97 |
{I1DCNT {SUBsB == ir1}} & I1_R2R |// SUB B ; 90 |
{I1DCNT {SUBsC == ir1}} & I1_R2R |// SUB C ; 91 |
{I1DCNT {SUBsD == ir1}} & I1_R2R |// SUB D ; 92 |
{I1DCNT {SUBsE == ir1}} & I1_R2R |// SUB E ; 93 |
{I1DCNT {SUBsH == ir1}} & I1_R2R |// SUB H ; 94 |
{I1DCNT {SUBsL == ir1}} & I1_R2R |// SUB L ; 95 |
{I1DCNT {XORsA == ir1}} & I1_R2R |// XOR A ; AF |
{I1DCNT {XORsB == ir1}} & I1_R2R |// XOR B ; A8 |
{I1DCNT {XORsC == ir1}} & I1_R2R |// XOR C ; A9 |
{I1DCNT {XORsD == ir1}} & I1_R2R |// XOR D ; AA |
{I1DCNT {XORsE == ir1}} & I1_R2R |// XOR E ; AB |
{I1DCNT {XORsH == ir1}} & I1_R2R |// XOR H ; AC |
{I1DCNT {XORsL == ir1}} & I1_R2R |// XOR L ; AD |
{I1DCNT {RET == ir1}} & I1_RET |// RET ; C9 |
{I1DCNT {RETsC == ir1 & cf }} & I1_RET |// RET C ; D8 |
{I1DCNT {RETsM == ir1 & sf }} & I1_RET |// RET M ; F8 |
{I1DCNT {RETsNC== ir1 & ~cf }} & I1_RET |// RET NC ; D0 |
{I1DCNT {RETsP == ir1 & ~sf }} & I1_RET |// RET P ; F0 |
{I1DCNT {RETsPE== ir1 & pvf }} & I1_RET |// RET PE ; E8 |
{I1DCNT {RETsPO== ir1 & ~pvf}} & I1_RET |// RET PO ; E0 |
{I1DCNT {RETsNZ== ir1 & ~zf }} & I1_RET |// RET NZ ; C0 |
{I1DCNT {RETsZ == ir1 & zf }} & I1_RET |// RET Z ; C8 |
{I1DCNT {EXs6SP7_HL == ir1}} & I1_RMW |// EX (SP),HL ; E3 |
{I1DCNT {DECs6HL7 == ir1}} & I1_RMW |// DEC (HL) ; 35 |
{I1DCNT {INCs6HL7 == ir1}} & I1_RMW |// INC (HL) ; 34 |
{I1DCNT {RSTs0 == ir1}} & I1_RST |// RST 0 ; C7 |
{I1DCNT {RSTs10H == ir1}} & I1_RST |// RST 10H ; D7 |
{I1DCNT {RSTs18H == ir1}} & I1_RST |// RST 18H ; DF |
{I1DCNT {RSTs20H == ir1}} & I1_RST |// RST 20H ; E7 |
{I1DCNT {RSTs28H == ir1}} & I1_RST |// RST 28H ; EF |
{I1DCNT {RSTs30H == ir1}} & I1_RST |// RST 30H ; F7 |
{I1DCNT {RSTs38H == ir1}} & I1_RST |// RST 38H ; FF |
{I1DCNT {RSTs8H == ir1}} & I1_RST ;// RST 8H ; CF |
|
//-------- CB decodes ----------------------- |
|
// First cut below |
// CB_RLC = 7'b01_00_000, // these must be compaired with ir[9:3] |
// CB_RRC = 7'b01_00_001, // these must be compaired with ir[9:3] |
// CB_RL = 7'b01_00_010, // these must be compaired with ir[9:3] |
// CB_RR = 7'b01_00_011, // these must be compaired with ir[9:3] |
// CB_SLA = 7'b01_00_100, // these must be compaired with ir[9:3] |
// CB_SRA = 7'b01_00_101, // these must be compaired with ir[9:3] |
// CB_SLL = 7'b01_00_110, // these must be compaired with ir[9:3] |
// CB_SRL = 7'b01_00_111, // these must be compaired with ir[9:3] |
|
// CB_BIT = 4'b01_01, // these must be compaired with ir[9:6] |
// CB_RES = 4'b01_10, // these must be compaired with ir[9:6] |
// CB_SET = 4'b01_11, // these must be compaired with ir[9:6] |
|
// note these are all read-modify-writ except CB_BIT |
assign cb_mem = (CB_MEM == ir1[2:0]); // this must be compaired with ir[2:0] |
|
// The ED Group |
// These are the "unique instructions in the 46, 47 rows that NEED? to be implemented |
// Not sure I want to worry about all undocumented stuff in these rows - hard to believe |
// It will matter.(IM modes are very system dependent - hard to believe even a programmer |
// would use undocumented instructions to muck with this stuff) |
// reg 2 reg simply executed by ir2 logic |
// ED_IMs0 = 10'h246// IM 0 ; ED 46 set IM0 |
// ED_LDsI_A = 10'h247// LD I,A ; ED 47 move a to I |
// ED_IMs1 = 10'h256// IM 1 ; ED 56 set IM1 |
// ED_LDsA_I = 10'h257// LD A,I ; ED 57 move I to A |
// ED_IMs2 = 10'h25E// IM 2 ; ED 5E set IM2 |
// ED_RRD = 10'h267// RRD ; ED 67 nibble roates A HL |
// ED_RLD = 10'h26F// RLD ; ED 6F nibble roates A HL |
|
// set (or clear) repeat flag at DEC_EB. |
// set (or clear) inc flag at DEC_EB. |
// seperate flows for LD, CP, IN, OUT. |
// ED_LDI == ir1// LDI ; ED A0 These are block move |
// ED_CPI == ir1// CPI ; ED A1 type insts that don't repeat |
// ED_INI == ir1// INI ; ED A2 |
// ED_OUTI == ir1// OUTI ; ED A3 |
// ED_LDD == ir1// LDD ; ED A8 |
// ED_CPD == ir1// CPD ; ED A9 |
// ED_IND == ir1// IND ; ED AA |
// ED_OUTD == ir1// OUTD ; ED AB |
wire dec_blk_rpt = |
ED_LDIR == ir1 |// LDIR ; ED B0 These are block move |
ED_CPIR == ir1 |// CPIR ; ED B1 type insts that DO repeat |
ED_INIR == ir1 |// INIR ; ED B2 |
ED_OTIR == ir1 |// OTIR ; ED B3 |
ED_LDDR == ir1 |// LDDR ; ED B8 |
ED_CPDR == ir1 |// CPDR ; ED B9 |
ED_INDR == ir1 |// INDR ; ED BA |
ED_OTDR == ir1 ;// OTDR ; ED BB |
wire ed_blk_mv = ED_LDIR == ir1 | ED_LDI == ir1 | |
ED_LDDR == ir1 | ED_LDD == ir1 ; |
wire ed_blk_cp = ED_CPIR == ir1 | ED_CPI == ir1 | |
ED_CPDR == ir1 | ED_CPD == ir1 ; |
wire ed_blk_in = ED_INIR == ir1 | ED_INI == ir1 | |
ED_INDR == ir1 | ED_IND == ir1 ; |
|
wire ed_blk_out = ED_OTIR == ir1 | ED_OUTI == ir1 | |
ED_OTDR == ir1 | ED_OUTD == ir1 ; |
|
wire dec_blk_io = ed_blk_in | ed_blk_in; |
|
wire blk_done = ~blk_rpt_flg | beq0 & ceq0 | blk_io_flg & ceq0; |
|
assign dec_blk_inc = ED_LDIR == ir1 | |
ED_CPIR == ir1 | |
ED_INIR == ir1 | |
ED_OTIR == ir1 | |
ED_LDI == ir1 | |
ED_CPI == ir1 | |
ED_INI == ir1 | |
ED_OUTI == ir1 ; |
|
|
//The ED70 instruction reads from I/O port C, |
//but does not store the result. |
//It just affects the flags. Hard to test. like the other IN x,(C) instruction. |
// |
//ED71 simply outs the value 0 to I/O port C. |
// This suggests that we should decode as follows: |
// I hope if I don't get all the IM duplicates right it won't be a tragedy |
// ED_INsREG_6C7 = 7'b1001___000,// compair with {ir[7:6],ir[2:0]} |
// |
// ED_SBCsHL_REG = 8'b1001__0010, // compair with {ir[9:6],ir[3:0]} |
// ED_ADCsHL_REG = 8'b1001__1010, // compair with {ir[9:6],ir[3:0]} |
// ED_LDs6NN7_REG = 8'b1001__0011, // compair with {ir[9:6],ir[3:0]} REG = BC,DE,HL,SP |
// ED_LDsREG_6NN7 = 8'b1001__1011, // compair with {ir[9:6],ir[3:0]} REG = BC,DE,HL,SP |
// ED_NEG = 7'b1001___100, // compair with {ir[9:6],ir[2:0]} all A<= -A |
// ED_RETN = 7'b1001___101, // compair with {ir[9:6],ir[2:0]} and !reti |
wire ed_nn = ED_LDs6NN7_REG == {ir1[9:6],ir1[3:0]} | |
ED_LDsREG_6NN7 == {ir1[9:6],ir1[3:0]} ; |
|
// we use all these to enable interrupts |
wire ed_retn = ED_RETN == {ir1[9:6],ir1[2:0]}; |
|
assign ed_dbl_rd = ED_LDsREG_6NN7 == {ir1[9:6],ir1[3:0]}; |
|
|
// assign cb_mem = CB_MEM = ir1[2:0]; // CB_MEM = 3'h110, |
|
|
|
|
wire jmpr_true = |
JRs$t2 == ir1 | |
JRsC_$t2 == ir1 & fr[0] | |
JRsNC_$t2 == ir1 & ~fr[0] | |
JRsZ_$t2 == ir1 & fr[6] | |
JRsNZ_$t2 == ir1 & ~fr[6] ; |
|
//assign { sf, zf. f5f, hf, f3f, pvf, nf, cf} = fr; |
wire callnn_true = CALLsC_NN == ir1 & cf | |
CALLsNC_NN == ir1 & ~cf | |
CALLsNN == ir1 | |
CALLsNZ_NN == ir1 & ~zf | |
CALLsPE_NN == ir1 & pvf | |
CALLsPO_NN == ir1 & ~pvf| |
CALLsP_NN == ir1 & ~sf | |
CALLsZ_NN == ir1 & zf | |
CALLsM_NN == ir1 & sf ; |
|
wire jmpnn_true = JPsC == ir1 & cf | |
JPsNC == ir1 & ~cf | |
JP == ir1 | |
JPsNZ == ir1 & ~zf | |
JPsPE == ir1 & pvf | |
JPsPO == ir1 & ~pvf| |
JPsP == ir1 & ~sf | |
JPsZ == ir1 & zf | |
JPsM == ir1 & sf ; |
|
// PUSHsAF == ir1 |
// PUSHsBC == ir1 |
// PUSHsDE == ir1 |
// PUSHsHL == ir1 |
|
wire os_a = LDs6BC7_A == ir1 | // LD (BC),A ; 02 |
LDs6DE7_A == ir1 | // LD (DE),A ; 12 |
LDs6HL7_A == ir1 | // LD (HL),A ; 77 |
LDs6NN7_A == ir1 | // LD (NN),A ; 32 XX XX |
PUSHsAF == ir1 | |
OUTs6N7_A == ir1 | |
(ED_OUTs6C7_REG == {ir1[9:6],ir1[2:0]}) & REG8_A == ir1[5:3] ; |
|
wire os_b = LDs6HL7_B == ir1 | // LD (HL),B ; 70 |
ED_LDs6NN7_REG == {ir1[9:6],ir1[3:0]} & DBL_REG_BC == ir1[5:4] | |
ED_OUTs6C7_REG == {ir1[9:6],ir1[2:0]} & REG8_B == ir1[5:3] ; |
|
wire os_c = LDs6HL7_C == ir1 | // LD (HL),C ; 71 |
PUSHsBC == ir1 | // PUSH BC |
ED_OUTs6C7_REG == {ir1[9:6],ir1[2:0]} & REG8_C == ir1[5:3] ; |
|
wire os_d = LDs6HL7_D == ir1 | // LD (HL),D ; 72 |
ED_LDs6NN7_REG == {ir1[9:6],ir1[3:0]} & DBL_REG_DE == ir1[5:4] | |
ED_OUTs6C7_REG == {ir1[9:6],ir1[2:0]} & REG8_D == ir1[5:3] ; |
|
|
wire os_e = LDs6HL7_E == ir1 | // LD (HL),E ; 73 |
PUSHsDE == ir1 | // PUSH DE |
ED_OUTs6C7_REG == {ir1[9:6],ir1[2:0]} & REG8_E == ir1[5:3] ; |
|
wire os_h = LDs6HL7_H == ir1 | // LD (HL),H ; 74 |
LDs6NN7_HL == ir1 | // LD (NN),HL ; 22 XX XX |
ED_LDs6NN7_REG == {ir1[9:6],ir1[3:0]} & DBL_REG_HL == ir1[5:4] | |
ED_OUTs6C7_REG == {ir1[9:6],ir1[2:0]} & REG8_H == ir1[5:3] ; |
|
wire os_l = LDs6HL7_L == ir1 | // LD (HL),L ; 75 |
PUSHsHL == ir1 | |
ED_OUTs6C7_REG == {ir1[9:6],ir1[2:0]} & REG8_L == ir1[5:3] ; |
|
// wire os_sp = ED_LDs6NN7_REG == {ir1[9:6],ir1[3:0]} & DBL_REG_SP == ir1[5:4]; not used ? |
|
wire os_f = PUSHsAF == ir1 ; |
|
|
//---------------- inst hazard ---------------------------------------------------------- |
// |
// On some reflection, I don't think I'm going to worry about this immediately - it |
// should be easy to kludge in a fix if necessary -- and there are more important things |
// todo. It is a very bad programming practice to muck with the instruction stream in any |
// case -- I have to believe most target applications do not do this -- although I'll probably |
// get hit pretty early with a instruction test that does. Oh well -- if that happens we fix |
// it. |
// Well -- think some here -- the hazard is because of a change in design. |
// If used to any extent.. Somebody WILL |
// want this to act the same way as the origional - even if the programming is "poor". |
// >>>>>>>> bite the bullet and do it. |
// |
// if we do an operand store and the address == pc-1 its an inst hazard, We need to execute the |
// store decrement pc and re-fetch. This is a high priority interrupt. |
// what about multi-byte stores - like LDs6NN7_A or LDs6NN7_HL - i guess we do an IF - to start |
// the pipe before the os -- same logic. |
// |
|
|
//-----------------data hazard ---------------------------------------------------------- |
// |
// Issues here have evolved to a degree as the design progressed. However the |
// Key has always been that for each instruction (no matter how complex) there |
// is only a single state in which the previous instruction can also be active |
// and that is the DEC_EXEC state. If there is a data hazard, we need to delay |
// execution of that state until the ir2 execution completes (which it always does |
// in a single tick). Note that only the RET instructions test the flag register |
// on DEC_EXEC. |
// |
// WARNING: be very careful about this. Data hazard logic is very difficult to |
// verify as there are so many instruction pairs to test. |
// |
// Situations 1) operand stores from ir1 when register is updated in ir2 |
// 2) flag tests when fr is being updated |
// 3) sp issues see below LDsSP_HL DECsSP INCsSP |
// ANY OTHERS ??? |
// |
// upd_ar, upd_br, upd_cr, upd_dr, upd_er, upd_hr, upd_lr,upd_fr, |
wire use_hl_exec = LDsSP_HL == ir1; |
wire use_sp_exec = MEM_OFSP == next_mem_state | |
MEM_OSSP == next_mem_state ; |
wire upd_sp_exec = DECsSP == ir2 | |
INCsSP == ir2 ; |
|
|
|
wire use_fr_exec = ( RETsC == ir1 | |
RETsM == ir1 | |
RETsNC == ir1 | |
RETsP == ir1 | |
RETsPE == ir1 | |
RETsPO == ir1 | |
RETsNZ == ir1 | |
RETsZ == ir1 ) ; |
|
assign hazard = (dec_state == DEC_EXEC & exec_ir2 ) & ( upd_fr & use_fr_exec | |
upd_ar & os_a | |
upd_br & os_b | |
upd_cr & os_c | |
upd_dr & os_d | |
upd_er & os_e | |
upd_hr & os_h | |
upd_lr & os_l | |
upd_hr & use_hl_exec | |
upd_lr & use_hl_exec | |
upd_sp_exec & use_sp_exec ); |
|
|
|
|
|
|
// does not include extension stuff as we are mostly looking for hazards here |
// course we do use these terms to build more decodes |
// |
wire opadr_bc = LDsA_6BC7 == ir1 | LDs6BC7_A == ir1; |
wire opadr_de = LDsA_6DE7 == ir1 | LDs6DE7_A == ir1; |
wire opadr_hl = LDsB_6HL7 == ir1 | ORs6HL7 == ir1 | LDs6HL7_B == ir1 | |
LDsD_6HL7 == ir1 | LDsC_6HL7 == ir1 | LDs6HL7_C == ir1 | |
LDsH_6HL7 == ir1 | LDsE_6HL7 == ir1 | LDs6HL7_D == ir1 | |
ADDsA_6HL7 == ir1 | LDsL_6HL7 == ir1 | LDs6HL7_E == ir1 | |
SUBs6HL7 == ir1 | LDsA_6HL7 == ir1 | LDs6HL7_H == ir1 | |
ANDs6HL7 == ir1 | ADCsA_6HL7 == ir1 | LDs6HL7_L == ir1 | |
XORs6HL7 == ir1 | SBCs6HL7 == ir1 | CPs6HL7 == ir1 ; |
|
//assign use_a = os_a; |
//assign use_b = os_b | opadr_bc; |
//assign use_c = os_c | opadr_bc; |
//assign use_d = os_d | opadr_de; |
//assign use_e = os_e | opadr_de; |
//assign use_h = os_h | opadr_hl; |
//assign use_l = os_l | opadr_hl; |
|
|
// old logic not used |
//assign use_flags = c_jmp8 | c_jmp4 | c_call | c_ret; |
|
|
|
//wire bc_eq0 = beq0 & ceq0; |
// ??? not used ? why defined ? I simply re-wrote the test re-name |
//assign rpt_blk_mv = (blk_mv_reg ) & !bc_eq0 | |
// (blk_cmp_reg) & !bc_eq0 & (nn[7:0] != 8'h0) | |
// (blk_in_reg | blk_out_reg) & !b_eq0 ; |
|
|
|
|
|
|
|
// BASIC ARCHITECTURE OF THIS FILE pc and sp not shown, but are inputs to src mux. |
// _____ and may be updated from adder output. |
// | | |
// | | pc-1 register is required to implement relative jumps. |
// | | |
// _____ |lit | |\ |
// | | | | | \ |
// | | |src2 | | \ _____ _____ |
// | | | |----->| | | | | | |
// |src | |_____| |adder|------->| | | | |
// |mux | | | | | | | |
// | |------------------->| / |2/1 |------->|wb | |
// | | | | / |mux | |adr | |
// |_____| | |/ | | | | |
// ------------------->| | | | |
// |_____| |_____| |
// MEM_NOP |
// MEM_IFPP1 MEM_OFIXpD MEM_CALL MEM_IFRST MEM_OFHL_PM MEM_IOF_C |
// MEM_OS1, MEM_OSIXpD MEM_OSNN, MEM_IFREL_N MEM_OSHL_PM MEM_IOS_C |
// MEM_OF1, MEM_OSADR MEM_OFNN MEM_JMPHL MEM_OSDE_PM MEM_IOF_N |
// MEM_OFSP MEM_OSSP_PCM2 MEM_OFADRP1 MEM_IFNN MEM_INTA MEM_IOS_N |
// MEM_OSSP MEM_OSSP_P MEM_OSADRP1 MEM_IFINT MEM_OS_HL_N |
// |
|
wire src_sp = next_mem_state == MEM_OF1 & EXs6SP7_HL == ir1 | //special case rmw |
next_mem_state == MEM_OFSP | |
next_mem_state == MEM_OSSP | |
next_mem_state == MEM_CALL ; |
wire src_pc = next_mem_state == MEM_IFPP1 | |
next_mem_state == MEM_IFREL_N ; |
|
wire src_nn = next_mem_state == MEM_IFNN | |
next_mem_state == MEM_OSNN | |
next_mem_state == MEM_OFNN ; |
|
|
wire src_de = dec_state == DEC_EXEC & LDsA_6DE7 == ir1 | // MEM_OS1 MEM_OF1 |
dec_state == DEC_EXEC & LDs6DE7_A == ir1 | // are both true at this time |
next_mem_state == MEM_OSDE_PM ; |
wire src_bc = dec_state == DEC_EXEC & LDsA_6BC7 == ir1 | |
dec_state == DEC_EXEC & LDs6BC7_A == ir1 | |
next_mem_state ==MEM_IOF_C | |
next_mem_state ==MEM_IOS_C ; |
|
|
// don't forget that hl source can be modified by prefix |
// this gets messy as we use wb_adr_o for some of these. |
// |
wire src_hl = next_mem_state == MEM_OF1 & |
(dec_state == DEC_EXEC) & |
!src_de & !src_bc & !src_sp | |
next_mem_state == MEM_OS1 & |
(dec_state == DEC_EXEC) & |
!src_de & !src_bc | |
next_mem_state == MEM_OFHL_PM | |
next_mem_state == MEM_OSHL_PM | |
next_mem_state == MEM_OS_HL_N | |
next_mem_state == MEM_JMPHL ; |
|
wire src_ix = next_mem_state == MEM_OFIXpD & ir1dd | |
next_mem_state == MEM_OSIXpD & ir1dd ; |
|
wire src_iy = next_mem_state == MEM_OFIXpD & ir1fd | |
next_mem_state == MEM_OSIXpD & ir1fd ; |
|
wire src_adr = next_mem_state == MEM_OFADRP1 | |
next_mem_state == MEM_OSADRP1 | |
next_mem_state == MEM_NOP | |
next_mem_state == MEM_OSADR ; |
|
wire src_int = next_mem_state == MEM_IOF_N | |
next_mem_state == MEM_IOS_N ; |
|
|
|
wire [15:0] src_mux = {16{ src_sp }} & sp | |
{16{ src_pc }} & pc | |
{16{ src_nn }} & nn | |
{16{ src_hl }} & hl | |
{16{ src_de }} & de | |
{16{ src_bc }} & bc | |
{16{ src_ix }} & ixr | |
{16{ src_iy }} & iyr | |
{16{ src_adr }} & wb_adr_o | |
{16{ src_int }} & { intr, nn[15:8] } | |
{16{next_mem_state == MEM_IFRST}} & {10'h0, ir1[6:4], 3'h0} ; |
|
wire block_mv_inc = (dec_state == DEC_ED) ? dec_blk_inc : blk_inc_flg; // flag set at DEC_ED |
|
|
|
wire inc = next_mem_state ==MEM_OFADRP1 | |
next_mem_state ==MEM_OSADRP1 | |
next_mem_state ==MEM_OFHL_PM & block_mv_inc | |
next_mem_state ==MEM_OSHL_PM & block_mv_inc | |
next_mem_state ==MEM_OSDE_PM & block_mv_inc | |
next_mem_state ==MEM_OFSP | |
next_mem_state ==MEM_IFPP1 | |
next_mem_state ==MEM_OSSP_PCM2 | |
next_mem_state ==MEM_OSSP_P ; |
|
wire dec = next_mem_state ==MEM_OFHL_PM & ~block_mv_inc | |
next_mem_state ==MEM_OSHL_PM & ~block_mv_inc | |
next_mem_state ==MEM_OSDE_PM & ~block_mv_inc | |
next_mem_state == MEM_OFSP ; |
|
|
wire reln = next_mem_state == MEM_IFREL_N | |
next_mem_state == MEM_OFIXpD | |
next_mem_state == MEM_OSIXpD ; |
|
wire [15:0] src2 = {16{ inc }} & 16'h0001 | |
{16{ dec }} & 16'hffff | |
{16{ reln }} & {{8{nn[15]}},nn[15:8]}| |
{16{~(reln | inc | dec)}} & 16'h0 ;// lint complains that this signal |
// has no load -YES it is not needed - |
// more for information -- amazing complaint though |
|
wire [15:0] adr_alu = src2 + src_mux; |
|
|
wire pre_inc_dec = next_mem_state == MEM_CALL | |
next_mem_state == MEM_OSSP_P | |
next_mem_state == MEM_OSSP ; |
|
|
wire [15:0] mux21 = pre_inc_dec ? adr_alu : src_mux; |
|
assign wb_rdy_nhz = (!wb_cyc_o | wb_ack_i ) & ~hazard; // wishbone ready with no hazard |
wire wb_rdy = !wb_cyc_o | wb_ack_i; |
|
assign we_next = next_mem_state == MEM_OS1 | |
next_mem_state == MEM_OSSP | |
next_mem_state == MEM_OSIXpD | |
next_mem_state == MEM_OSADR | |
next_mem_state == MEM_OSSP_PCM2 | |
next_mem_state == MEM_OSSP_P | |
next_mem_state == MEM_CALL | |
next_mem_state == MEM_OSNN | |
next_mem_state == MEM_OSADRP1 | |
next_mem_state == MEM_OSHL_PM | |
next_mem_state == MEM_OSDE_PM | |
next_mem_state == MEM_OS_HL_N | |
next_mem_state == MEM_IOS_C | |
next_mem_state == MEM_IOS_N ; |
|
|
//-------1---------2---------3--------State Machines-------6---------7---------8---------9--------0 |
// we do this just to save virtual paper below. |
// 6 5 4 15 |
assign {next_dec_state, next_mem_state, next_pipe_state} = next_state; |
|
always @(ir1 or wb_int or inst_haz or dec_state or mem_exec_dec or cb_mem or ed_nn or |
ed_blk_cp or ed_blk_in or ed_blk_out or ed_retn or ed_blk_mv or ed_dbl_rd or blk_done or |
fr or jmpr_true or callnn_true or jmpnn_true ) |
|
begin |
case (dec_state) |
DEC_IDLE: next_state = {DEC_IF1, MEM_NOP, IPIPE_NOP}; |
|
DEC_HALT: |
if (wb_int) next_state = {DEC_INT1,MEM_NOP ,IPIPE_NOP};// stay here until interrupt or reset |
else next_state = {DEC_HALT,MEM_NOP ,IPIPE_NOP}; |
DEC_IF1 : next_state = {DEC_IF2 ,MEM_IFPP1 ,IPIPE_NOP}; |
DEC_IF2 : next_state = {DEC_EXEC,MEM_IFPP1 ,IPIPE_EN1}; |
DEC_IF2A: next_state = {DEC_EXEC,MEM_IFPP1 ,IPIPE_NOP}; |
DEC_EXEC: |
if (inst_haz) next_state = {DEC_IF1, MEM_DECPC , IPIPE_NOP}; |
else if (wb_int) next_state = {DEC_INT1,MEM_NOP ,IPIPE_NOP}; |
else |
case (mem_exec_dec) // full case but can all tools understand ? just make a default |
I1_CB : next_state = {DEC_CB, MEM_IFPP1, IPIPE_EN1};// IF2_NOP -> nn <= (MEM) |
I1_DDFD : next_state = {DEC_DDFD, MEM_IFPP1, IPIPE_EN1};// gets real inst |
I1_ED : next_state = {DEC_ED, MEM_IFPP1, IPIPE_EN1}; |
I1_JMP : next_state = {DEC_IF2, MEM_JMPHL, IPIPE_NOP}; |
I1_N : next_state = {DEC_N, MEM_IFPP1, IPIPE_ENN}; |
I1_NN : next_state = {DEC_NN, MEM_IFPP1, IPIPE_ENN}; |
I1_OF : next_state = {DEC_OF, MEM_OF1, IPIPE_EN12};//transfer, don't activate |
I1_OS : next_state = {DEC_IF2, MEM_OS1, IPIPE_EN1}; // -> ir2_NOP |
I1_POP : next_state = {DEC_POP, MEM_OFSP, IPIPE_EN12}; |
I1_PUSH : next_state = {DEC_PUSH, MEM_OSSP, IPIPE_EN12}; |
I1_RET : next_state = {DEC_RET, MEM_OFSP, IPIPE_EN12}; |
I1_RMW : next_state = {DEC_RMW, MEM_OF1, IPIPE_EN12};//can't activate till data rdy |
I1_RST : next_state = {DEC_IF2, MEM_IFRST, IPIPE_ENN}; |
I1_R2R : next_state = {DEC_EXEC, MEM_IFPP1, IPIPE_EN12A2}; |
default : next_state = {DEC_EXEC, MEM_IFPP1, IPIPE_EN12A2}; //I1_R2R |
endcase |
DEC_CB: if (cb_mem) next_state = {DEC_CBM, MEM_OF1, IPIPE_EN12}; |
else next_state = {DEC_EXEC, MEM_IFPP1, IPIPE_EN12A2}; |
DEC_DDFD: // except for CB and EB these all act the same H and L get modified by prefix |
case (mem_exec_dec) |
I1_CB : next_state = {DEC_PFxCB,MEM_IFPP1, IPIPE_EN1};// IF2_NOP -> nn <= (MEM) |
I1_DDFD : next_state = {DEC_DDFD, MEM_IFPP1, IPIPE_EN1}; |
I1_ED : next_state = {DEC_ED, MEM_IFPP1, IPIPE_EN1};//How do we clear the prefix? |
I1_JMP : next_state = {DEC_IF2, MEM_JMPHL, IPIPE_NOP}; |
I1_N : next_state = {DEC_N, MEM_IFPP1, IPIPE_ENN}; |
I1_NN : next_state = {DEC_NN, MEM_IFPP1, IPIPE_ENN}; |
I1_OF : next_state = {DEC_DDOF, MEM_IFPP1, IPIPE_ENN}; // d to nn - need to get d |
// LD A,(BC) LD A,(DE) will |
// become ix+d - do we care ? |
// i hope not |
I1_OS : next_state = {DEC_DDOS, MEM_IFPP1, IPIPE_ENN}; // d to nn |
I1_POP : next_state = {DEC_POP, MEM_OFSP, IPIPE_EN12}; |
I1_PUSH : next_state = {DEC_PUSH, MEM_OSSP, IPIPE_EN12}; |
I1_RET : next_state = {DEC_RET, MEM_OFSP, IPIPE_EN12}; |
I1_RMW : next_state = {DEC_RMW, MEM_OF1, IPIPE_EN12}; |
I1_RST : next_state = {DEC_IF2, MEM_IFRST, IPIPE_NOP}; // just dump next inst |
I1_R2R : next_state = {DEC_EXEC, MEM_IFPP1, IPIPE_EN12A2}; //I1_R2R |
default : next_state = {DEC_EXEC, MEM_IFPP1, IPIPE_EN12A2}; //I1_R2R |
endcase |
DEC_ED: |
if (ed_nn) next_state = {DEC_EDNN1, MEM_IFPP1, IPIPE_ENN}; |
// we need to set inc and io and repeat flags on this state for continued block |
// processing -- keep the states of this machine somewhat manageable. |
else if (ed_blk_cp ) next_state = {DEC_EDBCP1, MEM_OFHL_PM, IPIPE_EN12};// MEM_OFHL_PM triggers --BC |
else if (ed_blk_in ) next_state = {DEC_EDBIN1, MEM_IOF_C, IPIPE_EN12};// MEM_IOF_C triggers --B |
else if (ed_blk_out) next_state = {DEC_EDBOUT1,MEM_OFHL_PM, IPIPE_EN12}; |
else if (ed_blk_mv ) next_state = {DEC_EDBMV1, MEM_OFHL_PM, IPIPE_EN12}; |
else if (ed_retn ) next_state = {DEC_RET, MEM_OFSP, IPIPE_EN12};// see int logic below |
else next_state = {DEC_EXEC, MEM_IFPP1, IPIPE_EN12A2}; |
// double register reads and writes here |
DEC_EDNN1: next_state = {DEC_EDNN2, MEM_NOP, IPIPE_ENN}; // address to nn |
DEC_EDNN2: |
if (ed_dbl_rd) next_state = {DEC_EDRD1, MEM_OFNN, IPIPE_NOP}; |
else next_state = {DEC_EDWR, MEM_OSNN, IPIPE_NOP};// OSNN selects data ok? |
DEC_EDRD1: next_state = {DEC_EDRD2, MEM_OFADRP1, IPIPE_ENN}; // 1st byte 2n |
DEC_EDRD2: next_state = {DEC_IF2, MEM_IFPP1, IPIPE_ENNA2}; // 2nd byte 2nn |
DEC_EDWR: next_state = {DEC_IF1, MEM_OSADRP1, IPIPE_NOP}; |
|
// ED block moves |
DEC_EDBCP1: |
if (blk_done) next_state = {DEC_EXEC, MEM_IFPP1,IPIPE_ENNA2}; |
else if(wb_int) next_state = {DEC_INT1, MEM_NOP, IPIPE_ENNA2}; |
else next_state = {DEC_EDBCP2, MEM_NOP, IPIPE_ENNA2};//set flags |
DEC_EDBCP2: next_state = {DEC_EDBCP3, MEM_NOP, IPIPE_NOP};//wait for fr. alu_out is slow |
DEC_EDBCP3: if (fr[7]) next_state = {DEC_EXEC , MEM_IFPP1, IPIPE_NOP}; |
else next_state = {DEC_EDBCP1, MEM_OFHL_PM, IPIPE_NOP}; |
|
DEC_EDBIN1: next_state = {DEC_EDBIN2, MEM_NOP, IPIPE_ENN}; |
DEC_EDBIN2: if (blk_done) next_state = {DEC_IF2A, MEM_OSHL_PM,IPIPE_NOP}; // implies nn |
else if (wb_int) next_state = {DEC_INT1, MEM_OSHL_PM,IPIPE_NOP}; |
else next_state = {DEC_EDBIN1,MEM_OSHL_PM,IPIPE_NOP};//set flags |
DEC_EDBIN3: next_state = {DEC_EDBIN1, MEM_IOF_C, IPIPE_NOP}; |
|
DEC_EDBOUT1: next_state = {DEC_EDBOUT2, MEM_NOP, IPIPE_ENN}; |
DEC_EDBOUT2:if (blk_done) next_state = {DEC_EXEC, MEM_IOS_C,IPIPE_NOP}; |
else if (wb_int) next_state = {DEC_INT1, MEM_IOS_C,IPIPE_NOP}; // DEC_EDBOUT: if (blk_rpt) |
else next_state = {DEC_EDBOUT3,MEM_IOS_C,IPIPE_NOP}; |
|
DEC_EDBOUT3: next_state = {DEC_EDBOUT1,MEM_OFHL_PM, IPIPE_NOP}; |
|
DEC_EDBMV1: next_state = {DEC_EDBMV2, MEM_NOP, IPIPE_ENN}; |
DEC_EDBMV2: if (blk_done) next_state = {DEC_EXEC, MEM_OSDE_PM,IPIPE_NOP}; |
else if (wb_int) next_state = {DEC_INT1, MEM_OSDE_PM,IPIPE_NOP}; //DEC_EDBOUT: if (blk_rpt) |
else next_state = {DEC_EDBMV3,MEM_OSDE_PM,IPIPE_NOP}; |
|
DEC_EDBMV3: next_state = {DEC_EDBMV1,MEM_OFHL_PM, IPIPE_NOP}; |
|
DEC_N: |
if (INsA_6N7== ir1) next_state = {DEC_NIN, MEM_IOF_N, IPIPE_EN12}; |
else if (OUTs6N7_A==ir1) next_state = {DEC_IF1, MEM_IOS_N, IPIPE_EN12}; |
else if (LDs6HL7_N==ir1) next_state = {DEC_IF1, MEM_OS_HL_N, IPIPE_EN12}; |
else if (jmpr_true) next_state = {DEC_IF2, MEM_IFREL_N, IPIPE_NOP}; |
else next_state = {DEC_EXEC, MEM_IFPP1, IPIPE_EN12A2};//r2r or false jumps |
DEC_NIN: next_state = {DEC_IF2, MEM_IFPP1, IPIPE_ENNA2}; |
|
|
//ISSUES: LDsSP_NN - load commanded from ir2 decode? and mechaninsm for updating PC on |
// JMP and CALL |
// on CALL We have IFNN for JMP |
// For CALL Use MEM_CALL to transfer pc<=nn, nn<=pc, adr<=sp then MEM_OSSP then IFPP1 |
// For LDsSP_NN yes update from ir2 decode. |
DEC_NN: |
if (callnn_true) next_state = {DEC_NNCALL1, MEM_NOP, IPIPE_ENN};// this gets new adr in nn |
//if we store from nn we can't do |
// a mem op now |
|
else if (jmpnn_true) next_state = {DEC_NNJMP, MEM_NOP, IPIPE_ENN}; // gotta get nn before we can |
// transfer to adr. |
else if (LDs6NN7_A==ir1) next_state = {DEC_NNOS3, MEM_IFPP1, IPIPE_ENN}; |
else if (LDs6NN7_HL==ir1) next_state = {DEC_NNOS1, MEM_IFPP1, IPIPE_ENN}; |
else if (LDsA_6NN7==ir1) next_state = {DEC_NNOF3, MEM_IFPP1, IPIPE_ENN}; |
else if (LDsHL_6NN7==ir1) next_state = {DEC_NNOF1, MEM_IFPP1, IPIPE_ENN}; |
else next_state = { DEC_IF2, MEM_IFPP1, IPIPE_ENNEN2A2}; |
|
DEC_NNCALL1: next_state = {DEC_NNCALL2, MEM_CALL , IPIPE_NOP}; |
DEC_NNCALL2: next_state = {DEC_IF1, MEM_OSSP, IPIPE_ENN};//A1 activates r2r xfers from ir1 |
DEC_NNJMP: next_state = {DEC_IF2, MEM_IFNN , IPIPE_NOP}; |
|
// ISSUE: we blow out ir1 here - so need to keep some status to execute OSNN2. |
// general solution if not DEC_EXEC we get op frmo nn high byte. |
// note that first MEM_OSNN trabsferrs nn to wb_adr_o. |
DEC_NNOS1: next_state = {DEC_NNOS2, MEM_OSNN, IPIPE_EN1}; |
DEC_NNOS2: next_state = {DEC_IF2A, MEM_OSNN, IPIPE_NOP}; |
DEC_NNOS3: next_state = {DEC_IF2A, MEM_OSNN, IPIPE_EN1}; |
|
DEC_NNOF1: next_state = {DEC_NNOF2, MEM_OFNN, IPIPE_EN12}; |
DEC_NNOF2: next_state = {DEC_NNOF4, MEM_OFNN, IPIPE_ENN}; |
DEC_NNOF3: next_state = {DEC_NNOF4, MEM_OFNN, IPIPE_EN12}; |
DEC_NNOF4: next_state = {DEC_EXEC, MEM_IFPP1, IPIPE_ENNA2}; |
|
DEC_DDOS: next_state = {DEC_IF2A, MEM_OSIXpD, IPIPE_EN12}; |
DEC_DDOF: next_state = {DEC_OF , MEM_OFIXpD, IPIPE_EN12}; |
|
|
DEC_OF: next_state = {DEC_EXEC, MEM_IFPP1 , IPIPE_ENNA2}; |
DEC_POP: next_state = {DEC_NNOF4, MEM_OFSP, IPIPE_ENN }; |
DEC_PUSH: next_state = {DEC_IF2A , MEM_OSSP, IPIPE_NOP }; |
|
|
DEC_RET: next_state = { DEC_RET2, MEM_OFSP, IPIPE_ENN }; |
DEC_RET2: next_state = { DEC_NNCALL2, MEM_NOP, IPIPE_ENN }; |
// blow off a tick so we don't gronk adr |
DEC_RMW: next_state = {DEC_RMW2, MEM_NOP, IPIPE_ENNA2}; //activate |
DEC_RMW2: next_state = {DEC_IF1 , MEM_OSADR, IPIPE_NOP }; // from nn |
|
|
// IF memory -- rmw else these are all reg 2 reg |
DEC_CBM: if (CB_BIT==ir1[9:6]) next_state = {DEC_IF2, MEM_IFPP1, IPIPE_ENNA2}; |
else next_state = {DEC_RMW2 , MEM_NOP, IPIPE_ENNA2}; |
|
// The DDCB anf FDCB all assume memory operands |
// These beauties always rmw memory. If a register op is default, they also |
// update the register. Programmers think of this as 2 ops for the price of 1. |
// unfortunately it is 2 ops for the price of 4.-- its not the number of lines |
// of assembler code that count but the number of bytes assembled. Oh well I signed |
// up for this...... and had a notion of what I was getting into. |
// |
DEC_PFxCB: next_state = { DEC_PFxCB2, MEM_IFPP1, IPIPE_ENN}; // this gets d |
DEC_PFxCB2: next_state = { DEC_PFxCB3, MEM_OFIXpD, IPIPE_EN1}; //actual inst |
DEC_PFxCB3: next_state = { DEC_PFxCB4, MEM_IFPP1, IPIPE_ENNEN2A2}; |
DEC_PFxCB4: next_state = { DEC_IF2A, MEM_OSADR, IPIPE_EN1}; //execute ir2 |
|
// crap gotta subtract 2 (we always increment pc 2 times relative to the inst |
// that got interrupted. also can't push and dec pc without 2 adders. |
// choices: 1) fix up pc in 2 ticks 2) fix in 1 tick 3) add adder and do it fast |
// if there's anyone who knows is there anyone who cares. |
// guess I'll do it fast -- just a 16 bit subtractor. heck silicon is |
// cheap. |
DEC_INT1: next_state = {DEC_INT2, MEM_OSSP_PCM2, IPIPE_NOP}; //must derement PC |
DEC_INT2: next_state = {DEC_INT3, MEM_OSSP_P, IPIPE_NOP}; //must dec sp and PC 2 ops? |
DEC_INT3: next_state = {DEC_INT4, MEM_INTA, IPIPE_NOP}; |
DEC_INT4: next_state = {DEC_INT5, MEM_NOP, IPIPE_ENN}; |
DEC_INT5: next_state = {DEC_IF2, MEM_IFINT, IPIPE_NOP}; |
default: next_state = {DEC_IDLE, MEM_NOP, IPIPE_NOP}; |
endcase |
end |
|
|
always @(posedge wb_clk_i or posedge rst_i) |
if (rst_i) dec_state <= DEC_IDLE; |
else if (wb_rdy_nhz ) dec_state <= next_dec_state; |
|
|
//-----------------------instruction register #1 ---------------------------------- |
// // next_pipe_state {ir1,ir2,nn,act_ir2} |
|
wire update_prefix = dec_state == DEC_EXEC | dec_state == DEC_DDFD; |
|
always @(posedge wb_clk_i or posedge rst_i) |
if (rst_i) ir1 <= NOP; |
else if (wb_rdy_nhz & next_pipe_state[3]) ir1 <= {2'b0, wb_dat_i} ; |
else if ( wb_rdy_nhz &update_prefix ) ir1 <= {ir1[7:0]==8'hed, ir1[7:0]==8'hcd, ir1[7:0]}; |
|
//----------- prefix states ----------------------------------------- |
// strings of prefix insts are ignored up to last one. Also dded and fded are ignored |
// but ddcd and fdcd are defined prefix sets. |
// |
always @(posedge wb_clk_i) |
if (wb_rdy_nhz & next_pipe_state[3]) {ir1dd, ir1fd } <= 2'b0; |
else if ( wb_rdy_nhz & update_prefix ) |
{ir1dd, ir1fd } <= {ir1dd | (ir1[7:0]==8'hdd ) & (ir1[7:0]!=8'hed) & (ir1[7:0]!=8'hfd), |
ir1fd | (ir1[7:0]==8'hfd ) & (ir1[7:0]!=8'hed) & (ir1[7:0]!=8'hdd) }; |
|
//------------------- inst reg #2 ----------------------------------- |
// This stuff is key to the data hazard logic. Hazards arise only AFTER activation of |
// a previous instruction. Fundamentally all state changes related to ir1 may be |
// delayed eithor by a delay in wb response, or by a hazard. Ir2 state changes |
// are keyed off exec_ir2 - and always happen immediately. ( exec_ir2 always is |
// immediately reset - unless of course a new instruction is transferred and executed. |
// |
// |
// |
always @(posedge wb_clk_i or posedge rst_i) |
if (rst_i) ir2 <= 10'h0; |
else if (wb_rdy_nhz & next_pipe_state[2]) ir2 <= ir1; |
|
always @(posedge wb_clk_i or posedge rst_i) |
if (rst_i) |
begin |
ir2dd <= 1'b0; |
ir2fd <= 1'b0; |
end |
else if (wb_rdy_nhz & next_pipe_state[2]) |
begin |
ir2dd <= ir1dd; |
ir2fd <= ir1fd; |
end |
|
always @(posedge wb_clk_i ) |
if (wb_rdy_nhz & next_pipe_state[0]) exec_ir2 <= 1'b1; |
else exec_ir2 <= 1'b0; |
|
|
|
|
|
//--------------- block move flags ------------------------ |
always @(posedge wb_clk_i) |
if (dec_state == DEC_ED) blk_inc_flg <= dec_blk_inc; |
|
always @(posedge wb_clk_i) |
if (dec_state == DEC_ED) blk_rpt_flg <= dec_blk_rpt; |
|
|
always @(posedge wb_clk_i) |
if (dec_state == DEC_ED) blk_io_flg <= dec_blk_io; |
|
|
//-------------------------- memory interface stuff ---------------------------- |
|
|
// -- wb_adr_o |
always @(posedge wb_clk_i) if (wb_rdy) wb_adr_o <= mux21; |
|
// -- wb_we_o; |
|
always @(posedge wb_clk_i or posedge rst_i) |
if (rst_i) wb_we_o <= 1'b0; |
else if (wb_rdy_nhz) wb_we_o <= we_next; |
|
|
|
// -- wb_cyc_o |
// below is old logic -- appears not needed |
//wire no_wb_start = mem_idle | mem_halt | mem_op3 & blk_cmp_reg | mem_op1 & rmw_reg; |
always @(posedge wb_clk_i or posedge rst_i) |
if (rst_i) wb_cyc_o <= 1'b0; |
else if (wb_rdy_nhz) wb_cyc_o <= next_mem_state != MEM_NOP ; |
|
// -- wb_stb_o; |
|
always @(posedge wb_clk_i or posedge rst_i) |
if (rst_i) wb_stb_o <= 1'b0; |
else if (wb_rdy_nhz) wb_stb_o <= next_mem_state != MEM_NOP ; |
|
|
// -- wb_lock lets not worry about lock unless somebody thinks it matters. |
|
// -- wb_tga_o |
always @(posedge wb_clk_i or posedge rst_i) |
if (rst_i) wb_tga_o <= 2'b0; |
else if (wb_rdy_nhz) |
begin |
if (next_mem_state == MEM_IOF_C | |
next_mem_state == MEM_IOS_C | |
next_mem_state == MEM_IOF_N | |
next_mem_state == MEM_IOS_N ) wb_tga_o <= TAG_IO; |
|
else if (next_mem_state == MEM_INTA ) wb_tga_o <= TAG_INT; |
else wb_tga_o <= 2'b0 ; |
end |
|
//------------ the input-output data register (nn) ----------------------------------------- |
// basicaly we store lsb's folowed by msb's |
// input is always to msb (of input regiser) first (if a 2 byte operand, lsb<=msb before transfer) |
// this gets nn to position { msb, lsb } before we execute 2 byte transfer. |
// |
// if we don't update - we byte swap as well as |
// when we read |
// IMPORTANT We store from MSB's so that on block moves read and write from same place. |
// this makes the output look somewhat bass-ackwards but who is looking? |
// |
// There is probably a simpler way to do this. Unfortunately there are a lot of |
// dependencies here. Ill continue as planned till it proves untractable. |
// Issue is that we are using ir1 to provide the op specification -- but in general |
// ir1 gets gronked before 2nd store (if it happens) - so we need to capture both |
// data first time OSIXpD OS1 OSSP, and MEM_OSNN |
// |
// on consideration lets make a flag flag_firstos that gets set on first store after |
// DEC_EXEC |
// ISSUE reads both here and in ir1 need to execute on wb_ack_i ? |
// I recall wb_ack_i must stay active until a change in cycle ? |
// need to review wb spec. |
// |
//issue: how is EXs6SP7_HL implemented -- it is known as a rmw - and only trick for this file is |
// that nn must be properly updates with ir2 |
|
always @(posedge wb_clk_i or posedge rst_i) |
if (rst_i) flag_os1 <= 1'b0; |
else if ((DEC_EXEC == next_dec_state) & wb_rdy) flag_os1 <= 1'b0; |
else if ( we_next ) flag_os1 <= 1'b1; |
|
|
wire [15:0] pc_2 = pc - 16'h2; |
always @(posedge wb_clk_i) |
if (wb_rdy_nhz) |
begin |
if ( we_next & flag_os1) nn <= { nn[7:0], nn[15:8] } ; |
else if(we_next & ( next_mem_state == MEM_CALL)) nn <= {pc[7:0], pc[15:8]}; |
else if(we_next & ( next_mem_state == MEM_OSSP_PCM2)) nn <= {pc_2[7:0], pc_2[15:8]}; |
else if(EXs6SP7_HL== ir2 & ir2dd & exec_ir2) nn <= ixr; |
else if(EXs6SP7_HL== ir2 & ir2fd & exec_ir2) nn <= iyr; |
else if(EXs6SP7_HL== ir2 & exec_ir2) nn <= hl; |
// these are the general cases with ir1 providing register specification |
else if(we_next & ( next_mem_state == MEM_OS1 | |
next_mem_state == MEM_OSIXpD | |
next_mem_state == MEM_OSSP | |
next_mem_state == MEM_OSNN ) ) |
begin |
if (os_a) nn[15:8] <= ar; |
if (os_b) nn[15:8] <= br; |
if (os_c) nn <= {cr, br }; // use for PUSHsBC |
if (os_d) nn[15:8] <= dr; |
if (os_e) nn <= {er, dr }; // use for PUSHsDE |
if (os_h) nn[15:8] <= hr; |
if (os_l) nn <= {lr, hr }; // use for PUSHsHL |
if (os_f) nn <= {fr, ar }; // use for PUSHsAF |
end |
// 4/19/2004 previously no if here - if not needed we don't need next_pipe_state[1] eithor |
else if (next_pipe_state[1]) nn <= { wb_dat_i, nn[15:8] }; |
end |
|
|
|
//------------------- pc and sp ---------------------------------------------------- |
always @(posedge wb_clk_i or posedge rst_i) |
if (rst_i) pc <= 16'h0; |
else if (wb_rdy_nhz) |
begin |
if (next_mem_state == MEM_DECPC) pc <= pc - 16'h1; // decrementer could perhaps be shared. |
if (next_mem_state == MEM_IFPP1) pc <= adr_alu; |
if (next_mem_state == MEM_CALL ) pc <= nn; //Use MEM_CALL to exchange pc<=>nn |
if (next_mem_state == MEM_IFRST) pc <= src_mux; |
if (next_mem_state == MEM_JMPHL) pc <= src_mux; |
if (next_mem_state == MEM_IFNN ) pc <= src_mux; |
if (next_mem_state == MEM_IFINT) pc <= src_mux; |
end |
|
//---------------------------------- sp ----------------------------------------------------- |
// |
// with pc updates are always made from ir1 as the PC is so critical to instruction flow. |
// (this of course creates the possibility of an "inst_hazard" - where data is stored in an |
// instruction already fetched - see below) |
// with sp the situation is not so simple. |
// Issues - especially regarding hazards. |
// |
// LDsSP_NN this should be done from ir2 - no hazard as active state is ALWAYS IF2 |
// |
// ADDsHL_SP The add is a pre-add so sp cannot be modified before inst is executed from ir2 |
// DECsSP Just do it with ir1 at DEC_EXEC gotcha need -- IFPP1 in general use ir2 -> hazard |
// EXs6SP7_HL rmw - no change to sp - no issue here |
// INCsSP Just do it with ir1 at DEC_EXEC gotcha -- IFPP1 use ir2 -> hazard |
// LDsSP_HL do from ir1 and use standard hazard logic (if H or L is being |
// updated -- wait) |
// |
// ED_LDs6NN7_REG REG== SP // needs to be done from ir2 |
// ED_LDsREG_6NN7 REG== SP // do from ir2 - no hazard as executed on IF2 - refill pipe |
|
always @(posedge wb_clk_i ) |
if (exec_ir2 ) // this has priority of course |
begin |
if (LDsSP_NN == ir2) sp <= nn; |
if (ED_LDsREG_6NN7 == ir2) sp <= nn; |
if ( DECsSP == ir2 ) sp <= add16; |
if ( INCsSP == ir2 ) sp <= add16; |
end |
else if (wb_rdy_nhz) |
begin |
if ( DECsSP == ir1 & dec_state == DEC_EXEC) sp <= adr_alu; |
if ( INCsSP == ir1 & dec_state == DEC_EXEC) sp <= adr_alu; |
if ( LDsSP_HL == ir1 & dec_state == DEC_EXEC) sp <= {hr,lr}; |
if (next_mem_state == MEM_OFSP ) sp <= adr_alu; |
if (next_mem_state == MEM_OSSP ) sp <= adr_alu; |
if (next_mem_state == MEM_OSSP_PCM2 ) sp <= adr_alu; |
if (next_mem_state == MEM_OSSP_P ) sp <= adr_alu; |
end |
//----------------- inst hazard logic ------------------------------------------ |
|
|
|
always @(posedge wb_clk_i or posedge rst_i) |
if (rst_i) inst_haz <= 1'b0; |
else if (we_next & (pc - 16'h1) == mux21) inst_haz <= 1'b1; |
else if (dec_state == DEC_EXEC) inst_haz <= 1'b0; // highest priority interrupt |
|
//-------------------- int logic ---------------------------------------- |
// We have a wishbone interrupt system - which i guess does not preclude a |
// non-maskable interrupt...... but bottom line is that such an interrupt is |
// definately out of favor with current system thinking. Within an embedded system |
// ( the target application here ) a single interrupt controller capable of handeling |
// as many interrupts as desired is the best choice. |
// Therefore we enable only mode 2 interrupts and a single enable ff. |
// |
// This begs the question of what to do with the "RETI" instruction -- ED4D. We opt to |
// enable interrupts with this instruction (and all its "aliases"). |
// |
always @(posedge wb_clk_i or posedge rst_i) |
if (rst_i) int_en <= 1'b0; |
else if (wb_rdy_nhz) |
begin |
if ((dec_state == DEC_EXEC) & (DI== ir1)) int_en <= 1'b0; |
else if ((dec_state == DEC_EXEC) & en_int_next) int_en <= 1'b1; |
else if ((dec_state == DEC_ED) & ed_retn) int_en <= 1'b0; |
if (dec_state == DEC_INT1) int_en <= 1'b0; |
end |
|
|
always @(posedge wb_clk_i or posedge rst_i) |
if (rst_i) en_int_next <=1'b0; |
else if (wb_rdy_nhz) |
begin |
if ((dec_state == DEC_EXEC) & (EI== ir1)) en_int_next <=1'b1; |
else if (dec_state == DEC_EXEC) en_int_next <=1'b0; |
end |
|
always @(posedge wb_clk_i) |
wb_irq_sync <= int_req_i; |
|
assign wb_int = wb_irq_sync & int_en; |
|
endmodule |
|
/trunk/rtl/z80_sdram_cfg.v
0,0 → 1,98
/////////////////////////////////////////////////////////////////////////////////////////////// |
//// |
//// file name: z80_sdram_cfg |
//// description: configure address range and mux data for on-board sdram |
//// project: wb_z80 //// |
//// |
//// Author: B.J. Porcella |
//// bporcella@sbcglobal.net |
//// |
//// |
//// |
/////////////////////////////////////////////////////////////////////////////////////////////// |
//// |
//// Copyright (C) 2000-2002 B.J. Porcella |
//// Real Time Solutions |
//// |
//// |
//// 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 SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY |
//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR |
//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
//// POSSIBILITY OF SUCH DAMAGE. |
//// |
/////////////////////////////////////////////////////////////////////////////////////////////// |
// CVS Log |
// |
// $Id: z80_sdram_cfg.v,v 1.1 2004-04-27 21:27:13 bporcella Exp $ |
// |
// $Date: 2004-04-27 21:27:13 $ |
// $Revision: 1.1 $ |
// $Author: bporcella $ |
// $Locker: $ |
// $State: Exp $ |
// |
// Change History: |
// $Log: not supported by cvs2svn $ |
// Revision 1.1.1.1 2004/04/13 23:47:42 bporcella |
// import first files |
// |
// |
// |
//-------1---------2---------3--------Module Name and Port List------7---------8---------9--------0 |
module z80_sdram_cfg (cfg_ce_spram_o, cfg_do, cfg_ack_o, wb_adr_i, sdram_di, wb_dat_i, wb_ack_i, |
wb_stb_i, wb_cyc_i, wb_tga_i); |
|
|
//-------1---------2---------3--------Output Ports---------6---------7---------8---------9--------0 |
output cfg_ce_spram_o; |
output [7:0] cfg_do; |
output cfg_ack_o; |
|
//-------1---------2---------3--------Input Ports----------6---------7---------8---------9--------0 |
|
input [15:0] wb_adr_i; |
input [7:0] sdram_di, wb_dat_i; |
input wb_ack_i; |
input wb_stb_i; |
input wb_cyc_i; |
input [1:0] wb_tga_i; |
|
//-------1---------2---------3--------Parameters-----------6---------7---------8---------9--------0 |
//-------1---------2---------3--------Wires------5---------6---------7---------8---------9--------0 |
//-------1---------2---------3--------Registers--5---------6---------7---------8---------9--------0 |
//-------1---------2---------3--------Assignments----------6---------7---------8---------9--------0 |
|
// this assigns the low half of the address space to the on-board sdram. Any given implementation |
// might well wish to modify this assigmnment |
// Lot of I/O for not much logic --- guess if there were no "rules" I would simply put this stuff |
// in the top level. |
|
|
|
wire sram_addr = ~wb_adr_i[15] & (wb_tga_i == 2'b00); |
|
wire cfg_ce_spram_o = sram_addr & wb_cyc_i & wb_stb_i; |
|
wire [7:0] cfg_do = sram_addr ? sdram_di : wb_dat_i; |
|
wire cfg_ack_o = cfg_ce_spram_o | wb_ack_i; |
|
//-------1---------2---------3--------State Machines-------6---------7---------8---------9--------0 |
|
|
|
endmodule |