Source code for qick.tprocv2_assembler

"""
///////////////////////////////////////////////////////////////////////////////
//  FERMI RESEARCH LAB
///////////////////////////////////////////////////////////////////////////////
//  Date        : 2024_8_2
//  Version     : 3
//  Revision    : 23
///////////////////////////////////////////////////////////////////////////////
Description: Assembler for Qick Processor
-Create Binary Files  ( list2bin, file_asm2bin, str_asm2bin )
-Create Instruction List ( file_asm2list, str_asm2list )
-Create Assembler File from Instruction List ( list2asm )

p_list        = Assembler.file_asm2list(filenames[0])
p_list[0] > program_list
p_list[1] > label_dict

p_txt, p_bin  = Assembler.file_asm2bin(filenames[0])
p_txt > Used for Simulation
p_bin > Used to store in the memory

Get ASM from Program List Structure
p_asm         = Assembler.list2asm(p_list[0], p_list[1])

///////////////////////////////////////////////////////////////////////////////
Release (March 2024)
To be used with qick_processor version 17th or Higher....

"""

###################################
###      UNDER DEVELOPMENT      ###
###################################

##### DEFINITIONS
###############################################################################

# Instructions.
instList = {
        'NOP'        : '000 - No Operation',
        'TEST'       : '000 - Update ALU Flags with an Operation',
        'JUMP'       : '001 - Branch to a Specific Address',
        'CALL'       : '001 - Function Call',
        'RET'        : '001 - Function Return',
        'FLAG'       : '010 - FLAG set / reset',
        'TIME'       : '010 - Time Instruction',
        'ARITH'      : '010 - Opeates (A+/-B)*C+/-D',
        'DIV'        : '010 - Opeates (A/B) Return Quotient and Reminder',
        'NET'        : '011 - Network Peripheral Instruction',
        'COM'        : '011 - Communication Peripheral Instruction',
        'PA'         : '011 - Cutsom Peripheral Instruction',
        'PB'         : '011 - Cutsom Peripheral Instruction',
        'REG_WR'     : '100 - Register Write',
        'DMEM_WR'    : '101 - Data Memory Write',
        'WMEM_WR'    : '101 - WaveParam Memory Write',
        'TRIG'       : '110 - Trigger Set',
        'DPORT_WR'   : '110 - Data Port Write',
        'DPORT_RD'   : '110 - Data Port Read',
        'WPORT_WR'   : '110 - WaveParam Port Write',
        'CLEAR'      : 'Complex Clear Flag (dt_new).',
        'WAIT'       : 'Complex - Jump [HERE] Until time value arrives.'
        }

# ALU OPERATIONS 
aluList = {
        '+'     : '0000',
        '-'     : '0010',
        'AND'   : '0100',
        '&'     : '0100',
        'MSK'   : '0100',
        'ASR'   : '0110',
        'ABS'   : '1000',
        'MSH'   : '1010',
        'LSH'   : '1100',
        'SWP'   : '1110',
        'NOT'   : '0001',
        '!'     : '0001',
        'OR'    : '0011',
        '|'     : '0011',
        'XOR'   : '0101',
        '^'     : '0101',
        'CAT'   : '0111',
        '::'    : '0111',
        'RFU'   : '1001',
        'PAR'   : '1011',
        'SL'    : '1101',
        '<<'    : '1101',
        'SR'    : '1111',
        '>>'    : '1111' }

aluList_s = {
        '+'   : '00',
        '-'   : '01',
        'AND' : '10',
        'ASR' : '11' } ## List with Commands for -op()

aluList_op = ['ABS', 'MSH', 'LSH', 'SWP', 'PAR', 'NOT'] ## List with Commands with one parameter

arithList = { 
'T'   : '0000', #  A*B
'TP'  : '0001', #  A*B+C
'TM'  : '0010', #  A*B-C
'PT'  : '0011', # (D+A)*B
'PTP' : '0100', # (D+A)*B+C
'PTM' : '0101', # (D+A)*B-C
'MT'  : '0110', # (D-A)*B
'MTP' : '0111', # (D-A)*B+C
'MTM' : '1000', # (D-A)*B-C
}

# CONDITIONALS
condList = {
    '1'   : '000',
    'Z'   : '001',
    'S'   : '010',
    'NZ'  : '011',
    'NS'  : '100',
    'F'   : '101',
    'NF'  : '110',
    '0'   : '111'}

#### REGULAR EXPRESSIONS
###############################################################################

# LIT SHOULD BE LAST
Param_List = { 
    'TIME'      : {'RegEx' : r'(?<=@)[\-0-9]+'               , 'RL': '@'        , 'RR': ''   },
    'ADDR'      : {'RegEx' : r'\[(.*)\]'                     , 'RL': '['        , 'RR': ']'  },
    'UF'        : {'RegEx' : r'-uf'                          , 'RL': ''         , 'RR': ''   },
    'WW'        : {'RegEx' : r'-ww'                          , 'RL': ''         , 'RR': ''   },
    'WP'        : {'RegEx' : r'-wp\(([_a-z\s]*)\)'           , 'RL': '-wp('     , 'RR': ')'  },
    'OP'        : {'RegEx' : r'-op\(([\s#a-zA-Z0-9+\-<>_]*)\)', 'RL': '-op('     , 'RR': ')'  }, 
    'IF'        : {'RegEx' : r'-if\(([A-Z\s]*)\)'            , 'RL': '-if('     , 'RR': ')'  },
    'WR'        : {'RegEx' : r'-wr\(([a-z\s0-9]*)\)'         , 'RL': '-wr('     , 'RR': ')'  },
    'PORT'      : {'RegEx' : r'p([0-9]+)'                    , 'RL': 'p'        , 'RR': ''   },
    'LIT'       : {'RegEx' : r'(?<=#)[ubh0-9ABCDEF\-_]+'      , 'RL': '#'        , 'RR': ''   },
}

Alias_List = { 
## REGISTER NAME
   'w_freq'        : 'w0'  ,
   'w_phase'       : 'w1'  ,
   'w_env'         : 'w2'  ,
   'w_gain'        : 'w3'  ,
   'w_length'      : 'w4'  ,
   'w_conf'        : 'w5'  ,
   'zero'          : 's0'  ,
   's_zero'        : 's0'  ,
   's_rand'        : 's1'  ,
   's_cfg'         : 's2'  ,
   's_ctrl'        : 's2'  ,
   's_arith_l'     : 's3'  ,
   's_div_q'       : 's4'  ,
   's_div_r'       : 's5'  ,
   's_core_r1'     : 's6'  ,
   's_core_r2'     : 's7'  ,
   's_port_l'      : 's8'  ,
   's_port_h'      : 's9'  ,
   's_status'      : 's10' ,
   's_usr_time'    : 's11' ,
   'curr_usr_time' : 's11' ,
   's_core_w1'     : 's12' ,
   's_core_w2'     : 's13' ,
   'out_usr_time'  : 's14' ,
   's_out_time'    : 's14' ,
   's_addr'        : 's15' ,
## Status
   'bit_arith_rdy' : '#h0001' ,
   'bit_arith_new' : '#h0002' ,
   'bit_div_rdy'   : '#h0004' ,
   'bit_div_new'   : '#h0008' ,
   'bit_qnet_rdy'  : '#h0010' ,
   'bit_qnet_new'  : '#h0020' ,
   'bit_qcom_rdy'  : '#h0040' ,
   'bit_qcom_new'  : '#h0080' ,
   'bit_qpa_rdy'   : '#h0100' ,
   'bit_qpa_new'   : '#h0200' ,
   'bit_qpb_rdy'   : '#h0400' ,
   'bit_qpb_new'   : '#h0800' ,
   'bit_port_new'  : '#h8000' ,
## Config
   'cfg_src_axi'       : '#h00' ,
   'cfg_src_arith'     : '#h01' ,
   'cfg_src_qnet'      : '#h02' ,
   'cfg_src_qcom'      : '#h03' ,
   'cfg_src_qpa'       : '#h04' ,
   'cfg_src_qpb'       : '#h05' ,
   'cfg_src_core'      : '#h06' ,
   'cfg_src_port'      : '#h07' ,
   'cfg_flg_int'       : '#h00' ,
   'cfg_flg_axi'       : '#h10' ,
   'cfg_flg_ext'       : '#h20' ,
   'cfg_flg_div'       : '#h30' ,
   'cfg_flg_arith'     : '#h30' ,
   'cfg_flg_port'      : '#h40' ,
   'cfg_flg_qnet'      : '#h50' ,
   'cfg_flg_qcom'      : '#h60' ,
   'cfg_flg_qpa'       : '#h70' ,
   'cfg_src_flg_arith' : '#h31' ,
   'cfg_src_flg_qnet'  : '#h52' ,
   'cfg_src_flg_qcom'  : '#h63' ,
   'cfg_src_flg_qpa'   : '#h76' ,
## CTRL
   'ctrl_clr_arith'   : ' #h1_0000'   ,
   'ctrl_clr_div'     : ' #h2_0000'   ,
   'ctrl_clr_qnet'    : ' #h4_0000'   ,
   'ctrl_clr_qcom'    : ' #h8_0000'   ,
   'ctrl_clr_qpa'     : '#h10_0000'   ,
   'ctrl_clr_qpb'     : '#h20_0000'   ,
   'ctrl_clr_port'    : '#h40_0000'   ,
   'clr_all'          : '#h7F_0000'   ,
   'ctrl_csf_arith'   : '#h01_00_3_1' ,
   'ctrl_csf_div'     : '#h02_00_3_0' ,
   'ctrl_csf_qnet'    : '#h04_00_5_2' ,
   'ctrl_csf_qcom'    : '#h08_00_6_3' ,
   'ctrl_csf_qpa'     : '#h10_00_7_4' 
}


regex = {
    'LABEL'     : r'[A-Za-z0-9_]+(?=\:)' , 
    'DIRECTIVE' : r'(?<=\.)[A-Z]+'       , 
    'CMD'       : r'^[A-Z_]+'            , 
    'CNAME'     : r'^[A-Za-z_]+'         , # Name for CONSTANT
    'NAME'      : r'^[A-Za-z0-9_]+'      , # Name for ALIAS AND LABEL
    'LIT'       : r'(?<=#)[ubh0-9ABCDEF\-_]+',
    'CDS'       : r'\s*([\w&\+\']+)'}

import re
import copy
import logging

logger = logging.getLogger(__name__)

def find_pattern(regex : str, text : str):
    match = re.search(regex, text)
    match = match.group() if (match) else None
    return match

def check_name(name_str : str) -> bool:
    # Check for correct Characters
    name_check = re.findall(regex['NAME'], name_str)
    if not name_check:
        raise RuntimeError('CHECK_NAME, Name Error: ' + name_str)
    name_check = name_check[0]
    if (name_check != name_str):
        raise RuntimeError('CHECK_NAME, Name should use AlphaNumeric and _ characters: ' + name_str)
    # Check for Register Name
    if ( check_reg(name_str) ):
        raise RuntimeError('CHECK_NAME, Name can not be a Register name: ' + name_str)
    return True

[docs]def parse_labels(program_list : list, label_dict : dict) -> None: """add addresses for labels in command arguments """ for command in program_list: if 'LABEL' in command and 'ADDR' not in command: if command['LABEL'] in label_dict: command['ADDR'] = label_dict[ command['LABEL'] ] elif command['LABEL'] == 'PREV': command['ADDR'] = "&%d" % (command['P_ADDR'] - 1) elif command['LABEL'] == 'HERE': command['ADDR'] = "&%d" % (command['P_ADDR']) elif command['LABEL'] == 'NEXT': command['ADDR'] = "&%d" % (command['P_ADDR'] + 1) elif command['LABEL'] == 'SKIP': command['ADDR'] = "&%d" % (command['P_ADDR'] + 2) else: raise RuntimeError('unrecognized label %s (should be a defined label, or PREV/HERE/NEXT/SKIP'%(command['LABEL']))
[docs]def integer2bin(strin : str, bits : int = 8, uint : int = 0) -> str: """ receives an integer in str format and returns their bits as a string. :strin (str): string with an integer :bits (int): number of bits to return :uint (int): is unsigned :returns (str): bits as a string """ if (uint == 0): minv = -2**(bits-1) maxv = 2**(bits-1) - 1 else: minv = 0 maxv = 2**(bits) - 1 dec = int(strin, 10) # Check max. if dec < minv: raise RuntimeError("integer2bin: number %d is smaller than %d" % (dec, minv)) # Check max. if dec > maxv: raise RuntimeError("integer2bin: number %d is bigger than %d" % (dec, maxv)) # Check if number is negative. if dec < 0: dec = dec + 2**bits # Convert to binary. fmt = "{0:0" + str(bits) + "b}" binv = fmt.format(dec) return binv
[docs]def get_src_type (src : str) -> str: """ :returns (tuple): Type of Source """ src_type = 'X' REG = re.findall('s(\d+)|r(\d+)|w(\d+)|#([ubh0-9A-F\-]+)',src) #S,R,W,Signed, Unsigned, Binary, Hexa if not REG: raise RuntimeError('get_src_type: Source Data not Recognized '+src ) #print('Register Type> ',REG, REG[0]) if ( len(REG) != 1 ): raise RuntimeError('get_src_type: Source Data not Recognized '+src ) REG = REG[0] if (REG[0]): src_type = 'RS' elif (REG[1]): src_type = 'RD' elif (REG[2]): src_type = 'RW' elif (REG[3]): src_type = 'N' else: src_type = 'XX' return src_type
def check_num(num_str : str) -> bool: r = False num = re.search('^(\d+)', num_str) extr_num = num.group(0) if num else '' if (extr_num == num_str): r = True return r def check_lit(lit_str : str) -> bool: r = False lit = re.search('#(-?\d+)|#u(\d+)|#b(\d+)|#h([0-9A-F]+)|&(\d+)|@(-?\d+)', lit_str) extr_lit = lit.group(0) if lit else '' if (extr_lit == lit_str): r = True return r def get_imm_dt (lit : str, bit_len : int, lit_val : int = 0) -> str: LIT = re.findall('#(-?\d+)|#u(\d+)|#b(\d+)|#h([0-9A-F]+)|&(\d+)|@(-?\d+)',lit) #S,R,W,Signed, Unsigned, Binary, Hexa if ( not LIT or not check_lit(lit)): raise RuntimeError("get_imm_dt: Data Format incorrect "+ lit ) LIT = LIT[0] try: if (LIT[0]): ## is Signed literal = str(int(LIT[0])) DataImm = '_'+ integer2bin(literal, bit_len) elif (LIT[1]): ## is Unsigned literal = str(int(LIT[1])) DataImm = '_'+ integer2bin(literal, bit_len,1) elif (LIT[2]): ## is Binary literal = str(int(LIT[2],2)) DataImm = '_'+ integer2bin(literal, bit_len,1) elif (LIT[3]): ## is Hexa literal = str(int(LIT[3],16)) DataImm = '_'+ integer2bin(literal, bit_len,1) elif (LIT[4]): ## is Address literal = str(int(LIT[4])) DataImm = '_'+ integer2bin(literal, bit_len,1) elif (LIT[5]): ## is Time literal = str(int(LIT[5])) DataImm = '_'+ integer2bin(literal, bit_len) else: raise RuntimeError("get_imm_dt: Data Format incorrect "+ lit ) except: raise RuntimeError("get_imm_dt: Data Format incorrect "+ lit ) if (lit_val) : return int(literal) else: return DataImm def check_reg(name_reg : str) -> bool: r = False name = re.search('s(\d+)|r(\d+)|w(\d+)', name_reg) extr_reg = name.group(0) if name else '' if (extr_reg == name_reg): r = True return r
[docs]def get_reg_addr (reg : str, Type : str) -> str: """ :returns: register_address. """ if not check_reg(reg): #extr_num == name_num): raise RuntimeError('get_reg_addr: Register '+ reg +' Name error' ) REG = re.findall('s(\d+)|r(\d+)|w(\d+)', reg)[0] if (Type=='Dest'): if (REG[0]): ## is SREG if (int(REG[0]) > 15): raise RuntimeError('get_reg_addr: Register s'+ str(REG[0])+' is not a sreg (Max 15)' ) return '00'+integer2bin(REG[0], 5,1) elif (REG[1]): ## is DREG if (int(REG[1]) > 31): raise RuntimeError('get_reg_addr: Register d'+ str(REG[1])+' is not a dreg (Max 31)' ) return '01'+integer2bin(REG[1], 5,1) elif (REG[2]): ## is WREG if (int(REG[2]) > 5): raise RuntimeError('get_reg_addr: Register w'+ str(REG[2])+' is not a wreg (Max 5)' ) return '10'+integer2bin(REG[2], 5,1) elif (Type=='src_data'): if (REG[0]): ## is SREG if (int(REG[0]) > 15): raise RuntimeError('get_reg_addr: Register s'+ str(REG[0])+' is not a sreg (Max 15)' ) return '0_00'+integer2bin(REG[0], 5,1) elif (REG[1]): ## is DREG if (int(REG[1]) > 31): raise RuntimeError('get_reg_addr: Register d'+ str(REG[1])+' is not a dreg (Max 31)' ) return '0_01'+integer2bin(REG[1], 5,1) elif (REG[2]): ## is WREG if (int(REG[2]) > 5): raise RuntimeError('get_reg_addr: Register w'+ str(REG[1])+' is not a wreg (Max 5)' ) return '0_10'+integer2bin(REG[2], 5,1) elif (Type=='src_addr'): if (REG[0]): ## is SREG if (int(REG[0]) > 15): raise RuntimeError('get_reg_addr: Register s'+ str(REG[0])+' is not a sreg (Max 15)' ) return '0'+integer2bin(REG[0], 5,1) elif (REG[1]): ## is DREG if (int(REG[1]) > 31): raise RuntimeError('get_reg_addr: Register d'+ str(REG[1])+' is not a dreg (Max 31)' ) return '1'+integer2bin(REG[1], 5,1) elif (REG[2]): ## is WREG if (int(REG[2]) > 5): raise RuntimeError('get_reg_addr: Register w'+ str(REG[2])+' is not a wreg (Max 5)' ) raise RuntimeError('get_reg_addr: Register w'+ str(REG[2])+' Can not be wreg' ) return 'X'
class LFSR: def __init__(self): self.val_bin = '00000000000000000000000000000000' self.val_int = 0 def seed(self, seed): fmt = "{0:032b}" self.val_int = seed self.val_bin = fmt.format(seed) def nxt(self)-> int: inv_bin = self.val_bin[::-1] feedback = inv_bin[31] + inv_bin[21] + inv_bin[1] + inv_bin[0] ones = feedback.count('1') if (ones % 2 == 0): new_value = '1' else: new_value = '0' self.val_bin = self.val_bin[1:]+new_value self.val_int = int(self.val_bin, 2) return self.val_int def print (self, debug=False): if not debug: print (self.val_bin, self.val_int) else: print ('Bin: %32s / Hex: %8x / Dec: %0d' %(self.val_bin, self.val_int, self.val_int)) class Assembler(): WAIT_TIME_OFFSET = 10 @staticmethod def list2asm(program_list : list, label_dict : dict) -> str: """ translates a program list to assembly. :program_list (list): each element is a dictionary with all the commands and instructions. :label_dict (dictionary): dictionary with all labels information found. ({'P_ADDR': 0,'LINE': 0, 'ADDR': 0}) :returns (str): assembly as a string. """ def process_command(command : dict, p_addr : int) -> str: """ processes one command from program list and adds it to the assembler string as an instruction. :command (dict): current instruction from program_list to add in assembler :p_addr (int): program address of the command in memory. // p_addr stands for program address. :returns (str): returns the new line of assembler code """ logger.debug("process_command: processing %s at p_addr=%d"%(command, p_addr)) assembler = "" assembler += "RET\n" if (command['CMD']=='RET') else f" {command['CMD']} " if (command['CMD'] == 'DPORT_WR') or (command['CMD']=='WPORT_WR') or (command['CMD']=='TRIG') or (command['CMD']=='DPORT_RD'): assembler += 'p'+command['DST'] + ' ' elif ('DST' in command): assembler += command['DST'] + ' ' assembler += f"{command['SRC']} " if ('SRC' in command) else '' assembler += f"{command['DATA']} " if ('DATA' in command) else '' if ('ADDR' in command): if (not 'LABEL' in command): if ( f"&{p_addr-1}" == command['ADDR'] and command['CMD'] == 'JUMP'): assembler += "PREV " elif ( f"&{p_addr}" == command['ADDR'] and command['CMD'] == 'JUMP'): assembler += "HERE " elif ( f"&{p_addr+1}" == command['ADDR'] and command['CMD'] == 'JUMP'): assembler += "NEXT " elif ( f"&{p_addr+2}" == command['ADDR'] and command['CMD'] == 'JUMP'): assembler += "SKIP " else: assembler += f"[{command['ADDR']}] " assembler += f"{command['LABEL'] } " if ('LABEL' in command) else '' assembler += f"-if({command['IF']}) " if ('IF' in command) else '' assembler += f"-wr({command['WR']}) " if ('WR' in command) else '' assembler += f"{command['LIT']} " if ('LIT' in command) else '' assembler += f"-op({command['OP']}) " if ('OP' in command) else '' assembler += "-uf " if ('UF' in command and command['UF']=='1') else '' assembler += "-ww " if ('WW' in command) else '' assembler += f"-wp({command['WP']}) " if ('WP' in command) else '' assembler += f"p{command['PORT']} " if ('PORT' in command) else '' assembler += f"{command['TIME']} " if ('TIME' in command) else '' assembler += f"{command['NUM']} " if ('NUM' in command) else '' if ('DEN' in command): assembler += '#' if (command['DEN'][0] != 'r') else '' assembler += f"{command['DEN']} " assembler += f"{command['C_OP']} " if ('C_OP' in command) else '' assembler += f"{command['R1']} " if ('R1' in command) else '' assembler += f"{command['R2']} " if ('R2' in command) else '' assembler += f"{command['R3']} " if ('R3' in command) else '' assembler += f"{command['R4']} " if ('R4' in command) else '' logger.debug("process_command: generated ASM string: %s"%(assembler)) assembler += '\n' return assembler # make a copy of the program list before parse_labels modifies it program_list = copy.deepcopy(program_list) # add label addresses parse_labels(program_list, label_dict) assembler_code = '' key_list = list(label_dict.keys()) val_list = list(label_dict.values()) wait_cnt = 0 for ind, command in enumerate(program_list, start=1): # CHECK FOR LABEL IN THAT MEMORY PLACE address = command['P_ADDR'] if ('P_ADDR' in command) else (ind+wait_cnt) # set correct instruction address in memory. if ( command['CMD'] == 'WAIT'): wait_cnt = wait_cnt + 1 # LABEL in the Correct Line PADDR = '&' + str(address) if (PADDR in val_list): label = key_list[val_list.index(PADDR)] if (label[0:2]=='F_' or label[0:2]=='S_' or label[0:2]=='T_'): label = '\n' + label assembler_code += label + ':\n' # CHECK FOR LABEL SOURCE if ('SRC' in command): if (command['SRC'] =='label'): ADDR = command['ADDR'] if (ADDR in val_list): label = key_list[val_list.index(ADDR)] #command.pop['ADDR'] command['LABEL'] = label assembler_code += process_command(command, address) return assembler_code @staticmethod def file_asm2list(filename : str) -> tuple: """ takes in a filename to open it and remove all comments. returns it as a list of strings containing each line parsed. :filename (str): file to open and parse :returns (list): list with all lines of the original file stripped except comments (//). """ parsed_file = [] with open(filename, 'r') as f: for line in f.readlines(): comment = line.find("//") if (comment >= 0): line = line[:comment] parsed_file.append(line.strip()) program_list, label_dict = Assembler.get_list(parsed_file) return (program_list, label_dict) def str_asm2list(asm_str : str) -> tuple: x = asm_str.splitlines() parsed_asm = [] for line in x: comment = line.find("//") if (comment >= 0): line = line[:comment] parsed_asm.append(line.strip()) program_list, label_dict = Assembler.get_list(parsed_asm) return (program_list, label_dict) def get_list(asm_str : str) -> tuple: """ process the asm and return the program instructions as a list of dictionaries with the labels. :assembler string (asm_str): string with the ASM. :returns (tuple): (program_list, label_dict) :program_list (list): program instructions as a list of dictionaries. :label_dict (dict): dictionary with all labels found plus their memory address in program memory. ({'LABEL': '&0'}) """ def label_recognition(file_lines : list) -> (dict, list): """ gets and returns all labels from file. IMPORTANT: This function updates 'Alias_List'. :file_lines (list): file as a list of strings, each element represents a new line. (should be stripped) :returns (tuple): (label_dictionary, label_line_idxs :label_dictionary (dict): dictionary with all labels found plus their memory address in program memory. ({'LABEL': '&0'}) :label_line_idxs (list): line numbers with labels, to be skipped in command interpretation """ label_dict = {} label_line_idxs = [] mem_addr = 1 # address 0 goes NOP # Check if LABEL, DIRETIVE OR INSTRUCTION for line_number, command in enumerate(file_lines, start=1): if (command): label = find_pattern(regex['LABEL'], command) directive = find_pattern(regex['DIRECTIVE'], command) instruction = find_pattern(regex['CMD'], command) if (label): # add label to label_dict if not already registered. L_Name = command[:-1] if not check_name(L_Name): raise RuntimeError('LABEL_RECOGNITION: Label Name error in line ' + str(line_number) ) if label in label_dict: raise RuntimeError('LABEL_RECOGNITION: Label "' + label + '" already in use as LABEL in line ' + str(line_number) ) if label in Alias_List: raise RuntimeError('LABEL_RECOGNITION: Label "' + label + '" already in use as ALIAS in line ' + str(line_number) ) if (label == 'reg'): raise RuntimeError('LABEL_RECOGNITION: reg is not a valid label in line ' + str(line_number) ) label_dict[label] = '&' + str(mem_addr) label_line_idxs.append(line_number) elif (directive): # identify Aliases and adds them to Alias_List. if ( directive == 'ALIAS'): directive_params = list(filter(lambda x:x, command.split(' '))) if len(directive_params) != 3: raise RuntimeError('DIRECTIVE_RECOGNITION: ALIAS Parameters error in line ' + str(line_number) ) A_Name = directive_params[1] A_Reg = directive_params[2] if not check_name(A_Name): raise RuntimeError('DIRECTIVE_RECOGNITION: Alias Name Error in line ' + str(line_number) ) if A_Name in Alias_List: raise RuntimeError('DIRECTIVE_RECOGNITION: Alias "' + A_Name +'" already in use as ALIAS in line ' + str(line_number) ) if A_Name in label_dict: raise RuntimeError('DIRECTIVE_RECOGNITION: Alias "' + A_Name +'" already in use as LABEL in line ' + str(line_number) ) if not check_reg(A_Reg): raise RuntimeError('DIRECTIVE_RECOGNITION: Register Name error in line ' + str(line_number) ) Alias_List.update({ A_Name : A_Reg } ) logger.info("ALIAS_RECOGNITION: > " + A_Reg + ' is called ' + A_Name) elif ( directive == 'CONST'): directive_params = list(filter(lambda x:x, command.split(' '))) if len(directive_params) != 3: raise RuntimeError('DIRECTIVE_RECOGNITION: CONST Parameters error in line ' + str(line_number) ) C_name = directive_params[1] C_val = directive_params[2] if not check_name(C_name): raise RuntimeError('DIRECTIVE_RECOGNITION: Alias Name Error in line ' + str(line_number) ) if C_name in Alias_List: raise RuntimeError('DIRECTIVE_RECOGNITION: Const "' + C_name +'" already in use as ALIAS in line ' + str(line_number) ) if C_name in label_dict: raise RuntimeError('DIRECTIVE_RECOGNITION: Const "' + C_name +'" already in use as LABEL in line ' + str(line_number) ) lit_val = get_imm_dt (C_val, 32, 1) #if error: # raise RuntimeError('DIRECTIVE_RECOGNITION: CONST '+C_name+' Value '+C_val+' is not a Literal in line ' + str(line_number) ) Alias_List.update({ C_name : C_val } ) logger.info("DIRECTIVE_RECOGNITION: > " + C_val + ' is called ' + C_name) elif ( directive == 'ADDR'): directive_params = list(filter(lambda x:x, command.split(' '))) if len(directive_params) != 2: raise RuntimeError('DIRECTIVE_RECOGNITION: ADDR Parameters error in line ' + str(line_number) ) if not check_num(directive_params[1]): raise RuntimeError('DIRECTIVE_RECOGNITION: Address Value '+ directive_params[1] + ' error in Line ' + str(line_number)) Value = int(directive_params[1]) distance = Value - mem_addr if (distance < 0): raise RuntimeError('DIRECTIVE_RECOGNITION: New Memory Address '+str(Value)+ ' before than next empty address ('+str(mem_addr)+') in Line ' + str(line_number)) mem_addr = Value elif ( directive == 'END'): mem_addr += 1 else: raise RuntimeError('DIRECTIVE_RECOGNITION: Directive Not Recognized in Line ' + str(line_number)) elif (instruction): # Identify instructions to correctly set addresses. if instruction not in instList.keys(): raise RuntimeError('CMD_RECOGNITION: Command Not Recognized in Line ' + str(line_number)) if (instruction == 'WAIT'): mem_addr += 2 else: mem_addr += 1 else: raise RuntimeError('CMD_RECOGNITION: Instruction Not Recognized in Line ' + str(line_number)) show_info = ('\n## ALIAS LIST') show_info += '\n' + ('###############################') show_info += '\n' + ('REG > ALIAS NAME\n-----|-------------') for key in Alias_List: show_info += '\n' + str( (f"{Alias_List[key]:<3}" + ' > '+ key) ) show_info += '\n' + ('###############################') logger.debug("ALIAS_RECOGNITION: "+show_info) show_info = ('\n## LABEL LIST ') show_info += '\n' + ('###############################') show_info += '\n' + ('LABEL NAME > PMEM ADDRESS\n-----------------|------------- ') for key in label_dict: show_info += '\n' + str( (f"{key:<15}" + ' > ' + label_dict[key]) ) show_info += '\n' + ('###############################') logger.debug("LABEL_RECOGNITION: "+show_info) return label_dict, label_line_idxs def command_recognition(file_lines : list, label_line_idxs : list) -> list: """ gets and returns all commands from file. IMPORTANT: Uses 'Alias_List', 'Param_List'. :file_lines (list): file as a list of strings, each element represents a new line. (should be stripped) :label_line_idxs (list): line numbers with labels, to be skipped in command interpretation :returns: program_list :program_list (list): program instructions as a list of dictionaries. """ program_list = [{'P_ADDR': 0, 'CMD': 'NOP'}] mem_addr = 0 for line_number, command in enumerate(file_lines, start=1): command_info = {} instruction = find_pattern(regex['CMD'], command) directive = find_pattern(regex['DIRECTIVE'], command) if ((not command) or (line_number in label_line_idxs)): continue elif (directive): if ( directive == 'END'): mem_addr += 1 command_info = { 'LINE' : line_number, 'P_ADDR' : mem_addr, 'ADDR' : F"&{str(mem_addr)}", 'CMD' : 'JUMP' } program_list.append(command_info) logger.debug("COMMAND_RECOGNITION: END OF PROGRAM") elif ( directive == 'ADDR'): ## Already Verified on Label Recognition directive_params = list(filter(lambda x:x, command.split(' '))) Value = int(directive_params[1]) distance = Value - mem_addr for ind in range(distance-1): mem_addr += 1 command_nop = {} command_nop['P_ADDR'] = mem_addr command_nop['LINE'] = line_number command_nop['CMD'] = 'NOP' program_list.append(command_nop) elif (instruction): if instruction not in instList.keys(): raise RuntimeError(f"COMMAND_RECOGNITION: < {instruction} > is not a Recognized Command in Line " + str(line_number)) mem_addr += 1 command_info['P_ADDR'] = mem_addr # CHECK for Literal Values ############################################################### LIT = re.findall(regex['LIT'], command) if (LIT and len(LIT) == 2 and LIT[0] != LIT[1]): raise RuntimeError('COMMAND_RECOGNITION: Literals not equals in Line ' + str(line_number)) # CHANGE ALIAS ############################################################### cmd_words = re.split(' |\(|\)|\[|\]', command) for key in Alias_List: CHANGE = find_pattern(key, command) if (key in cmd_words): command = command.replace(CHANGE, Alias_List[key]) if CHANGE else command # Extract PARAMETERS ############################################################### command_info['LINE'] = line_number # Stores Line Number for ERROR Messages for key in Param_List: PARAM = re.findall(Param_List[key]['RegEx'], command) if PARAM: if (len(PARAM) >1): raise RuntimeError('COMMAND_RECOGNITION: Duplicated Parameter ' + key +' in line '+str(line_number)) command_info[key] = PARAM[0].strip() aux = Param_List[key]['RL'] + PARAM[0] + Param_List[key]['RR'] command = command.replace(aux, '') # COMMANDS PARAMETERS CHECK ############################################################### CMD_DEST_SOURCE = re.findall(regex['CDS'], command) ## SINGLE PARAMETERS CHECK ########################################################### if ('OP' in command_info): comp_OP_PARAM = "#b(\d+)" param_op = re.findall(comp_OP_PARAM, command_info['OP']) if param_op: try: str(int(param_op[0],2)) except ValueError: raise RuntimeError("COMMAND_RECOGNITION: Binary value incorrect in Line " + str(line_number)) if ('LIT' in command_info) : # Remove underscores command_info['LIT'] = command_info['LIT'].replace('_','') # Check if Binary OK if (command_info['LIT'][0] == 'b'): try: command_info['LIT'] = str(int(command_info['LIT'][1:],2)) except ValueError: raise RuntimeError("COMMAND_RECOGNITION: Binary value incorrect in Line " + str(line_number)) command_info['LIT'] = '#' + command_info['LIT'] ########################################################### if ('TIME' in command_info) : command_info['TIME'] = '@' + command_info['TIME'] ########################################################### if ('WW' in command_info) : command_info['WW'] = '1' ########################################################### if ('UF' in command_info) : command_info['UF'] = '1' if not('OP' in command_info): raise RuntimeError("COMMAND_RECOGNITION: No Operation < -op() > set for Flag Update < -uf > in Line " + str(line_number)) ## COMMAND VERIFICATION ########################################################### if (CMD_DEST_SOURCE[0] == 'REG_WR'): if (len(CMD_DEST_SOURCE) <= 2): raise RuntimeError("COMMAND_RECOGNITION: " + CMD_DEST_SOURCE[0] + " Not enough parameters in Line " + str(line_number)) if (CMD_DEST_SOURCE[1] == 'r_wave'): if ('TIME' in command_info): raise RuntimeError("COMMAND_RECOGNITION: " + CMD_DEST_SOURCE[0] + " Instruction is NOT a timed intruction < -@Time > in Line " + str(line_number)) else: if ('WP' in command_info): raise RuntimeError("COMMAND_RECOGNITION: Not allowed Write Port < -wp() > in Line " + str(line_number)) if ('WR' in command_info): raise RuntimeError("COMMAND_RECOGNITION: Not allowed Write Register < -wr() > in Line " + str(line_number)) if ('WW' in command_info): raise RuntimeError("COMMAND_RECOGNITION: Not allowed Write WaveMemory < -ww() > in Line " + str(line_number)) if ('TIME' in command_info): raise RuntimeError("COMMAND_RECOGNITION: " + CMD_DEST_SOURCE[0] + " Instruction is NOT a timed intruction < -@Time > in Line " + str(line_number)) elif CMD_DEST_SOURCE[0] in ['NOP', 'TEST', 'RET', 'TIME', 'FLAG', 'ARITH', 'DIV', 'NET', 'COM', 'PA', 'PB']: if ('WP' in command_info): raise RuntimeError("COMMAND_RECOGNITION: Not allowed Write Port < -wp() > in Line " + str(line_number)) if ('WR' in command_info): raise RuntimeError("COMMAND_RECOGNITION: Not allowed Write Register < -wr() > in Line " + str(line_number)) if ('WW' in command_info): raise RuntimeError("COMMAND_RECOGNITION: Not allowed Write WaveMemory < -ww() > in Line " + str(line_number)) if ('TIME' in command_info): raise RuntimeError("COMMAND_RECOGNITION: " + CMD_DEST_SOURCE[0] + " Instruction is NOT a timed intruction < -@Time > in Line " + str(line_number)) ########################################################### elif CMD_DEST_SOURCE[0] in ['JUMP', 'CALL']: if ('WP' in command_info): raise RuntimeError("COMMAND_RECOGNITION: Not allowed Write Port < -wp() > in Line " + str(line_number)) if ('WW' in command_info): raise RuntimeError("COMMAND_RECOGNITION: Not allowed Write WaveMemory < -ww() > in Line " + str(line_number)) if ('TIME' in command_info): raise RuntimeError("COMMAND_RECOGNITION: " + CMD_DEST_SOURCE[0] + " Instruction is NOT a timed intruction < -@Time > in Line " + str(line_number)) elif (CMD_DEST_SOURCE[0] == 'DMEM_WR'): if ('WP' in command_info): raise RuntimeError("COMMAND_RECOGNITION: Not allowed Write Port < -wp() > in Line " + str(line_number)) if ('WW' in command_info): raise RuntimeError("COMMAND_RECOGNITION: Not allowed Write WaveMemory < -ww() > in Line " + str(line_number)) if ('TIME' in command_info): raise RuntimeError("COMMAND_RECOGNITION: DMEM_WR is NOT a timed intruction < -@Time > in Line " + str(line_number)) if ( not('ADDR' in command_info) ): raise RuntimeError("COMMAND_RECOGNITION: Memory Address < [] > not set in Line " + str(line_number)) ########################################################### elif (CMD_DEST_SOURCE[0] == 'WMEM_WR'): if ('TIME' in command_info) : if ('WR' in command_info) : raise RuntimeError("COMMAND_RECOGNITION: Not allowed SDI with Literal Time in Line " + str(line_number)) if ('OP' in command_info) : raise RuntimeError("COMMAND_RECOGNITION: Not allowed ALU Operation Operation with Literal Time in Line " + str(line_number)) if ( ('WP' in command_info) and not('PORT' in command_info) ): raise RuntimeError("COMMAND_RECOGNITION: No Port Address < -p() > in Line " + str(line_number)) ########################################################### elif CMD_DEST_SOURCE[0] in ['DPORT_WR', 'WPORT_WR', 'TRIG']: if ( not('PORT' in command_info) ): raise RuntimeError("COMMAND_RECOGNITION: No port in PORT_WR Instruction in line " + str(line_number)) # GET COMMAND DESTINATION SOURCE ############################################################### CMD_DEST_SOURCE = re.findall(regex['CDS'], command) command_info['CMD'] = CMD_DEST_SOURCE[0] ############################################################################### ## MORE THAN ONE SOURCE if ( len(CMD_DEST_SOURCE) > 3) : if CMD_DEST_SOURCE[0] in ['ARITH', 'NET', 'PA', 'PB']: command_info['C_OP'] = CMD_DEST_SOURCE[1] command_info['R1'] = CMD_DEST_SOURCE[2] command_info['R2'] = CMD_DEST_SOURCE[3] if ( len(CMD_DEST_SOURCE) > 4) : command_info['R3'] = CMD_DEST_SOURCE[4] if ( len(CMD_DEST_SOURCE) > 5) : command_info['R4'] = CMD_DEST_SOURCE[5] if (CMD_DEST_SOURCE[0] == 'NET') : raise RuntimeError('COMMAND_RECOGNITION: NET command max 3 Registers in line ' + str(line_number) ) if ( len(CMD_DEST_SOURCE) > 6) : raise RuntimeError('COMMAND_RECOGNITION: ' + CMD_DEST_SOURCE[0]+' Command max 4 Registers in line ' + str(line_number) ) elif (CMD_DEST_SOURCE[0] == 'REG_WR') and (CMD_DEST_SOURCE[2] == 'label' ) : command_info['DST'] = CMD_DEST_SOURCE[1] command_info['SRC'] = CMD_DEST_SOURCE[2] command_info['LABEL'] = CMD_DEST_SOURCE[3] else: raise RuntimeError("COMMAND_RECOGNITION: [>3] Parameter Error in line " + str(line_number) ) ############################################################################### ## ONLY ONE SOURCE / DEST elif ( len(CMD_DEST_SOURCE) == 3) : if (CMD_DEST_SOURCE[0] == 'REG_WR'): if (CMD_DEST_SOURCE[2] == 'label' ) : raise RuntimeError("COMMAND_RECOGNITION: Missing label in line " + str(line_number)) command_info['DST'] = CMD_DEST_SOURCE[1] command_info['SRC'] = CMD_DEST_SOURCE[2] elif (CMD_DEST_SOURCE[0] =='DPORT_WR' ) : if ( int(command_info['PORT']) > 3): raise RuntimeError("COMMAND_RECOGNITION: Data Port MAX port number is p3 in line " + str(line_number)) command_info['DST'] = command_info['PORT'] command_info.pop('PORT') command_info['SRC'] = CMD_DEST_SOURCE[1] command_info['DATA'] = CMD_DEST_SOURCE[2] elif CMD_DEST_SOURCE[0] in ['COM', 'TIME', 'NET', 'PA', 'PB']: command_info['C_OP'] = CMD_DEST_SOURCE[1] command_info['R1'] = CMD_DEST_SOURCE[2] elif (CMD_DEST_SOURCE[0] == 'DIV') : command_info['NUM'] = CMD_DEST_SOURCE[1] command_info['DEN'] = CMD_DEST_SOURCE[2] else: raise RuntimeError("COMMAND_RECOGNITION: [3] Parameter Error in line " + str(line_number) ) ############################################################################### ## NO SOURCE OR -- SOURCE IN EXTRACTED PARAMETER elif ( len(CMD_DEST_SOURCE) == 2) : if (CMD_DEST_SOURCE[0] =='DMEM_WR' ) : command_info['SRC'] = CMD_DEST_SOURCE[1] command_info['DST'] = '[' + command_info['ADDR'] + ']' command_info.pop('ADDR') elif (CMD_DEST_SOURCE[0] =='TRIG'): command_info['SRC'] = CMD_DEST_SOURCE[1] if ( int(command_info['PORT']) > 31): raise RuntimeError("COMMAND_RECOGNITION: Trigger Port max por number is p31 in line " + str(line_number)) command_info['DST'] = command_info['PORT'] command_info.pop('PORT') elif (CMD_DEST_SOURCE[0] =='WPORT_WR'): command_info['SRC'] = CMD_DEST_SOURCE[1] if ( int(command_info['PORT']) > 15): raise RuntimeError("COMMAND_RECOGNITION: Wave Port Port max value is 15 in line " + str(line_number)) command_info['DST'] = command_info['PORT'] command_info.pop('PORT') elif CMD_DEST_SOURCE[0] in ['FLAG', 'NET', 'COM', 'PA', 'PB']: command_info['C_OP'] = CMD_DEST_SOURCE[1] elif (CMD_DEST_SOURCE[0]=='TIME'): # DST is ADDR command_info['C_OP'] = CMD_DEST_SOURCE[1] elif (CMD_DEST_SOURCE[0]=='DIV'): if 'LIT' not in command_info: raise RuntimeError("COMMAND_RECOGNITION: Dividend Parameter Error in line " + str(line_number)) command_info['NUM'] = CMD_DEST_SOURCE[1] command_info['DEN'] = command_info['LIT'] elif CMD_DEST_SOURCE[0] in ['JUMP', 'CALL']: if CMD_DEST_SOURCE[1] == 's15': logger.info("COMMAND_RECOGNITION: BRANCH to s_addr > line " + str(line_number)) command_info['ADDR'] = 's15' else: logger.info("COMMAND_RECOGNITION: BRANCH to label or keyword : " + CMD_DEST_SOURCE[1] + " > line " + str(line_number)) command_info['LABEL'] = CMD_DEST_SOURCE[1] elif (CMD_DEST_SOURCE[0]=='WAIT'): logger.debug("COMMAND_RECOGNITION: WAIT adding Instruction") command_info['C_OP'] = CMD_DEST_SOURCE[1] command_info['P_ADDR'] = mem_addr mem_addr += 1 elif (CMD_DEST_SOURCE[0]=='CLEAR'): command_info['C_OP'] = CMD_DEST_SOURCE[1] logger.debug("COMMAND_RECOGNITION: CLEAR Instruction") command_info['P_ADDR'] = mem_addr else: raise RuntimeError("COMMAND_RECOGNITION: [2] Parameter Error in line " + str(line_number)) ############################################################################### ## NO DESTINATION OR -- DESTINATION / SOURCE IN EXTRACTED PARAMETER elif ( len(CMD_DEST_SOURCE) ==1 ): if CMD_DEST_SOURCE[0] in ['NOP', 'ARITH', 'TEST', 'RET']: pass elif (CMD_DEST_SOURCE[0] =='DPORT_RD') : if 'PORT' not in command_info: raise RuntimeError("COMMAND_RECOGNITION: No Port for DPORT_RD in line " + str(line_number)) if ( int(command_info['PORT']) > 7): raise RuntimeError("COMMAND_RECOGNITION: Data Port Read max value is 7 in line " + str(line_number)) command_info['DST'] = command_info['PORT'] command_info.pop('PORT') elif (CMD_DEST_SOURCE[0]=='WMEM_WR'): if 'ADDR' not in command_info: raise RuntimeError("COMMAND_RECOGNITION: No Address for WMEM_WR in line " + str(line_number)) command_info['DST'] = '[' + command_info['ADDR'] + ']' command_info.pop('ADDR') elif CMD_DEST_SOURCE[0] in ['JUMP', 'CALL']: if 'ADDR' not in command_info: raise RuntimeError("COMMAND_RECOGNITION: Address Parameter Error in line " + str(line_number)) command_info['ADDR'] = command_info['ADDR'] else: raise RuntimeError("COMMAND_RECOGNITION: [1] Parameter Error in line " + str(line_number)) else: raise RuntimeError("COMMAND_RECOGNITION: Error Processing Line " + str(line_number)) + ". Command not recognized." # ADD CMD TO PROGRAM ########################################################### program_list.append(command_info) else: raise RuntimeError("COMMAND_RECOGNITION: Not a Command in Line " + str(line_number)) return program_list ##### START ASSEMBLER TO LIST logger.debug("ASM2LIST: ##### STEP_1 - LABEL RECOGNITION") label_dict, label_line_idxs = label_recognition(asm_str) logger.debug("ASM2LIST: ##### STEP_2 - COMMAND RECOGNITION") program_list = command_recognition(asm_str, label_line_idxs) return (program_list, label_dict) @staticmethod def list2bin(program_list : list, label_dict : dict = {}, save_unparsed_filename : str = "") -> list: """ translates a program list to binary form. :program_list (list): each element is a dictionary with all the commands and instructions. see ' asm2list() ' :label_dict (dict): dictionary with label information only if program_list contains labels. :save_unparsed_filename (str): if not null, opens this file and saves unparsed binary ('_' not removed). :returns (tuple): (binary_program_list, binary_program_array) :binary_program_list (list): each element is a string with 0s and 1s representing the binary program :binary_program_array (list): each element is a list of 32-bit ints representing the binary program """ logger.debug("LIST2BIN: ##### LIST 2 BIN") # make a copy of the program list before parse_labels modifies it program_list = copy.deepcopy(program_list) # add label addresses parse_labels(program_list, label_dict) # first line is NOP #binary_program_list = ['000_000__000__0_0_0_00_00___00000___000000__000000____0_0000000__0_0000000__0000000000000000__0000000'] binary_program_list = [] CODE = 'x' for command in program_list: logger.debug("list2bin: translating %s"%(command)) if 'CMD' not in command: raise RuntimeError("COMMAND_TRANSLATION: No Command at line " + str(command['LINE'])) if not ('UF' in command): command['UF'] = '0' ############################################################################### if command['CMD'] == 'NOP': CODE = '000_000__000__0_0_0_00_00___00000___000000__000000____0_0000000__0_0000000__0000000000000000__0000000' ############################################################################### elif command['CMD'] == 'TEST': command['UF'] = '1' CODE = Instruction.CFG(command) ############################################################################### elif command['CMD'] == 'REG_WR': CODE = Instruction.REG_WR(command) ############################################################################### elif command['CMD'] == 'DMEM_WR': CODE = Instruction.DMEM_WR(command) ############################################################################### elif command['CMD'] == 'WMEM_WR': CODE = Instruction.WMEM_WR(command) ############################################################################### elif command['CMD'] =='TRIG': CODE = Instruction.PORT_WR(command) ############################################################################### elif command['CMD'] in ['DPORT_WR', 'DPORT_RD', 'WPORT_WR']: CODE = Instruction.PORT_WR(command) ############################################################################### elif command['CMD'] == 'JUMP': CODE = Instruction.BRANCH(command, '00') ############################################################################### elif command['CMD'] == 'CALL': CODE = Instruction.BRANCH(command, '10') ############################################################################### elif command['CMD'] == 'RET': CODE = Instruction.BRANCH(command, '11') ############################################################################### elif command['CMD'] in ['TIME', 'FLAG', 'DIV']: CODE = Instruction.CTRL(command) ############################################################################### elif command['CMD'] in ['NET', 'COM']: CODE = Instruction.CTRL(command) ############################################################################### elif command['CMD'] in ['PA', 'PB']: CODE = Instruction.CTRL(command) ############################################################################### elif command['CMD'] == 'ARITH': CODE = Instruction.ARITH(command) ############################################################################### elif command['CMD'] == 'CLEAR': CODE = Instruction.CLEAR(command) ############################################################################### elif command['CMD'] == 'WAIT': CODE = Instruction.WAIT(command) logger.debug('COMMAND_TRANSLATION: Command Wait add one more instruction ' + str(command['LINE']) ) else: raise RuntimeError("COMMAND_TRANSLATION: Command Listed but not programmed > " + command['CMD']) ################################################################################### # most commands translate to a binary machine-code string, WAIT translates to a list of str # if we have a binary string, put it in a list if isinstance(CODE, str): CODE = [CODE] # check that each line has the correct length for inst in CODE: length = inst.count('0') + inst.count('1') if (length != 72): raise RuntimeError(f"COMMAND_TRANSLATION: {CODE}\nINSTRUCTION LENGTH > {length} at line {command['LINE']}") # label with the command type CODE[-1] += ' //' + command['CMD'] # append the new lines binary_program_list.extend(CODE) if (save_unparsed_filename): with open(save_unparsed_filename, "w+") as f: for line in binary_program_list: f.write(f"{line}\n") binary_array = [] for line_bin in binary_program_list: tmp = line_bin.replace('_', '') b0 = '0b'+tmp[40:72] n0 = int(b0,2) b1 = '0b'+ tmp[8:40] n1 = int(b1,2) b2 = '0b'+tmp[:8] n2 = int(b2,2) binary_line = [n0, n1, n2, 0, 0, 0, 0, 0] binary_array.append(binary_line) return binary_program_list, binary_array def file_asm2bin(filename : str, save_unparsed_filename : str = "") -> list: """ opens file with assembler and returns the binary :filename (str): file containing ASM. :save_unparsed_filename (str): if not null, opens this file and saves unparsed binary ('_' not removed). """ program_list, label_dict = Assembler.file_asm2list(filename) binary_program_list = Assembler.list2bin(program_list, label_dict, save_unparsed_filename) return binary_program_list def str_asm2bin(str_asm : str, save_unparsed_filename : str = "") -> list: """ get STR with assembler and returns the binary :asm_str (str): string ASM. :save_unparsed_filename (str): if not null, opens this file and saves unparsed binary ('_' not removed). """ program_list, label_dict = Assembler.str_asm2list(str_asm) binary_program_list = Assembler.list2bin(program_list, label_dict, save_unparsed_filename) return binary_program_list ############################################################################### ## BASIC COMANDS ############################################################################### class Instruction(): #PROCESSING @staticmethod def __PROCESS_CONDITION(command : dict) -> str: cond = '' if ('IF' in command ): if command['IF'] not in condList: raise RuntimeError('Parameter.IF: Posible CONDITIONS are (' + ', '.join(list(condList.keys())) + ') in instruction ' + str(command['LINE']) ) cond = condList[command['IF']] else: cond = '000' return cond @staticmethod def __PROCESS_WR(command : dict) -> tuple: #### Get WR RD = '0000000' Rdi=Wr = '0' if ('WR' in command ): Wr = '1' regex_inside_parenthesis = r'\s*([\w]+)' DEST_SOURCE = re.findall(regex_inside_parenthesis, command['WR']) #### SOURCE if len(DEST_SOURCE) != 2: raise RuntimeError('Parameter.WR: Write Register error <-wr(reg source) in instruction ' + str(command['LINE']) ) if (DEST_SOURCE[1] == 'op'): if 'OP' not in command : raise RuntimeError('Parameter.WR: Operation < -op() > option not found in instruction ' + str(command['LINE']) ) Rdi = '0' elif (DEST_SOURCE[1] == 'imm'): if 'LIT' not in command: raise RuntimeError('Parameter.WR: Literal Value not found in instruction ' + str(command['LINE']) ) Rdi = '1' else: raise RuntimeError('Parameter.WR: Posible Source Dest for <-wr(reg source)> are (op, imm) in instruction ' + str(command['LINE']) ) #### DESTINATION REGISTER RD = get_reg_addr (DEST_SOURCE [0], 'Dest') return Wr, Rdi, RD @staticmethod def __PROCESS_WP (command : dict) -> tuple: #### WRITE PORT Wp=Sp='0' Dp='000000' if ('WP' in command ): #### DESTINATION PORT if 'PORT' not in command: raise RuntimeError('Parameter.WP: Port Address not recognized < pX > ' + str(command['LINE']) ) Wp='1' Dp = integer2bin(command['PORT'], 6) if (command['WP'] == 'r_wave'): Sp = '1' elif (command['WP'] == 'wmem'): Sp = '0' else: raise RuntimeError('Parameter.WP: Source Wave Port not recognized (wreg, r_wave) ' + str(command['LINE']) ) return Wp, Sp, Dp @staticmethod def __PROCESS_SOURCE (command : dict) -> tuple: df = alu_op = 'X' rsD0 = rsD1 = DataImm ='' FULL = (command['CMD']=='REG_WR') and (command['SRC']=='op') if ('OP' in command): cmd_op = command['OP'].split() if (len(cmd_op)==1 ) : # Operation is COPY REG (Add Zero) #print('LEN 1') src_type = get_src_type(cmd_op[0]) #print('src_type[0] > ', src_type ) df = '01' rsD1 = '0_0000000' if FULL: alu_op = '0000' # REG_WR rd op -op(rs) else: alu_op = '00' # -wr(rd op) -op(rs) if ('LIT' in command): DataImm = get_imm_dt (command ['LIT'], 16) else: DataImm = '_0000000000000000' if src_type[0]!='R': raise RuntimeError('Parameter.SRC: Operand can not be a Literal.') rsD0 = get_reg_addr(cmd_op[0], 'src_data') elif (len(cmd_op)==2 ) : #print('LEN 2 >',cmd_op) operation = cmd_op[0] src_type = get_src_type(cmd_op[1]) #print('src_type[1] > ', src_type) if not FULL: raise RuntimeError('Parameter.SRC: 1-FULL Operation Not Allowed > ' + str(command['OP']) +' in instruction ' + str(command['LINE']) ) if operation not in aluList_op: #ALU LIST ONE PARAMETER raise RuntimeError('Parameter.SRC: Operation Not Recognized > ' + str(command['OP']) ) df = '10' alu_op = aluList[operation] DataImm = '__000000000000000000000000' if src_type[0]!='R': raise RuntimeError('Parameter.SRC: Operand can not be a Literal.') rsD0 = get_reg_addr(cmd_op[1], 'src_data') ## ABS Should be on rsD1 if (operation == 'ABS') : df = '01' rsD1 = rsD0 rsD0 = '0_0000000' DataImm = '_0000000000000000' #if (error!=0): # raise RuntimeError('Parameter.SRC: 1-Operation Not Allowed > ' + str(command['OP']) +' in instruction ' + str(command['LINE']) ) elif (len(cmd_op)==3 ) : #print('LEN 3 >',cmd_op) ## CHECK FOR FIRST OPERAND (ALU_IN_A > rsD0) src_type = get_src_type(cmd_op[0]) #print('First Operand >',src_type, cmd_op[0]) if src_type[0]!='R': raise RuntimeError('Parameter.SRC: First Operand can not be a Literal.') rsD0 = get_reg_addr(cmd_op[0], 'src_data') ## CHECK FOR SECOND OPERAND (ALU_IN_B > Imm|rsD1) src_type = get_src_type(cmd_op[2]) #print('Second Operand >',src_type, cmd_op[2]) if src_type[0]=='R': ## REG OP REG df = '01' rsD1 = get_reg_addr(cmd_op[2], 'src_data') ## Literal for Second Data Task -wr(rd imm) if ('LIT' in command): DataImm = get_imm_dt (command['LIT'], 16) else: DataImm = '_0000000000000000' elif src_type[0]=='N': ## is Number DataImm = get_imm_dt (cmd_op[2], 24) #if (error): # raise RuntimeError('Parameter.SRC: Literal Value error in instruction ' + str(command['LINE']) ) if cmd_op[1] in ['SR', 'SL', 'ASR']: lit_val = get_imm_dt (cmd_op[2], 24, 1) if (lit_val > 15): raise RuntimeError('Parameter.SRC: Max Shift is 15 in instruction ' + str(command['LINE']) ) #if (error): # raise RuntimeError('Parameter.SRC: Literal Value error in instruction ' + str(command['LINE']) ) df = '10' DataImm = '_'+DataImm ## CHECK FOR OPERATION operation = cmd_op[1] if (FULL): if operation not in aluList: raise RuntimeError('Parameter.SRC: ALU {Full List} Operation Not Recognized in instruction ' + str(command['LINE']) ) alu_op = aluList[ operation ] else: if operation not in aluList_s: raise RuntimeError('Parameter.SRC: ALU {Reduced List} Operation Not Recognized in instruction ' + str(command['LINE']) ) alu_op = aluList_s[ operation ] ## LITERAL and NO OP elif ('LIT' in command): df = '11' alu_op = '00' DataImm = '__'+get_imm_dt (command['LIT'], 32) else: df = '11' alu_op = '00' DataImm = '___00000000000000000000000000000000' #if (error): # raise RuntimeError('Parameter.SRC: Error in line ' + str(command['LINE']) ) # return error, 'X', 'X', 'X' Data_Source = rsD0 +'__'+ rsD1 +'_'+ DataImm return Data_Source, alu_op, df @staticmethod def __PROCESS_MEM_ADDR (ADDR_CMD : str) -> tuple: AI = '0' rsA0 = rsA1 = 'x' comp_ADDR_FMT = "s(\d+)|r(\d+)|&(\d+)|\s*([A-Z]{3}|[A-Z]{2}|\+|\-)" param_op = re.findall(comp_ADDR_FMT, ADDR_CMD) if (len(param_op)==1 ) : ## CHECK FOR OPERAND rsA1 = '000000' # Register ZERO if (param_op[0][0]): ## is SREG rsA0 = '00000___0' + integer2bin(param_op[0][0], 5) elif (param_op[0][1]): ## is DREG rsA0 = '00000___1' + integer2bin(param_op[0][1], 5) elif (param_op[0][2]): ## is Literal rsA0 = '___'+ integer2bin(param_op[0][2], 11) AI = '1' else: raise RuntimeError('Parameter.MEM_ADDR: First Operand not recognized.') elif (len(param_op)==3 ) : ## CHECK FOR FIRST OPERAND if (param_op[0][0]): ## is SREG rsA1 = '0'+integer2bin(param_op[0][0], 5) elif (param_op[0][1]): ## is DREG rsA1 = '1' + integer2bin(param_op[0][1], 5) elif (param_op[0][2]): ## is Literal raise RuntimeError('Parameter.MEM_ADDR: First Operand can not be a Literal.') ## CHECK FOR SECOND OPERAND if (param_op[2][0]): ## is SREG rsA0 = '00000___0' + integer2bin(param_op[2][0], 5) elif (param_op[2][1]): ## is DREG rsA0 = '00000___1' + integer2bin(param_op[2][1], 5) elif (param_op[2][2]): ## is Literal rsA0 = '___'+ integer2bin(param_op[2][2], 11) AI = '1' ## CHECK FOR PLUS if param_op[1][3] != '+': ## is R_Reg raise RuntimeError('Parameter.MEM_ADDR: Address Operand should be < + >.') else: raise RuntimeError('Parameter.MEM_ADDR: Address format error, should be Data Register(r) or Literal(&): '+ADDR_CMD) return rsA0, rsA1, AI #INSTRUCTIONS @staticmethod def REG_WR (current : dict) -> str: AI = '0' RdP = '000000' ######### CONDITIONAL COND = Instruction.__PROCESS_CONDITION(current) ######### SOURCES #### SOURCE ALU if (current ['SRC'] == 'op'): if 'OP' not in current: raise RuntimeError('Instruction.REG_WR: No < -op() > for Operation Writting in instruction ' + str(current['LINE'])) DATA, alu_op, DF = Instruction.__PROCESS_SOURCE (current) CFG = '00__' + current ['UF'] + '__'+ alu_op ADDR = '___00000000000__000000' # 17 Bits 11 + 6 #### SOURCE IMM elif (current ['SRC'] == 'imm'): #### Get Data Source if 'LIT' not in current: raise RuntimeError('Instruction.REG_WR: No Literal value for immediate Assignation (#) in instruction ' + str(current['LINE']) ) DATA, alu_op, DF = Instruction.__PROCESS_SOURCE(current) CFG = '11__' + current ['UF'] + '_00_' + alu_op ADDR = '___00000000000__000000' # 17 Bits 11 + 6 #### SOURCE LABEL elif (current ['SRC'] == 'label'): #### Get Data Source if 'ADDR' not in current: raise RuntimeError('Instruction.REG_WR: Address error in line ' + str(current['LINE']) ) comp_addr = "&(\d+)" address = re.findall(comp_addr, current['ADDR']) current['LIT'] = current['ADDR'] if not address[0]: # LITERAL raise RuntimeError('Instruction.REG_WR: Address error in line ' + str(current['LINE']) ) DATA, alu_op, DF = Instruction.__PROCESS_SOURCE(current) ADDR = '___00000000000__000000' # 17 Bits 11 + 6 CFG = '11__' + current ['UF'] + '_00_00' #### SOURCE DATA MEMORY elif (current ['SRC'] == 'dmem'): #### Get Data Source DATA, alu_op, DF = Instruction.__PROCESS_SOURCE(current) CFG = '01__' + current ['UF'] + '_00_' + alu_op #### Get ADDRESS if 'ADDR' not in current: raise RuntimeError('Instruction.REG_WR: No Address for dmem in line ' + str(current['LINE']) ) rsA0, rsA1, AI = Instruction.__PROCESS_MEM_ADDR (current ['ADDR']) ADDR = rsA0 + '__' + rsA1 CFG = '01__' + current ['UF'] + '_00_'+alu_op #### SOURCE WAVE MEM elif (current ['SRC'] == 'wmem'): if (COND != '000'): raise RuntimeError('Instruction.REG_WR: Wave Register Write is not conditional < -if() > in instruction ' + str(current['LINE']) ) WW = WP = '0' if ('WW' in current): WW = '1' #### WRITE PORT WP, Sp, RdP = Instruction.__PROCESS_WP(current) COND = WW + Sp + WP #### WRITE REGISTER Wr = Rdi = '0' Wr, Rdi, RD = Instruction.__PROCESS_WR(current) #### Get Data Source DATA, alu_op, DF = Instruction.__PROCESS_SOURCE(current) #### Get ADDRESS if 'ADDR' not in current: raise RuntimeError('Instruction.REG_WR: No addres for <wmem> source in instruction ' + str(current['LINE']) ) rsA0, rsA1, AI = Instruction.__PROCESS_MEM_ADDR (current ['ADDR']) if rsA1 != '000000': raise RuntimeError('Instruction.REG_WR: Wave Memory Addres Error Source Should be LIT or Reg in instruction ' + str(current['LINE']) ) ADDR = rsA0 + '__' + RdP else: raise RuntimeError('Instruction.REG_WR: Posible REG_WR sources are (op, imm, dmem, wmem, label ) in instruction ' + str(current['LINE']) ) ######### DESTINATION REGISTER if (current ['SRC'] == 'wmem'): if current ['DST'] == 'w0': raise RuntimeError('Instruction.REG_WR: Wave Memory Source Should have a Wave Register <r_wave> Destination ' + str(current['LINE']) ) Wr = Rdi = '0' Wr, Rdi, RD = Instruction.__PROCESS_WR(current) CFG = '10__' + current ['UF'] +'_'+ Wr + Rdi +'_'+ alu_op elif ( (current ['SRC'] == 'label') and () ): if (RD!='15'): logger.warning('Instruction.REG_WR: Register used to BRANCH should be s15 in instruction ' + str(current['LINE']) ) else: comp_OP_PARAM = "^s(\d+)|^r(\d+)|^w(\d+)|(r_wave)" RD = re.findall(comp_OP_PARAM, current ['DST']) if not RD: raise RuntimeError('Instruction.REG_WR: Destination Register '+current ['DST']+' not Recognized in instruction ' + str(current['LINE']) ) RD = get_reg_addr (current ['DST'], 'Dest') return '100_' + AI + DF +'__'+ COND +'__'+ CFG +'___'+ADDR+'____'+DATA + '__' + RD @staticmethod def DMEM_WR (current : dict) -> str: #### CONDITIONAL COND = Instruction.__PROCESS_CONDITION(current) #### WRITE REGISTER Wr = Rdi = '0' Wr, Rdi, RD = Instruction.__PROCESS_WR(current) #### DATA SOURCE DATA, alu_op, DF = Instruction.__PROCESS_SOURCE(current) #### ADDRESS rsA0, rsA1, AI = Instruction.__PROCESS_MEM_ADDR (current['DST']) ADDR = rsA0 + '__' + rsA1 #### SOURCE if (current ['SRC'] == 'op'): if 'OP' not in current: raise RuntimeError('Instruction.MEM_WR: > -op() option not found in instruction ' + str(current['LINE']) ) DI = '0' elif (current ['SRC'] == 'imm'): if 'LIT' not in current: raise RuntimeError('Instruction.MEM_WR: No Literal value found in instruction ' + str(current['LINE']) ) DI = '1' else: raise RuntimeError('Instruction.MEM_WR: Posible MEM_WR sources are (op, imm) in instruction ' + str(current['LINE']) ) CFG = current['UF']+ '_'+Wr+Rdi+'_'+ alu_op return '101_'+AI+DF+'__'+COND+'__0_'+DI+'_'+CFG+"___"+ADDR+'____'+DATA+'__'+RD @staticmethod def WMEM_WR (current : dict) -> str: AI=Wp=TI='0' #### WMEM ADDRESS if 'DST' not in current: raise RuntimeError('Instruction.WMEM_WR: No address specified in line ' + str(current['LINE']) ) rsA0, rsA1, AI = Instruction.__PROCESS_MEM_ADDR (current['DST']) if rsA1 != '000000': raise RuntimeError('Instruction.REG_WR: Wave Memory Addres Error Source Should be LIT or Reg in line ' + str(current['LINE']) ) #### WRITE REGISTER Wr = Rdi = '0' Wr, Rdi, RD = Instruction.__PROCESS_WR(current) #### WRITE PORT Wp, Sp, Dp = Instruction.__PROCESS_WP(current) #### DATA SOURCE DATA, alu_op, DF = Instruction.__PROCESS_SOURCE(current) #if error: # raise RuntimeError('Instruction.WMEM_WR: Error in line ' + str(current['LINE']) ) # CODE = 'X' if ('TIME' in current ): TI='1' TIME = get_imm_dt (current ['TIME'], 32) #if (error): # raise RuntimeError('Parameter.WMEM_WR: Time Value error in instruction ') DATA = '_____' + TIME CFG = '1_' + TI+'_' +current['UF'] +'_'+ Wr +Rdi +'_'+ alu_op return '101_'+AI+DF+'__1'+Sp+Wp+'__'+CFG+"___"+rsA0+'__'+Dp+'____'+DATA+'__'+RD @staticmethod def CFG (current : dict) -> str: AI=SO=TO= '0' ADDR = '00000000000_000000' #### CONDITIONAL COND = Instruction.__PROCESS_CONDITION(current) #### WRITE REGISTER Wr = Rdi = '0' Wr, Rdi, RD = Instruction.__PROCESS_WR(current) #### DATA SOURCE DATA, alu_op, DF = Instruction.__PROCESS_SOURCE(current) #if (error): # logger.error('Instruction.CFG: Error in line ' + str(current['LINE']) ) # CODE = 'X' CFG = current['UF'] +'_'+ Wr + Rdi +'_'+ alu_op return '000_'+AI+DF+'__'+COND+'__'+SO+TO+'__'+CFG+"_______"+ADDR+'____'+DATA+'__'+RD @staticmethod def BRANCH (current : dict, cj : str) -> str: #### CONDITIONAL COND = Instruction.__PROCESS_CONDITION(current) #### WRITE REGISTER Wr = Rdi = '0' Wr, Rdi, RD = Instruction.__PROCESS_WR(current) #### DATA SOURCE DATA, alu_op, DF = Instruction.__PROCESS_SOURCE(current) #### DESTINATION MEMORY ADDRESS if (cj =='11'): # RET Instruction. ADDR came from STACK current['UF'] = '0' AI = '0' ADDR = '_00000000000_000000' else: comp_addr = "&(\d+)|s(\d+)" addr = re.findall(comp_addr, current['ADDR']) try: if (addr[0][0]): # LITERAL ADDR = '_' + integer2bin(addr[0][0], 11, uint=1) + '_000000' AI = '1' elif (addr[0][1] == '15'): #SREG s15 ADDR = '_00000000000_000000' AI = '0' else: raise RuntimeError("Instruction.BRANCH: JUMP Memory Address not recognized (imm or s15)") except IndexError: raise RuntimeError(f"COMMAND RECOGNITION: for address at line {current['LINE']}. (possible extra [])") #if (error): # raise RuntimeError("Instruction.BRANCH: Exit with Error in instruction " + str(current['LINE']) ) # CODE = 'X' CFG = current['UF'] +'_'+ Wr+Rdi +'_'+ alu_op return '001_'+AI+DF+'__'+COND+'__'+cj+'__'+CFG+"______"+ADDR+'____'+DATA+'__'+RD @staticmethod def PORT_WR (current : dict) -> str: ##### DATA PORTS if current['CMD'] in ['DPORT_WR', 'DPORT_RD', 'TRIG']: SO=AI=Ww=Sp= '0' rsA0 = '___00000000000' #### WRITE REGISTER Wr = Rdi = '0' Wr, Rdi, RD = Instruction.__PROCESS_WR(current) #### PORT DESTINATION #### TRIG PORT if (current['CMD'] == 'TRIG'): Wp= '1' AI=Sp = '1' current['DST'] = str(int(current['DST'])+32) if (current['SRC'] == 'set'): rsA0 = '___00000000001' elif (current['SRC'] == 'clr'): rsA0 = '___00000000000' else: raise RuntimeError('Instruction.PORT_WR: Possible options for TRIG command are (set, clr)' ) #### DATA PORT elif (current['CMD'] == 'DPORT_WR'): Wp= '1' Sp= '0' if (current ['SRC'] == 'imm'): if 'DATA' not in current: raise RuntimeError('Instruction.PORT_WR: No Port Data value found in line ' + str(current['LINE']) ) if int(current['DATA']) > 2047: raise RuntimeError('Instruction.PORT_WR: Data imm should be smaller than 2047 No Port Data value found in line ' + str(current['LINE']) ) AI=Sp = '1' # DATA CAMES WITHOUT # rsA0 = '___'+ integer2bin(current['DATA'], 11) elif (current ['SRC'] == 'reg'): if 'DATA' not in current: raise RuntimeError('Instruction.PORT_WR: No Port Register found in line ' + str(current['LINE']) ) AI=Sp = '0' comp_REG_FMT = "r(\d+)" param_op = re.findall(comp_REG_FMT, current['DATA']) if not param_op: raise RuntimeError('Instruction.PORT_WR: Register Selection Error, should be dreg in line ' + str(current['LINE']) ) rsA0 = '00000___1' + integer2bin(param_op[0], 5) else: raise RuntimeError('Instruction.PORT_WR: Posible DPORT_WR sources are (imm, reg) in line ' + str(current['LINE']) ) #### READ DATA PORT else: TO=Wp='0' ##### WAVEFORM PORT else: AI=Ww=Sp= '0' SO=Wp= '1' #### SOURCE if (current['SRC'] == 'wmem'): Sp = '0' if 'ADDR' not in current: raise RuntimeError('Instruction.PORT_WR: No address specified for < wmem > in line ' + str(current['LINE']) ) rsA0, rsA1, AI = Instruction.__PROCESS_MEM_ADDR (current ['ADDR']) if (rsA1 != '000000'): raise RuntimeError('Instruction.REG_WR: Wave Memory Addres Error Source Should be LIT or Reg in line ' + str(current['LINE']) ) elif (current['SRC'] == 'r_wave'): Sp='1' #### WRITE WAVE MEMORY if ('WW' in current ): if 'ADDR' not in current: raise RuntimeError('Instruction.PORT_WR: No address specified for < -ww > in line ' + str(current['LINE']) ) Ww = '1' rsA0, rsA1, AI = Instruction.__PROCESS_MEM_ADDR (current ['ADDR']) if (rsA1 != '000000'): raise RuntimeError('Instruction.REG_WR: Wave Memory Addres Error Source Should be LIT or Reg in line ' + str(current['LINE']) ) else: Ww = '0' rsA0 = '___00000000000' else: raise RuntimeError('Instruction.PORT_WR: Posible wave sources are (wmem, r_wave) in line ' + str(current['LINE']) ) DF = '11' #### OUT TIME if ('TIME' in current): TO = '1' DF = '11' TIME = get_imm_dt (current ['TIME'], 32) #if (error): # raise RuntimeError('Parameter.WMEM_WR: Time Value error in instruction ') DATA = '_____' + TIME #DATA = '______'+ integer2bin(current['TIME'], 32) CFG = SO+TO+'____00000' RD = '0000000' if ('WR' in current or 'OP' in current): raise RuntimeError('Instruction.PORT_WR: If time specified, Not allowed SDI <-wr(), -op()> in line ' + str(current['LINE']) ) else: TO = '0' logger.debug('Instruction.PORT_WR: No time specified for command will use s_time in line ' + str(current['LINE']) ) #### WRITE REGISTER Wr = Rdi = '0' Wr, Rdi, RD = Instruction.__PROCESS_WR(current) #### DATA SOURCE DATA, alu_op, DF = Instruction.__PROCESS_SOURCE(current) CFG = SO+TO+'__'+current['UF'] +'_'+Wr+Rdi +'_'+ alu_op #### OUT PORT if 'DST' not in current: raise RuntimeError('Instruction.PORT_WR: No Destination Port in line ' + str(current['LINE']) ) rsA1 = integer2bin(current['DST'], 6,1) #if (error): # raise RuntimeError("Instruction.PORT_WR: Exit with Error in line " + str(current['LINE']) ) # CODE = 'X' COND = Ww+Sp+Wp ADDR = rsA0+'__'+rsA1 return '110'+'_'+AI+DF+'__'+COND+'__'+CFG+ '___'+ADDR +'____'+ DATA+'__'+RD ################################ TO UPDATE CODE HERE. NOT LAST VERSION @staticmethod def CTRL (current : dict) -> str: Header = '010' RA0=RA1='000000' RD0=RD1='0_0000000' ImmFill='__0000000000000000' DF='01' AI='0' #### CONDITIONAL COND = Instruction.__PROCESS_CONDITION(current) ######### TIME if (current ['CMD'] == 'TIME'): CTRL_ADDR = '000' if (current['C_OP'] == 'rst'): OPERATION = '_0001' elif (current['C_OP'] == 'updt'): OPERATION = '_0010' elif (current['C_OP'] == 'set_ref'): OPERATION = '_0100' elif (current['C_OP'] == 'inc_ref'): OPERATION = '_1000' else: raise RuntimeError('Instruction.CTRL: Posible Operations for TIME command are (rst, set_ref, inc_ref)' ) if ('LIT' in current ): DF ='11' RD0 = '_' RD1 = get_imm_dt (current ['LIT'], 32) ImmFill='__' elif ('R1' in current): RD1 = get_reg_addr (current['R1'], 'src_data') else: if (current['C_OP'] !='rst'): raise RuntimeError('Instruction.CTRL: No Time Data' ) ######### FLAG elif (current ['CMD'] == 'FLAG'): CTRL_ADDR = '001' if (current['C_OP'] == 'set'): OPERATION = '_0001' elif (current['C_OP'] == 'clr'): OPERATION = '_0010' elif (current['C_OP'] == 'inv'): OPERATION = '_0100' else: raise RuntimeError('Instruction.CTRL: Posible Operations for FLAG command are (set, clr, inv)' ) ######### DIVISION elif (current ['CMD'] == 'DIV'): CTRL_ADDR = '011' OPERATION = '_0000' RA1 = get_reg_addr (current['NUM'], 'src_addr') if (check_reg(current['DEN'])) : # Is Register RD1 = get_reg_addr (current['DEN'], 'src_data') elif (check_lit(current['DEN'])) : # Is Literal Value DF ='11' RD0 ='_' RD1 = get_imm_dt (current ['DEN'], 32) ImmFill='__' else: raise RuntimeError('Instruction.CTRL: DIV Denominator not recognized in line ' + str(current['LINE']) ) ######### NET elif (current ['CMD'] == 'NET'): Header = '011' CTRL_ADDR = '_00' # QNET ADDRESS if (current['C_OP'] == 'set_net'): OPERATION = '00001' elif (current['C_OP'] == 'sync_net'): OPERATION = '01000' elif (current['C_OP'] == 'updt_offset'): OPERATION = '01001' elif (current['C_OP'] == 'set_dt'): OPERATION = '01010' elif (current['C_OP'] == 'get_dt'): OPERATION = '01011' elif (current['C_OP'] == 'set_flag'): OPERATION = '01010' elif (current['C_OP'] == 'get_flag'): OPERATION = '01011' else: raise RuntimeError('Instruction.CTRL: NET Operation not recognized' ) ######### COM elif (current ['CMD'] == 'COM'): Header = '011' CTRL_ADDR = '_01' # QCOM ADDRESS if (current['C_OP'] == 'set_flag'): if (current['R1'] == '0'): OPERATION = '00000' elif (current['R1'] == '1'): OPERATION = '00010' else: raise RuntimeError('Instruction.CTRL: COM flag value can be 0 or 1' ) elif (current['C_OP'] == 'sync'): OPERATION = '00110' elif (current['C_OP'] == 'reset'): OPERATION = '11111' else: if (current['C_OP'] == 'set_byte_1'): OPERATION = '00100' elif (current['C_OP'] == 'set_byte_2'): OPERATION = '00101' elif (current['C_OP'] == 'set_hw_1'): OPERATION = '01000' elif (current['C_OP'] == 'set_hw_2'): OPERATION = '01001' elif (current['C_OP'] == 'set_word_1'): OPERATION = '01100' elif (current['C_OP'] == 'set_word_2'): OPERATION = '01101' else: raise RuntimeError('Instruction.CTRL: Possible Operations for COM command are (set_flag, set_byte, set_hw, set_word)' ) if ('LIT' in current ): DF='11' RD0 = '' RD1 = get_imm_dt (current ['LIT'], 32) ImmFill='' elif ('R1' in current): RD1 = get_reg_addr (current['R1'], 'src_data') else: if (current['C_OP'] !='rst'): raise RuntimeError('Instruction.CTRL: No Time Data' ) ######### CUSTOM Peripheral elif (current ['CMD'] == 'PA' or current ['CMD'] == 'PB'): Header = '011' if (current ['CMD'] == 'PA'): CTRL_ADDR = '_10' # PA PERIPHERAL else: CTRL_ADDR = '_11' # PB PERIPHERAL if ( int(current['C_OP']) > 31): raise RuntimeError("COMMAND_RECOGNITION: External Peripheral Operation not in range [0:31] in line " + str(current['LINE']) ) OPERATION = integer2bin(current['C_OP'], 5,1) if ('LIT' in current): raise RuntimeError('Instruction.CTRL: No Immediate value allowed in Peripheral instruction' ) if ('R1' in current): RD0 = get_reg_addr (current['R1'], 'src_data') if ('R2' in current): RD1 = get_reg_addr (current['R2'], 'src_data') if ('R3' in current): RA0 = get_reg_addr (current['R3'], 'src_addr') if ('R4' in current): RA1 = get_reg_addr (current['R4'], 'src_addr') #if (error): # raise RuntimeError("Instruction.CTRL: Error in instruction " + str(current['LINE']) ) # CODE = 'X' return Header+'_'+AI+DF+'__'+COND+'___'+CTRL_ADDR+'__'+OPERATION+'___00000___'+RA0+'__'+RA1+'____'+RD0+'__'+RD1+ImmFill+'__0000000' @staticmethod def ARITH (current : dict) -> str: RsC=RsD='000000' #### CONDITIONAL COND = Instruction.__PROCESS_CONDITION(current) if 'LIT' in current: raise RuntimeError('Instruction.ARITH: No Immediate value allowed ' ) if 'C_OP' not in current: raise RuntimeError('Instruction.ARITH: No ARITH Operation ' ) if (current['C_OP'] in arithList ): ARITH_OP = arithList[current['C_OP']] if (current['C_OP'] == 'T'): # A*B if any([x not in current for x in ['R1', 'R2']]): raise RuntimeError('Instruction.ARITH: Few Sources > Need Two Source Register for T operation' ) RsA = get_reg_addr (current['R1'], 'src_data') RsB = get_reg_addr (current['R2'], 'src_data') elif (current['C_OP'] == 'TP') : # A*B+C if any([x not in current for x in ['R1', 'R2', 'R3']]): raise RuntimeError('Instruction.ARITH: Few Sources > Need three Source Register for TP operation' ) RsA = get_reg_addr (current['R1'], 'src_data') RsB = get_reg_addr (current['R2'], 'src_data') RsC = get_reg_addr (current['R3'], 'src_addr') elif (current['C_OP'] == 'TM') : # A*B-C if any([x not in current for x in ['R1', 'R2', 'R3']]): raise RuntimeError('Instruction.ARITH: Few Sources > Need three Source Register for TM operation' ) RsA = get_reg_addr (current['R1'], 'src_data') RsB = get_reg_addr (current['R2'], 'src_data') RsC = get_reg_addr (current['R3'], 'src_addr') elif (current['C_OP'] == 'PT') : # (D+A)*B if any([x not in current for x in ['R1', 'R2', 'R3']]): raise RuntimeError('Instruction.ARITH: Few Sources > Need three Source Register for PT operation' ) RsD = get_reg_addr (current['R1'], 'src_addr') RsA = get_reg_addr (current['R2'], 'src_data') RsB = get_reg_addr (current['R3'], 'src_data') elif (current['C_OP'] == 'MT' ): #(D-A)*B if any([x not in current for x in ['R1', 'R2', 'R3']]): raise RuntimeError('Instruction.ARITH: Few Sources > Need three Source Register for PT operation' ) RsD = get_reg_addr (current['R1'], 'src_addr') RsA = get_reg_addr (current['R2'], 'src_data') RsB = get_reg_addr (current['R3'], 'src_data') elif (current['C_OP'] == 'PTP'): #(D+A)*B+C if any([x not in current for x in ['R1', 'R2', 'R3', 'R4']]): raise RuntimeError('Instruction.ARITH: Few Sources > Need Four Source Register for PTP operation' ) RsD = get_reg_addr (current['R1'], 'src_addr') RsA = get_reg_addr (current['R2'], 'src_data') RsB = get_reg_addr (current['R3'], 'src_data') RsC = get_reg_addr (current['R4'], 'src_addr') elif (current['C_OP'] == 'PTM'): #(D+A)*B-C if any([x not in current for x in ['R1', 'R2', 'R3', 'R4']]): raise RuntimeError('Instruction.ARITH: Few Sources > Need Four Source Register for PTP operation' ) RsD = get_reg_addr (current['R1'], 'src_addr') RsA = get_reg_addr (current['R2'], 'src_data') RsB = get_reg_addr (current['R3'], 'src_data') RsC = get_reg_addr (current['R4'], 'src_addr') elif (current['C_OP'] == 'MTP'): #(D-A)*B+C if any([x not in current for x in ['R1', 'R2', 'R3', 'R4']]): raise RuntimeError('Instruction.ARITH: Few Sources > Need Four Source Register for PTP operation' ) RsD = get_reg_addr (current['R1'], 'src_addr') RsA = get_reg_addr (current['R2'], 'src_data') RsB = get_reg_addr (current['R3'], 'src_data') RsC = get_reg_addr (current['R4'], 'src_addr') elif (current['C_OP'] == 'MTM'): #(D-A)*B-C if any([x not in current for x in ['R1', 'R2', 'R3', 'R4']]): raise RuntimeError('Instruction.ARITH: Few Sources > Need Four Source Register for PTP operation' ) RsD = get_reg_addr (current['R1'], 'src_addr') RsA = get_reg_addr (current['R2'], 'src_data') RsB = get_reg_addr (current['R3'], 'src_data') RsC = get_reg_addr (current['R4'], 'src_addr') else: raise RuntimeError('Instruction.ARITH: No Recognized Operation' ) #if (error): # raise RuntimeError("Instruction.ARITH: Exit with Error in line " + str(current['LINE']) ) # CODE = 'X' return '010_001__'+COND+'___010___'+ARITH_OP +'___00000___'+RsC+'__'+RsD+'____'+RsA+'__'+RsB+'__0000000000000000__0000000' @staticmethod def WAIT (current : dict) -> str: binary_multi_list = [] if 'ADDR' not in current: current['ADDR'] = '&'+str(current['P_ADDR']) elif current['ADDR'] != 's15': raise RuntimeError('Instruction.WAIT: unrecognized ADDR %s in line %d' % (current['ADDR'], current['LINE'])) test_op = '' jump_cond = '' if (current['C_OP'] == 'time') : test_op = 's11 - #' + str(int(current['TIME'][1:])-Assembler.WAIT_TIME_OFFSET) jump_cond = 'S' elif (current['C_OP'] == 'port_dt') : test_op = 's10 AND #h8000' jump_cond = 'Z' elif (current['C_OP'] == 'div_rdy') : test_op = 's10 AND #h4' jump_cond = 'Z' elif (current['C_OP'] == 'div_dt') : test_op = 's10 AND #h8' jump_cond = 'Z' elif (current['C_OP'] == 'qpa_rdy') : test_op = 's10 AND #h100' jump_cond = 'Z' elif (current['C_OP'] == 'qpa_dt') : test_op = 's10 AND #h200' jump_cond = 'Z' else: msg = 'No Recognized Operation in line ' + str(current['LINE']) raise RuntimeError('Instruction.WAIT: ' + msg ) current['OP'] = test_op current['UF'] = '1' CODE = Instruction.CFG(current) ## ADD TEST INSTRUCTION binary_multi_list.append(CODE) current['IF'] = jump_cond CODE = Instruction.BRANCH(current, '00') ## ADD JUMP INSTRUCTION binary_multi_list.append(CODE) return binary_multi_list @staticmethod def CLEAR (current : dict) -> str: current['CMD'] = 'REG_WR' current['DST'] = 's2' current['SRC'] = 'imm' if (current['C_OP'] == 'arith') : current['LIT'] = '#h10000' elif (current['C_OP'] == 'div' ) : current['LIT'] = '#h20000' elif (current['C_OP'] == 'qnet' ) : current['LIT'] = '#h40000' elif (current['C_OP'] == 'qcom' ) : current['LIT'] = '#h80000' elif (current['C_OP'] == 'qpa' ) : current['LIT'] = '#h100000' elif (current['C_OP'] == 'qpb' ) : current['LIT'] = '#h200000' elif (current['C_OP'] == 'port' ) : current['LIT'] = '#h400000' elif (current['C_OP'] == 'all' ) : current['LIT'] = '#h7F0000' else: raise RuntimeError('Instruction.CLEAR: No Recognized Operation in line ' + str(current['LINE']) ) return Instruction.REG_WR(current)