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.