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 18

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 18 mcleod_ide
         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 15 mcleod_ide
    output csync                        //               
60
    );
61
 
62
        reg [2:0] BorderColor = 3'b100;
63
        reg TimexHiColorMode = 0;
64
 
65 18 mcleod_ide
        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 15 mcleod_ide
        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 18 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
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 15 mcleod_ide
 
75
        ram64bytes palette (
76 18 mcleod_ide
                .clk(clk14),    // only for write operations. Read operations are asynchronous
77
                .a(paletteaddr),
78 15 mcleod_ide
                .din(din),
79
                .dout(palettedout),
80 18 mcleod_ide
                .we(palettewe)  // RAM is written if WE is enabled at the rising edge of clk
81 15 mcleod_ide
                );
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 18 mcleod_ide
        // ULA+ : palette RAM address and control bus multiplexing
308 15 mcleod_ide
        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 18 mcleod_ide
                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 15 mcleod_ide
                        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 18 mcleod_ide
   //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 15 mcleod_ide
        // CPU contention
365
        reg CPUClk = 0;
366
        assign clkcpu = CPUClk;
367
        reg ioreqtw3 = 0;
368
        reg mreqt23 = 0;
369
        wire ioreq_n = (a[0] | iorq_n) & ~dataportsel & ~addrportsel;
370
        wire Nor1 = (~(a[14] | ~ioreq_n)) |
371
                    (~(~a[15] | ~ioreq_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
                                        ioreq_n |
378
                                        ~ioreqtw3;
379
        wire CLKContention = ~Nor1 | ~Nor2;
380
 
381
        always @(posedge clk7) begin    // change clk7 by clk14 for 7MHz CPU clock operation
382
                if (CPUClk && !CLKContention)   // if there's no contention, the clock can go low
383
                        CPUClk <= 0;
384
                else
385
                        CPUClk <= 1;
386
        end
387
        always @(posedge CPUClk) begin
388
                ioreqtw3 <= ioreq_n;
389
                mreqt23 <= mreq_n;
390
        end
391
 
392 18 mcleod_ide
        // ULA+ : palette management
393 15 mcleod_ide
        always @(posedge clk7 or posedge reset) begin
394
                if (reset)
395
                        ULAPlusConfig <= 0;
396
                else begin
397
                        if (addrportsel && !wr_n)
398
                                ULAPlusAddrReg <= din;
399
                        else if (dataportsel && !wr_n && ULAPlusAddrReg[7:6]==2'b01)
400
                                ULAPlusConfig <= din[0];
401
                end
402
        end
403
 
404
        // ULA-CPU interface
405
        assign dout = (!a[15] && a[14] && !mreq_n)? vramdout : // CPU reads VRAM through ULA as in the +3, not directly
406
                      (!iorq_n && !a[0])?          {1'b1,ear,1'b1,kbcolumns} :   // CPU reads keyboard and EAR state
407
                                          (!iorq_n && a[7:0]==8'hFF && !rd_n)? {6'b000000,TimexHiColorMode,1'b0} : // Timex hicolor config port. Only bit 1 is reported.
408
                                          (addrportsel && !rd_n)? ULAPlusAddrReg :  // ULA+ addr register
409
                                          (dataportsel && !rd_n && ULAPlusAddrReg[7:6]==2'b01)? {7'b0000000, ULAPlusConfig} :
410
                                          (dataportsel && !rd_n && ULAPlusAddrReg[7:6]==2'b00)? palettedout :
411
                                          (Border_n)?                  AttrReg :  // to emulate
412
                                                                      8'hFF;     // port FF (well, cannot be actually FF anymore)
413
        assign vramdin = din;           // The CPU doesn't need to share the memory input data bus with the ULA
414
        assign kbrows = {a[11]? 1'bz : 1'b0,    // high impedance or 0, as if diodes were been placed in between
415
                                                  a[10]? 1'bz : 1'b0,   // if the keyboard matrix is to be implemented within the FPGA, then
416
                                                  a[9]?  1'bz : 1'b0,   // there's no need to do this.
417
                                                  a[12]? 1'bz : 1'b0,
418
                                                  a[13]? 1'bz : 1'b0,
419
                                                  a[8]?  1'bz : 1'b0,
420
                                                  a[14]? 1'bz : 1'b0,
421
                                                  a[15]? 1'bz : 1'b0 };
422
        reg rMic = 0;
423
        reg rSpk = 0;
424
        assign mic = rMic;
425
        assign spk = rSpk;
426
        always @(negedge clk7 or posedge reset) begin
427
                if (reset)
428
                        TimexHiColorMode <= 0;
429
                else if (!iorq_n && a[7:0]==8'hFF && !wr_n)
430
                        TimexHiColorMode <= din[1];
431
                else if (!iorq_n & !a[0] & !wr_n)
432
                        {rSpk,rMic,BorderColor} <= din[5:0];
433
        end
434
endmodule

powered by: WebSVN 2.1.0

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