forked from Github_Repos/cvw
		
	
		
			
				
	
	
		
			287 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			287 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/python3
 | |
| ##################################
 | |
| # testgen-JAL.py
 | |
| #
 | |
| # Ben Bracker (bbracker@hmc.edu) 19 January 2021
 | |
| # Based on testgen-ADD-SUB.py by David Harris
 | |
| #
 | |
| # Generate directed and random test vectors for RISC-V Design Validation.
 | |
| ##################################
 | |
| 
 | |
| ##################################
 | |
| # libraries
 | |
| ##################################
 | |
| from datetime import datetime
 | |
| from random import randint
 | |
| from random import choice
 | |
| from random import seed
 | |
| from random import getrandbits
 | |
| from copy import deepcopy
 | |
| 
 | |
| ##################################
 | |
| # helper functions
 | |
| ##################################
 | |
| def InitTestGroup():
 | |
|   global TestGroup,TestGroupSizes,AllRegs,UnusedRegs,StoreAdrReg
 | |
|   TestGroup += 1
 | |
|   TestGroupSizes.append(0)
 | |
|   UnusedRegs = deepcopy(AllRegs)
 | |
|   oldStoreAdrReg = StoreAdrReg
 | |
|   while ((StoreAdrReg == oldStoreAdrReg) or (StoreAdrReg == 0) or (StoreAdrReg == 31)):
 | |
|     StoreAdrReg = choice(UnusedRegs)
 | |
|   UnusedRegs.remove(StoreAdrReg)
 | |
|   f.write("\n    # ---------------------------------------------------------------------------------------------\n")
 | |
|   f.write("    # new register for address of test results\n")
 | |
|   addInst("    la x"+str(StoreAdrReg)+", test_1_res\n")
 | |
|   f.write("    # ---------------------------------------------------------------------------------------------\n")
 | |
| 
 | |
| def registerSelect():
 | |
|   # ensures that rd experiences all possible registers
 | |
|   # *** does not yet ensure that rs experiences all possible registers
 | |
|   # ensures that at least once rd = rs
 | |
|   global UnusedRegs
 | |
|   if len(UnusedRegs)==0: 
 | |
|     InitTestGroup()
 | |
|   rd = choice(UnusedRegs)
 | |
|   UnusedRegs.remove(rd)
 | |
|   OtherRegs = deepcopy(UnusedRegs)
 | |
|   if 0 in OtherRegs: 
 | |
|     OtherRegs.remove(0)
 | |
|   if len(OtherRegs) == 0:
 | |
|     OtherRegs = deepcopy(AllRegs)
 | |
|     OtherRegs.remove(0)
 | |
|   rs = choice(OtherRegs)
 | |
|   OtherRegs = deepcopy(AllRegs)
 | |
|   OtherRegs.remove(StoreAdrReg)
 | |
|   OtherRegs.remove(rd)
 | |
|   if 0 in OtherRegs: 
 | |
|     OtherRegs.remove(0)
 | |
|   if rs in OtherRegs: 
 | |
|     OtherRegs.remove(rs)
 | |
|   DataReg = choice(OtherRegs)
 | |
|   OtherRegs.remove(DataReg)
 | |
|   OtherRd = choice(OtherRegs)
 | |
|   return (rd,rs,DataReg,OtherRd)
 | |
| 
 | |
| def addInst(line):
 | |
|   global CurrAdr
 | |
|   f.write(line)
 | |
|   if ("li x" in line) and ("slli x" not in line):
 | |
|     CurrAdr += 8 if (xlen == 32) else 20
 | |
|   elif ("la x" in line):
 | |
|     CurrAdr += 8
 | |
|   else:
 | |
|     CurrAdr += 4
 | |
| 
 | |
| def expectValue(expectReg, expectVal, sigOffset):
 | |
|   global TestGroupSizes
 | |
|   TestGroupSizes[TestGroup-1] += 1
 | |
|   addInst("    "+storecmd+" x"+str(expectReg)+", "+str(wordsize*sigOffset)+"(x"+str(StoreAdrReg)+")\n")
 | |
|   f.write("    RVTEST_IO_ASSERT_GPR_EQ(x"+str(StoreAdrReg+1)+", x"+str(expectReg)+", "+formatstr.format(expectVal)+")\n")
 | |
|   if (xlen == 32):
 | |
|     r.write(formatrefstr.format(expectVal)+"\n")
 | |
|   else:
 | |
|     r.write(formatrefstr.format(expectVal % 2**32)+"\n" + formatrefstr.format(expectVal >> 32)+"\n")
 | |
| 
 | |
| def addJalr(rs,rd,dist):
 | |
|   target = CurrAdr + 20 + dist
 | |
|   target31_12 = CurrAdr >> 12 # 20 bits for lui
 | |
|   target11_0 = target - (target31_12 << 12) # 12 remaining bits
 | |
|   target31_16 = target31_12 >> 4 # lui sign extends, so shift in a leading 0
 | |
|   target15_12 = target31_12 - (target31_16 << 4) # the nibble we just lost
 | |
|   if target11_0 > 0:
 | |
|     offset = randint(-(1<<11)-1,(1<<11)-2-target11_0)
 | |
|   else:
 | |
|     offset = randint(-(1<<11)-1-target11_0,(1<<11)-2)
 | |
|   addInst("    lui x"+str(rs)+", 0x"+imm20formatstr.format(target31_16)+"\n")
 | |
|   addInst("    addi x"+str(rs)+", x"+str(rs)+", SEXT_IMM(0x0"+imm12formatstr.format(target15_12 << 8)+")\n")
 | |
|   addInst("    slli x"+str(rs)+", x"+str(rs)+", SEXT_IMM(4)\n") 
 | |
|   addInst("    addi x"+str(rs)+", x"+str(rs)+", SEXT_IMM(0x"+imm12formatstr.format(0xfff&(offset+target11_0+randint(0,1)))+")\n")
 | |
|   addInst("    JALR x"+str(rd)+", x"+str(rs)+", SEXT_IMM(0x"+imm12formatstr.format(0xfff&(-offset))+")\n")
 | |
| 
 | |
| ##################################
 | |
| # test functions
 | |
| ##################################
 | |
| def writeForwardsJumpVector(spacers,instr):
 | |
|   global TestNum
 | |
|   TestNum += 1
 | |
|   rd, rs, DataReg, OtherRd = registerSelect()
 | |
|   # Header
 | |
|   f.write("\n")
 | |
|   f.write("    # Testcase "+str(TestNum)+"\n")
 | |
|   # Test Code
 | |
|   addInst("    li x"+str(DataReg)+", "+formatstr.format(expected)+"\n")
 | |
|   if (instr=="JAL"):
 | |
|     addInst("    JAL x"+str(rd)+", 1f\n")
 | |
|   elif (instr=="JALR"):
 | |
|     dist = spacers*(8 if (xlen == 32) else 20) # Compute distance from linked adr to target adr
 | |
|     addJalr(rs,rd,dist);
 | |
|   else:
 | |
|     exit("invalid instruction") 
 | |
|   LinkAdr = CurrAdr if (rd!=0) else 0 # rd's expected value
 | |
|   for i in range(spacers):
 | |
|     addInst("    li x"+str(DataReg)+", "+formatstr.format(unexpected)+"\n")
 | |
|   f.write("1:\n")
 | |
|   # Store values to be verified
 | |
|   expectValue(rd, LinkAdr, 2*TestNum+0)
 | |
|   expectValue(DataReg, expected, 2*TestNum+1)
 | |
| 
 | |
| def writeBackwardsJumpVector(spacers,instr):
 | |
|   global TestNum
 | |
|   TestNum += 1
 | |
|   rd, rs, DataReg, OtherRd = registerSelect()
 | |
|   # Header
 | |
|   f.write("\n")
 | |
|   f.write("    # Testcase "+str(TestNum)+"\n")
 | |
|   # Test Code
 | |
|   addInst("    JAL x"+str(OtherRd)+", 2f\n")
 | |
|   f.write("1:\n")
 | |
|   addInst("    li x"+str(DataReg)+", "+formatstr.format(expected)+"\n")
 | |
|   addInst("    JAL x"+str(OtherRd)+", 3f\n")
 | |
|   f.write("2:\n")
 | |
|   for i in range(spacers):
 | |
|     addInst("    li x"+str(DataReg)+", "+formatstr.format(unexpected)+"\n")
 | |
|   if (instr=="JAL"):
 | |
|     addInst("    JAL x"+str(rd)+", 1b\n")
 | |
|   elif (instr=="JALR"):
 | |
|     dist = -20 - 4 - (1+spacers)*(8 if (xlen == 32) else 20) # Compute distance from linked adr to target adr
 | |
|     addJalr(rs,rd,dist);
 | |
|   else:
 | |
|     exit("invalid instruction") 
 | |
|   LinkAdr = CurrAdr if (rd!=0) else 0 # rd's expected value
 | |
|   f.write("3:\n")
 | |
|   # Store values to be verified
 | |
|   expectValue(rd, LinkAdr, 2*TestNum+0)
 | |
|   expectValue(DataReg, expected, 2*TestNum+1)
 | |
| 
 | |
| def writeChainVector(repetitions,spacers):
 | |
|   global TestNum
 | |
|   TestNum += 1
 | |
|   rd, rs, DataReg,OtherRd = registerSelect()
 | |
|   # Header
 | |
|   f.write("\n")
 | |
|   f.write("    # Testcase "+str(TestNum)+"\n")
 | |
|   # Test Code
 | |
|   addInst("    li x"+str(DataReg)+", "+formatstr.format(expected)+"\n")
 | |
|   for i in range(repetitions):
 | |
|     addInst("    JAL x"+str(OtherRd)+", "+str(3*i+2)+"f\n")
 | |
|     if spacers:
 | |
|       for j in range(i):
 | |
|         addInst("    li x"+str(DataReg)+", "+formatstr.format(unexpected)+"\n")
 | |
|     f.write(str(3*i+1)+":\n")
 | |
|     addInst("    JAL x"+str(OtherRd)+", "+str(3*i+3)+"f\n")
 | |
|     if spacers:
 | |
|       for j in range(i):
 | |
|         addInst("    li x"+str(DataReg)+", "+formatstr.format(unexpected)+"\n")
 | |
|     f.write(str(3*i+2)+":\n")
 | |
|     addInst("    JAL x"+str(rd)+", "+str(3*i+1)+"b\n")
 | |
|     LinkAdr = CurrAdr if (rd!=0) else 0 # rd's expected value
 | |
|     if spacers:
 | |
|       for j in range(i):
 | |
|         addInst("    li x"+str(DataReg)+", "+formatstr.format(unexpected)+"\n")
 | |
|     f.write(str(3*i+3)+":\n")
 | |
|   # Store values to be verified
 | |
|   expectValue(rd, LinkAdr, 2*TestNum+0)
 | |
|   expectValue(DataReg, expected, 2*TestNum+1)
 | |
| 
 | |
| ##################################
 | |
| # main body
 | |
| ##################################
 | |
| 
 | |
| # change these to suite your tests
 | |
| test = 0
 | |
| tests = ["JAL","JALR"]
 | |
| author = "Ben Bracker (bbracker@hmc.edu)"
 | |
| xlens = [32,64]
 | |
| numtests = 100
 | |
| 
 | |
| # setup
 | |
| seed(0) # make tests reproducible
 | |
| 
 | |
| # generate files for each test
 | |
| for test in tests:
 | |
|   for xlen in xlens:
 | |
|     print(test+" "+str(xlen))
 | |
|     CurrAdr = int("80000108",16)
 | |
|     TestNum = -1
 | |
|     TestGroup = 1
 | |
|     TestGroupSizes = [0]
 | |
|     AllRegs = list(range(0,32))
 | |
|     UnusedRegs = deepcopy(AllRegs) 
 | |
|     StoreAdrReg = 6 # matches what's in header script 
 | |
|     UnusedRegs.remove(6)
 | |
|     if (xlen==64):
 | |
|       expected = int("fedbca9876540000",16)
 | |
|       unexpected = int("ffff0000ffff0000",16)
 | |
|     else:
 | |
|       expected = int("fedbca98",16)
 | |
|       unexpected = int("ff00ff00",16)
 | |
| 
 | |
|     formatstrlen = str(int(xlen/4))
 | |
|     formatstr = "0x{:0" + formatstrlen + "x}" # format as xlen-bit hexadecimal number
 | |
|     formatrefstr = "{:08x}" # format as xlen-bit hexadecimal number with no leading 0x
 | |
|     imm20formatstr = "{:05x}"
 | |
|     imm12formatstr = "{:03x}"
 | |
| 
 | |
|     if (xlen == 32):
 | |
|       storecmd = "sw"
 | |
|       wordsize = 4
 | |
|     else:
 | |
|       storecmd = "sd"
 | |
|       wordsize = 8
 | |
| 
 | |
|     imperaspath = "../../imperas-riscv-tests/riscv-test-suite/rv" + str(xlen) + "i/"
 | |
|     basename = "WALLY-" + test 
 | |
|     fname = imperaspath + "src/" + basename + ".S"
 | |
|     refname = imperaspath + "references/" + basename + ".reference_output"
 | |
| 
 | |
|     # print custom header part
 | |
|     f = open(fname, "w")
 | |
|     r = open(refname, "w")
 | |
|     f.write("///////////////////////////////////////////\n")
 | |
|     f.write("// "+fname+ "\n")
 | |
|     f.write("//\n")
 | |
|     f.write("// This file can be used to test the RISC-V JAL(R) instruction.\n")
 | |
|     f.write("// But be warned that altering the test environment may break this test!\n")
 | |
|     f.write("// In order to work, this test expects that the first instruction (la)\n")
 | |
|     f.write("// be allocated at 0x80000100.\n")
 | |
|     f.write("//\n")
 | |
|     f.write("// " + author + "\n")
 | |
|     f.write("// Created "+str(datetime.now())+"\n") 
 | |
|     
 | |
|     # insert generic header
 | |
|     h = open("testgen_header.S", "r")
 | |
|     for line in h:  
 | |
|       f.write(line)
 | |
| 
 | |
|     # print directed test vectors
 | |
|     if test == "JAL":
 | |
|       for i in range(0,31):
 | |
|         writeForwardsJumpVector(randint(0,4),"JAL")
 | |
|       for i in range(0,31):
 | |
|         writeBackwardsJumpVector(randint(0,4),"JAL")
 | |
|       writeForwardsJumpVector(100,"JAL")
 | |
|       writeBackwardsJumpVector(100,"JAL")
 | |
|       writeChainVector(6,True)
 | |
|       writeChainVector(16,False)
 | |
|     elif test == "JALR":
 | |
|       for i in range(0,31):
 | |
|         writeForwardsJumpVector(randint(0,4),"JALR")
 | |
|       for i in range(0,31):
 | |
|         writeBackwardsJumpVector(randint(0,4),"JALR")
 | |
|       # can't make these latter two too long else 12 bit immediate overflows
 | |
|       # (would need to lui or slli rs to achieve longer ranges)
 | |
|       writeForwardsJumpVector(15,"JALR")
 | |
|       writeBackwardsJumpVector(15,"JALR")
 | |
| 
 | |
|     # print footer
 | |
|     h = open("testgen_footer.S", "r")
 | |
|     for line in h:  
 | |
|       f.write(line)
 | |
| 
 | |
|     # Finish
 | |
|     f.write(".fill "+str(sum(TestGroupSizes))+", "+str(wordsize)+", -1\n")
 | |
|     f.write("\nRV_COMPLIANCE_DATA_END\n")
 | |
|     f.close()
 | |
|     r.close()
 |