From 4cfeb8586dbbf07feaaf37d187392d2fcc77b69b Mon Sep 17 00:00:00 2001 From: sorgelig Date: Sat, 20 Apr 2019 03:36:14 +0800 Subject: [PATCH] Support tape loading from external player through ADC input. --- ZX-Spectrum.qsf | 2 +- ZX-Spectrum.sv | 17 ++++- ZX-Spectrum_Q13.srf | 1 + sys/ltc2308.sv | 162 ++++++++++++++++++++++++++++++++++++++++++++ sys/sys.qip | 1 + sys/sys_q13.qip | 1 + sys/sys_top.v | 9 ++- 7 files changed, 188 insertions(+), 5 deletions(-) create mode 100644 sys/ltc2308.sv diff --git a/ZX-Spectrum.qsf b/ZX-Spectrum.qsf index 9ede156..fc58871 100644 --- a/ZX-Spectrum.qsf +++ b/ZX-Spectrum.qsf @@ -63,6 +63,7 @@ set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC_FOR_AREA ON set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_DUPLICATION ON set_global_assignment -name PHYSICAL_SYNTHESIS_ASYNCHRONOUS_SIGNAL_PIPELINING ON set_global_assignment -name ALM_REGISTER_PACKING_EFFORT LOW +set_global_assignment -name ADV_NETLIST_OPT_SYNTH_WYSIWYG_REMAP ON set_global_assignment -name SEED 3 #============================================================ @@ -382,5 +383,4 @@ set_global_assignment -name SYSTEMVERILOG_FILE tape.sv set_global_assignment -name VERILOG_FILE mouse.v set_global_assignment -name SYSTEMVERILOG_FILE keyboard.sv set_global_assignment -name SYSTEMVERILOG_FILE "ZX-Spectrum.sv" -set_global_assignment -name ADV_NETLIST_OPT_SYNTH_WYSIWYG_REMAP ON set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file diff --git a/ZX-Spectrum.sv b/ZX-Spectrum.sv index 2375ad4..541c573 100644 --- a/ZX-Spectrum.sv +++ b/ZX-Spectrum.sv @@ -62,7 +62,9 @@ module emu output [15:0] AUDIO_R, output AUDIO_S, // 1 - signed audio samples, 0 - unsigned output [1:0] AUDIO_MIX, // 0 - no mix, 1 - 25%, 2 - 50%, 3 - 100% (mono) - input TAPE_IN, + + //ADC + inout [3:0] ADC_BUS, // SD-SPI output SD_SCK, @@ -123,7 +125,7 @@ assign {SD_SCK, SD_MOSI, SD_CS} = 'Z; assign AUDIO_S = 1; assign AUDIO_MIX = status[3:2]; -assign LED_USER = ioctl_download | tape_led; +assign LED_USER = ioctl_download | tape_led | tape_adc_act; assign LED_DISK = 0; assign LED_POWER = 0; @@ -1056,7 +1058,16 @@ always @(posedge clk_sys) begin end end -assign tape_in = tape_loaded_reg ? tape_vin : ~(ear_out | mic_out); +assign tape_in = tape_loaded_reg ? tape_vin : tape_adc_act ? tape_adc : ~(ear_out | mic_out); + +wire tape_adc, tape_adc_act; +ltc2308_tape ltc2308_tape +( + .clk(CLK_50M), + .ADC_BUS(ADC_BUS), + .dout(tape_adc), + .active(tape_adc_act) +); ////////////////// ARCH SET ////////////////// diff --git a/ZX-Spectrum_Q13.srf b/ZX-Spectrum_Q13.srf index 977fafe..f64be59 100644 --- a/ZX-Spectrum_Q13.srf +++ b/ZX-Spectrum_Q13.srf @@ -22,6 +22,7 @@ { "" "" "" "RST port on the PLL is not properly connected on instance emu:emu\|pll:pll\|pll_0002:pll_inst\|altera_pll:altera_pll_i\|general\[2\].gpll. The reset port on the PLL should be connected. If the PLL loses lock for any reason, you might need to manually reset the PLL in order to re-establish lock to the reference clock." { } { } 0 0 "" 0 0 "Quartus II" 0 -1 0 ""} { "" "" "" "*" { } { } 0 10268 "" 0 0 "Quartus II" 0 -1 0 ""} { "" "" "" "*" { } { } 0 276027 "" 0 0 "Quartus II" 0 -1 0 ""} +{ "" "" "" "*" { } { } 0 276020 "" 0 0 "Quartus II" 0 -1 0 ""} { "" "" "" "altera_pll.v" { } { } 0 9999 "" 0 0 "Quartus II" 0 -1 0 ""} { "" "" "" "altera_cyclonev_pll.v" { } { } 0 9999 "" 0 0 "Quartus II" 0 -1 0 ""} { "" "" "" "altera_pll_reconfig_core.v" { } { } 0 9999 "" 0 0 "Quartus II" 0 -1 0 ""} diff --git a/sys/ltc2308.sv b/sys/ltc2308.sv new file mode 100644 index 0000000..33134fd --- /dev/null +++ b/sys/ltc2308.sv @@ -0,0 +1,162 @@ +//============================================================================ +// +// LTC2308 controller +// Copyright (C) 2019 Sorgelig +// +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 of the License, or (at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +// more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +//============================================================================ + + +// NUM_CH 1..8 +// Sampling rate = ADC_RATE/NUM_CH +// ADC_RATE max is ~500KHz +// CLK_RATE max is ~80MHz +module ltc2308 #(parameter NUM_CH = 2, ADC_RATE = 96000, CLK_RATE = 50000000) +( + input reset, + input clk, + + inout [3:0] ADC_BUS, + + output reg dout_sync, // toggle with every ADC round + output reg [(NUM_CH*12)-1:0] dout // 12 bits per channel (unsigned) +); + +localparam TCONV = CLK_RATE/625000; + +reg sck; +wire sdo = cfg[5]; + +assign ADC_BUS[3] = sck; +wire sdi = ADC_BUS[2]; +assign ADC_BUS[1] = sdo; +assign ADC_BUS[0] = convst; + +reg convst; +reg [5:0] cfg; + +reg [31:0] sum; +wire [31:0] next_sum = sum + ADC_RATE; + +reg [2:0] pin; +wire [2:0] next_pin = (pin == (NUM_CH-1)) ? 3'd0 : (pin + 1'd1); + +always @(posedge clk) begin + reg [7:0] tconv; + reg [3:0] bitcnt; + reg [10:0] adcin; + + convst <= 0; + + if(reset) begin + sum <= 0; + tconv <= 0; + bitcnt <= 0; + sck <= 0; + cfg <= 0; + dout <= 0; + pin <= NUM_CH[2:0]-1'd1; + end + else begin + sum <= next_sum; + if(next_sum >= CLK_RATE) begin + sum <= next_sum - CLK_RATE; + tconv <= TCONV[7:0]; + convst <= 1; + bitcnt <= 12; + cfg <= {1'b1, next_pin[0], next_pin[2:1], 1'b1, 1'b0}; + if(!next_pin) dout_sync <= ~dout_sync; + end + + if(tconv) tconv <= tconv - 1'd1; + else if(bitcnt) begin + sck <= ~sck; + + if(sck) cfg <= cfg<<1; + else begin + adcin <= {adcin[9:0],sdi}; + bitcnt <= bitcnt - 1'd1; + if(bitcnt == 1) begin + dout[pin*12 +:12] <= {adcin,sdi}; + pin <= next_pin; + end + end + end + else sck <= 0; + end +end + +endmodule + +module ltc2308_tape #(parameter HIST_LOW = 16, HIST_HIGH = 64, ADC_RATE = 48000, CLK_RATE = 50000000) +( + input reset, + input clk, + + inout [3:0] ADC_BUS, + output reg dout, + output active +); + +wire [11:0] adc_data; +wire adc_sync; +ltc2308 #(1, ADC_RATE, CLK_RATE) adc +( + .reset(reset), + .clk(clk), + + .ADC_BUS(ADC_BUS), + .dout(adc_data), + .dout_sync(adc_sync) +); + +always @(posedge clk) begin + reg [13:0] data1,data2,data3,data4, sum; + reg adc_sync_d; + + adc_sync_d<=adc_sync; + if(adc_sync_d ^ adc_sync) begin + data1 <= data2; + data2 <= data3; + data3 <= data4; + data4 <= adc_data; + + sum <= data1+data2+data3+data4; + + if(sum[13:2]HIST_HIGH) dout <= 1; + end +end + +assign active = |act; + +reg [1:0] act; +always @(posedge clk) begin + reg [31:0] onesec; + reg old_dout; + + onesec <= onesec + 1; + if(onesec>CLK_RATE) begin + onesec <= 0; + if(act) act <= act - 1'd1; + end + + old_dout <= dout; + if(old_dout ^ dout) act <= 2; +end + +endmodule diff --git a/sys/sys.qip b/sys/sys.qip index 986b6d2..7184ddc 100644 --- a/sys/sys.qip +++ b/sys/sys.qip @@ -17,6 +17,7 @@ set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) a set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) i2s.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) spdif.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) audio_out.v ] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) ltc2308.sv ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) sigma_delta_dac.v ] set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) hdmi_config.sv ] set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) sysmem.sv ] diff --git a/sys/sys_q13.qip b/sys/sys_q13.qip index 760991a..1ebcbc3 100644 --- a/sys/sys_q13.qip +++ b/sys/sys_q13.qip @@ -21,6 +21,7 @@ set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) a set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) i2s.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) spdif.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) audio_out.v ] +set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) ltc2308.sv ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) sigma_delta_dac.v ] set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) hdmi_config.sv ] set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) sysmem.sv ] diff --git a/sys/sys_top.v b/sys/sys_top.v index 517189f..0cecbac 100644 --- a/sys/sys_top.v +++ b/sys/sys_top.v @@ -83,6 +83,12 @@ module sys_top output SDIO_CLK, input SDIO_CD, + ////////// ADC ////////////// + output ADC_SCK, + input ADC_SDO, + output ADC_SDI, + output ADC_CONVST, + ////////// MB KEY /////////// input [1:0] KEY, @@ -860,7 +866,8 @@ emu emu .AUDIO_R(audio_rs), .AUDIO_S(audio_s), .AUDIO_MIX(audio_mix), - .TAPE_IN(0), + + .ADC_BUS({ADC_SCK,ADC_SDO,ADC_SDI,ADC_CONVST}), .SD_SCK(SDIO_CLK), .SD_MOSI(SDIO_CMD),