📄 spec2vhdl.py
字号:
if (addr & (1<<n)) : self.name += '1' else : self.name += '0' else : self.name += 'x' if count_ones(mask) <= 4 : # can decode with a single 4 bit LUT self.version = 0 self.finalmask = mask return # need multiple level decode # find best available upper level decode mask1 = mask for s in chip_selects : m = s._remainder(addr, mask) if ( m < mask1 ) : upper1 = s mask1 = m if ( mask1 == mask ) or ( count_ones(mask1) > 9 ) : # didn't find a suitable decode, need to make one # these values are magic, designed to result in no more than # three levels of logic, and no more than four inputs at each level lut = { 5:3, 6:3, 7:3, 8:5, 9:5, 10:6, 11:3, 12:3, 13:3, 14:8, 15:8, 16:9 } umask = trim_ones_lsb(mask, lut[count_ones(mask)]) upper1 = ChipSelect(addr, umask) chip_selects.append(upper1) mask1 = upper1._remainder(addr, mask) if count_ones(mask1) <= 3 : # can decode with a single upper level self.version = 1 self.ena1name = upper1.name self.finalmask = mask1 return # need another upper level decode # find best available upper level decode mask2 = mask1 for s in chip_selects : m = s._remainder(addr, mask1) if count_ones(m) < count_ones(mask2) : upper2 = s mask2 = m elif ( count_ones(m) == count_ones(mask2)) and ( m < mask2 ) : upper2 = s mask2 = m if count_ones(mask2) > 2 : # didn't find a suitable decode, need to make one # we want to have 2 bits left to decode umask = trim_ones_lsb(mask1, 2) upper2 = ChipSelect(addr, umask) chip_selects.append(upper2) mask2 = upper2._remainder(addr, mask1) # combine the two upper decodes and 2 bits of address self.version = 3 self.ena1name = upper1.name self.ena2name = upper2.name self.finalmask = mask2 return # return the bits in the 'addr, mask' block that # this chipselect object does not decode def _remainder(self, addr, mask) : if ( self.mask & addr ) != ( self.mask & self.addr ) : # wrong address return mask if ( self.mask & mask ) != self.mask : # too specific return mask return mask & ~self.mask def __str__ (self) : return self.name def __repr__ (self) : return self.name def __cmp__ (self, other) : # ordering is such that upper level selects come # before lower level ones that (might) use them smask = self.mask for n in reversed(range(14)) : if (smask & (1<<n)) : break smask |= (1<<n) omask = other.mask for n in reversed(range(14)) : if (omask & (1<<n)) : break omask |= (1<<n) saddr = self.addr & smask oaddr = other.addr & omask if saddr < oaddr : return -2 if saddr > oaddr : return 2 if smask < omask : return -1 if smask > omask : return 1 return 0 def signal (self) : # the VHDL signal declaration return "\tsignal "+self.name+" : std_logic;\n" def logic (self) : # the VHDL implementation logic = " "+self.name+" <= " if self.version & 1 : logic += " and "+self.ena1name if self.version & 2 : logic += " and "+self.ena2name for n in reversed(range(14)) : if (self.finalmask & (1<<n)) : logic += " and " if (self.addr & (1<<n)) : logic += "addr("+str(n+2)+")" else : logic += "not(addr("+str(n+2)+"))" logic += ";\n" # its easier to put 'and' in front of every term and delete # the first one later, than to figure out which term is first logic = logic.replace(" and ","",1) return logicdef usage (): print "\nUsage: spec2vhdl [options] <name>\n" print " Reads <name>.spec, writes <name>.rspec and <name>.vhd, where" print " <name>.spec is an FPGA spec, <name>.rspec is a config RAM data" print " spec (used later in the build process), and <name>.vhd is a top" print " level VHDL file that implements the specfied FPGA.\n" print " Options:" print " -s <spec_name> use <spec_name> as input file" print " -r <rspec_name> use <rspec_name> for RAM spec output" print " -v <vhdl_name> use <vhdl_name> for VHDL output" print " -l <lib_path> read module specs from <lib_path>" print " -h print this help screen"try: opts, args = getopt.gnu_getopt(sys.argv[1:],"hs:r:v:l:")except getopt.GetoptError: usage() sys.exit(2)if len(args) > 1 : usage() sys.exit(2)libpath = "."if len(args) == 1 : spec_fname = args[0]+".spec" rspec_fname = args[0]+".rspec" vhdl_fname = args[0]+".vhd"else : spec_fname = "" rspec_fname = "" vhdl_fname = ""for opt,value in opts : if opt == '-h' : usage() sys.exit(2) if opt == "-s" : spec_fname = value if opt == "-r" : rspec_fname = value if opt == "-v" : vhdl_fname = value if opt == "-l" : libpath = valuefor name in spec_fname, rspec_fname, vhdl_fname : if len(name) == 0 : usage() sys.exit(2)# read the source file into a config file objectsrc = ConfigParser.ConfigParser()# read in core stuff firstsrc.read("core.spec")src.read(spec_fname)if len(src.sections()) == 0 : print "ERROR: source file '"+spec_fname+"' not found, empty, or misformatted" sys.exit(2)# get a list of all module spec files in the librarylibpath += "/*.mspec"mspecs = glob.glob(libpath)if len(mspecs) == 0 : print "ERROR: no module specs found at '"+libpath+"'" sys.exit(2)# read the module spec file(s) into a config file objectlib = ConfigParser.ConfigParser()for name in mspecs : lib.read(name)# create empty data structuresinstances = []modspecs = {}packages = []chip_selects = []# create instances of VHDL modules based on spec filefor name in src.sections() : instances.append(ModuleInstance(name))# assign addresses to instances# size of address space: 16K 32-bit words, with the# first 256 words (1K bytes) reserved for config RAMupper_limit = 0x4000lower_limit = 0x0100# chip select for the RAMchip_selects.append(ChipSelect(0,0x3F00))# preliminary sort gets like modules together, and instances# in numerical orderinstances.sort(key=ModuleInstance.get_id_code_and_instance)# instances are placed from largest to smallest, since larger# address spaces have more demanding alignment requirementsinstances.sort(key=ModuleInstance.get_num_regs, reverse=1)for i in instances : if i.get_num_regs() == 0 : # no registers, doesn't need address space or chip select break # instances are placed starting at the top of the address # space, since the RAM block at the bottom would mess # up alignment of anything bigger than 256 registers. upper_limit -= i.get_blk_size() if upper_limit < lower_limit : print "ERROR: ran out of address space in FPGA" sys.exit(1) i.assign_address(upper_limit)# sort so that derived selects come after the ones they use# (not strictly neccessary, VHDL can figure it out anyway)chip_selects.sort()# restore "sorted by ID code and instance" ordering for# subsequent processinginstances.sort(key=ModuleInstance.get_id_code_and_instance)# more gathering of infomation and validation needs to be done here# start generating output, top level VHDL file first# prepare for substitution into top-level VHDL filetoplevel_values = {}toplevel_values["outfile"] = vhdl_fnametoplevel_values["preprocessor"] = sys.argv[0]toplevel_values["infile"] = spec_fnametoplevel_values["timestamp"] = str(datetime.datetime.now()).split(".")[0]toplevel_values["packages"] = ""for p in packages : toplevel_values["packages"] += "use work."+p+"_pkg.all;\n"toplevel_values["instance_vhdl"] = ""for i in instances : toplevel_values["instance_vhdl"] += i.vhdl()toplevel_values["chipselect_signals"] = ""toplevel_values["chipselect_logic"] = ""for cs in chip_selects : toplevel_values["chipselect_signals"] += cs.signal() toplevel_values["chipselect_logic"] += cs.logic()# do the substitution and write output filetoplevel_in = open("toplevel.vhd", "r")toplevel_out = open(vhdl_fname, "w")toplevel_out.write(string.Template(toplevel_in.read()).substitute(toplevel_values))# next we generate the data to be merged into the final .fpga fileram_template = ""symbol_values = {}#print instancesfor i in instances: ram_template += i.ram_template() symbol_values.update(i.symbol_table())symbol_specs = {}for m in modspecs.values(): symbol_specs.update(m.symbol_table())bf = bitfile.BitFile()# 't' section - template for RAMbf["t"] = repr(ram_template)# 'v' section - symbol valuesbf["v"] = repr(symbol_values)# 's' section - symbol specsbf["s"] = repr(symbol_specs)# write to filebf.tofilename(rspec_fname)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -