riscv-tests icon indicating copy to clipboard operation
riscv-tests copied to clipboard

ERROR in using "rv32ui-p-fence_i.dump" test file

Open Y-BoBo opened this issue 5 years ago • 11 comments

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?

Y-BoBo avatar Sep 02 '19 07:09 Y-BoBo

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.

a0u avatar Sep 02 '19 07:09 a0u

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 into addi 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!

Y-BoBo avatar Sep 02 '19 08:09 Y-BoBo

The test is written correctly as is. To further explain how it works:

  1. Two lh instructions load the new instruction bits from the memory location labeled by insn (addi a3, a3, 333).
  2. Two sh instructions then overwrite the 32-bit word that contains addi a3, a3, 222.
  3. 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 of fence.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.

a0u avatar Sep 02 '19 10:09 a0u

Thank you again. I deeply understood the real meaning of this test file through your answer.

Y-BoBo avatar Sep 02 '19 12:09 Y-BoBo

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 .

aswaterman avatar Sep 02 '19 22:09 aswaterman

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
  1. 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 <fail>
  1. 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?

Y-BoBo avatar Sep 04 '19 10:09 Y-BoBo

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 .

aswaterman avatar Sep 04 '19 12:09 aswaterman

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.

Y-BoBo avatar Sep 04 '19 13:09 Y-BoBo

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 avatar Sep 04 '19 14:09 aswaterman

@aswaterman Thank you. I will try this with Spike.

Y-BoBo avatar Sep 04 '19 15:09 Y-BoBo

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.

WRansohoff avatar Mar 18 '20 19:03 WRansohoff