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

Subversion Repositories mcs-4

[/] [mcs-4/] [trunk/] [rtl/] [verilog/] [i4002/] [i4002.v] - Blame information for rev 6

Details | Compare with Previous | View Log

Line No. Rev Author Line
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

powered by: WebSVN 2.1.0

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