借助上一篇文章所提及的验证环境,在本篇文章中,将会阐述如何增添一个用例来验证指令集,以及怎样运用编译器编译汇编代码,并生成二进制的 Bin 文件。针对 RISC-V 所使用的编译器,这里采用的是“山河编译器”。山河编译器(MounRiver Studio)是一款国产的集成开发环境(IDE),官网地址:http://www.mounriver.com,可自行下载对应版本,并将编译器路径添加到环境变量中。
// -------------------------------------------------------------------------------------------------
// Copyright 2024 Kearn Chen, [email protected]
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// -------------------------------------------------------------------------------------------------
// Description :
// 1. Instr smoke test
// -------------------------------------------------------------------------------------------------
task initcase;
load_instr("instr_smoke_test/instr_smoke_test.bin");
endtask
task testcase;
#1_000_000;
endtask
在验证用例中,任务initcase
加载Bin文件到仿真模型中,任务testcase
延迟1毫秒,等待CPU执行完软件指令。
/*Copyright 2018-2021 T-Head Semiconductor Co., Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.text
.align 1
.global _start
_start:
#---------------------------------------#
# main execution routine #
#---------------------------------------#
#---------------------------------------#
# RV32I instructions #
#---------------------------------------#
#---------------------------------------#
# Int Reg-imm Ins #
#---------------------------------------#
#ADDi
ADDI:
#func 1 test basic
#-1 +5
li x5, 0x4
li x4, 0x5
addi x4, x4, 0xffffffff
bne x4, x5, TEST_FAIL
#2047+2047
li x5, 0xffe
li x4, 0x7ff
addi x4, x4, 0x7ff
bne x4, x5, TEST_FAIL
#-2048+-2048
li x5, 0xfffff000
li x4, 0xfffff800
addi x4, x4, 0xfffff800
bne x4, x5, TEST_FAIL
#func 2 test MV
addi x4, x4, 0x123
addi x5, x4, 0x0
bne x4, x5, TEST_FAIL
#func 3 test nop
li x5, 0x0
addi x5, x5, 0x0
addi x0, x0, 0x0
addi x0, x0, 0x5
bne x5, x0, TEST_FAIL
#SLTI
SLTI:
li x4, 0x1
#signed compare 0xfff compare with 0xffffffff(imm expand)
li x5, 0xfff
slti x5, x5, 0xffffffff
bne x5, x0, TEST_FAIL
#signed compare 0xfff compare with 0x1(imm not expand)
li x5, 0xfff
slti x5, x5, 0x1
bne x5, x0, TEST_FAIL
#signed compare 0xffffffff compare with 0x1
li x5, 0xffffffff
slti x5, x5, 0x1
bne x5, x4, TEST_FAIL
#signed compare 0x1 compare with 0x1
li x5, 0x1
slti x5, x5, 0x1
bne x5, x0, TEST_FAIL
#SLTIU
SLTIU:
li x4, 0x1
#0xffffffff compare with 0xfff
li x5, 0xffffffff
sltiu x5, x5, 0x7ff
bne x5, x0, TEST_FAIL
#0xfff compare with 0x1
li x5, 0xfff
sltiu x5, x5, 0x1
bne x5, x0, TEST_FAIL
#0x1 compare with 0xfff(no sign extend)
li x5, 0x1
sltiu x5, x5, 0x7ff
bne x5, x4, TEST_FAIL
#ANDI
ANDI:
#0xaaaaaaaa andi 0xfff(sign extend)
li x4, 0xaaaaaaaa
li x5, 0xaaaaaaaa
andi x5, x5, 0xffffffff
bne x4, x5, TEST_FAIL
#0xaaaaaaaa andi 0x7ff(sign extend)
li x4, 0x2aa
li x5, 0xaaaaaaaa
andi x5, x5, 0x7ff
bne x4, x5, TEST_FAIL
#0xaaaaaaaa andi 0x0
li x4, 0x0
li x5, 0xaaaaaaaa
andi x5, x5, 0x0
bne x4, x5, TEST_FAIL
#ORI
ORI:
#0xaaaaaaaa ori 0xffffffff(sign extend)
li x4, 0xffffffff
li x5, 0xaaaaaaaa
ori x5, x5, 0xffffffff
bne x4, x5, TEST_FAIL
#0xaaaaaaaa ori 0x7ff(sign extend)
li x4, 0x2aa
li x5, 0xaaaaaaaa
ori x5, x5, 0x7ff
beq x4, x5, TEST_FAIL
#0xaaaaaaaa ori 0x0
li x4, 0xaaaaaaaa
li x5, 0xaaaaaaaa
ori x5, x5, 0x0
bne x4, x5, TEST_FAIL
#XORI
XORI:
#not
li x4, 0xabcdabcd
xori x5, x4, -1
not x6, x4
bne x6, x5, TEST_FAIL
#0xf
li x4, 0xabcdffff
li x6, 0xabcdfff0
xori x5, x4, 0xf
bne x6, x5, TEST_FAIL
#0x0
li x4, 0xabcdabcd
li x6, 0xabcdabcd
xori x5, x4, 0x0
bne x6, x5, TEST_FAIL
#SLLI
SLLI:
li x4, 0xabcd1234
slli x2, x4, 0 #IMM5 = 0, x2 = x4
bne x2, x4, TEST_FAIL
li x4, 0xabcd1234
slli x2, x4, 31 #IMM5 = 31, x2 = 0
li x3, 0x0
bne x2, x3, TEST_FAIL
li x4, 0xaaaaaaaa
slli x2, x4, 8 #IMM5 = 8, x2 = 0xaaaaaa
li x3, 0xaaaaaa00
bne x2, x3, TEST_FAIL
#SRLI
SRLI:
li x2, 0xabcd1234
srli x3, x2, 0 #IMM5 = 0, r2 = r1
bne x2, x3, TEST_FAIL
li x2, 0xaaaaaaaa
srli x3, x2, 31 #IMM5 = 31, r2 = 1
li x4, 0x1
bne x3, x4, TEST_FAIL
li x2, 0xaaaaaaaa
srli x2, x2, 1 #IMM5 = 1, r2 = 0x55555555
li x3, 0x55555555
bne x2, x3, TEST_FAIL
#SRAI
SRAI:
li x2, 0xaaaaaaaa
srai x2, x2, 31 #IMM5 = 31,sign=1, x2 = 0xffffffff
li x3, 0xffffffff
bne x2, x3, TEST_FAIL
li x2, 0x55555555
srai x2, x2, 31 #IMM5=31, sign=0, x2 = 0
li x3, 0
bne x2, x3, TEST_FAIL
li x2, 0x55555555
srai x2, x2, 1 #IMM5=1 , x2 = 2aaaaaaa
li x3, 0x2aaaaaaa
bne x2, x3, TEST_FAIL
li x2, 0xabcd1234
srai x2, x2, 0 # /IMM5=0, r2 = abcd1234
li x3, 0xabcd1234
bne x2, x3, TEST_FAIL
#LUI
LUI:
lui x2, 0x7bcd1
li x3, 0x7bcd1000
bne x2, x3, TEST_FAIL
lui x2, 0x89abc
li x3, 0x89abc000
bne x2, x3, TEST_FAIL
#AUIPC
AUIPC:
auipc x2, 0x0
li x3, 0xa010
add x2, x3, x2
auipc x4, 0xa
bne x2, x4, TEST_FAIL
auipc x2, 0x0
li x3, 0x80000010
add x2, x3, x2
auipc x4, 0x80000
bne x2, x4, TEST_FAIL
#---------------------------------------#
# Int Reg-Reg Ins #
#---------------------------------------#
#ADD
ADD:
#-1+ -1
li x3, 0xffffffff
li x4, 0xffffffff
add x5, x3, x4
li x6, 0xfffffffe
bne x5, x6, TEST_FAIL
#0x8000000+ 0x80000000
li x3, 0x80000000
li x4, 0x80000000
add x5, x3, x4
li x6, 0x0
bne x5, x6, TEST_FAIL
#0x7fffffff+ 0x7fffffff
li x3, 0x7fffffff
li x4, 0x7fffffff
add x5, x3, x4
li x6, 0xfffffffe
bne x5, x6, TEST_FAIL
#SUB
SUB:
#0x80000000- 0x7fffffff
li x3, 0x80000000
li x4, 0x7fffffff
sub x5, x3, x4
li x6, 0x1
bne x5, x6, TEST_FAIL
#0x7fffffff - 0x80000000
li x3, 0x7fffffff
li x4, 0x80000000
sub x5, x3, x4
li x6, 0xffffffff
bne x5, x6, TEST_FAIL
#0xf - 0x2
li x3, 0xf
li x4, 0x2
sub x5, x3, x4
li x6, 0xd
bne x5, x6, TEST_FAIL
#SLT
SLT:
li x3, 0x1
li x4, 0x0
li x5, 0x80000000
li x6, 0xffffffff
#1 / 1
slt x7, x3, x3
bne x7, x4, TEST_FAIL
#1 / 0
slt x7, x3, x4
bne x7, x4, TEST_FAIL
#0 / 1
slt x7, x4, x3
bne x7, x3, TEST_FAIL
#0x80000000/ 0x1 # -max /1
slt x7, x5, x3
bne x7, x3, TEST_FAIL
#SLTU
SLTU:
li x3, 0x1
li x4, 0x0
li x5, 0x80000000
li x6, 0xffffffff
#1 / 1
sltu x7, x3, x3
bne x7, x4, TEST_FAIL
#1 / 0
sltu x7, x3, x4
bne x7, x4, TEST_FAIL
#0 / 1
sltu x7, x4, x3
bne x7, x3, TEST_FAIL
#0x80000000/0x1
sltu x7, x5, x3
bne x7, x4, TEST_FAIL
#AND
AND:
li x3, 0x0
li x4, 0xffffffff
#0xabcdabcd 0xffffffff
li x5, 0xabcdabcd
and x6, x5, x4
bne x6, x5, TEST_FAIL
#0xabcdabcd 0x0
li x5, 0xabcdabcd
and x6, x5, x3
bne x6, x3, TEST_FAIL
#OR
OR:
li x3, 0x0
li x4, 0xffffffff
#0xabcdabcd | 0xffffffff
li x5, 0xabcdabcd
or x6, x5, x4
bne x6, x4, TEST_FAIL
#0xabcdabcd | 0x0
li x5, 0xabcdabcd
or x6, x5, x3
bne x6, x5, TEST_FAIL
#XOR
XOR:
li x3, 0x0
li x4, 0xffffffff
#0xabcd | 0xffffffff #not
li x5, 0xabcdabcd
xor x6, x5, x4
not x5, x5
bne x6, x5, TEST_FAIL
#0xabcd | 0x0
li x5, 0xabcdabcd
xor x6, x5, x3
bne x6, x5, TEST_FAIL
#SLL
SLL:
li x4, 0xabcd1234
sll x2, x4, x0 #IMM5 = 0, x2 = x4
bne x2, x4, TEST_FAIL
li x4, 0xabcd1234
li x5, 31
sll x2, x4, x5 #IMM5 = 31, x2 = 0
li x3, 0x0
bne x2, x3, TEST_FAIL
li x4, 0xaaaaaaaa
li x5, 0x8
sll x2, x4, x5 #IMM5 = 8, x2 = 0xaaaaaa
li x3, 0xaaaaaa00
bne x2, x3, TEST_FAIL
li x4, 0xaaaaaaaa
li x5, 0x21
sll x2, x4, x5 #IMM5 = 0x1, x2 = 0x55555554
li x3, 0x55555554
bne x2, x3, TEST_FAIL
#SRL
SRL:
li x2, 0xabcd1234
srl x3, x2, x0 #IMM5 = 0, r2 = r1
bne x2, x3, TEST_FAIL
li x2, 0xaaaaaaaa
li x5, 31
srl x3, x2, x5 #IMM5 = 31, r2 = 1
li x4, 0x1
bne x3, x4, TEST_FAIL
li x2, 0xaaaaaaaa
li x5, 0x1
srl x2, x2, x5 #IMM5 = 1, r2 = 0x55555555
li x3, 0x55555555
bne x2, x3, TEST_FAIL
li x2, 0xaaaaaaaa
li x5, 0x21
srl x2, x2, x5 #IMM5 = 0x1, x2 = 0x55555555
li x3, 0x55555555
bne x2, x3, TEST_FAIL
#SRA
SRA:
li x2, 0xaaaaaaaa
li x5, 0x1f
sra x2, x2, x5 #IMM5 = 31,sign=1, x2 = 0xffffffff
li x3, 0xffffffff
bne x2, x3, TEST_FAIL
li x2, 0x55555555
li x5, 0x1f
sra x2, x2, x5 #IMM5=31, sign=0, x2 = 0
li x3, 0
bne x2, x3, TEST_FAIL
li x2, 0x55555555
li x5, 0x1
sra x2, x2, x5 #IMM5=1 , x2 = 2aaaaaaa
li x3, 0x2aaaaaaa
bne x2, x3, TEST_FAIL
li x2, 0x55555555
li x5, 0x21
sra x2, x2, x5 #IMM5=1 , x2 = 2aaaaaaa
li x3, 0x2aaaaaaa
bne x2, x3, TEST_FAIL
li x2, 0xabcd1234
sra x2, x2, x0 # /IMM5=0, r2 = abcd1234
li x3, 0xabcd1234
bne x2, x3, TEST_FAIL
######################################################
# RV32I
######################################################
#*****************************************************
# store and load
#*****************************************************
#r1 is link reg ,r2 is stack reg
#r0 = 0
#r3 = ffffffff
li x3,0xffffffff
li x8,0xaaaaaaaa
#x3 = ffffffff
#addr is in x4
#sw and lw
li x4,0x0000a000 #x4 = 0000a000
sw x8,0xfffffffc(x4) #mem[0x0000affc] = 0xaaaaaaaa
lw x5,0xfffffffc(x4) # x5 = aaaaaaaa
bne x8,x5,TEST_FAIL
sw x8,0x7fc(x4) #mem[0x0000a7fc] = 0xaaaaaaaa
lw x5,0x7fc(x4) # x5 = aaaaaaaa
bne x8,x5,TEST_FAIL
sw x3,0x0(x4) #mem[0x0000a000] = 0xffffffff
lw x5,0x0(x4) # x5 = 0xffffffff
bne x3,x5,TEST_FAIL
li x6,0xffff8000 #x6 = 0xffff_8000
li x8,0x00008000 #x8 cmp reg = 0000_8000
li x9,0xaaaaaaaa
li x10,0xaaaa8000
#sh and lh
sw x9,0x0(x4) #mem[0x0000a000] = 0xaaaaaaaa
sh x6,0x0(x4) #mem[0x0000a000] = 0xaaaa_8000
lhu x7,0x0(x4) # x7 = 0x0000_8000 zeroextend
lh x5,0x0(x4) #x5 = 0xffff_8000 signextend
lw x11,0x0(x4)
bne x7,x8,TEST_FAIL
bne x6,x5,TEST_FAIL
bne x11,x10,TEST_FAIL
sh x6,0xfffffffe(x4) #mem[0x0000affe] = 0x8000
lhu x7,0xfffffffe(x4) # x7 = 0x0000_8000 zeroextend
lh x5,0xfffffffe(x4) #x5 = 0xffff_8000 signextend
bne x7,x8,TEST_FAIL
bne x6,x5,TEST_FAIL
sh x6,0x7fe(x4) #mem[0x0000a7fe] = 0x8000
lhu x7,0x7fe(x4) # x7 = 0x0000_8000 zeroextend
lh x5,0x7fe(x4) #x5 = 0xffff_8000 signextend
bne x7,x8,TEST_FAIL
bne x6,x5,TEST_FAIL
#sb and lb
li x8,0x000000ff
li x9,0xaaaaaaaa
li x10,0xaaaaaaff
sw x9,0x0(x4) #mem[0x0000a000] = 0xaaaaaaaa
sb x3,0x0(x4) #mem[0x0000a000] = 0xaaaaaaff
lbu x7,0x0(x4) # x7 = 0x0000_00ff zeroextend
lb x5,0x0(x4) #x5 = 0xffff_ffff signextend
lw x11,0x0(x4)
bne x7,x8,TEST_FAIL
bne x3,x5,TEST_FAIL
bne x10,x11,TEST_FAIL
sb x3,0xffffffff(x4) #mem[0x0000afff] = ff
lbu x7,0xffffffff(x4) # x7 = 0x0000_00ff zeroextend
lb x5,0xffffffff(x4) #x5 = 0xffff_ffff signextend
bne x7,x8,TEST_FAIL
bne x3,x5,TEST_FAIL
sb x3,0x7ff(x4) #mem[0x0000a7ff] = ff
lbu x7,0x7ff(x4) # x7 = 0x0000_00ff zeroextend
lb x5,0x7ff(x4) #x5 = 0xffff_ffff signextend
bne x7,x8,TEST_FAIL
bne x3,x5,TEST_FAIL
#*************************************************
# jmp
#**************************************************
jal x1, BRANCH_LABEL
A:
jal x0,JREG_LABEL #j
#***********************************************************
# branch
#r0 = 0
#r3 = ffff_ffff
#r4 = 8000_0000
#*************************************************************
BRANCH_LABEL:
li x4,0x80000000
#beq
beq x0,x4,TEST_FAIL
beq x4,x4,BNE_LABEL
beq x0,x0,TEST_FAIL #not execute
#bne
BNE_LABEL:
bne x4,x4,TEST_FAIL
bne x0,x4,BLT_LABEL
beq x0,x0,TEST_FAIL #not execute
#blt
BLT_LABEL:
blt x0,x4,TEST_FAIL
blt x4,x4,TEST_FAIL
blt x4,x0,BGE_LABEL
beq x0,x0,TEST_FAIL #not execute
#bge
BGE_LABEL:
bge x4,x3,TEST_FAIL
bge x3,x4,BGEE_LABEL
beq x0,x0,TEST_FAIL #not execute
BGEE_LABEL: #equal
bge x3,x3,BGEU_LABEL
beq x0,x0,TEST_FAIL #not execute
#bgeu
BGEU_LABEL:
bgeu x4,x3,TEST_FAIL
bgeu x3,x4,BGEUE_LABEL
beq x0,x0,TEST_FAIL #not execute
BGEUE_LABEL:
bgeu x3,x3,BLTU_LABEL
beq x0,x0,TEST_FAIL #not execute
#bltu
BLTU_LABEL:
bltu x4,x0,TEST_FAIL
bltu x4,x4,TEST_FAIL
bltu x0,x4,J_LABEL
beq x0,x0,TEST_FAIL #not execute
J_LABEL:
jalr x1,x1,0x0 #jump to A
B:
jal x0,TEST_PASS
JREG_LABEL:
jalr x0,x1,0x0 #jr jump to B
#---------------------------------------#
#exit
#---------------------------------------#
TEST_PASS:
la a0, 0xC0000
la a1, 0x54 // 'T'
sw a1, (a0)
la a1, 0x65 // 'e'
sw a1, (a0)
la a1, 0x73 // 's'
sw a1, (a0)
la a1, 0x74 // 't'
sw a1, (a0)
la a1, 0x20 // ' '
sw a1, (a0)
la a1, 0x70 // 'p'
sw a1, (a0)
la a1, 0x61 // 'a'
sw a1, (a0)
la a1, 0x73 // 's'
sw a1, (a0)
la a1, 0x73 // 's'
sw a1, (a0)
la a1, 0x21 // '!'
sw a1, (a0)
la a1, 0x0a // '\n'
sw a1, (a0)
1:
j 1b
#---------------------------------------#
#fail
#---------------------------------------#
TEST_FAIL:
la a0, 0xC0000
la a1, 0x54 // 'T'
sw a1, (a0)
la a1, 0x65 // 'e'
sw a1, (a0)
la a1, 0x73 // 's'
sw a1, (a0)
la a1, 0x74 // 't'
sw a1, (a0)
la a1, 0x20 // ' '
sw a1, (a0)
la a1, 0x66 // 'f'
sw a1, (a0)
la a1, 0x61 // 'a'
sw a1, (a0)
la a1, 0x6a // 'i'
sw a1, (a0)
la a1, 0x6c // 'l'
sw a1, (a0)
la a1, 0x21 // '!'
sw a1, (a0)
la a1, 0x0a // '\n'
sw a1, (a0)
1:
j 1b
上述测试指令来源于平头哥的玄铁E902的冒烟测试用例,对其做了大量修改,删去了压缩指令集部分。在所有指令都执行正确后,会跳转到TEST_PASS
代码段,并在终端上打印"Test pass!"
,然后等待仿真结束。在进行指令测试时,任意指令执行错误,都会跳转到TEST_FAIL
代码段,并在终端上打印"Test fail!"
,然后等待结束仿真。
OUTPUT_ARCH( "riscv" )
ENTRY(_start)
SECTIONS
{
. = 0x00000000;
.text.init : { *(.text.init) }
. = ALIGN(0x1000);
.tohost : { *(.tohost) }
. = ALIGN(0x1000);
.text : { *(.text) }
. = ALIGN(0x1000);
.data : { *(.data) }
.bss : { *(.bss) }
_end = .;
}
# -------------------------------------------------------------------------------------------------
# Copyright 2024 Kearn Chen, [email protected]
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -------------------------------------------------------------------------------------------------
PREFIX := riscv-none-embed-
LINKER := link.ld
OBJECT += instr_smoke.o
CFLAGS := -march=rv32e -mabi=ilp32e
LFLAGS := -march=rv32e -mabi=ilp32e -T$(LINKER) -nostartfiles -nostdlib
TARGET := $(notdir $(shell pwd))
all : $(TARGET).asm $(TARGET).bin
%.bin : %.elf
$(PREFIX)objcopy -Obinary $< $@
%.asm : %.elf
$(PREFIX)objdump -D $< > $@
%.elf : $(OBJECT)
$(PREFIX)gcc $(LFLAGS) -o $@ $^
%.o : %.S
$(PREFIX)gcc $(CFLAGS) -c -o $@ $<
clean :
@rm -rf *.o *.elf *.asm *.bin
.PHONY: clean all
.SECONDARY:
*Verdi* : Create FSDB file 'novas.fsdb'
*Verdi* : Begin traversing the scopes, layer (0).
*Verdi* : End of traversing.
[MCU_INFO] : Test pass!
$finish called from file "../env/test_top.v", line 78.
$finish at simulation time 1001000
本文介绍了指令集的验证流程以及一个基本的指令冒烟用例,通过精心设计的指令码,能够有效地支持自动比对功能的实现。