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