aboutsummaryrefslogblamecommitdiff
path: root/config/config.py
blob: ddf7d0b807036f9e96607226b5b9aba3dc15d524 (plain) (tree)
1
2
3
4
5
6
                     


                                            
 
           








                                                                                                   
                                                                                              
                                                                        


                                                                                                                             
                                                                                    

                              
        


                               


                             
                                                                           
                                                     
 

                                     
 
                                                       


                                                              

                                
 

                                                                     
                                                                     



                                                                      
 




                        

                   







                                                                      

                        


                                                                




                               
                        










                                                                



                                                              










                                                                  
                             
                                                                  






                                                                   
                         











                                                                               

                    


                                               









                                                                          





                                                                        
 

                                                                                      

                                            
                                                                                 






                                                       

                                                               






                                                                                                              
                                                                     
 



                           







                                                                     




                                                                                     

                                         



                                                                     
                                                                                                                         


















                                                                   





























                                                                                                                         


                                                                      

                                                                      
 



























                                                                                                                                    

                                    







                                                                

                                    





























































                                                                        
 





                                                             
                   


                          
#!/usr/bin/env python
"""
Generate core_selector.v for a set of cores.
"""

def main():
    """
    Parse arguments and config file, generate core list, generate output.
    """

    from argparse       import ArgumentParser, FileType, ArgumentDefaultsHelpFormatter
    from ConfigParser   import RawConfigParser
    from sys            import exit

    parser = ArgumentParser(description = __doc__, formatter_class = ArgumentDefaultsHelpFormatter)
    parser.add_argument("-d", "--debug",   help = "enable debugging",   action = "store_true")
    parser.add_argument("-s", "--section", help = "config file section")
    parser.add_argument("-c", "--config",  help = "configuration file",   default = "config.cfg",       type = FileType("r"))
    parser.add_argument("--verilog",       help = "verilog output file",  default = "core_selector.v",  type = FileType("w"))
    parser.add_argument("--makefile",      help = "output makefile",      default = "core_vfiles.mk",   type = FileType("w"))
    parser.add_argument("core",            help = "name(s) of core(s)", nargs = "*")
    args = parser.parse_args()

    try:
        cfg = RawConfigParser()
        cfg.readfp(args.config)

        if args.core:
            cores = args.core
        else:
            section = args.section or cfg.get("default", "default-section")
            cores = cfg.get(section, "cores").split()

        cores.insert(0, "board_regs")
        cores.insert(1, "comm_regs")

        cores = tuple(Core.new(core) for core in cores)
        core_number = 0
        for core in cores:
            core_number = core.assign_core_number(core_number)
        for core in cores[2:]:
            core.add_vfiles(cfg)

        args.verilog.write(createModule_template.format(
            addrs = "".join(core.createAddr()     for core in cores),
            insts = "".join(core.createInstance() for core in cores),
            muxes = "".join(core.createMux()      for core in cores)))

        args.makefile.write(listVfiles_template.format(
            vfiles = "".join(core.listVfiles()    for core in cores)))

    except Exception, e:
        if args.debug:
            raise
        exit(str(e))


class Core(object):
    """
    Data and methods for a generic core.  We can use this directly for
    most cores, a few are weird and require subclassing to override
    particular methods.
    """

    # Class variable tracking how many times a particular core has
    # been instantiated.  This controls instance numbering.

    _instance_count = {}

    # Map from core name to subclass for the special case cores.

    special_class = {}

    def __init__(self, name):
        self.name = name
        self.core_number = None
        self.vfiles = ()
        self.instance_number = self._instance_count.get(name, 0)
        self._instance_count[name] = self.instance_number + 1

    @classmethod
    def new(cls, name):
        return cls.special_class.get(name, cls)(name)

    def assign_core_number(self, n):
        self.core_number = n
        return n + 1

    def add_vfiles(self, cfg):
        if self.instance_number == 0:
            self.vfiles = cfg.get(self.name, "vfiles").split()

    @property
    def instance_name(self):
        if self._instance_count[self.name] > 1:
            return "{}_{}".format(self.name, self.instance_number)
        else:
            return self.name

    @property
    def upper_instance_name(self):
        return self.instance_name.upper()

    def createInstance(self):
        return createInstance_template_generic.format(core = self)

    def createAddr(self):
        return createAddr_template.format(core = self)

    def createMux(self):
        return createMux_template.format(core = self, core0 = self)

    def listVfiles(self):
        return "".join(" \\\n\t$(CORE_TREE)/" + vfile for vfile in self.vfiles)


class BoardCore(Core):
    """
    Board-level cores have a slightly different API, which we handle
    with a different template, at least for now.
    """

    def createInstance(self):
        return createInstance_template_board.format(core = self)


class SubCore(Core):
    """"
    Override mux handling for TRNG's sub-cores.
    """

    def __init__(self, name, parent):
        super(SubCore, self).__init__(name)
        self.parent = parent

    def createMux(self):
        return createMux_template.format(core = self, core0 = self.parent)


class TRNGCore(Core):
    """
    The TRNG core has an internal mux and a collection of sub-cores.
    Mostly this means that our method calls have to iterate over all
    of the subcores after handling the base TRNG core, but we also use
    a different instance template in the hope that it is easier to read.
    """

    subcore_names = ("avalanche_entropy", "rosc_entropy", "trng_mixer", "trng_csprng")

    def __init__(self, name):
        super(TRNGCore, self).__init__(name)
        self.subcores = tuple(SubCore(name, self) for name in self.subcore_names)

    def assign_core_number(self, n):
        n = super(TRNGCore, self).assign_core_number(n)
        for subcore in self.subcores:
            n = subcore.assign_core_number(n)
        return n

    def createInstance(self):
        return createInstance_template_TRNG.format(core = self)

    def createAddr(self):
        return super(TRNGCore, self).createAddr() + "".join(subcore.createAddr() for subcore in self.subcores)

    def createMux(self):
        return super(TRNGCore, self).createMux() + "".join(subcore.createMux() for subcore in self.subcores)

# Hook special classes in as handlers for the cores that require them

Core.special_class.update(
    board_regs = BoardCore,
    comm_regs  = BoardCore,
    trng       = TRNGCore)


# Templates (format strings), here instead of inline in the functions
# that use them, both because some of these are shared between
# multiple functions and because it's easier to read these (and get
# the indentation right) when the're separate.

# Template used by .createAddr() methods.

createAddr_template = """\
   localparam   CORE_ADDR_{core.upper_instance_name:21s} = 9'h{core.core_number:02x};
"""

# Template used by Core.createInstance().

createInstance_template_generic = """\
   //----------------------------------------------------------------
   // {core.upper_instance_name}
   //----------------------------------------------------------------
   wire                 enable_{core.instance_name} = sys_ena && (addr_core_num == CORE_ADDR_{core.upper_instance_name});
   wire [31: 0]         read_data_{core.instance_name};
   wire                 error_{core.instance_name};

   {core.name} {core.instance_name}_inst
     (
      .clk(sys_clk),
      .reset_n(~sys_rst),

      .cs(enable_{core.instance_name} & (sys_eim_rd | sys_eim_wr)),
      .we(sys_eim_wr),

      .address(addr_core_reg),
      .write_data(sys_write_data),
      .read_data(read_data_{core.instance_name})
      );


"""

# Template used by BoardCore.createInstance().  This has minor
# differences from the generic template, maybe we can merge them, or
# maybe we can do something about the (gratuitous?) differences that
# make this necessary.

createInstance_template_board = """\
   //----------------------------------------------------------------
   // {core.upper_instance_name}
   //----------------------------------------------------------------
   wire                 enable_{core.instance_name} = sys_ena && (addr_core_num == CORE_ADDR_{core.upper_instance_name});
   wire [31: 0]         read_data_{core.instance_name};
   wire                 error_{core.instance_name};

   {core.name} {core.instance_name}_inst
     (
      .clk(sys_clk),
      .rst(sys_rst),

      .cs(enable_{core.instance_name} & (sys_eim_rd | sys_eim_wr)),
      .we(sys_eim_wr),

      .address(addr_core_reg),
      .write_data(sys_write_data),
      .read_data(read_data_{core.instance_name}),
      .error(error_{core.instance_name})
      );


"""

# Template used by TRNGCore.createInstance(); this is different enough
# from the generic template that it's (probably) clearer to have this
# separate.
#
# Should this also be checking sys_ena?  Not obvious to me either way.

createInstance_template_TRNG = """\
   //----------------------------------------------------------------
   // {core.upper_instance_name}
   //----------------------------------------------------------------
   wire                 enable_{core.instance_name} = (addr_core_num >= CORE_ADDR_TRNG) && (addr_core_num <= CORE_ADDR_TRNG_CSPRNG);
   wire [31: 0]         read_data_{core.instance_name};
   wire                 error_{core.instance_name};
   wire [3:0]           trng_prefix = addr_core_num[3:0] - CORE_ADDR_TRNG;

   {core.name} {core.instance_name}_inst
     (
      .clk(sys_clk),
      .reset_n(~sys_rst),

      .cs(enable_{core.instance_name} & (sys_eim_rd | sys_eim_wr)),
      .we(sys_eim_wr),

      .address({{trng_prefix, addr_core_reg}}),
      .write_data(sys_write_data),
      .read_data(read_data_{core.instance_name}),

      .avalanche_noise(noise),
      .debug(debug)
      );


"""

# Template for .createMux() methods.

createMux_template = """\
       CORE_ADDR_{core.upper_instance_name}:
         begin
            sys_read_data_mux = read_data_{core0.instance_name};
            sys_error_mux = error_{core0.instance_name};
         end
"""

# Top-level (createModule) template.

createModule_template = """\
// NOTE: This file is generated; do not edit by hand.

module core_selector
  (
   input wire          sys_clk,
   input wire          sys_rst,

   input wire [16: 0]  sys_eim_addr,
   input wire          sys_eim_wr,
   input wire          sys_eim_rd,
   output wire [31: 0] sys_read_data,
   input wire [31: 0]  sys_write_data,
   output wire         sys_error,

   input wire          noise,
   output wire [7 : 0] debug
   );


   //----------------------------------------------------------------
   // Address Decoder
   //----------------------------------------------------------------
   // upper 9 bits specify core being addressed
   wire [ 8: 0]         addr_core_num   = sys_eim_addr[16: 8];
   // lower 8 bits specify register offset in core
   wire [ 7: 0]         addr_core_reg   = sys_eim_addr[ 7: 0];


   //----------------------------------------------------------------
   // Core Address Table
   //----------------------------------------------------------------
{addrs}

{insts}
   //----------------------------------------------------------------
   // Output (Read Data) Multiplexer
   //----------------------------------------------------------------
   reg [31: 0]          sys_read_data_mux;
   assign               sys_read_data = sys_read_data_mux;
   reg                  sys_error_mux;
   assign               sys_error = sys_error_mux;

   always @*

     case (addr_core_num)
{muxes}
       default:
         begin
            sys_read_data_mux = {{32{{1'b0}}}};
            sys_error_mux = 1;
         end
     endcase


endmodule


//======================================================================
// EOF core_selector.v
//======================================================================
"""

# Template for makefile snippet listing Verilog source files.

listVfiles_template = """\
vfiles +={vfiles}
"""

# Run main program.

if __name__ == "__main__":
    main()