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
    from Rev 5 to Rev 6
    Reverse comparison

Rev 5 → Rev 6

/rtl/verilog/common/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
/rtl/verilog/common/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
 
/rtl/verilog/common/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
/rtl/verilog/common/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
/rtl/verilog/common/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
/rtl/verilog/common/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
/rtl/verilog/common/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
/rtl/verilog/common/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
 
/rtl/verilog/i4001/busicom.mem
0,0 → 1,1287
////////////////////////////////////////////
// busicode - Verilog memory list
// created from ..\asm\busicode.hex by hex2code.pl
// StarBoard Design
 
@0
F0
11
01
50
B0
51
5F
AD
B1
F0
51
5F
AD
1C
29
68
51
73
27
EC
F5
B3
68
F0
51
A0
F3
B3
F5
E1
66
27
EA
F5
F7
14
00
52
46
40
00
B0
EC
F8
F8
E4
27
EA
E7
50
64
27
EA
E6
34
20
A0
A5
B1
30
68
51
73
D0
E1
D1
F3
F5
FC
85
1A
00
F0
00
00
11
4F
50
B0
26
20
28
10
53
00
51
00
71
5A
60
14
4B
F7
14
57
43
02
D4
40
D4
D3
29
E2
D0
E2
C0
6C
22
20
23
EA
F6
73
6D
1A
76
F0
BC
C0
A9
14
D9
28
00
F0
51
4A
40
F7
BB
C7
63
53
19
1A
68
58
05
41
31
18
22
12
05
0C
9D
6D
3D
BD
8D
5D
2D
06
7D
4D
1D
0D
AD
A4
0E
BF
06
91
98
F1
CD
D7
FD
8A
05
61
F9
D7
D7
CA
C5
50
6A
28
07
50
64
79
B4
26
18
22
00
D1
50
65
27
EA
FC
B9
A2
F5
F7
1C
77
A9
79
CD
40
7A
14
61
B2
F5
FA
F6
B2
83
B3
D0
82
B2
50
64
77
BF
29
A2
F5
F7
14
F8
EF
F2
F7
1C
F7
EC
B9
29
A3
E0
69
29
E9
1C
7A
A2
E0
69
A9
E4
DF
E7
28
00
26
10
19
FD
C0
33
A5
F2
F2
86
B8
B6
41
0E
66
66
66
66
66
27
E9
29
E0
69
77
0E
27
EC
B3
ED
29
E5
B3
E4
C0
D4
85
B6
29
E9
27
EB
FB
E0
69
77
21
F1
C0
D4
85
B8
41
33
D4
85
B6
FA
F9
29
E8
F1
27
EB
FB
E0
69
77
35
1A
43
6D
C1
68
68
68
68
68
68
29
E0
79
4A
E4
E5
C0
68
68
29
E9
BD
E0
79
53
C0
DE
B9
AD
68
68
BD
A9
F8
F1
B9
29
E9
BD
E0
A9
1C
61
C0
68
68
29
EE
F8
F3
C1
68
68
68
68
29
EE
F6
C1
27
EE
F5
C1
66
66
66
27
E6
C0
66
66
D1
41
81
D8
41
81
A4
41
82
27
EE
F5
FA
F6
E6
C0
D4
85
B8
DE
B9
41
A2
DE
B9
BD
68
29
DF
EB
79
A2
F3
C1
AD
FB
C1
AD
F8
BD
F3
C1
D7
95
C1
DC
84
C1
A5
F6
B5
F3
C1
A4
F6
C1
D4
85
B8
29
AB
E5
C0
29
ED
BB
C0
7B
CD
6A
C0
DD
9B
F3
D0
9A
C1
42
D3
00
42
94
42
A3
42
AA
42
AE
42
B3
42
B9
42
CA
42
DE
42
E7
42
EC
42
46
44
00
51
80
51
81
51
81
2A
00
40
00
6F
6F
6F
6F
6F
6F
BF
F4
BF
7F
10
DA
51
4A
2E
FF
BA
DF
B9
29
E0
42
2C
7F
17
DF
BF
A5
42
26
D1
8F
F7
14
25
A4
BF
BE
F6
F3
DE
F6
42
26
A4
BE
29
ED
BA
ED
BB
11
2C
D2
BD
EC
F6
F7
E1
50
B0
68
6B
AB
B9
51
A2
F7
14
37
11
3F
F0
E1
E2
7D
53
2A
0C
2E
00
D8
11
4B
E1
50
B0
7B
4B
C0
50
6A
B8
DD
9F
F1
1C
5F
BA
DF
42
61
27
E9
77
77
AA
1C
68
52
8F
AF
52
8A
AE
52
8A
19
6E
D2
29
E1
50
B2
42
3F
52
8A
AA
14
83
97
F1
1C
83
DA
52
8A
A7
9B
F7
14
56
42
5C
9C
F1
1C
8F
FA
D1
F5
F5
40
65
A4
BD
26
40
27
EE
1C
A1
D8
E6
F0
51
4A
41
C6
51
0A
51
46
51
49
C0
D3
B5
FA
C1
D1
B3
BB
42
C2
52
F9
EF
E5
42
C2
52
F9
DD
9B
F1
82
BA
F7
BA
93
BB
F3
BA
99
BA
F1
C0
52
F9
A3
8B
82
BB
F7
BA
C0
D4
85
B6
27
EC
B2
29
EC
82
F6
C1
52
D6
F7
66
27
E4
DF
BD
C0
29
EC
F4
E4
C0
DB
8D
1A
F1
6E
D0
29
EB
FB
E0
79
F1
C0
27
ED
B2
29
ED
B3
C0
32
C0
30
40
4B
ED
6C
14
75
0E
D9
FC
A7
0F
FB
8D
04
02
87
EF
FC
6D
0F
7B
0F
76
46
8D
A2
3C
48
A0
73
E1
9E
32
9A
36
E5
51
51
34
29
21
51
A9
3F
52
A7
29
52
CA
A7
22
53
CF
3C
DD
A7
24
FF
85
F1
5D
CE
73
DD
5D
A7
40
8D
03
E3
E5
0E
49
52
5E
5A
A9
56
AC
4D
21
A7
51
A0
40
CF
3C
5E
5A
DD
A7
56
86
F3
FE
CA
CA
A7
67
FE
7B
6F
90
76
47
02
A7
1C
04
0C
A7
6A
0D
C2
B1
10
B4
7B
6E
9E
DF
CF
9A
CE
84
CA
5F
A7
7C
DD
53
9A
7C
A7
3C
6C
66
75
66
D9
A7
98
6C
98
75
97
A7
98
82
AE
7B
B1
AA
77
A3
FD
EB
B4
A8
F1
E9
9A
9E
A7
3C
DB
AB
FC
C6
03
BC
B0
E7
D4
B7
1E
97
BD
31
3C
31
BD
1E
2C
BC
01
0D
BF
B4
FF
B7
AC
8A
EF
82
49
D9
4A
FC
4A
7F
F1
6C
D5
75
D3
0B
46
FC
EF
FD
F1
D7
A9
DF
53
9A
E3
5F
F3
BC
5F
E7
F3
74
E8
A7
EE
00
CA
CE
ED
DD
5F
C2
B7
DA
F3
FD
02
0E
03
0C
04
0D
F1
09
FA
44
F1
09
FA
F1
20
28
11
06
50
B0
26
20
28
10
32
F0
54
50
71
11
60
14
02
F7
14
0E
30
44
02
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
51
A7
53
61
3E
65
63
44
9C
5B
55
6A
36
58
7A
5D
41
5F
85
57
98
35
A9
5B
9F
7A
96
36
59
93
2E
00
00
00
00
00
00
00
00
00
33
41
FE
41
48
41
4A
68
68
41
53
41
04
41
34
41
21
41
A2
41
9A
BD
29
ED
BB
C0
2E
6D
AB
B7
BA
F6
AB
F6
8E
BB
F7
BA
B7
F6
F3
C1
AF
B9
FA
D0
29
EB
FB
E0
79
7D
C0
AF
B9
F3
29
E9
97
12
8E
D9
E0
79
87
F0
C0
7B
96
6A
FA
C1
AF
F8
BF
C1
41
5F
00
27
E6
20
40
26
00
40
4B
41
02
41
04
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
// End of file
/rtl/verilog/i4001/i4001.v
0,0 → 1,240
`timescale 1ns / 1ps
`default_nettype none
////////////////////////////////////////////////////////////////////////
//
// MCS-4 i4001 ROM and I/O Port module
//
// This module emulates the Intel 4001 ROM and I/O chip. To make the
// most efficient use of FPGA block ram resources, the ROM storage
// is implemented using an "i4001_rom" module, which can be connected
// to multiple "i4001" modules via a rom_addr / rom_data bus.
//
// 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 i4001 #(
parameter [3:0] ROM_NUMBER = 4'd0,
parameter [3:0] IO_OUTPUT = 4'b0000,
parameter [3:0] IO_INVERT = 4'b0000,
parameter [3:0] IO_PULLUP = 4'b0000,
parameter [3:0] IO_PULLDOWN = 4'b0000
) (
input wire sysclk,
input wire clk1_pad,
input wire clk2_pad,
input wire sync_pad,
input wire poc_pad,
input wire cmrom_pad,
inout tri [3:0] data_pad,
inout wire [3:0] io_pad,
input wire clear_pad,
output wor [11:0] rom_addr,
input wire [ 7:0] rom_data
);
 
// FUTURE: Sync these to the sysclk domain
wire clk1 = clk1_pad;
wire clk2 = clk2_pad;
wire sync = sync_pad;
wire poc = poc_pad;
wire cmrom = cmrom_pad;
wire clear = clear_pad;
 
// Identify the execution phases
wire a12, a22, a32;
wire m11, m12, m21, m22;
wire x21, x22;
timing_recovery timing_recovery (
.sysclk (sysclk),
.clk1 (clk1),
.clk2 (clk2),
.sync (sync),
.a12 (a12),
.a22 (a22),
.a32 (a32),
.m11 (m11),
.m12 (m12),
.m21 (m21),
.m22 (m22),
.x21 (x21),
.x22 (x22)
);
 
// Forward declarations
wire mbusread;
wire ioread, iowrite;
wire [3:0] io_in;
reg [3:0] rom_out;
reg chipsel;
 
// Mux ROM and I/O data for output
reg [3:0] data_out;
always @(posedge sysclk) begin
if (~clk2) begin
data_out = 4'bxxxx;
if (ioread) data_out = io_in;
if (mbusread) data_out = rom_out;
end
end
 
// Latch external bus drive signal
wire n0108 = ((chipsel & (m11 | m21)) | ioread) & ~poc;
reg extbusdrive;
always @(posedge sysclk) begin
if (~clk2) begin
extbusdrive <= n0108;
end
end
 
// Drive the tristate data bus
assign data_pad = extbusdrive ? data_out : 4'bzzzz;
 
 
// Common chip number match
wire chipnum = (data_pad == ROM_NUMBER);
 
 
// =======================================
// ROM interface
// =======================================
 
// Latch the address
reg [7:0] fetch_addr;
always @(posedge sysclk) begin
if (clk2) begin
if (a12) fetch_addr[ 3:0] <= data_pad;
if (a22) fetch_addr[ 7:4] <= data_pad;
end
end
 
// Latch the chip select
always @(posedge sysclk) begin
if (a12) chipsel <= 1'b0;
if (a32 & clk2) chipsel <= cmrom & chipnum;
end
 
reg n0128;
always @(posedge sysclk) begin
if (clk1) begin
n0128 <= ioread;
end
end
assign mbusread = ~(ioread | n0128);
 
// Access the external Block RAM array
assign rom_addr = extbusdrive ? {ROM_NUMBER, fetch_addr} : 12'h000;
 
//
// Mux the ROM data for output
//
// A real i4001 muxes the ROM ouputs on M11 and M21, depending on
// inertial delays to provide the required 40ns hold time when
// changing from the upper 4 bits to the lower 4 bits.
//
// Actual measurements show the FPGA emulation of the i4001 switches
// its outputs 10-12ns after CLK2 goes low, while the re-created
// instruction pointer board needs at least 120ns hold time. Oops.
//
// By changing this mux to use M12 and M22 instead, the outputs
// are held at the correct values long enough for the IP board to
// latch the correct values.
//
always @(posedge sysclk) begin
if (m12) rom_out = rom_data[7:4];
if (m22) rom_out = rom_data[3:0];
end
 
 
// =======================================
// I/O Port interface
// =======================================
 
localparam [3:0] OPA_WRR = 4'b0010;
localparam [3:0] OPA_RDR = 4'b1010;
 
// SRC flip-flop
reg srcff;
always @(posedge sysclk) begin
if (clk2) begin
if (x22 & cmrom) srcff <= chipnum;
end
end
wire m22_srcff_cm = m22 & srcff & cmrom;
 
// Decode an I/O Read operation
reg n0161;
// always @(*) begin
// if (a12)
// n0161 <= 1'b0;
// if (clk2 & m22_srcff_cm & (data_pad == OPA_RDR))
// n0161 <= 1'b1;
// end
always @(posedge sysclk) begin
if (clk2) begin
if (a12)
n0161 <= 1'b0;
if (m22_srcff_cm & (data_pad == OPA_RDR))
n0161 <= 1'b1;
end
end
assign ioread = x21 & n0161;
 
// Decode an I/O Write operation
reg n0135;
// always @(*) begin
// if (a12)
// n0135 <= 1'b0;
// if (clk2 & m22_srcff_cm & (data_pad == OPA_WRR))
// n0135 <= 1'b1;
// end
always @(posedge sysclk) begin
if (clk2) begin
if (a12)
n0135 <= 1'b0;
if (m22_srcff_cm & (data_pad == OPA_WRR))
n0135 <= 1'b1;
end
end
assign iowrite = x22 & n0135;
 
// Latch new output data
reg [3:0] io_out;
always @(posedge sysclk) begin
if (clear | poc)
io_out <= 4'b0000;
if (clk2 & iowrite) begin
io_out <= data_pad;
end
end
 
// I/O config
generate
genvar p;
for (p = 0; p < 4; p = p + 1) begin: IO_PORTS
if (IO_OUTPUT[p]) begin: IO_OUT_CONFIG
if (IO_INVERT[p]) assign io_pad[p] = ~io_out[p];
else assign io_pad[p] = io_out[p];
end
else begin: IO_IN_CONFIG
assign io_pad[p] = 1'bz;
if (IO_PULLUP[p]) PULLUP pu(.O(io_pad[p]));
if (IO_PULLDOWN[p]) PULLDOWN pd(.O(io_pad[p]));
end
if (IO_INVERT[p]) assign io_in[p] = ~io_pad[p];
else assign io_in[p] = io_pad[p];
end
endgenerate
 
endmodule
/rtl/verilog/i4001/i4001_rom.v
0,0 → 1,52
`timescale 1ns / 1ps
`default_nettype none
////////////////////////////////////////////////////////////////////////
//
// MCS-4 i4001 shared ROM storage
//
// This module emulates the Intel 4001 ROM storage. It is separate from
// the "i4001" module to make efficient use of FPGA block ram resources.
// One i4001_rom instantiation can be connected to multiple "i4001"
// modules via a rom_addr / rom_data bus.
//
// 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 i4001_rom #(
parameter ROM_FILE = "i4001-0.mem",
parameter [3:0] ROM_NUMBER = 4'd0,
parameter ROM_SIZE = 2048
) (
input wire sysclk,
input wire [11:0] rom_addr,
output reg [ 7:0] rom_data
);
 
(* rom_style="block" *)
reg [7:0] rom_array [0:ROM_SIZE-1];
initial begin
$readmemh (ROM_FILE, rom_array);
end
 
wire [11:0] array_addr = {rom_addr[11:8] - ROM_NUMBER,
rom_addr[ 7:0]};
 
// Block RAMs have synchronous read ports
// that require a clock to read the array
always @(posedge sysclk) begin
rom_data <= rom_array[array_addr];
end
 
endmodule
/rtl/verilog/i4001/i4001_tb.v
0,0 → 1,214
`timescale 1ns / 1ps
`default_nettype none
////////////////////////////////////////////////////////////////////////
//
// MCS-4 i4001 ROM testbench
//
// This module is a testbench for the i4001 and i4001_rom modules.
//
// This testbench instantiates i4001 and i4001_rom modules, and
// and enough of the i4004 system bus logic to be able to test
// ROM access. The testbench dumps the contents of ROM in a
// textual hex dump format that can be reviewed by a human; not
// the ideal testbench operation but useful at the time.
//
// 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 i4001_tb;
 
localparam SYSCLK_TCY = 50; // 20 MHz Oscillator period in ns
// localparam SYSCLK_TCY = 20; // 50 MHz Oscillator period in ns
 
// Inputs
reg sysclk;
wire clk1;
wire clk2;
reg poc;
reg clear_pad = 1'b0;
 
wire [11:0] rom_addr;
wire [ 7:0] rom_data;
 
// Bidirs
wire [3:0] data_pad;
wire [3:0] io_pad;
 
// Generate a system clock
always begin
sysclk = 1'b0;
#(SYSCLK_TCY / 2);
sysclk = 1'b1;
#(SYSCLK_TCY / 2);
end
 
// Instantiate the 2-phase clock generator
clockgen #(
.SYSCLK_TCY (SYSCLK_TCY)
) clockgen (
.sysclk (sysclk),
.clk1 (clk1),
.clk2 (clk2)
);
 
// Timing generator outputs
wire a12;
wire a22;
wire a32;
wire m12;
wire m22;
wire x12;
wire x22;
wire x32;
wire sync;
 
// Generate the 8 execution phase indicators
timing_generator timing_generator (
.clk1 (clk1),
.clk2 (clk2),
.a12 (a12),
.a22 (a22),
.a32 (a32),
.m12 (m12),
.m22 (m22),
.x12 (x12),
.x22 (x22),
.x32 (x32),
.sync (sync)
);
 
reg [3:0] opr, opa;
always @(*) begin
if (clk2) begin
if (m12) opr <= data_pad;
if (m22) opa <= data_pad;
end
end
 
// Manage the CPU tristate buffers
reg ior = 1'b0;
reg L;
always @(*) begin
if (clk2)
L <= a32 | m12 | (x12 & (ior | poc));
end
 
wire n0702 = ~clk2;
reg n0707;
always @(*) begin
if (clk1) begin
n0707 <= L;
end
end
wire n0700 = n0707 | (L & n0702) | poc;
 
 
reg [11:0] addr;
reg [ 3:0] data_out;
always @(*) begin
if (poc)
data_out = 4'bzzzz;
else begin
(* PARALLEL_CASE *)
case (1'b1)
a12: data_out = addr[ 3:0];
a22: data_out = addr[ 7:4];
a32: data_out = addr[11:8];
m12: data_out = 4'bxxxx;
m22: data_out = 4'bxxxx;
x12: data_out = opa;
x22: data_out = 4'b1111;
x32: data_out = 4'b1111;
default: data_out = 4'bxxxx;
endcase
end
end
assign data_pad = n0700 ? 4'bzzzz : data_out;
 
// Instantiate the Units Under Test (UUT)
i4001 #(
.ROM_NUMBER (4'd0)
) rom_0 (
.sysclk (sysclk),
.clk1_pad (clk1),
.clk2_pad (clk2),
.sync_pad (sync),
.poc_pad (poc),
.cmrom_pad (a32),
.data_pad (data_pad),
.io_pad (io_pad),
.clear_pad (clear_pad),
.rom_addr (rom_addr),
.rom_data (rom_data)
);
 
i4001 #(
.ROM_NUMBER (4'd1)
) rom_1 (
.sysclk (sysclk),
.clk1_pad (clk1),
.clk2_pad (clk2),
.sync_pad (sync),
.poc_pad (poc),
.cmrom_pad (a32),
.data_pad (data_pad),
.io_pad (io_pad),
.clear_pad (clear_pad),
.rom_addr (rom_addr),
.rom_data (rom_data)
);
 
i4001_rom #(
.ROM_FILE ("busicom.mem"),
.ROM_NUMBER (4'd0)
) rom_store (
.sysclk (sysclk),
.rom_addr (rom_addr),
.rom_data (rom_data)
);
 
 
always @(posedge sync) begin
if (poc)
addr <= 12'h000;
else begin
if (addr[3:0] == 4'h0)
$write("\n@%03x", addr);
$write(" %x%x", opr, opa);
if (addr == 1279) begin
$write("\n");
$finish;
end
addr <= addr + 1'b1;
end
end
 
initial begin
// Initialize Inputs
poc = 1'b1;
clear_pad = 1'b1;
 
// Wait 3 SYNCs to reset
@(posedge sync);
@(posedge sync);
@(posedge sync);
#10;
poc = 1'b0;
clear_pad = 1'b0;
 
end
 
endmodule
 
/rtl/verilog/i4002/i4002.v
0,0 → 1,266
`timescale 1ns / 1ps
`default_nettype none
////////////////////////////////////////////////////////////////////////
//
// MCS-4 i40021 RAM and Output Port module
//
// This module emulates the Intel 4002 RAM and Output Port chip. The
// RAM storage is implemented using an "i4002_ram" module, which is
// dependent on the availability of dual-port distributed RAM.
//
// 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 i4002 #(
parameter CHIP_NUMBER = 0, // Mask and P0 config
parameter RAM_ARRAY_SIZE = 32 // Size of the RAM array
) (
input wire sysclk, // 20 MHz oscillator input
// MCS-4 system bus interface
input wire clk1, // MCS-4 Phase 1 clock
input wire clk2, // MCS-4 Phase 2 clock
input wire sync, // MCS-4 Phase synchronization
input wire reset, // MCS-4 Synchronous reset
input wire cm, // MCS-4 Command Line (bank select)
inout tri [3:0] data, // MCS-4 bidirectional data bus
 
output reg [3:0] oport, // i4002 Output port
 
// Ram array dual-port interface
input wire [4:0] ram0_addr2,
output wire [3:0] ram0_data2_out,
input wire [4:0] ram1_addr2,
output wire [3:0] ram1_data2_out,
input wire [4:0] ram2_addr2,
output wire [3:0] ram2_data2_out,
input wire [4:0] ram3_addr2,
output wire [3:0] ram3_data2_out
);
 
//
// Recover the cycle timing
//
wire a12, m12, m22, x22, x32;
timing_recovery timing_recovery (
.sysclk (sysclk),
.clk1 (clk1),
.clk2 (clk2),
.sync (sync),
.a12 (a12),
.m12 (m12),
.m22 (m22),
.x22 (x22),
.x32 (x32)
);
 
// Capture OPA during the M2 subcycle
reg io;
reg [3:0] opa;
always @(posedge sysclk) begin
if (reset) begin
io = 1'b0;
opa = 4'b0000;
end
else begin
if (clk2 & m22) begin
io = cm;
opa = data;
end
end
end
 
// Decode I/O type operations
wire wrm = io & (opa == 4'b0000);
wire wmp = io & (opa == 4'b0001);
wire wrx = io & (opa[3:2] == 2'b01);
wire rdm = io & (opa[3:2] == 2'b10) & (opa[1:0] != 2'b10);
wire rdx = io & (opa[3:2] == 2'b11);
 
// Capture the SRC address during the X22/X32 subcycles
reg ram_sel = 1'b0;
reg src_ram_sel = 1'b0;
reg [1:0] reg_num = 2'b00;
reg [3:0] char_num = 4'b0000;
always @(posedge sysclk) begin
if (reset) begin
ram_sel = 1'b0;
src_ram_sel = 1'b0;
reg_num = 2'b00;
char_num = 4'b0000;
end
else begin
if (cm & x22 & clk2) begin
ram_sel = (data[3:2] == CHIP_NUMBER);
src_ram_sel = ram_sel;
reg_num = data[1:0];
end
if (clk2 & x32 & src_ram_sel) begin
char_num = data;
end
if (a12) begin
src_ram_sel = 1'b0;
end
end
end
 
// Decode the register address
wire [4:0] reg_addr = opa[2] ? {3'b100, opa[1:0]} :
{1'b0, char_num};
wire reg_write = ram_sel & clk2 & x22 & (wrm | wrx);
wire reg0_write = reg_write & (reg_num == 2'b00);
wire reg1_write = reg_write & (reg_num == 2'b01);
wire reg2_write = reg_write & (reg_num == 2'b10);
wire reg3_write = reg_write & (reg_num == 2'b11);
 
// Latch the output port value
always @(posedge sysclk) begin
if (reset) begin
oport = 4'b0000;
end
else if (ram_sel) begin
if (clk2 & x22 & wmp)
oport = data;
end
end
 
//
// In a real i4002, the RAM array is refreshed as follows:
// 1) During the M11 subcycle, CLK1 causes all column sense
// lines to be precharged to a "high" state.
// 2) During the M12 subcycle, the refresh row counter selects
// a row to be refreshed. CLK2 causes the selected row to
// be read onto the column sense lines.
// 3) During the M22 subcycle, the selected row is rewritten
// with the data read during the M12 subcycle.
//
// The refresh row counter is 5 bits wide, and counts from 0x1f
// down to 0x00 before rolling over. The upper bit determines
// whether a "main memory" or "status" row is selected. Since
// there are 16 "main memory" rows but only four status rows,
// the status rows are refreshed four times per refresh cycle.
//
// The RAM array is written using a similar sequence:
// 1) During the X11 subcycle, CLK1 causes all column sense
// lines to be precharged to a "high" state.
// 2) During the X12 subcycle, a row is selected based on the
// most recent SRC command or the low two bits of OPA for
// status register reads and writes. CLK2 causes the
// selected row to be read onto the column sense lines.
// 3) During the X21 subcycle, if the current operation is a
// read, the data from the selected register is gated onto
// the data bus.
// 4) During the X22 subcycle, if the current operation is a
// write, the selected row is written. The previously
// selected register receives the data from the data bus,
// while the other registers in the row receive the data
// read during the X12 subcycle.
//
// When the RESET line is asserted, the RAM row read operations
// are inhibited. This causes the refresh operations to write
// zeros into the RAM. Also inhibited are the data bus gate
// signals, preventing data bus values from being written during
// any erroneous write operations.
//
reg [4:0] rfsh_addr = 5'd0;
reg [4:0] rfsh_next = 5'd0;
always @(posedge sysclk) begin
if (m12)
rfsh_addr <= rfsh_next;
if (m22)
rfsh_next <= rfsh_addr + 1'd1;
end
 
//
// Mux the RAM's write port signals
//
wire [4:0] ram_addr = reset ? rfsh_addr : reg_addr;
wire [3:0] ram_data_out = reset ? 4'h0 : data;
wire ram0_write = reset ? 1'b1 : reg0_write;
wire ram1_write = reset ? 1'b1 : reg1_write;
wire ram2_write = reset ? 1'b1 : reg2_write;
wire ram3_write = reset ? 1'b1 : reg3_write;
 
// Select the correct RAM output
wire [3:0] ram0_data_in;
wire [3:0] ram1_data_in;
wire [3:0] ram2_data_in;
wire [3:0] ram3_data_in;
reg [3:0] reg_data_in;
always @(*) begin
case (reg_num)
2'b00 : reg_data_in = ram0_data_in;
2'b01 : reg_data_in = ram1_data_in;
2'b10 : reg_data_in = ram2_data_in;
2'b11 : reg_data_in = ram3_data_in;
endcase
end
 
wire reg_read = ram_sel & x22 & (rdm | rdx);
assign data = reg_read ? reg_data_in : 4'bzzzz;
 
 
// Instantiate RAM0 array
i4002_ram #(
.RAM_ARRAY_SIZE (RAM_ARRAY_SIZE)
) ram0 (
.sysclk (sysclk),
.addr (ram_addr),
.write (ram0_write),
.data_in (ram_data_out),
.data_out (ram0_data_in),
.addr2 (ram0_addr2),
.data2_out (ram0_data2_out)
);
 
// Instantiate RAM1 array
i4002_ram #(
.RAM_ARRAY_SIZE (RAM_ARRAY_SIZE)
) ram1 (
.sysclk (sysclk),
.addr (ram_addr),
.write (ram1_write),
.data_in (ram_data_out),
.data_out (ram1_data_in),
.addr2 (ram1_addr2),
.data2_out (ram1_data2_out)
);
 
// Instantiate RAM2 array
i4002_ram #(
.RAM_ARRAY_SIZE (RAM_ARRAY_SIZE)
) ram2 (
.sysclk (sysclk),
.addr (ram_addr),
.write (ram2_write),
.data_in (ram_data_out),
.data_out (ram2_data_in),
.addr2 (ram2_addr2),
.data2_out (ram2_data2_out)
);
 
// Instantiate RAM3 array
i4002_ram #(
.RAM_ARRAY_SIZE (RAM_ARRAY_SIZE)
) ram3 (
.sysclk (sysclk),
.addr (ram_addr),
.write (ram3_write),
.data_in (ram_data_out),
.data_out (ram3_data_in),
.addr2 (ram3_addr2),
.data2_out (ram3_data2_out)
);
 
endmodule
/rtl/verilog/i4002/i4002_ram.v
0,0 → 1,74
`timescale 1ns / 1ps
`default_nettype none
////////////////////////////////////////////////////////////////////////
//
// MCS-4 i4002 RAM storage
//
// This module defines the RAM allocated to a single i4002 register,
// containing 16x4-bit "main" memory array and a 4x4-bit "status"
// array. An i4002 RAM chip contains four of these RAM register modules.
//
// This implementation allocates a single 20x4-bit dual-port
// RAM: ram_array. The "main" memory array is represented by the
// elements [0:15] of ram_array, while the "status" array is
// represented by elements [16:19].
//
// This module defines a dual-port array to allow the VFD driver access
// to the "Working Register", WR, which is stored in RAM0 register 1.
// The synthesis tools should recognize theinstantiations that do not
// need to be dual-port and trim the unneeded logic and storage.
//
// 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 i4002_ram #(
parameter RAM_ARRAY_SIZE = 32 // Size of the RAM array
) (
input wire sysclk,
input wire [4:0] addr, // Address
input wire write, // Write Enable
input wire [3:0] data_in, // Data input to write
output wire [3:0] data_out, // Data output (unregistered)
 
input wire [4:0] addr2, // 2nd port address
output wire [3:0] data2_out // 2nd port data output (unregisted)
);
 
//
// Infer a 32x4 distributed dual-port RAM
//
// The "status" characters are stored in [16:19]
//
(* ram_style="distributed" *)
reg [3:0] ram_array [0:(RAM_ARRAY_SIZE-1)];
always @(posedge sysclk) begin
if (write) begin
ram_array[addr] <= data_in;
end
end
assign data_out = ram_array[addr];
assign data2_out = ram_array[addr2];
 
`ifdef XILINX_ISIM
// Pre-initialize the RAM
genvar i;
generate
for (i = 0; i < RAM_ARRAY_SIZE; i = i + 1) begin : initial_ram
initial ram_array[i] = 4'bxxxx;
end
endgenerate
`endif
 
endmodule
/rtl/verilog/i4002/i4002_tb.v
0,0 → 1,269
`timescale 1ns / 1ps
`default_nettype none
////////////////////////////////////////////////////////////////////////
//
// MCS-4 i4001 RAM testbench
//
// This module is a testbench for the i4002 and i4002_ram modules.
//
// This testbench instantiates an i4002 RAM module, and enough of
// the i4004 system bus logic to be able to test RAM access.
//
// 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 i4002_tb;
 
localparam SYSCLK_TCY = 20; // sysclk period in nanoseconds
 
// Inputs
reg rst;
reg reset;
reg cm;
reg [4:0] ram0_addr2;
reg [4:0] ram1_addr2;
reg [4:0] ram2_addr2;
reg [4:0] ram3_addr2;
 
// Outputs
wire [3:0] oport;
wire [3:0] ram0_data2_out;
wire [3:0] ram1_data2_out;
wire [3:0] ram2_data2_out;
wire [3:0] ram3_data2_out;
 
// Bidirs
wire [3:0] data;
 
// Simulate the system clock
reg sysclk;
always begin
sysclk = 1'b0;
#(SYSCLK_TCY / 2);
sysclk = 1'b1;
#(SYSCLK_TCY / 2);
end
 
// Instantiate a 2-phase clock generator
wire clk1, clk2;
clockgen #(
.SYSCLK_TCY (SYSCLK_TCY)
) clockgen (
.sysclk (sysclk),
.clk1 (clk1),
.clk2 (clk2)
);
 
// Generate the 8 execution phase indicators
wire a12, a22, a32, m12, m22, x12, x22, x32, sync;
timing_generator timing_generator (
.clk1 (clk1),
.clk2 (clk2),
.a12 (a12),
.a22 (a22),
.a32 (a32),
.m12 (m12),
.m22 (m22),
.x12 (x12),
.x22 (x22),
.x32 (x32),
.sync (sync)
);
 
 
// Instantiate the Unit Under Test (UUT)
i4002 uut (
.sysclk (sysclk),
.clk1 (clk1),
.clk2 (clk2),
.sync (sync),
.reset (reset),
.cm (cm),
.data (data),
.oport (oport),
.ram0_addr2 (ram0_addr2),
.ram0_data2_out (ram0_data2_out),
.ram1_addr2 (ram1_addr2),
.ram1_data2_out (ram1_data2_out),
.ram2_addr2 (ram2_addr2),
.ram2_data2_out (ram2_data2_out),
.ram3_addr2 (ram3_addr2),
.ram3_data2_out (ram3_data2_out)
);
 
reg data_dir = 1'b0;
reg [3:0] data_out = 4'bxxxx;
reg [3:0] data_in = 4'bxxxx;
assign data = data_dir ? data_out : 4'bzzzz;
 
initial begin
// Initialize Inputs
rst = 1;
reset = 1;
cm = 0;
ram0_addr2 = 5'h00;
ram1_addr2 = 5'h00;
ram2_addr2 = 5'h00;
ram3_addr2 = 5'h00;
 
// Wait 100 ns for global reset to finish
#100;
rst = 0;
@(negedge sync);
reset = 0;
end
 
// Simulate enough of a i4004 CPU to access RAM
always @(*) begin
data_dir = 1'b1;
data_out = 4'bxxxx;
cm = 1'b0;
case (1'b1)
a12 : task_a12;
a22 : task_a22;
a32 : task_a32;
m12 : task_m12;
m22 : task_m22;
x12 : task_x12;
x22 : task_x22;
x32 : task_x32;
default : /* default */;
endcase
end
 
//
// i4004 simulation registers
//
//
reg [11:0] ip = 12'h000;
reg [1:0] chip_num = 2'b00;
reg [1:0] reg_num = 2'b01;
reg [3:0] char_num = 4'ha;
reg [3:0] acc;
 
reg [7:0] rom[0:'hfff];
wire [7:0] rom_data = rom[ip];
initial begin
`ifdef USE_READMEMH
$readmemh("i4002_tb.mem", rom, 0);
`else
rom[ 0] = 8'hFD; // DCL
rom[ 1] = 8'h21; // SRC R0
rom[ 2] = 8'hE9; // RDM
rom[ 3] = 8'hE0; // WRM
rom[ 4] = 8'h21; // SRC R0
rom[ 5] = 8'hE9; // RDM
rom[ 6] = 8'hE0; // WRM
rom[ 7] = 8'hFF; // HLT (sim only)
`endif
end
 
// Capture OPR during the M1 phase
reg [3:0] opr;
always @(*) begin
if (clk2 & m12)
opr = data;
end
 
// Capture OPA during the M2 phase
reg [3:0] opa;
always @(*) begin
if (clk2 & m22)
opa = data;
end
 
// Instruction decode
wire src = (opr == 4'b0010) & opa[0];
wire io = (opr == 4'b1110);
wire ior = io & opa[3];
wire iow = io & ~opa[3];
wire ag = (opr == 4'b1111);
wire iac = ag & (opa == 4'b0010);
 
always @(*) begin
if (clk2 & ior) begin
acc = data;
end
end
 
task task_a12();
begin
data_out = ip[3:0];
data_dir = 1'b1;
end
endtask : task_a12
 
task task_a22();
begin
data_out = ip[7:4];
end
endtask : task_a22
 
task task_a32();
begin
data_out = ip[11:8];
cm = 1'b1;
end
endtask : task_a32
 
task task_m12();
begin
data_out = rom_data[7:4];
end
endtask : task_m12
 
task task_m22();
begin
data_out = rom_data[3:0];
cm = io;
if (~reset) begin
ip = ip + 'd1;
end
end
endtask : task_m22
 
task task_x12();
begin
data_out = opa;
if ({opr, opa} == 8'hFF)
$stop();
end
endtask : task_x12
 
task task_x22();
begin
if (src) begin
data_out = {chip_num, reg_num};
cm = 1'b1;
end
if (iow) begin
data_out = acc + 'd1;
end
if (ior) begin
data_dir = 1'b0;
end
end
endtask : task_x22
 
task task_x32();
begin
if (src) begin
data_out = char_num;
end
end
endtask : task_x32
 
 
endmodule
/rtl/verilog/i4003/i4003.v
0,0 → 1,79
`timescale 1ns / 1ps
`default_nettype none
////////////////////////////////////////////////////////////////////////
//
// MCS-4 i4003 Shift Register
//
// This module emulates the Intel 4003 shift register chip.
//
// 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 i4003 #(
parameter SYSCLK_TCY = 20 // System clock period in nanoseconds
) (
input wire sysclk,
input wire cp,
input wire serial_in,
input wire enable,
output wire [9:0] parallel_out,
output reg serial_out
);
 
initial begin
serial_out = 1'b0;
end
 
localparam LATCH_DELAY_NS = 250;
localparam LATCH_DELAY_CY = nstocy(LATCH_DELAY_NS);
 
localparam W = clog2(LATCH_DELAY_CY);
 
reg cp_delayed = 1'b0;
reg [W-1:0] cp_delay = 0;
wire cp_edge = (cp_delay == LATCH_DELAY_CY[W-1:0]);
always @(posedge sysclk) begin
if (cp == cp_delayed) begin
cp_delay <= 0;
end
else begin
if (cp_edge) begin
cp_delay <= 0;
cp_delayed <= cp;
end
else begin
cp_delay <= cp_delay + 1'b1;
end
end
end
 
reg [9:0] shifter = 10'h000;
always @(posedge sysclk) begin
if (cp_edge & cp) begin
shifter <= {shifter[8:0], serial_in};
end
end
assign parallel_out = enable ? shifter : 10'h000;
 
always @(posedge sysclk) begin
if (cp_edge & ~cp) begin
serial_out <= shifter[9];
end
end
 
 
`include "../common/functions.vh"
 
endmodule
/rtl/verilog/i4003/i4003_tb.v
0,0 → 1,104
`timescale 1ns / 1ps
`default_nettype none
////////////////////////////////////////////////////////////////////////
//
// MCS-4 i40031 Shift Register testbench
//
// This testbench instantiates two i4003 modules, resets them, and
// shifts a single '1' bit through them.
//
// 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 i4003_tb;
 
// Inputs
reg sysclk = 1'b0;
reg cp;
reg serial_in;
reg enable;
 
// Interconnection
wire serial_chain;
 
// Outputs
wire [19:0] parallel_out;
wire serial_out;
 
// Instantiate the Unit Under Test (UUT)
i4003 #(
.SYSCLK_TCY (50)
) uut1 (
.sysclk (sysclk),
.cp (cp),
.serial_in (serial_in),
.enable (enable),
.parallel_out (parallel_out[9:0]),
.serial_out (serial_chain)
);
 
// Instantiate the Unit Under Test (UUT)
i4003 #(
.SYSCLK_TCY (50)
) uut2 (
.sysclk (sysclk),
.cp (cp),
.serial_in (serial_chain),
.enable (enable),
.parallel_out (parallel_out[19:10]),
.serial_out (serial_out)
);
 
always begin
#25 sysclk = ~sysclk;
end
 
integer i;
 
initial begin
// Initialize Inputs
cp = 1'b0;
serial_in = 1'b0;
enable = 1'b0;
 
// Wait 100 ns for global reset to finish
#100;
enable = 1'b1;
 
// Shift a 1 down the registers
shift(1'b1);
for (i = 0; i < 21; i = i + 1)
shift(1'b0);
 
$finish;
end
 
task shift(
input si
);
begin
cp = 1'b1;
#250;
serial_in = si;
#2750;
serial_in = 1'b0;
#3000;
cp = 1'b0;
#6000;
end
endtask
 
endmodule
 
/rtl/verilog/i4004/alu.v
1,18 → 1,18
`timescale 1ns / 1ps
`default_nettype none
////////////////////////////////////////////////////////////////////////
//
//
// 4004 Arithmetic Logic Unit
//
//
// 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.
20,222 → 20,222
////////////////////////////////////////////////////////////////////////
 
module alu(
input wire sysclk,
// Inputs from the Timing and I/O board
input wire a12,
input wire m12,
input wire x12,
input wire poc,
// Common 4-bit data bus
inout wire [3:0] data,
input wire sysclk,
 
// Outputs to the Instruction Decode board
output wire acc_0,
output wire add_0,
output reg cy_1,
// Inputs from the Timing and I/O board
input wire a12,
input wire m12,
input wire x12,
input wire poc,
 
// Inputs from the Instruction Decode board
input wire cma,
input wire write_acc_1,
input wire write_carry_2,
input wire read_acc_3,
input wire add_group_4,
input wire inc_group_5,
input wire sub_group_6,
input wire ior,
input wire iow,
input wire ral,
input wire rar,
input wire ope_n,
input wire daa,
input wire dcl,
input wire inc_isz,
input wire kbp,
input wire o_ib,
input wire tcs,
input wire xch,
input wire n0342,
input wire x21_clk2,
input wire x31_clk2,
input wire com_n,
// Outputs to external pins
output wire cmram0,
output wire cmram1,
output wire cmram2,
output wire cmram3,
output wire cmrom
);
// Common 4-bit data bus
inout wire [3:0] data,
 
reg [3:0] acc;
reg cy;
// Outputs to the Instruction Decode board
output wire acc_0,
output wire add_0,
output reg cy_1,
 
// Decode logic
wire n0854 = ~(~x12);
wire n0351 = ~(x21_clk2 | ~dcl);
wire n0415 = ~(x21_clk2 | ope_n);
wire add_ib = ~(x31_clk2 | ~inc_isz);
wire cy_ib = ~(x31_clk2 | ~iow);
wire acb_ib = ~((x31_clk2 | ~xch) & (x21_clk2 | ~iow));
wire n0477 = ~((~x31_clk2 & ~ior) | (a12 & ior));
wire adc_cy = ~(write_carry_2 | n0477);
wire add_acc = ~(write_acc_1 | n0477);
wire adsr = ~(x31_clk2 | ~rar);
wire adsl = ~(x31_clk2 | ~ral);
wire acc_adac = ~(~cma | n0342);
wire acc_ada = ~(read_acc_3 | n0342);
wire cy_ada = ~(add_group_4 | n0342);
wire cy_adac = ~(sub_group_6 | n0342);
// Inputs from the Instruction Decode board
input wire cma,
input wire write_acc_1,
input wire write_carry_2,
input wire read_acc_3,
input wire add_group_4,
input wire inc_group_5,
input wire sub_group_6,
input wire ior,
input wire iow,
input wire ral,
input wire rar,
input wire ope_n,
input wire daa,
input wire dcl,
input wire inc_isz,
input wire kbp,
input wire o_ib,
input wire tcs,
input wire xch,
input wire n0342,
input wire x21_clk2,
input wire x31_clk2,
input wire com_n,
 
// Latch the incoming data bus
reg [3:0] tmp; // It's the name used in simulator!
always @(posedge sysclk) begin
if (~n0342)
tmp <= data;
if (m12)
tmp <= 4'b1111;
end
// Invert some of the incoming data
reg n0893, n0891, n0889, n0887; // D3, D2, D1, D0
always @(posedge sysclk) begin
if (sub_group_6) begin
n0887 <= tmp[0];
n0889 <= ~tmp[1];
n0891 <= tmp[2];
n0893 <= ~tmp[3];
end
if (~(sub_group_6 | m12)) begin
n0887 <= ~tmp[0];
n0889 <= tmp[1];
n0891 <= ~tmp[2];
n0893 <= tmp[3];
end
end
// Outputs to external pins
output wire cmram0,
output wire cmram1,
output wire cmram2,
output wire cmram3,
output wire cmrom
);
 
// Feedback from Accumulator
reg n0873, n0872, n0871, n0870;
always @(posedge sysclk) begin
if (acc_ada)
{n0873, n0872, n0871, n0870} <= acc ^ 4'b1010;
if (acc_adac)
{n0873, n0872, n0871, n0870} <= acc ^ 4'b0101;
if (m12)
{n0873, n0872, n0871, n0870} <= 4'b1010;
end
reg [3:0] acc;
reg cy;
 
// Carry generator
wire n0546 = ~(inc_group_5 | n0342);
reg n0550;
always @(posedge sysclk) begin
if (m12) n0550 <= 1'b0;
if (n0546) n0550 <= 1'b1;
if (cy_adac) n0550 <= ~cy;
if (cy_ada) n0550 <= cy;
end
wire n0911 = ~(n0550 ? (n0887 | n0870) : (n0887 & n0870));
wire n0553 = n0911;
wire n0912 = ~(n0553 ? (n0889 | n0871) : (n0889 & n0871));
wire n0556 = n0912;
wire n0913 = ~(n0556 ? (n0891 | n0872) : (n0891 & n0872));
wire n0559 = n0913;
wire n0914 = ~(n0559 ? (n0893 | n0873) : (n0893 & n0873));
wire n0861 = n0914;
// Decode logic
wire n0854 = ~(~x12);
wire n0351 = ~(x21_clk2 | ~dcl);
wire n0415 = ~(x21_clk2 | ope_n);
wire add_ib = ~(x31_clk2 | ~inc_isz);
wire cy_ib = ~(x31_clk2 | ~iow);
wire acb_ib = ~((x31_clk2 | ~xch) & (x21_clk2 | ~iow));
wire n0477 = ~((~x31_clk2 & ~ior) | (a12 & ior));
wire adc_cy = ~(write_carry_2 | n0477);
wire add_acc = ~(write_acc_1 | n0477);
wire adsr = ~(x31_clk2 | ~rar);
wire adsl = ~(x31_clk2 | ~ral);
wire acc_adac = ~(~cma | n0342);
wire acc_ada = ~(read_acc_3 | n0342);
wire cy_ada = ~(add_group_4 | n0342);
wire cy_adac = ~(sub_group_6 | n0342);
 
// Adder
wire n0878 = ~((n0887 & n0550 & n0870) | (n0553 & (n0887 | n0870 | n0550)));
wire n0875 = ~((n0889 & n0553 & n0871) | (n0556 & (n0889 | n0871 | n0553)));
wire n0879 = ~((n0891 & n0556 & n0872) | (n0559 & (n0891 | n0872 | n0556)));
wire n0877 = ~((n0893 & n0559 & n0873) | (n0861 & (n0893 | n0873 | n0559)));
wire n0846 = ~n0878;
wire n0847 = n0875;
wire n0848 = ~n0879;
wire n0514 = n0877;
// Latch the incoming data bus
reg [3:0] tmp; // It's the name used in simulator!
always @(posedge sysclk) begin
if (~n0342)
tmp <= data;
if (m12)
tmp <= 4'b1111;
end
 
// Shifter / Accumulator and Carry
reg [3:0] acc_out; // {n0356, n0348, n0347, n0346}
wire n0803 = ~((acc_out[3] & (acc_out[2] | acc_out[1])) | cy_1);
wire n0403 = ~(~daa | n0803);
wire [3:0] acc_in = {n0514, n0848, n0847, n0846};
always @(posedge sysclk) begin
if (adsr)
{acc, cy} <= {cy_1, acc_in};
if (add_acc)
acc <= acc_in;
if (adsl)
{cy, acc} <= {acc_in, cy_1};
if (adc_cy)
cy <= n0861;
if (n0403 & n0415)
cy <= 1'b1;
// Dynamic refresh would occur during M12
end
// Accumulator output latch
always @(posedge sysclk) begin
if (n0854) begin
cy_1 <= cy;
acc_out <= acc;
end
end
assign acc_0 = ~|acc_out;
assign add_0 = ~|acc_in;
// Invert some of the incoming data
reg n0893, n0891, n0889, n0887; // D3, D2, D1, D0
always @(posedge sysclk) begin
if (sub_group_6) begin
n0887 <= tmp[0];
n0889 <= ~tmp[1];
n0891 <= tmp[2];
n0893 <= ~tmp[3];
end
if (~(sub_group_6 | m12)) begin
n0887 <= ~tmp[0];
n0889 <= tmp[1];
n0891 <= ~tmp[2];
n0893 <= tmp[3];
end
end
 
// Keyboard Process logic
wire n0378 = ~((daa & n0803) | o_ib);
wire n0345 = kbp & (acc_out == 4'b1000);
wire n0354 = kbp & (acc_out == 4'b0100);
wire n0363 = kbp & (acc_out == 4'b0010);
wire n0370 = kbp & (acc_out == 4'b0001);
wire n0377 = (kbp & (acc_out == 4'b0000)) | ~n0378;
wire n0358 = ~(n0345 | n0354 | n0363 | n0370 | n0377 | n0403);
wire n0366 = ~( n0354 | n0363 | n0370 | n0377 | tcs );
wire n0359 = ~(n0345 | n0370 | n0377 | tcs );
wire n0357 = ~(n0345 | n0363 | n0377 | n0403);
// Feedback from Accumulator
reg n0873, n0872, n0871, n0870;
always @(posedge sysclk) begin
if (acc_ada)
{n0873, n0872, n0871, n0870} <= acc ^ 4'b1010;
if (acc_adac)
{n0873, n0872, n0871, n0870} <= acc ^ 4'b0101;
if (m12)
{n0873, n0872, n0871, n0870} <= 4'b1010;
end
 
// Data output mux
reg [3:0] dout;
always @(*) begin
dout = 4'bzzzz;
if (acb_ib)
dout = acc_out;
if (add_ib)
dout = acc_in;
if (cy_ib)
dout = {3'bxxx, cy_1};
if (n0415)
dout = {n0358, n0366, n0359, n0357};
end
assign data = dout;
// Generate CMROM / CMRAMn
// This may get moved to the Timing & I/O board
// Inputs: {n0355, n0364, n0371}, n0351, poc, com_n
wire n0355 = ~acc_out[2];
wire n0364 = ~acc_out[1];
wire n0371 = ~acc_out[0];
reg n0749, n0750, n0751;
always @(posedge sysclk) begin
if (poc) begin
n0749 <= 1'b1;
n0750 <= 1'b1;
n0751 <= 1'b1;
end
else begin
if (n0351) begin
n0749 <= n0355;
n0750 <= n0364;
n0751 <= n0371;
end
end
end
// Carry generator
wire n0546 = ~(inc_group_5 | n0342);
reg n0550;
always @(posedge sysclk) begin
if (m12) n0550 <= 1'b0;
if (n0546) n0550 <= 1'b1;
if (cy_adac) n0550 <= ~cy;
if (cy_ada) n0550 <= cy;
end
wire n0911 = ~(n0550 ? (n0887 | n0870) : (n0887 & n0870));
wire n0553 = n0911;
wire n0912 = ~(n0553 ? (n0889 | n0871) : (n0889 & n0871));
wire n0556 = n0912;
wire n0913 = ~(n0556 ? (n0891 | n0872) : (n0891 & n0872));
wire n0559 = n0913;
wire n0914 = ~(n0559 ? (n0893 | n0873) : (n0893 & n0873));
wire n0861 = n0914;
 
assign cmram3 = ~(com_n | n0749);
assign cmram2 = ~(com_n | n0750);
assign cmram1 = ~(com_n | n0751);
assign cmram0 = ~(com_n | ~n0749 | ~n0750 | ~n0751);
assign cmrom = ~(com_n | poc);
// Adder
wire n0878 = ~((n0887 & n0550 & n0870) | (n0553 & (n0887 | n0870 | n0550)));
wire n0875 = ~((n0889 & n0553 & n0871) | (n0556 & (n0889 | n0871 | n0553)));
wire n0879 = ~((n0891 & n0556 & n0872) | (n0559 & (n0891 | n0872 | n0556)));
wire n0877 = ~((n0893 & n0559 & n0873) | (n0861 & (n0893 | n0873 | n0559)));
wire n0846 = ~n0878;
wire n0847 = n0875;
wire n0848 = ~n0879;
wire n0514 = n0877;
 
// Shifter / Accumulator and Carry
reg [3:0] acc_out; // {n0356, n0348, n0347, n0346}
wire n0803 = ~((acc_out[3] & (acc_out[2] | acc_out[1])) | cy_1);
wire n0403 = ~(~daa | n0803);
wire [3:0] acc_in = {n0514, n0848, n0847, n0846};
always @(posedge sysclk) begin
if (adsr)
{acc, cy} <= {cy_1, acc_in};
if (add_acc)
acc <= acc_in;
if (adsl)
{cy, acc} <= {acc_in, cy_1};
if (adc_cy)
cy <= n0861;
if (n0403 & n0415)
cy <= 1'b1;
// Dynamic refresh would occur during M12
end
 
// Accumulator output latch
always @(posedge sysclk) begin
if (n0854) begin
cy_1 <= cy;
acc_out <= acc;
end
end
assign acc_0 = ~|acc_out;
assign add_0 = ~|acc_in;
 
// Keyboard Process logic
wire n0378 = ~((daa & n0803) | o_ib);
wire n0345 = kbp & (acc_out == 4'b1000);
wire n0354 = kbp & (acc_out == 4'b0100);
wire n0363 = kbp & (acc_out == 4'b0010);
wire n0370 = kbp & (acc_out == 4'b0001);
wire n0377 = (kbp & (acc_out == 4'b0000)) | ~n0378;
wire n0358 = ~(n0345 | n0354 | n0363 | n0370 | n0377 | n0403);
wire n0366 = ~( n0354 | n0363 | n0370 | n0377 | tcs );
wire n0359 = ~(n0345 | n0370 | n0377 | tcs );
wire n0357 = ~(n0345 | n0363 | n0377 | n0403);
 
// Data output mux
reg [3:0] dout;
always @(*) begin
dout = 4'bzzzz;
if (acb_ib)
dout = acc_out;
if (add_ib)
dout = acc_in;
if (cy_ib)
dout = {3'bxxx, cy_1};
if (n0415)
dout = {n0358, n0366, n0359, n0357};
end
assign data = dout;
 
// Generate CMROM / CMRAMn
// This may get moved to the Timing & I/O board
// Inputs: {n0355, n0364, n0371}, n0351, poc, com_n
wire n0355 = ~acc_out[2];
wire n0364 = ~acc_out[1];
wire n0371 = ~acc_out[0];
reg n0749, n0750, n0751;
always @(posedge sysclk) begin
if (poc) begin
n0749 <= 1'b1;
n0750 <= 1'b1;
n0751 <= 1'b1;
end
else begin
if (n0351) begin
n0749 <= n0355;
n0750 <= n0364;
n0751 <= n0371;
end
end
end
 
assign cmram3 = ~(com_n | n0749);
assign cmram2 = ~(com_n | n0750);
assign cmram1 = ~(com_n | n0751);
assign cmram0 = ~(com_n | ~n0749 | ~n0750 | ~n0751);
assign cmrom = ~(com_n | poc);
 
endmodule
/rtl/verilog/i4004/i4004.v
1,18 → 1,18
`timescale 1ns / 1ps
`default_nettype none
////////////////////////////////////////////////////////////////////////
//
//
// 4004 CPU Integration Module
//
//
// 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.
20,270 → 20,270
////////////////////////////////////////////////////////////////////////
 
module i4004(
input wire sysclk,
input wire clk1_pad,
input wire clk2_pad,
input wire poc_pad,
input wire test_pad,
inout wire [3:0] data_pad,
output wire cmrom_pad,
output wire cmram0_pad,
output wire cmram1_pad,
output wire cmram2_pad,
output wire cmram3_pad,
output wire sync_pad
input wire sysclk,
input wire clk1_pad,
input wire clk2_pad,
input wire poc_pad,
input wire test_pad,
inout wire [3:0] data_pad,
output wire cmrom_pad,
output wire cmram0_pad,
output wire cmram1_pad,
output wire cmram2_pad,
output wire cmram3_pad,
output wire sync_pad
);
 
// Common BiDir data bus
wire [3:0] data;
// Common BiDir data bus
wire [3:0] data;
 
// Timing and I/O Board Outputs
wire clk1;
wire clk2;
wire a12;
wire a22;
wire a32;
wire m12;
wire m22;
wire x12;
wire x22;
wire x32;
wire gate;
wire poc; // Clean POC_PAD
wire n0432; // Clean TEST_PAD
// Timing and I/O Board Outputs
wire clk1;
wire clk2;
wire a12;
wire a22;
wire a32;
wire m12;
wire m22;
wire x12;
wire x22;
wire x32;
wire gate;
wire poc; // Clean POC_PAD
wire n0432; // Clean TEST_PAD
 
// Outputs from the Instruction Decode board
wire jcn_isz;
wire jin_fin;
wire jun_jms;
wire cn_n;
wire bbl;
wire jms;
wire sc;
wire dc;
wire n0636;
wire sc_m22_clk2;
wire fin_fim_src_jin;
wire inc_isz_add_sub_xch_ld;
wire inc_isz_xch;
wire opa0_n;
wire cma;
wire write_acc_1;
wire write_carry_2;
wire read_acc_3;
wire add_group_4;
wire inc_group_5;
wire sub_group_6;
wire ior;
wire iow;
wire ral;
wire rar;
wire ope_n;
wire daa;
wire dcl;
wire inc_isz;
wire kbp;
wire o_ib;
wire tcs;
wire xch;
wire n0342;
wire x21_clk2;
wire x31_clk2;
wire com_n;
// Outputs from the Instruction Decode board
wire jcn_isz;
wire jin_fin;
wire jun_jms;
wire cn_n;
wire bbl;
wire jms;
wire sc;
wire dc;
wire n0636;
wire sc_m22_clk2;
wire fin_fim_src_jin;
wire inc_isz_add_sub_xch_ld;
wire inc_isz_xch;
wire opa0_n;
wire cma;
wire write_acc_1;
wire write_carry_2;
wire read_acc_3;
wire add_group_4;
wire inc_group_5;
wire sub_group_6;
wire ior;
wire iow;
wire ral;
wire rar;
wire ope_n;
wire daa;
wire dcl;
wire inc_isz;
wire kbp;
wire o_ib;
wire tcs;
wire xch;
wire n0342;
wire x21_clk2;
wire x31_clk2;
wire com_n;
 
// Outputs from the ALU board
wire acc_0;
wire add_0;
wire cy_1;
wire cmram0;
wire cmram1;
wire cmram2;
wire cmram3;
wire cmrom;
// Outputs from the ALU board
wire acc_0;
wire add_0;
wire cy_1;
wire cmram0;
wire cmram1;
wire cmram2;
wire cmram3;
wire cmrom;
 
// Instantiate the Timing and I/O board
timing_io tio_board (
.sysclk(sysclk),
.clk1_pad(clk1_pad),
.clk2_pad(clk2_pad),
.poc_pad(poc_pad),
.ior(ior),
.clk1(clk1),
.clk2(clk2),
.a12(a12),
.a22(a22),
.a32(a32),
.m12(m12),
.m22(m22),
.x12(x12),
.x22(x22),
.x32(x32),
.gate(gate),
.poc(poc),
.data(data),
.data_pad(data_pad),
.test_pad(test_pad),
.n0432(n0432),
.sync_pad(sync_pad),
.cmrom(cmrom),
.cmrom_pad(cmrom_pad),
.cmram0(cmram0),
.cmram0_pad(cmram0_pad),
.cmram1(cmram1),
.cmram1_pad(cmram1_pad),
.cmram2(cmram2),
.cmram2_pad(cmram2_pad),
.cmram3(cmram3),
.cmram3_pad(cmram3_pad)
);
// Instantiate the Timing and I/O board
timing_io tio_board (
.sysclk(sysclk),
.clk1_pad(clk1_pad),
.clk2_pad(clk2_pad),
.poc_pad(poc_pad),
.ior(ior),
.clk1(clk1),
.clk2(clk2),
.a12(a12),
.a22(a22),
.a32(a32),
.m12(m12),
.m22(m22),
.x12(x12),
.x22(x22),
.x32(x32),
.gate(gate),
.poc(poc),
.data(data),
.data_pad(data_pad),
.test_pad(test_pad),
.n0432(n0432),
.sync_pad(sync_pad),
.cmrom(cmrom),
.cmrom_pad(cmrom_pad),
.cmram0(cmram0),
.cmram0_pad(cmram0_pad),
.cmram1(cmram1),
.cmram1_pad(cmram1_pad),
.cmram2(cmram2),
.cmram2_pad(cmram2_pad),
.cmram3(cmram3),
.cmram3_pad(cmram3_pad)
);
 
// Instantiate the Instruction Decode board
instruction_decode id_board (
.sysclk(sysclk),
.clk1(clk1),
.clk2(clk2),
.a22(a22),
.m12(m12),
.m22(m22),
.x12(x12),
.x22(x22),
.x32(x32),
.poc(poc),
.n0432(n0432),
.data(data),
.jcn_isz(jcn_isz),
.jin_fin(jin_fin),
.jun_jms(jun_jms),
.cn_n(cn_n),
.bbl(bbl),
.jms(jms),
.sc(sc),
.dc(dc),
.n0636(n0636),
.sc_m22_clk2(sc_m22_clk2),
.fin_fim_src_jin(fin_fim_src_jin),
.inc_isz_add_sub_xch_ld(inc_isz_add_sub_xch_ld),
.inc_isz_xch(inc_isz_xch),
.opa0_n(opa0_n),
.acc_0(acc_0),
.add_0(add_0),
.cy_1(cy_1),
.cma(cma),
.write_acc_1(write_acc_1),
.write_carry_2(write_carry_2),
.read_acc_3(read_acc_3),
.add_group_4(add_group_4),
.inc_group_5(inc_group_5),
.sub_group_6(sub_group_6),
.ior(ior),
.iow(iow),
.ral(ral),
.rar(rar),
.ope_n(ope_n),
.daa(daa),
.dcl(dcl),
.inc_isz(inc_isz),
.kbp(kbp),
.o_ib(o_ib),
.tcs(tcs),
.xch(xch),
.n0342(n0342),
.x21_clk2(x21_clk2),
.x31_clk2(x31_clk2),
.com_n(com_n)
);
// Instantiate the Instruction Decode board
instruction_decode id_board (
.sysclk(sysclk),
.clk1(clk1),
.clk2(clk2),
.a22(a22),
.m12(m12),
.m22(m22),
.x12(x12),
.x22(x22),
.x32(x32),
.poc(poc),
.n0432(n0432),
.data(data),
.jcn_isz(jcn_isz),
.jin_fin(jin_fin),
.jun_jms(jun_jms),
.cn_n(cn_n),
.bbl(bbl),
.jms(jms),
.sc(sc),
.dc(dc),
.n0636(n0636),
.sc_m22_clk2(sc_m22_clk2),
.fin_fim_src_jin(fin_fim_src_jin),
.inc_isz_add_sub_xch_ld(inc_isz_add_sub_xch_ld),
.inc_isz_xch(inc_isz_xch),
.opa0_n(opa0_n),
.acc_0(acc_0),
.add_0(add_0),
.cy_1(cy_1),
.cma(cma),
.write_acc_1(write_acc_1),
.write_carry_2(write_carry_2),
.read_acc_3(read_acc_3),
.add_group_4(add_group_4),
.inc_group_5(inc_group_5),
.sub_group_6(sub_group_6),
.ior(ior),
.iow(iow),
.ral(ral),
.rar(rar),
.ope_n(ope_n),
.daa(daa),
.dcl(dcl),
.inc_isz(inc_isz),
.kbp(kbp),
.o_ib(o_ib),
.tcs(tcs),
.xch(xch),
.n0342(n0342),
.x21_clk2(x21_clk2),
.x31_clk2(x31_clk2),
.com_n(com_n)
);
 
// Instantiate the ALU board
alu alu_board (
.sysclk(sysclk),
.a12(a12),
.m12(m12),
.x12(x12),
.poc(poc),
.data(data),
.acc_0(acc_0),
.add_0(add_0),
.cy_1(cy_1),
.cma(cma),
.write_acc_1(write_acc_1),
.write_carry_2(write_carry_2),
.read_acc_3(read_acc_3),
.add_group_4(add_group_4),
.inc_group_5(inc_group_5),
.sub_group_6(sub_group_6),
.ior(ior),
.iow(iow),
.ral(ral),
.rar(rar),
.ope_n(ope_n),
.daa(daa),
.dcl(dcl),
.inc_isz(inc_isz),
.kbp(kbp),
.o_ib(o_ib),
.tcs(tcs),
.xch(xch),
.n0342(n0342),
.x21_clk2(x21_clk2),
.x31_clk2(x31_clk2),
.com_n(com_n),
.cmram0(cmram0),
.cmram1(cmram1),
.cmram2(cmram2),
.cmram3(cmram3),
.cmrom(cmrom)
);
// Instantiate the ALU board
alu alu_board (
.sysclk(sysclk),
.a12(a12),
.m12(m12),
.x12(x12),
.poc(poc),
.data(data),
.acc_0(acc_0),
.add_0(add_0),
.cy_1(cy_1),
.cma(cma),
.write_acc_1(write_acc_1),
.write_carry_2(write_carry_2),
.read_acc_3(read_acc_3),
.add_group_4(add_group_4),
.inc_group_5(inc_group_5),
.sub_group_6(sub_group_6),
.ior(ior),
.iow(iow),
.ral(ral),
.rar(rar),
.ope_n(ope_n),
.daa(daa),
.dcl(dcl),
.inc_isz(inc_isz),
.kbp(kbp),
.o_ib(o_ib),
.tcs(tcs),
.xch(xch),
.n0342(n0342),
.x21_clk2(x21_clk2),
.x31_clk2(x31_clk2),
.com_n(com_n),
.cmram0(cmram0),
.cmram1(cmram1),
.cmram2(cmram2),
.cmram3(cmram3),
.cmrom(cmrom)
);
 
// Instantiate the Instruction Pointer board
instruction_pointer ip_board (
.sysclk(sysclk),
.clk1(clk1),
.clk2(clk2),
.a12(a12),
.a22(a22),
.a32(a32),
.m12(m12),
.m22(m22),
.x12(x12),
.x22(x22),
.x32(x32),
.poc(poc),
.m12_m22_clk1_m11_m12(gate),
.data(data),
.jcn_isz(jcn_isz),
.jin_fin(jin_fin),
.jun_jms(jun_jms),
.cn_n(cn_n),
.bbl(bbl),
.jms(jms),
.sc(sc),
.dc(dc)
);
// Instantiate the Instruction Pointer board
instruction_pointer ip_board (
.sysclk(sysclk),
.clk1(clk1),
.clk2(clk2),
.a12(a12),
.a22(a22),
.a32(a32),
.m12(m12),
.m22(m22),
.x12(x12),
.x22(x22),
.x32(x32),
.poc(poc),
.m12_m22_clk1_m11_m12(gate),
.data(data),
.jcn_isz(jcn_isz),
.jin_fin(jin_fin),
.jun_jms(jun_jms),
.cn_n(cn_n),
.bbl(bbl),
.jms(jms),
.sc(sc),
.dc(dc)
);
 
// Instantiate the Scratchpad board
scratchpad sp_board (
.sysclk(sysclk),
.clk1(clk1),
.clk2(clk2),
.a12(a12),
.a22(a22),
.a32(a32),
.m12(m12),
.m22(m22),
.x12(x12),
.x22(x22),
.x32(x32),
.poc(poc),
.m12_m22_clk1_m11_m12(gate),
.data(data),
.n0636(n0636),
.sc_m22_clk2(sc_m22_clk2),
.fin_fim_src_jin(fin_fim_src_jin),
.inc_isz_add_sub_xch_ld(inc_isz_add_sub_xch_ld),
.inc_isz_xch(inc_isz_xch),
.opa0_n(opa0_n),
.sc(sc),
.dc(dc)
);
// Instantiate the Scratchpad board
scratchpad sp_board (
.sysclk(sysclk),
.clk1(clk1),
.clk2(clk2),
.a12(a12),
.a22(a22),
.a32(a32),
.m12(m12),
.m22(m22),
.x12(x12),
.x22(x22),
.x32(x32),
.poc(poc),
.m12_m22_clk1_m11_m12(gate),
.data(data),
.n0636(n0636),
.sc_m22_clk2(sc_m22_clk2),
.fin_fim_src_jin(fin_fim_src_jin),
.inc_isz_add_sub_xch_ld(inc_isz_add_sub_xch_ld),
.inc_isz_xch(inc_isz_xch),
.opa0_n(opa0_n),
.sc(sc),
.dc(dc)
);
 
endmodule
/rtl/verilog/i4004/i4004_tb.v
0,0 → 1,174
`timescale 1ns / 1ps
`default_nettype none
////////////////////////////////////////////////////////////////////////
//
// MCS-4 i4004 CPU testbench
//
// This module is a testbench for the i4004 and related modules.
//
// This testbench instantiates an i4004 CPU module, i4001 and
// i4001_rom ROM modules, and an i4002 RAM module, so that the
// simulation can be compared with that of Lagos Kintle's software
// emulator.
//
// 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 i4004_tb;
 
localparam SYSCLK_TCY = 50; // 20 MHz Oscillator period in ns
// localparam SYSCLK_TCY = 20; // 50 MHz Oscillator period in ns
 
// Inputs
reg sysclk = 1'b0;
reg poc_pad = 1'b1;
reg test_pad = 1'b1;
reg clear_pad = 1'b0;
wire clk1_pad;
wire clk2_pad;
 
// Outputs
wire cmrom_pad;
wire cmram0_pad;
wire cmram1_pad;
wire cmram2_pad;
wire cmram3_pad;
wire sync_pad;
 
// Bidirs
wire [3:0] data_pad;
wire [3:0] io_pad;
 
// Generate a system clock
always begin
sysclk = 1'b0;
#(SYSCLK_TCY / 2);
sysclk = 1'b1;
#(SYSCLK_TCY / 2);
end
 
// Instantiate the 2-phase clock generator
clockgen #(
.SYSCLK_TCY (SYSCLK_TCY)
) clockgen (
.sysclk (sysclk),
.clk1 (clk1_pad),
.clk2 (clk2_pad)
);
 
// Instantiate a 4001 ROM chip
wire [11:0] rom_addr;
wire [ 7:0] rom_data;
i4001 #(
.ROM_NUMBER(4'd0),
.IO_OUTPUT(4'b1111)
) rom_0 (
.sysclk(sysclk),
.clk1_pad(clk1_pad),
.clk2_pad(clk2_pad),
.sync_pad(sync_pad),
.poc_pad(poc_pad),
.cmrom_pad(cmrom_pad),
.data_pad(data_pad),
.io_pad(io_pad),
.clear_pad(clear_pad),
.rom_addr(rom_addr),
.rom_data(rom_data)
);
 
i4001_rom #(
.ROM_NUMBER(4'd0)
) rom_store (
.sysclk(sysclk),
.rom_addr(rom_addr),
.rom_data(rom_data)
);
 
// Instantiate a 4002 RAM chip
wire [3:0] oport;
i4002 ram_0 (
.sysclk (sysclk),
.clk1 (clk1_pad),
.clk2 (clk2_pad),
.sync (sync_pad),
.reset (poc_pad),
.cm (cmram0_pad),
.data (data_pad),
.oport (oport),
.ram0_addr2 (5'h00),
.ram0_data2_out (),
.ram1_addr2 (5'h00),
.ram1_data2_out (),
.ram2_addr2 (5'h00),
.ram2_data2_out (),
.ram3_addr2 (5'h00),
.ram3_data2_out ()
);
 
// Instantiate the Unit Under Test (UUT)
i4004 i4004 (
.clk1_pad(clk1_pad),
.clk2_pad(clk2_pad),
.poc_pad(poc_pad),
.test_pad(test_pad),
.data_pad(data_pad),
.cmrom_pad(cmrom_pad),
.cmram0_pad(cmram0_pad),
.cmram1_pad(cmram1_pad),
.cmram2_pad(cmram2_pad),
.cmram3_pad(cmram3_pad),
.sync_pad(sync_pad)
);
 
// Simplify access to internal registers
wire [3:0] acc = i4004.alu_board.acc;
wire cy = i4004.alu_board.cy;
 
wire [7:0] r0r1 = i4004.sp_board.dram_array[0];
wire [7:0] r2r3 = i4004.sp_board.dram_array[1];
wire [7:0] r4r5 = i4004.sp_board.dram_array[2];
wire [7:0] r6r7 = i4004.sp_board.dram_array[3];
wire [7:0] r8r9 = i4004.sp_board.dram_array[4];
wire [7:0] rarb = i4004.sp_board.dram_array[5];
wire [7:0] rcrd = i4004.sp_board.dram_array[6];
wire [7:0] rerf = i4004.sp_board.dram_array[7];
 
wire [11:0] ip0 = i4004.ip_board.dram_array[0];
wire [11:0] ip1 = i4004.ip_board.dram_array[1];
wire [11:0] ip2 = i4004.ip_board.dram_array[2];
wire [11:0] ip3 = i4004.ip_board.dram_array[3];
wire [1:0] ptr = i4004.ip_board.addr_ptr;
 
// Count cycles to make it easier to sync with the analyzer
integer cycle = 1;
always @(posedge clk1_pad or negedge clk1_pad or
posedge clk2_pad or negedge clk2_pad) begin
cycle = cycle + 1;
if (cycle == 1100) begin
// Bring us out of reset
poc_pad = 1'b0;
end
end
 
// initial begin
// // Wait for 33 SYNCs to allow the i4002 RAMs to initialize
// repeat (33)
// @(posedge sync_pad);
 
// // Bring us out of reset
// poc_pad = 1'b0;
// end
 
endmodule
/rtl/verilog/i4004/instruction_decode.v
1,18 → 1,18
`timescale 1ns / 1ps
`default_nettype none
////////////////////////////////////////////////////////////////////////
//
//
// 4004 Instruction Decoder
//
//
// 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.
20,239 → 20,239
////////////////////////////////////////////////////////////////////////
 
module instruction_decode(
input wire sysclk, // 50 MHz FPGA clock
// Inputs from the Timing and I/O board
input wire clk1,
input wire clk2,
input wire a22,
input wire m12,
input wire m22,
input wire x12,
input wire x22,
input wire x32,
input wire poc, // Power-On Clear (reset)
input wire n0432, // Conditioned TEST_PAD
input wire sysclk, // 50 MHz FPGA clock
 
// Common 4-bit data bus
inout wire [3:0] data,
// Inputs from the Timing and I/O board
input wire clk1,
input wire clk2,
input wire a22,
input wire m12,
input wire m22,
input wire x12,
input wire x22,
input wire x32,
input wire poc, // Power-On Clear (reset)
input wire n0432, // Conditioned TEST_PAD
 
// These drive the Instruction Pointer (IP) board
output wire jcn_isz, // JCN+ISZ
output wire jin_fin, // JIN+FIN
output wire jun_jms, // JUN+JMS
output wire cn_n, // ~CN
output wire bbl, // BBL
output wire jms, // JMS
// Outputs to both the IP and SP boards
output wire sc, // SC (Single Cycle)
output wire dc, // DC (Double Cycle, ~SC)
// Common 4-bit data bus
inout wire [3:0] data,
 
// Outputs to the Scratch Pad (SP) board
output wire n0636, // JIN+FIN
output wire sc_m22_clk2, // SC&M22&CLK2
output wire fin_fim_src_jin, // FIN+FIM+SRC+JIN
output wire inc_isz_add_sub_xch_ld, // INC+ISZ+ADD+SUB+XCH+LD
output wire inc_isz_xch, // INC+ISZ+XCH
output wire opa0_n, // ~OPA.0
// These drive the Instruction Pointer (IP) board
output wire jcn_isz, // JCN+ISZ
output wire jin_fin, // JIN+FIN
output wire jun_jms, // JUN+JMS
output wire cn_n, // ~CN
output wire bbl, // BBL
output wire jms, // JMS
 
// Inputs from the ALU board (condition bits)
input wire acc_0, // ACC_0
input wire add_0, // ADD_0
input wire cy_1, // CY_1
// Outputs to both the IP and SP boards
output wire sc, // SC (Single Cycle)
output wire dc, // DC (Double Cycle, ~SC)
 
// Outputs to the Arithmetic Logic Unit (ALU) board
output wire cma,
output wire write_acc_1,
output wire write_carry_2,
output wire read_acc_3,
output wire add_group_4,
output wire inc_group_5,
output wire sub_group_6,
output wire ior,
output wire iow,
output wire ral,
output wire rar,
output wire ope_n,
output wire daa,
output wire dcl,
output wire inc_isz,
output wire kbp,
output wire o_ib,
output wire tcs,
output wire xch,
output wire n0342,
output wire x21_clk2,
output wire x31_clk2,
output wire com_n
);
wire sc_m12_clk2 = sc & m12 & clk2;
assign sc_m22_clk2 = sc & m22 & clk2;
// Outputs to the Scratch Pad (SP) board
output wire n0636, // JIN+FIN
output wire sc_m22_clk2, // SC&M22&CLK2
output wire fin_fim_src_jin, // FIN+FIM+SRC+JIN
output wire inc_isz_add_sub_xch_ld, // INC+ISZ+ADD+SUB+XCH+LD
output wire inc_isz_xch, // INC+ISZ+XCH
output wire opa0_n, // ~OPA.0
 
// Latch the first 4 bits of the opcode
reg [3:0] opr = 4'b0000;
always @(posedge sysclk) begin
if (sc_m12_clk2)
opr <= data;
end
// Latch the second 4 bits of the opcode
reg [3:0] opa = 4'b0000;
always @(posedge sysclk) begin
if (sc_m22_clk2)
opa <= data;
end
assign opa0_n = ~opa[0];
// Full OPR Decoding
wire nop = (opr == 4'b0000);
wire jcn = (opr == 4'b0001);
wire fim_src = (opr == 4'b0010);
assign jin_fin = (opr == 4'b0011);
wire jun = (opr == 4'b0100);
assign jms = (opr == 4'b0101);
wire inc = (opr == 4'b0110);
wire isz = (opr == 4'b0111);
wire add = (opr == 4'b1000);
wire sub = (opr == 4'b1001);
wire ld = (opr == 4'b1010);
assign xch = (opr == 4'b1011);
assign bbl = (opr == 4'b1100);
wire ldm = (opr == 4'b1101);
wire io = (opr == 4'b1110);
wire ope = (opr == 4'b1111);
assign ope_n = ~ope;
assign n0636 = jin_fin;
assign jcn_isz = jcn | isz;
assign jun_jms = jun | jms;
wire ldm_bbl = ldm | bbl;
assign inc_isz = (inc | isz) & sc;
assign inc_isz_xch = inc | isz | xch;
assign inc_isz_add_sub_xch_ld = inc | isz | add | sub | xch | ld;
assign fin_fim_src_jin = fim_src | jin_fin;
// OPE: OPA Decoding
assign o_ib = ope & (opa[3] == 1'b0);
wire clb = ope & (opa == 4'b0000);
wire clc = ope & (opa == 4'b0001);
wire iac = ope & (opa == 4'b0010);
wire cmc = ope & (opa == 4'b0011);
assign cma = ope & (opa == 4'b0100);
assign ral = ope & (opa == 4'b0101);
assign rar = ope & (opa == 4'b0110);
wire tcc = ope & (opa == 4'b0111);
wire dac = ope & (opa == 4'b1000);
assign tcs = ope & (opa == 4'b1001);
wire stc = ope & (opa == 4'b1010);
assign daa = ope & (opa == 4'b1011);
assign kbp = ope & (opa == 4'b1100);
assign dcl = ope & (opa == 4'b1101);
// Inputs from the ALU board (condition bits)
input wire acc_0, // ACC_0
input wire add_0, // ADD_0
input wire cy_1, // CY_1
 
// IO: OPA Decoding
assign iow = io & (opa[3] == 1'b0);
assign ior = io & (opa[3] == 1'b1);
wire adm = io & (opa == 4'b1011);
wire sbm = io & (opa == 4'b1000);
// Outputs to the Arithmetic Logic Unit (ALU) board
output wire cma,
output wire write_acc_1,
output wire write_carry_2,
output wire read_acc_3,
output wire add_group_4,
output wire inc_group_5,
output wire sub_group_6,
output wire ior,
output wire iow,
output wire ral,
output wire rar,
output wire ope_n,
output wire daa,
output wire dcl,
output wire inc_isz,
output wire kbp,
output wire o_ib,
output wire tcs,
output wire xch,
output wire n0342,
output wire x21_clk2,
output wire x31_clk2,
output wire com_n
);
 
wire fin_fim = fin_fim_src_jin & ~opa[0];
wire src = fim_src & opa[0];
assign write_acc_1 = ~(kbp | tcs | daa | xch | poc | cma | tcc | dac | iac |
clb | ior | ld | sub | add | ldm_bbl);
assign write_carry_2 = ~(tcs | poc | tcc | stc | cmc | dac | iac |
clc | clb | sbm | adm | sub | add);
assign read_acc_3 = ~(daa | rar | ral | dac | iac | sbm | adm | sub | add);
assign add_group_4 = ~(tcs | tcc | adm | add);
assign inc_group_5 = ~(inc_isz | stc | iac);
assign sub_group_6 = ~(cmc | sbm | sub | m12);
wire sc_m12_clk2 = sc & m12 & clk2;
assign sc_m22_clk2 = sc & m22 & clk2;
 
// The Condition Flip-Flop
reg n0397;
wire n0486 = ~((opa[2] & acc_0) | (opa[1] & cy_1) | (opa[0] & n0432));
wire n0419 = ~((add_0 | ~isz) & (~jcn | ((n0486 | opa[3]) & (~n0486 | ~opa[3]))));
wire n0413 = ~((sc & n0419 & x32) | (~x32 & n0397));
reg n0405;
always @(posedge sysclk) begin
if (clk2)
n0405 <= n0413;
end
always @(posedge sysclk) begin
if (clk1)
n0397 <= ~n0405;
end
assign cn_n = ~n0397;
// Latch the first 4 bits of the opcode
reg [3:0] opr = 4'b0000;
always @(posedge sysclk) begin
if (sc_m12_clk2)
opr <= data;
end
 
// The Single-Cycle Flip-Flop
reg n0343 = 1'b0;
wire n0368 = ~((sc & (fin_fim | jcn_isz | jun_jms) & x32) | (n0343 & ~x32));
reg n0362 = 1'b1;
always @(posedge sysclk) begin
if (clk2)
n0362 <= n0368;
if (clk1)
n0343 <= ~n0362;
end
assign sc = ~n0343;
assign dc = ~sc;
// Latch the second 4 bits of the opcode
reg [3:0] opa = 4'b0000;
always @(posedge sysclk) begin
if (sc_m22_clk2)
opa <= data;
end
assign opa0_n = ~opa[0];
 
// Generate ~(X21&~CLK2)
reg n0360;
always @(posedge sysclk) begin
if (clk2)
n0360 <= ~x12;
end
wire n0337 = ~(n0360 | clk2);
assign x21_clk2 = ~n0337;
// Full OPR Decoding
wire nop = (opr == 4'b0000);
wire jcn = (opr == 4'b0001);
wire fim_src = (opr == 4'b0010);
assign jin_fin = (opr == 4'b0011);
wire jun = (opr == 4'b0100);
assign jms = (opr == 4'b0101);
wire inc = (opr == 4'b0110);
wire isz = (opr == 4'b0111);
wire add = (opr == 4'b1000);
wire sub = (opr == 4'b1001);
wire ld = (opr == 4'b1010);
assign xch = (opr == 4'b1011);
assign bbl = (opr == 4'b1100);
wire ldm = (opr == 4'b1101);
wire io = (opr == 4'b1110);
wire ope = (opr == 4'b1111);
 
// Generate ~(X31&~CLK2)
reg n0380;
always @(posedge sysclk) begin
if (clk2)
n0380 <= ~x22;
end
wire n0375 = ~(n0380 | clk2);
assign x31_clk2 = ~n0375;
// Generate ~COM
wire n0329 = io;
assign ope_n = ~ope;
assign n0636 = jin_fin;
assign jcn_isz = jcn | isz;
assign jun_jms = jun | jms;
wire ldm_bbl = ldm | bbl;
assign inc_isz = (inc | isz) & sc;
assign inc_isz_xch = inc | isz | xch;
assign inc_isz_add_sub_xch_ld = inc | isz | add | sub | xch | ld;
assign fin_fim_src_jin = fim_src | jin_fin;
 
reg n0414, n0797;
always @(posedge sysclk) begin
if (clk2)
n0414 <= a22;
else
n0797 <= n0414;
end
// OPE: OPA Decoding
assign o_ib = ope & (opa[3] == 1'b0);
wire clb = ope & (opa == 4'b0000);
wire clc = ope & (opa == 4'b0001);
wire iac = ope & (opa == 4'b0010);
wire cmc = ope & (opa == 4'b0011);
assign cma = ope & (opa == 4'b0100);
assign ral = ope & (opa == 4'b0101);
assign rar = ope & (opa == 4'b0110);
wire tcc = ope & (opa == 4'b0111);
 
reg n0433, n0801;
always @(posedge sysclk) begin
if (clk2)
n0433 <= m12;
else
n0801 <= n0433;
end
reg n0425, n0805;
always @(posedge sysclk) begin
if (clk2)
n0425 <= x12;
else
n0805 <= n0425;
end
wire dac = ope & (opa == 4'b1000);
assign tcs = ope & (opa == 4'b1001);
wire stc = ope & (opa == 4'b1010);
assign daa = ope & (opa == 4'b1011);
assign kbp = ope & (opa == 4'b1100);
assign dcl = ope & (opa == 4'b1101);
 
wire n0782 = ~((n0801 & n0329) | (src & n0805) | n0797);
assign com_n = n0782;
// Generate N0342
wire n0332 = ~(((n0329 | poc) & x22 & clk2) | (~(n0329 | poc) & n0337 & clk1));
assign n0342 = n0332;
// IO: OPA Decoding
assign iow = io & (opa[3] == 1'b0);
assign ior = io & (opa[3] == 1'b1);
wire adm = io & (opa == 4'b1011);
wire sbm = io & (opa == 4'b1000);
 
// Output OPA onto the data bus
wire opa_ib = (ldm_bbl | jun_jms) & ~x21_clk2;
assign data = opa_ib ? opa : 4'bzzzz;
wire fin_fim = fin_fim_src_jin & ~opa[0];
wire src = fim_src & opa[0];
 
assign write_acc_1 = ~(kbp | tcs | daa | xch | poc | cma | tcc | dac | iac |
clb | ior | ld | sub | add | ldm_bbl);
assign write_carry_2 = ~(tcs | poc | tcc | stc | cmc | dac | iac |
clc | clb | sbm | adm | sub | add);
assign read_acc_3 = ~(daa | rar | ral | dac | iac | sbm | adm | sub | add);
assign add_group_4 = ~(tcs | tcc | adm | add);
assign inc_group_5 = ~(inc_isz | stc | iac);
assign sub_group_6 = ~(cmc | sbm | sub | m12);
 
// The Condition Flip-Flop
reg n0397;
wire n0486 = ~((opa[2] & acc_0) | (opa[1] & cy_1) | (opa[0] & n0432));
wire n0419 = ~((add_0 | ~isz) & (~jcn | ((n0486 | opa[3]) & (~n0486 | ~opa[3]))));
wire n0413 = ~((sc & n0419 & x32) | (~x32 & n0397));
reg n0405;
always @(posedge sysclk) begin
if (clk2)
n0405 <= n0413;
end
always @(*) begin
if (clk1)
n0397 <= ~n0405;
end
assign cn_n = ~n0397;
 
// The Single-Cycle Flip-Flop
reg n0343 = 1'b0;
wire n0368 = ~((sc & (fin_fim | jcn_isz | jun_jms) & x32) | (n0343 & ~x32));
reg n0362 = 1'b1;
always @(posedge sysclk) begin
if (clk2)
n0362 <= n0368;
if (clk1)
n0343 <= ~n0362;
end
assign sc = ~n0343;
assign dc = ~sc;
 
// Generate ~(X21&~CLK2)
reg n0360;
always @(posedge sysclk) begin
if (clk2)
n0360 <= ~x12;
end
wire n0337 = ~(n0360 | clk2);
assign x21_clk2 = ~n0337;
 
// Generate ~(X31&~CLK2)
reg n0380;
always @(posedge sysclk) begin
if (clk2)
n0380 <= ~x22;
end
wire n0375 = ~(n0380 | clk2);
assign x31_clk2 = ~n0375;
 
// Generate ~COM
wire n0329 = io;
 
reg n0414, n0797;
always @(posedge sysclk) begin
if (clk2)
n0414 <= a22;
else
n0797 <= n0414;
end
 
reg n0433, n0801;
always @(posedge sysclk) begin
if (clk2)
n0433 <= m12;
else
n0801 <= n0433;
end
 
reg n0425, n0805;
always @(posedge sysclk) begin
if (clk2)
n0425 <= x12;
else
n0805 <= n0425;
end
 
wire n0782 = ~((n0801 & n0329) | (src & n0805) | n0797);
assign com_n = n0782;
 
// Generate N0342
wire n0332 = ~(((n0329 | poc) & x22 & clk2) | (~(n0329 | poc) & n0337 & clk1));
assign n0342 = n0332;
 
// Output OPA onto the data bus
wire opa_ib = (ldm_bbl | jun_jms) & ~x21_clk2;
assign data = opa_ib ? opa : 4'bzzzz;
 
endmodule
/rtl/verilog/i4004/instruction_pointer.v
1,18 → 1,18
`timescale 1ns / 1ps
`default_nettype none
////////////////////////////////////////////////////////////////////////
//
//
// 4004 Instruction Pointer Array
//
//
// 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.
20,195 → 20,212
////////////////////////////////////////////////////////////////////////
 
module instruction_pointer (
input wire sysclk, // 50 MHz FPGA clock
input wire sysclk, // 50 MHz FPGA clock
 
// Inputs from the Timing and I/O board
input wire clk1,
input wire clk2,
input wire a12,
input wire a22,
input wire a32,
input wire m12,
input wire m22,
input wire x12,
input wire x22,
input wire x32,
input wire poc, // Power-On Clear (reset)
input wire m12_m22_clk1_m11_m12, // M12+M22+CLK1~(M11+M12)
// Inputs from the Timing and I/O board
input wire clk1,
input wire clk2,
input wire a12,
input wire a22,
input wire a32,
input wire m12,
input wire m22,
input wire x12,
input wire x22,
input wire x32,
input wire poc, // Power-On Clear (reset)
input wire m12_m22_clk1_m11_m12, // M12+M22+CLK1~(M11+M12)
 
// Common 4-bit data bus
inout wire [3:0] data,
// Common 4-bit data bus
inout wire [3:0] data,
 
// Inputs from the Instruction Decode board
input wire jcn_isz, // JCN+ISZ
input wire jin_fin, // JIN+FIN
input wire jun_jms, // JUN+JMS
input wire cn_n, // ~CN
input wire bbl, // BBL
input wire jms, // JMS
input wire sc, // SC (Single Cycle)
input wire dc // DC (Double Cycle, ~SC)
);
// Inputs from the Instruction Decode board
input wire jcn_isz, // JCN+ISZ
input wire jin_fin, // JIN+FIN
input wire jun_jms, // JUN+JMS
input wire cn_n, // ~CN
input wire bbl, // BBL
input wire jms, // JMS
input wire sc, // SC (Single Cycle)
input wire dc // DC (Double Cycle, ~SC)
);
 
reg [11:0] dram_array [0:3];
reg [11:0] dram_temp;
wire [3:0] din_n;
reg [11:0] dram_array [0:3];
reg [11:0] dram_temp;
wire [3:0] din_n;
 
wire inh = (jin_fin & sc) | ((jun_jms | (jcn_isz & ~cn_n)) & dc);
wire inh = (jin_fin & sc) | ((jun_jms | (jcn_isz & ~cn_n)) & dc);
 
// Row Counter stuff
wire [1:0] addr_ptr; // Effective Address counter
wire addr_ptr_step; // CLK2(JMS&DC&M22+BBL(M22+X12+X22))
assign addr_ptr_step = ~(~clk2 | ~(((m22 | x12 | x22) & bbl) |
(m22 & dc & jms)));
counter addr_ptr_0 (
.sysclk(sysclk),
.step_a(clk1),
.step_b(addr_ptr_step),
.q(addr_ptr[0])
);
counter addr_ptr_1 (
.sysclk(sysclk),
.step_a( addr_ptr[0]),
.step_b(~addr_ptr[0]),
.q(addr_ptr[1])
);
// Row Counter stuff
wire [1:0] addr_ptr; // Effective Address counter
wire addr_ptr_step; // CLK2(JMS&DC&M22+BBL(M22+X12+X22))
wire n0459;
wire n0466;
 
// Refresh counter stuff
wire [1:0] addr_rfsh; // Row Refresh counter
wire addr_rfsh_step; // (~INH)&X32&CLK2
assign addr_rfsh_step = ~inh & x32 & clk2;
counter addr_rfsh_0 (
.sysclk(sysclk),
.step_a(clk1),
.step_b(addr_rfsh_step),
.q(addr_rfsh[0])
);
counter addr_rfsh_1 (
.sysclk(sysclk),
.step_a( addr_rfsh[0]),
.step_b(~addr_rfsh[0]),
.q(addr_rfsh[1])
);
assign addr_ptr_step = ~(~clk2 | ~(((m22 | x12 | x22) & bbl) |
(m22 & dc & jms)));
counter addr_ptr_0 (
.sysclk(sysclk),
.step_a_in(clk1),
.step_b_in(addr_ptr_step),
.step_a_out(n0459),
.step_b_out(n0466),
.q(),
.qn(addr_ptr[0])
);
counter addr_ptr_1 (
.sysclk(sysclk),
.step_a_in(n0459),
.step_b_in(n0466),
.step_a_out(),
.step_b_out(),
.q(),
.qn(addr_ptr[1])
);
 
// Row selection mux
reg [1:0] row; // {N0409, N0420}
always @(posedge sysclk) begin
if (x12)
row <= addr_rfsh;
if (x32)
row <= addr_ptr;
end
// Refresh counter stuff
wire [1:0] addr_rfsh; // Row Refresh counter
wire addr_rfsh_step; // (~INH)&X32&CLK2
wire n0455;
wire n0463;
 
assign addr_rfsh_step = ~inh & x32 & clk2;
 
// Row Precharge/Read/Write stuff
wire precharge; // (~INH)(X11+X31)CLK1
wire row_read; // (~POC)CLK2(X12+X32)~INH
wire row_write; // ((~SC)(JIN+FIN))CLK1(M11+X21~INH)
counter addr_rfsh_0 (
.sysclk(sysclk),
.step_a_in(clk1),
.step_b_in(addr_rfsh_step),
.step_a_out(n0455),
.step_b_out(n0463),
.q(),
.qn(addr_rfsh[0])
);
counter addr_rfsh_1 (
.sysclk(sysclk),
.step_a_in(n0455),
.step_b_in(n0463),
.step_a_out(),
.step_b_out(),
.q(),
.qn(addr_rfsh[1])
);
 
reg n0517;
always @(posedge sysclk) begin
if (clk2)
n0517 <= ~(m22 | x22);
end
assign precharge = ~(n0517 | inh | ~clk1);
// Row selection mux
reg [1:0] row; // {N0409, N0420}
always @(posedge sysclk) begin
if (x12)
row <= addr_rfsh;
if (x32)
row <= addr_ptr;
end
 
assign row_read = ~poc & clk2 & (x12 | x32) & ~inh;
reg n0438;
always @(posedge sysclk) begin
if (clk2)
n0438 <= ~((x12 & ~inh) | a32);
end
assign row_write = ~(n0438 | (jin_fin & ~sc) | ~clk1);
 
// Row Precharge/Read/Write stuff
wire precharge; // (~INH)(X11+X31)CLK1
wire row_read; // (~POC)CLK2(X12+X32)~INH
wire row_write; // ((~SC)(JIN+FIN))CLK1(M11+X21~INH)
 
// Column Read selection stuff
reg n0416;
always @(posedge sysclk) begin
if (clk2)
n0416 <= ~x32;
end
wire radb0 = ~(n0416 | clk2);
reg n0517;
always @(posedge sysclk) begin
if (clk2)
n0517 <= ~(m22 | x22);
end
assign precharge = ~(n0517 | inh | ~clk1);
 
reg n0384;
always @(posedge sysclk) begin
if (clk2)
n0384 <= ~a12;
end
wire radb1 = ~(n0384 | clk2);
assign row_read = ~poc & clk2 & (x12 | x32) & ~inh;
 
reg n0374;
always @(posedge sysclk) begin
if (clk2)
n0374 <= ~a22;
end
wire radb2 = ~(n0374 | clk2);
reg n0438;
always @(posedge sysclk) begin
if (clk2)
n0438 <= ~((x12 & ~inh) | a32);
end
assign row_write = ~(n0438 | (jin_fin & ~sc) | ~clk1);
 
 
// Column Write selection stuff
wire n0322 = ~(sc | cn_n);
wire wadb0 = ~(~clk2 | ~(a12 | (sc & jin_fin & x32) |
(((jcn_isz & n0322) | (jun_jms & ~sc)) & m22)));
wire wadb1 = ~(~clk2 | ~(a22 | (sc & jin_fin & x22) |
(((jcn_isz & n0322) | (jun_jms & ~sc)) & m12)));
wire wadb2 = ~(~clk2 | ~(a32 | (jun_jms & ~sc & x22)));
// Column Read selection stuff
reg n0416;
always @(posedge sysclk) begin
if (clk2)
n0416 <= ~x32;
end
wire radb0 = ~(n0416 | clk2);
 
reg n0384;
always @(posedge sysclk) begin
if (clk2)
n0384 <= ~a12;
end
wire radb1 = ~(n0384 | clk2);
 
// Manage the row data buffer
always @(posedge sysclk) begin
if (precharge)
dram_temp <= 12'b0;
if (row_read)
dram_temp <= dram_array[row];
if (wadb0)
dram_temp[ 3:0] <= ~din_n;
if (wadb1)
dram_temp[ 7:4] <= ~din_n;
if (wadb2)
dram_temp[11:8] <= ~din_n;
end
reg n0374;
always @(posedge sysclk) begin
if (clk2)
n0374 <= ~a22;
end
wire radb2 = ~(n0374 | clk2);
 
// Handle row writes
always @(posedge sysclk) begin
if (row_write)
dram_array[row] <= dram_temp;
end
 
// Manage the data output mux
reg [3:0] dout;
always @* begin
(* PARALLEL_CASE *)
case (1'b1)
radb0: dout = dram_temp[ 3:0];
radb1: dout = dram_temp[ 7:4];
radb2: dout = dram_temp[11:8];
default: dout = 4'bzzzz;
endcase
end
assign data = dout;
// Data In mux and incrementer
reg [3:0] incr_in;
always @(posedge sysclk) begin
if (m12_m22_clk1_m11_m12)
incr_in <= data;
end
// Column Write selection stuff
wire n0322 = ~(sc | cn_n);
wire wadb0 = ~(~clk2 | ~(a12 | (sc & jin_fin & x32) |
(((jcn_isz & n0322) | (jun_jms & ~sc)) & m22)));
wire wadb1 = ~(~clk2 | ~(a22 | (sc & jin_fin & x22) |
(((jcn_isz & n0322) | (jun_jms & ~sc)) & m12)));
wire wadb2 = ~(~clk2 | ~(a32 | (jun_jms & ~sc & x22)));
 
reg carry_out, carry_in;
wire [4:0] incr_out = (a12 | ((a22 | a32) & carry_in)) ?
(incr_in + 4'b0001) : {1'b0, incr_in};
always @(posedge sysclk) begin
if (clk2)
carry_out <= incr_out[4];
if (clk1)
carry_in <= carry_out;
end
assign din_n = ~incr_out[3:0];
 
// Manage the row data buffer
wire [11:0] row_data = dram_array[row];
always @(posedge sysclk) begin
if (precharge)
dram_temp <= 12'b0;
 
if (row_read)
dram_temp <= row_data;
 
if (wadb0)
dram_temp[ 3:0] <= ~din_n;
if (wadb1)
dram_temp[ 7:4] <= ~din_n;
if (wadb2)
dram_temp[11:8] <= ~din_n;
end
 
// Handle row writes
always @(posedge sysclk) begin
if (row_write)
dram_array[row] <= dram_temp;
end
 
// Manage the data output mux
reg [3:0] dout;
always @(*) begin
(* PARALLEL_CASE *)
case (1'b1)
radb0: dout = dram_temp[ 3:0];
radb1: dout = dram_temp[ 7:4];
radb2: dout = dram_temp[11:8];
default: dout = 4'bzzzz;
endcase
end
assign data = dout;
 
// Data In mux and incrementer
reg [3:0] incr_in;
always @(posedge sysclk) begin
if (m12_m22_clk1_m11_m12)
incr_in <= data;
end
 
reg carry_out, carry_in;
wire [4:0] incr_out = (a12 | ((a22 | a32) & carry_in)) ?
(incr_in + 4'b0001) : {1'b0, incr_in};
always @(posedge sysclk) begin
if (clk2)
carry_out <= incr_out[4];
if (clk1)
carry_in <= carry_out;
end
assign din_n = ~incr_out[3:0];
 
endmodule
/rtl/verilog/i4004/scratchpad.v
1,18 → 1,18
`timescale 1ns / 1ps
`default_nettype none
////////////////////////////////////////////////////////////////////////
//
//
// 4004 Scratchpad Register Array
//
//
// 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.
20,149 → 20,163
////////////////////////////////////////////////////////////////////////
 
module scratchpad (
input wire sysclk, // 50 MHz FPGA clock
input wire sysclk, // 50 MHz FPGA clock
 
// Inputs from the Timing and I/O board
input wire clk1,
input wire clk2,
input wire a12,
input wire a22,
input wire a32,
input wire m12,
input wire m22,
input wire x12,
input wire x22,
input wire x32,
input wire poc, // Power-On Clear (reset)
input wire m12_m22_clk1_m11_m12, // M12+M22+CLK1~(M11+M12)
// Inputs from the Timing and I/O board
input wire clk1,
input wire clk2,
input wire a12,
input wire a22,
input wire a32,
input wire m12,
input wire m22,
input wire x12,
input wire x22,
input wire x32,
input wire poc, // Power-On Clear (reset)
input wire m12_m22_clk1_m11_m12, // M12+M22+CLK1~(M11+M12)
 
// Common 4-bit data bus
inout wire [3:0] data,
// Common 4-bit data bus
inout wire [3:0] data,
 
// Inputs from the Instruction Decode board
input wire n0636, // JIN+FIN
input wire sc_m22_clk2, // SC&M22&CLK2
input wire fin_fim_src_jin, // FIN+FIM+SRC+JIN
input wire inc_isz_add_sub_xch_ld, // INC+ISZ+ADD+SUB+XCH+LD
input wire inc_isz_xch, // INC+ISZ+XCH
input wire opa0_n, // ~OPA.0
input wire sc, // SC (Single Cycle)
input wire dc // DC (Double Cycle, ~SC)
);
// Inputs from the Instruction Decode board
input wire n0636, // JIN+FIN
input wire sc_m22_clk2, // SC&M22&CLK2
input wire fin_fim_src_jin, // FIN+FIM+SRC+JIN
input wire inc_isz_add_sub_xch_ld, // INC+ISZ+ADD+SUB+XCH+LD
input wire inc_isz_xch, // INC+ISZ+XCH
input wire opa0_n, // ~OPA.0
input wire sc, // SC (Single Cycle)
input wire dc // DC (Double Cycle, ~SC)
);
 
reg [7:0] dram_array [0:7];
reg [7:0] dram_temp;
reg [3:0] din_n;
reg [7:0] dram_array [0:7];
reg [7:0] dram_temp;
reg [3:0] din_n;
 
// Refresh counter stuff
wire [2:0] reg_rfsh; // Row Refresh counter
wire reg_rfsh_step; // SC&A12&CLK2
assign reg_rfsh_step = sc & a12 & clk2;
counter reg_rfsh_0 (
.sysclk(sysclk),
.step_a(clk1),
.step_b(reg_rfsh_step),
.q(reg_rfsh[0])
);
counter reg_rfsh_1 (
.sysclk(sysclk),
.step_a( reg_rfsh[0]),
.step_b(~reg_rfsh[0]),
.q(reg_rfsh[1])
);
counter reg_rfsh_2 (
.sysclk(sysclk),
.step_a( reg_rfsh[1]),
.step_b(~reg_rfsh[1]),
.q(reg_rfsh[2])
);
// Refresh counter stuff
wire [2:0] reg_rfsh; // Row Refresh counter
wire reg_rfsh_step; // SC&A12&CLK2
wire n0571;
wire n0574;
wire n0600;
wire n0610;
 
// Row selection mux
reg [2:0] row; // {N0646, N0617, N0582}
always @(posedge sysclk) begin
if (sc & a22)
row <= reg_rfsh;
if (sc_m22_clk2)
row <= data[3:1];
end
assign reg_rfsh_step = sc & a12 & clk2;
 
counter reg_rfsh_0 (
.sysclk(sysclk),
.step_a_in(clk1),
.step_b_in(reg_rfsh_step),
.step_a_out(n0571),
.step_b_out(n0574),
.q(reg_rfsh[0]),
.qn()
);
counter reg_rfsh_1 (
.sysclk(sysclk),
.step_a_in(n0571),
.step_b_in(n0574),
.step_a_out(n0600),
.step_b_out(n0610),
.q(reg_rfsh[1]),
.qn()
);
counter reg_rfsh_2 (
.sysclk(sysclk),
.step_a_in(n0600),
.step_b_in(n0610),
.step_a_out(),
.step_b_out(),
.q(reg_rfsh[2]),
.qn()
);
 
// Row Precharge/Read/Write stuff
wire precharge; // SC(A22+M22)CLK2
wire row_read; // (~POC)&CLK2&SC(A32+X12)
wire row_write; // CLK2&SC(A12+M12)
// Row selection mux
reg [2:0] row; // {N0646, N0617, N0582}
always @(posedge sysclk) begin
if (sc & a22)
row <= reg_rfsh;
if (sc_m22_clk2)
row <= data[3:1];
end
 
assign precharge = sc & (a22 | m22) & clk2;
assign row_read = ~(poc | ~(clk2 & sc & (a32 | x12)));
assign row_write = sc & (a12 | m12) & clk2;
 
// Row Precharge/Read/Write stuff
wire precharge; // SC(A22+M22)CLK2
wire row_read; // (~POC)&CLK2&SC(A32+X12)
wire row_write; // CLK2&SC(A12+M12)
 
// Column Read selection stuff
reg n0615;
always @(posedge sysclk) begin
if (clk2)
n0615 <= ~(x12 & (fin_fim_src_jin |
(opa0_n & inc_isz_add_sub_xch_ld)));
end
wire rrab0 = ~(dc | n0615 | clk2);
assign precharge = sc & (a22 | m22) & clk2;
assign row_read = ~(poc | ~(clk2 & sc & (a32 | x12)));
assign row_write = sc & (a12 | m12) & clk2;
 
reg n0592;
always @(posedge sysclk) begin
if (clk2)
n0592 <= ~((x22 & fin_fim_src_jin) |
(~opa0_n & x12 & inc_isz_add_sub_xch_ld));
end
wire rrab1 = ~(dc | n0592 | clk2);
 
// Column Read selection stuff
reg n0615;
always @(posedge sysclk) begin
if (clk2)
n0615 <= ~(x12 & (fin_fim_src_jin |
(opa0_n & inc_isz_add_sub_xch_ld)));
end
wire rrab0 = ~(dc | n0615 | clk2);
 
// Column Write selection stuff
wire n0564 = opa0_n & fin_fim_src_jin & dc;
wire n0568 = inc_isz_xch & x32 & sc;
wire wrab0 = clk2 & ((m12 & n0564) | ( opa0_n & n0568));
wire wrab1 = clk2 & ((m22 & n0564) | (~opa0_n & n0568));
reg n0592;
always @(posedge sysclk) begin
if (clk2)
n0592 <= ~((x22 & fin_fim_src_jin) |
(~opa0_n & x12 & inc_isz_add_sub_xch_ld));
end
wire rrab1 = ~(dc | n0592 | clk2);
 
 
// Force row 0 if FIN&X12
wire fin_x12 = (n0636 & opa0_n) & x12;
// Column Write selection stuff
wire n0564 = opa0_n & fin_fim_src_jin & dc;
wire n0568 = inc_isz_xch & x32 & sc;
wire wrab0 = clk2 & ((m12 & n0564) | ( opa0_n & n0568));
wire wrab1 = clk2 & ((m22 & n0564) | (~opa0_n & n0568));
 
// Manage the row data buffer
always @(posedge sysclk) begin
if (precharge)
dram_temp <= 8'b0;
if (row_read)
dram_temp <= dram_array[fin_x12 ? 3'b000 : row];
if (wrab0)
dram_temp[ 7:4] <= ~din_n;
if (wrab1)
dram_temp[ 3:0] <= ~din_n;
end
 
// Handle row writes
always @(posedge sysclk) begin
if (row_write)
dram_array[row] <= dram_temp;
end
// Force row 0 if FIN&X12
wire fin_x12 = (n0636 & opa0_n) & x12;
 
// Manage the data output mux
reg [3:0] dout;
always @* begin
(* PARALLEL_CASE *)
case (1'b1)
rrab0: dout = dram_temp[ 7:4];
rrab1: dout = dram_temp[ 3:0];
default: dout = 4'bzzzz;
endcase
end
assign data = dout;
// Data In latch
always @(posedge sysclk) begin
if (m12_m22_clk1_m11_m12)
din_n <= ~data;
end
// Manage the row data buffer
wire [7:0] row_data = dram_array[fin_x12 ? 3'b000 : row];
always @(posedge sysclk) begin
if (precharge)
dram_temp <= 8'b0;
 
if (row_read)
dram_temp <= row_data;
 
if (wrab0)
dram_temp[ 7:4] <= ~din_n;
if (wrab1)
dram_temp[ 3:0] <= ~din_n;
end
 
// Handle row writes
always @(posedge sysclk) begin
if (row_write)
dram_array[row] <= dram_temp;
end
 
// Manage the data output mux
reg [3:0] dout;
always @* begin
(* PARALLEL_CASE *)
case (1'b1)
rrab0: dout = dram_temp[ 7:4];
rrab1: dout = dram_temp[ 3:0];
default: dout = 4'bzzzz;
endcase
end
assign data = dout;
 
// Data In latch
always @(posedge sysclk) begin
if (m12_m22_clk1_m11_m12)
din_n <= ~data;
end
 
endmodule
/rtl/verilog/i4004/timing_io.v
1,18 → 1,18
`timescale 1ns / 1ps
`default_nettype none
////////////////////////////////////////////////////////////////////////
//
//
// 4004 Timing and I/O Interfaces
//
//
// 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.
20,140 → 20,132
////////////////////////////////////////////////////////////////////////
 
module timing_io(
input wire sysclk,
input wire clk1_pad,
input wire clk2_pad,
input wire poc_pad,
input wire ior,
// Timing and I/O Board Outputs
output wire clk1,
output wire clk2,
output wire a12,
output wire a22,
output wire a32,
output wire m12,
output wire m22,
output wire x12,
output wire x22,
output wire x32,
output wire gate,
output reg poc,
// External I/O Pad conditioning
inout wire [3:0] data,
inout wire [3:0] data_pad,
input wire test_pad,
output reg n0432,
output reg sync_pad,
input wire cmrom,
output wire cmrom_pad,
input wire cmram0,
output wire cmram0_pad,
input wire cmram1,
output wire cmram1_pad,
input wire cmram2,
output wire cmram2_pad,
input wire cmram3,
output wire cmram3_pad
input wire sysclk,
input wire clk1_pad,
input wire clk2_pad,
input wire poc_pad,
input wire ior,
 
// Timing and I/O Board Outputs
output wire clk1,
output wire clk2,
output wire a12,
output wire a22,
output wire a32,
output wire m12,
output wire m22,
output wire x12,
output wire x22,
output wire x32,
output wire gate,
output reg poc,
 
// External I/O Pad conditioning
inout wire [3:0] data,
inout wire [3:0] data_pad,
input wire test_pad,
output reg n0432,
output wire sync_pad,
input wire cmrom,
output wire cmrom_pad,
input wire cmram0,
output wire cmram0_pad,
input wire cmram1,
output wire cmram1_pad,
input wire cmram2,
output wire cmram2_pad,
input wire cmram3,
output wire cmram3_pad
);
 
// Simple pass-throughs
assign clk1 = clk1_pad;
assign clk2 = clk2_pad;
assign cmrom_pad = cmrom;
assign cmram0_pad = cmram0;
assign cmram1_pad = cmram1;
assign cmram2_pad = cmram2;
assign cmram3_pad = cmram3;
// Simple pass-throughs
assign clk1 = clk1_pad;
assign clk2 = clk2_pad;
assign cmrom_pad = cmrom;
assign cmram0_pad = cmram0;
assign cmram1_pad = cmram1;
assign cmram2_pad = cmram2;
assign cmram3_pad = cmram3;
 
 
// Generate the 8 execution phase indicators
reg [0:7] master = 8'h00;
reg [0:7] slave = 8'h00;
always @(posedge sysclk) begin
if (clk2)
master <= {~|slave[0:6], slave[0:6]};
else
sync_pad <= master[7];
// Generate the 8 execution phase indicators
timing_generator timing_generator (
.sysclk (sysclk),
.clk1 (clk1),
.clk2 (clk2),
.a12 (a12),
.a22 (a22),
.a32 (a32),
.m12 (m12),
.m22 (m22),
.x12 (x12),
.x22 (x22),
.x32 (x32),
.sync (sync_pad)
);
 
if (clk1)
slave <= master;
end
// Generate the DRAM Input Gate signal
// Properly called M12+M22+CLK1~(M11&M12)
wire n0279 = ~(a32 | m12);
reg n0278;
always @(posedge sysclk) begin
if (clk2)
n0278 <= n0279;
end
wire n0708 = ~((n0278 & clk1) | m12 | m22);
assign gate = ~n0708;
 
assign a12 = slave[0];
assign a22 = slave[1];
assign a32 = slave[2];
assign m12 = slave[3];
assign m22 = slave[4];
assign x12 = slave[5];
assign x22 = slave[6];
assign x32 = slave[7];
 
// Generate a clean POC signal
always @(posedge sysclk or posedge poc_pad) begin
if (poc_pad) poc <= 1'b1;
else if (a12) poc <= 1'b0;
end
 
// Generate the DRAM Input Gate signal
// Properly called M12+M22+CLK1~(M11&M12)
wire n0279 = ~(a32 | m12);
reg n0278;
always @(posedge sysclk) begin
if (clk2)
n0278 <= n0279;
end
wire n0708 = ~((n0278 & clk1) | m12 | m22);
assign gate = ~n0708;
// Generate a clean ~TEST signal (n0432)
always @(posedge sysclk) begin
n0432 <= ~test_pad;
end
 
// Generate a clean POC signal
always @(posedge sysclk) begin
if (poc_pad) poc <= 1'b1;
else if (a12) poc <= 1'b0;
else poc <= poc;
end
// Generate a clean ~TEST signal (n0432)
always @(posedge sysclk) begin
n0432 <= ~test_pad;
end
// Manage the Data I/O pads
reg L;
always @(posedge sysclk) begin
if (clk2)
L <= a32 | m12 | (x12 & (ior | poc));
end
 
// Manage the Data I/O pads
reg L;
always @(posedge sysclk) begin
if (clk2)
L <= a32 | m12 | (x12 & (ior | poc));
end
wire n0702 = ~clk2;
reg n0685;
reg n0699;
reg n0707;
always @(posedge sysclk) begin
if (clk1) begin
n0685 <= ~L;
n0707 <= L;
end
if (n0702)
n0699 <= ~L;
end
wire n0700 = n0707 | (L & n0702) | poc;
wire n0659 = (clk2 & n0685) | (clk1 & L);
wire n0676 = clk1 | n0685 | n0699;
 
wire n0702 = ~clk2;
reg n0685;
reg n0699;
reg n0707;
always @(posedge sysclk) begin
if (clk1) begin
n0685 <= ~L;
n0707 <= L;
end
if (n0702)
n0699 <= ~L;
end
wire n0700 = n0707 | (L & n0702) | poc;
wire n0659 = (clk2 & n0685) | (clk1 & L);
wire n0676 = clk1 | n0685 | n0699;
// Incoming data from the external pads
reg [3:0] data_in;
always @* begin
if (n0659) data_in = 4'b1111;
else if (n0676) data_in = 4'bzzzz;
else if (poc) data_in = 4'b0000;
else data_in = data_pad;
end
assign data = data_in;
// Incoming data from the external pads
reg [3:0] data_in;
always @* begin
if (n0659) data_in = 4'b1111;
else if (n0676) data_in = 4'bzzzz;
else if (poc) data_in = 4'b0000;
else data_in = data_pad;
end
assign data = data_in;
 
// Outgoing data to the external pads
reg [3:0] data_out;
always @(posedge sysclk) begin
if (n0702)
data_out <= data;
end
assign data_pad = poc ? 4'b0000 : (n0700 ? 4'bzzzz : data_out);
// Outgoing data to the external pads
reg [3:0] data_out;
always @(posedge sysclk) begin
if (n0702)
data_out <= data;
end
assign data_pad = poc ? 4'b0000 : (n0700 ? 4'bzzzz : data_out);
 
endmodule
/rtl/verilog/i4004/timing_io_tb.v
0,0 → 1,156
`timescale 1ns / 1ps
`default_nettype none
////////////////////////////////////////////////////////////////////////
//
// MCS-4 i4004 CPU Timing and I/O Interface testbench
//
// This testbench instantiates a timing_io module, and drives it
// with the basic 8-subcycle (A1, A2, A3, M1, M2, X1, X2, X3)
// instruction cycle to allow confirmation of the correct direction
// of transfer through the system bus interface.
//
// 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_io_tb;
 
localparam SYSCLK_TCY = 20; // sysclk period in nanoseconds
 
// Inputs
reg sysclk;
wire clk1_pad;
wire clk2_pad;
reg poc_pad = 1'b0;
reg test_pad = 1'b0;
reg ior = 1'b0;
reg cmrom = 1'b0;
reg cmram0 = 1'b0;
reg cmram1 = 1'b0;
reg cmram2 = 1'b0;
reg cmram3 = 1'b0;
 
// Outputs
wire clk1;
wire clk2;
wire a12;
wire a22;
wire a32;
wire m12;
wire m22;
wire x12;
wire x22;
wire x32;
wire sync;
wire gate;
wire poc;
wire n0432;
wire cmrom_pad;
wire cmram0_pad;
wire cmram1_pad;
wire cmram2_pad;
wire cmram3_pad;
 
// Bidirs
wire [3:0] data;
wire [3:0] data_pad;
 
// Instantiate the Unit Under Test (UUT)
timing_io uut (
.sysclk(sysclk),
.clk1_pad(clk1_pad),
.clk2_pad(clk2_pad),
.poc_pad(poc_pad),
.ior(ior),
.clk1(clk1),
.clk2(clk2),
.a12(a12),
.a22(a22),
.a32(a32),
.m12(m12),
.m22(m22),
.x12(x12),
.x22(x22),
.x32(x32),
.sync(sync),
.gate(gate),
.poc(poc),
.data(data),
.data_pad(data_pad),
.test_pad(test_pad),
.n0432(n0432),
.cmrom(cmrom),
.cmrom_pad(cmrom_pad),
.cmram0(cmram0),
.cmram0_pad(cmram0_pad),
.cmram1(cmram1),
.cmram1_pad(cmram1_pad),
.cmram2(cmram2),
.cmram2_pad(cmram2_pad),
.cmram3(cmram3),
.cmram3_pad(cmram3_pad)
);
 
// Instantiate the 2-phase clock generator
clockgen #(
.SYSCLK_TCY(SYSCLK_TCY)
) clockgen (
.sysclk(sysclk),
.clk1(clk1_pad),
.clk2(clk2_pad)
);
 
always begin
sysclk = 1'b0;
#(SYSCLK_TCY / 2);
sysclk = 1'b1;
#(SYSCLK_TCY / 2);
end
 
reg [3:0] data_out;
always @* begin
if (poc)
data_out = 4'bzzzz;
else begin
(* PARALLEL_CASE *)
case (1'b1)
a12: data_out = 4'b0001;
a22: data_out = 4'b0010;
a32: data_out = 4'b0011;
m12: data_out = 4'bzzzz;
m22: data_out = 4'bzzzz;
x12: data_out = 4'b0110;
x22: data_out = 4'b0111;
x32: data_out = 4'b1000;
default: data_out = 4'bxxxx;
endcase
end
end
assign data = data_out;
assign data_pad = 4'bzzzz;
 
initial begin
// Initialize Inputs
poc_pad = 1'b1;
 
// Wait 10000 ns for global reset to finish
#10000;
 
// Add stimulus here
@(posedge m12);
poc_pad = 1'b0;
end
 
endmodule
 

powered by: WebSVN 2.1.0

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