Browse Source

fpga: parameterize USB max packet size

Centralize the USB max packet definition, and add a helper function
for extracting C or Verilog constant definitions from a header file.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
H. Peter Anvin 2 years ago
parent
commit
5328aa117d

+ 1 - 0
fpga/max80.qsf

@@ -210,6 +210,7 @@ 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 SYSTEMVERILOG_FILE usb/usb.sv
+set_global_assignment -name VERILOG_INCLUDE_FILE usb/usbparam.vh
 set_global_assignment -name VERILOG_FILE ip/statusram.v
 set_global_assignment -name VERILOG_INCLUDE_FILE iodevs.vh
 set_global_assignment -name SYSTEMVERILOG_FILE serial.sv

+ 1 - 1
fpga/usb/Makefile

@@ -6,7 +6,7 @@ PERLOPT = -I$(PERLINC)
 TARGETS = usb_desc.v
 ALSO    = usb_desc.bin
 
-includes = ../../iodevs.conf
+includes = ../../iodevs.conf usbparam.vh
 
 all: $(TARGETS) $(ALSO)
 

+ 8 - 3
fpga/usb/usb_desc.conf

@@ -4,6 +4,9 @@
 #
 
 require '../../iodevs.conf';
+require 'hconst.ph';
+
+my %usbparam     = header_const('usbparam.vh');
 
 usb_languages('en_US', 'sv_SE');
 
@@ -15,6 +18,8 @@ my $serial       = usb_serial('XXXXXX-XXXXXX'); # 12 characters
 my $manufacturer = usb_string(''   => 'Peter & Per');
 my $product      = usb_string(''   => 'MAX80 I/O card for ABC');
 
+my $maxpacket    = 1 << ($usbparam{'USB_PACKET_BITS'} || 6);
+
 sub acm_channels($$@) {
     my($channel_count,$ep_base,@names) = @_;
     my @d;
@@ -68,7 +73,7 @@ sub acm_channels($$@) {
 			usb_desc('endpoint',
 				 ep_i($ep_intr),
 				 byte(3),	# Interrupt, data
-				 word(64),	# Max packet size
+				 word($maxpacket),
 				 byte(2)),	# Interval
 	    },
 
@@ -85,14 +90,14 @@ sub acm_channels($$@) {
 			usb_desc('endpoint',
 				 ep_i($ep_data),
 				 byte(2),      # Bulk, data
-				 word(64),     # Max packet size
+				 word($maxpacket),
 				 byte(0)),     # Interval
 
 			# Data endpoint (output)
 			usb_desc('endpoint',
 				 ep_o($ep_data),
 				 byte(2),	# Bulk, data
-				 word(64),	# Max packet size
+				 word($maxpacket),
 				 byte(0))       # Interval
 
 	     });

+ 3 - 1
fpga/usb/usb_serial/src_v/usb_cdc_core.sv

@@ -62,6 +62,8 @@
 //        15:0 - mask of corresponding status bits
 //       31:16 - invert polarity (0 = irq on status 1, 1 = irq on status 0)
 
+`include "../../usbparam.vh"
+
 module usb_cdc_channel
   #(parameter [3:0] data_ep_num = 4'd1,
     parameter [3:0] intr_ep_num = data_ep_num+1'b1)
@@ -100,7 +102,7 @@ module usb_cdc_channel
 
    localparam fifo_bits   = 10;
    localparam fifo_size   = 1 << fifo_bits;
-   localparam packet_bits = 6;
+   localparam packet_bits = `USB_PACKET_BITS;
    localparam packet_size = 1 << packet_bits;
 
    // Control line status in the USB domain

+ 2 - 0
fpga/usb/usbparam.vh

@@ -0,0 +1,2 @@
+// Legal values are 3, 4, 5, or 6 for 8, 16, 32 or 64 bytes
+`define `USB_PACKET_BITS	6

+ 95 - 0
tools/perlinc/hconst.ph

@@ -0,0 +1,95 @@
+#!/usr/bin/perl
+#
+# Routine to read define'd constants from a Verilog or C header
+# If expressions are used, they need to be defined with care to
+# be able to evaluate them. Conditionals are NOT processed.
+#
+
+use strict;
+use Math::BigInt;
+
+sub header_const($) {
+    my($file) = @_;
+
+    my %bases = ('d' => 10, 'b' => 2, 'o' => 8, 'q' => 8, 'h' => 16,
+		 'x' => 16, '0' => 8, '0x' => 16, '' => 10);
+
+    my %syms = ();
+    open(my $f, '<', $file)
+	or die "$0: $file: $!\n";
+
+    while (defined(my $l = <$f>)) {
+	chomp $l;
+	while ($l =~ /\/$/) {
+	    my $ll = <$f>;
+	    last unless (defined($ll));
+	    chomp $ll;
+	    $l = substr($l,0,-1) . $ll;
+	}
+
+	$l =~ s/\/\/.*$//;
+	$l =~ s/\/\*.*?\*\///g;
+	if ($l =~ /^\s*[\`\#]\s*define\s+\`?([[:alpha:]_]\w*)\s+(.*?)\s*$/) {
+	    $syms{$1} = $2;
+	} elsif ($l =~ /^\s*[\`\#]\s*undef\s+\`?([[:alpha:]_]\w*)/) {
+	    delete $syms{$1};
+	}
+    }
+
+    close($f);
+
+    foreach my $s (keys %syms) {
+	my $e = $syms{$s};
+	my $o = '';
+
+	# Don't try to evaluate if...
+	next if ($e =~ /[\"\$\@\[\{\\]/);
+
+	$e =~ s/\`//g;
+
+	while ($e =~ /^(.*?)\b[0-9]*\'([bhod])([0-9a-f_]+)\b(.*)$/i ||
+	       $e =~ /^(.*?)\b()(0[0-7_]+|0b[0-1_]+|0x[0-9a-f_]+)\b(.*)$/i) {
+	    $e = $4;
+	    $o .= $1;
+
+	    my $base = lc($2);
+	    my $dig = $3;
+	    $dig =~ s/_//g;
+
+	    if ($base ne '') {
+		$base = $bases{$base};
+	    } elsif ($dig =~ /^0x/i) {
+		$base = 16;
+	    } elsif ($dig =~ /^0b/i) {
+		$base = 2;
+	    } elsif ($dig =~ /^0/) {
+		$base = 8;
+	    }
+
+	    $o .= Math::BigInt::from_base($dig, $base)->bstr();
+	}
+	$syms{$s} = $o.$e;
+    }
+
+    foreach my $s (keys %syms) {
+	my $e = $syms{$s};
+	my $o = '';
+
+	while ($e =~ /^(.*?)\b\`?([[:alpha:]_]\w*)\b(.*)$/) {
+	    $e = $3;
+	    $o .= $1;
+
+	    if (defined($syms{$2})) {
+		$e = $syms{$2} . $e;
+	    } else {
+		$o .= $2;
+	    }
+	}
+
+	$syms{$s} = eval("{ use bigint; return ($o$e); }");
+    }
+
+    return %syms;
+}
+
+1;