OpenCores
URL https://opencores.org/ocsvn/tv80/tv80/trunk

Subversion Repositories tv80

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 1 to Rev 2
    Reverse comparison

Rev 1 → Rev 2

/trunk/rtl/core/t80_top.v
0,0 → 1,135
/*
* Copyright (c) 2003-2004 by Cisco Systems Inc.
* $Id: t80_top.v,v 1.1 2004-05-16 17:39:57 ghutchis Exp $
* All rights reserved.
*
* Author: Guy Hutchison
*
*/
 
module t80_top (/*AUTOARG*/
// Outputs
t80_cpu_req, t80_cpu_read, t80_cpu_addr, t80_cpu_wdata,
t80_cpu_mem_rdata, t80_cpu_mem_ack,
// Inputs
clk250, reset, cpu_reset, cpu_t80_ack, cpu_t80_rdata, cpu_t80_addr,
cpu_t80_mem_read, cpu_t80_mem_wdata, cpu_t80_mem_req
);
 
input clk250;
input reset;
input cpu_reset;
// interface from T80 to Alkindi registers
output t80_cpu_req;
input cpu_t80_ack;
output t80_cpu_read;
output [10:0] t80_cpu_addr;
output [15:0] t80_cpu_wdata;
input [15:0] cpu_t80_rdata;
 
// interface from external CPU to T80
input [15:0] cpu_t80_addr;
input cpu_t80_mem_read;
input [7:0] cpu_t80_mem_wdata;
output [7:0] t80_cpu_mem_rdata;
input cpu_t80_mem_req;
output t80_cpu_mem_ack;
 
wire [15:0] addr;
 
`ifdef T80_4K_RAM
parameter asz = 12,
depth = 4096;
`else
parameter asz = 11,
depth = 2048;
`endif
reg lcl_reset, lcl_cpu_reset_n;
wire [7:0] ram_wdata;
wire [7:0] ram_rdata;
wire [7:0] din, dout;
assign ram_wdata = dout;
always @(posedge clk250)
begin
lcl_reset <= #1 reset;
lcl_cpu_reset_n <= #1 ~cpu_reset;
end
ak_clk_sync req_sync (.clk(clk250), .din (cpu_t80_mem_req), .dout(cpu_sync_req));
 
wire wait_n = 1'b1;
wire int_n = 1'b1;
wire nmi_n = 1'b1;
wire busrq_n = 1'b1;
t80_wrap t80_inst
(
// Outputs
.mem_req (mem_req),
.mem_rd (mem_rd),
.io_req (io_req),
.io_rd (io_rd),
.addr (addr[15:0]),
.dout (dout[7:0]),
// Inputs
.clk250 (clk250),
.reset_n (lcl_cpu_reset_n),
.wait_n (wait_n),
.int_n (int_n),
.nmi_n (nmi_n),
.busrq_n (busrq_n),
.mem_ack (mem_ack),
.io_ack (io_ack),
.din (din[7:0]));
ak_t80_io t80_io0
(/*AUTOINST*/
// Outputs
.io_ack (io_ack),
.int_n (int_n),
.nmi_n (nmi_n),
.din (din[7:0]),
.t80_cpu_req (t80_cpu_req),
.t80_cpu_read (t80_cpu_read),
.t80_cpu_addr (t80_cpu_addr[10:0]),
.t80_cpu_wdata (t80_cpu_wdata[15:0]),
// Inputs
.clk250 (clk250),
.reset (reset),
.io_req (io_req),
.io_rd (io_rd),
.addr (addr[15:0]),
.mreq_n (mreq_n),
.dout (dout[7:0]),
.ram_rdata (ram_rdata[7:0]),
.cpu_t80_ack (cpu_t80_ack),
.cpu_t80_rdata (cpu_t80_rdata[15:0]));
 
t80_memctl t80_memctl0
(
// Outputs
.mem_ack (mem_ack),
.ram_rdata (ram_rdata[7:0]),
.t80_cpu_mem_rdata (t80_cpu_mem_rdata[7:0]),
.t80_cpu_mem_ack (t80_cpu_mem_ack),
// Inputs
.clk250 (clk250),
.reset (reset),
.mem_req (mem_req),
.mem_rd (mem_rd),
.addr (addr[asz-1:0]),
.ram_wdata (ram_wdata[7:0]),
.cpu_t80_addr (cpu_t80_addr[asz-1:0]),
.cpu_t80_mem_read (cpu_t80_mem_read),
.cpu_t80_mem_wdata (cpu_t80_mem_wdata[7:0]),
.cpu_t80_mem_req (cpu_sync_req));
 
// synopsys dc_script_begin
// set_attribute current_design "revision" "$Id: t80_top.v,v 1.1 2004-05-16 17:39:57 ghutchis Exp $" -type string -quiet
// synopsys dc_script_end
endmodule // t80_top
/trunk/rtl/core/tv80_reg.v
0,0 → 1,71
//
// TV80 8-Bit Microprocessor Core
// Based on the VHDL T80 core by Daniel Wallner (jesus@opencores.org)
//
// Copyright (c) 2004 Guy Hutchison (ghutchis@opencores.org)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
module tv80_reg (/*AUTOARG*/
// Outputs
DOBH, DOAL, DOCL, DOBL, DOCH, DOAH,
// Inputs
AddrC, AddrA, AddrB, DIH, DIL, clk, CEN, WEH, WEL
);
input [2:0] AddrC;
output [7:0] DOBH;
input [2:0] AddrA;
input [2:0] AddrB;
input [7:0] DIH;
output [7:0] DOAL;
output [7:0] DOCL;
input [7:0] DIL;
output [7:0] DOBL;
output [7:0] DOCH;
output [7:0] DOAH;
input clk, CEN, WEH, WEL;
 
reg [7:0] RegsH [0:7];
reg [7:0] RegsL [0:7];
 
always @(posedge clk)
begin
if (CEN)
begin
if (WEH) RegsH[AddrA] <= DIH;
if (WEL) RegsL[AddrA] <= DIL;
end
end
assign DOAH = RegsH[AddrA];
assign DOAL = RegsL[AddrA];
assign DOBH = RegsH[AddrB];
assign DOBL = RegsL[AddrB];
assign DOCH = RegsH[AddrC];
assign DOCL = RegsL[AddrC];
 
// break out ram bits for waveform debug
wire [7:0] H = RegsH[2];
wire [7:0] L = RegsL[2];
// synopsys dc_script_begin
// set_attribute current_design "revision" "$Id: tv80_reg.v,v 1.1 2004-05-16 17:39:57 ghutchis Exp $" -type string -quiet
// synopsys dc_script_end
endmodule
 
/trunk/rtl/core/tv80_alu.v
0,0 → 1,442
//
// TV80 8-Bit Microprocessor Core
// Based on the VHDL T80 core by Daniel Wallner (jesus@opencores.org)
//
// Copyright (c) 2004 Guy Hutchison (ghutchis@opencores.org)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
module tv80_alu (/*AUTOARG*/
// Outputs
Q, F_Out,
// Inputs
Arith16, Z16, ALU_Op, IR, ISet, BusA, BusB, F_In
);
 
parameter Mode = 0;
parameter Flag_C = 0;
parameter Flag_N = 1;
parameter Flag_P = 2;
parameter Flag_X = 3;
parameter Flag_H = 4;
parameter Flag_Y = 5;
parameter Flag_Z = 6;
parameter Flag_S = 7;
 
input Arith16;
input Z16;
input [3:0] ALU_Op ;
input [5:0] IR;
input [1:0] ISet;
input [7:0] BusA;
input [7:0] BusB;
input [7:0] F_In;
output [7:0] Q;
output [7:0] F_Out;
reg [7:0] Q;
reg [7:0] F_Out;
 
function [4:0] AddSub4;
input [3:0] A;
input [3:0] B;
input Sub;
input Carry_In;
begin
AddSub4 = { 1'b0, A } + { 1'b0, (Sub)?~B:B } + Carry_In;
end
endfunction // AddSub4
function [3:0] AddSub3;
input [2:0] A;
input [2:0] B;
input Sub;
input Carry_In;
begin
AddSub3 = { 1'b0, A } + { 1'b0, (Sub)?~B:B } + Carry_In;
end
endfunction // AddSub4
 
function [1:0] AddSub1;
input A;
input B;
input Sub;
input Carry_In;
begin
AddSub1 = { 1'b0, A } + { 1'b0, (Sub)?~B:B } + Carry_In;
end
endfunction // AddSub4
 
// AddSub variables (temporary signals)
reg UseCarry;
reg Carry7_v;
reg OverFlow_v;
reg HalfCarry_v;
reg Carry_v;
reg [7:0] Q_v;
 
reg [7:0] BitMask;
 
 
always @(/*AUTOSENSE*/ALU_Op or BusA or BusB or F_In or IR)
begin
case (IR[5:3])
3'b000 : BitMask = 8'b00000001;
3'b001 : BitMask = 8'b00000010;
3'b010 : BitMask = 8'b00000100;
3'b011 : BitMask = 8'b00001000;
3'b100 : BitMask = 8'b00010000;
3'b101 : BitMask = 8'b00100000;
3'b110 : BitMask = 8'b01000000;
default: BitMask = 8'b10000000;
endcase // case(IR[5:3])
UseCarry = ~ ALU_Op[2] && ALU_Op[0];
{ HalfCarry_v, Q_v[3:0] } = AddSub4(BusA[3:0], BusB[3:0], ALU_Op[1], ALU_Op[1] ^ (UseCarry && F_In[Flag_C]) );
{ Carry7_v, Q_v[6:4] } = AddSub3(BusA[6:4], BusB[6:4], ALU_Op[1], HalfCarry_v);
{ Carry_v, Q_v[7] } = AddSub1(BusA[7], BusB[7], ALU_Op[1], Carry7_v);
OverFlow_v = Carry_v ^ Carry7_v;
end // always @ *
reg [7:0] Q_t;
reg [8:0] DAA_Q;
always @ (/*AUTOSENSE*/ALU_Op or Arith16 or BitMask or BusA or BusB
or Carry_v or F_In or HalfCarry_v or IR or ISet
or OverFlow_v or Q_v or Z16)
begin
Q_t = 8'hxx;
DAA_Q = {9{1'bx}};
F_Out = F_In;
case (ALU_Op)
4'b0000, 4'b0001, 4'b0010, 4'b0011, 4'b0100, 4'b0101, 4'b0110, 4'b0111 :
begin
F_Out[Flag_N] = 1'b0;
F_Out[Flag_C] = 1'b0;
case (ALU_Op[2:0])
3'b000, 3'b001 : // ADD, ADC
begin
Q_t = Q_v;
F_Out[Flag_C] = Carry_v;
F_Out[Flag_H] = HalfCarry_v;
F_Out[Flag_P] = OverFlow_v;
end
3'b010, 3'b011, 3'b111 : // SUB, SBC, CP
begin
Q_t = Q_v;
F_Out[Flag_N] = 1'b1;
F_Out[Flag_C] = ~ Carry_v;
F_Out[Flag_H] = ~ HalfCarry_v;
F_Out[Flag_P] = OverFlow_v;
end
3'b100 : // AND
begin
Q_t[7:0] = BusA & BusB;
F_Out[Flag_H] = 1'b1;
end
3'b101 : // XOR
begin
Q_t[7:0] = BusA ^ BusB;
F_Out[Flag_H] = 1'b0;
end
default : // OR 3'b110
begin
Q_t[7:0] = BusA | BusB;
F_Out[Flag_H] = 1'b0;
end
endcase // case(ALU_OP[2:0])
if (ALU_Op[2:0] == 3'b111 )
begin // CP
F_Out[Flag_X] = BusB[3];
F_Out[Flag_Y] = BusB[5];
end
else
begin
F_Out[Flag_X] = Q_t[3];
F_Out[Flag_Y] = Q_t[5];
end
if (Q_t[7:0] == 8'b00000000 )
begin
F_Out[Flag_Z] = 1'b1;
if (Z16 == 1'b1 )
begin
F_Out[Flag_Z] = F_In[Flag_Z]; // 16 bit ADC,SBC
end
end
else
begin
F_Out[Flag_Z] = 1'b0;
end // else: !if(Q_t[7:0] == 8'b00000000 )
F_Out[Flag_S] = Q_t[7];
case (ALU_Op[2:0])
3'b000, 3'b001, 3'b010, 3'b011, 3'b111 : // ADD, ADC, SUB, SBC, CP
;
default :
F_Out[Flag_P] = ~(^Q_t);
endcase // case(ALU_Op[2:0])
if (Arith16 == 1'b1 )
begin
F_Out[Flag_S] = F_In[Flag_S];
F_Out[Flag_Z] = F_In[Flag_Z];
F_Out[Flag_P] = F_In[Flag_P];
end
end // case: 4'b0000, 4'b0001, 4'b0010, 4'b0011, 4'b0100, 4'b0101, 4'b0110, 4'b0111
4'b1100 :
begin
// DAA
F_Out[Flag_H] = F_In[Flag_H];
F_Out[Flag_C] = F_In[Flag_C];
DAA_Q[7:0] = BusA;
DAA_Q[8] = 1'b0;
if (F_In[Flag_N] == 1'b0 )
begin
// After addition
// Alow > 9 || H == 1
if (DAA_Q[3:0] > 9 || F_In[Flag_H] == 1'b1 )
begin
if ((DAA_Q[3:0] > 9) )
begin
F_Out[Flag_H] = 1'b1;
end
else
begin
F_Out[Flag_H] = 1'b0;
end
DAA_Q = DAA_Q + 6;
end // if (DAA_Q[3:0] > 9 || F_In[Flag_H] == 1'b1 )
// new Ahigh > 9 || C == 1
if (DAA_Q[8:4] > 9 || F_In[Flag_C] == 1'b1 )
begin
DAA_Q = DAA_Q + 96; // 0x60
end
end
else
begin
// After subtraction
if (DAA_Q[3:0] > 9 || F_In[Flag_H] == 1'b1 )
begin
if (DAA_Q[3:0] > 5 )
begin
F_Out[Flag_H] = 1'b0;
end
DAA_Q[7:0] = DAA_Q[7:0] - 6;
end
if (BusA > 153 || F_In[Flag_C] == 1'b1 )
begin
DAA_Q = DAA_Q - 352; // 0x160
end
end // else: !if(F_In[Flag_N] == 1'b0 )
F_Out[Flag_X] = DAA_Q[3];
F_Out[Flag_Y] = DAA_Q[5];
F_Out[Flag_C] = F_In[Flag_C] || DAA_Q[8];
Q_t = DAA_Q[7:0];
if (DAA_Q[7:0] == 8'b00000000 )
begin
F_Out[Flag_Z] = 1'b1;
end
else
begin
F_Out[Flag_Z] = 1'b0;
end
F_Out[Flag_S] = DAA_Q[7];
F_Out[Flag_P] = ~ (^DAA_Q);
end // case: 4'b1100
4'b1101, 4'b1110 :
begin
// RLD, RRD
Q_t[7:4] = BusA[7:4];
if (ALU_Op[0] == 1'b1 )
begin
Q_t[3:0] = BusB[7:4];
end
else
begin
Q_t[3:0] = BusB[3:0];
end
F_Out[Flag_H] = 1'b0;
F_Out[Flag_N] = 1'b0;
F_Out[Flag_X] = Q_t[3];
F_Out[Flag_Y] = Q_t[5];
if (Q_t[7:0] == 8'b00000000 )
begin
F_Out[Flag_Z] = 1'b1;
end
else
begin
F_Out[Flag_Z] = 1'b0;
end
F_Out[Flag_S] = Q_t[7];
F_Out[Flag_P] = ~(^Q_t);
end // case: when 4'b1101, 4'b1110
4'b1001 :
begin
// BIT
Q_t[7:0] = BusB & BitMask;
F_Out[Flag_S] = Q_t[7];
if (Q_t[7:0] == 8'b00000000 )
begin
F_Out[Flag_Z] = 1'b1;
F_Out[Flag_P] = 1'b1;
end
else
begin
F_Out[Flag_Z] = 1'b0;
F_Out[Flag_P] = 1'b0;
end
F_Out[Flag_H] = 1'b1;
F_Out[Flag_N] = 1'b0;
F_Out[Flag_X] = 1'b0;
F_Out[Flag_Y] = 1'b0;
if (IR[2:0] != 3'b110 )
begin
F_Out[Flag_X] = BusB[3];
F_Out[Flag_Y] = BusB[5];
end
end // case: when 4'b1001
4'b1010 :
// SET
Q_t[7:0] = BusB | BitMask;
4'b1011 :
// RES
Q_t[7:0] = BusB & ~ BitMask;
4'b1000 :
begin
// ROT
case (IR[5:3])
3'b000 : // RLC
begin
Q_t[7:1] = BusA[6:0];
Q_t[0] = BusA[7];
F_Out[Flag_C] = BusA[7];
end
3'b010 : // RL
begin
Q_t[7:1] = BusA[6:0];
Q_t[0] = F_In[Flag_C];
F_Out[Flag_C] = BusA[7];
end
3'b001 : // RRC
begin
Q_t[6:0] = BusA[7:1];
Q_t[7] = BusA[0];
F_Out[Flag_C] = BusA[0];
end
3'b011 : // RR
begin
Q_t[6:0] = BusA[7:1];
Q_t[7] = F_In[Flag_C];
F_Out[Flag_C] = BusA[0];
end
3'b100 : // SLA
begin
Q_t[7:1] = BusA[6:0];
Q_t[0] = 1'b0;
F_Out[Flag_C] = BusA[7];
end
3'b110 : // SLL (Undocumented) / SWAP
begin
if (Mode == 3 )
begin
Q_t[7:4] = BusA[3:0];
Q_t[3:0] = BusA[7:4];
F_Out[Flag_C] = 1'b0;
end
else
begin
Q_t[7:1] = BusA[6:0];
Q_t[0] = 1'b1;
F_Out[Flag_C] = BusA[7];
end // else: !if(Mode == 3 )
end // case: 3'b110
3'b101 : // SRA
begin
Q_t[6:0] = BusA[7:1];
Q_t[7] = BusA[7];
F_Out[Flag_C] = BusA[0];
end
default : // SRL
begin
Q_t[6:0] = BusA[7:1];
Q_t[7] = 1'b0;
F_Out[Flag_C] = BusA[0];
end
endcase // case(IR[5:3])
F_Out[Flag_H] = 1'b0;
F_Out[Flag_N] = 1'b0;
F_Out[Flag_X] = Q_t[3];
F_Out[Flag_Y] = Q_t[5];
F_Out[Flag_S] = Q_t[7];
if (Q_t[7:0] == 8'b00000000 )
begin
F_Out[Flag_Z] = 1'b1;
end
else
begin
F_Out[Flag_Z] = 1'b0;
end
F_Out[Flag_P] = ~(^Q_t);
 
if (ISet == 2'b00 )
begin
F_Out[Flag_P] = F_In[Flag_P];
F_Out[Flag_S] = F_In[Flag_S];
F_Out[Flag_Z] = F_In[Flag_Z];
end
end // case: 4'b1000
default :
;
endcase // case(ALU_Op)
Q = Q_t;
end // always @ (Arith16, ALU_OP, F_In, BusA, BusB, IR, Q_v, Carry_v, HalfCarry_v, OverFlow_v, BitMask, ISet, Z16)
endmodule // T80_ALU
/trunk/rtl/core/tv80s.v
0,0 → 1,160
//
// TV80 8-Bit Microprocessor Core
// Based on the VHDL T80 core by Daniel Wallner (jesus@opencores.org)
//
// Copyright (c) 2004 Guy Hutchison (ghutchis@opencores.org)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
module tv80s (/*AUTOARG*/
// Outputs
m1_n, mreq_n, iorq_n, rd_n, wr_n, rfsh_n, halt_n, busak_n, A, do,
// Inputs
reset_n, clk, wait_n, int_n, nmi_n, busrq_n, di
);
 
parameter Mode = 0; // 0 => Z80, 1 => Fast Z80, 2 => 8080, 3 => GB
parameter T2Write = 0; // 0 => wr_n active in T3, /=0 => wr_n active in T2
parameter IOWait = 1; // 0 => Single cycle I/O, 1 => Std I/O cycle
 
 
input reset_n;
input clk;
input wait_n;
input int_n;
input nmi_n;
input busrq_n;
output m1_n;
output mreq_n;
output iorq_n;
output rd_n;
output wr_n;
output rfsh_n;
output halt_n;
output busak_n;
output [15:0] A;
input [7:0] di;
output [7:0] do;
 
reg mreq_n;
reg iorq_n;
reg rd_n;
reg wr_n;
wire cen;
wire intcycle_n;
wire no_read;
wire write;
wire iorq;
reg [7:0] di_reg;
wire [2:0] mcycle;
wire [2:0] tstate;
 
assign cen = 1;
 
tv80_core i_tv80_core
(
.cen (cen),
.m1_n (m1_n),
.iorq (iorq),
.no_read (no_read),
.write (write),
.rfsh_n (rfsh_n),
.halt_n (halt_n),
.wait_n (wait_n),
.int_n (int_n),
.nmi_n (nmi_n),
.reset_n (reset_n),
.busrq_n (busrq_n),
.busak_n (busak_n),
.clk (clk),
.IntE (),
.stop (),
.A (A),
.dinst (di),
.di (di_reg),
.do (do),
.mc (mcycle),
.ts (tstate),
.intcycle_n (intcycle_n)
);
 
always @(posedge clk)
begin
if (!reset_n)
begin
rd_n <= #1 1'b1;
wr_n <= #1 1'b1;
iorq_n <= #1 1'b1;
mreq_n <= #1 1'b1;
di_reg <= #1 0;
end
else
begin
rd_n <= #1 1'b1;
wr_n <= #1 1'b1;
iorq_n <= #1 1'b1;
mreq_n <= #1 1'b1;
if (mcycle == 3'b001)
begin
if (tstate == 3'b001 || (tstate == 3'b010 && wait_n == 1'b0))
begin
rd_n <= #1 ~ intcycle_n;
mreq_n <= #1 ~ intcycle_n;
iorq_n <= #1 intcycle_n;
end
if (tstate == 3'b011)
mreq_n <= #1 1'b0;
end // if (mcycle == 3'b001)
else
begin
if ((tstate == 3'b001 || (tstate == 3'b010 && wait_n == 1'b0)) && no_read == 1'b0 && write == 1'b0)
begin
rd_n <= #1 1'b0;
iorq_n <= #1 ~ iorq;
mreq_n <= #1 iorq;
end
if (T2Write == 0)
begin
if (tstate == 3'b010 && write == 1'b1)
begin
wr_n <= #1 1'b0;
iorq_n <= #1 ~ iorq;
mreq_n <= #1 iorq;
end
end
else
begin
if ((tstate == 3'b001 || (tstate == 3'b010 && wait_n == 1'b0)) && write == 1'b1)
begin
wr_n <= #1 1'b0;
iorq_n <= #1 ~ iorq;
mreq_n <= #1 iorq;
end
end // else: !if(T2write == 0)
end // else: !if(mcycle == 3'b001)
if (tstate == 3'b010 && wait_n == 1'b1)
di_reg <= #1 di;
end // else: !if(!reset_n)
end // always @ (posedge clk or negedge reset_n)
endmodule // t80s
 
/trunk/rtl/core/tv80_mcode.v
0,0 → 1,2759
//
// TV80 8-Bit Microprocessor Core
// Based on the VHDL T80 core by Daniel Wallner (jesus@opencores.org)
//
// Copyright (c) 2004 Guy Hutchison (ghutchis@opencores.org)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
module tv80_mcode (/*AUTOARG*/
// Outputs
MCycles, TStates, Prefix, Inc_PC, Inc_WZ, IncDec_16, Read_To_Reg,
Read_To_Acc, Set_BusA_To, Set_BusB_To, ALU_Op, Save_ALU, PreserveC,
Arith16, Set_Addr_To, IORQ, Jump, JumpE, JumpXY, Call, RstP, LDZ,
LDW, LDSPHL, Special_LD, ExchangeDH, ExchangeRp, ExchangeAF,
ExchangeRS, I_DJNZ, I_CPL, I_CCF, I_SCF, I_RETN, I_BT, I_BC, I_BTR,
I_RLD, I_RRD, I_INRC, SetDI, SetEI, IMode, Halt, NoRead, Write,
// Inputs
IR, ISet, MCycle, F, NMICycle, IntCycle
);
parameter Mode = 0;
parameter Flag_C = 0;
parameter Flag_N = 1;
parameter Flag_P = 2;
parameter Flag_X = 3;
parameter Flag_H = 4;
parameter Flag_Y = 5;
parameter Flag_Z = 6;
parameter Flag_S = 7;
 
input [7:0] IR;
input [1:0] ISet ;
input [2:0] MCycle ;
input [7:0] F ;
input NMICycle ;
input IntCycle ;
output [2:0] MCycles ;
output [2:0] TStates ;
output [1:0] Prefix ; // None,BC,ED,DD/FD
output Inc_PC ;
output Inc_WZ ;
output [3:0] IncDec_16 ; // BC,DE,HL,SP 0 is inc
output Read_To_Reg ;
output Read_To_Acc ;
output [3:0] Set_BusA_To ; // B,C,D,E,H,L,DI/DB,A,SP(L),SP(M),0,F
output [3:0] Set_BusB_To ; // B,C,D,E,H,L,DI,A,SP(L),SP(M),1,F,PC(L),PC(M),0
output [3:0] ALU_Op ;
output Save_ALU ;
output PreserveC ;
output Arith16 ;
output [2:0] Set_Addr_To ; // aNone,aXY,aIOA,aSP,aBC,aDE,aZI
output IORQ ;
output Jump ;
output JumpE ;
output JumpXY ;
output Call ;
output RstP ;
output LDZ ;
output LDW ;
output LDSPHL ;
output [2:0] Special_LD ; // A,I;A,R;I,A;R,A;None
output ExchangeDH ;
output ExchangeRp ;
output ExchangeAF ;
output ExchangeRS ;
output I_DJNZ ;
output I_CPL ;
output I_CCF ;
output I_SCF ;
output I_RETN ;
output I_BT ;
output I_BC ;
output I_BTR ;
output I_RLD ;
output I_RRD ;
output I_INRC ;
output SetDI ;
output SetEI ;
output [1:0] IMode ;
output Halt ;
output NoRead ;
output Write ;
 
// regs
reg [2:0] MCycles ;
reg [2:0] TStates ;
reg [1:0] Prefix ; // None,BC,ED,DD/FD
reg Inc_PC ;
reg Inc_WZ ;
reg [3:0] IncDec_16 ; // BC,DE,HL,SP 0 is inc
reg Read_To_Reg ;
reg Read_To_Acc ;
reg [3:0] Set_BusA_To ; // B,C,D,E,H,L,DI/DB,A,SP(L),SP(M),0,F
reg [3:0] Set_BusB_To ; // B,C,D,E,H,L,DI,A,SP(L),SP(M),1,F,PC(L),PC(M),0
reg [3:0] ALU_Op ;
reg Save_ALU ;
reg PreserveC ;
reg Arith16 ;
reg [2:0] Set_Addr_To ; // aNone,aXY,aIOA,aSP,aBC,aDE,aZI
reg IORQ ;
reg Jump ;
reg JumpE ;
reg JumpXY ;
reg Call ;
reg RstP ;
reg LDZ ;
reg LDW ;
reg LDSPHL ;
reg [2:0] Special_LD ; // A,I;A,R;I,A;R,A;None
reg ExchangeDH ;
reg ExchangeRp ;
reg ExchangeAF ;
reg ExchangeRS ;
reg I_DJNZ ;
reg I_CPL ;
reg I_CCF ;
reg I_SCF ;
reg I_RETN ;
reg I_BT ;
reg I_BC ;
reg I_BTR ;
reg I_RLD ;
reg I_RRD ;
reg I_INRC ;
reg SetDI ;
reg SetEI ;
reg [1:0] IMode ;
reg Halt ;
reg NoRead ;
reg Write ;
 
parameter aNone = 3'b111;
parameter aBC = 3'b000;
parameter aDE = 3'b001;
parameter aXY = 3'b010;
parameter aIOA = 3'b100;
parameter aSP = 3'b101;
parameter aZI = 3'b110;
// constant aNone : std_logic_vector[2:0] = 3'b000;
// constant aXY : std_logic_vector[2:0] = 3'b001;
// constant aIOA : std_logic_vector[2:0] = 3'b010;
// constant aSP : std_logic_vector[2:0] = 3'b011;
// constant aBC : std_logic_vector[2:0] = 3'b100;
// constant aDE : std_logic_vector[2:0] = 3'b101;
// constant aZI : std_logic_vector[2:0] = 3'b110;
 
function is_cc_true;
input [7:0] F;
input [2:0] cc;
begin
if (Mode == 3 )
begin
case (cc)
3'b000 : is_cc_true = F[7] == 1'b0; // NZ
3'b001 : is_cc_true = F[7] == 1'b1; // Z
3'b010 : is_cc_true = F[4] == 1'b0; // NC
3'b011 : is_cc_true = F[4] == 1'b1; // C
3'b100 : is_cc_true = 0;
3'b101 : is_cc_true = 0;
3'b110 : is_cc_true = 0;
3'b111 : is_cc_true = 0;
endcase
end
else
begin
case (cc)
3'b000 : is_cc_true = F[6] == 1'b0; // NZ
3'b001 : is_cc_true = F[6] == 1'b1; // Z
3'b010 : is_cc_true = F[0] == 1'b0; // NC
3'b011 : is_cc_true = F[0] == 1'b1; // C
3'b100 : is_cc_true = F[2] == 1'b0; // PO
3'b101 : is_cc_true = F[2] == 1'b1; // PE
3'b110 : is_cc_true = F[7] == 1'b0; // P
3'b111 : is_cc_true = F[7] == 1'b1; // M
endcase
end
end
endfunction // is_cc_true
 
reg [2:0] DDD;
reg [2:0] SSS;
reg [1:0] DPAIR;
reg [7:0] IRB;
always @ (/*AUTOSENSE*/F or IR or ISet or IntCycle or MCycle
or NMICycle)
begin
DDD = IR[5:3];
SSS = IR[2:0];
DPAIR = IR[5:4];
IRB = IR;
 
MCycles = 3'b001;
if (MCycle == 3'b001 )
begin
TStates = 3'b100;
end
else
begin
TStates = 3'b011;
end
Prefix = 2'b00;
Inc_PC = 1'b0;
Inc_WZ = 1'b0;
IncDec_16 = 4'b0000;
Read_To_Acc = 1'b0;
Read_To_Reg = 1'b0;
Set_BusB_To = 4'b0000;
Set_BusA_To = 4'b0000;
ALU_Op = { 1'b0, IR[5:3] };
Save_ALU = 1'b0;
PreserveC = 1'b0;
Arith16 = 1'b0;
IORQ = 1'b0;
Set_Addr_To = aNone;
Jump = 1'b0;
JumpE = 1'b0;
JumpXY = 1'b0;
Call = 1'b0;
RstP = 1'b0;
LDZ = 1'b0;
LDW = 1'b0;
LDSPHL = 1'b0;
Special_LD = 3'b000;
ExchangeDH = 1'b0;
ExchangeRp = 1'b0;
ExchangeAF = 1'b0;
ExchangeRS = 1'b0;
I_DJNZ = 1'b0;
I_CPL = 1'b0;
I_CCF = 1'b0;
I_SCF = 1'b0;
I_RETN = 1'b0;
I_BT = 1'b0;
I_BC = 1'b0;
I_BTR = 1'b0;
I_RLD = 1'b0;
I_RRD = 1'b0;
I_INRC = 1'b0;
SetDI = 1'b0;
SetEI = 1'b0;
IMode = 2'b11;
Halt = 1'b0;
NoRead = 1'b0;
Write = 1'b0;
case (ISet)
2'b00 :
begin
 
//----------------------------------------------------------------------------
//
// Unprefixed instructions
//
//----------------------------------------------------------------------------
 
case (IRB)
// 8 BIT LOAD GROUP
8'b01000000,8'b01000001,8'b01000010,8'b01000011,8'b01000100,8'b01000101,8'b01000111,
8'b01001000,8'b01001001,8'b01001010,8'b01001011,8'b01001100,8'b01001101,8'b01001111,
8'b01010000,8'b01010001,8'b01010010,8'b01010011,8'b01010100,8'b01010101,8'b01010111,
8'b01011000,8'b01011001,8'b01011010,8'b01011011,8'b01011100,8'b01011101,8'b01011111,
8'b01100000,8'b01100001,8'b01100010,8'b01100011,8'b01100100,8'b01100101,8'b01100111,
8'b01101000,8'b01101001,8'b01101010,8'b01101011,8'b01101100,8'b01101101,8'b01101111,
8'b01111000,8'b01111001,8'b01111010,8'b01111011,8'b01111100,8'b01111101,8'b01111111 :
begin
// LD r,r'
Set_BusB_To[2:0] = SSS;
ExchangeRp = 1'b1;
Set_BusA_To[2:0] = DDD;
Read_To_Reg = 1'b1;
end // case: 8'b01000000,8'b01000001,8'b01000010,8'b01000011,8'b01000100,8'b01000101,8'b01000111,...
8'b00000110,8'b00001110,8'b00010110,8'b00011110,8'b00100110,8'b00101110,8'b00111110 :
begin
// LD r,n
MCycles = 3'b010;
case (MCycle)
2 :
begin
Inc_PC = 1'b1;
Set_BusA_To[2:0] = DDD;
Read_To_Reg = 1'b1;
end
default :;
endcase // case(MCycle)
end // case: 8'b00000110,8'b00001110,8'b00010110,8'b00011110,8'b00100110,8'b00101110,8'b00111110
8'b01000110,8'b01001110,8'b01010110,8'b01011110,8'b01100110,8'b01101110,8'b01111110 :
begin
// LD r,(HL)
MCycles = 3'b010;
case (MCycle)
1 :
Set_Addr_To = aXY;
2 :
begin
Set_BusA_To[2:0] = DDD;
Read_To_Reg = 1'b1;
end
default :;
endcase // case(MCycle)
end // case: 8'b01000110,8'b01001110,8'b01010110,8'b01011110,8'b01100110,8'b01101110,8'b01111110
8'b01110000,8'b01110001,8'b01110010,8'b01110011,8'b01110100,8'b01110101,8'b01110111 :
begin
// LD (HL),r
MCycles = 3'b010;
case (MCycle)
1 :
begin
Set_Addr_To = aXY;
Set_BusB_To[2:0] = SSS;
Set_BusB_To[3] = 1'b0;
end
2 :
Write = 1'b1;
default :;
endcase // case(MCycle)
end // case: 8'b01110000,8'b01110001,8'b01110010,8'b01110011,8'b01110100,8'b01110101,8'b01110111
8'b00110110 :
begin
// LD (HL),n
MCycles = 3'b011;
case (MCycle)
2 :
begin
Inc_PC = 1'b1;
Set_Addr_To = aXY;
Set_BusB_To[2:0] = SSS;
Set_BusB_To[3] = 1'b0;
end
3 :
Write = 1'b1;
default :;
endcase // case(MCycle)
end // case: 8'b00110110
8'b00001010 :
begin
// LD A,(BC)
MCycles = 3'b010;
case (MCycle)
1 :
Set_Addr_To = aBC;
2 :
Read_To_Acc = 1'b1;
default :;
endcase // case(MCycle)
end // case: 8'b00001010
8'b00011010 :
begin
// LD A,(DE)
MCycles = 3'b010;
case (MCycle)
1 :
Set_Addr_To = aDE;
2 :
Read_To_Acc = 1'b1;
default :;
endcase // case(MCycle)
end // case: 8'b00011010
8'b00111010 :
begin
if (Mode == 3 )
begin
// LDD A,(HL)
MCycles = 3'b010;
case (MCycle)
1 :
Set_Addr_To = aXY;
2 :
begin
Read_To_Acc = 1'b1;
IncDec_16 = 4'b1110;
end
default :;
endcase
end
else
begin
// LD A,(nn)
MCycles = 3'b100;
case (MCycle)
2 :
begin
Inc_PC = 1'b1;
LDZ = 1'b1;
end
3 :
begin
Set_Addr_To = aZI;
Inc_PC = 1'b1;
end
4 :
begin
Read_To_Acc = 1'b1;
end
default :;
endcase
end // else: !if(Mode == 3 )
end // case: 8'b00111010
8'b00000010 :
begin
// LD (BC),A
MCycles = 3'b010;
case (MCycle)
1 :
begin
Set_Addr_To = aBC;
Set_BusB_To = 4'b0111;
end
2 :
begin
Write = 1'b1;
end
default :;
endcase // case(MCycle)
end // case: 8'b00000010
8'b00010010 :
begin
// LD (DE),A
MCycles = 3'b010;
case (MCycle)
1 :
begin
Set_Addr_To = aDE;
Set_BusB_To = 4'b0111;
end
2 :
Write = 1'b1;
default :;
endcase // case(MCycle)
end // case: 8'b00010010
8'b00110010 :
begin
if (Mode == 3 )
begin
// LDD (HL),A
MCycles = 3'b010;
case (MCycle)
1 :
begin
Set_Addr_To = aXY;
Set_BusB_To = 4'b0111;
end
2 :
begin
Write = 1'b1;
IncDec_16 = 4'b1110;
end
default :;
endcase // case(MCycle)
end
else
begin
// LD (nn),A
MCycles = 3'b100;
case (MCycle)
2 :
begin
Inc_PC = 1'b1;
LDZ = 1'b1;
end
3 :
begin
Set_Addr_To = aZI;
Inc_PC = 1'b1;
Set_BusB_To = 4'b0111;
end
4 :
begin
Write = 1'b1;
end
default :;
endcase
end // else: !if(Mode == 3 )
end // case: 8'b00110010
 
// 16 BIT LOAD GROUP
8'b00000001,8'b00010001,8'b00100001,8'b00110001 :
begin
// LD dd,nn
MCycles = 3'b011;
case (MCycle)
2 :
begin
Inc_PC = 1'b1;
Read_To_Reg = 1'b1;
if (DPAIR == 2'b11 )
begin
Set_BusA_To[3:0] = 4'b1000;
end
else
begin
Set_BusA_To[2:1] = DPAIR;
Set_BusA_To[0] = 1'b1;
end
end // case: 2
3 :
begin
Inc_PC = 1'b1;
Read_To_Reg = 1'b1;
if (DPAIR == 2'b11 )
begin
Set_BusA_To[3:0] = 4'b1001;
end
else
begin
Set_BusA_To[2:1] = DPAIR;
Set_BusA_To[0] = 1'b0;
end
end // case: 3
default :;
endcase // case(MCycle)
end // case: 8'b00000001,8'b00010001,8'b00100001,8'b00110001
8'b00101010 :
begin
if (Mode == 3 )
begin
// LDI A,(HL)
MCycles = 3'b010;
case (MCycle)
1 :
Set_Addr_To = aXY;
2 :
begin
Read_To_Acc = 1'b1;
IncDec_16 = 4'b0110;
end
default :;
endcase
end
else
begin
// LD HL,(nn)
MCycles = 3'b101;
case (MCycle)
2 :
begin
Inc_PC = 1'b1;
LDZ = 1'b1;
end
3 :
begin
Set_Addr_To = aZI;
Inc_PC = 1'b1;
LDW = 1'b1;
end
4 :
begin
Set_BusA_To[2:0] = 3'b101; // L
Read_To_Reg = 1'b1;
Inc_WZ = 1'b1;
Set_Addr_To = aZI;
end
5 :
begin
Set_BusA_To[2:0] = 3'b100; // H
Read_To_Reg = 1'b1;
end
default :;
endcase
end // else: !if(Mode == 3 )
end // case: 8'b00101010
8'b00100010 :
begin
if (Mode == 3 )
begin
// LDI (HL),A
MCycles = 3'b010;
case (MCycle)
1 :
begin
Set_Addr_To = aXY;
Set_BusB_To = 4'b0111;
end
2 :
begin
Write = 1'b1;
IncDec_16 = 4'b0110;
end
default :;
endcase
end
else
begin
// LD (nn),HL
MCycles = 3'b101;
case (MCycle)
2 :
begin
Inc_PC = 1'b1;
LDZ = 1'b1;
end
3 :
begin
Set_Addr_To = aZI;
Inc_PC = 1'b1;
LDW = 1'b1;
Set_BusB_To = 4'b0101; // L
end
4 :
begin
Inc_WZ = 1'b1;
Set_Addr_To = aZI;
Write = 1'b1;
Set_BusB_To = 4'b0100; // H
end
5 :
Write = 1'b1;
default :;
endcase
end // else: !if(Mode == 3 )
end // case: 8'b00100010
8'b11111001 :
begin
// LD SP,HL
TStates = 3'b110;
LDSPHL = 1'b1;
end
8'b11000101,8'b11010101,8'b11100101,8'b11110101 :
begin
// PUSH qq
MCycles = 3'b011;
case (MCycle)
1 :
begin
TStates = 3'b101;
IncDec_16 = 4'b1111;
Set_Addr_To = aSP;
if (DPAIR == 2'b11 )
begin
Set_BusB_To = 4'b0111;
end
else
begin
Set_BusB_To[2:1] = DPAIR;
Set_BusB_To[0] = 1'b0;
Set_BusB_To[3] = 1'b0;
end
end // case: 1
2 :
begin
IncDec_16 = 4'b1111;
Set_Addr_To = aSP;
if (DPAIR == 2'b11 )
begin
Set_BusB_To = 4'b1011;
end
else
begin
Set_BusB_To[2:1] = DPAIR;
Set_BusB_To[0] = 1'b1;
Set_BusB_To[3] = 1'b0;
end
Write = 1'b1;
end // case: 2
3 :
Write = 1'b1;
default :;
endcase // case(MCycle)
end // case: 8'b11000101,8'b11010101,8'b11100101,8'b11110101
8'b11000001,8'b11010001,8'b11100001,8'b11110001 :
begin
// POP qq
MCycles = 3'b011;
case (MCycle)
1 :
Set_Addr_To = aSP;
2 :
begin
IncDec_16 = 4'b0111;
Set_Addr_To = aSP;
Read_To_Reg = 1'b1;
if (DPAIR == 2'b11 )
begin
Set_BusA_To[3:0] = 4'b1011;
end
else
begin
Set_BusA_To[2:1] = DPAIR;
Set_BusA_To[0] = 1'b1;
end
end // case: 2
3 :
begin
IncDec_16 = 4'b0111;
Read_To_Reg = 1'b1;
if (DPAIR == 2'b11 )
begin
Set_BusA_To[3:0] = 4'b0111;
end
else
begin
Set_BusA_To[2:1] = DPAIR;
Set_BusA_To[0] = 1'b0;
end
end // case: 3
default :;
endcase // case(MCycle)
end // case: 8'b11000001,8'b11010001,8'b11100001,8'b11110001
 
// EXCHANGE, BLOCK TRANSFER AND SEARCH GROUP
8'b11101011 :
begin
if (Mode != 3 )
begin
// EX DE,HL
ExchangeDH = 1'b1;
end
end
8'b00001000 :
begin
if (Mode == 3 )
begin
// LD (nn),SP
MCycles = 3'b101;
case (MCycle)
2 :
begin
Inc_PC = 1'b1;
LDZ = 1'b1;
end
3 :
begin
Set_Addr_To = aZI;
Inc_PC = 1'b1;
LDW = 1'b1;
Set_BusB_To = 4'b1000;
end
4 :
begin
Inc_WZ = 1'b1;
Set_Addr_To = aZI;
Write = 1'b1;
Set_BusB_To = 4'b1001;
end
5 :
Write = 1'b1;
default :;
endcase
end
else if (Mode < 2 )
begin
// EX AF,AF'
ExchangeAF = 1'b1;
end
end // case: 8'b00001000
8'b11011001 :
begin
if (Mode == 3 )
begin
// RETI
MCycles = 3'b011;
case (MCycle)
1 :
Set_Addr_To = aSP;
2 :
begin
IncDec_16 = 4'b0111;
Set_Addr_To = aSP;
LDZ = 1'b1;
end
3 :
begin
Jump = 1'b1;
IncDec_16 = 4'b0111;
I_RETN = 1'b1;
SetEI = 1'b1;
end
default :;
endcase
end
else if (Mode < 2 )
begin
// EXX
ExchangeRS = 1'b1;
end
end // case: 8'b11011001
8'b11100011 :
begin
if (Mode != 3 )
begin
// EX (SP),HL
MCycles = 3'b101;
case (MCycle)
1 :
Set_Addr_To = aSP;
2 :
begin
Read_To_Reg = 1'b1;
Set_BusA_To = 4'b0101;
Set_BusB_To = 4'b0101;
Set_Addr_To = aSP;
end
3 :
begin
IncDec_16 = 4'b0111;
Set_Addr_To = aSP;
TStates = 3'b100;
Write = 1'b1;
end
4 :
begin
Read_To_Reg = 1'b1;
Set_BusA_To = 4'b0100;
Set_BusB_To = 4'b0100;
Set_Addr_To = aSP;
end
5 :
begin
IncDec_16 = 4'b1111;
TStates = 3'b101;
Write = 1'b1;
end
default :;
endcase
end // if (Mode != 3 )
end // case: 8'b11100011
 
// 8 BIT ARITHMETIC AND LOGICAL GROUP
8'b10000000,8'b10000001,8'b10000010,8'b10000011,8'b10000100,8'b10000101,8'b10000111,
8'b10001000,8'b10001001,8'b10001010,8'b10001011,8'b10001100,8'b10001101,8'b10001111,
8'b10010000,8'b10010001,8'b10010010,8'b10010011,8'b10010100,8'b10010101,8'b10010111,
8'b10011000,8'b10011001,8'b10011010,8'b10011011,8'b10011100,8'b10011101,8'b10011111,
8'b10100000,8'b10100001,8'b10100010,8'b10100011,8'b10100100,8'b10100101,8'b10100111,
8'b10101000,8'b10101001,8'b10101010,8'b10101011,8'b10101100,8'b10101101,8'b10101111,
8'b10110000,8'b10110001,8'b10110010,8'b10110011,8'b10110100,8'b10110101,8'b10110111,
8'b10111000,8'b10111001,8'b10111010,8'b10111011,8'b10111100,8'b10111101,8'b10111111 :
begin
// ADD A,r
// ADC A,r
// SUB A,r
// SBC A,r
// AND A,r
// OR A,r
// XOR A,r
// CP A,r
Set_BusB_To[2:0] = SSS;
Set_BusA_To[2:0] = 3'b111;
Read_To_Reg = 1'b1;
Save_ALU = 1'b1;
end // case: 8'b10000000,8'b10000001,8'b10000010,8'b10000011,8'b10000100,8'b10000101,8'b10000111,...
8'b10000110,8'b10001110,8'b10010110,8'b10011110,8'b10100110,8'b10101110,8'b10110110,8'b10111110 :
begin
// ADD A,(HL)
// ADC A,(HL)
// SUB A,(HL)
// SBC A,(HL)
// AND A,(HL)
// OR A,(HL)
// XOR A,(HL)
// CP A,(HL)
MCycles = 3'b010;
case (MCycle)
1 :
Set_Addr_To = aXY;
2 :
begin
Read_To_Reg = 1'b1;
Save_ALU = 1'b1;
Set_BusB_To[2:0] = SSS;
Set_BusA_To[2:0] = 3'b111;
end
default :;
endcase // case(MCycle)
end // case: 8'b10000110,8'b10001110,8'b10010110,8'b10011110,8'b10100110,8'b10101110,8'b10110110,8'b10111110
8'b11000110,8'b11001110,8'b11010110,8'b11011110,8'b11100110,8'b11101110,8'b11110110,8'b11111110 :
begin
// ADD A,n
// ADC A,n
// SUB A,n
// SBC A,n
// AND A,n
// OR A,n
// XOR A,n
// CP A,n
MCycles = 3'b010;
if (MCycle == 3'b010 )
begin
Inc_PC = 1'b1;
Read_To_Reg = 1'b1;
Save_ALU = 1'b1;
Set_BusB_To[2:0] = SSS;
Set_BusA_To[2:0] = 3'b111;
end
end // case: 8'b11000110,8'b11001110,8'b11010110,8'b11011110,8'b11100110,8'b11101110,8'b11110110,8'b11111110
8'b00000100,8'b00001100,8'b00010100,8'b00011100,8'b00100100,8'b00101100,8'b00111100 :
begin
// INC r
Set_BusB_To = 4'b1010;
Set_BusA_To[2:0] = DDD;
Read_To_Reg = 1'b1;
Save_ALU = 1'b1;
PreserveC = 1'b1;
ALU_Op = 4'b0000;
end
8'b00110100 :
begin
// INC (HL)
MCycles = 3'b011;
case (MCycle)
1 :
Set_Addr_To = aXY;
2 :
begin
TStates = 3'b100;
Set_Addr_To = aXY;
Read_To_Reg = 1'b1;
Save_ALU = 1'b1;
PreserveC = 1'b1;
ALU_Op = 4'b0000;
Set_BusB_To = 4'b1010;
Set_BusA_To[2:0] = DDD;
end // case: 2
3 :
Write = 1'b1;
default :;
endcase // case(MCycle)
end // case: 8'b00110100
8'b00000101,8'b00001101,8'b00010101,8'b00011101,8'b00100101,8'b00101101,8'b00111101 :
begin
// DEC r
Set_BusB_To = 4'b1010;
Set_BusA_To[2:0] = DDD;
Read_To_Reg = 1'b1;
Save_ALU = 1'b1;
PreserveC = 1'b1;
ALU_Op = 4'b0010;
end
8'b00110101 :
begin
// DEC (HL)
MCycles = 3'b011;
case (MCycle)
1 :
Set_Addr_To = aXY;
2 :
begin
TStates = 3'b100;
Set_Addr_To = aXY;
ALU_Op = 4'b0010;
Read_To_Reg = 1'b1;
Save_ALU = 1'b1;
PreserveC = 1'b1;
Set_BusB_To = 4'b1010;
Set_BusA_To[2:0] = DDD;
end // case: 2
3 :
Write = 1'b1;
default :;
endcase // case(MCycle)
end // case: 8'b00110101
 
// GENERAL PURPOSE ARITHMETIC AND CPU CONTROL GROUPS
8'b00100111 :
begin
// DAA
Set_BusA_To[2:0] = 3'b111;
Read_To_Reg = 1'b1;
ALU_Op = 4'b1100;
Save_ALU = 1'b1;
end
8'b00101111 :
// CPL
I_CPL = 1'b1;
8'b00111111 :
// CCF
I_CCF = 1'b1;
8'b00110111 :
// SCF
I_SCF = 1'b1;
8'b00000000 :
begin
if (NMICycle == 1'b1 )
begin
// NMI
MCycles = 3'b011;
case (MCycle)
1 :
begin
TStates = 3'b101;
IncDec_16 = 4'b1111;
Set_Addr_To = aSP;
Set_BusB_To = 4'b1101;
end
2 :
begin
TStates = 3'b100;
Write = 1'b1;
IncDec_16 = 4'b1111;
Set_Addr_To = aSP;
Set_BusB_To = 4'b1100;
end
3 :
begin
TStates = 3'b100;
Write = 1'b1;
end
default :;
endcase // case(MCycle)
end
else if (IntCycle == 1'b1 )
begin
// INT (IM 2)
MCycles = 3'b101;
case (MCycle)
1 :
begin
LDZ = 1'b1;
TStates = 3'b101;
IncDec_16 = 4'b1111;
Set_Addr_To = aSP;
Set_BusB_To = 4'b1101;
end
2 :
begin
TStates = 3'b100;
Write = 1'b1;
IncDec_16 = 4'b1111;
Set_Addr_To = aSP;
Set_BusB_To = 4'b1100;
end
3 :
begin
TStates = 3'b100;
Write = 1'b1;
end
4 :
begin
Inc_PC = 1'b1;
LDZ = 1'b1;
end
5 :
Jump = 1'b1;
default :;
endcase
end
end // case: 8'b00000000
8'b01110110 :
// HALT
Halt = 1'b1;
8'b11110011 :
// DI
SetDI = 1'b1;
8'b11111011 :
// EI
SetEI = 1'b1;
 
// 16 BIT ARITHMETIC GROUP
8'b00001001,8'b00011001,8'b00101001,8'b00111001 :
begin
// ADD HL,ss
MCycles = 3'b011;
case (MCycle)
2 :
begin
NoRead = 1'b1;
ALU_Op = 4'b0000;
Read_To_Reg = 1'b1;
Save_ALU = 1'b1;
Set_BusA_To[2:0] = 3'b101;
case (IR[5:4])
0,1,2 :
begin
Set_BusB_To[2:1] = IR[5:4];
Set_BusB_To[0] = 1'b1;
end
default :
Set_BusB_To = 4'b1000;
endcase // case(IR[5:4])
TStates = 3'b100;
Arith16 = 1'b1;
end // case: 2
3 :
begin
NoRead = 1'b1;
Read_To_Reg = 1'b1;
Save_ALU = 1'b1;
ALU_Op = 4'b0001;
Set_BusA_To[2:0] = 3'b100;
case (IR[5:4])
0,1,2 :
Set_BusB_To[2:1] = IR[5:4];
default :
Set_BusB_To = 4'b1001;
endcase
Arith16 = 1'b1;
end // case: 3
default :;
endcase // case(MCycle)
end // case: 8'b00001001,8'b00011001,8'b00101001,8'b00111001
8'b00000011,8'b00010011,8'b00100011,8'b00110011 :
begin
// INC ss
TStates = 3'b110;
IncDec_16[3:2] = 2'b01;
IncDec_16[1:0] = DPAIR;
end
8'b00001011,8'b00011011,8'b00101011,8'b00111011 :
begin
// DEC ss
TStates = 3'b110;
IncDec_16[3:2] = 2'b11;
IncDec_16[1:0] = DPAIR;
end
 
// ROTATE AND SHIFT GROUP
8'b00000111,
// RLCA
8'b00010111,
// RLA
8'b00001111,
// RRCA
8'b00011111 :
// RRA
begin
Set_BusA_To[2:0] = 3'b111;
ALU_Op = 4'b1000;
Read_To_Reg = 1'b1;
Save_ALU = 1'b1;
end // case: 8'b00000111,...
 
// JUMP GROUP
8'b11000011 :
begin
// JP nn
MCycles = 3'b011;
case (MCycle)
2 :
begin
Inc_PC = 1'b1;
LDZ = 1'b1;
end
3 :
begin
Inc_PC = 1'b1;
Jump = 1'b1;
end
default :;
endcase // case(MCycle)
end // case: 8'b11000011
8'b11000010,8'b11001010,8'b11010010,8'b11011010,8'b11100010,8'b11101010,8'b11110010,8'b11111010 :
begin
if (IR[5] == 1'b1 && Mode == 3 )
begin
case (IRB[4:3])
2'b00 :
begin
// LD ($FF00+C),A
MCycles = 3'b010;
case (MCycle)
1 :
begin
Set_Addr_To = aBC;
Set_BusB_To = 4'b0111;
end
2 :
begin
Write = 1'b1;
IORQ = 1'b1;
end
default :;
endcase // case(MCycle)
end // case: 2'b00
2'b01 :
begin
// LD (nn),A
MCycles = 3'b100;
case (MCycle)
2 :
begin
Inc_PC = 1'b1;
LDZ = 1'b1;
end
3 :
begin
Set_Addr_To = aZI;
Inc_PC = 1'b1;
Set_BusB_To = 4'b0111;
end
4 :
Write = 1'b1;
default :;
endcase // case(MCycle)
end // case: default :...
2'b10 :
begin
// LD A,($FF00+C)
MCycles = 3'b010;
case (MCycle)
1 :
Set_Addr_To = aBC;
2 :
begin
Read_To_Acc = 1'b1;
IORQ = 1'b1;
end
default :;
endcase // case(MCycle)
end // case: 2'b10
2'b11 :
begin
// LD A,(nn)
MCycles = 3'b100;
case (MCycle)
2 :
begin
Inc_PC = 1'b1;
LDZ = 1'b1;
end
3 :
begin
Set_Addr_To = aZI;
Inc_PC = 1'b1;
end
4 :
Read_To_Acc = 1'b1;
default :;
endcase // case(MCycle)
end
endcase
end
else
begin
// JP cc,nn
MCycles = 3'b011;
case (MCycle)
2 :
begin
Inc_PC = 1'b1;
LDZ = 1'b1;
end
3 :
begin
Inc_PC = 1'b1;
if (is_cc_true(F, IR[5:3]) )
begin
Jump = 1'b1;
end
end
default :;
endcase
end // else: !if(DPAIR == 2'b11 )
end // case: 8'b11000010,8'b11001010,8'b11010010,8'b11011010,8'b11100010,8'b11101010,8'b11110010,8'b11111010
8'b00011000 :
begin
if (Mode != 2 )
begin
// JR e
MCycles = 3'b011;
case (MCycle)
2 :
Inc_PC = 1'b1;
3 :
begin
NoRead = 1'b1;
JumpE = 1'b1;
TStates = 3'b101;
end
default :;
endcase
end // if (Mode != 2 )
end // case: 8'b00011000
8'b00111000 :
begin
if (Mode != 2 )
begin
// JR C,e
MCycles = 3'b011;
case (MCycle)
2 :
begin
Inc_PC = 1'b1;
if (F[Flag_C] == 1'b0 )
begin
MCycles = 3'b010;
end
end
3 :
begin
NoRead = 1'b1;
JumpE = 1'b1;
TStates = 3'b101;
end
default :;
endcase
end // if (Mode != 2 )
end // case: 8'b00111000
8'b00110000 :
begin
if (Mode != 2 )
begin
// JR NC,e
MCycles = 3'b011;
case (MCycle)
2 :
begin
Inc_PC = 1'b1;
if (F[Flag_C] == 1'b1 )
begin
MCycles = 3'b010;
end
end
3 :
begin
NoRead = 1'b1;
JumpE = 1'b1;
TStates = 3'b101;
end
default :;
endcase
end // if (Mode != 2 )
end // case: 8'b00110000
8'b00101000 :
begin
if (Mode != 2 )
begin
// JR Z,e
MCycles = 3'b011;
case (MCycle)
2 :
begin
Inc_PC = 1'b1;
if (F[Flag_Z] == 1'b0 )
begin
MCycles = 3'b010;
end
end
3 :
begin
NoRead = 1'b1;
JumpE = 1'b1;
TStates = 3'b101;
end
default :;
endcase
end // if (Mode != 2 )
end // case: 8'b00101000
8'b00100000 :
begin
if (Mode != 2 )
begin
// JR NZ,e
MCycles = 3'b011;
case (MCycle)
2 :
begin
Inc_PC = 1'b1;
if (F[Flag_Z] == 1'b1 )
begin
MCycles = 3'b010;
end
end
3 :
begin
NoRead = 1'b1;
JumpE = 1'b1;
TStates = 3'b101;
end
default :;
endcase
end // if (Mode != 2 )
end // case: 8'b00100000
8'b11101001 :
// JP (HL)
JumpXY = 1'b1;
8'b00010000 :
begin
if (Mode == 3 )
begin
I_DJNZ = 1'b1;
end
else if (Mode < 2 )
begin
// DJNZ,e
MCycles = 3'b011;
case (MCycle)
1 :
begin
TStates = 3'b101;
I_DJNZ = 1'b1;
Set_BusB_To = 4'b1010;
Set_BusA_To[2:0] = 3'b000;
Read_To_Reg = 1'b1;
Save_ALU = 1'b1;
ALU_Op = 4'b0010;
end
2 :
begin
I_DJNZ = 1'b1;
Inc_PC = 1'b1;
end
3 :
begin
NoRead = 1'b1;
JumpE = 1'b1;
TStates = 3'b101;
end
default :;
endcase
end // if (Mode < 2 )
end // case: 8'b00010000
 
// CALL AND RETURN GROUP
8'b11001101 :
begin
// CALL nn
MCycles = 3'b101;
case (MCycle)
2 :
begin
Inc_PC = 1'b1;
LDZ = 1'b1;
end
3 :
begin
IncDec_16 = 4'b1111;
Inc_PC = 1'b1;
TStates = 3'b100;
Set_Addr_To = aSP;
LDW = 1'b1;
Set_BusB_To = 4'b1101;
end
4 :
begin
Write = 1'b1;
IncDec_16 = 4'b1111;
Set_Addr_To = aSP;
Set_BusB_To = 4'b1100;
end
5 :
begin
Write = 1'b1;
Call = 1'b1;
end
default :;
endcase // case(MCycle)
end // case: 8'b11001101
8'b11000100,8'b11001100,8'b11010100,8'b11011100,8'b11100100,8'b11101100,8'b11110100,8'b11111100 :
begin
if (IR[5] == 1'b0 || Mode != 3 )
begin
// CALL cc,nn
MCycles = 3'b101;
case (MCycle)
2 :
begin
Inc_PC = 1'b1;
LDZ = 1'b1;
end
3 :
begin
Inc_PC = 1'b1;
LDW = 1'b1;
if (is_cc_true(F, IR[5:3]) )
begin
IncDec_16 = 4'b1111;
Set_Addr_To = aSP;
TStates = 3'b100;
Set_BusB_To = 4'b1101;
end
else
begin
MCycles = 3'b011;
end // else: !if(is_cc_true(F, IR[5:3]) )
end // case: 3
4 :
begin
Write = 1'b1;
IncDec_16 = 4'b1111;
Set_Addr_To = aSP;
Set_BusB_To = 4'b1100;
end
5 :
begin
Write = 1'b1;
Call = 1'b1;
end
default :;
endcase
end // if (IR[5] == 1'b0 || Mode != 3 )
end // case: 8'b11000100,8'b11001100,8'b11010100,8'b11011100,8'b11100100,8'b11101100,8'b11110100,8'b11111100
8'b11001001 :
begin
// RET
MCycles = 3'b011;
case (MCycle)
1 :
begin
TStates = 3'b101;
Set_Addr_To = aSP;
end
2 :
begin
IncDec_16 = 4'b0111;
Set_Addr_To = aSP;
LDZ = 1'b1;
end
3 :
begin
Jump = 1'b1;
IncDec_16 = 4'b0111;
end
default :;
endcase // case(MCycle)
end // case: 8'b11001001
8'b11000000,8'b11001000,8'b11010000,8'b11011000,8'b11100000,8'b11101000,8'b11110000,8'b11111000 :
begin
if (IR[5] == 1'b1 && Mode == 3 )
begin
case (IRB[4:3])
2'b00 :
begin
// LD ($FF00+nn),A
MCycles = 3'b011;
case (MCycle)
2 :
begin
Inc_PC = 1'b1;
Set_Addr_To = aIOA;
Set_BusB_To = 4'b0111;
end
3 :
Write = 1'b1;
default :;
endcase // case(MCycle)
end // case: 2'b00
2'b01 :
begin
// ADD SP,n
MCycles = 3'b011;
case (MCycle)
2 :
begin
ALU_Op = 4'b0000;
Inc_PC = 1'b1;
Read_To_Reg = 1'b1;
Save_ALU = 1'b1;
Set_BusA_To = 4'b1000;
Set_BusB_To = 4'b0110;
end
3 :
begin
NoRead = 1'b1;
Read_To_Reg = 1'b1;
Save_ALU = 1'b1;
ALU_Op = 4'b0001;
Set_BusA_To = 4'b1001;
Set_BusB_To = 4'b1110; // Incorrect unsigned !!!!!!!!!!!!!!!!!!!!!
end
default :;
endcase // case(MCycle)
end // case: 2'b01
2'b10 :
begin
// LD A,($FF00+nn)
MCycles = 3'b011;
case (MCycle)
2 :
begin
Inc_PC = 1'b1;
Set_Addr_To = aIOA;
end
3 :
Read_To_Acc = 1'b1;
default :;
endcase // case(MCycle)
end // case: 2'b10
2'b11 :
begin
// LD HL,SP+n -- Not correct !!!!!!!!!!!!!!!!!!!
MCycles = 3'b101;
case (MCycle)
2 :
begin
Inc_PC = 1'b1;
LDZ = 1'b1;
end
3 :
begin
Set_Addr_To = aZI;
Inc_PC = 1'b1;
LDW = 1'b1;
end
4 :
begin
Set_BusA_To[2:0] = 3'b101; // L
Read_To_Reg = 1'b1;
Inc_WZ = 1'b1;
Set_Addr_To = aZI;
end
5 :
begin
Set_BusA_To[2:0] = 3'b100; // H
Read_To_Reg = 1'b1;
end
default :;
endcase // case(MCycle)
end // case: 2'b11
endcase // case(IRB[4:3])
end
else
begin
// RET cc
MCycles = 3'b011;
case (MCycle)
1 :
begin
if (is_cc_true(F, IR[5:3]) )
begin
Set_Addr_To = aSP;
end
else
begin
MCycles = 3'b001;
end
TStates = 3'b101;
end // case: 1
2 :
begin
IncDec_16 = 4'b0111;
Set_Addr_To = aSP;
LDZ = 1'b1;
end
3 :
begin
Jump = 1'b1;
IncDec_16 = 4'b0111;
end
default :;
endcase
end // else: !if(IR[5] == 1'b1 && Mode == 3 )
end // case: 8'b11000000,8'b11001000,8'b11010000,8'b11011000,8'b11100000,8'b11101000,8'b11110000,8'b11111000
8'b11000111,8'b11001111,8'b11010111,8'b11011111,8'b11100111,8'b11101111,8'b11110111,8'b11111111 :
begin
// RST p
MCycles = 3'b011;
case (MCycle)
1 :
begin
TStates = 3'b101;
IncDec_16 = 4'b1111;
Set_Addr_To = aSP;
Set_BusB_To = 4'b1101;
end
2 :
begin
Write = 1'b1;
IncDec_16 = 4'b1111;
Set_Addr_To = aSP;
Set_BusB_To = 4'b1100;
end
3 :
begin
Write = 1'b1;
RstP = 1'b1;
end
default :;
endcase // case(MCycle)
end // case: 8'b11000111,8'b11001111,8'b11010111,8'b11011111,8'b11100111,8'b11101111,8'b11110111,8'b11111111
// INPUT AND OUTPUT GROUP
8'b11011011 :
begin
if (Mode != 3 )
begin
// IN A,(n)
MCycles = 3'b011;
case (MCycle)
2 :
begin
Inc_PC = 1'b1;
Set_Addr_To = aIOA;
end
3 :
begin
Read_To_Acc = 1'b1;
IORQ = 1'b1;
end
default :;
endcase
end // if (Mode != 3 )
end // case: 8'b11011011
8'b11010011 :
begin
if (Mode != 3 )
begin
// OUT (n),A
MCycles = 3'b011;
case (MCycle)
2 :
begin
Inc_PC = 1'b1;
Set_Addr_To = aIOA;
Set_BusB_To = 4'b0111;
end
3 :
begin
Write = 1'b1;
IORQ = 1'b1;
end
default :;
endcase
end // if (Mode != 3 )
end // case: 8'b11010011
 
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// MULTIBYTE INSTRUCTIONS
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
 
8'b11001011 :
begin
if (Mode != 2 )
begin
Prefix = 2'b01;
end
end
 
8'b11101101 :
begin
if (Mode < 2 )
begin
Prefix = 2'b10;
end
end
 
8'b11011101,8'b11111101 :
begin
if (Mode < 2 )
begin
Prefix = 2'b11;
end
end
endcase // case(IRB)
end // case: 2'b00
 
2'b01 :
begin
 
//----------------------------------------------------------------------------
//
// CB prefixed instructions
//
//----------------------------------------------------------------------------
Set_BusA_To[2:0] = IR[2:0];
Set_BusB_To[2:0] = IR[2:0];
case (IRB)
8'b00000000,8'b00000001,8'b00000010,8'b00000011,8'b00000100,8'b00000101,8'b00000111,
8'b00010000,8'b00010001,8'b00010010,8'b00010011,8'b00010100,8'b00010101,8'b00010111,
8'b00001000,8'b00001001,8'b00001010,8'b00001011,8'b00001100,8'b00001101,8'b00001111,
8'b00011000,8'b00011001,8'b00011010,8'b00011011,8'b00011100,8'b00011101,8'b00011111,
8'b00100000,8'b00100001,8'b00100010,8'b00100011,8'b00100100,8'b00100101,8'b00100111,
8'b00101000,8'b00101001,8'b00101010,8'b00101011,8'b00101100,8'b00101101,8'b00101111,
8'b00110000,8'b00110001,8'b00110010,8'b00110011,8'b00110100,8'b00110101,8'b00110111,
8'b00111000,8'b00111001,8'b00111010,8'b00111011,8'b00111100,8'b00111101,8'b00111111 :
begin
// RLC r
// RL r
// RRC r
// RR r
// SLA r
// SRA r
// SRL r
// SLL r (Undocumented) / SWAP r
if (MCycle == 3'b001 ) begin
ALU_Op = 4'b1000;
Read_To_Reg = 1'b1;
Save_ALU = 1'b1;
end
end // case: 8'b00000000,8'b00000001,8'b00000010,8'b00000011,8'b00000100,8'b00000101,8'b00000111,...
8'b00000110,8'b00010110,8'b00001110,8'b00011110,8'b00101110,8'b00111110,8'b00100110,8'b00110110 :
begin
// RLC (HL)
// RL (HL)
// RRC (HL)
// RR (HL)
// SRA (HL)
// SRL (HL)
// SLA (HL)
// SLL (HL) (Undocumented) / SWAP (HL)
MCycles = 3'b011;
case (MCycle)
1 , 7 :
Set_Addr_To = aXY;
2 :
begin
ALU_Op = 4'b1000;
Read_To_Reg = 1'b1;
Save_ALU = 1'b1;
Set_Addr_To = aXY;
TStates = 3'b100;
end
3 :
Write = 1'b1;
default :;
endcase // case(MCycle)
end // case: 8'b00000110,8'b00010110,8'b00001110,8'b00011110,8'b00101110,8'b00111110,8'b00100110,8'b00110110
8'b01000000,8'b01000001,8'b01000010,8'b01000011,8'b01000100,8'b01000101,8'b01000111,
8'b01001000,8'b01001001,8'b01001010,8'b01001011,8'b01001100,8'b01001101,8'b01001111,
8'b01010000,8'b01010001,8'b01010010,8'b01010011,8'b01010100,8'b01010101,8'b01010111,
8'b01011000,8'b01011001,8'b01011010,8'b01011011,8'b01011100,8'b01011101,8'b01011111,
8'b01100000,8'b01100001,8'b01100010,8'b01100011,8'b01100100,8'b01100101,8'b01100111,
8'b01101000,8'b01101001,8'b01101010,8'b01101011,8'b01101100,8'b01101101,8'b01101111,
8'b01110000,8'b01110001,8'b01110010,8'b01110011,8'b01110100,8'b01110101,8'b01110111,
8'b01111000,8'b01111001,8'b01111010,8'b01111011,8'b01111100,8'b01111101,8'b01111111 :
begin
// BIT b,r
if (MCycle == 3'b001 )
begin
Set_BusB_To[2:0] = IR[2:0];
ALU_Op = 4'b1001;
end
end // case: 8'b01000000,8'b01000001,8'b01000010,8'b01000011,8'b01000100,8'b01000101,8'b01000111,...
8'b01000110,8'b01001110,8'b01010110,8'b01011110,8'b01100110,8'b01101110,8'b01110110,8'b01111110 :
begin
// BIT b,(HL)
MCycles = 3'b010;
case (MCycle)
1 , 7 :
Set_Addr_To = aXY;
2 :
begin
ALU_Op = 4'b1001;
TStates = 3'b100;
end
default :;
endcase // case(MCycle)
end // case: 8'b01000110,8'b01001110,8'b01010110,8'b01011110,8'b01100110,8'b01101110,8'b01110110,8'b01111110
8'b11000000,8'b11000001,8'b11000010,8'b11000011,8'b11000100,8'b11000101,8'b11000111,
8'b11001000,8'b11001001,8'b11001010,8'b11001011,8'b11001100,8'b11001101,8'b11001111,
8'b11010000,8'b11010001,8'b11010010,8'b11010011,8'b11010100,8'b11010101,8'b11010111,
8'b11011000,8'b11011001,8'b11011010,8'b11011011,8'b11011100,8'b11011101,8'b11011111,
8'b11100000,8'b11100001,8'b11100010,8'b11100011,8'b11100100,8'b11100101,8'b11100111,
8'b11101000,8'b11101001,8'b11101010,8'b11101011,8'b11101100,8'b11101101,8'b11101111,
8'b11110000,8'b11110001,8'b11110010,8'b11110011,8'b11110100,8'b11110101,8'b11110111,
8'b11111000,8'b11111001,8'b11111010,8'b11111011,8'b11111100,8'b11111101,8'b11111111 :
begin
// SET b,r
if (MCycle == 3'b001 )
begin
ALU_Op = 4'b1010;
Read_To_Reg = 1'b1;
Save_ALU = 1'b1;
end
end // case: 8'b11000000,8'b11000001,8'b11000010,8'b11000011,8'b11000100,8'b11000101,8'b11000111,...
8'b11000110,8'b11001110,8'b11010110,8'b11011110,8'b11100110,8'b11101110,8'b11110110,8'b11111110 :
begin
// SET b,(HL)
MCycles = 3'b011;
case (MCycle)
1 , 7 :
Set_Addr_To = aXY;
2 :
begin
ALU_Op = 4'b1010;
Read_To_Reg = 1'b1;
Save_ALU = 1'b1;
Set_Addr_To = aXY;
TStates = 3'b100;
end
3 :
Write = 1'b1;
default :;
endcase // case(MCycle)
end // case: 8'b11000110,8'b11001110,8'b11010110,8'b11011110,8'b11100110,8'b11101110,8'b11110110,8'b11111110
8'b10000000,8'b10000001,8'b10000010,8'b10000011,8'b10000100,8'b10000101,8'b10000111,
8'b10001000,8'b10001001,8'b10001010,8'b10001011,8'b10001100,8'b10001101,8'b10001111,
8'b10010000,8'b10010001,8'b10010010,8'b10010011,8'b10010100,8'b10010101,8'b10010111,
8'b10011000,8'b10011001,8'b10011010,8'b10011011,8'b10011100,8'b10011101,8'b10011111,
8'b10100000,8'b10100001,8'b10100010,8'b10100011,8'b10100100,8'b10100101,8'b10100111,
8'b10101000,8'b10101001,8'b10101010,8'b10101011,8'b10101100,8'b10101101,8'b10101111,
8'b10110000,8'b10110001,8'b10110010,8'b10110011,8'b10110100,8'b10110101,8'b10110111,
8'b10111000,8'b10111001,8'b10111010,8'b10111011,8'b10111100,8'b10111101,8'b10111111 :
begin
// RES b,r
if (MCycle == 3'b001 )
begin
ALU_Op = 4'b1011;
Read_To_Reg = 1'b1;
Save_ALU = 1'b1;
end
end // case: 8'b10000000,8'b10000001,8'b10000010,8'b10000011,8'b10000100,8'b10000101,8'b10000111,...
8'b10000110,8'b10001110,8'b10010110,8'b10011110,8'b10100110,8'b10101110,8'b10110110,8'b10111110 :
begin
// RES b,(HL)
MCycles = 3'b011;
case (MCycle)
1 , 7 :
Set_Addr_To = aXY;
2 :
begin
ALU_Op = 4'b1011;
Read_To_Reg = 1'b1;
Save_ALU = 1'b1;
Set_Addr_To = aXY;
TStates = 3'b100;
end
3 :
Write = 1'b1;
default :;
endcase // case(MCycle)
end // case: 8'b10000110,8'b10001110,8'b10010110,8'b10011110,8'b10100110,8'b10101110,8'b10110110,8'b10111110
endcase // case(IRB)
end // case: 2'b01
default :
begin : default_ed_block
//----------------------------------------------------------------------------
//
// ED prefixed instructions
//
//----------------------------------------------------------------------------
 
case (IRB)
8'b00000000,8'b00000001,8'b00000010,8'b00000011,8'b00000100,8'b00000101,8'b00000110,8'b00000111
,8'b00001000,8'b00001001,8'b00001010,8'b00001011,8'b00001100,8'b00001101,8'b00001110,8'b00001111
,8'b00010000,8'b00010001,8'b00010010,8'b00010011,8'b00010100,8'b00010101,8'b00010110,8'b00010111
,8'b00011000,8'b00011001,8'b00011010,8'b00011011,8'b00011100,8'b00011101,8'b00011110,8'b00011111
,8'b00100000,8'b00100001,8'b00100010,8'b00100011,8'b00100100,8'b00100101,8'b00100110,8'b00100111
,8'b00101000,8'b00101001,8'b00101010,8'b00101011,8'b00101100,8'b00101101,8'b00101110,8'b00101111
,8'b00110000,8'b00110001,8'b00110010,8'b00110011,8'b00110100,8'b00110101,8'b00110110,8'b00110111
,8'b00111000,8'b00111001,8'b00111010,8'b00111011,8'b00111100,8'b00111101,8'b00111110,8'b00111111
 
,8'b10000000,8'b10000001,8'b10000010,8'b10000011,8'b10000100,8'b10000101,8'b10000110,8'b10000111
,8'b10001000,8'b10001001,8'b10001010,8'b10001011,8'b10001100,8'b10001101,8'b10001110,8'b10001111
,8'b10010000,8'b10010001,8'b10010010,8'b10010011,8'b10010100,8'b10010101,8'b10010110,8'b10010111
,8'b10011000,8'b10011001,8'b10011010,8'b10011011,8'b10011100,8'b10011101,8'b10011110,8'b10011111
, 8'b10100100,8'b10100101,8'b10100110,8'b10100111
, 8'b10101100,8'b10101101,8'b10101110,8'b10101111
, 8'b10110100,8'b10110101,8'b10110110,8'b10110111
, 8'b10111100,8'b10111101,8'b10111110,8'b10111111
,8'b11000000,8'b11000001,8'b11000010,8'b11000011,8'b11000100,8'b11000101,8'b11000110,8'b11000111
,8'b11001000,8'b11001001,8'b11001010,8'b11001011,8'b11001100,8'b11001101,8'b11001110,8'b11001111
,8'b11010000,8'b11010001,8'b11010010,8'b11010011,8'b11010100,8'b11010101,8'b11010110,8'b11010111
,8'b11011000,8'b11011001,8'b11011010,8'b11011011,8'b11011100,8'b11011101,8'b11011110,8'b11011111
,8'b11100000,8'b11100001,8'b11100010,8'b11100011,8'b11100100,8'b11100101,8'b11100110,8'b11100111
,8'b11101000,8'b11101001,8'b11101010,8'b11101011,8'b11101100,8'b11101101,8'b11101110,8'b11101111
,8'b11110000,8'b11110001,8'b11110010,8'b11110011,8'b11110100,8'b11110101,8'b11110110,8'b11110111
,8'b11111000,8'b11111001,8'b11111010,8'b11111011,8'b11111100,8'b11111101,8'b11111110,8'b11111111 :
; // NOP, undocumented
8'b01111110,8'b01111111 :
// NOP, undocumented
;
// 8 BIT LOAD GROUP
8'b01010111 :
begin
// LD A,I
Special_LD = 3'b100;
TStates = 3'b101;
end
8'b01011111 :
begin
// LD A,R
Special_LD = 3'b101;
TStates = 3'b101;
end
8'b01000111 :
begin
// LD I,A
Special_LD = 3'b110;
TStates = 3'b101;
end
8'b01001111 :
begin
// LD R,A
Special_LD = 3'b111;
TStates = 3'b101;
end
// 16 BIT LOAD GROUP
8'b01001011,8'b01011011,8'b01101011,8'b01111011 :
begin
// LD dd,(nn)
MCycles = 3'b101;
case (MCycle)
2 :
begin
Inc_PC = 1'b1;
LDZ = 1'b1;
end
3 :
begin
Set_Addr_To = aZI;
Inc_PC = 1'b1;
LDW = 1'b1;
end
4 :
begin
Read_To_Reg = 1'b1;
if (IR[5:4] == 2'b11 )
begin
Set_BusA_To = 4'b1000;
end
else
begin
Set_BusA_To[2:1] = IR[5:4];
Set_BusA_To[0] = 1'b1;
end
Inc_WZ = 1'b1;
Set_Addr_To = aZI;
end // case: 4
5 :
begin
Read_To_Reg = 1'b1;
if (IR[5:4] == 2'b11 )
begin
Set_BusA_To = 4'b1001;
end
else
begin
Set_BusA_To[2:1] = IR[5:4];
Set_BusA_To[0] = 1'b0;
end
end // case: 5
default :;
endcase // case(MCycle)
end // case: 8'b01001011,8'b01011011,8'b01101011,8'b01111011
8'b01000011,8'b01010011,8'b01100011,8'b01110011 :
begin
// LD (nn),dd
MCycles = 3'b101;
case (MCycle)
2 :
begin
Inc_PC = 1'b1;
LDZ = 1'b1;
end
3 :
begin
Set_Addr_To = aZI;
Inc_PC = 1'b1;
LDW = 1'b1;
if (IR[5:4] == 2'b11 )
begin
Set_BusB_To = 4'b1000;
end
else
begin
Set_BusB_To[2:1] = IR[5:4];
Set_BusB_To[0] = 1'b1;
Set_BusB_To[3] = 1'b0;
end
end // case: 3
4 :
begin
Inc_WZ = 1'b1;
Set_Addr_To = aZI;
Write = 1'b1;
if (IR[5:4] == 2'b11 )
begin
Set_BusB_To = 4'b1001;
end
else
begin
Set_BusB_To[2:1] = IR[5:4];
Set_BusB_To[0] = 1'b0;
Set_BusB_To[3] = 1'b0;
end
end // case: 4
5 :
begin
Write = 1'b1;
end
default :;
endcase // case(MCycle)
end // case: 8'b01000011,8'b01010011,8'b01100011,8'b01110011
8'b10100000 , 8'b10101000 , 8'b10110000 , 8'b10111000 :
begin
// LDI, LDD, LDIR, LDDR
MCycles = 3'b100;
case (MCycle)
1 :
begin
Set_Addr_To = aXY;
IncDec_16 = 4'b1100; // BC
end
2 :
begin
Set_BusB_To = 4'b0110;
Set_BusA_To[2:0] = 3'b111;
ALU_Op = 4'b0000;
Set_Addr_To = aDE;
if (IR[3] == 1'b0 )
begin
IncDec_16 = 4'b0110; // IX
end
else
begin
IncDec_16 = 4'b1110;
end
end // case: 2
3 :
begin
I_BT = 1'b1;
TStates = 3'b101;
Write = 1'b1;
if (IR[3] == 1'b0 )
begin
IncDec_16 = 4'b0101; // DE
end
else
begin
IncDec_16 = 4'b1101;
end
end // case: 3
4 :
begin
NoRead = 1'b1;
TStates = 3'b101;
end
default :;
endcase // case(MCycle)
end // case: 8'b10100000 , 8'b10101000 , 8'b10110000 , 8'b10111000
8'b10100001 , 8'b10101001 , 8'b10110001 , 8'b10111001 :
begin
// CPI, CPD, CPIR, CPDR
MCycles = 3'b100;
case (MCycle)
1 :
begin
Set_Addr_To = aXY;
IncDec_16 = 4'b1100; // BC
end
2 :
begin
Set_BusB_To = 4'b0110;
Set_BusA_To[2:0] = 3'b111;
ALU_Op = 4'b0111;
Save_ALU = 1'b1;
PreserveC = 1'b1;
if (IR[3] == 1'b0 )
begin
IncDec_16 = 4'b0110;
end
else
begin
IncDec_16 = 4'b1110;
end
end // case: 2
3 :
begin
NoRead = 1'b1;
I_BC = 1'b1;
TStates = 3'b101;
end
4 :
begin
NoRead = 1'b1;
TStates = 3'b101;
end
default :;
endcase // case(MCycle)
end // case: 8'b10100001 , 8'b10101001 , 8'b10110001 , 8'b10111001
8'b01000100,8'b01001100,8'b01010100,8'b01011100,8'b01100100,8'b01101100,8'b01110100,8'b01111100 :
begin
// NEG
ALU_Op = 4'b0010;
Set_BusB_To = 4'b0111;
Set_BusA_To = 4'b1010;
Read_To_Acc = 1'b1;
Save_ALU = 1'b1;
end
8'b01000110,8'b01001110,8'b01100110,8'b01101110 :
begin
// IM 0
IMode = 2'b00;
end
8'b01010110,8'b01110110 :
// IM 1
IMode = 2'b01;
8'b01011110,8'b01110111 :
// IM 2
IMode = 2'b10;
// 16 bit arithmetic
8'b01001010,8'b01011010,8'b01101010,8'b01111010 :
begin
// ADC HL,ss
MCycles = 3'b011;
case (MCycle)
2 :
begin
NoRead = 1'b1;
ALU_Op = 4'b0001;
Read_To_Reg = 1'b1;
Save_ALU = 1'b1;
Set_BusA_To[2:0] = 3'b101;
case (IR[5:4])
0,1,2 :
begin
Set_BusB_To[2:1] = IR[5:4];
Set_BusB_To[0] = 1'b1;
end
default :
Set_BusB_To = 4'b1000;
endcase
TStates = 3'b100;
end // case: 2
3 :
begin
NoRead = 1'b1;
Read_To_Reg = 1'b1;
Save_ALU = 1'b1;
ALU_Op = 4'b0001;
Set_BusA_To[2:0] = 3'b100;
case (IR[5:4])
0,1,2 :
begin
Set_BusB_To[2:1] = IR[5:4];
Set_BusB_To[0] = 1'b0;
end
default :
Set_BusB_To = 4'b1001;
endcase // case(IR[5:4])
end // case: 3
default :;
endcase // case(MCycle)
end // case: 8'b01001010,8'b01011010,8'b01101010,8'b01111010
8'b01000010,8'b01010010,8'b01100010,8'b01110010 :
begin
// SBC HL,ss
MCycles = 3'b011;
case (MCycle)
2 :
begin
NoRead = 1'b1;
ALU_Op = 4'b0011;
Read_To_Reg = 1'b1;
Save_ALU = 1'b1;
Set_BusA_To[2:0] = 3'b101;
case (IR[5:4])
0,1,2 :
begin
Set_BusB_To[2:1] = IR[5:4];
Set_BusB_To[0] = 1'b1;
end
default :
Set_BusB_To = 4'b1000;
endcase
TStates = 3'b100;
end // case: 2
3 :
begin
NoRead = 1'b1;
ALU_Op = 4'b0011;
Read_To_Reg = 1'b1;
Save_ALU = 1'b1;
Set_BusA_To[2:0] = 3'b100;
case (IR[5:4])
0,1,2 :
Set_BusB_To[2:1] = IR[5:4];
default :
Set_BusB_To = 4'b1001;
endcase
end // case: 3
default :;
endcase // case(MCycle)
end // case: 8'b01000010,8'b01010010,8'b01100010,8'b01110010
8'b01101111 :
begin
// RLD
MCycles = 3'b100;
case (MCycle)
2 :
begin
NoRead = 1'b1;
Set_Addr_To = aXY;
end
3 :
begin
Read_To_Reg = 1'b1;
Set_BusB_To[2:0] = 3'b110;
Set_BusA_To[2:0] = 3'b111;
ALU_Op = 4'b1101;
TStates = 3'b100;
Set_Addr_To = aXY;
Save_ALU = 1'b1;
end
4 :
begin
I_RLD = 1'b1;
Write = 1'b1;
end
default :;
endcase // case(MCycle)
end // case: 8'b01101111
8'b01100111 :
begin
// RRD
MCycles = 3'b100;
case (MCycle)
2 :
Set_Addr_To = aXY;
3 :
begin
Read_To_Reg = 1'b1;
Set_BusB_To[2:0] = 3'b110;
Set_BusA_To[2:0] = 3'b111;
ALU_Op = 4'b1110;
TStates = 3'b100;
Set_Addr_To = aXY;
Save_ALU = 1'b1;
end
4 :
begin
I_RRD = 1'b1;
Write = 1'b1;
end
default :;
endcase // case(MCycle)
end // case: 8'b01100111
8'b01000101,8'b01001101,8'b01010101,8'b01011101,8'b01100101,8'b01101101,8'b01110101,8'b01111101 :
begin
// RETI, RETN
MCycles = 3'b011;
case (MCycle)
1 :
Set_Addr_To = aSP;
2 :
begin
IncDec_16 = 4'b0111;
Set_Addr_To = aSP;
LDZ = 1'b1;
end
3 :
begin
Jump = 1'b1;
IncDec_16 = 4'b0111;
I_RETN = 1'b1;
end
default :;
endcase // case(MCycle)
end // case: 8'b01000101,8'b01001101,8'b01010101,8'b01011101,8'b01100101,8'b01101101,8'b01110101,8'b01111101
8'b01000000,8'b01001000,8'b01010000,8'b01011000,8'b01100000,8'b01101000,8'b01110000,8'b01111000 :
begin
// IN r,(C)
MCycles = 3'b010;
case (MCycle)
1 :
Set_Addr_To = aBC;
2 :
begin
IORQ = 1'b1;
if (IR[5:3] != 3'b110 )
begin
Read_To_Reg = 1'b1;
Set_BusA_To[2:0] = IR[5:3];
end
I_INRC = 1'b1;
end
default :;
endcase // case(MCycle)
end // case: 8'b01000000,8'b01001000,8'b01010000,8'b01011000,8'b01100000,8'b01101000,8'b01110000,8'b01111000
8'b01000001,8'b01001001,8'b01010001,8'b01011001,8'b01100001,8'b01101001,8'b01110001,8'b01111001 :
begin
// OUT (C),r
// OUT (C),0
MCycles = 3'b010;
case (MCycle)
1 :
begin
Set_Addr_To = aBC;
Set_BusB_To[2:0] = IR[5:3];
if (IR[5:3] == 3'b110 )
begin
Set_BusB_To[3] = 1'b1;
end
end
2 :
begin
Write = 1'b1;
IORQ = 1'b1;
end
default :;
endcase // case(MCycle)
end // case: 8'b01000001,8'b01001001,8'b01010001,8'b01011001,8'b01100001,8'b01101001,8'b01110001,8'b01111001
8'b10100010 , 8'b10101010 , 8'b10110010 , 8'b10111010 :
begin
// INI, IND, INIR, INDR
MCycles = 3'b100;
case (MCycle)
1 :
begin
Set_Addr_To = aBC;
Set_BusB_To = 4'b1010;
Set_BusA_To = 4'b0000;
Read_To_Reg = 1'b1;
Save_ALU = 1'b1;
ALU_Op = 4'b0010;
end
2 :
begin
IORQ = 1'b1;
Set_BusB_To = 4'b0110;
Set_Addr_To = aXY;
end
3 :
begin
if (IR[3] == 1'b0 )
begin
IncDec_16 = 4'b0010;
end
else
begin
IncDec_16 = 4'b1010;
end
TStates = 3'b100;
Write = 1'b1;
I_BTR = 1'b1;
end // case: 3
4 :
begin
NoRead = 1'b1;
TStates = 3'b101;
end
default :;
endcase // case(MCycle)
end // case: 8'b10100010 , 8'b10101010 , 8'b10110010 , 8'b10111010
8'b10100011 , 8'b10101011 , 8'b10110011 , 8'b10111011 :
begin
// OUTI, OUTD, OTIR, OTDR
MCycles = 3'b100;
case (MCycle)
1 :
begin
TStates = 3'b101;
Set_Addr_To = aXY;
Set_BusB_To = 4'b1010;
Set_BusA_To = 4'b0000;
Read_To_Reg = 1'b1;
Save_ALU = 1'b1;
ALU_Op = 4'b0010;
end
2 :
begin
Set_BusB_To = 4'b0110;
Set_Addr_To = aBC;
end
3 :
begin
if (IR[3] == 1'b0 )
begin
IncDec_16 = 4'b0010;
end
else
begin
IncDec_16 = 4'b1010;
end
IORQ = 1'b1;
Write = 1'b1;
I_BTR = 1'b1;
end // case: 3
4 :
begin
NoRead = 1'b1;
TStates = 3'b101;
end
default :;
endcase // case(MCycle)
end // case: 8'b10100011 , 8'b10101011 , 8'b10110011 , 8'b10111011
endcase // case(IRB)
end // block: default_ed_block
endcase // case(ISet)
if (Mode == 1 )
begin
if (MCycle == 3'b001 )
begin
//TStates = 3'b100;
end
else
begin
TStates = 3'b011;
end
end
 
if (Mode == 3 )
begin
if (MCycle == 3'b001 )
begin
//TStates = 3'b100;
end
else
begin
TStates = 3'b100;
end
end
 
if (Mode < 2 )
begin
if (MCycle == 3'b110 )
begin
Inc_PC = 1'b1;
if (Mode == 1 )
begin
Set_Addr_To = aXY;
TStates = 3'b100;
Set_BusB_To[2:0] = SSS;
Set_BusB_To[3] = 1'b0;
end
if (IRB == 8'b00110110 || IRB == 8'b11001011 )
begin
Set_Addr_To = aNone;
end
end
if (MCycle == 3'b111 )
begin
if (Mode == 0 )
begin
TStates = 3'b101;
end
if (ISet != 2'b01 )
begin
Set_Addr_To = aXY;
end
Set_BusB_To[2:0] = SSS;
Set_BusB_To[3] = 1'b0;
if (IRB == 8'b00110110 || ISet == 2'b01 )
begin
// LD (HL),n
Inc_PC = 1'b1;
end
else
begin
NoRead = 1'b1;
end
end
end // if (Mode < 2 )
end // always @ (IR, ISet, MCycle, F, NMICycle, IntCycle)
// synopsys dc_script_begin
// set_attribute current_design "revision" "$Id: tv80_mcode.v,v 1.1 2004-05-16 17:39:57 ghutchis Exp $" -type string -quiet
// synopsys dc_script_end
endmodule // T80_MCode
 
 
 
/trunk/rtl/core/tv80_core.v
0,0 → 1,1304
//
// TV80 8-Bit Microprocessor Core
// Based on the VHDL T80 core by Daniel Wallner (jesus@opencores.org)
//
// Copyright (c) 2004 Guy Hutchison (ghutchis@opencores.org)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
module tv80_core (/*AUTOARG*/
// Outputs
m1_n, iorq, no_read, write, rfsh_n, halt_n, busak_n, A, do, mc, ts,
intcycle_n, IntE, stop,
// Inputs
reset_n, clk, cen, wait_n, int_n, nmi_n, busrq_n, dinst, di
);
// Beginning of automatic inputs (from unused autoinst inputs)
// End of automatics
parameter Mode = 1; // 0 => Z80, 1 => Fast Z80, 2 => 8080, 3 => GB
parameter IOWait = 1; // 1 => Single cycle I/O, 1 => Std I/O cycle
parameter Flag_C = 0;
parameter Flag_N = 1;
parameter Flag_P = 2;
parameter Flag_X = 3;
parameter Flag_H = 4;
parameter Flag_Y = 5;
parameter Flag_Z = 6;
parameter Flag_S = 7;
 
input reset_n;
input clk;
input cen;
input wait_n;
input int_n;
input nmi_n;
input busrq_n;
output m1_n;
output iorq;
output no_read;
output write;
output rfsh_n;
output halt_n;
output busak_n;
output [15:0] A;
input [7:0] dinst;
input [7:0] di;
output [7:0] do;
output [2:0] mc;
output [2:0] ts;
output intcycle_n;
output IntE;
output stop;
 
reg m1_n;
reg iorq;
reg rfsh_n;
reg halt_n;
reg busak_n;
reg [15:0] A;
reg [7:0] do;
reg [2:0] mc;
reg [2:0] ts;
reg intcycle_n;
reg IntE;
reg stop;
 
parameter aNone = 3'b111;
parameter aBC = 3'b000;
parameter aDE = 3'b001;
parameter aXY = 3'b010;
parameter aIOA = 3'b100;
parameter aSP = 3'b101;
parameter aZI = 3'b110;
 
// Registers
reg [7:0] ACC, F;
reg [7:0] Ap, Fp;
reg [7:0] I;
reg [7:0] R;
reg [15:0] SP, PC;
reg [7:0] RegDIH;
reg [7:0] RegDIL;
wire [15:0] RegBusA;
wire [15:0] RegBusB;
wire [15:0] RegBusC;
reg [2:0] RegAddrA_r;
reg [2:0] RegAddrA;
reg [2:0] RegAddrB_r;
reg [2:0] RegAddrB;
reg [2:0] RegAddrC;
reg RegWEH;
reg RegWEL;
reg Alternate;
 
// Help Registers
reg [15:0] TmpAddr; // Temporary address register
reg [7:0] IR; // Instruction register
reg [1:0] ISet; // Instruction set selector
reg [15:0] RegBusA_r;
 
reg [15:0] ID16;
reg [7:0] Save_Mux;
 
reg [2:0] tstate;
reg [2:0] mcycle;
reg IntE_FF1;
reg IntE_FF2;
reg Halt_FF;
reg BusReq_s;
reg BusAck;
reg ClkEn;
reg NMI_s;
reg INT_s;
reg [1:0] IStatus;
 
reg [7:0] DI_Reg;
reg T_Res;
reg [1:0] XY_State;
reg [2:0] Pre_XY_F_M;
reg NextIs_XY_Fetch;
reg XY_Ind;
reg No_BTR;
reg BTR_r;
reg Auto_Wait;
reg Auto_Wait_t1;
reg Auto_Wait_t2;
reg IncDecZ;
 
// ALU signals
reg [7:0] BusB;
reg [7:0] BusA;
wire [7:0] ALU_Q;
wire [7:0] F_Out;
 
// Registered micro code outputs
reg [4:0] Read_To_Reg_r;
reg Arith16_r;
reg Z16_r;
reg [3:0] ALU_Op_r;
reg Save_ALU_r;
reg PreserveC_r;
reg [2:0] mcycles;
 
// Micro code outputs
wire [2:0] mcycles_d;
wire [2:0] tstates;
reg IntCycle;
reg NMICycle;
wire Inc_PC;
wire Inc_WZ;
wire [3:0] IncDec_16;
wire [1:0] Prefix;
wire Read_To_Acc;
wire Read_To_Reg;
wire [3:0] Set_BusB_To;
wire [3:0] Set_BusA_To;
wire [3:0] ALU_Op;
wire Save_ALU;
wire PreserveC;
wire Arith16;
wire [2:0] Set_Addr_To;
wire Jump;
wire JumpE;
wire JumpXY;
wire Call;
wire RstP;
wire LDZ;
wire LDW;
wire LDSPHL;
wire iorq_i;
wire [2:0] Special_LD;
wire ExchangeDH;
wire ExchangeRp;
wire ExchangeAF;
wire ExchangeRS;
wire I_DJNZ;
wire I_CPL;
wire I_CCF;
wire I_SCF;
wire I_RETN;
wire I_BT;
wire I_BC;
wire I_BTR;
wire I_RLD;
wire I_RRD;
wire I_INRC;
wire SetDI;
wire SetEI;
wire [1:0] IMode;
wire Halt;
 
reg [15:0] PC16;
reg [15:0] PC16_B;
reg [15:0] SP16, SP16_A, SP16_B;
reg [15:0] ID16_B;
reg Oldnmi_n;
tv80_mcode #(Mode, Flag_C, Flag_N, Flag_P, Flag_X, Flag_H, Flag_Y, Flag_Z, Flag_S) i_mcode
(
.IR (IR),
.ISet (ISet),
.MCycle (mcycle),
.F (F),
.NMICycle (NMICycle),
.IntCycle (IntCycle),
.MCycles (mcycles_d),
.TStates (tstates),
.Prefix (Prefix),
.Inc_PC (Inc_PC),
.Inc_WZ (Inc_WZ),
.IncDec_16 (IncDec_16),
.Read_To_Acc (Read_To_Acc),
.Read_To_Reg (Read_To_Reg),
.Set_BusB_To (Set_BusB_To),
.Set_BusA_To (Set_BusA_To),
.ALU_Op (ALU_Op),
.Save_ALU (Save_ALU),
.PreserveC (PreserveC),
.Arith16 (Arith16),
.Set_Addr_To (Set_Addr_To),
.IORQ (iorq_i),
.Jump (Jump),
.JumpE (JumpE),
.JumpXY (JumpXY),
.Call (Call),
.RstP (RstP),
.LDZ (LDZ),
.LDW (LDW),
.LDSPHL (LDSPHL),
.Special_LD (Special_LD),
.ExchangeDH (ExchangeDH),
.ExchangeRp (ExchangeRp),
.ExchangeAF (ExchangeAF),
.ExchangeRS (ExchangeRS),
.I_DJNZ (I_DJNZ),
.I_CPL (I_CPL),
.I_CCF (I_CCF),
.I_SCF (I_SCF),
.I_RETN (I_RETN),
.I_BT (I_BT),
.I_BC (I_BC),
.I_BTR (I_BTR),
.I_RLD (I_RLD),
.I_RRD (I_RRD),
.I_INRC (I_INRC),
.SetDI (SetDI),
.SetEI (SetEI),
.IMode (IMode),
.Halt (Halt),
.NoRead (no_read),
.Write (write)
);
 
tv80_alu #(Mode, Flag_C, Flag_N, Flag_P, Flag_X, Flag_H, Flag_Y, Flag_Z, Flag_S) i_alu
(
.Arith16 (Arith16_r),
.Z16 (Z16_r),
.ALU_Op (ALU_Op_r),
.IR (IR[5:0]),
.ISet (ISet),
.BusA (BusA),
.BusB (BusB),
.F_In (F),
.Q (ALU_Q),
.F_Out (F_Out)
);
 
always @(/*AUTOSENSE*/ALU_Q or BusAck or BusB or DI_Reg
or ExchangeRp or IR or Save_ALU_r or Set_Addr_To or XY_Ind
or XY_State or cen or mcycle or tstate or tstates)
begin
ClkEn = cen && ~ BusAck;
 
if (tstate == tstates)
T_Res = 1'b1;
else T_Res = 1'b0;
if (XY_State != 2'b00 && XY_Ind == 1'b0 &&
((Set_Addr_To == aXY) ||
(mcycle == 3'b001 && IR == 8'b11001011) ||
(mcycle == 3'b001 && IR == 8'b00110110)))
NextIs_XY_Fetch = 1'b1;
else
NextIs_XY_Fetch = 1'b0;
 
if (ExchangeRp)
Save_Mux = BusB;
else if (!Save_ALU_r)
Save_Mux = DI_Reg;
else
Save_Mux = ALU_Q;
end // always @ *
always @ (posedge clk)
begin
if (reset_n == 1'b0 )
begin
PC <= #1 0; // Program Counter
A <= #1 0;
TmpAddr <= #1 0;
IR <= #1 8'b00000000;
ISet <= #1 2'b00;
XY_State <= #1 2'b00;
IStatus <= #1 2'b00;
mcycles <= #1 3'b000;
do <= #1 8'b00000000;
 
ACC <= #1 8'hFF;
F <= #1 8'hFF;
Ap <= #1 8'hFF;
Fp <= #1 8'hFF;
I <= #1 0;
R <= #1 0;
SP <= #1 16'hFFFF;
Alternate <= #1 1'b0;
 
Read_To_Reg_r <= #1 5'b00000;
Arith16_r <= #1 1'b0;
BTR_r <= #1 1'b0;
Z16_r <= #1 1'b0;
ALU_Op_r <= #1 4'b0000;
Save_ALU_r <= #1 1'b0;
PreserveC_r <= #1 1'b0;
XY_Ind <= #1 1'b0;
end
else
begin
 
if (ClkEn == 1'b1 )
begin
 
ALU_Op_r <= #1 4'b0000;
Save_ALU_r <= #1 1'b0;
Read_To_Reg_r <= #1 5'b00000;
 
mcycles <= #1 mcycles_d;
 
if (IMode != 2'b11 )
begin
IStatus <= #1 IMode;
end
 
Arith16_r <= #1 Arith16;
PreserveC_r <= #1 PreserveC;
if (ISet == 2'b10 && ALU_Op[2] == 1'b0 && ALU_Op[0] == 1'b1 && mcycle == 3'b011 )
begin
Z16_r <= #1 1'b1;
end
else
begin
Z16_r <= #1 1'b0;
end
 
if (mcycle == 3'b001 && tstate[2] == 1'b0 )
begin
// mcycle == 1 && tstate == 1, 2, || 3
 
if (tstate == 2 && wait_n == 1'b1 )
begin
if (Mode < 2 )
begin
A[7:0] <= #1 R;
A[15:8] <= #1 I;
R[6:0] <= #1 R[6:0] + 1;
end
 
if (Jump == 1'b0 && Call == 1'b0 && NMICycle == 1'b0 && IntCycle == 1'b0 && ~ (Halt_FF == 1'b1 || Halt == 1'b1) )
begin
PC <= #1 PC16;
end
 
if (IntCycle == 1'b1 && IStatus == 2'b01 )
begin
IR <= #1 8'b11111111;
end
else if (Halt_FF == 1'b1 || (IntCycle == 1'b1 && IStatus == 2'b10) || NMICycle == 1'b1 )
begin
IR <= #1 8'b00000000;
end
else
begin
IR <= #1 dinst;
end
 
ISet <= #1 2'b00;
if (Prefix != 2'b00 )
begin
if (Prefix == 2'b11 )
begin
if (IR[5] == 1'b1 )
begin
XY_State <= #1 2'b10;
end
else
begin
XY_State <= #1 2'b01;
end
end
else
begin
if (Prefix == 2'b10 )
begin
XY_State <= #1 2'b00;
XY_Ind <= #1 1'b0;
end
ISet <= #1 Prefix;
end
end
else
begin
XY_State <= #1 2'b00;
XY_Ind <= #1 1'b0;
end
end // if (tstate == 2 && wait_n == 1'b1 )
 
end
else
begin
// either (mcycle > 1) OR (mcycle == 1 AND tstate > 3)
 
if (mcycle == 3'b110 )
begin
XY_Ind <= #1 1'b1;
if (Prefix == 2'b01 )
begin
ISet <= #1 2'b01;
end
end
if (T_Res == 1'b1 )
begin
BTR_r <= #1 (I_BT || I_BC || I_BTR) && ~ No_BTR;
if (Jump == 1'b1 )
begin
A[15:8] <= #1 DI_Reg;
A[7:0] <= #1 TmpAddr[7:0];
PC[15:8] <= #1 DI_Reg;
PC[7:0] <= #1 TmpAddr[7:0];
end
else if (JumpXY == 1'b1 )
begin
A <= #1 RegBusC;
PC <= #1 RegBusC;
end else if (Call == 1'b1 || RstP == 1'b1 )
begin
A <= #1 TmpAddr;
PC <= #1 TmpAddr;
end
else if (mcycle == mcycles && NMICycle == 1'b1 )
begin
A <= #1 16'b0000000001100110;
PC <= #1 16'b0000000001100110;
end
else if (mcycle == 3'b011 && IntCycle == 1'b1 && IStatus == 2'b10 )
begin
A[15:8] <= #1 I;
A[7:0] <= #1 TmpAddr[7:0];
PC[15:8] <= #1 I;
PC[7:0] <= #1 TmpAddr[7:0];
end
else
begin
case (Set_Addr_To)
aXY :
begin
if (XY_State == 2'b00 )
begin
A <= #1 RegBusC;
end
else
begin
if (NextIs_XY_Fetch == 1'b1 )
begin
A <= #1 PC;
end
else
begin
A <= #1 TmpAddr;
end
end // else: !if(XY_State == 2'b00 )
end // case: aXY
aIOA :
begin
if (Mode == 3 )
begin
// Memory map I/O on GBZ80
A[15:8] <= #1 8'hFF;
end
else if (Mode == 2 )
begin
// Duplicate I/O address on 8080
A[15:8] <= #1 DI_Reg;
end
else
begin
A[15:8] <= #1 ACC;
end
A[7:0] <= #1 DI_Reg;
end // case: aIOA
 
aSP :
begin
A <= #1 SP;
end
aBC :
begin
if (Mode == 3 && iorq_i == 1'b1 )
begin
// Memory map I/O on GBZ80
A[15:8] <= #1 8'hFF;
A[7:0] <= #1 RegBusC[7:0];
end
else
begin
A <= #1 RegBusC;
end
end // case: aBC
aDE :
begin
A <= #1 RegBusC;
end
aZI :
begin
if (Inc_WZ == 1'b1 )
begin
A <= #1 TmpAddr + 1;
end
else
begin
A[15:8] <= #1 DI_Reg;
A[7:0] <= #1 TmpAddr[7:0];
end
end // case: aZI
default :
begin
A <= #1 PC;
end
endcase // case(Set_Addr_To)
end // else: !if(mcycle == 3'b011 && IntCycle == 1'b1 && IStatus == 2'b10 )
 
Save_ALU_r <= #1 Save_ALU;
ALU_Op_r <= #1 ALU_Op;
if (I_CPL == 1'b1 )
begin
// CPL
ACC <= #1 ~ ACC;
F[Flag_Y] <= #1 ~ ACC[5];
F[Flag_H] <= #1 1'b1;
F[Flag_X] <= #1 ~ ACC[3];
F[Flag_N] <= #1 1'b1;
end
if (I_CCF == 1'b1 )
begin
// CCF
F[Flag_C] <= #1 ~ F[Flag_C];
F[Flag_Y] <= #1 ACC[5];
F[Flag_H] <= #1 F[Flag_C];
F[Flag_X] <= #1 ACC[3];
F[Flag_N] <= #1 1'b0;
end
if (I_SCF == 1'b1 )
begin
// SCF
F[Flag_C] <= #1 1'b1;
F[Flag_Y] <= #1 ACC[5];
F[Flag_H] <= #1 1'b0;
F[Flag_X] <= #1 ACC[3];
F[Flag_N] <= #1 1'b0;
end
end // if (T_Res == 1'b1 )
 
if (tstate == 2 && wait_n == 1'b1 )
begin
if (ISet == 2'b01 && mcycle == 3'b111 )
begin
IR <= #1 dinst;
end
if (JumpE == 1'b1 )
begin
PC <= #1 PC16;
end
else if (Inc_PC == 1'b1 )
begin
//PC <= #1 PC + 1;
PC <= #1 PC16;
end
if (BTR_r == 1'b1 )
begin
//PC <= #1 PC - 2;
PC <= #1 PC16;
end
if (RstP == 1'b1 )
begin
TmpAddr <= #1 { 10'h0, IR[5:3], 3'h0 };
//TmpAddr <= #1 (others =>1'b0);
//TmpAddr[5:3] <= #1 IR[5:3];
end
end
if (tstate == 3 && mcycle == 3'b110 )
begin
TmpAddr <= #1 SP16;
end
 
if ((tstate == 2 && wait_n == 1'b1) || (tstate == 4 && mcycle == 3'b001) )
begin
if (IncDec_16[2:0] == 3'b111 )
begin
SP <= #1 SP16;
end
end
 
if (LDSPHL == 1'b1 )
begin
SP <= #1 RegBusC;
end
if (ExchangeAF == 1'b1 )
begin
Ap <= #1 ACC;
ACC <= #1 Ap;
Fp <= #1 F;
F <= #1 Fp;
end
if (ExchangeRS == 1'b1 )
begin
Alternate <= #1 ~ Alternate;
end
end // else: !if(mcycle == 3'b001 && tstate(2) == 1'b0 )
 
if (tstate == 3 )
begin
if (LDZ == 1'b1 )
begin
TmpAddr[7:0] <= #1 DI_Reg;
end
if (LDW == 1'b1 )
begin
TmpAddr[15:8] <= #1 DI_Reg;
end
 
if (Special_LD[2] == 1'b1 )
begin
case (Special_LD[1:0])
2'b00 :
begin
ACC <= #1 I;
F[Flag_P] <= #1 IntE_FF2;
end
2'b01 :
begin
ACC <= #1 R;
F[Flag_P] <= #1 IntE_FF2;
end
2'b10 :
I <= #1 ACC;
default :
R <= #1 ACC;
endcase
end
end // if (tstate == 3 )
 
if ((I_DJNZ == 1'b0 && Save_ALU_r == 1'b1) || ALU_Op_r == 4'b1001 )
begin
if (Mode == 3 )
begin
F[6] <= #1 F_Out[6];
F[5] <= #1 F_Out[5];
F[7] <= #1 F_Out[7];
if (PreserveC_r == 1'b0 )
begin
F[4] <= #1 F_Out[4];
end
end
else
begin
F[7:1] <= #1 F_Out[7:1];
if (PreserveC_r == 1'b0 )
begin
F[Flag_C] <= #1 F_Out[0];
end
end
end // if ((I_DJNZ == 1'b0 && Save_ALU_r == 1'b1) || ALU_Op_r == 4'b1001 )
if (T_Res == 1'b1 && I_INRC == 1'b1 )
begin
F[Flag_H] <= #1 1'b0;
F[Flag_N] <= #1 1'b0;
if (DI_Reg[7:0] == 8'b00000000 )
begin
F[Flag_Z] <= #1 1'b1;
end
else
begin
F[Flag_Z] <= #1 1'b0;
end
F[Flag_S] <= #1 DI_Reg[7];
F[Flag_P] <= #1 ~ (^DI_Reg[7:0]);
end // if (T_Res == 1'b1 && I_INRC == 1'b1 )
 
if (tstate == 1 && Auto_Wait_t1 == 1'b0 )
begin
do <= #1 BusB;
if (I_RLD == 1'b1 )
begin
do[3:0] <= #1 BusA[3:0];
do[7:4] <= #1 BusB[3:0];
end
if (I_RRD == 1'b1 )
begin
do[3:0] <= #1 BusB[7:4];
do[7:4] <= #1 BusA[3:0];
end
end
 
if (T_Res == 1'b1 )
begin
Read_To_Reg_r[3:0] <= #1 Set_BusA_To;
Read_To_Reg_r[4] <= #1 Read_To_Reg;
if (Read_To_Acc == 1'b1 )
begin
Read_To_Reg_r[3:0] <= #1 4'b0111;
Read_To_Reg_r[4] <= #1 1'b1;
end
end
 
if (tstate == 1 && I_BT == 1'b1 )
begin
F[Flag_X] <= #1 ALU_Q[3];
F[Flag_Y] <= #1 ALU_Q[1];
F[Flag_H] <= #1 1'b0;
F[Flag_N] <= #1 1'b0;
end
if (I_BC == 1'b1 || I_BT == 1'b1 )
begin
F[Flag_P] <= #1 IncDecZ;
end
 
if ((tstate == 1 && Save_ALU_r == 1'b0 && Auto_Wait_t1 == 1'b0) ||
(Save_ALU_r == 1'b1 && ALU_Op_r != 4'b0111) )
begin
case (Read_To_Reg_r)
5'b10111 :
ACC <= #1 Save_Mux;
5'b10110 :
do <= #1 Save_Mux;
5'b11000 :
SP[7:0] <= #1 Save_Mux;
5'b11001 :
SP[15:8] <= #1 Save_Mux;
5'b11011 :
F <= #1 Save_Mux;
endcase
end // if ((tstate == 1 && Save_ALU_r == 1'b0 && Auto_Wait_t1 == 1'b0) ||...
end // if (ClkEn == 1'b1 )
end // else: !if(reset_n == 1'b0 )
end
 
//-------------------------------------------------------------------------
//
// BC('), DE('), HL('), IX && IY
//
//-------------------------------------------------------------------------
always @ (posedge clk)
begin
if (ClkEn == 1'b1 )
begin
// Bus A / Write
RegAddrA_r <= #1 { Alternate, Set_BusA_To[2:1] };
if (XY_Ind == 1'b0 && XY_State != 2'b00 && Set_BusA_To[2:1] == 2'b10 )
begin
RegAddrA_r <= #1 { XY_State[1], 2'b11 };
end
 
// Bus B
RegAddrB_r <= #1 { Alternate, Set_BusB_To[2:1] };
if (XY_Ind == 1'b0 && XY_State != 2'b00 && Set_BusB_To[2:1] == 2'b10 )
begin
RegAddrB_r <= #1 { XY_State[1], 2'b11 };
end
 
// Address from register
RegAddrC <= #1 { Alternate, Set_Addr_To[1:0] };
// Jump (HL), LD SP,HL
if ((JumpXY == 1'b1 || LDSPHL == 1'b1) )
begin
RegAddrC <= #1 { Alternate, 2'b10 };
end
if (((JumpXY == 1'b1 || LDSPHL == 1'b1) && XY_State != 2'b00) || (mcycle == 3'b110) )
begin
RegAddrC <= #1 { XY_State[1], 2'b11 };
end
 
if (I_DJNZ == 1'b1 && Save_ALU_r == 1'b1 && Mode < 2 )
begin
IncDecZ <= #1 F_Out[Flag_Z];
end
if ((tstate == 2 || (tstate == 3 && mcycle == 3'b001)) && IncDec_16[2:0] == 3'b100 )
begin
if (ID16 == 0 )
begin
IncDecZ <= #1 1'b0;
end
else
begin
IncDecZ <= #1 1'b1;
end
end
RegBusA_r <= #1 RegBusA;
end
end // always @ (posedge clk)
 
always @(/*AUTOSENSE*/Alternate or ExchangeDH or IncDec_16
or RegAddrA_r or RegAddrB_r or XY_State or mcycle or tstate)
begin
if ((tstate == 2 || (tstate == 3 && mcycle == 3'b001 && IncDec_16[2] == 1'b1)) && XY_State == 2'b00)
RegAddrA = { Alternate, IncDec_16[1:0] };
else if ((tstate == 2 || (tstate == 3 && mcycle == 3'b001 && IncDec_16[2] == 1'b1)) && IncDec_16[1:0] == 2'b10)
RegAddrA = { XY_State[1], 2'b11 };
else if (ExchangeDH == 1'b1 && tstate == 3)
RegAddrA = { Alternate, 2'b10 };
else if (ExchangeDH == 1'b1 && tstate == 4)
RegAddrA = { Alternate, 2'b01 };
else
RegAddrA = RegAddrA_r;
if (ExchangeDH == 1'b1 && tstate == 3)
RegAddrB = { Alternate, 2'b01 };
else
RegAddrB = RegAddrB_r;
end // always @ *
 
always @(/*AUTOSENSE*/ALU_Op_r or Auto_Wait_t1 or ExchangeDH
or IncDec_16 or Read_To_Reg_r or Save_ALU_r or mcycle
or tstate or wait_n)
begin
RegWEH = 1'b0;
RegWEL = 1'b0;
if ((tstate == 1 && Save_ALU_r == 1'b0 && Auto_Wait_t1 == 1'b0) ||
(Save_ALU_r == 1'b1 && ALU_Op_r != 4'b0111) )
begin
case (Read_To_Reg_r)
5'b10000 , 5'b10001 , 5'b10010 , 5'b10011 , 5'b10100 , 5'b10101 :
begin
RegWEH = ~ Read_To_Reg_r[0];
RegWEL = Read_To_Reg_r[0];
end
endcase // case(Read_To_Reg_r)
end // if ((tstate == 1 && Save_ALU_r == 1'b0 && Auto_Wait_t1 == 1'b0) ||...
 
if (ExchangeDH == 1'b1 && (tstate == 3 || tstate == 4) )
begin
RegWEH = 1'b1;
RegWEL = 1'b1;
end
 
if (IncDec_16[2] == 1'b1 && ((tstate == 2 && wait_n == 1'b1 && mcycle != 3'b001) || (tstate == 3 && mcycle == 3'b001)) )
begin
case (IncDec_16[1:0])
2'b00 , 2'b01 , 2'b10 :
begin
RegWEH = 1'b1;
RegWEL = 1'b1;
end
endcase
end
end // always @ *
 
always @(/*AUTOSENSE*/ExchangeDH or ID16 or IncDec_16 or RegBusA_r
or RegBusB or Save_Mux or mcycle or tstate)
begin
RegDIH = Save_Mux;
RegDIL = Save_Mux;
 
if (ExchangeDH == 1'b1 && tstate == 3 )
begin
RegDIH = RegBusB[15:8];
RegDIL = RegBusB[7:0];
end
else if (ExchangeDH == 1'b1 && tstate == 4 )
begin
RegDIH = RegBusA_r[15:8];
RegDIL = RegBusA_r[7:0];
end
else if (IncDec_16[2] == 1'b1 && ((tstate == 2 && mcycle != 3'b001) || (tstate == 3 && mcycle == 3'b001)) )
begin
RegDIH = ID16[15:8];
RegDIL = ID16[7:0];
end
end
 
tv80_reg i_reg
(
.clk (clk),
.CEN (ClkEn),
.WEH (RegWEH),
.WEL (RegWEL),
.AddrA (RegAddrA),
.AddrB (RegAddrB),
.AddrC (RegAddrC),
.DIH (RegDIH),
.DIL (RegDIL),
.DOAH (RegBusA[15:8]),
.DOAL (RegBusA[7:0]),
.DOBH (RegBusB[15:8]),
.DOBL (RegBusB[7:0]),
.DOCH (RegBusC[15:8]),
.DOCL (RegBusC[7:0])
);
 
//-------------------------------------------------------------------------
//
// Buses
//
//-------------------------------------------------------------------------
 
always @ (posedge clk)
begin
if (ClkEn == 1'b1 )
begin
case (Set_BusB_To)
4'b0111 :
BusB <= #1 ACC;
4'b0000 , 4'b0001 , 4'b0010 , 4'b0011 , 4'b0100 , 4'b0101 :
begin
if (Set_BusB_To[0] == 1'b1 )
begin
BusB <= #1 RegBusB[7:0];
end
else
begin
BusB <= #1 RegBusB[15:8];
end
end
4'b0110 :
BusB <= #1 DI_Reg;
4'b1000 :
BusB <= #1 SP[7:0];
4'b1001 :
BusB <= #1 SP[15:8];
4'b1010 :
BusB <= #1 8'b00000001;
4'b1011 :
BusB <= #1 F;
4'b1100 :
BusB <= #1 PC[7:0];
4'b1101 :
BusB <= #1 PC[15:8];
4'b1110 :
BusB <= #1 8'b00000000;
default :
BusB <= #1 8'hxx;
endcase
 
case (Set_BusA_To)
4'b0111 :
BusA <= #1 ACC;
4'b0000 , 4'b0001 , 4'b0010 , 4'b0011 , 4'b0100 , 4'b0101 :
begin
if (Set_BusA_To[0] == 1'b1 )
begin
BusA <= #1 RegBusA[7:0];
end
else
begin
BusA <= #1 RegBusA[15:8];
end
end
4'b0110 :
BusA <= #1 DI_Reg;
4'b1000 :
BusA <= #1 SP[7:0];
4'b1001 :
BusA <= #1 SP[15:8];
4'b1010 :
BusA <= #1 8'b00000000;
default :
BusB <= #1 8'hxx;
endcase
end
end
 
//-------------------------------------------------------------------------
//
// Generate external control signals
//
//-------------------------------------------------------------------------
always @ (posedge clk)
begin
if (reset_n == 1'b0 )
begin
rfsh_n <= #1 1'b1;
end
else
begin
if (cen == 1'b1 )
begin
if (mcycle == 3'b001 && ((tstate == 2 && wait_n == 1'b1) || tstate == 3) )
begin
rfsh_n <= #1 1'b0;
end
else
begin
rfsh_n <= #1 1'b1;
end
end
end
end
 
always @(/*AUTOSENSE*/BusAck or Halt_FF or I_DJNZ or IntCycle
or IntE_FF1 or di or iorq_i or mcycle or tstate)
begin
mc = mcycle;
ts = tstate;
DI_Reg = di;
halt_n = ~ Halt_FF;
busak_n = ~ BusAck;
intcycle_n = ~ IntCycle;
IntE = IntE_FF1;
iorq = iorq_i;
stop = I_DJNZ;
end
 
//-----------------------------------------------------------------------
//
// Syncronise inputs
//
//-----------------------------------------------------------------------
 
always @ (posedge clk)
begin : sync_inputs
 
if (reset_n == 1'b0 )
begin
BusReq_s <= #1 1'b0;
INT_s <= #1 1'b0;
NMI_s <= #1 1'b0;
Oldnmi_n <= #1 1'b0;
end
else
begin
if (cen == 1'b1 )
begin
BusReq_s <= #1 ~ busrq_n;
INT_s <= #1 ~ int_n;
if (NMICycle == 1'b1 )
begin
NMI_s <= #1 1'b0;
end
else if (nmi_n == 1'b0 && Oldnmi_n == 1'b1 )
begin
NMI_s <= #1 1'b1;
end
Oldnmi_n <= #1 nmi_n;
end
end
end
 
//-----------------------------------------------------------------------
//
// Main state machine
//
//-----------------------------------------------------------------------
 
always @ (posedge clk)
begin
if (reset_n == 1'b0 )
begin
mcycle <= #1 3'b001;
tstate <= #1 3'b000;
Pre_XY_F_M <= #1 3'b000;
Halt_FF <= #1 1'b0;
BusAck <= #1 1'b0;
NMICycle <= #1 1'b0;
IntCycle <= #1 1'b0;
IntE_FF1 <= #1 1'b0;
IntE_FF2 <= #1 1'b0;
No_BTR <= #1 1'b0;
Auto_Wait_t1 <= #1 1'b0;
Auto_Wait_t2 <= #1 1'b0;
m1_n <= #1 1'b1;
end
else
begin
if (cen == 1'b1 )
begin
if (T_Res == 1'b1 )
begin
Auto_Wait_t1 <= #1 1'b0;
end
else
begin
Auto_Wait_t1 <= #1 Auto_Wait || iorq_i;
end
Auto_Wait_t2 <= #1 Auto_Wait_t1;
No_BTR <= #1 (I_BT && (~ IR[4] || ~ F[Flag_P])) ||
(I_BC && (~ IR[4] || F[Flag_Z] || ~ F[Flag_P])) ||
(I_BTR && (~ IR[4] || F[Flag_Z]));
if (tstate == 2 )
begin
if (SetEI == 1'b1 )
begin
IntE_FF1 <= #1 1'b1;
IntE_FF2 <= #1 1'b1;
end
if (I_RETN == 1'b1 )
begin
IntE_FF1 <= #1 IntE_FF2;
end
end
if (tstate == 3 )
begin
if (SetDI == 1'b1 )
begin
IntE_FF1 <= #1 1'b0;
IntE_FF2 <= #1 1'b0;
end
end
if (IntCycle == 1'b1 || NMICycle == 1'b1 )
begin
Halt_FF <= #1 1'b0;
end
if (mcycle == 3'b001 && tstate == 2 && wait_n == 1'b1 )
begin
m1_n <= #1 1'b1;
end
if (BusReq_s == 1'b1 && BusAck == 1'b1 )
begin
end
else
begin
BusAck <= #1 1'b0;
if (tstate == 2 && wait_n == 1'b0 )
begin
end
else if (T_Res == 1'b1 )
begin
if (Halt == 1'b1 )
begin
Halt_FF <= #1 1'b1;
end
if (BusReq_s == 1'b1 )
begin
BusAck <= #1 1'b1;
end
else
begin
tstate <= #1 3'b001;
if (NextIs_XY_Fetch == 1'b1 )
begin
mcycle <= #1 3'b110;
Pre_XY_F_M <= #1 mcycle;
if (IR == 8'b00110110 && Mode == 0 )
begin
Pre_XY_F_M <= #1 3'b010;
end
end
else if ((mcycle == 3'b111) || (mcycle == 3'b110 && Mode == 1 && ISet != 2'b01) )
begin
mcycle <= #1 Pre_XY_F_M + 1;
end
else if ((mcycle == mcycles) ||
No_BTR == 1'b1 ||
(mcycle == 3'b010 && I_DJNZ == 1'b1 && IncDecZ == 1'b1) )
begin
m1_n <= #1 1'b0;
mcycle <= #1 3'b001;
IntCycle <= #1 1'b0;
NMICycle <= #1 1'b0;
if (NMI_s == 1'b1 && Prefix == 2'b00 )
begin
NMICycle <= #1 1'b1;
IntE_FF1 <= #1 1'b0;
end
else if ((IntE_FF1 == 1'b1 && INT_s == 1'b1) && Prefix == 2'b00 && SetEI == 1'b0 )
begin
IntCycle <= #1 1'b1;
IntE_FF1 <= #1 1'b0;
IntE_FF2 <= #1 1'b0;
end
end
else
begin
mcycle <= #1 mcycle + 1;
end
end
end
else
begin // verilog has no "nor" operator
if ( ~(Auto_Wait == 1'b1 && Auto_Wait_t2 == 1'b0) &&
~(IOWait == 1 && iorq_i == 1'b1 && Auto_Wait_t1 == 1'b0) )
begin
tstate <= #1 tstate + 1;
end
end
end
if (tstate == 0 )
begin
m1_n <= #1 1'b0;
end
end
end
end
 
always @(/*AUTOSENSE*/BTR_r or DI_Reg or IncDec_16 or JumpE or PC
or RegBusA or RegBusC or SP or tstate)
begin
if (JumpE == 1'b1 )
begin
PC16_B = { {8{DI_Reg[7]}}, DI_Reg };
end
else if (BTR_r == 1'b1 )
begin
PC16_B = -2;
end
else
begin
PC16_B = 1;
end
 
if (tstate == 3)
begin
SP16_A = RegBusC;
SP16_B = { {8{DI_Reg[7]}}, DI_Reg };
end
else
begin
// suspect that ID16 and SP16 could be shared
SP16_A = SP;
if (IncDec_16[3] == 1'b1)
SP16_B = -1;
else
SP16_B = 1;
end
 
if (IncDec_16[3])
ID16_B = -1;
else
ID16_B = 1;
 
ID16 = RegBusA + ID16_B;
PC16 = PC + PC16_B;
SP16 = SP16_A + SP16_B;
end // always @ *
 
always @(/*AUTOSENSE*/IntCycle or NMICycle or mcycle)
begin
Auto_Wait = 1'b0;
if (IntCycle == 1'b1 || NMICycle == 1'b1 )
begin
if (mcycle == 3'b001 )
begin
Auto_Wait = 1'b1;
end
end
end // always @ *
// synopsys dc_script_begin
// set_attribute current_design "revision" "$Id: tv80_core.v,v 1.1 2004-05-16 17:39:57 ghutchis Exp $" -type string -quiet
// synopsys dc_script_end
endmodule // T80
 
/trunk/tests/tv80_env.h
0,0 → 1,65
// Environment library
// Creates definitions of the special I/O ports used by the
// environment, as well as some utility functions to allow
// programs to print out strings in the test log.
 
#ifndef TV80_ENV_H
#define TV80_ENV_H
 
sfr at 0x80 sim_ctl_port;
sfr at 0x81 msg_port;
sfr at 0x82 timeout_port;
sfr at 0x83 max_timeout_low;
sfr at 0x84 max_timeout_high;
 
#define SC_TEST_PASSED 0x01
#define SC_TEST_FAILED 0x02
#define SC_DUMPON 0x03
#define SC_DUMPOFF 0x04
 
void print (char *string)
{
char *iter;
 
timeout_port = 0x02;
timeout_port = 0x01;
 
iter = string;
while (*iter != 0) {
msg_port = *iter++;
}
}
 
void print_num (int num)
{
int cd = 0;
int i;
char digits[8];
 
timeout_port = 0x02;
timeout_port = 0x01;
 
while (num > 0) {
digits[cd++] = (num % 10) + '0';
num /= 10;
}
for (i=cd; i>0; i--)
msg_port = digits[i-1];
}
 
void sim_ctl (unsigned char code)
{
sim_ctl_port = code;
}
 
void set_timeout (unsigned int max_timeout)
{
timeout_port = 0x02;
 
max_timeout_low = (max_timeout & 0xFF);
max_timeout_high = (max_timeout >> 8);
 
timeout_port = 0x01;
}
 
#endif
/trunk/tests/fib.c
0,0 → 1,54
// Recursively compute fibonnaci sequence, using a
// really inefficient algorithm.
// (Stack exercise test)
 
#include "tv80_env.h"
 
int answers[] = { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144,
233, 377, 610, 987, 1597, 2584, 4181 };
 
int fib (int n)
{
int rv;
timeout_port = 0x02;
 
if (n < 2) rv = n;
else rv = fib(n-1) + fib(n-2);
 
timeout_port = 0x01;
return rv;
}
 
int main ()
{
int fn, fr;
char pass;
 
set_timeout (60000);
pass = 1;
 
for (fn = 1; fn < 20; fn++) {
print ("Computing Fibonacci number ");
print_num (fn);
print ("\n");
fr = fib(fn);
print ("Number is: ");
print_num (fr);
 
if (fr == answers[fn-1]) {
print (" (correct)\n");
} else {
print (" (incorrect)\n");
print ("Correct result: ");
print_num (answers[fn-1]);
pass = 0;
print ("\n");
}
}
 
if (pass)
sim_ctl (SC_TEST_PASSED);
else
sim_ctl (SC_TEST_FAILED);
}
/trunk/tests/hello.c
0,0 → 1,23
 
sfr at 0x80 sim_ctl_port;
sfr at 0x81 msg_port;
sfr at 0x82 timeout_port;
 
void print (char *string)
{
char *iter;
 
iter = string;
while (*iter != 0) {
msg_port = *iter++;
}
}
 
int main ()
{
print ("Hello, world!\n");
 
sim_ctl_port = 0x01;
return 0;
}
 
/trunk/tests/malloc.c
0,0 → 1,39
#include <malloc.h>
 
#include "tv80_env.h"
 
#define TEST_SIZE 200
int main ()
{
char *foo;
int i;
int cksum_in, cksum_out;
 
sim_ctl (SC_DUMPON);
 
foo = malloc (TEST_SIZE);
set_timeout (30000);
 
print ("Memory allocated\n");
 
cksum_in = 0;
for (i=0; i<TEST_SIZE; i=i+1) {
cksum_in += i;
foo[i] = i;
}
 
print ("Values assigned\n");
 
cksum_out = 0;
for (i=0; i<TEST_SIZE; i++)
cksum_out += foo[i];
 
print ("Checksum computed\n");
 
if (cksum_in == cksum_out)
sim_ctl (SC_TEST_PASSED);
else
sim_ctl (SC_TEST_FAILED);
 
return 0;
}
/trunk/tests/basic_int.asm
0,0 → 1,65
.module basic_int
 
test_ctl_port = 0x80
print_port = 0x81
int_timeout_port = 0x90
 
.area BOOT_VEC
jp main
.area INT_VEC
 
int_entry:
exx
 
ld b, a
ld hl, #int_seen_str
 
print_str:
ld a, (hl)
cp #0
jp z, print_str_exit
out (print_port), a
inc hl
jp print_str
 
print_str_exit:
ld a, b
exx
 
ld h, #1
reti
 
.area _CODE
 
main:
ld h, #0
ld bc, #100
ld a, #50
out (int_timeout_port), a
 
test_timeout_loop:
ld a, #1
cp h
jp z, test_pass
dec bc
jp nz, test_timeout_loop
 
test_fail:
ld a, #2
out (test_ctl_port), a
.db 0x76 ; hlt
 
test_pass:
ld a, #1
out (test_ctl_port), a
.db 0x76 ; hlt
.area _DATA
 
int_seen_str:
.ascii "Interrupt asserted"
.db 0x0a
.db 0x00
/trunk/tests/Makefile
0,0 → 1,36
# Makefile for Z80 C/Assembly files
# Assumes that SDCC is installed parallel to TV80 root
 
SDCC_ROOT=../../sdcc
CC=$(SDCC_ROOT)/bin/sdcc -mz80
AS=$(SDCC_ROOT)/bin/as-z80
LD=$(SDCC_ROOT)/bin/link-z80
IHEX2MEM=../scripts/ihex2mem.py
LINK_OPTIONS=-- -m -j -x -b_CODE=0x0200 -b_DATA=0x8000 -k$(SDCC_ROOT)/share/sdcc/lib/z80 -k$(SDCC_ROOT)/lib/z80 -lz80
AS_LINK_OPTIONS=-bBOOT_VEC=0x0000 -bINT_VEC=0x0038
C_LINK_OPTIONS=$(SDCC_ROOT)/share/sdcc/lib/z80/crt0.o
 
%.vmem : %.ihx
$(IHEX2MEM) $^ $@
 
%.ihx : %.c
$(CC) $^
 
%.o : %.asm
$(AS) -o $*.o $^
 
%.ihx : %.o
$(LD) $(LINK_OPTIONS) $(AS_LINK_OPTIONS) -i $* $^ -e
 
clean :
rm -f *.map
rm -f *.mem
rm -f *.rel
rm -f *.rst
rm -f *.sym
rm -f *.o
rm -f *.lnk
rm -f *.ihx
rm -f *.lst
rm -f *.vmem
 
/trunk/doc/env_io_map.txt
0,0 → 1,52
 
==================================================
TV80 Microprocessor Core Environment Documentation
==================================================
 
Environment Memory Map:
 
Environment memory space is divided into a 32k ROM region and a 32k RAM
region, as follows:
 
0000-7FFF: ROM
8000-FFFF: RAM
 
Environment I/O space is allocated as follows:
 
00-0F: Unused
10-1F: Test devices
20-7F: Unused
80-8F: Environment control
A0-FF: Unused
 
The Environment control registers are:
 
80 : Simulation control
 
Write '01' to end simulation with test passed
Write '02' to end with test failed
Write '03' to turn on dumping
Write '04' to turn off dumping
 
81 : Message output
 
Write characters to this port one at a time. When the
newline ('\n', ASCII 0x0A) character is written, the
environment will print out the collected string.
 
82 : Timeout control
 
Bit[0] enables the timeout counter
Bit[1] resets the counter to 0
Timeout counter defaults to enabled at simulation start
 
83 : Max timeout [low]
84 : Max timeout [high]
 
Holds 16-bit timeout value (amount of time in clocks before
timeout error occurs).
 
90 : Interrupt countdown
 
When set, starts a countdown (in clocks) until assertion of
the INT_N signal.
/trunk/scripts/run
0,0 → 1,19
#!/usr/bin/env python
 
import sys, os
 
testname = sys.argv[1]
simulator = "cver"
 
filelist = " -f env/tb.vf"
testdef = " +incdir+env -l logs/%s.log +define+DUMPFILE_NAME=\\\"logs/%s.dump\\\" +define+PROGRAM_FILE=\\\"tests/%s.vmem\\\"" % (testname, testname, testname)
 
os.chdir ("tests")
os.system ("make %s.vmem" % testname)
os.chdir ("..")
 
command = simulator + filelist + testdef
 
print "command:",command
os.system (command)
 
trunk/scripts/run Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: trunk/scripts/ihex2mem.py =================================================================== --- trunk/scripts/ihex2mem.py (nonexistent) +++ trunk/scripts/ihex2mem.py (revision 2) @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +def ihex2mem (infile, outfile): + ifh = open (infile, 'r') + ofh = open (outfile, 'w') + + bcount = 0 + line = ifh.readline() + while (line != ''): + if (line[0] == ':'): + rlen = int(line[1:3], 16) + addr = int(line[3:7], 16) + rtyp = int(line[7:9], 16) + ptr = 9 + for i in range (0, rlen): + val = int(line[9+i*2:9+i*2+2], 16) + ofh.write ("@%02x %02x\n" % (addr+i, val)) + bcount += 1 + + line = ifh.readline() + + ifh.close() + ofh.close() + + return bcount + +def cmdline (): + import sys + + infile = sys.argv[1] + outfile = sys.argv[2] + + bc = ihex2mem (infile, outfile) + print "Converted %d bytes from %s to %s" % (bc, infile, outfile) + +if __name__ == '__main__': + cmdline() +
trunk/scripts/ihex2mem.py Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: trunk/env/async_mem.v =================================================================== --- trunk/env/async_mem.v (nonexistent) +++ trunk/env/async_mem.v (revision 2) @@ -0,0 +1,29 @@ +module async_mem (/*AUTOARG*/ + // Outputs + rd_data, + // Inputs + wr_clk, wr_data, wr_cs, addr, rd_cs + ); + + parameter asz = 15, + depth = 32768; + + input wr_clk; + input [7:0] wr_data; + input wr_cs; + + input [asz-1:0] addr; + inout [7:0] rd_data; + input rd_cs; + + reg [7:0] mem [0:depth-1]; + + always @(posedge wr_clk) + begin + if (wr_cs) + mem[addr] <= #1 wr_data; + end + + assign rd_data = (rd_cs) ? mem[addr] : {8{1'bz}}; + +endmodule // async_mem Index: trunk/env/tb.vf =================================================================== --- trunk/env/tb.vf (nonexistent) +++ trunk/env/tb.vf (revision 2) @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2003-2004 by Cisco Systems Inc. + * $Id: tb.vf,v 1.1 2004-05-16 17:39:57 ghutchis Exp $ + * All rights reserved. + * + * Author: Guy Hutchison + * + */ + +rtl/core/tv80_alu.v +rtl/core/tv80_mcode.v +rtl/core/tv80_reg.v +rtl/core/tv80_core.v +rtl/core/tv80s.v +env/tb_top.v +env/env_io.v +env/async_mem.v + Index: trunk/env/env_tasks.v =================================================================== --- trunk/env/env_tasks.v (nonexistent) +++ trunk/env/env_tasks.v (revision 2) @@ -0,0 +1,29 @@ +task test_pass; + begin + $display ("%t: --- TEST PASSED ---", $time); + #100; + $finish; + end +endtask // test_pass + +task test_fail; + begin + $display ("%t: !!! TEST FAILED !!!", $time); + #100; + $finish; + end +endtask // test_fail + +task dumpon; + begin + $dumpfile (`DUMPFILE_NAME); + $dumpvars; + end +endtask // dumpon + +task dumpoff; + begin + // ??? + end +endtask // dumpoff + Index: trunk/env/env_io.v =================================================================== --- trunk/env/env_io.v (nonexistent) +++ trunk/env/env_io.v (revision 2) @@ -0,0 +1,117 @@ + +module env_io (/*AUTOARG*/ + // Outputs + DI, + // Inputs + clk, iorq_n, rd_n, wr_n, addr, DO + ); + + input clk; + input iorq_n; + input rd_n; + input wr_n; + input [7:0] addr; + input [7:0] DO; + inout [7:0] DI; + + reg [7:0] io_data; + + reg [7:0] str_buf [0:255]; + reg io_cs; + integer buf_ptr, i; + + reg [7:0] timeout_ctl; + reg [15:0] cur_timeout; + reg [15:0] max_timeout; + + reg [7:0] int_countdown; + + assign DI = (!iorq_n & !rd_n & io_cs) ? io_data : {8{1'bz}}; + + initial + begin + io_cs = 0; + buf_ptr = 0; + cur_timeout = 0; + max_timeout = 10000; + timeout_ctl = 1; + int_countdown = 0; + end + + always @(posedge clk) + begin + if (!iorq_n & !wr_n) + case (addr) + 8'h80 : + begin + case (DO) + 1 : tb_top.test_pass; + + 2 : tb_top.test_fail; + + 3 : tb_top.dumpon; + + 4 : tb_top.dumpoff; + + default : + begin + $display ("%t: ERROR : Unknown I/O command %x", $time, DO); + end + endcase // case(DO) + end // case: :... + + 8'h81 : + begin + str_buf[buf_ptr] = DO; + buf_ptr = buf_ptr + 1; + + //$display ("%t: DEBUG : Detected write of character %x", $time, DO); + if (DO == 8'h0A) + begin + $write ("%t: PROGRAM : ", $time); + + for (i=0; i= max_timeout) + begin + $display ("%t: ERROR : Reached timeout %d cycles", $time, max_timeout); + tb_top.test_fail; + end + end // always @ (posedge clk) + + always @(posedge clk) + begin + if (int_countdown == 1) + begin + tb_top.int_n <= #1 1'b0; + int_countdown = 0; + end + else if (int_countdown > 1) + int_countdown = int_countdown - 1; + end + +endmodule // env_io Index: trunk/env/tb_top.v =================================================================== --- trunk/env/tb_top.v (nonexistent) +++ trunk/env/tb_top.v (revision 2) @@ -0,0 +1,104 @@ +module tb_top; + + reg clk; + reg reset_n; + reg wait_n; + reg int_n; + reg nmi_n; + reg busrq_n; + wire m1_n; + wire mreq_n; + wire iorq_n; + wire rd_n; + wire wr_n; + wire rfsh_n; + wire halt_n; + wire busak_n; + wire [15:0] A; + wire [7:0] di; + wire [7:0] do; + wire ram_rd_cs, ram_wr_cs, rom_rd_cs; + + always + begin + clk = 1; + #5; + clk = 0; + #5; + end + + assign rom_rd_cs = !mreq_n & !rd_n & !A[15]; + assign ram_rd_cs = !mreq_n & !rd_n & A[15]; + assign ram_wr_cs = !mreq_n & !wr_n & A[15]; + + tv80s tv80s_inst + ( + // Outputs + .m1_n (m1_n), + .mreq_n (mreq_n), + .iorq_n (iorq_n), + .rd_n (rd_n), + .wr_n (wr_n), + .rfsh_n (rfsh_n), + .halt_n (halt_n), + .busak_n (busak_n), + .A (A[15:0]), + .do (do[7:0]), + // Inputs + .reset_n (reset_n), + .clk (clk), + .wait_n (wait_n), + .int_n (int_n), + .nmi_n (nmi_n), + .busrq_n (busrq_n), + .di (di[7:0])); + + async_mem ram + ( + // Outputs + .rd_data (di), + // Inputs + .wr_clk (clk), + .wr_data (do), + .wr_cs (ram_wr_cs), + .addr (A[14:0]), + .rd_cs (ram_rd_cs)); + + async_mem rom + ( + // Outputs + .rd_data (di), + // Inputs + .wr_clk (), + .wr_data (), + .wr_cs (1'b0), + .addr (A[14:0]), + .rd_cs (rom_rd_cs)); + + env_io env_io_inst + ( + // Outputs + .DI (di[7:0]), + // Inputs + .clk (clk), + .iorq_n (iorq_n), + .rd_n (rd_n), + .wr_n (wr_n), + .addr (A[7:0]), + .DO (do[7:0])); + + initial + begin + reset_n = 0; + wait_n = 1; + int_n = 1; + nmi_n = 1; + busrq_n = 1; + $readmemh (`PROGRAM_FILE, tb_top.rom.mem); + repeat (20) @(negedge clk); + reset_n = 1; + end + +`include "env_tasks.v" + +endmodule // tb_top

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.