EDAboard.com | EDAboard.eu | EDAboard.de | EDAboard.co.uk | RTV forum PL | NewsGroups PL

Simplify handling of SW accessible registers in FPGA

Ask a question - edaboard.com

elektroda.net NewsGroups Forum Index - VHDL Language - Simplify handling of SW accessible registers in FPGA

Goto page 1, 2  Next


Guest

Wed Mar 09, 2016 12:01 pm   



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 Smile
And please send us feedback on potential improvements for your applications.

Rob Gaddi
Guest

Wed Mar 09, 2016 7:36 pm   



rickman wrote:

Quote:
On 3/9/2016 5:01 AM, espen.tallaksen_at_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 Smile
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.

Rob Gaddi
Guest

Wed Mar 09, 2016 8:43 pm   



rickman wrote:

Quote:
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(Cool := 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(Cool;
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*Cool := nd(i*8+7 downto i*Cool;
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 (Cool
#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.

Rob Gaddi
Guest

Wed Mar 09, 2016 9:40 pm   



rickman wrote:

Quote:
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(Cool := 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(Cool;
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*Cool := nd(i*8+7 downto i*Cool;
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 (Cool
#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.

Rob Gaddi
Guest

Wed Mar 09, 2016 11:48 pm   



Allan Herriman wrote:

Quote:
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.

rickman
Guest

Thu Mar 10, 2016 12:09 am   



On 3/9/2016 5:01 AM, espen.tallaksen_at_bitvis.no wrote:
Quote:
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 Smile
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

rickman
Guest

Thu Mar 10, 2016 1:00 am   



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

On 3/9/2016 5:01 AM, espen.tallaksen_at_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 Smile
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.


Quote:
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.


Quote:
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

rickman
Guest

Thu Mar 10, 2016 2:30 am   



On 3/9/2016 1:43 PM, Rob Gaddi wrote:
Quote:
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(Cool := 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(Cool;
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*Cool := nd(i*8+7 downto i*Cool;
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 (Cool
#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

michael6866
Guest

Thu Mar 10, 2016 4:26 am   



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

On 3/9/2016 5:01 AM, espen.tallaksen_at_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 Smile
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.

Allan Herriman
Guest

Thu Mar 10, 2016 4:32 am   



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

[snip]

Quote:
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

rickman
Guest

Thu Mar 10, 2016 5:59 am   



On 3/9/2016 2:40 PM, Rob Gaddi wrote:
Quote:
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.


Quote:
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


Guest

Thu Mar 10, 2016 2:22 pm   



Quote:
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


Guest

Thu Mar 10, 2016 2:31 pm   



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.


Guest

Thu Mar 10, 2016 2:35 pm   



> 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.


Guest

Thu Mar 10, 2016 5:13 pm   



> 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/

Goto page 1, 2  Next

elektroda.net NewsGroups Forum Index - VHDL Language - Simplify handling of SW accessible registers in FPGA

Ask a question - edaboard.com

Arabic versionBulgarian versionCatalan versionCzech versionDanish versionGerman versionGreek versionEnglish versionSpanish versionFinnish versionFrench versionHindi versionCroatian versionIndonesian versionItalian versionHebrew versionJapanese versionKorean versionLithuanian versionLatvian versionDutch versionNorwegian versionPolish versionPortuguese versionRomanian versionRussian versionSlovak versionSlovenian versionSerbian versionSwedish versionTagalog versionUkrainian versionVietnamese versionChinese version
RTV map EDAboard.com map News map EDAboard.eu map EDAboard.de map EDAboard.co.uk map