From eb5b40f20c7433f4a8715307de7e6b4452fee7eb Mon Sep 17 00:00:00 2001 From: ArvinDelavari Date: Sun, 4 Aug 2024 18:37:43 +0330 Subject: [PATCH 1/5] Add assembler source files --- Software/AssembleX/address_mapping.py | 66 ++ Software/AssembleX/assembler.py | 844 ++++++++++++++++++++++++++ Software/AssembleX/data_conversion.py | 233 +++++++ Software/AssembleX/registers_rv32i.py | 92 +++ Software/AssembleX/variables.py | 28 + 5 files changed, 1263 insertions(+) create mode 100644 Software/AssembleX/address_mapping.py create mode 100644 Software/AssembleX/assembler.py create mode 100644 Software/AssembleX/data_conversion.py create mode 100644 Software/AssembleX/registers_rv32i.py create mode 100644 Software/AssembleX/variables.py diff --git a/Software/AssembleX/address_mapping.py b/Software/AssembleX/address_mapping.py new file mode 100644 index 0000000..4367320 --- /dev/null +++ b/Software/AssembleX/address_mapping.py @@ -0,0 +1,66 @@ +# AssembleX V3.0 +# RISC-V Assembly Software Assistant for the phoeniX project (https://github.com/phoeniX-Digital-Design/phoeniX) + +# Description: Address mapping and translation functions +# Copyright 2024 Iran University of Science and Technology. + +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. + +def define_reset_address(first_line): + start_address = first_line.split() + try: + if start_address[0] == '.RESET_ADDRESS': + address_pre = start_address[1] + if address_pre[0:2] == '0x' or address_pre[0:2] == '0X': + address = (int(address_pre, base=16) >> 2) * 4 + else: + address = (int(address_pre) >> 2) * 4 + print('INFO: .RESET_ADDRESS set to', "0x{:08x}".format(address)) + return address + else: + print('WARNING: .RESET_ADDRESS not defined. -> .RESET_ADDRESS overridden to 0x00000000\n') + return 0 + except: + print('WARNING: .RESET_ADDRESS not defined. -> .RESET_ADDRESS overridden to 0x00000000\n') + return 0 + +def label_mapping(base_address, line, instrcnt, expected_instructions_count, label_counter, label_list, label_address_list): + words = line.split() + # Check if blank line or comment or start_address + try: + if words[0][0] == '#': + # Ignore comment and move on + return 0 + elif words[0] == '.RESET_ADDRESS': + # Ignore start_address + return 0 + except: + # Ignore blank line and move on + return 0 + + if len(words) == 1 and line[-1] == ':': + label = line.split(':')[0] + label_counter[0] = label_counter[0] + 1 + label_list.append(label) + label_address_list.append(base_address + int(expected_instructions_count[0]) * 4) + elif len(words) > 1 and words[0][-1] == ':' and words[1][0] == '#': # Decodes labels with comments + label = line.split(':')[0] + label_counter[0] = label_counter[0] + 1 + label_list.append(label) + label_address_list.append(base_address + int(expected_instructions_count[0]) * 4) + else: + # It is an instruction + instrcnt[0] = instrcnt[0] + 1 + if words[0] == 'LI' or words[0] == 'li' or words[0] == 'LA' or words[0] == 'la': + offset = 2 # Because LI = expands to two instructions + else: + offset = 1 + expected_instructions_count[0] = expected_instructions_count[0] + offset + +def address_mapping(label_counter, label_list, label_address_list): + print('Address Mapping') + print('---------------') + for i in range(label_counter[0]): + print('%+-8s' % label_list[i], ": 0x{:08x}".format(label_address_list[i])) \ No newline at end of file diff --git a/Software/AssembleX/assembler.py b/Software/AssembleX/assembler.py new file mode 100644 index 0000000..a243a7d --- /dev/null +++ b/Software/AssembleX/assembler.py @@ -0,0 +1,844 @@ +# AssembleX V3.0 +# RISC-V Assembly Software Assistant for the phoeniX project (https://github.com/phoeniX-Digital-Design/phoeniX) + +# Description: The main assembler function +# Copyright 2024 Iran University of Science and Technology. + +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. + +from Software.AssembleX.variables import * +from Software.AssembleX.registers_rv32i import registers_rv32i +from Software.AssembleX.registers_rv32i import register_index_mapping +from Software.AssembleX.data_conversion import int_to_binary + +# Return address of a label in code +def parse_address_label(input_value): + for i in range(lable_counter[0]): + if input_value == label_list[i]: + return label_address_list[i] + return input_value +# Check validity of operand registers +def validity_registers(register): + if register not in registers_rv32i: + return 1 + else: + return 0 +# Check validity of labels +def validity_label(label): + if label in label_list: + return 1 + else: + return 0 + +def immediate_generator(immediate_value, line_number, error_status, jbflag, laflag): + try: + # Integer literal + if int(immediate_value) < 0: + immediate_value = 0xffffffff + 1 + int(immediate_value) # 2's complement taken if -ve number + immediate_value_binary = '{:032b}'.format(int(immediate_value)) + return immediate_value_binary + except: + try: + # Hexadecimal literal + if immediate_value[0:2] == '0x' or immediate_value[0:2] == '0X': + if int(immediate_value, base=16) < 0: + immediate_value = 0xffffffff + 1 + int(immediate_value, base=16) # 2's complement taken if -ve number + immediate_value_binary = '{:032b}'.format(int(immediate_value)) # 2's complement 32-bit binary + else: + immediate_value_binary = '{:032b}'.format(int(immediate_value, base=16)) + return immediate_value_binary + # Address Translation -> Relative address for j/b-type instructions + elif jbflag == 1 and validity_label(immediate_value.rstrip(':')): + address_label = parse_address_label(immediate_value) + pc_relative_address = address_label - pc[0] + if pc_relative_address < 0: + pc_relative_address = 0xffffffff + 1 + pc_relative_address # pc relative addr 2's complement + immediate_value_binary = '{:032b}'.format(pc_relative_address, base = 16) + return immediate_value_binary + # Address Translation -> Absolute address for 'la' instruction + elif laflag == 1 and validity_label(immediate_value.rstrip(':')): + address_label = parse_address_label(immediate_value) + abs_address = address_label + immediate_value_binary = '{:032b}'.format(abs_address, base = 16) # pc relative addr signed 32-bit + return immediate_value_binary + else: + print("ERROR: Invalid immediate/offset value or label at line no: ", line_number) + error_status[0] = 1 + return 0 + except: + print("ERROR: Invalid immediate/offset value or label at line no: ", line_number) + error_status[0] = 1 + return 0 + +def assembler(pc, line, line_number, error_flag, error_counter, bin_instruction): + opcode_array = [] + # Instruction fields - initialization + rs1 = 'x0' + rs2 = 'x0' + rd = 'x0' + immediate = 0 + # Instruction type flags + r_type_flag = 0 + i_type_flag = 0 + s_type_flag = 0 + b_type_flag = 0 + u_type_flag = 0 + j_type_flag = 0 + # Pseudo instruction flags + pseudo_instruction_mv_type_flag = 0 + pseudo_instruction_mvi_type_flag = 0 + pseudo_instruction_nop_type_flag = 0 + pseudo_instruction_j_type_flag = 0 + pseudo_instruction_not_type_flag = 0 + pseudo_instruction_inv_type_flag = 0 + pseudo_instruction_seqz_type_flag = 0 + pseudo_instruction_snez_type_flag = 0 + pseudo_instruction_beqz_type_flag = 0 + pseudo_instruction_bnez_type_flag = 0 + pseudo_instruction_li_type_flag = 0 + pseudo_instruction_la_type_flag = 0 + pseudo_instruction_jr_type_flag = 0 + + instruction_error_flag = 0 + arguement = line.split() + try: + if arguement[0][0] == '#': + # Ignore comment + return 0 + elif arguement[0] == '.RESET_ADDRESS': + # Ignore .RESET_ADDRESS + return 0 + elif validity_label(arguement[0].rstrip(':')): + return 0 + except: + return 0 + try: + opcode = arguement[0] + except: + print("FATAL ERROR: Instruction at line no: ", line_number, " - opcode not defined.\n") + error_counter[0] = error_counter[0] + 1 + return 2 + + # opcode decoding + if opcode == 'LUI' or opcode == 'lui': + u_type_flag = 1 + opcode_bin = '0110111' + elif opcode == 'AUIPC' or opcode == 'auipc': + u_type_flag = 1 + opcode_bin = '0010111' + elif opcode == 'JAL' or opcode == 'jal': + j_type_flag = 1 + opcode_bin = '1101111' + elif opcode == 'JALR' or opcode == 'jalr': + i_type_flag = 1 + opcode_bin = '1100111' + elif opcode == 'BEQ' or opcode == 'beq' or opcode == 'BNE' or opcode == 'bne' or \ + opcode == 'BLT' or opcode == 'blt' or opcode == 'BGE' or opcode == 'bge' or \ + opcode == 'BLTU' or opcode == 'bltu' or opcode == 'BGEU' or opcode == 'bgeu': + b_type_flag = 1 + opcode_bin = '1100011' + elif opcode == 'LB' or opcode == 'lb' or opcode == 'LH' or opcode == 'lh' or \ + opcode == 'LW' or opcode == 'lw' or opcode == 'LBU' or opcode == 'lbu' or \ + opcode == 'LHU' or opcode == 'lhu': + i_type_flag = 1 + opcode_bin = '0000011' + elif opcode == 'SB' or opcode == 'sb' or opcode == 'SH' or opcode == 'sh' or \ + opcode == 'SW' or opcode == 'sw': + s_type_flag = 1 + opcode_bin = '0100011' + elif opcode == 'ADDI' or opcode == 'addi' or opcode == 'SLTI' or opcode == 'slti' or \ + opcode == 'SLTIU' or opcode == 'sltiu' or opcode == 'XORI' or opcode == 'xori' or \ + opcode == 'ORI' or opcode == 'ori' or opcode == 'ANDI' or opcode == 'andi' or \ + opcode == 'SLLI' or opcode == 'slli' or opcode == 'SRLI' or opcode == 'srli' or \ + opcode == 'SRAI' or opcode == 'srai': + i_type_flag = 1 + opcode_bin = '0010011' + elif opcode == 'ADD' or opcode == 'add' or opcode == 'SUB' or opcode == 'sub' or \ + opcode == 'SLL' or opcode == 'sll' or opcode == 'SLT' or opcode == 'slt' or \ + opcode == 'SLTU' or opcode == 'sltu' or opcode == 'XOR' or opcode == 'xor' or \ + opcode == 'SRL' or opcode == 'srl' or opcode == 'SRA' or opcode == 'sra' or \ + opcode == 'MUL' or opcode == 'mul' or opcode == 'MULH' or opcode == 'mulh' or \ + opcode == 'MULHSU' or opcode == 'mulhsu' or opcode == 'MULHU' or opcode == 'mulhu' or \ + opcode == 'DIV' or opcode == 'div' or opcode == 'DIVU' or opcode == 'divu' or \ + opcode == 'REM' or opcode == 'rem' or opcode == 'REMU' or opcode == 'remu' or \ + opcode == 'SRL' or opcode == 'srl' or opcode == 'SRA' or opcode == 'sra' or \ + opcode == 'OR' or opcode == 'or' or opcode == 'AND' or opcode == 'and': + r_type_flag = 1 + opcode_bin = '0110011' + elif opcode == 'EBREAK' or opcode == 'ebreak' or opcode == 'ECALL' or opcode == 'ecall' or \ + opcode == 'CSRRW' or opcode == 'csrrw' or opcode == 'CSRRS' or opcode == 'csrrs': + opcode_bin = '1110011' # SYSTEM opcode + + # Pseudo instructions decoding + elif opcode == 'MV' or opcode == 'mv': + pseudo_instruction_mv_type_flag = 1 + opcode_bin = '0010011' # Pseudo instruction - ADDI + elif opcode == 'MVI' or opcode == 'mvi': + pseudo_instruction_mvi_type_flag = 1 + opcode_bin = '0010011' # Pseudo instruction - ADDI + elif opcode == 'NOP' or opcode == 'nop': + pseudo_instruction_nop_type_flag = 1 + opcode_bin = '0010011' # Pseudo instruction - ADDI + elif opcode == 'J' or opcode == 'j': + pseudo_instruction_j_type_flag = 1 + opcode_bin = '1101111' # Pseudo instruction -JAL + elif opcode == 'NOT' or opcode == 'not': + pseudo_instruction_not_type_flag = 1 + opcode_bin = '0010011' # Pseudo instruction - XORI + elif opcode == 'INV' or opcode == 'inv': + pseudo_instruction_inv_type_flag = 1 + opcode_bin = '0010011' # Pseudo instruction - XORI + elif opcode == 'SEQZ' or opcode == 'seqz': + pseudo_instruction_seqz_type_flag = 1 + opcode_bin = '0010011' # Pseudo instruction - SLTIU + elif opcode == 'SNEZ' or opcode == 'snez': + pseudo_instruction_snez_type_flag = 1 + opcode_bin = '0110011' # Pseudo instruction - SLTU + elif opcode == 'BEQZ' or opcode == 'beqz': + pseudo_instruction_beqz_type_flag = 1 + opcode_bin = '1100011' # Pseudo instruction - BEQ + elif opcode == 'BNEZ' or opcode == 'bnez': + pseudo_instruction_bnez_type_flag = 1 + opcode_bin = '1100011' # Pseudo instruction - BNE + + # 2-step pseudo instructions + elif opcode == 'LI' or opcode == 'li': + pseudo_instruction_li_type_flag = 1 + opcode_array.append('0110111') # LUI + opcode_array.append('0010011') # ADDI + elif opcode == 'LA' or opcode == 'la': + pseudo_instruction_la_type_flag = 1 + opcode_array.append('0110111') # LUI + opcode_array.append('0010011') # ADDI + elif opcode == 'JR' or opcode == 'jr': + pseudo_instruction_jr_type_flag = 1 + opcode_bin = '1100111' # Pseudo instruction - JALR + else: + print("ERROR: Invalid/unsupported opcode at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + + # R-type instructions + if r_type_flag == 1: + try: + rd = arguement[1] + rs1 = arguement[2] + rs2 = arguement[3] + if validity_registers(rd) or validity_registers(rs1) or validity_registers(rs2): + print("ERROR: Invalid/unsupported register at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + elif len(arguement) > 4 and arguement[4][0] != '#': # Integrity check; ignore if inline comment + print("ERROR: Invalid no. of operands at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + except: + print("FATAL ERROR: Instruction at line no: ", line_number, " is missing one or more operands!\n") + error_counter[0] = error_counter[0] + 1 + return 2 + + # I-type instructions + if i_type_flag == 1: + try: + rd = arguement[1] + rs1 = arguement[2] + immediate = arguement[3] + if validity_registers(rd) or validity_registers(rs1): + print("ERROR: Invalid/unsupported register at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + elif len(arguement) > 4 and arguement[4][0] != '#': # Integrity check; ignore if inline comment + print("ERROR: Invalid no. of operands at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + except: + print("FATAL ERROR: Instruction at line no: ", line_number, " is missing one or more operands!\n") + error_counter[0] = error_counter[0] + 1 + return 2 + + # S-type instructions + if s_type_flag == 1: + try: + rs2 = arguement[1] + rs1 = arguement[2] + immediate = arguement[3] + if validity_registers(rs2) or validity_registers(rs1): + print("ERROR: Invalid/unsupported register at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + elif len(arguement) > 4 and arguement[4][0] != '#': # Integrity check; ignore if inline comment + print("ERROR: Invalid no. of operands at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + except: + print("FATAL ERROR: Instruction at line no: ", line_number, " is missing one or more operands!\n") + error_counter[0] = error_counter[0] + 1 + return 2 + + # B-type instructions + if b_type_flag == 1: + try: + rs1 = arguement[1] + rs2 = arguement[2] + immediate = arguement[3] + if validity_registers(rs1) or validity_registers(rs2): + print("ERROR: Invalid/unsupported register at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + elif len(arguement) > 4 and arguement[4][0] != '#': # Integrity check; ignore if inline comment + print("ERROR: Invalid no. of operands at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + except: + print("FATAL ERROR: Instruction at line no: ", line_number, " is missing one or more operands!\n") + error_counter[0] = error_counter[0] + 1 + return 2 + + # U-type/J-type instructions + if u_type_flag == 1 or j_type_flag == 1: + try: + rd = arguement[1] + immediate = arguement[2] + if validity_registers(rd): + print("ERROR: Invalid/unsupported register at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + elif len(arguement) > 3 and arguement[3][0] != '#': # Integrity check; ignore if inline comment + print("ERROR: Invalid no. of operands at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + except: + print("FATAL ERROR: Instruction at line no: ", line_number, " is missing one or more operands!\n") + error_counter[0] = error_counter[0] + 1 + return 2 + + # Pseudo instruction: MV + if pseudo_instruction_mv_type_flag == 1: + try: + i_type_flag = 1 # Derived from i-type + rd = arguement[1] + rs1 = arguement[2] + immediate = 0 + if validity_registers(rd) or validity_registers(rs1): + print("ERROR: Invalid/unsupported register at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + elif len(arguement) > 3 and arguement[3][0] != '#': # Integrity check; ignore if inline comment + print("ERROR: Invalid no. of operands at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + except: + print("FATAL ERROR: Instruction at line no: ", line_number, " is missing one or more operands!\n") + error_counter[0] = error_counter[0] + 1 + return 2 + + # Pseudo instruction: MVI + if pseudo_instruction_mvi_type_flag == 1: + try: + i_type_flag = 1 # Derived from i-type + rd = arguement[1] + rs1 = 'x0' + immediate = arguement[2] + if validity_registers(rd): + print("ERROR: Invalid/unsupported register at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + elif len(arguement) > 3 and arguement[3][0] != '#': # Integrity check; ignore if inline comment + print("ERROR: Invalid no. of operands at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + except: + print("FATAL ERROR: Instruction at line no: ", line_number, " is missing one or more operands!\n") + error_counter[0] = error_counter[0] + 1 + return 2 + + # Pseudo instruction: NOP + if pseudo_instruction_nop_type_flag == 1: + i_type_flag = 1 # Derived from i-type + rd = 'x0' + rs1 = 'x0' + immediate = 0 + if len(arguement) > 1 and arguement[1][0] != '#': # Integrity check; ignore if inline comment + print("ERROR: Invalid no. of operands at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + + # Pseudo instruction: J + if pseudo_instruction_j_type_flag == 1: + try: + j_type_flag = 1 # Derived from j-type + rd = 'x0' + immediate = arguement[1] + if len(arguement) > 2 and arguement[2][0] != '#': # Integrity check; ignore if inline comment + print("ERROR: Invalid no. of operands at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + except: + print("FATAL ERROR: Instruction at line no: ", line_number, " is missing one or more operands!\n") + error_counter[0] = error_counter[0] + 1 + return 2 + + # Pseudo instruction: NOT + if pseudo_instruction_not_type_flag == 1: + try: + i_type_flag = 1 # Derived from i-type + rd = arguement[1] + rs1 = arguement[2] + immediate = -1 + if validity_registers(rd) or validity_registers(rs1): + print("ERROR: Invalid/unsupported register at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + elif len(arguement) > 3 and arguement[3][0] != '#': # Integrity check; ignore if inline comment + print("ERROR: Invalid no. of operands at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + except: + print("FATAL ERROR: Instruction at line no: ", line_number, " is missing one or more operands!\n") + error_counter[0] = error_counter[0] + 1 + return 2 + + # Pseudo instruction: INV + if pseudo_instruction_inv_type_flag == 1: + try: + i_type_flag = 1 # Derived from i-type + rd = arguement[1] + rs1 = arguement[1] + immediate = -1 + if validity_registers(rd): + print("ERROR: Invalid/unsupported register at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + elif len(arguement) > 2 and arguement[2][0] != '#': # Integrity check; ignore if inline comment + print("ERROR: Invalid no. of operands at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + except: + print("FATAL ERROR: Instruction at line no: ", line_number, " is missing one or more operands!\n") + error_counter[0] = error_counter[0] + 1 + return 2 + + # Pseudo instruction: SEQZ + if pseudo_instruction_seqz_type_flag == 1: + try: + i_type_flag = 1 # Derived from i-type + rd = arguement[1] + rs1 = arguement[2] + immediate = 1 + if validity_registers(rd) or validity_registers(rs1): + print("ERROR: Invalid/unsupported register at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + elif len(arguement) > 3 and arguement[3][0] != '#': # Integrity check; ignore if inline comment + print("ERROR: Invalid no. of operands at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + except: + print("FATAL ERROR: Instruction at line no: ", line_number, " is missing one or more operands!\n") + error_counter[0] = error_counter[0] + 1 + return 2 + + # Pseudo instruction: SNEZ + if pseudo_instruction_snez_type_flag == 1: + try: + r_type_flag = 1 # Derived from r-type + rd = arguement[1] + rs1 = 'x0' + rs2 = arguement[2] + if validity_registers(rd) or validity_registers(rs2): + print("ERROR: Invalid/unsupported register at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + elif len(arguement) > 3 and arguement[3][0] != '#': # Integrity check; ignore if inline comment + print("ERROR: Invalid no. of operands at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + except: + print("FATAL ERROR: Instruction at line no: ", line_number, " is missing one or more operands!\n") + error_counter[0] = error_counter[0] + 1 + return 2 + + # Pseudo instruction: BEQZ + if pseudo_instruction_beqz_type_flag == 1: + try: + b_type_flag = 1 # Derived from b-type + rs1 = arguement[1] + rs2 = 'x0' + immediate = arguement[2] + if validity_registers(rs1): + print("ERROR: Invalid/unsupported register at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + elif len(arguement) > 3 and arguement[3][0] != '#': # Integrity check; ignore if inline comment + print("ERROR: Invalid no. of operands at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + except: + print("FATAL ERROR: Instruction at line no: ", line_number, " is missing one or more operands!\n") + error_counter[0] = error_counter[0] + 1 + return 2 + + # Pseudo instruction: BNEZ + if pseudo_instruction_bnez_type_flag == 1: + try: + b_type_flag = 1 # Derived from b-type + rs1 = arguement[1] + rs2 = 'x0' + immediate = arguement[2] + if validity_registers(rs1): + print("ERROR: Invalid/unsupported register at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + elif len(arguement) > 3 and arguement[3][0] != '#': # Integrity check; ignore if inline comment + print("ERROR: Invalid no. of operands at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + except: + print("FATAL ERROR: Instruction at line no: ", line_number, " is missing one or more operands!\n") + error_counter[0] = error_counter[0] + 1 + return 2 + + # Pseudo instruction: LI/LA + if pseudo_instruction_li_type_flag or pseudo_instruction_la_type_flag: + try: + rs1 = arguement[1] # For ADDI + rd = arguement[1] # For LUI, ADDI + immediate = arguement[2] + if validity_registers(rd): + print("ERROR: Invalid/unsupported register at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + elif len(arguement) > 3 and arguement[3][0] != '#': # Integrity check; ignore if inline comment + print("ERROR: Invalid no. of operands at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + except: + print("FATAL ERROR: Instruction at line no: ", line_number, " is missing one or more operands!\n") + error_counter[0] = error_counter[0] + 1 + return 2 + + # Pseudo instruction: JR + if pseudo_instruction_jr_type_flag: + try: + i_type_flag = 1 # Derived from i-type + rd = 'x0' + rs1 = arguement[1] + immediate = 0 + if validity_registers(rs1): + print("ERROR: Invalid/unsupported register at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + elif len(arguement) > 2 and arguement[2][0] != '#': # Integrity check; ignore if inline comment + print("ERROR: Invalid no. of operands at line no: ", line_number) + instruction_error_flag = 1 + error_flag[0] = 1 + except: + print("FATAL ERROR: Instruction at line no: ", line_number, " is missing one or more operands!\n") + error_counter[0] = error_counter[0] + 1 + return 2 + + rs1_bin = register_index_mapping(rs1) + rs2_bin = register_index_mapping(rs2) + rd_bin = register_index_mapping(rd) + + # Decode immediate/offset + error_status = [0] + if r_type_flag == 0: + immediate_bin = immediate_generator(immediate, line_number, error_status, (j_type_flag or b_type_flag), + pseudo_instruction_la_type_flag) + if error_status[0] == 1: + instruction_error_flag = 1 + error_flag[0] = 1 + + # Decoding 'funct3' and 'funct7' fields of instruction + if instruction_error_flag == 0 and (opcode == 'EBREAK' or opcode == 'ebreak'): + funct3 = '000' + funct7 = '0000000' + bin_instruction.append('00000000000100000000000001110011') + elif instruction_error_flag == 0 and (opcode == 'ECALL' or opcode == 'ecall'): + funct3 = '000' + funct7 = '0000000' + bin_instruction.append('00000000000000000000000001110011') + elif instruction_error_flag == 0 and (opcode == 'ADD' or opcode == 'add'): + funct3 = '000' + funct7 = '0000000' + bin_instruction.append(funct7 + rs2_bin + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'SUB' or opcode == 'sub'): + funct3 = '000' + funct7 = '0100000' + bin_instruction.append(funct7 + rs2_bin + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'SLL' or opcode == 'sll'): + funct3 = '001' + funct7 = '0000000' + bin_instruction.append(funct7 + rs2_bin + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'SLT' or opcode == 'slt'): + funct3 = '010' + funct7 = '0000000' + bin_instruction.append(funct7 + rs2_bin + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'SLTU' or opcode == 'sltu'): + funct3 = '011' + funct7 = '0000000' + bin_instruction.append(funct7 + rs2_bin + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'XOR' or opcode == 'xor'): + funct3 = '100' + funct7 = '0000000' + bin_instruction.append(funct7 + rs2_bin + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'SRL' or opcode == 'srl'): + funct3 = '101' + funct7 = '0000000' + bin_instruction.append(funct7 + rs2_bin + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'SRA' or opcode == 'sra'): + funct3 = '101' + funct7 = '0100000' + bin_instruction.append(funct7 + rs2_bin + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'OR' or opcode == 'or'): + funct3 = '110' + funct7 = '0000000' + bin_instruction.append(funct7 + rs2_bin + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'AND' or opcode == 'and'): + funct3 = '111' + funct7 = '0000000' + bin_instruction.append(funct7 + rs2_bin + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'MUL' or opcode == 'mul'): + funct3 = '000' + funct7 = '0000001' + bin_instruction.append(funct7 + rs2_bin + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'MULH' or opcode == 'mulh'): + funct3 = '001' + funct7 = '0000001' + bin_instruction.append(funct7 + rs2_bin + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'MULHSU' or opcode == 'mulhsu'): + funct3 = '010' + funct7 = '0000001' + bin_instruction.append(funct7 + rs2_bin + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'MULHU' or opcode == 'mulhu'): + funct3 = '011' + funct7 = '0000001' + bin_instruction.append(funct7 + rs2_bin + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'DIV' or opcode == 'div'): + funct3 = '100' + funct7 = '0000001' + bin_instruction.append(funct7 + rs2_bin + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'DIVU' or opcode == 'divu'): + funct3 = '101' + funct7 = '0000001' + bin_instruction.append(funct7 + rs2_bin + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'REM' or opcode == 'rem'): + funct3 = '110' + funct7 = '0000001' + bin_instruction.append(funct7 + rs2_bin + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'REMU' or opcode == 'remu'): + funct3 = '111' + funct7 = '0000001' + bin_instruction.append(funct7 + rs2_bin + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'JALR' or opcode == 'jalr'): + immediate_bin_11_0 = immediate_bin[20:32] # immediate[11:0] + funct3 = '000' + bin_instruction.append(immediate_bin_11_0 + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'LB' or opcode == 'lb'): + immediate_bin_11_0 = immediate_bin[20:32] # immediate[11:0] + funct3 = '000' + bin_instruction.append(immediate_bin_11_0 + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'LH' or opcode == 'lh'): + immediate_bin_11_0 = immediate_bin[20:32] # immediate[11:0] + funct3 = '001' + bin_instruction.append(immediate_bin_11_0 + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'LW' or opcode == 'lw'): + immediate_bin_11_0 = immediate_bin[20:32] # immediate[11:0] + funct3 = '010' + bin_instruction.append(immediate_bin_11_0 + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'LBU' or opcode == 'lbu'): + immediate_bin_11_0 = immediate_bin[20:32] # immediate[11:0] + funct3 = '100' + bin_instruction.append(immediate_bin_11_0 + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'LHU' or opcode == 'lhu'): + immediate_bin_11_0 = immediate_bin[20:32] # immediate[11:0] + funct3 = '101' + bin_instruction.append(immediate_bin_11_0 + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'ADDI' or opcode == 'addi'): + immediate_bin_11_0 = immediate_bin[20:32] # immediate[11:0] + funct3 = '000' + bin_instruction.append(immediate_bin_11_0 + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'SLTI' or opcode == 'slti'): + immediate_bin_11_0 = immediate_bin[20:32] # immediate[11:0] + funct3 = '010' + bin_instruction.append(immediate_bin_11_0 + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'SLTIU' or opcode == 'sltiu'): + immediate_bin_11_0 = immediate_bin[20:32] # immediate[11:0] + funct3 = '011' + bin_instruction.append(immediate_bin_11_0 + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'XORI' or opcode == 'xori'): + immediate_bin_11_0 = immediate_bin[20:32] # immediate[11:0] + funct3 = '100' + bin_instruction.append(immediate_bin_11_0 + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'ORI' or opcode == 'ori'): + immediate_bin_11_0 = immediate_bin[20:32] # immediate[11:0] + funct3 = '110' + bin_instruction.append(immediate_bin_11_0 + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'ANDI' or opcode == 'andi'): + immediate_bin_11_0 = immediate_bin[20:32] # immediate[11:0] + funct3 = '111' + bin_instruction.append(immediate_bin_11_0 + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'SLLI' or opcode == 'slli'): + shamnt = immediate_bin[27:32] # immediate[4:0] + funct3 = '001' + funct7 = '0000000' + bin_instruction.append(funct7 + shamnt + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'SRLI' or opcode == 'srli'): + shamnt = immediate_bin[27:32] # immediate[4:0] + funct3 = '101' + funct7 = '0000000' + bin_instruction.append(funct7 + shamnt + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'SRAI' or opcode == 'srai'): + shamnt = immediate_bin[27:32] # immediate[4:0] + funct3 = '101' + funct7 = '0100000' + bin_instruction.append(funct7 + shamnt + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'SB' or opcode == 'sb'): + immediate_bin_11_0 = immediate_bin[20:32] # immediate[11:0] + funct3 = '000' + bin_instruction.append(immediate_bin_11_0[0:7] + rs2_bin + rs1_bin + funct3 + immediate_bin_11_0[7:12] + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'SH' or opcode == 'sh'): + immediate_bin_11_0 = immediate_bin[20:32] # immediate[11:0] + funct3 = '001' + bin_instruction.append(immediate_bin_11_0[0:7] + rs2_bin + rs1_bin + funct3 + immediate_bin_11_0[7:12] + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'SW' or opcode == 'sw'): + immediate_bin_11_0 = immediate_bin[20:32] # immediate[11:0] + funct3 = '010' + bin_instruction.append(immediate_bin_11_0[0:7] + rs2_bin + rs1_bin + funct3 + immediate_bin_11_0[7:12] + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'BEQ' or opcode == 'beq'): + immediate_bin_12_1 = immediate_bin[19:31] # immediate[12:1] + funct3 = '000' + bin_instruction.append(immediate_bin_12_1[0] + immediate_bin_12_1[2:8] + rs2_bin + rs1_bin + funct3 + immediate_bin_12_1[8:12] + + immediate_bin_12_1[1] + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'BNE' or opcode == 'bne'): + immediate_bin_12_1 = immediate_bin[19:31] # immediate[12:1] + funct3 = '001' + bin_instruction.append(immediate_bin_12_1[0] + immediate_bin_12_1[2:8] + rs2_bin + rs1_bin + funct3 + immediate_bin_12_1[8:12] + + immediate_bin_12_1[1] + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'BLT' or opcode == 'blt'): + immediate_bin_12_1 = immediate_bin[19:31] # immediate[12:1] + funct3 = '100' + bin_instruction.append(immediate_bin_12_1[0] + immediate_bin_12_1[2:8] + rs2_bin + rs1_bin + funct3 + immediate_bin_12_1[8:12] + + immediate_bin_12_1[1] + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'BGE' or opcode == 'bge'): + immediate_bin_12_1 = immediate_bin[19:31] # immediate[12:1] + funct3 = '101' + bin_instruction.append(immediate_bin_12_1[0] + immediate_bin_12_1[2:8] + rs2_bin + rs1_bin + funct3 + immediate_bin_12_1[8:12] + + immediate_bin_12_1[1] + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'BLTU' or opcode == 'bltu'): + immediate_bin_12_1 = immediate_bin[19:31] # immediate[12:1] + funct3 = '110' + bin_instruction.append(immediate_bin_12_1[0] + immediate_bin_12_1[2:8] + rs2_bin + rs1_bin + funct3 + immediate_bin_12_1[8:12] + + immediate_bin_12_1[1] + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'BGEU' or opcode == 'bgeu'): + immediate_bin_12_1 = immediate_bin[19:31] # immediate[12:1] + funct3 = '111' + bin_instruction.append(immediate_bin_12_1[0] + immediate_bin_12_1[2:8] + rs2_bin + rs1_bin + funct3 + immediate_bin_12_1[8:12] + + immediate_bin_12_1[1] + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'LUI' or opcode == 'lui'): + immediate_bin_31_12 = immediate_bin[12:32] # Observed to be immediate[19:0] in all implementations, not immediate[31:12] + bin_instruction.append(immediate_bin_31_12 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'AUIPC' or opcode == 'auipc'): + immediate_bin_31_12 = immediate_bin[12:32] # Observed to be immediate[19:0] in all implementations, not immediate[31:12] + bin_instruction.append(immediate_bin_31_12 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'JAL' or opcode == 'jal'): + immediate_bin_20_1 = immediate_bin[11:31] # immediate[20:1] + bin_instruction.append(immediate_bin_20_1[0] + immediate_bin_20_1[10:20] + immediate_bin_20_1[9] + immediate_bin_20_1[1:9] + + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (pseudo_instruction_mv_type_flag or pseudo_instruction_mvi_type_flag or pseudo_instruction_nop_type_flag): # = ADDI + immediate_bin_11_0 = immediate_bin[20:32] # immediate[11:0] + funct3 = '000' + bin_instruction.append(immediate_bin_11_0 + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and pseudo_instruction_j_type_flag: # = JAL + immediate_bin_20_1 = immediate_bin[11:31] # immediate[20:1] + bin_instruction.append(immediate_bin_20_1[0] + immediate_bin_20_1[10:20] + immediate_bin_20_1[9] + immediate_bin_20_1[1:9] + + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (pseudo_instruction_not_type_flag or pseudo_instruction_inv_type_flag): # = XORI + immediate_bin_11_0 = immediate_bin[20:32] # immediate[11:0] + funct3 = '100' + bin_instruction.append(immediate_bin_11_0 + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and pseudo_instruction_seqz_type_flag: # = SLTIU + immediate_bin_11_0 = immediate_bin[20:32] # immediate[11:0] + funct3 = '011' + bin_instruction.append(immediate_bin_11_0 + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and pseudo_instruction_snez_type_flag: # = SLTU + funct3 = '011' + funct7 = '0000000' + bin_instruction.append(funct7 + rs2_bin + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and pseudo_instruction_beqz_type_flag: # = BEQ + immediate_bin_12_1 = immediate_bin[19:31] # immediate[12:1] + funct3 = '000' + bin_instruction.append(immediate_bin_12_1[0] + immediate_bin_12_1[2:8] + rs2_bin + rs1_bin + funct3 + immediate_bin_12_1[8:12] + + immediate_bin_12_1[1] + opcode_bin) + elif instruction_error_flag == 0 and pseudo_instruction_bnez_type_flag: # = BNE + immediate_bin_12_1 = immediate_bin[19:31] # immediate[12:1] + funct3 = '001' + bin_instruction.append(immediate_bin_12_1[0] + immediate_bin_12_1[2:8] + rs2_bin + rs1_bin + funct3 + immediate_bin_12_1[8:12] + + immediate_bin_12_1[1] + opcode_bin) + elif instruction_error_flag == 0 and (pseudo_instruction_li_type_flag or pseudo_instruction_la_type_flag): # = LUI + ADDI + # LUI + if immediate_bin[20] == '0': + immediate_bin_31_12 = immediate_bin[0:20] # immediate[31:12] + else: + temp = int(immediate_bin[0:20], base=2) + 1 + immediate_bin_lui = int_to_binary(temp) + immediate_bin_31_12 = immediate_bin_lui[12:32] # immediate[31:12] + 1 + bin_instruction.append(immediate_bin_31_12 + rd_bin + opcode_array[0]) # Write LUI instruction + # ADDI + immediate_bin_11_0 = immediate_bin[20:32] # immediate[11:0] + funct3 = '000' + bin_instruction.append(immediate_bin_11_0 + rs1_bin + funct3 + rd_bin + opcode_array[1]) # Write ADDI instruction + elif instruction_error_flag == 0 and (pseudo_instruction_jr_type_flag): # = JALR + immediate_bin_11_0 = immediate_bin[20:32] # immediate[11:0] + funct3 = '000' + bin_instruction.append(immediate_bin_11_0 + rs1_bin + funct3 + rd_bin + opcode_bin) + elif instruction_error_flag == 0 and (opcode == 'CSRRW' or opcode == 'csrrw'): + # Remove the '0x' prefix if it exists + if immediate.startswith("0x"): + immediate = immediate[2:] + decimal_immediate = int(immediate, 16) + binary_immediate = bin(decimal_immediate)[2:] + # Zero-extend to the specified bit size + csr_address = binary_immediate.zfill(12) + csr_address = csr_address[-12:] # Ensure it's no longer than the bit size + bin_instruction.append(csr_address + rs1_bin + "001" + rd_bin + "1110011") + elif instruction_error_flag == 0 and (opcode == 'CSRRS' or opcode == 'csrrs'): + # Remove the '0x' prefix if it exists + if immediate.startswith("0x"): + immediate = immediate[2:] + decimal_immediate = int(immediate, 16) + binary_immediate = bin(decimal_immediate)[2:] + # Zero-extend to the specified bit size + csr_address = binary_immediate.zfill(12) + csr_address = csr_address[-12:] # Ensure it's no longer than the bit size + bin_instruction.append(csr_address + rs1_bin + "010" + rd_bin + "1110011") + elif instruction_error_flag == 0 and (opcode == 'CSRRC' or opcode == 'csrrc'): + # Remove the '0x' prefix if it exists + if immediate.startswith("0x"): + immediate = immediate[2:] + decimal_immediate = int(immediate, 16) + binary_immediate = bin(decimal_immediate)[2:] + # Zero-extend to the specified bit size + csr_address = binary_immediate.zfill(12) + csr_address = csr_address[-12:] # Ensure it's no longer than the bit size + bin_instruction.append(csr_address + rs1_bin + "011" + rd_bin + "1110011") + else: + funct3 = 'XXX' + + # Update pc + if pseudo_instruction_li_type_flag or pseudo_instruction_la_type_flag: + pc[0] = pc[0] + 8 # LI expands to two instructions + else: + pc[0] = pc[0] + 4 + + # Check for any errors logged in the instruction + if instruction_error_flag == 0: + print("INFO: Processing line", line_number, "- PASSED") + return 0 + else: + error_counter[0] = error_counter[0] + 1 + print("ERROR: Processing line", line_number, "- FAILED\n") + return 1 \ No newline at end of file diff --git a/Software/AssembleX/data_conversion.py b/Software/AssembleX/data_conversion.py new file mode 100644 index 0000000..24ab0e8 --- /dev/null +++ b/Software/AssembleX/data_conversion.py @@ -0,0 +1,233 @@ +# AssembleX V3.0 +# RISC-V Assembly Software Assistant for the phoeniX project (https://github.com/phoeniX-Digital-Design/phoeniX) + +# Description: Data conversion functions +# Copyright 2024 Iran University of Science and Technology. + +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. + +def binary_to_hex(bin_instruction, hex_instruction): + for line in bin_instruction: + hex_instruction.append("{:08x}".format(int(line, 2))) # 32-bit hex from binary string + +def int_to_binary(value): + temp = value + if value < 0: + temp = 0xffffffff + 1 + value # 2'string complement taken if -ve number + binary = '{:032b}'.format(int(temp)) # Signed 32-bit binary + return binary + +parse_ascii = [False] +def ascii_to_hex(arguement): + if arguement: + string = arguement[0] + x = string.split("'") + if ((len(x) == 3 and len(x[1]) == 1) or + ((len(x) == 3 and len(x[1]) == 2) and (x[1] == '\\n' or x[1] == '\\r'))): + arguement_hex = character_to_hex(x[1]) + parse_ascii[0] = True + if arguement_hex != "#ERR": + modified_line = x[0] + arguement_hex + x[2] + arguement[0] = modified_line + else: + arguement[0] = arguement + +def character_to_hex(character): + if character == ' ': + return '0x20' + elif character == '!': + return '0x21' + elif character == '"': + return '0x22' + elif character == '#': + return '0x23' + elif character == '$': + return '0x24' + elif character == '%': + return '0x25' + elif character == '&': + return '0x26' + elif character == "'": + return '0x27' + elif character == '(': + return '0x28' + elif character == ')': + return '0x29' + elif character == '*': + return '0x2A' + elif character == '+': + return '0x2B' + elif character == ',': + return '0x2C' + elif character == '-': + return '0x2D' + elif character == '.': + return '0x2E' + elif character == '/': + return '0x2F' + elif character == '0': + return '0x30' + elif character == '1': + return '0x31' + elif character == '2': + return '0x32' + elif character == '3': + return '0x33' + elif character == '4': + return '0x34' + elif character == '5': + return '0x35' + elif character == '6': + return '0x36' + elif character == '7': + return '0x37' + elif character == '8': + return '0x38' + elif character == '9': + return '0x39' + elif character == ':': + return '0x3A' + elif character == ';': + return '0x3B' + elif character == '<': + return '0x3C' + elif character == '=': + return '0x3D' + elif character == '>': + return '0x3E' + elif character == '?': + return '0x3F' + elif character == '@': + return '0x40' + elif character == 'A': + return '0x41' + elif character == 'B': + return '0x42' + elif character == 'C': + return '0x43' + elif character == 'D': + return '0x44' + elif character == 'E': + return '0x45' + elif character == 'F': + return '0x46' + elif character == 'G': + return '0x47' + elif character == 'H': + return '0x48' + elif character == 'I': + return '0x49' + elif character == 'J': + return '0x4A' + elif character == 'K': + return '0x4B' + elif character == 'L': + return '0x4C' + elif character == 'M': + return '0x4D' + elif character == 'N': + return '0x4E' + elif character == 'O': + return '0x4F' + elif character == 'P': + return '0x50' + elif character == 'Q': + return '0x51' + elif character == 'R': + return '0x52' + elif character == 'S': + return '0x53' + elif character == 'T': + return '0x54' + elif character == 'U': + return '0x55' + elif character == 'V': + return '0x56' + elif character == 'W': + return '0x57' + elif character == 'X': + return '0x58' + elif character == 'Y': + return '0x59' + elif character == 'Z': + return '0x5A' + elif character == '[': + return '0x5B' + elif character == '\\': + return '0x5C' + elif character == ']': + return '0x5D' + elif character == '^': + return '0x5E' + elif character == '_': + return '0x5F' + elif character == '`': + return '0x60' + elif character == 'a': + return '0x61' + elif character == 'b': + return '0x62' + elif character == 'c': + return '0x63' + elif character == 'd': + return '0x64' + elif character == 'e': + return '0x65' + elif character == 'f': + return '0x66' + elif character == 'g': + return '0x67' + elif character == 'h': + return '0x68' + elif character == 'i': + return '0x69' + elif character == 'j': + return '0x6A' + elif character == 'k': + return '0x6B' + elif character == 'l': + return '0x6C' + elif character == 'm': + return '0x6D' + elif character == 'n': + return '0x6E' + elif character == 'o': + return '0x6F' + elif character == 'p': + return '0x70' + elif character == 'q': + return '0x71' + elif character == 'r': + return '0x72' + elif character == 'string': + return '0x73' + elif character == 't': + return '0x74' + elif character == 'u': + return '0x75' + elif character == 'v': + return '0x76' + elif character == 'w': + return '0x77' + elif character == 'x': + return '0x78' + elif character == 'y': + return '0x79' + elif character == 'z': + return '0x7A' + elif character == '{': + return '0x7B' + elif character == '|': + return '0x7C' + elif character == '}': + return '0x7D' + elif character == '~': + return '0x7E' + elif character == '\\n': + return '0x0A' + elif character == '\\r': + return '0x0D' + else: + return '#ERR' \ No newline at end of file diff --git a/Software/AssembleX/registers_rv32i.py b/Software/AssembleX/registers_rv32i.py new file mode 100644 index 0000000..f3b28c2 --- /dev/null +++ b/Software/AssembleX/registers_rv32i.py @@ -0,0 +1,92 @@ +# AssembleX V3.0 +# RISC-V Assembly Software Assistant for the phoeniX project (https://github.com/phoeniX-Digital-Design/phoeniX) + +# Description: Registers + Index mapping +# Copyright 2024 Iran University of Science and Technology. + +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. + +registers_rv32i = [ 'x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7', + 'x8', 'x9', 'x10', 'x11', 'x12', 'x13', 'x14', 'x15', + 'x16', 'x17', 'x18', 'x19', 'x20', 'x21', 'x22', 'x23', + 'x24', 'x25', 'x26', 'x27', 'x28', 'x29', 'x30', 'x31', + 'X0', 'X1', 'X2', 'X3', 'X4', 'X5', 'X6', 'X7', + 'X8', 'X9', 'X10', 'X11', 'X12', 'X13', 'X14', 'X15', + 'X16', 'X17', 'X18', 'X19', 'X20', 'X21', 'X22', 'X23', + 'X24', 'X25', 'X26', 'X27', 'X28', 'X29', 'X30', 'X31', + 'zero', 'ZERO', 'ra', 'RA', 'sp', 'SP', 'gp', 'GP', 'tp', 'TP', + 't0', 'T0', 't1', 'T1', 't2', 'T2', 's0', 'S0', + 's1', 'S1', 'a0', 'A0', 'a1', 'A1', 'a2', 'A2', + 'a3', 'A3', 'a4', 'A4', 'a5', 'A5', 'a6', 'A6', + 'a7', 'A7', 's2', 'S2', 's3', 'S3', 's4', 'S4', + 's5', 'S5', 's6', 'S6', 's7', 'S7', 's8', 'S8', + 's9', 'S9', 's10', 'S10', 's11', 'S11', 't3', 'T3', + 't4', 'T4', 't5', 'T5', 't6', 'T6' ] + +def register_index_mapping(register): + if register == 'x0' or register == 'X0' or register == 'zero' or register == 'ZERO': + return '00000' + elif register == 'x1' or register == 'X1' or register == 'ra' or register == 'RA': + return '00001' + elif register == 'x2' or register == 'X2' or register == 'sp' or register == 'SP': + return '00010' + elif register == 'x3' or register == 'X3' or register == 'gp' or register == 'GP': + return '00011' + elif register == 'x4' or register == 'X4' or register == 'tp' or register == 'TP': + return '00100' + elif register == 'x5' or register == 'X5' or register == 't0' or register == 'T0': + return '00101' + elif register == 'x6' or register == 'X6' or register == 't1' or register == 'T1': + return '00110' + elif register == 'x7' or register == 'X7' or register == 't2' or register == 'T2': + return '00111' + elif register == 'x8' or register == 'X8' or register == 'fp' or register == 'FP' or register == 's0' or register == 'S0': + return '01000' + elif register == 'x9' or register == 'X9' or register == 's1' or register == 'S1': + return '01001' + elif register == 'x10' or register == 'X10' or register == 'a0' or register == 'A0': + return '01010' + elif register == 'x11' or register == 'X11' or register == 'a1' or register == 'A1': + return '01011' + elif register == 'x12' or register == 'X12' or register == 'a2' or register == 'A2': + return '01100' + elif register == 'x13' or register == 'X13' or register == 'a3' or register == 'A3': + return '01101' + elif register == 'x14' or register == 'X14' or register == 'a4' or register == 'A4': + return '01110' + elif register == 'x15' or register == 'X15' or register == 'a5' or register == 'A5': + return '01111' + elif register == 'x16' or register == 'X16' or register == 'a6' or register == 'A6': + return '10000' + elif register == 'x17' or register == 'X17' or register == 'a7' or register == 'A7': + return '10001' + elif register == 'x18' or register == 'X18' or register == 's2' or register == 'S2': + return '10010' + elif register == 'x19' or register == 'X19' or register == 's3' or register == 'S3': + return '10011' + elif register == 'x20' or register == 'X20' or register == 's4' or register == 'S4': + return '10100' + elif register == 'x21' or register == 'X21' or register == 's5' or register == 'S5': + return '10101' + elif register == 'x22' or register == 'X22' or register == 's6' or register == 'S6': + return '10110' + elif register == 'x23' or register == 'X23' or register == 's7' or register == 'S7': + return '10111' + elif register == 'x24' or register == 'X24' or register == 's8' or register == 'S8': + return '11000' + elif register == 'x25' or register == 'X25' or register == 's9' or register == 'S9': + return '11001' + elif register == 'x26' or register == 'X26' or register == 's10' or register == 'S10': + return '11010' + elif register == 'x27' or register == 'X27' or register == 's11' or register == 'S11': + return '11011' + elif register == 'x28' or register == 'X28' or register == 't3' or register == 'T3': + return '11100' + elif register == 'x29' or register == 'X29' or register == 't4' or register == 'T4': + return '11101' + elif register == 'x30' or register == 'X30' or register == 't5' or register == 'T5': + return '11110' + else: + return '11111' \ No newline at end of file diff --git a/Software/AssembleX/variables.py b/Software/AssembleX/variables.py new file mode 100644 index 0000000..486370d --- /dev/null +++ b/Software/AssembleX/variables.py @@ -0,0 +1,28 @@ +# AssembleX V3.0 +# RISC-V Assembly Software Assistant for the phoeniX project (https://github.com/phoeniX-Digital-Design/phoeniX) + +# Description: Global variables +# Copyright 2024 Iran University of Science and Technology. + +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. + +pc = [0] +line_number = 1 + +# BIN/HEX assembled instructions +bin_instruction = [] +hex_instruction = [] + +# Error detection varibales intial values +error_flag = [0] +error_counter = [0] +instruction_sts = 0 + +# Address mapping varibales intial values +label_list = [] +label_address_list = [] +instruction_counter = [0] +expected_instructions_count = [0] +lable_counter = [0] \ No newline at end of file From 3705c17e1797c2da9d1de62c7fbdd1a6013b412e Mon Sep 17 00:00:00 2001 From: ArvinDelavari Date: Sun, 4 Aug 2024 18:38:22 +0330 Subject: [PATCH 2/5] =?UTF-8?q?=E2=9C=85=20Run=20sample=20codes=20with=20A?= =?UTF-8?q?ssembleX=20V3.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fibonacci/fibonacci.s | 3 -- .../fibonacci/fibonacci_firmware.hex | 51 ++++++++++--------- .../multiplication_firmware.hex | 8 +-- .../sum1to100/sum1to100_firmware.hex | 8 +-- 4 files changed, 35 insertions(+), 35 deletions(-) diff --git a/Software/Sample_Assembly_Codes/fibonacci/fibonacci.s b/Software/Sample_Assembly_Codes/fibonacci/fibonacci.s index a8d5f52..874c137 100644 --- a/Software/Sample_Assembly_Codes/fibonacci/fibonacci.s +++ b/Software/Sample_Assembly_Codes/fibonacci/fibonacci.s @@ -1,6 +1,3 @@ -.text -.globl main - main: li sp, 0xffc addi sp, sp, -48 diff --git a/Software/Sample_Assembly_Codes/fibonacci/fibonacci_firmware.hex b/Software/Sample_Assembly_Codes/fibonacci/fibonacci_firmware.hex index 27e1dfd..c340526 100644 --- a/Software/Sample_Assembly_Codes/fibonacci/fibonacci_firmware.hex +++ b/Software/Sample_Assembly_Codes/fibonacci/fibonacci_firmware.hex @@ -1,31 +1,34 @@ 00001137 -FFC10113 -FD010113 +ffc10113 +fd010113 02812623 03010413 -FE042623 -00100793 -FEF42423 -00A00793 -FEF42023 -FE042223 -0300006F -FEC42703 -FE842783 -00F707B3 -FCF42E23 -FE842783 -FEF42623 -FDC42783 -FEF42423 -FE442783 +fe042623 +000007b7 00178793 -FEF42223 -FE442703 -FE042783 -FCF746E3 -00000793 +fef42423 +000007b7 +00a78793 +fef42023 +fe042223 +0300006f +fec42703 +fe842783 +00f707b3 +fcf42e23 +fe842783 +fef42623 +fdc42783 +fef42423 +fe442783 +00178793 +fef42223 +fe442703 +fe042783 +fcf746e3 +000007b7 +00078793 00078513 -02C12403 +02c12403 03010113 00100073 diff --git a/Software/Sample_Assembly_Codes/multiplication/multiplication_firmware.hex b/Software/Sample_Assembly_Codes/multiplication/multiplication_firmware.hex index a183a6e..a41e693 100644 --- a/Software/Sample_Assembly_Codes/multiplication/multiplication_firmware.hex +++ b/Software/Sample_Assembly_Codes/multiplication/multiplication_firmware.hex @@ -1,6 +1,6 @@ -7F900093 +7f900093 01900613 -00C00693 -02D60733 -7F900113 +00c00693 +02d60733 +7f900113 00100073 diff --git a/Software/Sample_Assembly_Codes/sum1to100/sum1to100_firmware.hex b/Software/Sample_Assembly_Codes/sum1to100/sum1to100_firmware.hex index 34747bb..69d6fa0 100644 --- a/Software/Sample_Assembly_Codes/sum1to100/sum1to100_firmware.hex +++ b/Software/Sample_Assembly_Codes/sum1to100/sum1to100_firmware.hex @@ -1,8 +1,8 @@ 06500613 -000006B3 +000006b3 00000733 -00E68733 +00e68733 00168693 -FEC6CCE3 -06E02223 +fec6cce3 +06e02223 00100073 From 9cd89c0e9a4cbb07136136fb15feecc2dffec602 Mon Sep 17 00:00:00 2001 From: ArvinDelavari Date: Sun, 4 Aug 2024 18:38:58 +0330 Subject: [PATCH 3/5] =?UTF-8?q?=F0=9F=94=A7=20Add=20AssembleX=20V3.0=20mai?= =?UTF-8?q?n=20file?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AssembleX.py | 178 ++++++++++++++++++++++++++++++++++++++++++++++ AssembleX_V1.0.py | 69 ------------------ 2 files changed, 178 insertions(+), 69 deletions(-) create mode 100644 AssembleX.py delete mode 100644 AssembleX_V1.0.py diff --git a/AssembleX.py b/AssembleX.py new file mode 100644 index 0000000..e22cdf4 --- /dev/null +++ b/AssembleX.py @@ -0,0 +1,178 @@ +# AssembleX V3.0 +# RISC-V Assembly Software Assistant for the phoeniX project (https://github.com/phoeniX-Digital-Design/phoeniX) + +# Description: AssembleX main code +# Copyright 2024 Iran University of Science and Technology. + +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. + +import sys +import os +import glob + +from Software.AssembleX.variables import * +from Software.AssembleX.assembler import assembler +from Software.AssembleX.address_mapping import address_mapping +from Software.AssembleX.address_mapping import label_mapping +from Software.AssembleX.address_mapping import define_reset_address +from Software.AssembleX.data_conversion import binary_to_hex +from Software.AssembleX.data_conversion import ascii_to_hex + +testbench_file = "phoeniX_Testbench.v" +option = sys.argv[1] +project_name = sys.argv[2] +output_name = project_name + "_firmware" + ".hex" + +if option == 'sample': + directory = "Sample_Assembly_Codes" +elif option == 'code': + directory = "User_Codes" +else: + raise ValueError("Options are: sample, code") + +print("\nAssembleX V3.0 - RV32IM Assembly Code Executant Software") +print("Iran University of Science and Technology - Summer 2024") +print("--------------------------------------------------------") + +try: + source_path = list(glob.iglob(os.path.join("Software", directory, project_name, '*' + ".s")))[0] + firmware_hex_path = os.path.join("Software", directory, project_name, output_name) + print(source_path) + print(firmware_hex_path) + #source_path = sys.argv[1] + #firmware_hex_path = sys.argv[1].rstrip('.s') + '_firmware.hex' +except: + print('INFO: No arguments/unsupported arguments\n') + +try: + source_file = open(source_path, "r") + source_code_unformatted = source_file.read().splitlines() + print("INFO: Source file opened successfully\n") +except: + print("FATAL ERROR: Unable to open source file\n") + exit(1) + +print('Assembly code pre-processing') +print('----------------------------') +source_code = [] +for line in source_code_unformatted: + instruction_format_space = " ".join(line.split()) + instruction_format_comments = " #".join(instruction_format_space.split('#', 2)) + instruction_format_leadspace = instruction_format_comments.lstrip() + source_code.append(instruction_format_leadspace) + +# Re-format immediate expressions +processed_code_1 = [] +for line in source_code: + arguments = line.split(',') + try: + if arguments[0][0] == '#': + processed_code_1.append(line) + continue + elif arguments[0] == '.RESET_ADDRESS': + processed_code_1.append(line) + continue + except: + processed_code_1.append(line) + continue + # Check for 2 argument immediate expressions: 'x(y)' -> parse: 'y x' + # Check for ASCII: char -> hex + parse_ascii = [False] + try: + arguement_2_wc = arguments[1] + arguement_2_wc = arguement_2_wc.split('#', 2) + len_arguement_2_wc = len(arguement_2_wc) + arguement_2 = [arguement_2_wc[0]] + ascii_to_hex(arguement_2) + arguement_2_pp = arguement_2[0].replace(')', '(') + arguement_2_pp = "".join(arguement_2_pp.split()) + arguement_2_list = arguement_2_pp.split('(') + if len_arguement_2_wc == 2: + arguments[1] = ' ' + arguement_2_list[1] + ', ' + arguement_2_list[0] + ' ' + '#' + arguement_2_wc[1] # Modified expression + else: # No inline comment + arguments[1] = ' ' + arguement_2_list[1] + ', ' + arguement_2_list[0] # Modified expression + processed_code_1.append(",".join(arguments)) + except: + if parse_ascii[0]: + if len_arguement_2_wc == 2: + arguments[1] = arguement_2[0] + ' ' + '#' + arguement_2_wc[1] # Modified expression + else: + arguments[1] = arguement_2[0] # Modified expression + processed_code_1.append(",".join(arguments)) + else: + processed_code_1.append(line) + continue + +# Remove "," change "," -> " " +processed_code_2 = [] +for line in processed_code_1: + line = line.replace(',', ' ') + processed_code_2.append(" ".join(line.split())) + +lines_of_code = len(processed_code_2) +print('Lines of code =', lines_of_code, '\n') + +start_address = define_reset_address(processed_code_2[0]) + +for line in source_code: + label_state = label_mapping(start_address, line, instruction_counter, + expected_instructions_count, lable_counter, + label_list, label_address_list) +address_mapping(lable_counter, label_list, label_address_list) + +# Parser +print('') +print('Parser') +print('------') +pc[0] = start_address +for line in processed_code_2: + instruction_sts = assembler(pc, line, line_number, error_flag, error_counter, bin_instruction) + line_number = line_number + 1 + +# Summary +print('\nSummary') +print('-------') +if error_flag[0] == 0: + print('- Lines of code (source) = ', lines_of_code) + print('- Assembled instructions = ', instruction_counter[0]) + print('- Instructions with ERRORS = ', error_counter[0]) + binary_to_hex(bin_instruction, hex_instruction) + try: + # HEX firmware file write + file = open(firmware_hex_path, "w") + for line in hex_instruction: + file.write(line + '\n') + print('\nDONE: Successfully created FIRMWARE file\n') + file.close() + except: + print('\nFATAL ERROR: Unable to create FIRMWARE file\n') +else: + print('- Lines of code (source) = ', lines_of_code) + print('- Assembled instructions = ', instruction_counter[0]) + print('- Instructions with ERRORS = ', error_counter[0]) + print('\nFAIL:Failed to parse the assembly code due to errors') + +# Change firmware in the testbench file +with open(testbench_file, 'r') as file: + lines = file.readlines() +# Edit source files of testbench names +with open(testbench_file, 'w') as file: + for line in lines: + # Change instruction memory source file + if line.startswith(" `define FIRMWARE "): + print("Line found!") + # Modify the input file name + firmware_hex_path = firmware_hex_path.replace("\\", "\\\\") + print(firmware_hex_path) + modified_line = line.replace(line,' `define FIRMWARE '+ '"' + firmware_hex_path + '"' +'\n' ) + print(modified_line) + file.write(modified_line) + else: + file.write(line) + +# OS: cmd commands to execute Verilog simulations: +os.system("iverilog -IModules -o phoeniX.vvp phoeniX_Testbench.v") +os.system("vvp phoeniX.vvp") +os.system("gtkwave phoeniX.gtkw") \ No newline at end of file diff --git a/AssembleX_V1.0.py b/AssembleX_V1.0.py deleted file mode 100644 index d1ab86d..0000000 --- a/AssembleX_V1.0.py +++ /dev/null @@ -1,69 +0,0 @@ -# ---------------------------------------------------------------- -# | AssembleX V1.0 | -# | ------------------------------------------------------------ | -# | Custom-built RISC-V assembly code executant for phoeniX core | -# | By : Arvin Delavari - Faraz Ghoreishy | -# | Iran University of Science and Technology - Summer 2023 | -# ---------------------------------------------------------------- - -import os -import sys -import glob - -testbench_file = "phoeniX_Testbench.v" -option = sys.argv[1] -project_name = sys.argv[2] -output_name = project_name + "_firmware" + ".hex" - -if option == 'sample': - directory = "Sample_Assembly_Codes" -elif option == 'code': - directory = "User_Codes" -else: - raise ValueError("Options are: sample, code") - -input_file = list(glob.iglob(os.path.join("Software", directory, project_name, '*' + ".txt")))[0] -output_file = os.path.join("Software", directory, project_name, output_name) -print(input_file) -print(output_file) - -# Read the contents of the input file (assembly text file) -with open(input_file, "r") as file: - lines = file.readlines() - -# Remove the first and third columns from each line (PC and Code) -modified_lines = [line.split()[1] +'\n' for line in lines] - -# Remove the "0x" prefix from each line -modified_lines = [line[2:] for line in modified_lines] - -# Remove '\n\n' elements from the array -final_hex_code = [elem for elem in modified_lines if elem != '\n\n'] -# print(final_hex_code) - -# Write the modified contents to the output file -with open(output_file, "w") as file: - file.writelines(final_hex_code) - -# Change firmware in the testbench file -with open(testbench_file, 'r') as file: - lines = file.readlines() -# Edit source files of testbench names -with open(testbench_file, 'w') as file: - for line in lines: - # Change instruction memory source file - if line.startswith(" `define FIRMWARE "): - print("Line found!") - # Modify the input file name - output_file = output_file.replace("\\", "\\\\") - print(output_file) - modified_line = line.replace(line,' `define FIRMWARE '+ '"' + output_file + '"' +'\n' ) - print(modified_line) - file.write(modified_line) - else: - file.write(line) - -# OS: cmd commands to execute Verilog simulations: -os.system("iverilog -IModules -o phoeniX.vvp phoeniX_Testbench.v") -os.system("vvp phoeniX.vvp") -os.system("gtkwave phoeniX.gtkw") \ No newline at end of file From c3f4dcd349ce590ebb97c271dba0dc3796b3c08e Mon Sep 17 00:00:00 2001 From: ArvinDelavari Date: Sun, 4 Aug 2024 18:39:20 +0330 Subject: [PATCH 4/5] =?UTF-8?q?=F0=9F=93=9D=20Update=20software=20README.m?= =?UTF-8?q?d?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Software/README.md | 64 ++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/Software/README.md b/Software/README.md index 01e79db..1704414 100644 --- a/Software/README.md +++ b/Software/README.md @@ -2,7 +2,8 @@ Software ====================
-This directory contains source files of sample codes and user codes which will be executed on the phoeniX processor. In this directory, there are three subdirectories included: +This directory contains source files the assembler, sample codes and user codes which will be executed on the phoeniX processor. In this directory, there are three subdirectories included: +- `AssembleX` - `Sample_Assembly_Codes` - `Sample_C_Codes` - `User_Codes` @@ -10,70 +11,73 @@ This directory contains source files of sample codes and user codes which will b The code execution and simulation on the phoeniX RISC-V processor follow two distinct branches: one for Linux systems and another for Windows systems.
-### Linux +### AssembleX V3.0 -#### Running Sample Codes
-The directory `/Software` contains sample codes for some conventional programs and algorithms in both Assembly and C which can be found in `/Sample_Assembly_Codes` and `/Sample_C_Codes` sub-directories respectively. +The `AssembleX` software is an assembly code executant designed for the [phoeniX project](https://github.com/phoeniX-Digital-Design/phoeniX). AssembleX is powered by [riscv-assembler](https://github.com/celebi-pkg/riscv-assembler) and [PQR5ASM](https://github.com/iammituraj/pqr5asm) open-source projects. Current version of AssembleX (V3.0) supports `RV32IM` extenstions of standard RISC-V ISA. -phoeniX convention for naming projects is as follows; The main source file of the project is named as `{project.c}` or `{project.s}`. This file along other required source files are kept in one directory which has the same name as the project itself, i.e. `/project`. +
-Sample projects provided at this time are `bubble_sort`, `fibonacci`, `find_max_array`, `sum1ton`. -To run any of these sample projects simply run `make sample` followed by the name of the project passed as a variable named project to the Makefile. +#### Running Sample Codes +
+ +To run any of these sample projects simply run python `AssembleX.py sample` followed by the name of the project passed as a variable named project to the Python script. +The input command format for the terminal follows the structure illustrated below: ```shell -make sample project={project} +python AssembleX.py sample {project_name} ``` For example: ```shell -make sample project=fibonacci +python AssembleX.py sample fibonacci ``` - -Provided that the RISC-V toolchain is set up correctly, the Makefile will compile the source codes separately, then using the linker script `riscv.ld` provided in `/Firmware` it links all the object files necessary together and creates `firmware.elf`. It then creates `start.elf` which is built from `start.s` and `start.ld` and concatenate these together and finally forms the `{project}_firmware.hex`. This final file can be directly fed to our verilog testbench. Makefile automatically runs the testbench and calls upon `gtkwave` to display the selected signals in the waveform viewer. - +After execution of this script, firmware file will be generated and this final file can be directly fed to our Verilog testbench. AssembleX automatically runs the testbench and calls upon gtkwave to display the selected signals in the waveform viewer application, gtkwave.
#### Running Your Own Code
-In order to run your own code on phoeniX, create a directory named to your project such as `/my_project` in `/Software/User_Codes/`. Put all your `.c` and `.s` files in `/my_project` and run the following `make` command from the main directory: +In order to run your own code on phoeniX, create a directory named to your project such as `/my_project` in `/Software/User_Codes`. Put all your `user_code.s` files in my_project and run the following command from the main directory: + ```shell -make code project=my_project +python AssembleX.py code my_project ``` -Provided that you name your project sub-directory correctly and the RISC-V Toolchain is configured without any troubles on your machine, the Makefile will compile all your source files separately, then using the linker script `riscv.ld` provided in `/Firmware` it links all the object files necessary together and creates `firmware.elf`. It then creates `start.elf` which is built from `start.s` and `start.ld` and concatenate these together and finally forms the `my_project_firmware.hex`. After that, `iverilog` and `gtkwave` are used to compile the design and view the selected waveforms. -> Further Configurations -: The default testbench provided as `phoeniX_Testbench.v` is currently set to support up to 4MBytes of memory and the stack pointer register `sp` is configured accordingly. If you wish to change this, you need configure both the testbench and the initial value the `sp` is set to in `/Firmware/start.s`. If you wish to use other specific libraries and header files not provided in `/Firmware` please beware you may need to change linker scripts `riscv.ld` and `start.ld`. + +Provided that you name your project sub-directory correctly the AssembleX software will create `my_project_firmware.hex` and fed it directly to the testbench of phoeniX processor. After that, iverilog and GTKWave are used to compile the design and view the selected waveforms. +
-### Windows +### RISC-V GCC-GNU #### Running Sample Codes
-We have meticulously developed a lightweight and user-friendly software solution with the help of Python. Our execution assistant software, `AssembleX`, has been crafted to cater to the specific needs of Windows systems, enabling seamless execution of assembly code on the phoeniX processor. +The directory `/Software` contains sample codes for some conventional programs and algorithms in both Assembly and C which can be found in `/Sample_Assembly_Codes` and `/Sample_C_Codes` sub-directories respectively. -This tool enhances the efficiency of the code execution process, offering a streamlined experience for users seeking to enter the realm of assembly programming on pheoniX processor in a very simple and user-friendly way. +phoeniX convention for naming projects is as follows; The main source file of the project is named as `{project.c}` or `{project.s}`. This file along other required source files are kept in one directory which has the same name as the project itself, i.e. `/project`. -Before running the script, note that the assembly output of the Venus Simulator for the code must be also saved in the project directory. -To run any of these sample projects simply run python `AssembleX_V1.0.py sample` followed by the name of the project passed as a variable named project to the Python script. -The input command format for the terminal follows the structure illustrated below: +Sample projects provided at this time are `bubble_sort`, `fibonacci`, `find_max_array`, `sum1ton`. +To run any of these sample projects simply run `make sample` followed by the name of the project passed as a variable named project to the Makefile. ```shell -python AssembleX_V1.0.py sample {project_name} +make sample project={project} ``` For example: ```shell -python AssembleX_V1.0.py sample fibonacci +make sample project=fibonacci ``` -After execution of this script, firmware file will be generated and this final file can be directly fed to our Verilog testbench. AssembleX automatically runs the testbench and calls upon gtkwave to display the selected signals in the waveform viewer application, gtkwave. + +Provided that the RISC-V toolchain is set up correctly, the Makefile will compile the source codes separately, then using the linker script `riscv.ld` provided in `/Firmware` it links all the object files necessary together and creates `firmware.elf`. It then creates `start.elf` which is built from `start.s` and `start.ld` and concatenate these together and finally forms the `{project}_firmware.hex`. This final file can be directly fed to our verilog testbench. Makefile automatically runs the testbench and calls upon `gtkwave` to display the selected signals in the waveform viewer. +
#### Running Your Own Code
-In order to run your own code on phoeniX, create a directory named to your project such as `/my_project in /Software/User_Codes/`. Put all your ``user_code.s` files in my_project and run the following command from the main directory: +In order to run your own code on phoeniX, create a directory named to your project such as `/my_project` in `/Software/User_Codes/`. Put all your `.c` and `.s` files in `/my_project` and run the following `make` command from the main directory: ```shell -python AssembleX_V1.0.py code my_project +make code project=my_project ``` -Provided that you name your project sub-directory correctly the AssembleX software will create `my_project_firmware.hex` and fed it directly to the testbench of phoeniX processor. After that, iverilog and GTKWave are used to compile the design and view the selected waveforms. +Provided that you name your project sub-directory correctly and the RISC-V Toolchain is configured without any troubles on your machine, the Makefile will compile all your source files separately, then using the linker script `riscv.ld` provided in `/Firmware` it links all the object files necessary together and creates `firmware.elf`. It then creates `start.elf` which is built from `start.s` and `start.ld` and concatenate these together and finally forms the `my_project_firmware.hex`. After that, `iverilog` and `gtkwave` are used to compile the design and view the selected waveforms. +> Further Configurations +: The default testbench provided as `phoeniX_Testbench.v` is currently set to support up to 4MBytes of memory and the stack pointer register `sp` is configured accordingly. If you wish to change this, you need configure both the testbench and the initial value the `sp` is set to in `/Firmware/start.s`. If you wish to use other specific libraries and header files not provided in `/Firmware` please beware you may need to change linker scripts `riscv.ld` and `start.ld`.
- From 7bfca544556b0fbcf8ce0fce8db24deae7e9f83c Mon Sep 17 00:00:00 2001 From: ArvinDelavari Date: Sun, 4 Aug 2024 18:39:59 +0330 Subject: [PATCH 5/5] =?UTF-8?q?=F0=9F=93=9D=20Update=20README.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 02fe244..4aac5d4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![License](https://img.shields.io/github/license/phoeniX-Digital-Design/AssembleX?color=dark-green) ![GCC Test](https://img.shields.io/badge/GCC_tests-passed-dark_green) -![Version](https://img.shields.io/badge/Version-0.4-blue) +![Version](https://img.shields.io/badge/Version-0.4.1-blue) ![ISA](https://img.shields.io/badge/RV32-IEM_extension-blue) @@ -34,6 +34,7 @@ Publications: - A. Delavari, F. Ghoreishy, H. S. Shahhoseini and S. Mirzakuchaki (2023), “phoeniX: A RISC-V Platform for Approximate Computing Technical Specifications,” [Online]. Available: http://www.iust.ac.ir/content/76158/phoeniX-POINTS--A-RISC-V-Platform-for-Approximate-Computing +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. - Designed By: [Arvin Delavari](https://github.com/ArvinDelavari) and [Faraz Ghoreishy](https://github.com/FarazGhoreishy) - Contact us: arvin_delavari@elec.iust.ac.ir - faraz_ghoreishy@elec.iust.ac.ir @@ -271,15 +272,14 @@ We have meticulously developed a lightweight and user-friendly software solution This tool enhances the efficiency of the code execution process, offering a streamlined experience for users seeking to enter the realm of assembly programming on pheoniX processor in a very simple and user-friendly way. -Before running the script, note that the assembly output of the Venus Simulator for the code must be also saved in the project directory. -To run any of these sample projects simply run python `AssembleX_V1.0.py sample` followed by the name of the project passed as a variable named project to the Python script. +To run any of these sample projects simply run python `AssembleX.py sample` followed by the name of the project passed as a variable named project to the Python script. The input command format for the terminal follows the structure illustrated below: ```shell -python AssembleX_V1.0.py sample {project_name} +python AssembleX.py sample {project_name} ``` For example: ```shell -python AssembleX_V1.0.py sample fibonacci +python AssembleX.py sample fibonacci ``` After execution of this script, firmware file will be generated and this final file can be directly fed to our Verilog testbench. AssembleX automatically runs the testbench and calls upon gtkwave to display the selected signals in the waveform viewer application, gtkwave. @@ -290,7 +290,7 @@ After execution of this script, firmware file will be generated and this final f In order to run your own code on phoeniX, create a directory named to your project such as `/my_project` in `/Software/User_Codes`. Put all your `user_code.s` files in my_project and run the following command from the main directory: ```shell -python AssembleX_V1.0.py code my_project +python AssembleX.py code my_project ``` Provided that you name your project sub-directory correctly the AssembleX software will create `my_project_firmware.hex` and fed it directly to the testbench of phoeniX processor. After that, iverilog and GTKWave are used to compile the design and view the selected waveforms.