mirror of
				https://github.com/openhwgroup/cvw
				synced 2025-02-11 06:05:49 +00:00 
			
		
		
		
	Renamed testbench_imperas.sv to testbench-imperas.sv
This commit is contained in:
		
							parent
							
								
									c1d6fddea8
								
							
						
					
					
						commit
						8d4cdcbd1a
					
				| @ -27,7 +27,7 @@ | |||||||
| `include "config.vh" | `include "config.vh" | ||||||
| import cvw::*; | import cvw::*; | ||||||
| 
 | 
 | ||||||
| `define DEBUG_TRACE 0 | `define DEBUG_TRACE 1 | ||||||
| // Debug Levels
 | // Debug Levels
 | ||||||
| // 0: don't check against QEMU
 | // 0: don't check against QEMU
 | ||||||
| // 1: print disagreements with QEMU, but only halt on PCW disagreements
 | // 1: print disagreements with QEMU, but only halt on PCW disagreements
 | ||||||
|  | |||||||
| @ -1,369 +0,0 @@ | |||||||
| ///////////////////////////////////////////
 |  | ||||||
| // testbench.sv
 |  | ||||||
| //
 |  | ||||||
| // Written: David_Harris@hmc.edu 9 January 2021
 |  | ||||||
| // Modified: 
 |  | ||||||
| //
 |  | ||||||
| // Purpose: Wally Testbench and helper modules
 |  | ||||||
| //          Applies test programs from the riscv-arch-test and Imperas suites
 |  | ||||||
| // 
 |  | ||||||
| // A component of the Wally configurable RISC-V project.
 |  | ||||||
| // 
 |  | ||||||
| // Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
 |  | ||||||
| //
 |  | ||||||
| // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
 |  | ||||||
| //
 |  | ||||||
| // Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file 
 |  | ||||||
| // except in compliance with the License, or, at your option, the Apache License version 2.0. You 
 |  | ||||||
| // may obtain a copy of the License at
 |  | ||||||
| //
 |  | ||||||
| // https://solderpad.org/licenses/SHL-2.1/
 |  | ||||||
| //
 |  | ||||||
| // Unless required by applicable law or agreed to in writing, any work 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.
 |  | ||||||
| ////////////////////////////////////////////////////////////////////////////////////////////////
 |  | ||||||
| 
 |  | ||||||
| `include "config.vh" |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| // This is set from the command line script
 |  | ||||||
| // `define USE_IMPERAS_DV
 |  | ||||||
| 
 |  | ||||||
| `ifdef USE_IMPERAS_DV |  | ||||||
|   `include "idv/idv.svh" |  | ||||||
| `endif |  | ||||||
| 
 |  | ||||||
| import cvw::*; |  | ||||||
| 
 |  | ||||||
| module testbench; |  | ||||||
|   parameter DEBUG=0; |  | ||||||
| 
 |  | ||||||
| `ifdef USE_IMPERAS_DV |  | ||||||
|   import idvPkg::*; |  | ||||||
|   import rvviApiPkg::*; |  | ||||||
|   import idvApiPkg::*; |  | ||||||
| `endif |  | ||||||
| 
 |  | ||||||
|   `include "parameter-defs.vh" |  | ||||||
| 
 |  | ||||||
|   logic        clk; |  | ||||||
|   logic        reset_ext, reset; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|   logic [P.XLEN-1:0] testadr, testadrNoBase; |  | ||||||
|   string InstrFName, InstrDName, InstrEName, InstrMName, InstrWName; |  | ||||||
|   logic [31:0] InstrW; |  | ||||||
| 
 |  | ||||||
|   logic [3:0]  dummy; |  | ||||||
| 
 |  | ||||||
|   logic [P.AHBW-1:0] HRDATAEXT; |  | ||||||
|   logic             HREADYEXT, HRESPEXT; |  | ||||||
|   logic             HSELEXTSDC; |  | ||||||
|   logic [P.PA_BITS-1:0] HADDR; |  | ||||||
|   logic [P.AHBW-1:0] HWDATA; |  | ||||||
|   logic [P.XLEN/8-1:0] HWSTRB; |  | ||||||
|   logic             HWRITE; |  | ||||||
|   logic [2:0]       HSIZE; |  | ||||||
|   logic [2:0]       HBURST; |  | ||||||
|   logic [3:0]       HPROT; |  | ||||||
|   logic [1:0]       HTRANS; |  | ||||||
|   logic             HMASTLOCK; |  | ||||||
|   logic             HCLK, HRESETn; |  | ||||||
|   logic [P.XLEN-1:0] PCW; |  | ||||||
| 
 |  | ||||||
|   string ProgramAddrMapFile, ProgramLabelMapFile; |  | ||||||
|   integer   	ProgramAddrLabelArray [string] = '{ "begin_signature" : 0, "tohost" : 0 }; |  | ||||||
|   logic 	    DCacheFlushDone, DCacheFlushStart; |  | ||||||
|   string 		testName; |  | ||||||
|   string memfilename, testDir, adrstr, elffilename; |  | ||||||
| 
 |  | ||||||
|   logic [31:0] GPIOIN, GPIOOUT, GPIOEN; |  | ||||||
|   logic        UARTSin, UARTSout; |  | ||||||
| 
 |  | ||||||
|   logic        SDCIntr; |  | ||||||
| 
 |  | ||||||
|   logic        HREADY; |  | ||||||
|   logic        HSELEXT; |  | ||||||
|    |  | ||||||
|   logic             InitializingMemories; |  | ||||||
|   integer           ResetCount, ResetThreshold; |  | ||||||
|   logic             InReset; |  | ||||||
| 
 |  | ||||||
|   // Imperas look here.
 |  | ||||||
|   initial |  | ||||||
|     begin |  | ||||||
|       ResetCount = 0; |  | ||||||
|       ResetThreshold = 2; |  | ||||||
|       InReset = 1; |  | ||||||
|       testadr = 0; |  | ||||||
|       testadrNoBase = 0; |  | ||||||
| 
 |  | ||||||
|       if ($value$plusargs("testDir=%s", testDir)) begin |  | ||||||
|           memfilename = {testDir, "/ref/ref.elf.memfile"}; |  | ||||||
|           elffilename = {testDir, "/ref/ref.elf"}; |  | ||||||
|           $display($sformatf("%m @ t=%0t: loading testDir %0s", $time, testDir)); |  | ||||||
|       end else begin |  | ||||||
|           $error("Must specify test directory using plusarg testDir"); |  | ||||||
|       end |  | ||||||
| 
 |  | ||||||
|       if (P.BUS_SUPPORTED) $readmemh(memfilename, dut.uncore.uncore.ram.ram.memory.RAM); |  | ||||||
| 	  else $error("Imperas test bench requires BUS."); |  | ||||||
| 
 |  | ||||||
|       ProgramAddrMapFile = {testDir, "/ref/ref.elf.objdump.addr"}; |  | ||||||
|       ProgramLabelMapFile = {testDir, "/ref/ref.elf.objdump.lab"}; |  | ||||||
|        |  | ||||||
|       // declare memory labels that interest us, the updateProgramAddrLabelArray task will find the addr of each label and fill the array
 |  | ||||||
|       // to expand, add more elements to this array and initialize them to zero (also initilaize them to zero at the start of the next test)
 |  | ||||||
|       updateProgramAddrLabelArray(ProgramAddrMapFile, ProgramLabelMapFile, ProgramAddrLabelArray); |  | ||||||
|       $display("Read memfile %s", memfilename); |  | ||||||
|        |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
| `ifdef USE_IMPERAS_DV |  | ||||||
| 
 |  | ||||||
|     rvviTrace #(.XLEN(P.XLEN), .FLEN(P.FLEN)) rvvi(); |  | ||||||
|     wallyTracer #(P) wallyTracer(rvvi); |  | ||||||
| 
 |  | ||||||
|     trace2log idv_trace2log(rvvi); |  | ||||||
|     trace2cov idv_trace2cov(rvvi); |  | ||||||
| 
 |  | ||||||
|     // enabling of comparison types
 |  | ||||||
|     trace2api #(.CMP_PC      (1), |  | ||||||
|                 .CMP_INS     (1), |  | ||||||
|                 .CMP_GPR     (1), |  | ||||||
|                 .CMP_FPR     (1), |  | ||||||
|                 .CMP_VR      (0), |  | ||||||
|                 .CMP_CSR     (1) |  | ||||||
|                ) idv_trace2api(rvvi); |  | ||||||
| 
 |  | ||||||
|     initial begin  |  | ||||||
|        |  | ||||||
|       IDV_MAX_ERRORS = 3; |  | ||||||
| 
 |  | ||||||
|       // Initialize REF (do this before initializing the DUT)
 |  | ||||||
|       if (!rvviVersionCheck(RVVI_API_VERSION)) begin |  | ||||||
|         $display($sformatf("%m @ t=%0t: Expecting RVVI API version %0d.", $time, RVVI_API_VERSION)); |  | ||||||
|         $fatal; |  | ||||||
|       end |  | ||||||
|       void'(rvviRefConfigSetString(IDV_CONFIG_MODEL_VENDOR,            "riscv.ovpworld.org")); |  | ||||||
|       void'(rvviRefConfigSetString(IDV_CONFIG_MODEL_NAME,              "riscv")); |  | ||||||
|       void'(rvviRefConfigSetString(IDV_CONFIG_MODEL_VARIANT,           "RV64GC")); |  | ||||||
|       void'(rvviRefConfigSetInt(IDV_CONFIG_MODEL_ADDRESS_BUS_WIDTH,     39)); |  | ||||||
|       void'(rvviRefConfigSetInt(IDV_CONFIG_MAX_NET_LATENCY_RETIREMENTS, 6)); |  | ||||||
| 
 |  | ||||||
|       if (!rvviRefInit(elffilename)) begin |  | ||||||
|         $display($sformatf("%m @ t=%0t: rvviRefInit failed", $time)); |  | ||||||
|         $fatal; |  | ||||||
|       end |  | ||||||
| 
 |  | ||||||
|       // Volatile CSRs
 |  | ||||||
|       void'(rvviRefCsrSetVolatile(0, 32'hC00));   // CYCLE
 |  | ||||||
|       void'(rvviRefCsrSetVolatile(0, 32'hB00));   // MCYCLE
 |  | ||||||
|       void'(rvviRefCsrSetVolatile(0, 32'hC02));   // INSTRET
 |  | ||||||
|       void'(rvviRefCsrSetVolatile(0, 32'hB02));   // MINSTRET
 |  | ||||||
|       void'(rvviRefCsrSetVolatile(0, 32'hC01));   // TIME
 |  | ||||||
|        |  | ||||||
|       // cannot predict this register due to latency between
 |  | ||||||
|       // pending and taken
 |  | ||||||
|       void'(rvviRefCsrSetVolatile(0, 32'h344));   // MIP
 |  | ||||||
|       void'(rvviRefCsrSetVolatile(0, 32'h144));   // SIP
 |  | ||||||
| 
 |  | ||||||
|       // Privileges for PMA are set in the imperas.ic
 |  | ||||||
|       // volatile (IO) regions are defined here
 |  | ||||||
|       // only real ROM/RAM areas are BOOTROM and UNCORE_RAM
 |  | ||||||
|       if (P.CLINT_SUPPORTED) begin |  | ||||||
|           void'(rvviRefMemorySetVolatile(P.CLINT_BASE, (P.CLINT_BASE + P.CLINT_RANGE))); |  | ||||||
|       end |  | ||||||
|       if (P.GPIO_SUPPORTED) begin |  | ||||||
|           void'(rvviRefMemorySetVolatile(P.GPIO_BASE, (P.GPIO_BASE + P.GPIO_RANGE))); |  | ||||||
|       end |  | ||||||
|       if (P.UART_SUPPORTED) begin |  | ||||||
|           void'(rvviRefMemorySetVolatile(P.UART_BASE, (P.UART_BASE + P.UART_RANGE))); |  | ||||||
|       end |  | ||||||
|       if (P.PLIC_SUPPORTED) begin |  | ||||||
|           void'(rvviRefMemorySetVolatile(P.PLIC_BASE, (P.PLIC_BASE + P.PLIC_RANGE))); |  | ||||||
|       end |  | ||||||
|       if (P.SDC_SUPPORTED) begin |  | ||||||
|           void'(rvviRefMemorySetVolatile(P.SDC_BASE, (P.SDC_BASE + P.SDC_RANGE))); |  | ||||||
|       end |  | ||||||
| 
 |  | ||||||
|       if(P.XLEN==32) begin |  | ||||||
|           void'(rvviRefCsrSetVolatile(0, 32'hC80));   // CYCLEH
 |  | ||||||
|           void'(rvviRefCsrSetVolatile(0, 32'hB80));   // MCYCLEH
 |  | ||||||
|           void'(rvviRefCsrSetVolatile(0, 32'hC82));   // INSTRETH
 |  | ||||||
|           void'(rvviRefCsrSetVolatile(0, 32'hB82));   // MINSTRETH
 |  | ||||||
|       end |  | ||||||
| 
 |  | ||||||
|       void'(rvviRefCsrSetVolatile(0, 32'h104));   // SIE - Temporary!!!!
 |  | ||||||
|        |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     always @(dut.core.MTimerInt)   void'(rvvi.net_push("MTimerInterrupt",    dut.core.MTimerInt)); |  | ||||||
|     always @(dut.core.MExtInt)     void'(rvvi.net_push("MExternalInterrupt", dut.core.MExtInt)); |  | ||||||
|     always @(dut.core.SExtInt)     void'(rvvi.net_push("SExternalInterrupt", dut.core.SExtInt)); |  | ||||||
|     always @(dut.core.MSwInt)      void'(rvvi.net_push("MSWInterrupt",       dut.core.MSwInt)); |  | ||||||
|     always @(dut.core.priv.priv.csr.csrs.csrs.STimerInt) void'(rvvi.net_push("STimerInterrupt", dut.core.priv.priv.csr.csrs.csrs.STimerInt)); |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     final begin |  | ||||||
|       void'(rvviRefShutdown()); |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
| `endif |  | ||||||
| 
 |  | ||||||
|   flopenr #(P.XLEN) PCWReg(clk, reset, ~dut.core.ieu.dp.StallW, dut.core.ifu.PCM, PCW); |  | ||||||
|   flopenr  #(32)   InstrWReg(clk, reset, ~dut.core.ieu.dp.StallW,  dut.core.ifu.InstrM, InstrW); |  | ||||||
| 
 |  | ||||||
|   // check assertions for a legal configuration
 |  | ||||||
|   riscvassertions #(P) riscvassertions(); |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|   // instantiate device to be tested
 |  | ||||||
|   assign GPIOIN = 0; |  | ||||||
|   assign UARTSin = 1; |  | ||||||
| 
 |  | ||||||
|   if(P.EXT_MEM_SUPPORTED) begin |  | ||||||
|     ram_ahb #(.BASE(P.EXT_MEM_BASE), .RANGE(P.EXT_MEM_RANGE))  |  | ||||||
|     ram (.HCLK, .HRESETn, .HADDR, .HWRITE, .HTRANS, .HWDATA, .HSELRam(HSELEXT),  |  | ||||||
|          .HREADRam(HRDATAEXT), .HREADYRam(HREADYEXT), .HRESPRam(HRESPEXT), .HREADY, |  | ||||||
|          .HWSTRB); |  | ||||||
|   end else begin  |  | ||||||
|     assign HREADYEXT = 1; |  | ||||||
|     assign HRESPEXT = 0; |  | ||||||
|     assign HRDATAEXT = 0; |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   if(P.FPGA) begin : sdcard |  | ||||||
|     // *** fix later
 |  | ||||||
| /* -----\/----- EXCLUDED -----\/----- |  | ||||||
|     sdModel sdcard |  | ||||||
|       (.sdClk(SDCCLK), |  | ||||||
|        .cmd(SDCCmd),  |  | ||||||
|        .dat(SDCDat)); |  | ||||||
| 
 |  | ||||||
|     assign SDCCmd = SDCCmdOE ? SDCCmdOut : 1'bz; |  | ||||||
|     assign SDCCmdIn = SDCCmd; |  | ||||||
|     assign SDCDatIn = SDCDat; |  | ||||||
|  -----/\----- EXCLUDED -----/\----- */ |  | ||||||
|     assign SDCIntr = '0; |  | ||||||
|   end else begin |  | ||||||
|     assign SDCIntr = '0; |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   wallypipelinedsoc #(P) dut(.clk, .reset_ext, .reset, .HRDATAEXT, .HREADYEXT, .HRESPEXT, .HSELEXT, .HSELEXTSDC, |  | ||||||
|                         .HCLK, .HRESETn, .HADDR, .HWDATA, .HWSTRB, .HWRITE, .HSIZE, .HBURST, .HPROT, |  | ||||||
|                         .HTRANS, .HMASTLOCK, .HREADY, .TIMECLK(1'b0), .GPIOIN, .GPIOOUT, .GPIOEN, |  | ||||||
|                         .UARTSin, .UARTSout, .SDCIntr);  |  | ||||||
| 
 |  | ||||||
|   // Track names of instructions
 |  | ||||||
|   instrTrackerTB it(clk, reset, dut.core.ieu.dp.FlushE, |  | ||||||
|                 dut.core.ifu.InstrRawF[31:0], |  | ||||||
|                 dut.core.ifu.InstrD, dut.core.ifu.InstrE, |  | ||||||
|                 dut.core.ifu.InstrM,  InstrW, |  | ||||||
|                 InstrFName, InstrDName, InstrEName, InstrMName, InstrWName); |  | ||||||
| 
 |  | ||||||
|   // initialize tests
 |  | ||||||
| 
 |  | ||||||
|   // generate clock to sequence tests
 |  | ||||||
|   always |  | ||||||
|     begin |  | ||||||
|       clk = 1; # 5; clk = 0; # 5; |  | ||||||
|       // if ($time % 100000 == 0) $display("Time is %0t", $time);
 |  | ||||||
|     end |  | ||||||
|     |  | ||||||
|   // check results
 |  | ||||||
|   assign reset_ext = InReset; |  | ||||||
|    |  | ||||||
|   always @(negedge clk) |  | ||||||
|     begin     |  | ||||||
|       InitializingMemories = 0; |  | ||||||
|       if(InReset == 1) begin |  | ||||||
|         // once the test inidicates it's done we need to immediately hold reset for a number of cycles.
 |  | ||||||
|         if(ResetCount < ResetThreshold) ResetCount = ResetCount + 1; |  | ||||||
|         else begin // hit reset threshold so we remove reset.
 |  | ||||||
|           InReset = 0; |  | ||||||
|           ResetCount = 0; |  | ||||||
|         end |  | ||||||
|       end |  | ||||||
|     end // always @ (negedge clk)
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|   // track the current function or global label
 |  | ||||||
|   if (DEBUG == 1) begin : FunctionName |  | ||||||
|     FunctionName #(P) FunctionName(.reset(reset), |  | ||||||
| 			      .clk(clk), |  | ||||||
| 			      .ProgramAddrMapFile(ProgramAddrMapFile), |  | ||||||
| 			      .ProgramLabelMapFile(ProgramLabelMapFile)); |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   // Termination condition
 |  | ||||||
|   // terminate on a specific ECALL after li x3,1 for old Imperas tests,  *** remove this when old imperas tests are removed
 |  | ||||||
|   // or sw	gp,-56(t0) for new Imperas tests
 |  | ||||||
|   // or sd gp, -56(t0) 
 |  | ||||||
|   // or on a jump to self infinite loop (6f) for RISC-V Arch tests
 |  | ||||||
|   logic ecf; // remove this once we don't rely on old Imperas tests with Ecalls
 |  | ||||||
|   if (P.ZICSR_SUPPORTED) assign ecf = dut.core.priv.priv.EcallFaultM; |  | ||||||
|   else                  assign ecf = 0; |  | ||||||
|   assign DCacheFlushStart = ecf &  |  | ||||||
| 			    (dut.core.ieu.dp.regf.rf[3] == 1 |  |  | ||||||
| 			     (dut.core.ieu.dp.regf.we3 &  |  | ||||||
| 			      dut.core.ieu.dp.regf.a3 == 3 &  |  | ||||||
| 			      dut.core.ieu.dp.regf.wd3 == 1)) | |  | ||||||
|            ((dut.core.ifu.InstrM == 32'h6f | dut.core.ifu.InstrM == 32'hfc32a423 | dut.core.ifu.InstrM == 32'hfc32a823) & dut.core.ieu.c.InstrValidM ) | |  | ||||||
|            ((dut.core.lsu.IEUAdrM == ProgramAddrLabelArray["tohost"]) & InstrMName == "SW" );  |  | ||||||
| 
 |  | ||||||
|   DCacheFlushFSM #(P) DCacheFlushFSM(.clk(clk), |  | ||||||
|     			.reset(reset), |  | ||||||
| 	    		.start(DCacheFlushStart), |  | ||||||
| 		    	.done(DCacheFlushDone)); |  | ||||||
| 
 |  | ||||||
|   // initialize the branch predictor
 |  | ||||||
|   if (P.BPRED_SUPPORTED == 1) |  | ||||||
|     begin |  | ||||||
|       genvar adrindex; |  | ||||||
|        |  | ||||||
|       // Initializing all zeroes into the branch predictor memory.
 |  | ||||||
|       for(adrindex = 0; adrindex < 1024; adrindex++) begin |  | ||||||
|         initial begin  |  | ||||||
|         force dut.core.ifu.bpred.bpred.Predictor.DirPredictor.PHT.mem[adrindex] = 0; |  | ||||||
|         force dut.core.ifu.bpred.bpred.TargetPredictor.memory.mem[adrindex] = 0; |  | ||||||
|         #1; |  | ||||||
|         release dut.core.ifu.bpred.bpred.Predictor.DirPredictor.PHT.mem[adrindex]; |  | ||||||
|         release dut.core.ifu.bpred.bpred.TargetPredictor.memory.mem[adrindex]; |  | ||||||
|         end |  | ||||||
|       end |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|   watchdog #(P.XLEN, 1000000) watchdog(.clk, .reset);  // check if PCW is stuck
 |  | ||||||
| 
 |  | ||||||
| endmodule |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /* verilator lint_on STMTDLY */ |  | ||||||
| /* verilator lint_on WIDTH */ |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| task automatic updateProgramAddrLabelArray; |  | ||||||
|   input string ProgramAddrMapFile, ProgramLabelMapFile; |  | ||||||
|   inout  integer ProgramAddrLabelArray [string]; |  | ||||||
|   // Gets the memory location of begin_signature
 |  | ||||||
|   integer ProgramLabelMapFP, ProgramAddrMapFP; |  | ||||||
|   ProgramLabelMapFP = $fopen(ProgramLabelMapFile, "r"); |  | ||||||
|   ProgramAddrMapFP = $fopen(ProgramAddrMapFile, "r"); |  | ||||||
|    |  | ||||||
|   if (ProgramLabelMapFP & ProgramAddrMapFP) begin // check we found both files
 |  | ||||||
|     while (!$feof(ProgramLabelMapFP)) begin |  | ||||||
|       string label, adrstr; |  | ||||||
|       integer returncode; |  | ||||||
|       returncode = $fscanf(ProgramLabelMapFP, "%s\n", label); |  | ||||||
|       returncode = $fscanf(ProgramAddrMapFP, "%s\n", adrstr); |  | ||||||
|       if (ProgramAddrLabelArray.exists(label))  |  | ||||||
|         ProgramAddrLabelArray[label] = adrstr.atohex(); |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
|   $fclose(ProgramLabelMapFP); |  | ||||||
|   $fclose(ProgramAddrMapFP); |  | ||||||
| endtask |  | ||||||
| 
 |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user