OpenCores
URL https://opencores.org/ocsvn/mcs-4/mcs-4/trunk

Subversion Repositories mcs-4

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /mcs-4/trunk/rtl/verilog/common
    from Rev 5 to Rev 6
    Reverse comparison

Rev 5 → Rev 6

/clockgen.v
0,0 → 1,119
`timescale 1ns / 1ps
`default_nettype none
////////////////////////////////////////////////////////////////////////
//
// MCS-4 common clock generator sub-module
//
// This module implements a two-phase clock generator suitable
// for use with the MCS-4 emulation.
//
// This file is part of the MCS-4 project hosted at OpenCores:
// http://www.opencores.org/cores/mcs-4/
//
// Copyright © 2012, 2021 by Reece Pollack <rrpollack@opencores.org>
//
// These materials are provided under the Creative Commons
// "Attribution-NonCommercial-ShareAlike" (CC BY-NC-SA) Public License.
// They are NOT "public domain", and are protected by copyright.
//
// This work based on materials provided by Intel Corporation and
// others under the same license. See the file doc/License for
// details of this license.
//
////////////////////////////////////////////////////////////////////////
 
module clockgen #(
parameter SYSCLK_TCY = 20, // System clock cycle time in nanoseconds
parameter EXT_CLK_PROP = 0 // External clock propagation delay in sysclk cycles
) (
input wire sysclk,
output reg clk1,
output reg clk2,
output reg clk1_ext,
output reg clk2_ext
);
 
//
// Instruction phase timing in nanoseconds
//
// These are chosen to be nicely divisible by the clock
// period from any of these three systems while giving
// timing that would be compatible with a real i4004:
// * 50ns (20 MHz) -- P170-DH replacement board
// * 20ns (50 MHz) -- Digilent Spartan-3e Starter board
// * 10ns (100 MHz) -- Digilent Atlys Spartan-6 board
//
localparam TPW = 400; // Clock high pulse width
localparam TD1 = 400; // Delay from clk1 to clk2
localparam TD2 = 200; // Delay from clk2 to clk1
 
// MCS-4 instruction phase cycle time
localparam TCY = TD1 + TPW + TD2 + TPW;
 
// Calculate counter maximum value and width
localparam CMAX = (TCY / SYSCLK_TCY) - 1;
localparam W = clog2(CMAX);
 
//
// Instruction phase timing in sysclk cycles
//
localparam SYSCLK_TPW = TPW / SYSCLK_TCY;
localparam SYSCLK_TD1 = TD1 / SYSCLK_TCY;
localparam SYSCLK_TD2 = TD2 / SYSCLK_TCY;
 
// Divide the system clock to produce basic machine cycle
localparam [W-1:0] CLOCKDIV_MAX = CMAX;
reg [W-1:0] clockdiv = 1'd0;
always @(posedge sysclk) begin
clockdiv <= (clockdiv == CLOCKDIV_MAX) ? 1'd0 : (clockdiv + 1'd1);
end
 
// Set the timing of the internal 2-phase clocks
localparam [W-1:0] CLK1_START = SYSCLK_TD2 - 1,
CLK1_END = CLK1_START + SYSCLK_TPW,
CLK2_START = CLK1_END + SYSCLK_TD1,
CLK2_END = CLK2_START + SYSCLK_TPW;
 
always @(posedge sysclk) begin
case (clockdiv)
CLK1_START: clk1 <= 1'b1;
CLK1_END: clk1 <= 1'b0;
endcase
end
 
always @(posedge sysclk) begin
case (clockdiv)
CLK2_START: clk2 <= 1'b1;
CLK2_END: clk2 <= 1'b0;
endcase
end
 
//
// Set the timing of the external 2-phase clocks
//
// It takes ~70ns for the clocks to propagate from the FPGA through the
// clock driver chip to the reconstructed i4004 CPU circuitry. To match
// the timings, this module also provides advanced clock outputs.
//
localparam [W-1:0] CLK1_EXT_START = CLK1_START - EXT_CLK_PROP,
CLK1_EXT_END = CLK1_END - EXT_CLK_PROP,
CLK2_EXT_START = CLK2_START - EXT_CLK_PROP,
CLK2_EXT_END = CLK2_END - EXT_CLK_PROP;
 
always @(posedge sysclk) begin
case (clockdiv)
CLK1_EXT_START: clk1_ext <= 1'b1;
CLK1_EXT_END: clk1_ext <= 1'b0;
endcase
end
 
always @(posedge sysclk) begin
case (clockdiv)
CLK2_EXT_START: clk2_ext <= 1'b1;
CLK2_EXT_END: clk2_ext <= 1'b0;
endcase
end
 
`include "functions.vh"
 
endmodule
/clockgen_tb.v
0,0 → 1,65
`timescale 1ns / 1ps
`default_nettype none
////////////////////////////////////////////////////////////////////////
//
// MCS-4 common clock generator testbench
//
// This module is a testbench for the two-phase clock generator module.
//
// As a testbench, it leaves much to be desired. It allows a user to
// observe the behavior of the module through simulation, but does
// not verify its proper operation. Use at your own risk.
//
// This file is part of the MCS-4 project hosted at OpenCores:
// http://www.opencores.org/cores/mcs-4/
//
// Copyright © 2012, 2021 by Reece Pollack <rrpollack@opencores.org>
//
// These materials are provided under the Creative Commons
// "Attribution-NonCommercial-ShareAlike" (CC BY-NC-SA) Public License.
// They are NOT "public domain", and are protected by copyright.
//
// This work based on materials provided by Intel Corporation and
// others under the same license. See the file doc/License for
// details of this license.
//
////////////////////////////////////////////////////////////////////////
 
module clockgen_tb;
 
parameter SYSCLK_TCY = 20;
 
// Inputs
reg sysclk;
 
// Outputs
wire clk1;
wire clk2;
wire clk1_ext;
wire clk2_ext;
 
// Instantiate the Unit Under Test (UUT)
clockgen #(
.SYSCLK_TCY (SYSCLK_TCY),
.EXT_CLK_PROP (4)
) clockgen (
.sysclk (sysclk),
.clk1 (clk1),
.clk2 (clk2),
.clk1_ext (clk1_ext),
.clk2_ext (clk2_ext)
);
 
always begin
sysclk = 1'b0;
#(SYSCLK_TCY / 2);
sysclk = 1'b1;
#(SYSCLK_TCY / 2);
end
 
initial begin
$display ("counter width (W) is %d\n", clockgen.W);
end
 
endmodule
 
/counter.v
1,18 → 1,21
`timescale 1ns / 1ps
`default_nettype none
////////////////////////////////////////////////////////////////////////
//
// 4004 Counter sub-module
//
//
// MCS-4 common counter sub-module
//
// This module emulates the counter logic found in Intel MCS-4
// integrated circuits such as the i4004 CPU.
//
// This file is part of the MCS-4 project hosted at OpenCores:
// http://www.opencores.org/cores/mcs-4/
//
 
//
//
// Copyright © 2012, 2021 by Reece Pollack <rrpollack@opencores.org>
//
// These materials are provided under the Creative Commons
// "Attribution-NonCommercial-ShareAlike" Public License. They
// are NOT "public domain" and are protected by copyright.
//
// "Attribution-NonCommercial-ShareAlike" (CC BY-NC-SA) Public License.
// They are NOT "public domain", and are protected by copyright.
//
// This work based on materials provided by Intel Corporation and
// others under the same license. See the file doc/License for
// details of this license.
19,17 → 22,34
//
////////////////////////////////////////////////////////////////////////
 
module counter(
input wire sysclk,
input wire step_a,
input wire step_b,
output reg q = 1'b0
);
module counter (
input wire sysclk,
 
reg q_n = 1'b1;
always @(posedge sysclk) begin
if (step_a) q <= ~q_n;
if (step_b) q_n <= q;
end
input wire step_a_in,
input wire step_b_in,
 
output wire step_a_out,
output wire step_b_out,
output wire q,
output wire qn
);
 
reg master = 1'b0;
reg slave = 1'b0;
always @(posedge sysclk) begin
if (step_a_in)
master <= ~slave;
end
 
always @(posedge sysclk) begin
if (step_b_in)
slave <= master;
end
 
assign step_a_out = slave;
assign step_b_out = ~slave;
 
assign q = step_a_out;
assign qn = step_b_out;
 
endmodule
/counter_tb.v
0,0 → 1,107
`timescale 1ns / 1ps
`default_nettype none
////////////////////////////////////////////////////////////////////////
//
// MCS-4 common counter testbench
//
// This module is a testbench for the counter logic found in Intel MCS-4
// integrated circuits such as the i4004 CPU.
//
// This file is part of the MCS-4 project hosted at OpenCores:
// http://www.opencores.org/cores/mcs-4/
//
// Copyright © 2012, 2021 by Reece Pollack <rrpollack@opencores.org>
//
// These materials are provided under the Creative Commons
// "Attribution-NonCommercial-ShareAlike" (CC BY-NC-SA) Public License.
// They are NOT "public domain", and are protected by copyright.
//
// This work based on materials provided by Intel Corporation and
// others under the same license. See the file doc/License for
// details of this license.
//
////////////////////////////////////////////////////////////////////////
 
module counter_tb;
 
// Inputs
reg sysclk;
reg clk1 = 1'b0;
reg clk2 = 1'b0;
wire step;
 
// Outputs
wire q0, q0n, q1, q1n, q2, q2n;
 
// Inter-module connections
wire b01a, b01b;
wire b12a, b12b;
 
// Instantiate the Unit Under Test (UUT)
counter b0 (
.step_a_in(clk1),
.step_b_in(step),
.step_a_out(b01a),
.step_b_out(b01b),
.q(q0),
.qn(q0n)
);
 
counter b1 (
.step_a_in(b01a),
.step_b_in(b01b),
.step_a_out(b12a),
.step_b_out(b12b),
.q(q1),
.qn(q1n)
);
 
counter b2 (
.step_a_in(b12a),
.step_b_in(b12b),
.step_a_out(),
.step_b_out(),
.q(q2),
.qn(q2n)
);
 
always begin
sysclk = 1'b0; #10;
sysclk = 1'b1; #10;
end
 
reg [4:0] clockdiv = 5'b0;
always @(posedge sysclk) begin
clockdiv = (clockdiv == 5'd19) ? 5'b0 : (clockdiv + 5'd1);
if (clockdiv == 5'd0 ) clk1 = 1'b1;
if (clockdiv == 5'd5 ) clk1 = 1'b0;
if (clockdiv == 5'd10) clk2 = 1'b1;
if (clockdiv == 5'd15) clk2 = 1'b0;
end
 
// Generate the 8 execution phase indicators
reg [0:7] master = 8'h00;
reg [0:7] slave = 8'h00;
reg sync_pad;
always @(*) begin
if (clk2)
master <= {~|slave[0:6], slave[0:6]};
else
sync_pad <= master[7];
 
if (clk1)
slave <= master;
end
 
wire a12 = slave[0];
wire a22 = slave[1];
wire a32 = slave[2];
wire m12 = slave[3];
wire m22 = slave[4];
wire x12 = slave[5];
wire x22 = slave[6];
wire x32 = slave[7];
 
assign step = x32 & clk2;
 
endmodule
/functions.vh
0,0 → 1,68
////////////////////////////////////////////////////////////////////////
//
// MCS-4 common useful functions
//
// This file contains a set of useful functions used by other
// MCS-4 emulation modules.
//
// This file is part of the MCS-4 project hosted at OpenCores:
// http://www.opencores.org/cores/mcs-4/
//
// Copyright © 2021 by Reece Pollack <rrpollack@opencores.org>
//
// These materials are provided under the Creative Commons
// "Attribution-NonCommercial-ShareAlike" (CC BY-NC-SA) Public License.
// They are NOT "public domain", and are protected by copyright.
//
// This work based on materials provided by Intel Corporation and
// others under the same license. See the file doc/License for
// details of this license.
//
////////////////////////////////////////////////////////////////////////
 
//
// Calculate integer ceil(log2(value))
//
// This is useful for determining the width of a register
// required to hold the specified value.
//
// The implementation of $clog2() in iSim is FUBAR. This
// performs the same function, except it actually works.
//
function integer clog2 (
input integer value
);
integer bits;
begin
value = value - 1;
for (bits = 0; value > 0; bits = bits + 1)
value = value >> 1;
clog2 = bits;
end
endfunction
 
//
// Convert Nanoseconds to Cycles
//
// This converts nanoseconds to cycles, rounded up. This
// implementation assumes SYSCLK_TCY is already defined.
//
function integer nstocy (
input integer ns
);
begin
nstocy = (ns + (SYSCLK_TCY - 1)) / SYSCLK_TCY;
end
endfunction
 
//
// Calculate a Base-2 ceiling
//
function integer ceil2 (
input integer value,
input integer step
);
begin
ceil2 = (value + (step - 1)) & ~(step - 1);
end
endfunction
/timing_generator.v
0,0 → 1,110
`timescale 1ns / 1ps
`default_nettype none
////////////////////////////////////////////////////////////////////////
//
// MCS-4 clock phase generator module
//
// This file is part of the MCS-4 project hosted at OpenCores:
// http://www.opencores.org/cores/mcs-4/
//
// Copyright © 2021 by Reece Pollack <rrpollack@opencores.org>
//
// These materials are provided under the Creative Commons
// "Attribution-NonCommercial-ShareAlike" (CC BY-NC-SA) Public License.
// They are NOT "public domain", and are protected by copyright.
//
// This work based on materials provided by Intel Corporation and
// others under the same license. See the file doc/License for
// details of this license.
//
////////////////////////////////////////////////////////////////////////
 
/*
* Generate the clock phase timing internal to the i4004 CPU
*/
module timing_generator (
input wire sysclk, // System clock
input wire clk1, // Clock phase 1
input wire clk2, // Clock phase 2
 
output reg a11,
output reg a12,
output reg a21,
output reg a22,
output reg a31,
output reg a32,
 
output reg m11,
output reg m12,
output reg m21,
output reg m22,
 
output reg x11,
output reg x12,
output reg x21,
output reg x22,
output reg x31,
output reg x32,
 
output reg sync
);
 
 
//
// Generate the cycle timing
//
always @(posedge sysclk) begin
if (clk2) begin
a11 <= ~(a12 | a22 | a32 | m12 | m22 | x12 | x22);
a21 <= a12;
a31 <= a22;
m11 <= a32;
m21 <= m12;
x11 <= m22;
x21 <= x12;
x31 <= x22;
end
end
 
always @(posedge sysclk) begin
if (clk1) begin
a12 <= a11;
a22 <= a21;
a32 <= a31;
m12 <= m11;
m22 <= m21;
x12 <= x11;
x22 <= x21;
x32 <= x31;
end
end
 
always @(posedge sysclk) begin
if (~clk2)
sync <= x31;
end
 
// This is self-initializing in hardware, but
// initialization is required for simulation to
// avoid endlessly propagating X states
initial begin
a11 = 1'b0;
a12 = 1'b0;
a21 = 1'b0;
a22 = 1'b0;
a31 = 1'b0;
a32 = 1'b0;
m11 = 1'b0;
m12 = 1'b0;
m21 = 1'b0;
m22 = 1'b0;
x11 = 1'b0;
x12 = 1'b0;
x21 = 1'b0;
x22 = 1'b0;
x31 = 1'b0;
x32 = 1'b0;
sync = 1'b0;
end
 
endmodule
/timing_recovery.v
0,0 → 1,83
`timescale 1ns / 1ps
`default_nettype none
////////////////////////////////////////////////////////////////////////
//
// MCS-4 clock phase recovery module
//
// This file is part of the MCS-4 project hosted at OpenCores:
// http://www.opencores.org/cores/mcs-4/
//
// Copyright © 2021 by Reece Pollack <rrpollack@opencores.org>
//
// These materials are provided under the Creative Commons
// "Attribution-NonCommercial-ShareAlike" (CC BY-NC-SA) Public License.
// They are NOT "public domain", and are protected by copyright.
//
// This work based on materials provided by Intel Corporation and
// others under the same license. See the file doc/License for
// details of this license.
//
////////////////////////////////////////////////////////////////////////
 
/*
* Recover the clock phase timing from the MCS-4 bus
*
* This module is for use in other component emulations
* such as the i4001 ROM and the i4002 RAM chips.
*/
module timing_recovery (
input wire sysclk, // System clock
input wire clk1, // Clock phase 1
input wire clk2, // Clock phase 2
input wire sync, // Clock sync
 
output reg a11,
output reg a12,
output reg a21,
output reg a22,
output reg a31,
output reg a32,
 
output reg m11,
output reg m12,
output reg m21,
output reg m22,
 
output reg x11,
output reg x12,
output reg x21,
output reg x22,
output reg x31,
output reg x32
);
 
//
// Recover the cycle timing
//
always @(posedge sysclk) begin
if (clk2) begin
a11 <= sync;
a21 <= a12;
a31 <= a22;
m11 <= a32;
m21 <= m12;
x11 <= m22;
x21 <= x12;
x31 <= x22;
end
end
 
always @(posedge sysclk) begin
if (clk1) begin
a12 <= a11;
a22 <= a21;
a32 <= a31;
m12 <= m11;
m22 <= m21;
x12 <= x11;
x22 <= x21;
x32 <= x31;
end
end
 
endmodule
/timing_tb.v
0,0 → 1,140
`timescale 1ns / 1ps
`default_nettype none
////////////////////////////////////////////////////////////////////////
//
// MCS-4 clock phase generator and recovery module testbench
//
// As a testbench, it leaves much to be desired. It allows a user to
// observe the behavior of the modules through simulation, but does
// not verify their proper operation. Use at your own risk.
//
// This file is part of the MCS-4 project hosted at OpenCores:
// http://www.opencores.org/cores/mcs-4/
//
// Copyright © 2021 by Reece Pollack <rrpollack@opencores.org>
//
// These materials are provided under the Creative Commons
// "Attribution-NonCommercial-ShareAlike" (CC BY-NC-SA) Public License.
// They are NOT "public domain", and are protected by copyright.
//
// This work based on materials provided by Intel Corporation and
// others under the same license. See the file doc/License for
// details of this license.
//
////////////////////////////////////////////////////////////////////////
 
module timing_tb;
 
localparam SYSCLK_TCY = 50;
 
// Shared
reg sysclk;
wire sync;
 
// Clockgen outputs
wire clk1;
wire clk2;
 
clockgen #(
.SYSCLK_TCY (SYSCLK_TCY)
) clockgen (
.sysclk (sysclk),
.clk1 (clk1),
.clk2 (clk2)
);
 
// Generater outputs
wire gen_a11;
wire gen_a12;
wire gen_a21;
wire gen_a22;
wire gen_a31;
wire gen_a32;
wire gen_m11;
wire gen_m12;
wire gen_m21;
wire gen_m22;
wire gen_x11;
wire gen_x12;
wire gen_x21;
wire gen_x22;
wire gen_x31;
wire gen_x32;
 
// Instantiate the timing generator
timing_generator generator (
.sysclk(sysclk),
.clk1(clk1),
.clk2(clk2),
.a11(gen_a11),
.a12(gen_a12),
.a21(gen_a21),
.a22(gen_a22),
.a31(gen_a31),
.a32(gen_a32),
.m11(gen_m11),
.m12(gen_m12),
.m21(gen_m21),
.m22(gen_m22),
.x11(gen_x11),
.x12(gen_x12),
.x21(gen_x21),
.x22(gen_x22),
.x31(gen_x31),
.x32(gen_x32),
.sync(sync)
);
 
// Recovery outputs
wire rec_a11;
wire rec_a12;
wire rec_a21;
wire rec_a22;
wire rec_a31;
wire rec_a32;
wire rec_m11;
wire rec_m12;
wire rec_m21;
wire rec_m22;
wire rec_x11;
wire rec_x12;
wire rec_x21;
wire rec_x22;
wire rec_x31;
wire rec_x32;
 
// Instantiate the timing recovery
timing_recovery recovery (
.sysclk(sysclk),
.clk1(clk1),
.clk2(clk2),
.sync(sync),
.a11(rec_a11),
.a12(rec_a12),
.a21(rec_a21),
.a22(rec_a22),
.a31(rec_a31),
.a32(rec_a32),
.m11(rec_m11),
.m12(rec_m12),
.m21(rec_m21),
.m22(rec_m22),
.x11(rec_x11),
.x12(rec_x12),
.x21(rec_x21),
.x22(rec_x22),
.x31(rec_x31),
.x32(rec_x32)
);
 
initial begin
// Initialize Inputs
sysclk = 0;
 
forever begin
#(SYSCLK_TCY/2) sysclk = ~sysclk;
end
end
 
endmodule
 

powered by: WebSVN 2.1.0

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