FreeCalypso > hg > fc-pcm-if
changeset 1:b3190839cce3
first FPGA version, MCSI Rx only
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 11 Oct 2024 21:11:24 +0000 |
parents | 4624f3da093a |
children | a4918a161d2e |
files | .hgignore fpga/mcsi-rx/Makefile fpga/mcsi-rx/clk_check.v fpga/mcsi-rx/clk_edge.v fpga/mcsi-rx/mcsi_rx.v fpga/mcsi-rx/sync_inputs.v fpga/mcsi-rx/top.v fpga/mcsi-rx/uart_tx.v |
diffstat | 8 files changed, 249 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Fri Oct 11 21:11:24 2024 +0000 @@ -0,0 +1,6 @@ +syntax: regexp + +\.asc$ +\.bin$ +\.json$ +\.rpt$
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fpga/mcsi-rx/Makefile Fri Oct 11 21:11:24 2024 +0000 @@ -0,0 +1,21 @@ +VSRC= clk_check.v clk_edge.v mcsi_rx.v sync_inputs.v top.v uart_tx.v +PCF= ../common/icestick-mcsi.pcf +PROJ= fpga + +all: ${PROJ}.bin timing.rpt + +${PROJ}.json: ${VSRC} + ../tools/yosys-tee top $@ synthesis.rpt ${VSRC} + +${PROJ}.asc: ${PROJ}.json ${PCF} + nextpnr-ice40 --hx1k --package tq144 --asc $@ --pcf ${PCF} \ + --json ${PROJ}.json -l pnr.rpt + +${PROJ}.bin: ${PROJ}.asc + icepack $< $@ + +timing.rpt: ${PROJ}.asc + icetime -d hx1k -mtr $@ $< + +clean: + rm -f *.json *.asc *.bin *.rpt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fpga/mcsi-rx/clk_check.v Fri Oct 11 21:11:24 2024 +0000 @@ -0,0 +1,21 @@ +/* + * The logic implemented in this module detects if MCSI_CLK is running or not, + * for the purpose of visual indication on a LED. In the future Tx-capable + * FPGA, this logic will also be used to reset the Tx buffer when the clock + * stops. + */ + +module clk_check (IntClk, MCSI_CLK_sync, MCSI_CLK_running); + +input IntClk; +input MCSI_CLK_sync; +output MCSI_CLK_running; + +reg [15:0] shift_reg; + +always @(posedge IntClk) + shift_reg <= {shift_reg[14:0],MCSI_CLK_sync}; + +assign MCSI_CLK_running = (shift_reg != 16'h0000) && (shift_reg != 16'hFFFF); + +endmodule
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fpga/mcsi-rx/clk_edge.v Fri Oct 11 21:11:24 2024 +0000 @@ -0,0 +1,19 @@ +/* + * This Verilog module captures the logic that detects falling edges of + * MCSI_CLK: it is the edge on which we have to sample data and frame sync. + */ + +module clk_edge (IntClk, MCSI_CLK_sync, MCSI_CLK_negedge); + +input IntClk; +input MCSI_CLK_sync; +output MCSI_CLK_negedge; + +reg prev_state; + +always @(posedge IntClk) + prev_state <= MCSI_CLK_sync; + +assign MCSI_CLK_negedge = !MCSI_CLK_sync && prev_state; + +endmodule
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fpga/mcsi-rx/mcsi_rx.v Fri Oct 11 21:11:24 2024 +0000 @@ -0,0 +1,32 @@ +/* + * This Verilog module captures the logic that receives 16-bit PCM samples + * from MCSI. This logic block also detects loss of frame sync. + */ + +module mcsi_rx (IntClk, MCSI_FS_sync, MCSI_Din_sync, MCSI_CLK_negedge, + PCM_sample_out, PCM_sample_strobe, FS_lost); + +input IntClk; +input MCSI_FS_sync, MCSI_Din_sync, MCSI_CLK_negedge; +output [15:0] PCM_sample_out; +output PCM_sample_strobe; +output FS_lost; + +reg [15:0] shift_reg; +reg [6:0] bit_count; + +always @(posedge IntClk) + if (MCSI_CLK_negedge) + begin + shift_reg <= {shift_reg[14:0],MCSI_Din_sync}; + if (MCSI_FS_sync) + bit_count <= 7'd0; + else if (bit_count != 7'd127) + bit_count <= bit_count + 7'd1; + end + +assign PCM_sample_out = shift_reg; +assign PCM_sample_strobe = MCSI_CLK_negedge && (bit_count == 7'd16); +assign FS_lost = (bit_count == 7'd127); + +endmodule
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fpga/mcsi-rx/sync_inputs.v Fri Oct 11 21:11:24 2024 +0000 @@ -0,0 +1,35 @@ +/* + * This Verilog module captures the input synchronizer logic: passing + * all 3 MCSI inputs through double-DFF synchronizers to bring them into + * our internal clock domain. + */ + +module sync_inputs (IntClk, MCSI_CLK_raw, MCSI_CLK_sync, MCSI_FS_raw, + MCSI_FS_sync, MCSI_Din_raw, MCSI_Din_sync); + +input IntClk; +input MCSI_CLK_raw, MCSI_FS_raw, MCSI_Din_raw; +output MCSI_CLK_sync, MCSI_FS_sync, MCSI_Din_sync; +reg MCSI_CLK_sync, MCSI_FS_sync, MCSI_Din_sync; + +reg MCSI_CLK_sync1, MCSI_FS_sync1, MCSI_Din_sync1; + +always @(posedge IntClk) + MCSI_CLK_sync1 <= MCSI_CLK_raw; + +always @(posedge IntClk) + MCSI_CLK_sync <= MCSI_CLK_sync1; + +always @(posedge IntClk) + MCSI_FS_sync1 <= MCSI_FS_raw; + +always @(posedge IntClk) + MCSI_FS_sync <= MCSI_FS_sync1; + +always @(posedge IntClk) + MCSI_Din_sync1 <= MCSI_Din_raw; + +always @(posedge IntClk) + MCSI_Din_sync <= MCSI_Din_sync1; + +endmodule
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fpga/mcsi-rx/top.v Fri Oct 11 21:11:24 2024 +0000 @@ -0,0 +1,70 @@ +/* + * Top level Verilog module for MCSI Rx-only FPGA. + */ + +module top (CLK12, LED1, LED2, LED3, LED4, LED5, UART_TxD, UART_RxD, UART_RTS, + UART_CTS, UART_DTR, UART_DSR, UART_DCD, MCSI_CLK, MCSI_FSYNCH, + MCSI_TXD, MCSI_RXD); + +input CLK12; +output LED1, LED2, LED3, LED4, LED5; + +input UART_TxD, UART_RTS, UART_DTR; +output UART_RxD, UART_CTS, UART_DSR, UART_DCD; + +input MCSI_CLK, MCSI_FSYNCH, MCSI_TXD; +output MCSI_RXD; + +/* input synchronizers */ + +wire MCSI_CLK_sync, MCSI_FS_sync, MCSI_Din_sync; + +sync_inputs sync (CLK12, MCSI_CLK, MCSI_CLK_sync, MCSI_FSYNCH, MCSI_FS_sync, + MCSI_TXD, MCSI_Din_sync); + +/* running clock detector */ + +wire MCSI_CLK_running; + +clk_check clk_check (CLK12, MCSI_CLK_sync, MCSI_CLK_running); + +/* MCSI_CLK edge detector */ + +wire MCSI_CLK_negedge; + +clk_edge clk_edge (CLK12, MCSI_CLK_sync, MCSI_CLK_negedge); + +/* MCSI Rx logic */ + +wire [15:0] PCM_sample_out; +wire PCM_sample_strobe; +wire FS_lost, clk_fs_good; + +mcsi_rx mcsi_rx (CLK12, MCSI_FS_sync, MCSI_Din_sync, MCSI_CLK_negedge, + PCM_sample_out, PCM_sample_strobe, FS_lost); + +assign clk_fs_good = MCSI_CLK_running && !FS_lost; + +/* output to the host */ + +uart_tx uart_tx (CLK12, PCM_sample_strobe, PCM_sample_out, UART_RxD); + +/* UART modem control outputs: unused */ + +assign UART_CTS = 1'b1; +assign UART_DSR = 1'b0; +assign UART_DCD = 1'b0; + +/* board LEDs */ + +assign LED1 = 1'b0; +assign LED2 = 1'b1; +assign LED3 = 1'b0; +assign LED4 = 1'b1; +assign LED5 = clk_fs_good; + +/* No MCSI output in this version */ + +assign MCSI_RXD = 1'b0; + +endmodule
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fpga/mcsi-rx/uart_tx.v Fri Oct 11 21:11:24 2024 +0000 @@ -0,0 +1,45 @@ +/* + * This Verilog module captures the UART output logic. + */ + +module uart_tx (IntClk, Tx_trigger, Tx_data, UART_out); + +input IntClk; +input Tx_trigger; +input [15:0] Tx_data; +output UART_out; +reg UART_out; + +reg tx_active; +reg [5:0] clk_div; +reg [4:0] bit_count; +reg [17:0] shift_reg; + +initial begin + tx_active = 1'b0; + UART_out = 1'b1; +end + +always @(posedge IntClk) + if (!tx_active && Tx_trigger) + begin + tx_active <= 1'b1; + UART_out <= 1'b0; + clk_div <= 6'd0; + shift_reg <= {Tx_data[15:8],2'b01,Tx_data[7:0]}; + bit_count <= 5'd0; + end + else if (tx_active) + begin + clk_div <= clk_div + 6'd1; + if (clk_div == 6'd63) + begin + UART_out <= shift_reg[0]; + shift_reg <= {1,shift_reg[17:1]}; + bit_count <= bit_count + 5'd1; + if (bit_count == 5'd19) + tx_active <= 1'b0; + end + end + +endmodule