Browse Source

ioregs: export I/O register address as symbols

Export the I/O registers as symbols, which should at least in theory
make debugging simpler. Unfortunately there seems to be some bugs with
negative addresses in binutils (sigh.)
H. Peter Anvin 3 years ago
parent
commit
5b686b909a
5 changed files with 172 additions and 49 deletions
  1. 5 2
      rv32/Makefile
  2. 69 0
      rv32/iodeva.h
  3. 5 47
      rv32/ioregs.h
  4. 83 0
      rv32/ioregsa.pl
  5. 10 0
      rv32/max80.ld

+ 5 - 2
rv32/Makefile

@@ -44,7 +44,7 @@ ROMS    := $(wildcard roms/*.rom)
 ROMOBJS  = $(ROMS:.rom=.o)
 
 max80.elf: head.o dummy.o die.o main.o system.o \
-	  irqasm.o irqtable.o spurious_irq.o sbrk.o \
+	  ioregsa.o irqasm.o irqtable.o spurious_irq.o sbrk.o \
 	  console.o rtc.o romcopy.o \
 	  sdcard.o diskcache.o \
 	  abcmem.o abcio.o abcdisk.o abcrtc.o abcpun80.o \
@@ -55,7 +55,7 @@ max80.elf: head.o dummy.o die.o main.o system.o \
 	  fatfs.a
 
 testimg.elf: head.o dummy.o die.o test/main.o test/system.o \
-	  irqasm.o irqtable.o spurious_irq.o sbrk.o \
+	  ioregsa.o irqasm.o irqtable.o spurious_irq.o sbrk.o \
 	  console.o rtc.o romcopy.o \
 	  sdcard.o diskcache.o \
 	  abcmem.o abcio.o abcdisk.o abcrtc.o abcpun80.o \
@@ -112,6 +112,9 @@ testimg.o: testimg.S testimg.bin
 %.s: %.S | $(genhdrs)
 	$(CC) $(SFLAGS) $(SFLAGS_$<) $(gendeps) -E -o $@ $<
 
+ioregsa.S: ioregs.h ioregsa.pl | $(genhdrs)
+	$(PERL) ioregsa.pl $< $@
+
 roms/%.o: roms/%.rom rom.S
 	$(CC) $(SFLAGS) $(SFLAGS_$(F<)) -DNAME='rom_$*' -DFILE='"$<"' \
 		-c -o $@ rom.S

+ 69 - 0
rv32/iodeva.h

@@ -0,0 +1,69 @@
+#ifndef IODEVA_H
+#define IODEVA_H
+
+#define _NEGBASE(b)	((0xffffffff << (b)) & 0xffffffff)
+#define XDEV_ADDR_BASE  _NEGBASE(XDEV_ADDR_SHIFT+XDEV_ADDR_BITS)
+#define IODEV_ADDR_BASE _NEGBASE(IODEV_ADDR_SHIFT+IODEV_ADDR_BITS)
+
+/* Address for I/O device d, subregister r, offset o */
+#define IODEVA(b,r,o)   ((b ## _BASE)+((r) << 2)+(o))
+
+#ifdef __ASSEMBLY__
+
+/*
+ * The I/O device range is designed so that it can be addressed via
+ * negative offsets from the zero register. Use (zero) after the
+ * macro in a load or store instruction.
+ */
+#define IODEVV(d,r)	IODEVA(d,r,0)
+#define IODEVB0(d,r)	IODEVA(d,r,0)
+#define IODEVB1(d,r)	IODEVA(d,r,1)
+#define IODEVB2(d,r)	IODEVA(d,r,2)
+#define IODEVB3(d,r)	IODEVA(d,r,3)
+#define IODEVH0(d,r)	IODEVA(d,r,0)
+#define IODEVH1(d,r)	IODEVA(d,r,1)
+#define IODEVL(d,r)	IODEVA(d,r,0)
+
+#define IODEVRV(d,r)	IODEVA(d,r,0)
+#define IODEVRB0(d,r)	IODEVA(d,r,0)
+#define IODEVRB1(d,r)	IODEVA(d,r,1)
+#define IODEVRB2(d,r)	IODEVA(d,r,2)
+#define IODEVRB3(d,r)	IODEVA(d,r,3)
+#define IODEVRH0(d,r)	IODEVA(d,r,0)
+#define IODEVRH1(d,r)	IODEVA(d,r,1)
+#define IODEVRL(d,r)	IODEVA(d,r,0)
+
+#define PTR(x)	    x
+
+#else
+
+/* Writable registers */
+#define IODEVV(d,r)   (*(volatile void     *)IODEVA(d,r,0))
+#define IODEVB0(d,r)  (*(volatile uint8_t  *)IODEVA(d,r,0))
+#define IODEVB1(d,r)  (*(volatile uint8_t  *)IODEVA(d,r,1))
+#define IODEVB2(d,r)  (*(volatile uint8_t  *)IODEVA(d,r,2))
+#define IODEVB3(d,r)  (*(volatile uint8_t  *)IODEVA(d,r,3))
+#define IODEVH0(d,r)  (*(volatile uint16_t *)IODEVA(d,r,0))
+#define IODEVH1(d,r)  (*(volatile uint16_t *)IODEVA(d,r,2))
+#define IODEVL(d,r)   (*(volatile uint32_t *)IODEVA(d,r,0))
+
+/* Readonly registers */
+#define IODEVRV(d,r)  (*(const volatile void     *)IODEVA(d,r,0))
+#define IODEVRB0(d,r) (*(const volatile uint8_t  *)IODEVA(d,r,0))
+#define IODEVRB1(d,r) (*(const volatile uint8_t  *)IODEVA(d,r,1))
+#define IODEVRB2(d,r) (*(const volatile uint8_t  *)IODEVA(d,r,2))
+#define IODEVRB3(d,r) (*(const volatile uint8_t  *)IODEVA(d,r,3))
+#define IODEVRH0(d,r) (*(const volatile uint16_t *)IODEVA(d,r,0))
+#define IODEVRH1(d,r) (*(const volatile uint16_t *)IODEVA(d,r,2))
+#define IODEVRL(d,r)  (*(const volatile uint32_t *)IODEVA(d,r,0))
+
+#define PTR(x) (&(x))
+
+#endif /* __ASSEMBLY__ */
+
+#define IODEVB(d,r)	IODEVB0(d,r)
+#define IODEVH(d,r)	IODEVH0(d,r)
+#define IODEVRB(d,r)	IODEVRB0(d,r)
+#define IODEVRH(d,r)	IODEVRH0(d,r)
+
+#endif /* IODEVA_H */

+ 5 - 47
rv32/ioregs.h

@@ -3,53 +3,7 @@
 
 #include "compiler.h"
 #include "iodevs.h"
-
-/* Address for I/O device d, subregister r, offset o */
-#define IODEVA(b,r,o)   ((b ## _BASE)+((r) << 2)+(o))
-
-#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,0)(zero)
-#define IODEVB(d,r) IODEVV(d,r,0)
-#define IODEVH(d,r) IODEVV(d,r,0)
-#define IODEVL(d,r) IODEVV(d,r,0)
-
-#define PTR(x)	    x
-
-#else
-
-/* Writable registers */
-#define IODEVV(d,r)   (*(volatile void     *)IODEVA(d,r,0))
-#define IODEVB(d,r)   (*(volatile uint8_t  *)IODEVA(d,r,0))
-#define IODEVB0(d,r)  (*(volatile uint8_t  *)IODEVA(d,r,0))
-#define IODEVB1(d,r)  (*(volatile uint8_t  *)IODEVA(d,r,1))
-#define IODEVB2(d,r)  (*(volatile uint8_t  *)IODEVA(d,r,2))
-#define IODEVB3(d,r)  (*(volatile uint8_t  *)IODEVA(d,r,3))
-#define IODEVH(d,r)   (*(volatile uint16_t *)IODEVA(d,r,0))
-#define IODEVH0(d,r)  (*(volatile uint16_t *)IODEVA(d,r,0))
-#define IODEVH1(d,r)  (*(volatile uint16_t *)IODEVA(d,r,2))
-#define IODEVL(d,r)   (*(volatile uint32_t *)IODEVA(d,r,0))
-
-/* Readonly registers */
-#define IODEVRV(d,r)  (*(const volatile void     *)IODEVA(d,r,0))
-#define IODEVRB(d,r)  (*(const volatile uint8_t  *)IODEVA(d,r,0))
-#define IODEVRB0(d,r) (*(const volatile uint8_t  *)IODEVA(d,r,0))
-#define IODEVRB1(d,r) (*(const volatile uint8_t  *)IODEVA(d,r,1))
-#define IODEVRB2(d,r) (*(const volatile uint8_t  *)IODEVA(d,r,2))
-#define IODEVRB3(d,r) (*(const volatile uint8_t  *)IODEVA(d,r,3))
-#define IODEVRH(d,r)  (*(const volatile uint16_t *)IODEVA(d,r,0))
-#define IODEVRH0(d,r) (*(const volatile uint16_t *)IODEVA(d,r,0))
-#define IODEVRH1(d,r) (*(const volatile uint16_t *)IODEVA(d,r,2))
-#define IODEVRL(d,r)  (*(const volatile uint32_t *)IODEVA(d,r,0))
-
-#define PTR(x) (&(x))
-
-#endif
+#include "iodeva.h"
 
 #define CPU_HZ			84000000
 #define TIMER_HZ		(1 << TIMER_SHIFT)
@@ -79,6 +33,7 @@
 #define ROMCOPY_INPUT		IODEVRL(ROMCOPY,4)
 #define ROMCOPY_STATUS_DONE	1
 
+/* n = 0...7 */
 #define TTY_DATA(n)		IODEVB(TTY,0+((n) << 2))
 #define TTY_WATERCTL(n)		IODEVH0(TTY,1+((n) << 2))
 #define TTY_WATERCTL_TX_LOW(x)	((x) << 0)
@@ -174,7 +129,10 @@
 #define ABC_INP1_DATA		IODEVB1(ABC,5)
 #define ABC_INP_ENABLE		IODEVB2(ABC,5)
 
+/* n = 0 ... 511 */
 #define ABCMEMMAP_PAGE(n)	IODEVL(ABCMEMMAP,n)
+
+/* n = 0 ... 255 */
 #define ABCMEMMAP_WRPORT(n)	IODEVL(ABCMEMMAP,128+((n) << 1))
 #define ABCMEMMAP_RDPORT(n)	IODEVL(ABCMEMMAP,129+((n) << 1))
 #define ABCMEMMAP_WRCOUNT(n)	IODEVL(ABCMEMMAP,384+((n) << 1))

+ 83 - 0
rv32/ioregsa.pl

@@ -0,0 +1,83 @@
+#!/usr/bin/perl
+#
+# Parse ioregs.h into a .S file to export the register names
+# as actual symbols; this is highly useful for debugging.
+
+use strict;
+use integer;
+
+my($infile, $outfile) = @ARGV;
+
+unless (defined($outfile)) {
+    die "Usage: $0 infile outfile\n";
+}
+
+open(my $in, '<', $infile)
+    or die "$0: $infile: $!\n";
+open(my $out, '>', $outfile)
+    or die "$0: $outfile: $!\n";
+
+my %range = ();
+my %sizes = ('B' => 1, 'H' => 2, 'L' => 4);
+my %syms;
+
+sub outsym($$$$) {
+    my($out, $sym, $dev, $size) = @_;
+
+    print $out ".globl $sym\n";
+    print $out "$sym = . + ($dev - XDEV_ADDR_BASE)\n";
+    if ($size) {
+	print $out ".type $sym, \@object\n";
+	print $out ".size $sym, $size\n";
+    }
+}
+
+print $out "\#include \"iodevs.h\"\n";
+print $out "\#include \"iodeva.h\"\n";
+print $out "\n";
+
+print $out "\.section \".iodevs\",\"aw\",\@nobits\n\n";
+
+outsym($out, 'IODEV_BASE', 'IODEV_ADDR_BASE', 0);
+outsym($out, 'XDEV_BASE', 'XDEV_ADDR_BASE', 0);
+
+while (my $l = <$in>) {
+    $l =~ s/^\s+//;
+    $l =~ s/\s+$//;
+
+    if ($l =~ /^\/\*\s*(\w+)\s*\=\s*([0-9]+)\s*(\.\.\.\s*([0-9]+))\s*\*\//) {
+	$range{$1} = [$2, $3 ? $4 : $2];
+    } elsif ($l =~ /^\/\*\s*(\w+)\s*\=\s*\*\//) {
+	undef $range{$1};
+    } elsif ($l =~ /^\#\s*define\s+(\w+)(\((\w+)\))?\s+(IODEVR?(\w).*)$/) {
+	my $sym = $1;
+	my $dev = $4;
+	my $size = $sizes{$5};
+	
+	if ($2) {
+	    my $v = $3;
+	    my $r = $range{$v};
+	    next unless (defined($r));
+
+	    for (my $i = $r->[0]; $i <= $r->[1]; $i++) {
+		print $out "\#define $v $i\n";
+		outsym($out, $sym.$i, $dev, $size);
+		print $out "\#undef $v\n";
+		print $out "\n";
+	    }
+	} else {
+	    outsym($out, $sym, $dev, $size);
+	    print $out "\n";
+	}
+    }
+}
+
+close($in);
+close($out);
+
+		    
+	
+    
+    
+
+

+ 10 - 0
rv32/max80.ld

@@ -6,6 +6,8 @@
 #define __ASSEMBLY__
 #define __LDSCRIPT__
 #include "sys.h"
+#include "iodevs.h"
+#include "iodeva.h"
 
 OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv",
               "elf32-littleriscv")
@@ -308,7 +310,15 @@ SECTIONS
 
 	__dram_end = .;
 
+	/* Dummy section containing I/O device symbols */
+	. = XDEV_ADDR_BASE;
+	.iodevs (NOLOAD) : {
+		. = .;		/* Force output */
+		KEEP(*(.iodevs))
+	}
+
 	/* Catch missing sections */
+	. = __dram_end;
 	__junk_start = .;
 	.junk : {
 		*(*)