Browse Source

Merge remote-tracking branch 'origin/main' into slow

Resolved Conflicts:
	fpga/output/v1.jic
	fpga/output/v1.sof
	fpga/output/v2.jic
	fpga/output/v2.sof
H. Peter Anvin 3 years ago
parent
commit
06f36dc8f0

+ 1 - 1
fpga/clkbuf.sv

@@ -27,7 +27,7 @@ module clk_buf
 			     .datain_h ( ~invert ),
 			     .datain_l (  invert ),
 			     .outclock ( clk ),
-			     .dataout  ( ddio_pin )
+			     .dataout  ( pin )
 			     );
 	end // else: !if( noddio )
    endgenerate

+ 6 - 0
fpga/ip/cdc_fifo.qip

@@ -0,0 +1,6 @@
+set_global_assignment -name IP_TOOL_NAME "FIFO"
+set_global_assignment -name IP_TOOL_VERSION "21.1"
+set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{Cyclone IV E}"
+set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "cdc_fifo.v"]
+set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "cdc_fifo_inst.v"]
+set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "cdc_fifo_bb.v"]

+ 205 - 0
fpga/ip/cdc_fifo.v

@@ -0,0 +1,205 @@
+// megafunction wizard: %FIFO%
+// GENERATION: STANDARD
+// VERSION: WM1.0
+// MODULE: dcfifo 
+
+// ============================================================
+// File Name: cdc_fifo.v
+// Megafunction Name(s):
+// 			dcfifo
+//
+// Simulation Library Files(s):
+// 			altera_mf
+// ============================================================
+// ************************************************************
+// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
+//
+// 21.1.0 Build 842 10/21/2021 SJ Lite Edition
+// ************************************************************
+
+
+//Copyright (C) 2021  Intel Corporation. All rights reserved.
+//Your use of Intel Corporation's design tools, logic functions 
+//and other software and tools, and any partner logic 
+//functions, and any output files from any of the foregoing 
+//(including device programming or simulation files), and any 
+//associated documentation or information are expressly subject 
+//to the terms and conditions of the Intel Program License 
+//Subscription Agreement, the Intel Quartus Prime License Agreement,
+//the Intel FPGA IP License Agreement, or other applicable license
+//agreement, including, without limitation, that your use is for
+//the sole purpose of programming logic devices manufactured by
+//Intel and sold by Intel or its authorized distributors.  Please
+//refer to the applicable agreement for further details, at
+//https://fpgasoftware.intel.com/eula.
+
+
+// synopsys translate_off
+`timescale 1 ps / 1 ps
+// synopsys translate_on
+module cdc_fifo (
+	aclr,
+	data,
+	rdclk,
+	rdreq,
+	wrclk,
+	wrreq,
+	q,
+	rdempty,
+	rdfull,
+	rdusedw,
+	wrempty,
+	wrfull,
+	wrusedw);
+
+	input	  aclr;
+	input	[7:0]  data;
+	input	  rdclk;
+	input	  rdreq;
+	input	  wrclk;
+	input	  wrreq;
+	output	[7:0]  q;
+	output	  rdempty;
+	output	  rdfull;
+	output	[8:0]  rdusedw;
+	output	  wrempty;
+	output	  wrfull;
+	output	[8:0]  wrusedw;
+`ifndef ALTERA_RESERVED_QIS
+// synopsys translate_off
+`endif
+	tri0	  aclr;
+`ifndef ALTERA_RESERVED_QIS
+// synopsys translate_on
+`endif
+
+	wire [7:0] sub_wire0;
+	wire  sub_wire1;
+	wire  sub_wire2;
+	wire [8:0] sub_wire3;
+	wire  sub_wire4;
+	wire  sub_wire5;
+	wire [8:0] sub_wire6;
+	wire [7:0] q = sub_wire0[7:0];
+	wire  rdempty = sub_wire1;
+	wire  rdfull = sub_wire2;
+	wire [8:0] rdusedw = sub_wire3[8:0];
+	wire  wrempty = sub_wire4;
+	wire  wrfull = sub_wire5;
+	wire [8:0] wrusedw = sub_wire6[8:0];
+
+	dcfifo	dcfifo_component (
+				.aclr (aclr),
+				.data (data),
+				.rdclk (rdclk),
+				.rdreq (rdreq),
+				.wrclk (wrclk),
+				.wrreq (wrreq),
+				.q (sub_wire0),
+				.rdempty (sub_wire1),
+				.rdfull (sub_wire2),
+				.rdusedw (sub_wire3),
+				.wrempty (sub_wire4),
+				.wrfull (sub_wire5),
+				.wrusedw (sub_wire6),
+				.eccstatus ());
+	defparam
+		dcfifo_component.intended_device_family = "Cyclone IV E",
+		dcfifo_component.lpm_numwords = 512,
+		dcfifo_component.lpm_showahead = "OFF",
+		dcfifo_component.lpm_type = "dcfifo",
+		dcfifo_component.lpm_width = 8,
+		dcfifo_component.lpm_widthu = 9,
+		dcfifo_component.overflow_checking = "ON",
+		dcfifo_component.rdsync_delaypipe = 5,
+		dcfifo_component.read_aclr_synch = "ON",
+		dcfifo_component.underflow_checking = "ON",
+		dcfifo_component.use_eab = "ON",
+		dcfifo_component.write_aclr_synch = "ON",
+		dcfifo_component.wrsync_delaypipe = 5;
+
+
+endmodule
+
+// ============================================================
+// CNX file retrieval info
+// ============================================================
+// Retrieval info: PRIVATE: AlmostEmpty NUMERIC "0"
+// Retrieval info: PRIVATE: AlmostEmptyThr NUMERIC "-1"
+// Retrieval info: PRIVATE: AlmostFull NUMERIC "0"
+// Retrieval info: PRIVATE: AlmostFullThr NUMERIC "-1"
+// Retrieval info: PRIVATE: CLOCKS_ARE_SYNCHRONIZED NUMERIC "0"
+// Retrieval info: PRIVATE: Clock NUMERIC "4"
+// Retrieval info: PRIVATE: Depth NUMERIC "512"
+// Retrieval info: PRIVATE: Empty NUMERIC "1"
+// Retrieval info: PRIVATE: Full NUMERIC "1"
+// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone IV E"
+// Retrieval info: PRIVATE: LE_BasedFIFO NUMERIC "0"
+// Retrieval info: PRIVATE: LegacyRREQ NUMERIC "1"
+// Retrieval info: PRIVATE: MAX_DEPTH_BY_9 NUMERIC "0"
+// Retrieval info: PRIVATE: OVERFLOW_CHECKING NUMERIC "0"
+// Retrieval info: PRIVATE: Optimize NUMERIC "2"
+// Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0"
+// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0"
+// Retrieval info: PRIVATE: UNDERFLOW_CHECKING NUMERIC "0"
+// Retrieval info: PRIVATE: UsedW NUMERIC "1"
+// Retrieval info: PRIVATE: Width NUMERIC "8"
+// Retrieval info: PRIVATE: dc_aclr NUMERIC "1"
+// Retrieval info: PRIVATE: diff_widths NUMERIC "0"
+// Retrieval info: PRIVATE: msb_usedw NUMERIC "0"
+// Retrieval info: PRIVATE: output_width NUMERIC "8"
+// Retrieval info: PRIVATE: rsEmpty NUMERIC "1"
+// Retrieval info: PRIVATE: rsFull NUMERIC "1"
+// Retrieval info: PRIVATE: rsUsedW NUMERIC "1"
+// Retrieval info: PRIVATE: sc_aclr NUMERIC "0"
+// Retrieval info: PRIVATE: sc_sclr NUMERIC "0"
+// Retrieval info: PRIVATE: wsEmpty NUMERIC "1"
+// Retrieval info: PRIVATE: wsFull NUMERIC "1"
+// Retrieval info: PRIVATE: wsUsedW NUMERIC "1"
+// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
+// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone IV E"
+// Retrieval info: CONSTANT: LPM_NUMWORDS NUMERIC "512"
+// Retrieval info: CONSTANT: LPM_SHOWAHEAD STRING "OFF"
+// Retrieval info: CONSTANT: LPM_TYPE STRING "dcfifo"
+// Retrieval info: CONSTANT: LPM_WIDTH NUMERIC "8"
+// Retrieval info: CONSTANT: LPM_WIDTHU NUMERIC "9"
+// Retrieval info: CONSTANT: OVERFLOW_CHECKING STRING "ON"
+// Retrieval info: CONSTANT: RDSYNC_DELAYPIPE NUMERIC "5"
+// Retrieval info: CONSTANT: READ_ACLR_SYNCH STRING "ON"
+// Retrieval info: CONSTANT: UNDERFLOW_CHECKING STRING "ON"
+// Retrieval info: CONSTANT: USE_EAB STRING "ON"
+// Retrieval info: CONSTANT: WRITE_ACLR_SYNCH STRING "ON"
+// Retrieval info: CONSTANT: WRSYNC_DELAYPIPE NUMERIC "5"
+// Retrieval info: USED_PORT: aclr 0 0 0 0 INPUT GND "aclr"
+// Retrieval info: USED_PORT: data 0 0 8 0 INPUT NODEFVAL "data[7..0]"
+// Retrieval info: USED_PORT: q 0 0 8 0 OUTPUT NODEFVAL "q[7..0]"
+// Retrieval info: USED_PORT: rdclk 0 0 0 0 INPUT NODEFVAL "rdclk"
+// Retrieval info: USED_PORT: rdempty 0 0 0 0 OUTPUT NODEFVAL "rdempty"
+// Retrieval info: USED_PORT: rdfull 0 0 0 0 OUTPUT NODEFVAL "rdfull"
+// Retrieval info: USED_PORT: rdreq 0 0 0 0 INPUT NODEFVAL "rdreq"
+// Retrieval info: USED_PORT: rdusedw 0 0 9 0 OUTPUT NODEFVAL "rdusedw[8..0]"
+// Retrieval info: USED_PORT: wrclk 0 0 0 0 INPUT NODEFVAL "wrclk"
+// Retrieval info: USED_PORT: wrempty 0 0 0 0 OUTPUT NODEFVAL "wrempty"
+// Retrieval info: USED_PORT: wrfull 0 0 0 0 OUTPUT NODEFVAL "wrfull"
+// Retrieval info: USED_PORT: wrreq 0 0 0 0 INPUT NODEFVAL "wrreq"
+// Retrieval info: USED_PORT: wrusedw 0 0 9 0 OUTPUT NODEFVAL "wrusedw[8..0]"
+// Retrieval info: CONNECT: @aclr 0 0 0 0 aclr 0 0 0 0
+// Retrieval info: CONNECT: @data 0 0 8 0 data 0 0 8 0
+// Retrieval info: CONNECT: @rdclk 0 0 0 0 rdclk 0 0 0 0
+// Retrieval info: CONNECT: @rdreq 0 0 0 0 rdreq 0 0 0 0
+// Retrieval info: CONNECT: @wrclk 0 0 0 0 wrclk 0 0 0 0
+// Retrieval info: CONNECT: @wrreq 0 0 0 0 wrreq 0 0 0 0
+// Retrieval info: CONNECT: q 0 0 8 0 @q 0 0 8 0
+// Retrieval info: CONNECT: rdempty 0 0 0 0 @rdempty 0 0 0 0
+// Retrieval info: CONNECT: rdfull 0 0 0 0 @rdfull 0 0 0 0
+// Retrieval info: CONNECT: rdusedw 0 0 9 0 @rdusedw 0 0 9 0
+// Retrieval info: CONNECT: wrempty 0 0 0 0 @wrempty 0 0 0 0
+// Retrieval info: CONNECT: wrfull 0 0 0 0 @wrfull 0 0 0 0
+// Retrieval info: CONNECT: wrusedw 0 0 9 0 @wrusedw 0 0 9 0
+// Retrieval info: GEN_FILE: TYPE_NORMAL cdc_fifo.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL cdc_fifo.inc FALSE
+// Retrieval info: GEN_FILE: TYPE_NORMAL cdc_fifo.cmp FALSE
+// Retrieval info: GEN_FILE: TYPE_NORMAL cdc_fifo.bsf FALSE
+// Retrieval info: GEN_FILE: TYPE_NORMAL cdc_fifo_inst.v TRUE
+// Retrieval info: GEN_FILE: TYPE_NORMAL cdc_fifo_bb.v TRUE
+// Retrieval info: LIB_FILE: altera_mf

+ 3 - 3
fpga/max80.qpf

@@ -19,14 +19,14 @@
 #
 # Quartus Prime
 # Version 21.1.0 Build 842 10/21/2021 SJ Lite Edition
-# Date created = 14:03:58  December 29, 2021
+# Date created = 19:51:05  December 29, 2021
 #
 # -------------------------------------------------------------------------- #
 
 QUARTUS_VERSION = "21.1"
-DATE = "14:03:58  December 29, 2021"
+DATE = "19:51:05  December 29, 2021"
 
 # Revisions
 
-PROJECT_REVISION = "v2"
 PROJECT_REVISION = "v1"
+PROJECT_REVISION = "v2"

+ 2 - 1
fpga/max80.qsf

@@ -257,7 +257,6 @@ set_global_assignment -name VERILOG_FILE usb/usb_serial/src_v/usbf_sie_tx.v
 set_global_assignment -name VERILOG_FILE usb/usb_serial/src_v/usbf_sie_rx.v
 set_global_assignment -name VERILOG_FILE usb/usb_serial/src_v/usbf_defs.v
 set_global_assignment -name VERILOG_FILE usb/usb_serial/src_v/usbf_crc16.v
-set_global_assignment -name VERILOG_FILE usb/usb_serial/src_v/usb_cdc_top.v
 set_global_assignment -name SYSTEMVERILOG_FILE usb/usb.sv
 set_global_assignment -name VERILOG_FILE ip/statusram.v
 set_global_assignment -name VERILOG_INCLUDE_FILE iodevs.vh
@@ -291,5 +290,7 @@ set_global_assignment -name SYSTEMVERILOG_FILE v2.sv
 set_global_assignment -name SOURCE_TCL_SCRIPT_FILE scripts/pins.tcl
 set_global_assignment -name VERILOG_FILE ip/fifo.v
 set_global_assignment -name VERILOG_FILE ip/ddufifo.v
+set_global_assignment -name VERILOG_FILE ip/cdc_fifo.v
+set_global_assignment -name QIP_FILE ip/cdc_fifo.qip
 
 set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

+ 24 - 32
fpga/max80.sv

@@ -592,21 +592,7 @@ module max80
 			      max80_minor, max80_fixes };
 
    // System reset
-   wire        usb_rxd_break;
-   reg	       usb_rxd_break_q;
-   reg	       usb_rxd_break_rst;
-
-   always @(negedge rst_n or posedge sys_clk)
-     if (~rst_n)
-       begin
-	  usb_rxd_break_q   <= 1'b1;
-	  usb_rxd_break_rst <= 1'b0;
-       end
-     else
-       begin
-	  usb_rxd_break_q   <= usb_rxd_break;
-	  usb_rxd_break_rst <= usb_rxd_break & ~usb_rxd_break_q;
-       end
+   wire	       usb_rxd_break_rst; // Break due to USB serial port BREAK
 
    // Reset control. Note that CPU reset command 0 is intentionally ignored.
    wire [3:0] cpu_reset_cmd =
@@ -705,34 +691,40 @@ module max80
 
    assign tty_cts_out = 1'b1;	// Always assert CTS# for now
 
+   // The physical tty now just snoops USB ACM channel 0; as such it does
+   // not respond to any write requests nor issue any irqs
    tty console (
 	    .rst_n ( hard_rst_n ),
 	    .clk   ( sys_clk ),
 
-	    .valid ( iodev_valid_console ),
+	    .valid ( iodev_valid_console &
+		     cpu_mem_addr[6:2] == 5'b00000 &
+		     cpu_mem_wstrb[0] ),
 	    .wstrb ( cpu_mem_wstrb ),
 	    .wdata ( cpu_mem_wdata ),
-	    .rdata ( iodev_rdata_console ),
+	    .rdata ( ),
 	    .addr  ( cpu_mem_addr[3:2] ),
-	    .irq   ( iodev_irq_console ),
+	    .irq   ( ),
 
 	    .tty_txd ( tty_data_out ) // DTE -> DCE
 	    );
 
    max80_usb usb (
-		  .rst_n         ( hard_rst_n ),
-		  .clock48       ( usb_clk ),
-
-		  .sys_clk       ( sys_clk ),
-		  .cpu_valid     ( iodev_valid_usbdesc ),
-		  .cpu_addr      ( cpu_mem_addr[17:2] ),
-		  .cpu_rdata     ( iodev_rdata_usbdesc ),
-		  .cpu_wdata     ( cpu_mem_wdata ),
-		  .cpu_wstrb     ( cpu_mem_wstrb ),
-
-		  .tty_rxd       ( ),
-		  .tty_rxd_break ( usb_rxd_break ),
-		  .tty_txd       ( tty_data_out ),
+		  .hard_rst_n         ( hard_rst_n ),
+		  .clock48            ( usb_clk ),
+
+		  .rst_n              ( rst_n ),
+		  .sys_clk            ( sys_clk ),
+		  .cpu_valid_usbdesc  ( iodev_valid_usbdesc ),
+		  .cpu_valid_cdc      ( iodev_valid_console ),
+		  .cpu_addr           ( cpu_mem_addr ),
+		  .cpu_rdata_usbdesc  ( iodev_rdata_usbdesc ),
+		  .cpu_rdata_cdc      ( iodev_rdata_console ),
+		  .cpu_wdata          ( cpu_mem_wdata ),
+		  .cpu_wstrb          ( cpu_mem_wstrb ),
+		  .irq                ( iodev_irq_console ),
+
+		  .tty_rxd_break ( usb_rxd_break_rst ),
 
 		  .usb_dp        ( usb_dp ),
 		  .usb_dn        ( usb_dn ),
@@ -832,7 +824,7 @@ module max80
    assign spi_miso       = esp_ctr[2];
    assign spi_cs_flash_n = esp_ctr[3]; // IO01
    assign spi_cs_esp_n   = esp_ctr[4]; // IO10
-   assign spi_int        = esp_ctr[5]; // IO09
+   assign esp_int        = esp_ctr[5]; // IO09
    assign esp_io0        = 1'b1;
 
 `endif

BIN
fpga/output/v1.jic


BIN
fpga/output/v1.sof


BIN
fpga/output/v2.jic


BIN
fpga/output/v2.sof


+ 1 - 0
fpga/spirom.sv

@@ -232,6 +232,7 @@ module spirom (
    reg [1:0]   go_spi_q;
    wire        go_spi_s;
    reg	       spi_more_q;
+   reg	       spi_active;
 
    // Explicit synchronizers for handshake signals
    synchronizer #(.width(1)) go_spi_synchro

+ 54 - 37
fpga/usb/usb.sv

@@ -5,27 +5,38 @@
 // to the output of the tty
 //
 
-module max80_usb (
-		  input		rst_n,
-		  input		clock48,
-
-		  input		sys_clk,
-		  input		cpu_valid,
-		  input [15:0]	cpu_addr,
-		  output [31:0] cpu_rdata,
-		  input [31:0]	cpu_wdata,
-		  input [3:0]	cpu_wstrb,
-
-		  output	tty_rxd,
-		  output	tty_rxd_break,
-		  input		tty_txd,
-
-		  inout		usb_dp, // Single ended D+
-		  inout		usb_dn, // Single ended D-
-		  input		usb_rx, // Differential input
-		  input		usb_rx_ok, // Differential input available
-		  output	usb_pu		// Driver for 1.5 kohm pullup
-		  );
+module max80_usb
+  #( parameter [2:0] channels = 3'd1 )
+   (
+    input		  hard_rst_n,
+    input		  clock48,
+
+    input		  rst_n,
+    input		  sys_clk,
+    input		  cpu_valid_usbdesc,
+    input		  cpu_valid_cdc,
+    input  [31:0]	  cpu_addr,
+    output [31:0]	  cpu_rdata_usbdesc,
+    output [31:0]	  cpu_rdata_cdc,
+    input  [31:0]	  cpu_wdata,
+    input   [3:0]	  cpu_wstrb,
+    output [channels-1:0] irq,
+
+    output		  tty_rxd_break, // Break on channel 0
+
+    inout		  usb_dp, // Single ended D+
+    inout		  usb_dn, // Single ended D-
+    input		  usb_rx, // Differential input
+    input		  usb_rx_ok, // Differential input available
+    output		  usb_pu		// Driver for 1.5 kohm pullup
+	  );
+
+   //
+   // BREAK status by channel
+   //
+   wire [channels-1:0]		recv_break;
+
+   assign tty_rxd_break = recv_break[0]; // = system soft reset
 
    //
    // UTMI interface to PHY
@@ -56,15 +67,18 @@ module max80_usb (
    wire			 usb_en;
 
    //
-   // Reset and I/O pins
+   // Reset: reset USB on hard_rst# but synchronize to the USB clock
    //
    reg			 usb_rst_n;
-   always @(negedge rst_n or posedge clock48)
-     if (~rst_n)
+   always @(negedge hard_rst_n or posedge clock48)
+     if (~hard_rst_n)
        usb_rst_n <= 1'b0;
      else
        usb_rst_n <= 1'b1;
 
+   //
+   // I/O pins to PHY
+   //
    assign usb_dp = ( usb_rst_n & ~usb_tx_oen ) ? usb_tx_dp : 1'bz;
    assign usb_dn = ( usb_rst_n & ~usb_tx_oen ) ? usb_tx_dn : 1'bz;
    assign usb_pu = ( usb_rst_n & usb_en )      ? 1'b1 : 1'bz;
@@ -100,10 +114,18 @@ module max80_usb (
 		       .usb_en_o           ( usb_en )
 		       );
 
-   usb_cdc_top #(.BAUDRATE(115200))
+   usb_cdc_core #(.channels(channels))
    usb_serial (
 	       .clk_i             ( clock48 ),
 	       .rst_i             ( ~usb_rst_n ),
+	       .enable_i	  ( 1'b1 ),
+
+	       .utmi_data_in_i    ( utmi_data_in ),
+	       .utmi_txready_i    ( utmi_txready ),
+	       .utmi_rxvalid_i    ( utmi_rxvalid ),
+	       .utmi_rxactive_i   ( utmi_rxactive ),
+	       .utmi_rxerror_i    ( utmi_rxerror ),
+	       .utmi_linestate_i  ( utmi_linestate ),
 
 	       .utmi_data_out_o   ( utmi_data_out ),
 	       .utmi_txvalid_o    ( utmi_txvalid ),
@@ -113,22 +135,17 @@ module max80_usb (
 	       .utmi_dppulldown_o ( utmi_dppulldown ),
 	       .utmi_dmpulldown_o ( utmi_dmpulldown ),
 
-	       .utmi_data_in_i    ( utmi_data_in ),
-	       .utmi_txready_i    ( utmi_txready ),
-	       .utmi_rxvalid_i    ( utmi_rxvalid ),
-	       .utmi_rxactive_i   ( utmi_rxactive ),
-	       .utmi_rxerror_i    ( utmi_rxerror ),
-	       .utmi_linestate_i  ( utmi_linestate ),
-
+	       .rst_n             ( rst_n ),
 	       .sys_clk           ( sys_clk ),
-	       .cpu_valid         ( cpu_valid ),
+	       .cpu_valid_usbdesc ( cpu_valid_usbdesc ),
+	       .cpu_valid_cdc     ( cpu_valid_cdc ),
 	       .cpu_addr          ( cpu_addr ),
-	       .cpu_rdata         ( cpu_rdata ),
+	       .cpu_rdata_usbdesc ( cpu_rdata_usbdesc ),
+	       .cpu_rdata_cdc     ( cpu_rdata_cdc ),
 	       .cpu_wdata         ( cpu_wdata ),
 	       .cpu_wstrb         ( cpu_wstrb ),
+	       .irq               ( irq ),
 
-	       .tx_i              ( tty_txd ),
-	       .rx_o              ( tty_rxd ),
-	       .rx_break_o        ( tty_rxd_break )
+	       .recv_break_o      ( recv_break )
 	       );
 endmodule // max80_usb

+ 1 - 1
fpga/usb/usb_desc.conf

@@ -112,7 +112,7 @@ usb_device {
 		     byte(500 >> 1)),	 # Up to 500 mA
 
 		# Descriptors for each ACM channel
-		acm_channels(1,2)	# 1 channel starting at EP 2
+		acm_channels(1,1)	# 1 channel starting at EP 1
     },
 };
 

+ 3 - 3
fpga/usb/usb_desc.v

@@ -109,7 +109,7 @@ module usb_desc_rom (
 		rom[8'h58] = 8'h01;
 		rom[8'h59] = 8'h07;
 		rom[8'h5a] = 8'h05;
-		rom[8'h5b] = 8'h83;
+		rom[8'h5b] = 8'h82;
 		rom[8'h5c] = 8'h03;
 		rom[8'h5d] = 8'h40;
 		rom[8'h5e] = 8'h00;
@@ -125,14 +125,14 @@ module usb_desc_rom (
 		rom[8'h68] = 8'h04;
 		rom[8'h69] = 8'h07;
 		rom[8'h6a] = 8'h05;
-		rom[8'h6b] = 8'h82;
+		rom[8'h6b] = 8'h81;
 		rom[8'h6c] = 8'h02;
 		rom[8'h6d] = 8'h40;
 		rom[8'h6e] = 8'h00;
 		rom[8'h6f] = 8'h00;
 		rom[8'h70] = 8'h07;
 		rom[8'h71] = 8'h05;
-		rom[8'h72] = 8'h02;
+		rom[8'h72] = 8'h01;
 		rom[8'h73] = 8'h02;
 		rom[8'h74] = 8'h40;
 		rom[8'h75] = 8'h00;

+ 370 - 154
fpga/usb/usb_serial/src_v/usb_cdc_core.sv

@@ -34,42 +34,303 @@
 // Boston, MA  02111-1307  USA
 //-----------------------------------------------------------------
 
-module usb_cdc_core
+// Multiport CDC interface
+//
+// Each channel contains the following registers seen from the CPU:
+//
+// 0 - RW - FIFO read/write data register
+// 1 - RW - watermark control
+//         3:1 - transmit FIFO low watermark  (resets to 1/4)
+//         7:5 - transmit FIFO high watermark (resets to 3/4)
+//        11:9 - receive FIFO low watermark   (resets to 1/4)
+//       15:13 - receive FIFO high watermark  (resets to 3/4)
+// 2 - RO - status register (some bits W1C)
+//           0 - transmit FIFO empty
+//           1 - transmit FIFO <= low watermark
+//           2 - transmit FIFO >= high watermark
+//           3 - transmit FIFO full
+//           4 - receive FIFO empty
+//           5 - receive FIFO <= low watermark
+//           6 - receive FIFO >= high watermark
+//           7 - receive FIFO full
+//           8 - receive FIFO not empty after two USB frames
+//           9 - BREAK received (sticky, W1C)
+//          10 - USB device configured
+// 3 - RW - interrupt enable register
+//           * - mask of corresponding status bits
+
+module usb_cdc_channel
+  #(parameter [3:0] data_ep_num = 4'd1,
+    parameter [3:0] intr_ep_num = data_ep_num+1'b1)
   (
-   // Inputs
-   input	 clk_i
-		 ,input rst_i
-		 ,input enable_i
-		 ,input [ 7:0] utmi_data_in_i
-		 ,input utmi_txready_i
-		 ,input utmi_rxvalid_i
-		 ,input utmi_rxactive_i
-		 ,input utmi_rxerror_i
-		 ,input [ 1:0] utmi_linestate_i
-		 ,input inport_valid_i
-		 ,input [ 7:0] inport_data_i
-		 ,input outport_accept_i
-
-		 // Outputs
-		 ,output [ 7:0] utmi_data_out_o
-		 ,output utmi_txvalid_o
-		 ,output [ 1:0] utmi_op_mode_o
-		 ,output [ 1:0] utmi_xcvrselect_o
-		 ,output utmi_termselect_o
-		 ,output utmi_dppulldown_o
-		 ,output utmi_dmpulldown_o
-		 ,output inport_accept_o
-		 ,output outport_valid_o
-		 ,output [ 7:0] outport_data_o
-		 ,output outport_break_o,
-
    // CPU bus
+   input	 rst_n,
    input	 sys_clk,
    input	 cpu_valid,
-   input [15:0]  cpu_addr,
+   input [1:0]	 cpu_addr,
    output [31:0] cpu_rdata,
    input [31:0]  cpu_wdata,
-   input [3:0]	 cpu_wstrb
+   input	 cpu_wstrb,
+   output	 irq,
+
+   // Core FIFO interface
+   input	 clk_i,
+   input	 rst_i,
+		 usb_endpoint.dstr data_ep,
+		 usb_endpoint.dstr intr_ep,
+
+   // Control signals
+   input	 recv_break_i,
+   output	 recv_break_o, // sys_clk domain, reflects the status register
+
+   // USB status
+   input	 usb_configured,
+
+   // Top of frame strobe *in sys_clk domain*
+   input	 start_of_frame_s
+   );
+
+   localparam fifo_size   = 511;
+   localparam fifo_bits   = $clog2(fifo_size);
+   localparam packet_bits = 6;
+   localparam packet_size = 1 << packet_bits;
+
+   // Up to four bits per watermark, but all are not necessarily
+   // implemented
+   localparam water_bits  = 3;
+
+   wire		 fifo_access = cpu_valid & cpu_addr == 2'b00;
+   reg		 fifo_access_q;
+   reg		 fifo_read_q;
+
+   always @(posedge sys_clk)
+     begin
+	fifo_access_q <= fifo_access;
+	fifo_read_q   <= fifo_access & ~cpu_wstrb;
+     end
+
+   wire		        txempty;
+   wire		        txfull;
+   wire [fifo_bits-1:0] txused;
+   wire [water_bits:0]	txused_msb = txused[fifo_bits-1:fifo_bits-water_bits];
+   wire		        inport_empty_w;
+   reg			inport_valid_q;
+
+   cdc_fifo txfifo (
+		    .wrclk   ( sys_clk ),
+		    .data    ( cpu_wdata[7:0] ),
+		    .wrreq   ( fifo_access & ~fifo_access_q & cpu_wstrb ),
+		    .wrempty ( txempty ),
+		    .wrfull  ( txfull ),
+		    .wrusedw ( txused ),
+
+		    .rdclk   ( clk_i ),
+		    .q       ( data_ep.d.tx_data ),
+		    .rdreq   ( ~inport_valid_q | data_ep.u.tx_data_accept ),
+		    .rdempty ( inport_empty_w ),
+		    .rdfull  ( ),
+		    .rdusedw ( )
+		    );
+
+   always @(posedge clk_i or posedge rst_i)
+     if (rst_i)
+       inport_valid_q <= 1'b0;
+     else if ( ~inport_empty_w )
+       inport_valid_q <= 1'b1;
+     else if ( data_ep.u.tx_data_accept )
+       inport_valid_q <= 1'b0;
+
+   assign data_ep.d.tx_data_valid = inport_valid_q;
+   assign data_ep.d.tx_ready      = inport_valid_q;
+   assign data_ep.d.tx_data_strb  = inport_valid_q;
+
+   // Must terminate a transfer at the max packet size
+   reg [packet_bits-1:0] inport_cnt_q;
+   wire			 inport_last_w = inport_empty_w | &inport_cnt_q;
+
+   always @(posedge clk_i or posedge rst_i)
+     if (rst_i)
+       inport_cnt_q <= 'd0;
+     else if (inport_last_w & data_ep.u.tx_data_accept)
+       inport_cnt_q <= 'd0;
+     else if (inport_valid_q & data_ep.u.tx_data_accept)
+       inport_cnt_q <= inport_cnt_q + 1'b1;
+
+   assign data_ep.d.tx_data_last = inport_last_w;
+
+   wire [7:0]	        rdata_fifo;
+   wire		        rxempty;
+   wire		        rxfull;
+   wire [fifo_bits-1:0] rxused;
+   wire [water_bits:0]	rxused_msb = rxused[fifo_bits-1:fifo_bits-water_bits];
+   wire [fifo_bits-1:0] outport_used_w;
+
+   wire			outport_valid_w = data_ep.u.rx_valid & data_ep.uc.rx_strb;
+
+   assign data_ep.d.rx_space = outport_used_w <= fifo_size - packet_size;
+
+   cdc_fifo rxfifo (
+		    .rdclk   ( sys_clk ),
+		    .q       ( rdata_fifo ),
+		    .rdreq   ( fifo_access & ~fifo_access_q & ~cpu_wstrb ),
+		    .rdempty ( rxempty ),
+		    .rdfull  ( rxfull ),
+		    .rdusedw ( rxused ),
+
+		    .wrclk   ( clk_i ),
+		    .data    ( data_ep.uc.rx_data ),
+		    .wrreq   ( outport_valid_w ),
+		    .wrempty ( ),
+		    .wrfull  ( ),
+		    .wrusedw ( outport_used_w )
+		    );
+
+   // Queued data wakeup
+   reg [1:0]		had_rxdata;
+
+   always @(posedge sys_clk)
+     begin
+	if (start_of_frame_s)
+	  had_rxdata <= { had_rxdata[0], 1'b1 };
+	if (rxempty)
+	  had_rxdata <= 2'b00;
+     end
+
+   wire [15:0] status_mask = 16'b0000_0111_1111_1111; // Implemented bit mask
+   reg  [15:0] irq_mask;
+   wire [ 3:0] water_mask     = 4'b1111 << (4-water_bits);
+   wire [15:0] water_ctl_mask = {4{water_mask}};
+   reg  [15:0] water_ctl;
+
+   wire        recv_break_s;
+   reg	       recv_break_q;
+
+   synchronizer #(.width(1)) break_synchro
+     (
+      .rst_n ( rst_n ),
+      .clk   ( sys_clk ),
+      .d     ( recv_break_i ),
+      .q     ( recv_break_s )
+      );
+
+   always @(negedge rst_n or posedge sys_clk)
+     if (~rst_n)
+       begin
+	  water_ctl    <= 16'h8787 & water_ctl_mask;
+	  irq_mask     <= 16'b0;
+	  recv_break_q <= 1'b0;
+       end
+     else
+       begin
+	  if (recv_break_s)
+	    recv_break_q <= 1'b1;
+
+	  if (cpu_valid & cpu_wstrb)
+	    case (cpu_addr)
+	      2'b01: water_ctl <= cpu_wdata[15:0] & water_ctl_mask;
+	      2'b10: if (cpu_wdata[9]) recv_break_q <= 1'b0;
+	      2'b11: irq_mask  <= cpu_wdata[15:0] & status_mask;
+	      default: /* do nothing */;
+	    endcase // case (cpu_addr)
+       end // else: !if(~rst_n)
+
+   assign recv_break_o = recv_break_q; // Available to external logic
+
+   tri0 [15:0] status;
+   assign status[0]    = txempty;
+   assign status[1]    = (txused_msb <= water_ctl[3:4-water_bits]);
+   assign status[2]    = (txused_msb >= water_ctl[7:8-water_bits]);
+   assign status[3]    = txfull;
+
+   assign status[4]    = rxempty;
+   assign status[5]    = (rxused_msb <= water_ctl[11:12-water_bits]);
+   assign status[6]    = (rxused_msb >= water_ctl[15:16-water_bits]);
+   assign status[7]    = rxfull;
+
+   assign status[8]    = had_rxdata[1];
+   assign status[9]    = recv_break_q;
+   assign status[10]   = usb_configured;
+
+   assign irq = |(status & irq_mask);
+
+   always @(*)
+     case (cpu_addr)
+       2'b00:   cpu_rdata = { 24'b0, rdata_fifo };
+       2'b01:   cpu_rdata = { 16'b0, water_ctl };
+       2'b10:   cpu_rdata = { 16'b0, status };
+       2'b11:   cpu_rdata = { 16'b0, irq_mask };
+       default: cpu_rdata = 32'bx;
+     endcase // case (cpu_addr)
+
+   // Channel configurations
+   assign data_ep.c.ep_num  = data_ep_num;
+   assign data_ep.c.ep_mask = 4'b1111;
+   assign intr_ep.c.ep_num  = intr_ep_num;
+   assign intr_ep.c.ep_mask = 4'b1111;
+
+   // Data channel endpoint: unused signals
+   assign data_ep.d.ep_iso        = 1'b0;
+   assign data_ep.d.cfg_int_rx    = 1'b0;
+   assign data_ep.d.cfg_int_tx    = 1'b0;
+   assign data_ep.d.ep_stall      = 1'b0;
+
+   // Notification channel endpoint: currently never used at all
+   assign intr_ep.d.ep_iso        = 1'b0;
+   assign intr_ep.d.cfg_int_rx    = 1'b0;
+   assign intr_ep.d.cfg_int_tx    = 1'b0;
+   assign intr_ep.d.ep_stall      = 1'b0;
+   assign intr_ep.d.tx_ready      = 1'b0;
+   assign intr_ep.d.tx_data_valid = 1'b0;
+   assign intr_ep.d.tx_data_strb  = 1'b0;
+   assign intr_ep.d.tx_data       = 8'bx;
+   assign intr_ep.d.tx_data_last  = 1'b0;
+   assign intr_ep.d.rx_space      = 1'b0;
+
+endmodule // usb_cdc_channel
+
+module usb_cdc_core
+  #( parameter [2:0] channels = 3'd1 )
+  (
+   // Inputs
+   input		 clk_i,
+   input		 rst_i,
+   input		 enable_i,
+   input [ 7:0]		 utmi_data_in_i,
+   input		 utmi_txready_i,
+   input		 utmi_rxvalid_i,
+   input		 utmi_rxactive_i,
+   input		 utmi_rxerror_i,
+   input [ 1:0]		 utmi_linestate_i,
+   //input		 inport_valid_i,
+   //input [ 7:0]	 inport_data_i,
+   //input		 outport_accept_i,
+
+   // Outputs
+   output [ 7:0]	 utmi_data_out_o,
+   output		 utmi_txvalid_o,
+   output [ 1:0]	 utmi_op_mode_o,
+   output [ 1:0]	 utmi_xcvrselect_o,
+   output		 utmi_termselect_o,
+   output		 utmi_dppulldown_o,
+   output		 utmi_dmpulldown_o,
+   output [channels-1:0] recv_break_o,
+
+   //output		 inport_accept_o,
+   //output		 outport_valid_o,
+   //output [ 7:0]	 outport_data_o,
+   //output		 outport_break_o,
+
+   // CPU bus
+   input		 rst_n,
+   input		 sys_clk,
+   input		 cpu_valid_cdc,
+   input		 cpu_valid_usbdesc,
+   input  [31:0]	 cpu_addr,
+   output [31:0]	 cpu_rdata_cdc,
+   output [31:0]	 cpu_rdata_usbdesc,
+   input  [31:0]	 cpu_wdata,
+   input   [3:0]	 cpu_wstrb,
+   output [channels-1:0] irq
    );
 
    parameter USB_SPEED_HS = "False"; // True or False
@@ -168,7 +429,7 @@ module usb_cdc_core
    wire  usb_reset_w;
    reg [6:0] device_addr_q;
 
-   localparam endpoint_channels = 4;
+   localparam endpoint_channels = channels*2 + 1;
    usb_endpoint usb_ep [0:endpoint_channels-1] ();
 
    wire       utmi_chirp_en_w;
@@ -391,13 +652,15 @@ module usb_cdc_core
    //-----------------------------------------------------------------
    // Core
    //-----------------------------------------------------------------
+   wire start_of_frame_w;		// Or reset, but close enough
+
    usbf_device_core #(.endpoint_channels(endpoint_channels))
      u_core
        (
 	.clk_i(clk_i),
 	.rst_i(rst_i),
 
-	.intr_o(),
+	.intr_o(start_of_frame_w),
 
 	// UTMI interface
 	.utmi_data_o(utmi_data_out_o),
@@ -519,8 +782,7 @@ module usb_cdc_core
    reg [15:0]  desc_base_addr_r;
    reg [15:0]  desc_len_r;
 
-   reg	       rx_break_q;
-   reg	       rx_break_r;
+   reg [7:0]   rx_break_r;
 
    reg	       addressed_q;
    reg	       addressed_r;
@@ -546,13 +808,14 @@ module usb_cdc_core
 
    always @ *
      begin
-	ctrl_stall_r    = 1'b0;
-	ctrl_ack_r      = 1'b0;
-	device_addr_r   = device_addr_q;
-	addressed_r     = addressed_q;
-	configured_r    = configured_q;
-	set_with_data_r = set_with_data_q;
-	rx_break_r      = 1'b0;
+	ctrl_stall_r     = 1'b0;
+	ctrl_ack_r       = 1'b0;
+	ctrl_send_data_r = 1'b0;
+	device_addr_r    = device_addr_q;
+	addressed_r      = addressed_q;
+	configured_r     = configured_q;
+	set_with_data_r  = set_with_data_q;
+	rx_break_r       = 8'b0;
 
 	if (setup_valid_q)
 	  begin
@@ -596,15 +859,10 @@ module usb_cdc_core
 			begin
 			   $display("SET_CONF: Configuration %x", wValue_w);
 
-			   if (wValue_w == 16'd0)
-			     begin
-				configured_r = 1'b0;
-				ctrl_ack_r   = setup_set_w && setup_no_data_w;
-			     end
 			   // Only support one configuration for now
-			   else if (wValue_w == 16'd1)
+			   if (wValue_w < 16'd2)
 			     begin
-				configured_r = 1'b1;
+				configured_r = wValue_w[0];
 				ctrl_ack_r   = setup_set_w && setup_no_data_w;
 			     end
 			   else
@@ -615,14 +873,16 @@ module usb_cdc_core
 			   $display("GET_INTERFACE");
 			   ctrl_stall_r = 1'b1;
 			end
+//`ifdef HANDLE_SET_INTERFACE
 		      `REQ_SET_INTERFACE:
 			begin
 			   $display("SET_INTERFACE: %x %x", wValue_w, wIndex_w);
-			   if (wValue_w == 16'd0 && wIndex_w == 16'd0)
+			   if (wValue_w == 16'd0 && wIndex_w < (channels << 1))
 			     ctrl_ack_r   = setup_set_w && setup_no_data_w;
 			   else
 			     ctrl_stall_r = 1'b1;
 			end
+//`endif
 		      default:
 			begin
 			   ctrl_stall_r = 1'b1;
@@ -647,7 +907,7 @@ module usb_cdc_core
 			end
 		      `CDC_SEND_BREAK:
 			begin
-			   rx_break_r    = (wValue_w != 16'd0);
+			   rx_break_r[wIndex_w[3:1]] = wIndex_w[0] & |wValue_w;
 			end
 		      default:
 			begin
@@ -672,7 +932,6 @@ module usb_cdc_core
 	  addressed_q     <= 1'b0;
 	  configured_q    <= 1'b0;
 	  set_with_data_q <= 1'b0;
-	  rx_break_q      <= 1'b0;
        end
      else if (usb_reset_w)
        begin
@@ -680,7 +939,6 @@ module usb_cdc_core
 	  addressed_q     <= 1'b0;
 	  configured_q    <= 1'b0;
 	  set_with_data_q <= 1'b0;
-	  rx_break_q      <= 1'b0;
        end
      else
        begin
@@ -688,7 +946,6 @@ module usb_cdc_core
 	  addressed_q     <= addressed_r;
 	  configured_q    <= configured_r;
 	  set_with_data_q <= set_with_data_r;
-	  rx_break_q      <= rx_break_r;
        end
 
    //-----------------------------------------------------------------
@@ -874,126 +1131,85 @@ module usb_cdc_core
    assign usb_ep[0].d.tx_data_last  = ctrl_txlast_q;
    assign usb_ep[0].d.ep_stall      = ctrl_txstall_q;
 
+   // Unused endpoint 0 signals
+   assign usb_ep[0].d.ep_iso        = 1'b0;
+   assign usb_ep[0].d.cfg_int_rx    = 1'b0;
+   assign usb_ep[0].d.cfg_int_tx    = 1'b0;
+
    //-----------------------------------------------------------------
    // Descriptor ROM
    //-----------------------------------------------------------------
+   wire [7:0] rdata_usbdesc;
+
    usb_desc_rom
      u_rom
        (
-	.clk		(clk_i),
-	.usb_addr	(desc_addr_r),
-	.usb_rdata	(desc_data_w),
+	.clk		( clk_i ),
+	.usb_addr	( desc_addr_r ),
+	.usb_rdata	( desc_data_w ),
 
 	// CPU interface for modifications
-	.cpu_clk        (sys_clk),
-	.cpu_addr	(cpu_addr),
-	.cpu_rdata	(cpu_rdata[7:0]),
-	.cpu_wdata	(cpu_wdata[7:0]),
-	.cpu_wren	(cpu_valid & cpu_wstrb[0])
+	.cpu_clk        ( sys_clk ),
+	.cpu_addr	( cpu_addr[17:2] ),
+	.cpu_rdata	( cpu_rdata_usbdesc[7:0] ),
+	.cpu_wdata	( cpu_wdata[7:0] ),
+	.cpu_wren	( cpu_valid_usbdesc & cpu_wstrb[0] )
 	);
-   assign cpu_rdata[31:8] = 24'bx;
-
-   //-----------------------------------------------------------------
-   // Unused Endpoint Downstream Signals
-   //-----------------------------------------------------------------
-
-   assign usb_ep[0].d.ep_iso        = 1'b0;
-   assign usb_ep[0].d.cfg_int_rx    = 1'b0;
-   assign usb_ep[0].d.cfg_int_tx    = 1'b0;
 
-   // EP1: unused
-   assign usb_ep[1].d.ep_iso        = 1'b0;
-   assign usb_ep[1].d.cfg_int_rx    = 1'b0;
-   assign usb_ep[1].d.cfg_int_tx    = 1'b0;
-   assign usb_ep[1].d.ep_stall      = 1'b1;
-   assign usb_ep[1].d.tx_ready      = 1'b0;
-   assign usb_ep[1].d.tx_data_valid = 1'b0;
-   assign usb_ep[1].d.tx_data_strb  = 1'b0;
-   assign usb_ep[1].d.tx_data       = 8'bx;
-   assign usb_ep[1].d.tx_data_last  = 1'b0;
-   assign usb_ep[1].d.rx_space      = 1'b0;
-
-   // EP2: data channel
-   assign usb_ep[2].d.ep_iso        = 1'b0;
-   assign usb_ep[2].d.cfg_int_rx    = 1'b0;
-   assign usb_ep[2].d.cfg_int_tx    = 1'b0;
-   assign usb_ep[2].d.ep_stall      = 1'b0;
-
-   // EP3: notification output
-   assign usb_ep[3].d.ep_iso        = 1'b0;
-   assign usb_ep[3].d.cfg_int_rx    = 1'b0;
-   assign usb_ep[3].d.cfg_int_tx    = 1'b0;
-   assign usb_ep[3].d.ep_stall      = 1'b0;
-   assign usb_ep[3].d.tx_ready      = 1'b0;
-   assign usb_ep[3].d.tx_data_valid = 1'b0;
-   assign usb_ep[3].d.tx_data_strb  = 1'b0;
-   assign usb_ep[3].d.tx_data       = 8'bx;
-   assign usb_ep[3].d.tx_data_last  = 1'b0;
-   assign usb_ep[3].d.rx_space      = 1'b0;
+   assign cpu_rdata_usbdesc[31:8] = 24'b0;
 
    //-----------------------------------------------------------------
-   // Stream endpoint channel configuration
+   // Channel streaming interfaces and CPU interfaces
    //-----------------------------------------------------------------
-   assign usb_ep[1].c.ep_num        = 4'd1;
-   assign usb_ep[1].c.ep_mask       = 4'b1111;
-   assign usb_ep[2].c.ep_num        = 4'd2;
-   assign usb_ep[2].c.ep_mask       = 4'b1111;
-   assign usb_ep[3].c.ep_num        = 4'd3;
-   assign usb_ep[3].c.ep_mask       = 4'b1111;
 
-   //-----------------------------------------------------------------
-   // Stream I/O
-   //-----------------------------------------------------------------
-   reg        inport_valid_q;
-   reg [7:0]  inport_data_q;
-   reg [10:0] inport_cnt_q;
-   reg	      outport_break_q;
+   wire		       start_of_frame_ws;
+   reg		       start_of_frame_q;
 
-   always @ (posedge clk_i or posedge rst_i)
-     if (rst_i)
-       begin
-	  inport_valid_q  <= 1'b0;
-	  inport_data_q   <= 8'b0;
-       end
-     else if (inport_accept_o)
-       begin
-	  inport_valid_q <= inport_valid_i;
-	  inport_data_q  <= inport_data_i;
-       end
+   synchronizer #(.width(1))
+   sof_sync (
+	     .rst_n ( 1'b1 ),
+	     .clk   ( sys_clk ),
+	     .d     ( start_of_frame_w ),
+	     .q     ( start_of_frame_ws )
+	     );
 
-   wire [10:0] max_packet_w   = usb_hs_w ? 11'd511 : 11'd63;
-   wire        inport_last_w  = !inport_valid_i || (inport_cnt_q == max_packet_w);
+   always @(posedge sys_clk)
+     start_of_frame_q <= start_of_frame_ws;
 
-   always @ (posedge clk_i or posedge rst_i)
-     if (rst_i)
-       inport_cnt_q  <= 11'b0;
-     else if (inport_last_w && usb_ep[2].u.tx_data_accept)
-       inport_cnt_q  <= 11'b0;
-     else if (inport_valid_q && usb_ep[2].u.tx_data_accept)
-       inport_cnt_q  <= inport_cnt_q + 11'd1;
-
-   assign usb_ep[2].d.tx_data_valid = inport_valid_q;
-   assign usb_ep[2].d.tx_ready      = inport_valid_q;
-   assign usb_ep[2].d.tx_data_strb  = inport_valid_q;
-   assign usb_ep[2].d.tx_data       = inport_data_q;
-   assign usb_ep[2].d.tx_data_last  = inport_last_w;
+   wire start_of_frame_s = start_of_frame_ws & ~start_of_frame_q;
 
-   assign inport_accept_o     = !inport_valid_q | usb_ep[2].u.tx_data_accept;
+   tri0 [31:0]         rdata_chan[0:7];
 
-   assign outport_valid_o      = usb_ep[2].u.rx_valid && usb_ep[2].uc.rx_strb;
-   assign outport_data_o       = usb_ep[2].uc.rx_data;
-   assign usb_ep[2].d.rx_space = outport_accept_i;
-
-   always @(posedge clk_i or posedge rst_i)
-     if (rst_i)
-       outport_break_q <= 1'b0;
-     else
-       outport_break_q <= rx_break_q |
-			  (outport_break_q &
-			   ~setup_set_w &
-			   ~outport_valid_o &
-			   ~(inport_valid_q & usb_ep[2].u.tx_data_accept));
+   generate
+      genvar  cn;
+      for (cn = 0; cn < channels; cn++)
+	begin : chan
+	   usb_cdc_channel #(.data_ep_num ( cn*2+1 ),
+			     .intr_ep_num ( cn*2+2 ))
+	   cchan (
+		 .rst_n            ( rst_n ),
+		 .sys_clk          ( sys_clk ),
+		 .cpu_valid        ( cpu_valid_cdc & cpu_addr[6:4] == cn ),
+		 .cpu_addr         ( cpu_addr[3:2] ),
+		 .cpu_rdata        ( rdata_chan[cn] ),
+		 .cpu_wdata        ( cpu_wdata ),
+		 .cpu_wstrb        ( cpu_wstrb[0] ),
+		 .irq              ( irq[cn] ),
+
+		 .clk_i            ( clk_i ),
+		 .rst_i            ( rst_i ),
+		 .data_ep          ( usb_ep[cn*2+1].dstr ),
+		 .intr_ep          ( usb_ep[cn*2+2].dstr ),
+
+		 .usb_configured   ( configured_q ),
+
+		 .recv_break_i     ( rx_break_r[cn] ),
+		 .recv_break_o     ( recv_break_o[cn] ),
+		 .start_of_frame_s ( start_of_frame_s )
+		 );
+	end // block: chan
+   endgenerate
 
-   assign outport_break_o  = outport_break_q;
+   assign cpu_rdata_cdc = rdata_chan[cpu_addr[6:4]];
 
 endmodule

+ 0 - 547
fpga/usb/usb_serial/src_v/usb_cdc_top.v

@@ -1,547 +0,0 @@
-//-----------------------------------------------------------------
-//                       USB Serial Port
-//                            V0.1
-//                     Ultra-Embedded.com
-//                       Copyright 2020
-//
-//                 Email: admin@ultra-embedded.com
-//
-//                         License: LGPL
-//-----------------------------------------------------------------
-//
-// This source file may be used and distributed without
-// restriction provided that this copyright statement is not
-// removed from the file and that any derivative work contains
-// the original copyright notice and the associated disclaimer.
-//
-// This source file is free software; you can redistribute it
-// and/or modify it under the terms of the GNU Lesser General
-// Public License as published by the Free Software Foundation;
-// either version 2.1 of the License, or (at your option) any
-// later version.
-//
-// This source 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 Lesser General Public License for more
-// details.
-//
-// You should have received a copy of the GNU Lesser General
-// Public License along with this source; if not, write to the
-// Free Software Foundation, Inc., 59 Temple Place, Suite 330,
-// Boston, MA  02111-1307  USA
-//-----------------------------------------------------------------
-
-//-----------------------------------------------------------------
-//                          Generated File
-//-----------------------------------------------------------------
-
-module usb_cdc_top
-//-----------------------------------------------------------------
-// Params
-//-----------------------------------------------------------------
-#(
-     parameter BAUDRATE         = 115200
-)
-//-----------------------------------------------------------------
-// Ports
-//-----------------------------------------------------------------
-(
-     input	   clk_i,
-     input	   rst_i,
-
-     output [7:0]  utmi_data_out_o,
-     output	   utmi_txvalid_o,
-     output [1:0]  utmi_op_mode_o,
-     output [1:0]  utmi_xcvrselect_o,
-     output	   utmi_termselect_o,
-     output	   utmi_dppulldown_o,
-     output	   utmi_dmpulldown_o,
-
-     input [7:0]   utmi_data_in_i,
-     input	   utmi_txready_i,
-     input	   utmi_rxvalid_i,
-     input	   utmi_rxactive_i,
-     input	   utmi_rxerror_i,
-     input [1:0]   utmi_linestate_i,
-
-     input	   sys_clk,
-     input	   cpu_valid,
-     input [15:0]  cpu_addr,
-     output [31:0] cpu_rdata,
-     input [31:0]  cpu_wdata,
-     input [3:0]   cpu_wstrb,
-
-     input	   tx_i,
-     output	   rx_o,
-     output	   rx_break_o
-);
-
-wire  [  7:0]  usb_rx_data_w;
-wire           usb_tx_accept_w;
-wire           enable_w = 1'h1;
-wire           usb_tx_valid_w;
-wire           usb_rx_accept_w;
-wire  [  7:0]  usb_tx_data_w;
-wire           usb_rx_valid_w;
-wire           usb_rx_break_w;
-
-usb_cdc_core
-u_usb
-(
-    // Inputs
-     .clk_i(clk_i)
-    ,.rst_i(rst_i)
-    ,.enable_i(enable_w)
-    ,.utmi_data_in_i(utmi_data_in_i)
-    ,.utmi_txready_i(utmi_txready_i)
-    ,.utmi_rxvalid_i(utmi_rxvalid_i)
-    ,.utmi_rxactive_i(utmi_rxactive_i)
-    ,.utmi_rxerror_i(utmi_rxerror_i)
-    ,.utmi_linestate_i(utmi_linestate_i)
-    ,.inport_valid_i(usb_tx_valid_w)
-    ,.inport_data_i(usb_tx_data_w)
-    ,.outport_accept_i(usb_rx_accept_w)
-
-    // Outputs
-    ,.utmi_data_out_o(utmi_data_out_o)
-    ,.utmi_txvalid_o(utmi_txvalid_o)
-    ,.utmi_op_mode_o(utmi_op_mode_o)
-    ,.utmi_xcvrselect_o(utmi_xcvrselect_o)
-    ,.utmi_termselect_o(utmi_termselect_o)
-    ,.utmi_dppulldown_o(utmi_dppulldown_o)
-    ,.utmi_dmpulldown_o(utmi_dmpulldown_o)
-    ,.inport_accept_o(usb_tx_accept_w)
-    ,.outport_valid_o(usb_rx_valid_w)
-    ,.outport_data_o(usb_rx_data_w)
-    ,.outport_break_o(usb_rx_break_w),
-
- // CPU bus
- .sys_clk           ( sys_clk ),
- .cpu_valid         ( cpu_valid ),
- .cpu_addr          ( cpu_addr ),
- .cpu_rdata         ( cpu_rdata ),
- .cpu_wdata         ( cpu_wdata ),
- .cpu_wstrb         ( cpu_wstrb )
-);
-
-//-----------------------------------------------------------------
-// Output FIFO
-//-----------------------------------------------------------------
-wire       tx_valid_w;
-wire [7:0] tx_data_w;
-wire       tx_accept_w;
-
-usb_cdc_fifo
-#(
-    .WIDTH(8),
-    .DEPTH(512),
-    .ADDR_W(9)
-)
-u_fifo_tx
-(
-    .clk_i(clk_i),
-    .rst_i(rst_i),
-
-    // In
-    .push_i(tx_valid_w),
-    .data_in_i(tx_data_w),
-    .accept_o(tx_accept_w),
-
-    // Out
-    .pop_i(usb_tx_accept_w),
-    .data_out_o(usb_tx_data_w),
-    .valid_o(usb_tx_valid_w)
-);
-
-//-----------------------------------------------------------------
-// Input FIFO
-//-----------------------------------------------------------------
-wire       rx_valid_w;
-wire [7:0] rx_data_w;
-wire       rx_accept_w;
-
-usb_cdc_fifo
-#(
-    .WIDTH(8),
-    .DEPTH(512),
-    .ADDR_W(9)
-)
-u_fifo_rx
-(
-    .clk_i(clk_i),
-    .rst_i(rst_i),
-
-    // In
-    .push_i(usb_rx_valid_w),
-    .data_in_i(usb_rx_data_w),
-    .accept_o(usb_rx_accept_w),
-
-    // Out
-    .pop_i(rx_accept_w),
-    .data_out_o(rx_data_w),
-    .valid_o(rx_valid_w)
-);
-
-//-----------------------------------------------------------------
-// Registers
-//-----------------------------------------------------------------
-
-// Configuration
-localparam   STOP_BITS = 1'b0; // 0 = 1, 1 = 2
-localparam   CLK_FREQ  = 48000000;
-localparam   BIT_DIV   = (CLK_FREQ / BAUDRATE) - 1;
-
-localparam   START_BIT = 4'd0;
-localparam   STOP_BIT0 = 4'd9;
-localparam   STOP_BIT1 = 4'd10;
-
-// TX Signals
-reg          tx_busy_q;
-reg [3:0]    tx_bits_q;
-reg [31:0]   tx_count_q;
-reg [7:0]    tx_shift_reg_q;
-reg          txd_q;
-
-// RX Signals
-reg          rxd_q;
-reg [7:0]    rx_data_q;
-reg [3:0]    rx_bits_q;
-reg [31:0]   rx_count_q;
-reg [7:0]    rx_shift_reg_q;
-reg          rx_ready_q;
-reg          rx_busy_q;
-
-reg          rx_err_q;
-
-//-----------------------------------------------------------------
-// Re-sync RXD
-//-----------------------------------------------------------------
-reg rxd_ms_q;
-
-always @ (posedge clk_i or posedge rst_i)
-if (rst_i)
-begin
-   rxd_ms_q <= 1'b1;
-   rxd_q    <= 1'b1;
-end
-else
-begin
-   rxd_ms_q <= tx_i;
-   rxd_q    <= rxd_ms_q;
-end
-
-//-----------------------------------------------------------------
-// RX Clock Divider
-//-----------------------------------------------------------------
-wire rx_sample_w = (rx_count_q == 32'b0);
-
-always @ (posedge clk_i or posedge rst_i)
-if (rst_i)
-    rx_count_q        <= 32'b0;
-else
-begin
-    // Inactive
-    if (!rx_busy_q)
-        rx_count_q    <= {1'b0, BIT_DIV[31:1]};
-    // Rx bit timer
-    else if (rx_count_q != 0)
-        rx_count_q    <= (rx_count_q - 1);
-    // Active
-    else if (rx_sample_w)
-    begin
-        // Last bit?
-        if ((rx_bits_q == STOP_BIT0 && !STOP_BITS) || (rx_bits_q == STOP_BIT1 && STOP_BITS))
-            rx_count_q    <= 32'b0;
-        else
-            rx_count_q    <= BIT_DIV;
-    end
-end
-
-//-----------------------------------------------------------------
-// RX Shift Register
-//-----------------------------------------------------------------
-always @ (posedge clk_i or posedge rst_i)
-if (rst_i)
-begin
-    rx_shift_reg_q <= 8'h00;
-    rx_busy_q      <= 1'b0;
-end
-// Rx busy
-else if (rx_busy_q && rx_sample_w)
-begin
-    // Last bit?
-    if (rx_bits_q == STOP_BIT0 && !STOP_BITS)
-        rx_busy_q <= 1'b0;
-    else if (rx_bits_q == STOP_BIT1 && STOP_BITS)
-        rx_busy_q <= 1'b0;
-    else if (rx_bits_q == START_BIT)
-    begin
-        // Start bit should still be low as sampling mid
-        // way through start bit, so if high, error!
-        if (rxd_q)
-            rx_busy_q <= 1'b0;
-    end
-    // Rx shift register
-    else
-        rx_shift_reg_q <= {rxd_q, rx_shift_reg_q[7:1]};
-end
-// Start bit?
-else if (!rx_busy_q && rxd_q == 1'b0)
-begin
-    rx_shift_reg_q <= 8'h00;
-    rx_busy_q      <= 1'b1;
-end
-
-always @ (posedge clk_i or posedge rst_i)
-if (rst_i)
-    rx_bits_q  <= START_BIT;
-else if (rx_sample_w && rx_busy_q)
-begin
-    if ((rx_bits_q == STOP_BIT1 && STOP_BITS) || (rx_bits_q == STOP_BIT0 && !STOP_BITS))
-        rx_bits_q <= START_BIT;
-    else
-        rx_bits_q <= rx_bits_q + 4'd1;
-end
-else if (!rx_busy_q && (BIT_DIV == 32'b0))
-    rx_bits_q  <= START_BIT + 4'd1;
-else if (!rx_busy_q)
-    rx_bits_q  <= START_BIT;
-
-//-----------------------------------------------------------------
-// RX Data
-//-----------------------------------------------------------------
-always @ (posedge clk_i or posedge rst_i)
-if (rst_i)
-begin
-   rx_ready_q      <= 1'b0;
-   rx_data_q       <= 8'h00;
-   rx_err_q        <= 1'b0;
-end
-else
-begin
-   // If reading data, reset data state
-   if (tx_accept_w)
-   begin
-       rx_ready_q <= 1'b0;
-       rx_err_q   <= 1'b0;
-   end
-
-   if (rx_busy_q && rx_sample_w)
-   begin
-       // Stop bit
-       if ((rx_bits_q == STOP_BIT1 && STOP_BITS) || (rx_bits_q == STOP_BIT0 && !STOP_BITS))
-       begin
-           // RXD should be still high
-           if (rxd_q)
-           begin
-               rx_data_q      <= rx_shift_reg_q;
-               rx_ready_q     <= 1'b1;
-           end
-           // Bad Stop bit - wait for a full bit period
-           // before allowing start bit detection again
-           else
-           begin
-               rx_ready_q      <= 1'b0;
-               rx_data_q       <= 8'h00;
-               rx_err_q        <= 1'b1;
-           end
-       end
-       // Mid start bit sample - if high then error
-       else if (rx_bits_q == START_BIT && rxd_q)
-           rx_err_q        <= 1'b1;
-   end
-end
-
-assign tx_data_w   = rx_data_q;
-assign tx_valid_w  = rx_ready_q;
-
-//-----------------------------------------------------------------
-// TX Clock Divider
-//-----------------------------------------------------------------
-wire tx_sample_w = (tx_count_q == 32'b0);
-
-always @ (posedge clk_i or posedge rst_i)
-if (rst_i)
-    tx_count_q      <= 32'b0;
-else
-begin
-    // Idle
-    if (!tx_busy_q)
-        tx_count_q  <= BIT_DIV;
-    // Tx bit timer
-    else if (tx_count_q != 0)
-        tx_count_q  <= (tx_count_q - 1);
-    else if (tx_sample_w)
-        tx_count_q  <= BIT_DIV;
-end
-
-//-----------------------------------------------------------------
-// TX Shift Register
-//-----------------------------------------------------------------
-reg tx_complete_q;
-
-always @ (posedge clk_i or posedge rst_i)
-if (rst_i)
-begin
-    tx_shift_reg_q <= 8'h00;
-    tx_busy_q      <= 1'b0;
-    tx_complete_q  <= 1'b0;
-end
-// Tx busy
-else if (tx_busy_q)
-begin
-    // Shift tx data
-    if (tx_bits_q != START_BIT && tx_sample_w)
-        tx_shift_reg_q <= {1'b0, tx_shift_reg_q[7:1]};
-
-    // Last bit?
-    if (tx_bits_q == STOP_BIT0 && tx_sample_w && !STOP_BITS)
-    begin
-        tx_busy_q      <= 1'b0;
-        tx_complete_q  <= 1'b1;
-    end
-    else if (tx_bits_q == STOP_BIT1 && tx_sample_w && STOP_BITS)
-    begin
-        tx_busy_q      <= 1'b0;
-        tx_complete_q  <= 1'b1;
-    end
-end
-// Buffer data to transmit
-else if (rx_valid_w)
-begin
-    tx_shift_reg_q <= rx_data_w;
-    tx_busy_q      <= 1'b1;
-    tx_complete_q  <= 1'b0;
-end
-else
-    tx_complete_q  <= 1'b0;
-
-assign rx_accept_w = ~tx_busy_q;
-
-always @ (posedge clk_i or posedge rst_i)
-if (rst_i)
-    tx_bits_q  <= 4'd0;
-else if (tx_sample_w && tx_busy_q)
-begin
-    if ((tx_bits_q == STOP_BIT1 && STOP_BITS) || (tx_bits_q == STOP_BIT0 && !STOP_BITS))
-        tx_bits_q <= START_BIT;
-    else
-        tx_bits_q <= tx_bits_q + 4'd1;
-end
-
-//-----------------------------------------------------------------
-// UART Tx Pin
-//-----------------------------------------------------------------
-reg txd_r;
-
-always @ *
-begin
-    txd_r = 1'b1;
-
-    if (tx_busy_q)
-    begin
-        // Start bit (TXD = L)
-        if (tx_bits_q == START_BIT)
-            txd_r = 1'b0;
-        // Stop bits (TXD = H)
-        else if (tx_bits_q == STOP_BIT0 || tx_bits_q == STOP_BIT1)
-            txd_r = 1'b1;
-        // Data bits
-        else
-            txd_r = tx_shift_reg_q[0];
-    end
-end
-
-always @ (posedge clk_i or posedge rst_i)
-if (rst_i)
-    txd_q <= 1'b1;
-else
-    txd_q <= txd_r;
-
-assign rx_o = txd_q;
-assign rx_break_o = usb_rx_break_w;
-
-endmodule
-
-module usb_cdc_fifo
-//-----------------------------------------------------------------
-// Params
-//-----------------------------------------------------------------
-#(
-    parameter WIDTH   = 8,
-    parameter DEPTH   = 4,
-    parameter ADDR_W  = 2
-)
-//-----------------------------------------------------------------
-// Ports
-//-----------------------------------------------------------------
-(
-    // Inputs
-     input               clk_i
-    ,input               rst_i
-    ,input  [WIDTH-1:0]  data_in_i
-    ,input               push_i
-    ,input               pop_i
-
-    // Outputs
-    ,output [WIDTH-1:0]  data_out_o
-    ,output              accept_o
-    ,output              valid_o
-);
-
-//-----------------------------------------------------------------
-// Local Params
-//-----------------------------------------------------------------
-localparam COUNT_W = ADDR_W + 1;
-
-//-----------------------------------------------------------------
-// Registers
-//-----------------------------------------------------------------
-reg [WIDTH-1:0]   ram_q[DEPTH-1:0];
-reg [ADDR_W-1:0]  rd_ptr_q;
-reg [ADDR_W-1:0]  wr_ptr_q;
-reg [COUNT_W-1:0] count_q;
-
-//-----------------------------------------------------------------
-// Sequential
-//-----------------------------------------------------------------
-always @ (posedge clk_i )
-if (rst_i)
-begin
-    count_q   <= {(COUNT_W) {1'b0}};
-    rd_ptr_q  <= {(ADDR_W) {1'b0}};
-    wr_ptr_q  <= {(ADDR_W) {1'b0}};
-end
-else
-begin
-    // Push
-    if (push_i & accept_o)
-    begin
-        ram_q[wr_ptr_q] <= data_in_i;
-        wr_ptr_q        <= wr_ptr_q + 1;
-    end
-
-    // Pop
-    if (pop_i & valid_o)
-        rd_ptr_q      <= rd_ptr_q + 1;
-
-    // Count up
-    if ((push_i & accept_o) & ~(pop_i & valid_o))
-        count_q <= count_q + 1;
-    // Count down
-    else if (~(push_i & accept_o) & (pop_i & valid_o))
-        count_q <= count_q - 1;
-end
-
-//-------------------------------------------------------------------
-// Combinatorial
-//-------------------------------------------------------------------
-/* verilator lint_off WIDTH */
-assign valid_o       = (count_q != 0);
-assign accept_o      = (count_q != DEPTH);
-/* verilator lint_on WIDTH */
-
-assign data_out_o    = ram_q[rd_ptr_q];
-
-endmodule

+ 10 - 11
fpga/usb/usb_serial/src_v/usbf_device_core.sv

@@ -107,8 +107,6 @@ module usbf_endpoint_mux
   #(parameter endpoint_channels = 4)
    (
     input	      valid_i,
-    input [3:0]       ep_select_i,
-    input	      ep_select_rx_i,
     usb_endpoint.ustr ep_u [0:endpoint_channels-1],
     usb_endpoint.dstr ep_d
     );
@@ -117,7 +115,7 @@ module usbf_endpoint_mux
 
    // Quartus seems to need these intermediate variables
    // to be able to use structures here.
-   usb_ep_d_t   u_d [0:endpoint_channels-1];
+   usb_ep_d_t   ep_u_d [0:endpoint_channels-1];
    usb_ep_u_t   ep_d_u;
    usb_ep_uc_t  ep_d_uc;
 
@@ -126,15 +124,15 @@ module usbf_endpoint_mux
 
    always_comb
      begin
-	ep_d_u             = ep_d.u;
-	ep_d_u.ep_selected = 1'b1;
-	ep_d_uc            = ep_d.uc;
+	ep_d_u               = ep_d.u;
+	ep_d_u.ep_selected   = 1'b1;
+	ep_d_uc              = ep_d.uc;
 
 	ep_d.c = '{ default:'bx }; // Irrelevant
 	ep_d.d = '{ default:'b0 };
 	for (int j = 0; j < endpoint_channels; j++)
 	  if (selected[j])
-	    ep_d.d = u_d[j];
+	    ep_d.d = ep_u_d[j];
      end
 
    generate
@@ -144,7 +142,7 @@ module usbf_endpoint_mux
 	   always_comb
 	     begin
 		selected[i] = ~|selected[i-1:-1] &&
-			      ((ep_select_i & ep_u[i].c.ep_mask) ==
+			      ((ep_d_uc.ep_select & ep_u[i].c.ep_mask) ==
 			       ep_u[i].c.ep_num);
 
 		ep_u[i].uc = ep_d_uc;
@@ -153,7 +151,7 @@ module usbf_endpoint_mux
 		else
 		  ep_u[i].u = '{ default:'b0 };
 
-		u_d[i] = ep_u[i].d;
+		ep_u_d[i] = ep_u[i].d;
 	     end
 	end
    endgenerate
@@ -291,12 +289,13 @@ module usbf_device_core
    //-----------------------------------------------------------------
    usb_endpoint ept ();		// Endpoint selected by token
 
+   assign ept.uc.ep_select    = token_ep_w;
+   assign ept.uc.ep_select_rx = token_pid_w == `PID_IN | token_pid_w == `PID_PING;
+
    usbf_endpoint_mux #(.endpoint_channels(endpoint_channels))
    u_endpoint_mux
      (
       .valid_i     ( ~rst_i & ~usb_rst_w ),
-      .ep_select_i ( token_ep_w ),
-      .ep_select_rx_i ( token_pid_w == `PID_IN || token_pid_w == `PID_PING ),
       .ep_u        ( ep ),
       .ep_d        ( ept.dstr )
       );

File diff suppressed because it is too large
+ 1145 - 1145
rv32/boot.mif


+ 1 - 6
rv32/console.c

@@ -8,15 +8,10 @@
 #include "console.h"
 #include "io.h"
 
-void __cold __con_set_baudrate(uint32_t baud)
-{
-    __con_set_baudrate_inline(baud);
-}
-
 static __always_inline void __con_putc(char c)
 {
     /* Wait for FIFO space */
-    while (CON_STATUS & (1 << 4))
+    while (CON_FLOW_CTL && (CON_STATUS & CON_STATUS_TX_HIGH))
 	pause();
 
     if (c == '\n')

+ 4 - 28
rv32/console.h

@@ -4,7 +4,8 @@
 #include "compiler.h"
 #include "io.h"
 
-void __con_set_baudrate(uint32_t);
+#define CON_FLOW_CTL 0		/* Block on output full? */
+
 void con_putc(char c);
 void con_puts(const char *);
 void __fmt_printf(1,0) con_vprintf(const char *, va_list);
@@ -12,33 +13,8 @@ void __fmt_printf(1,2) con_printf(const char *, ...);
 
 static __always_inline void con_flush(void)
 {
-    while (!(CON_STATUS & 1))
-	/* wait */;
-}
-
-static __always_inline void __con_set_baudrate_inline(uint32_t baud)
-{
-    uint32_t bauddiv;
-
-    /*
-     * Produce a CON_BAUD_BITS binary fraction. The +1 produces better
-     * rounding behavior: see Hacker's Delight.
-     */
-    bauddiv = (baud * ((1ULL << (32+CON_BAUD_BITS))/CON_BAUD_BASE+1)) >> 32;
-
-    /*
-     * Not really a divisor, but a fractional multiplier. The -1
-     * is simply a technicality of the implementation.
-     */
-    CON_BAUDDIV = bauddiv - 1;
-}
-
-static __always_inline void con_set_baudrate(uint32_t baud)
-{
-    if (__is_constant(baud))
-	__con_set_baudrate_inline(baud);
-    else
-	__con_set_baudrate(baud);
+    while (CON_FLOW_CTL && !(CON_STATUS & CON_STATUS_TX_EMPTY))
+	pause();
 }
 
 #endif /* CONSOLE_H */

+ 17 - 4
rv32/ioregs.h

@@ -80,10 +80,23 @@
 #define ROMCOPY_STATUS_DONE	1
 
 #define CON_DATA		IODEVB(CONSOLE,0)
-#define CON_BAUDDIV		IODEVL(CONSOLE,1)
-#define CON_BAUD_BASE		(CPU_HZ >> 4)
-#define CON_BAUD_BITS		24
-#define CON_STATUS		IODEVRL(CONSOLE,2)
+#define CON_WATERCTL		IODEVL(CONSOLE,1)
+#define CON_WATERCTL_TX_LOW(x)	((x) << 0)
+#define CON_WATERCTL_TX_HIGH(x)	((x) << 4)
+#define CON_WATERCTL_RX_LOW(x)	((x) << 8)
+#define CON_WATERCTL_RX_HIGH(x)	((x) << 12)
+#define CON_STATUS		IODEVL(CONSOLE,2)
+#define CON_STATUS_TX_EMPTY	0x0001
+#define CON_STATUS_TX_LOW	0x0002
+#define CON_STATUS_TX_HIGH	0x0004
+#define CON_STATUS_TX_FULL	0x0008
+#define CON_STATUS_RX_EMPTY	0x0010
+#define CON_STATUS_RX_LOW	0x0020
+#define CON_STATUS_RX_HIGH	0x0040
+#define CON_STATUS_RX_FULL	0x0080
+#define CON_STATUS_RX_STALE	0x0100
+#define CON_STATUS_RX_BREAK	0x0200
+#define CON_STATUS_USB_CONFIG	0x0400
 #define CON_IRQEN		IODEVL(CONSOLE,3)
 
 #define SDCARD_CTL		IODEVL(SDCARD,0)

+ 2 - 2
rv32/system.c

@@ -70,6 +70,8 @@ IRQHANDLER(sysclock)
     uint32_t count = timer_irq_count;
     count++;
     timer_irq_count = count;
+    if ( MINITESTS )
+	CON_DATA = (count & 63) + '0'; /* Liveness... */
 }
 
 static void __cold __noinline late_init(void);
@@ -85,8 +87,6 @@ void __hot init(void)
 #endif
 	"firmware compiled on: " __DATE__ " " __TIME__ "\n";
 
-    con_set_baudrate(115200);
-
     timer_irq_start = rdtime();
 
     /* Start ROM copy engine, unmask timer and fatal exceptions */

+ 0 - 2
rv32/test/main.c

@@ -201,8 +201,6 @@ void main(void)
     time_to_main = rdtime() - time_zero;
     null_ptr = get_null_ptr();
 
-    con_set_baudrate(115200);
-
     CON_DATA = '1';
     unmask_irq(BUSERR_IRQ);
 

Some files were not shown because too many files changed in this diff