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

Subversion Repositories zx_ula

[/] [zx_ula/] [branches/] [xilinx/] [spectrum_48k_spartan3a_for_gameduino_mod_vga_timex_hicolor_ulaplus/] [ula.v] - Blame information for rev 29

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 29 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 [7:0] rgbulaplus,        // 8-bit RGB value for current pixel, ULA+
58
         output ulaplus_enabled,        // =1 if ULAPlus enabled. To help selecting the right outputs to the RGB DAC
59
    output csync                        //               
60
    );
61
 
62
        reg [2:0] BorderColor = 3'b100;
63
        reg TimexHiColorMode = 0;
64
 
65
        reg ULAPlusConfig = 0;   // bit 0 of reg.64
66
        reg [7:0] ULAPlusAddrReg = 0;     // ULA+ register address, BF3Bh port.
67
        assign ulaplus_enabled = ULAPlusConfig;
68
        wire addrportsel = !iorq_n && a[0] && !a[2] && (a[7:6]==2'b00) && (a[15:14]==2'b10); // port BF3Bh
69
        wire dataportsel = !iorq_n && a[0] && !a[2] && (a[7:6]==2'b00) && (a[15:14]==2'b11); // port FF3Bh
70
        wire cpu_writes_palette = dataportsel && !wr_n && (ULAPlusAddrReg[7:6]==2'b00);  //=1 if CPU wants to write a palette entry to RAM
71
        reg [5:0] paletteaddr;   // address bus of palette RAM
72
        wire [7:0] palettedout;  // data out port of palette RAM
73
        reg palettewe;                          // WE signal of palette RAM (palette RAM is always selected and output enabled)
74
 
75
        ram64bytes palette (
76
                .clk(clk14),    // only for write operations. Read operations are asynchronous
77
                .a(paletteaddr),
78
                .din(din),
79
                .dout(palettedout),
80
                .we(palettewe)  // RAM is written if WE is enabled at the rising edge of clk
81
                );
82
 
83
        // Pixel clock
84
        reg clk7 = 0;
85
        always @(posedge clk14)
86
                clk7 <= !clk7;
87
 
88
        // Horizontal counter
89
        reg [8:0] hc = 0;
90
        always @(posedge clk7) begin
91
                if (hc==447)
92
                        hc <= 0;
93
                else
94
                        hc <= hc + 1;
95
        end
96
 
97
        // Vertical counter
98
        reg [8:0] vc = 0;
99
        always @(posedge clk7) begin
100
                if (hc==447) begin
101
                        if (vc == 311)
102
                                vc <= 0;
103
                        else
104
                                vc <= vc + 1;
105
                end
106
        end
107
 
108
        // HBlank generation
109
        reg HBlank_n = 1;
110
        always @(negedge clk7) begin
111
                if (`cyclestart(hc,320))
112
                        HBlank_n <= 0;
113
                else if (`cycleend(hc,415))
114
                        HBlank_n <= 1;
115
        end
116
 
117
        // HSync generation (6C ULA version)
118
        reg HSync_n = 1;
119
        always @(negedge clk7) begin
120
                if (`cyclestart(hc,344))
121
                        HSync_n <= 0;
122
                else if (`cycleend(hc,375))
123
                        HSync_n <= 1;
124
        end
125
 
126
        // VBlank generation
127
        reg VBlank_n = 1;
128
        always @(negedge clk7) begin
129
                if (`cyclestart(vc,248))
130
                        VBlank_n <= 0;
131
                else if (`cycleend(vc,255))
132
                        VBlank_n <= 1;
133
        end
134
 
135
        // VSync generation (PAL)
136
        reg VSync_n = 1;
137
        always @(negedge clk7) begin
138
                if (`cyclestart(vc,248))
139
                        VSync_n <= 0;
140
                else if (`cycleend(vc,251))
141
                        VSync_n <= 1;
142
        end
143
 
144
        // INT generation
145
        reg INT_n = 1;
146
        assign msk_int_n = INT_n;
147
        always @(negedge clk7) begin
148
                if (`cyclestart(vc,248) && `cyclestart(hc,0))
149
                        INT_n <= 0;
150
                else if (`cyclestart(vc,248) && `cycleend(hc,31))
151
                        INT_n <= 1;
152
        end
153
 
154
        // Border control signal (=0 when we're not displaying paper/ink pixels)
155
        reg Border_n = 1;
156
        always @(negedge clk7) begin
157
                if ( (vc[7] & vc[6]) | vc[8] | hc[8])
158
                        Border_n <= 0;
159
                else
160
                        Border_n <= 1;
161
        end
162
 
163
        // VidEN generation (delaying Border 8 clocks)
164
        reg VidEN_n = 1;
165
        always @(negedge clk7) begin
166
                if (hc[3])
167
                        VidEN_n <= !Border_n;
168
        end
169
 
170
        // DataLatch generation (posedge to capture data from memory)
171
        reg DataLatch_n = 1;
172
        always @(negedge clk7) begin
173
                if (hc[0] & hc[1] & Border_n & hc[3])
174
                        DataLatch_n <= 0;
175
                else
176
                        DataLatch_n <= 1;
177
        end
178
 
179
        // AttrLatch generation (posedge to capture data from memory)
180
        reg AttrLatch_n = 1;
181
        always @(negedge clk7) begin
182
                if (hc[0] & !hc[1] & Border_n & hc[3])
183
                        AttrLatch_n <= 0;
184
                else
185
                        AttrLatch_n <= 1;
186
        end
187
 
188
        // SLoad generation (negedge to load shift register)
189
        reg SLoad = 0;
190
        always @(negedge clk7) begin
191
                if (!hc[0] & !hc[1] & hc[2] & !VidEN_n)
192
                        SLoad <= 1;
193
                else
194
                        SLoad <= 0;
195
        end
196
 
197
        // AOLatch generation (negedge to update attr output latch)
198
        reg AOLatch_n = 1;
199
        always @(negedge clk7) begin
200
                if (hc[0] & !hc[1] & hc[2])
201
                        AOLatch_n <= 0;
202
                else
203
                        AOLatch_n <= 1;
204
        end
205
 
206
        // First buffer for bitmap
207
        reg [7:0] BitmapReg = 0;
208
        always @(negedge DataLatch_n) begin
209
                BitmapReg <= vramdout;
210
        end
211
 
212
        // Shift register (second bitmap register)
213
        reg [7:0] SRegister = 0;
214
        always @(negedge clk7) begin
215
                if (SLoad)
216
                        SRegister <= BitmapReg;
217
                else
218
                        SRegister <= {SRegister[6:0],1'b0};
219
        end
220
 
221
        // First buffer for attribute
222
        reg [7:0] AttrReg = 0;
223
        always @(negedge AttrLatch_n) begin
224
                AttrReg <= vramdout;
225
        end
226
 
227
        // Second buffer for attribute
228
        reg [7:0] AttrOut = 0;
229
        always @(negedge AOLatch_n) begin
230
                if (!VidEN_n)
231
                        AttrOut <= AttrReg;
232
                else
233
                        AttrOut <= {2'b00,BorderColor,BorderColor};
234
        end
235
 
236
        // Flash counter and pixel generation
237
        reg [4:0] FlashCnt = 0;
238
        always @(negedge VSync_n) begin
239
                FlashCnt <= FlashCnt + 1;
240
        end
241
        wire Pixel = SRegister[7] ^ (AttrOut[7] & FlashCnt[4]);
242
 
243
        // RGB generation
244
        reg rI,rG,rR,rB;
245
        assign r = rR;
246
        assign g = rG;
247
        assign b = rB;
248
        assign i = rI;
249
        always @(*) begin
250
                if (HBlank_n && VBlank_n)
251
                        {rI,rG,rR,rB} = (Pixel)? {AttrOut[6],AttrOut[2:0]} : {AttrOut[6],AttrOut[5:3]};
252
                else
253
                        {rI,rG,rR,rB} = 4'b0000;
254
        end
255
 
256
        //CSync generation
257
        assign csync = HSync_n & VSync_n;
258
 
259
        // VRAM address and control line generation
260
        reg [13:0] rVA = 0;
261
        reg rVCS = 0;
262
        reg rVOE = 0;
263
        reg rVWE = 0;
264
        assign va = rVA;
265
        assign vramcs = rVCS;
266
        assign vramoe = rVOE;
267
        assign vramwe = rVWE;
268
        // Latches to hold delayed versions of V and H counters
269
        reg [8:0] v = 0;
270
        reg [8:0] c = 0;
271
        // Address and control line multiplexor ULA/CPU
272
        always @(negedge clk7) begin
273
                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
274
                        c <= hc;
275
                        v <= vc;
276
                end
277
        end
278
        // Address and control line multiplexor ULA/CPU
279
        always @(*) begin
280
                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
281
                        rVA = (TimexHiColorMode)?       {1'b1,v[7:6],v[2:0],v[5:3],c[7:3]} :                                                                                                             // (cycles 9 and 13 load attr byte). 
282
                                                                                                {4'b0110,v[7:3],c[7:3]};                                                                                                                                                // Attribute address depends upon the mode selected
283
                        rVCS = 1;
284
                        rVOE = !hc[0];
285
                        rVWE = 0;
286
                end
287
                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 
288
                        rVA = {1'b0,v[7:6],v[2:0],v[5:3],c[7:3]};                                                // (cycles 11 and 15 load display byte)
289
                        rVCS = 1;
290
                        rVOE = !hc[0];
291
                        rVWE = 0;
292
                end
293
                else if (Border_n && hc[3:0]==4'b0000) begin
294
                        rVA = a[13:0];
295
                        rVCS = 0;
296
                        rVOE = 0;
297
                        rVWE = 0;
298
                end
299
                else begin      // when VRAM is not in use by ULA, give it to CPU
300
                        rVA = a[13:0];
301
                        rVCS = !a[15] & a[14] & !mreq_n;
302
                        rVOE = !rd_n;
303
                        rVWE = !wr_n;
304
                end
305
        end
306
 
307
        // ULA+ : palette RAM address and control bus multiplexing
308
        always @(*) begin
309
                if (Border_n && (hc[3:0]==10 || hc[3:0]==14)) begin         // present address of paper to palette RAM
310
                        palettewe = 0;
311
                        paletteaddr = { AttrReg[7:6],1'b1,AttrReg[5:3] };
312
                end
313
                else if (Border_n && (hc[3:0]==11 || hc[3:0]==15)) begin    // present address of ink to palette RAM
314
                        palettewe = 0;
315
                        paletteaddr = { AttrReg[7:6],1'b0,AttrReg[2:0] };
316
                end
317
                else if (dataportsel) begin                                                                             // if CPU requests access, give it palette control
318
                        paletteaddr = ULAPlusAddrReg[5:0];
319
                        palettewe = cpu_writes_palette;
320
                end
321
                else begin              // if palette RAM is not being used to display pixels, and the CPU doesn't need it, put the border color address
322
                        palettewe = 0;           // blocking assignment, so we will first deassert WE at palette RAM...
323
                        paletteaddr = {3'b001, BorderColor};  // ... then, we can change the palette RAM address
324
                end
325
        end
326
 
327
   //ULA+ : palette reading and attribute generation
328
        // First buffers for paper and ink
329
        reg [7:0] ULAPlusPaper = 0;
330
        reg [7:0] ULAPlusInk = 0;
331
        reg [7:0] ULAPlusBorder = 0;
332
        wire ULAPlusPixel = SRegister[7];
333
        always @(negedge clk14) begin
334
                if (Border_n && (hc[3:0]==10 || hc[3:0]==14) && !clk7)    // this happens 1/2 clk7 after address is settled
335
                        ULAPlusPaper <= palettedout;
336
                else if (Border_n && (hc[3:0]==11 || hc[3:0]==15) && !clk7)       // this happens 1/2 clk7 after address is settled
337
                        ULAPlusInk <= palettedout;
338
                else if (hc[3:0]==12 && !dataportsel)    // On cycle 12, palette RAM is not used to retrieve ink/paper color. If CPU is not reclaiming it...
339
                        ULAPlusBorder <= palettedout;                   //... take the chance to update the BorderColor register by reading the palette RAM. The address
340
        end                                                                                                     // presented at the palette RAM address bus will be 001BBB, where BBB is the border color code.
341
        // Second buffers for paper and ink
342
        reg [7:0] ULAPlusPaperOut = 0;
343
        reg [7:0] ULAPlusInkOut = 0;
344
        always @(negedge AOLatch_n) begin
345
                if (!VidEN_n) begin     // if it's "paper time", load output buffers with current ink and paper color
346
                        ULAPlusPaperOut <= ULAPlusPaper;
347
                        ULAPlusInkOut <= ULAPlusInk;
348
                end
349
                else begin      // if not, it's "border/blanking time", so load output buffers with current border color
350
                        ULAPlusPaperOut <= ULAPlusBorder;
351
                        ULAPlusInkOut <= ULAPlusBorder;
352
                end
353
        end
354
        // ULA+ : final RGB generation depending on pixel value and blanking period.
355
        reg [7:0] rRGBULAPlus;
356
        assign rgbulaplus = rRGBULAPlus;
357
        always @(*) begin
358
                if (HBlank_n && VBlank_n)
359
                        rRGBULAPlus = (ULAPlusPixel)? ULAPlusInkOut : ULAPlusPaperOut;
360
                else
361
                        rRGBULAPlus = 8'h00;
362
        end
363
 
364
        // CPU contention handler (Altwasser version)
365
        /////////////////////////////////////////////////////////////////////
366
        reg CPUClk = 0;
367
        assign clkcpu = CPUClk;
368
        reg ioreqtw3 = 0;
369
        reg mreqt23 = 0;
370
        wire ioreq_n = (a[0] | iorq_n) & ~dataportsel & ~addrportsel;
371
        wire Nor1 = (~(a[14] | ~ioreq_n)) |
372
                    (~(~a[15] | ~ioreq_n)) |
373
                                        (~(hc[2] | hc[3])) |
374
                                        (~Border_n | ~ioreqtw3 | ~CPUClk | ~mreqt23);
375
        wire Nor2 = (~(hc[2] | hc[3])) |
376
                    ~Border_n |
377
                                        ~CPUClk |
378
                                        ioreq_n |
379
                                        ~ioreqtw3;
380
        wire CLKContention = ~Nor1 | ~Nor2;
381
 
382
        always @(posedge CPUClk) begin
383
                ioreqtw3 <= ioreq_n;
384
                mreqt23 <= mreq_n;
385
        end
386
        /////////////////////////////////////////////////////////////////////
387
 
388
//      // CPU contention handler (Chris version)
389
//      /////////////////////////////////////////////////////////////////////
390
//      reg CPUClk = 0;
391
//      assign clkcpu = CPUClk;
392
//      wire ioreq_n = (a[0] | iorq_n) & ~dataportsel & ~addrportsel;
393
//      reg ULANotReadingVRAM = 1;
394
//      reg CycleMayContend = 0;
395
//
396
//      always @(negedge clk7) begin
397
//              ULANotReadingVRAM <= ~Border_n | (~hc[2] & ~hc[3]);
398
//      end
399
//      always @(posedge CPUClk) begin
400
//              CycleMayContend <= ioreq_n & mreq_n;
401
//      end
402
//      wire CLKContention = ~(ULANotReadingVRAM | (((~a[14] | a[15]) & ioreq_n) | ~CycleMayContend));
403
//      /////////////////////////////////////////////////////////////////////
404
 
405
//      // CPU modified contention handler for broken IO bus cycle of T80 core (Chris version)
406
//      /////////////////////////////////////////////////////////////////////
407
//      reg CPUClk = 0;
408
//      assign clkcpu = CPUClk;
409
//      wire ioreq_n = (a[0] | iorq_n) & ~dataportsel & ~addrportsel;
410
//      reg ULANotReadingVRAM = 1;
411
//      reg CycleMayContend = 0;
412
//
413
//      always @(negedge clk7) begin
414
//              ULANotReadingVRAM <= ~Border_n | (~hc[2] & ~hc[3]);
415
//      end
416
//      always @(posedge CPUClk) begin
417
//              CycleMayContend <= (ioreq_n | CPUClk) & mreq_n;
418
//      end
419
//      wire CLKContention = ~(ULANotReadingVRAM | (((~a[14] | a[15]) & (ioreq_n | ~CPUClk)) | ~CycleMayContend));
420
//      /////////////////////////////////////////////////////////////////////
421
 
422
        always @(posedge clk7) begin    // change clk7 by clk14 for 7MHz CPU clock operation
423
                if (CPUClk && !CLKContention)   // if there's no contention, the clock can go low
424
                        CPUClk <= 0;
425
                else
426
                        CPUClk <= 1;
427
        end
428
 
429
        // ULA+ : palette management
430
        always @(posedge clk7 or posedge reset) begin
431
                if (reset)
432
                        ULAPlusConfig <= 0;
433
                else begin
434
                        if (addrportsel && !wr_n)
435
                                ULAPlusAddrReg <= din;
436
                        else if (dataportsel && !wr_n && ULAPlusAddrReg[7:6]==2'b01)
437
                                ULAPlusConfig <= din[0];
438
                end
439
        end
440
 
441
        // ULA-CPU interface
442
        assign dout = (!a[15] && a[14] && !mreq_n && !rd_n)? vramdout : // CPU reads VRAM through ULA as in the +3, not directly
443
                      (!iorq_n && !a[0] && !rd_n)?          {1'b1,ear,1'b1,kbcolumns} :  // CPU reads keyboard and EAR state
444
                                          (!iorq_n && a[7:0]==8'hFF && !rd_n)? {6'b000000,TimexHiColorMode,1'b0} : // Timex hicolor config port. Only bit 1 is reported.
445
                                          (addrportsel && !rd_n)? ULAPlusAddrReg :  // ULA+ addr register
446
                                          (dataportsel && !rd_n && ULAPlusAddrReg[7:6]==2'b01)? {7'b0000000, ULAPlusConfig} :
447
                                          (dataportsel && !rd_n && ULAPlusAddrReg[7:6]==2'b00)? palettedout :
448
                                          (Border_n)?                  AttrReg :  // to emulate
449
                                                                      8'hFF;     // port FF (well, cannot be actually FF anymore)
450
        assign vramdin = din;           // The CPU doesn't need to share the memory input data bus with the ULA
451
        assign kbrows = {a[11]? 1'bz : 1'b0,    // high impedance or 0, as if diodes were been placed in between
452
                                                  a[10]? 1'bz : 1'b0,   // if the keyboard matrix is to be implemented within the FPGA, then
453
                                                  a[9]?  1'bz : 1'b0,   // there's no need to do this.
454
                                                  a[12]? 1'bz : 1'b0,
455
                                                  a[13]? 1'bz : 1'b0,
456
                                                  a[8]?  1'bz : 1'b0,
457
                                                  a[14]? 1'bz : 1'b0,
458
                                                  a[15]? 1'bz : 1'b0 };
459
        reg rMic = 0;
460
        reg rSpk = 0;
461
        assign mic = rMic;
462
        assign spk = rSpk;
463
        always @(negedge clk7 or posedge reset) begin
464
                if (reset)
465
                        TimexHiColorMode <= 0;
466
                else if (!iorq_n && a[7:0]==8'hFF && !wr_n)
467
                        TimexHiColorMode <= din[1];
468
                else if (!iorq_n & !a[0] & !wr_n)
469
                        {rSpk,rMic,BorderColor} <= din[5:0];
470
        end
471
endmodule

powered by: WebSVN 2.1.0

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