1 |
6 |
rrpollack |
`timescale 1ns / 1ps
|
2 |
|
|
`default_nettype none
|
3 |
|
|
////////////////////////////////////////////////////////////////////////
|
4 |
|
|
//
|
5 |
|
|
// MCS-4 i40021 RAM and Output Port module
|
6 |
|
|
//
|
7 |
|
|
// This module emulates the Intel 4002 RAM and Output Port chip. The
|
8 |
|
|
// RAM storage is implemented using an "i4002_ram" module, which is
|
9 |
|
|
// dependent on the availability of dual-port distributed RAM.
|
10 |
|
|
//
|
11 |
|
|
// This file is part of the MCS-4 project hosted at OpenCores:
|
12 |
|
|
// http://www.opencores.org/cores/mcs-4/
|
13 |
|
|
//
|
14 |
|
|
// Copyright © 2021 by Reece Pollack <rrpollack@opencores.org>
|
15 |
|
|
//
|
16 |
|
|
// These materials are provided under the Creative Commons
|
17 |
|
|
// "Attribution-NonCommercial-ShareAlike" (CC BY-NC-SA) Public License.
|
18 |
|
|
// They are NOT "public domain", and are protected by copyright.
|
19 |
|
|
//
|
20 |
|
|
// This work based on materials provided by Intel Corporation and
|
21 |
|
|
// others under the same license. See the file doc/License for
|
22 |
|
|
// details of this license.
|
23 |
|
|
//
|
24 |
|
|
////////////////////////////////////////////////////////////////////////
|
25 |
|
|
|
26 |
|
|
module i4002 #(
|
27 |
|
|
parameter CHIP_NUMBER = 0, // Mask and P0 config
|
28 |
|
|
parameter RAM_ARRAY_SIZE = 32 // Size of the RAM array
|
29 |
|
|
) (
|
30 |
|
|
input wire sysclk, // 20 MHz oscillator input
|
31 |
|
|
// MCS-4 system bus interface
|
32 |
|
|
input wire clk1, // MCS-4 Phase 1 clock
|
33 |
|
|
input wire clk2, // MCS-4 Phase 2 clock
|
34 |
|
|
input wire sync, // MCS-4 Phase synchronization
|
35 |
|
|
input wire reset, // MCS-4 Synchronous reset
|
36 |
|
|
input wire cm, // MCS-4 Command Line (bank select)
|
37 |
|
|
inout tri [3:0] data, // MCS-4 bidirectional data bus
|
38 |
|
|
|
39 |
|
|
output reg [3:0] oport, // i4002 Output port
|
40 |
|
|
|
41 |
|
|
// Ram array dual-port interface
|
42 |
|
|
input wire [4:0] ram0_addr2,
|
43 |
|
|
output wire [3:0] ram0_data2_out,
|
44 |
|
|
input wire [4:0] ram1_addr2,
|
45 |
|
|
output wire [3:0] ram1_data2_out,
|
46 |
|
|
input wire [4:0] ram2_addr2,
|
47 |
|
|
output wire [3:0] ram2_data2_out,
|
48 |
|
|
input wire [4:0] ram3_addr2,
|
49 |
|
|
output wire [3:0] ram3_data2_out
|
50 |
|
|
);
|
51 |
|
|
|
52 |
|
|
//
|
53 |
|
|
// Recover the cycle timing
|
54 |
|
|
//
|
55 |
|
|
wire a12, m12, m22, x22, x32;
|
56 |
|
|
timing_recovery timing_recovery (
|
57 |
|
|
.sysclk (sysclk),
|
58 |
|
|
.clk1 (clk1),
|
59 |
|
|
.clk2 (clk2),
|
60 |
|
|
.sync (sync),
|
61 |
|
|
.a12 (a12),
|
62 |
|
|
.m12 (m12),
|
63 |
|
|
.m22 (m22),
|
64 |
|
|
.x22 (x22),
|
65 |
|
|
.x32 (x32)
|
66 |
|
|
);
|
67 |
|
|
|
68 |
|
|
// Capture OPA during the M2 subcycle
|
69 |
|
|
reg io;
|
70 |
|
|
reg [3:0] opa;
|
71 |
|
|
always @(posedge sysclk) begin
|
72 |
|
|
if (reset) begin
|
73 |
|
|
io = 1'b0;
|
74 |
|
|
opa = 4'b0000;
|
75 |
|
|
end
|
76 |
|
|
else begin
|
77 |
|
|
if (clk2 & m22) begin
|
78 |
|
|
io = cm;
|
79 |
|
|
opa = data;
|
80 |
|
|
end
|
81 |
|
|
end
|
82 |
|
|
end
|
83 |
|
|
|
84 |
|
|
// Decode I/O type operations
|
85 |
|
|
wire wrm = io & (opa == 4'b0000);
|
86 |
|
|
wire wmp = io & (opa == 4'b0001);
|
87 |
|
|
wire wrx = io & (opa[3:2] == 2'b01);
|
88 |
|
|
wire rdm = io & (opa[3:2] == 2'b10) & (opa[1:0] != 2'b10);
|
89 |
|
|
wire rdx = io & (opa[3:2] == 2'b11);
|
90 |
|
|
|
91 |
|
|
// Capture the SRC address during the X22/X32 subcycles
|
92 |
|
|
reg ram_sel = 1'b0;
|
93 |
|
|
reg src_ram_sel = 1'b0;
|
94 |
|
|
reg [1:0] reg_num = 2'b00;
|
95 |
|
|
reg [3:0] char_num = 4'b0000;
|
96 |
|
|
always @(posedge sysclk) begin
|
97 |
|
|
if (reset) begin
|
98 |
|
|
ram_sel = 1'b0;
|
99 |
|
|
src_ram_sel = 1'b0;
|
100 |
|
|
reg_num = 2'b00;
|
101 |
|
|
char_num = 4'b0000;
|
102 |
|
|
end
|
103 |
|
|
else begin
|
104 |
|
|
if (cm & x22 & clk2) begin
|
105 |
|
|
ram_sel = (data[3:2] == CHIP_NUMBER);
|
106 |
|
|
src_ram_sel = ram_sel;
|
107 |
|
|
reg_num = data[1:0];
|
108 |
|
|
end
|
109 |
|
|
if (clk2 & x32 & src_ram_sel) begin
|
110 |
|
|
char_num = data;
|
111 |
|
|
end
|
112 |
|
|
if (a12) begin
|
113 |
|
|
src_ram_sel = 1'b0;
|
114 |
|
|
end
|
115 |
|
|
end
|
116 |
|
|
end
|
117 |
|
|
|
118 |
|
|
// Decode the register address
|
119 |
|
|
wire [4:0] reg_addr = opa[2] ? {3'b100, opa[1:0]} :
|
120 |
|
|
{1'b0, char_num};
|
121 |
|
|
wire reg_write = ram_sel & clk2 & x22 & (wrm | wrx);
|
122 |
|
|
wire reg0_write = reg_write & (reg_num == 2'b00);
|
123 |
|
|
wire reg1_write = reg_write & (reg_num == 2'b01);
|
124 |
|
|
wire reg2_write = reg_write & (reg_num == 2'b10);
|
125 |
|
|
wire reg3_write = reg_write & (reg_num == 2'b11);
|
126 |
|
|
|
127 |
|
|
// Latch the output port value
|
128 |
|
|
always @(posedge sysclk) begin
|
129 |
|
|
if (reset) begin
|
130 |
|
|
oport = 4'b0000;
|
131 |
|
|
end
|
132 |
|
|
else if (ram_sel) begin
|
133 |
|
|
if (clk2 & x22 & wmp)
|
134 |
|
|
oport = data;
|
135 |
|
|
end
|
136 |
|
|
end
|
137 |
|
|
|
138 |
|
|
//
|
139 |
|
|
// In a real i4002, the RAM array is refreshed as follows:
|
140 |
|
|
// 1) During the M11 subcycle, CLK1 causes all column sense
|
141 |
|
|
// lines to be precharged to a "high" state.
|
142 |
|
|
// 2) During the M12 subcycle, the refresh row counter selects
|
143 |
|
|
// a row to be refreshed. CLK2 causes the selected row to
|
144 |
|
|
// be read onto the column sense lines.
|
145 |
|
|
// 3) During the M22 subcycle, the selected row is rewritten
|
146 |
|
|
// with the data read during the M12 subcycle.
|
147 |
|
|
//
|
148 |
|
|
// The refresh row counter is 5 bits wide, and counts from 0x1f
|
149 |
|
|
// down to 0x00 before rolling over. The upper bit determines
|
150 |
|
|
// whether a "main memory" or "status" row is selected. Since
|
151 |
|
|
// there are 16 "main memory" rows but only four status rows,
|
152 |
|
|
// the status rows are refreshed four times per refresh cycle.
|
153 |
|
|
//
|
154 |
|
|
// The RAM array is written using a similar sequence:
|
155 |
|
|
// 1) During the X11 subcycle, CLK1 causes all column sense
|
156 |
|
|
// lines to be precharged to a "high" state.
|
157 |
|
|
// 2) During the X12 subcycle, a row is selected based on the
|
158 |
|
|
// most recent SRC command or the low two bits of OPA for
|
159 |
|
|
// status register reads and writes. CLK2 causes the
|
160 |
|
|
// selected row to be read onto the column sense lines.
|
161 |
|
|
// 3) During the X21 subcycle, if the current operation is a
|
162 |
|
|
// read, the data from the selected register is gated onto
|
163 |
|
|
// the data bus.
|
164 |
|
|
// 4) During the X22 subcycle, if the current operation is a
|
165 |
|
|
// write, the selected row is written. The previously
|
166 |
|
|
// selected register receives the data from the data bus,
|
167 |
|
|
// while the other registers in the row receive the data
|
168 |
|
|
// read during the X12 subcycle.
|
169 |
|
|
//
|
170 |
|
|
// When the RESET line is asserted, the RAM row read operations
|
171 |
|
|
// are inhibited. This causes the refresh operations to write
|
172 |
|
|
// zeros into the RAM. Also inhibited are the data bus gate
|
173 |
|
|
// signals, preventing data bus values from being written during
|
174 |
|
|
// any erroneous write operations.
|
175 |
|
|
//
|
176 |
|
|
reg [4:0] rfsh_addr = 5'd0;
|
177 |
|
|
reg [4:0] rfsh_next = 5'd0;
|
178 |
|
|
always @(posedge sysclk) begin
|
179 |
|
|
if (m12)
|
180 |
|
|
rfsh_addr <= rfsh_next;
|
181 |
|
|
if (m22)
|
182 |
|
|
rfsh_next <= rfsh_addr + 1'd1;
|
183 |
|
|
end
|
184 |
|
|
|
185 |
|
|
//
|
186 |
|
|
// Mux the RAM's write port signals
|
187 |
|
|
//
|
188 |
|
|
wire [4:0] ram_addr = reset ? rfsh_addr : reg_addr;
|
189 |
|
|
wire [3:0] ram_data_out = reset ? 4'h0 : data;
|
190 |
|
|
wire ram0_write = reset ? 1'b1 : reg0_write;
|
191 |
|
|
wire ram1_write = reset ? 1'b1 : reg1_write;
|
192 |
|
|
wire ram2_write = reset ? 1'b1 : reg2_write;
|
193 |
|
|
wire ram3_write = reset ? 1'b1 : reg3_write;
|
194 |
|
|
|
195 |
|
|
// Select the correct RAM output
|
196 |
|
|
wire [3:0] ram0_data_in;
|
197 |
|
|
wire [3:0] ram1_data_in;
|
198 |
|
|
wire [3:0] ram2_data_in;
|
199 |
|
|
wire [3:0] ram3_data_in;
|
200 |
|
|
reg [3:0] reg_data_in;
|
201 |
|
|
always @(*) begin
|
202 |
|
|
case (reg_num)
|
203 |
|
|
2'b00 : reg_data_in = ram0_data_in;
|
204 |
|
|
2'b01 : reg_data_in = ram1_data_in;
|
205 |
|
|
2'b10 : reg_data_in = ram2_data_in;
|
206 |
|
|
2'b11 : reg_data_in = ram3_data_in;
|
207 |
|
|
endcase
|
208 |
|
|
end
|
209 |
|
|
|
210 |
|
|
wire reg_read = ram_sel & x22 & (rdm | rdx);
|
211 |
|
|
assign data = reg_read ? reg_data_in : 4'bzzzz;
|
212 |
|
|
|
213 |
|
|
|
214 |
|
|
// Instantiate RAM0 array
|
215 |
|
|
i4002_ram #(
|
216 |
|
|
.RAM_ARRAY_SIZE (RAM_ARRAY_SIZE)
|
217 |
|
|
) ram0 (
|
218 |
|
|
.sysclk (sysclk),
|
219 |
|
|
.addr (ram_addr),
|
220 |
|
|
.write (ram0_write),
|
221 |
|
|
.data_in (ram_data_out),
|
222 |
|
|
.data_out (ram0_data_in),
|
223 |
|
|
.addr2 (ram0_addr2),
|
224 |
|
|
.data2_out (ram0_data2_out)
|
225 |
|
|
);
|
226 |
|
|
|
227 |
|
|
// Instantiate RAM1 array
|
228 |
|
|
i4002_ram #(
|
229 |
|
|
.RAM_ARRAY_SIZE (RAM_ARRAY_SIZE)
|
230 |
|
|
) ram1 (
|
231 |
|
|
.sysclk (sysclk),
|
232 |
|
|
.addr (ram_addr),
|
233 |
|
|
.write (ram1_write),
|
234 |
|
|
.data_in (ram_data_out),
|
235 |
|
|
.data_out (ram1_data_in),
|
236 |
|
|
.addr2 (ram1_addr2),
|
237 |
|
|
.data2_out (ram1_data2_out)
|
238 |
|
|
);
|
239 |
|
|
|
240 |
|
|
// Instantiate RAM2 array
|
241 |
|
|
i4002_ram #(
|
242 |
|
|
.RAM_ARRAY_SIZE (RAM_ARRAY_SIZE)
|
243 |
|
|
) ram2 (
|
244 |
|
|
.sysclk (sysclk),
|
245 |
|
|
.addr (ram_addr),
|
246 |
|
|
.write (ram2_write),
|
247 |
|
|
.data_in (ram_data_out),
|
248 |
|
|
.data_out (ram2_data_in),
|
249 |
|
|
.addr2 (ram2_addr2),
|
250 |
|
|
.data2_out (ram2_data2_out)
|
251 |
|
|
);
|
252 |
|
|
|
253 |
|
|
// Instantiate RAM3 array
|
254 |
|
|
i4002_ram #(
|
255 |
|
|
.RAM_ARRAY_SIZE (RAM_ARRAY_SIZE)
|
256 |
|
|
) ram3 (
|
257 |
|
|
.sysclk (sysclk),
|
258 |
|
|
.addr (ram_addr),
|
259 |
|
|
.write (ram3_write),
|
260 |
|
|
.data_in (ram_data_out),
|
261 |
|
|
.data_out (ram3_data_in),
|
262 |
|
|
.addr2 (ram3_addr2),
|
263 |
|
|
.data2_out (ram3_data2_out)
|
264 |
|
|
);
|
265 |
|
|
|
266 |
|
|
endmodule
|