基于Python实现ARM随机指令生成器

本文

主要介绍一个基于Python实现的ARM随机指令生成器。

版本 说明
0.1 初版发布

背景

在CPU验证中,出于各种原因,经常需要通过汇编程序来实现定向测试,不管是TOP验证环境还是UT验证环境,都有这样的需求。

通过elf作为CPU验证的激励是一个很好的选择,通过已有的高质量测试集合可以有效的保证验证质量,比如ARM Raven测试集。但是对于UT验证或TOP验证的某些场景下需要手写汇编程序作为激励输入,手写汇编的方式提高了灵活性,可以定向测试某些场景,但是毕竟产能有限,且不好保证测试质量。

基于上述背景,所以基于Python实现了ARM随机指令生成器。

功能

支持指令集合中随机选取指令组成测试程序,并且单条指令支持以下字段的随机:

# <id>          : 整型寄存器编号d
# <in>          : 整型寄存器编号n
# <im>          : 整型寄存器编号m
# <ia>          : 整型寄存器编号a
# <fd>          : 浮点寄存器编号d
# <fn>          : 浮点寄存器编号n
# <fm>          : 浮点寄存器编号m
# <fa>          : 浮点寄存器编号a
# <T1>          : 向量处理类型1
# <T2>          : 向量处理类型2
# <V>           : 浮点寄存器类型(H/S/D)
# <R>           : 整型寄存器类型(X/W)
# <index>       : element索引值

目前仅支持这些随机字段,本文目的不是提供一个完整功能的随机指令生成器,而是展示一个框架,方便使用者自定义一些功能。

文件结构

  ├── A64_TPL.list
  ├── A32_TPL.list
  ├── T32_TPL.list
  ├── gen_testcode.py
  ├── src
  │   ├── Function.py
  │   ├── SuperTPL.py
  │   └── TPL
  │       ├── TPL_demo1.py
  │       ├── TPL_demo2.py
  └── tools

Function.py文件

Function.py文件是一个函数集合:(TPL指template)

  • add_TPL(TPL):将某指令TPL添加到TPL_list,作为一个指令集合,便于从中随机选取指令,组合成测试程序。
  • get_random_TPL():从TPL_list随机选取一条指令TPL。
  • gen_testinstr_codeblock(test_depend):从指令集合中随机抽取100次,组成100条指令的测试程序,这里test_depend为1,会缩小寄存器编号的随机范围,提高指令间依赖的概率。
  • gen_cfgfreg_codeblock_a64(random_data_list):从random_data_list中随机选取数据来更新浮点寄存器,通过此方法更新操作数可提高测试质量。
  • gen_cfgfreg_codeblock_a32(random_data_list)、gen_cfgfreg_codeblock_t32(random_data_list)同上。
  • gen_cfggreg_codeblock_a64(random_data_list):从random_data_list中随机选取数据来更新整型寄存器,通过此方法更新操作数可提高测试质量。
  • gen_cfggreg_codeblock_a32(random_data_list):、gen_cfggreg_codeblock_t32(random_data_list)同上。
  • gen_cfgfpcr_codeblock_a64():产生合法的随机数据,配置浮点控制寄存器,目的是覆盖更多的随机场景。
  • gen_cfgfpcr_codeblock_a32()、gen_cfgfpcr_codeblock_t32()同上。
  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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
import random
import re

TPL_list =[]

cfgfreg_codeblock_a64 = ["    mov    x0,    #0x<data0>", \
                         "    mov    x1,    #0x<data1>", \
                         "    mov    x2,    #0x<data2>", \
                         "    mov    x3,    #0x<data3>", \
                         "    mov    x4,    #0x<data4>", \
                         "    mov    x5,    #0x<data5>", \
                         "    mov    x6,    #0x<data6>", \
                         "    mov    x7,    #0x<data7>", \
                         "    bfi    x11,   x0,    #0,    #16", \
                         "    bfi    x11,   x1,    #16,   #16", \
                         "    bfi    x11,   x2,    #32,   #16", \
                         "    bfi    x11,   x3,    #48,   #16", \
                         "    bfi    x12,   x4,    #0,    #16", \
                         "    bfi    x12,   x5,    #16,   #16", \
                         "    bfi    x12,   x6,    #32,   #16", \
                         "    bfi    x12,   x7,    #48,   #16", \
                         "    fmov   d<num>,    x11", \
                         "    fmov   v<num>.D[1], x12"]

cfgfreg_codeblock_a32 = ["    mov    r0,    #0x<data0>", \
                         "    mov    r1,    #0x<data1>", \
                         "    mov    r2,    #0x<data2>", \
                         "    mov    r3,    #0x<data3>", \
                         "    bfi    r8,    r0,    #0,    #16", \
                         "    bfi    r8,    r1,    #16,   #16", \
                         "    bfi    r9,    r2,    #32,   #16", \
                         "    bfi    r9,    r3,    #48,   #16", \
                         "    vmov   d<num>,    r8,   r9"]

cfgfreg_codeblock_t32 = ["    mov    r0,    #0x<data0>", \
                         "    mov    r1,    #0x<data1>", \
                         "    mov    r2,    #0x<data2>", \
                         "    mov    r3,    #0x<data3>", \
                         "    bfi    r8,    r0,    #0,    #16", \
                         "    bfi    r8,    r1,    #16,   #16", \
                         "    bfi    r9,    r2,    #32,   #16", \
                         "    bfi    r9,    r3,    #48,   #16", \
                         "    vmov   d<num>,    r8,   r9"]

cfggreg_codeblock_a64 = ["    mov    x0,    #0x<data0>", \
                         "    mov    x1,    #0x<data1>", \
                         "    mov    x2,    #0x<data2>", \
                         "    mov    x3,    #0x<data3>", \
                         "    bfi    x0,    x0,    #0,    #16", \
                         "    bfi    x0,    x1,    #16,   #16", \
                         "    bfi    x0,    x2,    #32,   #16", \
                         "    bfi    x0,    x3,    #48,   #16", \
                         "    mov    x<num>,    x0"]

cfggreg_codeblock_a32 = ["    mov    r0,    #0x<data0>", \
                         "    mov    r1,    #0x<data1>", \
                         "    bfi    r0,    r0,    #0,    #16", \
                         "    bfi    r0,    r1,    #16,   #16", \
                         "    mov    r<num>,    r0"]

cfggreg_codeblock_t32 = ["    mov    r0,    #0x<data0>", \
                         "    mov    r1,    #0x<data1>", \
                         "    bfi    r0,    r0,    #0,    #16", \
                         "    bfi    r0,    r1,    #16,   #16", \
                         "    mov    r<num>,    r0"]

#fpcr #[19]:FZ16; [23:22]:RMode, [24]:FZ; [25]:DN; [26]:AHP
cfgfpcr_codeblock_a64 = ["    mov    x0,    #0x0000", \
                         "    mov    x1,    #0x<data>", \
                         "    mov    x2,    #0x0000", \
                         "    mov    x3,    #0x0000", \
                         "    bfi    x11,   x0,    #0,    #16", \
                         "    bfi    x11,   x1,    #16,   #16", \
                         "    bfi    x11,   x2,    #32,   #16", \
                         "    bfi    x11,   x3,    #48,   #16", \
                         "    msr    fpcr,  x11"]

cfgfpcr_codeblock_a32 = ["    mov    r0,    #0x0000", \
                         "    mov    r1,    #0x<data>", \
                         "    bfi    r0,    x0,    #0,    #16", \
                         "    bfi    r0,    r1,    #16,   #16", \
                         "    vmsr   fpscr, r0"]

cfgfpcr_codeblock_t32 = ["    mov    r0,    #0x0000", \
                         "    mov    r1,    #0x<data>", \
                         "    bfi    r0,    x0,    #0,    #16", \
                         "    bfi    r0,    r1,    #16,   #16", \
                         "    vmsr   fpscr, r0"]

def add_TPL(TPL):
    global TPL_list
    TPL_list.append(TPL)

def get_random_TPL():
    global TPL_list
    return random.choice(TPL_list)

def gen_testinstr_codeblock(test_depend):
    codeblock = []
    for i in range(100):
        instr_tpl = get_random_TPL()
        if test_depend == 1:
            instr_tpl.test_depend()
        codeblock.append(instr_tpl.gen_one_instr())
    return codeblock

def gen_cfgfreg_codeblock_a64(random_data_list):
    global cfgfreg_codeblock_a64
    codeblock = []
    for i in range(32):
        data0 = random.choice(random_data_list)
        data1 = random.choice(random_data_list)
        for instr in cfgfreg_codeblock_a64:
            instr = re.sub(r"<data0>", data0[12:16], instr)
            instr = re.sub(r"<data1>", data0[8:12], instr)
            instr = re.sub(r"<data2>", data0[4:8], instr)
            instr = re.sub(r"<data3>", data0[0:4], instr)
            instr = re.sub(r"<data4>", data0[12:16], instr)
            instr = re.sub(r"<data5>", data0[8:12], instr)
            instr = re.sub(r"<data6>", data0[4:8], instr)
            instr = re.sub(r"<data7>", data0[0:4], instr)
            instr = re.sub(r"<num>", str(i), instr)
            codeblock.append(instr)
    return codeblock

def gen_cfgfreg_codeblock_a32(random_data_list):
    global cfgfreg_codeblock_a32
    codeblock = []
    for i in range(32):
        data0 = random.choice(random_data_list)
        for instr in cfgfreg_codeblock_a32:
            instr = re.sub(r"<data0>", data0[12:16], instr)
            instr = re.sub(r"<data1>", data0[8:12], instr)
            instr = re.sub(r"<data2>", data0[4:8], instr)
            instr = re.sub(r"<data3>", data0[0:4], instr)
            instr = re.sub(r"<num>", str(i), instr)
            codeblock.append(instr)
    return codeblock

def gen_cfgfreg_codeblock_t32(random_data_list):
    global cfgfreg_codeblock_t32
    codeblock = []
    for i in range(32):
        data0 = random.choice(random_data_list)
        for instr in cfgfreg_codeblock_t32:
            instr = re.sub(r"<data0>", data0[12:16], instr)
            instr = re.sub(r"<data1>", data0[8:12], instr)
            instr = re.sub(r"<data2>", data0[4:8], instr)
            instr = re.sub(r"<data3>", data0[0:4], instr)
            instr = re.sub(r"<num>", str(i), instr)
            codeblock.append(instr)
    return codeblock

def gen_cfggreg_codeblock_a64(random_data_list):
    global cfggreg_codeblock_a64
    codeblock = []
    for i in range(1, 29):
        data0 = random.choice(random_data_list)
        for instr in cfggreg_codeblock_a64:
            instr = re.sub(r"<data0>", data0[12:16], instr)
            instr = re.sub(r"<data1>", data0[8:12], instr)
            instr = re.sub(r"<data2>", data0[4:8], instr)
            instr = re.sub(r"<data3>", data0[0:4], instr)
            instr = re.sub(r"<num>", str(i), instr)
            codeblock.append(instr)
    return codeblock

def gen_cfggreg_codeblock_a32(random_data_list):
    global cfggreg_codeblock_a32
    codeblock = []
    for i in range(1, 12):
        data0 = random.choice(random_data_list)
        for instr in cfggreg_codeblock_a64:
            instr = re.sub(r"<data0>", data0[4:8], instr)
            instr = re.sub(r"<data1>", data0[0:4], instr)
            instr = re.sub(r"<num>", str(i), instr)
            codeblock.append(instr)
    return codeblock

def gen_cfggreg_codeblock_t32(random_data_list):
    global cfggreg_codeblock_t32
    codeblock = []
    for i in range(1, 12):
        data0 = random.choice(random_data_list)
        for instr in cfggreg_codeblock_a64:
            instr = re.sub(r"<data0>", data0[4:8], instr)
            instr = re.sub(r"<data1>", data0[0:4], instr)
            instr = re.sub(r"<num>", str(i), instr)
            codeblock.append(instr)
    return codeblock

def gen_cfgfpcr_codeblock_a64():
    global cfgfreg_codeblock_a64
    codeblock = []
    data0 = ["0", "8"]
    data1 = ["0", "4", "8", "c"]
    data2 = ["0", "1", "2", "3"]
    data3 = ["0"]
    data = random.choice(data3)+random.choice(data2)+random.choice(data1)+random.choice(data0)
    for instr in cfgfpcr_codeblock_a64:
        instr = re.sub(r"<data>", data, instr)
        codeblock.append(instr)
    return codeblock

def gen_cfgfpcr_codeblock_a32():
    global cfgfreg_codeblock_a32
    codeblock = []
    data0 = ["0", "8"]
    data1 = ["0", "4", "8", "c"]
    data2 = ["0", "1", "2", "3"]
    data3 = ["0"]
    data = random.choice(data3)+random.choice(data2)+random.choice(data1)+random.choice(data0)
    for instr in cfgfpcr_codeblock_a32:
        instr = re.sub(r"<data>", data, instr)
        codeblock.append(instr)
    return codeblock

def gen_cfgfpcr_codeblock_t32():
    global cfgfreg_codeblock_t32
    codeblock = []
    data0 = ["0", "8"]
    data1 = ["0", "4", "8", "c"]
    data2 = ["0", "1", "2", "3"]
    data3 = ["0"]
    data = random.choice(data3)+random.choice(data2)+random.choice(data1)+random.choice(data0)
    for instr in cfgfpcr_codeblock_t32:
        instr = re.sub(r"<data>", data, instr)
        codeblock.append(instr)
    return codeblock

SuperTPL.py文件

SuperTPL.py文件是每个指令TPL的父类,定义了基础的变量和函数。主要内容如下:

  • 定义各字段的随机范围(属于默认值)。
  • 设置test_depend下的寄存器编号字段随机范围。
  • 设置非A64下的寄存器编号字段随机范围。
  • 各个字段的随机范围重新定义函数(为子类的个性化设置提供方法)。
  • 各个字段的获取随机值函数。
  • gen_one_instr(self)函数:生成一条指令,主要对指令TPL的各个字段进行随机值替换。
  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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import random
import re

class SuperTPL(object):
    def __init__(self):
        super(SuperTPL, self).__init__()

        self._instr_tpl = "TPL V<d>.<T1>, V<n>.<T1>, V<m>.<T1>"
        self._id_list = ["0","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"]
        self._in_list = ["0","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"]
        self._im_list = ["0","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"]
        self._ia_list = ["0","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"]
        self._fd_list = ["0","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"]
        self._fn_list = ["0","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"]
        self._fm_list = ["0","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"]
        self._fa_list = ["0","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"]
        self._T1_list = ["8B", "16B", "4H", "8H", "2S", "4S", "2D"]
        self._T2_list = ["8B", "16B", "4H", "8H", "2S", "4S", "2D"]
        self._V_list  = ["H", "S", "D"]
        self._R_list  = ["W", "X"]
        self._index_list = ["0","1","2","3","4","5","6","7"]

    def test_depend(self):
        self._id_list = ["0","1","2","3","4"]
        self._in_list = ["0","1","2","3","4"]
        self._im_list = ["0","1","2","3","4"]
        self._ia_list = ["0","1","2","3","4"]
        self._fd_list = ["0","1","2","3","4"]
        self._fn_list = ["0","1","2","3","4"]
        self._fm_list = ["0","1","2","3","4"]
        self._fa_list = ["0","1","2","3","4"]

    def is_not_a64(self):
        self._id_list = ["0","1","2","3","4","5","6","7","8","9","10","11"]
        self._in_list = ["0","1","2","3","4","5","6","7","8","9","10","11"]
        self._im_list = ["0","1","2","3","4","5","6","7","8","9","10","11"]
        self._ia_list = ["0","1","2","3","4","5","6","7","8","9","10","11"]
        self._fd_list = ["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"]
        self._fn_list = ["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"]
        self._fm_list = ["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"]
        self._fa_list = ["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"]

    def set_instr_tpl(self, instr_tpl):
        self._instr_tpl = instr_tpl

# set random range
#-------------------------------------------------------------
    def set_randomrange_id(self, id_list):
        self._id_list = id_list

    def set_randomrange_in(self, in_list):
        self._in_list = in_list

    def set_randomrange_im(self, im_list):
        self._im_list = im_list

    def set_randomrange_ia(self, ia_list):
        self._ia_list = ia_list

    def set_randomrange_fd(self, fd_list):
        self._fd_list = fd_list

    def set_randomrange_fn(self, fn_list):
        self._fn_list = fn_list

    def set_randomrange_fm(self, fm_list):
        self._fm_list = fm_list

    def set_randomrange_fa(self, fa_list):
        self._fa_list = fa_list

    def set_randomrange_T1(self, T1_list):
        self._T1_list = T1_list

    def set_randomrange_T2(self, T2_list):
        self._T2_list = T2_list

    def set_randomrange_V(self, V_list):
        self._V_list = V_list

    def set_randomrange_R(self, R_list):
        self._R_list = R_list

    def set_randomrange_index(self, index_list):
        self._index_list = index_list
#-------------------------------------------------------------


# get random value
#-------------------------------------------------------------
    def get_randomvalue_id(self):
        return random.choice(self._id_list)

    def get_randomvalue_in(self):
        return random.choice(self._in_list)

    def get_randomvalue_im(self):
        return random.choice(self._im_list)

    def get_randomvalue_ia(self):
        return random.choice(self._ia_list)

    def get_randomvalue_fd(self):
        return random.choice(self._fd_list)

    def get_randomvalue_fn(self):
        return random.choice(self._fn_list)

    def get_randomvalue_fm(self):
        return random.choice(self._fm_list)

    def get_randomvalue_fa(self):
        return random.choice(self._fa_list)

    def get_randomvalue_T1(self):
        return random.choice(self._T1_list)

    def get_randomvalue_T2(self):
        return random.choice(self._T2_list)

    def get_randomvalue_V(self):
        return random.choice(self._V_list)

    def get_randomvalue_R(self):
        return random.choice(self._R_list)

    def get_randomvalue_index(self):
        return random.choice(self._index_list)
#-------------------------------------------------------------


# gen one instr
#-------------------------------------------------------------
    def gen_one_instr(self):
        self._instr = self._instr_tpl
        self._instr = re.sub(r"<id>", self.get_randomvalue_id(), self._instr)
        self._instr = re.sub(r"<in>", self.get_randomvalue_in(), self._instr)
        self._instr = re.sub(r"<im>", self.get_randomvalue_im(), self._instr)
        self._instr = re.sub(r"<ia>", self.get_randomvalue_ia(), self._instr)
        self._instr = re.sub(r"<fd>", self.get_randomvalue_fd(), self._instr)
        self._instr = re.sub(r"<fn>", self.get_randomvalue_fn(), self._instr)
        self._instr = re.sub(r"<fm>", self.get_randomvalue_fm(), self._instr)
        self._instr = re.sub(r"<fa>", self.get_randomvalue_fa(), self._instr)
        self._instr = re.sub(r"<T1>", self.get_randomvalue_T1(), self._instr)
        self._instr = re.sub(r"<T2>", self.get_randomvalue_T2(), self._instr)
        self._instr = re.sub(r"<V>", self.get_randomvalue_V(), self._instr)
        self._instr = re.sub(r"<R>", self.get_randomvalue_R(), self._instr)
        self._instr = re.sub(r"<index>", self.get_randomvalue_index(), self._instr)

        return self._instr
#-------------------------------------------------------------

TPL下的文件

TPL下的文件是指令的模板,继承自SuperTPL.py。以下指令模板仅为展示所用,不代表ARM合法指令。

 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
from SuperTPL import SuperTPL
from Function import add_TPL

class demo1_ADD_01(SuperTPL):
    def __init__(self):
        super(demo1_ADD_01, self).__init__()
        self.set_instr_tpl("    ADD01 W<id>, W<in>, W<im>")
        self.set_randomrange_id(["0, 1"])
add_TPL(demo1_ADD_01())

class demo1_ADD_02(SuperTPL):
    def __init__(self):
        super(demo1_ADD_02, self).__init__()
        self.set_instr_tpl("    ADD02 W<id>, W<in>, W<im>")
        self.set_randomrange_id(["3, 4"])
add_TPL(demo1_ADD_02())

class demo1_ADD_03(SuperTPL):
    def __init__(self):
        super(demo1_ADD_03, self).__init__()
        self.set_instr_tpl("    ADD03 W<id>, W<in>, W<im>")
        self.set_randomrange_id(["5, 6"])
add_TPL(demo1_ADD_03())

class demo1_ADD_04(SuperTPL):
    def __init__(self):
        super(demo1_ADD_04, self).__init__()
        self.set_instr_tpl("    ADD04 W<id>, W<in>, W<im>")
        self.set_randomrange_id(["7, 8"])
add_TPL(demo1_ADD_04())

class demo1_ADD_05(SuperTPL):
    def __init__(self):
        super(demo1_ADD_05, self).__init__()
        self.set_instr_tpl("    ADD05 W<id>, W<in>, W<im>")
        self.set_randomrange_id(["9, 10"])
add_TPL(demo1_ADD_05())

xx_TPL.list文件

xx_TPL.list是src/TPL/目录下的集合清单,罗列了单个TPL名称,也对多个TPL进行了分组,供gen_testcode.py使用。

注意:对于单个TPL文件的组织,可以定义单条指令及它的多种变型,也可以定义多条指令,具体粒度由使用者灵活掌握。这里建议一个TPL定义一组同类型指令,比如浮点双精度加法运算。

casename=TPL_demo1, groupname=demo
casename=TPL_demo2, groupname=demo

gen_testcode.py文件

gen_testcode.py文件是整个环境的top脚本。提供的使用参数如下:

  • args_ISA :设置生成的指令类型,A64 or A32 or T32
  • args_filename :设置输出文件名称
  • args_casename :设置随机的TPL名称(不可与groupname同时设置)
  • args_groupname :设置随机的多个TPL组合名称(不可与casename同时设置)
  • args_testfloat :设置是否使用testfloat数据更新浮点寄存器,可选参数为FP64、FP32、FP16(此环境暂时没集成testfloat,不可设置),如果不设置默认使用随机值。
  • args_sizelevel :设置sizelevel(默认为1),生成的测试指令数等于 sizelevel*100 + cfgfreg_instrnum…
  • args_cfgfpcr :设置支持fpcr寄存器配置(在每100条测试指令前配置)
  • args_seednum :设置随机种子,随机种子会注释到输出文件首行,目的是支持可复现性。
  • args_test_depend :设置支持test_depend,如果测试指令依赖,会将寄存器编号的随机范围缩小。
  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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
import sys
import os
import random
import re

sys.path.insert(0, "src")
sys.path.insert(0, "src/TPL")

from Function import *

args_ISA        = ""
args_filename   = ""
args_casename   = ""
args_groupname  = ""
args_testfloat  = ""
args_sizelevel  = 1
args_cfgfpcr    = 0
args_seednum    = 0
args_test_depend = 0

# usage
#--------------------------------------------------------
if sys.argv[1] == "--help" or sys.argv[1] == "-h":
    print ""
    print "<usage>:"
    print "    python gen_testcode.py [ISA=xxx] [filename=xxx] ([casename=xxx] or [groupname=xxx]) [testfloat=xxx] [sizelevel=xxx] [-cfgfpcr] [seednum=xxx] [-test_depend]"
    print "<args>:"
    print "    ISA=xxx       : set A64 or A32 or T32"
    print "    filename=xxx  : set the outfile testcode filename.s"
    print "    casename=xxx  : one TPL case exist in TPL.list, generate testcode by the TPL case instr template"
    print "    groupname=xxx : one group TPL case exist in TPL.list, generate testcode by the group TPL case instr template"
    print "    testfloat=xxx : insert code block in testcode to config fp registers by testfloat special value(FP64/FP32/FP16)"
    print "    sizelevel=xxx : set code size level, size is n*100 test isntrs"
    print "    -cfgfpcr      : insert code block in testcode to config fpcr register by random value"
    print "    seednum=xxx   : set the random seed,the purpose is to be able to recover the test scenario"
    print "    -test_depend  : if test instr depend, the reg random range is 0~5"
    print "<note>:"
    print "    filename must be set"
    print "    casename and groupname can't be set at the same time"
    print "<example>:"
    print "    one case: python gen_testcode.py filename=test0 ISA=A64 casename=TPL_demo1 sizelevel=10 testfloat=FP64 -cfgfpcr"
    print "    one group case: python gen_testcode.py filename=test0 ISA=A64 groupname=demo sizelevel=10 testfloat=FP64 -cfgfpcr"
    print ""
    sys.exit()

root_path = os.getcwd()
if os.path.basename(root_path) != "random_instr_generator":
    print "[GEN_TESTCODE ERROR]: must run the script under the random_instr_generator path, please double check your current work directory"
    sys.exit()
#--------------------------------------------------------


# fet args
#--------------------------------------------------------
gen_testcode_command = "python gen_testcode.py"
for args in sys.argv:
    gen_testcode_command = gen_testcode_command+" "+args
print "[GEN_TESTCODE START]: "+gen_testcode_command

for args in sys.argv:
    if args.strip().split("=")[0].strip() == "ISA":
        args_ISA = args.strip().split("=")[1].strip()
    if args.strip().split("=")[0].strip() == "filename":
        args_filename = args.strip().split("=")[1].strip()
    if args.strip().split("=")[0].strip() == "casename":
        args_casename = args.strip().split("=")[1].strip()
    if args.strip().split("=")[0].strip() == "groupname":
        args_groupname = args.strip().split("=")[1].strip()
    if args.strip().split("=")[0].strip() == "testfloat":
        args_testfloat = args.strip().split("=")[1].strip()
    if args.strip().split("=")[0].strip() == "sizelevel":
        args_sizelevel = int(args.strip().split("=")[1].strip())
    if args.strip().split("=")[0].strip() == "seednum":
        args_seednum = int(args.strip().split("=")[1].strip())
    if args == "-cfgfpcr":
        args_cfgfpcr = 1
    if args == "-test_depend":
        args_test_depend = 1

# args check
if args_filename == "":
    print "[GEN_TESTCODE ERROR]: args filename=xxx must be set, please double check ypur args"
    sys.exit()
if args_casename == "" and args_groupname == "":
    print "[GEN_TESTCODE ERROR]: args casename=xxx and groupname=xxx must be set one of them, please double check ypur args"
    sys.exit()
if args_casename != "" and args_groupname != "":
    print "[GEN_TESTCODE ERROR]: args casename=xxx and groupname=xxx can't be set at the same time, please double check ypur args"
    sys.exit()

# set random seed
if args_seednum != 0:
    random.seed(args_seednum)
#--------------------------------------------------------


# import TPL
#--------------------------------------------------------
if args_ISA == "A64":
    TPL_listpath  = "./A64_TPL.list"
if args_ISA == "A32":
    TPL_listpath  = "./A32_TPL.list"
if args_ISA == "T32":
    TPL_listpath  = "./T32_TPL.list"

TPL_listfile  = open(TPL_listpath, "r")
TPL_casename  = ""
TPL_groupname = ""
import_TPL_list = []

# get import_TPL_list from TPL.list
while True:
    TPL_line = TPL_listfile.readline()
    if not TPL_line:
        break

    TPL_casename  = ""
    TPL_groupname = ""

    find_result = re.findall(r"^[ ]*//.*", TPL_line)
    if len(find_result) != 0:
        continue

    find_result = re.findall(r"^[ ]*casename=([a-zA-Z_0-9]+),[ ]*groupname=([a-zA-Z_0-9]+)[ ]*", TPL_line)
    if len(find_result) != 0:
        TPL_casename  = find_result[0][0]
        TPL_groupname = find_result[0][1]

    # one case
    if args_casename != "":
        if args_casename == TPL_casename:
            import_TPL_list.append(TPL_casename)

    # one group
    if args_groupname != "":
        if args_groupname == TPL_groupname:
            import_TPL_list.append(TPL_casename)

TPL_listfile.close()

# check import_TPL_list
import_TPL_num = len(import_TPL_list)
if args_casename != "":
    if import_TPL_num != 1:
        print "[GEN_TESTCODE ERROR]: can't find the "+args_casename+" or more than one in TPL.list, please double check run args or TPL.list"
        sys.exit()

if args_groupname != "":
    if import_TPL_num == 0:
        print "[GEN_TESTCODE ERROR]: can't find the "+args_groupname+" in TPL.list, please double check run args or TPL.list"
        sys.exit()

# import the TPL list
for TPL in import_TPL_list:
    __import__(TPL)
#--------------------------------------------------------


# prepare random data list
#--------------------------------------------------------
fdata_list = []
tf_path = root_path+"/tools/testfoat/berkeley-testfloat-3/build/Linux-ARM-VFPv2-GCC/"

if args_testfloat == "FP64":
    os.chdir(tf_path)
    testfloat_command = "./testfloat_gen f64 1 -seed "+str(args_seednum)+" -n 1000 >tf64_"+str(args_seednum)
    os.system(testfloat_command)
    tf64_file = open("./tf64_"+str(args_seednum), "r")
    for i in range(1000):
        line = tf64_file.readline()
        line = re.sub(r"[ ]", "", line)
        line = re.sub(r"[\n]", "", line)
        fdata_list.append(line)
    tf64_file.close()
    os.system("rm -rf tf64_"+str(args_seednum))
    os.chdir(root_path)

if args_testfloat == "FP32":
    os.chdir(tf_path)
    testfloat_command = "./testfloat_gen f32 1 -seed "+str(args_seednum)+" -n 2000 >tf32_"+str(args_seednum)
    os.system(testfloat_command)
    tf32_file = open("./tf32_"+str(args_seednum), "r")
    for i in range(1000):
        line0 = tf32_file.readline()
        line0 = re.sub(r"[ ]", "", line0)
        line0 = re.sub(r"[\n]", "", line0)
        line1 = tf32_file.readline()
        line1 = re.sub(r"[ ]", "", line1)
        line1 = re.sub(r"[\n]", "", line1)
        fdata_list.append(line0+line1)
    tf32_file.close()
    os.system("rm -rf tf32_"+str(args_seednum))
    os.chdir(root_path)

if args_testfloat == "FP16":
    os.chdir(tf_path)
    testfloat_command = "./testfloat_gen f16 1 -seed "+str(args_seednum)+" -n 4000 >tf16_"+str(args_seednum)
    os.system(testfloat_command)
    tf16_file = open("./tf16_"+str(args_seednum), "r")
    for i in range(1000):
        line0 = tf16_file.readline()
        line0 = re.sub(r"[ ]", "", line0)
        line0 = re.sub(r"[\n]", "", line0)
        line1 = tf16_file.readline()
        line1 = re.sub(r"[ ]", "", line1)
        line1 = re.sub(r"[\n]", "", line1)
        line2 = tf16_file.readline()
        line2 = re.sub(r"[ ]", "", line2)
        line2 = re.sub(r"[\n]", "", line2)
        line3 = tf16_file.readline()
        line3 = re.sub(r"[ ]", "", line3)
        line3 = re.sub(r"[\n]", "", line3)
        fdata_list.append(line0+line1+line2+line3)
    tf16_file.close()
    os.system("rm -rf tf16_"+str(args_seednum))
    os.chdir(root_path)

if args_testfloat == "":
    data0_list = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"]
    for i in range(1000):
        data = []
        data = random.choice(data0_list)
        data = data + random.choice(data0_list)
        data = data + random.choice(data0_list)
        data = data + random.choice(data0_list)
        data = data + random.choice(data0_list)
        data = data + random.choice(data0_list)
        data = data + random.choice(data0_list)
        data = data + random.choice(data0_list)
        data = data + random.choice(data0_list)
        data = data + random.choice(data0_list)
        data = data + random.choice(data0_list)
        data = data + random.choice(data0_list)
        data = data + random.choice(data0_list)
        data = data + random.choice(data0_list)
        data = data + random.choice(data0_list)
        data = data + random.choice(data0_list)
        fdata_list.append(data)

idata_list = []
data0_list = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"]
for i in range(1000):
    data = []
    data = random.choice(data0_list)
    data = data + random.choice(data0_list)
    data = data + random.choice(data0_list)
    data = data + random.choice(data0_list)
    data = data + random.choice(data0_list)
    data = data + random.choice(data0_list)
    data = data + random.choice(data0_list)
    data = data + random.choice(data0_list)
    data = data + random.choice(data0_list)
    data = data + random.choice(data0_list)
    data = data + random.choice(data0_list)
    data = data + random.choice(data0_list)
    data = data + random.choice(data0_list)
    data = data + random.choice(data0_list)
    data = data + random.choice(data0_list)
    data = data + random.choice(data0_list)
    idata_list.append(data)
#--------------------------------------------------------


# gen testcode
#--------------------------------------------------------
testcode = []
for i in range(args_sizelevel):
    testcode0 = []
    testcode1 = []
    testcode2 = []
    testcode3 = []

    if args_ISA == "A64":
        testcode0 = gen_cfgfpcr_codeblock_a64()
        testcode1 = gen_cfgfreg_codeblock_a64(fdata_list)
        testcode2 = gen_cfgfreg_codeblock_a64(idata_list)
        testcode3 = gen_testinstr_codeblock(args_test_depend)
    if args_ISA == "A32":
        testcode0 = gen_cfgfpcr_codeblock_a32()
        testcode1 = gen_cfgfreg_codeblock_a32(fdata_list)
        testcode2 = gen_cfgfreg_codeblock_a32(idata_list)
        testcode3 = gen_testinstr_codeblock(args_test_depend)
    if args_ISA == "T32":
        testcode0 = gen_cfgfpcr_codeblock_t32()
        testcode1 = gen_cfgfreg_codeblock_t32(fdata_list)
        testcode2 = gen_cfgfreg_codeblock_t32(idata_list)
        testcode3 = gen_testinstr_codeblock(args_test_depend)
    testcode = testcode + testcode0 + testcode1 + testcode2 + testcode3

testcode_path = root_path+"/"+args_filename+".s"
if os.path.exists(testcode_path):
    os.system("rm -rf "+testcode_path)

os.system("touch "+testcode_path)
testcode_file = open(testcode_path, "a")
for instr in testcode:
    testcode_file.write(instr+"\n")
testcode_file.close()
#--------------------------------------------------------

tools目录

tools目录下是为了集成testfloat或其他应用程序而提供的,暂时未集成testfloat。

使用方法

  • 首先参考/src/TPL/TPL_demo1.py文件,定义新的指令类型,对于随机字段的随机范围可重新定义,也可以使用默认范围。
  • 如果有环境中未支持的随机字段,需要在SuperTPL.py文件添加相关操作,包括定义随机范围、获取随机值、随机字段替换等。
  • 将TPL添加至对应的xx_TPL.list,casename与TPL文件名称保持一致,groupnamename可自定义。
  • 使用gen_testcode.py脚本生成随机指令,具体gen_testcode.py的使用方法和参数可以通过-h获取。
  • 对于生成随机指令的合法性,需要通过ARM编译器进行检验,成功编译说明TPL没问题,成熟的TPL可能需要经过多次检验。

文章原创,可能存在部分错误,欢迎指正,联系邮箱 cao_arvin@163.com。