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

Subversion Repositories zx_ula

[/] [zx_ula/] [branches/] [xilinx/] [spectrum_48k_spartan3_starter_kit_timex_hicolor_ulaplus/] [ula.v] - Blame information for rev 15

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 15 mcleod_ide
`timescale 1ns / 1ps
2
//////////////////////////////////////////////////////////////////////////////////
3
// Company:        Dept. Architecture and Computing Technology. University of Seville
4
// Engineer:       Miguel Angel Rodriguez Jodar. rodriguj@atc.us.es
5
// 
6
// Create Date:    19:13:39 4-Apr-2012 
7
// Design Name:    ZX Spectrum
8
// Module Name:    ula 
9
// Project Name: 
10
// Target Devices: 
11
// Tool versions: 
12
// Description: 
13
//
14
// Dependencies: 
15
//
16
// Revision: 
17
// Revision 1.00 - File Created
18
// Additional Comments: GPL License policies apply to the contents of this file.
19
//
20
//////////////////////////////////////////////////////////////////////////////////
21
 
22
`define cyclestart(a,b) ((a)==(b))
23
`define cycleend(a,b) ((a)==(b+1))
24
 
25
module ula(
26
    input clk14,                        // 14MHz master clock
27
         input reset,                   // to reset the ULA to normal color mode.
28
         // CPU interfacing
29
    input [15:0] a,              // Address bus from CPU (not all lines are used)
30
    input [7:0] din,             // Input data bus from CPU
31
         output [7:0] dout,      // Output data bus to CPU
32
    input mreq_n,                       // MREQ from CPU
33
    input iorq_n,                       // IORQ from CPU
34
    input rd_n,                 // RD from CPU
35
    input wr_n,                 // WR from CPU
36
         input rfsh_n,                  // RFSH from CPU
37
         output clkcpu,         // CLK to CPU
38
         output msk_int_n,      // Vertical retrace interrupt, to CPU
39
         // VRAM interfacing
40
    output [13:0] va,     // Address bus to VRAM (16K)
41
         input [7:0] vramdout,// Data from VRAM to ULA/CPU
42
         output [7:0] vramdin,// Data from CPU to VRAM
43
    output vramoe,               // 
44
    output vramcs,               // Control signals for VRAM
45
    output vramwe,               //
46
         // ULA I/O
47
    input ear,                             //
48
    output mic,                    // I/O ports
49
    output spk,            //
50
         output [7:0] kbrows,   // Keyboard rows
51
    input [4:0] kbcolumns,       //  Keyboard columns
52
         // Video output
53
    output r,                           //
54
    output g,                           // RGB TTL signal
55
    output b,                           // with separate bright
56
    output i,                           // and composite sync
57
    output csync                        //               
58
    );
59
 
60
        reg [2:0] BorderColor = 3'b100;
61
        reg TimexHiColorMode = 0;
62
 
63
        reg ULAPlusConfig = 0;
64
        reg [7:0] ULAPlusAddrReg = 0;
65
        wire addrportsel = !iorq_n && a[0] && !a[2] && (a[7:6]==2'b00) && (a[15:14]==2'b10); // port BF3Bh
66
        wire dataportsel = !iorq_n && a[0] && !a[2] && (a[7:6]==2'b00) && (a[15:14]==2'b11); // port FF3Bh
67
        wire cpu_writes_palette = dataportsel && !wr_n && (ULAPlusAddrReg[7:6]==2'b00);
68
        reg [5:0] paletteaddr;
69
        wire [7:0] palettedout;
70
        reg palettewe;
71
 
72
        ram64bytes palette (
73
                .clk(clk14),
74
                .a(paletteaddr),
75
                .din(din),
76
                .dout(palettedout),
77
                .we(palettewe)
78
                );
79
 
80
        // Pixel clock
81
        reg clk7 = 0;
82
        always @(posedge clk14)
83
                clk7 <= !clk7;
84
 
85
        // Horizontal counter
86
        reg [8:0] hc = 0;
87
        always @(posedge clk7) begin
88
                if (hc==447)
89
                        hc <= 0;
90
                else
91
                        hc <= hc + 1;
92
        end
93
 
94
        // Vertical counter
95
        reg [8:0] vc = 0;
96
        always @(posedge clk7) begin
97
                if (hc==447) begin
98
                        if (vc == 311)
99
                                vc <= 0;
100
                        else
101
                                vc <= vc + 1;
102
                end
103
        end
104
 
105
        // HBlank generation
106
        reg HBlank_n = 1;
107
        always @(negedge clk7) begin
108
                if (`cyclestart(hc,320))
109
                        HBlank_n <= 0;
110
                else if (`cycleend(hc,415))
111
                        HBlank_n <= 1;
112
        end
113
 
114
        // HSync generation (6C ULA version)
115
        reg HSync_n = 1;
116
        always @(negedge clk7) begin
117
                if (`cyclestart(hc,344))
118
                        HSync_n <= 0;
119
                else if (`cycleend(hc,375))
120
                        HSync_n <= 1;
121
        end
122
 
123
        // VBlank generation
124
        reg VBlank_n = 1;
125
        always @(negedge clk7) begin
126
                if (`cyclestart(vc,248))
127
                        VBlank_n <= 0;
128
                else if (`cycleend(vc,255))
129
                        VBlank_n <= 1;
130
        end
131
 
132
        // VSync generation (PAL)
133
        reg VSync_n = 1;
134
        always @(negedge clk7) begin
135
                if (`cyclestart(vc,248))
136
                        VSync_n <= 0;
137
                else if (`cycleend(vc,251))
138
                        VSync_n <= 1;
139
        end
140
 
141
        // INT generation
142
        reg INT_n = 1;
143
        assign msk_int_n = INT_n;
144
        always @(negedge clk7) begin
145
                if (`cyclestart(vc,248) && `cyclestart(hc,0))
146
                        INT_n <= 0;
147
                else if (`cyclestart(vc,248) && `cycleend(hc,31))
148
                        INT_n <= 1;
149
        end
150
 
151
        // Border control signal (=0 when we're not displaying paper/ink pixels)
152
        reg Border_n = 1;
153
        always @(negedge clk7) begin
154
                if ( (vc[7] & vc[6]) | vc[8] | hc[8])
155
                        Border_n <= 0;
156
                else
157
                        Border_n <= 1;
158
        end
159
 
160
        // VidEN generation (delaying Border 8 clocks)
161
        reg VidEN_n = 1;
162
        always @(negedge clk7) begin
163
                if (hc[3])
164
                        VidEN_n <= !Border_n;
165
        end
166
 
167
        // DataLatch generation (posedge to capture data from memory)
168
        reg DataLatch_n = 1;
169
        always @(negedge clk7) begin
170
                if (hc[0] & hc[1] & Border_n & hc[3])
171
                        DataLatch_n <= 0;
172
                else
173
                        DataLatch_n <= 1;
174
        end
175
 
176
        // AttrLatch generation (posedge to capture data from memory)
177
        reg AttrLatch_n = 1;
178
        always @(negedge clk7) begin
179
                if (hc[0] & !hc[1] & Border_n & hc[3])
180
                        AttrLatch_n <= 0;
181
                else
182
                        AttrLatch_n <= 1;
183
        end
184
 
185
        // SLoad generation (negedge to load shift register)
186
        reg SLoad = 0;
187
        always @(negedge clk7) begin
188
                if (!hc[0] & !hc[1] & hc[2] & !VidEN_n)
189
                        SLoad <= 1;
190
                else
191
                        SLoad <= 0;
192
        end
193
 
194
        // AOLatch generation (negedge to update attr output latch)
195
        reg AOLatch_n = 1;
196
        always @(negedge clk7) begin
197
                if (hc[0] & !hc[1] & hc[2])
198
                        AOLatch_n <= 0;
199
                else
200
                        AOLatch_n <= 1;
201
        end
202
 
203
        // First buffer for bitmap
204
        reg [7:0] BitmapReg = 0;
205
        always @(negedge DataLatch_n) begin
206
                BitmapReg <= vramdout;
207
        end
208
 
209
        // Shift register (second bitmap register)
210
        reg [7:0] SRegister = 0;
211
        always @(negedge clk7) begin
212
                if (SLoad)
213
                        SRegister <= BitmapReg;
214
                else
215
                        SRegister <= {SRegister[6:0],1'b0};
216
        end
217
 
218
        // First buffer for attribute
219
        reg [7:0] AttrReg = 0;
220
        always @(negedge AttrLatch_n) begin
221
                AttrReg <= vramdout;
222
        end
223
 
224
        // Second buffer for attribute
225
        reg [7:0] AttrOut = 0;
226
        always @(negedge AOLatch_n) begin
227
                if (!VidEN_n)
228
                        AttrOut <= AttrReg;
229
                else
230
                        AttrOut <= {2'b00,BorderColor,BorderColor};
231
        end
232
 
233
        // Flash counter and pixel generation
234
        reg [4:0] FlashCnt = 0;
235
        always @(negedge VSync_n) begin
236
                FlashCnt <= FlashCnt + 1;
237
        end
238
        wire Pixel = SRegister[7] ^ (AttrOut[7] & FlashCnt[4]);
239
 
240
        // RGB generation
241
        reg rI,rG,rR,rB;
242
        assign r = rR;
243
        assign g = rG;
244
        assign b = rB;
245
        assign i = rI;
246
        always @(*) begin
247
                if (HBlank_n && VBlank_n)
248
                        {rI,rG,rR,rB} = (Pixel)? {AttrOut[6],AttrOut[2:0]} : {AttrOut[6],AttrOut[5:3]};
249
                else
250
                        {rI,rG,rR,rB} = 4'b0000;
251
        end
252
 
253
        //CSync generation
254
        assign csync = HSync_n & VSync_n;
255
 
256
        // VRAM address and control line generation
257
        reg [13:0] rVA = 0;
258
        reg rVCS = 0;
259
        reg rVOE = 0;
260
        reg rVWE = 0;
261
        assign va = rVA;
262
        assign vramcs = rVCS;
263
        assign vramoe = rVOE;
264
        assign vramwe = rVWE;
265
        // Latches to hold delayed versions of V and H counters
266
        reg [8:0] v = 0;
267
        reg [8:0] c = 0;
268
        // Address and control line multiplexor ULA/CPU
269
        always @(negedge clk7) begin
270
                if (Border_n && (hc[3:0]==4'b0111 || hc[3:0]==4'b1011)) begin     // cycles 7 and 11: load V and C from VC and HC
271
                        c <= hc;
272
                        v <= vc;
273
                end
274
        end
275
        // Address and control line multiplexor ULA/CPU
276
        always @(*) begin
277
                if (Border_n && (hc[3:0]==4'b1000 || hc[3:0]==4'b1001 || hc[3:0]==4'b1100 || hc[3:0]==4'b1101)) begin       // cycles 8 and 12: present attribute address to VRAM
278
                        rVA = (TimexHiColorMode)?       {1'b1,v[7:6],v[2:0],v[5:3],c[7:3]} :                                                                                                             // (cycles 9 and 13 load attr byte). 
279
                                                                                                {4'b0110,v[7:3],c[7:3]};                                                                                                                                                // Attribute address depends upon the mode selected
280
                        rVCS = 1;
281
                        rVOE = !hc[0];
282
                        rVWE = 0;
283
                end
284
                else if (Border_n && (hc[3:0]==4'b1010 || hc[3:0]==4'b1011 || hc[3:0]==4'b1110 || hc[3:0]==4'b1111)) begin  // cycles 10 and 14: present display address to VRAM 
285
                        rVA = {1'b0,v[7:6],v[2:0],v[5:3],c[7:3]};                                                // (cycles 11 and 15 load display byte)
286
                        rVCS = 1;
287
                        rVOE = !hc[0];
288
                        rVWE = 0;
289
                end
290
                else if (Border_n && hc[3:0]==4'b0000) begin
291
                        rVA = a[13:0];
292
                        rVCS = 0;
293
                        rVOE = 0;
294
                        rVWE = 0;
295
                end
296
                else begin      // when VRAM is not in use by ULA, give it to CPU
297
                        rVA = a[13:0];
298
                        rVCS = !a[15] & a[14] & !mreq_n;
299
                        rVOE = !rd_n;
300
                        rVWE = !wr_n;
301
                end
302
        end
303
 
304
        // Palette addr and control bus multiplexing
305
        always @(*) begin
306
                if (Border_n && (hc[3:0]==10 || hc[3:0]==14)) begin         // present address of paper to palette RAM
307
                        palettewe = 0;
308
                        paletteaddr = { AttrReg[7:6],1'b1,AttrReg[5:3] };
309
                end
310
                else if (Border_n && (hc[3:0]==11 || hc[3:0]==15)) begin    // present address of ink to palette RAM
311
                        palettewe = 0;
312
                        paletteaddr = { AttrReg[7:6],1'b0,AttrReg[2:0] };
313
                end
314
                else if (dataportsel) begin                                                                             // if CPU requests access, give it palette control
315
                        paletteaddr = ULAPlusAddrReg[5:0];
316
                        palettewe = cpu_writes_palette;
317
                end
318
                else begin
319
                        palettewe = 0;           // blocking assignment, so we will first deassert WE at palette RAM...
320
                        paletteaddr = {3'b001, BorderColor};  // ... then, we can change the palette RAM address
321
                end
322
        end
323
 
324
        // CPU contention
325
        reg CPUClk = 0;
326
        assign clkcpu = CPUClk;
327
        reg ioreqtw3 = 0;
328
        reg mreqt23 = 0;
329
        wire ioreq_n = (a[0] | iorq_n) & ~dataportsel & ~addrportsel;
330
        wire Nor1 = (~(a[14] | ~ioreq_n)) |
331
                    (~(~a[15] | ~ioreq_n)) |
332
                                        (~(hc[2] | hc[3])) |
333
                                        (~Border_n | ~ioreqtw3 | ~CPUClk | ~mreqt23);
334
        wire Nor2 = (~(hc[2] | hc[3])) |
335
                    ~Border_n |
336
                                        ~CPUClk |
337
                                        ioreq_n |
338
                                        ~ioreqtw3;
339
        wire CLKContention = ~Nor1 | ~Nor2;
340
 
341
        always @(posedge clk7) begin    // change clk7 by clk14 for 7MHz CPU clock operation
342
                if (CPUClk && !CLKContention)   // if there's no contention, the clock can go low
343
                        CPUClk <= 0;
344
                else
345
                        CPUClk <= 1;
346
        end
347
        always @(posedge CPUClk) begin
348
                ioreqtw3 <= ioreq_n;
349
                mreqt23 <= mreq_n;
350
        end
351
 
352
        // ULA+ palette management
353
        always @(posedge clk7 or posedge reset) begin
354
                if (reset)
355
                        ULAPlusConfig <= 0;
356
                else begin
357
                        if (addrportsel && !wr_n)
358
                                ULAPlusAddrReg <= din;
359
                        else if (dataportsel && !wr_n && ULAPlusAddrReg[7:6]==2'b01)
360
                                ULAPlusConfig <= din[0];
361
                end
362
        end
363
 
364
        // ULA-CPU interface
365
        assign dout = (!a[15] && a[14] && !mreq_n)? vramdout : // CPU reads VRAM through ULA as in the +3, not directly
366
                      (!iorq_n && !a[0])?          {1'b1,ear,1'b1,kbcolumns} :   // CPU reads keyboard and EAR state
367
                                          (!iorq_n && a[7:0]==8'hFF && !rd_n)? {6'b000000,TimexHiColorMode,1'b0} : // Timex hicolor config port. Only bit 1 is reported.
368
                                          (addrportsel && !rd_n)? ULAPlusAddrReg :  // ULA+ addr register
369
                                          (dataportsel && !rd_n && ULAPlusAddrReg[7:6]==2'b01)? {7'b0000000, ULAPlusConfig} :
370
                                          (dataportsel && !rd_n && ULAPlusAddrReg[7:6]==2'b00)? palettedout :
371
                                          (Border_n)?                  AttrReg :  // to emulate
372
                                                                      8'hFF;     // port FF (well, cannot be actually FF anymore)
373
        assign vramdin = din;           // The CPU doesn't need to share the memory input data bus with the ULA
374
        assign kbrows = {a[11]? 1'bz : 1'b0,    // high impedance or 0, as if diodes were been placed in between
375
                                                  a[10]? 1'bz : 1'b0,   // if the keyboard matrix is to be implemented within the FPGA, then
376
                                                  a[9]?  1'bz : 1'b0,   // there's no need to do this.
377
                                                  a[12]? 1'bz : 1'b0,
378
                                                  a[13]? 1'bz : 1'b0,
379
                                                  a[8]?  1'bz : 1'b0,
380
                                                  a[14]? 1'bz : 1'b0,
381
                                                  a[15]? 1'bz : 1'b0 };
382
        reg rMic = 0;
383
        reg rSpk = 0;
384
        assign mic = rMic;
385
        assign spk = rSpk;
386
        always @(negedge clk7 or posedge reset) begin
387
                if (reset)
388
                        TimexHiColorMode <= 0;
389
                else if (!iorq_n && a[7:0]==8'hFF && !wr_n)
390
                        TimexHiColorMode <= din[1];
391
                else if (!iorq_n & !a[0] & !wr_n)
392
                        {rSpk,rMic,BorderColor} <= din[5:0];
393
        end
394
endmodule

powered by: WebSVN 2.1.0

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