Browse Source

Default baud rate = 115200, baud rate programmable

Set the default tty baud rate to 115200.
Initialize the baud rate and stack pointer explicitly in the firmware.
Move I/O firmware refinitions into header files.
H. Peter Anvin 3 years ago
parent
commit
f2060589ab

+ 1 - 0
.gitignore

@@ -25,6 +25,7 @@ greybox_tmp/
 *.log
 *.deps
 *.stamp
+.*.d
 *.build/
 fpga/output_files/*.htm
 fpga/output_files/*.htm_files/

+ 5 - 0
fpga/functions.sv

@@ -70,3 +70,8 @@ function string tostr(input integer i);
    else
      tostr = "9";
 endfunction
+
+function longint unsigned
+  round_div(input longint unsigned num, input longint unsigned den);
+   round_div = (num + (den >> 1))/den;
+endfunction // round_div

+ 2 - 1
fpga/max80.qsf

@@ -179,5 +179,6 @@ set_global_assignment -name SDC_FILE max80.sdc
 set_global_assignment -name SYSTEMVERILOG_FILE max80.sv
 set_global_assignment -name SOURCE_FILE max80.pins
 set_global_assignment -name SOURCE_TCL_SCRIPT_FILE scripts/pins.tcl
-set_global_assignment -name QIP_FILE ip/fifo.qip
+set_global_assignment -name VERILOG_FILE ip/fifo.v
+
 set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

+ 3 - 1
fpga/max80.sv

@@ -536,8 +536,10 @@ module max80 (
 	    .sys_clk ( sys_clk ),
 	    .tty_clk ( vid_clk ), // 48 MHz
 
+	    .valid ( iodev[1] ),
+	    .wstrb ( cpu_mem_wstrb ),
 	    .wdata ( cpu_mem_wdata ),
-	    .wstrb ( iodev[1] & cpu_mem_wstrb[0] ),
+	    .addr ( cpu_mem_addr[2] ),
 
 	    .tty_txd ( tty_rxd ) // DTE -> DCE
 	    );

File diff suppressed because it is too large
+ 2562 - 2609
fpga/output_files/max80.jam


BIN
fpga/output_files/max80.jbc


BIN
fpga/output_files/max80.jic


+ 1 - 1
fpga/output_files/max80.map

@@ -10,7 +10,7 @@ Quad-Serial configuration device dummy clock cycle: 8
 
 Notes:
 
-- Data checksum for this conversion is 0xF77E70CA
+- Data checksum for this conversion is 0xF76CC72A
 
 - All the addresses in this file are byte addresses
 

BIN
fpga/output_files/max80.pof


BIN
fpga/output_files/max80.sof


+ 1 - 0
fpga/scripts/qsfdeps.pl

@@ -28,6 +28,7 @@ while (defined(my $l = <$in>)) {
     next if ($type !~ /_file$/i || $type =~ /^generate_/i);
     
     $name =~ s/^quartus_\w+://;
+    $name =~ s/\s-.*$//;
 
     if ($name =~ /\.cof$/i) {
 	$cof_list{$name}++;

+ 44 - 16
fpga/tty.sv

@@ -10,29 +10,38 @@
 //
 
 module tty (
-	    input 	rst_n,
-	    input 	sys_clk,
-	    input 	tty_clk,
+	    input 	 rst_n,
+	    input 	 sys_clk,
+	    input 	 tty_clk,
 
-	    input [7:0] wdata,
-	    input 	wstrb,
+	    input 	 valid,
+	    input [3:0]  wstrb,
+	    input [31:0] wdata,
+	    input [0:0]  addr,
 
-	    output 	tty_txd
+	    output 	 tty_txd
 	    );
+
+   `include "functions.sv"	// For ModelSim
+   
    //
    // Baud rate generator; produces a clock enable synchronous
    // with tty_clk
    //
-   parameter [15:0] DIVISOR = 16'd2; // == tty_clk/(3*16)
+   parameter [31:0]	BAUDRATE = 115200;
+   parameter [31:0]	TTY_CLK  = 48000000;
+
+   localparam divisor_bits = 16;
    
-   reg [15:0] 		divisor = DIVISOR;
-   reg [15:0] 		clk_div;
-   reg 			tty_clk_en; // tty clock tick (clock enable)
+   reg  [divisor_bits-1:0]  divisor_q = round_div(TTY_CLK, BAUDRATE << 4) - 1;
+   wire [divisor_bits-1:0]  divisor;
+   reg  [divisor_bits-1:0]  clk_div;
+   reg 			    tty_clk_en; // tty clock tick (clock enable)
 
    always @(negedge rst_n or posedge tty_clk)
      if (~rst_n)
        begin
-	  clk_div <= 16'h0;
+	  clk_div <= 16;	// Give enough time for synchronizer
 	  tty_clk_en <= 1'b0;
        end
      else
@@ -70,16 +79,35 @@ module tty (
 		.wrfull ( ),
 		.wrusedw ( )
 		);
-      
+
    //
    // CPU -> transmitter data. No wait state is needed nor expected.
    //
-   reg 	      old_wstrb;
-   
+
+   // Data mask (if/when needed)
+   wire [31:0] wmask = {{8{wstrb[3]}}, {8{wstrb[2]}},
+			{8{wstrb[1]}}, {8{wstrb[0]}}};
+
+   // Data (FIFO) register; normally addressed as byte
+   // Protect against long pulses (edge detect)
+   reg old_wstrb;
+   always @(posedge sys_clk)
+     old_wstrb <= wstrb[0];
+
+   assign tx_wrreq = rst_n & wstrb[0] & (addr == 0);
+
+   // Divisor register
    always @(posedge sys_clk)
-	old_wstrb <= wstrb;
+     if (wstrb[0] & (addr == 1))
+       divisor_q <= wdata[divisor_bits-1:0] & wmask;
 
-   assign tx_wrreq = wstrb & ~old_wstrb; // Protect against long pulses
+   synchronizer #(.width(divisor_bits), .stages(2)) sync_divisor
+     (
+      .rst_n ( rst_n ),
+      .clk ( tty_clk ),
+      .d ( divisor_q ),
+      .q ( divisor )
+      );
 
    //
    // Transmitter

+ 11 - 6
fw/Makefile

@@ -15,6 +15,8 @@ LDFLAGS   = $(CFLAGS) \
 	    -Wl,--section-start=.init=0 -Wl,-q \
 	    -Wl,-z,common-page-size=16 -Wl,-z,max-page-size=16
 
+gendeps   = -MD -MF .$(@F).d
+
 # Delete output files on error
 .DELETE_ON_ERROR:
 
@@ -46,22 +48,25 @@ boot.elf: head.o hello.o
 	$(CC) $(LDFLAGS) -o $@ $^
 
 %.o: %.c
-	$(CC) $(CFLAGS) $(CFLAGS_$<) -c -o $@ $<
+	$(CC) $(CFLAGS) $(CFLAGS_$<) $(gendeps) -c -o $@ $<
 
 %.s: %.c
-	$(CC) $(CFLAGS) $(CFLAGS_$<) -S -o $@ $<
+	$(CC) $(CFLAGS) $(CFLAGS_$<) $(gendeps) -S -o $@ $<
 
 %.i: %.c
-	$(CC) $(CFLAGS) $(CFLAGS_$<) -E -o $@ $<
+	$(CC) $(CFLAGS) $(CFLAGS_$<) $(gendeps) -E -o $@ $<
 
 %.o: %.S
-	$(CC) $(SFLAGS) $(SFLAGS_$<) -c -o $@ $<
+	$(CC) $(SFLAGS) $(SFLAGS_$<) $(gendeps) -c -o $@ $<
 
 %.s: %.S
-	$(CC) $(SFLAGS) $(SFLAGS_$<) -E -o $@ $<
+	$(CC) $(SFLAGS) $(SFLAGS_$<) $(gendeps) -o $@ $<
 
 clean:
-	rm -f *.o *.i *.s *.elf *.bin
+	rm -f *.o *.i *.s *.elf *.bin .*.d
 
 spotless: clean
 	rm -f *.mem *.hex *.mif
+
+-include .*.d
+

+ 29 - 21
fw/boot.mif

@@ -4,28 +4,36 @@ WIDTH = 32;
 ADDRESS_RADIX = HEX;
 DATA_RADIX = HEX;
 CONTENT BEGIN
-000 : 0160006F;
-001 : 00000000;
+000 : 00002137;
+001 : 0120006F;
 002 : 00000000;
 003 : 00000000;
 004 : 0040006F;
-005 : 0023A001;
-006 : 0393C000;
-007 : C30304C0;
-008 : 10630003;
-009 : 46B70203;
-00A : 8293000F;
-00B : 12FD2406;
-00C : FE029FE3;
-00D : 00130793;
-00E : 0FF7F313;
-00F : C0600023;
-010 : 0023B7ED;
-011 : 0385C460;
-012 : 0000BFD9;
-013 : 6C6C6548;
-014 : 57202C6F;
-015 : 646C726F;
-016 : 000A0D21;
-[017..7FF] : 00;
+005 : 47E5A001;
+006 : C4F02223;
+007 : C0000023;
+008 : 06C00F13;
+009 : 000F4803;
+00A : 02081D63;
+00B : 1406F6B7;
+00C : 3FF68293;
+00D : FFF84313;
+00E : 40235393;
+00F : 00181593;
+010 : 0013F513;
+011 : 00B56633;
+012 : 0FF67813;
+013 : C1000023;
+014 : C01028F3;
+015 : C0102E73;
+016 : 411E0EB3;
+017 : FFD2FCE3;
+018 : 0023BFD1;
+019 : 0F05C500;
+01A : 0000BF75;
+01B : 6C6C6548;
+01C : 57202C6F;
+01D : 646C726F;
+01E : 000A0D21;
+[01F..7FF] : 00;
 END;

+ 3 - 0
fw/head.S

@@ -1,8 +1,11 @@
+#include "sys.h"
+
 	// The linker ensures that section .init is first
 	.section ".init","ax"
 	.org 0
 	.globl _reset
 _reset:
+	li sp,SRAM_SIZE
 	j _start
 
 	.org 0x10

+ 8 - 9
fw/hello.c

@@ -1,10 +1,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#define IODEVB(d,r) (*(volatile uint8_t *)(0xfffffc00+((d) << 6)+((r) << 2)))
-
-#define LED     IODEVB(0,0)
-#define CONSOLE IODEVB(1,0)
+#include "io.h"
 
 void die(void)
 {
@@ -18,17 +15,19 @@ void _start(void)
     const char *p;
     uint8_t led = 0;
 
-    LED = led = 0;
+    con_set_baudrate(115000);
+    set_led(led = 0);
 
     for (p = hello; *p; p++)
 	CONSOLE = *p;
 
     while ( 1 ) {
-      for (int x = 0; x < 1000000; x++)
+      for (int x = 0; x < 10000000; x++)
 	/* nothing */;
-
-      LED = ++led;
+      led = (led << 1) | ((~led >> 2) & 1);
+      set_led(led);
+      udelay(4000000);
     }
-    
+
     die();
 }

+ 49 - 0
fw/io.h

@@ -0,0 +1,49 @@
+#ifndef IO_H
+#define IO_H
+
+#include "iodev.h"
+
+static inline void con_write(uint8_t c)
+{
+    CONSOLE = c;
+}
+
+static inline void con_set_baudrate(uint32_t b)
+{
+    uint32_t bauddiv = (CON_BAUD_BASE + (b >> 1))/b;
+    CON_BAUDDIV = bauddiv ? bauddiv - 1 : 0;
+}
+
+static inline void set_led(uint8_t leds)
+{
+    LED = leds;
+}
+
+static inline uint32_t rdtime(void)
+{
+    uint32_t t;
+
+    asm volatile("rdtime %0" : "=r" (t));
+    return t;
+}
+
+static inline uint64_t rdtimeq(void)
+{
+    uint32_t l, h1, h0;
+
+    asm volatile("rdtimeh %0; rdtime %1; %rdtimeh %2"
+		 : "=r" (h1), "=r" (l), "=r" (h0));
+
+    return ((int32_t)l < 0) ? h1 : h0;
+}
+
+static inline void udelay(uint32_t us)
+{
+    uint32_t cycles = us * (CPU_CLK_HZ / 1000000);
+    uint32_t start = rdtime();
+
+    while (rdtime() - start < cycles)
+	/* wait */;
+}
+
+#endif /* IO_H */

+ 44 - 0
fw/iodev.h

@@ -0,0 +1,44 @@
+#ifndef IODEV_H
+#define IODEV_H
+
+/* Address for I/O device d, subregister r */
+#define IODEVA(d,r) (0xfffffc00+((d) << 6)+((r) << 2))
+
+#ifdef __ASSEMBLY__
+
+/*
+ * The I/O device range is designed so that it can be addressed via
+ * negative offsets from the zero register, so no explicit base
+ * pointer register is necesary.
+ */
+#define IODEVV(d,r) IODEVA(d,r)(zero)
+#define IODEVB(d,r) IODEVV(d,r)
+#define IODEVH(d,r) IODEVV(d,r)
+#define IODEVL(d,r) IODEVV(d,r)
+
+#else
+
+#include <stdint.h>
+
+/* Writable registers */
+#define IODEVV(d,r) (*(volatile void     *)IODEVA(d,r))
+#define IODEVB(d,r) (*(volatile uint8_t  *)IODEVA(d,r))
+#define IODEVH(d,r) (*(volatile uint16_t *)IODEVA(d,r))
+#define IODEVL(d,r) (*(volatile uint32_t *)IODEVA(d,r))
+
+/* Readonly registers */
+#define IODEVRV(d,r) (*(const volatile void     *)IODEVA(d,r))
+#define IODEVRB(d,r) (*(const volatile uint8_t  *)IODEVA(d,r))
+#define IODEVRH(d,r) (*(const volatile uint16_t *)IODEVA(d,r))
+#define IODEVRL(d,r) (*(const volatile uint32_t *)IODEVA(d,r))
+
+#endif
+
+#define CPU_CLK_HZ	84000000
+
+#define LED		IODEVB(0,0)
+#define CONSOLE		IODEVB(1,0)
+#define CON_BAUDDIV	IODEVL(1,1)
+#define CON_BAUD_BASE	(48000000U >> 4)
+
+#endif /* IODEV_H */

+ 6 - 0
fw/sys.h

@@ -0,0 +1,6 @@
+#ifndef SYS_H
+#define SYS_H
+
+#define SRAM_SIZE	8192	/* Size of builtin SRAM */
+
+#endif /* SYS_H */

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