From c3c105980eb1027ece733c637de0af2011350060 Mon Sep 17 00:00:00 2001 From: Eugene Lozovoy Date: Sat, 9 Jul 2022 21:38:12 +0300 Subject: [PATCH] cpld: refactor video color signal generation assume 28.375MHz Y2 by default --- cpld/chroma_gen.v | 122 +++++++++++++++++++++++++------------------ cpld/clocks.sdc | 21 ++++---- cpld/top.v | 29 +++++----- cpld/zx_ula.qsf | 4 +- pcb/rev.A/ERRATA.txt | 3 +- 5 files changed, 101 insertions(+), 78 deletions(-) diff --git a/cpld/chroma_gen.v b/cpld/chroma_gen.v index c5fa411..92affd1 100644 --- a/cpld/chroma_gen.v +++ b/cpld/chroma_gen.v @@ -1,14 +1,18 @@ // Based on Joerg Wolfram's code // module chroma_gen #( - parameter CLK_FREQ + parameter CLK_FREQ = 16_000_000 ) ( - input cg_clock, // input clock - input cg_enable, // colour enable - input cg_hsync, // hor. sync - input cg_pnsel, // system (pal/ntsc) - input [2:0] cg_rgb, // rgb input - output reg [2:0] cg_out // chroma out + input clk, // input clock + input en, // colour enable + input hsync, // hor. sync + input ntsc, // system (pal/ntsc) + input r, // rgbi input + input g, + input b, + input i, + output reg out_carrier, // chroma out + output reg [1:0] out ); localparam CARRIER_WIDTH = @@ -60,89 +64,103 @@ localparam NTSC_CARRIER = // localparam PAL_CARRIER = 64'd17_734_475 * (1<<(CARRIER_WIDTH-1)) / CLK_FREQ; // localparam NTSC_CARRIER = 64'd14_318_180 * (1<<(CARRIER_WIDTH-1)) / CLK_FREQ; -reg [CARRIER_WIDTH:0] carrier; -wire [31:0] carrier_next; -reg [3:0] burst_cnt; -wire burst; -reg oddeven; -reg [3:0] phase; -reg [3:0] scarrier; -wire cenable; - // DDS for PAL-carrier -assign carrier_next = (cg_pnsel == 1'b0)? +reg [CARRIER_WIDTH:0] carrier; +wire [31:0] carrier_next = (!ntsc)? (carrier + PAL_CARRIER) : (carrier + NTSC_CARRIER) ; - -always @(posedge cg_clock) begin +always @(posedge clk) begin carrier <= carrier_next[CARRIER_WIDTH:0]; end + // burst generator -always @(posedge carrier[CARRIER_WIDTH] or negedge cg_hsync) begin - if (cg_hsync == 1'b0) +reg [3:0] burst_cnt; +always @(posedge carrier[CARRIER_WIDTH] or negedge hsync) begin + if (hsync == 1'b0) burst_cnt <= 4'b0100; else if (burst_cnt != 4'b0000) burst_cnt <= burst_cnt + 1'b1; end -assign burst = burst_cnt[3]; +wire burst = burst_cnt[3]; + // odd/even line -always @(posedge cg_hsync) begin - if (cg_pnsel == 1'b0) +reg oddeven; +always @(posedge hsync) begin + if (!ntsc) oddeven <= ~oddeven; else oddeven <= 1'b0; end // carrier phase +reg [3:0] phase; always @* begin if (burst == 1'b1) begin - if ((oddeven == 1'b0) && (cg_pnsel == 1'b0)) - phase <= 4'b0110; // burst phase 135 deg + if ((oddeven == 1'b0) && (!ntsc)) + phase <= 4'h6; // burst phase 135 deg else - phase <= 4'b1010; // burst phase -135 deg + phase <= 4'hA; // burst phase -135 deg end else if (oddeven == 1'b0) begin - case (cg_rgb) - 3'b001: phase <= 4'b0000; // blue phase - 3'b010: phase <= 4'b0101; // red phase - 3'b011: phase <= 4'b0011; // magenta phase - 3'b100: phase <= 4'b1011; // green phase - 3'b101: phase <= 4'b1101; // cyan phase - 3'b110: phase <= 4'b0111; // yellow phase - default: phase <= 4'b0000; // dummy function + case ({r,g,b}) + 3'b010: phase <= 4'hB; // green + 3'b011: phase <= 4'hD; // cyan + 3'b100: phase <= 4'h5; // red + 3'b101: phase <= 4'h3; // magenta + 3'b110: phase <= 4'h7; // yellow + default: phase <= 4'hF; // blue endcase end else begin - case (cg_rgb) - 3'b001: phase <= 4'b0000; // blue phase - 3'b010: phase <= 4'b1011; // red phase - 3'b011: phase <= 4'b1101; // magenta phase - 3'b100: phase <= 4'b0101; // green phase - 3'b101: phase <= 4'b0011; // cyan phase - 3'b110: phase <= 4'b1001; // yellow phase - default: phase <= 4'b0000; // dummy function + case ({r,g,b}) + 3'b010: phase <= 4'h5; // green + 3'b011: phase <= 4'h3; // cyan + 3'b100: phase <= 4'hB; // red + 3'b101: phase <= 4'hD; // magenta + 3'b110: phase <= 4'h9; // yellow + default: phase <= 4'h1; // blue endcase end end + +// carrier amplitude +reg [1:0] amplitude; +always @* begin + if (burst == 1'b1) + amplitude <= 2'b01; + else case ({i,r,g,b}) + 4'b0001: amplitude <= 2'b10; + 4'b0010: amplitude <= 2'b10; + 4'b0011: amplitude <= 2'b10; + 4'b0100: amplitude <= 2'b10; + 4'b0101: amplitude <= 2'b10; + 4'b0110: amplitude <= 2'b10; + 4'b1001: amplitude <= 2'b11; + 4'b1010: amplitude <= 2'b11; + 4'b1011: amplitude <= 2'b11; + 4'b1100: amplitude <= 2'b11; + 4'b1101: amplitude <= 2'b11; + 4'b1110: amplitude <= 2'b11; + default: amplitude <= 2'b00; + endcase +end + + // modulated carrier +reg [3:0] scarrier; always @* scarrier <= carrier[CARRIER_WIDTH:CARRIER_WIDTH-3] + phase; -// colour enable -assign cenable = - cg_enable == 1'b1 && - cg_rgb != 3'b000 && - cg_rgb != 3'b111; // chroma signal -always @(posedge cg_clock) begin - cg_out[2] <= cenable; - cg_out[1] <= burst; - cg_out[0] <= scarrier[3]; +always @(posedge clk) begin + out_carrier <= scarrier[3]; + out[1] <= en && amplitude[1]; + out[0] <= en && amplitude[0]; end diff --git a/cpld/clocks.sdc b/cpld/clocks.sdc index 62907d4..5500d34 100644 --- a/cpld/clocks.sdc +++ b/cpld/clocks.sdc @@ -1,16 +1,17 @@ create_clock -period 14.4MHz -name {clk_14mhz} [get_ports {clk14}] -create_clock -period 16.1MHz -name {clk_16mhz} [get_ports {clk16}] +create_clock -period 32.1MHz -name {clk_pal} [get_ports {clkpal}] -# clkcpu 3.5 create_generated_clock -name {clkcpu} -divide_by 4 -source [get_ports {clk14}] [get_registers {hc0[1]}] - -# int len in turbo = 66 create_generated_clock -name {n_int} -divide_by 64 -source [get_ports {clk14}] [get_registers {n_int~reg0}] +create_generated_clock -name {hsync1} -divide_by 64 -source [get_ports {clk14}] [get_registers {hsync1}] +create_generated_clock -name {chroma_carrier} -divide_by 6 -source [get_ports {clkpal}] [get_registers {chroma_gen:*|carrier[16]}] -# chroma carrier (4.43MHz) -create_generated_clock -name {chroma_carrier} -divide_by 3 -source [get_ports {clk16}] [get_registers {*:chroma_gen1|carrier[14]}] +# All these transitions happens when carrier is inactive, so no any glitches will be visible +set_false_path -from [get_registers {chroma_gen:*|burst_cnt[3]}] -to [get_registers {chroma_gen:*|out_carrier}] +set_false_path -from [get_registers {chroma_gen:*|oddeven}] -to [get_registers {chroma_gen:*|out_carrier}] +set_false_path -from [get_registers {hsync1}] -to [get_registers {chroma_gen:*|burst_cnt[*]}] -set_false_path -from [get_registers {r~reg0}] -to [get_clocks {clk_16mhz}] -set_false_path -from [get_registers {g~reg0}] -to [get_clocks {clk_16mhz}] -set_false_path -from [get_registers {b~reg0}] -to [get_clocks {clk_16mhz}] -set_false_path -from [get_registers {hsync1}] -to [get_clocks {chroma_carrier}] +set_false_path -from [get_registers {r~reg0}] -to [get_registers {chroma_gen:*}] +set_false_path -from [get_registers {g~reg0}] -to [get_registers {chroma_gen:*}] +set_false_path -from [get_registers {b~reg0}] -to [get_registers {chroma_gen:*}] +set_false_path -from [get_registers {i~reg0}] -to [get_registers {chroma_gen:*}] diff --git a/cpld/top.v b/cpld/top.v index 7ff0236..f413d0c 100644 --- a/cpld/top.v +++ b/cpld/top.v @@ -1,7 +1,7 @@ module zx_ula( input rst_n, input clk14, - input clk16, + input clkpal, output clkcpu, @@ -42,7 +42,7 @@ module zx_ula( output reg csync ); -wire [15:0] xa = {a15, a14, va[13:2], a1, a0}; // a1-va[1] and a0-va[0] may be swapped if fitter is cranky +wire [15:0] xa = {a15, a14, va[13:2], va[1], va[0]}; // a1-va[1] and a0-va[0] may be swapped if fitter is cranky wire [7:0] xd = vd; reg screen_read; @@ -206,17 +206,22 @@ assign ay_clk = hc[1]; /* VIDEO */ -reg [2:0] chroma0; -chroma_gen #(.CLK_FREQ(16_000_000)) chroma_gen1( - .cg_clock(clk16), - .cg_rgb({g,r,b}), - .cg_hsync(hsync1), - .cg_enable(1'b1), - .cg_pnsel(1'b0), - .cg_out(chroma0) +wire chroma_carrier; +wire [1:0] chroma0; +chroma_gen #(.CLK_FREQ(28_375_000)) chroma_gen1( + .clk(clkpal), + .hsync(hsync1), + .en(1'b1), + .ntsc(1'b0), + .r(r), + .g(g), + .b(b), + .i(i), + .out_carrier(chroma_carrier), + .out(chroma0) ); -assign chroma[0] = chroma0[1]? chroma0[0] : 1'bz; -assign chroma[1] = chroma0[2]? chroma0[0] : 1'bz; +assign chroma[0] = chroma0[0]? chroma_carrier : 1'bz; +assign chroma[1] = chroma0[1]? chroma_carrier : 1'bz; /* MEMORY CONTROLLER */ diff --git a/cpld/zx_ula.qsf b/cpld/zx_ula.qsf index a9b8f55..8e4beb0 100644 --- a/cpld/zx_ula.qsf +++ b/cpld/zx_ula.qsf @@ -105,7 +105,7 @@ set_location_assignment PIN_16 -to a15 set_global_assignment -name AUTO_RESOURCE_SHARING OFF set_global_assignment -name AUTO_LCELL_INSERTION OFF set_location_assignment PIN_9 -to csync -set_location_assignment PIN_2 -to clk16 +set_location_assignment PIN_2 -to clkpal set_location_assignment PIN_11 -to chroma[1] set_location_assignment PIN_12 -to chroma[0] set_location_assignment PIN_33 -to kd[1] @@ -118,8 +118,6 @@ set_location_assignment PIN_40 -to ay_bdir set_location_assignment PIN_41 -to ay_clk set_location_assignment PIN_79 -to tape_in set_location_assignment PIN_80 -to ra14 -set_global_assignment -name FMAX_REQUIREMENT "16 MHz" -section_id clk16 -set_instance_assignment -name CLOCK_SETTINGS clk16 -to clk16 set_global_assignment -name BASED_ON_CLOCK_SETTINGS clk14 -section_id clkcpu set_global_assignment -name MULTIPLY_BASE_CLOCK_PERIOD_BY 2 -section_id clkcpu set_global_assignment -name OPTIMIZE_HOLD_TIMING OFF diff --git a/pcb/rev.A/ERRATA.txt b/pcb/rev.A/ERRATA.txt index 7fb2649..f3e6eac 100644 --- a/pcb/rev.A/ERRATA.txt +++ b/pcb/rev.A/ERRATA.txt @@ -6,4 +6,5 @@ To improve RGBI colour balance use these values: 2. R42 10k 3. R39 18k 4. R46 15k -5. R49 3.6k +5. R49 2.4k +6. R50 4.7k