#!/usr/bin/python3 """ © IBM Corp. 2020 Licensed under the Apache License, Version 2.0 (the "License"), as modified by the terms below; you may not use the files in this repository except in compliance with the License as modified. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Modified Terms: 1) For the purpose of the patent license granted to you in Section 3 of the License, the "Work" hereby includes implementations of the work of authorship in physical form. 2) Notwithstanding any terms to the contrary in the License, any licenses necessary for implementation of the Work that are available from OpenPOWER via the Power ISA End User License Agreement (EULA) are explicitly excluded hereunder, and may be obtained from OpenPOWER under the terms and conditions of the EULA. Unless required by applicable law or agreed to in writing, the reference design distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Additional rights, including the ability to physically implement a softcore that is compliant with the required sections of the Power ISA Specification, are available at no cost under the terms of the OpenPOWER Power ISA EULA, which can be obtained (along with the Power ISA) here: https://openpowerfoundation.org. Brief explanation of modifications: Modification 1: This modification extends the patent license to an implementation of the Work in physical form – i.e., it unambiguously permits a user to make and use the physical chip. Modification 2: This modification clarifies that licenses for the Power ISA are provided via the (royalty-free) Power ISA EULA, and not under this license. To prevent fragmentation of the Power ISA, the Power ISA EULA requires that Power ISA Cores be licensed consistent with the terms of the Power ISA EULA. By ensuring that rights available via the Power ISA EULA are received under (and subject to) the EULA, this consistency is maintained in accordance with the terms of the EULA. Any necessary additional licenses for the specific Power ISA Core are granted under this modified Apache license. """ from types import MethodType from string import Template import time from ctypes import c_uint32 # ------------------------------------------------------------------------------------------------- # Initialization header = """ * arci v.0.0001 * ----------------------------------------------------------------------------------------- """ header += f'* Generated: {time.strftime("%b %d %Y %I:%M:%S %p %Z", time.gmtime())}\n' header += '*\n' magic = "0x08675309" savespr = "tar" tplFileAsm = 'arcitst.tpl' tstName = 'simple' outFileTst = f'{tstName}.tst' outFileAsm = f'{tstName}.s' # ------------------------------------------------------------------------------------------------- # Process command line # ------------------------------------------------------------------------------------------------- # Classes class Fac: def __init__(self, name, value=None, spr=False, gpr=False, fpr=False, vsr=False, rname=None): self.name = name self.rname = name if rname is None else rname self.init = value self.value = value self.spr = spr self.gpr = gpr self.fpr = fpr self.vsr = vsr self.ref = False self.chg = False facs[name] = self def comment(self): return '' def print(self): lines.append(f'R {self.rname:6} {self.value:08X}') class Op: def __init__(self, name): self.name = name ops[name] = self def fmt(self, val): return f'{val:08X}' def se16(self, v): v = v & 0xFFFF if v > 0x7FFF: v = 0xFFFF0000 + v return v # has to also keep addresses since tst can be sparse when branching (to gen'd label) def addToStream(self): ops.append(self.op) # probs make different Op versions for different formats class Addi(Op): def __init__(self): self.name = 'addi' def do(self, rt, ra, v): self.rt = rt self.ra = ra self.imm = v v = self.se16(v) if ra == 'r0': res = c_uint32(v).value else: res = c_uint32(c_uint32(gpr[ra].value).value + v).value gpr[rt].value = res self.cia = cia.value cia.value += 4 self.nia = cia.value if ra != 'r0': gpr[ra].ref = True gpr[rt].chg = True cia.chg = True self.op = f'{self.name:10s} {self.rt},{self.ra},{self.imm}' self.res = [(gpr[rt].rname, gpr[rt].value, gpr[rt].comment()),(cia.rname, self.nia, cia.comment())] return self def print(self): self.addToStream() lines.append(f'I {self.cia:08X} {self.op}') for i in range(len(self.res)): lines.append(f'R {self.res[i][0]:6} {self.res[i][1]:08X} {self.res[i][2]}') lines.append('') return self class Add(Op): def __init__(self): self.name = 'add' def do(self, rt, ra, rb): self.rt = rt self.ra = ra self.rb = rb res = c_uint32(c_uint32(gpr[ra].value).value + c_uint32(gpr[rb].value).value).value gpr[rt].value = res self.cia = cia.value cia.value += 4 self.nia = cia.value gpr[ra].ref = True gpr[rb].ref = True gpr[rt].chg = True cia.chg = True self.op = f'{self.name:10s} {self.rt},{self.ra},{self.rb}' self.res = [(gpr[rt].rname, gpr[rt].value, gpr[rt].comment()),(cia.rname, self.nia, cia.comment())] return self def print(self): lines.append(f'I {self.cia:08X} {self.op}') for i in range(len(self.res)): lines.append(f'R {self.res[i][0]:6} {self.res[i][1]:08X} {self.res[i][2]}') lines.append('') return self class Add_R(Op): def __init__(self): self.name = 'add.' def do(self, rt, ra, rb): self.rt = rt self.ra = ra self.rb = rb res = c_uint32(c_uint32(gpr[ra].value).value + c_uint32(gpr[rb].value).value).value gpr[rt].value = res if res == 0: cr0 = 0x2 elif res < 0: cr0 = 0x8 else: cr0 = 0x4 cr0 = cr0 | xer.so() cr.value = (cr.value & 0x00FFFFFF) | (cr0 << 28) self.cia = cia.value cia.value += 4 self.nia = cia.value gpr[ra].ref = True gpr[rb].ref = True gpr[rt].chg = True cr.chg = True cia.chg = True self.op = f'{self.name:10s} {self.rt},{self.ra},{self.rb}' self.res = [(gpr[rt].rname, gpr[rt].value,gpr[rt].comment()), (cr.rname, cr.value, cr.comment()), (cia.rname, self.nia, cia.comment())] return self def print(self): lines.append(f'I {self.cia:08X} {self.op}') for i in range(len(self.res)): lines.append(f'R {self.res[i][0]:6} {self.res[i][1]:08X} {self.res[i][2]}') lines.append('') return self # ------------------------------------------------------------------------------------------------- # Helpers # def: print if nonzero # all=True: print all # ref=True: print only if referenced # chg=True: print only if changed def printSPR(all=False, ref=None, chg=None): for k,f in facs.items(): if f.spr: n = f.rname v = f.value c = f.comment() if all or (v != 0 and ref is None and chg is None) or (ref is not None and f.ref == ref) or (chg is not None and f.chg == chg): lines.append(f'R {n:6} {v:08X} {c}') def printRegs(all=False, ref=None, chg=None): for i in range(32): g = gpr[f'r{i}'] n = g.rname v = g.value c = g.comment() if all or (v != 0 and ref is None and chg is None) or (ref is not None and g.ref == ref) or (chg is not None and g.chg == chg): lines.append(f'R {n:6} {v:08X} {c}') def printTest(): for i in range(len(lines)): print(lines[i]) def genAsm(tplFile, asmFile): f = open(tplFile, 'r') tplString = f.read() tpl = Template(tplString) tstData = { 'tst_name': tstName, 'tst_info': 'wtf', 'magic': magic, 'savespr': savespr } for k,f in facs.items(): if f.spr: tstData[f'init_{f.rname.lower()}'] = f'0x{f.init:08X}' tstData[f'expt_{f.rname.lower()}'] = f'0x{f.init:08X}' for i in range(32): v = gpr[f'r{i}'].init tstData[f'init_r{i}'] = f'0x{v:08X}' v = gpr[f'r{i}'].value tstData[f'expt_r{i}'] = f'0x{v:08X}' stream = '' for i in range(len(ops)): stream += f'\t\t\t{ops[i]}\n' tstData['stream'] = stream[0:-1] tpl = tpl.substitute(tstData) f = open(asmFile, "w") f.write(tpl) f.close() # ------------------------------------------------------------------------------------------------- # Create facs and aliases lines = [] facs = {} ops = [] cia = Fac('CIA', 0x120000, spr=True) def commentCR(self): c = '* ' x = f'{self.value:08X}' for i in range(8): c += f'F{i}:{x[i]} ' return c cr = Fac('CR', 0, spr=True) cr.comment = MethodType(commentCR, cr) def xerSO(self): return (self.value & 0x80000000) >> 31 xer = Fac('XER', 0, spr=True) xer.so = MethodType(xerSO, xer) ctr = Fac('CTR', 0xF0000000, spr=True) lr = Fac('LR', 0, spr=True) tar = Fac('TAR', 0, spr=True) #srr0 = Fac('SRR0', 0, spr=True) #srr1 = Fac('SRR1', 0, spr=True) #dar = Fac('DAR', 0, spr=True) #dsisr = Fac('DSISR',0, spr=True) gpr = {} # probs some trick r0 = 'r0' r1 = 'r1' r2 = 'r2' r3 = 'r3' r4 = 'r4' r5 = 'r5' r6 = 'r6' r7 = 'r7' r8 = 'r8' r9 = 'r9' r10 = 'r10' r11 = 'r11' r12 = 'r12' r13 = 'r13' r14 = 'r14' r15 = 'r15' r16 = 'r16' r17 = 'r17' r18 = 'r18' r19 = 'r19' r20 = 'r20' r21 = 'r21' r22 = 'r22' r23 = 'r23' r24 = 'r24' r25 = 'r25' r26 = 'r26' r27 = 'r27' r28 = 'r28' r29 = 'r29' r30 = 'r30' r31 = 'r31' def commentGPR(self): return f'* {self.value:10}' for i in range(32): #name = f'R{i:02}' name = f'r{i}' gpr[name] = Fac(name, 0, gpr=True, rname=f'R{i:02}') gpr[name].comment = MethodType(commentGPR, gpr[name]) # ------------------------------------------------------------------------------------------------- # Create ops cia.ref = True addi = Addi() add = Add() add_r = Add_R() # ------------------------------------------------------------------------------------------------- # Do something lines.append(header) lines.append('* Initialization\n') printSPR(all=True) printRegs(all=True) lines.append('\n* Instructions\n') # phony dumb test addi.do(r3,r3,1).print() addi.do(r3,r3,1).print() addi.do(r3,r3,1).print() addi.do(r4,r0,-3).print() add_r.do(r4,r4,r3).print() lines.append('\n* Results (Changed)\n') printSPR(chg=True) printRegs(chg=True) lines.append('\n* Results\n') printSPR(all=True) printRegs(all=True) # create .tst file printTest() # create .s file genAsm(tplFileAsm, outFileAsm)