Skip to content

Latest commit

 

History

History
303 lines (270 loc) · 12.2 KB

README.md

File metadata and controls

303 lines (270 loc) · 12.2 KB

HwMap

Tool to define the memory interface between memory mapped hardware and C code

To install this Eclipse plugin, use this link as the update site: https://raw.githubusercontent.com/frankbenoit/HwMap.p2/master/repository

The user writes a description (.hwmap) of the memory addresses and registers, that will build the API between an FPGA design and the C code accessing it.

This .hwmap file can also be seen as a documentation. The HwMap tool reads that file and generates C-Header and VHDL-packages from it. Those can then be used in the code on both sides to ensure consistency.

In addition HwMap comes with an Eclipse editor, which let's you edit the .hwmap with validation and some content assist functionality.

Example files:

Output C    "../../C-Code/includes/MyHardware.h"
Output VHDL "../../FPGA/pcore/mycore_v1_00_a/hdl/vhdl/my_hardware.vhd"

Component MyHardware 0x10000 {

  Block Regs 0x100 {
    0x00 ModuleAndVersion
      [ 7 ..  0] Version
                  Constant 0x03 CurrentVersion
      [31 ..  8] Module_ID
                  Constant 0x123456 ID
                  
    // Control is a write-only register. On read always zero-vector will be returned.
    0x04 Control
      [       0] Enable
      [       1] IRQ_Enable
      [ 7 ..  3] State_Command
                  Constant 0 Nothing
                  Constant 1 StartSimulation
                  Constant 2 StopSimulation
                  Constant 3 ClearMemory
      
    0x08 Status
      [       0] Enabled
      [       1] IRQ_Enabled
      [       2] IRQ_Pending
      
    0x0C Baudrate
      // cycles @50MHz needed for 1 bit
      Constant   50 Rate_1MBit
      Constant  500 Rate_100KBit
      Constant 1000 Rate_50KBit
  }
  Block Channel 0x100 {
    0x00 Control
    0x04 Status
  }
  Block TraceMem 0x1000 {
  }
  
  0x0000 Regs    Registers
  0x0400 Channel Channel_0
  0x0500 Channel Channel_1
  0x0600 Channel Channel_2
  0x0700 Channel Channel_3
  0x4000 TraceMem TraceMem
}

Running the standlone generator like this...

C:\C5\HwMap>java -jar hwmap.jar C:\C5\HwMap\example\sub1\sub2\myhw.hwmap
Output directory: C:\C5\HwMap\example\sub1\sub2
Write C header: ../../C-Code/includes/MyHardware.h
Write VHDL package: ../../FPGA/pcore/mycore_v1_00_a/hdl/vhdl/my_hardware_package.vhd
Code generation finished.

C:\C5\HwMap>

Here the generated C header file...

// generated by HwMap : https://github.com/frankbenoit/HwMap
#ifndef MYHARDWARE_H
#define MYHARDWARE_H

#define MyHardware_Regs_ModuleAndVersion_Version_BITPOS 0
#define MyHardware_Regs_ModuleAndVersion_Version_WIDTH 8
#define MyHardware_Regs_ModuleAndVersion_Version_MASK 0xFF
#define MyHardware_Regs_ModuleAndVersion_Version_CONST_CurrentVersion 0x3
#define MyHardware_Regs_ModuleAndVersion_Module_ID_BITPOS 8
#define MyHardware_Regs_ModuleAndVersion_Module_ID_WIDTH 24
#define MyHardware_Regs_ModuleAndVersion_Module_ID_MASK 0xFFFFFF00
#define MyHardware_Regs_ModuleAndVersion_Module_ID_CONST_ID 0x123456
#define MyHardware_Regs_Control_Enable_BITPOS 0
#define MyHardware_Regs_Control_Enable_WIDTH 1
#define MyHardware_Regs_Control_Enable_MASK 0x1
#define MyHardware_Regs_Control_IRQ_Enable_BITPOS 1
#define MyHardware_Regs_Control_IRQ_Enable_WIDTH 1
#define MyHardware_Regs_Control_IRQ_Enable_MASK 0x2
#define MyHardware_Regs_Control_State_Command_BITPOS 3
#define MyHardware_Regs_Control_State_Command_WIDTH 5
#define MyHardware_Regs_Control_State_Command_MASK 0xF8
#define MyHardware_Regs_Control_State_Command_CONST_Nothing 0x0
#define MyHardware_Regs_Control_State_Command_CONST_StartSimulation 0x1
#define MyHardware_Regs_Control_State_Command_CONST_StopSimulation 0x2
#define MyHardware_Regs_Control_State_Command_CONST_ClearMemory 0x3
#define MyHardware_Regs_Status_Enabled_BITPOS 0
#define MyHardware_Regs_Status_Enabled_WIDTH 1
#define MyHardware_Regs_Status_Enabled_MASK 0x1
#define MyHardware_Regs_Status_IRQ_Enabled_BITPOS 1
#define MyHardware_Regs_Status_IRQ_Enabled_WIDTH 1
#define MyHardware_Regs_Status_IRQ_Enabled_MASK 0x2
#define MyHardware_Regs_Status_IRQ_Pending_BITPOS 2
#define MyHardware_Regs_Status_IRQ_Pending_WIDTH 1
#define MyHardware_Regs_Status_IRQ_Pending_MASK 0x4
#define MyHardware_Regs_Baudrate_CONST_Rate_1MBit 0x32
#define MyHardware_Regs_Baudrate_CONST_Rate_100KBit 0x1F4
#define MyHardware_Regs_Baudrate_CONST_Rate_50KBit 0x3E8

struct MyHardware_Regs {
    uint32 ModuleAndVersion;
    uint32 Control;
    uint32 Status;
    uint32 Baudrate;
    uint32 __dummy_0[0x3C];
}

struct MyHardware_Channel {
    uint32 Control;
    uint32 Status;
    uint32 __dummy_0[0x3E];
}

struct MyHardware_TraceMem {
    uint32 __dummy_0[0x400];
}

struct MyHardware {
    struct MyHardware_Regs Registers;
    uint32 __dummy_0[0xC0];
    struct MyHardware_Channel Channel_0;
    struct MyHardware_Channel Channel_1;
    struct MyHardware_Channel Channel_2;
    struct MyHardware_Channel Channel_3;
    uint32 __dummy_1[0xE00];
    struct MyHardware_TraceMem TraceMem;
}

#endif

In the C software, a base pointer must be casted to struct MyHardware*, then the addresses of the registers can be accessed.

struct MyHardware* hw = (struct MyHardware*)0x12340000ULL;
HwOut32( &hw->Registers.Control, 0x123 );

Those fields could be marked as volatile and access them directly. But it was seen by compiler optimization, that those accesses are not guaranteed to be then same then. Better to get the address and use a macro/function to access the hardware register.

Here the VHDL package file...

-- generated by HwMap : https://github.com/frankbenoit/HwMap
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

package my_hardware_pck is

  constant MyHardware_Regs_ModuleAndVersion_Version_BITPOS : integer := 0;
  constant MyHardware_Regs_ModuleAndVersion_Version_WIDTH : integer := 8;
  constant MyHardware_Regs_ModuleAndVersion_Version_MASK : std_logic_vector( 7 downto 0 ) := CONV_STD_LOGIC_VECTOR( 16#FF#, 8 );
  constant MyHardware_Regs_ModuleAndVersion_Version_CONST_CurrentVersion : std_logic_vector( 7 downto 0 ) := CONV_STD_LOGIC_VECTOR( 16#3#, 8 );
  constant MyHardware_Regs_ModuleAndVersion_Module_ID_BITPOS : integer := 8;
  constant MyHardware_Regs_ModuleAndVersion_Module_ID_WIDTH : integer := 24;
  constant MyHardware_Regs_ModuleAndVersion_Module_ID_MASK : std_logic_vector( 23 downto 0 ) := CONV_STD_LOGIC_VECTOR( 16#FFFFFF00#, 24 );
  constant MyHardware_Regs_ModuleAndVersion_Module_ID_CONST_ID : std_logic_vector( 23 downto 0 ) := CONV_STD_LOGIC_VECTOR( 16#123456#, 24 );
  constant MyHardware_Regs_Control_Enable_BITPOS : integer := 0;
  constant MyHardware_Regs_Control_Enable_WIDTH : integer := 1;
  constant MyHardware_Regs_Control_Enable_MASK : std_logic_vector( 0 downto 0 ) := CONV_STD_LOGIC_VECTOR( 16#1#, 1 );
  constant MyHardware_Regs_Control_IRQ_Enable_BITPOS : integer := 1;
  constant MyHardware_Regs_Control_IRQ_Enable_WIDTH : integer := 1;
  constant MyHardware_Regs_Control_IRQ_Enable_MASK : std_logic_vector( 0 downto 0 ) := CONV_STD_LOGIC_VECTOR( 16#2#, 1 );
  constant MyHardware_Regs_Control_State_Command_BITPOS : integer := 3;
  constant MyHardware_Regs_Control_State_Command_WIDTH : integer := 5;
  constant MyHardware_Regs_Control_State_Command_MASK : std_logic_vector( 4 downto 0 ) := CONV_STD_LOGIC_VECTOR( 16#F8#, 5 );
  constant MyHardware_Regs_Control_State_Command_CONST_Nothing : std_logic_vector( 4 downto 0 ) := CONV_STD_LOGIC_VECTOR( 16#0#, 5 );
  constant MyHardware_Regs_Control_State_Command_CONST_StartSimulation : std_logic_vector( 4 downto 0 ) := CONV_STD_LOGIC_VECTOR( 16#1#, 5 );
  constant MyHardware_Regs_Control_State_Command_CONST_StopSimulation : std_logic_vector( 4 downto 0 ) := CONV_STD_LOGIC_VECTOR( 16#2#, 5 );
  constant MyHardware_Regs_Control_State_Command_CONST_ClearMemory : std_logic_vector( 4 downto 0 ) := CONV_STD_LOGIC_VECTOR( 16#3#, 5 );
  constant MyHardware_Regs_Status_Enabled_BITPOS : integer := 0;
  constant MyHardware_Regs_Status_Enabled_WIDTH : integer := 1;
  constant MyHardware_Regs_Status_Enabled_MASK : std_logic_vector( 0 downto 0 ) := CONV_STD_LOGIC_VECTOR( 16#1#, 1 );
  constant MyHardware_Regs_Status_IRQ_Enabled_BITPOS : integer := 1;
  constant MyHardware_Regs_Status_IRQ_Enabled_WIDTH : integer := 1;
  constant MyHardware_Regs_Status_IRQ_Enabled_MASK : std_logic_vector( 0 downto 0 ) := CONV_STD_LOGIC_VECTOR( 16#2#, 1 );
  constant MyHardware_Regs_Status_IRQ_Pending_BITPOS : integer := 2;
  constant MyHardware_Regs_Status_IRQ_Pending_WIDTH : integer := 1;
  constant MyHardware_Regs_Status_IRQ_Pending_MASK : std_logic_vector( 0 downto 0 ) := CONV_STD_LOGIC_VECTOR( 16#4#, 1 );
  constant MyHardware_Regs_Baudrate_CONST_Rate_1MBit : std_logic_vector( 31 downto 0 ) := CONV_STD_LOGIC_VECTOR( 16#32#, 32 );
  constant MyHardware_Regs_Baudrate_CONST_Rate_100KBit : std_logic_vector( 31 downto 0 ) := CONV_STD_LOGIC_VECTOR( 16#1F4#, 32 );
  constant MyHardware_Regs_Baudrate_CONST_Rate_50KBit : std_logic_vector( 31 downto 0 ) := CONV_STD_LOGIC_VECTOR( 16#3E8#, 32 );
  type Block_MyHardware_Regs_Selection is record
    UnmappedSelection : std_logic;
    Selected_ModuleAndVersion : std_logic;
    Selected_Control : std_logic;
    Selected_Status : std_logic;
    Selected_Baudrate : std_logic;
  end record;

  type Block_MyHardware_Channel_Selection is record
    UnmappedSelection : std_logic;
    Selected_Control : std_logic;
    Selected_Status : std_logic;
  end record;

  type Block_MyHardware_TraceMem_Selection is record
    UnmappedSelection : std_logic;
  end record;

  type Comp_MyHardware_Selection is record
    Block_Regs : Block_MyHardware_Regs_Selection;
    Block_Channel : Block_MyHardware_Channel_Selection;
    Block_TraceMem : Block_MyHardware_TraceMem_Selection;
    UnmappedSelection : std_logic;
    Selected_Registers : std_logic;
    Selected_Channel_0 : std_logic;
    Selected_Channel_1 : std_logic;
    Selected_Channel_2 : std_logic;
    Selected_Channel_3 : std_logic;
    Selected_TraceMem : std_logic;
  end record;

end package my_hardware_pck;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity my_hardware_Decoder_MyHardware is
  Port (
    addr  : in std_logic_vector( 15 downto 0 );
    cycle : in std_logic;
    selection : out work.my_hardware_pck.Comp_MyHardware_Selection );
end out_Decoder_CapSim;

architecture Behavioral of my_hardware_Decoder_MyHardware is
  signal res : work.my_hardware_pck.Comp_MyHardware_Selection;
begin
  selection <= res;
  res.UnmappedSelection <= '1' when
    res.Selected_Registers = '0' and
    res.Selected_Channel_0 = '0' and
    res.Selected_Channel_1 = '0' and
    res.Selected_Channel_2 = '0' and
    res.Selected_Channel_3 = '0' and
    res.Selected_TraceMem = '0' and
    cycle = '1' else '0';
  res.Block_Regs.Selected_ModuleAndVersion <= '1' when
    addr( 7 downto 2 ) = "000000" and
    cycle = '1' else '0';
  res.Block_Regs.Selected_Control <= '1' when
    addr( 7 downto 2 ) = "000001" and
    cycle = '1' else '0';
  res.Block_Regs.Selected_Status <= '1' when
    addr( 7 downto 2 ) = "000010" and
    cycle = '1' else '0';
  res.Block_Regs.Selected_Baudrate <= '1' when
    addr( 7 downto 2 ) = "000011" and
    cycle = '1' else '0';
  res.Block_Regs.UnmappedSelection <= '1' when
    res.Block_Regs.Selected_ModuleAndVersion = '0' and
    res.Block_Regs.Selected_Control = '0' and
    res.Block_Regs.Selected_Status = '0' and
    res.Block_Regs.Selected_Baudrate = '0' and
    cycle = '1' else '0';
  res.Block_Channel.Selected_Control <= '1' when
    addr( 7 downto 2 ) = "000000" and
    cycle = '1' else '0';
  res.Block_Channel.Selected_Status <= '1' when
    addr( 7 downto 2 ) = "000001" and
    cycle = '1' else '0';
  res.Block_Channel.UnmappedSelection <= '1' when
    res.Block_Channel.Selected_Control = '0' and
    res.Block_Channel.Selected_Status = '0' and
    cycle = '1' else '0';
  res.Block_TraceMem.UnmappedSelection <= '1' when
    cycle = '1' else '0';
  res.Selected_Registers <= '1' when
    addr( 15 downto 8 ) = "00000000" and
    cycle = '1' else '0';
  res.Selected_Channel_0 <= '1' when
    addr( 15 downto 8 ) = "00000100" and
    cycle = '1' else '0';
  res.Selected_Channel_1 <= '1' when
    addr( 15 downto 8 ) = "00000101" and
    cycle = '1' else '0';
  res.Selected_Channel_2 <= '1' when
    addr( 15 downto 8 ) = "00000110" and
    cycle = '1' else '0';
  res.Selected_Channel_3 <= '1' when
    addr( 15 downto 8 ) = "00000111" and
    cycle = '1' else '0';
  res.Selected_TraceMem <= '1' when
    addr( 15 downto 12 ) = "0100" and
    cycle = '1' else '0';
end Behavioral;