OpenCores
URL https://opencores.org/ocsvn/aoocs/aoocs/trunk

Subversion Repositories aoocs

[/] [aoocs/] [trunk/] [rtl/] [cia8520.v] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 alfik
/*
2
 * Copyright 2010, Aleksander Osman, alfik@poczta.fm. All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or without modification, are
5
 * permitted provided that the following conditions are met:
6
 *
7
 *  1. Redistributions of source code must retain the above copyright notice, this list of
8
 *     conditions and the following disclaimer.
9
 *
10
 *  2. Redistributions in binary form must reproduce the above copyright notice, this list
11
 *     of conditions and the following disclaimer in the documentation and/or other materials
12
 *     provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
15
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
17
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
 */
24
 
25
/*! \file
26
 * \brief Commodore 8520 Complex Interface Adapter implementation.
27
 */
28
 
29
/*! \brief \copybrief cia8520.v
30
*/
31
module cia8520(
32
    //% \name Clock and reset
33
    //% @{
34
    input CLK_I,
35
    input reset_n,
36
    //% @}
37
 
38
    //% \name WISHBONE slave
39
    //% @{
40
    input CYC_I,
41
    input STB_I,
42
    input WE_I,
43
    input [3:0] ADR_I,
44
    input [7:0] DAT_I,
45
    output reg ACK_O,
46
    output reg [7:0] DAT_O,
47
    //% @}
48
 
49
    //% \name Internal OCS ports
50
    //% @{
51
    input pulse_709379_hz,
52
    //% @}
53
 
54
    //% \name 8520 synchronous interface
55
    //% @{
56
    output [7:0] pa_o,
57
    output [7:0] pb_o,
58
    input [7:0] pa_i,
59
    input [7:0] pb_i,
60
 
61
    input flag_n,
62
    output reg pc_n,
63
    input tod,
64
    output irq_n,
65
 
66
    input sp_i,
67
    output reg sp_o,
68
    input cnt_i,
69
    output reg cnt_o
70
    //% @}
71
);
72
 
73
reg [7:0] pa_o_reg;
74
assign pa_o = (ddra & pa_o_reg) | (~ddra & pa_i);
75
reg [7:0] pb_o_reg;
76
assign pb_o = (ddrb & pb_o_reg) | (~ddrb & pb_i);
77
 
78
assign irq_n = ~icr_data[5];
79
 
80
reg last_cnt_i;
81
 
82
// 0 = input, 1 = output
83
reg [7:0] ddra;
84
reg [7:0] ddrb;
85
 
86
reg [15:0] timera_latch;
87
reg [15:0] timerb_latch;
88
reg [5:0] cra;
89
reg [6:0] crb;
90
reg [23:0] tod_counter;
91
reg [23:0] tod_latch;
92
reg tod_write_stop;
93
reg tod_read_latch;
94
reg [23:0] tod_alarm;
95
 
96
reg serial_irq;
97
reg [7:0] serial_latch;
98
reg serial_latched;
99
reg [7:0] serial_shift;
100
reg [4:0] serial_counter;
101
 
102
reg [5:0] icr_mask;
103
reg [5:0] icr_data;
104
 
105
wire icr_data_read;
106
assign icr_data_read = (CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b0 && ADR_I == 4'd13) ? 1'b1 : 1'b0;
107
 
108
// from datasheet:
109
// write high && one-shot && stopped(?) ----> timer <= latch; initiate counting regardless start; start <= 1'b1(?)
110
// write high && stopped ----> timer <= latch;
111
// write high && running ----> latch
112
 
113
// Timer A
114
reg [15:0] timera;
115
reg underflowa;
116
 
117
wire timera_force_load;
118
assign timera_force_load =
119
    (CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b1 && ADR_I == 4'd14 && DAT_I[4] == 1'b1 && ACK_O == 1'b1) ? 1'b1 : 1'b0;
120
 
121
wire timera_loadhigh_when_stopped;
122
assign timera_loadhigh_when_stopped =
123
    (CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b1 && ADR_I == 4'd5 && cra[0] == 1'b0 && ACK_O == 1'b1) ? 1'b1 : 1'b0;
124
 
125
wire timera_tick;
126
assign timera_tick =
127
    (cra[0] == 1'b1 &&
128
        (
129
            (cra[4] == 1'b0 && pulse_709379_hz == 1'b1) ||
130
            (cra[4] == 1'b1 && last_cnt_i == 1'b0 && cnt_i == 1'b1)
131
        )
132
    ) ? 1'b1 : 1'b0;
133
 
134
// Timer B
135
reg [15:0] timerb;
136
reg underflowb;
137
 
138
wire timerb_force_load;
139
assign timerb_force_load =
140
    (CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b1 && ADR_I == 4'd15 && DAT_I[4] == 1'b1 && ACK_O == 1'b1) ? 1'b1 : 1'b0;
141
 
142
wire timerb_loadhigh_when_stopped;
143
assign timerb_loadhigh_when_stopped =
144
    (CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b1 && ADR_I == 4'd7 && crb[0] == 1'b0 && ACK_O == 1'b1) ? 1'b1 : 1'b0;
145
 
146
wire timerb_tick;
147
assign timerb_tick =
148
    (crb[0] == 1'b1 &&
149
        (
150
            (crb[5:4] == 2'b00 && pulse_709379_hz == 1'b1) ||
151
            (crb[5:4] == 2'b01 && last_cnt_i == 1'b0 && cnt_i == 1'b1) ||
152
            (crb[5:4] == 2'b10 && underflowa == 1'b1) ||
153
            (crb[5:4] == 2'b11 && underflowa == 1'b1 && cnt_i == 1'b1)
154
        )
155
    ) ? 1'b1 : 1'b0;
156
 
157
wire alarm;
158
assign alarm = (tod_counter == tod_alarm);
159
 
160
always @(posedge CLK_I or negedge reset_n) begin
161
    if(reset_n == 1'b0) begin
162
        ACK_O <= 1'b0;
163
        DAT_O <= 8'd0;
164
 
165
        pa_o_reg <= 8'd0;
166
        pb_o_reg <= 8'd0;
167
        ddra <= 8'd0;
168
        ddrb <= 8'd0;
169
 
170
        timera <= 16'd0;
171
        underflowa <= 1'b0;
172
        timerb <= 16'd0;
173
        underflowb <= 1'b0;
174
 
175
        timera_latch <= 16'hFFFF;
176
        timerb_latch <= 16'hFFFF;
177
        cra <= 6'd0;
178
        crb <= 7'd0;
179
 
180
        tod_counter <= 24'd0;
181
        tod_latch <= 24'd0;
182
        tod_write_stop <= 1'b1;
183
        tod_read_latch <= 1'b0;
184
        tod_alarm <= 24'd0;
185
 
186
        pc_n <= 1'b1;
187
 
188
        sp_o <= 1'b1;
189
        cnt_o <= 1'b1;
190
        serial_irq <= 1'b0;
191
        serial_latch <= 8'd0;
192
        serial_latched <= 1'b0;
193
        serial_shift <= 8'd0;
194
        serial_counter <= 5'd0;
195
 
196
        icr_mask <= 6'd0;
197
        icr_data <= 6'd0;
198
    end
199
    else begin
200
        last_cnt_i <= cnt_i;
201
 
202
        if(ACK_O == 1'b1)                           ACK_O <= 1'b0;
203
        else if(CYC_I == 1'b1 && STB_I == 1'b1)     ACK_O <= 1'b1;
204
 
205
        if(tod == 1'b1 && tod_write_stop == 1'b0) tod_counter <= tod_counter + 24'd1;
206
 
207
        if(pc_n == 1'b0) pc_n <= 1'b1;
208
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && ADR_I == 4'd1 && ACK_O == 1'b1) pc_n <= 1'b0;
209
 
210
        // interrupt data
211
        if(underflowa == 1'b1)  icr_data[0] <= 1'b1;        else if(icr_data_read == 1'b1) icr_data[0] <= 1'b0;
212
        if(underflowb == 1'b1)  icr_data[1] <= 1'b1;        else if(icr_data_read == 1'b1) icr_data[1] <= 1'b0;
213
        if(alarm == 1'b1)       icr_data[2] <= 1'b1;        else if(icr_data_read == 1'b1) icr_data[2] <= 1'b0;
214
        if(serial_irq == 1'b1)  icr_data[3] <= 1'b1;        else if(icr_data_read == 1'b1) icr_data[3] <= 1'b0;
215
        if(flag_n == 1'b0)      icr_data[4] <= 1'b1;        else if(icr_data_read == 1'b1) icr_data[4] <= 1'b0;
216
 
217
        if( (underflowa == 1'b1     && icr_mask[0] == 1'b1) ||
218
            (underflowb == 1'b1     && icr_mask[1] == 1'b1) ||
219
            (alarm == 1'b1          && icr_mask[2] == 1'b1) ||
220
            (serial_irq == 1'b1     && icr_mask[3] == 1'b1) ||
221
            (flag_n == 1'b0         && icr_mask[4] == 1'b1)
222
        ) begin
223
            icr_data[5] <= 1'b1;
224
        end
225
        else if(icr_data_read == 1'b1) icr_data[5] <= 1'b0;
226
 
227
 
228
        //******** SERIAL
229
        if(serial_irq == 1'b1) serial_irq <= 1'b0;
230
 
231
        // serial output
232
        if(cra[5] == 1'b1) begin
233
            if(serial_counter == 5'd0 && serial_latched == 1'b1) begin
234
                serial_shift <= serial_latch;
235
                serial_counter <= 5'd1;
236
                serial_latched <= 1'b0;
237
            end
238
            else if(serial_counter > 5'd0 && serial_counter[0] == 1'b1 && underflowa == 1'b1) begin
239
                 serial_counter <= serial_counter + 5'd1;
240
                 cnt_o <= 1'b0;
241
                 sp_o <= serial_shift[7];
242
                 serial_shift <= { serial_shift[6:0], 1'b0 };
243
            end
244
            else if(serial_counter > 5'd0 && serial_counter[0] == 1'b0 && underflowa == 1'b1) begin
245
                 cnt_o <= 1'b1;
246
                 if(serial_counter == 5'd16) begin
247
                    if(serial_latched == 1'b0) begin
248
                        serial_irq <= 1'b1;
249
                        serial_counter <= 5'd0;
250
                    end
251
                    else begin
252
                        serial_shift <= serial_latch;
253
                        serial_counter <= 5'd1;
254
                        serial_latched <= 1'b0;
255
                    end
256
                 end
257
                 else serial_counter <= serial_counter + 5'd1;
258
            end
259
        end
260
        // serial input
261
        else begin
262
            if(last_cnt_i == 1'b0 && cnt_i == 1'b1) begin
263
                serial_shift <= { serial_shift[6:0], sp_i };
264
 
265
                if(serial_counter == 5'd7) begin
266
                    serial_counter <= 5'd0;
267
                    serial_latch <= { serial_shift[6:0], sp_i };
268
                    serial_irq <= 1'b1;
269
                    serial_counter <= 5'd0;
270
                end
271
                else serial_counter <= serial_counter + 5'd1;
272
            end
273
        end
274
 
275
        // Timer A
276
        // PBON==on, OUTMODE==toggle, START==on
277
        if(cra[1] == 1'b1 && cra[2] == 1'b1 && cra[0] == 1'b1) pb_o_reg[6] <= 1'b1;
278
        // PBON==on, OUTMODE==pulse
279
        else if(cra[1] == 1'b1 && cra[2] == 1'b0) pb_o_reg[6] <= underflowa;
280
 
281
        // START==on, RUNMODE==single-shot, underflowa
282
        if(cra[0] == 1'b1 && cra[3] == 1'b1 && underflowa == 1'b1) cra[0] <= 1'b0;
283
 
284
        if(underflowa == 1'b1) underflowa <= 1'b0;
285
 
286
        if(timera_force_load == 1'b1 || timera_loadhigh_when_stopped == 1'b1) timera <= timera_latch;
287
        else if(timera_tick == 1'b1 && timera == 16'd1) begin
288
            timera <= timera_latch;
289
            underflowa <= 1'b1;
290
        end
291
        else if(timera_tick == 1'b1) timera <= timera - 16'd1;
292
 
293
 
294
        // Timer B
295
        // PBON==on, OUTMODE==toggle, START==on
296
        if(crb[1] == 1'b1 && crb[2] == 1'b1 && crb[0] == 1'b1) pb_o_reg[7] <= 1'b1;
297
        // PBON==on, OUTMODE==pulse
298
        else if(crb[1] == 1'b1 && crb[2] == 1'b0) pb_o_reg[7] <= underflowb;
299
 
300
        // START==on, RUNMODE==single-shot, underflowa
301
        if(crb[0] == 1'b1 && crb[3] == 1'b1 && underflowb == 1'b1) crb[0] <= 1'b0;
302
 
303
        if(underflowb == 1'b1) underflowb <= 1'b0;
304
 
305
        if(timerb_force_load == 1'b1 || timerb_loadhigh_when_stopped == 1'b1) timerb <= timerb_latch;
306
        else if(timerb_tick == 1'b1 && timerb == 16'd1) begin
307
            timerb <= timerb_latch;
308
            underflowb <= 1'b1;
309
        end
310
        else if(timerb_tick == 1'b1) timerb <= timerb - 16'd1;
311
 
312
        // Port Register A write
313
        if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b1 && ADR_I == 4'd0)         pa_o_reg <= DAT_I;
314
        // Port Register A read
315
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b0 && ADR_I == 4'd0)    DAT_O <= (ddra & pa_o_reg) | (~ddra & pa_i);
316
        // Port Register B write
317
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b1 && ADR_I == 4'd1) begin
318
            if(cra[1] == 1'b0 && crb[1] == 1'b0)        pb_o_reg <= DAT_I;
319
            else if(cra[1] == 1'b1 && crb[1] == 1'b0)   {pb_o_reg[7],pb_o_reg[5:0]} <= {DAT_I[7],DAT_I[5:0]};
320
            else if(cra[1] == 1'b0 && crb[1] == 1'b1)   pb_o_reg[6:0]               <= DAT_I[6:0];
321
            else if(cra[1] == 1'b1 && crb[1] == 1'b1)   pb_o_reg[5:0]               <= DAT_I[5:0];
322
        end
323
        // Port Register B read
324
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b0 && ADR_I == 4'd1)    DAT_O <= (ddrb & pb_o_reg) | (~ddrb & pb_i);
325
        // Data Direction Register A write
326
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b1 && ADR_I == 4'd2)    ddra <= DAT_I;
327
        // Data Direction Register A read
328
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b0 && ADR_I == 4'd2)    DAT_O <= ddra;
329
        // Data Direction Register B write
330
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b1 && ADR_I == 4'd3)    ddrb <= DAT_I;
331
        // Data Direction Register B read
332
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b0 && ADR_I == 4'd3)    DAT_O <= ddrb;
333
 
334
        // Timer A Low byte write
335
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b1 && ADR_I == 4'd4)    timera_latch[7:0] <= DAT_I;
336
        // Timer A Low byte read
337
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b0 && ADR_I == 4'd4)    DAT_O <= timera[7:0];
338
        // Timer A High byte write
339
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b1 && ADR_I == 4'd5) begin
340
            timera_latch[15:8] <= DAT_I;
341
            // START==off, RUNMODE==single-shot
342
            if(cra[0] == 1'b0 && cra[3] == 1'b1) cra[0] <= 1'b1;
343
        end
344
        // Timer A High byte read
345
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b0 && ADR_I == 4'd5)    DAT_O <= timera[15:8];
346
 
347
        // Timer B Low byte write
348
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b1 && ADR_I == 4'd6)    timerb_latch[7:0] <= DAT_I;
349
        // Timer B Low byte read
350
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b0 && ADR_I == 4'd6)    DAT_O <= timerb[7:0];
351
        // Timer B High byte write
352
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b1 && ADR_I == 4'd7) begin
353
            timerb_latch[15:8] <= DAT_I;
354
            // START==off, RUNMODE==single-shot
355
            if(crb[0] == 1'b0 && crb[3] == 1'b1) crb[0] <= 1'b1;
356
        end
357
        // Timer B High byte read
358
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b0 && ADR_I == 4'd7)    DAT_O <= timerb[15:8];
359
 
360
        // TOD/ALARM low byte write
361
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b1 && ADR_I == 4'd8) begin
362
            if(crb[6] == 1'b0) begin
363
                tod_counter[7:0] <= DAT_I;
364
                tod_write_stop <= 1'b0;
365
            end
366
            else tod_alarm[7:0] <= DAT_I;
367
        end
368
        // TOD low byte read
369
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b0 && ADR_I == 4'd8) begin
370
            if(tod_read_latch == 1'b0) DAT_O <= tod_counter[7:0];
371
            else begin
372
                DAT_O <= tod_latch[7:0];
373
                tod_read_latch <= 1'b0;
374
            end
375
        end
376
        // TOD/ALARM mid byte write
377
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b1 && ADR_I == 4'd9) begin
378
            if(crb[6] == 1'b0) begin
379
                tod_counter[15:8] <= DAT_I;
380
            end
381
            else tod_alarm[15:8] <= DAT_I;
382
        end
383
        // TOD mid byte read
384
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b0 && ADR_I == 4'd9) begin
385
            if(tod_read_latch == 1'b0) DAT_O <= tod_counter[15:8];
386
            else DAT_O <= tod_latch[15:8];
387
        end
388
        // TOD/ALARM high byte write
389
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b1 && ADR_I == 4'd10) begin
390
            if(crb[6] == 1'b0) begin
391
                tod_counter[23:16] <= DAT_I;
392
                tod_write_stop <= 1'b1;
393
            end
394
            else tod_alarm[23:16] <= DAT_I;
395
        end
396
        // TOD high byte read
397
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b0 && ADR_I == 4'd10) begin
398
            DAT_O <= tod_counter[23:16];
399
            tod_latch <= tod_counter;
400
            tod_read_latch <= 1'b1;
401
        end
402
        // empty register write
403
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b1 && ADR_I == 4'd11) begin
404
        end
405
        // empty register read
406
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b0 && ADR_I == 4'd11)   DAT_O <= 8'd0;
407
        // Serial Data Register write
408
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b1 && ADR_I == 4'd12) begin
409
            serial_latch <= DAT_I;
410
            serial_latched <= 1'b1;
411
        end
412
        // Serial Data Register read
413
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b0 && ADR_I == 4'd12)    DAT_O <= serial_latch;
414
        // Interrupt Control Register write
415
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b1 && ADR_I == 4'd13) begin
416
            if(DAT_I[7] == 1'b1)  icr_mask <= icr_mask | DAT_I[5:0];
417
            else                  icr_mask <= icr_mask & (~DAT_I[5:0]);
418
        end
419
        // Interrupt Control Register read
420
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b0 && ADR_I == 4'd13)   DAT_O <= { icr_data[5], 2'b0, icr_data[4:0] };
421
 
422
        // Control Register A write
423
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b1 && ADR_I == 4'd14) begin
424
            cra <= { DAT_I[6:5], DAT_I[3:0] };
425
 
426
            if(cra[5] != DAT_I[6]) begin
427
                serial_latched <= 1'b0;
428
                serial_counter <= 5'd0;
429
 
430
                cnt_o <= 1'b1;
431
                sp_o <= (DAT_I[6] == 1'b0) ? 1'b1 : 1'b0;
432
            end
433
        end
434
        // Control Register A read
435
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b0 && ADR_I == 4'd14)   DAT_O <= { 1'b0, cra[5:4], 1'b0, cra[3:0] };
436
        // Control Register B write
437
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b1 && ADR_I == 4'd15)   crb <= { DAT_I[7:5], DAT_I[3:0] };
438
        // Control Register B read
439
        else if(CYC_I == 1'b1 && STB_I == 1'b1 && WE_I == 1'b0 && ADR_I == 4'd15)   DAT_O <= { crb[6:4], 1'b0, crb[3:0] };
440
    end
441
end
442
 
443
endmodule
444
 

powered by: WebSVN 2.1.0

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