diff --git a/Arcade-Astrocade.sv b/Arcade-Astrocade.sv index 33587ff..c931751 100644 --- a/Arcade-Astrocade.sv +++ b/Arcade-Astrocade.sv @@ -19,6 +19,15 @@ //============================================================================ +//============================================================================ +// Cabinet Build - enabled by set global assignment "CABINET" in QSF +//---------------------------------------------------------------------------- +// This needs some changes to sys_top.v to allow access to output pins used +// for SD card on IO board. These are used to drive Gorf ranking lights and +// provide a third audio output for Wizard of Wor +//============================================================================ + + //=========================================================================== // Current status / To Do list //=========================================================================== @@ -187,12 +196,16 @@ module emu input [6:0] USER_IN, output [6:0] USER_OUT, - // Gorf Cabinet interface to drive ranking lights - // Needs mod to sys_top.v to allow access to these `ifdef CABINET + // Needs mod to sys_top.v to allow access to these pins + + // Gorf Cabinet interface to drive ranking lights output [3:0] L_Address, output L_Data, output L_Write, + + // WoW third audio channel + output A_Channel, `endif input OSD_STATUS @@ -388,8 +401,13 @@ wire [7:0] ct1_sz = {3'D7,~B2_F,~B2_R,~B2_L,~B2_D,~B2_U}; wire [7:0] ct2_sz = {2'D3,sw[2][0],~B1_F,~B1_R,~B1_L,~B1_D,~B1_U}; // Wizard of Wor wire [7:0] ct0_ww = {sw[2][2],~B2_S,~B1_S,1'b1,sw[2][1],1'b1,~B1_C,1'b1}; +`ifdef CABINET // Cabinet doesn't use digital sticks +wire [7:0] ct1_ww = {2'd3,~B2_F,B2_FB,~B2_R,~B2_L,~B2_D,~B2_U}; +wire [7:0] ct2_ww = {Votrax_Status,1'd1,~B1_F,B1_FB,~B1_R,~B1_L,~B1_D,~B1_U}; +`else wire [7:0] ct1_ww = sw[0][1] ? {2'd3,~B2_F,~W2_FB,~W2_R,~W2_L,~W2_D,~W2_U} : {2'd3,~B2_F,B2_FB,~B2_R,~B2_L,~B2_D,~B2_U}; wire [7:0] ct2_ww = sw[0][0] ? {Votrax_Status,1'd1,~B1_F,~W1_FB,~W1_R,~W1_L,~W1_D,~W1_U} : {Votrax_Status,1'd1,~B1_F,B1_FB,~B1_R,~B1_L,~B1_D,~B1_U}; +`endif // Gorf wire [7:0] ct0_gf = {sw[2][2],sw[2][0],~B2_S,~B1_S,1'b1,sw[2][1],~B1_C,1'b1}; wire [7:0] ct1_gf = {1'd0,2'd1,~B2_F,~B2_R,~B2_L,~B2_D,~B2_U}; @@ -1050,8 +1068,14 @@ end // Wizard of Wor - Third sound channel - -// P2 controls (uses P1 buttons for P2) +second_order_dac wow3 +( + .i_clk(CLK_AUDIO), + .i_res(~reset), + .i_ce(1'b1), + .i_func(sample_l), + .o_DAC(wowdac) +); `endif diff --git a/files.qip b/files.qip index 5abbe4c..38d3dca 100644 --- a/files.qip +++ b/files.qip @@ -24,4 +24,5 @@ set_global_assignment -name SYSTEMVERILOG_FILE rtl/seawolf_samples.sv set_global_assignment -name VHDL_FILE rtl/seawolf_samples_S.vhd set_global_assignment -name VHDL_FILE rtl/seawolf_samples_D.vhd set_global_assignment -name VHDL_FILE rtl/wow_control.vhd +set_global_assignment -name VERILOG_FILE rtl/second_order_dac.v set_global_assignment -name SYSTEMVERILOG_FILE "Arcade-Astrocade.sv" diff --git a/releases/Arcade-Astrocade_20231211.rbf b/releases/Arcade-Astrocade_20231211.rbf new file mode 100644 index 0000000..7a3247b Binary files /dev/null and b/releases/Arcade-Astrocade_20231211.rbf differ diff --git a/rtl/second_order_dac.v b/rtl/second_order_dac.v new file mode 100644 index 0000000..7fe89b1 --- /dev/null +++ b/rtl/second_order_dac.v @@ -0,0 +1,68 @@ +`timescale 1ns / 1ps + +//MIT License +// +//Copyright (c) 2020 Mike Field +// +//Permission is hereby granted, free of charge, to any person obtaining a copy +//of this software and associated documentation files (the "Software"), to deal +//in the Software without restriction, including without limitation the rights +//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +//copies of the Software, and to permit persons to whom the Software is +//furnished to do so, subject to the following conditions: +// +//The above copyright notice and this permission notice shall be included in all +//copies or substantial portions of the Software. +// +//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +//SOFTWARE. + +module second_order_dac( + input wire i_clk, + input wire i_res, + input wire i_ce, + input wire [15:0] i_func, + output wire o_DAC +); + + reg this_bit; + + reg [19:0] DAC_acc_1st; + reg [19:0] DAC_acc_2nd; + reg [19:0] i_func_extended; + + assign o_DAC = this_bit; + + always @(*) + i_func_extended = {i_func[15],i_func[15],i_func[15],i_func[15],i_func}; + + always @(posedge i_clk or negedge i_res) + begin + if (i_res==0) + begin + DAC_acc_1st<=16'd0; + DAC_acc_2nd<=16'd0; + this_bit = 1'b0; + end + else if(i_ce == 1'b1) + begin + if(this_bit == 1'b1) + begin + DAC_acc_1st = DAC_acc_1st + i_func_extended - (2**15); + DAC_acc_2nd = DAC_acc_2nd + DAC_acc_1st - (2**15); + end + else + begin + DAC_acc_1st = DAC_acc_1st + i_func_extended + (2**15); + DAC_acc_2nd = DAC_acc_2nd + DAC_acc_1st + (2**15); + end + // When the high bit is set (a negative value) we need to output a 0 and when it is clear we need to output a 1. + this_bit = ~DAC_acc_2nd[19]; + end + end +endmodule \ No newline at end of file diff --git a/sys/vga_out.sv b/sys/vga_out.sv index fe8172b..c258712 100644 --- a/sys/vga_out.sv +++ b/sys/vga_out.sv @@ -16,14 +16,16 @@ module vga_out output reg csync_o ); -wire [5:0] red = din[23:18]; -wire [5:0] green = din[15:10]; -wire [5:0] blue = din[7:2]; +wire [7:0] red = din[23:16]; +wire [7:0] green = din[15:8]; +wire [7:0] blue = din[7:0]; // http://marsee101.blog19.fc2.com/blog-entry-2311.html -// Y = 16 + 0.257*R + 0.504*G + 0.098*B (Y = 0.299*R + 0.587*G + 0.114*B) -// Pb = 128 - 0.148*R - 0.291*G + 0.439*B (Pb = -0.169*R - 0.331*G + 0.500*B) -// Pr = 128 + 0.439*R - 0.368*G - 0.071*B (Pr = 0.500*R - 0.419*G - 0.081*B) + + +// Y = 0.301*R + 0.586*G + 0.113*B (Y = 0.299*R + 0.587*G + 0.114*B) +// Pb = 128 - 0.168*R - 0.332*G + 0.500*B (Pb = -0.169*R - 0.331*G + 0.500*B) +// Pr = 128 + 0.500*R - 0.418*G - 0.082*B (Pr = 0.500*R - 0.419*G - 0.081*B) reg [7:0] y, pb, pr; reg [23:0] rgb; @@ -36,25 +38,25 @@ always @(posedge clk) begin reg hsync2, vsync2, csync2; reg hsync1, vsync1, csync1; - y_1r <= 19'd04096 + ({red, 8'd0} + {red, 3'd0}); - pb_1r <= 19'd32768 - ({red, 7'd0} + {red, 4'd0} + {red, 3'd0}); - pr_1r <= 19'd32768 + ({red, 8'd0} + {red, 7'd0} + {red, 6'd0}); + y_1r <= {red, 6'd0} + {red, 3'd0} + {red, 2'd0} + red; + pb_1r <= 19'd32768 - ({red, 5'd0} + {red, 3'd0} + {red, 1'd0}); + pr_1r <= 19'd32768 + {red, 7'd0}; - y_1g <= {green, 9'd0} + {green, 2'd0}; - pb_1g <= {green, 8'd0} + {green, 5'd0} + {green, 3'd0}; - pr_1g <= {green, 8'd0} + {green, 6'd0} + {green, 5'd0} + {green, 4'd0} + {green, 3'd0}; + y_1g <= {green, 7'd0} + {green, 4'd0} + {green, 2'd0} + {green, 1'd0}; + pb_1g <= {green, 6'd0} + {green, 4'd0} + {green, 2'd0} + green; + pr_1g <= {green, 6'd0} + {green, 5'd0} + {green, 3'd0} + {green, 1'd0}; - y_1b <= {blue, 6'd0} + {blue, 5'd0} + {blue, 2'd0}; - pb_1b <= {blue, 8'd0} + {blue, 7'd0} + {blue, 6'd0}; - pr_1b <= {blue, 6'd0} + {blue, 3'd0}; + y_1b <= {blue, 4'd0} + {blue, 3'd0} + {blue, 2'd0} + blue; + pb_1b <= {blue, 7'd0}; + pr_1b <= {blue, 4'd0} + {blue, 2'd0} + blue; y_2 <= y_1r + y_1g + y_1b; pb_2 <= pb_1r - pb_1g + pb_1b; pr_2 <= pr_1r - pr_1g - pr_1b; - y <= ( y_2[18] || !y_2[17:12]) ? 8'd16 : (y_2[17:8] > 235) ? 8'd235 : y_2[15:8]; - pb <= (pb_2[18] || !pb_2[17:12]) ? 8'd16 : (&pb_2[17:12]) ? 8'd240 : pb_2[15:8]; - pr <= (pr_2[18] || !pr_2[17:12]) ? 8'd16 : (&pr_2[17:12]) ? 8'd240 : pr_2[15:8]; + y <= y_2[18] ? 8'd0 : y_2[16] ? 8'd255 : y_2[15:8]; + pb <= pb_2[18] ? 8'd0 : pb_2[16] ? 8'd255 : pb_2[15:8]; + pr <= pr_2[18] ? 8'd0 : pr_2[16] ? 8'd255 : pr_2[15:8]; hsync_o <= hsync2; hsync2 <= hsync1; hsync1 <= hsync; vsync_o <= vsync2; vsync2 <= vsync1; vsync1 <= vsync; diff --git a/sys/video_freak.sv b/sys/video_freak.sv index 18beb03..4fe143b 100644 --- a/sys/video_freak.sv +++ b/sys/video_freak.sv @@ -173,7 +173,7 @@ sys_umul #(12,12) mul(CLK_VIDEO,mul_start,mul_run, mul_arg1,mul_arg2,mul_res); wire [11:0] wideres = mul_res[11:0] + hsize; always @(posedge CLK_VIDEO) begin - reg [11:0] oheight,wres; + reg [11:0] oheight,htarget,wres; reg [12:0] arxf,aryf; reg [3:0] cnt; reg narrow; @@ -188,11 +188,18 @@ always @(posedge CLK_VIDEO) begin else if(~div_start & ~div_run & ~mul_start & ~mul_run) begin cnt <= cnt + 1'd1; case(cnt) + // example ideal and non-ideal cases: + // [1] 720x400 4:3 VGA 80x25 text-mode (non-square pixels) + // [2] 640x480 4:3 VGA graphics mode (square pixels) + // [3] 512x512 4:3 X68000 graphics mode (non-square pixels) 0: begin div_num <= HDMI_HEIGHT; div_den <= vsize; div_start <= 1; end + // [1] 1080 / 400 -> 2 + // [2] 1080 / 480 -> 2 + // [3] 1080 / 512 -> 2 1: if(!div_res[11:0]) begin // screen resolution is lower than video resolution. @@ -206,6 +213,9 @@ always @(posedge CLK_VIDEO) begin mul_arg2 <= div_res[11:0]; mul_start <= 1; end + // [1] 1080 / 400 * 400 -> 800 + // [2] 1080 / 480 * 480 -> 960 + // [3] 1080 / 512 * 512 -> 1024 2: begin oheight <= mul_res[11:0]; @@ -219,24 +229,39 @@ always @(posedge CLK_VIDEO) begin mul_arg2 <= arx_i; mul_start <= 1; end + // [1] 1080 / 400 * 400 * 4 -> 3200 + // [2] 1080 / 480 * 480 * 4 -> 3840 + // [3] 1080 / 512 * 512 * 4 -> 4096 4: begin div_num <= mul_res; div_den <= ary_i; div_start <= 1; end + // [1] 1080 / 480 * 480 * 4 / 3 -> 1066 + // [2] 1080 / 480 * 480 * 4 / 3 -> 1280 + // [3] 1080 / 512 * 512 * 4 / 3 -> 1365 + // saved as htarget 5: begin + htarget <= div_res[11:0]; div_num <= div_res; div_den <= hsize; div_start <= 1; end + // computes wide scaling factor as a ceiling division + // [1] 1080 / 400 * 400 * 4 / 3 / 720 -> 1 + // [2] 1080 / 480 * 480 * 4 / 3 / 640 -> 2 + // [3] 1080 / 512 * 512 * 4 / 3 / 512 -> 2 6: begin mul_arg1 <= hsize; mul_arg2 <= div_res[11:0] ? div_res[11:0] : 12'd1; mul_start <= 1; end + // [1] 1080 / 400 * 400 * 4 / 3 / 720 * 720 -> 720 + // [2] 1080 / 480 * 480 * 4 / 3 / 640 * 640 -> 1280 + // [3] 1080 / 512 * 512 * 4 / 3 / 512 * 512 -> 1024 7: if(mul_res <= HDMI_WIDTH) begin cnt <= 10; @@ -247,17 +272,32 @@ always @(posedge CLK_VIDEO) begin div_den <= hsize; div_start <= 1; end + // [1] 1920 / 720 -> 2 + // [2] 1920 / 640 -> 3 + // [3] 1920 / 512 -> 3 9: begin mul_arg1 <= hsize; mul_arg2 <= div_res[11:0] ? div_res[11:0] : 12'd1; mul_start <= 1; end + // [1] 1920 / 720 * 720 -> 1440 + // [2] 1920 / 640 * 640 -> 1920 + // [3] 1920 / 512 * 512 -> 1536 10: begin - narrow <= ((div_num[11:0] - mul_res[11:0]) <= (wideres - div_num[11:0])) || (wideres > HDMI_WIDTH); - wres <= wideres; + narrow <= ((htarget - mul_res[11:0]) <= (wideres - htarget)) || (wideres > HDMI_WIDTH); + wres <= mul_res[11:0] == htarget ? mul_res[11:0] : wideres; end + // [1] 1066 - 720 = 346 <= 1440 - 1066 = 374 || 1440 > 1920 -> true + // [2] 1280 - 1280 = 0 <= 1920 - 1280 = 640 || 1920 > 1920 -> true + // [3] 1365 - 1024 = 341 <= 1536 - 1365 = 171 || 1536 > 1920 -> false + // 1. narrow flag is true when mul_res[11:0] narrow width is closer to + // htarget aspect ratio target width or when wideres wider width + // does not fit to the screen. + // 2. wres becomes wideres only when mul_res[11:0] narrow width not equal + // to target width, meaning it is not optimal for source aspect ratio. + // otherwise it is set to narrow width that is optimal. 11: begin case(SCALE)