remove write_ptp, add bitwidths.txt file
[pinmux.git] / src / bsv / pinmux_generator.py
index 72fc39af381bdb00707601bedc9c105661df3edf..bcc1b254cb9b0a5a5d5582fb3eb8d3bcd3057eea 100644 (file)
@@ -39,6 +39,9 @@ copyright = '''
 header = copyright + '''
 package pinmux;
 
+import GetPut::*;
+import Vector::*;
+
 '''
 footer = '''
    endmodule
@@ -72,19 +75,106 @@ def pinmuxgen(pth=None, verify=True):
     shutil.copyfile(os.path.join(cwd, 'Makefile.template'),
                     os.path.join(bp, 'Makefile'))
     cwd = os.path.join(cwd, 'bsv_lib')
-    for fname in ['AXI4_Lite_Types.bsv', 'Semi_FIFOF.bsv']:
+    for fname in []:
         shutil.copyfile(os.path.join(cwd, fname),
                         os.path.join(bl, fname))
 
     bus = os.path.join(bp, 'busenable.bsv')
     pmp = os.path.join(bp, 'pinmux.bsv')
-    ptp = os.path.join(bp, 'PinTop.bsv')
     bvp = os.path.join(bp, 'bus.bsv')
+    idef = os.path.join(bp, 'instance_defines.bsv')
+    slow = os.path.join(bp, 'slow_peripherals.bsv')
+    slowt = os.path.join(cwd, 'slow_peripherals_template.bsv')
+    slowmf = os.path.join(bp, 'slow_memory_map.bsv')
+    slowmt = os.path.join(cwd, 'slow_tuple2_template.bsv')
+    fastmf = os.path.join(bp, 'fast_memory_map.bsv')
+    fastmt = os.path.join(cwd, 'fast_tuple2_template.bsv')
+    soc = os.path.join(bp, 'socgen.bsv')
+    soct = os.path.join(cwd, 'soc_template.bsv')
 
     write_pmp(pmp, p, ifaces, iocells)
-    write_ptp(ptp, p, ifaces)
     write_bvp(bvp, p, ifaces)
     write_bus(bus, p, ifaces)
+    write_instances(idef, p, ifaces)
+    write_slow(slow, slowt, slowmf, slowmt, p, ifaces, iocells)
+    write_soc(soc, soct, fastmf, fastmt, p, ifaces, iocells)
+
+
+def write_slow(slow, slowt, slowmf, slowmt, p, ifaces, iocells):
+    """ write out the slow_peripherals.bsv file.
+        joins all the peripherals together into one AXI Lite interface
+    """
+    imports = ifaces.slowimport()
+    ifdecl = ifaces.slowifdeclmux() + '\n' + ifaces.extifdecl()
+    regdef = ifaces.axi_reg_def()
+    slavedecl = ifaces.axi_slave_idx()
+    fnaddrmap = ifaces.axi_addr_map()
+    mkslow = ifaces.mkslow_peripheral()
+    mkcon = ifaces.mk_connection()
+    mkcellcon = ifaces.mk_cellconn()
+    pincon = ifaces.mk_pincon()
+    inst = ifaces.extifinstance()
+    inst2 = ifaces.extifinstance2()
+    mkplic = ifaces.mk_plic()
+    numsloirqs = ifaces.mk_sloirqsdef()
+    ifacedef = ifaces.mk_ext_ifacedef()
+    ifacedef = ifaces.mk_ext_ifacedef()
+    clockcon = ifaces.mk_slowclk_con()
+
+    with open(slow, "w") as bsv_file:
+        with open(slowt) as f:
+            slowt = f.read()
+        bsv_file.write(slowt.format(imports, ifdecl, regdef, slavedecl,
+                                    fnaddrmap, mkslow, mkcon, mkcellcon,
+                                    pincon, inst, mkplic,
+                                    numsloirqs, ifacedef,
+                                    inst2, clockcon))
+
+    with open(slowmf, "w") as bsv_file:
+        with open(slowmt) as f:
+            slowmt = f.read()
+        bsv_file.write(slowmt.format(regdef, slavedecl, fnaddrmap))
+
+
+def write_soc(soc, soct, fastmf, fastmt, p, ifaces, iocells):
+    """ write out the soc.bsv file.
+        joins all the peripherals together as AXI Masters
+    """
+    ifaces.fastbusmode = True  # side-effects... shouldn't really do this
+
+    imports = ifaces.slowimport()
+    ifdecl = ifaces.fastifdecl()
+    regdef = ifaces.axi_fastmem_def()
+    slavedecl = ifaces.axi_fastslave_idx()
+    mastdecl = ifaces.axi_master_idx()
+    fnaddrmap = ifaces.axi_fastaddr_map()
+    mkfast = ifaces.mkfast_peripheral()
+    mkcon = ifaces.mk_fast_connection()
+    mkmstcon = ifaces.mk_master_connection()
+    mkcellcon = ifaces.mk_cellconn()
+    pincon = ifaces.mk_fast_pincon()
+    inst = ifaces.extfastifinstance()
+    mkplic = ifaces.mk_plic()
+    numsloirqs = ifaces.mk_sloirqsdef()
+    ifacedef = ifaces.mk_ext_ifacedef()
+    dma = ifaces.mk_dma_irq()
+    num_dmachannels = ifaces.num_dmachannels()
+    clockcon = ifaces.mk_fastclk_con()
+
+    with open(soc, "w") as bsv_file:
+        with open(soct) as f:
+            soct = f.read()
+        bsv_file.write(soct.format(imports, ifdecl, mkfast,
+                                   slavedecl, mastdecl, mkcon,
+                                   inst, dma, num_dmachannels,
+                                   pincon, regdef, fnaddrmap,
+                                   clockcon, mkmstcon,
+                                   ))
+
+    with open(fastmf, "w") as bsv_file:
+        with open(fastmt) as f:
+            fastmt = f.read()
+        bsv_file.write(fastmt.format(regdef, slavedecl, mastdecl, fnaddrmap))
 
 
 def write_bus(bus, p, ifaces):
@@ -102,7 +192,8 @@ def write_pmp(pmp, p, ifaces, iocells):
 
         cell_bit_width = 'Bit#(%d)' % p.cell_bitwidth
         bsv_file.write('''\
-   interface MuxSelectionLines;
+      (*always_ready,always_enabled*)
+      interface MuxSelectionLines;
 
       // declare the method which will capture the user pin-mux
       // selection values.The width of the input is dependent on the number
@@ -116,38 +207,61 @@ def write_pmp(pmp, p, ifaces, iocells):
 
         bsv_file.write('''
 
-      interface PeripheralSide;
-      // declare the interface to the peripherals
-      // Each IO cell will have 3 input field (output from pin mux
-      // and on output field (input to pinmux)''')
-        # ==============================================================
+      interface IOCellSide;
+      // declare the interface to the IO cells.
+      // Each IO cell will have 1 input field (output from pin mux)
+      // and an output and out-enable field (input to pinmux)''')
 
-        # == create method definitions for all peripheral interfaces ==#
+        # == create method definitions for all iocell interfaces ==#
         iocells.ifacefmt(bsv_file)
 
         # ===== finish interface definition and start module definition=======
         bsv_file.write("\n      endinterface\n")
 
+        ifaces.ifacepfmt(bsv_file)
         # ===== io cell definition =======
         bsv_file.write('''
+      (*always_ready,always_enabled*)
+      interface PeripheralSide;
+      // declare the interface to the peripherals
+      // Each peripheral's function will be either an input, output
+      // or be bi-directional.  an input field will be an output from the
+      // peripheral and an output field will be an input to the peripheral.
+      // Bi-directional functions also have an output-enable (which
+      // again comes *in* from the peripheral)''')
+        # ==============================================================
 
-      interface IOCellSide;
-      // declare the interface to the IO cells.
-      // Each IO cell will have 3 input field (output from pin mux
-      // and on output field (input to pinmux)''')
-
-        # == create method definitions for all iocell interfaces ==#
-        ifaces.ifacefmt(bsv_file)
+        # == create method definitions for all peripheral interfaces ==#
+        ifaces.ifacefmt2(bsv_file)
         bsv_file.write("\n      endinterface\n")
 
         # ===== finish interface definition and start module definition=======
         bsv_file.write('''
 
    interface Ifc_pinmux;
+      // this interface controls how each IO cell is routed.  setting
+      // any given IO cell's mux control value will result in redirection
+      // of not just the input or output to different peripheral functions
+      // but also the *direction* control - if appropriate - as well.
       interface MuxSelectionLines mux_lines;
+
+      // this interface contains the inputs, outputs and direction-control
+      // lines for all peripherals.  GPIO is considered to also be just
+      // a peripheral because it also has in, out and direction-control.
       interface PeripheralSide peripheral_side;
+
+      // this interface is to be linked to the individual IO cells.
+      // if looking at a "non-muxed" GPIO design, basically the
+      // IO cell input, output and direction-control wires are cut
+      // (giving six pairs of dangling wires, named left and right)
+      // these iocells are routed in their place on one side ("left")
+      // and the matching *GPIO* peripheral interfaces in/out/dir
+      // connect to the OTHER side ("right").  the result is that
+      // the muxer settings end up controlling the routing of where
+      // the I/O from the IOcell actually goes.
       interface IOCellSide iocell_side;
    endinterface
+
    (*synthesize*)
    module mkpinmux(Ifc_pinmux);
 ''')
@@ -170,6 +284,7 @@ def write_pmp(pmp, p, ifaces, iocells):
         # ========================= Actual pinmuxing ========================#
         bsv_file.write('''
       /*====== This where the muxing starts for each io-cell======*/
+      Wire#(Bit#(1)) val0<-mkDWire(0); // need a zero
 ''')
         bsv_file.write(p.pinmux)
         bsv_file.write('''
@@ -187,101 +302,103 @@ def write_pmp(pmp, p, ifaces, iocells):
         bsv_file.write("\n    endinterface;")
 
         bsv_file.write('''
+
     interface iocell_side = interface IOCellSide
 ''')
         iocells.ifacedef(bsv_file)
         bsv_file.write("\n     endinterface;")
 
         bsv_file.write('''
-    interface peripheral_side = interface PeripheralSide
-''')
-        ifaces.ifacedef(bsv_file)
-        bsv_file.write("\n     endinterface;")
 
+     interface peripheral_side = interface PeripheralSide
+''')
+        ifaces.ifacedef2(bsv_file)
+        bsv_file.write("\n      endinterface;")
 
         bsv_file.write(footer)
         print("BSV file successfully generated: bsv_src/pinmux.bsv")
         # ======================================================================
 
 
-def write_ptp(ptp, p, ifaces):
-    with open(ptp, 'w') as bsv_file:
-        bsv_file.write(copyright + '''
-package PinTop;
-    import pinmux::*;
-    interface Ifc_PintTop;
-        method ActionValue#(Bool) write(Bit#({0}) addr, Bit#({1}) data);
-        method Tuple2#(Bool,Bit#({1})) read(Bit#({0}) addr);
-        interface PeripheralSide peripheral_side;
-    endinterface
-
-    module mkPinTop(Ifc_PintTop);
-        // instantiate the pin-mux module here
-        Ifc_pinmux pinmux <-mkpinmux;
-
-        // declare the registers which will be used to mux the IOs
-'''.format(p.ADDR_WIDTH, p.DATA_WIDTH))
-
-        cell_bit_width = str(p.cell_bitwidth)
-        for cell in p.muxed_cells:
-            bsv_file.write('''
-                Reg#(Bit#({0})) rg_muxio_{1} <-mkReg(0);'''.format(
-                cell_bit_width, cell[0]))
-
-        bsv_file.write('''
-        // rule to connect the registers to the selection lines of the
-        // pin-mux module
-        rule connect_selection_registers;''')
-
-        for cell in p.muxed_cells:
-            bsv_file.write('''
-          pinmux.mux_lines.cell{0}_mux(rg_muxio_{0});'''.format(cell[0]))
-
-        bsv_file.write('''
-        endrule
-        // method definitions for the write user interface
-        method ActionValue#(Bool) write(Bit#({2}) addr, Bit#({3}) data);
-          Bool err=False;
-          case (addr[{0}:{1}])'''.format(p.upper_offset, p.lower_offset,
-                                         p.ADDR_WIDTH, p.DATA_WIDTH))
-        index = 0
-        for cell in p.muxed_cells:
-            bsv_file.write('''
-            {0}: rg_muxio_{1}<=truncate(data);'''.format(index, cell[0]))
-            index = index + 1
-
-        bsv_file.write('''
-            default: err=True;
-          endcase
-          return err;
-        endmethod''')
-
-        bsv_file.write('''
-        // method definitions for the read user interface
-        method Tuple2#(Bool,Bit#({3})) read(Bit#({2}) addr);
-          Bool err=False;
-          Bit#(32) data=0;
-          case (addr[{0}:{1}])'''.format(p.upper_offset, p.lower_offset,
-                                         p.ADDR_WIDTH, p.DATA_WIDTH))
-        index = 0
-        for cell in p.muxed_cells:
-            bsv_file.write('''
-                {0}: data=zeroExtend(rg_muxio_{1});'''.format(index, cell[0]))
-            index = index + 1
-
-        bsv_file.write('''
-            default:err=True;
-          endcase
-          return tuple2(err,data);
-        endmethod
-        interface peripheral_side=pinmux.peripheral_side;
-    endmodule
-endpackage
-''')
-
-
 def write_bvp(bvp, p, ifaces):
     # ######## Generate bus transactors ################
+    gpiocfg = '\t\tinterface GPIO_config#({4}) bank{3}_config;\n' \
+              '\t\tinterface AXI4_Lite_Slave_IFC#({0},{1},{2}) bank{3}_slave;'
+    muxcfg = '\t\tinterface MUX_config#({4}) muxb{3}_config;\n' \
+        '\t\tinterface AXI4_Lite_Slave_IFC#({0},{1},{2}) muxb{3}_slave;'
+
+    gpiodec = '\tGPIO#({0}) mygpio{1} <- mkgpio();'
+    muxdec = '\tMUX#({0}) mymux{1} <- mkmux();'
+    gpioifc = '\tinterface bank{0}_config=mygpio{0}.pad_config;\n' \
+              '\tinterface bank{0}_slave=mygpio{0}.axi_slave;'
+    muxifc = '\tinterface muxb{0}_config=mymux{0}.mux_config;\n' \
+        '\tinterface muxb{0}_slave=mymux{0}.axi_slave;'
     with open(bvp, 'w') as bsv_file:
-        bsv_file.write(axi4_lite.format(p.ADDR_WIDTH, p.DATA_WIDTH))
+        # assume here that all muxes have a 1:1 gpio
+        cfg = []
+        decl = []
+        idec = []
+        iks = sorted(ifaces.keys())
+        for iname in iks:
+            if not iname.startswith('gpio'):  # TODO: declare other interfaces
+                continue
+            bank = iname[4:]
+            ifc = ifaces[iname]
+            npins = len(ifc.pinspecs)
+            cfg.append(gpiocfg.format(p.ADDR_WIDTH, p.DATA_WIDTH,
+                                      0,  # USERSPACE
+                                      bank, npins))
+            cfg.append(muxcfg.format(p.ADDR_WIDTH, p.DATA_WIDTH,
+                                     0,  # USERSPACE
+                                     bank, npins))
+            decl.append(gpiodec.format(npins, bank))
+            decl.append(muxdec .format(npins, bank))
+            idec.append(gpioifc.format(bank))
+            idec.append(muxifc.format(bank))
+        print dir(ifaces)
+        print ifaces.items()
+        print dir(ifaces['gpioa'])
+        print ifaces['gpioa'].pinspecs
+        gpiodecl = '\n'.join(decl) + '\n' + '\n'.join(idec)
+        gpiocfg = '\n'.join(cfg)
+        bsv_file.write(axi4_lite.format(gpiodecl, gpiocfg))
     # ##################################################
+
+
+def write_instances(idef, p, ifaces):
+    with open(idef, 'w') as bsv_file:
+        txt = '''\
+`define ADDR {0}
+`define PADDR {2}
+`define DATA {1}
+`define Reg_width {1}
+`define USERSPACE 0
+`define RV64
+
+// TODO: work out if these are needed
+`define PWM_AXI4Lite
+`define PRFDEPTH 6
+`define VADDR 39
+`define DCACHE_BLOCK_SIZE 4
+`define DCACHE_WORD_SIZE 8
+`define PERFMONITORS                            64
+`define DCACHE_WAYS 4
+`define DCACHE_TAG_BITS 20      // tag_bits = 52
+
+// CLINT
+    `define ClintBase       'h02000000
+    `define ClintEnd        'h020BFFFF
+
+`define PLIC
+       `define PLICBase                'h0c000000
+       `define PLICEnd         'h10000000
+`define INTERRUPT_PINS 64
+
+`define BAUD_RATE 130
+`ifdef simulate
+  `define BAUD_RATE 5 //130 //
+`endif
+'''
+        bsv_file.write(txt.format(p.ADDR_WIDTH,
+                                  p.DATA_WIDTH,
+                                  p.PADDR_WIDTH))