Skip to content

Commit

Permalink
Merge pull request #5 from phoeniX-Digital-Design/phoeniX-V0.4.1
Browse files Browse the repository at this point in the history
phoeniX V0.4.1
  • Loading branch information
ArvinDelavari authored Aug 4, 2024
2 parents 86817ff + 7bfca54 commit cd0f79b
Show file tree
Hide file tree
Showing 13 changed files with 1,516 additions and 140 deletions.
178 changes: 178 additions & 0 deletions AssembleX.py
Original file line number Diff line number Diff line change
@@ -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. <[email protected]>

# 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")
69 changes: 0 additions & 69 deletions AssembleX_V1.0.py

This file was deleted.

12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -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)

<picture>
Expand Down Expand Up @@ -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: [email protected] - [email protected]
Expand Down Expand Up @@ -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.
</div>
Expand All @@ -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.
Expand Down
66 changes: 66 additions & 0 deletions Software/AssembleX/address_mapping.py
Original file line number Diff line number Diff line change
@@ -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. <[email protected]>

# 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]))
Loading

0 comments on commit cd0f79b

Please sign in to comment.