Simplify handling of SW accessible registers in FPGA

Guest
Save lots of work
- Auto-generate register related code and documentation, and
- Keep SW, FPGA and Documentation synchronized
Register Wizard is now free :)

Register Wizard is now released as a freeware to generate 'C' code, VHDL code and documentation from a single register definition file.
This allows a major efficiency boost for developing systems with software accessible registers, - and equally important - a simple way of keeping your Software, FPGA and Documentation synchronized.

The register definition file is written as normal text in the JSON file format. From this file you can automatically generate the following:

- 'C' header file for all registers and their addresses
- VHDL package for all registers and their addresses
- Full VHDL simple processor interface for register access
(May easily be wrapped to Avalon or AXI4-lite)
- Self-checking VHDL testbench for the processor interface
(Using UVVM Utility Library)
- Documentation in the form of a register map and register description
in the Office Open XML format for simple inclusion in MS Word.

This also means that specification changes are handled in a very structured manner - just by extending or modifying the register definition file and re-generating all the above.

The tool and usage is of course properly documented - including a tutorial and example, - and may be downloaded from our web-site: http://bitvis.no/products/register_wizard/

Enjoy :)
And please send us feedback on potential improvements for your applications.
 
rickman wrote:

On 3/9/2016 5:01 AM, espen.tallaksen@bitvis.no wrote:
Save lots of work
- Auto-generate register related code and documentation, and
- Keep SW, FPGA and Documentation synchronized
Register Wizard is now free :)

Register Wizard is now released as a freeware to generate 'C' code, VHDL code and documentation from a single register definition file.
This allows a major efficiency boost for developing systems with software accessible registers, - and equally important - a simple way of keeping your Software, FPGA and Documentation synchronized.

The register definition file is written as normal text in the JSON file format. From this file you can automatically generate the following:

- 'C' header file for all registers and their addresses
- VHDL package for all registers and their addresses
- Full VHDL simple processor interface for register access
(May easily be wrapped to Avalon or AXI4-lite)
- Self-checking VHDL testbench for the processor interface
(Using UVVM Utility Library)
- Documentation in the form of a register map and register description
in the Office Open XML format for simple inclusion in MS Word.

This also means that specification changes are handled in a very structured manner - just by extending or modifying the register definition file and re-generating all the above.

The tool and usage is of course properly documented - including a tutorial and example, - and may be downloaded from our web-site: http://bitvis.no/products/register_wizard/

Enjoy :)
And please send us feedback on potential improvements for your applications.

I'm a bit unclear on this. What is the assumption on how the registers
are created in the VHDL code. Is this a block RAM or discrete registers
in the fabric? I can see providing a C header file for a memory mapped
register bank, but how can you define the registers in the VHDL if you
don't know how they need to be implemented?

Haven't actually looked at what the bitvis thing is up to, but I've
implemented a similar system here (though I'm less than thrilled with
the way it all came together).

In mine, each register gets its own record type associated with it,
made up of unsigned/signed/std_logic/std_logic_vector based on the
register definition file, and there are conversion functions for
translating records to/from the data bus std_logic_vector, all of which
goes into a package that I import into the module that actually does the
work.

So that gives you automation of defining registers. I never
got around to the next logical step, auto-generating the code that
defines the "register file" as a record of all the subrecords,
and handles the bus transactions against that record in some kind of
DoBusTransaction(regfile) call. It would be straightforward to do
if cumbersome.

It's still up to the designer to actually make those registers do
things, but lots of things follow some very basic patterns. Read-only
status registers are always updated before DoBusTransaction. Write-only
registers get their values used and then blanked after
DoBusTransaction. And so on. There's still plenty on the designer's
plate, but a ton of the crappy boilerplate can be automated, while
generating C headers and pretty documentation along the way.

--
Rob Gaddi, Highland Technology -- www.highlandtechnology.com
Email address domain is currently out of order. See above to fix.
 
rickman wrote:

On 3/9/2016 12:36 PM, Rob Gaddi wrote:
rickman wrote:

I'm a bit unclear on this. What is the assumption on how the registers
are created in the VHDL code. Is this a block RAM or discrete registers
in the fabric? I can see providing a C header file for a memory mapped
register bank, but how can you define the registers in the VHDL if you
don't know how they need to be implemented?


Haven't actually looked at what the bitvis thing is up to, but I've
implemented a similar system here (though I'm less than thrilled with
the way it all came together).

In mine, each register gets its own record type associated with it,
made up of unsigned/signed/std_logic/std_logic_vector based on the
register definition file, and there are conversion functions for
translating records to/from the data bus std_logic_vector, all of which
goes into a package that I import into the module that actually does the
work.

I'm not clear on what you are describing here. Sounds like you are
substituting an HDL definition of a register with a configuration file
definition of a register.

Exactly. I (hand)write an XML file defining all the registers in a
peripheral, then I cook it down and get a VHDL package with definitions
such as:

constant BUSSTATE_ADDR : t_addr := 16#026#;

type t_BUSSTATE is record
IACKIN : std_logic;
IRQ : std_logic_vector(6 downto 0);
DTACK : std_logic;
BERR : std_logic;
RETRY : std_logic;
end record t_BUSSTATE;

pure function BUSSTATE_TO_WORD(dat : t_BUSSTATE) return t_word is
variable ret : t_word;
begin
ret := (others => '0');
ret(0) := dat.IACKIN;
ret(7 downto 1) := std_logic_vector(dat.IRQ);
ret(8) := dat.DTACK;
ret(9) := dat.BERR;
ret(10) := dat.RETRY;
return ret;
end function BUSSTATE_TO_WORD;

pure function WORD_TO_BUSSTATE(dat : t_word) return t_BUSSTATE is
variable ret : t_BUSSTATE;
begin
ret.IACKIN := dat(0);
ret.IRQ := std_logic_vector(dat(7 downto 1));
ret.DTACK := dat(8);
ret.BERR := dat(9);
ret.RETRY := dat(10);
return ret;
end function WORD_TO_BUSSTATE;

procedure UPDATE_BUSSTATE(reg : inout t_BUSSTATE; nd : in t_word; be : in t_be) is
variable tmp : t_word;
begin
tmp := BUSSTATE_TO_WORD(reg);
for i in be'range loop
if (be(i) = '1') then
tmp(i*8 + 7 downto i*8) := nd(i*8+7 downto i*8);
end if;
end loop;
reg := WORD_TO_BUSSTATE(tmp);
end procedure UPDATE_BUSSTATE;

The generated VHDL file I sliced those out of is, as an example, 2500
lines long. Those translation functions are responsible for making sure
that everyone agrees which bit of the word represents BERR.

It also cogenerates a C header file with a struct that puts uint32_t
BUSSTATE (and all the other registers in the peripheral) at the correct
location, and contains

/******************************************************************************
* BUSSTATE Field Descriptions
*****************************************************************************/

/* CTLREG_BUSSTATE_RETRY - The current state of the (active-low) RETRY
* line.
*/

#define CTLREG_BUSSTATE_RETRY_LSB (10)
#define CTLREG_BUSSTATE_RETRY (0x00000400u)

/* CTLREG_BUSSTATE_BERR - The current state of the (active-low) BERR line.
*/

#define CTLREG_BUSSTATE_BERR_LSB (9)
#define CTLREG_BUSSTATE_BERR (0x00000200u)

/* CTLREG_BUSSTATE_DTACK - The current state of the (active-low) DTACK
* line.
*/

#define CTLREG_BUSSTATE_DTACK_LSB (8)
#define CTLREG_BUSSTATE_DTACK (0x00000100u)

/* CTLREG_BUSSTATE_IRQ - The current state of the (active-low) IRQ lines 7
* through 1.
*/

#define CTLREG_BUSSTATE_IRQ_LSB (1)
#define CTLREG_BUSSTATE_IRQ_MASK (0x000000FEu)
#define CTLREG_BUSSTATE_IRQ(x) ((x) << CTLREG_BUSSTATE_IRQ_LSB)

/* CTLREG_BUSSTATE_IACKIN - The current state of the (active-low) IACKIN
* line.
*/

#define CTLREG_BUSSTATE_IACKIN_LSB (0)
#define CTLREG_BUSSTATE_IACKIN (0x00000001u)

It also writes out HTML documentation where the bitfields of a BUSSTATE
are shown as a 4 row table (1,3 are bit numbers, 2,4 are fields)
followed by a bulleted list with the descriptive text.

And the most important part is that every time I type "make", I am
guaranteed that the VHDL, C, and HTML are all in sync. I still need to
go around synchronizing all of the logic, but since cutting over to this
system I have NEVER got the wrong bit in the wrong place. Because
that's a stupid mistake in copying data redundantly, which is exactly
the sort of thing computers are better at than we are.

--
Rob Gaddi, Highland Technology -- www.highlandtechnology.com
Email address domain is currently out of order. See above to fix.
 
rickman wrote:

On 3/9/2016 1:43 PM, Rob Gaddi wrote:
rickman wrote:

On 3/9/2016 12:36 PM, Rob Gaddi wrote:
rickman wrote:

I'm a bit unclear on this. What is the assumption on how the registers
are created in the VHDL code. Is this a block RAM or discrete registers
in the fabric? I can see providing a C header file for a memory mapped
register bank, but how can you define the registers in the VHDL if you
don't know how they need to be implemented?


Haven't actually looked at what the bitvis thing is up to, but I've
implemented a similar system here (though I'm less than thrilled with
the way it all came together).

In mine, each register gets its own record type associated with it,
made up of unsigned/signed/std_logic/std_logic_vector based on the
register definition file, and there are conversion functions for
translating records to/from the data bus std_logic_vector, all of which
goes into a package that I import into the module that actually does the
work.

I'm not clear on what you are describing here. Sounds like you are
substituting an HDL definition of a register with a configuration file
definition of a register.


Exactly. I (hand)write an XML file defining all the registers in a
peripheral, then I cook it down and get a VHDL package with definitions
such as:

constant BUSSTATE_ADDR : t_addr := 16#026#;

type t_BUSSTATE is record
IACKIN : std_logic;
IRQ : std_logic_vector(6 downto 0);
DTACK : std_logic;
BERR : std_logic;
RETRY : std_logic;
end record t_BUSSTATE;

pure function BUSSTATE_TO_WORD(dat : t_BUSSTATE) return t_word is
variable ret : t_word;
begin
ret := (others => '0');
ret(0) := dat.IACKIN;
ret(7 downto 1) := std_logic_vector(dat.IRQ);
ret(8) := dat.DTACK;
ret(9) := dat.BERR;
ret(10) := dat.RETRY;
return ret;
end function BUSSTATE_TO_WORD;

pure function WORD_TO_BUSSTATE(dat : t_word) return t_BUSSTATE is
variable ret : t_BUSSTATE;
begin
ret.IACKIN := dat(0);
ret.IRQ := std_logic_vector(dat(7 downto 1));
ret.DTACK := dat(8);
ret.BERR := dat(9);
ret.RETRY := dat(10);
return ret;
end function WORD_TO_BUSSTATE;

procedure UPDATE_BUSSTATE(reg : inout t_BUSSTATE; nd : in t_word; be : in t_be) is
variable tmp : t_word;
begin
tmp := BUSSTATE_TO_WORD(reg);
for i in be'range loop
if (be(i) = '1') then
tmp(i*8 + 7 downto i*8) := nd(i*8+7 downto i*8);
end if;
end loop;
reg := WORD_TO_BUSSTATE(tmp);
end procedure UPDATE_BUSSTATE;

The generated VHDL file I sliced those out of is, as an example, 2500
lines long. Those translation functions are responsible for making sure
that everyone agrees which bit of the word represents BERR.

It also cogenerates a C header file with a struct that puts uint32_t
BUSSTATE (and all the other registers in the peripheral) at the correct
location, and contains

/******************************************************************************
* BUSSTATE Field Descriptions
*****************************************************************************/

/* CTLREG_BUSSTATE_RETRY - The current state of the (active-low) RETRY
* line.
*/

#define CTLREG_BUSSTATE_RETRY_LSB (10)
#define CTLREG_BUSSTATE_RETRY (0x00000400u)

/* CTLREG_BUSSTATE_BERR - The current state of the (active-low) BERR line.
*/

#define CTLREG_BUSSTATE_BERR_LSB (9)
#define CTLREG_BUSSTATE_BERR (0x00000200u)

/* CTLREG_BUSSTATE_DTACK - The current state of the (active-low) DTACK
* line.
*/

#define CTLREG_BUSSTATE_DTACK_LSB (8)
#define CTLREG_BUSSTATE_DTACK (0x00000100u)

/* CTLREG_BUSSTATE_IRQ - The current state of the (active-low) IRQ lines 7
* through 1.
*/

#define CTLREG_BUSSTATE_IRQ_LSB (1)
#define CTLREG_BUSSTATE_IRQ_MASK (0x000000FEu)
#define CTLREG_BUSSTATE_IRQ(x) ((x) << CTLREG_BUSSTATE_IRQ_LSB)

/* CTLREG_BUSSTATE_IACKIN - The current state of the (active-low) IACKIN
* line.
*/

#define CTLREG_BUSSTATE_IACKIN_LSB (0)
#define CTLREG_BUSSTATE_IACKIN (0x00000001u)

It also writes out HTML documentation where the bitfields of a BUSSTATE
are shown as a 4 row table (1,3 are bit numbers, 2,4 are fields)
followed by a bulleted list with the descriptive text.

And the most important part is that every time I type "make", I am
guaranteed that the VHDL, C, and HTML are all in sync. I still need to
go around synchronizing all of the logic, but since cutting over to this
system I have NEVER got the wrong bit in the wrong place. Because
that's a stupid mistake in copying data redundantly, which is exactly
the sort of thing computers are better at than we are.

Good idea. One change I think I would make would be to hand write the C
file and derive the rest of the code from that. If any additional info
is needed for the VHDL that isn't needed in the C header file it can
easily be incorporated in C comments and parsed out by the conversion
program. I just prefer not to have yet enough source file.

Thought about making C, VHDL, or HTML the source format rather than XML.
Either of the first two can be really ugly to parse, and HTML was even
uglier to write than my XML format. Certainly any of those formats have
to chock-full of redudant information to be useful.
CTLREG_BUSSTATE_IRQ_LSB, CTLREG_BUSSTATE_IRQ_MASK,
CTLREG_BUSSTATE_IRQ(x) as an example, to say nothing of the enumerated
fields.

The idea was to optimize for parseability and just generate from there,
since good XML editors are a dime a dozen. That way the processing code
can also be responsible for things like automatically doling out
addresses, etc.

The reality became that, no, good XML editors are in fact NOT a dime a
dozen and I wound up having to always write the XML by hand in a text
editor. Between projects I inevitably forget what my tag names and
attributes were and have to go relearn them from whatever the last
project was, which is a nuisance. And XML turns out to be less elegant
than one might want; in offering 5 ways to do anything you wind up
spending far too much time trying to figure out the "best" way.

So it works well enough that I keep using it and can't justify time
spent improving it, but requires enough smacking of the TV set that I
haven't really made any kind of open-source project from it.

--
Rob Gaddi, Highland Technology -- www.highlandtechnology.com
Email address domain is currently out of order. See above to fix.
 
Allan Herriman wrote:

On Wed, 09 Mar 2016 18:43:55 +0000, Rob Gaddi wrote:

[snip]

It also cogenerates a C header file with a struct that puts uint32_t
BUSSTATE (and all the other registers in the peripheral) at the correct
location, and contains

Here we use a C typedef to create a "reg32_t" type, which is just like
uint32_t but with an added volatile qualifier.

Then we just define all registers as "reg32_t" and banish a whole class
of hard to find bugs.

Of course, (in keeping with the C spirit) one can make the bugs come back
by calling functions which expect arguments to be pointers to uint32_t.

Regards,
Allan

I have my struct CTLREGS full of uint32_ts, and then wind up with a
volatile struct CTLREGS *. That way I can make local copies of the
structure that aren't flagged as volatile, work with them, and copy them
back en masse; a capability that I've so far used zero times.

--
Rob Gaddi, Highland Technology -- www.highlandtechnology.com
Email address domain is currently out of order. See above to fix.
 
On 3/9/2016 5:01 AM, espen.tallaksen@bitvis.no wrote:
Save lots of work
- Auto-generate register related code and documentation, and
- Keep SW, FPGA and Documentation synchronized
Register Wizard is now free :)

Register Wizard is now released as a freeware to generate 'C' code, VHDL code and documentation from a single register definition file.
This allows a major efficiency boost for developing systems with software accessible registers, - and equally important - a simple way of keeping your Software, FPGA and Documentation synchronized.

The register definition file is written as normal text in the JSON file format. From this file you can automatically generate the following:

- 'C' header file for all registers and their addresses
- VHDL package for all registers and their addresses
- Full VHDL simple processor interface for register access
(May easily be wrapped to Avalon or AXI4-lite)
- Self-checking VHDL testbench for the processor interface
(Using UVVM Utility Library)
- Documentation in the form of a register map and register description
in the Office Open XML format for simple inclusion in MS Word.

This also means that specification changes are handled in a very structured manner - just by extending or modifying the register definition file and re-generating all the above.

The tool and usage is of course properly documented - including a tutorial and example, - and may be downloaded from our web-site: http://bitvis.no/products/register_wizard/

Enjoy :)
And please send us feedback on potential improvements for your applications.

I'm a bit unclear on this. What is the assumption on how the registers
are created in the VHDL code. Is this a block RAM or discrete registers
in the fabric? I can see providing a C header file for a memory mapped
register bank, but how can you define the registers in the VHDL if you
don't know how they need to be implemented?

--

Rick
 
On 3/9/2016 12:36 PM, Rob Gaddi wrote:
rickman wrote:

On 3/9/2016 5:01 AM, espen.tallaksen@bitvis.no wrote:
Save lots of work
- Auto-generate register related code and documentation, and
- Keep SW, FPGA and Documentation synchronized
Register Wizard is now free :)

Register Wizard is now released as a freeware to generate 'C' code, VHDL code and documentation from a single register definition file.
This allows a major efficiency boost for developing systems with software accessible registers, - and equally important - a simple way of keeping your Software, FPGA and Documentation synchronized.

The register definition file is written as normal text in the JSON file format. From this file you can automatically generate the following:

- 'C' header file for all registers and their addresses
- VHDL package for all registers and their addresses
- Full VHDL simple processor interface for register access
(May easily be wrapped to Avalon or AXI4-lite)
- Self-checking VHDL testbench for the processor interface
(Using UVVM Utility Library)
- Documentation in the form of a register map and register description
in the Office Open XML format for simple inclusion in MS Word.

This also means that specification changes are handled in a very structured manner - just by extending or modifying the register definition file and re-generating all the above.

The tool and usage is of course properly documented - including a tutorial and example, - and may be downloaded from our web-site: http://bitvis.no/products/register_wizard/

Enjoy :)
And please send us feedback on potential improvements for your applications.

I'm a bit unclear on this. What is the assumption on how the registers
are created in the VHDL code. Is this a block RAM or discrete registers
in the fabric? I can see providing a C header file for a memory mapped
register bank, but how can you define the registers in the VHDL if you
don't know how they need to be implemented?


Haven't actually looked at what the bitvis thing is up to, but I've
implemented a similar system here (though I'm less than thrilled with
the way it all came together).

In mine, each register gets its own record type associated with it,
made up of unsigned/signed/std_logic/std_logic_vector based on the
register definition file, and there are conversion functions for
translating records to/from the data bus std_logic_vector, all of which
goes into a package that I import into the module that actually does the
work.

I'm not clear on what you are describing here. Sounds like you are
substituting an HDL definition of a register with a configuration file
definition of a register.


So that gives you automation of defining registers. I never
got around to the next logical step, auto-generating the code that
defines the "register file" as a record of all the subrecords,
and handles the bus transactions against that record in some kind of
DoBusTransaction(regfile) call. It would be straightforward to do
if cumbersome.

Are you talking about the CPU's view of the register file? I'm not
clear on what you mean my "defining registers". They have to be defined
in HDL both for the CPU and for the hardware as well as for the CPU code.


It's still up to the designer to actually make those registers do
things, but lots of things follow some very basic patterns. Read-only
status registers are always updated before DoBusTransaction. Write-only
registers get their values used and then blanked after
DoBusTransaction. And so on. There's still plenty on the designer's
plate, but a ton of the crappy boilerplate can be automated, while
generating C headers and pretty documentation along the way.

Which boiler plate is being automated, the register signal declarations?

--

Rick
 
On 3/9/2016 1:43 PM, Rob Gaddi wrote:
rickman wrote:

On 3/9/2016 12:36 PM, Rob Gaddi wrote:
rickman wrote:

I'm a bit unclear on this. What is the assumption on how the registers
are created in the VHDL code. Is this a block RAM or discrete registers
in the fabric? I can see providing a C header file for a memory mapped
register bank, but how can you define the registers in the VHDL if you
don't know how they need to be implemented?


Haven't actually looked at what the bitvis thing is up to, but I've
implemented a similar system here (though I'm less than thrilled with
the way it all came together).

In mine, each register gets its own record type associated with it,
made up of unsigned/signed/std_logic/std_logic_vector based on the
register definition file, and there are conversion functions for
translating records to/from the data bus std_logic_vector, all of which
goes into a package that I import into the module that actually does the
work.

I'm not clear on what you are describing here. Sounds like you are
substituting an HDL definition of a register with a configuration file
definition of a register.


Exactly. I (hand)write an XML file defining all the registers in a
peripheral, then I cook it down and get a VHDL package with definitions
such as:

constant BUSSTATE_ADDR : t_addr := 16#026#;

type t_BUSSTATE is record
IACKIN : std_logic;
IRQ : std_logic_vector(6 downto 0);
DTACK : std_logic;
BERR : std_logic;
RETRY : std_logic;
end record t_BUSSTATE;

pure function BUSSTATE_TO_WORD(dat : t_BUSSTATE) return t_word is
variable ret : t_word;
begin
ret := (others => '0');
ret(0) := dat.IACKIN;
ret(7 downto 1) := std_logic_vector(dat.IRQ);
ret(8) := dat.DTACK;
ret(9) := dat.BERR;
ret(10) := dat.RETRY;
return ret;
end function BUSSTATE_TO_WORD;

pure function WORD_TO_BUSSTATE(dat : t_word) return t_BUSSTATE is
variable ret : t_BUSSTATE;
begin
ret.IACKIN := dat(0);
ret.IRQ := std_logic_vector(dat(7 downto 1));
ret.DTACK := dat(8);
ret.BERR := dat(9);
ret.RETRY := dat(10);
return ret;
end function WORD_TO_BUSSTATE;

procedure UPDATE_BUSSTATE(reg : inout t_BUSSTATE; nd : in t_word; be : in t_be) is
variable tmp : t_word;
begin
tmp := BUSSTATE_TO_WORD(reg);
for i in be'range loop
if (be(i) = '1') then
tmp(i*8 + 7 downto i*8) := nd(i*8+7 downto i*8);
end if;
end loop;
reg := WORD_TO_BUSSTATE(tmp);
end procedure UPDATE_BUSSTATE;

The generated VHDL file I sliced those out of is, as an example, 2500
lines long. Those translation functions are responsible for making sure
that everyone agrees which bit of the word represents BERR.

It also cogenerates a C header file with a struct that puts uint32_t
BUSSTATE (and all the other registers in the peripheral) at the correct
location, and contains

/******************************************************************************
* BUSSTATE Field Descriptions
*****************************************************************************/

/* CTLREG_BUSSTATE_RETRY - The current state of the (active-low) RETRY
* line.
*/

#define CTLREG_BUSSTATE_RETRY_LSB (10)
#define CTLREG_BUSSTATE_RETRY (0x00000400u)

/* CTLREG_BUSSTATE_BERR - The current state of the (active-low) BERR line.
*/

#define CTLREG_BUSSTATE_BERR_LSB (9)
#define CTLREG_BUSSTATE_BERR (0x00000200u)

/* CTLREG_BUSSTATE_DTACK - The current state of the (active-low) DTACK
* line.
*/

#define CTLREG_BUSSTATE_DTACK_LSB (8)
#define CTLREG_BUSSTATE_DTACK (0x00000100u)

/* CTLREG_BUSSTATE_IRQ - The current state of the (active-low) IRQ lines 7
* through 1.
*/

#define CTLREG_BUSSTATE_IRQ_LSB (1)
#define CTLREG_BUSSTATE_IRQ_MASK (0x000000FEu)
#define CTLREG_BUSSTATE_IRQ(x) ((x) << CTLREG_BUSSTATE_IRQ_LSB)

/* CTLREG_BUSSTATE_IACKIN - The current state of the (active-low) IACKIN
* line.
*/

#define CTLREG_BUSSTATE_IACKIN_LSB (0)
#define CTLREG_BUSSTATE_IACKIN (0x00000001u)

It also writes out HTML documentation where the bitfields of a BUSSTATE
are shown as a 4 row table (1,3 are bit numbers, 2,4 are fields)
followed by a bulleted list with the descriptive text.

And the most important part is that every time I type "make", I am
guaranteed that the VHDL, C, and HTML are all in sync. I still need to
go around synchronizing all of the logic, but since cutting over to this
system I have NEVER got the wrong bit in the wrong place. Because
that's a stupid mistake in copying data redundantly, which is exactly
the sort of thing computers are better at than we are.

Good idea. One change I think I would make would be to hand write the C
file and derive the rest of the code from that. If any additional info
is needed for the VHDL that isn't needed in the C header file it can
easily be incorporated in C comments and parsed out by the conversion
program. I just prefer not to have yet enough source file.

--

Rick
 
On Wednesday, March 9, 2016 at 12:39:25 PM UTC-5, Rob Gaddi wrote:
rickman wrote:

On 3/9/2016 5:01 AM, espen.tallaksen@bitvis.no wrote:
Save lots of work
- Auto-generate register related code and documentation, and
- Keep SW, FPGA and Documentation synchronized
Register Wizard is now free :)

Register Wizard is now released as a freeware to generate 'C' code, VHDL code and documentation from a single register definition file.
This allows a major efficiency boost for developing systems with software accessible registers, - and equally important - a simple way of keeping your Software, FPGA and Documentation synchronized.

The register definition file is written as normal text in the JSON file format. From this file you can automatically generate the following:

- 'C' header file for all registers and their addresses
- VHDL package for all registers and their addresses
- Full VHDL simple processor interface for register access
(May easily be wrapped to Avalon or AXI4-lite)
- Self-checking VHDL testbench for the processor interface
(Using UVVM Utility Library)
- Documentation in the form of a register map and register description
in the Office Open XML format for simple inclusion in MS Word.

This also means that specification changes are handled in a very structured manner - just by extending or modifying the register definition file and re-generating all the above.

The tool and usage is of course properly documented - including a tutorial and example, - and may be downloaded from our web-site: http://bitvis.no/products/register_wizard/

Enjoy :)
And please send us feedback on potential improvements for your applications.

I'm a bit unclear on this. What is the assumption on how the registers
are created in the VHDL code. Is this a block RAM or discrete registers
in the fabric? I can see providing a C header file for a memory mapped
register bank, but how can you define the registers in the VHDL if you
don't know how they need to be implemented?


Haven't actually looked at what the bitvis thing is up to, but I've
implemented a similar system here (though I'm less than thrilled with
the way it all came together).

In mine, each register gets its own record type associated with it,
made up of unsigned/signed/std_logic/std_logic_vector based on the
register definition file, and there are conversion functions for
translating records to/from the data bus std_logic_vector, all of which
goes into a package that I import into the module that actually does the
work.

So that gives you automation of defining registers. I never
got around to the next logical step, auto-generating the code that
defines the "register file" as a record of all the subrecords,
and handles the bus transactions against that record in some kind of
DoBusTransaction(regfile) call. It would be straightforward to do
if cumbersome.

It's still up to the designer to actually make those registers do
things, but lots of things follow some very basic patterns. Read-only
status registers are always updated before DoBusTransaction. Write-only
registers get their values used and then blanked after
DoBusTransaction. And so on. There's still plenty on the designer's
plate, but a ton of the crappy boilerplate can be automated, while
generating C headers and pretty documentation along the way.

--
Rob Gaddi, Highland Technology -- www.highlandtechnology.com
Email address domain is currently out of order. See above to fix.

There is also a standard IEEE 1685-2009 which uses "IP-XACT" format for defining peripheral registers. Major EDA vendors have tools supporting the format and its extensions for code generation.
 
On Wed, 09 Mar 2016 18:43:55 +0000, Rob Gaddi wrote:

[snip]

It also cogenerates a C header file with a struct that puts uint32_t
BUSSTATE (and all the other registers in the peripheral) at the correct
location, and contains

Here we use a C typedef to create a "reg32_t" type, which is just like
uint32_t but with an added volatile qualifier.

Then we just define all registers as "reg32_t" and banish a whole class
of hard to find bugs.

Of course, (in keeping with the C spirit) one can make the bugs come back
by calling functions which expect arguments to be pointers to uint32_t.

Regards,
Allan
 
On 3/9/2016 2:40 PM, Rob Gaddi wrote:
rickman wrote:

Good idea. One change I think I would make would be to hand write the C
file and derive the rest of the code from that. If any additional info
is needed for the VHDL that isn't needed in the C header file it can
easily be incorporated in C comments and parsed out by the conversion
program. I just prefer not to have yet enough source file.


Thought about making C, VHDL, or HTML the source format rather than XML.
Either of the first two can be really ugly to parse, and HTML was even
uglier to write than my XML format.

But it wouldn't have to be a full C parser, just any limited subset you
care to specify. In essence the idea is to write a "special" format
file that can be read by a C compiler for those purposes. But whatever,
each way has it's drawbacks and advantages.


Certainly any of those formats have
to chock-full of redudant information to be useful.
CTLREG_BUSSTATE_IRQ_LSB, CTLREG_BUSSTATE_IRQ_MASK,
CTLREG_BUSSTATE_IRQ(x) as an example, to say nothing of the enumerated
fields.

The idea was to optimize for parseability and just generate from there,
since good XML editors are a dime a dozen. That way the processing code
can also be responsible for things like automatically doling out
addresses, etc.

The reality became that, no, good XML editors are in fact NOT a dime a
dozen and I wound up having to always write the XML by hand in a text
editor. Between projects I inevitably forget what my tag names and
attributes were and have to go relearn them from whatever the last
project was, which is a nuisance. And XML turns out to be less elegant
than one might want; in offering 5 ways to do anything you wind up
spending far too much time trying to figure out the "best" way.

So it works well enough that I keep using it and can't justify time
spent improving it, but requires enough smacking of the TV set that I
haven't really made any kind of open-source project from it.

Lol, I like that image, smacking the TV. Yeah, there are lots of ideas
that sound good until you implement them.

--

Rick
 
I'm a bit unclear on this. What is the assumption on how the registers
are created in the VHDL code. Is this a block RAM or discrete registers
in the fabric? I can see providing a C header file for a memory mapped
register bank, but how can you define the registers in the VHDL if you
don't know how they need to be implemented?

The registers are discrete. Registers that are not manipulated by the core functionality (e.g. IER in the provided example) are generated as a part of the autogenerated processor/register interface (PIF) sub-module. Registers that are manipulated by the core functionality (e.g. IRR) are located in the core sub-module. For these registers you pass control from PIF to core and register contents from core to PIF. Everything inside PIF - including the bus interface is auto-generated. We did it this way to allow full flexibility and reduced probability of "assumption-bugs". Hence any register type is possible.

-Espen
 
I see from the discussion above that we should also show the result-files from Register Wizard in the provided download. The result-files are described in the current documentation, but the actual files are not shown. I think everything will be clearer, and hopefully your questions will be answered when we include the result files from the documented example. Most probably we will provide this as a separate zip-file ASAP.
 
> There is also a standard IEEE 1685-2009 which uses "IP-XACT" format for defining peripheral registers. Major EDA vendors have tools supporting the format and its extensions for code generation.

IP-XACT is probably very good for data exchange between different tools, but it is not very good as a human-readable format. We made our own format to significantly increase readability for designers. We evaluated XML, but concluded JSON was better.
 
> I see from the discussion above that we should also show the result-files from Register Wizard in the provided download. The result-files are described in the current documentation, but the actual files are not shown. I think everything will be clearer, and hopefully your questions will be answered when we include the result files from the documented example. Most probably we will provide this as a separate zip-file ASAP.

A zip-file showing the generated outputs is now provided for download under http://bitvis.no/products/register_wizard/
 
On Wednesday, March 9, 2016 at 12:39:25 PM UTC-5, Rob Gaddi wrote:
In mine, each register gets its own record type associated with it,
made up of unsigned/signed/std_logic/std_logic_vector based on the
register definition file, and there are conversion functions for
translating records to/from the data bus std_logic_vector, all of which
goes into a package that I import into the module that actually does the
work.

I do the same but I put the actual bit definitions into the record like this...
type t_INPUT_DMA_CONTROL_PORT is record
Start: std_ulogic_vector(31 downto 31);
Reserved: std_ulogic_vector(30 downto 26);
Max_Count: std_ulogic_vector(25 downto 0);
end record;

That way the 'to/from' std_ulogic_vector functions can be written without having to refer to bit locations, like this...
function To_Std_ULogic_Vector(L : t_INPUT_DMA_CONTROL_PORT) return std_ulogic_vector is
variable RetVal: std_ulogic_vector(31 downto 0);
begin
RetVal := (others => '0');
RetVal(L.Start'range) := L.Start;
RetVal(L.Reserved'range) := L.Reserved;
RetVal(L.Max_Count'range) := L.Max_Count;
return(RetVal);
end To_Std_ULogic_Vector;

function From_Std_ULogic_Vector(L : std_ulogic_vector) return t_INPUT_DMA_CONTROL_PORT is
variable RetVal: t_INPUT_DMA_CONTROL_PORT;
variable Lx: std_ulogic_vector(L'length - 1 downto 0);
begin
Lx := L;
RetVal.Start := Lx(RetVal.Start'range);
RetVal.Reserved := Lx(RetVal.Reserved'range);
RetVal.Max_Count := Lx(RetVal.Max_Count'range);
return(RetVal);
end From_Std_ULogic_Vector;

Given the record definition, it is a quick macro run to generate these to/from functions which is completed quickly. If only bit definitions change, then only the record needs to be modified and everything recompiled. If you add/subtract fields then the record and two functions need to be updated and everything recompiled. All in all, not much maintenance.

It's not trying to do as much as I think the OP is doing, but it does handle most of the work and most of the stuff that is error prone anyway.

So that gives you automation of defining registers. I never
got around to the next logical step, auto-generating the code that
defines the "register file" as a record of all the subrecords,
and handles the bus transactions against that record in some kind of
DoBusTransaction(regfile) call. It would be straightforward to do
if cumbersome.

I have, but actually I just use a spreadsheet for a lot of the work. Archive the spreadsheet along the source.
 
On 3/10/2016 10:13 AM, espen.tallaksen@bitvis.no wrote:
I see from the discussion above that we should also show the result-files from Register Wizard in the provided download. The result-files are described in the current documentation, but the actual files are not shown. I think everything will be clearer, and hopefully your questions will be answered when we include the result files from the documented example. Most probably we will provide this as a separate zip-file ASAP.

A zip-file showing the generated outputs is now provided for download under http://bitvis.no/products/register_wizard/

Some feedback. Your flyer is way too terse and I'm not inclined to
download a full user manual to learn the first things about a tool. You
might want to have a quick overview manual to give potential customers
an idea of the facilities of the tool without having to learn the whole
thing or wade through a full manual.

The files download is a good start. In addition to the outputs, I found
the input which doesn't look too hard to learn. But your example
includes no bit fields in the registers. Isn't that essential? I would
also include at least one example of logic that is added by the user to
be incorporated in one of the output files, the core file I assume.
Perhaps something simple like a bit that is cleared when read. Some
sort of overview description would be useful explaining each of the
output files and how they are intended to be used including some of the
specifics of each file. Something I can read in 15-30 minutes rather
than hours.

I see your user manual has a tutorial and I was able to scan it quickly
and found it includes the use of "Write-to-Trigger" which would be
interesting to see. Maybe the download could use the files from the
tutorial?

Just my 10 minute look at your materials. :)

--

Rick
 
On Thursday, March 10, 2016 at 7:35:31 AM UTC-5, espen.t...@bitvis.no wrote:
There is also a standard IEEE 1685-2009 which uses "IP-XACT" format for defining peripheral registers. Major EDA vendors have tools supporting the format and its extensions for code generation.

IP-XACT is probably very good for data exchange between different tools, but it is not very good as a human-readable format. We made our own format to significantly increase readability for designers. We evaluated XML, but concluded JSON was better.

Yes, that's why there is the RDL languages such as http://www.accellera.org/activities/working-groups/systemrdl
 
torsdag 10. mars 2016 18.34.29 UTC+1 skrev rickman fřlgende:
On 3/10/2016 10:13 AM, espen wrote:
I see from the discussion above that we should also show the result-files from Register Wizard in the provided download. The result-files are described in the current documentation, but the actual files are not shown. I think everything will be clearer, and hopefully your questions will be answered when we include the result files from the documented example. Most probably we will provide this as a separate zip-file ASAP.

A zip-file showing the generated outputs is now provided for download under http://bitvis.no/products/register_wizard/

Some feedback. Your flyer is way too terse and I'm not inclined to
download a full user manual to learn the first things about a tool. You
might want to have a quick overview manual to give potential customers
an idea of the facilities of the tool without having to learn the whole
thing or wade through a full manual.

The files download is a good start. In addition to the outputs, I found
the input which doesn't look too hard to learn. But your example
includes no bit fields in the registers. Isn't that essential? I would
also include at least one example of logic that is added by the user to
be incorporated in one of the output files, the core file I assume.
Perhaps something simple like a bit that is cleared when read. Some
sort of overview description would be useful explaining each of the
output files and how they are intended to be used including some of the
specifics of each file. Something I can read in 15-30 minutes rather
than hours.

I see your user manual has a tutorial and I was able to scan it quickly
and found it includes the use of "Write-to-Trigger" which would be
interesting to see. Maybe the download could use the files from the
tutorial?

Just my 10 minute look at your materials. :)

--

Rick

Thanks for good suggestions on improving the documentation with simpler get-started-documentation. I will add it in our issue tracking system.

-Espen
 
fredag 11. mars 2016 03.30.24 UTC+1 skrev michael6866 fřlgende:
On Thursday, March 10, 2016 at 7:35:31 AM UTC-5, espen.t...@bitvis.no wrote:
There is also a standard IEEE 1685-2009 which uses "IP-XACT" format for defining peripheral registers. Major EDA vendors have tools supporting the format and its extensions for code generation.

IP-XACT is probably very good for data exchange between different tools, but it is not very good as a human-readable format. We made our own format to significantly increase readability for designers. We evaluated XML, but concluded JSON was better.

Yes, that's why there is the RDL languages such as http://www.accellera.org/activities/working-groups/systemrdl

Thanks. Seems to be dead though, with no support...
 

Welcome to EDABoard.com

Sponsor

Back
Top