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

Subversion Repositories zx_ula

[/] [zx_ula/] [branches/] [xilinx/] [ulaplus_replacement-upgrade_for_sp16-48k/] [rtl_ulaplus/] [ula.v] - Blame information for rev 29

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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