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)