diff --git a/.gitignore b/.gitignore index dbe330a..2597fae 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ split_verilogs .vscode **/__pycache__/ *.fst +*.log *.dat **/UT_* NemuBR/ diff --git a/tests/uFTB-with-ftq/env/bpu_top.py b/tests/uFTB-with-ftq/env/bpu_top.py index 466024c..8f9fb3a 100644 --- a/tests/uFTB-with-ftq/env/bpu_top.py +++ b/tests/uFTB-with-ftq/env/bpu_top.py @@ -5,7 +5,7 @@ from .uftb_model import uFTBModel def assert_equal(a, b): if a != b: - print(f"[Error] Expected is {a}, but actual is {b}") + logger.error(f"[Error] Expected is {a}, but actual is {b}") exit(1) def compare_uftb_full_pred(uftb_output, std_output): @@ -148,27 +148,27 @@ class BPUTop: else: self.s1_hit_way = None - # print("-" * 30) + logger.debug("-" * 30) if self.s1_fire: # Debug Imformation - # print("[BPU]") - # print("New prediction at", hex(self.s1_pc)) - # if bpu_output["s1"]["full_pred"]["hit"]: - # print("Dut Hit") + logger.debug("[BPU]") + logger.debug(f"New prediction at {hex(self.s1_pc)}") + if bpu_output["s1"]["full_pred"]["hit"]: + logger.debug("Dut Hit") - # print("FTB Entry in pred result: ") - # if bpu_output["s1"]["full_pred"]["hit"]: - # ftb_entry.print(self.s1_pc) - # else: - # print("No FTB Entry") - # print("br_taken_mask:", bpu_output["s1"]["full_pred"]["br_taken_mask_0"], bpu_output["s1"]["full_pred"]["br_taken_mask_1"]) + logger.debug("FTB Entry in pred result: ") + if bpu_output["s1"]["full_pred"]["hit"]: + logger.debug(ftb_entry.__str__(self.s1_pc)) + else: + logger.debug("No FTB Entry") + logger.debug(f"br_taken_mask: {bpu_output['s1']['full_pred']['br_taken_mask_0']}, {bpu_output['s1']['full_pred']['br_taken_mask_1']}") - # print("FTB Entry in uFTB Model: ") - # if model_output: - # model_output[0].print(self.s1_pc) - # print("br_taken_mask:", model_output[1]) - # else: - # print("No FTB Entry") + logger.debug("FTB Entry in uFTB Model: ") + if model_output: + logger.debug(model_output[0].__str__(self.s1_pc)) + logger.debug(f"br_taken_mask: {model_output[1]}") + else: + logger.debug("No FTB Entry") # Compare dut output and uFTB model output expected_hit = model_output is not None diff --git a/tests/uFTB-with-ftq/env/ftb.py b/tests/uFTB-with-ftq/env/ftb.py index f23b961..50c00dc 100644 --- a/tests/uFTB-with-ftq/env/ftb.py +++ b/tests/uFTB-with-ftq/env/ftb.py @@ -8,15 +8,18 @@ class FTBSlot: self.tarStart = 0 self.sharing = 0 - def print(self, pc, is_cond_branch): + def __str__(self, pc, is_cond_branch): + str = "" if not self.valid: - print("*\tInvalid FTBSlot") - return + str += "*\tInvalid FTBSlot\n" + return str if is_cond_branch: - print(f"*\t[Conditional Branch Inst] at PC {hex(get_slot_addr(pc, self.offset))}: Target: {hex(get_target_addr(pc, self.tarStart, self.lower, 12))}") + str += f"*\t[Conditional Branch Inst] at PC {hex(get_slot_addr(pc, self.offset))}: Target: {hex(get_target_addr(pc, self.tarStart, self.lower, 12))}\n" else: - print(f"*\t[Jump Inst] PC {hex(get_slot_addr(pc, self.offset))}: Target: {hex(get_target_addr(pc, self.tarStart, self.lower, 20))}") + str += f"*\t[Jump Inst] PC {hex(get_slot_addr(pc, self.offset))}: Target: {hex(get_target_addr(pc, self.tarStart, self.lower, 20))}\n" + + return str class FTBEntry: @@ -165,16 +168,17 @@ class FTBEntry: return entry - - def print(self, pc): - print(f"[FTBEntry at {hex(pc)}]") - print(f"* Slots:") - self.brSlot.print(pc, True) - self.tailSlot.print(pc, self.tailSlot.sharing) - print("* Other Info:") - print(f"*\tFallthrough Addr: {hex(get_fallthrough_addr(pc, self.pftAddr, self.carry))}") - print(f"*\tisCall: {self.isCall}, isRet: {self.isRet}, isJalr: {self.isJalr}, isJal: {self.isJal}") - print(f"*\tlast_may_be_rvi_call: {self.last_may_be_rvi_call}, always_taken: {self.always_taken}") + def __str__(self, pc) -> str: + str = "" + str += f"[FTBEntry] at {hex(pc)}\n" + str += f"* Slots:\n" + str += self.brSlot.__str__(pc, True) + str += self.tailSlot.__str__(pc, self.tailSlot.sharing) + str += "* Other Info:\n" + str += f"*\tFallthrough Addr: {hex(get_fallthrough_addr(pc, self.pftAddr, self.carry))}\n" + str += f"*\tisCall: {self.isCall}, isRet: {self.isRet}, isJalr: {self.isJalr}, isJal: {self.isJal}\n" + str += f"*\tlast_may_be_rvi_call: {self.last_may_be_rvi_call}, always_taken: {self.always_taken}\n" + return str class FTBProvider(): def __init__(self): diff --git a/tests/uFTB-with-ftq/env/ftq.py b/tests/uFTB-with-ftq/env/ftq.py index ab59a41..396987d 100644 --- a/tests/uFTB-with-ftq/env/ftq.py +++ b/tests/uFTB-with-ftq/env/ftq.py @@ -1,3 +1,4 @@ +from mlvp import * from random import random from .bundle import * from .config import * @@ -31,27 +32,30 @@ class PredictionStatistician: self.jmp_branches_list[pc] = [branch_type, 1, int(correct)] def summary(self): - print("=" * 30) - print("Summary") - print("[Conditional Branches]") + summary_str = "" + summary_str += "=" * 30 + "\n" + summary_str += "Summary\n" + summary_str += "[Conditional Branches]\n" cond_branches_total = sum([record[0] for record in self.cond_branches_list.values()]) cond_branches_correct = sum([record[1] for record in self.cond_branches_list.values()]) - print(f"Total: {cond_branches_total}, Correct: {cond_branches_correct}, Accuracy: {cond_branches_correct / cond_branches_total}") + summary_str += f"Total: {cond_branches_total}, Correct: {cond_branches_correct}, Accuracy: {cond_branches_correct / cond_branches_total}\n" for pc, record in self.cond_branches_list.items(): - print(f"PC: {hex(pc)}\tTotal: {record[0]}\tCorrect: {record[1]}\tAccuracy: {record[1] / record[0]}") + summary_str += f"PC: {hex(pc)}\tTotal: {record[0]}\tCorrect: {record[1]}\tAccuracy: {record[1] / record[0]}\n" - print("[Jump Branches]") + summary_str += "[Jump Branches]\n" jmp_branches_total = sum([record[1] for record in self.jmp_branches_list.values()]) jmp_branches_correct = sum([record[2] for record in self.jmp_branches_list.values()]) - print(f"Total: {jmp_branches_total}, Correct: {jmp_branches_correct}, Accuracy: {jmp_branches_correct / jmp_branches_total}") + summary_str += f"Total: {jmp_branches_total}, Correct: {jmp_branches_correct}, Accuracy: {jmp_branches_correct / jmp_branches_total}\n" for pc, record in self.jmp_branches_list.items(): - print(f"PC: {hex(pc)}\tType: {record[0]}\tTotal: {record[1]}\tCorrect: {record[2]}\tAccuracy: {record[2] / record[1]}") + summary_str += f"PC: {hex(pc)}\tType: {record[0]}\tTotal: {record[1]}\tCorrect: {record[2]}\tAccuracy: {record[2] / record[1]}\n" - print("[All Branches]") + summary_str += "[All Branches]\n" total = cond_branches_total + jmp_branches_total correct = cond_branches_correct + jmp_branches_correct - print(f"Total: {total}, Correct: {correct}, Accuracy: {correct / total}") + summary_str += f"Total: {total}, Correct: {correct}, Accuracy: {correct / total}\n" + + logger.info(summary_str) @staticmethod def get_type(is_call, is_ret, is_jalr, is_jal): @@ -104,13 +108,12 @@ class FTQ: update_request, redirect_request = None, None if self.update_queue: update_request = self._generate_update_request(self.update_queue.pop(0)) - # print("Send Update Request: %s" % hex(update_request['bits_pc']), \ - # "br_taken_mask:", update_request["bits_br_taken_mask_0"], update_request["bits_br_taken_mask_1"]) - + logger.debug(f"Send Update Request: {hex(update_request['bits_pc'])}\ + br_taken_mask: {update_request['bits_br_taken_mask_0']}, {update_request['bits_br_taken_mask_1']}") if self.redirect_queue: cfi_target = self.redirect_queue.pop(0) redirect_request = self._generate_redirect_request(cfi_target) - # print("Send Redirect Request: (target: %s)" % hex(cfi_target)) + logger.debug("Send Redirect Request: (target: %s)" % hex(cfi_target)) return (update_request, redirect_request) @@ -129,18 +132,18 @@ class FTQ: entry = self._get_entry(self.exec_ptr) executor_current_pc = self.executor.current_inst()[0] self.exec_ptr += 1 - # print("Executing FTQ entry at pc %s" % hex(entry.pc)) + logger.debug("Executing FTQ entry at pc %s" % hex(entry.pc)) # Prediction Block Hit if entry.full_pred["hit"] and entry.pc == executor_current_pc: - # print("Prediction Block Hit") + logger.debug("Prediction Block Hit") # Execute the prediction block all_branches, redirect_addr, br_taken_mask = self._execute_this_pred_block(entry.pc, entry.full_pred) - # if redirect_addr is None: - # print("Predicition is correct") - # else: - # print("Prediction is wrong, redirect to %s" % hex(redirect_addr)) + if redirect_addr is None: + logger.debug("Predicition is correct") + else: + logger.debug("Prediction is wrong, redirect to %s" % hex(redirect_addr)) new_ftb_entry = self._update_ftb_entry_from_branches(entry.pc, entry.ftb, all_branches, br_taken_mask) self.update_queue.append((entry.pc, new_ftb_entry, br_taken_mask)) if redirect_addr is not None: @@ -148,9 +151,9 @@ class FTQ: # Prediction Block Miss else: - # print("Prediction Block Miss") - # if entry.pc != executor_current_pc: - # print("Target Error: actual: %s expected: %s" % (hex(entry.pc), hex(executor_current_pc))) + logger.debug("Prediction Block Miss") + if entry.pc != executor_current_pc: + logger.debug("Target Error: actual: %s expected: %s" % (hex(entry.pc), hex(executor_current_pc))) # Create a new FTB entry and update & redirect new_ftb_entry, br_taken_mask = self._generate_new_ftb_entry(executor_current_pc) @@ -288,14 +291,14 @@ class FTQ: ftb_entry.pftAddr = get_pftaddr(fallthrough_addr) ftb_entry.carry = get_pftaddr_carry(pc, fallthrough_addr) - # print("Generate FTB Entry") - # ftb_entry.print(pc) + logger.debug("Generate FTB Entry") + logger.debug(ftb_entry.__str__(pc)) return ftb_entry, br_taken_mask def _update_entries(self, bpu_out, ftb_entry): if bpu_out["s1"]["valid"]: - # print("Add ftq entry (pc: %s)" % hex(bpu_out["s1"]["pc_3"])) + logger.debug("Add ftq entry (pc: %s)" % hex(bpu_out["s1"]["pc_3"])) entry = self._get_entry(self.bpu_ptr) entry.full_pred = bpu_out["s1"]["full_pred"] entry.pc = bpu_out["s1"]["pc_3"] diff --git a/tests/uFTB-with-ftq/env/uftb_model.py b/tests/uFTB-with-ftq/env/uftb_model.py index 309de75..a6c286d 100644 --- a/tests/uFTB-with-ftq/env/uftb_model.py +++ b/tests/uFTB-with-ftq/env/uftb_model.py @@ -1,4 +1,5 @@ from mlvp.utils import PLRU, TwoBitsCounter +from mlvp import logger from .ftb import * class uFTBWay: @@ -42,7 +43,7 @@ class uFTBModel: def print_all_ftb_ways(self): for i in range(UFTB_WAYS_NUM): - print(f"way {i}: valid: {self.ftbways[i].valid}, tag: {hex(self.ftbways[i].tag << 1)}") + logger.debug(f"way {i}: valid: {self.ftbways[i].valid}, tag: {hex(self.ftbways[i].tag << 1)}") def _generate_br_taken_mask(self, hit_way): ftb_entry = self.ftbways[hit_way].ftb_entry @@ -91,7 +92,7 @@ class uFTBModel: if selected_way is None or way < selected_way: selected_way = way break - # print(f"Hit selected way is {selected_way}") + logger.debug(f"Hit selected way is {selected_way}") new_update_queue.append((self.update_queue[i][0], self.update_queue[i][1] - 1, selected_way)) self.update_queue = new_update_queue @@ -107,7 +108,7 @@ class uFTBModel: if not update_request["valid"]: return - # print(f"ftb entry {hex(update_request['bits_pc'])} is put into way {selected_way}") + logger.debug(f"ftb entry {hex(update_request['bits_pc'])} is put into way {selected_way}") self.ftbways[selected_way].valid = 1 self.ftbways[selected_way].tag = uFTBWay.get_tag(update_request["bits_pc"]) self.ftbways[selected_way].ftb_entry = FTBEntry.from_dict(update_request["ftb_entry"]) diff --git a/tests/uFTB-with-ftq/tests/test_with_ftq.py b/tests/uFTB-with-ftq/tests/test_with_ftq.py index 4607a9d..eb8a75a 100644 --- a/tests/uFTB-with-ftq/tests/test_with_ftq.py +++ b/tests/uFTB-with-ftq/tests/test_with_ftq.py @@ -62,6 +62,9 @@ def test_uftb(request): set_func_coverage(request, g) set_line_coverage(request, "VFauFTB_coverage.dat") + import logging + mlvp.setup_logging(log_level=logging.INFO, log_file="uftb_with_ftq.log") + mlvp.run(uftb_test()) uFTB.finalize()