-
Notifications
You must be signed in to change notification settings - Fork 0
/
asm2logisim.py
127 lines (110 loc) · 4.45 KB
/
asm2logisim.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import os, sys, argparse
"""
Generate the base for the Logisim-evolution's 'hex words addressed' format.
The base is split into a list of strings for easier modification.
"""
def generate_hex_words_base():
ret = []
ret.append("v3.0 hex words addressed\n")
for i in range(2048):
ret.append(
f"{i * 8:04x}: "
"00000000 00000000 00000000 00000000 "
"00000000 00000000 00000000 00000000\n"
);
return ret
"""
Write a byte of data at a specified address into the string representation of the dataset.
"""
def write_byte(byte_in, address, base):
line = (address // 32) + 1
column = address % 32
column = 6 + (column // 4) * 9 + 2 * (3 - (column % 4))
base[line] = base[line][:column] + byte_in + base[line][column + 2:]
"""
Transform data from the Intel HEX format into the Logisim-evolution's 'hex words addressed' format.
"""
def hex_to_logisim(hex_in, base):
segment_offset = 0
linear_offset = 0
for line in hex_in:
line = line.split(":")[1]
count = int(line[0:2], 16)
address = int(line[2:6], 16)
rectype = line[6:8]
data = line[8:-2]
match rectype:
case "00": # Data
address += segment_offset + linear_offset
for i in range(count):
chunk = data[(2 * i):(2 * i + 2)]
write_byte(chunk, address + i, base)
case "01": # End Of File
break
case "02": # Extended Segment Address
segment_offset = int(data, 16) * 16
case "04": # Extended Linear Address
segment_offset = int(data + "0000", 16)
case _:
print(f"Unsupported record type: {rectype}.")
exit(1)
"""
Assemble, link and convert a RISC-V assembly source file or an existing ELF file into the
Logisim-evolution's 'hex words addressed' format.
This script has only been tested on Arch Linux, using `riscv64-elf-gcc` and `riscv64-elf-binutils`
packages.
The script creates some intermediate files that remain on disk, unless you uncomment the final line.
"""
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Convert a file to the Logisim-evolution's 'hex words addressed' format."
)
parser.add_argument("input_file")
parser.add_argument("-l", "--linker-script")
parser.add_argument("--remove-system-instructions", action="store_true")
args = parser.parse_args()
file_name, file_ext = os.path.splitext(args.input_file)
# Assemble the source.
if file_ext == ".s":
err = os.system(f"riscv64-elf-as -march=rv32i -mlittle-endian -o {file_name}.o {file_name}.s")
if err != 0:
print("'as' failed.", file=sys.stderr)
exit(err)
# Link the assembled output.
if args.linker_script:
err = os.system(f"riscv64-elf-ld -melf32lriscv -T {linker_script} -o {file_name}.l.o {file_name}.o")
if err != 0:
print("'ld' failed.", file=sys.stderr)
exit(err)
# Determine which file to convert.
if args.linker_script:
file_to_convert = f"{file_name}.l.o"
elif file_ext == ".s":
file_to_convert = f"{file_name}.o"
else:
file_to_convert = file_name + file_ext
# Convert the ELF file into an Intel HEX file.
err = os.system(f"riscv64-elf-objcopy -O ihex {file_to_convert} {file_name}.hex")
if err != 0:
print("'objcopy' failed.", file=sys.stderr)
exit(err)
# Convert the Intel HEX file into the Logisim-evolution's 'v3.0 hex words addressed' format.
base = generate_hex_words_base()
with open(f"{file_name}.hex", "r") as f_in:
hex_in = f_in.readlines()
hex_to_logisim(hex_in, base)
# Remove the SYSTEM instructions
if args.remove_system_instructions:
for i in range(1, len(base)):
line = base[i].split(": ")
data = line[1].split(" ")
for j in range(len(data)):
if data[j][-2:] in ["73", "F3"]:
data[j] = "00000013" # nop = addi zero, zero, 0
base[i] = ": ".join([line[0], " ".join(data)])
# Save the data.
with open(f"{file_name}.lgs", "w") as f_out:
for l in base:
f_out.write(l)
# Optional: cleanup.
# os.system(f"rm -f {fname}.o {fname}.l.o {fname}.hex")