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 26

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

powered by: WebSVN 2.1.0

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