mkzynq.go (5354B)
1 // Copyright 2014 Brian Swetland <swetland@frotz.net> 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Tool to generate a SystemVerilog wrapper around the Xilinx Zynq PS7 Macro 16 17 package main 18 19 import "flag" 20 import "os" 21 import "bufio" 22 import "strings" 23 import "strconv" 24 import "fmt" 25 26 type net struct { 27 next *net 28 kind string 29 def string 30 name string 31 value string 32 } 33 34 const ( 35 SIMPLE_FIXUP = 1 36 PREFIX_FIXUP = 2 37 ) 38 39 type fixup struct { 40 next *fixup 41 pattern string 42 mapping string 43 kind int 44 } 45 46 func fixup_nets(netlist *net, fixups *fixup) { 47 for n := netlist; n != nil; n = n.next { 48 for f := fixups; f != nil; f = f.next { 49 if (f.kind == PREFIX_FIXUP) && strings.HasPrefix(n.name, f.pattern) { 50 n.value = f.mapping + strings.ToLower(strings.TrimPrefix(n.name, f.pattern)) 51 goto fixedup 52 } 53 if (f.kind == SIMPLE_FIXUP) && (n.name == f.pattern) { 54 n.value = f.mapping 55 goto fixedup 56 } 57 } 58 // tie off unmapped input nets 59 if n.kind == "input" { 60 n.value = "0" 61 } 62 fixedup: 63 } 64 } 65 66 // extract input|output|inout [...] <name>; lines from blackbox macro verilog source 67 68 func load_template(fn string) *net { 69 var netlist *net 70 file, _ := os.Open(fn) 71 scanner := bufio.NewScanner(file) 72 for scanner.Scan() { 73 line := scanner.Text() 74 line = strings.TrimSpace(line) 75 if !strings.HasSuffix(line, ";") { 76 continue 77 } 78 line = line[:len(line)-1] 79 parts := strings.Split(line, " "); 80 if (parts[0] != "input") && (parts[0] != "output") && (parts[0] != "inout") { 81 continue; 82 } 83 if (len(parts) == 3) { 84 netlist = &net{ 85 next: netlist, 86 kind: parts[0], 87 def: parts[1], 88 name: parts[2], 89 } 90 } else if (len(parts) == 2) { 91 netlist = &net{ 92 next: netlist, 93 kind: parts[0], 94 def: "", 95 name: parts[1], 96 } 97 } else { 98 continue; 99 } 100 } 101 return netlist 102 } 103 104 var axi_m_gp = flag.Int("axi-master-gp", 0, "number of gp axi master ifcs (0-2)") 105 var axi_s_gp = flag.Int("axi-slave-gp", 0, "number of gp axi slave ifcs (0-2)") 106 var axi_s_hp = flag.Int("axi-slave-hp", 0, "number of gp axi slave ifcs (0-4)") 107 var fclks = flag.Int("fclks", 1, "number of clocks from PS") 108 var tmpl = flag.String("template", "PS7.v", "template for PS7 macro") 109 110 var fixups *fixup 111 var ports *net 112 113 func mkport(kind string, def string, name string) { 114 ports = &net{ 115 next: ports, 116 kind: kind, 117 def: def, 118 name: name, 119 } 120 } 121 122 func prefix_fixup(prefix string, mapping string) { 123 fixups = &fixup { 124 next: fixups, 125 kind: PREFIX_FIXUP, 126 pattern: prefix, 127 mapping: mapping, 128 } 129 } 130 131 func simple_fixup(prefix string, mapping string) { 132 fixups = &fixup { 133 next: fixups, 134 kind: SIMPLE_FIXUP, 135 pattern: prefix, 136 mapping: mapping, 137 } 138 } 139 140 func fixup_axi(count int, prefix string, mapping string, kind string) { 141 defval := "" 142 if (kind == "axi_ifc.slave") { 143 defval = "0" 144 } 145 for n := 1; n <= count; n++ { 146 num := strconv.Itoa(n-1) 147 prefix_fixup(prefix + num, mapping + num + ".") 148 simple_fixup(prefix + num + "ACLK", mapping + num + "_clk") 149 simple_fixup(prefix + num + "AWQOS", defval) 150 simple_fixup(prefix + num + "ARQOS", defval) 151 simple_fixup(prefix + num + "AWPROT", defval) 152 simple_fixup(prefix + num + "ARPROT", defval) 153 simple_fixup(prefix + num + "WID", defval) 154 simple_fixup(prefix + num + "ARESETN", "") 155 simple_fixup(prefix + num + "WRISSUECAP1EN", "0") 156 simple_fixup(prefix + num + "RDISSUECAP1EN", "0") 157 simple_fixup(prefix + num + "WACOUNT", "") 158 simple_fixup(prefix + num + "RACOUNT", "") 159 simple_fixup(prefix + num + "WCOUNT", "") 160 simple_fixup(prefix + num + "RCOUNT", "") 161 mkport(kind, "", mapping + num) 162 mkport("input", "", mapping + num + "_clk") 163 } 164 } 165 166 func main() { 167 flag.Parse() 168 169 netlist := load_template(*tmpl) 170 171 fixup_axi(*axi_m_gp, "MAXIGP", "m_axi_gp", "axi_ifc.master") 172 fixup_axi(*axi_s_gp, "SAXIGP", "s_axi_gp", "axi_ifc.slave") 173 fixup_axi(*axi_s_hp, "SAXIHP", "s_axi_hp", "axi_ifc.slave") 174 175 // route clocks out from PS7 176 simple_fixup("FCLKCLK", "{ fclk3_i, fclk2_i, fclk1_i, fclk0_i }") 177 for n := 0; n < *fclks; n++ { 178 mkport("output", "", "fclk" + strconv.Itoa(n)) 179 } 180 181 fixup_nets(netlist, fixups) 182 183 fmt.Printf("// machine-generated by mkzynq.go - do not edit\n") 184 fmt.Printf("`timescale 1ns / 1ps\n\n") 185 fmt.Printf("module zynq_ps7(\n") 186 for p := ports; p != nil; p = p.next { 187 if p.next != nil { 188 fmt.Printf("\t%s %s,\n", p.kind, p.name) 189 } else { 190 fmt.Printf("\t%s %s\n", p.kind, p.name) 191 } 192 } 193 fmt.Printf("\t);\n\n") 194 195 // global buffers for active clocks from PS 196 fmt.Printf("wire fclk0_i, fclk1_i, fclk2_i, fclk3_i;\n\n") 197 for n := 0; n < *fclks; n++ { 198 fmt.Printf("BUFG fclk%d_bufg(.I(fclk%d_i), .O(fclk%d));\n", n, n, n); 199 } 200 201 fmt.Printf("\nPS7 ps7_i(\n") 202 for n := netlist; n != nil; n = n.next { 203 if n.next != nil { 204 fmt.Printf("\t.%s(%s),\n", n.name, n.value) 205 } else { 206 fmt.Printf("\t.%s(%s)\n", n.name, n.value) 207 } 208 } 209 fmt.Printf("\t);\n\nendmodule\n") 210 } 211