一个向ROM导入机器码的Python脚本

离.nvme0n1p2

TL;DR(或许也没有那么长)

食用方法

  • 下载Python脚本replace.py (或者也许你愿意从文末复制?)

https://bhpan.buaa.edu.cn/link/AA142FF068D230494AB6CF02281EEFE6FF(无需存档) Name: replace.py Expires: 2023-11-26 21:59 Pickup Code: 0xdeadbeef

  • 执行以下命令:
1
python replace.py <.circ文件名> <机器码文本文件名>

大功告成!修改后的.circ文件将保存在当前目录中,文件名为原文件名后加上当前的时间,格式为原文件名_机器码文本文件名_hhmmss.circ

使用例: image.png

值得注意的事

支持什么机器码文本文件?

  1. MarsHexadecimal Text格式导出的文件
  2. Logisim通过ROM->Contents->Save方式导出的文件

提示 No match?

鉴于P3课下的需求,本脚本设置为匹配Address Bit Width = 12Data Bit Width=32的ROM,如果有其他需求,可以自行修改pattern变量的相关内容

背景

向Logisim中导入取自Mars的机器码时,需要手动修改文本文件,且涉及多次鼠标点击。鉴于笔者较懒,遂尝试编写脚本一劳永逸地解决问题。

前期准备

瞪眼法发现,Logisim 以.circ文件格式保存电路,这些文件本质上是 XML 文档,允许以文本形式进行读取和编辑,样式如下图:

image.png

以文本格式打开某含有ROM组件的.circ文件,搜索ROM关键词得:

image.png

我们先看第一个:

image.png

这个显然不是,略过(逃

在此部分实际上存储的是从左侧工具栏选择组件时的默认设置。你可能注意到,当从侧边栏选择一个组件并在将其放置到画布上之前修改了左下角的组件属性,那么下一次选择该组件时,其默认属性就会变为之前修改过的设置,这些设置重启Logisim后仍会保留。这些个默认设置就存储在这里。

再看第二个:

image.png

直觉告诉我们它就是我们想要的,我们观察它的几个标签:

  • loc=(310,170)决定了组件在画布上的位置,鉴于每个人的画布布局(通常来说)都不同,这部分的影响需要排除
  • addrWidth=12dataWidth=32规定了组件的地址位宽的数据位宽,在P3中,ROM的要求是地址位宽12位,数据位宽32位
  • contents显然我们想要替换的机器码就保存在这里

脚本编写

正则表达式设计

1
(<comp lib="4" loc="\([^"]+\)" name="ROM">\s*<a name="addrWidth" val="12"/>\s*<a name="dataWidth" val="32"/>\s*<a name="contents">addr/data: 12 32\s*)(.*?)(</a>\s*</comp>)

比OOPre的三个式子简单多了()

Python程序设计

略,总之就是读取-查找-替换-输出四步走

改进空间

本脚本有很多改进的方向,笔者本人就想到了两个

  • 当前脚本使用的re.search()方法只返回第一个匹配结果,对于P3的要求足够,但是可以改进
  • 可以接受可选的多个输入,决定匹配ROM的addrWidthdataWidth

源代码

(或者也许你愿意从文末复制?)

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
import sys
import re
import datetime

def read_file(file_name):
try:
with open(file_name, 'r') as f:
return f.readlines()
except FileNotFoundError:
print("File not found: " + file_name)
exit(1)

def write_file(file_name, lines):
try:
with open(file_name, 'w') as f:
f.writelines(lines)
except FileNotFoundError:
print("File not found: " + file_name)
exit(1)

def main(circ_flie_path, hex_text_path):
circ_data = read_file(circ_flie_path)
hex_data = read_file(hex_text_path)

new_hex_code = []
start = False
for line in hex_data:
if line.strip() != 'v2.0 raw':
start = True
if start:
new_hex_code.append(line)

circ_content = "".join(circ_data)
pattern = (
r'(<comp lib="4" loc="\([^"]+\)" name="ROM">\s*'
r'<a name="addrWidth" val="12"/>\s*'
r'<a name="dataWidth" val="32"/>\s*'
r'<a name="contents">addr/data: 12 32\s*)(.*?)(</a>\s*</comp>)'
)
match = re.search(pattern, circ_content, re.DOTALL)
if match is None:
print("No match")
exit(1)

result = []

result.append(circ_content[:match.start()])
result.append(match.group(1))
result.append("".join(new_hex_code))
result.append(match.group(3))
result.append(circ_content[match.end():])

result = "".join(result)

circ_name = circ_flie_path.split('\\')[-1].split('.')[0]
hex_name = hex_text_path.split('\\')[-1].split('.')[0]
new_file_name = circ_name + "_" + hex_name + "_" + datetime.datetime.now().strftime("%H%M%S") + ".circ"

write_file(new_file_name, result)
print('Replace success, new file: ' + new_file_name)


if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: python replace.py <circ_file_path> <hex_text_path>")
exit(1)
main(sys.argv[1], sys.argv[2])

潜伏 回复 离.nvme0n1p2

可以使用re.sub()一键实现正则匹配替换

0%