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 |
|