def build(self, asm, parsers, stmt, n, length, trace=False): if length != 2: raise assembler.AssemblerError(line=stmt.lineno,\ msg="operand %s S-type explicit length invalid: %s" % (n+1,length)) value = parsers.evaluate_expr(asm, stmt, self.expr, debug=False, trace=trace) if isinstance(value, int): raise assembler.AssemblerError(line=stmt.lineno,\ msg="operand %s S-type value not an address: %s" % (n+1,value)) try: base, disp = asm.bases.find(value, 12, asm, trace=trace) except KeyError: # Could not resolve base register and displacement raise assembler.AssemblerError(line=stmt.lineno,\ msg="operand %s S-type constant could not resolve implied base " "register for location: %s" % (n+1,value)) from None value = (base << 12) + (0xFFF & disp) b = value.to_bytes(2, byteorder="big", signed=False) if __debug__: if trace: print("%s return bytes: %s '%s'" \ % (assembler.eloc(self,"build",module=this_module),len(b),b)) return b
def parse_scope(self,stmt,parser,scope=None,required=False): prsr=self.__fetch_parser(parser) if stmt.opnd_fld: string=stmt.opnd_fld.text else: string=None if scope is not None: scp=scope else: scp=prsr._init_scope(scope=None) scp.statement(stmt) # Tell the scope what statement is being parsed if string is None: if required: raise assembler.AssemblerError(source=stmt.source,line=stmt.lineno,\ msg="required operand field missing") else: return scp # There are operands to parse... try: # Returns a likely subclassed asmfsmbp.AsmFSMScope object return self.__parse(prsr,string,scope=scp) except assembler.AsmParserError as ape: lpos=stmt.opnd_fld.ndx2loc(ape.token.linepos) raise assembler.AssemblerError(source=stmt.source,line=stmt.lineno,\ linepos=lpos.pndx+1,msg=ape.msg) from None
def parse_operands(self,stmt,parser,scope=None,required=False): # If the parse is for operands then the source and string positions # are different than if this is a statement field parse using an FSM-based # parser opnd=stmt.opnd_fld if opnd is not None: loc=opnd.start() source=loc.source string=opnd.text operpos=loc.pndx else: source=stmt.logline.source string=None # Only parse operands if they are actually present in the statement if string is None: if required: raise assembler.AssemblerError(source=source,line=stmt.lineno,\ msg="%s operation required operand field missing" % stmt.instu) else: return None try: # Returns a asmfsmbp.xxxScope object return self.__parse(parser,string,scope=scope) except assembler.AsmParserError as ape: raise assembler.AssemblerError(source=source,line=stmt.lineno,\ msg=ape.msg) from None
def xmode_setting(self, stmt, mode, setting): try: mdict = self.xmode_dir[mode] except KeyError: raise assembler.AssemblerError(line=stmt.lineno,\ msg="XMODE mode not recognized: %s" % mode) from None try: self.__xmode_setting(mode, setting, mdict) except KeyError: raise assembler.AssemblerError(line=stmt.lineno,\ msg="XMODE %s setting invalid: %s" % (mode,setting)) from None
def __source(self, typ, sid, stmtno=None, srcno=0, fixed=False): if len(self._sources) >= self._depth: raise assembler.AssemblerError(line=stmtno,\ msg="nested input source depth reached: %s" % self._depth) src_cls = LineBuffer.source_type[typ] srco = src_cls(typ, sid, srcno=srcno, fixed=fixed) try: srco.init(pathmgr=self._opath, variable=self._env) except SourceError as se: raise assembler.AssemblerError(line=stmtno, msg=se.msg) from None # Input source now ready to be used self.__appendSource(srco)
def evaluate_expr(self,asm,stmt,expr,debug=False,trace=False): try: return expr.evaluate(external=asm,debug=debug,trace=False) except pratt3.PParserError as pe: # Convert PParserError into an AssemblerError. The PParserError object # may contain an object generated by the PParser object without a # source. Before using the src for the AssemblerError we need to # make sure it is valid. If all else fails, simply convert the # ptok to a printable string and use whatever results. raise assembler.AssemblerError(line=stmt.lineno,linepos=pe.pos,msg=pe.msg) \ from None except assembler.LabelError as le: # Convert LabelError into an AssemblerError raise assembler.AssemblerError(line=stmt.lineno,linepos=le.ltok.linepos,\ msg=le.msg) from None
def insert(self, length, inst, bldr, line, signed=False): value = self.value try: bldr.range_check(self.size, value, signed=signed) except RangeCheckError as re: raise assembler.AssemblerError(line=line,\ msg="%s field %s" \ % (self.name,re)) from None # Prepare value for insertion into instruction if needed. if signed: uint = bldr.s2u_int(value, self.size) else: uint = value # This codes takes the field and # positions it for insertion into # the instruction being built # # |0 inst_bits| | # This diagram shows what # | |<-field->| | # this code is doing to # <----------instruction--------------> # accomplish this. # ^ ^ | uint | inst_bits = length * 8 # | | | | unshifted = inst_bits - self.size # | | +<--unshifted # | left | | left_shift = unshifted - self.start # field start->+<---shift---+ to_insert = uint << left_shift # | field | # | in pos. | # This adds the field to the instruction inst |= to_insert return inst # This is the instruction with the new field added to it
def validate(self): logline=self.logline try: logline.validate() except asmcards.LineError as le: raise assembler.AssemblerError(source=le.source,line=self.lineno,\ msg=le.msg) from None
def build(self, asm, parsers, stmt, n, length, trace=False): try: value = parsers.evaluate_expr(asm, stmt, self.expr, debug=False, trace=trace) except assembler.AddrArithError as ae: raise assembler.AssemblerError(line=stmt.lineno,\ msg="operand %s address arithmetic error, %s" \ % (n+1,ae)) assert isinstance(value,(int,assembler.Address)),\ "%s internal calculation of operand %s address expression resulted in an"\ "unsupported value: %s" \ % (assembler.eloc(self,"build",module=this_module),n+1,value) if isinstance(value, assembler.Address): if length not in self.lengths: raise assembler.AssemblerError(line=stmt.lineno,\ msg="operand %s %s-type explicit length invalid for an address "\ "nominal value: %s" % (n+1,self.typ,length)) if value.isAbsolute(): value = value.address else: raise assembler.AssemblerError(line=stmt.lineno,\ msg="operand %s address constant did not evaluate to an "\ "absolute address: %s" % (n+1,value)) # Convert computed address constant to bytes b = value.to_bytes((value.bit_length() // 8) + 1, byteorder="big", signed=False) # Perform left truncation/padding pad = b'\x00' * length bindata = pad + b b = bindata[len(bindata) - length:] if __debug__: if trace: print("%s return bytes: %s '%s'" % (assembler.eloc( self, "build", module=this_module), len(b), b)) return b
def __exhausted(self): # Current source is done try: self._cur_src.fini() except SourceError as se: # This is a fatal uncaught exception raise assembler.AssemblerError(msg=se.msg) from None # Unnest one input source self._sources.pop() if len(self._sources)==0: raise BufferEmpty from None # All sources done, tell the assembler self._cur_src=self._sources[-1]
def newFile(self,filename,stmtno=None): #fname=os.path.abspath(filename) fname=filename # Detection of recursion requires work for src in self._sources: if src._typ!="F": continue if src.fname==fname: raise assembler.AssemblerError(line=stmtno,\ msg="nested file recursion encountered for file: %s" \ % (fname)) # No recursion, safe to add as source self._fileno+=1 self.__source("F",filename,stmtno=stmtno,srcno=self._fileno)
def __parse(self, asm, stmt, field, debug=False): ddebug = self.debug or debug if __debug__: if ddebug: print("%s [%s] field.amp: %s" \ % (assembler.eloc(self,"__parse",module=this_module),\ stmt.lineno,field.amp)) if not field.amp: return field.text pm = asm.PM try: return pm.parse_model(stmt, field, debug=ddebug) except assembler.AsmParserError as ape: raise assembler.AssemblerError(source=stmt.source,line=stmt.lineno,\ msg=ape.msg)
def operand_new(self,gs,trace=False): if trace: cls_str="asmparsers.py - %s.operand_new()" % self.__class__.__name__ print(cls_str) gs.cur_operand=None stmt=gs.stmt if gs.operands==gs.next_oprndx: raise assembler.AssemblerError(line=gs.lineno,msg="too many operands") try: gs.cur_operand=stmt.get_operand(gs.next_oprndx) except IndexError: cls_str="asmparsers.py - %s.new_operand() -" % self.__class__.__name__ raise ValueError("%s INTERNAL operand not supported: %s" \ % (cls_str,gs.next_oprndx)) from None gs.next_oprndx+=1 self.operand_init(gs,trace=trace)
def fields(self, fmt): mach = fmt.mach # Dictionary of machine field definitions my_fields = [] # Determine values for all fixed content fields vector = False for mfield, mf in mach.items(): vector = vector or mf.typ == "V" # Detect vector registers if not mf.fixed: continue try: fixed_value = self.fixed[mfield] except KeyError: # WARNING: this should not occur if msldb has done a proper validation. # Correct the bug in msldb.py if this is raised. raise ValueError("%s instruction definition does not define " "fixed value for field: %s"\ % (eloc(self,"fields",module=this_module),mfield)) fld = Field(mfield=mf, value=fixed_value) my_fields.append(fld) # Process values from statement operands rxb = 0 for mfield in self.soper.mfields: try: mf = mach[mfield] # mf is the msldb.mfield object for which the operand provides its value except KeyError: # WARNING: this should not occur if msldb has done proper validation. # Correct the bug in msldb.py if this is raised. raise ValueError("%s instruction format %s does not define mach " "field: %s" % (eloc(self,"fields",module=this_module),\ fmt.ID,mfield)) mf_typ = mf.typ # This is the machine field type # The Operand object now provides its value for this mfield type value = self.operand.field(mf_typ) if mf_typ == "V": if value < 0 or value > 31: raise assembler.AssemblerError(line=line,\ msg="%s field outside of valid vector register range: %s" \ % (mf.name,value)) vreg = value & 0xF if value > 15: rxb |= mf.rxb fld = Field(mfield=mf, value=vreg) else: fld = Field(mfield=mf, value=value) my_fields.append(fld) # Generate RXB field if required if rxb: try: mf_rxb = mach["RXB"] except KeyError: # WARNING: this should not occur if msldb has done a proper validation. # Correct the bug in msldb.py if this is raised. raise ValueError(\ "%s instruction definition does not define field RXB" \ % assembler.eloc(self,"fields",module=this_module)) fld = Field(mfield=mf_rxb, value=rxb) my_fields.append(fld) return my_fields
def validate_operand(self,line,n,trace=False): operand=self.operand ok=operand.validate_source(self.exprs,trace=trace) if not ok: raise assembler.AssemblerError(line=line,msg=operand.source_error()) return
def Pass0(self,stmt,scope,debug=False): try: scope.Pass0(stmt,self,debug=debug) except assmebler.AsmParserError as ape: raise assembler.AssemblerError(source=stmt.source,line=stmt.lineno,\ linepos=ape.token.linepos+1,msg=ape.msg) from None