Hi.

One of things that has bitten me before is when the different areas of a project start to use there own header files of magic numbers, or worse still they just write the magic numbers straight into the code. This causes real pain once a project gets to a certain size, and gives even more grief when we get to the second version.

To try to solve this I propose adding the attached patch. It contains a plain text file that contains a small machine readable description of every register. There is also a small piece of perl that will process this text file and generate source files for C, assembler and verilog.

As an extension I will eventually add support to generate HTML and other documentation formats directly from the source script.

What do people think? Can I just check this in, and if I do will people use it? Would people like it done differently? (I'm really not keen to go to XML input files, by the way).

I would also propose adding the file oga1_defs.v (that's a bad name) and including it in all the places where it's needed. It took me about 2 weeks to realise that there were two different things called TARGET_*. I spent another day screaming that the values of TARGET_ are not consistent amongst everything in the XP10 (the _syn.v files have drifted from the others).

MM
Index: registers.txt
===================================================================
--- registers.txt       (revision 0)
+++ registers.txt       (revision 0)
@@ -0,0 +1,280 @@
+# This file describes all of the registers used in OGD1.  From it we
+# generate all other files that describe the registers, that means
+# verilog, assembler, C and html files.
+#
+# The format is fairly simple.  It consits of a number of blocks, each
+# block contains a number of registers.  I have assumed that each
+# block is implimented by one piece of verilog (or the address
+# decoding is).
+#
+# The tags are:
+#
+# REG_BLOCK <name>
+#   This starts a new register block.  If there is only one instance
+#   of this block then the name descibes both the name of the block
+#   and the name of the instance.
+#
+# REG_BLOCK_ENDS
+#   This ends a register block.
+#
+# REG_BLOCK_AT <address>
+# REG_BLOCK_AT <name> <address>
+#   This command gives the global address of the block or block
+#   instance.  The first format is used when there is only one instance
+#   of this block.  The second format is used when there are multiple
+#   instances.  Each instance is then named.
+#
+# REG_VWIDTH <width>
+#   This gives the bit width of the verilog address decoder attached
+#   to this block.
+#
+# REG_VSHIFT <shift>
+#   This gives the number of LSBs to shift off when we generate the
+#   verilog.  This is useful when the verilog is decoding uint32s.
+#
+# REG_TYPE
+#   Starts a register type.  A register type describes the contents of
+#   a register, this is most useful when multiple registers have the
+#   same contents.  Types are global.
+#
+# REG_TYPE_ENDS
+#   Close a preceeding type.
+#
+# REG <offset> <flag> <name>
+# REG <offset> <flag> <name> <type>
+# REG <offset> <flag> <name> ...
+#   The REG command describes a register.  The offset is the address
+#   of the register within the block.  The flag can be R, W or RW.
+#   The first format describes a simple register containing an
+#   unsigned int.  The second format describes a register of the named
+#   type.  The third format indicates that the following lines
+#   describe the contents of the register.
+#
+# REG_ENDS
+#   This closes the "..." format of REG definition.
+#
+# REG_BIT <bit> <flag> <name>
+#   This defines a bit within a register.  It can only occure within a
+#   REG_TYPE or REG "..." section.
+#
+# REG_BITS <lsb-bit> <msb-bit> <flag> <name>
+#   This defines a bit range within a register.  It can only occure
+#   within a REG_TYPE or REG "..." section.
+#
+# REG_ENUM <lsb-bit> <msb-bit> <flag> [ <value> <name> ]
+#   This is used to give names to the values that a register can be
+#   set to.  It can only occure within a REG_TYPE or REG "..." 
+#   section.
+#
+# REG_DOC
+#   This allows documentation to be added to a given section.  All of
+#   the lines that follow are part of the documentation string until
+#   there is a line containing just a dot.
+
+REG_BLOCK PCI_CONFIG
+
+REG_BLOCK_AT 0
+REG_VWIDTH 6
+REG_VSHIFT 2
+
+REG_DOC
+These are the definitions of the PCI Configuration structure.  The
+entries between 0 and 0x40 are standardised, and come from the PCI
+specification.  The entries after 0x40 are OGP specific.
+.
+
+REG 0x0000 R  VENDOR_ID
+REG 0x0002 R  DEVICE_ID
+REG 0x0004 RW COMMAND
+REG 0x0006 RW CONTROL
+REG 0x0008 R  CLASS_REVISION
+REG 0x000A R  CLASS
+REG 0x000C RW LATENCY
+REG 0x0010 RW BAR0
+REG 0x0014 RW BAR1
+REG 0x0018 RW BAR2
+REG 0x001C RW BAR3
+REG 0x0020 RW BAR4
+REG 0x0024 RW BAR5
+REG 0x002C R  SUBSYSTEM_SUBVENDOR
+REG 0x0030 RW EPROM
+REG 0x0034 R  CAPS_POINTER
+REG 0x003C RW FLAGS
+
+REG 0x0040 RW MEM_DECODE ...
+REG_BIT 0 RW BAR0_EN
+REG_BIT 1 RW BAR1_EN
+REG_BIT 2 RW BAR2_EN
+REG_BIT 3 RW EPROM_EN
+REG_BIT 4 RW VGA_EN
+REG_BIT 5 RW MDA_EN
+REG_BIT 6 RW CGA_EN
+REG_BIT 7 RW VMEM_EN
+REG_ENDS
+
+REG_BLOCK_ENDS
+
+
+# Memory map:
+# 
+# 0x0000-0x03ff: Reserved for XP10 register space
+# 0x0400-0x040f: Memory arbiter
+# 0x0410-0x041f: Memory controller
+# 0x0420-0x07ff: unused
+# 0x0800-0x0bff: video controller 0 
+# 0x0c00-0x0fff: video controller 1
+# 0x1000-0xffff: unused
+
+
+REG_BLOCK XP10
+
+REG_BLOCK_AT 0x0000
+REG_VWIDTH 6
+REG_VSHIFT 2
+
+REG_TYPE       SERIAL_DATA_LINE
+REG_DOC
+This type defines the bits used to control the lines of the four
+serial interaces (Top / Bottom, DDC / I2C).
+.
+REG_BIT 0 W OUTPUT
+REG_BIT 1 W OUTPUT_ENABLE
+REG_ENUM 0 1 W [ 0 HIZ 2 LO 3 HI 1 BAD ]
+REG_BIT 0 R STATUS
+REG_TYPE_ENDS
+
+REG 0x0000 RW DDC_CLOCK_TOP    SERIAL_DATA_LINE
+REG 0x0004 RW DDC_CLOCK_BOTTOM SERIAL_DATA_LINE
+REG 0x0008 RW DDC_DATA_TOP     SERIAL_DATA_LINE
+REG 0x000C RW DDC_DATA_BOTTOM  SERIAL_DATA_LINE
+REG 0x0010 RW I2C_SDA_TOP      SERIAL_DATA_LINE
+REG 0x0014 RW I2C_SDA_BOTTOM   SERIAL_DATA_LINE
+REG 0x0018 RW I2C_SCL_TOP      SERIAL_DATA_LINE
+REG 0x001C RW I2C_SCL_BOTTOM   SERIAL_DATA_LINE
+
+REG 0x0020 W VIDEO_RESET ...
+REG_DOC
+Is VIDEO_RESET active high or active low?
+.
+REG_ENDS
+
+REG 0x0024  W RESET_INTERRUPT
+
+REG 0x0024 R  INTERRUPT_FLAGS ...
+REG_BIT 0 R HOTPLUG_TOP
+REG_BIT 1 R HOTPLUG_BOTTOM
+REG_BIT 2 R BRIDGE
+REG_ENDS
+
+REG 0x0028 W  DAC_POWER_ON
+
+REG 0x0040  W BPROM_SI
+REG 0x0040 R  BPROM_SO
+REG 0x0044  W BPROM_CE_BAR
+REG 0x0048  W BPROM_SCK
+REG 0x004C  W BPROM_REG_SEL
+
+REG 0x0050  W CPROM_SI
+REG 0x0050 R  CPROM_SO
+REG 0x0054  W CPROM_CE_BAR
+REG 0x0058  W CPROM_SCK
+REG 0x005C  W CPROM_REG_SEL
+
+REG 0x0060  W XCONFIG_DIN
+REG 0x0064  W XCONFIG_CCLK
+REG 0x0068  W XCONFIG_PROGRAM
+REG 0x006C  W XCONFIG_SEL
+
+REG 0x0070 R  XCONFIG_INITN
+REG 0x0074 R  XCONFIG_DONE
+
+REG 0x0070  W HQ_CONTROL ...
+REG_BITS 0 9 W LOAD_ADDRESS
+REG_BIT 10 W BYPASS_EN
+REG_BIT 11 W RUN_EN
+REG_ENDS
+
+REG 0x0074  W HQ_DATA
+
+REG 0x0078 RW CACHE_ENABLE
+
+REG 0x007C RW TEST_REG
+
+REG_BLOCK_ENDS
+
+
+REG_BLOCK MEMARB
+
+REG_BLOCK_AT 0x0400
+REG_VWIDTH 2
+REG_VSHIFT 2
+
+REG 0x0000  W LMR_REGISTER
+REG 0x0008  W LMR_RESET
+REG 0x000C  W LMR_REFRESH_CTRL ...
+REG_BITS 0 10 W REFRESH_DELAY
+REG_BIT  11 W REFRESH_ENABLE
+REG_BIT  12 W MEM_CKE
+REG_ENDS
+
+REG_BLOCK_ENDS
+
+
+REG_BLOCK MEMCTL
+
+REG_BLOCK_AT 0x0410
+REG_VWIDTH 4
+REG_VSHIFT 2
+
+REG 0x0000  W R2W_WAIT
+REG 0x0004  W W2R_WAIT
+REG 0x0008  W ACT2RW_WAIT
+REG 0x000C  W R2PRE_WAIT
+REG 0x0010  W W2PRE_WAIT
+REG 0x0014  W PRE2ACT_WAIT
+REG 0x0018  W ACT2PRE_WAIT
+REG 0x001C  W REFRESH2ACT_WAIT
+REG 0x0020  W CAS_LATENCY
+
+REG_BLOCK_ENDS
+
+
+
+REG_BLOCK VM
+
+REG_BLOCK_AT VM0 0x0800
+REG_BLOCK_AT VM1 0x0C00
+REG_VWIDTH 9
+REG_VSHIFT 2
+
+REG 0x0000  W PROGRAM_MEMORY
+
+REG_BLOCK_ENDS
+
+
+REG_BLOCK VC
+
+REG_BLOCK_AT VC0 0x0A00
+REG_BLOCK_AT VC1 0x0E00
+REG_VWIDTH 4
+REG_VSHIFT 2
+
+REG 0x0000  W PIXEL_X_START
+REG 0x0004  W PIXEL_Y_START
+REG 0x0008  W CLEAR_INT
+REG 0x000C  W PIXEL_INFO ...
+REG_BITS 0 2 W PIXEL_DEPTH
+REG_BIT  3   W PIXEL_RATE
+REG_ENDS
+REG 0x0010  W CPU_RESET_B
+REG 0x0014  W INTERRUPT_ENABLE
+REG 0x0018  W VIDEO_ENABLE
+REG 0x0020  W PC_START
+REG 0x0024  W DIVIDERS ...
+REG_BITS  0 2 W DIVISOR1
+REG_BITS  3 8 W DIVISOR0
+REG_BIT   9   W BASE_CLOCK
+REG_BIT  10   W OE
+REG_ENDS
+
+REG_BLOCK_ENDS
Index: mk_registers.pl
===================================================================
--- mk_registers.pl     (revision 0)
+++ mk_registers.pl     (revision 0)
@@ -0,0 +1,517 @@
+#!/usr/bin/perl -w
+
+use strict;
+use Pod::Usage;
+use Getopt::Long;
+
+my $output_filename;
+my $output_type = "c";
+
+GetOptions(
+    "help" => sub { pod2usage(0); },
+    "output=s" => \$output_filename,
+    "type=s" => \$output_type
+) or pod2usage("Bad options.");
+$#ARGV == 0 or pod2usage("Wrong number of arguments.");
+
+my %types;
+my %regs;
+my %blocks;
+
+
+sub error(@)
+{
+    print @_;
+    exit(1);
+}
+
+sub parse_input_file($)
+{
+  # These are defined when we are in the middle of a multiline type.
+  my $block;
+  my $type;
+  my $reg;
+
+  while (<>) {
+    if (/^REG_BLOCK\s+(\S+)\s*$/) {
+      my ($name) = ($1);
+      #printf(" %s\n", $addr);
+      $block = $name;
+      my %bh = (
+               name => $name,
+               vwidth => 16,
+               copies => [ ]
+              );
+      $blocks{$block} = \%bh;
+    } elsif (/^REG_BLOCK_ENDS/) {
+      error("REG_BLOCK_ENDS must follow a REG_BLOCK") if (!defined($block));
+      error("No REG_ENDS after REG ...") if (defined $reg);
+      error("No REG_TYPE_ENDS after REG_TYPE") if (defined $type);
+      undef $block;
+    } elsif (/^REG_BLOCK_AT\s+(\S+)\s*$/) {
+      error("REG_BLOCK_AT must be in a REG_BLOCK") if (!defined($block));
+      my ($addr) = ($1);
+      $addr = hex($addr) if ($addr =~ s/0x//);
+      $blocks{$block}->{addr} = $addr;
+    } elsif (/^REG_BLOCK_AT\s+(\S+)\s+(\S+)/) {
+      error("REG_BLOCK_AT must be in a REG_BLOCK") if (!defined($block));
+      my ($name, $addr) = ($1, $2);
+      $addr = hex($addr) if ($addr =~ s/0x//);
+      push @{$blocks{$block}->{copies}}, [ $name, $addr ];
+    } elsif (/^REG_VWIDTH\s+(\S+)/) {
+      $blocks{$block}->{vwidth} = $1;
+    } elsif (/^REG_VSHIFT\s+(\S+)/) {
+      $blocks{$block}->{vshift} = $1;
+    } elsif (/^REG_ENUM\s+(\S+)/) {
+      # TODO
+    } elsif (/^REG_TYPE\s+(\S+)/) {
+      $type = $1;
+      my %th = (
+               name => $type,
+               doc => "",
+               bits => []
+              );
+      $types{$type} = \%th;
+    } elsif (/^REG_TYPE_ENDS/) {
+      error("REG_TYPE_ENDS must follow a REG_TYPE") if (!defined($type));
+      undef $type;
+    } elsif (/^REG\s+(\S+)\s+(\S+)\s+(\S+)(\s+(\S+))?/) {
+      my ($name, $addr, $flags, $extra) = ($3, $1, $2, $5);
+      error("No REG_ENDS after REG ...") if (defined $reg);
+      error("No REG_TYPE_ENDS after REG_TYPE") if (defined $type);
+      $addr = hex($addr) if ($addr =~ s/0x//);
+      #printf("m %s %d\n", $extra, $addr) if defined($extra);
+      my %rh = (
+               name => $name,
+               doc => "",
+               flags => $flags,
+               addr => $addr,
+               block => $block,
+               bits => []
+              );
+      $blocks{$block}->{regs}{$name} = \%rh;
+      if (defined $extra and $extra eq "...") {
+       $reg = $name;
+      } elsif (defined $extra) {
+       $blocks{$block}->{regs}{$name}->{type} = $extra;
+      }
+    } elsif (/^REG_ENDS/) {
+      error("REG_ENDS must follow a REG ...") if (!defined($reg));
+      undef $reg;
+    } elsif (/^REG_DOC/) {
+      error("REG_DOC must follow a REG or be in a REG_TYPE or REG_BLOCK")
+       if (!defined($type) && !defined($reg) && !defined($block));
+      my $doc = "";
+      while (<>) {
+       last if (/^\.\s*$/);
+       $doc .= $_;
+      }
+      $types{$type}->{doc} = $doc if (defined $type);
+      $blocks{$block}->{regs}{$reg}->{doc} = $doc if (defined $reg);
+      $blocks{$block}->{doc} .= $doc if (defined $block and not (defined $type 
or defined $reg));
+    } elsif (/^REG_BIT\s+(\S+)\s+(\S+)\s+(\S+)/) {
+      my @bitpos = ($1, $2, $3);
+      error("REG_BIT must follow a REG or be in a REG_TYPE")
+       if (!defined($type) && !defined($reg));
+      push @{$types{$type}->{bits}}, [ @bitpos ] if (defined $type);
+      push @{$blocks{$block}->{regs}{$reg}->{bits}}, [ @bitpos ] if (defined 
$reg);
+    } elsif (/^REG_BITS\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/) {
+      my @bitpos = ($1, $3, $4, $2);
+      error("REG_BITS must follow a REG or be in a REG_TYPE")
+       if (!defined($type) && !defined($reg));
+      push @{$types{$type}->{bits}}, [ @bitpos ] if (defined $type);
+      push @{$blocks{$block}->{regs}{$reg}->{bits}}, [ @bitpos ] if (defined 
$reg);
+    } elsif (/^\s*#/) {
+    } elsif (/^\s*$/) {
+    } else {
+      error("Bad line $_");
+    }
+  }
+}
+
+parse_input_file($ARGV[0]);
+
+open(INC, "> $output_filename") or
+  die "Can't open output file $output_filename";
+
+sub print_bits_asm($@)
+{
+  my ($name, @list) = @_;
+
+  for my $b (@list) {
+    my $nm = sprintf("%s_%s_", $name, @{$b}[2]);
+    if (@{$b} == 3) {
+      printf(INC "%-40s EQU 0x%08x ; %2s\n",
+            $nm."MASK", 1 << @{$b}[0], @{$b}[1]);
+      printf(INC "%-40s EQU %10u\n",
+            $nm."POSN", @{$b}[0]);
+    } elsif (@{$b} == 4) {
+      my $mm = ((1 << (@{$b}[3] + 1)) - 1) & ~ ((1 << @{$b}[0]) - 1);
+      printf(INC "%-40s EQU 0x%08x ; %2s\n",
+            $nm."MASK", $mm, @{$b}[1]);
+      printf(INC "%-40s EQU %10u\n",
+            $nm."LSB_POSN", @{$b}[0]);
+      printf(INC "%-40s EQU %10u\n",
+            $nm."MSB_POSN", @{$b}[3]);
+    }
+  }
+}
+
+sub print_bits_c($@)
+{
+  my ($name, @list) = @_;
+
+  for my $b (@list) {
+    my $nm = sprintf("%s_%s_", $name, @{$b}[2]);
+    if (@{$b} == 3) {
+      printf(INC "#define %-40s 0x%08x /* %2s */\n",
+            $nm."MASK", 1 << @{$b}[0], @{$b}[1]);
+      printf(INC "#define %-40s %u\n",
+            $nm."POSN", @{$b}[0]);
+    } elsif (@{$b} == 4) {
+      my $mm = ((1 << (@{$b}[3] + 1)) - 1) & ~ ((1 << @{$b}[0]) - 1);
+      printf(INC "#define %-40s 0x%08x /* %2s */\n",
+            $nm."MASK", $mm, @{$b}[1]);
+      printf(INC "#define %-40s %u\n",
+            $nm."LSB_POSN", @{$b}[0]);
+      printf(INC "#define %-40s %u\n",
+            $nm."MSB_POSN", @{$b}[3]);
+    }
+  }
+
+  my $i = 0;
+  for my $b (@list) {
+    next if (@{$b}[1] eq "R");
+    $i++;
+  }
+  return if ($i == 0);
+
+  printf(INC "#define %s(", $name);
+  $i = 0;
+  for my $b (@list) {
+    next if (@{$b}[1] eq "R");
+    my $p = lc(sprintf("%s", @{$b}[2]));
+    printf(INC "%s%s", ($i == 0) ? "" : ", ", $p);
+    $i++;
+  }
+  printf(INC ") \\\n    (");
+  $i = 0;
+  for my $b (@list) {
+    next if (@{$b}[1] eq "R");
+    my $p = lc(sprintf("%s", @{$b}[2]));
+    my $nm = sprintf("%s_%s_", $name, @{$b}[2]);
+    printf(INC " | \\\n     ") if ($i != 0);
+    if (@{$b} == 3) {
+      printf(INC "((%s) ? %sMASK : 0)", $p, $nm);
+    } else {
+      printf(INC "(((%s) << %sLSB_POSN) \\\n         & %sMASK)", $p, $nm, $nm);
+    }
+    $i++;
+  }
+  printf(INC ")\n");
+}
+
+sub print_bits_v($@)
+{
+  my ($name, @list) = @_;
+
+  for my $b (@list) {
+    my $nm = sprintf("%s_%s_", $name, @{$b}[2]);
+    if (@{$b} == 3) {
+      printf(INC "parameter %-40s = 32'h%08x;\n",
+            $nm."MASK", 1 << @{$b}[0]);
+      printf(INC "parameter %-40s = 5'd%u;\n", $nm."POSN", @{$b}[0]);
+    } elsif (@{$b} == 4) {
+      my $mm = ((1 << (@{$b}[3] + 1)) - 1) & ~ ((1 << @{$b}[0]) - 1);
+      printf(INC "parameter %-40s = 32'h%08x;\n", $nm."MASK", $mm);
+      printf(INC "parameter %-40s = 5'd%u;\n", $nm."LSB_POSN", @{$b}[0]);
+      printf(INC "parameter %-40s = 5'd%u;\n", $nm."MSB_POSN", @{$b}[3]);
+    }
+  }
+}
+
+sub comment($)
+{
+  my ($text) = @_;
+
+  return unless defined $text;
+  return if $text eq "";
+
+  if ($output_type eq "c") {
+    if ($text =~ /\n.*\n/) {
+      printf(INC "/*\n * %s\n */\n",
+            join("\n * ",
+                 split('\n', $text)));
+    } else {
+      chomp($text);
+      printf(INC "/* %s */\n", $text);
+    }
+  } elsif ($output_type eq "v") {
+    if ($text =~ /\n.*\n/) {
+      printf(INC "// %s\n//\n",
+            join("\n// ",
+                 split('\n', $text)));
+    } else {
+      chomp($text);
+      printf(INC "// %s\n", $text);
+    }
+  } elsif ($output_type eq "x") {
+    if ($text =~ /\n.*\n/) {
+      printf(INC ";; %s\n\n",
+            join("\n;; ",
+                 split('\n', $text)));
+    } else {
+      chomp($text);
+      printf(INC ";; %s\n", $text);
+    }
+  }
+}
+
+sub dump_regs_c($$$)
+{
+  my ($block, $copy, $base) = @_;
+
+  comment($blocks{$block}->{doc});
+
+  for my $t (sort { $blocks{$block}->{regs}{$a}->{addr} <=>
+                     $blocks{$block}->{regs}{$b}->{addr} }
+            keys %{$blocks{$block}->{regs}}) {
+    my $name = sprintf("%s_%s",
+                      $copy, $blocks{$block}->{regs}{$t}->{name});
+
+    comment($blocks{$block}->{regs}{$t}->{doc});
+
+    printf(INC "#define %-40s     0x%04X /* %2s */\n",
+          $name,
+          $blocks{$block}->{regs}{$t}->{addr} + $base,
+          $blocks{$block}->{regs}{$t}->{flags});
+  }
+}
+
+sub dump_regs_c2($$$)
+{
+  my ($block, $copy, $base) = @_;
+
+  for my $t (sort { $blocks{$block}->{regs}{$a}->{addr} <=>
+                     $blocks{$block}->{regs}{$b}->{addr} }
+            keys %{$blocks{$block}->{regs}}) {
+    my $name = sprintf("%s_%s",
+                      $copy, $blocks{$block}->{regs}{$t}->{name});
+
+    if (scalar @{$blocks{$block}->{regs}{$t}->{bits}}) {
+      printf(INC "\n/* Bits for register %s */\n", $name);
+
+      print_bits_c($blocks{$block}->{regs}{$t}->{name},
+                  @{$blocks{$block}->{regs}{$t}->{bits}});
+    }
+  }
+}
+
+sub dump_regs_asm($$$)
+{
+  my ($block, $copy, $base) = @_;
+
+  comment($blocks{$block}->{doc});
+
+  for my $t (sort { $blocks{$block}->{regs}{$a}->{addr} <=>
+                     $blocks{$block}->{regs}{$b}->{addr} }
+            keys %{$blocks{$block}->{regs}}) {
+    my $name = sprintf("%s_%s",
+                      $copy, $blocks{$block}->{regs}{$t}->{name});
+
+    comment($blocks{$block}->{regs}{$t}->{doc});
+
+    printf(INC "%-40s EQU     0x%04X ; %2s\n",
+          $name,
+          $blocks{$block}->{regs}{$t}->{addr} + $base,
+          $blocks{$block}->{regs}{$t}->{flags});
+  }
+}
+
+sub dump_regs_asm2($$$)
+{
+  my ($block, $copy, $base) = @_;
+
+  comment($blocks{$block}->{doc});
+
+  for my $t (sort { $blocks{$block}->{regs}{$a}->{addr} <=>
+                     $blocks{$block}->{regs}{$b}->{addr} }
+            keys %{$blocks{$block}->{regs}}) {
+    my $name = sprintf("%s_%s",
+                      $copy, $blocks{$block}->{regs}{$t}->{name});
+
+    comment($blocks{$block}->{regs}{$t}->{doc});
+
+    if (scalar @{$blocks{$block}->{regs}{$t}->{bits}}) {
+      printf(INC "; Bits for register %s\n", $name);
+
+      print_bits_asm($blocks{$block}->{regs}{$t}->{name},
+                    @{$blocks{$block}->{regs}{$t}->{bits}});
+    }
+  }
+}
+
+sub dump_regs_v
+{
+  my ($block, $copy, $base) = @_;
+
+  my $am = (1 << $blocks{$block}->{vwidth}) - 1;
+  my $hd = ($blocks{$block}->{vwidth} + 3) / 4;
+  my $sh = $blocks{$block}->{vshift};
+  $sh = 0 unless defined ($sh);
+
+  comment($blocks{$block}->{doc});
+
+  for my $t (sort { $blocks{$block}->{regs}{$a}->{addr} <=>
+                     $blocks{$block}->{regs}{$b}->{addr} }
+            keys %{$blocks{$block}->{regs}} )
+  {
+    my $name = sprintf("%s_%s",
+                      $block, $blocks{$block}->{regs}{$t}->{name});
+
+    comment($blocks{$block}->{regs}{$t}->{doc});
+
+    printf(INC "parameter %-40s = %d'h%0*x;\n",
+            $name, $blocks{$block}->{vwidth}, $hd,
+          (($blocks{$block}->{regs}{$t}->{addr} + $base) >> $sh) & $am);
+
+    print_bits_v($blocks{$block}->{regs}{$t}->{name},
+                @{$blocks{$block}->{regs}{$t}->{bits}});
+  }
+}
+
+sub get_addr($)
+{
+  my ($bl) = @_;
+
+  return $blocks{$bl}->{addr}
+    if (defined($blocks{$bl}->{addr}));
+
+  for my $c (@{$blocks{$bl}->{copies}}) {
+    return @{$c}[1];
+  }
+
+  return 0;
+}
+
+
+if ($output_type eq "c") {
+
+  my $fn = uc($output_filename);
+  $fn =~ s/\./_/;
+
+  printf(INC "\n#ifndef %s__\n#define %s__\n\n", $fn, $fn);
+
+  for my $t (keys %types) {
+    printf(INC "\n/* TYPE %s */\n\n", $t);
+    comment($types{$t}->{doc});
+    print_bits_c($t, @{$types{$t}->{bits}});
+  }
+
+  for my $bl (sort { get_addr($a) <=> get_addr($b) } keys %blocks) {
+    printf(INC "\n/* BLOCK %s */\n\n", $bl);
+
+    # For the C we dump one set of info per instance
+    for my $c (@{$blocks{$bl}->{copies}}) {
+      dump_regs_c($bl, @{$c}[0], @{$c}[1]);
+    }
+    if (defined($blocks{$bl}->{addr})) {
+      dump_regs_c($bl, $bl, $blocks{$bl}->{addr});
+    }
+    dump_regs_c2($bl, $bl, $blocks{$bl}->{addr});
+  }
+
+  printf(INC "\n#endif /* %s__ */\n\n", $fn);
+
+} elsif ($output_type eq "x") {
+
+  for my $t (keys %types) {
+    printf(INC "\n; TYPE %s\n\n", $t);
+    comment($types{$t}->{doc});
+    print_bits_asm($t, @{$types{$t}->{bits}});
+  }
+
+  for my $bl (sort { get_addr($a) <=> get_addr($b) } keys %blocks) {
+    printf(INC "\n; BLOCK %s\n\n", $bl);
+
+    # For the ASM we dump one set of info per instance
+    for my $c (@{$blocks{$bl}->{copies}}) {
+      dump_regs_asm($bl, @{$c}[0], @{$c}[1]);
+    }
+    if (defined($blocks{$bl}->{addr})) {
+      dump_regs_asm($bl, $bl, $blocks{$bl}->{addr});
+    }
+    dump_regs_asm2($bl, $bl, $blocks{$bl}->{addr});
+  }
+
+} elsif ($output_type eq "v") {
+
+  for my $t (keys %types) {
+    printf(INC "\n// TYPE %s\n\n", $t);
+    comment($types{$t}->{doc});
+    print_bits_v($t, @{$types{$t}->{bits}});
+  }
+
+  for my $bl (sort { get_addr($a) <=> get_addr($b) } keys %blocks) {
+    printf(INC "\n// BLOCK %s\n\n", $bl);
+
+    # Dump one set of info per block for VERILOG
+    dump_regs_v($bl, $bl, 0);
+  }
+
+} else {
+  error("Bad type \"$output_type\"");
+}
+
+exit(0);
+
+__END__
+
+=head1 NAME
+
+mk_registers.pl - Make register definitions
+
+=head1 SYNOPSIS
+
+  mk_registers.pl --help
+
+  mk_registers.pl [OPTIONS] input.txt
+
+=head2 Options
+
+=over 8
+
+=item --output <filename>
+
+Specify the output file name.
+
+=item --type <type_string>
+
+Specify the output file type.  <type_string> can be one of
+"c", "v", "x" or "html".
+
+"c" means that the output file will be a C header file.
+
+"v" means that the output file will be a verilog file.
+
+"x" means that the output file will be a .inc file suitable
+for the nasm assembler.
+
+"html" is not yet supported, but will eventually produce
+register documentation.
+
+=back
+
+=head1 DESCRIPTION
+
+This program is used to process a textual description of the registers
+used within the Open Graphics Hardware.  From this textual descritpion
+it will produce C include files, Assembler include files, verilog and
+HTML documentation..
+
+This is useful, because it means that there is one source of
+information about register from which all copies are made.
+
+=head1 BUGS
+
+Maybe?
Index: Makefile
===================================================================
--- Makefile    (revision 0)
+++ Makefile    (revision 0)
@@ -0,0 +1,17 @@
+
+all:: ogd_reg_defines.inc ogd_regs.v ogd_reg_defines.h
+
+ogd_reg_defines.inc: registers.txt
+       perl mk_registers.pl --output=$@ --type=x $<
+
+ogd_regs.v: registers.txt
+       perl mk_registers.pl --output=$@ --type=v $<
+
+ogd_reg_defines.h: registers.txt
+       perl mk_registers.pl --output=$@ --type=c $<
+
+
+ogd_reg_defines.inc ogd_regs.v ogd_reg_defines.h: mk_registers.pl
+
+clean:
+       rm -f ogd_reg_defines.inc ogd_regs.v ogd_reg_defines.h
// These are all on the XP10?

parameter PCI_TARGET_CFG   = 0;
parameter PCI_TARGET_ENG   = 1;
parameter PCI_TARGET_MEM   = 2;
parameter PCI_TARGET_VMEM  = 3;
parameter PCI_TARGET_IO    = 4;
parameter PCI_TARGET_PROM  = 5;

parameter PCI_TARGET_MAX   = 5;


// Bridge Targets
//
// The bridge target is passed as a one-hot encoding on the 4-bit
// 'flags' bus when the 'ADDR' command is active.
parameter BR_TARGET_ENG  = 2'd0;
parameter BR_TARGET_MEM  = 2'd1;


// Bridge Commands
//
parameter BR_CMD_IDLE   = 2'd0;
parameter BR_CMD_ADDR   = 2'd1;
parameter BR_CMD_RCOUNT = 2'd2;
parameter BR_CMD_WRITE  = 2'd3;
_______________________________________________
Open-graphics mailing list
[email protected]
http://lists.duskglow.com/mailman/listinfo/open-graphics
List service provided by Duskglow Consulting, LLC (www.duskglow.com)

Reply via email to