riscv-tests
riscv-tests copied to clipboard
ERROR in using "rv32ui-p-fence_i.dump" test file
When I use "rv32ui-p-fence_i.dump" as a testbench to test my risc-v CPU , I found that the test file has some problems : ... 800000fc: 06f00693 li a3,111 80000100: 00002517 auipc a0,0x2 80000104: f0051503 lh a0,-256(a0) # 80002000 <begin_signature> 80000108: 00002597 auipc a1,0x2 8000010c: efa59583 lh a1,-262(a1) # 80002002 <begin_signature+0x2> 80000110: 00000013 nop 80000114: 00000013 nop 80000118: 00000013 nop 8000011c: 00000013 nop 80000120: 00000013 nop 80000124: 00000013 nop 80000128: 00000013 nop 8000012c: 00000013 nop 80000130: 00000013 nop 80000134: 00000013 nop 80000138: 00000013 nop 8000013c: 00000013 nop 80000140: 00000297 auipc t0,0x0 80000144: 00a29a23 sh a0,20(t0) # 80000154 <reset_vector+0x108> 80000148: 00000297 auipc t0,0x0 8000014c: 00b29723 sh a1,14(t0) # 80000156 <reset_vector+0x10a> 80000150: 0000100f fence.i 80000154: 0de68693 addi a3,a3,222
80000158 <test_2>:
80000158: 00000013 nop
8000015c: 1bc00e93 li t4,444
80000160: 00200193 li gp,2
80000164: 07d69a63 bne a3,t4,800001d8
This test involves self-modifying code. The instructions from 0x80000100 to 0x8000014c, shown in the assembly below, change addi a3, a3, 222
into addi a3, a3, 333
. The fence.i
should ensure that the instruction fetch at label 1
observes the results of the preceding stores.
li a3, 111
lh a0, insn
lh a1, insn+2
# test I$ hit
.align 6
sh a0, 1f, t0
sh a1, 1f+2, t0
fence.i
1: addi a3, a3, 222
TEST_CASE( 2, a3, 444, nop )
As described by the user-level spec, your core must synchronize the instructions and data streams somehow, such as flushing the I-cache or maintaining I/D-cache coherence by snooping or invalidation.
Thanks for your answer. But I have some more questions:
- what is self-modifying code used for?
- Must I store data in D-cache before run this test?
- Should I change
addi a3, a3, 22
intoaddi a3, a3, 333
in the test file manually or the test file has changed itself? - If it is changed itself, I want to know how does it make this?
I am a beginner of RISC-V CPU design, and I have finished myself CPU. Now I want to use some standard test files to verify my CPU, and I found many different test files in riscv
branch in git hub, such as :
riscv-tests
riscv-compilance
would you please tell me what is the difference between these tests?
Thank you very very much!
The test is written correctly as is. To further explain how it works:
- Two
lh
instructions load the new instruction bits from the memory location labeled byinsn
(addi a3, a3, 333
). - Two
sh
instructions then overwrite the 32-bit word that containsaddi a3, a3, 222
. - The subsequent
fence.i
means that that the core must execute the new instruction at that PC, not the previous one. (In other words, your implementation offence.i
is likely deficient.)
Self-modifying code is not so widespread anymore, given that executable pages are often kept read-only for security considerations, but the scenario that a data store modifies a line already cached in the I-cache is fairly common:
- The OS loads a new executable on process creation.
- A JIT compiler writes new instruction blocks dynamically.
I found many different test files in riscv branch in git hub, such as : riscv-tests riscv-compilance would you please tell me what is the difference between these tests?
riscv-tests is the original collection of ISA-level tests that check for basic functionality and some edge cases that a designer might likely overlook, but they do not test every aspect of the specification. The riscv-compliance suites, which came later, are intended to be more comprehensive and is developed by the official Compliance Task Group of the RISC-V Foundation.
Thank you again. I deeply understood the real meaning of this test file through your answer.
The test self-modifies the code to replace the instruction at 80000154 with a different instruction. If that isn’t working, you probably didn’t implement the fence.i instruction correctly.
On Mon, Sep 2, 2019 at 12:04 AM yuanbobo345 [email protected] wrote:
When I use "rv32ui-p-fence_i.dump" as a testbench to test my risc-v CPU , I found that the test file has some problems : ... 800000fc: 06f00693 li a3,111 80000100: 00002517 auipc a0,0x2 80000104: f0051503 lh a0,-256(a0) # 80002000 <begin_signature> 80000108: 00002597 auipc a1,0x2 8000010c: efa59583 lh a1,-262(a1) # 80002002 <begin_signature+0x2> 80000110: 00000013 nop 80000114: 00000013 nop 80000118: 00000013 nop 8000011c: 00000013 nop 80000120: 00000013 nop 80000124: 00000013 nop 80000128: 00000013 nop 8000012c: 00000013 nop 80000130: 00000013 nop 80000134: 00000013 nop 80000138: 00000013 nop 8000013c: 00000013 nop 80000140: 00000297 auipc t0,0x0 80000144: 00a29a23 sh a0,20(t0) # 80000154 <reset_vector+0x108> 80000148: 00000297 auipc t0,0x0 8000014c: 00b29723 sh a1,14(t0) # 80000156 <reset_vector+0x10a> 80000150: 0000100f fence.i 80000154: 0de68693 addi a3,a3,222
80000158 <test_2>: 80000158: 00000013 nop 8000015c: 1bc00e93 li t4,444 80000160: 00200193 li gp,2 80000164: 07d69a63 bne a3,t4,800001d8 ... when pc = 80000164 , the CPU executes ”bne“ instruction , a3=111+222=333 , t4=444 , obviously a3 dosen't equal t4,so I can't pass "rv32ui-p-fence_i.dump" . My question is why is the test file designed this way? Why can't I pass the test? *
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/riscv/riscv-tests/issues/202?email_source=notifications&email_token=AAH3XQS3UBC4AYMAFPEGSGLQHS3IHA5CNFSM4IS2H5EKYY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4HIWY5JQ, or mute the thread https://github.com/notifications/unsubscribe-auth/AAH3XQXK6PF5OMDVEWAL7XDQHS3IHANCNFSM4IS2H5EA .
The first question
I have changed my design so that I-cache can be read and write. But when I ran the test file again, I found another problem:
......
80000100: 00002517 auipc a0,0x2
80000104: f0051503 lh a0,-256(a0) # 80002000 <begin_signature>
80000108: 00002597 auipc a1,0x2
8000010c: efa59583 lh a1,-262(a1) # 80002002 <begin_signature+0x2>
......
80000140: 00000297 auipc t0,0x0
80000144: 00a29a23 sh a0,20(t0) # 80000154 <reset_vector+0x108>
80000148: 00000297 auipc t0,0x0
8000014c: 00b29723 sh a1,14(t0) # 80000156 <reset_vector+0x10a>
80000150: 0000100f fence.i
80000154: 0de68693 addi a3,a3,222
80000158 <test_2>:
80000158: 00000013 nop
......
80002000 <begin_signature>:
80002000: 14d68693 addi a3,a3,333
-
When
PC=80000104
, CPU executed instructionlh a0,-256(a0) # 80002000 <begin_signature>
, when this instruction has been executed,a0
in regfile was updated toFFFF8693
. -
When
PC=80000144
, CPU executed instructionsh a0,20(t0) # 80000154 <reset_vector+0x108>
, when this instruction has been executed, the data in I-cache which address is80000154
was updated toFFFF8693
instead of14d68693
. -
My question is: should I change
80000104 lh
intolw
, and80000144 sh
intosw
, so that the instruction in80000154
can be updated to14d68693
rather thanFFFF8693
? Or did I make a mistake betweenLittle-Endian
andBig-Endian
? My CPU was designed inLittle-Endian
.
The second question
When I ran the test file rv32ui-p-sb.dump
, I met the same problem:
8000013c <test_4>:
8000013c: 00002097 auipc ra,0x2
80000140: ec408093 addi ra,ra,-316 # 80002000 <begin_signature>
80000144: fffff137 lui sp,0xfffff
80000148: fa010113 addi sp,sp,-96 # ffffefa0 <_end+0x7fffcf90>
8000014c: 00208123 sb sp,2(ra)
80000150: 00209f03 lh t5,2(ra)
80000154: fffffeb7 lui t4,0xfffff
80000158: fa0e8e93 addi t4,t4,-96 # ffffefa0 <_end+0x7fffcf90>
8000015c: 00400193 li gp,4
80000160: 39df1863 bne t5,t4,800004f0 <fail>
-
When
PC=8000014c
,sb
instruction write data insp/x2=ffffefa0
toaddress=80000200
, butsb
write the low 8bits to cache, and then signe-extened to 32bits. -
As a result, data in
80000200
isffffffa0
, so whenPC=80000160
, data int5
isffffffa0
which is not equal to data int4(ffffefa0)
, which means I cannot pass this test.
I want to know whether my design was wrong or the test file was wrong?
These tests are all known to be correct, so you have some bugs if they aren’t passing.
For example, sb only writes one byte of memory. It does not sign-extend then write four bytes.
On Wed, Sep 4, 2019 at 3:52 AM yuanbobo345 [email protected] wrote:
The first question
I have changed my design so that I-cache can be read and write. But when I ran the test file again, I found another problem:
...... 80000100: 00002517 auipc a0,0x2 80000104: f0051503 lh a0,-256(a0) # 80002000 <begin_signature> 80000108: 00002597 auipc a1,0x2 8000010c: efa59583 lh a1,-262(a1) # 80002002 <begin_signature+0x2> ...... 80000140: 00000297 auipc t0,0x0 80000144: 00a29a23 sh a0,20(t0) # 80000154 <reset_vector+0x108> 80000148: 00000297 auipc t0,0x0 8000014c: 00b29723 sh a1,14(t0) # 80000156 <reset_vector+0x10a> 80000150: 0000100f fence.i 80000154: 0de68693 addi a3,a3,222
80000158 <test_2>: 80000158: 00000013 nop ...... 80002000 <begin_signature>: 80002000: 14d68693 addi a3,a3,333
When PC=80000104, CPU executed instruction lh a0,-256(a0) # 80002000 <begin_signature>, when this instruction has been executed, a0 in regfile was updated to FFFF8693. 2.
When PC=80000144, CPU executed instruction sh a0,20(t0) # 80000154 <reset_vector+0x108>, when this instruction has been executed, the data in I-cache which address is 80000154 was updated to FFFF8693 instead of 14d68693. 3.
My question is: should I change 80000104 lh into lw, and 80000144 sh into sw, so that the instruction in 80000154 can be updated to 14d68693 rather than FFFF8693? Or did I make a mistake between Little-Endian and Big-Endian? My CPU was designed in Little-Endian.
The second question
When I ran the test file rv32ui-p-sb.dump, I met the same problem:
8000013c <test_4>: 8000013c: 00002097 auipc ra,0x2 80000140: ec408093 addi ra,ra,-316 # 80002000 <begin_signature> 80000144: fffff137 lui sp,0xfffff 80000148: fa010113 addi sp,sp,-96 # ffffefa0 <_end+0x7fffcf90> 8000014c: 00208123 sb sp,2(ra) 80000150: 00209f03 lh t5,2(ra) 80000154: fffffeb7 lui t4,0xfffff 80000158: fa0e8e93 addi t4,t4,-96 # ffffefa0 <_end+0x7fffcf90> 8000015c: 00400193 li gp,4 80000160: 39df1863 bne t5,t4,800004f0
When PC=8000014c, sb instruction write data in sp/x2=ffffefa0 to address=80000200, but sb write the low 8bits to cache, and then signe-extened to 32bits. 2.
As a result, data in 80000200 is ffffffa0, so when PC=80000160, data in t5 is ffffffa0 which is not equal to data in t4(ffffefa0), which means I cannot pass this test.
I want to know whether my design was wrong or the test file was wrong?
— You are receiving this because you commented.
Reply to this email directly, view it on GitHub https://github.com/riscv/riscv-tests/issues/202?email_source=notifications&email_token=AAH3XQVSCDSEA6B2VIJP74LQH6HPPA5CNFSM4IS2H5EKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD53FPTI#issuecomment-527849421, or mute the thread https://github.com/notifications/unsubscribe-auth/AAH3XQQSMJU47UDMCCWFRT3QH6HPPANCNFSM4IS2H5EA .
After reading riscv-spec.pdf
carefully, I found sb, sh
does not sign-extend before writing to memory.
But in my first question, lh
load a 16-bit value from memory indeed, then sign-extended to 32bits before storing it.
So how the instruction in pc=80000154
can be updated to the new instruction 80002000: 14d68693 addi a3,a3,333
with 80000104: f0051503 lh a0,-256(a0)
and 80000144: 00a29a23 sh a0,20(t0)
?
In my design, it only change the low 16bits value of instruction in pc= 80000154
, and it is updated to 0de68693
as the low 16bits are the same with the instruction in 80002000: 14d68693 addi a3,a3,333
.
I recommend using a simulator that executes these tests correctly (e.g. Spike) to see how the test runs.
On Wed, Sep 4, 2019 at 6:21 AM yuanbobo345 [email protected] wrote:
After reading riscv-spec.pdf carefully, I found sb, sh does not sign-extend before writing to memory.
But in my first question, lh load a 16-bit value from memory indeed, then sign-extended to 32bits before storing it.
So how the instruction in pc=80000154 can be updated to the new instruction 80002000: 14d68693 addi a3,a3,333 with 80000104: f0051503 lh a0,-256(a0) and 80000144: 00a29a23 sh a0,20(t0) ?
In my design, it only change the low 16bits value of instruction in pc= 80000154, and it is updated to 0de68693 as the low 16bits are the same with the instruction in 80002000: 14d68693 addi a3,a3,333.
— You are receiving this because you commented.
Reply to this email directly, view it on GitHub https://github.com/riscv/riscv-tests/issues/202?email_source=notifications&email_token=AAH3XQUKB6RHGTE7SFILEB3QH6Y5VA5CNFSM4IS2H5EKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD53RJXA#issuecomment-527897820, or mute the thread https://github.com/notifications/unsubscribe-auth/AAH3XQVPC6T6SKR7RBRSQYTQH6Y5VANCNFSM4IS2H5EA .
@aswaterman Thank you. I will try this with Spike.
I don't think that this test can succeed if it is executing from read-only memory, because instructions in a read-only .text
section cannot be written to.
Would it be possible to place the self-modifying instructions in the .data
section and execute them from there, or is it expected that this test file will be compiled such that the .text
section goes into a memory space that is both executable and writable?
Even if the tests aren't running from ROM, I think it's pretty common for microcontrollers to guard against unprotected writes to Flash memory in ways that might prevent naive "Store" instruction from successfully writing to NVM.