| 1 | import os |
|---|
| 2 | import subprocess |
|---|
| 3 | import win32com.client |
|---|
| 4 | |
|---|
| 5 | |
|---|
| 6 | ProjectName = "CP11U" |
|---|
| 7 | XilinxPath = os.environ["XILINX"] |
|---|
| 8 | XilinxBin = os.path.join(XilinxPath,'bin\\nt') |
|---|
| 9 | |
|---|
| 10 | ProjectDirectory = os.getcwd() |
|---|
| 11 | WorkbookPath = os.path.join(ProjectDirectory,WorkbookFilename) |
|---|
| 12 | WorkbookFilename = "%s.xlsx" % ProjectName |
|---|
| 13 | |
|---|
| 14 | Excel = win32com.client.Dispatch("Excel.Application") |
|---|
| 15 | try: |
|---|
| 16 | ProjectWorkbook = Excel.Workbooks(WorkbookFilename) #check if it's already open |
|---|
| 17 | except Exception,e: |
|---|
| 18 | try: |
|---|
| 19 | ProjectWorkbook = Excel.Workbooks.Open(WorkbookPath) #open it |
|---|
| 20 | except Exception,ex: |
|---|
| 21 | print ex |
|---|
| 22 | |
|---|
| 23 | run, runXST, runNGDBuild, runMAP, runPAR, runBitgen = False, True, False, False, False, False |
|---|
| 24 | getXDL = True |
|---|
| 25 | |
|---|
| 26 | |
|---|
| 27 | |
|---|
| 28 | class XilinxProject: |
|---|
| 29 | ''' |
|---|
| 30 | XilinxProject class accepts a Workbook specifying a Xilinx compilation project |
|---|
| 31 | ''' |
|---|
| 32 | def __init__(self,ProjectWorkbook,ProjectPath): |
|---|
| 33 | |
|---|
| 34 | |
|---|
| 35 | self.ProjectWorkbook = ProjectWorkbook |
|---|
| 36 | self.ProjectSheet = ProjectWorkbook.Sheets("Project") |
|---|
| 37 | self.SynthesisSheet = ProjectWorkbook.Sheets("Synthesis") |
|---|
| 38 | self.TranslationSheet = ProjectWorkbook.Sheets("Translation") |
|---|
| 39 | self.ConstraintsSheet = ProjectWorkbook.Sheets("Constraints") |
|---|
| 40 | self.BitstreamSheet = ProjectWorkbook.Sheets("Bitstream") |
|---|
| 41 | |
|---|
| 42 | self.ProjectPath = self.ProjectSheet.Range("ProjectPath").Value |
|---|
| 43 | self.top = self.ProjectSheet.Range("top").Value |
|---|
| 44 | self.tmpdir = self.ProjectSheet.Range("tmpdir").Value |
|---|
| 45 | self.xsthdpdir = self.ProjectSheet.Range("xsthdpdir").Value |
|---|
| 46 | self.part = self.ProjectSheet.Range("part").Value |
|---|
| 47 | #Make tmp_dir and hdp_dir if necessary |
|---|
| 48 | if (not os.path.exists(tmpdir)): |
|---|
| 49 | os.mkdir(os.path.join(self.ProjectPath,self.tmpdir)) |
|---|
| 50 | if (not os.path.exists(xsthdpdir)): |
|---|
| 51 | os.mkdir(os.path.join(self.ProjectPath,self.xsthdpdir)) |
|---|
| 52 | |
|---|
| 53 | def SetUCF(self,ucf_file_path): |
|---|
| 54 | self.ucf_file = ucf_file_path |
|---|
| 55 | self.ConstraintsSheet.Range("ucffile").Formula = ucf_file_path |
|---|
| 56 | |
|---|
| 57 | def GetUCF(self): |
|---|
| 58 | self.ucf_file = self.ConstraintsSheet.Range("ucffile").Formula |
|---|
| 59 | |
|---|
| 60 | #------------------------------------------------------------------------ |
|---|
| 61 | #UCF Generation |
|---|
| 62 | #------------------------------------------------------------------------ |
|---|
| 63 | def GenerateUCF(self): |
|---|
| 64 | ConstraintsRange = self.ConstraintsSheet.Range("ConstraintsRange") |
|---|
| 65 | Constraints = self.ConstraintsSheet.Range(ConstraintsRange).Formula |
|---|
| 66 | |
|---|
| 67 | self.ucf_file = "%s.ucf"%self.top |
|---|
| 68 | ucf_fo = open(self.ucf_file, mode='w') |
|---|
| 69 | for net,loc,iostandard,slew in Constraints: |
|---|
| 70 | line = "NET \"%s\" LOC = \"%s\" | IOSTANDARD = %s" % (net,loc,iostandard) |
|---|
| 71 | if (slew == None): |
|---|
| 72 | line += ";\n" |
|---|
| 73 | else: |
|---|
| 74 | line += " | SLEW = %s;\n" % slew |
|---|
| 75 | ucf_fo.write(line) |
|---|
| 76 | ucf_fo.close() |
|---|
| 77 | self.SetUCF(ucf_file) |
|---|
| 78 | |
|---|
| 79 | #------------------------------------------------------------------------ |
|---|
| 80 | #End UCF Generation |
|---|
| 81 | #------------------------------------------------------------------------ |
|---|
| 82 | |
|---|
| 83 | |
|---|
| 84 | #------------------------------------------------------------------------ |
|---|
| 85 | #XST file Generation |
|---|
| 86 | #------------------------------------------------------------------------ |
|---|
| 87 | def GenerateXST(self): |
|---|
| 88 | SynthesisParametersRange = self.SynthesisSheet.Range("SynthParams").Value |
|---|
| 89 | |
|---|
| 90 | #There is a problem with integer values turning into Floats when accessed using Range("xx:xx").Value, use Formula instead |
|---|
| 91 | #SynthesisParameters = SynthesisSheet.Range(SynthesisParametersRange).Value |
|---|
| 92 | #this xst writer used to have the style "for param,default,setting in SynthesisParameters:" |
|---|
| 93 | |
|---|
| 94 | SynthesisParametersRows = self.SynthesisSheet.Range(SynthesisParametersRange).Rows |
|---|
| 95 | self.xst_file = "%s.xst"%top |
|---|
| 96 | xst_fo = open(self.xst_file, mode='w') |
|---|
| 97 | xst_fo.write("set -tmpdir %s\n" % self.tmpdir) |
|---|
| 98 | xst_fo.write("set -xsthdpdir %s\n" % self.xsthdpdir) |
|---|
| 99 | xst_fo.write("run\n") |
|---|
| 100 | |
|---|
| 101 | for row in SynthesisParametersRows: |
|---|
| 102 | Parameter=row.Columns(1).Value |
|---|
| 103 | |
|---|
| 104 | if row.Columns(3).HasFormula: |
|---|
| 105 | Setting = row.Columns(3).Value |
|---|
| 106 | else: |
|---|
| 107 | Setting = row.Columns(3).Formula |
|---|
| 108 | |
|---|
| 109 | if row.Columns(2).HasFormula: |
|---|
| 110 | Default = row.Columns(2).Value |
|---|
| 111 | else: |
|---|
| 112 | Default = row.Columns(2).Formula |
|---|
| 113 | |
|---|
| 114 | if (Setting != None) and (Setting != ""): |
|---|
| 115 | xst_fo.write("-%s %s\n"%(Parameter,Setting)) |
|---|
| 116 | elif (Default != None) and (Default != ""): |
|---|
| 117 | xst_fo.write("-%s %s\n"%(Parameter,Default)) |
|---|
| 118 | |
|---|
| 119 | xst_fo.close() |
|---|
| 120 | #------------------------------------------------------------------------ |
|---|
| 121 | #End of XST file Generation |
|---|
| 122 | #------------------------------------------------------------------------ |
|---|
| 123 | |
|---|
| 124 | |
|---|
| 125 | |
|---|
| 126 | #------------------------------------------------------------------------ |
|---|
| 127 | #PRJ file Generation |
|---|
| 128 | #------------------------------------------------------------------------ |
|---|
| 129 | def GeneratePRJ(self): |
|---|
| 130 | SrcFilesAddress = ProjectSheet.Range("SrcFiles").Value |
|---|
| 131 | SrcFileArray = ProjectSheet.Range(SrcFilesAddress).Value |
|---|
| 132 | SrcFileList = [] |
|---|
| 133 | for line in SrcFileArray: |
|---|
| 134 | for element in line: |
|---|
| 135 | SrcFileList.append(element) |
|---|
| 136 | |
|---|
| 137 | prj_file = open("%s.prj"%top,mode='w') |
|---|
| 138 | #todo: verilog and vhdl segregation |
|---|
| 139 | for file in SrcFileList: |
|---|
| 140 | line = "vhdl work %s\n" % file #previous version had a path appended... |
|---|
| 141 | prj_file.write(line) |
|---|
| 142 | prj_file.close() |
|---|
| 143 | #------------------------------------------------------------------------ |
|---|
| 144 | #End of PRJ file Generation |
|---|
| 145 | #------------------------------------------------------------------------ |
|---|
| 146 | |
|---|
| 147 | def GenerateLSO(self): |
|---|
| 148 | #Generate LSO file |
|---|
| 149 | lso_file = open ("%s.lso"%top,mode='w') |
|---|
| 150 | lso_file.write('work') |
|---|
| 151 | lso_file.close() |
|---|
| 152 | |
|---|
| 153 | |
|---|
| 154 | def GenerateBitgenOptions(self): |
|---|
| 155 | BitgenParametersRange = self.ConstraintsSheet.Range("ConstraintsRange") |
|---|
| 156 | BitgenParameters = self.ConstraintsSheet.Range(BitgenParametersRange).Formula |
|---|
| 157 | self.bitgen_g_options = [] |
|---|
| 158 | for option,setting in BitgenParameters: |
|---|
| 159 | self.bitgen_g_options.append("%s:%s"%(option,setting)) |
|---|
| 160 | |
|---|
| 161 | |
|---|
| 162 | |
|---|
| 163 | ##bit_gen_g_options.append('DebugBitstream:No') |
|---|
| 164 | ##bit_gen_g_options.append('Binary:no') |
|---|
| 165 | ##bit_gen_g_options.append('CRC:Enable') |
|---|
| 166 | ##bit_gen_g_options.append('ConfigRate:6') |
|---|
| 167 | ##bit_gen_g_options.append('CclkPin:PullUp') |
|---|
| 168 | ##bit_gen_g_options.append('M0Pin:PullUp') |
|---|
| 169 | ##bit_gen_g_options.append('M1Pin:PullUp') |
|---|
| 170 | ##bit_gen_g_options.append('M2Pin:PullUp') |
|---|
| 171 | ##bit_gen_g_options.append('ProgPin:PullUp') |
|---|
| 172 | ##bit_gen_g_options.append('DonePin:PullUp') |
|---|
| 173 | ##bit_gen_g_options.append('TckPin:PullUp') |
|---|
| 174 | ##bit_gen_g_options.append('TdiPin:PullUp') |
|---|
| 175 | ##bit_gen_g_options.append('TdoPin:PullUp') |
|---|
| 176 | ##bit_gen_g_options.append('TmsPin:PullUp') |
|---|
| 177 | ##bit_gen_g_options.append('UnusedPin:PullDown') |
|---|
| 178 | ##bit_gen_g_options.append('UserID:0xFFFFFFFF') |
|---|
| 179 | ###bit_gen_g_options.append('DCMShutDown:Disable') #not available |
|---|
| 180 | ##bit_gen_g_options.append('StartUpClk:CClk') |
|---|
| 181 | ##bit_gen_g_options.append('DONE_cycle:4') |
|---|
| 182 | ##bit_gen_g_options.append('GTS_cycle:5') |
|---|
| 183 | ##bit_gen_g_options.append('GWE_cycle:6') |
|---|
| 184 | ##bit_gen_g_options.append('LCK_cycle:NoWait') |
|---|
| 185 | ##bit_gen_g_options.append('Match_cycle:Auto') |
|---|
| 186 | ##bit_gen_g_options.append('Security:None') |
|---|
| 187 | ##bit_gen_g_options.append('DonePipe:No') |
|---|
| 188 | ##bit_gen_g_options.append('DriveDone:Yes') |
|---|
| 189 | |
|---|
| 190 | def RunSynthesis(self): |
|---|
| 191 | xst_path = os.path.join(XilinxBin,"xst") |
|---|
| 192 | self.SynthesisProcess = subprocess.Popen([xst_path,"-ifn", self.xst_file, "-ofn", "%s_xst_log.syr"%self.top],stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE) |
|---|
| 193 | # xst -ifn CPU_TOP.xst -ofn CPU_TOP_xst_log.syr |
|---|
| 194 | |
|---|
| 195 | def RunTranslate(self): |
|---|
| 196 | ngdbuild_path = os.path.join(XilinxBin,"ngdbuild") |
|---|
| 197 | TranslationSheet |
|---|
| 198 | |
|---|
| 199 | self.TranslateProcess = subprocess.Popen([ngdbuild_path,"-dd", self.tmpdir, "-aul", "-uc", self.ucf_file, "-p", self.part, '%s.ngc'%self.top, '%s.ngd'%self.top]) |
|---|
| 200 | |
|---|
| 201 | # ngdbuild -dd tmp -aul -uc CP11-CPU.ucf -p xc5vlx85-ff676-1 CPU_TOP.ngc CPU_TOP.ngd |
|---|
| 202 | # map -p xc5vlx85-ff676-1 -cm area -pr b -k 4 -c 100 -tx off -o CPU_TOP_map.ncd CPU_TOP.ngd CPU_TOP.pcf |
|---|
| 203 | # par -w -ol std -t 1 CPU_TOP_map.ncd CPU_TOP_par.ncd CPU_TOP.pcf |
|---|
| 204 | |
|---|
| 205 | |
|---|
| 206 | class XSTFile: |
|---|
| 207 | def __init__(self,name): |
|---|
| 208 | if os.path.exists(name): |
|---|
| 209 | self.File = open(name) |
|---|
| 210 | |
|---|
| 211 | |
|---|
| 212 | class Synthesizer: |
|---|
| 213 | def __init__(self): |
|---|
| 214 | self.xst_path = os.path.join(XilinxBin,"xst") |
|---|
| 215 | self.XST_Attr_Map = {} |
|---|
| 216 | |
|---|
| 217 | self.InputFileName |
|---|
| 218 | self.XST_Attr |
|---|
| 219 | self.InputFormat |
|---|
| 220 | |
|---|
| 221 | |
|---|
| 222 | def Run(self): |
|---|
| 223 | RunReq = [self.xst_path,"-ifn", "%s.xst"%top, "-ofn", "%s_xst_log.syr"%top] |
|---|
| 224 | print "Invoking Synthesis Tool: " + RunReq |
|---|
| 225 | self.retcode = subprocess.call(RunReq) |
|---|
| 226 | |
|---|
| 227 | def LogPrint(Port,File): |
|---|
| 228 | ln = Port.readline() |
|---|
| 229 | print ln |
|---|
| 230 | File.write(ln) |
|---|
| 231 | |
|---|
| 232 | def HyperlinkSelection(Excel): |
|---|
| 233 | for cell in Excel.Selection: |
|---|
| 234 | cell.Hyperlinks.Add(cell,cell.Value) |
|---|
| 235 | |
|---|
| 236 | #todo: define classes for each of the synthesis and placement files |
|---|
| 237 | #create XML-RPC interface to marshal and demarshal components and invoke toolchain |
|---|
| 238 | if __name__ == "__main__": |
|---|
| 239 | if run: |
|---|
| 240 | if runXST: |
|---|
| 241 | #Invoke XST |
|---|
| 242 | xst_path = os.path.join(XilinxBin,"xst") |
|---|
| 243 | retcode = subprocess.call([xst_path,"-ifn", "%s.xst"%top, "-ofn", "%s_xst_log.syr"%top]) |
|---|
| 244 | if runNGDBuild: |
|---|
| 245 | #Invoke NGDBuild |
|---|
| 246 | part = '%(device)s-%(package)s-%(speed)s'%globals() |
|---|
| 247 | ngdbuild_path = os.path.join(XilinxBin,"ngdbuild") |
|---|
| 248 | retcode = subprocess.call([ngdbuild_path,"-dd", tmpdir, "-aul", "-uc", ucf_file, "-p", part, '%s.ngc'%top, '%s.ngd'%top]) |
|---|
| 249 | |
|---|
| 250 | if runMAP: |
|---|
| 251 | #Invoke MAP |
|---|
| 252 | map_path = os.path.join(XilinxBin,"map") |
|---|
| 253 | retcode = subprocess.call([map_path, '-p', part, '-cm', 'area', '-pr', 'b', '-k', '4', '-c', '100', '-tx', 'off', '-o', '%s_map.ncd'%top, '%s.ngd'%top, '%s.pcf'%top]) |
|---|
| 254 | if genXDL: |
|---|
| 255 | xdl_path = os.path.join(XilinxBin,"xdl") |
|---|
| 256 | retcode = subprocess.call([xdl_path,'-ncd2xdl','%s_map.ncd'%top]) |
|---|
| 257 | if runPAR: |
|---|
| 258 | #Invoke PAR |
|---|
| 259 | par_path = os.path.join(XilinxBin,"par") |
|---|
| 260 | retcode = subprocess.call([par_path, '-w', '-ol', 'std', '-t', '1', '%s_map.ncd'%top, '%s_par.ncd'%top, '%s.pcf'%top]) |
|---|
| 261 | if genXDL: |
|---|
| 262 | xdl_path = os.path.join(XilinxBin,"xdl") |
|---|
| 263 | retcode = subprocess.call([xdl_path,'-ncd2xdl','%s_par.ncd'%top]) |
|---|
| 264 | if runBitgen: |
|---|
| 265 | #Invoke Bitgen |
|---|
| 266 | bitgen_path = os.path.join(XilinxBin,"bitgen") |
|---|
| 267 | bitgen_arglist = [bitgen_path, '%s_par.ncd'%top,'%s.bit'%top, '-w'] |
|---|
| 268 | for opt in bit_gen_g_options: |
|---|
| 269 | bitgen_arglist.append('-g') |
|---|
| 270 | bitgen_arglist.append('%s'%opt) |
|---|
| 271 | retcode = subprocess.call(bitgen_arglist) |
|---|