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

Subversion Repositories mcs-4

[/] [mcs-4/] [trunk/] [rtl/] [verilog/] [i4001/] [i4001.v] - Blame information for rev 7

Go to most recent revision | 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 i4001 ROM and I/O Port module
6
//
7
// This module emulates the Intel 4001 ROM and I/O chip. To make the
8
// most efficient use of FPGA block ram resources, the ROM storage
9
// is implemented using an "i4001_rom" module, which can be connected
10
// to multiple "i4001" modules via a rom_addr / rom_data bus.
11
//
12
// This file is part of the MCS-4 project hosted at OpenCores:
13
//      http://www.opencores.org/cores/mcs-4/
14
//
15
// Copyright © 2021 by Reece Pollack <rrpollack@opencores.org>
16
//
17
// These materials are provided under the Creative Commons
18
// "Attribution-NonCommercial-ShareAlike" (CC BY-NC-SA) Public License.
19
// They are NOT "public domain", and are protected by copyright.
20
//
21
// This work based on materials provided by Intel Corporation and
22
// others under the same license. See the file doc/License for
23
// details of this license.
24
//
25
////////////////////////////////////////////////////////////////////////
26
 
27
module i4001 #(
28
    parameter [3:0] ROM_NUMBER  = 4'd0,
29
    parameter [3:0] IO_OUTPUT   = 4'b0000,
30
    parameter [3:0] IO_INVERT   = 4'b0000,
31
    parameter [3:0] IO_PULLUP   = 4'b0000,
32
    parameter [3:0] IO_PULLDOWN = 4'b0000
33
    ) (
34
    input  wire         sysclk,
35
    input  wire         clk1_pad,
36
    input  wire         clk2_pad,
37
    input  wire         sync_pad,
38
    input  wire         poc_pad,
39
    input  wire         cmrom_pad,
40
    inout  tri  [3:0]   data_pad,
41
    inout  wire [3:0]   io_pad,
42
    input  wire         clear_pad,
43
    output wor  [11:0]  rom_addr,
44
    input  wire [ 7:0]  rom_data
45
    );
46
 
47
    // FUTURE: Sync these to the sysclk domain
48
    wire clk1   = clk1_pad;
49
    wire clk2   = clk2_pad;
50
    wire sync   = sync_pad;
51
    wire poc    = poc_pad;
52
    wire cmrom  = cmrom_pad;
53
    wire clear  = clear_pad;
54
 
55
    // Identify the execution phases
56
    wire    a12, a22, a32;
57
    wire    m11, m12, m21, m22;
58
    wire    x21, x22;
59
    timing_recovery timing_recovery (
60
        .sysclk (sysclk),
61
        .clk1   (clk1),
62
        .clk2   (clk2),
63
        .sync   (sync),
64
        .a12    (a12),
65
        .a22    (a22),
66
        .a32    (a32),
67
        .m11    (m11),
68
        .m12    (m12),
69
        .m21    (m21),
70
        .m22    (m22),
71
        .x21    (x21),
72
        .x22    (x22)
73
    );
74
 
75
    // Forward declarations
76
    wire mbusread;
77
    wire ioread, iowrite;
78
    wire [3:0]  io_in;
79
    reg  [3:0]  rom_out;
80
    reg         chipsel;
81
 
82
    // Mux ROM and I/O data for output
83
    reg  [3:0]  data_out;
84
    always @(posedge sysclk) begin
85
        if (~clk2) begin
86
            data_out = 4'bxxxx;
87
            if (ioread)   data_out = io_in;
88
            if (mbusread) data_out = rom_out;
89
        end
90
    end
91
 
92
    // Latch external bus drive signal
93
    wire n0108 = ((chipsel & (m11 | m21)) | ioread) & ~poc;
94
    reg  extbusdrive;
95
    always @(posedge sysclk) begin
96
        if (~clk2) begin
97
            extbusdrive <= n0108;
98
        end
99
    end
100
 
101
    // Drive the tristate data bus
102
    assign data_pad = extbusdrive ? data_out : 4'bzzzz;
103
 
104
 
105
    // Common chip number match
106
    wire chipnum = (data_pad == ROM_NUMBER);
107
 
108
 
109
    // =======================================
110
    // ROM interface
111
    // =======================================
112
 
113
    // Latch the address
114
    reg  [7:0]  fetch_addr;
115
    always @(posedge sysclk) begin
116
        if (clk2) begin
117
            if (a12) fetch_addr[ 3:0] <= data_pad;
118
            if (a22) fetch_addr[ 7:4] <= data_pad;
119
        end
120
    end
121
 
122
    // Latch the chip select
123
    always @(posedge sysclk) begin
124
        if (a12)        chipsel <= 1'b0;
125
        if (a32 & clk2) chipsel <= cmrom & chipnum;
126
    end
127
 
128
    reg  n0128;
129
    always @(posedge sysclk) begin
130
        if (clk1) begin
131
            n0128 <= ioread;
132
        end
133
    end
134
    assign mbusread = ~(ioread | n0128);
135
 
136
    // Access the external Block RAM array
137
    assign rom_addr = extbusdrive ? {ROM_NUMBER, fetch_addr} : 12'h000;
138
 
139
    //
140
    // Mux the ROM data for output
141
    //
142
    // A real i4001 muxes the ROM ouputs on M11 and M21, depending on
143
    // inertial delays to provide the required 40ns hold time when
144
    // changing from the upper 4 bits to the lower 4 bits.
145
    //
146
    // Actual measurements show the FPGA emulation of the i4001 switches
147
    // its outputs 10-12ns after CLK2 goes low, while the re-created
148
    // instruction pointer board needs at least 120ns hold time. Oops.
149
    //
150
    // By changing this mux to use M12 and M22 instead, the outputs
151
    // are held at the correct values long enough for the IP board to
152
    // latch the correct values.
153
    //
154
    always @(posedge sysclk) begin
155
        if (m12) rom_out = rom_data[7:4];
156
        if (m22) rom_out = rom_data[3:0];
157
    end
158
 
159
 
160
    // =======================================
161
    // I/O Port interface
162
    // =======================================
163
 
164
    localparam [3:0] OPA_WRR = 4'b0010;
165
    localparam [3:0] OPA_RDR = 4'b1010;
166
 
167
    // SRC flip-flop
168
    reg  srcff;
169
    always @(posedge sysclk) begin
170
        if (clk2) begin
171
            if (x22 & cmrom) srcff <= chipnum;
172
        end
173
    end
174
    wire m22_srcff_cm = m22 & srcff & cmrom;
175
 
176
    // Decode an I/O Read operation
177
    reg  n0161;
178
    // always @(*) begin
179
    //     if (a12)
180
    //         n0161 <= 1'b0;
181
    //     if (clk2 & m22_srcff_cm & (data_pad == OPA_RDR))
182
    //         n0161 <= 1'b1;
183
    // end
184
    always @(posedge sysclk) begin
185
        if (clk2) begin
186
            if (a12)
187
                n0161 <= 1'b0;
188
            if (m22_srcff_cm & (data_pad == OPA_RDR))
189
                n0161 <= 1'b1;
190
        end
191
    end
192
    assign ioread = x21 & n0161;
193
 
194
    // Decode an I/O Write operation
195
    reg  n0135;
196
    // always @(*) begin
197
    //     if (a12)
198
    //         n0135 <= 1'b0;
199
    //     if (clk2 & m22_srcff_cm & (data_pad == OPA_WRR))
200
    //         n0135 <= 1'b1;
201
    // end
202
    always @(posedge sysclk) begin
203
        if (clk2) begin
204
            if (a12)
205
                n0135 <= 1'b0;
206
            if (m22_srcff_cm & (data_pad == OPA_WRR))
207
                n0135 <= 1'b1;
208
        end
209
    end
210
    assign iowrite = x22 & n0135;
211
 
212
    // Latch new output data
213
    reg  [3:0]  io_out;
214
    always @(posedge sysclk) begin
215
        if (clear | poc)
216
            io_out <= 4'b0000;
217
        if (clk2 & iowrite) begin
218
            io_out <= data_pad;
219
        end
220
    end
221
 
222
    // I/O config
223
    generate
224
        genvar p;
225
        for (p = 0; p < 4; p = p + 1) begin: IO_PORTS
226
            if (IO_OUTPUT[p]) begin: IO_OUT_CONFIG
227
                if (IO_INVERT[p])   assign io_pad[p] = ~io_out[p];
228
                else                assign io_pad[p] =  io_out[p];
229
            end
230
            else begin: IO_IN_CONFIG
231
                assign io_pad[p] = 1'bz;
232
                if (IO_PULLUP[p])   PULLUP   pu(.O(io_pad[p]));
233
                if (IO_PULLDOWN[p]) PULLDOWN pd(.O(io_pad[p]));
234
            end
235
            if (IO_INVERT[p])   assign io_in[p] = ~io_pad[p];
236
            else                assign io_in[p] =  io_pad[p];
237
        end
238
    endgenerate
239
 
240
endmodule

powered by: WebSVN 2.1.0

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